home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / vp21beta.zip / ATVSRC.RAR / DIALOGS.PAS < prev    next >
Pascal/Delphi Source File  |  2000-08-15  |  56KB  |  2,293 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Turbo Pascal Version 7.0                        }
  5. {       Turbo Vision Unit                               }
  6. {                                                       }
  7. {       Copyright (c) 1992 Borland International        }
  8. {                                                       }
  9. {       Virtual Pascal v2.1                             }
  10. {       Copyright (C) 1996-2000 vpascal.com             }
  11. {                                                       }
  12. {*******************************************************}
  13.  
  14. unit Dialogs;
  15.  
  16. {$X+,I-,S-,Cdecl-,Use32+}
  17.  
  18. interface
  19.  
  20. uses Objects, Drivers, Views, Validate;
  21.  
  22. const
  23.  
  24. { Color palettes }
  25.  
  26.   CGrayDialog    = #32#33#34#35#36#37#38#39#40#41#42#43#44#45#46#47 +
  27.                    #48#49#50#51#52#53#54#55#56#57#58#59#60#61#62#63;
  28.   CBlueDialog    = #64#65#66#67#68#69#70#71#72#73#74#75#76#77#78#79 +
  29.                    #80#81#82#83#84#85#86#87#88#89#90#91#92#92#94#95;
  30.   CCyanDialog    = #96#97#98#99#100#101#102#103#104#105#106#107#108 +
  31.                    #109#110#111#112#113#114#115#116#117#118#119#120 +
  32.                    #121#122#123#124#125#126#127;
  33.  
  34.   CDialog        = CGrayDialog;
  35.  
  36.   CStaticText    = #6;
  37.   CLabel         = #7#8#9#9;
  38.   CButton        = #10#11#12#13#14#14#14#15;
  39.   CCluster       = #16#17#18#18#31;
  40.   CInputLine     = #19#19#20#21;
  41.   CHistory       = #22#23;
  42.   CHistoryWindow = #19#19#21#24#25#19#20;
  43.   CHistoryViewer = #6#6#7#6#6;
  44.  
  45. { TDialog palette entires }
  46.  
  47.   dpBlueDialog = 0;
  48.   dpCyanDialog = 1;
  49.   dpGrayDialog = 2;
  50.  
  51. { TButton flags }
  52.  
  53.   bfNormal    = $00;
  54.   bfDefault   = $01;
  55.   bfLeftJust  = $02;
  56.   bfBroadcast = $04;
  57.   bfGrabFocus = $08;
  58.  
  59. { TMultiCheckboxes flags }
  60. { hibyte = number of bits }
  61. { lobyte = bit mask }
  62.  
  63.   cfOneBit       = $0101;
  64.   cfTwoBits      = $0203;
  65.   cfFourBits     = $040F;
  66.   cfEightBits    = $08FF;
  67.  
  68. type
  69.  
  70. { TDialog object }
  71.  
  72.   { Palette layout }
  73.   {  1 = Frame passive }
  74.   {  2 = Frame active }
  75.   {  3 = Frame icon }
  76.   {  4 = ScrollBar page area }
  77.   {  5 = ScrollBar controls }
  78.   {  6 = StaticText }
  79.   {  7 = Label normal }
  80.   {  8 = Label selected }
  81.   {  9 = Label shortcut }
  82.   { 10 = Button normal }
  83.   { 11 = Button default }
  84.   { 12 = Button selected }
  85.   { 13 = Button disabled }
  86.   { 14 = Button shortcut }
  87.   { 15 = Button shadow }
  88.   { 16 = Cluster normal }
  89.   { 17 = Cluster selected }
  90.   { 18 = Cluster shortcut }
  91.   { 19 = InputLine normal text }
  92.   { 20 = InputLine selected text }
  93.   { 21 = InputLine arrows }
  94.   { 22 = History arrow }
  95.   { 23 = History sides }
  96.   { 24 = HistoryWindow scrollbar page area }
  97.   { 25 = HistoryWindow scrollbar controls }
  98.   { 26 = ListViewer normal }
  99.   { 27 = ListViewer focused }
  100.   { 28 = ListViewer selected }
  101.   { 29 = ListViewer divider }
  102.   { 30 = InfoPane }
  103.   { 31 = Cluster disabled }
  104.   { 32 = Reserved }
  105.  
  106.   PDialog = ^TDialog;
  107.   TDialog = object(TWindow)
  108.     constructor Init(var Bounds: TRect; ATitle: TTitleStr);
  109.     constructor Load(var S: TStream);
  110.     function GetPalette: PPalette; virtual;
  111.     procedure HandleEvent(var Event: TEvent); virtual;
  112.     function Valid(Command: Word): Boolean; virtual;
  113.     procedure SizeLimits(var Min, Max: TPoint); virtual; // Added for VPPM
  114.   end;
  115.  
  116. { TSItem }
  117.  
  118.   PSItem = ^TSItem;
  119.   TSItem = record
  120.     Value: PString;
  121.     Next: PSItem;
  122.   end;
  123.  
  124. { TInputLine object }
  125.  
  126.   { Palette layout }
  127.   { 1 = Passive }
  128.   { 2 = Active }
  129.   { 3 = Selected }
  130.   { 4 = Arrows }
  131.  
  132.   PInputLine = ^TInputLine;
  133.   TInputLine = object(TView)
  134.     Data: PString;
  135.     MaxLen: Integer;
  136.     CurPos: Integer;
  137.     FirstPos: Integer;
  138.     SelStart: Integer;
  139.     SelEnd: Integer;
  140.     Validator: PValidator;
  141.     constructor Init(var Bounds: TRect; AMaxLen: Integer);
  142.     constructor Load(var S: TStream);
  143.     destructor Done; virtual;
  144.     function DataSize: Word; virtual;
  145.     procedure Draw; virtual;
  146.     procedure GetData(var Rec); virtual;
  147.     function GetPalette: PPalette; virtual;
  148.     procedure HandleEvent(var Event: TEvent); virtual;
  149.     procedure SelectAll(Enable: Boolean);
  150.     procedure SetData(var Rec); virtual;
  151.     procedure SetState(AState: Word; Enable: Boolean); virtual;
  152.     procedure SetValidator(AValid: PValidator);
  153.     procedure Store(var S: TStream);
  154.     function Valid(Command: Word): Boolean; virtual;
  155.   private
  156.     function CanScroll(Delta: Integer): Boolean;
  157.   end;
  158.  
  159. { TButton object }
  160.  
  161.   { Palette layout }
  162.   { 1 = Normal text }
  163.   { 2 = Default text }
  164.   { 3 = Selected text }
  165.   { 4 = Disabled text }
  166.   { 5 = Normal shortcut }
  167.   { 6 = Default shortcut }
  168.   { 7 = Selected shortcut }
  169.   { 8 = Shadow }
  170.  
  171.   PButton = ^TButton;
  172.   TButton = object(TView)
  173.     Title: PString;
  174.     Command: Word;
  175.     Flags: Byte;
  176.     AmDefault: Boolean;
  177.     constructor Init(var Bounds: TRect; ATitle: TTitleStr; ACommand: Word;
  178.       AFlags: Word);
  179.     constructor Load(var S: TStream);
  180.     destructor Done; virtual;
  181.     procedure Draw; virtual;
  182.     procedure DrawState(Down: Boolean);
  183.     function GetPalette: PPalette; virtual;
  184.     procedure HandleEvent(var Event: TEvent); virtual;
  185.     procedure MakeDefault(Enable: Boolean);
  186.     procedure Press; virtual;
  187.     procedure SetState(AState: Word; Enable: Boolean); virtual;
  188.     procedure Store(var S: TStream);
  189.   end;
  190.  
  191. { TCluster }
  192.  
  193.   { Palette layout }
  194.   { 1 = Normal text }
  195.   { 2 = Selected text }
  196.   { 3 = Normal shortcut }
  197.   { 4 = Selected shortcut }
  198.   { 5 = Disabled text }
  199.  
  200.   PCluster = ^TCluster;
  201.   TCluster = object(TView)
  202.     Value: LongInt;
  203.     Sel: Integer;
  204.     EnableMask: LongInt;
  205.     Strings: TStringCollection;
  206.     constructor Init(var Bounds: TRect; AStrings: PSItem);
  207.     constructor Load(var S: TStream);
  208.     destructor Done; virtual;
  209.     function ButtonState(Item: Integer): Boolean;
  210.     function DataSize: Word; virtual;
  211.     procedure DrawBox(const Icon: String; Marker: Char);
  212.     procedure DrawMultiBox(const Icon, Marker: String);
  213.     procedure GetData(var Rec); virtual;
  214.     function GetHelpCtx: Word; virtual;
  215.     function GetPalette: PPalette; virtual;
  216.     procedure HandleEvent(var Event: TEvent); virtual;
  217.     function Mark(Item: Integer): Boolean; virtual;
  218.     function MultiMark(Item: Integer): Byte; virtual;
  219.     procedure Press(Item: Integer); virtual;
  220.     procedure MovedTo(Item: Integer); virtual;
  221.     procedure SetButtonState(AMask: Longint; Enable: Boolean);
  222.     procedure SetData(var Rec); virtual;
  223.     procedure SetState(AState: Word; Enable: Boolean); virtual;
  224.     procedure Store(var S: TStream);
  225.   private
  226.     function Column(Item: Integer): Integer;
  227.     function FindSel(P: TPoint): Integer;
  228.     function Row(Item: Integer): Integer;
  229.   end;
  230.  
  231. { TRadioButtons }
  232.  
  233.   { Palette layout }
  234.   { 1 = Normal text }
  235.   { 2 = Selected text }
  236.   { 3 = Normal shortcut }
  237.   { 4 = Selected shortcut }
  238.  
  239.   PRadioButtons = ^TRadioButtons;
  240.   TRadioButtons = object(TCluster)
  241.     procedure Draw; virtual;
  242.     function Mark(Item: Integer): Boolean; virtual;
  243.     procedure MovedTo(Item: Integer); virtual;
  244.     procedure Press(Item: Integer); virtual;
  245.     procedure SetData(var Rec); virtual;
  246.   end;
  247.  
  248. { TCheckBoxes }
  249.  
  250.   { Palette layout }
  251.   { 1 = Normal text }
  252.   { 2 = Selected text }
  253.   { 3 = Normal shortcut }
  254.   { 4 = Selected shortcut }
  255.  
  256.   PCheckBoxes = ^TCheckBoxes;
  257.   TCheckBoxes = object(TCluster)
  258.     procedure Draw; virtual;
  259.     function Mark(Item: Integer): Boolean; virtual;
  260.     procedure Press(Item: Integer); virtual;
  261.   end;
  262.  
  263. { TMultiCheckBoxes }
  264.  
  265.   { Palette layout }
  266.   { 1 = Normal text }
  267.   { 2 = Selected text }
  268.   { 3 = Normal shortcut }
  269.   { 4 = Selected shortcut }
  270.  
  271.   PMultiCheckBoxes = ^TMultiCheckBoxes;
  272.   TMultiCheckBoxes = object(TCluster)
  273.     SelRange: Byte;
  274.     Flags: Word;
  275.     States: PString;
  276.     constructor Init(var Bounds: TRect; AStrings: PSItem;
  277.       ASelRange: Byte; AFlags: Word; const AStates: String);
  278.     constructor Load(var S: TStream);
  279.     destructor Done; virtual;
  280.     function DataSize: Word; virtual;
  281.     procedure Draw; virtual;
  282.     procedure GetData(var Rec); virtual;
  283.     function MultiMark(Item: Integer): Byte; virtual;
  284.     procedure Press(Item: Integer); virtual;
  285.     procedure SetData(var Rec); virtual;
  286.     procedure Store(var S: TStream);
  287.   end;
  288.  
  289. { TListBox }
  290.  
  291.   { Palette layout }
  292.   { 1 = Active }
  293.   { 2 = Inactive }
  294.   { 3 = Focused }
  295.   { 4 = Selected }
  296.   { 5 = Divider }
  297.  
  298.   PListBox = ^TListBox;
  299.   TListBox = object(TListViewer)
  300.     List: PCollection;
  301.     constructor Init(var Bounds: TRect; ANumCols: Word;
  302.       AScrollBar: PScrollBar);
  303.     constructor Load(var S: TStream);
  304.     function DataSize: Word; virtual;
  305.     procedure GetData(var Rec); virtual;
  306.     function GetText(Item: Integer; MaxLen: Integer): String; virtual;
  307.     procedure NewList(AList: PCollection); virtual;
  308.     procedure SetData(var Rec); virtual;
  309.     procedure Store(var S: TStream);
  310.   end;
  311.  
  312. { TStaticText }
  313.  
  314.   { Palette layout }
  315.   { 1 = Text }
  316.  
  317.   PStaticText = ^TStaticText;
  318.   TStaticText = object(TView)
  319.     Text: PString;
  320.     constructor Init(var Bounds: TRect; const AText: String);
  321.     constructor Load(var S: TStream);
  322.     destructor Done; virtual;
  323.     procedure Draw; virtual;
  324.     function GetPalette: PPalette; virtual;
  325.     procedure GetText(var S: String); virtual;
  326.     procedure Store(var S: TStream);
  327.   end;
  328.  
  329. { TParamText }
  330.  
  331.   { Palette layout }
  332.   { 1 = Text }
  333.  
  334.   PParamText = ^TParamText;
  335.   TParamText = object(TStaticText)
  336.     ParamCount: Integer;
  337.     ParamList: Pointer;
  338.     constructor Init(var Bounds: TRect; const AText: String;
  339.       AParamCount: Integer);
  340.     constructor Load(var S: TStream);
  341.     function DataSize: Word; virtual;
  342.     procedure GetText(var S: String); virtual;
  343.     procedure SetData(var Rec); virtual;
  344.     procedure Store(var S: TStream);
  345.   end;
  346.  
  347. { TLabel }
  348.  
  349.   { Palette layout }
  350.   { 1 = Normal text }
  351.   { 2 = Selected text }
  352.   { 3 = Normal shortcut }
  353.   { 4 = Selected shortcut }
  354.  
  355.   PLabel = ^TLabel;
  356.   TLabel = object(TStaticText)
  357.     Link: PView;
  358.     Light: Boolean;
  359.     constructor Init(var Bounds: TRect; const AText: String; ALink: PView);
  360.     constructor Load(var S: TStream);
  361.     procedure Draw; virtual;
  362.     function GetPalette: PPalette; virtual;
  363.     procedure HandleEvent(var Event: TEvent); virtual;
  364.     procedure Store(var S: TStream);
  365.   end;
  366.  
  367. { THistoryViewer }
  368.  
  369.   { Palette layout }
  370.   { 1 = Active }
  371.   { 2 = Inactive }
  372.   { 3 = Focused }
  373.   { 4 = Selected }
  374.   { 5 = Divider }
  375.  
  376.   PHistoryViewer = ^THistoryViewer;
  377.   THistoryViewer = object(TListViewer)
  378.     HistoryId: Word;
  379.     constructor Init(var Bounds: TRect; AHScrollBar, AVScrollBar: PScrollBar;
  380.       AHistoryId: Word);
  381.     function GetPalette: PPalette; virtual;
  382.     function GetText(Item: Integer; MaxLen: Integer): String; virtual;
  383.     procedure HandleEvent(var Event: TEvent); virtual;
  384.     function HistoryWidth: Integer;
  385.   end;
  386.  
  387. { THistoryWindow }
  388.  
  389.   { Palette layout }
  390.   { 1 = Frame passive }
  391.   { 2 = Frame active }
  392.   { 3 = Frame icon }
  393.   { 4 = ScrollBar page area }
  394.   { 5 = ScrollBar controls }
  395.   { 6 = HistoryViewer normal text }
  396.   { 7 = HistoryViewer selected text }
  397.  
  398.   PHistoryWindow = ^THistoryWindow;
  399.   THistoryWindow = object(TWindow)
  400.     Viewer: PListViewer;
  401.     constructor Init(var Bounds: TRect; HistoryId: Word);
  402.     function GetPalette: PPalette; virtual;
  403.     function GetSelection: String; virtual;
  404.     procedure InitViewer(HistoryId: Word); virtual;
  405.   end;
  406.  
  407. { THistory }
  408.  
  409.   { Palette layout }
  410.   { 1 = Arrow }
  411.   { 2 = Sides }
  412.  
  413.   PHistory = ^THistory;
  414.   THistory = object(TView)
  415.     Link: PInputLine;
  416.     HistoryId: Word;
  417.     constructor Init(var Bounds: TRect; ALink: PInputLine; AHistoryId: Word);
  418.     constructor Load(var S: TStream);
  419.     procedure Draw; virtual;
  420.     function GetPalette: PPalette; virtual;
  421.     procedure HandleEvent(var Event: TEvent); virtual;
  422.     function InitHistoryWindow(var Bounds: TRect): PHistoryWindow; virtual;
  423.     procedure RecordHistory(const S: String); virtual;
  424.     procedure Store(var S: TStream);
  425.   end;
  426.  
  427. { SItem routines }
  428.  
  429. function NewSItem(const Str: String; ANext: PSItem): PSItem;
  430.  
  431. { Dialogs registration procedure }
  432.  
  433. procedure RegisterDialogs;
  434.  
  435. { Stream Registration Records }
  436.  
  437. const
  438.   RDialog: TStreamRec = (
  439.      ObjType: 10;
  440.      VmtLink: Ofs(TypeOf(TDialog)^);
  441.      Load:    @TDialog.Load;
  442.      Store:   @TDialog.Store
  443.   );
  444.  
  445. const
  446.   RInputLine: TStreamRec = (
  447.      ObjType: 11;
  448.      VmtLink: Ofs(TypeOf(TInputLine)^);
  449.      Load:    @TInputLine.Load;
  450.      Store:   @TInputLine.Store
  451.   );
  452.  
  453. const
  454.   RButton: TStreamRec = (
  455.      ObjType: 12;
  456.      VmtLink: Ofs(TypeOf(TButton)^);
  457.      Load:    @TButton.Load;
  458.      Store:   @TButton.Store
  459.   );
  460.  
  461. const
  462.   RCluster: TStreamRec = (
  463.      ObjType: 13;
  464.      VmtLink: Ofs(TypeOf(TCluster)^);
  465.      Load:    @TCluster.Load;
  466.      Store:   @TCluster.Store
  467.   );
  468.  
  469. const
  470.   RRadioButtons: TStreamRec = (
  471.      ObjType: 14;
  472.      VmtLink: Ofs(TypeOf(TRadioButtons)^);
  473.      Load:    @TRadioButtons.Load;
  474.      Store:   @TRadioButtons.Store
  475.   );
  476.  
  477. const
  478.   RCheckBoxes: TStreamRec = (
  479.      ObjType: 15;
  480.      VmtLink: Ofs(TypeOf(TCheckBoxes)^);
  481.      Load:    @TCheckBoxes.Load;
  482.      Store:   @TCheckBoxes.Store
  483.   );
  484.  
  485. const
  486.   RMultiCheckBoxes: TStreamRec = (
  487.      ObjType: 27;
  488.      VmtLink: Ofs(TypeOf(TMultiCheckBoxes)^);
  489.      Load:    @TMultiCheckBoxes.Load;
  490.      Store:   @TMultiCheckBoxes.Store
  491.   );
  492.  
  493. const
  494.   RListBox: TStreamRec = (
  495.      ObjType: 16;
  496.      VmtLink: Ofs(TypeOf(TListBox)^);
  497.      Load:    @TListBox.Load;
  498.      Store:   @TListBox.Store
  499.   );
  500.  
  501. const
  502.   RStaticText: TStreamRec = (
  503.      ObjType: 17;
  504.      VmtLink: Ofs(TypeOf(TStaticText)^);
  505.      Load:    @TStaticText.Load;
  506.      Store:   @TStaticText.Store
  507.   );
  508.  
  509. const
  510.   RLabel: TStreamRec = (
  511.      ObjType: 18;
  512.      VmtLink: Ofs(TypeOf(TLabel)^);
  513.      Load:    @TLabel.Load;
  514.      Store:   @TLabel.Store
  515.   );
  516.  
  517. const
  518.   RHistory: TStreamRec = (
  519.      ObjType: 19;
  520.      VmtLink: Ofs(TypeOf(THistory)^);
  521.      Load:    @THistory.Load;
  522.      Store:   @THistory.Store
  523.   );
  524.  
  525. const
  526.   RParamText: TStreamRec = (
  527.      ObjType: 20;
  528.      VmtLink: Ofs(TypeOf(TParamText)^);
  529.      Load:    @TParamText.Load;
  530.      Store:   @TParamText.Store
  531.   );
  532.  
  533. const
  534.  
  535. { Dialog broadcast commands }
  536.  
  537.   cmRecordHistory = 60;
  538.  
  539. implementation
  540.  
  541. uses HistList;
  542.  
  543. const
  544.  
  545. { TButton messages }
  546.  
  547.   cmGrabDefault    = 61;
  548.   cmReleaseDefault = 62;
  549.  
  550. { Utility functions }
  551.  
  552. function IsBlank(Ch: Char): Boolean;
  553. begin
  554.   IsBlank := (Ch = ' ') or (Ch = #13) or (Ch = #10);
  555. end;
  556.  
  557. { TDialog }
  558.  
  559. constructor TDialog.Init(var Bounds: TRect; ATitle: TTitleStr);
  560. begin
  561.   inherited Init(Bounds, ATitle, wnNoNumber);
  562.   Options := Options or ofVersion20;
  563.   GrowMode := 0;
  564.   Flags := wfMove + wfClose;
  565.   Palette := dpGrayDialog;
  566. end;
  567.  
  568. constructor TDialog.Load(var S: TStream);
  569. begin
  570.   inherited Load(S);
  571.   if Options and ofVersion = ofVersion10 then
  572.   begin
  573.     Palette := dpGrayDialog;
  574.     Inc(Options, ofVersion20);
  575.   end;
  576. end;
  577.  
  578. function TDialog.GetPalette: PPalette;
  579. const
  580.   P: array[dpBlueDialog..dpGrayDialog] of string[Length(CBlueDialog)] =
  581.     (CBlueDialog, CCyanDialog, CGrayDialog);
  582. begin
  583.   GetPalette := @P[Palette];
  584. end;
  585.  
  586. procedure TDialog.HandleEvent(var Event: TEvent);
  587. begin
  588.   TWindow.HandleEvent(Event);
  589.   case Event.What of
  590.     evKeyDown:
  591.       case Event.KeyCode of
  592.         kbEsc:
  593.           begin
  594.             Event.What := evCommand;
  595.             Event.Command := cmCancel;
  596.             Event.InfoPtr := nil;
  597.             PutEvent(Event);
  598.             ClearEvent(Event);
  599.           end;
  600.         kbEnter:
  601.           begin
  602.             Event.What := evBroadcast;
  603.             Event.Command := cmDefault;
  604.             Event.InfoPtr := nil;
  605.             PutEvent(Event);
  606.             ClearEvent(Event);
  607.           end;
  608.       end;
  609.     evCommand:
  610.       case Event.Command of
  611.         cmOk, cmCancel, cmYes, cmNo:
  612.           if State and sfModal <> 0 then
  613.           begin
  614.             EndModal(Event.Command);
  615.             ClearEvent(Event);
  616.           end;
  617.       end;
  618.   end;
  619. end;
  620.  
  621. function TDialog.Valid(Command: Word): Boolean;
  622. begin
  623.   if Command = cmCancel then Valid := True
  624.   else Valid := TGroup.Valid(Command);
  625. end;
  626.  
  627. procedure TDialog.SizeLimits(var Min, Max: TPoint);
  628. begin
  629.   inherited SizeLimits(Min, Max);
  630.   Max.X := MaxLongint;
  631.   Max.Y := MaxLongint;
  632. end;
  633.  
  634. function NewSItem(const Str: String; ANext: PSItem): PSItem;
  635. var
  636.   Item: PSItem;
  637. begin
  638.   New(Item);
  639.   Item^.Value := NewStr(Str);
  640.   Item^.Next := ANext;
  641.   NewSItem := Item;
  642. end;
  643.  
  644. function HotKey(const S: String): Char;
  645. var
  646.   P: Word;
  647. begin
  648.   HotKey := #0;
  649.   if S = '' then
  650.     Exit;
  651.   P := Pos('~',S);
  652.   if P <> 0 then HotKey := UpCase(S[P+1]);
  653. end;
  654.  
  655. { TInputLine }
  656.  
  657. constructor TInputLine.Init(var Bounds: TRect; AMaxLen: Integer);
  658. begin
  659.   TView.Init(Bounds);
  660.   State := State or sfCursorVis;
  661.   Options := Options or (ofSelectable + ofFirstClick + ofVersion20);
  662.   GetMem(Data, AMaxLen + 1);
  663.   Data^ := '';
  664.   MaxLen := AMaxLen;
  665. end;
  666.  
  667. constructor TInputLine.Load(var S: TStream);
  668. begin
  669.   TView.Load(S);
  670.   S.Read(MaxLen, SizeOf(Integer) * 5);
  671.   GetMem(Data, MaxLen + 1);
  672.   S.Read(Data^[0], 1);
  673.   S.Read(Data^[1], Length(Data^));
  674.   if Options and ofVersion >= ofVersion20 then
  675.     Validator := PValidator(S.Get);
  676.   Options := Options or ofVersion20;
  677. end;
  678.  
  679. destructor TInputLine.Done;
  680. begin
  681.   FreeMem(Data, MaxLen + 1);
  682.   SetValidator(nil);
  683.   TView.Done;
  684. end;
  685.  
  686. function TInputLine.CanScroll(Delta: Integer): Boolean;
  687. begin
  688.   if Delta < 0 then
  689.     CanScroll := FirstPos > 0 else
  690.   if Delta > 0 then
  691.     CanScroll := Length(Data^) - FirstPos + 2 > Size.X else
  692.     CanScroll := False;
  693. end;
  694.  
  695. function TInputLine.DataSize: Word;
  696. var
  697.   DSize: Word;
  698. begin
  699.   DSize := 0;
  700.  
  701.   if Validator <> nil then
  702.     DSize := Validator^.Transfer(Data^, nil, vtDataSize);
  703.  
  704.   if DSize <> 0 then
  705.     DataSize := DSize
  706.   else
  707.     DataSize := MaxLen + 1;
  708. end;
  709.  
  710. procedure TInputLine.Draw;
  711. var
  712.   Color: Byte;
  713.   L, R: Integer;
  714.   B: TDrawBuffer;
  715. begin
  716.   if State and sfFocused = 0 then
  717.     Color := GetColor(1) else
  718.     Color := GetColor(2);
  719.   MoveChar(B, ' ', Color, Size.X);
  720.   MoveStr(B[1], Copy(Data^, FirstPos + 1, Size.X - 2), Color);
  721.   if CanScroll(1) then MoveChar(B[Size.X - 1], #16, GetColor(4), 1);
  722.   if State and sfFocused <> 0 then
  723.   begin
  724.     if CanScroll(-1) then MoveChar(B[0], #17, GetColor(4), 1);
  725.     L := SelStart - FirstPos;
  726.     R := SelEnd - FirstPos;
  727.     if L < 0 then L := 0;
  728.     if R > Size.X - 2 then R := Size.X - 2;
  729.     if L < R then MoveChar(B[L + 1], #0, GetColor(3), R - L);
  730.   end;
  731.   WriteLine(0, 0, Size.X, Size.Y, B);
  732.   SetCursor(CurPos - FirstPos + 1, 0);
  733. end;
  734.  
  735. procedure TInputLine.GetData(var Rec);
  736. begin
  737.   if (Validator = nil) or
  738.     (Validator^.Transfer(Data^, @Rec, vtGetData) = 0) then
  739.   begin
  740.     FillChar(Rec, DataSize, #0);
  741.     Move(Data^, Rec, Length(Data^) + 1);
  742.   end;
  743. end;
  744.  
  745. function TInputLine.GetPalette: PPalette;
  746. const
  747.   P: String[Length(CInputLine)] = CInputLine;
  748. begin
  749.   GetPalette := @P;
  750. end;
  751.  
  752. procedure TInputLine.HandleEvent(var Event: TEvent);
  753. const
  754.   PadKeys = [$47, $4B, $4D, $4F, $73, $74];
  755. var
  756.   Delta, Anchor, I: Integer;
  757.   ExtendBlock: Boolean;
  758.   OldData: string;
  759.   OldCurPos, OldFirstPos,
  760.   OldSelStart, OldSelEnd: Integer;
  761.   WasAppending: Boolean;
  762.  
  763. function MouseDelta: Integer;
  764. var
  765.   Mouse: TPoint;
  766. begin
  767.   MakeLocal(Event.Where, Mouse);
  768.   if Mouse.X <= 0 then MouseDelta := -1 else
  769.   if Mouse.X >= Size.X - 1 then MouseDelta := 1 else
  770.   MouseDelta := 0;
  771. end;
  772.  
  773. function MousePos: Integer;
  774. var
  775.   Pos: Integer;
  776.   Mouse: TPoint;
  777. begin
  778.   MakeLocal(Event.Where, Mouse);
  779.   if Mouse.X < 1 then Mouse.X := 1;
  780.   Pos := Mouse.X + FirstPos - 1;
  781.   if Pos < 0 then Pos := 0;
  782.   if Pos > Length(Data^) then Pos := Length(Data^);
  783.   MousePos := Pos;
  784. end;
  785.  
  786. procedure DeleteSelect;
  787. begin
  788.   if SelStart <> SelEnd then
  789.   begin
  790.     Delete(Data^, SelStart + 1, SelEnd - SelStart);
  791.     CurPos := SelStart;
  792.   end;
  793. end;
  794.  
  795. procedure AdjustSelectBlock;
  796. begin
  797.   if CurPos < Anchor then
  798.   begin
  799.     SelStart := CurPos;
  800.     SelEnd := Anchor;
  801.   end else
  802.   begin
  803.     SelStart := Anchor;
  804.     SelEnd := CurPos;
  805.   end;
  806. end;
  807.  
  808. procedure SaveState;
  809. begin
  810.   if Validator <> nil then
  811.   begin
  812.     OldData := Data^;
  813.     OldCurPos := CurPos;
  814.     OldFirstPos := FirstPos;
  815.     OldSelStart := SelStart;
  816.     OldSelEnd := SelEnd;
  817.     WasAppending := Length(Data^) = CurPos;
  818.   end;
  819. end;
  820.  
  821. procedure RestoreState;
  822. begin
  823.   if Validator <> nil then
  824.   begin
  825.     Data^ := OldData;
  826.     CurPos := OldCurPos;
  827.     FirstPos := OldFirstPos;
  828.     SelStart := OldSelStart;
  829.     SelEnd := OldSelEnd;
  830.   end;
  831. end;
  832.  
  833. function CheckValid(NoAutoFill: Boolean): Boolean;
  834. var
  835.   OldLen: Integer;
  836.   NewData: String;
  837. begin
  838.   if Validator <> nil then
  839.   begin
  840.     CheckValid := False;
  841.     OldLen := Length(Data^);
  842.     if (Validator^.Options and voOnAppend = 0) or
  843.       (WasAppending and (CurPos = OldLen)) then
  844.     begin
  845.       NewData := Data^;
  846.       if not Validator^.IsValidInput(NewData, NoAutoFill) then
  847.         RestoreState
  848.       else
  849.       begin
  850.         if Length(NewData) > MaxLen then NewData[0] := Char(MaxLen);
  851.         Data^ := NewData;
  852.         if (CurPos >= OldLen) and (Length(Data^) > OldLen) then
  853.           CurPos := Length(Data^);
  854.         CheckValid := True;
  855.       end;
  856.     end
  857.     else
  858.     begin
  859.       CheckValid := True;
  860.       if CurPos = OldLen then
  861.         if not Validator^.IsValidInput(Data^, False) then
  862.         begin
  863.           Validator^.Error;
  864.           CheckValid := False;
  865.         end;
  866.     end;
  867.   end
  868.   else
  869.     CheckValid := True;
  870. end;
  871.  
  872. begin
  873.   TView.HandleEvent(Event);
  874.   if State and sfSelected <> 0 then
  875.   begin
  876.     case Event.What of
  877.       evMouseDown:
  878.         begin
  879.           Delta := MouseDelta;
  880.           if CanScroll(Delta) then
  881.           begin
  882.             repeat
  883.               if CanScroll(Delta) then
  884.               begin
  885.                 Inc(FirstPos, Delta);
  886.                 DrawView;
  887.               end;
  888.             until not MouseEvent(Event, evMouseAuto);
  889.           end else
  890.           if Event.Double then SelectAll(True) else
  891.           begin
  892.             Anchor := MousePos;
  893.             repeat
  894.               if Event.What = evMouseAuto then
  895.               begin
  896.                 Delta := MouseDelta;
  897.                 if CanScroll(Delta) then Inc(FirstPos, Delta);
  898.               end;
  899.               CurPos := MousePos;
  900.               AdjustSelectBlock;
  901.               DrawView;
  902.             until not MouseEvent(Event, evMouseMove + evMouseAuto);
  903.           end;
  904.           ClearEvent(Event);
  905.         end;
  906.       evKeyDown:
  907.         begin
  908.           SaveState;
  909.           Event.KeyCode := CtrlToArrow(Event.KeyCode);
  910.           if (Event.ScanCode in PadKeys) and
  911.              (GetShiftState and $03 <> 0) then
  912.           begin
  913.             Event.CharCode := #0;
  914.             if CurPos = SelEnd then Anchor := SelStart
  915.             else Anchor := SelEnd;
  916.             ExtendBlock := True;
  917.           end
  918.           else
  919.             ExtendBlock := False;
  920.           case Event.KeyCode of
  921.             kbLeft:
  922.               if CurPos > 0 then Dec(CurPos);
  923.             kbRight:
  924.               if CurPos < Length(Data^) then
  925.               begin
  926.                 Inc(CurPos);
  927.                 CheckValid(True);
  928.               end;
  929.             kbHome:
  930.               CurPos := 0;
  931.             kbEnd:
  932.               begin
  933.                 CurPos := Length(Data^);
  934.                 CheckValid(True);
  935.               end;
  936.             kbBack:
  937.               if CurPos > 0 then
  938.               begin
  939.                 Delete(Data^, CurPos, 1);
  940.                 Dec(CurPos);
  941.                 if FirstPos > 0 then Dec(FirstPos);
  942.                 CheckValid(True);
  943.               end;
  944.             kbDel:
  945.               begin
  946.                 if SelStart = SelEnd then
  947.                   if CurPos < Length(Data^) then
  948.                   begin
  949.                     SelStart := CurPos;
  950.                     SelEnd := CurPos + 1;
  951.                   end;
  952.                 DeleteSelect;
  953.                 CheckValid(True);
  954.               end;
  955.             kbIns:
  956.               SetState(sfCursorIns, State and sfCursorIns = 0);
  957.           else
  958.             case Event.CharCode of
  959.               ' '..#255:
  960.                 begin
  961.                   if State and sfCursorIns <> 0 then
  962.                     Delete(Data^, CurPos + 1, 1) else DeleteSelect;
  963.                   if CheckValid(True) then
  964.                   begin
  965.                     if Length(Data^) < MaxLen then
  966.                     begin
  967.                       if FirstPos > CurPos then FirstPos := CurPos;
  968.                       Inc(CurPos);
  969.                       Insert(Event.CharCode, Data^, CurPos);
  970.                     end;
  971.                     CheckValid(False);
  972.                   end;
  973.                 end;
  974.               ^Y:
  975.                 begin
  976.                   Data^ := '';
  977.                   CurPos := 0;
  978.                 end;
  979.             else
  980.               Exit;
  981.             end
  982.           end;
  983.           if ExtendBlock then
  984.             AdjustSelectBlock
  985.           else
  986.           begin
  987.             SelStart := CurPos;
  988.             SelEnd := CurPos;
  989.           end;
  990.           if FirstPos > CurPos then FirstPos := CurPos;
  991.           I := CurPos - Size.X + 2;
  992.           if FirstPos < I then FirstPos := I;
  993.           DrawView;
  994.           ClearEvent(Event);
  995.         end;
  996.     end;
  997.   end;
  998. end;
  999.  
  1000. procedure TInputLine.SelectAll(Enable: Boolean);
  1001. begin
  1002.   CurPos := 0;
  1003.   FirstPos := 0;
  1004.   SelStart := 0;
  1005.   if Enable then SelEnd := Length(Data^) else SelEnd := 0;
  1006.   DrawView;
  1007. end;
  1008.  
  1009. procedure TInputLine.SetData(var Rec);
  1010. var
  1011.   DSize: Integer;
  1012. begin
  1013.   if (Validator = nil) or
  1014.     (Validator^.Transfer(Data^, @Rec, vtSetData) = 0) then
  1015.     begin
  1016.       DSize := DataSize;
  1017.       Move(Rec, Data^[0], DSize);
  1018.       if Length(Data^) > DSize then Data^[0] := Chr(DSize);
  1019.     end;
  1020.   SelectAll(True);
  1021. end;
  1022.  
  1023. procedure TInputLine.SetState(AState: Word; Enable: Boolean);
  1024. begin
  1025.   TView.SetState(AState, Enable);
  1026.   if (AState = sfSelected) or ((AState = sfActive) and
  1027.      (State and sfSelected <> 0)) then
  1028.     SelectAll(Enable)
  1029.   else if AState = sfFocused then
  1030.     DrawView;
  1031. end;
  1032.  
  1033. procedure TInputLine.SetValidator(AValid: PValidator);
  1034. begin
  1035.   if Validator <> nil then Validator^.Free;
  1036.   Validator := AValid;
  1037. end;
  1038.  
  1039. procedure TInputLine.Store(var S: TStream);
  1040. begin
  1041.   TView.Store(S);
  1042.   S.Write(MaxLen, SizeOf(Integer) * 5);
  1043.   S.WriteStr(Data);
  1044.   S.Put(Validator);
  1045. end;
  1046.  
  1047. function TInputLine.Valid(Command: Word): Boolean;
  1048.  
  1049.   function AppendError(Validator: PValidator): Boolean;
  1050.   begin
  1051.     AppendError := False;
  1052.     with Validator^ do
  1053.       if (Options and voOnAppend <> 0) and (CurPos <> Length(Data^))
  1054.           and not IsValidInput(Data^, True) then
  1055.       begin
  1056.         Error;
  1057.         AppendError := True;
  1058.       end;
  1059.   end;
  1060.  
  1061. begin
  1062.   Valid := inherited Valid(Command);
  1063.   if (Validator <> nil) and (State and sfDisabled = 0) then
  1064.     if Command = cmValid then
  1065.       Valid := Validator^.Status = vsOk
  1066.     else if Command <> cmCancel then
  1067.       if AppendError(Validator) or not Validator^.Valid(Data^) then
  1068.       begin
  1069.         Select;
  1070.         Valid := False;
  1071.       end;
  1072. end;
  1073.  
  1074. { TButton }
  1075.  
  1076. constructor TButton.Init(var Bounds: TRect; ATitle: TTitleStr;
  1077.   ACommand: Word; AFlags: Word);
  1078. begin
  1079.   TView.Init(Bounds);
  1080.   Options := Options or (ofSelectable + ofFirstClick +
  1081.     ofPreProcess + ofPostProcess);
  1082.   EventMask := EventMask or evBroadcast;
  1083.   if not CommandEnabled(ACommand) then State := State or sfDisabled;
  1084.   Flags := AFlags;
  1085.   if AFlags and bfDefault <> 0 then AmDefault := True
  1086.   else AmDefault := False;
  1087.   Title := NewStr(ATitle);
  1088.   Command := ACommand;
  1089. end;
  1090.  
  1091. constructor TButton.Load(var S: TStream);
  1092. begin
  1093.   TView.Load(S);
  1094.   Title := S.ReadStr;
  1095.   S.Read(Command, SizeOf(Word) + SizeOf(Byte) + SizeOf(Boolean));
  1096.   if not CommandEnabled(Command) then State := State or sfDisabled
  1097.   else State := State and not sfDisabled;
  1098. end;
  1099.  
  1100. destructor TButton.Done;
  1101. begin
  1102.   DisposeStr(Title);
  1103.   TView.Done;
  1104. end;
  1105.  
  1106. procedure TButton.Draw;
  1107. begin
  1108.   DrawState(False);
  1109. end;
  1110.  
  1111. procedure TButton.DrawState(Down: Boolean);
  1112. var
  1113.   CButton, CShadow: Word;
  1114.   Ch: Char;
  1115.   I, S, Y, T: Integer;
  1116.   B: TDrawBuffer;
  1117.  
  1118. procedure DrawTitle;
  1119. var
  1120.   L, SCOff: Integer;
  1121. begin
  1122.   if Flags and bfLeftJust <> 0 then L := 1 else
  1123.   begin
  1124.     L := (S - CStrLen(Title^) - 1) div 2;
  1125.     if L < 1 then L := 1;
  1126.   end;
  1127.   MoveCStr(B[I + L], Title^, CButton);
  1128.   if ShowMarkers and not Down then
  1129.   begin
  1130.     if State and sfSelected <> 0 then SCOff := 0 else
  1131.       if AmDefault then SCOff := 2 else SCOff := 4;
  1132.     WordRec(B[0]).Lo := Byte(SpecialChars[SCOff]);
  1133.     WordRec(B[S]).Lo := Byte(SpecialChars[SCOff + 1]);
  1134.   end;
  1135. end;
  1136.  
  1137. begin
  1138.   if State and sfDisabled <> 0 then CButton := GetColor($0404) else
  1139.   begin
  1140.     CButton := GetColor($0501);
  1141.     if State and sfActive <> 0 then
  1142.       if State and sfSelected <> 0 then CButton := GetColor($0703) else
  1143.         if AmDefault then CButton := GetColor($0602);
  1144.   end;
  1145.   CShadow := GetColor(8);
  1146.   S := Size.X - 1;
  1147.   T := Size.Y div 2 - 1;
  1148.   for Y := 0 to Size.Y - 2 do
  1149.   begin
  1150.     MoveChar(B, ' ', Byte(CButton), Size.X);
  1151.     WordRec(B[0]).Hi := CShadow;
  1152.     if Down then
  1153.     begin
  1154.       WordRec(B[1]).Hi := CShadow;
  1155.       Ch := ' ';
  1156.       I := 2;
  1157.     end else
  1158.     begin
  1159.       WordRec(B[S]).Hi := Byte(CShadow);
  1160.       if ShowMarkers then Ch := ' ' else
  1161.       begin
  1162.         if Y = 0 then
  1163.           WordRec(B[S]).Lo := Byte(ldBlockBottom) else
  1164.           WordRec(B[S]).Lo := Byte(ldBlockFull);
  1165.         Ch := ldBlockTop;
  1166.       end;
  1167.       I := 1;
  1168.     end;
  1169.     if (Y = T) and (Title <> nil) then DrawTitle;
  1170.     if ShowMarkers and not Down then
  1171.     begin
  1172.       WordRec(B[1]).Lo := Byte('[');
  1173.       WordRec(B[S - 1]).Lo := Byte(']');
  1174.     end;
  1175.     WriteLine(0, Y, Size.X, 1, B);
  1176.   end;
  1177.   MoveChar(B[0], ' ', Byte(CShadow), 2);
  1178.   MoveChar(B[2], Ch, Byte(CShadow), S - 1);
  1179.   WriteLine(0, Size.Y - 1, Size.X, 1, B);
  1180. end;
  1181.  
  1182. function TButton.GetPalette: PPalette;
  1183. const
  1184.   P: String[Length(CButton)] = CButton;
  1185. begin
  1186.   GetPalette := @P;
  1187. end;
  1188.  
  1189. procedure TButton.HandleEvent(var Event: TEvent);
  1190. var
  1191.   Down: Boolean;
  1192.   C: Char;
  1193.   Mouse: TPoint;
  1194.   ClickRect: TRect;
  1195. begin
  1196.   GetExtent(ClickRect);
  1197.   Inc(ClickRect.A.X);
  1198.   Dec(ClickRect.B.X);
  1199.   Dec(ClickRect.B.Y);
  1200.   if Event.What = evMouseDown then
  1201.   begin
  1202.     MakeLocal(Event.Where, Mouse);
  1203.     if not ClickRect.Contains(Mouse) then ClearEvent(Event);
  1204.   end;
  1205.   if Flags and bfGrabFocus <> 0 then
  1206.     TView.HandleEvent(Event);
  1207.   case Event.What of
  1208.     evMouseDown:
  1209.       begin
  1210.         if State and sfDisabled = 0 then
  1211.         begin
  1212.           Inc(ClickRect.B.X);
  1213.           Down := False;
  1214.           repeat
  1215.             MakeLocal(Event.Where, Mouse);
  1216.             if Down <> ClickRect.Contains(Mouse) then
  1217.             begin
  1218.               Down := not Down;
  1219.               DrawState(Down);
  1220.             end;
  1221.           until not MouseEvent(Event, evMouseMove);
  1222.           if Down then
  1223.           begin
  1224.             Press;
  1225.             DrawState(False);
  1226.           end;
  1227.         end;
  1228.         ClearEvent(Event);
  1229.       end;
  1230.     evKeyDown:
  1231.       if assigned(Title) then
  1232.         begin
  1233.           C := HotKey(Title^);
  1234.           if (Event.KeyCode = GetAltCode(C)) or
  1235.             (Owner^.Phase = phPostProcess) and (C <> #0) and
  1236.               (Upcase(Event.CharCode) = C) or
  1237.             (State and sfFocused <> 0) and (Event.CharCode = ' ') then
  1238.           begin
  1239.             Press;
  1240.             ClearEvent(Event);
  1241.           end;
  1242.         end;
  1243.     evBroadcast:
  1244.       case Event.Command of
  1245.         cmDefault:
  1246.           if AmDefault and (State and sfDisabled = 0) then
  1247.           begin
  1248.             Press;
  1249.             ClearEvent(Event);
  1250.           end;
  1251.         cmGrabDefault, cmReleaseDefault:
  1252.           if Flags and bfDefault <> 0 then
  1253.           begin
  1254.             AmDefault := Event.Command = cmReleaseDefault;
  1255.             DrawView;
  1256.           end;
  1257.         cmCommandSetChanged:
  1258.           begin
  1259.             SetState(sfDisabled, not CommandEnabled(Command));
  1260.             DrawView;
  1261.           end;
  1262.       end;
  1263.   end;
  1264. end;
  1265.  
  1266. procedure TButton.MakeDefault(Enable: Boolean);
  1267. var
  1268.   C: Word;
  1269. begin
  1270.   if Flags and bfDefault = 0 then
  1271.   begin
  1272.     if Enable then C := cmGrabDefault else C := cmReleaseDefault;
  1273.     Message(Owner, evBroadcast, C, @Self);
  1274.     AmDefault := Enable;
  1275.     DrawView;
  1276.   end;
  1277. end;
  1278.  
  1279. procedure TButton.Press;
  1280. var
  1281.   E: TEvent;
  1282. begin
  1283.   Message(Owner, evBroadcast, cmRecordHistory, nil);
  1284.   if Flags and bfBroadcast <> 0 then
  1285.     Message(Owner, evBroadcast, Command, @Self) else
  1286.   begin
  1287.     E.What := evCommand;
  1288.     E.Command := Command;
  1289.     E.InfoPtr := @Self;
  1290.     PutEvent(E);
  1291.   end;
  1292. end;
  1293.  
  1294. procedure TButton.SetState(AState: Word; Enable: Boolean);
  1295. begin
  1296.   TView.SetState(AState, Enable);
  1297.   if AState and (sfSelected + sfActive) <> 0 then DrawView;
  1298.   if AState and sfFocused <> 0 then MakeDefault(Enable);
  1299. end;
  1300.  
  1301. procedure TButton.Store(var S: TStream);
  1302. begin
  1303.   TView.Store(S);
  1304.   S.WriteStr(Title);
  1305.   S.Write(Command, SizeOf(Word) + SizeOf(Byte) + SizeOf(Boolean));
  1306. end;
  1307.  
  1308. { TCluster }
  1309.  
  1310. constructor TCluster.Init(var Bounds: TRect; AStrings: PSItem);
  1311. var
  1312.   I: Integer;
  1313.   P: PSItem;
  1314. begin
  1315.   TView.Init(Bounds);
  1316.   Options := Options or (ofSelectable + ofFirstClick + ofPreProcess +
  1317.     ofPostProcess + ofVersion20);
  1318.   I := 0;
  1319.   P := AStrings;
  1320.   while P <> nil do
  1321.   begin
  1322.     Inc(I);
  1323.     P := P^.Next;
  1324.   end;
  1325.   Strings.Init(I,0);
  1326.   while AStrings <> nil do
  1327.   begin
  1328.     P := AStrings;
  1329.     Strings.AtInsert(Strings.Count, AStrings^.Value);
  1330.     AStrings := AStrings^.Next;
  1331.     Dispose(P);
  1332.   end;
  1333.   Value := 0;
  1334.   Sel := 0;
  1335.   SetCursor(2,0);
  1336.   ShowCursor;
  1337.   EnableMask := $FFFFFFFF;
  1338. end;
  1339.  
  1340. constructor TCluster.Load(var S: TStream);
  1341. begin
  1342.   TView.Load(S);
  1343.   if (Options and ofVersion) >= ofVersion20 then
  1344.   begin
  1345.     S.Read(Value, SizeOf(Longint) * 2 + SizeOf(Integer));
  1346.   end
  1347.   else
  1348.   begin
  1349.     S.Read(Value, SizeOf(Word));
  1350.     S.Read(Sel, SizeOf(Integer));
  1351.     EnableMask := $FFFFFFFF;
  1352.     Options := Options or ofVersion20;
  1353.   end;
  1354.   Strings.Load(S);
  1355.   SetButtonState(0, True);
  1356. end;
  1357.  
  1358. destructor TCluster.Done;
  1359. begin
  1360.   Strings.Done;
  1361.   TView.Done;
  1362. end;
  1363.  
  1364. function TCluster.ButtonState(Item: Integer): Boolean;
  1365. begin
  1366.   if Item > 31
  1367.     then ButtonState := False
  1368.     else ButtonState := ((1 shl Item) and EnableMask) <> 0;
  1369. end;
  1370.  
  1371. function TCluster.DataSize: Word;
  1372. begin
  1373.   DataSize := SizeOf(Word);
  1374. end;
  1375.  
  1376. procedure TCluster.DrawBox(const Icon: String; Marker: Char);
  1377. begin
  1378.   DrawMultiBox(Icon, ' '+Marker);
  1379. end;
  1380.  
  1381. procedure TCluster.DrawMultiBox(const Icon, Marker: String);
  1382. var
  1383.   I,J,Cur,Col: Integer;
  1384.   CNorm, CSel, CDis, Color: Word;
  1385.   B: TDrawBuffer;
  1386.   SCOff: Byte;
  1387. begin
  1388.   CNorm := GetColor($0301);
  1389.   CSel := GetColor($0402);
  1390.   CDis := GetColor($0505);
  1391.   for I := 0 to Size.Y do
  1392.   begin
  1393.     MoveChar(B, ' ', Byte(CNorm), Size.X);
  1394.     for J := 0 to (Strings.Count - 1) div Size.Y + 1 do
  1395.     begin
  1396.       Cur := J*Size.Y + I;
  1397.       if Cur < Strings.Count then
  1398.       begin
  1399.         Col := Column(Cur);
  1400.         if (Col + CStrLen(PString(Strings.At(Cur))^) + 5 <
  1401.           Sizeof(TDrawBuffer) div SizeOf(Word)) and (Col < Size.X) then
  1402.         begin
  1403.           if not ButtonState(Cur) then
  1404.             Color := CDis
  1405.           else if (Cur = Sel) and (State and sfFocused <> 0) then
  1406.             Color := CSel
  1407.           else
  1408.             Color := CNorm;
  1409.           MoveChar(B[Col], ' ', Byte(Color), Size.X - Col);
  1410.           MoveStr(B[Col], Icon, Byte(Color));
  1411.           WordRec(B[Col+2]).Lo := Byte(Marker[MultiMark(Cur) + 1]);
  1412.           MoveCStr(B[Col+5], PString(Strings.At(Cur))^, Color);
  1413.           if ShowMarkers and (State and sfFocused <> 0) and (Cur = Sel) then
  1414.           begin
  1415.             WordRec(B[Col]).Lo := Byte(SpecialChars[0]);
  1416.             WordRec(B[Column(Cur+Size.Y)-1]).Lo := Byte(SpecialChars[1]);
  1417.           end;
  1418.         end;
  1419.       end;
  1420.     end;
  1421.     WriteBuf(0, I, Size.X, 1, B);
  1422.   end;
  1423.   SetCursor(Column(Sel)+2,Row(Sel));
  1424. end;
  1425.  
  1426. procedure TCluster.GetData(var Rec);
  1427. begin
  1428.   Word(Rec) := Value;
  1429. end;
  1430.  
  1431. function TCluster.GetHelpCtx: Word;
  1432. begin
  1433.   if HelpCtx = hcNoContext then GetHelpCtx := hcNoContext
  1434.   else GetHelpCtx := HelpCtx + Sel;
  1435. end;
  1436.  
  1437. function TCluster.GetPalette: PPalette;
  1438. const
  1439.   P: String[Length(CCluster)] = CCluster;
  1440. begin
  1441.   GetPalette := @P;
  1442. end;
  1443.  
  1444. procedure TCluster.HandleEvent(var Event: TEvent);
  1445. var
  1446.   Mouse: TPoint;
  1447.   I, S: Integer;
  1448.   C: Char;
  1449.  
  1450. procedure MoveSel;
  1451. begin
  1452.   if I <= Strings.Count then
  1453.   begin
  1454.     Sel := S;
  1455.     MovedTo(Sel);
  1456.     DrawView;
  1457.   end;
  1458. end;
  1459.  
  1460. begin
  1461.   TView.HandleEvent(Event);
  1462.   if (Options and ofSelectable) = 0 then Exit;
  1463.   if Event.What = evMouseDown then
  1464.   begin
  1465.     MakeLocal(Event.Where, Mouse);
  1466.     I := FindSel(Mouse);
  1467.     if I <> -1 then if ButtonState(I) then Sel := I;
  1468.     DrawView;
  1469.     repeat
  1470.       MakeLocal(Event.Where, Mouse);
  1471.       if FindSel(Mouse) = Sel then
  1472.         ShowCursor else
  1473.         HideCursor;
  1474.     until not MouseEvent(Event,evMouseMove); {Wait for mouse up}
  1475.     ShowCursor;
  1476.     MakeLocal(Event.Where, Mouse);
  1477.     if (FindSel(Mouse) = Sel) and ButtonState(Sel) then
  1478.     begin
  1479.       Press(Sel);
  1480.       DrawView;
  1481.     end;
  1482.     ClearEvent(Event);
  1483.   end else if Event.What = evKeyDown then
  1484.   begin
  1485.     S := Sel;
  1486.     case CtrlToArrow(Event.KeyCode) of
  1487.       kbUp:
  1488.         if State and sfFocused <> 0 then
  1489.         begin
  1490.           I := 0;
  1491.           repeat
  1492.             Inc(I);
  1493.             Dec(S);
  1494.             if S < 0 then S := Strings.Count - 1;
  1495.           until ButtonState(S) or (I > Strings.Count);
  1496.           MoveSel;
  1497.           ClearEvent(Event);
  1498.         end;
  1499.       kbDown:
  1500.         if State and sfFocused <> 0 then
  1501.         begin
  1502.           I := 0;
  1503.           repeat
  1504.             Inc(I);
  1505.             Inc(S);
  1506.             if S >= Strings.Count then S := 0;
  1507.           until ButtonState(S) or (I > Strings.Count);
  1508.           MoveSel;
  1509.           ClearEvent(Event);
  1510.         end;
  1511.       kbRight:
  1512.         if State and sfFocused <> 0 then
  1513.         begin
  1514.           I := 0;
  1515.           repeat
  1516.             Inc(I);
  1517.             Inc(S,Size.Y);
  1518.             if S >= Strings.Count then
  1519.             begin
  1520.               S := (S+1) mod Size.Y;
  1521.               if S >= Strings.Count then S := 0;
  1522.             end;
  1523.           until ButtonState(S) or (I > Strings.Count);
  1524.           MoveSel;
  1525.           ClearEvent(Event);
  1526.         end;
  1527.       kbLeft:
  1528.         if State and sfFocused <> 0 then
  1529.         begin
  1530.           I := 0;
  1531.           repeat
  1532.             Inc(I);
  1533.             if S > 0 then
  1534.             begin
  1535.               Dec(S, Size.Y);
  1536.               if S < 0 then
  1537.               begin
  1538.                 S := ((Strings.Count + Size.Y - 1) div Size.Y)*Size.Y + S - 1;
  1539.                 if S >= Strings.Count then S := Strings.Count-1;
  1540.               end;
  1541.             end else S := Strings.Count-1;
  1542.           until ButtonState(S) or (I > Strings.Count);
  1543.           MoveSel;
  1544.           ClearEvent(Event);
  1545.         end;
  1546.     else
  1547.       begin
  1548.         for I := 0 to Strings.Count-1 do
  1549.         begin
  1550.           C := HotKey(PString(Strings.At(I))^);
  1551.           if (GetAltCode(C) = Event.KeyCode) or
  1552.              (((Owner^.Phase = phPostProcess) or (State and sfFocused <> 0))
  1553.                and (C <> #0) and (UpCase(Event.CharCode) = C)) then
  1554.           begin
  1555.             if ButtonState(I) then
  1556.             begin
  1557.               if Focus then
  1558.               begin
  1559.                 Sel := I;
  1560.                 MovedTo(Sel);
  1561.                 Press(Sel);
  1562.                 DrawView;
  1563.               end;
  1564.               ClearEvent(Event);
  1565.             end;
  1566.             Exit;
  1567.           end;
  1568.         end;
  1569.         if (Event.CharCode = ' ') and (State and sfFocused <> 0)
  1570.           and ButtonState(Sel)then
  1571.         begin
  1572.           Press(Sel);
  1573.           DrawView;
  1574.           ClearEvent(Event);
  1575.         end;
  1576.       end
  1577.     end
  1578.   end;
  1579. end;
  1580.  
  1581. procedure TCluster.SetButtonState(AMask: Longint; Enable: Boolean);
  1582. var
  1583.   I,M: Longint;
  1584. begin
  1585.   if Enable then EnableMask := EnableMask or AMask
  1586.             else EnableMask := EnableMask and not AMask;
  1587.   if Strings.Count <= 32 then
  1588.   begin
  1589.     M := 1;
  1590.     for I := 1 to Strings.Count do
  1591.     begin
  1592.       if (M and EnableMask) <> 0 then
  1593.       begin
  1594.         Options := Options or ofSelectable;
  1595.         Exit;
  1596.       end;
  1597.       M := M shl 1;
  1598.     end;
  1599.     Options := Options and not ofSelectable;
  1600.   end;
  1601. end;
  1602.  
  1603. procedure TCluster.SetData(var Rec);
  1604. begin
  1605.   Value := Word(Rec);
  1606.   DrawView;
  1607. end;
  1608.  
  1609. procedure TCluster.SetState(AState: Word; Enable: Boolean);
  1610. begin
  1611.   TView.SetState(AState, Enable);
  1612.   if AState = sfFocused then DrawView;
  1613. end;
  1614.  
  1615. function TCluster.Mark(Item: Integer): Boolean;
  1616. begin
  1617.   Mark := False;
  1618. end;
  1619.  
  1620. function TCluster.MultiMark(Item: Integer): Byte;
  1621. begin
  1622.   MultiMark := Byte(Mark(Item) = True);
  1623. end;
  1624.  
  1625. procedure TCluster.MovedTo(Item: Integer);
  1626. begin
  1627. end;
  1628.  
  1629. procedure TCluster.Press(Item: Integer);
  1630. begin
  1631. end;
  1632.  
  1633. procedure TCluster.Store(var S: TStream);
  1634. begin
  1635.   TView.Store(S);
  1636.   S.Write(Value, SizeOf(Longint) * 2 + SizeOf(Integer));
  1637.   Strings.Store(S);
  1638. end;
  1639.  
  1640. function TCluster.Column(Item: Integer): Integer;
  1641. var
  1642.   I, Col, Width, L: Integer;
  1643. begin
  1644.   if Item < Size.Y then Column := 0
  1645.   else
  1646.   begin
  1647.     Width := 0;
  1648.     Col := -6;
  1649.     for I := 0 to Item do
  1650.     begin
  1651.       if I mod Size.Y = 0 then
  1652.       begin
  1653.         Inc(Col, Width + 6);
  1654.         Width := 0;
  1655.       end;
  1656.       if I < Strings.Count then
  1657.         L := CStrLen(PString(Strings.At(I))^);
  1658.       if L > Width then Width := L;
  1659.     end;
  1660.     Column := Col;
  1661.   end;
  1662. end;
  1663.  
  1664. function TCluster.FindSel(P: TPoint): Integer;
  1665. var
  1666.   I, S: Integer;
  1667.   R: TRect;
  1668. begin
  1669.   GetExtent(R);
  1670.   if not R.Contains(P) then FindSel := -1
  1671.   else
  1672.   begin
  1673.     I := 0;
  1674.     while P.X >= Column(I+Size.Y) do
  1675.       Inc(I, Size.Y);
  1676.     S := I + P.Y;
  1677.     if S >= Strings.Count then
  1678.       FindSel := -1 else
  1679.       FindSel := S;
  1680.   end;
  1681. end;
  1682.  
  1683. function TCluster.Row(Item: Integer): Integer;
  1684. begin
  1685.   Row := Item mod Size.Y;
  1686. end;
  1687.  
  1688. { TRadioButtons }
  1689.  
  1690. procedure TRadioButtons.Draw;
  1691. const
  1692.   Button = ' ( ) ';
  1693. begin
  1694.   DrawMultiBox(Button, #32#7);
  1695. end;
  1696.  
  1697. function TRadioButtons.Mark(Item: Integer): Boolean;
  1698. begin
  1699.   Mark := Item = Value;
  1700. end;
  1701.  
  1702. procedure TRadioButtons.Press(Item: Integer);
  1703. begin
  1704.   Value := Item;
  1705. end;
  1706.  
  1707. procedure TRadioButtons.MovedTo(Item: Integer);
  1708. begin
  1709.   Value := Item;
  1710. end;
  1711.  
  1712. procedure TRadioButtons.SetData(var Rec);
  1713. begin
  1714.   TCluster.SetData(Rec);
  1715.   Sel := Integer(Value);
  1716. end;
  1717.  
  1718. { TCheckBoxes }
  1719.  
  1720. procedure TCheckBoxes.Draw;
  1721. const
  1722.   Button = ' [ ] ';
  1723. begin
  1724.   DrawMultiBox(Button, ' X');
  1725. end;
  1726.  
  1727. function TCheckBoxes.Mark(Item: Integer): Boolean;
  1728. begin
  1729.   Mark := Value and (1 shl Item) <> 0;
  1730. end;
  1731.  
  1732. procedure TCheckBoxes.Press(Item: Integer);
  1733. begin
  1734.   Value := Value xor (1 shl Item);
  1735. end;
  1736.  
  1737. { TMultiCheckBoxes }
  1738.  
  1739. constructor TMultiCheckBoxes.Init(var Bounds: TRect; AStrings: PSItem;
  1740.   ASelRange: Byte; AFlags: Word; const AStates: String);
  1741. begin
  1742.   Inherited Init(Bounds, AStrings);
  1743.   SelRange := ASelRange;
  1744.   Flags := AFlags;
  1745.   States := NewStr(AStates);
  1746. end;
  1747.  
  1748. constructor TMultiCheckBoxes.Load(var S: TStream);
  1749. begin
  1750.   TCluster.Load(S);
  1751.   S.Read(SelRange, SizeOf(Byte));
  1752.   S.Read(Flags, SizeOf(Word));
  1753.   States := S.ReadStr;
  1754. end;
  1755.  
  1756. destructor TMultiCheckBoxes.Done;
  1757. begin
  1758.   DisposeStr(States);
  1759.   TCluster.Done;
  1760. end;
  1761.  
  1762. procedure TMultiCheckBoxes.Draw;
  1763. const
  1764.   Button = ' [ ] ';
  1765. begin
  1766.   DrawMultiBox(Button, States^);
  1767. end;
  1768.  
  1769. function TMultiCheckBoxes.DataSize: Word;
  1770. begin
  1771.   DataSize := SizeOf(Longint);
  1772. end;
  1773.  
  1774. function TMultiCheckBoxes.MultiMark(Item: Integer): Byte;
  1775. begin
  1776.   MultiMark := (Value shr (Word(Item) * WordRec(Flags).Hi))
  1777.     and WordRec(Flags).Lo;
  1778. end;
  1779.  
  1780. procedure TMultiCheckBoxes.GetData(var Rec);
  1781. begin
  1782.   Longint(Rec) := Value;
  1783. end;
  1784.  
  1785. procedure TMultiCheckBoxes.Press(Item: Integer);
  1786. var
  1787.   CurState: ShortInt;
  1788. begin
  1789.   CurState := (Value shr (Word(Item) * WordRec(Flags).Hi))
  1790.     and WordRec(Flags).Lo;
  1791.  
  1792.   Dec(CurState);
  1793.   if (CurState >= SelRange) or (CurState < 0) then
  1794.     CurState := SelRange - 1;
  1795.   Value := (Value and not (LongInt(WordRec(Flags).Lo)
  1796.     shl (Word(Item) * WordRec(Flags).Hi))) or
  1797.     (LongInt(CurState) shl (Word(Item) * WordRec(Flags).Hi));
  1798. end;
  1799.  
  1800. procedure TMultiCheckBoxes.SetData(var Rec);
  1801. begin
  1802.   Value := Longint(Rec);
  1803.   DrawView;
  1804. end;
  1805.  
  1806. procedure TMultiCheckBoxes.Store(var S: TStream);
  1807. begin
  1808.   TCluster.Store(S);
  1809.   S.Write(SelRange, SizeOf(Byte));
  1810.   S.Write(Flags, SizeOf(Word));
  1811.   S.WriteStr(States);
  1812. end;
  1813.  
  1814. { TListBox }
  1815.  
  1816. type
  1817.   TListBoxRec = record
  1818.     List: PCollection;
  1819.     Selection: Word;
  1820.   end;
  1821.  
  1822. constructor TListBox.Init(var Bounds: TRect; ANumCols: Word;
  1823.   AScrollBar: PScrollBar);
  1824. begin
  1825.   TListViewer.Init(Bounds, ANumCols, nil, AScrollBar);
  1826.   List := nil;
  1827.   SetRange(0);
  1828. end;
  1829.  
  1830. constructor TListBox.Load(var S: TStream);
  1831. begin
  1832.   TListViewer.Load(S);
  1833.   List := PCollection(S.Get);
  1834. end;
  1835.  
  1836. function TListBox.DataSize: Word;
  1837. begin
  1838.   DataSize := SizeOf(TListBoxRec);
  1839. end;
  1840.  
  1841. procedure TListBox.GetData(var Rec);
  1842. begin
  1843.   TListBoxRec(Rec).List := List;
  1844.   TListBoxRec(Rec).Selection := Focused;
  1845. end;
  1846.  
  1847. function TListBox.GetText(Item: Integer; MaxLen: Integer): String;
  1848. var
  1849.   S: PString;
  1850. begin
  1851.   GetText := '';
  1852.   if List <> nil then begin
  1853.     S := PString(List^.At(Item));
  1854.     if S <> nil then GetText := S^;
  1855.   end;
  1856. end;
  1857.  
  1858. procedure TListBox.NewList(AList: PCollection);
  1859. begin
  1860.   if List <> nil then Dispose(List, Done);
  1861.   List := AList;
  1862.   if AList <> nil then SetRange(AList^.Count)
  1863.   else SetRange(0);
  1864.   if Range > 0 then FocusItem(0);
  1865.   DrawView;
  1866. end;
  1867.  
  1868. procedure TListBox.SetData(var Rec);
  1869. begin
  1870.   NewList(TListBoxRec(Rec).List);
  1871.   FocusItem(TListBoxRec(Rec).Selection);
  1872.   DrawView;
  1873. end;
  1874.  
  1875. procedure TListBox.Store(var S: TStream);
  1876. begin
  1877.   TListViewer.Store(S);
  1878.   S.Put(List);
  1879. end;
  1880.  
  1881. { TStaticText }
  1882.  
  1883. constructor TStaticText.Init(var Bounds: TRect; const AText: String);
  1884. begin
  1885.   TView.Init(Bounds);
  1886.   Text := NewStr(AText);
  1887. end;
  1888.  
  1889. constructor TStaticText.Load(var S: TStream);
  1890. begin
  1891.   TView.Load(S);
  1892.   Text := S.ReadStr;
  1893. end;
  1894.  
  1895. destructor TStaticText.Done;
  1896. begin
  1897.   DisposeStr(Text);
  1898.   TView.Done;
  1899. end;
  1900.  
  1901. procedure TStaticText.Draw;
  1902. var
  1903.   Color: Byte;
  1904.   Center: Boolean;
  1905.   I, J, L, P, Y: Integer;
  1906.   B: TDrawBuffer;
  1907.   S: String;
  1908. begin
  1909.   Color := GetColor(1);
  1910.   GetText(S);
  1911.   L := Length(S);
  1912.   P := 1;
  1913.   Y := 0;
  1914.   Center := False;
  1915.   while Y < Size.Y do
  1916.   begin
  1917.     MoveChar(B, ' ', Color, Size.X);
  1918.     if P <= L then
  1919.     begin
  1920.       if S[P] = #3 then
  1921.       begin
  1922.         Center := True;
  1923.         Inc(P);
  1924.       end;
  1925.       I := P;
  1926.       repeat
  1927.         J := P;
  1928.         while (P <= L) and (S[P] = ' ') do Inc(P);
  1929.         while (P <= L) and (S[P] <> ' ') and (S[P] <> #13) do Inc(P);
  1930.       until (P > L) or (P >= I + Size.X) or (S[P] = #13);
  1931.       if P > I + Size.X then
  1932.         if J > I then P := J else P := I + Size.X;
  1933.       if Center then J := (Size.X - P + I) div 2 else J := 0;
  1934.       MoveBuf(B[J], S[I], Color, P - I);
  1935.       while (P <= L) and (S[P] = ' ') do Inc(P);
  1936.       if (P <= L) and (S[P] = #13) then
  1937.       begin
  1938.         Center := False;
  1939.         Inc(P);
  1940.         if (P <= L) and (S[P] = #10) then Inc(P);
  1941.       end;
  1942.     end;
  1943.     WriteLine(0, Y, Size.X, 1, B);
  1944.     Inc(Y);
  1945.   end;
  1946. end;
  1947.  
  1948. function TStaticText.GetPalette: PPalette;
  1949. const
  1950.   P: String[Length(CStaticText)] = CStaticText;
  1951. begin
  1952.   GetPalette := @P;
  1953. end;
  1954.  
  1955. procedure TStaticText.GetText(var S: String);
  1956. begin
  1957.   if Text <> nil then S := Text^
  1958.   else S := '';
  1959. end;
  1960.  
  1961. procedure TStaticText.Store(var S: TStream);
  1962. begin
  1963.   TView.Store(S);
  1964.   S.WriteStr(Text);
  1965. end;
  1966.  
  1967. { TParamText }
  1968.  
  1969. constructor TParamText.Init(var Bounds: TRect; const AText: String;
  1970.   AParamCount: Integer);
  1971. begin
  1972.   TStaticText.Init(Bounds, AText);
  1973.   ParamCount := AParamCount;
  1974. end;
  1975.  
  1976. constructor TParamText.Load(var S: TStream);
  1977. begin
  1978.   TStaticText.Load(S);
  1979.   S.Read(ParamCount, SizeOf(Integer));
  1980. end;
  1981.  
  1982. function TParamText.DataSize: Word;
  1983. begin
  1984.   DataSize := ParamCount * SizeOf(Longint);
  1985. end;
  1986.  
  1987. procedure TParamText.GetText(var S: String);
  1988. begin
  1989.   if Text <> nil then FormatStr(S, Text^, ParamList^)
  1990.   else S := '';
  1991. end;
  1992.  
  1993. procedure TParamText.SetData(var Rec);
  1994. begin
  1995.   ParamList := @Rec;
  1996.   DrawView;
  1997. end;
  1998.  
  1999. procedure TParamText.Store(var S: TStream);
  2000. begin
  2001.   TStaticText.Store(S);
  2002.   S.Write(ParamCount, SizeOf(Integer));
  2003. end;
  2004.  
  2005. { TLabel }
  2006.  
  2007. constructor TLabel.Init(var Bounds: TRect; const AText: String; ALink: PView);
  2008. begin
  2009.   TStaticText.Init(Bounds, AText);
  2010.   Link := ALink;
  2011.   Options := Options or (ofPreProcess + ofPostProcess);
  2012.   EventMask := EventMask or evBroadcast;
  2013. end;
  2014.  
  2015. constructor TLabel.Load(var S: TStream);
  2016. begin
  2017.   TStaticText.Load(S);
  2018.   GetPeerViewPtr(S, Link);
  2019. end;
  2020.  
  2021. procedure TLabel.Draw;
  2022. var
  2023.   Color: Word;
  2024.   B: TDrawBuffer;
  2025.   SCOff: Byte;
  2026. begin
  2027.   if Light then
  2028.   begin
  2029.     Color := GetColor($0402);
  2030.     SCOff := 0;
  2031.   end
  2032.   else
  2033.   begin
  2034.     Color := GetColor($0301);
  2035.     SCOff := 4;
  2036.   end;
  2037.   MoveChar(B[0], ' ', Byte(Color), Size.X);
  2038.   if Text <> nil then MoveCStr(B[1], Text^, Color);
  2039.   if ShowMarkers then WordRec(B[0]).Lo := Byte(SpecialChars[SCOff]);
  2040.   WriteLine(0, 0, Size.X, 1, B);
  2041. end;
  2042.  
  2043. function TLabel.GetPalette: PPalette;
  2044. const
  2045.   P: String[Length(CLabel)] = CLabel;
  2046. begin
  2047.   GetPalette := @P;
  2048. end;
  2049.  
  2050. procedure TLabel.HandleEvent(var Event: TEvent);
  2051. var
  2052.   C: Char;
  2053.  
  2054.   procedure FocusLink;
  2055.   begin
  2056.     if (Link <> nil) and (Link^.Options and ofSelectable <> 0) then
  2057.       Link^.Focus;
  2058.     ClearEvent(Event);
  2059.   end;
  2060.  
  2061. begin
  2062.   TStaticText.HandleEvent(Event);
  2063.   if Event.What = evMouseDown then FocusLink
  2064.   else if Event.What = evKeyDown then
  2065.   begin
  2066.     C := HotKey(Text^);
  2067.     if (GetAltCode(C) = Event.KeyCode) or
  2068.        ((C <> #0) and (Owner^.Phase = phPostProcess) and
  2069.         (UpCase(Event.CharCode) = C)) then FocusLink
  2070.   end
  2071.   else if Event.What = evBroadcast then
  2072.     if ((Event.Command = cmReceivedFocus) or
  2073.        (Event.Command = cmReleasedFocus)) and
  2074.        (Link <> nil) then
  2075.     begin
  2076.       Light := Link^.State and sfFocused <> 0;
  2077.       DrawView;
  2078.     end;
  2079. end;
  2080.  
  2081. procedure TLabel.Store(var S: TStream);
  2082. begin
  2083.   TStaticText.Store(S);
  2084.   PutPeerViewPtr(S, Link);
  2085. end;
  2086.  
  2087. { THistoryViewer }
  2088.  
  2089. constructor THistoryViewer.Init(var Bounds: TRect; AHScrollBar,
  2090.   AVScrollBar: PScrollBar; AHistoryId: Word);
  2091. begin
  2092.   TListViewer.Init(Bounds, 1, AHScrollBar, AVScrollBar);
  2093.   HistoryId := AHistoryId;
  2094.   SetRange(HistoryCount(AHistoryId));
  2095.   if Range > 1 then FocusItem(1);
  2096.   HScrollBar^.SetRange(1, HistoryWidth-Size.X + 3);
  2097. end;
  2098.  
  2099. function THistoryViewer.GetPalette: PPalette;
  2100. const
  2101.   P: String[Length(CHistoryViewer)] = CHistoryViewer;
  2102. begin
  2103.   GetPalette := @P;
  2104. end;
  2105.  
  2106. function THistoryViewer.GetText(Item: Integer; MaxLen: Integer): String;
  2107. begin
  2108.   GetText := HistoryStr(HistoryId, Item);
  2109. end;
  2110.  
  2111. procedure THistoryViewer.HandleEvent(var Event: TEvent);
  2112. begin
  2113.   if ((Event.What = evMouseDown) and (Event.Double)) or
  2114.      ((Event.What = evKeyDown) and (Event.KeyCode = kbEnter)) then
  2115.   begin
  2116.     EndModal(cmOk);
  2117.     ClearEvent(Event);
  2118.   end else if ((Event.What = evKeyDown) and (Event.KeyCode = kbEsc)) or
  2119.     ((Event.What = evCommand) and (Event.Command = cmCancel)) then
  2120.   begin
  2121.     EndModal(cmCancel);
  2122.     ClearEvent(Event);
  2123.   end else TListViewer.HandleEvent(Event);
  2124. end;
  2125.  
  2126. function THistoryViewer.HistoryWidth: Integer;
  2127. var
  2128.   Width, T, Count, I: Integer;
  2129. begin
  2130.   Width := 0;
  2131.   Count := HistoryCount(HistoryId);
  2132.   for I := 0 to Count-1 do
  2133.   begin
  2134.     T := Length(HistoryStr(HistoryId, I));
  2135.     if T > Width then Width := T;
  2136.   end;
  2137.   HistoryWidth := Width;
  2138. end;
  2139.  
  2140. { THistoryWindow }
  2141.  
  2142. constructor THistoryWindow.Init(var Bounds: TRect; HistoryId: Word);
  2143. begin
  2144.   TWindow.Init(Bounds, '', wnNoNumber);
  2145.   Flags := wfClose;
  2146.   InitViewer(HistoryId);
  2147. end;
  2148.  
  2149. function THistoryWindow.GetPalette: PPalette;
  2150. const
  2151.   P: String[Length(CHistoryWindow)] = CHistoryWindow;
  2152. begin
  2153.   GetPalette := @P;
  2154. end;
  2155.  
  2156. function THistoryWindow.GetSelection: String;
  2157. begin
  2158.   GetSelection := Viewer^.GetText(Viewer^.Focused,255);
  2159. end;
  2160.  
  2161. procedure THistoryWindow.InitViewer(HistoryId: Word);
  2162. var
  2163.   R: TRect;
  2164. begin
  2165.   GetExtent(R);
  2166.   R.Grow(-1,-1);
  2167.   Viewer := New(PHistoryViewer, Init(R,
  2168.     StandardScrollBar(sbHorizontal + sbHandleKeyboard),
  2169.     StandardScrollBar(sbVertical + sbHandleKeyboard),
  2170.     HistoryId));
  2171.   Insert(Viewer);
  2172. end;
  2173.  
  2174. { THistory }
  2175.  
  2176. constructor THistory.Init(var Bounds: TRect; ALink: PInputLine;
  2177.   AHistoryId: Word);
  2178. begin
  2179.   TView.Init(Bounds);
  2180.   Options := Options or ofPostProcess;
  2181.   EventMask := EventMask or evBroadcast;
  2182.   Link := ALink;
  2183.   HistoryId := AHistoryId;
  2184. end;
  2185.  
  2186. constructor THistory.Load(var S: TStream);
  2187. begin
  2188.   TView.Load(S);
  2189.   GetPeerViewPtr(S, Link);
  2190.   S.Read(HistoryId, SizeOf(Word));
  2191. end;
  2192.  
  2193. procedure THistory.Draw;
  2194. var
  2195.   B: TDrawBuffer;
  2196. begin
  2197.   MoveCStr(B, ldHistoryDropDown, GetColor($0102));
  2198.   WriteLine(0, 0, Size.X, Size.Y, B);
  2199. end;
  2200.  
  2201. function THistory.GetPalette: PPalette;
  2202. const
  2203.   P: String[Length(CHistory)] = CHistory;
  2204. begin
  2205.   GetPalette := @P;
  2206. end;
  2207.  
  2208. procedure THistory.HandleEvent(var Event: TEvent);
  2209. var
  2210.   HistoryWindow: PHistoryWindow;
  2211.   R,P: TRect;
  2212.   C: Word;
  2213.   Rslt: String;
  2214. begin
  2215.   TView.HandleEvent(Event);
  2216.   if (Event.What = evMouseDown) or
  2217.      ((Event.What = evKeyDown) and (CtrlToArrow(Event.KeyCode) = kbDown) and
  2218.       (Link^.State and sfFocused <> 0)) then
  2219.   begin
  2220.     if not Link^.Focus then
  2221.     begin
  2222.       ClearEvent(Event);
  2223.       Exit;
  2224.     end;
  2225.     RecordHistory(Link^.Data^);
  2226.     Link^.GetBounds(R);
  2227.     Dec(R.A.X); Inc(R.B.X); Inc(R.B.Y,7); Dec(R.A.Y,1);
  2228.     Owner^.GetExtent(P);
  2229.     R.Intersect(P);
  2230.     Dec(R.B.Y,1);
  2231.     HistoryWindow := InitHistoryWindow(R);
  2232.     if HistoryWindow <> nil then
  2233.     begin
  2234.       C := Owner^.ExecView(HistoryWindow);
  2235.       if C = cmOk then
  2236.       begin
  2237.         Rslt := HistoryWindow^.GetSelection;
  2238.         if Length(Rslt) > Link^.MaxLen then Rslt[0] := Char(Link^.MaxLen);
  2239.         Link^.Data^ := Rslt;
  2240.         Link^.SelectAll(True);
  2241.         Link^.DrawView;
  2242.       end;
  2243.       Dispose(HistoryWindow, Done);
  2244.     end;
  2245.     ClearEvent(Event);
  2246.   end
  2247.   else if (Event.What = evBroadcast) then
  2248.     if ((Event.Command = cmReleasedFocus) and (Event.InfoPtr = Link))
  2249.       or (Event.Command = cmRecordHistory) then
  2250.     RecordHistory(Link^.Data^);
  2251. end;
  2252.  
  2253. function THistory.InitHistoryWindow(var Bounds: TRect): PHistoryWindow;
  2254. var
  2255.   P: PHistoryWindow;
  2256. begin
  2257.   P := New(PHistoryWindow, Init(Bounds, HistoryId));
  2258.   P^.HelpCtx := Link^.HelpCtx;
  2259.   InitHistoryWindow := P;
  2260. end;
  2261.  
  2262. procedure THistory.RecordHistory(const S: String);
  2263. begin
  2264.   HistoryAdd(HistoryId, S);
  2265. end;
  2266.  
  2267. procedure THistory.Store(var S: TStream);
  2268. begin
  2269.   TView.Store(S);
  2270.   PutPeerViewPtr(S, Link);
  2271.   S.Write(HistoryId, SizeOf(Word));
  2272. end;
  2273.  
  2274. { Dialogs registration procedure }
  2275.  
  2276. procedure RegisterDialogs;
  2277. begin
  2278.   RegisterType(RDialog);
  2279.   RegisterType(RInputLine);
  2280.   RegisterType(RButton);
  2281.   RegisterType(RCluster);
  2282.   RegisterType(RRadioButtons);
  2283.   RegisterType(RCheckBoxes);
  2284.   RegisterType(RMultiCheckBoxes);
  2285.   RegisterType(RListBox);
  2286.   RegisterType(RStaticText);
  2287.   RegisterType(RLabel);
  2288.   RegisterType(RHistory);
  2289.   RegisterType(RParamText);
  2290. end;
  2291.  
  2292. end.
  2293.