home *** CD-ROM | disk | FTP | other *** search
/ Chip 1997 April / Chip_1997-04_cd.bin / prezent / cb / data.z / DIALOGS.PAS < prev    next >
Pascal/Delphi Source File  |  1997-01-16  |  44KB  |  1,493 lines

  1.  
  2. {*******************************************************}
  3. {                                                       }
  4. {       Delphi Visual Component Library                 }
  5. {                                                       }
  6. {       Copyright (c) 1995,96 Borland International     }
  7. {                                                       }
  8. {*******************************************************}
  9.  
  10. unit Dialogs;
  11.  
  12. {$R-}
  13.  
  14. interface
  15.  
  16. uses Windows, Messages, SysUtils, CommDlg, Classes, Graphics, Controls,
  17.   Forms;
  18.  
  19. const
  20.  
  21. { Maximum number of custom colors in color dialog }
  22.  
  23.   MaxCustomColors = 16;
  24.  
  25. type
  26.  
  27. { TCommonDialog }
  28.  
  29.   TCommonDialog = class(TComponent)
  30.   private
  31.     FCtl3D: Boolean;
  32.     FHelpContext: THelpContext;
  33.   protected
  34.     function Message(var Msg: TMessage): Boolean; virtual;
  35.     function TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool; virtual;
  36.   public
  37.     constructor Create(AOwner: TComponent); override;
  38.   published
  39.     property Ctl3D: Boolean read FCtl3D write FCtl3D default True;
  40.     property HelpContext: THelpContext read FHelpContext write FHelpContext default 0;
  41.   end;
  42.  
  43. { TOpenDialog }
  44.  
  45.   TOpenOption = (ofReadOnly, ofOverwritePrompt, ofHideReadOnly,
  46.     ofNoChangeDir, ofShowHelp, ofNoValidate, ofAllowMultiSelect,
  47.     ofExtensionDifferent, ofPathMustExist, ofFileMustExist, ofCreatePrompt,
  48.     ofShareAware, ofNoReadOnlyReturn, ofNoTestFileCreate, ofNoNetworkButton,
  49.     ofNoLongNames, ofOldStyleDialog, ofNoDereferenceLinks);
  50.   TOpenOptions = set of TOpenOption;
  51.  
  52.   TFileEditStyle = (fsEdit, fsComboBox);
  53.  
  54.   TOpenDialog = class(TCommonDialog)
  55.   private
  56.     FHistoryList: TStrings;
  57.     FOptions: TOpenOptions;
  58.     FFilter: string;
  59.     FFilterIndex: Integer;
  60.     FInitialDir: string;
  61.     FTitle: string;
  62.     FDefaultExt: string;
  63.     FFileName: TFileName;
  64.     FFiles: TStrings;
  65.     FFileEditStyle: TFileEditStyle;
  66.     procedure SetHistoryList(Value: TStrings);
  67.     procedure SetInitialDir(const Value: string);
  68.     function DoExecute(Func: Pointer): Bool;
  69.   public
  70.     constructor Create(AOwner: TComponent); override;
  71.     destructor Destroy; override;
  72.     function Execute: Boolean; virtual;
  73.     property Files: TStrings read FFiles;
  74.   published
  75.     property DefaultExt: string read FDefaultExt write FDefaultExt;
  76.     property FileEditStyle: TFileEditStyle read FFileEditStyle write FFileEditStyle;
  77.     property FileName: TFileName read FFileName write FFileName;
  78.     property Filter: string read FFilter write FFilter;
  79.     property FilterIndex: Integer read FFilterIndex write FFilterIndex default 1;
  80.     property HistoryList: TStrings read FHistoryList write SetHistoryList;
  81.     property InitialDir: string read FInitialDir write SetInitialDir;
  82.     property Options: TOpenOptions read FOptions write FOptions default [];
  83.     property Title: string read FTitle write FTitle;
  84.   end;
  85.  
  86. { TSaveDialog }
  87.  
  88.   TSaveDialog = class(TOpenDialog)
  89.     function Execute: Boolean; override;
  90.   end;
  91.  
  92. { TColorDialog }
  93.  
  94.   TColorDialogOption = (cdFullOpen, cdPreventFullOpen, cdShowHelp,
  95.     cdSolidColor, cdAnyColor);
  96.   TColorDialogOptions = set of TColorDialogOption;
  97.  
  98.   TCustomColors = array[0..MaxCustomColors - 1] of Longint;
  99.  
  100.   TColorDialog = class(TCommonDialog)
  101.   private
  102.     FColor: TColor;
  103.     FOptions: TColorDialogOptions;
  104.     FCustomColors: TStrings;
  105.     procedure SetCustomColors(Value: TStrings);
  106.   public
  107.     constructor Create(AOwner: TComponent); override;
  108.     destructor Destroy; override;
  109.     function Execute: Boolean;
  110.   published
  111.     property Color: TColor read FColor write FColor default clBlack;
  112.     property Ctl3D default False;
  113.     property CustomColors: TStrings read FCustomColors write SetCustomColors;
  114.     property Options: TColorDialogOptions read FOptions write FOptions default [];
  115.   end;
  116.  
  117. { TFontDialog }
  118.  
  119.   TFontDialogOption = (fdAnsiOnly, fdTrueTypeOnly, fdEffects,
  120.     fdFixedPitchOnly, fdForceFontExist, fdNoFaceSel, fdNoOEMFonts,
  121.     fdNoSimulations, fdNoSizeSel, fdNoStyleSel,  fdNoVectorFonts,
  122.     fdShowHelp, fdWysiwyg, fdLimitSize, fdScalableOnly, fdApplyButton);
  123.   TFontDialogOptions = set of TFontDialogOption;
  124.  
  125.   TFontDialogDevice = (fdScreen, fdPrinter, fdBoth);
  126.  
  127.   TFDApplyEvent = procedure(Sender: TObject; Wnd: HWND) of object;
  128.  
  129.   TFontDialog = class(TCommonDialog)
  130.   private
  131.     FFont: TFont;
  132.     FDevice: TFontDialogDevice;
  133.     FOptions: TFontDialogOptions;
  134.     FOnApply: TFDApplyEvent;
  135.     FMinFontSize: Integer;
  136.     FMaxFontSize: Integer;
  137.     procedure DoApply(Wnd: HWND);
  138.     procedure SetFont(Value: TFont);
  139.     procedure UpdateFromLogFont(const LogFont: TLogFont);
  140.   protected
  141.     procedure Apply(Wnd: HWND); dynamic;
  142.   public
  143.     constructor Create(AOwner: TComponent); override;
  144.     destructor Destroy; override;
  145.     function Execute: Boolean;
  146.   published
  147.     property Font: TFont read FFont write SetFont;
  148.     property Device: TFontDialogDevice read FDevice write FDevice default fdScreen;
  149.     property MinFontSize: Integer read FMinFontSize write FMinFontSize;
  150.     property MaxFontSize: Integer read FMaxFontSize write FMaxFontSize;
  151.     property Options: TFontDialogOptions read FOptions write FOptions default [fdEffects];
  152.     property OnApply: TFDApplyEvent read FOnApply write FOnApply;
  153.   end;
  154.  
  155. { TPrinterSetupDialog }
  156.  
  157.   TPrinterSetupDialog = class(TCommonDialog)
  158.   public
  159.     procedure Execute;
  160.   end;
  161.  
  162. { TPrintDialog }
  163.  
  164.   TPrintRange = (prAllPages, prSelection, prPageNums);
  165.   TPrintDialogOption = (poPrintToFile, poPageNums, poSelection, poWarning,
  166.     poHelp, poDisablePrintToFile);
  167.   TPrintDialogOptions = set of TPrintDialogOption;
  168.  
  169.   TPrintDialog = class(TCommonDialog)
  170.   private
  171.     FFromPage: Integer;
  172.     FToPage: Integer;
  173.     FCollate: Boolean;
  174.     FOptions: TPrintDialogOptions;
  175.     FPrintToFile: Boolean;
  176.     FPrintRange: TPrintRange;
  177.     FMinPage: Integer;
  178.     FMaxPage: Integer;
  179.     FCopies: Integer;
  180.     procedure SetNumCopies(Value: Integer);
  181.   public
  182.     function Execute: Boolean;
  183.   published
  184.     property Collate: Boolean read FCollate write FCollate default False;
  185.     property Copies: Integer read FCopies write SetNumCopies default 0;
  186.     property FromPage: Integer read FFromPage write FFromPage default 0;
  187.     property MinPage: Integer read FMinPage write FMinPage default 0;
  188.     property MaxPage: Integer read FMaxPage write FMaxPage default 0;
  189.     property Options: TPrintDialogOptions read FOptions write FOptions default [];
  190.     property PrintToFile: Boolean read FPrintToFile write FPrintToFile default False;
  191.     property PrintRange: TPrintRange read FPrintRange write FPrintRange default prAllPages;
  192.     property ToPage: Integer read FToPage write FToPage default 0;
  193.   end;
  194.  
  195. { TFindDialog }
  196.  
  197.   TFindOption = (frDown, frFindNext, frHideMatchCase, frHideWholeWord,
  198.     frHideUpDown, frMatchCase, frDisableMatchCase, frDisableUpDown,
  199.     frDisableWholeWord, frReplace, frReplaceAll, frWholeWord, frShowHelp);
  200.   TFindOptions = set of TFindOption;
  201.  
  202.   TFindReplaceFunc = function(var FindReplace: TFindReplace): HWnd stdcall;
  203.  
  204.   TFindDialog = class(TCommonDialog)
  205.   private
  206.     FOptions: TFindOptions;
  207.     FPosition: TPoint;
  208.     FHandle: HWnd;
  209.     FFindReplaceFunc: TFindReplaceFunc;
  210.     FRedirector: TWinControl;
  211.     FOnFind: TNotifyEvent;
  212.     FOnReplace: TNotifyEvent;
  213.     FFindReplace: TFindReplace;
  214.     FFindText: array[0..255] of Char;
  215.     FReplaceText: array[0..255] of Char;
  216.     function GetFindText: string;
  217.     function GetLeft: Integer;
  218.     function GetPosition: TPoint;
  219.     function GetReplaceText: string;
  220.     function GetTop: Integer;
  221.     procedure SetFindText(const Value: string);
  222.     procedure SetLeft(Value: Integer);
  223.     procedure SetPosition(const Value: TPoint);
  224.     procedure SetReplaceText(const Value: string);
  225.     procedure SetTop(Value: Integer);
  226.     property ReplaceText: string read GetReplaceText write SetReplaceText;
  227.     property OnReplace: TNotifyEvent read FOnReplace write FOnReplace;
  228.   protected
  229.     function Message(var Msg: TMessage): Boolean; override;
  230.     procedure Find; dynamic;
  231.     procedure Replace; dynamic;
  232.   public
  233.     constructor Create(AOwner: TComponent); override;
  234.     destructor Destroy; override;
  235.     procedure CloseDialog;
  236.     function Execute: Boolean;
  237.     property Handle: HWnd read FHandle;
  238.     property Left: Integer read GetLeft write SetLeft;
  239.     property Position: TPoint read GetPosition write SetPosition;
  240.     property Top: Integer read GetTop write SetTop;
  241.   published
  242.     property FindText: string read GetFindText write SetFindText;
  243.     property Options: TFindOptions read FOptions write FOptions default [frDown];
  244.     property OnFind: TNotifyEvent read FOnFind write FOnFind;
  245.   end;
  246.  
  247. { TReplaceDialog }
  248.  
  249.   TReplaceDialog = class(TFindDialog)
  250.   public
  251.     constructor Create(AOwner: TComponent); override;
  252.   published
  253.     property ReplaceText;
  254.     property OnReplace;
  255.   end;
  256.  
  257. { Message dialog }
  258.  
  259. type
  260.   TMsgDlgType = (mtWarning, mtError, mtInformation, mtConfirmation, mtCustom);
  261.   TMsgDlgBtn = (mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore,
  262.     mbAll, mbHelp);
  263.   TMsgDlgButtons = set of TMsgDlgBtn;
  264.  
  265. const
  266.   mbYesNoCancel = [mbYes, mbNo, mbCancel];
  267.   mbOKCancel = [mbOK, mbCancel];
  268.   mbAbortRetryIgnore = [mbAbort, mbRetry, mbIgnore];
  269.  
  270. function CreateMessageDialog(const Msg: string; DlgType: TMsgDlgType;
  271.   Buttons: TMsgDlgButtons): TForm;
  272.  
  273. function MessageDlg(const Msg: string; DlgType: TMsgDlgType;
  274.   Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
  275. function MessageDlgPos(const Msg: string; DlgType: TMsgDlgType;
  276.   Buttons: TMsgDlgButtons; HelpCtx: Longint; X, Y: Integer): Integer;
  277.  
  278. procedure ShowMessage(const Msg: string);
  279. procedure ShowMessagePos(const Msg: string; X, Y: Integer);
  280.  
  281. { Input dialog }
  282.  
  283. function InputBox(const ACaption, APrompt, ADefault: string): string;
  284. function InputQuery(const ACaption, APrompt: string;
  285.   var Value: string): Boolean;
  286.  
  287. implementation
  288.  
  289. uses StdCtrls, ExtCtrls, Consts, Printers;
  290.  
  291. { Private globals }
  292.  
  293. var
  294.   HelpMsg: Integer;
  295.   FindMsg: Integer;
  296.   WndProcPtrAtom: TAtom = 0;
  297.   HookCtl3D: Boolean;
  298.  
  299. { Center the given window on the screen }
  300.  
  301. procedure CenterWindow(Wnd: HWnd);
  302. var
  303.   Rect: TRect;
  304. begin
  305.   GetWindowRect(Wnd, Rect);
  306.   SetWindowPos(Wnd, 0,
  307.     (GetSystemMetrics(SM_CXSCREEN) - Rect.Right + Rect.Left) div 2,
  308.     (GetSystemMetrics(SM_CYSCREEN) - Rect.Bottom + Rect.Top) div 3,
  309.     0, 0, SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);
  310. end;
  311.  
  312. { Generic dialog hook. Centers the dialog on the screen in response to
  313.   the WM_INITDIALOG message }
  314.  
  315. function DialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  316. begin
  317.   Result := 0;
  318.   case Msg of
  319.     WM_INITDIALOG:
  320.       begin
  321.         if HookCtl3D then
  322.         begin
  323.           Subclass3DDlg(Wnd, CTL3D_ALL);
  324.           SetAutoSubClass(True);
  325.         end;
  326.         CenterWindow(Wnd);
  327.         Result := 1;
  328.       end;
  329.     WM_DESTROY:
  330.       if HookCtl3D then SetAutoSubClass(False);
  331.   end;
  332. end;
  333.  
  334. { TCommonDialog }
  335.  
  336. constructor TCommonDialog.Create(AOwner: TComponent);
  337. begin
  338.   inherited Create(AOwner);
  339.   FCtl3D := True;
  340. end;
  341.  
  342. function TCommonDialog.Message(var Msg: TMessage): Boolean;
  343. begin
  344.   Result := False;
  345.   if (Msg.Msg = HelpMsg) and (FHelpContext <> 0) then
  346.   begin
  347.     Application.HelpContext(FHelpContext);
  348.     Result := True;
  349.   end;
  350. end;
  351.  
  352. function TCommonDialog.TaskModalDialog(DialogFunc: Pointer; var DialogData): Bool;
  353. type
  354.   TDialogFunc = function(var DialogData): Bool stdcall;
  355. var
  356.   ActiveWindow: HWnd;
  357.   WindowList: Pointer;
  358. begin
  359.   ActiveWindow := GetActiveWindow;
  360.   WindowList := DisableTaskWindows(0);
  361.   try
  362.     Application.HookMainWindow(Message);
  363.     try
  364.       Result := TDialogFunc(DialogFunc)(DialogData);
  365.     finally
  366.       Application.UnhookMainWindow(Message);
  367.     end;
  368.   finally
  369.     EnableTaskWindows(WindowList);
  370.     SetActiveWindow(ActiveWindow);
  371.   end;
  372. end;
  373.  
  374. { Open and Save dialog routines }
  375.  
  376. function ExplorerHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  377. begin
  378.   Result := 0;
  379.   if (Msg = WM_NOTIFY) and (POFNotify(LParam)^.hdr.code = CDN_INITDONE) then
  380.     CenterWindow(GetWindowLong(Wnd, GWL_HWNDPARENT));
  381. end;
  382.  
  383. { TOpenDialog }
  384.  
  385. constructor TOpenDialog.Create(AOwner: TComponent);
  386. begin
  387.   inherited Create(AOwner);
  388.   FHistoryList := TStringList.Create;
  389.   FFiles := TStringList.Create;
  390.   FFilterIndex := 1;
  391.   FFileEditStyle := fsEdit;
  392. end;
  393.  
  394. destructor TOpenDialog.Destroy;
  395. begin
  396.   FFiles.Free;
  397.   FHistoryList.Free;
  398.   inherited Destroy;
  399. end;
  400.  
  401. function TOpenDialog.DoExecute(Func: Pointer): Bool;
  402. const
  403.   MultiSelectBufferSize = 8192;
  404.   OpenOptions: array [TOpenOption] of Longint = (
  405.     OFN_READONLY, OFN_OVERWRITEPROMPT, OFN_HIDEREADONLY,
  406.     OFN_NOCHANGEDIR, OFN_SHOWHELP, OFN_NOVALIDATE, OFN_ALLOWMULTISELECT,
  407.     OFN_EXTENSIONDIFFERENT, OFN_PATHMUSTEXIST, OFN_FILEMUSTEXIST,
  408.     OFN_CREATEPROMPT, OFN_SHAREAWARE, OFN_NOREADONLYRETURN,
  409.     OFN_NOTESTFILECREATE, OFN_NONETWORKBUTTON, OFN_NOLONGNAMES,
  410.     OFN_EXPLORER, OFN_NODEREFERENCELINKS);
  411. var
  412.   Option: TOpenOption;
  413.   P: PChar;
  414.   CDefaultExt: array[0..3] of Char;
  415.   OpenFilename: TOpenFilename;
  416.  
  417.   function AllocFilterStr(const S: string): PChar;
  418.   var
  419.     P: PChar;
  420.   begin
  421.     Result := nil;
  422.     if S <> '' then
  423.     begin
  424.       Result := StrCopy(StrAlloc(Length(S) + 2), PChar(S));
  425.       P := Result;
  426.       while P^ <> #0 do
  427.       begin
  428.         if (P^ in LeadBytes) and ((P+1)^ <> #0) then Inc(P)
  429.         else if P^ = '|' then P^ := #0;
  430.         Inc(P);
  431.       end;
  432.       Inc(P);
  433.       P^ := #0;
  434.     end;
  435.   end;
  436.  
  437.   function FindExtension(P: PChar): PChar;
  438.   begin
  439.     Result := '';
  440.     while P^ <> #0 do
  441.     begin
  442.       if (P^ in LeadBytes) and ((P+1)^ <> #0) then Inc(P)
  443.       else if P^ = '.' then Result := P + 1
  444.       else if P^ = '\' then Result := '';
  445.       Inc(P);
  446.     end;
  447.   end;
  448.  
  449.   function ExtractFileName(P: PChar; var S: string): PChar;
  450.   var
  451.     Separator: Char;
  452.   begin
  453.     Separator := #0;
  454.     if (ofAllowMultiSelect in FOptions) and
  455.       ((ofOldStyleDialog in FOptions) or not NewStyleControls) then
  456.       Separator := ' ';
  457.     Result := P;
  458.     while (Result[0] <> #0) and (Result[0] <> Separator) do Inc(Result);
  459.     SetString(S, P, Result - P);
  460.     if Result[0] = Separator then Inc(Result);
  461.   end;
  462.  
  463.   procedure ExtractFileNames(P: PChar);
  464.   var
  465.     DirName, FileName: string;
  466.   begin
  467.     P := ExtractFileName(P, DirName);
  468.     P := ExtractFileName(P, FileName);
  469.     if FileName = '' then
  470.       FFiles.Add(DirName)
  471.     else
  472.     begin
  473.       if not IsPathDelimiter(DirName, Length(DirName)) then
  474.         DirName := DirName + '\';
  475.       repeat
  476.         if (FileName[1] <> '\') and ((Length(FileName) <= 3) or
  477.           (FileName[2] <> ':') or (FileName[3] <> '\')) then
  478.           FileName := DirName + FileName;
  479.         FFiles.Add(FileName);
  480.         P := ExtractFileName(P, FileName);
  481.       until FileName = '';
  482.     end;
  483.   end;
  484.  
  485. begin
  486.   FFiles.Clear;
  487.   FillChar(OpenFileName, SizeOf(OpenFileName), 0);
  488.   with OpenFilename do
  489.   try
  490.     lStructSize := SizeOf(TOpenFilename);
  491.     hInstance := System.HInstance;
  492.     lpstrFilter := AllocFilterStr(FFilter);
  493.     nFilterIndex := FFilterIndex;
  494.     if ofAllowMultiSelect in FOptions then
  495.       nMaxFile := MultiSelectBufferSize else
  496.       nMaxFile := MAX_PATH;
  497.     GetMem(lpstrFile, nMaxFile + 2);
  498.     FillChar(lpstrFile^, nMaxFile + 2, 0);
  499.     StrLCopy(lpstrFile, PChar(FFileName), nMaxFile);
  500.     lpstrInitialDir := PChar(FInitialDir);
  501.     lpstrTitle := PChar(FTitle);
  502.     HookCtl3D := FCtl3D;
  503.     Flags := OFN_ENABLEHOOK;
  504.     for Option := Low(Option) to High(Option) do
  505.       if Option in FOptions then
  506.         Flags := Flags or OpenOptions[Option];
  507.     if NewStyleControls then
  508.       Flags := Flags xor OFN_EXPLORER
  509.     else
  510.       Flags := Flags and not OFN_EXPLORER;
  511.     if FDefaultExt <> '' then
  512.     begin
  513.       P := PChar(FDefaultExt);
  514.       if (P^ = #0) and (Flags and OFN_EXPLORER = 0) then
  515.         P := FindExtension(PChar(FFileName));
  516.       lpstrDefExt := StrLCopy(CDefaultExt, P, 3)
  517.     end;
  518.     if (ofOldStyleDialog in Options) or not NewStyleControls then
  519.       lpfnHook := DialogHook
  520.     else
  521.       lpfnHook := ExplorerHook;
  522.     hWndOwner := Application.Handle;
  523.     Result := TaskModalDialog(Func, OpenFileName);
  524.     if Result then
  525.     begin
  526.       if ofAllowMultiSelect in FOptions then
  527.       begin
  528.         ExtractFileNames(lpstrFile);
  529.         FFileName := FFiles[0];
  530.       end else
  531.       begin
  532.         ExtractFileName(lpstrFile, FFileName);
  533.         FFiles.Add(FFileName);
  534.       end;
  535.       if (Flags and OFN_EXTENSIONDIFFERENT) <> 0 then
  536.         Include(FOptions, ofExtensionDifferent) else
  537.         Exclude(FOptions, ofExtensionDifferent);
  538.       if (Flags and OFN_READONLY) <> 0 then
  539.         Include(FOptions, ofReadOnly) else
  540.         Exclude(FOptions, ofReadOnly);
  541.       FFilterIndex := nFilterIndex;
  542.     end;
  543.   finally
  544.     if lpstrFile <> nil then FreeMem(lpstrFile, nMaxFile + 2);
  545.     if lpstrFilter <> nil then StrDispose(lpstrFilter);
  546.   end;
  547. end;
  548.  
  549. procedure TOpenDialog.SetHistoryList(Value: TStrings);
  550. begin
  551.   FHistoryList.Assign(Value);
  552. end;
  553.  
  554. procedure TOpenDialog.SetInitialDir(const Value: string);
  555. var
  556.   L: Integer;
  557. begin
  558.   L := Length(Value);
  559.   if (L > 1) and IsPathDelimiter(Value, L)
  560.     and not IsDelimiter(':', Value, L - 1) then Dec(L);
  561.   FInitialDir := Copy(Value, 1, L);
  562. end;
  563.  
  564. function TOpenDialog.Execute: Boolean;
  565. begin
  566.   Result := DoExecute(@GetOpenFileName);
  567. end;
  568.  
  569. { TSaveDialog }
  570.  
  571. function TSaveDialog.Execute: Boolean;
  572. begin
  573.   Result := DoExecute(@GetSaveFileName);
  574. end;
  575.  
  576. { TColorDialog }
  577.  
  578. constructor TColorDialog.Create(AOwner: TComponent);
  579. begin
  580.   inherited Create(AOwner);
  581.   FCustomColors := TStringList.Create;
  582. end;
  583.  
  584. destructor TColorDialog.Destroy;
  585. begin
  586.   FCustomColors.Free;
  587.   inherited Destroy;
  588. end;
  589.  
  590. function TColorDialog.Execute: Boolean;
  591. const
  592.   DialogOptions: array[TColorDialogOption] of LongInt = (
  593.     CC_FULLOPEN, CC_PREVENTFULLOPEN, CC_SHOWHELP, CC_SOLIDCOLOR,
  594.     CC_ANYCOLOR);
  595. var
  596.   ChooseColorRec: TChooseColor;
  597.   Option: TColorDialogOption;
  598.   CustomColorsArray: TCustomColors;
  599.   ColorPrefix, ColorTags: string;
  600.  
  601.   procedure GetCustomColorsArray;
  602.   var
  603.     I: Integer;
  604.   begin
  605.     for I := 0 to MaxCustomColors - 1 do
  606.       FCustomColors.Values[ColorPrefix + ColorTags[I + 1]] :=
  607.         Format('%.6x', [CustomColorsArray[I]]);
  608.   end;
  609.  
  610.   procedure SetCustomColorsArray;
  611.   var
  612.     Value: string;
  613.     I: Integer;
  614.   begin
  615.     for I := 0 to MaxCustomColors - 1 do
  616.     begin
  617.       Value := FCustomColors.Values[ColorPrefix + ColorTags[I + 1]];
  618.       if Value <> '' then
  619.         CustomColorsArray[I] := StrToInt('$' + Value) else
  620.         CustomColorsArray[I] := -1;
  621.     end;
  622.   end;
  623.  
  624. begin
  625.   ColorPrefix := LoadStr(SColorPrefix);
  626.   ColorTags := LoadStr(SColorTags);
  627.   with ChooseColorRec do
  628.   begin
  629.     SetCustomColorsArray;
  630.     lStructSize := SizeOf(ChooseColorRec);
  631.     rgbResult := ColorToRGB(FColor);
  632.     lpCustColors := @CustomColorsArray;
  633.     Flags := CC_RGBINIT or CC_ENABLEHOOK;
  634.     for Option := Low(Option) to High(Option) do
  635.       if Option in FOptions then
  636.         Flags := Flags or DialogOptions[Option];
  637.     HookCtl3D := FCtl3D;
  638.     lpfnHook := DialogHook;
  639.     hWndOwner := Application.Handle;
  640.     Result := TaskModalDialog(@ChooseColor, ChooseColorRec);
  641.     if Result then
  642.     begin
  643.       FColor := rgbResult;
  644.       GetCustomColorsArray;
  645.     end;
  646.   end;
  647. end;
  648.  
  649. procedure TColorDialog.SetCustomColors(Value: TStrings);
  650. begin
  651.   FCustomColors.Assign(Value);
  652. end;
  653.  
  654. { TFontDialog }
  655.  
  656. const
  657.   IDAPPLYBTN = $402;
  658.  
  659. var
  660.   FontDialog: TFontDialog;
  661.  
  662. function FontDialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  663. begin
  664.   if (Msg = WM_COMMAND) and (LongRec(WParam).Lo = IDAPPLYBTN) and
  665.     (LongRec(WParam).Hi = BN_CLICKED) then
  666.   begin
  667.     FontDialog.DoApply(Wnd);
  668.     Result := 1;
  669.   end else
  670.     Result := DialogHook(Wnd, Msg, wParam, lParam);
  671. end;
  672.  
  673. constructor TFontDialog.Create(AOwner: TComponent);
  674. begin
  675.   inherited Create(AOwner);
  676.   FFont := TFont.Create;
  677.   FOptions := [fdEffects];
  678. end;
  679.  
  680. destructor TFontDialog.Destroy;
  681. begin
  682.   FFont.Free;
  683.   inherited Destroy;
  684. end;
  685.  
  686. procedure TFontDialog.Apply(Wnd: HWND);
  687. begin
  688.   if Assigned(FOnApply) then FOnApply(Self, Wnd);
  689. end;
  690.  
  691. procedure TFontDialog.DoApply(Wnd: HWND);
  692. const
  693.   IDCOLORCMB = $473;
  694. var
  695.   I: Integer;
  696.   LogFont: TLogFont;
  697. begin
  698.   SendMessage(Wnd, WM_CHOOSEFONT_GETLOGFONT, 0, LongInt(@LogFont));
  699.   UpdateFromLogFont(LogFont);
  700.   I := SendDlgItemMessage(Wnd, IDCOLORCMB, CB_GETCURSEL, 0, 0);
  701.   if I <> CB_ERR then
  702.     Font.Color := SendDlgItemMessage(Wnd, IDCOLORCMB, CB_GETITEMDATA, I, 0);
  703.   try
  704.     Apply(Wnd);
  705.   except
  706.     Application.HandleException(Self);
  707.   end;
  708. end;
  709.  
  710. function TFontDialog.Execute: Boolean;
  711. const
  712.   FontOptions: array[TFontDialogOption] of Longint = (
  713.     CF_ANSIONLY, CF_TTONLY, CF_EFFECTS, CF_FIXEDPITCHONLY, CF_FORCEFONTEXIST,
  714.     CF_NOFACESEL, CF_NOOEMFONTS, CF_NOSIMULATIONS, CF_NOSIZESEL,
  715.     CF_NOSTYLESEL, CF_NOVECTORFONTS, CF_SHOWHELP, CF_WYSIWYG, CF_LIMITSIZE,
  716.     CF_SCALABLEONLY, CF_APPLY);
  717.   Devices: array[TFontDialogDevice] of Longint = (
  718.     CF_SCREENFONTS, CF_PRINTERFONTS, CF_BOTH);
  719. var
  720.   ChooseFontRec: TChooseFont;
  721.   LogFont: TLogFont;
  722.   Option: TFontDialogOption;
  723.   SaveFontDialog: TFontDialog;
  724. begin
  725.   with ChooseFontRec do
  726.   begin
  727.     lStructSize := SizeOf(ChooseFontRec);
  728.     hDC := 0;
  729.     lpLogFont := @LogFont;
  730.     GetObject(Font.Handle, SizeOf(LogFont), @LogFont);
  731.     Flags := Devices[FDevice] or (CF_INITTOLOGFONTSTRUCT or CF_ENABLEHOOK);
  732.     for Option := Low(Option) to High(Option) do
  733.       if Option in FOptions then
  734.         Flags := Flags or FontOptions[Option];
  735.     if Assigned(FOnApply) then Flags := Flags or CF_APPLY;
  736.     rgbColors := Font.Color;
  737.     lCustData := 0;
  738.     HookCtl3D := Ctl3D;
  739.     lpfnHook := FontDialogHook;
  740.     nSizeMin := FMinFontSize;
  741.     nSizeMax := FMaxFontSize;
  742.     if nSizeMin > nSizeMax then Flags := Flags and (not CF_LIMITSIZE);
  743.     hWndOwner := Application.Handle;
  744.     SaveFontDialog := FontDialog;
  745.     FontDialog := Self;
  746.     Result := TaskModalDialog(@ChooseFont, ChooseFontRec);
  747.     FontDialog := SaveFontDialog;
  748.     if Result then
  749.     begin
  750.       UpdateFromLogFont(LogFont);
  751.       Font.Color := rgbColors;
  752.     end;
  753.   end;
  754. end;
  755.  
  756. procedure TFontDialog.SetFont(Value: TFont);
  757. begin
  758.   FFont.Assign(Value);
  759. end;
  760.  
  761. procedure TFontDialog.UpdateFromLogFont(const LogFont: TLogFont);
  762. var
  763.   Style: TFontStyles;
  764. begin
  765.   with LogFont do
  766.   begin
  767.     Font.Name := LogFont.lfFaceName;
  768.     Font.Height := LogFont.lfHeight;
  769.     Font.Charset := TFontCharset(LogFont.lfCharSet);
  770.     Style := [];
  771.     with LogFont do
  772.     begin
  773.       if lfWeight > FW_REGULAR then Include(Style, fsBold);
  774.       if lfItalic <> 0 then Include(Style, fsItalic);
  775.       if lfUnderline <> 0 then Include(Style, fsUnderline);
  776.       if lfStrikeOut <> 0 then Include(Style, fsStrikeOut);
  777.     end;
  778.     Font.Style := Style;
  779.   end;
  780. end;
  781.  
  782. { Printer dialog routines }
  783.  
  784. procedure GetPrinter(var DeviceMode, DeviceNames: THandle);
  785. var
  786.   Device, Driver, Port: array[0..79] of char;
  787.   DevNames: PDevNames;
  788.   Offset: PChar;
  789. begin
  790.   Printer.GetPrinter(Device, Driver, Port, DeviceMode);
  791.   if DeviceMode <> 0 then
  792.   begin
  793.     DeviceNames := GlobalAlloc(GHND, SizeOf(TDevNames) +
  794.      StrLen(Device) + StrLen(Driver) + StrLen(Port) + 3);
  795.     DevNames := PDevNames(GlobalLock(DeviceNames));
  796.     try
  797.       Offset := PChar(DevNames) + SizeOf(TDevnames);
  798.       with DevNames^ do
  799.       begin
  800.         wDriverOffset := Longint(Offset) - Longint(DevNames);
  801.         Offset := StrECopy(Offset, Driver) + 1;
  802.         wDeviceOffset := Longint(Offset) - Longint(DevNames);
  803.         Offset := StrECopy(Offset, Device) + 1;
  804.         wOutputOffset := Longint(Offset) - Longint(DevNames);;
  805.         StrCopy(Offset, Port);
  806.       end;
  807.     finally
  808.       GlobalUnlock(DeviceNames);
  809.     end;
  810.   end;
  811. end;
  812.  
  813. procedure SetPrinter(DeviceMode, DeviceNames: THandle);
  814. var
  815.   DevNames: PDevNames;
  816. begin
  817.   DevNames := PDevNames(GlobalLock(DeviceNames));
  818.   try
  819.     with DevNames^ do
  820.       Printer.SetPrinter(PChar(DevNames) + wDeviceOffset,
  821.         PChar(DevNames) + wDriverOffset,
  822.         PChar(DevNames) + wOutputOffset, DeviceMode);
  823.   finally
  824.     GlobalUnlock(DeviceNames);
  825.     GlobalFree(DeviceNames);
  826.   end;
  827. end;
  828.  
  829. function CopyData(Handle: THandle): THandle;
  830. var
  831.   Src, Dest: PChar;
  832.   Size: Integer;
  833. begin
  834.   if Handle <> 0 then
  835.   begin
  836.     Size := GlobalSize(Handle);
  837.     Result := GlobalAlloc(GHND, Size);
  838.     if Result <> 0 then
  839.       try
  840.         Src := GlobalLock(Handle);
  841.         Dest := GlobalLock(Result);
  842.         if (Src <> nil) and (Dest <> nil) then Move(Src^, Dest^, Size);
  843.       finally
  844.         GlobalUnlock(Handle);
  845.         GlobalUnlock(Result);
  846.       end
  847.   end
  848.   else Result := 0;
  849. end;
  850.  
  851. { TPrinterSetupDialog }
  852.  
  853. procedure TPrinterSetupDialog.Execute;
  854. var
  855.   PrintDlgRec: TPrintDlg;
  856.   DevHandle: THandle;
  857. begin
  858.   FillChar(PrintDlgRec, SizeOf(PrintDlgRec), 0);
  859.   with PrintDlgRec do
  860.   begin
  861.     lStructSize := SizeOf(PrintDlgRec);
  862.     hInstance := System.HInstance;
  863.     GetPrinter(DevHandle, hDevNames);
  864.     hDevMode := CopyData(DevHandle);
  865.     Flags := PD_ENABLESETUPHOOK or PD_PRINTSETUP;
  866.     HookCtl3D := Ctl3D;
  867.     lpfnSetupHook := DialogHook;
  868.     hWndOwner := Application.Handle;
  869.     if TaskModalDialog(@PrintDlg, PrintDlgRec) then
  870.       SetPrinter(hDevMode, hDevNames)
  871.     else begin
  872.       if hDevMode <> 0 then GlobalFree(hDevMode);
  873.       if hDevNames <> 0 then GlobalFree(hDevNames);
  874.     end;
  875.   end;
  876. end;
  877.  
  878. { TPrintDialog }
  879.  
  880. procedure TPrintDialog.SetNumCopies(Value: Integer);
  881. begin
  882.   FCopies := Value;
  883.   Printer.Copies := Value;
  884. end;
  885.  
  886. function TPrintDialog.Execute: Boolean;
  887. const
  888.   PrintRanges: array[TPrintRange] of Integer =
  889.     (PD_ALLPAGES, PD_SELECTION, PD_PAGENUMS);
  890. var
  891.   PrintDlgRec: TPrintDlg;
  892.   DevHandle: THandle;
  893. begin
  894.   FillChar(PrintDlgRec, SizeOf(PrintDlgRec), 0);
  895.   with PrintDlgRec do
  896.   begin
  897.     lStructSize := SizeOf(PrintDlgRec);
  898.     hInstance := System.HInstance;
  899.     GetPrinter(DevHandle, hDevNames);
  900.     hDevMode := CopyData(DevHandle);
  901.     Flags := PrintRanges[FPrintRange] or (PD_ENABLEPRINTHOOK or
  902.       PD_ENABLESETUPHOOK);
  903.     if FCollate then Inc(Flags, PD_COLLATE);
  904.     if not (poPrintToFile in FOptions) then Inc(Flags, PD_HIDEPRINTTOFILE);
  905.     if not (poPageNums in FOptions) then Inc(Flags, PD_NOPAGENUMS);
  906.     if not (poSelection in FOptions) then Inc(Flags, PD_NOSELECTION);
  907.     if poDisablePrintToFile in FOptions then Inc(Flags, PD_DISABLEPRINTTOFILE);
  908.     if FPrintToFile then Inc(Flags, PD_PRINTTOFILE);
  909.     if poHelp in FOptions then Inc(Flags, PD_SHOWHELP);
  910.     if not (poWarning in FOptions) then Inc(Flags, PD_NOWARNING);
  911.     nFromPage := FFromPage;
  912.     nToPage := FToPage;
  913.     nMinPage := FMinPage;
  914.     nMaxPage := FMaxPage;
  915.     HookCtl3D := Ctl3D;
  916.     lpfnPrintHook := DialogHook;
  917.     lpfnSetupHook := DialogHook;
  918.     hWndOwner := Application.Handle;
  919.     Result := TaskModalDialog(@PrintDlg, PrintDlgRec);
  920.     if Result then
  921.     begin
  922.       SetPrinter(hDevMode, hDevNames);
  923.       FCollate := Flags and PD_COLLATE <> 0;
  924.       FPrintToFile := Flags and PD_PRINTTOFILE <> 0;
  925.       if Flags and PD_SELECTION <> 0 then FPrintRange := prSelection else
  926.         if Flags and PD_PAGENUMS <> 0 then FPrintRange := prPageNums else
  927.           FPrintRange := prAllPages;
  928.       FFromPage := nFromPage;
  929.       FToPage := nToPage;
  930.       if nCopies = 1 then
  931.         Copies := Printer.Copies else
  932.         Copies := nCopies;
  933.     end
  934.     else begin
  935.       if hDevMode <> 0 then GlobalFree(hDevMode);
  936.       if hDevNames <> 0 then GlobalFree(hDevNames);
  937.     end;
  938.   end;
  939. end;
  940.  
  941. { TRedirectorWindow }
  942. { A redirector window is used to put the find/replace dialog into the
  943.   ownership chain of a form, but intercept messages that CommDlg.dll sends
  944.   exclusively to the find/replace dialog's owner.  TRedirectorWindow
  945.   creates its hidden window handle as owned by the target form, and the
  946.   find/replace dialog handle is created as owned by the redirector.  The
  947.   redirector wndproc forwards all messages to the find/replace component.
  948. }
  949.  
  950. type
  951.   TRedirectorWindow = class(TWinControl)
  952.   private
  953.     FFindReplaceDialog: TFindDialog;
  954.     FFormHandle: THandle;
  955.     procedure CMRelease(var Message); message CM_Release;
  956.   protected
  957.     procedure CreateParams(var Params: TCreateParams); override;
  958.     procedure WndProc(var Message: TMessage); override;
  959.   end;
  960.  
  961. procedure TRedirectorWindow.CreateParams(var Params: TCreateParams);
  962. begin
  963.   inherited CreateParams(Params);
  964.   with Params do
  965.   begin
  966.     Style := WS_VISIBLE or WS_POPUP;
  967.     WndParent := FFormHandle;
  968.   end;
  969. end;
  970.  
  971. procedure TRedirectorWindow.WndProc(var Message: TMessage);
  972. begin
  973.   inherited WndProc(Message);
  974.   if (Message.Result = 0) and Assigned(FFindReplaceDialog) then
  975.     Message.Result := Integer(FFindReplaceDialog.Message(Message));
  976. end;
  977.  
  978. procedure TRedirectorWindow.CMRelease(var Message);
  979. begin
  980.   Free;
  981. end;
  982.  
  983. { Find and Replace dialog routines }
  984.  
  985. function FindReplaceWndProc(Wnd: HWND; Msg, WParam, LParam: Longint): Longint; stdcall;
  986.  
  987.   function CallDefWndProc: Longint;
  988.   begin
  989.     Result := CallWindowProc(Pointer(GetProp(Wnd,
  990.       MakeIntAtom(WndProcPtrAtom))), Wnd, Msg, WParam, LParam);
  991.   end;
  992.  
  993. begin
  994.   case Msg of
  995.     WM_DESTROY:
  996.       if Application.DialogHandle = Wnd then Application.DialogHandle := 0;
  997.     WM_NCACTIVATE:
  998.       if WParam <> 0 then
  999.       begin
  1000.         if Application.DialogHandle = 0 then Application.DialogHandle := Wnd;
  1001.       end else
  1002.       begin
  1003.         if Application.DialogHandle = Wnd then Application.DialogHandle := 0;
  1004.       end;
  1005.     WM_NCDESTROY:
  1006.       begin
  1007.         Result := CallDefWndProc;
  1008.         RemoveProp(Wnd, MakeIntAtom(WndProcPtrAtom));
  1009.         Exit;
  1010.       end;
  1011.    end;
  1012.    Result := CallDefWndProc;
  1013. end;
  1014.  
  1015. function FindReplaceDialogHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
  1016. begin
  1017.   Result := DialogHook(Wnd, Msg, wParam, lParam);
  1018.   if Msg = WM_INITDIALOG then
  1019.   begin
  1020.     with TFindDialog(PFindReplace(LParam)^.lCustData) do
  1021.       if (Left <> -1) or (Top <> -1) then
  1022.         SetWindowPos(Wnd, 0, Left, Top, 0, 0, SWP_NOACTIVATE or
  1023.           SWP_NOSIZE or SWP_NOZORDER);
  1024.     SetProp(Wnd, MakeIntAtom(WndProcPtrAtom), GetWindowLong(Wnd, GWL_WNDPROC));
  1025.     SetWindowLong(Wnd, GWL_WNDPROC, Longint(@FindReplaceWndProc));
  1026.     Result := 1;
  1027.   end;
  1028. end;
  1029.  
  1030. const
  1031.   FindOptions: array[TFindOption] of Longint = (
  1032.     FR_DOWN, FR_FINDNEXT, FR_HIDEMATCHCASE, FR_HIDEWHOLEWORD,
  1033.     FR_HIDEUPDOWN, FR_MATCHCASE, FR_NOMATCHCASE, FR_NOUPDOWN, FR_NOWHOLEWORD,
  1034.     FR_REPLACE, FR_REPLACEALL, FR_WHOLEWORD, FR_SHOWHELP);
  1035.  
  1036. { TFindDialog }
  1037.  
  1038. constructor TFindDialog.Create(AOwner: TComponent);
  1039. begin
  1040.   inherited Create(AOwner);
  1041.   FOptions := [frDown];
  1042.   FPosition.X := -1;
  1043.   FPosition.Y := -1;
  1044.   with FFindReplace do
  1045.   begin
  1046.     lStructSize := SizeOf(TFindReplace);
  1047.     hWndOwner := Application.Handle;
  1048.     hInstance := System.HInstance;
  1049.     lpstrFindWhat := FFindText;
  1050.     wFindWhatLen := SizeOf(FFindText);
  1051.     lpstrReplaceWith := FReplaceText;
  1052.     wReplaceWithLen := SizeOf(FReplaceText);
  1053.     lCustData := Longint(Self);
  1054.     lpfnHook := FindReplaceDialogHook;
  1055.   end;
  1056.   FFindReplaceFunc := @CommDlg.FindText;
  1057. end;
  1058.  
  1059. destructor TFindDialog.Destroy;
  1060. begin
  1061.   if FHandle <> 0 then SendMessage(FHandle, WM_CLOSE, 0, 0);
  1062.   FRedirector.Free;
  1063.   inherited Destroy;
  1064. end;
  1065.  
  1066. procedure TFindDialog.CloseDialog;
  1067. begin
  1068.   if FHandle <> 0 then PostMessage(FHandle, WM_CLOSE, 0, 0);
  1069. end;
  1070.  
  1071. function GetTopWindow(Wnd: THandle; var ReturnVar: THandle):Bool; stdcall;
  1072. var
  1073.   Test: TWinControl;
  1074. begin
  1075.   Test := FindControl(Wnd);
  1076.   Result := True;
  1077.   if Assigned(Test) and (Test is TForm) then
  1078.   begin
  1079.     ReturnVar := Wnd;
  1080.     Result := False;
  1081.    end;
  1082. end;
  1083.  
  1084. function TFindDialog.Execute: Boolean;
  1085. var
  1086.   Option: TFindOption;
  1087. begin
  1088.   if FHandle <> 0 then
  1089.   begin
  1090.     BringWindowToTop(FHandle);
  1091.     Result := True;
  1092.   end else
  1093.   begin
  1094.     HookCtl3D := Ctl3D;
  1095.     FFindReplace.Flags := FR_ENABLEHOOK;
  1096.     FFindReplace.lpfnHook := FindReplaceDialogHook;
  1097.     FRedirector := TRedirectorWindow.Create(nil);
  1098.     with TRedirectorWindow(FRedirector) do
  1099.     begin
  1100.       FFindReplaceDialog := Self;
  1101.       EnumThreadWindows(GetCurrentThreadID, @GetTopWindow, LPARAM(@FFormHandle));
  1102.     end;
  1103.     FFindReplace.hWndOwner := FRedirector.Handle;
  1104.     for Option := Low(Option) to High(Option) do
  1105.       if Option in FOptions then
  1106.         FFindReplace.Flags := FFindReplace.Flags or FindOptions[Option];
  1107.     FHandle := FFindReplaceFunc(FFindReplace);
  1108.     Result := FHandle <> 0;
  1109.   end;
  1110. end;
  1111.  
  1112. procedure TFindDialog.Find;
  1113. begin
  1114.   if Assigned(FOnFind) then FOnFind(Self);
  1115. end;
  1116.  
  1117. function TFindDialog.GetFindText: string;
  1118. begin
  1119.   Result := FFindText;
  1120. end;
  1121.  
  1122. function TFindDialog.GetLeft: Integer;
  1123. begin
  1124.   Result := Position.X;
  1125. end;
  1126.  
  1127. function TFindDialog.GetPosition: TPoint;
  1128. var
  1129.   Rect: TRect;
  1130. begin
  1131.   Result := FPosition;
  1132.   if FHandle <> 0 then
  1133.   begin
  1134.     GetWindowRect(FHandle, Rect);
  1135.     Result := Rect.TopLeft;
  1136.   end;
  1137. end;
  1138.  
  1139. function TFindDialog.GetReplaceText: string;
  1140. begin
  1141.   Result := FReplaceText;
  1142. end;
  1143.  
  1144. function TFindDialog.GetTop: Integer;
  1145. begin
  1146.   Result := Position.Y;
  1147. end;
  1148.  
  1149. function TFindDialog.Message(var Msg: TMessage): Boolean;
  1150. var
  1151.   Option: TFindOption;
  1152.   Rect: TRect;
  1153. begin
  1154.   Result := inherited Message(Msg);
  1155.   if not Result then
  1156.     if (Msg.Msg = FindMsg) and (Pointer(Msg.LParam) = @FFindReplace) then
  1157.     begin
  1158.       FOptions := [];
  1159.       for Option := Low(Option) to High(Option) do
  1160.         if (FFindReplace.Flags and FindOptions[Option]) <> 0 then
  1161.           Include(FOptions, Option);
  1162.       if (FFindReplace.Flags and FR_FINDNEXT) <> 0 then
  1163.         Find
  1164.       else
  1165.       if (FFindReplace.Flags and (FR_REPLACE or FR_REPLACEALL)) <> 0 then
  1166.         Replace
  1167.       else
  1168.       if (FFindReplace.Flags and FR_DIALOGTERM) <> 0 then
  1169.       begin
  1170.         GetWindowRect(FHandle, Rect);
  1171.         FPosition := Rect.TopLeft;
  1172.         FHandle := 0;
  1173.         PostMessage(FRedirector.Handle,CM_RELEASE,0,0); // free redirector later
  1174.         FRedirector := nil;
  1175.       end;
  1176.       Result := True;
  1177.     end;
  1178. end;
  1179.  
  1180. procedure TFindDialog.Replace;
  1181. begin
  1182.   if Assigned(FOnReplace) then FOnReplace(Self);
  1183. end;
  1184.  
  1185. procedure TFindDialog.SetFindText(const Value: string);
  1186. begin
  1187.   StrLCopy(FFindText, PChar(Value), SizeOf(FFindText) - 1);
  1188. end;
  1189.  
  1190. procedure TFindDialog.SetLeft(Value: Integer);
  1191. begin
  1192.   SetPosition(Point(Value, Top));
  1193. end;
  1194.  
  1195. procedure TFindDialog.SetPosition(const Value: TPoint);
  1196. begin
  1197.   if (FPosition.X <> Value.X) or (FPosition.Y <> Value.Y) then
  1198.   begin
  1199.     FPosition := Value;
  1200.     if FHandle <> 0 then
  1201.       SetWindowPos(FHandle, 0, Value.X, Value.Y, 0, 0,
  1202.         SWP_NOACTIVATE or SWP_NOSIZE or SWP_NOZORDER);
  1203.   end;
  1204. end;
  1205.  
  1206. procedure TFindDialog.SetReplaceText(const Value: string);
  1207. begin
  1208.   StrLCopy(FReplaceText, PChar(Value), SizeOf(FReplaceText) - 1);
  1209. end;
  1210.  
  1211. procedure TFindDialog.SetTop(Value: Integer);
  1212. begin
  1213.   SetPosition(Point(Left, Value));
  1214. end;
  1215.  
  1216. { TReplaceDialog }
  1217.  
  1218. constructor TReplaceDialog.Create(AOwner: TComponent);
  1219. begin
  1220.   inherited Create(AOwner);
  1221.   FFindReplaceFunc := CommDlg.ReplaceText;
  1222. end;
  1223.  
  1224. { Message dialog }
  1225.  
  1226. function Max(I, J: Integer): Integer;
  1227. begin
  1228.   if I > J then Result := I else Result := J;
  1229. end;
  1230.  
  1231. function GetAveCharSize(Canvas: TCanvas): TPoint;
  1232. var
  1233.   I: Integer;
  1234.   Buffer: array[0..51] of Char;
  1235. begin
  1236.   for I := 0 to 25 do Buffer[I] := Chr(I + Ord('A'));
  1237.   for I := 0 to 25 do Buffer[I + 26] := Chr(I + Ord('a'));
  1238.   GetTextExtentPoint(Canvas.Handle, Buffer, 52, TSize(Result));
  1239.   Result.X := Result.X div 52;
  1240. end;
  1241.  
  1242. type
  1243.   TMessageForm = class(TForm)
  1244.   private
  1245.     procedure HelpButtonClick(Sender: TObject);
  1246.   end;
  1247.  
  1248. procedure TMessageForm.HelpButtonClick(Sender: TObject);
  1249. begin
  1250.   Application.HelpContext(HelpContext);
  1251. end;
  1252.  
  1253. function CreateMessageDialog(const Msg: string; DlgType: TMsgDlgType;
  1254.   Buttons: TMsgDlgButtons): TForm;
  1255. const
  1256.   mcHorzMargin = 8;
  1257.   mcVertMargin = 8;
  1258.   mcHorzSpacing = 10;
  1259.   mcVertSpacing = 10;
  1260.   mcButtonWidth = 50;
  1261.   mcButtonHeight = 14;
  1262.   mcButtonSpacing = 4;
  1263. const
  1264.   Captions: array[TMsgDlgType] of Word = (SMsgDlgWarning, SMsgDlgError,
  1265.     SMsgDlgInformation, SMsgDlgConfirm, 0);
  1266.   IconIDs: array[TMsgDlgType] of PChar = (IDI_EXCLAMATION, IDI_HAND,
  1267.     IDI_ASTERISK, IDI_QUESTION, nil);
  1268.   ButtonNames: array[TMsgDlgBtn] of string = (
  1269.     'Yes', 'No', 'OK', 'Cancel', 'Abort', 'Retry', 'Ignore', 'All', 'Help');
  1270.   ButtonCaptions: array[TMsgDlgBtn] of Word = (
  1271.     SMsgDlgYes, SMsgDlgNo, SMsgDlgOK, SMsgDlgCancel, SMsgDlgAbort,
  1272.     SMsgDlgRetry, SMsgDlgIgnore, SMsgDlgAll, SMsgDlgHelp);
  1273.   ModalResults: array[TMsgDlgBtn] of Integer = (
  1274.     mrYes, mrNo, mrOk, mrCancel, mrAbort, mrRetry, mrIgnore, mrAll, 0);
  1275. var
  1276.   DialogUnits: TPoint;
  1277.   HorzMargin, VertMargin, HorzSpacing, VertSpacing, ButtonWidth,
  1278.   ButtonHeight, ButtonSpacing, ButtonCount, ButtonGroupWidth,
  1279.   IconTextWidth, IconTextHeight, X: Integer;
  1280.   B, DefaultButton, CancelButton: TMsgDlgBtn;
  1281.   IconID: PChar;
  1282.   TextRect: TRect;
  1283. begin
  1284.   Result := TMessageForm.CreateNew(Application, 1);
  1285.   with Result do
  1286.   begin
  1287.     BorderStyle := bsDialog;
  1288.     Canvas.Font := Font;
  1289.     DialogUnits := GetAveCharSize(Canvas);
  1290.     HorzMargin := MulDiv(mcHorzMargin, DialogUnits.X, 4);
  1291.     VertMargin := MulDiv(mcVertMargin, DialogUnits.Y, 8);
  1292.     HorzSpacing := MulDiv(mcHorzSpacing, DialogUnits.X, 4);
  1293.     VertSpacing := MulDiv(mcVertSpacing, DialogUnits.Y, 8);
  1294.     ButtonWidth := MulDiv(mcButtonWidth, DialogUnits.X, 4);
  1295.     ButtonHeight := MulDiv(mcButtonHeight, DialogUnits.Y, 8);
  1296.     ButtonSpacing := MulDiv(mcButtonSpacing, DialogUnits.X, 4);
  1297.     SetRect(TextRect, 0, 0, Screen.Width div 2, 0);
  1298.     DrawText(Canvas.Handle, PChar(Msg), -1, TextRect,
  1299.       DT_CALCRECT or DT_WORDBREAK);
  1300.     IconID := IconIDs[DlgType];
  1301.     IconTextWidth := TextRect.Right;
  1302.     IconTextHeight := TextRect.Bottom;
  1303.     if IconID <> nil then
  1304.     begin
  1305.       Inc(IconTextWidth, 32 + HorzSpacing);
  1306.       if IconTextHeight < 32 then IconTextHeight := 32;
  1307.     end;
  1308.     ButtonCount := 0;
  1309.     for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do
  1310.       if B in Buttons then Inc(ButtonCount);
  1311.     ButtonGroupWidth := 0;
  1312.     if ButtonCount <> 0 then
  1313.       ButtonGroupWidth := ButtonWidth * ButtonCount +
  1314.         ButtonSpacing * (ButtonCount - 1);
  1315.     ClientWidth := Max(IconTextWidth, ButtonGroupWidth) + HorzMargin * 2;
  1316.     ClientHeight := IconTextHeight + ButtonHeight + VertSpacing +
  1317.       VertMargin * 2;
  1318.     Left := (Screen.Width div 2) - (Width div 2);
  1319.     Top := (Screen.Height div 2) - (Height div 2);
  1320.     if DlgType <> mtCustom then
  1321.       Caption := LoadStr(Captions[DlgType]) else
  1322.       Caption := Application.Title;
  1323.     if IconID <> nil then
  1324.       with TImage.Create(Result) do
  1325.       begin
  1326.         Name := 'Image';
  1327.         Parent := Result;
  1328.         Picture.Icon.Handle := LoadIcon(0, IconID);
  1329.         SetBounds(HorzMargin, VertMargin, 32, 32);
  1330.       end;
  1331.     with TLabel.Create(Result) do
  1332.     begin
  1333.       Name := 'Message';
  1334.       Parent := Result;
  1335.       WordWrap := True;
  1336.       Caption := Msg;
  1337.       BoundsRect := TextRect;
  1338.       SetBounds(IconTextWidth - TextRect.Right + HorzMargin, VertMargin,
  1339.         TextRect.Right, TextRect.Bottom);
  1340.     end;
  1341.     if mbOk in Buttons then DefaultButton := mbOk else
  1342.       if mbYes in Buttons then DefaultButton := mbYes else
  1343.         DefaultButton := mbRetry;
  1344.     if mbCancel in Buttons then CancelButton := mbCancel else
  1345.       if mbNo in Buttons then CancelButton := mbNo else
  1346.         CancelButton := mbOk;
  1347.     X := (ClientWidth - ButtonGroupWidth) div 2;
  1348.     for B := Low(TMsgDlgBtn) to High(TMsgDlgBtn) do
  1349.       if B in Buttons then
  1350.         with TButton.Create(Result) do
  1351.         begin
  1352.           Name := ButtonNames[B];
  1353.           Parent := Result;
  1354.           Caption := LoadStr(ButtonCaptions[B]);
  1355.           ModalResult := ModalResults[B];
  1356.           if B = DefaultButton then Default := True;
  1357.           if B = CancelButton then Cancel := True;
  1358.           SetBounds(X, IconTextHeight + VertMargin + VertSpacing,
  1359.             ButtonWidth, ButtonHeight);
  1360.           Inc(X, ButtonWidth + ButtonSpacing);
  1361.           if B = mbHelp then
  1362.             OnClick := TMessageForm(Result).HelpButtonClick;
  1363.         end;
  1364.   end;
  1365. end;
  1366.  
  1367. function MessageDlg(const Msg: string; DlgType: TMsgDlgType;
  1368.   Buttons: TMsgDlgButtons; HelpCtx: Longint): Integer;
  1369. begin
  1370.   Result := MessageDlgPos(Msg, DlgType, Buttons, HelpCtx, -1, -1);
  1371. end;
  1372.  
  1373. function MessageDlgPos(const Msg: string; DlgType: TMsgDlgType;
  1374.   Buttons: TMsgDlgButtons; HelpCtx: Longint; X, Y: Integer): Integer;
  1375. begin
  1376.   with CreateMessageDialog(Msg, DlgType, Buttons) do
  1377.     try
  1378.       HelpContext := HelpCtx;
  1379.       if X >= 0 then Left := X;
  1380.       if Y >= 0 then Top := Y;
  1381.       Result := ShowModal;
  1382.     finally
  1383.       Free;
  1384.     end;
  1385. end;
  1386.  
  1387. procedure ShowMessage(const Msg: string);
  1388. begin
  1389.   ShowMessagePos(Msg, -1, -1);
  1390. end;
  1391.  
  1392. procedure ShowMessagePos(const Msg: string; X, Y: Integer);
  1393. begin
  1394.   MessageDlgPos(Msg, mtCustom, [mbOK], 0, X, Y);
  1395. end;
  1396.  
  1397. { Input dialog }
  1398.  
  1399. function InputQuery(const ACaption, APrompt: string;
  1400.   var Value: string): Boolean;
  1401. var
  1402.   Form: TForm;
  1403.   Prompt: TLabel;
  1404.   Edit: TEdit;
  1405.   DialogUnits: TPoint;
  1406.   ButtonTop, ButtonWidth, ButtonHeight: Integer;
  1407. begin
  1408.   Result := False;
  1409.   Form := TForm.Create(Application);
  1410.   with Form do
  1411.     try
  1412.       Canvas.Font := Font;
  1413.       DialogUnits := GetAveCharSize(Canvas);
  1414.       BorderStyle := bsDialog;
  1415.       Caption := ACaption;
  1416.       ClientWidth := MulDiv(180, DialogUnits.X, 4);
  1417.       ClientHeight := MulDiv(63, DialogUnits.Y, 8);
  1418.       Position := poScreenCenter;
  1419.       Prompt := TLabel.Create(Form);
  1420.       with Prompt do
  1421.       begin
  1422.         Parent := Form;
  1423.         AutoSize := True;
  1424.         Left := MulDiv(8, DialogUnits.X, 4);
  1425.         Top := MulDiv(8, DialogUnits.Y, 8);
  1426.         Caption := APrompt;
  1427.       end;
  1428.       Edit := TEdit.Create(Form);
  1429.       with Edit do
  1430.       begin
  1431.         Parent := Form;
  1432.         Left := Prompt.Left;
  1433.         Top := MulDiv(19, DialogUnits.Y, 8);
  1434.         Width := MulDiv(164, DialogUnits.X, 4);
  1435.         MaxLength := 255;
  1436.         Text := Value;
  1437.         SelectAll;
  1438.       end;
  1439.       ButtonTop := MulDiv(41, DialogUnits.Y, 8);
  1440.       ButtonWidth := MulDiv(50, DialogUnits.X, 4);
  1441.       ButtonHeight := MulDiv(14, DialogUnits.Y, 8);
  1442.       with TButton.Create(Form) do
  1443.       begin
  1444.         Parent := Form;
  1445.         Caption := LoadStr(SMsgDlgOK);
  1446.         ModalResult := mrOk;
  1447.         Default := True;
  1448.         SetBounds(MulDiv(38, DialogUnits.X, 4), ButtonTop, ButtonWidth,
  1449.           ButtonHeight);
  1450.       end;
  1451.       with TButton.Create(Form) do
  1452.       begin
  1453.         Parent := Form;
  1454.         Caption := LoadStr(SMsgDlgCancel);
  1455.         ModalResult := mrCancel;
  1456.         Cancel := True;
  1457.         SetBounds(MulDiv(92, DialogUnits.X, 4), ButtonTop, ButtonWidth,
  1458.           ButtonHeight);
  1459.       end;
  1460.       if ShowModal = mrOk then
  1461.       begin
  1462.         Value := Edit.Text;
  1463.         Result := True;
  1464.       end;
  1465.     finally
  1466.       Form.Free;
  1467.     end;
  1468. end;
  1469.  
  1470. function InputBox(const ACaption, APrompt, ADefault: string): string;
  1471. begin
  1472.   Result := ADefault;
  1473.   InputQuery(ACaption, APrompt, Result);
  1474. end;
  1475.  
  1476. { Initialization and cleanup }
  1477.  
  1478. procedure InitGlobals;
  1479. var
  1480.   AtomText: array[0..31] of Char;
  1481. begin
  1482.   HelpMsg := RegisterWindowMessage(HelpMsgString);
  1483.   FindMsg := RegisterWindowMessage(FindMsgString);
  1484.   WndProcPtrAtom := GlobalAddAtom(StrFmt(AtomText,
  1485.     'WndProcPtr%.8X%.8X', [HInstance, GetCurrentThreadID]));
  1486. end;
  1487.  
  1488. initialization
  1489.   InitGlobals;
  1490. finalization
  1491.   if WndProcPtrAtom <> 0 then GlobalDeleteAtom(WndProcPtrAtom);
  1492. end.
  1493.