home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 June / Chip_2002-06_cd1.bin / zkuste / delphi / kolekce / d6 / rxlibsetup.exe / {app} / units / Rxgrdcpt.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-02-19  |  30.5 KB  |  1,087 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 2001,2002 SGB Software          }
  6. {         Copyright (c) 1997, 1998 Fedor Koshevnikov,   }
  7. {                        Igor Pavluk and Serge Korolev  }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11.  
  12. unit RxGrdCpt;
  13.  
  14. {$I RX.INC}
  15.  
  16. interface
  17.  
  18. {$IFDEF WIN32}
  19.  
  20. uses Windows, Messages, Classes, Graphics, Controls, Forms, Dialogs, Menus,
  21.   RxHook, VclUtils;
  22.  
  23. type
  24.   THideDirection = (hdLeftToRight, hdRightToLeft);
  25.  
  26.   TRxCaption = class;
  27.   TRxCaptionList = class;
  28.  
  29. { TRxGradientCaption }
  30.  
  31.   TRxGradientCaption = class(TComponent)
  32.   private
  33.     FActive: Boolean;
  34.     FWindowActive: Boolean;
  35.     FSaveRgn: HRgn;
  36.     FRgnChanged: Boolean;
  37.     FWinHook: TRxWindowHook;
  38.     FStartColor: TColor;
  39.     FCaptions: TRxCaptionList;
  40.     FFont: TFont;
  41.     FDefaultFont: Boolean;
  42.     FPopupMenu: TPopupMenu;
  43.     FClicked: Boolean;
  44.     FHideDirection: THideDirection;
  45.     FGradientInactive: Boolean;
  46.     FGradientActive: Boolean;
  47.     FFontInactiveColor: TColor;
  48.     FFormCaption: string;
  49.     FGradientSteps: Integer;
  50.     FOnActivate: TNotifyEvent;
  51.     FOnDeactivate: TNotifyEvent;
  52.     procedure SetHook;
  53.     procedure ReleaseHook;
  54.     procedure CheckToggleHook;
  55.     function GetActive: Boolean;
  56.     procedure SetActive(Value: Boolean);
  57.     procedure SetStartColor(Value: TColor);
  58.     procedure DrawGradientCaption(DC: HDC);
  59.     procedure CalculateGradientParams(var R: TRect; var Icons: TBorderIcons);
  60.     function GetForm: TForm;
  61.     function GetFormCaption: string;
  62.     procedure SetFormCaption(const Value: string);
  63.     procedure BeforeMessage(Sender: TObject; var Msg: TMessage;
  64.       var Handled: Boolean);
  65.     procedure AfterMessage(Sender: TObject; var Msg: TMessage;
  66.       var Handled: Boolean);
  67.     function CheckMenuPopup(X, Y: Integer): Boolean;
  68.     procedure SetFont(Value: TFont);
  69.     procedure FontChanged(Sender: TObject);
  70.     procedure SetDefaultFont(Value: Boolean);
  71.     procedure SetFontDefault;
  72.     function IsFontStored: Boolean;
  73.     function GetTextWidth: Integer;
  74.     procedure SetCaptions(Value: TRxCaptionList);
  75.     procedure SetGradientActive(Value: Boolean);
  76.     procedure SetGradientInactive(Value: Boolean);
  77.     procedure SetGradientSteps(Value: Integer);
  78.     procedure SetFontInactiveColor(Value: TColor);
  79.     procedure SetHideDirection(Value: THideDirection);
  80.     procedure SetPopupMenu(Value: TPopupMenu);
  81.   protected
  82.     procedure Loaded; override;
  83.     procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  84. {$IFDEF RX_D4}
  85.     function IsRightToLeft: Boolean;
  86. {$ENDIF}
  87.     property Form: TForm read GetForm;
  88.     property TextWidth: Integer read GetTextWidth;
  89.   public
  90.     constructor Create(AOwner: TComponent); override;
  91.     destructor Destroy; override;
  92.     procedure MoveCaption(FromIndex, ToIndex: Integer);
  93.     procedure Update;
  94.     procedure Clear;
  95.   published
  96.     property Active: Boolean read GetActive write SetActive default True;
  97.     property Captions: TRxCaptionList read FCaptions write SetCaptions;
  98.     property DefaultFont: Boolean read FDefaultFont write SetDefaultFont default True;
  99.     property FormCaption: string read GetFormCaption write SetFormCaption;
  100.     property FontInactiveColor: TColor read FFontInactiveColor
  101.       write SetFontInactiveColor default clInactiveCaptionText;
  102.     property Font: TFont read FFont write SetFont stored IsFontStored;
  103.     property GradientActive: Boolean read FGradientActive
  104.       write SetGradientActive default True;
  105.     property GradientInactive: Boolean read FGradientInactive
  106.       write SetGradientInactive default False;
  107.     property GradientSteps: Integer read FGradientSteps write SetGradientSteps
  108.       default 64;
  109.     property HideDirection: THideDirection read FHideDirection
  110.       write SetHideDirection default hdLeftToRight;
  111.     property PopupMenu: TPopupMenu read FPopupMenu write SetPopupMenu;
  112.     property StartColor: TColor read FStartColor write SetStartColor
  113.       default clWindowText;
  114.     property OnActivate: TNotifyEvent read FOnActivate write FOnActivate;
  115.     property OnDeactivate: TNotifyEvent read FOnDeactivate write FOnDeactivate;
  116.   end;
  117.  
  118. { TRxCaptionList }
  119.  
  120.   TRxCaptionList = class(TCollection)
  121.   private
  122.     FParent: TRxGradientCaption;
  123.     function GetCaption(Index: Integer): TRxCaption;
  124.     procedure SetCaption(Index: Integer; Value: TRxCaption);
  125.   protected
  126. {$IFDEF RX_D3}
  127.     function GetOwner: TPersistent; override;
  128. {$ENDIF}
  129.     procedure Update(Item: TCollectionItem); override;
  130.   public
  131.     constructor Create(AParent: TRxGradientCaption);
  132.     function Add: TRxCaption;
  133.     procedure RestoreDefaults;
  134.     property Parent: TRxGradientCaption read FParent;
  135.     property Items[Index: Integer]: TRxCaption read GetCaption write SetCaption; default;
  136.   end;
  137.  
  138. { TRxCaption }
  139.  
  140.   TRxCaption = class(TCollectionItem)
  141.   private
  142.     FCaption: string;
  143.     FFont: TFont;
  144.     FParentFont: Boolean;
  145.     FVisible: Boolean;
  146.     FGlueNext: Boolean;
  147.     FInactiveColor: TColor;
  148.     procedure SetCaption(const Value: string);
  149.     procedure SetFont(Value: TFont);
  150.     procedure SetParentFont(Value: Boolean);
  151.     procedure FontChanged(Sender: TObject);
  152.     function IsFontStored: Boolean;
  153.     function GetTextWidth: Integer;
  154.     procedure SetVisible(Value: Boolean);
  155.     procedure SetInactiveColor(Value: TColor);
  156.     procedure SetGlueNext(Value: Boolean);
  157.   protected
  158.     function GetParentCaption: TRxGradientCaption;
  159.     property TextWidth: Integer read GetTextWidth;
  160.   public
  161.     constructor Create(Collection: TCollection); override;
  162.     destructor Destroy; override;
  163.     procedure Assign(Source: TPersistent); override;
  164.     procedure RestoreDefaults; virtual;
  165.     property GradientCaption: TRxGradientCaption read GetParentCaption;
  166.   published
  167.     property Caption: string read FCaption write SetCaption;
  168.     property Font: TFont read FFont write SetFont stored IsFontStored;
  169.     property ParentFont: Boolean read FParentFont write SetParentFont
  170.       default True;
  171.     property InactiveColor: TColor read FInactiveColor write SetInactiveColor
  172.       default clInactiveCaptionText;
  173.     property GlueNext: Boolean read FGlueNext write SetGlueNext default False;
  174.     property Visible: Boolean read FVisible write SetVisible default True;
  175.   end;
  176.  
  177. function GradientFormCaption(AForm: TCustomForm;
  178.   AStartColor: TColor): TRxGradientCaption;
  179.  
  180. {$ENDIF WIN32}
  181.  
  182. implementation
  183.  
  184. {$IFDEF WIN32}
  185.  
  186. uses SysUtils, AppUtils;
  187.  
  188. function GradientFormCaption(AForm: TCustomForm;
  189.   AStartColor: TColor): TRxGradientCaption;
  190. begin
  191.   Result := TRxGradientCaption.Create(AForm);
  192.   with Result do
  193.     try
  194.       FStartColor := AStartColor;
  195.       FormCaption := AForm.Caption;
  196.       Update;
  197.     except
  198.       Free;
  199.       raise;
  200.     end;
  201. end;
  202.  
  203. { TRxCaptionList }
  204.  
  205. constructor TRxCaptionList.Create(AParent: TRxGradientCaption);
  206. begin
  207.   inherited Create(TRxCaption);
  208.   FParent := AParent;
  209. end;
  210.  
  211. function TRxCaptionList.Add: TRxCaption;
  212. begin
  213.   Result := TRxCaption(inherited Add);
  214. end;
  215.  
  216. function TRxCaptionList.GetCaption(Index: Integer): TRxCaption;
  217. begin
  218.   Result := TRxCaption(inherited Items[Index]);
  219. end;
  220.  
  221. {$IFDEF RX_D3}
  222. function TRxCaptionList.GetOwner: TPersistent;
  223. begin
  224.   Result := FParent;
  225. end;
  226. {$ENDIF}
  227.  
  228. procedure TRxCaptionList.RestoreDefaults;
  229. var
  230.   I: Integer;
  231. begin
  232.   BeginUpdate;
  233.   try
  234.     for I := 0 to Count-1 do
  235.       Items[I].RestoreDefaults;
  236.   finally
  237.     EndUpdate;
  238.   end;
  239. end;
  240.  
  241. procedure TRxCaptionList.SetCaption(Index: Integer; Value: TRxCaption);
  242. begin
  243.   Items[Index].Assign(Value);
  244. end;
  245.  
  246. procedure TRxCaptionList.Update(Item: TCollectionItem);
  247. begin
  248.   if (FParent <> nil) and not (csLoading in FParent.ComponentState) then
  249.     if FParent.Active then FParent.Update;
  250. end;
  251.  
  252. { TRxCaption }
  253.  
  254. constructor TRxCaption.Create(Collection: TCollection);
  255. var
  256.   Parent: TRxGradientCaption;
  257. begin
  258.   Parent := nil;
  259.   if Assigned(Collection) and (Collection is TRxCaptionList) then
  260.     Parent := TRxCaptionList(Collection).Parent;
  261.   try
  262.     inherited Create(Collection);
  263.     FFont := TFont.Create;
  264.     if Assigned(Parent) then begin
  265.       FFont.Assign(Parent.Font);
  266.       FFont.Color := Parent.Font.Color;
  267.     end
  268.     else FFont.Color := clCaptionText;
  269.     FFont.OnChange := FontChanged;
  270.     FCaption := '';
  271.     FParentFont := True;
  272.     FVisible := True;
  273.     FGlueNext := False;
  274.     FInactiveColor := clInactiveCaptionText;
  275.   finally
  276.     if Assigned(Parent) then Changed(False);
  277.   end;
  278. end;
  279.  
  280. destructor TRxCaption.Destroy;
  281. begin
  282.   FFont.Free;
  283.   FFont := nil;
  284.   inherited Destroy;
  285. end;
  286.  
  287. procedure TRxCaption.Assign(Source: TPersistent);
  288. begin
  289.   if Source is TRxCaption then begin
  290.     if Assigned(Collection) then Collection.BeginUpdate;
  291.     try
  292.       RestoreDefaults;
  293.       Caption := TRxCaption(Source).Caption;
  294.       ParentFont := TRxCaption(Source).ParentFont;
  295.       if not ParentFont then
  296.         Font.Assign(TRxCaption(Source).Font);
  297.       InactiveColor := TRxCaption(Source).InactiveColor;
  298.       GlueNext := TRxCaption(Source).GlueNext;
  299.       Visible := TRxCaption(Source).Visible;
  300.     finally
  301.       if Assigned(Collection) then Collection.EndUpdate;
  302.     end;
  303.   end
  304.   else inherited Assign(Source);
  305. end;
  306.  
  307. procedure TRxCaption.RestoreDefaults;
  308. begin
  309.   FInactiveColor := clInactiveCaptionText;
  310.   FVisible := True;
  311.   ParentFont := True;
  312. end;
  313.  
  314. function TRxCaption.GetParentCaption: TRxGradientCaption;
  315. begin
  316.   if Assigned(Collection) and (Collection is TRxCaptionList) then
  317.     Result := TRxCaptionList(Collection).Parent
  318.   else
  319.     Result := nil;
  320. end;
  321.  
  322. procedure TRxCaption.SetCaption(const Value: string);
  323. begin
  324.   FCaption := Value;
  325.   Changed(False);
  326. end;
  327.  
  328. procedure TRxCaption.FontChanged(Sender: TObject);
  329. begin
  330.   FParentFont := False;
  331.   Changed(False);
  332. end;
  333.  
  334. procedure TRxCaption.SetFont(Value: TFont);
  335. begin
  336.   FFont.Assign(Value);
  337. end;
  338.  
  339. procedure TRxCaption.SetParentFont(Value: Boolean);
  340. begin
  341.   if Value and (GradientCaption <> nil) then begin
  342.     FFont.OnChange := nil;
  343.     try
  344.       FFont.Assign(GradientCaption.Font);
  345.     finally
  346.       FFont.OnChange := FontChanged;
  347.     end;
  348.   end;
  349.   FParentFont := Value;
  350.   Changed(False);
  351. end;
  352.  
  353. function TRxCaption.IsFontStored: Boolean;
  354. begin
  355.   Result := not FParentFont;
  356. end;
  357.  
  358. function TRxCaption.GetTextWidth: Integer;
  359. var
  360.   Canvas: TCanvas;
  361.   PS: TPaintStruct;
  362. begin
  363.   BeginPaint(Application.Handle, PS);
  364.   try
  365.     Canvas := TCanvas.Create;
  366.     try
  367.       Canvas.Handle := PS.hDC;
  368.       Canvas.Font := FFont;
  369.       Result := Canvas.TextWidth(FCaption);
  370.     finally
  371.       Canvas.Free;
  372.     end;
  373.   finally
  374.     EndPaint(Application.Handle, PS);
  375.   end;
  376. end;
  377.  
  378. procedure TRxCaption.SetVisible(Value: Boolean);
  379. begin
  380.   if FVisible <> Value then begin
  381.     FVisible := Value;
  382.     Changed(False);
  383.   end;
  384. end;
  385.  
  386. procedure TRxCaption.SetInactiveColor(Value: TColor);
  387. begin
  388.   if FInactiveColor <> Value then begin
  389.     FInactiveColor := Value;
  390.     if (GradientCaption = nil) or not GradientCaption.FWindowActive then
  391.       Changed(False);
  392.   end;
  393. end;
  394.  
  395. procedure TRxCaption.SetGlueNext(Value: Boolean);
  396. begin
  397.   if FGlueNext <> Value then begin
  398.     FGlueNext := Value;
  399.     Changed(False);
  400.   end;
  401. end;
  402.  
  403. {$IFNDEF RX_D4}
  404. const
  405.   COLOR_GRADIENTACTIVECAPTION   =    27;
  406.   COLOR_GRADIENTINACTIVECAPTION =    28;
  407.   SPI_GETGRADIENTCAPTIONS       = $1008;
  408. {$ENDIF}
  409.  
  410. const
  411.   clGradientActiveCaption = TColor(COLOR_GRADIENTACTIVECAPTION or $80000000);
  412.   clGradientInactiveCaption = TColor(COLOR_GRADIENTINACTIVECAPTION or $80000000);
  413.  
  414. function SysGradient: Boolean;
  415. var
  416.   Info: BOOL;
  417. begin
  418.   if SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, SizeOf(Info), @Info, 0) then
  419.     Result := Info
  420.   else Result := False;
  421. end;
  422.  
  423. { TRxGradientCaption }
  424.  
  425. constructor TRxGradientCaption.Create(AOwner: TComponent);
  426. begin
  427.   inherited Create(AOwner);
  428.   FGradientSteps := 64;
  429.   FGradientActive := True;
  430.   FActive := True;
  431.   FCaptions := TRxCaptionList.Create(Self);
  432.   FWinHook := TRxWindowHook.Create(Self);
  433.   FWinHook.BeforeMessage := BeforeMessage;
  434.   FWinHook.AfterMessage := AfterMessage;
  435.   FStartColor := clWindowText;
  436.   FFontInactiveColor := clInactiveCaptionText;
  437.   FFormCaption := '';
  438.   FFont := TFont.Create;
  439.   SetFontDefault;
  440. end;
  441.  
  442. destructor TRxGradientCaption.Destroy;
  443. begin
  444.   FOnDeactivate := nil;
  445.   FOnActivate := nil;
  446.   if not (csDesigning in ComponentState) then
  447.     ReleaseHook;
  448.   FCaptions.Free;
  449.   FCaptions := nil;
  450.   FFont.Free;
  451.   FFont := nil;
  452.   inherited Destroy;
  453. end;
  454.  
  455. procedure TRxGradientCaption.Loaded;
  456. var
  457.   Loading: Boolean;
  458. begin
  459.   Loading := csLoading in ComponentState;
  460.   inherited Loaded;
  461.   if not (csDesigning in ComponentState) then begin
  462.     if Loading and (Owner is TCustomForm) then Update;
  463.   end;
  464. end;
  465.  
  466. procedure TRxGradientCaption.Notification(AComponent: TComponent;
  467.   Operation: TOperation);
  468. begin
  469.   inherited Notification(AComponent, Operation);
  470.   if (AComponent = PopupMenu) and (Operation = opRemove) then
  471.     PopupMenu := nil;
  472. end;
  473.  
  474. procedure TRxGradientCaption.SetPopupMenu(Value: TPopupMenu);
  475. begin
  476.   FPopupMenu := Value;
  477.   if Value <> nil then Value.FreeNotification(Self);
  478. end;
  479.  
  480. procedure TRxGradientCaption.SetCaptions(Value: TRxCaptionList);
  481. begin
  482.   Captions.Assign(Value);
  483. end;
  484.  
  485. procedure TRxGradientCaption.SetDefaultFont(Value: Boolean);
  486. begin
  487.   if FDefaultFont <> Value then begin
  488.     if Value then SetFontDefault;
  489.     FDefaultFont := Value;
  490.     if Active then Update;
  491.   end;
  492. end;
  493.  
  494. procedure TRxGradientCaption.SetFontDefault;
  495. var
  496.   NCMetrics: TNonClientMetrics;
  497. begin
  498.   with FFont do begin
  499.     OnChange := nil;
  500.     try
  501.       NCMetrics.cbSize := SizeOf(NCMetrics);
  502.       if SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, @NCMetrics, 0) then
  503.       begin
  504.         if (Owner is TForm) and
  505.           ((Owner as TForm).BorderStyle in [bsToolWindow, bsSizeToolWin]) then
  506.           Handle := CreateFontIndirect(NCMetrics.lfSmCaptionFont)
  507.         else
  508.           Handle := CreateFontIndirect(NCMetrics.lfCaptionFont);
  509.       end
  510.       else begin
  511.         Name := 'MS Sans Serif';
  512.         Size := 8;
  513.         Style := [fsBold];
  514.       end;
  515.       Color := clCaptionText;
  516. {$IFNDEF VER90}
  517.       Charset := DEFAULT_CHARSET;
  518. {$ENDIF}
  519.     finally
  520.       OnChange := FontChanged;
  521.     end;
  522.   end;
  523.   FDefaultFont := True;
  524. end;
  525.  
  526. function TRxGradientCaption.IsFontStored: Boolean;
  527. begin
  528.   Result := not DefaultFont;
  529. end;
  530.  
  531. function TRxGradientCaption.GetForm: TForm;
  532. begin
  533.   if Owner is TCustomForm then
  534.     Result := TForm(Owner as TCustomForm)
  535.   else
  536.     Result := nil;
  537. end;
  538.  
  539. function TRxGradientCaption.GetFormCaption: string;
  540. begin
  541.   if (Form <> nil) and (csDesigning in ComponentState) then
  542.     FFormCaption := Form.Caption;
  543.   Result := FFormCaption;
  544. end;
  545.  
  546. procedure TRxGradientCaption.SetFormCaption(const Value: string);
  547. begin
  548.   if FFormCaption <> Value then begin
  549.     FFormCaption := Value;
  550.     if (Form <> nil) and (csDesigning in ComponentState) then
  551.       Form.Caption := FFormCaption;
  552.     if Active then Update;
  553.   end;
  554. end;
  555.  
  556. procedure TRxGradientCaption.SetHook;
  557. begin
  558.   if not (csDesigning in ComponentState) and (Owner <> nil) and
  559.     (Owner is TCustomForm) then
  560.     FWinHook.WinControl := Form;
  561. end;
  562.  
  563. procedure TRxGradientCaption.ReleaseHook;
  564. begin
  565.   FWinHook.WinControl := nil;
  566. end;
  567.  
  568. procedure TRxGradientCaption.CheckToggleHook;
  569. begin
  570.   if Active then SetHook
  571.   else ReleaseHook;
  572. end;
  573.  
  574. function TRxGradientCaption.CheckMenuPopup(X, Y: Integer): Boolean;
  575. begin
  576.   Result := False;
  577.   if not (csDesigning in ComponentState) and Assigned(FPopupMenu) and
  578.     FPopupMenu.AutoPopup then
  579.   begin
  580.     FPopupMenu.PopupComponent := Self;
  581.     if Form <> nil then begin
  582.       Form.SendCancelMode(nil);
  583.       FPopupMenu.Popup(X, Y);
  584.       Result := True;
  585.     end;
  586.   end;
  587. end;
  588.  
  589. procedure TRxGradientCaption.BeforeMessage(Sender: TObject; var Msg: TMessage;
  590.   var Handled: Boolean);
  591. var
  592.   DrawRgn: HRgn;
  593.   R: TRect;
  594.   Icons: TBorderIcons;
  595. begin
  596.   if Active then begin
  597.     case Msg.Msg of
  598.       WM_NCACTIVATE:
  599.         begin
  600.           FWindowActive := (Msg.wParam <> 0);
  601.         end;
  602.       WM_NCRBUTTONDOWN:
  603.         if Assigned(FPopupMenu) and FPopupMenu.AutoPopup then begin
  604.           FClicked := True;
  605.           Msg.Result := 0;
  606.           Handled := True;
  607.         end;
  608.       WM_NCRBUTTONUP:
  609.         with TWMMouse(Msg) do
  610.           if FClicked then begin
  611.             FClicked := False;
  612.             if CheckMenuPopup(XPos, YPos) then begin
  613.               Result := 0;
  614.               Handled := True;
  615.             end;
  616.           end;
  617.       WM_NCPAINT:
  618.         begin
  619.           FSaveRgn := Msg.wParam;
  620.           FRgnChanged := False;
  621.           CalculateGradientParams(R, Icons);
  622.           if RectInRegion(FSaveRgn, R) then begin
  623.             DrawRgn := CreateRectRgn(R.Left, R.Top, R.Right, R.Bottom);
  624.             try
  625.               Msg.WParam := CreateRectRgn(0, 0, 1, 1);
  626.               FRgnChanged := True;
  627.               CombineRgn(Msg.WParam, FSaveRgn, DrawRgn, RGN_DIFF);
  628.             finally
  629.               DeleteObject(DrawRgn);
  630.             end;
  631.           end;
  632.         end;
  633.     end;
  634.   end;
  635. end;
  636.  
  637. procedure TRxGradientCaption.AfterMessage(Sender: TObject; var Msg: TMessage;
  638.   var Handled: Boolean);
  639. var
  640.   DC: HDC;
  641.   S: string;
  642. begin
  643.   if Active then begin
  644.     case Msg.Msg of
  645.       WM_NCACTIVATE:
  646.         begin
  647.           DC := GetWindowDC(Form.Handle);
  648.           try
  649.             DrawGradientCaption(DC);
  650.           finally
  651.             ReleaseDC(Form.Handle, DC);
  652.           end;
  653.         end;
  654.       WM_NCPAINT:
  655.         begin
  656.           if FRgnChanged then begin
  657.             DeleteObject(Msg.WParam);
  658.             Msg.WParam := FSaveRgn;
  659.             FRgnChanged := False;
  660.           end;
  661.           DC := GetWindowDC(Form.Handle);
  662.           try
  663.             DrawGradientCaption(DC);
  664.           finally
  665.             ReleaseDC(Form.Handle, DC);
  666.           end;
  667.         end;
  668.       WM_GETTEXT:
  669.         { Delphi doesn't send WM_SETTEXT to form's window procedure,
  670.           so we need to handle WM_GETTEXT to redraw non-client area
  671.           when form's caption changed }
  672.         begin
  673.           if csDesigning in ComponentState then begin
  674.             SetString(S, PChar(Msg.LParam), Msg.Result);
  675.             if AnsiCompareStr(S, FFormCaption) <> 0 then begin
  676.               FormCaption := S;
  677.               PostMessage(Form.Handle, WM_NCPAINT, 0, 0);
  678.             end;
  679.           end;
  680.         end;
  681.     end;
  682.   end;
  683. end;
  684.  
  685. procedure TRxGradientCaption.SetStartColor(Value: TColor);
  686. begin
  687.   if FStartColor <> Value then begin
  688.     FStartColor := Value;
  689.     if Active then Update;
  690.   end;
  691. end;
  692.  
  693. function TRxGradientCaption.GetActive: Boolean;
  694. begin
  695.   Result := FActive;
  696.   if not (csDesigning in ComponentState) then
  697.     Result := Result and NewStyleControls and (Owner is TCustomForm);
  698. end;
  699.  
  700. procedure TRxGradientCaption.SetActive(Value: Boolean);
  701. begin
  702.   if FActive <> Value then begin
  703.     FActive := Value;
  704.     FClicked := False;
  705.     Update;
  706.     if ([csDestroying, csReading] * ComponentState = []) then begin
  707.       if FActive then begin
  708.         if Assigned(FOnActivate) then FOnActivate(Self);
  709.       end
  710.       else begin
  711.         if Assigned(FOnDeactivate) then FOnDeactivate(Self);
  712.       end;
  713.     end;
  714.   end;
  715. end;
  716.  
  717. procedure TRxGradientCaption.Clear;
  718. begin
  719.   if FCaptions <> nil then FCaptions.Clear;
  720. end;
  721.  
  722. procedure TRxGradientCaption.MoveCaption(FromIndex, ToIndex: Integer);
  723. begin
  724.   Captions[FromIndex].Index := ToIndex;
  725. end;
  726.  
  727. procedure TRxGradientCaption.Update;
  728. var
  729.   Rgn: HRgn;
  730. begin
  731.   if not (csDesigning in ComponentState) and (Owner is TCustomForm) and
  732.     not (csLoading in ComponentState) then
  733.   begin
  734.     CheckToggleHook;
  735.     FWindowActive := False;
  736.     if (Form <> nil) and Form.HandleAllocated and Form.Visible then begin
  737.       if Active then begin
  738.         FWindowActive := (GetActiveWindow = Form.Handle) and
  739.           IsForegroundTask;
  740.       end;
  741.       with Form do
  742.         Rgn := CreateRectRgn(Left, Top, Left + Width, Top + Height);
  743.       try
  744.         SendMessage(Form.Handle, WM_NCPAINT, Rgn, 0);
  745.       finally
  746.         DeleteObject(Rgn);
  747.       end;
  748.     end;
  749.   end;
  750. end;
  751.  
  752. procedure TRxGradientCaption.CalculateGradientParams(var R: TRect;
  753.   var Icons: TBorderIcons);
  754. var
  755.   I: TBorderIcon;
  756.   BtnCount: Integer;
  757. begin
  758.   GetWindowRect(Form.Handle, R);
  759.   Icons := Form.BorderIcons;
  760.   case Form.BorderStyle of
  761.     bsDialog: Icons := Icons * [biSystemMenu, biHelp];
  762.     bsToolWindow, bsSizeToolWin: Icons := Icons * [biSystemMenu];
  763.     else begin
  764.       if not (biSystemMenu in Icons) then
  765.         Icons := Icons - [biMaximize, biMinimize];
  766.       if (Icons * [biMaximize, biMinimize] <> []) then
  767.         Icons := Icons - [biHelp];
  768.     end;
  769.   end;
  770.   BtnCount := 0;
  771.   for I := Low(TBorderIcon) to High(TBorderIcon) do
  772.     if I in Icons then Inc(BtnCount);
  773.   if (biMinimize in Icons) and not (biMaximize in Icons) then
  774.     Inc(BtnCount)
  775.   else if not (biMinimize in Icons) and (biMaximize in Icons) then
  776.     Inc(BtnCount);
  777.   case Form.BorderStyle of
  778.     bsToolWindow, bsSingle, bsDialog:
  779.       InflateRect(R, -GetSystemMetrics(SM_CXFIXEDFRAME),
  780.         -GetSystemMetrics(SM_CYFIXEDFRAME));
  781.     bsSizeable, bsSizeToolWin:
  782.       InflateRect(R, -GetSystemMetrics(SM_CXSIZEFRAME),
  783.         -GetSystemMetrics(SM_CYSIZEFRAME));
  784.   end;
  785.   if Form.BorderStyle in [bsToolWindow, bsSizeToolWin] then begin
  786.     R.Bottom := R.Top + GetSystemMetrics(SM_CYSMCAPTION) - 1;
  787.     Dec(R.Right, BtnCount * GetSystemMetrics(SM_CXSMSIZE));
  788.   end
  789.   else begin
  790.     R.Bottom := R.Top + GetSystemMetrics(SM_CYCAPTION) - 1;
  791.     Dec(R.Right, BtnCount * GetSystemMetrics(SM_CXSIZE));
  792.   end;
  793. end;
  794.  
  795. {$IFDEF RX_D4}
  796. function TRxGradientCaption.IsRightToLeft: Boolean;
  797. var
  798.   F: TForm;
  799. begin
  800.   F := Form;
  801.   if F <> nil then Result := F.IsRightToLeft
  802.   else Result := Application.IsRightToLeft;
  803. end;
  804. {$ENDIF}
  805.  
  806. procedure TRxGradientCaption.DrawGradientCaption(DC: HDC);
  807. var
  808.   R, DrawRect: TRect;
  809.   Icons: TBorderIcons;
  810.   C: TColor;
  811.   Ico: HIcon;
  812.   Image: TBitmap;
  813.   S: string;
  814.   IconCreated, DrawNext: Boolean;
  815.   I, J, SumWidth: Integer;
  816.  
  817.   procedure SetCaptionFont(Index: Integer);
  818.   begin
  819.     if (Index < 0) or Captions[Index].ParentFont then
  820.       Image.Canvas.Font.Assign(Self.Font)
  821.     else Image.Canvas.Font.Assign(Captions[Index].Font);
  822.     if not FWindowActive then begin
  823.       if Index < 0 then
  824.         Image.Canvas.Font.Color := FFontInactiveColor
  825.       else
  826.         Image.Canvas.Font.Color := Captions[Index].InactiveColor;
  827.     end;
  828.   end;
  829.  
  830.   function DrawStr(GluePrev, GlueNext: Boolean; PrevIndex: Integer): Boolean;
  831.   const
  832.     Points = '...';
  833.   var
  834.     Text: string;
  835.     Flags: Longint;
  836.   begin
  837.     if Length(S) > 0 then begin
  838.       Text := MinimizeText(S, Image.Canvas, R.Right - R.Left);
  839.       if GlueNext and (Text = S) then begin
  840.         if (Image.Canvas.TextWidth(Text + '.') >= R.Right - R.Left) then begin
  841.           if GluePrev then Text := Points
  842.           else Text := Text + Points;
  843.         end;
  844.       end;
  845.       if (Text <> Points) or GluePrev then begin
  846.         if (Text = Points) and GluePrev then begin
  847.           SetCaptionFont(-1);
  848.           if PrevIndex > 0 then begin
  849.             if FWindowActive then
  850.               Image.Canvas.Font.Color := Captions[PrevIndex].Font.Color
  851.             else
  852.               Image.Canvas.Font.Color := Captions[PrevIndex].InactiveColor;
  853.           end;
  854.         end;
  855.         Flags := DT_VCENTER or DT_SINGLELINE or DT_NOPREFIX;
  856. {$IFDEF RX_D4}
  857.         if IsRightToLeft then
  858.           Flags := Flags or DT_RIGHT or DT_RTLREADING else
  859. {$ENDIF}
  860.         Flags := Flags or DT_LEFT;
  861.         DrawText(Image.Canvas.Handle, PChar(Text), -1, R, Flags);
  862. {$IFDEF RX_D4}
  863.         if IsRightToLeft then
  864.           Dec(R.Right, Image.Canvas.TextWidth(Text)) else
  865. {$ENDIF}
  866.         Inc(R.Left, Image.Canvas.TextWidth(Text));
  867.       end;
  868.       Result := (Text = S);
  869.     end
  870.     else Result := True;
  871.   end;
  872.  
  873. begin
  874.   if Form.BorderStyle = bsNone then Exit;
  875.   Image := TBitmap.Create;
  876.   try
  877.     CalculateGradientParams(R, Icons);
  878.     GetWindowRect(Form.Handle, DrawRect);
  879.     OffsetRect(R, -DrawRect.Left, -DrawRect.Top);
  880.     DrawRect := R;
  881.     Image.Width := WidthOf(R);
  882.     Image.Height := HeightOf(R);
  883.     R := Rect(-Image.Width div 4, 0, Image.Width, Image.Height);
  884.     if SysGradient then begin
  885.       if FWindowActive then C := clGradientActiveCaption
  886.       else C := clGradientInactiveCaption;
  887.     end
  888.     else begin
  889.       if FWindowActive then C := clActiveCaption
  890.       else C := clInactiveCaption;
  891.     end;
  892.     if (FWindowActive and GradientActive) or
  893.       (not FWindowActive and GradientInactive) then
  894.     begin
  895.       GradientFillRect(Image.Canvas, R, FStartColor, C, fdLeftToRight,
  896.         FGradientSteps);
  897.     end
  898.     else begin
  899.       Image.Canvas.Brush.Color := C;
  900.       Image.Canvas. FillRect(R);
  901.     end;
  902.     R.Left := 0;
  903.     if (biSystemMenu in Icons) and (Form.BorderStyle in [bsSizeable,
  904.       bsSingle]) then
  905.     begin
  906.       IconCreated := False;
  907.       if Form.Icon.Handle <> 0 then
  908.         Ico := Form.Icon.Handle
  909.       else if Application.Icon.Handle <> 0 then begin
  910.         Ico := LoadImage(HInstance, 'MAINICON', IMAGE_ICON,
  911.           GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), 0);
  912.         IconCreated := Ico <> 0;
  913.         if not IconCreated then Ico := Application.Icon.Handle;
  914.       end
  915.       else Ico := LoadIcon(0, IDI_APPLICATION);
  916.       DrawIconEx(Image.Canvas.Handle, R.Left + 1 + (R.Bottom + R.Top -
  917.         GetSystemMetrics(SM_CXSMICON)) div 2, (R.Bottom + R.Top -
  918.         GetSystemMetrics(SM_CYSMICON)) div 2, Ico,
  919.         GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  920.         0, 0, DI_NORMAL);
  921.       if IconCreated then DestroyIcon(Ico);
  922.       Inc(R.Left, R.Bottom - R.Top);
  923.     end;
  924.     if (FFormCaption <> '') or ((Captions <> nil) and (Captions.Count > 0)) then
  925.     begin
  926.       SumWidth := 2;
  927.       SetBkMode(Image.Canvas.Handle, TRANSPARENT);
  928.       Inc(R.Left, 2);
  929.       if FHideDirection = hdLeftToRight then begin
  930.         for I := 0 to Captions.Count - 1 do
  931.           if Captions[I].Visible then
  932.             SumWidth := SumWidth + Captions[I].TextWidth;
  933.         SumWidth := SumWidth + TextWidth;
  934.         J := 0;
  935.         while (SumWidth > (R.Right - R.Left)) and (J < Captions.Count) do
  936.         begin
  937.           SumWidth := SumWidth - Captions[J].TextWidth;
  938.           while (J < Captions.Count - 1) and Captions[J].GlueNext do begin
  939.             SumWidth := SumWidth - Captions[J + 1].TextWidth;
  940.             Inc(J);
  941.           end;
  942.           Inc(J);
  943.         end;
  944.         for I := J to Captions.Count do begin
  945.           if I < Captions.Count then begin
  946.             if Captions[I].Visible then begin
  947.               S := Captions[I].Caption;
  948.               SetCaptionFont(I);
  949.             end
  950.             else S := '';
  951.           end
  952.           else begin
  953.             S := FFormCaption;
  954.             SetCaptionFont(-1);
  955.           end;
  956.           DrawStr(I = Captions.Count, False, -1);
  957.         end;
  958.       end
  959.       else begin
  960.         DrawNext := True;
  961.         J := 0;
  962.         if Captions <> nil then begin
  963.           while (SumWidth < (R.Right - R.Left)) and (J < Captions.Count) do
  964.           begin
  965.             if Captions[J].Visible then begin
  966.               SumWidth := SumWidth + Captions[J].TextWidth;
  967.               while Captions[J].GlueNext and (J < Captions.Count - 1) do
  968.               begin
  969.                 SumWidth := SumWidth + Captions[J + 1].TextWidth;
  970.                 Inc(J);
  971.               end;
  972.             end;
  973.             Inc(J);
  974.           end;
  975.           for I := 0 to J - 1 do begin
  976.             if Captions[I].Visible and DrawNext then begin
  977.               S := Captions[I].Caption;
  978.               if S <> '' then begin
  979.                 SetCaptionFont(I);
  980.                 DrawNext := DrawStr(((I > 0) and Captions[I - 1].GlueNext) or
  981.                   (I = 0), Captions[I].GlueNext, I - 1) and
  982.                   (Captions[I].GlueNext or (R.Right > R.Left));
  983.               end;
  984.             end;
  985.           end;
  986.         end;
  987.         if (R.Right > R.Left) and DrawNext and (FFormCaption <> '') then
  988.         begin
  989.           S := FFormCaption;
  990.           SetCaptionFont(-1);
  991.           DrawStr(False, False, -1);
  992.         end;
  993.       end;
  994.     end;
  995.     BitBlt(DC, DrawRect.Left, DrawRect.Top, Image.Width, Image.Height,
  996.       Image.Canvas.Handle, 0, 0, SRCCOPY);
  997.   finally
  998.     Image.Free;
  999.   end;
  1000. end;
  1001.  
  1002. procedure TRxGradientCaption.SetFont(Value: TFont);
  1003. begin
  1004.   FFont.Assign(Value);
  1005. end;
  1006.  
  1007. procedure TRxGradientCaption.FontChanged(Sender: TObject);
  1008. var
  1009.   I: Integer;
  1010. begin
  1011.   FDefaultFont := False;
  1012.   if (Captions <> nil) then begin
  1013.     Captions.BeginUpdate;
  1014.     try
  1015.       for I := 0 to Captions.Count - 1 do
  1016.         if Captions[I].ParentFont then Captions[I].SetParentFont(True);
  1017.     finally
  1018.       Captions.EndUpdate;
  1019.     end;
  1020.   end
  1021.   else if Active then Update;
  1022. end;
  1023.  
  1024. function TRxGradientCaption.GetTextWidth: Integer;
  1025. var
  1026.   Canvas: TCanvas;
  1027.   PS: TPaintStruct;
  1028. begin
  1029.   BeginPaint(Application.Handle, PS);
  1030.   try
  1031.     Canvas := TCanvas.Create;
  1032.     try
  1033.       Canvas.Handle := PS.hDC;
  1034.       Canvas.Font := FFont;
  1035.       Result := Canvas.TextWidth(FFormCaption);
  1036.     finally
  1037.       Canvas.Free;
  1038.     end;
  1039.   finally
  1040.     EndPaint(Application.Handle, PS);
  1041.   end;
  1042. end;
  1043.  
  1044. procedure TRxGradientCaption.SetGradientSteps(Value: Integer);
  1045. begin
  1046.   if FGradientSteps <> Value then begin
  1047.     FGradientSteps := Value;
  1048.     if Active and ((FWindowActive and GradientActive) or
  1049.       (not FWindowActive and GradientInactive)) then Update;
  1050.   end;
  1051. end;
  1052.  
  1053. procedure TRxGradientCaption.SetGradientActive(Value: Boolean);
  1054. begin
  1055.   if FGradientActive <> Value then begin
  1056.     FGradientActive := Value;
  1057.     if Active and FWindowActive then Update;
  1058.   end;
  1059. end;
  1060.  
  1061. procedure TRxGradientCaption.SetGradientInactive(Value: Boolean);
  1062. begin
  1063.   if FGradientInactive <> Value then begin
  1064.     FGradientInactive := Value;
  1065.     if Active and not FWindowActive then Update;
  1066.   end;
  1067. end;
  1068.  
  1069. procedure TRxGradientCaption.SetFontInactiveColor(Value: TColor);
  1070. begin
  1071.   if FFontInactiveColor <> Value then begin
  1072.     FFontInactiveColor := Value;
  1073.     if Active and not FWindowActive then Update;
  1074.   end;
  1075. end;
  1076.  
  1077. procedure TRxGradientCaption.SetHideDirection(Value: THideDirection);
  1078. begin
  1079.   if FHideDirection <> Value then begin
  1080.     FHideDirection := Value;
  1081.     if Active then Update;
  1082.   end;
  1083. end;
  1084.  
  1085. {$ENDIF WIN32}
  1086.  
  1087. end.