home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d6 / RX275D6.ZIP / Units / Rxgrdcpt.pas < prev    next >
Pascal/Delphi Source File  |  1999-10-12  |  31KB  |  1,085 lines

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