home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 9 / 09.iso / l / l040 / 13.ddi / RTLTV.ZIP / DIALOGS.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-10-28  |  54.8 KB  |  2,288 lines

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