home *** CD-ROM | disk | FTP | other *** search
/ PC Format Collection 48 / SENT14D.ISO / tech / delphi / disk14 / rtl70.pak / ODIALOGS.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1995-08-24  |  74.8 KB  |  2,496 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, Messages, 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.     if TextLen > High(Sz) then
  1365.       GetText(Sz, High(Sz))
  1366.     else
  1367.       GetText(Sz, TextLen);
  1368.  
  1369.     S := StrPas(Sz);
  1370.  
  1371.     if ReportError then
  1372.       IsValid := Validator^.Valid(S)
  1373.     else
  1374.       IsValid := Validator^.IsValid(S);
  1375.   end;
  1376. end;
  1377.  
  1378. { Clears the change flag for the associated edit control. }
  1379.  
  1380. procedure TEdit.ClearModify;
  1381. begin
  1382.   SendMessage(HWindow, em_SetModify, 0, 0);
  1383. end;
  1384.  
  1385. { Returns the number of the line of the associated edit control which
  1386.   contains the character whose position is passed.  If the position
  1387.   passed is greater than the position of the last character, the number
  1388.   of the last line is returned. If -1 is passed, the number of the line
  1389.   which contains the first selected character is returned. }
  1390.  
  1391. function TEdit.GetLineFromPos(CharPos: Integer): Integer;
  1392. begin
  1393.   GetLineFromPos := SendMessage(HWindow, em_LineFromChar, CharPos, 0);
  1394. end;
  1395.  
  1396. { Returns the number of characters in the associated edit control that
  1397.   occur before the line whose number is passed.  If -1 is passed, the
  1398.   line number of the line upon which the caret is positioned is used. }
  1399.  
  1400. function TEdit.GetLineIndex(LineNumber: Integer): Integer;
  1401. begin
  1402.   GetLineIndex := SendMessage(HWindow, em_LineIndex, LineNumber, 0);
  1403. end;
  1404.  
  1405. { Scrolls the text of the associated edit control by the specified
  1406.   horizontal and vertical amounts. }
  1407.  
  1408. procedure TEdit.Scroll(HorizontalUnit, VerticalUnit: Integer);
  1409. var
  1410.   LValue: LongRec;
  1411. begin
  1412.   LValue.Lo := VerticalUnit;
  1413.   LValue.Hi := HorizontalUnit;
  1414.   SendMessage(HWindow, em_LineScroll, 0, LongInt(LValue));
  1415. end;
  1416.  
  1417. { Sets the selection of the associated edit control to the passed string.
  1418.   (Does a "paste" type of action without affecting the clipboard). }
  1419.  
  1420. procedure TEdit.Insert(ATextString: PChar);
  1421. begin
  1422.   SendMessage(HWindow, em_ReplaceSel, 0, LongInt(ATextString));
  1423. end;
  1424.  
  1425. { Searchs for and selects the given text in the edit control and
  1426.   returns the offset of the text or -1 if the text is not found.
  1427.   If the StartPos = -1 then it is assumed that the start pos is
  1428.   the end of the current selection.
  1429. }
  1430. function TEdit.Search(StartPos: Integer; AText: PChar;
  1431.   CaseSensitive: Boolean): Integer;
  1432. var
  1433.   SText, Line, Pos: PChar;
  1434.   LineSize, LineLen, NumLines, CurLine, Offset, SBeg: Integer;
  1435. begin
  1436.   Search := -1;
  1437.   if AText[0] = #0 then Exit;
  1438.   Line := nil;
  1439.   LineSize := 0;
  1440.   if StartPos = -1 then GetSelection(SBeg, StartPos);
  1441.   if CaseSensitive then
  1442.     SText := AText else
  1443.     SText := AnsiLower(StrNew(AText));
  1444.   CurLine := GetLineFromPos(StartPos);
  1445.   Offset :=  StartPos - GetLineIndex(CurLine);
  1446.   NumLines := GetNumLines;
  1447.   while CurLine < NumLines do
  1448.   begin
  1449.     LineLen := GetLineLength(CurLine);
  1450.     if LineLen >= LineSize then
  1451.     begin
  1452.       if Line <> nil then FreeMem(Line, LineSize);
  1453.       LineSize := LineLen + 1;
  1454.       Line := MemAlloc(LineSize);
  1455.     end;
  1456.     if Line = nil then Exit;
  1457.     GetLine(Line, LineSize, CurLine);
  1458.     if not CaseSensitive then AnsiLower(Line);
  1459.     Pos := StrPos(@Line[Offset], SText);
  1460.     if Pos <> nil then
  1461.     begin
  1462.       SBeg := GetLineIndex(CurLine) + (Pos - Line);
  1463.       SetSelection(SBeg, SBeg + StrLen(SText));
  1464.       Search := SBeg;
  1465.       CurLine := MaxInt - 1;
  1466.     end;
  1467.     Offset := 0;
  1468.     Inc(CurLine);
  1469.   end;
  1470.   if Line <> nil then FreeMem(Line, LineSize);
  1471.   if not CaseSensitive then StrDispose(SText);
  1472. end;
  1473.  
  1474. { Deletes the selected text in the associated edit control.  Returns
  1475.   False if no text is selected. }
  1476.  
  1477. function TEdit.DeleteSelection: Boolean;
  1478. var
  1479.   StartPos, EndPos: Integer;
  1480. begin
  1481.   DeleteSelection := True;
  1482.   GetSelection(StartPos, EndPos);
  1483.   if StartPos <> EndPos then
  1484.     SendMessage(HWindow, wm_Clear, 0, 0)
  1485.   else DeleteSelection := False;
  1486. end;
  1487.  
  1488. { Deletes the text of the associated edit control between the passed
  1489.   positions.  Returns False if an error occurs. }
  1490.  
  1491. function TEdit.DeleteSubText(StartPos, EndPos: Integer): Boolean;
  1492. begin
  1493.   DeleteSubText :=
  1494.     SetSelection(StartPos, EndPos) and DeleteSelection;
  1495. end;
  1496.  
  1497. { Deletes the text at the passed line number in the associated edit
  1498.   control.  If -1 is passed, deletes the current line.  Returns False
  1499.   if the line passed is out of range (and not -1) or if an error occurs. }
  1500.  
  1501. function TEdit.DeleteLine(LineNumber: Integer): Boolean;
  1502. var
  1503.   FirstPos, LastPos: Integer;
  1504. begin
  1505.   DeleteLine := False;
  1506.   if LineNumber = -1 then LineNumber := GetLineFromPos(GetLineIndex(-1));
  1507.   FirstPos := GetLineIndex(LineNumber);
  1508.   if FirstPos <> -1 then
  1509.   begin
  1510.     LastPos := GetLineIndex(LineNumber + 1);
  1511.     if LastPos = -1 then LastPos := FirstPos + GetLineLength(LineNumber);
  1512.     if (FirstPos = 0) and (FirstPos = LastPos) then
  1513.     begin
  1514.       SetText('');
  1515.       DeleteLine := True;
  1516.     end
  1517.     else
  1518.       DeleteLine := DeleteSubText(FirstPos, LastPos);
  1519.   end;
  1520. end;
  1521.  
  1522. { Retrieves the text of the associated edit control between the passed
  1523.   positions. }
  1524.  
  1525. procedure TEdit.GetSubText(ATextString: PChar;
  1526.   StartPos, EndPos: Integer);
  1527. const
  1528.   cr_lf: PChar = #13#10;
  1529. var
  1530.   StartLine, EndLine, StartChar, EndChar: Integer;
  1531.   TempSize, TempIndex, TempStart, TempEnd: Integer;
  1532.   TempLine, TempLineLength: Integer;
  1533.   OkToContinue: Boolean;
  1534.   PLine: PChar;
  1535. begin
  1536.   if EndPos >= StartPos then
  1537.   begin
  1538.     StartLine := GetLineFromPos(StartPos);
  1539.     EndLine := GetLineFromPos(EndPos);
  1540.     StartChar := StartPos - GetLineIndex(StartLine);
  1541.     EndChar := EndPos - GetLineIndex(EndLine);
  1542.     TempIndex := 0;
  1543.     OkToContinue := True;
  1544.     for TempLine := StartLine to EndLine do
  1545.       if OkToContinue then
  1546.       begin
  1547.     TempLineLength := GetLineLength(TempLine);
  1548.         Inc(TempLineLength, 2); { Count the CR/LF }
  1549.         { Allocate memory for the line, leaving room for the terminating 0 }
  1550.     GetMem(PLine, TempLineLength + 1);
  1551.     if TempLine = StartLine then TempStart := StartChar
  1552.     else TempStart := 0;
  1553.     if TempLine = EndLine then TempEnd := EndChar
  1554.     else TempEnd := TempLineLength;
  1555.     TempSize := TempEnd - TempStart;
  1556.     if GetLine(PLine, TempLineLength + 1, TempLine) then
  1557.     begin
  1558.           StrCat(PLine, cr_lf); { Add back then CR/LF }
  1559.       StrMove(@ATextString[TempIndex], @PLine[TempStart], TempSize);
  1560.       TempIndex := TempIndex + TempSize;
  1561.         end
  1562.     else OkToContinue := False;
  1563.     FreeMem(PLine, TempLineLength + 1);
  1564.       end;
  1565.     ATextString[TempIndex] := #0;
  1566.   end;
  1567. end;
  1568.  
  1569. { Stores data of the TEdit object in the passed TStream. }
  1570. procedure TEdit.Store(var S: TStream);
  1571. begin
  1572.   TStatic.Store(S);
  1573.   S.Put(Validator);
  1574. end;
  1575.  
  1576. { Sets the given Validator object to be Self's validator.  Disposes
  1577.   of the current validator, if any. }
  1578.  
  1579. procedure TEdit.SetValidator(AValid: PValidator);
  1580. begin
  1581.   if Validator <> nil then Validator^.Free;
  1582.   Validator := AValid;
  1583. end;
  1584.  
  1585. { The window belongs to us if any of the window handles has an object
  1586.   attached }
  1587.  
  1588. function IsOurs(Wnd: HWnd): Boolean;
  1589. begin
  1590.   while (Wnd <> 0) and (GetObjectPtr(Wnd) = nil) do
  1591.     Wnd := GetParent(Wnd);
  1592.   IsOurs := Wnd <> 0;
  1593. end;
  1594.  
  1595. { Validates Self whenever the focus is about to be lost.
  1596.   Holds onto the focus if Self is not valid.  Checks first
  1597.   to make sure that the focus is not being taken by either
  1598.   (a) another app, or (b) a Cancel button, or (c) an OK
  1599.   button (in which case CanClose will validate); in each case,
  1600.   we don't want to validate. }
  1601.  
  1602. procedure TEdit.WMKillFocus(var Msg: TMessage);
  1603. var
  1604.   BtnId : Integer;
  1605. begin
  1606.   if ProcessFocus and IsOurs(Msg.WParam) then
  1607.   begin
  1608.     BtnId := GetDlgCtrlID(Msg.WParam);
  1609.  
  1610.     { Note that we do not allow IsValid to post the message
  1611.       box, since the change of focus resulting from that message
  1612.       will interfere with the change we are in the process of
  1613.       completing.  Instead, post a message to the Parent informing
  1614.       it of the validation failure, and providing it with a handle
  1615.       to Self. }
  1616.  
  1617.     if (BtnId <> id_Cancel) and (BtnId <> id_Ok) and not IsValid(False) then
  1618.     begin
  1619.       DefWndProc(Msg);
  1620.       ProcessFocus := False;
  1621.       PostMessage(Parent^.HWindow, wm_PostInvalid, HWindow, 0);
  1622.       Msg.Result := 0;
  1623.       Exit;
  1624.     end
  1625.   end;
  1626.   DefWndProc(Msg);
  1627. end;
  1628.  
  1629. { Validates Self whenever a character is entered.  Allows
  1630.   the character entry to be processed normally, then validates
  1631.   the result and restores Self's text to its original state
  1632.   if there is an incorrect entry.
  1633.  
  1634.   By default, the SupressFill parameter of the IsValidInput
  1635.   method call to the Validator is set to False, so that it
  1636.   is free to modify the string, if it is so configured. }
  1637.  
  1638. procedure TEdit.WMChar(var Msg: TMessage);
  1639. var
  1640.   S         : string;
  1641.   Sz, OldSz : array [0..255] of Char;
  1642.   Len       : Integer;
  1643.   StartPos, EndPos: Integer;
  1644.   WasAppending: Boolean;
  1645. begin
  1646.   if (Validator <> nil) and (GetNumLines <= 1) and
  1647.     (Msg.wParam <> vk_Back) then
  1648.   begin
  1649.     Len := TextLen;
  1650.     if Len > High(OldSz) then Len := High(OldSz);
  1651.     GetText(OldSz, Len);
  1652.     GetSelection(StartPos, EndPos);
  1653.     WasAppending := EndPos = StrLen(OldSz);
  1654.  
  1655.     DefWndProc(Msg);      { Process the new char ... }
  1656.  
  1657.     GetText(Sz, Len);
  1658.     S := StrPas(Sz);      { Validator expects a Pascal string }
  1659.  
  1660.     { Run the result of the edit through the validator.  If incorrect,
  1661.       then restore the original text.  Otherwise, set the (possibly)
  1662.       modified result of the validation back into the edit control,
  1663.       so the results of the auto-fill (if any) can be viewed.
  1664.     }
  1665.     GetSelection(StartPos, EndPos);
  1666.     if (Validator^.Options and voOnAppend = 0) or
  1667.       (WasAppending and (EndPos = StrLen(Sz))) then
  1668.     begin
  1669.       if not Validator^.IsValidInput(S, False) then
  1670.         SetText(OldSz)
  1671.       else
  1672.       begin
  1673.         StrPCopy(Sz, S);
  1674.         SetText(Sz);
  1675.         if (StartPos >= StrLen(OldSz)) and (StrLen(Sz) > StrLen(OldSz)) then
  1676.           StartPos := StrLen(Sz);
  1677.         if (EndPos >= StrLen(OldSz)) and (StrLen(Sz) > StrLen(OldSz)) then
  1678.           EndPos := StrLen(Sz);
  1679.       end;
  1680.       SetSelection(StartPos, EndPos);
  1681.     end
  1682.     else
  1683.     begin
  1684.       if EndPos = StrLen(Sz) then
  1685.         if not Validator^.IsValidInput(S, False) then
  1686.           Validator^.Error;
  1687.     end;
  1688.   end
  1689.   else
  1690.     DefWndProc(Msg);
  1691. end;
  1692.  
  1693. { Responds to the GetDlgCode query according to the
  1694.   current state of the control.  If the edit control
  1695.   contains valid input, then TABs are allowed for
  1696.   changing focus.  Otherwise, requests that TABs be
  1697.   sent to Self, where we will generate the Invalid
  1698.   message (See WMKeyDown below). }
  1699.  
  1700. procedure TEdit.WMGetDlgCode(var Msg: TMessage);
  1701. begin
  1702.   DefWndProc(Msg);
  1703.   if not IsValid(False) then
  1704.     Msg.Result := Msg.Result or dlgc_WantTab;
  1705. end;
  1706.  
  1707. { If the TAB key is sent to the Edit Control, check
  1708.   the validity before allowing the focus to change.
  1709.   The control will only get a TAB if WMGetDlgCode (above)
  1710.   allows it, which is done when the control contains
  1711.   invalid input (we re-validate here just for completeness,
  1712.   in case descendants redefine any of this behavior).
  1713.  
  1714.   We need to validate on TAB focus-changes because there
  1715.   is a case not handled by WMKillFocus: when focus is
  1716.   lost to an OK or CANCEL button by tabbing. }
  1717.  
  1718. procedure TEdit.WMKeyDown(var Msg: TMessage);
  1719. var
  1720.   WasAppending: Boolean;
  1721.   StartSel, EndSel: Integer;
  1722.   Sz: array[0..255] of Char;
  1723.   S: String;
  1724. begin
  1725.   if (Msg.WParam = vk_Tab) then
  1726.     if not IsValid(True) then
  1727.       Exit;
  1728.   if (Validator <> nil) and (Validator^.Options and voOnAppend <> 0)
  1729.     and (GetNumLines <= 1) then
  1730.   begin
  1731.     GetSelection(StartSel, EndSel);
  1732.     GetText(Sz, SizeOf(Sz));
  1733.     WasAppending := EndSel = StrLen(Sz);
  1734.     DefWndProc(Msg);
  1735.     if not WasAppending then
  1736.     begin
  1737.       GetSelection(StartSel, EndSel);
  1738.       GetText(Sz, SizeOf(Sz));
  1739.       S := StrPas(Sz);
  1740.       if (EndSel = StrLen(Sz)) and
  1741.           not Validator^.IsValidInput(S, False) then
  1742.         Validator^.Error;
  1743.     end;
  1744.   end
  1745.   else    
  1746.     DefWndProc(Msg);     { Else just ignore the TAB }
  1747. end;
  1748.  
  1749. { Transfers state information for TEdit controls. The TransferFlag passed
  1750.   specifies whether data is to be read from or written to the passed
  1751.   buffer, or whether the data element size is simply to be returned. The
  1752.   return value is the size (in bytes) of the transfer data.  TEdits trans-
  1753.   fer their data in one of two ways: if the TEdit does not own a Validator,
  1754.   it simply uses the inherited Transfer to transfer the edit text in the
  1755.   usual fashion.  If a Validator exists, however, it is used to transfer
  1756.   the data in the actual converted form corresponding to the Validator.
  1757.   This allows the application to treat the Edit control as, for example,
  1758.   an integer editor. }
  1759.  
  1760. function TEdit.Transfer(DataPtr: Pointer; TransferFlag: Word): Word;
  1761. var
  1762.   VTrans: TVTransfer;
  1763.   Sz    : PChar;
  1764.   S     : string;
  1765.   Trans : Word;
  1766. begin
  1767.   if (Validator <> nil) and (GetNumLines <= 1) then
  1768.   begin
  1769.     if TransferFlag = tf_GetData then
  1770.       VTrans := vtGetData   {GetText(DataPtr, TextLen)}
  1771.     else if TransferFlag = tf_SetData then
  1772.       VTrans := vtSetData   {SetText(DataPtr);}
  1773.     else
  1774.       VTrans := vtDataSize;
  1775.  
  1776.     GetMem(Sz, TextLen);
  1777.     GetText(Sz, TextLen);
  1778.     S := StrPas(Sz);
  1779.  
  1780.     Trans := Validator^.Transfer(S, DataPtr, VTrans);
  1781.  
  1782.     { If the validator does not implement a Transfer function, it will
  1783.       report a transfer amount of zero bytes.  In that case, we revert
  1784.       to the standard transfer behavior.  Otherwise, complete the transfer
  1785.       by setting the result of a SetData transfer back into the control. }
  1786.  
  1787.     if Trans = 0 then
  1788.       Trans := inherited Transfer(DataPtr, TransferFlag)
  1789.     else
  1790.       if VTrans = vtSetData then
  1791.       begin
  1792.         if Length(S) > TextLen-1 then
  1793.         begin
  1794.           FreeMem(Sz, TextLen);
  1795.           GetMem(Sz, Length(S)+1);
  1796.         end;
  1797.         StrPCopy(Sz, S);
  1798.         SetText(Sz);
  1799.       end;
  1800.     Transfer := Trans;
  1801.     FreeMem(Sz, TextLen);
  1802.   end
  1803.   else
  1804.     Transfer := inherited Transfer(DataPtr, TransferFlag);
  1805. end;
  1806.  
  1807. { Limits the amount of text that an edit control can have to the
  1808.   value of TextLen }
  1809.  
  1810. procedure TEdit.SetupWindow;
  1811. begin
  1812.   TStatic.SetupWindow;
  1813.   if TextLen <> 0 then SendMessage(HWindow, em_LimitText, TextLen - 1, 0);
  1814. end;
  1815.  
  1816. { TListBox }
  1817.  
  1818. { Constructor for an instance of TListBox.  Initializes its data fields
  1819.   using parameters passed and default values.  By default, an MS-Windows
  1820.   listbox associated with the TListBox will: be visible upon creation;
  1821.   have a border and a vertical scrollbar; maintain entries in alphabetical
  1822.   order; and notify its parent when a selection is made. }
  1823.  
  1824. constructor TListBox.Init(AParent: PWindowsObject; AnId: Integer;
  1825.   X, Y, W, H: Integer);
  1826. begin
  1827.   TControl.Init(AParent, AnId, nil, X, Y, W, H);
  1828.   Attr.Style := Attr.Style or lbs_Standard;
  1829. end;
  1830.  
  1831. { Returns the name of MS-Windows window class for a TListBox. }
  1832.  
  1833. function TListBox.GetClassName: PChar;
  1834. begin
  1835.   GetClassName := 'Listbox';
  1836. end;
  1837.  
  1838. { Transfers state information for a TListBox. The TransferFlag passed
  1839.   specifies whether data is to be read from or written to the passed
  1840.   buffer, or whether the data element size is simply to be returned.  The
  1841.   return value is the size (in bytes) of the transfer data. }
  1842.  
  1843. function TListBox.Transfer(DataPtr: Pointer; TransferFlag: Word): Word;
  1844. type
  1845.   PSingleRec = ^TSingleRec;
  1846.   TSingleRec = record
  1847.     Strings: PStrCollection;
  1848.     Selection: Integer;
  1849.   end;
  1850.   PMultiRec = ^TMultiRec;
  1851.   TMultiRec = record
  1852.     Strings: PStrCollection;
  1853.     Selections: PMultiSelRec;
  1854.   end;
  1855. var
  1856.   I: Integer;
  1857.   Style: LongInt;
  1858.  
  1859.   procedure DoAdd(P: PChar); far;
  1860.   begin
  1861.     AddString(P);
  1862.   end;
  1863.  
  1864. begin
  1865.   Style := GetWindowLong(HWindow, gwl_Style);
  1866.   if TransferFlag = tf_GetData then
  1867.     if Style and lbs_MultipleSel <> lbs_MultipleSel then
  1868.       with PSingleRec(DataPtr)^ do
  1869.     Selection := Integer(SendMessage(HWindow, lb_GetCurSel, 0, 0))
  1870.     else
  1871.       with PMultiRec(DataPtr)^ do
  1872.       begin
  1873.     FreeMultiSel(Selections);
  1874.     I := Integer(SendMessage(HWindow, lb_GetSelCount, 0, 0));
  1875.     Selections := AllocMultiSel(I);
  1876.     if Selections <> nil then
  1877.       SendMessage(HWindow, lb_GetSelItems, I,
  1878.         LongInt(@Selections^.Selections));
  1879.       end
  1880.   else if TransferFlag = tf_SetData then
  1881.     if Style and lbs_MultipleSel <> lbs_MultipleSel then
  1882.       with PSingleRec(DataPtr)^ do
  1883.       begin
  1884.     SendMessage(HWindow, lb_ResetContent, 0, 0);
  1885.     Strings^.ForEach(@DoAdd);
  1886.     SendMessage(HWindow, lb_SetCurSel, Selection, 0);
  1887.       end
  1888.     else
  1889.       with PMultiRec(DataPtr)^ do
  1890.       begin
  1891.     SendMessage(HWindow, lb_ResetContent, 0, 0);
  1892.     Strings^.ForEach(@DoAdd);
  1893.     SendMessage(HWindow, lb_SetSel, 0, -1); { Unselect all }
  1894.     if Selections <> nil then
  1895.       with Selections^ do
  1896.         for I := 0 to Count - 1  do
  1897.           SendMessage(HWindow, lb_SetSel, 1, Selections[I]);
  1898.       end;
  1899.   if Style and lbs_MultipleSel <> lbs_MultipleSel then
  1900.     Transfer := SizeOf(TSingleRec)
  1901.   else Transfer := SizeOf(TMultiRec);
  1902. end;
  1903.  
  1904. { Adds a string to an associated listbox.  Returns index of the string
  1905.   in the list (the first entry is at index 0).  A negative value is
  1906.   returned if an error occurs. }
  1907.  
  1908. function TListBox.AddString(AString: PChar): Integer;
  1909. begin
  1910.   AddString := Integer(SendMessage(HWindow, GetMsgID(mn_AddString),
  1911.     0, LongInt(AString)));
  1912. end;
  1913.  
  1914. { Inserts a string in the associated listbox at the passed index,
  1915.   returning the index of the string in the list.  A negative value is
  1916.   returned if an error occurs. }
  1917.  
  1918. function TListBox.InsertString(AString: PChar; Index: Integer): Integer;
  1919. begin
  1920.   InsertString := Integer(SendMessage(HWindow, GetMsgID(mn_InsertString),
  1921.     Index, LongInt(AString)));
  1922. end;
  1923.  
  1924. { Deletes the string at the passed index in the associated listbox. 
  1925.   Returns a count of the entries remaining in the list.  A negative value
  1926.   is returned if an error occurs. }
  1927.  
  1928. function TListBox.DeleteString(Index: Integer): Integer;
  1929. begin
  1930.   DeleteString := Integer(SendMessage(HWindow, GetMsgID(mn_DeleteString), 
  1931.     Index, 0));
  1932. end;
  1933.  
  1934. { Clears all the entries in the associated listbox. }
  1935.  
  1936. procedure TListBox.ClearList;
  1937. begin
  1938.   SendMessage(HWindow, GetMsgID(mn_ResetContent), 0, 0);
  1939. end;
  1940.  
  1941. { Returns the number of entries in the associated listbox. A negative
  1942.   value is returned if an error occurs. }
  1943.  
  1944. function TListBox.GetCount: Integer;
  1945. begin
  1946.   GetCount := Integer(SendMessage(HWindow, GetMsgID(mn_GetCount), 0, 0));
  1947. end; 
  1948.  
  1949. { Retrieves the contents of the string at the passed index of the
  1950.   associated listbox, returning the length of the string (in bytes) as
  1951.   the value of the call. A negative value is returned if the passed
  1952.   index is not valid. }
  1953.  
  1954. function TListBox.GetString(AString: PChar; Index: Integer): Integer;
  1955. begin
  1956.   GetString := Integer(SendMessage(HWindow, GetMsgID(mn_GetText), Index, 
  1957.     LongInt(AString)));
  1958. end; 
  1959.  
  1960. { Returns the length of the string at the passed index in the associated
  1961.   listbox.  Note that the strings in the listbox are stored as
  1962.   null-terminated arrays of characters rather than the traditional Pascal
  1963.   type of string. The length returned does not include the null 
  1964.   terminator.  A negative value is returned if an error occurs. }
  1965.  
  1966. function TListBox.GetStringLen(Index: Integer): Integer;
  1967. begin
  1968.   GetStringLen := Integer(SendMessage(HWindow, GetMsgID(mn_GetTextLen),
  1969.     Index, 0));
  1970. end; 
  1971.  
  1972. { Retrieves the text of the string which is selected in the associated
  1973.   listbox.  Returns the number of characters copied.  -1 is returned if
  1974.   no string is selected.  Since the Windows function is not passed a
  1975.   size parameter, we have to allocate a string to hold the largest
  1976.   string (gotten from a query), and copy a part of it. }
  1977.  
  1978. function TListBox.GetSelString(AString: PChar; MaxChars: Integer): Integer;
  1979. var
  1980.   Index: Integer;
  1981.   Length: Integer;
  1982.   TempString: PChar;
  1983. begin
  1984.   GetSelString := -1;
  1985.   Index := GetSelIndex;
  1986.   Length := GetStringLen(Index);
  1987.   if (Index > -1) then
  1988.     if (MaxChars >= Length) then
  1989.       GetSelString := GetString(AString, Index)
  1990.     else
  1991.     begin
  1992.       TempString := MemAlloc(Length+1);
  1993.       if TempString <> nil then
  1994.       begin
  1995.         GetString(TempString, Index);
  1996.         StrLCopy(AString, TempString, MaxChars);
  1997.         FreeMem(TempString, Length+1);
  1998.         GetSelString := MaxChars;
  1999.       end;
  2000.     end;
  2001. end;
  2002.  
  2003. { Selects the first string in the associated listbox following the passed
  2004.   index which begins with the passed string.  Searches for a match
  2005.   beginning at the passed Index.  If a match is not found after the last
  2006.   string has been compared, the search continues from the beginning of the
  2007.   list until a match is found or until the list has been completely
  2008.   traversed.  Searches from beginning of list when -1 is passed as the
  2009.   index.  Returns the index of the selected string.  A negative value is
  2010.   returned if an error occurs. }
  2011.  
  2012. function TListBox.SetSelString(AString: PChar; Index: Integer): Integer;
  2013. begin
  2014.   SetSelString := Integer(SendMessage(HWindow, GetMsgID(mn_SelectString), 
  2015.     Word(Index), LongInt(AString)));
  2016. end; 
  2017.  
  2018. { Returns the index of the selected string in the associated listbox.  A
  2019.   negative value is returned if no string is selected. }
  2020.  
  2021. function TListBox.GetSelIndex: Integer;
  2022. begin
  2023.   GetSelIndex := Integer(SendMessage(HWindow, GetMsgID(mn_GetCurSel), 
  2024.     0, 0));
  2025. end; 
  2026.  
  2027. { Selects the string at passed index in the associated listbox and forces
  2028.   the string into view.  Clears selection when -1 is passed as the index.
  2029.   A negative value is returned if an error occurs. }
  2030.  
  2031. function TListBox.SetSelIndex(Index: Integer): Integer;
  2032. begin
  2033.   SetSelIndex := Integer(SendMessage(HWindow, GetMsgID(mn_SetCurSel), 
  2034.     Index, 0));
  2035. end;
  2036.  
  2037. { Returns the appropriate MS-Windows message Integer identifier for the
  2038.   function identified by the passed MsgName string.  Allows instances of
  2039.   TComboBox to inherit many TListBox methods. }
  2040.  
  2041. function TListBox.GetMsgID(AMsg: TMsgName): Word;
  2042. const
  2043.   MsgXlat: array[TMsgName] of Word =
  2044.     (lb_AddString,    lb_InsertString, lb_DeleteString,
  2045.      lb_ResetContent, lb_GetCount,     lb_GetText,
  2046.      lb_GetTextLen,   lb_SelectString, lb_SetCurSel,
  2047.      lb_GetCurSel);
  2048. begin
  2049.   GetMsgId := MsgXLat[AMsg];
  2050. end;
  2051.  
  2052. { TComboBox }
  2053.  
  2054. { Constructor for a TCheckBox object.  Initializes its data fields using
  2055.   parameters passed and default values.  By default, an MS-Windows combobox
  2056.   associated with the TComboBox will have a vertical scrollbar and will
  2057.   maintain its entries in alphabetical order. }
  2058.  
  2059. constructor TComboBox.Init(AParent: PWindowsObject; AnID: Integer;
  2060.   X, Y, W, H: Integer; AStyle, ATextLen: Word);
  2061. begin
  2062.   TListBox.Init(AParent, AnID, X, Y, W, H);
  2063.   TextLen := ATextLen;
  2064.   Attr.Style :=
  2065.     ws_Child or ws_Visible or ws_Group or ws_TabStop or cbs_Sort
  2066.     or cbs_AutoHScroll or ws_VScroll or AStyle;
  2067. end;
  2068.  
  2069. constructor TComboBox.InitResource(AParent: PWindowsObject;
  2070.   ResourceID: Integer; ATextLen: Word);
  2071. begin
  2072.   TListBox.InitResource(AParent, ResourceID);
  2073.   TextLen := ATextLen;
  2074. end;
  2075.  
  2076. { Constructor for a TComboBox object.  Initializes the object with data
  2077.   from the passed TStream. }
  2078.  
  2079. constructor TComboBox.Load(var S: TStream);
  2080. begin
  2081.   TListBox.Load(S);
  2082.   S.Read(TextLen, SizeOf(TextLen));
  2083. end;
  2084.  
  2085. { Stores data of the TComboBox object in the passed TStream. }
  2086.  
  2087. procedure TComboBox.Store(var S: TStream);
  2088. begin
  2089.   TListBox.Store(S);
  2090.   S.Write(TextLen, SizeOf(TextLen));
  2091. end;
  2092.  
  2093. { Returns the name of MS-Windows window class for a TComboBox. }
  2094.  
  2095. function TComboBox.GetClassName: PChar;
  2096. begin
  2097.   GetClassName := 'Combobox';
  2098. end;
  2099.  
  2100. { Shows the list of an associated drop-down combobox. }
  2101.  
  2102. procedure TComboBox.ShowList;
  2103. begin
  2104.   if GetWindowLong(HWindow, gwl_Style) and cbs_DropDown = cbs_DropDown then
  2105.     SendMessage(HWindow, cb_ShowDropDown, 1, 0);
  2106. end;
  2107.  
  2108. { Hides the list of an associated drop-down combobox. }
  2109.  
  2110. procedure TComboBox.HideList;
  2111. begin
  2112.   if GetWindowLong(HWindow, gwl_Style) and cbs_DropDown = cbs_DropDown then
  2113.     SendMessage(HWindow, cb_ShowDropDown, 0, 0);
  2114. end;
  2115.  
  2116. function TComboBox.Transfer(DataPtr: Pointer; TransferFlag: Word): Word;
  2117. type
  2118.   PTranRec = ^TTranRec;
  2119.   TTranRec = record
  2120.     Strings: PStrCollection;
  2121.     Selection: array[0..32767] of Char;
  2122.   end;
  2123.  
  2124.   procedure DoAdd(P: PChar); far;
  2125.   begin
  2126.     AddString(P);
  2127.   end;
  2128.  
  2129. begin
  2130.   if TransferFlag = tf_GetData then
  2131.     with PTranRec(DataPtr)^ do
  2132.       GetWindowText(HWindow, Selection, TextLen)
  2133.   else if TransferFlag = tf_SetData then
  2134.     with PTranRec(DataPtr)^ do
  2135.     begin
  2136.       SendMessage(HWindow, cb_ResetContent, 0, 0);
  2137.       Strings^.ForEach(@DoAdd);
  2138.       SetSelString(Selection, -1);
  2139.       SetWindowText(HWindow, Selection);
  2140.     end;
  2141.   Transfer := SizeOf(Pointer) + TextLen;
  2142. end;
  2143.  
  2144. { Returns the appropriate Windows message Integer identifier for the
  2145.   function identified by the passed MsgName string. Allows instances
  2146.   of TComboBox to inherit many TListBox methods. }
  2147.  
  2148. function TComboBox.GetMsgID(AMsg: TMsgName): Word;
  2149. const
  2150.   MsgXlat: array[TMsgName] of Word =
  2151.     (cb_AddString,    cb_InsertString, cb_DeleteString,
  2152.      cb_ResetContent, cb_GetCount,     cb_GetLBText,
  2153.      cb_GetLBTextLen, cb_SelectString, cb_SetCurSel,
  2154.      cb_GetCurSel);
  2155. begin
  2156.   GetMsgId := MsgXLat[AMsg];
  2157. end;
  2158.  
  2159. procedure TComboBox.SetupWindow;
  2160. begin
  2161.   TListBox.SetupWindow;
  2162.   if TextLen <> 0 then SendMessage(HWindow, cb_LimitText, TextLen - 1, 0);
  2163. end;
  2164.  
  2165. { Returns the lenght of the associated edit control's text }
  2166.  
  2167. function TComboBox.GetTextLen: Integer;
  2168. begin
  2169.   GetTextLen := GetWindowTextLength(HWindow);
  2170. end;
  2171.  
  2172. { Fills the supplied string with the text of the associated edit
  2173.   control. Returns the number of characters copied. }
  2174.  
  2175. function TComboBox.GetText(Str: PChar; MaxChars: Integer): Integer;
  2176. begin
  2177.   GetText := GetWindowText(HWindow, Str, MaxChars);
  2178. end;
  2179.  
  2180. { Sets and selects the contents of the associated edit control to the
  2181.   supplied string. }
  2182.  
  2183. procedure TComboBox.SetText(Str: PChar);
  2184. begin
  2185.   if SetSelString(Str, -1) < 0 then
  2186.   begin
  2187.     SetWindowText(HWindow, Str);
  2188.     SetEditSel(0, StrLen(Str));
  2189.   end;
  2190. end;
  2191.  
  2192. { Selects characters in the edit control of the combo box which
  2193.   are between StartPos and EndPos. Returns cm_Err if the combo
  2194.   box does not have an edit control. }
  2195.  
  2196. function TComboBox.SetEditSel(StartPos, EndPos: Integer): Integer;
  2197. begin
  2198.   SetEditSel := Integer(SendMessage(HWindow, cb_SetEditSel, 0,
  2199.     MakeLong(StartPos, EndPos)));
  2200. end;
  2201.  
  2202. { Returns, in the supplied var parameters, the starting and ending
  2203.   positions of the text selected in the associated edit control.
  2204.   Returns False if the combo box has no edit control }
  2205.  
  2206. function TComboBox.GetEditSel(var StartPos, EndPos: Integer): Boolean;
  2207. var
  2208.   RetValue: LongInt;
  2209. begin
  2210.   RetValue := SendMessage(HWindow, cb_GetEditSel, 0, 0);
  2211.   StartPos := LoWord(RetValue);
  2212.   EndPos := HiWord(RetValue);
  2213.   GetEditSel := RetValue <> cb_Err;
  2214. end;
  2215.  
  2216. { Clears the text of the associated edit control }
  2217.  
  2218. procedure TComboBox.Clear;
  2219. begin
  2220.   SetText('');
  2221. end;
  2222.  
  2223. { TScrollBar }
  2224.  
  2225. { Constructor for a TScrollBar object.  Initializes the object with
  2226.   data from the passed TStream. }
  2227.  
  2228. constructor TScrollBar.Load(var S: TStream);
  2229. begin
  2230.   TControl.Load(S);
  2231.   S.Read(LineMagnitude, SizeOf(LineMagnitude));
  2232.   S.Read(PageMagnitude, SizeOf(PageMagnitude));
  2233. end;
  2234.  
  2235. { Stores data of the TScrollBar object in the passed TStream. }
  2236.  
  2237. procedure TScrollBar.Store(var S: TStream);
  2238. begin
  2239.   TControl.Store(S);
  2240.   S.Write(LineMagnitude, SizeOf(LineMagnitude));
  2241.   S.Write(PageMagnitude, SizeOf(PageMagnitude));
  2242. end;
  2243.  
  2244. { Constructor for a TScrollBar object.  Initializes its data fields
  2245.   (including its creation attributes) using parameters passed and
  2246.   default values. If the size attribute (H for horizontal scrollbars,
  2247.   W for vertical) is zero, the attribute is set to the appropriate
  2248.   system metric. }
  2249.  
  2250. constructor TScrollBar.Init(AParent: PWindowsObject; AnID: Integer;
  2251.   X, Y, W, H: Integer; IsHScrollBar: Boolean);
  2252. begin
  2253.   TControl.Init(AParent, AnID, nil, X, Y, W, H);
  2254.   LineMagnitude := 1;
  2255.   PageMagnitude := 10;
  2256.   if IsHScrollBar then
  2257.   begin
  2258.     Attr.Style := Attr.Style or sbs_Horz;
  2259.     if Attr.H = 0 then Attr.H := GetSystemMetrics(sm_CYHScroll);
  2260.   end
  2261.   else
  2262.   begin
  2263.     Attr.Style := Attr.Style or sbs_Vert;
  2264.     if Attr.W = 0 then Attr.W := GetSystemMetrics(sm_CXVScroll);
  2265.   end;
  2266. end;
  2267.  
  2268. constructor TScrollBar.InitResource(AParent: PWindowsObject; ResourceID: Word);
  2269. begin
  2270.   TControl.InitResource(AParent, ResourceID);
  2271.   LineMagnitude := 1;
  2272.   PageMagnitude := 10;
  2273. end;
  2274.  
  2275. { Returns the name of MS-Windows window class for a TScrollBar. }
  2276.  
  2277. function TScrollBar.GetClassName: PChar;
  2278. begin
  2279.   GetClassName := 'Scrollbar';
  2280. end;
  2281.  
  2282. { Transfers state information for a TScrollbar.  The TransferFlag passed
  2283.   specifies whether data is to be read from or written to the passed
  2284.   buffer, or whether the data element size is simply to be returned.  The
  2285.   return value is the size (in bytes) of the transfer data. }
  2286.  
  2287. function TScrollbar.Transfer(DataPtr: Pointer; TransferFlag: Word): Word;
  2288. var
  2289.   LoVal, HiVal, Pos: Integer;
  2290.   NewPtr: Pointer;
  2291. begin
  2292.   NewPtr := DataPtr;
  2293.   if TransferFlag = tf_GetData then
  2294.   begin
  2295.     GetRange(LoVal, HiVal);
  2296.     Pos := GetPosition;
  2297.     Move(LoVal, NewPtr^, SizeOf(Integer));
  2298.     Inc(LongInt(NewPtr), SizeOf(Integer));
  2299.     Move(HiVal, NewPtr^, SizeOf(Integer));
  2300.     Inc(LongInt(NewPtr), SizeOf(Integer));
  2301.     Move(Pos,   NewPtr^, SizeOf(Integer));
  2302.   end
  2303.   else if TransferFlag = tf_SetData then
  2304.   begin
  2305.     LoVal := Integer(NewPtr^);
  2306.     Inc(LongInt(NewPtr), SizeOf(Integer));
  2307.     HiVal := Integer(NewPtr^);
  2308.     Inc(LongInt(NewPtr), SizeOf(Integer));
  2309.     Pos := Integer(NewPtr^);
  2310.     SetRange(LoVal, HiVal);
  2311.     SetPosition(Pos);
  2312.   end;
  2313.   Transfer := (SizeOf(Integer) * 3);
  2314. end;
  2315.  
  2316. { Sets up an associated scrollbar by setting its range to 0..100. }
  2317.  
  2318. procedure TScrollBar.SetupWindow;
  2319. begin
  2320.   TControl.SetupWindow;
  2321.   SetRange(0, 100);
  2322. end; 
  2323.  
  2324. { Retrieves the range of values that the associated scrollbar can
  2325.   return. }
  2326.  
  2327. procedure TScrollBar.GetRange(var LoVal, HiVal: Integer);
  2328. begin
  2329.   GetScrollRange(HWindow, sb_Ctl, LoVal, HiVal);
  2330. end;
  2331.  
  2332. { Returns the position of the thumb of the associated scrollbar. }
  2333.  
  2334. function TScrollBar.GetPosition: Integer;
  2335. begin
  2336.   GetPosition := GetScrollPos(HWindow, sb_Ctl);
  2337. end;
  2338.   
  2339. { Sets the range of values that the associated scrollbar can return. }
  2340.  
  2341. procedure TScrollBar.SetRange(LoVal, HiVal: Integer);
  2342. begin
  2343.   SetScrollRange(HWindow, sb_Ctl, LoVal, HiVal, False);
  2344. end;
  2345.  
  2346. { Sets the position of the thumb of the associated scrollbar. }
  2347.  
  2348. procedure TScrollBar.SetPosition(ThumbPos: Integer);
  2349. var
  2350.   LoVal, HiVal: Integer;
  2351. begin
  2352.   GetRange(LoVal, HiVal);
  2353.   if ThumbPos > HiVal then ThumbPos := HiVal
  2354.   else if ThumbPos < LoVal then ThumbPos := LoVal;
  2355.   if ThumbPos <> GetPosition then
  2356.     SetScrollPos(HWindow, sb_Ctl, ThumbPos, True);
  2357. end;
  2358.  
  2359. { Changes the position (by Delta) of the thumb of the associated
  2360.   scrollbar.  Returns the new position. }
  2361.  
  2362. function TScrollBar.DeltaPos(Delta: Integer): Integer;
  2363. begin
  2364.   if Delta <> 0 then SetPosition(GetPosition + Delta);
  2365.   DeltaPos := GetPosition;
  2366. end;
  2367.  
  2368. { Responds to an sb_LineUp notification message which the associated
  2369.   scrollbar sent to its parent.  Changes the position (by LineMagnitude)
  2370.   of the thumb of the associated scrollbar. }
  2371.  
  2372. procedure TScrollBar.SBLineUp(var Msg: TMessage);
  2373. begin
  2374.   DeltaPos(0 - LineMagnitude);
  2375.   DefNotificationProc(Msg);
  2376. end;
  2377.  
  2378. { Responds to an sb_LineDown notification message which the associated
  2379.   scrollbar sent to its parent.  Changes the position (by LineMagnitude)
  2380.   of the thumb. }
  2381.  
  2382. procedure TScrollBar.SBLineDown(var Msg: TMessage);
  2383. begin
  2384.   DeltaPos(LineMagnitude);
  2385.   DefNotificationProc(Msg);
  2386. end;
  2387.  
  2388. { Responds to an sb_PageUp notification message which the associated
  2389.   scrollbar sent to its parent.  Changes the position (by PageMagnitude)
  2390.   of the thumb. }
  2391.  
  2392. procedure TScrollBar.SBPageUp(var Msg: TMessage);
  2393. begin
  2394.   DeltaPos(0 - PageMagnitude);
  2395.   DefNotificationProc(Msg);
  2396. end;
  2397.  
  2398. { Responds to an sb_PageDown notification message which the associated
  2399.   scrollbar sent to its parent.  Changes the position (by PageMagnitude)
  2400.   of the thumb. }
  2401.  
  2402. procedure TScrollBar.SBPageDown(var Msg: TMessage);
  2403. begin
  2404.   DeltaPos(PageMagnitude);
  2405.   DefNotificationProc(Msg);
  2406. end;
  2407.  
  2408. { Responds to an sb_ThumbPosition notification message which the
  2409.   associated scrollbar sent to its parent.  Moves the thumb of the 
  2410.   scrollbar to the new position. }
  2411.  
  2412. procedure TScrollBar.SBThumbPosition(var Msg: TMessage);
  2413. begin
  2414.   SetPosition(Msg.LParamLo);
  2415.   DefNotificationProc(Msg);
  2416. end;
  2417.  
  2418. { Responds to an sb_ThumbTrack notification message which the associated
  2419.   scrollbar sent to its parent.  Draws the thumb in the current position
  2420.   on the track. }
  2421.  
  2422. procedure TScrollBar.SBThumbTrack(var Msg: TMessage);
  2423. begin
  2424.   SetPosition(Msg.LParamLo);
  2425.   DefNotificationProc(Msg);
  2426. end;
  2427.  
  2428. { Responds to an sb_Top notification message which the associated
  2429.   scrollbar sent to its parent.  Moves the thumb to the top of the
  2430.   scrollbar. }
  2431.  
  2432. procedure TScrollBar.SBTop(var Msg: TMessage);
  2433. var
  2434.   Lo, Hi: Integer;
  2435. begin
  2436.   GetRange(Lo, Hi);
  2437.   SetPosition(Lo);
  2438.   DefNotificationProc(Msg);
  2439. end;
  2440.  
  2441. { Responds to an sb_Bottom notification message which the associated
  2442.   scrollbar sent to its parent.  Moves the thumb to the bottom of the
  2443.   scrollbar. }
  2444.  
  2445. procedure TScrollBar.SBBottom(var Msg: TMessage);
  2446. var
  2447.   Lo, Hi: Integer;
  2448. begin
  2449.   GetRange(Lo, Hi);
  2450.   SetPosition(Hi);
  2451.   DefNotificationProc(Msg);
  2452. end;
  2453.  
  2454. { ListBox multiple selection transfer records }
  2455.  
  2456. function AllocMultiSel(Size: Integer): PMultiSelRec;
  2457. var
  2458.   P: PMultiSelRec;
  2459. begin
  2460.   AllocMultiSel := nil;
  2461.   if Size <> 0 then
  2462.   begin
  2463.     P := MemAlloc( (Size + 1) * 2);
  2464.     if P <> nil then
  2465.     begin
  2466.       P^.Count := Size;
  2467.       AllocMultiSel := P;
  2468.     end;
  2469.   end;
  2470. end;
  2471.  
  2472. procedure FreeMultiSel(P: PMultiSelRec);
  2473. begin
  2474.   if P <> nil then FreeMem(P, (P^.Count + 1) * 2);
  2475. end;
  2476.  
  2477. { Stream routine }
  2478.  
  2479. procedure RegisterODialogs;
  2480. begin
  2481.   RegisterType(RDialog);
  2482.   RegisterType(RDlgWindow);
  2483.   RegisterType(RControl);
  2484.   RegisterType(RButton);
  2485.   RegisterType(RCheckBox);
  2486.   RegisterType(RRadioButton);
  2487.   RegisterType(RGroupBox);
  2488.   RegisterType(RListBox);
  2489.   RegisterType(RComboBox);
  2490.   RegisterType(RScrollBar);
  2491.   RegisterType(RStatic);
  2492.   RegisterType(REdit);
  2493. end;
  2494.  
  2495. end.
  2496.