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

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Turbo Pascal for Windows Run-time Library       }
  5. {       ObjectWindows Unit                              }
  6. {                                                       }
  7. {       Copyright (c) 1991 Borland International        }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11. unit ODialogs;
  12.  
  13. {$T-,R-}
  14.  
  15. interface
  16.  
  17. uses WinProcs, WinTypes, Objects, OWindows, Validate;
  18.  
  19. const
  20.  
  21. { TCheckBox check states }
  22.  
  23.   bf_Unchecked = 0;
  24.   bf_Checked   = 1;
  25.   bf_Grayed    = 2;
  26.  
  27. { Message number used for input validation }
  28.  
  29.   wm_PostInvalid = wm_User + 400;
  30.  
  31. type
  32.  
  33. { TDialog creation attributes }
  34.  
  35.   TDialogAttr = record
  36.     Name: PChar;
  37.     Param: LongInt;
  38.   end;
  39.  
  40. { TDialog object }
  41.  
  42.   PDialog = ^TDialog;
  43.   TDialog = object(TWindowsObject)
  44.     Attr: TDialogAttr;
  45.     IsModal: Boolean;
  46.     constructor Init(AParent: PWindowsObject; AName: PChar);
  47.     constructor Load(var S: TStream);
  48.     destructor Done; virtual;
  49.     procedure Store(var S: TStream);
  50.     function Create: Boolean; virtual;
  51.     function Execute: Integer; virtual;
  52.     procedure EndDlg(ARetValue: Integer); virtual;
  53.     function GetItemHandle(DlgItemID: Integer): HWnd;
  54.     function SendDlgItemMsg(DlgItemID: Integer; AMsg, WParam: Word;
  55.       LParam: LongInt): LongInt;
  56.     procedure Ok(var Msg: TMessage); virtual id_First + id_Ok;
  57.     procedure Cancel(var Msg: TMessage); virtual id_First + id_Cancel;
  58.     procedure WMInitDialog(var Msg: TMessage);
  59.       virtual wm_First + wm_InitDialog;
  60.     procedure WMQueryEndSession(var Msg: TMessage);
  61.       virtual wm_First + wm_QueryEndSession;
  62.     procedure WMClose(var Msg: TMessage);
  63.       virtual wm_First + wm_Close;
  64.     procedure WMPostInvalid(var Msg: TMessage);
  65.       virtual wm_First + wm_PostInvalid;
  66.     procedure DefWndProc(var Msg: TMessage); virtual;
  67.   end;
  68.  
  69. { TDlgWindow object }
  70.  
  71.   PDlgWindow = ^TDlgWindow;
  72.   TDlgWindow = object(TDialog)
  73.     constructor Init(AParent: PWindowsObject; AName: PChar);
  74.     procedure GetWindowClass(var AWndClass: TWndClass); virtual;
  75.     function Create: Boolean; virtual;
  76.   end;
  77.  
  78. { TControl object }
  79.  
  80.   PControl = ^TControl;
  81.   TControl = object(TWindow)
  82.     constructor Init(AParent: PWindowsObject; AnId: Integer;
  83.       ATitle: PChar; X, Y, W, H: Integer);
  84.     constructor InitResource(AParent: PWindowsObject; ResourceID: Word);
  85.     function Register: Boolean; virtual;
  86.     function GetClassName: PChar; virtual;
  87.     procedure WMPaint(var Msg: TMessage); virtual wm_First + wm_Paint;
  88.   end;
  89.  
  90. { TGroupBox object }
  91.  
  92.   PGroupBox = ^TGroupBox;
  93.   TGroupBox = object(TControl)
  94.     NotifyParent: Boolean;
  95.     constructor Init(AParent: PWindowsObject; AnID: Integer;
  96.       AText: PChar; X, Y, W, H: Integer);
  97.     constructor InitResource(AParent: PWindowsObject; ResourceID: Word);
  98.     constructor Load(var S: TStream);
  99.     procedure Store(var S: TStream);
  100.     function GetClassName: PChar; virtual;
  101.     procedure SelectionChanged(ControlId: Integer); virtual;
  102.   end;
  103.  
  104. { TButton object }
  105.  
  106.   PButton = ^TButton;
  107.   TButton = object(TControl)
  108.     constructor Init(AParent: PWindowsObject; AnId: Integer;
  109.       AText: PChar; X, Y, W, H: Integer; IsDefault: Boolean);
  110.     constructor InitResource(AParent: PWindowsObject; ResourceID: Word);
  111.     function GetClassName: PChar; virtual;
  112.   end;
  113.  
  114. { TCheckBox object }
  115.  
  116.   PCheckBox = ^TCheckBox;
  117.   TCheckBox = object(TButton)
  118.     Group: PGroupBox;
  119.     constructor Init(AParent: PWindowsObject; AnID: Integer;
  120.       ATitle: PChar; X, Y, W, H: Integer; AGroup: PGroupBox);
  121.     constructor InitResource(AParent: PWindowsObject; ResourceID: Word);
  122.     constructor Load(var S: TStream);
  123.     procedure Store(var S: TStream);
  124.     procedure Check;
  125.     procedure Uncheck;
  126.     procedure Toggle;
  127.     function GetClassName: PChar; virtual;
  128.     function GetCheck: Word;
  129.     procedure SetCheck(CheckFlag: Word);
  130.     function Transfer(DataPtr: Pointer; TransferFlag: Word): Word; virtual;
  131.     procedure BNClicked(var Msg: TMessage);
  132.       virtual nf_First + bn_Clicked;
  133.   end;
  134.  
  135. { TRadioButton object }
  136.  
  137.   PRadioButton = ^TRadioButton;
  138.   TRadioButton = object(TCheckBox)
  139.     constructor Init(AParent: PWindowsObject; AnID: Integer;
  140.       ATitle: PChar; X, Y, W, H: Integer; AGroup: PGroupBox);
  141.     function GetClassName: PChar; virtual;
  142.   end;
  143.  
  144. { TStatic object }
  145.  
  146.   PStatic = ^TStatic;
  147.   TStatic = object(TControl)
  148.     TextLen: Word;
  149.     constructor Init(AParent: PWindowsObject; AnId: Integer;
  150.       ATitle: PChar; X, Y, W, H: Integer; ATextLen: Word);
  151.     constructor InitResource(AParent: PWindowsObject; ResourceID: Word;
  152.       ATextLen: Word);
  153.     constructor Load(var S: TStream);
  154.     procedure Store(var S: TStream);
  155.     function GetClassName: PChar; virtual;
  156.     function GetText(ATextString: PChar; MaxChars: Integer): Integer;
  157.     function GetTextLen: Integer;
  158.     procedure SetText(ATextString: PChar);
  159.     procedure Clear;
  160.     function Transfer(DataPtr: Pointer; TransferFlag: Word): Word; virtual;
  161.   end;
  162.  
  163. { TEdit object }
  164.  
  165.   PEdit    = ^TEdit;
  166.   TEdit = object(TStatic)
  167.     Validator: PValidator;
  168.     constructor Init(AParent: PWindowsObject; AnId: Integer; ATitle: PChar;
  169.        X, Y, W, H: Integer; ATextLen: Word; Multiline: Boolean);
  170.     constructor InitResource(AParent: PWindowsObject; ResourceID: Word;
  171.       ATextLen: Word);
  172.     constructor Load(var S: TStream);
  173.     destructor  Done; virtual;
  174.     function GetClassName: PChar; virtual;
  175.     procedure Undo;
  176.     function CanClose: Boolean; virtual;
  177.     function CanUndo: Boolean;
  178.     procedure Paste;
  179.     procedure Copy;
  180.     procedure Cut;
  181.     function GetNumLines: Integer;
  182.     function GetLineLength(LineNumber: Integer): Integer;
  183.     function GetLine(ATextString: PChar;
  184.       StrSize, LineNumber: Integer): Boolean;
  185.     procedure GetSubText(ATextString: PChar; StartPos, EndPos: Integer);
  186.     function DeleteSubText(StartPos, EndPos: Integer): Boolean;
  187.     function DeleteLine(LineNumber: Integer): Boolean;
  188.     procedure GetSelection(var StartPos, EndPos: Integer);
  189.     function DeleteSelection: Boolean;
  190.     function IsModified: Boolean;
  191.     procedure ClearModify;
  192.     function GetLineFromPos(CharPos: Integer): Integer;
  193.     function GetLineIndex(LineNumber: Integer): Integer;
  194.     function IsValid(ReportError: Boolean): Boolean;
  195.     procedure Scroll(HorizontalUnit, VerticalUnit: Integer);
  196.     function SetSelection(StartPos, EndPos: Integer): Boolean;
  197.     procedure Insert(ATextString: PChar);
  198.     function Search(StartPos: Integer; AText: PChar; CaseSensitive: Boolean): Integer;
  199.     procedure SetupWindow; virtual;
  200.     procedure SetValidator(AValid: PValidator);
  201.     procedure Store(var S: TStream);
  202.     function  Transfer(DataPtr: Pointer; TransferFlag: Word): Word; virtual;
  203.     procedure CMEditCut(var Msg: TMessage);
  204.       virtual  cm_First + cm_EditCut;
  205.     procedure CMEditCopy(var Msg: TMessage);
  206.       virtual  cm_First + cm_EditCopy;
  207.     procedure CMEditPaste(var Msg: TMessage);
  208.       virtual  cm_First + cm_EditPaste;
  209.     procedure CMEditDelete(var Msg: TMessage);
  210.       virtual  cm_First + cm_EditDelete;
  211.     procedure CMEditClear(var Msg: TMessage);
  212.       virtual  cm_First + cm_EditClear;
  213.     procedure CMEditUndo(var Msg: TMessage);
  214.       virtual  cm_First + cm_EditUndo;
  215.     procedure WMChar(var Msg: TMessage);
  216.       virtual  wm_First + wm_Char;
  217.     procedure WMKeyDown(var Msg: TMessage);
  218.       virtual  wm_First + wm_KeyDown;
  219.     procedure WMGetDlgCode(var Msg: TMessage);
  220.       virtual  wm_First + wm_GetDlgCode;
  221.     procedure WMKillFocus(var Msg: TMessage);
  222.       virtual  wm_First + wm_KillFocus;
  223.   end;
  224.  
  225. { TListBox message name type }
  226.  
  227.   TMsgName = (
  228.     mn_AddString, mn_InsertString, mn_DeleteString,
  229.     mn_ResetContent, mn_GetCount, mn_GetText,
  230.     mn_GetTextLen, mn_SelectString, mn_SetCurSel,
  231.     mn_GetCurSel);
  232.  
  233. { Multiple selction transfer record }
  234.  
  235.   PMultiSelRec = ^TMultiSelRec;
  236.   TMultiSelRec = record
  237.     Count: Integer;
  238.     Selections: array[0..32760] of Integer;
  239.   end;
  240.  
  241. { TListBox object }
  242.  
  243.   PListBox = ^TListBox;
  244.   TListBox = object(TControl)
  245.     constructor Init(AParent: PWindowsObject; AnId: Integer;
  246.       X, Y, W, H: Integer);
  247.     function GetClassName: PChar; virtual;
  248.     function AddString(AString: PChar): Integer;
  249.     function InsertString(AString: PChar; Index: Integer): Integer;
  250.     function DeleteString(Index: Integer): Integer;
  251.     procedure ClearList;
  252.     function Transfer(DataPtr: Pointer; TransferFlag: Word): Word; virtual;
  253.     function GetCount: Integer;
  254.     function GetString(AString: PChar; Index: Integer): Integer;
  255.     function GetStringLen(Index: Integer): Integer;
  256.     function GetSelString(AString: PChar; MaxChars: Integer): Integer;
  257.     function SetSelString(AString: PChar; Index: Integer): Integer;
  258.     function GetSelIndex: Integer;
  259.     function SetSelIndex(Index: Integer): Integer;
  260.   private
  261.     function GetMsgID(AMsg: TMsgName): Word; virtual;
  262.   end;
  263.  
  264. { TComboBox object }
  265.  
  266.   PComboBox = ^TComboBox;
  267.   TComboBox = object(TListBox)
  268.     TextLen: Word;
  269.     constructor Init(AParent: PWindowsObject; AnID: Integer;
  270.       X, Y, W, H: Integer; AStyle: Word; ATextLen: Word);
  271.     constructor InitResource(AParent: PWindowsObject; ResourceID: Integer;
  272.       ATextLen: Word);
  273.     constructor Load(var S: TStream);
  274.     procedure Store(var S: TStream);
  275.     function GetClassName: PChar; virtual;
  276.     procedure ShowList;
  277.     procedure HideList;
  278.     function Transfer(DataPtr: Pointer; TransferFlag: Word): Word; virtual;
  279.     procedure SetupWindow; virtual;
  280.     function GetTextLen: Integer;
  281.     function GetText(Str: PChar; MaxChars: Integer): Integer;
  282.     procedure SetText(Str: PChar);
  283.     function SetEditSel(StartPos, EndPos: Integer): Integer;
  284.     function GetEditSel(var StartPos, EndPos: Integer): Boolean;
  285.     procedure Clear;
  286.   private
  287.     function GetMsgID(AMsg: TMsgName): Word; virtual;
  288.   end;
  289.  
  290. { TScrollBar transfer record }
  291.  
  292.   TScrollBarTransferRec = record
  293.     LowValue: Integer;
  294.     HighValue: Integer;
  295.     Position: Integer;
  296.   end;
  297.  
  298. { TScrollBar object }
  299.  
  300.   PScrollBar = ^TScrollBar;
  301.   TScrollBar = object(TControl)
  302.     LineMagnitude, PageMagnitude: Integer;
  303.     constructor Init(AParent: PWindowsObject; AnID: Integer;
  304.       X, Y, W, H: Integer; IsHScrollBar: Boolean);
  305.     constructor InitResource(AParent: PWindowsObject; ResourceID: Word);
  306.     constructor Load(var S: TStream);
  307.     procedure Store(var S: TStream);
  308.     function GetClassName: PChar; virtual;
  309.     procedure SetupWindow; virtual;
  310.     procedure GetRange(var LoVal, HiVal: Integer);
  311.     function GetPosition: Integer;
  312.     procedure SetRange(LoVal, HiVal: Integer);
  313.     procedure SetPosition(ThumbPos: Integer);
  314.     function DeltaPos(Delta: Integer): Integer;
  315.     function Transfer(DataPtr: Pointer; TransferFlag: Word): Word; virtual;
  316.     procedure SBLineUp(var Msg: TMessage);
  317.       virtual nf_First + sb_LineUp;
  318.     procedure SBLineDown(var Msg: TMessage);
  319.       virtual nf_First + sb_LineDown;
  320.     procedure SBPageUp(var Msg: TMessage);
  321.       virtual nf_First + sb_PageUp;
  322.     procedure SBPageDown(var Msg: TMessage);
  323.       virtual nf_First + sb_PageDown;
  324.     procedure SBThumbPosition(var Msg: TMessage);
  325.       virtual nf_First + sb_ThumbPosition;
  326.     procedure SBThumbTrack(var Msg: TMessage);
  327.       virtual nf_First + sb_ThumbTrack;
  328.     procedure SBTop(var Msg: TMessage);
  329.       virtual nf_First + sb_Top;
  330.     procedure SBBottom(var Msg: TMessage);
  331.       virtual nf_First + sb_Bottom;
  332.   end;
  333.  
  334. { Multi-selection support routines }
  335.  
  336. function AllocMultiSel(Size: Integer): PMultiSelRec;
  337. procedure FreeMultiSel(P: PMultiSelRec);
  338.  
  339. { Stream routine }
  340.  
  341. procedure RegisterODialogs;
  342.  
  343. const
  344.   RDialog: TStreamRec = (
  345.     ObjType: 54;
  346.     VmtLink: Ofs(TypeOf(TDialog)^);
  347.     Load:    @TDialog.Load;
  348.     Store:   @TDialog.Store);
  349.  
  350. const
  351.   RDlgWindow: TStreamRec = (
  352.     ObjType: 55;
  353.     VmtLink: Ofs(TypeOf(TDlgWindow)^);
  354.     Load:    @TDlgWindow.Load;
  355.     Store:   @TDlgWindow.Store);
  356.  
  357. const
  358.   RControl: TStreamRec = (
  359.     ObjType: 56;
  360.     VmtLink: Ofs(TypeOf(TControl)^);
  361.     Load:    @TControl.Load;
  362.     Store:   @TControl.Store);
  363.  
  364. const
  365.   RMDIClient: TStreamRec = (
  366.     ObjType: 58;
  367.     VmtLink: Ofs(TypeOf(TMDIClient)^);
  368.     Load:    @TMDIClient.Load;
  369.     Store:   @TMDIClient.Store);
  370.  
  371. const
  372.   RButton: TStreamRec = (
  373.     ObjType: 59;
  374.     VmtLink: Ofs(TypeOf(TButton)^);
  375.     Load:    @TButton.Load;
  376.     Store:   @TButton.Store);
  377.  
  378. const
  379.   RCheckBox: TStreamRec = (
  380.     ObjType: 60;
  381.     VmtLink: Ofs(TypeOf(TCheckBox)^);
  382.     Load:    @TCheckBox.Load;
  383.     Store:   @TCheckBox.Store);
  384.  
  385. const
  386.   RRadioButton: TStreamRec = (
  387.     ObjType: 61;
  388.     VmtLink: Ofs(TypeOf(TRadioButton)^);
  389.     Load:    @TRadioButton.Load;
  390.     Store:   @TRadioButton.Store);
  391.  
  392. const
  393.   RGroupBox: TStreamRec = (
  394.     ObjType: 62;
  395.     VmtLink: Ofs(TypeOf(TGroupBox)^);
  396.     Load:    @TGroupBox.Load;
  397.     Store:   @TGroupBox.Store);
  398.  
  399. const
  400.   RListBox: TStreamRec = (
  401.     ObjType: 63;
  402.     VmtLink: Ofs(TypeOf(TListBox)^);
  403.     Load:    @TListBox.Load;
  404.     Store:   @TListBox.Store);
  405.  
  406. const
  407.   RComboBox: TStreamRec = (
  408.     ObjType: 64;
  409.     VmtLink: Ofs(TypeOf(TComboBox)^);
  410.     Load:    @TComboBox.Load;
  411.     Store:   @TComboBox.Store);
  412.  
  413. const
  414.   RScrollBar: TStreamRec = (
  415.     ObjType: 65;
  416.     VmtLink: Ofs(TypeOf(TScrollBar)^);
  417.     Load:    @TScrollBar.Load;
  418.     Store:   @TScrollBar.Store);
  419.  
  420. const
  421.   RStatic: TStreamRec = (
  422.     ObjType: 66;
  423.     VmtLink: Ofs(TypeOf(TStatic)^);
  424.     Load:    @TStatic.Load;
  425.     Store:   @TStatic.Store);
  426.  
  427. const
  428.   REdit: TStreamRec = (
  429.     ObjType: 67;
  430.     VmtLink: Ofs(TypeOf(TEdit)^);
  431.     Load:    @TEdit.Load;
  432.     Store:   @TEdit.Store);
  433.  
  434. implementation
  435.  
  436. uses Strings, OMemory;
  437.  
  438. { Used while determining when to validate a TEdit control.  Inhibits
  439.   focus change from validating the control when bringing up a dialog
  440.   to report invalid data. }
  441.  
  442. const
  443.   ProcessFocus: Boolean = True;
  444.  
  445. { TDialog }
  446.  
  447. { Constructor for a TDialog object.  Calls TWindowsObject.Init, creating
  448.   an instance thunk for the TDialog. }
  449.  
  450. constructor TDialog.Init(AParent: PWindowsObject; AName: PChar);
  451. begin
  452.   TWindowsObject.Init(AParent);
  453.   DisableAutoCreate;
  454.   if PtrRec(AName).Seg <> 0 then Attr.Name := StrNew(AName)
  455.   else Attr.Name := AName;
  456.   Attr.Param := 0;
  457.   IsModal := False;
  458. end;
  459.  
  460. { Destructor for a TDialog.  TWindowsObject.Done is called to free
  461.   the instance thunk. }
  462.  
  463. destructor TDialog.Done;
  464. begin
  465.   if PtrRec(Attr.Name).Seg <> 0 then StrDispose(Attr.Name);
  466.   TWindowsObject.Done;
  467. end;
  468.  
  469. { Constructor for a TDialog object.  Initializes the TDialog with
  470.   data from the passed TStream. }
  471.  
  472. constructor TDialog.Load(var S: TStream);
  473. var
  474.   NameIsNumeric: Boolean;
  475. begin
  476.   TWindowsObject.Load(S);
  477.   DisableAutoCreate;
  478.   with Attr do
  479.   begin
  480.     S.Read(NameIsNumeric, SizeOf(NameIsNumeric));
  481.     if NameIsNumeric then S.Read(Name, SizeOf(Name))
  482.     else Name := S.StrRead;
  483.     S.Read(Param, SizeOf(Param));
  484.   end;
  485.   S.Read(IsModal, SizeOf(IsModal));
  486. end;
  487.  
  488. { Stores data of the TDialog object in the passed TStream. }
  489.  
  490. procedure TDialog.Store(var S: TStream);
  491. var
  492.   NameIsNumeric: Boolean;
  493. begin
  494.   TWindowsObject.Store(S);
  495.   with Attr do
  496.   begin
  497.     NameIsNumeric := PtrRec(Name).Seg = 0;
  498.     S.Write(NameIsNumeric, SizeOf(NameIsNumeric));
  499.     if NameIsNumeric then S.Write(Name, SizeOf(Name))
  500.     else S.StrWrite(Name);
  501.     S.Write(Param, SizeOf(Param));
  502.   end;
  503.   S.Write(IsModal, SizeOf(IsModal));
  504. end;
  505.  
  506. { Creates an MS-Windows modeless dialog, and associates the modeless
  507.   dialog interface element with the TDialog.  Creation and association is
  508.   not attempted if the Status data field is non-zero. }
  509.  
  510. function TDialog.Create: Boolean;
  511. var
  512.   HParent: HWnd;
  513. begin
  514.   if Status = 0 then
  515.   begin
  516.     DisableAutoCreate;
  517.     EnableKBHandler;
  518.     IsModal := False;
  519.     if Parent = nil then HParent := 0 else HParent := Parent^.HWindow;
  520.     HWindow := CreateDialogParam(HInstance, Attr.Name, HParent, Instance,
  521.       Attr.Param);
  522.     if HWindow = 0 then Status := em_InvalidWindow;
  523.   end;
  524.   Create := Status = 0;
  525. end;
  526.  
  527. { Creates an MS-Windows modal dialog, using the creation attributes
  528.   previously set in the Attr data field.  Associates the modal dialog
  529.   interface element with the TDialog.  Creation and association is not
  530.   attempted if the Status data field is non-zero. }
  531.  
  532. function TDialog.Execute: Integer;
  533. var
  534.   HParent: HWnd;
  535.   ReturnValue: Integer;
  536.   OldKbHandler: PWindowsObject;
  537. begin
  538.   if Status = 0 then
  539.   begin
  540.     DisableAutoCreate;
  541.     EnableKBHandler;
  542.     IsModal := True;
  543.     if Parent = nil then HParent := 0 else HParent := Parent^.HWindow;
  544.     OldKbHandler := Application^.KBHandlerWnd;
  545.     ReturnValue := DialogBoxParam(HInstance, Attr.Name, HParent, Instance,
  546.       Attr.Param);
  547.     Application^.KBHandlerWnd := OldKbHandler;
  548.     { -1 if the function cannot create the dialog box }
  549.     if ReturnValue = -1 then Status := em_InvalidWindow;
  550.     HWindow := 0;
  551.     Execute := ReturnValue;
  552.   end
  553.   else Execute := Status;
  554. end;
  555.  
  556. { Destroys the MS-Windows dialog associated with the TDialog. }
  557.  
  558. procedure TDialog.EndDlg(ARetValue: Integer);
  559.  
  560.   procedure DoEnableAutoCreate(P: PWindowsObject); far;
  561.   begin
  562.     if P^.HWindow <> 0 then P^.EnableAutoCreate;
  563.   end;
  564.  
  565. begin
  566.   if IsModal then
  567.   begin
  568.     ForEach(@DoEnableAutoCreate);
  569.     EndDialog(HWindow, ARetValue)
  570.   end;
  571. end;
  572.  
  573. { Responds to an incoming wm_InitDialog message.  This message is sent
  574.   after an MS-Windows dialog is created and before the dialog is displayed.
  575.   Calls SetupWindow to perform set up for the dialog. }
  576.  
  577. procedure TDialog.WMInitDialog(var Msg: TMessage);
  578. begin
  579.   SetupWindow;
  580. end;
  581.  
  582. { Respond to Windows attempt to close close down. Note: A DIALOG needs
  583.   to invert the test because windows expects the opposite of a normal
  584.   window. }
  585.  
  586. procedure TDialog.WMQueryEndSession(var Msg: TMessage);
  587. begin
  588.   if @Self = Application^.MainWindow then
  589.     Msg.Result := Integer(not Application^.CanClose)
  590.   else Msg.Result := Integer(not CanClose);
  591. end;
  592.  
  593. { Responds to a message from a child edit control that its contents
  594.   are invalid.  Posts the invalid message using that child's Validator
  595.   and returns the focus to that child.  This response method is used
  596.   to allow the KillFocus processing for the Edit control to post the
  597.   message outside the KillFocus chain, since posting a message box
  598.   while the focus is being taken causes a number of problems.  The
  599.   TEdit puts the handle to itself in WParam. }
  600.  
  601. procedure TDialog.WMPostInvalid(var Msg: TMessage);
  602. var
  603.   AnEdit: PEdit;
  604. begin
  605.   SetFocus(Msg.WParam);
  606.   AnEdit := PEdit(GetObjectPtr(Msg.WParam));
  607.   if (AnEdit <> nil) and (AnEdit^.Validator <> nil) then
  608.     AnEdit^.Validator^.Error;
  609.   ProcessFocus := True;
  610. end;
  611.  
  612. { Returns the handle of the dialog's control which has the passed Id. }
  613.  
  614. function TDialog.GetItemHandle(DlgItemID: Integer): HWND;
  615. begin
  616.   GetItemHandle := GetDlgItem(HWindow, DlgItemID);
  617. end;
  618.  
  619. { Sends the passed message to the dialog's control which has the passed
  620.   Id. }
  621.  
  622. function TDialog.SendDlgItemMsg(DlgItemID: Integer; AMsg, WParam: Word;
  623.   LParam: LongInt): LongInt;
  624. begin
  625.   SendDlgItemMsg :=
  626.     SendDlgItemMessage(HWindow, DlgItemID, AMsg, WParam, LParam);
  627. end;
  628.  
  629. { Specifies that default processing for an incoming message is to be
  630.   performed by MS-Windows by setting the Result field of the passed Msg
  631.   to zero. }
  632.  
  633. procedure TDialog.DefWndProc(var Msg: TMessage);
  634. begin
  635.   Msg.Result := 0;
  636. end;
  637.  
  638. { Responds to an incoming notification message from a button with an Id
  639.   equal to id_OK.  Calls CanClose.  If the call returns True, calls
  640.   TransferData and then ends the dialog, returning id_OK. }
  641.  
  642. procedure TDialog.Ok(var Msg: TMessage);
  643. begin
  644.   if IsModal then
  645.   begin
  646.     if CanClose then
  647.     begin
  648.       TransferData(tf_GetData);
  649.       EndDlg(id_OK);
  650.     end;
  651.   end else CloseWindow;
  652. end;
  653.  
  654. { Responds to an incoming notification message from a button with an Id
  655.   equal to id_Cancel.  Ends the dialog, returning id_Cancel. }
  656.  
  657. procedure TDialog.Cancel(var Msg: TMessage);
  658. begin
  659.   if IsModal then EndDlg(id_Cancel) else CloseWindow;
  660. end;
  661.  
  662. procedure TDialog.WMClose(var Msg: TMessage);
  663. begin
  664.   Cancel(Msg);
  665. end;
  666.  
  667. { TDlgWindow }
  668.  
  669. { Constructor for a TDlgWindow object.  Calls TDialog.Init, setting
  670.   the auto creation flag to True so that DlgWindow's appearing in
  671.   their parent's child window list will be recreated. }
  672.  
  673. constructor TDlgWindow.Init(AParent: PWindowsObject; AName: PChar);
  674. begin
  675.   TDialog.Init(AParent, AName);
  676.   EnableAutoCreate;
  677. end;
  678.  
  679. { Specifies registration attributes for the MS-Windows window class of the
  680.   TDlgWindow, allowing instances of TDlgWindow to be registered.  Sets the
  681.   fields of the passed TWndClass parameter to the default attributes
  682.   appropriate for a TDlgWindow. }
  683.  
  684. procedure TDlgWindow.GetWindowClass(var AWndClass: TWndClass);
  685. begin
  686.   AWndClass.style := cs_HRedraw or cs_VRedraw;
  687.   AWndClass.lpfnWndProc := @DefDlgProc;
  688.   AWndClass.cbClsExtra := 0;
  689.   AWndClass.cbWndExtra := DlgWindowExtra;
  690.   AWndClass.hbrBackground := HBrush(color_window + 1);
  691.   AWndClass.lpszMenuName := nil;
  692.   AWndClass.hInstance := HInstance;
  693.   AWndClass.hIcon := LoadIcon(0, idi_Application);
  694.   AWndClass.hCursor := LoadCursor(0, idc_Arrow);
  695.   AWndClass.lpszClassName := GetClassName;
  696. end;
  697.  
  698. { Creates an MS-Windows dialog window and associates the dialog window
  699.   interface element with the TDlgWindow.  Calls Self.Register to ensure
  700.   that the TDlgWindow's MS-Windows window class has been registered, then
  701.   calls TDialog.Create. }
  702.  
  703. function TDlgWindow.Create: Boolean;
  704. begin
  705.   Create := False;
  706.   if Register then Create := TDialog.Create;
  707. end;
  708.  
  709. { TControl }
  710.  
  711. { Constructor for a TControl.  Calls TWindow.Init, and sets
  712.   creation attributes using the parameters passed and default values. }
  713.  
  714. constructor TControl.Init(AParent: PWindowsObject; AnId: Integer;
  715.   ATitle: PChar; X, Y, W, H: Integer);
  716. begin
  717.   TWindow.Init(AParent, ATitle);
  718.   Attr.Id := AnId;
  719.   Attr.X := X;
  720.   Attr.Y := Y;
  721.   Attr.W := W;
  722.   Attr.H := H;
  723.   Attr.Style := ws_Child or ws_Visible or ws_Group or ws_TabStop;
  724. end;
  725.  
  726. { Constructor for a TControl to be associated with a MS-Windows
  727.   interface element created by MS-Windows from a resource definition.
  728.   Initializes its data fields using passed parameters.  Data transfer
  729.   is enabled for the TControl. }
  730.  
  731. constructor TControl.InitResource(AParent: PWindowsObject; ResourceID: Word);
  732. begin
  733.   TWindow.InitResource(AParent, ResourceID);
  734.   EnableTransfer;
  735. end;
  736.  
  737. { Generates a run-time error (via call to inherited Abstract method)
  738.   because an attempt should not be made to retrieve the window class name
  739.   for an instance of this abstract object type.  Redefines ancestor's
  740.   GetClassName, which returns a pointer to the name of the MS-Windows
  741.   window class of the window object. Descendant classes redefine this
  742.   method to return the MS-Windows window class name for their instances. }
  743.  
  744. function TControl.GetClassName: PChar;
  745. begin
  746.   Abstract;
  747. end;
  748.  
  749. { Redefines ancestor's Register method, which registers an MS-Windows class
  750.   for a window object.  This method simply returns True because TControl
  751.   descendants have pre-registered MS-Windows window classes. }
  752.  
  753. function TControl.Register: Boolean;
  754. begin
  755.   Register := True;
  756. end;
  757.  
  758. { Responds to an incoming wm_Paint message by calling the default window
  759.   procedure, supplied by MS-Windows, which is appropriate for the TControl.
  760.   Redefines ancestor's WMPaint. }
  761.  
  762. procedure TControl.WMPaint(var Msg: TMessage);
  763. begin
  764.   DefWndProc(Msg);
  765. end;
  766.  
  767. { TButton }
  768.  
  769. { Constructor for a TButton object.  Initializes its data fields using
  770.   parameters passed and default values. }
  771.  
  772. constructor TButton.Init(AParent: PWindowsObject; AnId: Integer; AText: PChar;
  773.   X, Y, W, H: Integer; IsDefault:  Boolean);
  774. begin
  775.   TControl.Init(AParent, AnId, AText, X, Y, W, H);
  776.   if IsDefault then
  777.     Attr.Style := Attr.Style or bs_DefPushButton
  778.   else Attr.Style := Attr.Style or bs_PushButton;
  779. end;
  780.  
  781. { Constructor for a TButton to be associated with a MS-Windows interface
  782.   element created by MS-Windows from a resource definition. Initializes
  783.   its data fields using passed parameters.  Disables transfer of state
  784.   data for the TButton. }
  785.  
  786. constructor TButton.InitResource(AParent: PWindowsObject; ResourceID: Word);
  787. begin
  788.   TControl.InitResource(AParent, ResourceID);
  789.   DisableTransfer;
  790. end;
  791.  
  792. { Returns the name of the MS-Windows window class for TButtons. }
  793.  
  794. function TButton.GetClassName: PChar;
  795. begin
  796.   if BWCCClassNames then
  797.     GetClassName := 'BorBtn'
  798.   else
  799.     GetClassName := 'Button';
  800. end;
  801.  
  802. { TCheckBox }
  803.  
  804. { Constructor for a TCheckBox object.  Initializes the object with data
  805.   from the passed TStream. }
  806.  
  807. constructor TCheckBox.Load(var S: TStream);
  808. begin
  809.   TButton.Load(S);
  810.   GetSiblingPtr(S, Group);
  811. end;
  812.  
  813. { Stores data of the TCheckBox object in the passed TStream. }
  814.  
  815. procedure TCheckBox.Store(var S: TStream);
  816. begin
  817.   TButton.Store(S);
  818.   PutSiblingPtr(S, Group);
  819. end;
  820.  
  821. { Constructor for a TCheckBox object.  Initializes its data fields using
  822.   passed parameters and default values. }
  823.  
  824. constructor TCheckBox.Init(AParent: PWindowsObject; AnID: Integer;
  825.   ATitle: PChar; X, Y, W, H: Integer; AGroup: PGroupBox);
  826. begin
  827.   TControl.Init(AParent, AnID, ATitle, X, Y, W, H);
  828.   Attr.Style := ws_Child or ws_Visible or ws_TabStop or bs_AutoCheckbox;
  829.   Group := AGroup;
  830. end;
  831.  
  832. { Constructor for a TControl to be associated with a MS-Windows
  833.   interface element created by MS-Windows from a resource definition.
  834.   Initializes its data fields using passed parameters.  Data transfer
  835.   is enabled for the TCheckBox. }
  836.  
  837. constructor TCheckBox.InitResource(AParent: PWindowsObject; ResourceID: Word);
  838. begin
  839.   TButton.InitResource(AParent, ResourceID);
  840.   EnableTransfer;
  841.   Group := nil;
  842. end;
  843.  
  844. { Transfers state information for the TCheckBox. The TransferFlag passed
  845.   specifies whether data is to be read from or written to the passed
  846.   buffer, or whether the data element size is simply to be returned. The
  847.   return value is the size (in bytes) of the transfer data. }
  848.  
  849. function TCheckBox.Transfer(DataPtr: Pointer; TransferFlag: Word): Word;
  850. var
  851.   CheckFlag: Word;
  852. begin
  853.   if TransferFlag = tf_GetData then
  854.   begin
  855.     CheckFlag := GetCheck;
  856.     Move(CheckFlag, DataPtr^, SizeOf(CheckFlag));
  857.   end
  858.   else if TransferFlag = tf_SetData then SetCheck(Word(DataPtr^)); 
  859.   Transfer := SizeOf(CheckFlag);
  860. end;
  861.  
  862. { Returns the check state of the associated check box.  Returns bf_Unchecked
  863.   (0), bf_Checked (1), or (if 3-state) bf_Grayed (2). }
  864.  
  865. function TCheckBox.GetCheck: Word;
  866. begin
  867.   GetCheck := SendMessage(HWindow, bm_GetCheck, 0, 0);
  868. end;
  869.  
  870. { Returns the name of the MS-Windows window class for TCheckBox. }
  871.  
  872. function TCheckBox.GetClassName: PChar;
  873. begin
  874.   if BWCCClassNames then
  875.     GetClassName := 'BorCheck'
  876.   else
  877.     GetClassName := TButton.GetClassName;
  878. end;
  879.  
  880. { Sets the check state of the associated check box.  Unchecks, checks, or
  881.   grays the checkbox (if 3-state) according to the CheckFlag passed.
  882.   (Pass bf_Unchecked (0), bf_Checked (1), or bf_Grayed (2)). If a Group has
  883.   been specified for the TCheckBox, notifies the Group that the state of the
  884.   check box has changed. }
  885.  
  886. procedure TCheckBox.SetCheck(CheckFlag: Word);
  887. begin
  888.   SendMessage(HWindow, bm_SetCheck, CheckFlag, 0);
  889.   if (Group <> nil) then Group^.SelectionChanged(Attr.Id);
  890. end;
  891.  
  892. { Places a checkmark in associated check box. }
  893.  
  894. procedure TCheckBox.Check;
  895. begin
  896.   SetCheck(1);
  897. end;
  898.  
  899. { Removes a checkmark from the associated check box. }
  900.  
  901. procedure TCheckBox.Uncheck;
  902. begin
  903.   SetCheck(0);
  904. end;
  905.  
  906. { Toggles the check state of the check box. }
  907.  
  908. procedure TCheckBox.Toggle;
  909. begin
  910.   if ((GetWindowLong(HWindow, gwl_Style) and bs_Auto3State) =  bs_Auto3State) then
  911.     SetCheck((GetCheck+1) mod 3)
  912.   else SetCheck((GetCheck+1) mod 2);
  913. end;
  914.  
  915. { Responds to an incoming bn_Clicked message.  If a Group has been
  916.   specified for the TCheckBox, notifies the Group that the state of
  917.   this TCheckBox has changed. }
  918.  
  919. procedure TCheckBox.BNClicked(var Msg: TMessage);
  920. begin
  921.   DefWndProc(Msg);
  922.   if (Group <> nil) then
  923.     Group^.SelectionChanged(Attr.Id);
  924.   DefNotificationProc(Msg);
  925. end;
  926.  
  927. { TRadioButton }
  928.  
  929. { Constructor for a TRadioButton object.  Initializes its data fields
  930.   using passed parameters and default values. }
  931.  
  932. constructor TRadioButton.Init(AParent: PWindowsObject; AnID: Integer;
  933.   ATitle: PChar; X, Y, W, H: Integer; AGroup: PGroupBox);
  934. begin
  935.   TCheckBox.Init(AParent, AnID, ATitle, X, Y, W, H, AGroup);
  936.   Attr.Style := ws_Child or ws_Visible or bs_AutoRadioButton;
  937. end;
  938.  
  939. { Returns the name of the MS-Windows window class for TRadioButton. }
  940.  
  941. function TRadioButton.GetClassName: PChar;
  942. begin
  943.   if BWCCClassNames then
  944.     GetClassName := 'BorRadio'
  945.   else
  946.     GetClassName := TButton.GetClassName;
  947. end;
  948.  
  949. { TGroupBox }
  950.  
  951. { Constructor for a TGroupBox object.  Initializes the object with data
  952.   from the passed TStream. }
  953.  
  954. constructor TGroupBox.Load(var S: TStream);
  955. begin
  956.   TControl.Load(S);
  957.   S.Read(NotifyParent, SizeOf(NotifyParent));
  958. end;
  959.  
  960. { Stores data of the TGroupBox object in the passed TStream. }
  961.  
  962. procedure TGroupBox.Store(var S: TStream);
  963. begin
  964.   TControl.Store(S);
  965.   S.Write(NotifyParent, SizeOf(NotifyParent));
  966. end;
  967.  
  968. { Constructor for a TGroupBox object.  Initializes its data fields using
  969.   parameters passed and default values. }
  970.  
  971. constructor TGroupBox.Init(AParent: PWindowsObject; AnID: Integer;
  972.   AText: PChar; X, Y, W, H: Integer);
  973. begin
  974.   TControl.Init(AParent, AnId, AText, X, Y, W, H);
  975.   NotifyParent := True;
  976.   Attr.Style := (Attr.Style or bs_GroupBox) and (not ws_TabStop);
  977. end;
  978.  
  979. { Constructor for a TGroupBox to be associated with a MS-Windows interface
  980.   element created by MS-Windows from a resource definition. Initializes
  981.   its data fields using passed parameters.  Disables transfer of state
  982.   data for the TGroupBox.  }
  983.  
  984. constructor TGroupBox.InitResource(AParent: PWindowsObject; ResourceID: Word);
  985. begin
  986.   TControl.InitResource(AParent, ResourceID);
  987.   NotifyParent := True;
  988.   DisableTransfer;
  989. end;
  990.  
  991. { Returns the name of MS-Windows window class for a TGroupBox. }
  992.  
  993. function TGroupBox.GetClassName: PChar;
  994. begin
  995.   GetClassName := 'Button';
  996. end;
  997.  
  998. { Notifies parent that the selection in the associated groupbox has
  999.   changed.  This method is called by TCheckBoxes grouped in the groupbox
  1000.   when their state changes. }
  1001.  
  1002. procedure TGroupBox.SelectionChanged(ControlId: Integer);
  1003. begin
  1004.   if NotifyParent then
  1005.     SendMessage(Parent^.HWindow, wm_Command, Attr.ID,
  1006.       MakeLong(HWindow, ControlId));
  1007. end;
  1008.  
  1009. { TStatic }
  1010.  
  1011. { Constructor for a TStatic object.  Initializes its data fields using
  1012.   passed parameters and default values.   By default, an associated
  1013.   static control will have left-justified text. }
  1014.  
  1015. constructor TStatic.Init(AParent: PWindowsObject; AnId: Integer;
  1016.   ATitle: PChar; X, Y, W, H: Integer; ATextLen: Word);
  1017. begin
  1018.   TControl.Init(AParent, AnId, ATitle, X, Y, W, H);
  1019.   TextLen := ATextLen;
  1020.   Attr.Style := (Attr.Style or ss_Left) and (not ws_TabStop);
  1021. end;
  1022.  
  1023. { Constructor for a TStatic to be associated with a MS-Windows
  1024.   interface element created by MS-Windows from a resource definition.
  1025.   Initializes its data fields using passed parameters.  Data transfer
  1026.   is disabled, by default, for the TStatic. }
  1027.  
  1028. constructor TStatic.InitResource(AParent: PWindowsObject; ResourceID: Word;
  1029.   ATextLen: Word);
  1030. begin
  1031.   TControl.InitResource(AParent, ResourceID);
  1032.   TextLen := ATextLen;
  1033. end;
  1034.  
  1035. { Constructor for a TStatic object.  Initializes the object with data
  1036.   from the passed TStream. }
  1037.  
  1038. constructor TStatic.Load(var S: TStream);
  1039. begin
  1040.   TControl.Load(S);
  1041.   S.Read(TextLen, SizeOf(TextLen));
  1042. end;
  1043.  
  1044. { Stores data of the TStatic object in the passed TStream. }
  1045.  
  1046. procedure TStatic.Store(var S: TStream);
  1047. begin
  1048.   TControl.Store(S);
  1049.   S.Write(TextLen, SizeOf(TextLen));
  1050. end;
  1051.  
  1052. { Returns the name of the MS-Windows window class for a TStatic control. }
  1053.  
  1054. function TStatic.GetClassName: PChar;
  1055. begin
  1056.   GetClassName := 'Static';
  1057. end;
  1058.  
  1059. { Transfers state information for TStatic controls. The TransferFlag passed
  1060.   specifies whether data is to be read from or written to the passed
  1061.   buffer, or whether the data element size is simply to be returned. The
  1062.   return value is the size (in bytes) of the transfer data. TStatic objects
  1063.   are different from other TControl objects in one key respect.  If the
  1064.   TStatic is created with InitResource then wb_EnableTransfer is False, else
  1065.   it is true.  This presupposes that if you are interested in creating a
  1066.   TStatic object directly, you probably want to be able to initialize it.
  1067.   This behavior can be modified with EnableTransfer/DisableTransfer.}
  1068.  
  1069. function TStatic.Transfer(DataPtr: Pointer; TransferFlag: Word): Word;
  1070. begin
  1071.   if TransferFlag = tf_GetData then
  1072.     GetText(DataPtr, TextLen)
  1073.   else if TransferFlag = tf_SetData then
  1074.     SetText(DataPtr);
  1075.   Transfer := TextLen;
  1076. end;
  1077.  
  1078. { Fills the passed string with the text of the associated text
  1079.   control.  Returns the number of characters copied.  }
  1080.  
  1081. function TStatic.GetText(ATextString: PChar; MaxChars: Integer): Integer;
  1082. begin
  1083.   GetText := GetWindowText(HWindow, ATextString, MaxChars);
  1084. end;
  1085.  
  1086. { Returns the length of the control's text }
  1087.  
  1088. function TStatic.GetTextLen: Integer;
  1089. begin
  1090.   GetTextLen := GetWindowTextLength(HWindow);
  1091. end;
  1092.  
  1093. { Sets the contents of the associated static text control to the passed
  1094.   string. }
  1095.  
  1096. procedure TStatic.SetText(ATextString: PChar);
  1097. begin
  1098.   SetWindowText(HWindow, ATextString);
  1099. end;
  1100.  
  1101. { Clears the text of the associated static text control. }
  1102.  
  1103. procedure TStatic.Clear;
  1104. begin
  1105.   SetText('');
  1106. end;
  1107.  
  1108. { TEdit }
  1109.  
  1110. { Constructor for a TEdit object.  Initializes its data fields using
  1111.   passed parameters and default values.   By default, an associated
  1112.   static control will have a border and its text will be left-justified.
  1113.   Also by default, an associated multiline edit control will have
  1114.   horizontal and vertical scroll bars. }
  1115.  
  1116. constructor TEdit.Init(AParent: PWindowsObject; AnId: Integer; ATitle: PChar;
  1117.   X, Y, W, H: Integer; ATextLen: Word; Multiline: Boolean);
  1118. begin
  1119.   TStatic.Init(AParent, AnId, ATitle, X, Y, W, H, ATextLen);
  1120.   Attr.Style := (Attr.Style and not ss_Left) or es_Left or
  1121.     es_AutoHScroll or ws_Border or ws_TabStop;
  1122.   if Multiline then
  1123.     Attr.Style := Attr.Style or es_Multiline or es_AutoVScroll or
  1124.       ws_VScroll or ws_HScroll;
  1125.   Validator := nil;
  1126. end;
  1127.  
  1128. { Constructor for a TEdit that is to be associated with a Windows
  1129.   resource.  Identical to ancestral InitResource with the addition
  1130.   of an initialization for the Validator.
  1131. }
  1132. constructor TEdit.InitResource(AParent: PWindowsObject; ResourceID: Word;
  1133.   ATextLen: Word);
  1134. begin
  1135.   inherited InitResource(AParent, ResourceID, ATextLen);
  1136.   Validator := nil;
  1137. end;
  1138.  
  1139. { Constructor for a TEdit object.  Initializes the object with data
  1140.   from the passed TStream. }
  1141.  
  1142. constructor TEdit.Load(var S: TStream);
  1143. begin
  1144.   TStatic.Load(S);
  1145.   Validator := PValidator(S.Get);
  1146. end;
  1147.  
  1148. { Destroys an instance of TEdit by disposing of its Validator (if any),
  1149.   and then calling upon the inherited destructor to complete the process. }
  1150.  
  1151. destructor TEdit.Done;
  1152. begin
  1153.   SetValidator(nil);
  1154.   inherited Done;
  1155. end;
  1156.  
  1157. { Returns the name of the MS-Windows window class for TEdits. }
  1158.  
  1159. function TEdit.GetClassName: PChar;
  1160. begin
  1161.   GetClassName := 'Edit';
  1162. end;
  1163.  
  1164. { Only allows the Edit Control to be closed if it passes
  1165.   Validation.  Otherwise returns the focus to Self. }
  1166.  
  1167. function TEdit.CanClose: Boolean;
  1168. var
  1169.   OkToClose: Boolean;
  1170. begin
  1171.   OkToClose := inherited CanClose;
  1172.   if OkToClose then
  1173.     if IsWindowEnabled(HWindow) and not IsValid(True) then
  1174.     begin
  1175.       OkToClose := False;
  1176.       SetFocus(HWindow);
  1177.     end;
  1178.   CanClose := OkToClose;
  1179. end;
  1180.  
  1181. { Returns a Boolean value indicating whether or not the last change to the
  1182.   text of the associated edit control can be undone.  }
  1183.  
  1184. function TEdit.CanUndo: Boolean;
  1185. begin
  1186.   CanUndo := SendMessage(HWindow, em_CanUndo, 0, 0) <> 0;
  1187. end;
  1188.  
  1189. { Undoes the last change to the to the text of the associated edit
  1190.   control. }
  1191.  
  1192. procedure TEdit.Undo;
  1193. begin
  1194.   SendMessage(HWindow, wm_Undo, 0, 0);
  1195. end;
  1196.  
  1197. { Pastes the contents of the clipboard into the text of the associated
  1198.   edit control. }
  1199.  
  1200. procedure TEdit.Paste;
  1201. begin
  1202.   SendMessage(HWindow, wm_Paste, 0, 0);
  1203. end;
  1204.  
  1205. { Copies the text selected in the associated edit control to the
  1206.   clipboard. }
  1207.  
  1208. procedure TEdit.Copy;
  1209. begin
  1210.   SendMessage(HWindow, wm_Copy, 0, 0);
  1211. end;
  1212.  
  1213. { Cuts the text selected in the associated edit control into the
  1214.   clipboard. }
  1215.  
  1216. procedure TEdit.Cut;
  1217. begin
  1218.   SendMessage(HWindow, wm_Cut, 0, 0);
  1219. end;
  1220.  
  1221. { Responds to an incoming "Cut" command (with a cm_EditCut command
  1222.   identifier) by calling Self.Cut. }
  1223.  
  1224. procedure TEdit.CMEditCut(var Msg: TMessage);
  1225. begin
  1226.   Cut;
  1227. end;
  1228.     
  1229. { Responds to an incoming "Copy" command (with a cm_EditCopy command
  1230.   identifier) by calling Self.Copy. }
  1231.  
  1232. procedure TEdit.CMEditCopy(var Msg: TMessage);
  1233. begin
  1234.   Copy;
  1235. end;
  1236.  
  1237. { Responds to an incoming "Paste" command (with a cm_EditPaste command
  1238.   identifier) by calling Self.Paste. }
  1239.  
  1240. procedure TEdit.CMEditPaste(var Msg: TMessage);
  1241. begin
  1242.   Paste;
  1243. end;
  1244.  
  1245. { Responds to an incoming "Delete" command (with a cm_EditDelete command
  1246.   identifier) by calling Self.Delete. }
  1247.  
  1248. procedure TEdit.CMEditDelete(var Msg: TMessage);
  1249. begin
  1250.   DeleteSelection;
  1251. end;
  1252.  
  1253. { Responds to an incoming "Clear" command (with a cm_EditClear command
  1254.   identifier) by calling Self.Clear. }
  1255.  
  1256. procedure TEdit.CMEditClear(var Msg: TMessage);
  1257. begin
  1258.   Clear;
  1259. end;
  1260.  
  1261. { Responds to an incoming "Undo" command (with a cm_EditUndo command
  1262.   identifier) by calling Self.Undo. }
  1263.  
  1264. procedure TEdit.CMEditUndo(var Msg: TMessage);
  1265. begin
  1266.   Undo;
  1267. end;
  1268.  
  1269. { Returns the number of lines in the associated edit control.  Returns
  1270.   zero if an error occurs or if the edit control contains no text. }
  1271.  
  1272. function TEdit.GetNumLines: Integer;
  1273. begin
  1274.   GetNumLines := SendMessage(HWindow, em_GetLineCount, 0, 0);
  1275. end;
  1276.  
  1277. { Returns the length of the line (whose number is passed) in the
  1278.  associated edit control.  If -1 is passed as the line number, the
  1279.  following applies: returns the length of the line upon which the caret
  1280.  is positioned; if text is selected on the line, returns the line length
  1281.  minus the number of selected characters; if selected text spans more
  1282.  than one line,  returns the length of the lines minus the number of
  1283.  selected characters. }
  1284.  
  1285. function TEdit.GetLineLength(LineNumber: Integer): Integer;
  1286. var
  1287.   StartPos: Integer;
  1288. begin
  1289.   StartPos := -1;
  1290.   if (LineNumber > -1) then
  1291.     StartPos := GetLineIndex(LineNumber);
  1292.   GetLineLength := SendMessage(HWindow, em_LineLength, StartPos, 0);
  1293. end;
  1294.  
  1295. { Retrieves the text of the line of the associated edit control with the
  1296.   passed line number.  Return False if an error occurs or if the text will
  1297.   not fit in the passed buffer. }
  1298.  
  1299. function TEdit.GetLine(ATextString: PChar;
  1300.   StrSize, LineNumber: Integer): Boolean;
  1301. var
  1302.   BytesCopied: Integer;
  1303. begin
  1304.   if (StrSize >= GetLineLength(LineNumber) + 1) then
  1305.   begin
  1306.     PWord(ATextString)^ := StrSize;
  1307.     BytesCopied := SendMessage(HWindow, em_GetLine, LineNumber,
  1308.       LongInt(ATextString));
  1309.     ATextString[BytesCopied] := #0;
  1310.     GetLine := True;
  1311.   end
  1312.   else GetLine := False;
  1313. end;
  1314.  
  1315. { Selects the text in the associated edit control which begins and ends
  1316.   at the passed positions. }
  1317.  
  1318. function TEdit.SetSelection(StartPos, EndPos: Integer): Boolean;
  1319. var
  1320.   LValue: LongRec;
  1321. begin
  1322.   LValue.Lo := StartPos;
  1323.   LValue.Hi := EndPos;
  1324.   SetSelection := SendMessage(HWindow, em_SetSel, 0, Longint(LValue)) <> 0;
  1325. end;
  1326.  
  1327. { Returns, in the passed var parameters, the starting and ending
  1328.   positions of the text selected in the associated edit control. }
  1329.  
  1330. procedure TEdit.GetSelection(var StartPos, EndPos: Integer);
  1331. var
  1332.   RetValue: LongRec;
  1333. begin
  1334.   Longint(RetValue) := SendMessage(HWindow, em_GetSel, 0, 0);
  1335.   StartPos := RetValue.Lo;
  1336.   EndPos := RetValue.Hi;
  1337. end;
  1338.  
  1339. { Returns a Boolean value indicating whether or not the user has changed
  1340.   the text in the associated edit control. }
  1341.  
  1342. function TEdit.IsModified: Boolean;
  1343. begin
  1344.   IsModified := (SendMessage(HWindow, em_GetModify, 0, 0) <> 0);
  1345. end;
  1346.  
  1347. { Performs the actual validation of Self, returning True if Self
  1348.   is valid, and False if not, and setting the focus to Self if
  1349.   invalid.  Reports an error to the user if ReportError is True,
  1350.   otherwise just returns the validity to allow deferred reporting.
  1351.   Local method for use by all other methods which must validate.
  1352.   NOTE that validation is only performed for Edit Controls containing
  1353.   a single line of text. }
  1354.  
  1355. function TEdit.IsValid(ReportError: Boolean): Boolean;
  1356. var
  1357.   S  : string;
  1358.   Sz : array [0..255] of Char;
  1359. begin
  1360.   IsValid := True;  { Unless proven otherwise }
  1361.  
  1362.   if (Validator <> nil) and (GetNumLines <= 1) then
  1363.   begin
  1364.     GetText(Sz, TextLen);
  1365.     S := StrPas(Sz);
  1366.  
  1367.     if ReportError then
  1368.       IsValid := Validator^.Valid(S)
  1369.     else
  1370.       IsValid := Validator^.IsValid(S);
  1371.   end;
  1372. end;
  1373.  
  1374. { Clears the change flag for the associated edit control. }
  1375.  
  1376. procedure TEdit.ClearModify;
  1377. begin
  1378.   SendMessage(HWindow, em_SetModify, 0, 0);
  1379. end;
  1380.  
  1381. { Returns the number of the line of the associated edit control which
  1382.   contains the character whose position is passed.  If the position
  1383.   passed is greater than the position of the last character, the number
  1384.   of the last line is returned. If -1 is passed, the number of the line
  1385.   which contains the first selected character is returned. }
  1386.  
  1387. function TEdit.GetLineFromPos(CharPos: Integer): Integer;
  1388. begin
  1389.   GetLineFromPos := SendMessage(HWindow, em_LineFromChar, CharPos, 0);
  1390. end;
  1391.  
  1392. { Returns the number of characters in the associated edit control that
  1393.   occur before the line whose number is passed.  If -1 is passed, the
  1394.   line number of the line upon which the caret is positioned is used. }
  1395.  
  1396. function TEdit.GetLineIndex(LineNumber: Integer): Integer;
  1397. begin
  1398.   GetLineIndex := SendMessage(HWindow, em_LineIndex, LineNumber, 0);
  1399. end;
  1400.  
  1401. { Scrolls the text of the associated edit control by the specified
  1402.   horizontal and vertical amounts. }
  1403.  
  1404. procedure TEdit.Scroll(HorizontalUnit, VerticalUnit: Integer);
  1405. var
  1406.   LValue: LongRec;
  1407. begin
  1408.   LValue.Lo := VerticalUnit;
  1409.   LValue.Hi := HorizontalUnit;
  1410.   SendMessage(HWindow, em_LineScroll, 0, LongInt(LValue));
  1411. end;
  1412.  
  1413. { Sets the selection of the associated edit control to the passed string.
  1414.   (Does a "paste" type of action without affecting the clipboard). }
  1415.  
  1416. procedure TEdit.Insert(ATextString: PChar);
  1417. begin
  1418.   SendMessage(HWindow, em_ReplaceSel, 0, LongInt(ATextString));
  1419. end;
  1420.  
  1421. { Searchs for and selects the given text in the edit control and
  1422.   returns the offset of the text or -1 if the text is not found.
  1423.   If the StartPos = -1 then it is assumed that the start pos is
  1424.   the end of the current selection.
  1425. }
  1426. function TEdit.Search(StartPos: Integer; AText: PChar;
  1427.   CaseSensitive: Boolean): Integer;
  1428. var
  1429.   SText, Line, Pos: PChar;
  1430.   LineSize, LineLen, NumLines, CurLine, Offset, SBeg: Integer;
  1431. begin
  1432.   Search := -1;
  1433.   if AText[0] = #0 then Exit;
  1434.   Line := nil;
  1435.   LineSize := 0;
  1436.   if StartPos = -1 then GetSelection(SBeg, StartPos);
  1437.   if CaseSensitive then
  1438.     SText := AText else
  1439.     SText := AnsiLower(StrNew(AText));
  1440.   CurLine := GetLineFromPos(StartPos);
  1441.   Offset :=  StartPos - GetLineIndex(CurLine);
  1442.   NumLines := GetNumLines;
  1443.   while CurLine < NumLines do
  1444.   begin
  1445.     LineLen := GetLineLength(CurLine);
  1446.     if LineLen >= LineSize then
  1447.     begin
  1448.       if Line <> nil then FreeMem(Line, LineSize);
  1449.       LineSize := LineLen + 1;
  1450.       Line := MemAlloc(LineSize);
  1451.     end;
  1452.     if Line = nil then Exit;
  1453.     GetLine(Line, LineSize, CurLine);
  1454.     if not CaseSensitive then AnsiLower(Line);
  1455.     Pos := StrPos(@Line[Offset], SText);
  1456.     if Pos <> nil then
  1457.     begin
  1458.       SBeg := GetLineIndex(CurLine) + (Pos - Line);
  1459.       SetSelection(SBeg, SBeg + StrLen(SText));
  1460.       Search := SBeg;
  1461.       CurLine := MaxInt - 1;
  1462.     end;
  1463.     Offset := 0;
  1464.     Inc(CurLine);
  1465.   end;
  1466.   if Line <> nil then FreeMem(Line, LineSize);
  1467.   if not CaseSensitive then StrDispose(SText);
  1468. end;
  1469.  
  1470. { Deletes the selected text in the associated edit control.  Returns
  1471.   False if no text is selected. }
  1472.  
  1473. function TEdit.DeleteSelection: Boolean;
  1474. var
  1475.   StartPos, EndPos: Integer;
  1476. begin
  1477.   DeleteSelection := True;
  1478.   GetSelection(StartPos, EndPos);
  1479.   if StartPos <> EndPos then
  1480.     SendMessage(HWindow, wm_Clear, 0, 0)
  1481.   else DeleteSelection := False;
  1482. end;
  1483.  
  1484. { Deletes the text of the associated edit control between the passed
  1485.   positions.  Returns False if an error occurs. }
  1486.  
  1487. function TEdit.DeleteSubText(StartPos, EndPos: Integer): Boolean;
  1488. begin
  1489.   DeleteSubText :=
  1490.     SetSelection(StartPos, EndPos) and DeleteSelection;
  1491. end;
  1492.  
  1493. { Deletes the text at the passed line number in the associated edit
  1494.   control.  If -1 is passed, deletes the current line.  Returns False
  1495.   if the line passed is out of range (and not -1) or if an error occurs. }
  1496.  
  1497. function TEdit.DeleteLine(LineNumber: Integer): Boolean;
  1498. var
  1499.   FirstPos, LastPos: Integer;
  1500. begin
  1501.   DeleteLine := False;
  1502.   if LineNumber = -1 then LineNumber := GetLineFromPos(GetLineIndex(-1));
  1503.   FirstPos := GetLineIndex(LineNumber);
  1504.   if FirstPos <> -1 then
  1505.   begin
  1506.     LastPos := GetLineIndex(LineNumber + 1);
  1507.     if LastPos = -1 then LastPos := FirstPos + GetLineLength(LineNumber);
  1508.     if (FirstPos = 0) and (FirstPos = LastPos) then
  1509.     begin
  1510.       SetText('');
  1511.       DeleteLine := True;
  1512.     end
  1513.     else
  1514.       DeleteLine := DeleteSubText(FirstPos, LastPos);
  1515.   end;
  1516. end;
  1517.  
  1518. { Retrieves the text of the associated edit control between the passed
  1519.   positions. }
  1520.  
  1521. procedure TEdit.GetSubText(ATextString: PChar;
  1522.   StartPos, EndPos: Integer);
  1523. const
  1524.   cr_lf: PChar = #13#10;
  1525. var
  1526.   StartLine, EndLine, StartChar, EndChar: Integer;
  1527.   TempSize, TempIndex, TempStart, TempEnd: Integer;
  1528.   TempLine, TempLineLength: Integer;
  1529.   OkToContinue: Boolean;
  1530.   PLine: PChar;
  1531. begin
  1532.   if EndPos >= StartPos then
  1533.   begin
  1534.     StartLine := GetLineFromPos(StartPos);
  1535.     EndLine := GetLineFromPos(EndPos);
  1536.     StartChar := StartPos - GetLineIndex(StartLine);
  1537.     EndChar := EndPos - GetLineIndex(EndLine);
  1538.     TempIndex := 0;
  1539.     OkToContinue := True;
  1540.     for TempLine := StartLine to EndLine do
  1541.       if OkToContinue then
  1542.       begin
  1543.     TempLineLength := GetLineLength(TempLine);
  1544.         Inc(TempLineLength, 2); { Count the CR/LF }
  1545.         { Allocate memory for the line, leaving room for the terminating 0 }
  1546.     GetMem(PLine, TempLineLength + 1);
  1547.     if TempLine = StartLine then TempStart := StartChar
  1548.     else TempStart := 0;
  1549.     if TempLine = EndLine then TempEnd := EndChar
  1550.     else TempEnd := TempLineLength;
  1551.     TempSize := TempEnd - TempStart;
  1552.     if GetLine(PLine, TempLineLength + 1, TempLine) then
  1553.     begin
  1554.           StrCat(PLine, cr_lf); { Add back then CR/LF }
  1555.       StrMove(@ATextString[TempIndex], @PLine[TempStart], TempSize);
  1556.       TempIndex := TempIndex + TempSize;
  1557.         end
  1558.     else OkToContinue := False;
  1559.     FreeMem(PLine, TempLineLength + 1);
  1560.       end;
  1561.     ATextString[TempIndex] := #0;
  1562.   end;
  1563. end;
  1564.  
  1565. { Stores data of the TEdit object in the passed TStream. }
  1566. procedure TEdit.Store(var S: TStream);
  1567. begin
  1568.   TStatic.Store(S);
  1569.   S.Put(Validator);
  1570. end;
  1571.  
  1572. { Sets the given Validator object to be Self's validator.  Disposes
  1573.   of the current validator, if any. }
  1574.  
  1575. procedure TEdit.SetValidator(AValid: PValidator);
  1576. begin
  1577.   if Validator <> nil then Validator^.Free;
  1578.   Validator := AValid;
  1579. end;
  1580.  
  1581. { The window belongs to us if any of the window handles has an object
  1582.   attached }
  1583.  
  1584. function IsOurs(Wnd: HWnd): Boolean;
  1585. begin
  1586.   while (Wnd <> 0) and (GetObjectPtr(Wnd) = nil) do
  1587.     Wnd := GetParent(Wnd);
  1588.   IsOurs := Wnd <> 0;
  1589. end;
  1590.  
  1591. { Validates Self whenever the focus is about to be lost.
  1592.   Holds onto the focus if Self is not valid.  Checks first
  1593.   to make sure that the focus is not being taken by either
  1594.   (a) another app, or (b) a Cancel button, or (c) an OK
  1595.   button (in which case CanClose will validate); in each case,
  1596.   we don't want to validate. }
  1597.  
  1598. procedure TEdit.WMKillFocus(var Msg: TMessage);
  1599. var
  1600.   BtnId : Integer;
  1601. begin
  1602.   if ProcessFocus and IsOurs(Msg.WParam) then
  1603.   begin
  1604.     BtnId := GetDlgCtrlID(Msg.WParam);
  1605.  
  1606.     { Note that we do not allow IsValid to post the message
  1607.       box, since the change of focus resulting from that message
  1608.       will interfere with the change we are in the process of
  1609.       completing.  Instead, post a message to the Parent informing
  1610.       it of the validation failure, and providing it with a handle
  1611.       to Self. }
  1612.  
  1613.     if (BtnId <> id_Cancel) and (BtnId <> id_Ok) and not IsValid(False) then
  1614.     begin
  1615.       DefWndProc(Msg);
  1616.       ProcessFocus := False;
  1617.       PostMessage(Parent^.HWindow, wm_PostInvalid, HWindow, 0);
  1618.       Msg.Result := 0;
  1619.       Exit;
  1620.     end
  1621.   end;
  1622.   DefWndProc(Msg);
  1623. end;
  1624.  
  1625. { Validates Self whenever a character is entered.  Allows
  1626.   the character entry to be processed normally, then validates
  1627.   the result and restores Self's text to its original state
  1628.   if there is an incorrect entry.
  1629.  
  1630.   By default, the SupressFill parameter of the IsValidInput
  1631.   method call to the Validator is set to False, so that it
  1632.   is free to modify the string, if it is so configured. }
  1633.  
  1634. procedure TEdit.WMChar(var Msg: TMessage);
  1635. var
  1636.   S         : string;
  1637.   Sz, OldSz : array [0..255] of Char;
  1638.   StartPos, EndPos: Integer;                            
  1639.   WasAppending: Boolean;
  1640. begin
  1641.   if (Validator <> nil) and (GetNumLines <= 1) and
  1642.     (Msg.wParam <> vk_Back) then
  1643.   begin
  1644.     GetText(OldSz, TextLen);
  1645.     GetSelection(StartPos, EndPos);
  1646.     WasAppending := EndPos = StrLen(OldSz);
  1647.  
  1648.     DefWndProc(Msg);      { Process the new char ... }
  1649.  
  1650.     GetText(Sz, TextLen);
  1651.     S := StrPas(Sz);      { Validator expects a Pascal string }
  1652.  
  1653.     { Run the result of the edit through the validator.  If incorrect,
  1654.       then restore the original text.  Otherwise, set the (possibly)
  1655.       modified result of the validation back into the edit control,
  1656.       so the results of the auto-fill (if any) can be viewed.
  1657.     }
  1658.     GetSelection(StartPos, EndPos);
  1659.     if (Validator^.Options and voOnAppend = 0) or
  1660.       (WasAppending and (EndPos = StrLen(Sz))) then
  1661.     begin
  1662.       if not Validator^.IsValidInput(S, False) then
  1663.         SetText(OldSz)
  1664.       else
  1665.       begin
  1666.         StrPCopy(Sz, S);
  1667.         SetText(Sz);
  1668.         if (StartPos >= StrLen(OldSz)) and (StrLen(Sz) > StrLen(OldSz)) then
  1669.           StartPos := StrLen(Sz);
  1670.         if (EndPos >= StrLen(OldSz)) and (StrLen(Sz) > StrLen(OldSz)) then
  1671.           EndPos := StrLen(Sz);
  1672.       end;
  1673.       SetSelection(StartPos, EndPos);
  1674.     end
  1675.     else
  1676.     begin
  1677.       if EndPos = StrLen(Sz) then
  1678.         if not Validator^.IsValidInput(S, False) then
  1679.           Validator^.Error;
  1680.     end;
  1681.   end
  1682.   else
  1683.     DefWndProc(Msg);
  1684. end;
  1685.  
  1686. { Responds to the GetDlgCode query according to the
  1687.   current state of the control.  If the edit control
  1688.   contains valid input, then TABs are allowed for
  1689.   changing focus.  Otherwise, requests that TABs be
  1690.   sent to Self, where we will generate the Invalid
  1691.   message (See WMKeyDown below). }
  1692.  
  1693. procedure TEdit.WMGetDlgCode(var Msg: TMessage);
  1694. begin
  1695.   DefWndProc(Msg);
  1696.   if not IsValid(False) then
  1697.     Msg.Result := Msg.Result or dlgc_WantTab;
  1698. end;
  1699.  
  1700. { If the TAB key is sent to the Edit Control, check
  1701.   the validity before allowing the focus to change.
  1702.   The control will only get a TAB if WMGetDlgCode (above)
  1703.   allows it, which is done when the control contains
  1704.   invalid input (we re-validate here just for completeness,
  1705.   in case descendants redefine any of this behavior).
  1706.  
  1707.   We need to validate on TAB focus-changes because there
  1708.   is a case not handled by WMKillFocus: when focus is
  1709.   lost to an OK or CANCEL button by tabbing. }
  1710.  
  1711. procedure TEdit.WMKeyDown(var Msg: TMessage);
  1712. var
  1713.   WasAppending: Boolean;
  1714.   StartSel, EndSel: Integer;
  1715.   Sz: array[0..255] of Char;
  1716.   S: String;
  1717. begin
  1718.   if (Msg.WParam = vk_Tab) then
  1719.     if not IsValid(True) then
  1720.       Exit;
  1721.   if (Validator <> nil) and (Validator^.Options and voOnAppend <> 0)
  1722.     and (GetNumLines <= 1) then
  1723.   begin
  1724.     GetSelection(StartSel, EndSel);
  1725.     GetText(Sz, SizeOf(Sz));
  1726.     WasAppending := EndSel = StrLen(Sz);
  1727.     DefWndProc(Msg);
  1728.     if not WasAppending then
  1729.     begin
  1730.       GetSelection(StartSel, EndSel);
  1731.       GetText(Sz, SizeOf(Sz));
  1732.       S := StrPas(Sz);
  1733.       if (EndSel = StrLen(Sz)) and
  1734.           not Validator^.IsValidInput(S, False) then
  1735.         Validator^.Error;
  1736.     end;
  1737.   end
  1738.   else    
  1739.     DefWndProc(Msg);     { Else just ignore the TAB }
  1740. end;
  1741.  
  1742. { Transfers state information for TEdit controls. The TransferFlag passed
  1743.   specifies whether data is to be read from or written to the passed
  1744.   buffer, or whether the data element size is simply to be returned. The
  1745.   return value is the size (in bytes) of the transfer data.  TEdits trans-
  1746.   fer their data in one of two ways: if the TEdit does not own a Validator,
  1747.   it simply uses the inherited Transfer to transfer the edit text in the
  1748.   usual fashion.  If a Validator exists, however, it is used to transfer
  1749.   the data in the actual converted form corresponding to the Validator.
  1750.   This allows the application to treat the Edit control as, for example,
  1751.   an integer editor. }
  1752.  
  1753. function TEdit.Transfer(DataPtr: Pointer; TransferFlag: Word): Word;
  1754. var
  1755.   VTrans: TVTransfer;
  1756.   Sz    : PChar;
  1757.   S     : string;
  1758.   Trans : Word;
  1759. begin
  1760.   if (Validator <> nil) and (GetNumLines <= 1) then
  1761.   begin
  1762.     if TransferFlag = tf_GetData then
  1763.       VTrans := vtGetData   {GetText(DataPtr, TextLen)}
  1764.     else if TransferFlag = tf_SetData then
  1765.       VTrans := vtSetData   {SetText(DataPtr);}
  1766.     else
  1767.       VTrans := vtDataSize;
  1768.  
  1769.     GetMem(Sz, TextLen);
  1770.     GetText(Sz, TextLen);
  1771.     S := StrPas(Sz);
  1772.  
  1773.     Trans := Validator^.Transfer(S, DataPtr, VTrans);
  1774.  
  1775.     { If the validator does not implement a Transfer function, it will
  1776.       report a transfer amount of zero bytes.  In that case, we revert
  1777.       to the standard transfer behavior.  Otherwise, complete the transfer
  1778.       by setting the result of a SetData transfer back into the control. }
  1779.  
  1780.     if Trans = 0 then
  1781.       Trans := inherited Transfer(DataPtr, TransferFlag)
  1782.     else
  1783.       if VTrans = vtSetData then
  1784.       begin
  1785.         if Length(S) > TextLen-1 then
  1786.         begin
  1787.           FreeMem(Sz, TextLen);
  1788.           GetMem(Sz, Length(S)+1);
  1789.         end;
  1790.         StrPCopy(Sz, S);
  1791.         SetText(Sz);
  1792.       end;
  1793.     Transfer := Trans;
  1794.     FreeMem(Sz, TextLen);
  1795.   end
  1796.   else
  1797.     Transfer := inherited Transfer(DataPtr, TransferFlag);
  1798. end;
  1799.  
  1800. { Limits the amount of text that an edit control can have to the
  1801.   value of TextLen }
  1802.  
  1803. procedure TEdit.SetupWindow;
  1804. begin
  1805.   TStatic.SetupWindow;
  1806.   if TextLen <> 0 then SendMessage(HWindow, em_LimitText, TextLen - 1, 0);
  1807. end;
  1808.  
  1809. { TListBox }
  1810.  
  1811. { Constructor for an instance of TListBox.  Initializes its data fields
  1812.   using parameters passed and default values.  By default, an MS-Windows
  1813.   listbox associated with the TListBox will: be visible upon creation;
  1814.   have a border and a vertical scrollbar; maintain entries in alphabetical
  1815.   order; and notify its parent when a selection is made. }
  1816.  
  1817. constructor TListBox.Init(AParent: PWindowsObject; AnId: Integer;
  1818.   X, Y, W, H: Integer);
  1819. begin
  1820.   TControl.Init(AParent, AnId, nil, X, Y, W, H);
  1821.   Attr.Style := Attr.Style or lbs_Standard;
  1822. end;
  1823.  
  1824. { Returns the name of MS-Windows window class for a TListBox. }
  1825.  
  1826. function TListBox.GetClassName: PChar;
  1827. begin
  1828.   GetClassName := 'Listbox';
  1829. end;
  1830.  
  1831. { Transfers state information for a TListBox. The TransferFlag passed
  1832.   specifies whether data is to be read from or written to the passed
  1833.   buffer, or whether the data element size is simply to be returned.  The
  1834.   return value is the size (in bytes) of the transfer data. }
  1835.  
  1836. function TListBox.Transfer(DataPtr: Pointer; TransferFlag: Word): Word;
  1837. type
  1838.   PSingleRec = ^TSingleRec;
  1839.   TSingleRec = record
  1840.     Strings: PStrCollection;
  1841.     Selection: Integer;
  1842.   end;
  1843.   PMultiRec = ^TMultiRec;
  1844.   TMultiRec = record
  1845.     Strings: PStrCollection;
  1846.     Selections: PMultiSelRec;
  1847.   end;
  1848. var
  1849.   I: Integer;
  1850.   Style: LongInt;
  1851.  
  1852.   procedure DoAdd(P: PChar); far;
  1853.   begin
  1854.     AddString(P);
  1855.   end;
  1856.  
  1857. begin
  1858.   Style := GetWindowLong(HWindow, gwl_Style);
  1859.   if TransferFlag = tf_GetData then
  1860.     if Style and lbs_MultipleSel <> lbs_MultipleSel then
  1861.       with PSingleRec(DataPtr)^ do
  1862.     Selection := Integer(SendMessage(HWindow, lb_GetCurSel, 0, 0))
  1863.     else
  1864.       with PMultiRec(DataPtr)^ do
  1865.       begin
  1866.     FreeMultiSel(Selections);
  1867.     I := Integer(SendMessage(HWindow, lb_GetSelCount, 0, 0));
  1868.     Selections := AllocMultiSel(I);
  1869.     if Selections <> nil then
  1870.       SendMessage(HWindow, lb_GetSelItems, I,
  1871.         LongInt(@Selections^.Selections));
  1872.       end
  1873.   else if TransferFlag = tf_SetData then
  1874.     if Style and lbs_MultipleSel <> lbs_MultipleSel then
  1875.       with PSingleRec(DataPtr)^ do
  1876.       begin
  1877.     SendMessage(HWindow, lb_ResetContent, 0, 0);
  1878.     Strings^.ForEach(@DoAdd);
  1879.     SendMessage(HWindow, lb_SetCurSel, Selection, 0);
  1880.       end
  1881.     else
  1882.       with PMultiRec(DataPtr)^ do
  1883.       begin
  1884.     SendMessage(HWindow, lb_ResetContent, 0, 0);
  1885.     Strings^.ForEach(@DoAdd);
  1886.     SendMessage(HWindow, lb_SetSel, 0, -1); { Unselect all }
  1887.     if Selections <> nil then
  1888.       with Selections^ do
  1889.         for I := 0 to Count - 1  do
  1890.           SendMessage(HWindow, lb_SetSel, 1, Selections[I]);
  1891.       end;
  1892.   if Style and lbs_MultipleSel <> lbs_MultipleSel then
  1893.     Transfer := SizeOf(TSingleRec)
  1894.   else Transfer := SizeOf(TMultiRec);
  1895. end;
  1896.  
  1897. { Adds a string to an associated listbox.  Returns index of the string
  1898.   in the list (the first entry is at index 0).  A negative value is
  1899.   returned if an error occurs. }
  1900.  
  1901. function TListBox.AddString(AString: PChar): Integer;
  1902. begin
  1903.   AddString := Integer(SendMessage(HWindow, GetMsgID(mn_AddString),
  1904.     0, LongInt(AString)));
  1905. end;
  1906.  
  1907. { Inserts a string in the associated listbox at the passed index,
  1908.   returning the index of the string in the list.  A negative value is
  1909.   returned if an error occurs. }
  1910.  
  1911. function TListBox.InsertString(AString: PChar; Index: Integer): Integer;
  1912. begin
  1913.   InsertString := Integer(SendMessage(HWindow, GetMsgID(mn_InsertString),
  1914.     Index, LongInt(AString)));
  1915. end;
  1916.  
  1917. { Deletes the string at the passed index in the associated listbox. 
  1918.   Returns a count of the entries remaining in the list.  A negative value
  1919.   is returned if an error occurs. }
  1920.  
  1921. function TListBox.DeleteString(Index: Integer): Integer;
  1922. begin
  1923.   DeleteString := Integer(SendMessage(HWindow, GetMsgID(mn_DeleteString), 
  1924.     Index, 0));
  1925. end;
  1926.  
  1927. { Clears all the entries in the associated listbox. }
  1928.  
  1929. procedure TListBox.ClearList;
  1930. begin
  1931.   SendMessage(HWindow, GetMsgID(mn_ResetContent), 0, 0);
  1932. end;
  1933.  
  1934. { Returns the number of entries in the associated listbox. A negative
  1935.   value is returned if an error occurs. }
  1936.  
  1937. function TListBox.GetCount: Integer;
  1938. begin
  1939.   GetCount := Integer(SendMessage(HWindow, GetMsgID(mn_GetCount), 0, 0));
  1940. end; 
  1941.  
  1942. { Retrieves the contents of the string at the passed index of the
  1943.   associated listbox, returning the length of the string (in bytes) as
  1944.   the value of the call. A negative value is returned if the passed
  1945.   index is not valid. }
  1946.  
  1947. function TListBox.GetString(AString: PChar; Index: Integer): Integer;
  1948. begin
  1949.   GetString := Integer(SendMessage(HWindow, GetMsgID(mn_GetText), Index, 
  1950.     LongInt(AString)));
  1951. end; 
  1952.  
  1953. { Returns the length of the string at the passed index in the associated
  1954.   listbox.  Note that the strings in the listbox are stored as
  1955.   null-terminated arrays of characters rather than the traditional Pascal
  1956.   type of string. The length returned does not include the null 
  1957.   terminator.  A negative value is returned if an error occurs. }
  1958.  
  1959. function TListBox.GetStringLen(Index: Integer): Integer;
  1960. begin
  1961.   GetStringLen := Integer(SendMessage(HWindow, GetMsgID(mn_GetTextLen),
  1962.     Index, 0));
  1963. end; 
  1964.  
  1965. { Retrieves the text of the string which is selected in the associated
  1966.   listbox.  Returns the number of characters copied.  -1 is returned if
  1967.   no string is selected.  Since the Windows function is not passed a
  1968.   size parameter, we have to allocate a string to hold the largest
  1969.   string (gotten from a query), and copy a part of it. }
  1970.  
  1971. function TListBox.GetSelString(AString: PChar; MaxChars: Integer): Integer;
  1972. var
  1973.   Index: Integer;
  1974.   Length: Integer;
  1975.   TempString: PChar;
  1976. begin
  1977.   GetSelString := -1;
  1978.   Index := GetSelIndex;
  1979.   Length := GetStringLen(Index);
  1980.   if (Index > -1) then
  1981.     if (MaxChars >= Length) then
  1982.       GetSelString := GetString(AString, Index)
  1983.     else
  1984.     begin
  1985.       TempString := MemAlloc(Length+1);
  1986.       if TempString <> nil then
  1987.       begin
  1988.         GetString(TempString, Index);
  1989.         StrLCopy(AString, TempString, MaxChars);
  1990.         FreeMem(TempString, Length+1);
  1991.         GetSelString := MaxChars;
  1992.       end;
  1993.     end;
  1994. end;
  1995.  
  1996. { Selects the first string in the associated listbox following the passed
  1997.   index which begins with the passed string.  Searches for a match
  1998.   beginning at the passed Index.  If a match is not found after the last
  1999.   string has been compared, the search continues from the beginning of the
  2000.   list until a match is found or until the list has been completely
  2001.   traversed.  Searches from beginning of list when -1 is passed as the
  2002.   index.  Returns the index of the selected string.  A negative value is
  2003.   returned if an error occurs. }
  2004.  
  2005. function TListBox.SetSelString(AString: PChar; Index: Integer): Integer;
  2006. begin
  2007.   SetSelString := Integer(SendMessage(HWindow, GetMsgID(mn_SelectString), 
  2008.     Word(Index), LongInt(AString)));
  2009. end; 
  2010.  
  2011. { Returns the index of the selected string in the associated listbox.  A
  2012.   negative value is returned if no string is selected. }
  2013.  
  2014. function TListBox.GetSelIndex: Integer;
  2015. begin
  2016.   GetSelIndex := Integer(SendMessage(HWindow, GetMsgID(mn_GetCurSel), 
  2017.     0, 0));
  2018. end; 
  2019.  
  2020. { Selects the string at passed index in the associated listbox and forces
  2021.   the string into view.  Clears selection when -1 is passed as the index.
  2022.   A negative value is returned if an error occurs. }
  2023.  
  2024. function TListBox.SetSelIndex(Index: Integer): Integer;
  2025. begin
  2026.   SetSelIndex := Integer(SendMessage(HWindow, GetMsgID(mn_SetCurSel), 
  2027.     Index, 0));
  2028. end;
  2029.  
  2030. { Returns the appropriate MS-Windows message Integer identifier for the
  2031.   function identified by the passed MsgName string.  Allows instances of
  2032.   TComboBox to inherit many TListBox methods. }
  2033.  
  2034. function TListBox.GetMsgID(AMsg: TMsgName): Word;
  2035. const
  2036.   MsgXlat: array[TMsgName] of Word =
  2037.     (lb_AddString,    lb_InsertString, lb_DeleteString,
  2038.      lb_ResetContent, lb_GetCount,     lb_GetText,
  2039.      lb_GetTextLen,   lb_SelectString, lb_SetCurSel, 
  2040.      lb_GetCurSel);
  2041. begin
  2042.   GetMsgId := MsgXLat[AMsg];
  2043. end;
  2044.  
  2045. { TComboBox }
  2046.  
  2047. { Constructor for a TCheckBox object.  Initializes its data fields using
  2048.   parameters passed and default values.  By default, an MS-Windows combobox
  2049.   associated with the TComboBox will have a vertical scrollbar and will
  2050.   maintain its entries in alphabetical order. }
  2051.  
  2052. constructor TComboBox.Init(AParent: PWindowsObject; AnID: Integer;
  2053.   X, Y, W, H: Integer; AStyle, ATextLen: Word);
  2054. begin
  2055.   TListBox.Init(AParent, AnID, X, Y, W, H);
  2056.   TextLen := ATextLen;
  2057.   Attr.Style :=
  2058.     ws_Child or ws_Visible or ws_Group or ws_TabStop or cbs_Sort
  2059.     or cbs_AutoHScroll or ws_VScroll or AStyle;
  2060. end;
  2061.  
  2062. constructor TComboBox.InitResource(AParent: PWindowsObject;
  2063.   ResourceID: Integer; ATextLen: Word);
  2064. begin
  2065.   TListBox.InitResource(AParent, ResourceID);
  2066.   TextLen := ATextLen;
  2067. end;
  2068.  
  2069. { Constructor for a TComboBox object.  Initializes the object with data
  2070.   from the passed TStream. }
  2071.  
  2072. constructor TComboBox.Load(var S: TStream);
  2073. begin
  2074.   TListBox.Load(S);
  2075.   S.Read(TextLen, SizeOf(TextLen));
  2076. end;
  2077.  
  2078. { Stores data of the TComboBox object in the passed TStream. }
  2079.  
  2080. procedure TComboBox.Store(var S: TStream);
  2081. begin
  2082.   TListBox.Store(S);
  2083.   S.Write(TextLen, SizeOf(TextLen));
  2084. end;
  2085.  
  2086. { Returns the name of MS-Windows window class for a TComboBox. }
  2087.  
  2088. function TComboBox.GetClassName: PChar;
  2089. begin
  2090.   GetClassName := 'Combobox';
  2091. end;
  2092.  
  2093. { Shows the list of an associated drop-down combobox. }
  2094.  
  2095. procedure TComboBox.ShowList;
  2096. begin
  2097.   if GetWindowLong(HWindow, gwl_Style) and cbs_DropDown = cbs_DropDown then
  2098.     SendMessage(HWindow, cb_ShowDropDown, 1, 0);
  2099. end;
  2100.  
  2101. { Hides the list of an associated drop-down combobox. }
  2102.  
  2103. procedure TComboBox.HideList;
  2104. begin
  2105.   if GetWindowLong(HWindow, gwl_Style) and cbs_DropDown = cbs_DropDown then
  2106.     SendMessage(HWindow, cb_ShowDropDown, 0, 0);
  2107. end;
  2108.  
  2109. function TComboBox.Transfer(DataPtr: Pointer; TransferFlag: Word): Word;
  2110. type
  2111.   PTranRec = ^TTranRec;
  2112.   TTranRec = record
  2113.     Strings: PStrCollection;
  2114.     Selection: array[0..32767] of Char;
  2115.   end;
  2116.  
  2117.   procedure DoAdd(P: PChar); far;
  2118.   begin
  2119.     AddString(P);
  2120.   end;
  2121.  
  2122. begin
  2123.   if TransferFlag = tf_GetData then
  2124.     with PTranRec(DataPtr)^ do
  2125.       GetWindowText(HWindow, Selection, TextLen)
  2126.   else if TransferFlag = tf_SetData then
  2127.     with PTranRec(DataPtr)^ do
  2128.     begin
  2129.       SendMessage(HWindow, cb_ResetContent, 0, 0);
  2130.       Strings^.ForEach(@DoAdd);
  2131.       SetSelString(Selection, -1);
  2132.       SetWindowText(HWindow, Selection);
  2133.     end;
  2134.   Transfer := SizeOf(Pointer) + TextLen;
  2135. end;
  2136.  
  2137. { Returns the appropriate Windows message Integer identifier for the
  2138.   function identified by the passed MsgName string. Allows instances
  2139.   of TComboBox to inherit many TListBox methods. }
  2140.  
  2141. function TComboBox.GetMsgID(AMsg: TMsgName): Word;
  2142. const
  2143.   MsgXlat: array[TMsgName] of Word =
  2144.     (cb_AddString,    cb_InsertString, cb_DeleteString,
  2145.      cb_ResetContent, cb_GetCount,     cb_GetLBText,
  2146.      cb_GetLBTextLen, cb_SelectString, cb_SetCurSel,
  2147.      cb_GetCurSel);
  2148. begin
  2149.   GetMsgId := MsgXLat[AMsg];
  2150. end;
  2151.  
  2152. procedure TComboBox.SetupWindow;
  2153. begin
  2154.   TListBox.SetupWindow;
  2155.   if TextLen <> 0 then SendMessage(HWindow, cb_LimitText, TextLen - 1, 0);
  2156. end;
  2157.  
  2158. { Returns the lenght of the associated edit control's text }
  2159.  
  2160. function TComboBox.GetTextLen: Integer;
  2161. begin
  2162.   GetTextLen := GetWindowTextLength(HWindow);
  2163. end;
  2164.  
  2165. { Fills the supplied string with the text of the associated edit
  2166.   control. Returns the number of characters copied. }
  2167.  
  2168. function TComboBox.GetText(Str: PChar; MaxChars: Integer): Integer;
  2169. begin
  2170.   GetText := GetWindowText(HWindow, Str, MaxChars);
  2171. end;
  2172.  
  2173. { Sets and selects the contents of the associated edit control to the
  2174.   supplied string. }
  2175.  
  2176. procedure TComboBox.SetText(Str: PChar);
  2177. begin
  2178.   if SetSelString(Str, -1) < 0 then
  2179.   begin
  2180.     SetWindowText(HWindow, Str);
  2181.     SetEditSel(0, StrLen(Str));
  2182.   end;
  2183. end;
  2184.  
  2185. { Selects characters in the edit control of the combo box which
  2186.   are between StartPos and EndPos. Returns cm_Err if the combo
  2187.   box does not have an edit control. }
  2188.  
  2189. function TComboBox.SetEditSel(StartPos, EndPos: Integer): Integer;
  2190. begin
  2191.   SetEditSel := Integer(SendMessage(HWindow, cb_SetEditSel, 0,
  2192.     MakeLong(StartPos, EndPos)));
  2193. end;
  2194.  
  2195. { Returns, in the supplied var parameters, the starting and ending
  2196.   positions of the text selected in the associated edit control.
  2197.   Returns False if the combo box has no edit control }
  2198.  
  2199. function TComboBox.GetEditSel(var StartPos, EndPos: Integer): Boolean;
  2200. var
  2201.   RetValue: LongInt;
  2202. begin
  2203.   RetValue := SendMessage(HWindow, cb_GetEditSel, 0, 0);
  2204.   StartPos := LoWord(RetValue);
  2205.   EndPos := HiWord(RetValue);
  2206.   GetEditSel := RetValue <> cb_Err;
  2207. end;
  2208.  
  2209. { Clears the text of the associated edit control }
  2210.  
  2211. procedure TComboBox.Clear;
  2212. begin
  2213.   SetText('');
  2214. end;
  2215.  
  2216. { TScrollBar }
  2217.  
  2218. { Constructor for a TScrollBar object.  Initializes the object with
  2219.   data from the passed TStream. }
  2220.  
  2221. constructor TScrollBar.Load(var S: TStream);
  2222. begin
  2223.   TControl.Load(S);
  2224.   S.Read(LineMagnitude, SizeOf(LineMagnitude));
  2225.   S.Read(PageMagnitude, SizeOf(PageMagnitude));
  2226. end;
  2227.  
  2228. { Stores data of the TScrollBar object in the passed TStream. }
  2229.  
  2230. procedure TScrollBar.Store(var S: TStream);
  2231. begin
  2232.   TControl.Store(S);
  2233.   S.Write(LineMagnitude, SizeOf(LineMagnitude));
  2234.   S.Write(PageMagnitude, SizeOf(PageMagnitude));
  2235. end;
  2236.  
  2237. { Constructor for a TScrollBar object.  Initializes its data fields
  2238.   (including its creation attributes) using parameters passed and
  2239.   default values. If the size attribute (H for horizontal scrollbars,
  2240.   W for vertical) is zero, the attribute is set to the appropriate
  2241.   system metric. }
  2242.  
  2243. constructor TScrollBar.Init(AParent: PWindowsObject; AnID: Integer;
  2244.   X, Y, W, H: Integer; IsHScrollBar: Boolean);
  2245. begin
  2246.   TControl.Init(AParent, AnID, nil, X, Y, W, H);
  2247.   LineMagnitude := 1;
  2248.   PageMagnitude := 10;
  2249.   if IsHScrollBar then
  2250.   begin
  2251.     Attr.Style := Attr.Style or sbs_Horz;
  2252.     if Attr.H = 0 then Attr.H := GetSystemMetrics(sm_CYHScroll);
  2253.   end
  2254.   else
  2255.   begin
  2256.     Attr.Style := Attr.Style or sbs_Vert;
  2257.     if Attr.W = 0 then Attr.W := GetSystemMetrics(sm_CXVScroll);
  2258.   end;
  2259. end;
  2260.  
  2261. constructor TScrollBar.InitResource(AParent: PWindowsObject; ResourceID: Word);
  2262. begin
  2263.   TControl.InitResource(AParent, ResourceID);
  2264.   LineMagnitude := 1;
  2265.   PageMagnitude := 10;
  2266. end;
  2267.  
  2268. { Returns the name of MS-Windows window class for a TScrollBar. }
  2269.  
  2270. function TScrollBar.GetClassName: PChar;
  2271. begin
  2272.   GetClassName := 'Scrollbar';
  2273. end;
  2274.  
  2275. { Transfers state information for a TScrollbar.  The TransferFlag passed
  2276.   specifies whether data is to be read from or written to the passed
  2277.   buffer, or whether the data element size is simply to be returned.  The
  2278.   return value is the size (in bytes) of the transfer data. }
  2279.  
  2280. function TScrollbar.Transfer(DataPtr: Pointer; TransferFlag: Word): Word;
  2281. var
  2282.   LoVal, HiVal, Pos: Integer;
  2283.   NewPtr: Pointer;
  2284. begin
  2285.   NewPtr := DataPtr;
  2286.   if TransferFlag = tf_GetData then
  2287.   begin
  2288.     GetRange(LoVal, HiVal);
  2289.     Pos := GetPosition;
  2290.     Move(LoVal, NewPtr^, SizeOf(Integer));
  2291.     Inc(LongInt(NewPtr), SizeOf(Integer));
  2292.     Move(HiVal, NewPtr^, SizeOf(Integer));
  2293.     Inc(LongInt(NewPtr), SizeOf(Integer));
  2294.     Move(Pos,   NewPtr^, SizeOf(Integer));
  2295.   end
  2296.   else if TransferFlag = tf_SetData then
  2297.   begin
  2298.     LoVal := Integer(NewPtr^);
  2299.     Inc(LongInt(NewPtr), SizeOf(Integer));
  2300.     HiVal := Integer(NewPtr^);
  2301.     Inc(LongInt(NewPtr), SizeOf(Integer));
  2302.     Pos := Integer(NewPtr^);
  2303.     SetRange(LoVal, HiVal);
  2304.     SetPosition(Pos);
  2305.   end;
  2306.   Transfer := (SizeOf(Integer) * 3);
  2307. end;
  2308.  
  2309. { Sets up an associated scrollbar by setting its range to 0..100. }
  2310.  
  2311. procedure TScrollBar.SetupWindow;
  2312. begin
  2313.   TControl.SetupWindow;
  2314.   SetRange(0, 100);
  2315. end; 
  2316.  
  2317. { Retrieves the range of values that the associated scrollbar can
  2318.   return. }
  2319.  
  2320. procedure TScrollBar.GetRange(var LoVal, HiVal: Integer);
  2321. begin
  2322.   GetScrollRange(HWindow, sb_Ctl, LoVal, HiVal);
  2323. end;
  2324.  
  2325. { Returns the position of the thumb of the associated scrollbar. }
  2326.  
  2327. function TScrollBar.GetPosition: Integer;
  2328. begin
  2329.   GetPosition := GetScrollPos(HWindow, sb_Ctl);
  2330. end;
  2331.   
  2332. { Sets the range of values that the associated scrollbar can return. }
  2333.  
  2334. procedure TScrollBar.SetRange(LoVal, HiVal: Integer);
  2335. begin
  2336.   SetScrollRange(HWindow, sb_Ctl, LoVal, HiVal, False);
  2337. end;
  2338.  
  2339. { Sets the position of the thumb of the associated scrollbar. }
  2340.  
  2341. procedure TScrollBar.SetPosition(ThumbPos: Integer);
  2342. var
  2343.   LoVal, HiVal: Integer;
  2344. begin
  2345.   GetRange(LoVal, HiVal);
  2346.   if ThumbPos > HiVal then ThumbPos := HiVal
  2347.   else if ThumbPos < LoVal then ThumbPos := LoVal;
  2348.   if ThumbPos <> GetPosition then
  2349.     SetScrollPos(HWindow, sb_Ctl, ThumbPos, True);
  2350. end;
  2351.  
  2352. { Changes the position (by Delta) of the thumb of the associated
  2353.   scrollbar.  Returns the new position. }
  2354.  
  2355. function TScrollBar.DeltaPos(Delta: Integer): Integer;
  2356. begin
  2357.   if Delta <> 0 then SetPosition(GetPosition + Delta);
  2358.   DeltaPos := GetPosition;
  2359. end;
  2360.  
  2361. { Responds to an sb_LineUp notification message which the associated
  2362.   scrollbar sent to its parent.  Changes the position (by LineMagnitude)
  2363.   of the thumb of the associated scrollbar. }
  2364.  
  2365. procedure TScrollBar.SBLineUp(var Msg: TMessage);
  2366. begin
  2367.   DeltaPos(0 - LineMagnitude);
  2368.   DefNotificationProc(Msg);
  2369. end;
  2370.  
  2371. { Responds to an sb_LineDown notification message which the associated
  2372.   scrollbar sent to its parent.  Changes the position (by LineMagnitude)
  2373.   of the thumb. }
  2374.  
  2375. procedure TScrollBar.SBLineDown(var Msg: TMessage);
  2376. begin
  2377.   DeltaPos(LineMagnitude);
  2378.   DefNotificationProc(Msg);
  2379. end;
  2380.  
  2381. { Responds to an sb_PageUp notification message which the associated
  2382.   scrollbar sent to its parent.  Changes the position (by PageMagnitude)
  2383.   of the thumb. }
  2384.  
  2385. procedure TScrollBar.SBPageUp(var Msg: TMessage);
  2386. begin
  2387.   DeltaPos(0 - PageMagnitude);
  2388.   DefNotificationProc(Msg);
  2389. end;
  2390.  
  2391. { Responds to an sb_PageDown notification message which the associated
  2392.   scrollbar sent to its parent.  Changes the position (by PageMagnitude)
  2393.   of the thumb. }
  2394.  
  2395. procedure TScrollBar.SBPageDown(var Msg: TMessage);
  2396. begin
  2397.   DeltaPos(PageMagnitude);
  2398.   DefNotificationProc(Msg);
  2399. end;
  2400.  
  2401. { Responds to an sb_ThumbPosition notification message which the
  2402.   associated scrollbar sent to its parent.  Moves the thumb of the 
  2403.   scrollbar to the new position. }
  2404.  
  2405. procedure TScrollBar.SBThumbPosition(var Msg: TMessage);
  2406. begin
  2407.   SetPosition(Msg.LParamLo);
  2408.   DefNotificationProc(Msg);
  2409. end;
  2410.  
  2411. { Responds to an sb_ThumbTrack notification message which the associated
  2412.   scrollbar sent to its parent.  Draws the thumb in the current position
  2413.   on the track. }
  2414.  
  2415. procedure TScrollBar.SBThumbTrack(var Msg: TMessage);
  2416. begin
  2417.   SetPosition(Msg.LParamLo);
  2418.   DefNotificationProc(Msg);
  2419. end;
  2420.  
  2421. { Responds to an sb_Top notification message which the associated
  2422.   scrollbar sent to its parent.  Moves the thumb to the top of the
  2423.   scrollbar. }
  2424.  
  2425. procedure TScrollBar.SBTop(var Msg: TMessage);
  2426. var
  2427.   Lo, Hi: Integer;
  2428. begin
  2429.   GetRange(Lo, Hi);
  2430.   SetPosition(Lo);
  2431.   DefNotificationProc(Msg);
  2432. end;
  2433.  
  2434. { Responds to an sb_Bottom notification message which the associated
  2435.   scrollbar sent to its parent.  Moves the thumb to the bottom of the
  2436.   scrollbar. }
  2437.  
  2438. procedure TScrollBar.SBBottom(var Msg: TMessage);
  2439. var
  2440.   Lo, Hi: Integer;
  2441. begin
  2442.   GetRange(Lo, Hi);
  2443.   SetPosition(Hi);
  2444.   DefNotificationProc(Msg);
  2445. end;
  2446.  
  2447. { ListBox multiple selection transfer records }
  2448.  
  2449. function AllocMultiSel(Size: Integer): PMultiSelRec;
  2450. var
  2451.   P: PMultiSelRec;
  2452. begin
  2453.   AllocMultiSel := nil;
  2454.   if Size <> 0 then
  2455.   begin
  2456.     P := MemAlloc( (Size + 1) * 2);
  2457.     if P <> nil then
  2458.     begin
  2459.       P^.Count := Size;
  2460.       AllocMultiSel := P;
  2461.     end;
  2462.   end;
  2463. end;
  2464.  
  2465. procedure FreeMultiSel(P: PMultiSelRec);
  2466. begin
  2467.   if P <> nil then FreeMem(P, (P^.Count + 1) * 2);
  2468. end;
  2469.  
  2470. { Stream routine }
  2471.  
  2472. procedure RegisterODialogs;
  2473. begin
  2474.   RegisterType(RDialog);
  2475.   RegisterType(RDlgWindow);
  2476.   RegisterType(RControl);
  2477.   RegisterType(RButton);
  2478.   RegisterType(RCheckBox);
  2479.   RegisterType(RRadioButton);
  2480.   RegisterType(RGroupBox);
  2481.   RegisterType(RListBox);
  2482.   RegisterType(RComboBox);
  2483.   RegisterType(RScrollBar);
  2484.   RegisterType(RStatic);
  2485.   RegisterType(REdit);
  2486. end;
  2487.  
  2488. end.
  2489.