home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d123456 / DFS.ZIP / DFSSplitter.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-28  |  43KB  |  1,382 lines

  1. {$I DFS.INC}  { Standard defines for all Delphi Free Stuff components }
  2.  
  3. {------------------------------------------------------------------------------}
  4. { TdfsSplitter v2.03                                                           }
  5. {------------------------------------------------------------------------------}
  6. { A descendant of the TSplitter component (D3, C3, & D4) that adds a           }
  7. { "maximize - restore" button.  This mimics the behavior of the splitter in    }
  8. { Netscape Communicator v4.5.  Clicking the button moves the splitter to its   }
  9. { farthest extreme.  Clicking again returns it to the last position.           }
  10. {                                                                              }
  11. { Copyright 2000-2001, Brad Stowers.  All Rights Reserved.                     }
  12. {                                                                              }
  13. { Copyright:                                                                   }
  14. { All Delphi Free Stuff (hereafter "DFS") source code is copyrighted by        }
  15. { Bradley D. Stowers (hereafter "author"), and shall remain the exclusive      }
  16. { property of the author.                                                      }
  17. {                                                                              }
  18. { Distribution Rights:                                                         }
  19. { You are granted a non-exlusive, royalty-free right to produce and distribute }
  20. { compiled binary files (executables, DLLs, etc.) that are built with any of   }
  21. { the DFS source code unless specifically stated otherwise.                    }
  22. { You are further granted permission to redistribute any of the DFS source     }
  23. { code in source code form, provided that the original archive as found on the }
  24. { DFS web site (http://www.delphifreestuff.com) is distributed unmodified. For }
  25. { example, if you create a descendant of TdfsColorButton, you must include in  }
  26. { the distribution package the colorbtn.zip file in the exact form that you    }
  27. { downloaded it from http://www.delphifreestuff.com/mine/files/colorbtn.zip.   }
  28. {                                                                              }
  29. { Restrictions:                                                                }
  30. { Without the express written consent of the author, you may not:              }
  31. {   * Distribute modified versions of any DFS source code by itself. You must  }
  32. {     include the original archive as you found it at the DFS site.            }
  33. {   * Sell or lease any portion of DFS source code. You are, of course, free   }
  34. {     to sell any of your own original code that works with, enhances, etc.    }
  35. {     DFS source code.                                                         }
  36. {   * Distribute DFS source code for profit.                                   }
  37. {                                                                              }
  38. { Warranty:                                                                    }
  39. { There is absolutely no warranty of any kind whatsoever with any of the DFS   }
  40. { source code (hereafter "software"). The software is provided to you "AS-IS", }
  41. { and all risks and losses associated with it's use are assumed by you. In no  }
  42. { event shall the author of the softare, Bradley D. Stowers, be held           }
  43. { accountable for any damages or losses that may occur from use or misuse of   }
  44. { the software.                                                                }
  45. {                                                                              }
  46. { Support:                                                                     }
  47. { Support is provided via the DFS Support Forum, which is a web-based message  }
  48. { system.  You can find it at http://www.delphifreestuff.com/discus/           }
  49. { All DFS source code is provided free of charge. As such, I can not guarantee }
  50. { any support whatsoever. While I do try to answer all questions that I        }
  51. { receive, and address all problems that are reported to me, you must          }
  52. { understand that I simply can not guarantee that this will always be so.      }
  53. {                                                                              }
  54. { Clarifications:                                                              }
  55. { If you need any further information, please feel free to contact me directly.}
  56. { This agreement can be found online at my site in the "Miscellaneous" section.}
  57. {------------------------------------------------------------------------------}
  58. { The lateset version of my components are always available on the web at:     }
  59. {   http://www.delphifreestuff.com/                                            }
  60. { See DFSSplitter.txt for notes, known issues, and revision history.           }
  61. {------------------------------------------------------------------------------}
  62. { Date last modified:  June 27, 2001                                           }
  63. {------------------------------------------------------------------------------}
  64.  
  65. unit dfsSplitter;
  66.  
  67. interface
  68.  
  69. uses
  70.   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  71.   ExtCtrls;
  72.  
  73. const
  74.   { This shuts up C++Builder 3 about the redefiniton being different. There
  75.     seems to be no equivalent in C1.  Sorry. }
  76.   {$IFDEF DFS_CPPB_3_UP}
  77.   {$EXTERNALSYM DFS_COMPONENT_VERSION}
  78.   {$ENDIF}
  79.   DFS_COMPONENT_VERSION = 'TdfsSplitter v2.03';
  80.   MOVEMENT_TOLERANCE = 5; // See WMLButtonUp message handler.
  81.   DEF_BUTTON_HIGHLIGHT_COLOR = $00FFCFCF; // RGB(207,207,255)
  82.  
  83. type
  84.   TdfsButtonWidthType = (btwPixels, btwPercentage);
  85.   TdfsButtonStyle = (bsNetscape, bsWindows);
  86.   TdfsWindowsButton = (wbMin, wbMax, wbClose);
  87.   TdfsWindowsButtons = set of TdfsWindowsButton;
  88.  
  89.   TdfsSplitter = class(TSplitter)
  90.   private
  91.     FShowButton: boolean;
  92.     FButtonWidthType: TdfsButtonWidthType;
  93.     FButtonWidth: integer;
  94.     FOnMaximize: TNotifyEvent;
  95.     FOnMinimize: TNotifyEvent;
  96.     FOnRestore: TNotifyEvent;
  97.     FMaximized: boolean;
  98.     FMinimized: boolean;
  99.     // Internal use for "restoring" from "maximized" state
  100.     FRestorePos: integer;
  101.     // For internal use to avoid calling GetButtonRect when not necessary
  102.     FLastKnownButtonRect: TRect;
  103.     // Internal use to avoid unecessary painting
  104.     FIsHighlighted: boolean;
  105.     // Internal for detecting real clicks
  106.     FGotMouseDown: boolean;
  107.     FButtonColor: TColor;
  108.     FButtonHighlightColor: TColor;
  109.     FArrowColor: TColor;
  110.     FTextureColor1: TColor;
  111.     FTextureColor2: TColor;
  112.     FAutoHighlightColor : boolean;
  113.     FAllowDrag: boolean;
  114.     FButtonStyle: TdfsButtonStyle;
  115.     FWindowsButtons: TdfsWindowsButtons;
  116.     FOnClose: TNotifyEvent;
  117.     FButtonCursor: TCursor;
  118.     procedure SetShowButton(const Value: boolean);
  119.     procedure SetButtonWidthType(const Value: TdfsButtonWidthType);
  120.     procedure SetButtonWidth(const Value: integer);
  121.     function GetButtonRect: TRect;
  122.     procedure SetMaximized(const Value: boolean);
  123.     procedure SetMinimized(const Value: boolean);
  124.     function GetAlign: TAlign;
  125.     procedure SetAlign(Value: TAlign);
  126.     procedure SetArrowColor(const Value: TColor);
  127.     procedure SetButtonColor(const Value: TColor);
  128.     procedure SetButtonHighlightColor(const Value: TColor);
  129.     procedure SetButtonStyle(const Value: TdfsButtonStyle);
  130.     procedure SetTextureColor1(const Value: TColor);
  131.     procedure SetTextureColor2(const Value: TColor);
  132.     procedure SetAutoHighLightColor(const Value: boolean);
  133.     procedure SetAllowDrag(const Value: boolean);
  134.     procedure SetWindowsButtons(const Value: TdfsWindowsButtons);
  135.     procedure SetButtonCursor(const Value: TCursor);
  136.     function GetVersion: string;
  137.     procedure SetVersion(const Val: string);
  138.     procedure WMLButtonDown(var Msg: TWMLButtonDown); message WM_LBUTTONDOWN;
  139.     procedure WMLButtonUp(var Msg: TWMLButtonUp); message WM_LBUTTONUP;
  140.     procedure WMMouseMove(var Msg: TWMMouseMove); message WM_MOUSEMOVE;
  141.     procedure CMMouseEnter(var Msg: TWMMouse); message CM_MOUSEENTER;
  142.     procedure CMMouseLeave(var Msg: TWMMouse); message CM_MOUSELEAVE;
  143.   protected
  144.     // Internal use for moving splitter position with FindControl and
  145.     // UpdateControlSize
  146.     FControl: TControl;
  147.     FDownPos: TPoint;
  148.  
  149.     procedure LoadOtherProperties(Reader: TReader); dynamic;
  150.     procedure StoreOtherProperties(Writer: TWriter); dynamic;
  151.     procedure DefineProperties(Filer: TFiler); override;
  152.     procedure Paint; override;
  153.     {$IFDEF DFS_COMPILER_4_UP}
  154.     function DoCanResize(var NewSize: integer): boolean; override;
  155.     {$ENDIF}
  156.     procedure Loaded; override;
  157.     procedure PaintButton(Highlight: boolean); dynamic;
  158.     function DrawArrow(ACanvas: TCanvas; AvailableRect: TRect; Offset: integer;
  159.        ArrowSize: integer; Color: TColor): integer; dynamic;
  160.     function WindowButtonHitTest(X, Y: integer): TdfsWindowsButton; dynamic;
  161.     function ButtonHitTest(X, Y: integer): boolean; dynamic;
  162.     procedure DoMaximize; dynamic;
  163.     procedure DoMinimize; dynamic;
  164.     procedure DoRestore; dynamic;
  165.     procedure DoClose; dynamic;
  166.     procedure FindControl; dynamic;
  167.     procedure UpdateControlSize(NewSize: integer); dynamic;
  168.     function GrabBarColor: TColor;
  169.     function VisibleWinButtons: integer;
  170.   public
  171.     constructor Create(AOwner: TComponent); override;
  172.  
  173.     procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
  174.  
  175.     property ButtonRect: TRect
  176.        read GetButtonRect;
  177.     property RestorePos: integer
  178.        read FRestorePos
  179.        write FRestorePos;
  180.   published
  181.     property Maximized: boolean
  182.        read FMaximized
  183.        write SetMaximized;
  184.     property Minimized: boolean
  185.        read FMinimized
  186.        write SetMinimized;
  187.  
  188.  
  189.     property Version: string
  190.        read GetVersion
  191.        write SetVersion
  192.        stored FALSE;
  193.     property AllowDrag: boolean
  194.        read FAllowDrag
  195.        write SetAllowDrag
  196.        default TRUE;
  197.     property ButtonCursor: TCursor
  198.        read FButtonCursor
  199.        write SetButtonCursor;
  200.     property ButtonStyle: TdfsButtonStyle
  201.        read FButtonStyle
  202.        write SetButtonStyle
  203.        default bsNetscape;
  204.     property WindowsButtons: TdfsWindowsButtons
  205.        read FWindowsButtons
  206.        write SetWindowsButtons
  207.        default [wbMin, wbMax, wbClose];
  208.     property ButtonWidthType: TdfsButtonWidthType
  209.        read FButtonWidthType
  210.        write SetButtonWidthType
  211.        default btwPixels;
  212.     property ButtonWidth: integer
  213.        read FButtonWidth
  214.        write SetButtonWidth
  215.        default 100;
  216.     property ShowButton: boolean
  217.        read FShowButton
  218.        write SetShowButton
  219.        default TRUE;
  220.     property ButtonColor: TColor
  221.        read FButtonColor
  222.        write SetButtonColor
  223.        default clBtnFace;
  224.     property ArrowColor: TColor
  225.        read FArrowColor
  226.        write SetArrowColor
  227.        default clNavy;
  228.     property ButtonHighlightColor: TColor
  229.        read FButtonHighlightColor
  230.        write SetButtonHighlightColor
  231.        default DEF_BUTTON_HIGHLIGHT_COLOR;
  232.     property AutoHighlightColor: Boolean
  233.        read FAutoHighlightColor
  234.        write SetAutoHighlightColor
  235.        default FALSE;
  236.     property TextureColor1: TColor
  237.        read FTextureColor1
  238.        write SetTextureColor1
  239.        default clWhite;
  240.     property TextureColor2: TColor
  241.        read FTextureColor2
  242.        write SetTextureColor2
  243.        default clNavy;
  244.     property Align: TAlign // Need to know when it changes to redraw arrows
  245.        read GetAlign
  246.        write SetAlign;
  247.     property Width
  248.        default 10;  // it looks best with 10
  249.     property Beveled
  250.        default FALSE; // it looks best without the bevel
  251.     property Enabled;
  252.  
  253.     property OnClose: TNotifyEvent
  254.        read FOnClose
  255.        write FOnClose;
  256.     property OnMaximize: TNotifyEvent
  257.        read FOnMaximize
  258.        write FOnMaximize;
  259.     property OnMinimize: TNotifyEvent
  260.        read FOnMinimize
  261.        write FOnMinimize;
  262.     property OnRestore: TNotifyEvent
  263.        read FOnRestore
  264.        write FOnRestore;
  265.   end;
  266.  
  267. implementation
  268.  
  269. { TdfsSplitter }
  270.  
  271. constructor TdfsSplitter.Create(AOwner: TComponent);
  272. begin
  273.   inherited Create(AOwner);
  274.  
  275.   Beveled := FALSE;
  276.   FAllowDrag := TRUE;
  277.   FButtonStyle := bsNetscape;
  278.   FWindowsButtons := [wbMin, wbMax, wbClose];
  279.   FButtonWidthType := btwPixels;
  280.   FButtonWidth := 100;
  281.   FShowButton := TRUE;
  282.   SetRectEmpty(FLastKnownButtonRect);
  283.   FIsHighlighted := FALSE;
  284.   FGotMouseDown := FALSE;
  285.   FControl := NIL;
  286.   FDownPos := Point(0,0);
  287.   FMaximized := FALSE;
  288.   FMinimized := FALSE;
  289.   FRestorePos := -1;
  290.   Width := 10;
  291.   FButtonColor := clBtnFace;
  292.   FArrowColor := clNavy;
  293.   FButtonHighlightColor := DEF_BUTTON_HIGHLIGHT_COLOR;
  294.   FAutoHighLightColor := FALSE;
  295.   FTextureColor1 := clWhite;
  296.   FTextureColor2 := clNavy;
  297. end;
  298.  
  299. function TdfsSplitter.GrabBarColor: TColor;
  300. var
  301.   BeginRGB: array[0..2] of Byte;
  302.   RGBDifference: array[0..2] of integer;
  303.   R,G,B: Byte;
  304.   BeginColor,
  305.   EndColor: TColor;
  306.   NumberOfColors: integer;
  307.  
  308. begin
  309.   //Need to figure out how many colors available at runtime
  310.   NumberOfColors := 256;
  311.  
  312.   BeginColor := clActiveCaption;
  313.   EndColor := clBtnFace;
  314.  
  315.   BeginRGB[0] := GetRValue(ColorToRGB(BeginColor));
  316.   BeginRGB[1] := GetGValue(ColorToRGB(BeginColor));
  317.   BeginRGB[2] := GetBValue(ColorToRGB(BeginColor));
  318.  
  319.   RGBDifference[0] := GetRValue(ColorToRGB(EndColor)) - BeginRGB[0];
  320.   RGBDifference[1] := GetGValue(ColorToRGB(EndColor)) - BeginRGB[1];
  321.   RGBDifference[2] := GetBValue(ColorToRGB(EndColor)) - BeginRGB[2];
  322.  
  323.   R := BeginRGB[0] + MulDiv (180, RGBDifference[0], NumberOfColors - 1);
  324.   G := BeginRGB[1] + MulDiv (180, RGBDifference[1], NumberOfColors - 1);
  325.   B := BeginRGB[2] + MulDiv (180, RGBDifference[2], NumberOfColors - 1);
  326.  
  327.   Result := RGB (R, G, B);
  328. end;
  329.  
  330. function TdfsSplitter.DrawArrow(ACanvas: TCanvas; AvailableRect: TRect; Offset: integer;
  331.    ArrowSize: integer; Color: TColor): integer;
  332. var
  333.   x, y, q, i, j: integer;
  334.   ArrowAlign: TAlign;
  335. begin
  336.   // STB Nitro drivers have a LineTo bug, so I've opted to use the slower
  337.   // SetPixel method to draw the arrows.
  338.  
  339.   if not Odd(ArrowSize) then
  340.     Dec(ArrowSize);
  341.   if ArrowSize < 1 then
  342.     ArrowSize := 1;
  343.  
  344.   if FMaximized then
  345.   begin
  346.     case Align of
  347.       alLeft:   ArrowAlign := alRight;
  348.       alRight:  ArrowAlign := alLeft;
  349.       alTop:    ArrowAlign := alBottom;
  350.     else //alBottom
  351.       ArrowAlign := alTop;
  352.     end;
  353.   end else
  354.     ArrowAlign := Align;
  355.   q := ArrowSize * 2 - 1 ;
  356.   Result := q;
  357.   ACanvas.Pen.Color := Color;
  358.   with AvailableRect do
  359.   begin
  360.     case ArrowAlign of
  361.       alLeft:
  362.         begin
  363.           x := Left + ((Right - Left - ArrowSize) div 2) + 1;
  364.           if Offset < 0 then
  365.             y := Bottom + Offset - q
  366.           else
  367.             y := Top + Offset;
  368.           for j := x + ArrowSize - 1 downto x do
  369.           begin
  370.             for i := y to y + q - 1 do
  371.               ACanvas.Pixels[j, i] := Color;
  372.             inc(y);
  373.             dec(q,2);
  374.           end;
  375.         end;
  376.       alRight:
  377.         begin
  378.           x := Left + ((Right - Left - ArrowSize) div 2) + 1;
  379.           if Offset < 0 then
  380.             y := Bottom + Offset - q
  381.           else
  382.             y := Top + Offset;
  383.           for j := x to x + ArrowSize - 1 do
  384.           begin
  385.             for i := y to y + q - 1 do
  386.               ACanvas.Pixels[j, i] := Color;
  387.             inc(y);
  388.             dec(q,2);
  389.           end;
  390.         end;
  391.       alTop:
  392.         begin
  393.           if Offset < 0 then
  394.             x := Right + Offset - q
  395.           else
  396.             x := Left + Offset;
  397.           y := Top + ((Bottom - Top - ArrowSize) div 2) + 1;
  398.           for i := y + ArrowSize - 1 downto y do
  399.           begin
  400.             for j := x to x + q - 1 do
  401.               ACanvas.Pixels[j, i] := Color;
  402.             inc(x);
  403.             dec(q,2);
  404.           end;
  405.         end;
  406.     else // alBottom
  407.       if Offset < 0 then
  408.         x := Right + Offset - q
  409.       else
  410.         x := Left + Offset;
  411.       y := Top + ((Bottom - Top - ArrowSize) div 2) + 1;
  412.       for i := y to y + ArrowSize - 1 do
  413.       begin
  414.         for j := x to x + q - 1 do
  415.           ACanvas.Pixels[j, i] := Color;
  416.         inc(x);
  417.         dec(q,2);
  418.       end;
  419.     end;
  420.   end;
  421. end;
  422.  
  423. function TdfsSplitter.GetButtonRect: TRect;
  424. var
  425.   BW: integer;
  426. begin
  427.   if ButtonStyle = bsWindows then
  428.   begin
  429.     if Align in [alLeft, alRight] then
  430.       BW := (ClientRect.Right - ClientRect.Left) * VisibleWinButtons
  431.     else
  432.       BW := (ClientRect.Bottom - ClientRect.Top) * VisibleWinButtons;
  433.     if BW < 1 then
  434.       SetRectEmpty(Result)
  435.     else
  436.     begin
  437.       if Align in [alLeft, alRight] then
  438.         Result := Rect(0, 0, ClientRect.Right - ClientRect.Left, BW -
  439.           VisibleWinButtons)
  440.       else
  441.         Result := Rect(ClientRect.Right - BW + VisibleWinButtons, 0,
  442.           ClientRect.Right, ClientRect.Bottom - ClientRect.Top);
  443.       InflateRect(Result, -1, -1);
  444.     end;
  445.   end
  446.   else
  447.   begin
  448.     // Calc the rectangle the button goes in
  449.     if ButtonWidthType = btwPercentage then
  450.     begin
  451.       if Align in [alLeft, alRight] then
  452.         BW := ClientRect.Bottom - ClientRect.Top
  453.       else
  454.         BW := ClientRect.Right - ClientRect.Left;
  455.       BW := MulDiv(BW, FButtonWidth, 100);
  456.     end
  457.     else
  458.       BW := FButtonWidth;
  459.     if BW < 1 then
  460.       SetRectEmpty(Result)
  461.     else
  462.     begin
  463.       Result := ClientRect;
  464.       if Align in [alLeft, alRight] then
  465.       begin
  466.         Result.Top := (ClientRect.Bottom - ClientRect.Top - BW) div 2;
  467.         Result.Bottom := Result.Top + BW;
  468.         InflateRect(Result, -1, 0);
  469.       end
  470.       else
  471.       begin
  472.         Result.Left := (ClientRect.Right - ClientRect.Left - BW) div 2;
  473.         Result.Right := Result.Left + BW;
  474.         InflateRect(Result, 0, -1);
  475.       end;
  476.     end;
  477.   end;
  478.   if not IsRectEmpty(Result) then
  479.   begin
  480.     if Result.Top < 1 then
  481.       Result.Top := 1;
  482.     if Result.Left < 1 then
  483.       Result.Left := 1;
  484.     if Result.Bottom >= ClientRect.Bottom then
  485.       Result.Bottom := ClientRect.Bottom - 1;
  486.     if Result.Right >= ClientRect.Right then
  487.       Result.Right := ClientRect.Right - 1;
  488.     // Make smaller if it's beveled
  489.     if Beveled then
  490.       if Align in [alLeft, alRight] then
  491.         InflateRect(Result, -3, 0)
  492.       else
  493.         InflateRect(Result, 0, -3);
  494.   end;
  495.   FLastKnownButtonRect := Result;
  496. end;
  497.  
  498. procedure TdfsSplitter.Paint;
  499. begin
  500. // Exclude button rect from update region here for less flicker.
  501.   inherited Paint;
  502.  
  503. // Don't paint while being moved unless ResizeStyle = rsUpdate!!!
  504. // Make rect smaller if Beveled is true.
  505.   PaintButton(FIsHighlighted);
  506. end;
  507.  
  508. {$IFDEF DFS_COMPILER_4_UP}
  509. function TdfsSplitter.DoCanResize(var NewSize: integer): boolean;
  510. begin
  511.   Result := inherited DoCanResize(NewSize);
  512.   // D4 version has a bug that causes it to not honor MinSize, which causes a
  513.   // really nasty problem.
  514.   if Result and (NewSize < MinSize) then
  515.     NewSize := MinSize;
  516. end;
  517. {$ENDIF}
  518.  
  519. procedure TdfsSplitter.PaintButton(Highlight: boolean);
  520. const
  521.   TEXTURE_SIZE = 3;
  522. var
  523.   BtnRect: TRect;
  524.   CaptionBtnRect: TRect;
  525.   BW: integer;
  526.   TextureBmp: TBitmap;
  527.   x, y: integer;
  528.   RW, RH: integer;
  529.   OffscreenBmp: TBitmap;
  530.   WinButton: array[0..2] of TdfsWindowsButton;
  531.   b: TdfsWindowsButton;
  532.   BtnFlag: UINT;
  533. begin
  534.   if (not FShowButton) or (not Enabled) or (GetParentForm(Self) = NIL) then
  535.     exit;
  536.  
  537.   if FAutoHighLightColor then
  538.     FButtonHighlightColor := GrabBarColor;
  539.  
  540.   BtnRect := ButtonRect; // So we don't repeatedly call GetButtonRect
  541.   if IsRectEmpty(BtnRect) then
  542.     exit; // nothing to draw
  543.  
  544.   OffscreenBmp := TBitmap.Create;
  545.   try
  546.     OffsetRect(BtnRect, -BtnRect.Left, -BtnRect.Top);
  547.     OffscreenBmp.Width := BtnRect.Right;
  548.     OffscreenBmp.Height := BtnRect.Bottom;
  549.  
  550.     if ButtonStyle = bsWindows then
  551.     begin
  552.       OffscreenBmp.Canvas.Brush.Color := Color;
  553.       OffscreenBmp.Canvas.FillRect(BtnRect);
  554.       if Align in [alLeft, alRight] then
  555.         BW := BtnRect.Right
  556.       else
  557.         BW := BtnRect.Bottom;
  558.       FillChar(WinButton, SizeOf(WinButton), 0);
  559.       x := 0;
  560.       if Align in [alLeft, alRight] then
  561.       begin
  562.         for b := High(TdfsWindowsButton) downto Low(TdfsWindowsButton) do
  563.           if b in WindowsButtons then
  564.           begin
  565.             WinButton[x] := b;
  566.             inc(x);
  567.           end;
  568.       end
  569.       else
  570.       begin
  571.         for b := Low(TdfsWindowsButton) to High(TdfsWindowsButton) do
  572.           if b in WindowsButtons then
  573.           begin
  574.             WinButton[x] := b;
  575.             inc(x);
  576.           end;
  577.       end;
  578.       for x := 0 to VisibleWinButtons - 1 do
  579.       begin
  580.         if Align in [alLeft, alRight] then
  581.           CaptionBtnRect := Bounds(0, x * BW, BW, BW)
  582.         else
  583.           CaptionBtnRect := Bounds(x * BW, 0, BW, BW);
  584.         BtnFlag := 0;
  585.         case WinButton[x] of
  586.           wbMin:
  587.             begin
  588.               if Minimized then
  589.                 BtnFlag := DFCS_CAPTIONRESTORE
  590.               else
  591.                 BtnFlag := DFCS_CAPTIONMIN;
  592.             end;
  593.           wbMax:
  594.             begin
  595.               if Maximized then
  596.                 BtnFlag := DFCS_CAPTIONRESTORE
  597.               else
  598.                 BtnFlag := DFCS_CAPTIONMAX;
  599.             end;
  600.           wbClose:
  601.             begin
  602.               BtnFlag := DFCS_CAPTIONCLOSE;
  603.             end;
  604.         end;
  605.         DrawFrameControl(OffscreenBmp.Canvas.Handle, CaptionBtnRect, DFC_CAPTION,
  606.           BtnFlag);
  607.       end;
  608.     end
  609.     else
  610.     begin
  611.       // Draw basic button
  612.       OffscreenBmp.Canvas.Brush.Color := clGray;
  613.       OffscreenBmp.Canvas.FrameRect(BtnRect);
  614.       InflateRect(BtnRect, -1, -1);
  615.  
  616.       OffscreenBmp.Canvas.Pen.Color := clWhite;
  617.       with BtnRect, OffscreenBmp.Canvas do
  618.       begin
  619.         // This is not going to work with the STB bug.  Have to find workaround.
  620.         MoveTo(Left, Bottom-1);
  621.         LineTo(Left, Top);
  622.         LineTo(Right, Top);
  623.       end;
  624.       Inc(BtnRect.Left);
  625.       Inc(BtnRect.Top);
  626.  
  627.       if Highlight then
  628.         OffscreenBmp.Canvas.Brush.Color := ButtonHighlightColor
  629.       else
  630.         OffscreenBmp.Canvas.Brush.Color := ButtonColor;
  631.       OffscreenBmp.Canvas.FillRect(BtnRect);
  632.       FIsHighlighted := Highlight;
  633.       Dec(BtnRect.Right);
  634.       Dec(BtnRect.Bottom);
  635.  
  636.       // Draw the insides of the button
  637.       with BtnRect do
  638.       begin
  639.         // Draw the arrows
  640.         if Align in [alLeft, alRight] then
  641.         begin
  642.           InflateRect(BtnRect, 0, -4);
  643.           BW := BtnRect.Right - BtnRect.Left;
  644.           DrawArrow(OffscreenBmp.Canvas, BtnRect, 1, BW, ArrowColor);
  645.           BW := DrawArrow(OffscreenBmp.Canvas, BtnRect, -1, BW, ArrowColor);
  646.           InflateRect(BtnRect, 0, -(BW+4));
  647.         end else begin
  648.           InflateRect(BtnRect, -4, 0);
  649.           BW := BtnRect.Bottom - BtnRect.Top;
  650.           DrawArrow(OffscreenBmp.Canvas, BtnRect, 1, BW, ArrowColor);
  651.           BW := DrawArrow(OffscreenBmp.Canvas, BtnRect, -1, BW, ArrowColor);
  652.           InflateRect(BtnRect, -(BW+4), 0);
  653.         end;
  654.  
  655.         // Draw the texture
  656.         // Note: This is so complex because I'm trying to make as much like the
  657.         //       Netscape splitter as possible.  They use a 3x3 texture pattern, and
  658.         //       that's harder to tile.  If the had used an 8x8 (or smaller
  659.         //       divisibly, i.e. 2x2 or 4x4), I could have used Brush.Bitmap and
  660.         //       FillRect and they whole thing would have been about half the size,
  661.         //       twice as fast, and 1/10th as complex.
  662.         RW := BtnRect.Right - BtnRect.Left;
  663.         RH := BtnRect.Bottom - BtnRect.Top;
  664.         if (RW >= TEXTURE_SIZE) and (RH >= TEXTURE_SIZE) then
  665.         begin
  666.           TextureBmp := TBitmap.Create;
  667.           try
  668.             with TextureBmp do
  669.             begin
  670.               Width := RW;
  671.               Height := RH;
  672.               // Draw first square
  673.               Canvas.Brush.Color := OffscreenBmp.Canvas.Brush.Color;
  674.               Canvas.FillRect(Rect(0, 0, RW+1, RH+1));
  675.               Canvas.Pixels[1,1] := TextureColor1;
  676.               Canvas.Pixels[2,2] := TextureColor2;
  677.  
  678.               // Tile first square all the way across
  679.               for x := 1 to ((RW div TEXTURE_SIZE) + ord(RW mod TEXTURE_SIZE > 0)) do
  680.               begin
  681.                 Canvas.CopyRect(Bounds(x * TEXTURE_SIZE, 0, TEXTURE_SIZE,
  682.                    TEXTURE_SIZE), Canvas, Rect(0, 0, TEXTURE_SIZE, TEXTURE_SIZE));
  683.               end;
  684.  
  685.               // Tile first row all the way down
  686.               for y := 1 to ((RH div TEXTURE_SIZE) + ord(RH mod TEXTURE_SIZE > 0)) do
  687.               begin
  688.                 Canvas.CopyRect(Bounds(0, y * TEXTURE_SIZE, RW, TEXTURE_SIZE),
  689.                    Canvas, Rect(0, 0, RW, TEXTURE_SIZE));
  690.               end;
  691.  
  692.               // Above could be better if it reversed process when splitter was
  693.               // taller than it was wider.  Optimized only for horizontal right now.
  694.             end;
  695.             // Copy texture bitmap to the screen.
  696.             OffscreenBmp.Canvas.CopyRect(BtnRect, TextureBmp.Canvas,
  697.                Rect(0, 0, RW, RH));
  698.           finally
  699.             TextureBmp.Free;
  700.           end;
  701.         end;
  702.       end;
  703.     end;
  704. (**)
  705.     Canvas.CopyRect(ButtonRect, OffscreenBmp.Canvas, Rect(0, 0,
  706.        OffscreenBmp.Width, OffscreenBmp.Height));
  707.   finally
  708.     OffscreenBmp.Free;
  709.   end;
  710. end;
  711.  
  712. procedure TdfsSplitter.SetButtonWidth(const Value: integer);
  713. begin
  714.   if Value <> FButtonWidth then
  715.   begin
  716.     FButtonWidth := Value;
  717.     if (FButtonWidthType = btwPercentage) and (FButtonWidth > 100) then
  718.       FButtonWidth := 100;
  719.     if FButtonWidth < 0 then
  720.       FButtonWidth := 0;
  721.     if (ButtonStyle = bsNetscape) and ShowButton then
  722.       Invalidate;
  723.   end;
  724. end;
  725.  
  726. procedure TdfsSplitter.SetButtonWidthType(const Value: TdfsButtonWidthType);
  727. begin
  728.   if Value <> FButtonWidthType then
  729.   begin
  730.     FButtonWidthType := Value;
  731.     if (FButtonWidthType = btwPercentage) and (FButtonWidth > 100) then
  732.       FButtonWidth := 100;
  733.     if (ButtonStyle = bsNetscape) and ShowButton then
  734.       Invalidate;
  735.   end;
  736. end;
  737.  
  738. procedure TdfsSplitter.SetShowButton(const Value: boolean);
  739. begin
  740.   if Value <> FShowButton then
  741.   begin
  742.     FShowButton := Value;
  743.     SetRectEmpty(FLastKnownButtonRect);
  744.     Invalidate;
  745.   end;
  746. end;
  747.  
  748. procedure TdfsSplitter.WMMouseMove(var Msg: TWMMouseMove);
  749. begin
  750.   if AllowDrag then
  751.   begin
  752.     inherited;
  753.  
  754.     // The order is important here.  ButtonHitTest must be evaluated before
  755.     // the ButtonStyle because it will change the cursor (over button or not).
  756.     // If the order were reversed, the cursor would not get set for bsWindows
  757.     // style since short-circuit boolean eval would stop it from ever being
  758.     // called in the first place.
  759.     if ButtonHitTest(Msg.XPos, Msg.YPos) and (ButtonStyle = bsNetscape) then
  760.     begin
  761.       if not FIsHighlighted then
  762.         PaintButton(TRUE)
  763.     end else
  764.       if FIsHighlighted then
  765.         PaintButton(FALSE);
  766.   end else
  767.     DefaultHandler(Msg); // Bypass TSplitter and just let normal handling occur.
  768. end;
  769.  
  770. procedure TdfsSplitter.CMMouseEnter(var Msg: TWMMouse);
  771. var
  772.   Pos: TPoint;
  773. begin
  774.   inherited;
  775.  
  776.   GetCursorPos(Pos); // CM_MOUSEENTER doesn't send mouse pos.
  777.   Pos := Self.ScreenToClient(Pos);
  778.   // The order is important here.  ButtonHitTest must be evaluated before
  779.   // the ButtonStyle because it will change the cursor (over button or not).
  780.   // If the order were reversed, the cursor would not get set for bsWindows
  781.   // style since short-circuit boolean eval would stop it from ever being
  782.   // called in the first place.
  783.   if ButtonHitTest(Pos.x, Pos.y) and (ButtonStyle = bsNetscape) then
  784.   begin
  785.     if not FIsHighlighted then
  786.       PaintButton(TRUE)
  787.   end else
  788.     if FIsHighlighted then
  789.       PaintButton(FALSE);
  790. end;
  791.  
  792. procedure TdfsSplitter.CMMouseLeave(var Msg: TWMMouse);
  793. begin
  794.   inherited;
  795.  
  796.   if (ButtonStyle = bsNetscape) and FIsHighlighted then
  797.     PaintButton(FALSE);
  798.  
  799.   FGotMouseDown := FALSE;
  800. end;
  801.  
  802. procedure TdfsSplitter.WMLButtonDown(var Msg: TWMLButtonDown);
  803. begin
  804.   if Enabled then
  805.   begin
  806.     FGotMouseDown := ButtonHitTest(Msg.XPos, Msg.YPos);
  807.     if FGotMouseDown then
  808.     begin
  809.       FindControl;
  810.       FDownPos := ClientToScreen(Point(Msg.XPos, Msg.YPos));
  811.     end;
  812.   end;
  813.   if AllowDrag then
  814.     inherited // Let TSplitter have it.
  815.   else
  816.     // Bypass TSplitter and just let normal handling occur. Prevents drag painting.
  817.     DefaultHandler(Msg);
  818. end;
  819.  
  820. procedure TdfsSplitter.WMLButtonUp(var Msg: TWMLButtonUp);
  821. var
  822.   CurPos: TPoint;
  823.   OldMax: boolean;
  824. begin
  825.   inherited;
  826.  
  827.   if FGotMouseDown then
  828.   begin
  829.     if ButtonHitTest(Msg.XPos, Msg.YPos) then
  830.     begin
  831.       CurPos := ClientToScreen(Point(Msg.XPos, Msg.YPos));
  832.       // More than a little movement is not a click, but a regular resize.
  833.       if ((Align in [alLeft, alRight]) and
  834.          (Abs(FDownPos.x - CurPos.X) <= MOVEMENT_TOLERANCE)) or
  835.          ((Align in [alTop, alBottom]) and
  836.          (Abs(FDownPos.y - CurPos.Y) <= MOVEMENT_TOLERANCE)) then
  837.       begin
  838.         StopSizing;
  839.         if ButtonStyle = bsNetscape then
  840.           Maximized := not Maximized
  841.         else
  842.           case WindowButtonHitTest(Msg.XPos, Msg.YPos) of
  843.             wbMin: Minimized := not Minimized;
  844.             wbMax: Maximized := not Maximized;
  845.             wbClose: DoClose;
  846.           end;
  847.       end;
  848.     end;
  849.     FGotMouseDown := FALSE;
  850.   end
  851.   else if AllowDrag then
  852.   begin
  853.     FindControl;
  854.     if FControl = NIL then
  855.       exit;
  856.  
  857.     OldMax := FMaximized;
  858.     case Align of
  859.       alLeft, alRight: FMaximized := FControl.Width <= MinSize;
  860.       alTop, alBottom: FMaximized := FControl.Height <= MinSize;
  861.     end;
  862.     if FMaximized then
  863.     begin
  864.       UpdateControlSize(MinSize);
  865.       if not OldMax then
  866.         DoMaximize;
  867.     end
  868.     else
  869.     begin
  870.       case Align of
  871.         alLeft,
  872.         alRight:  FRestorePos := FControl.Width;
  873.         alTop,
  874.         alBottom: FRestorePos := FControl.Height;
  875.       end;
  876.       if OldMax then
  877.         DoRestore;
  878.     end;
  879.   end;
  880.   Invalidate;
  881. end;
  882.  
  883. function TdfsSplitter.WindowButtonHitTest(X, Y: integer): TdfsWindowsButton;
  884. var
  885.   BtnRect: TRect;
  886.   i: integer;
  887.   b: TdfsWindowsButton;
  888.   WinButton: array[0..2] of TdfsWindowsButton;
  889.   BW: integer;
  890.   BRs: array[0..2] of TRect;
  891. begin
  892.   Result := wbMin;
  893.   // Figure out which one was hit.  This function assumes ButtonHitTest has
  894.   // been called and returned TRUE.
  895.   BtnRect := ButtonRect; // So we don't repeatedly call GetButtonRect
  896.   i := 0;
  897.   if Align in [alLeft, alRight] then
  898.   begin
  899.     for b := High(TdfsWindowsButton) downto Low(TdfsWindowsButton) do
  900.       if b in WindowsButtons then
  901.       begin
  902.         WinButton[i] := b;
  903.         inc(i);
  904.       end;
  905.   end
  906.   else
  907.     for b := Low(TdfsWindowsButton) to High(TdfsWindowsButton) do
  908.       if b in WindowsButtons then
  909.       begin
  910.         WinButton[i] := b;
  911.         inc(i);
  912.       end;
  913.  
  914.   if Align in [alLeft, alRight] then
  915.     BW := BtnRect.Right - BtnRect.Left
  916.   else
  917.     BW := BtnRect.Bottom - BtnRect.Top;
  918.   FillChar(BRs, SizeOf(BRs), 0);
  919.   for i := 0 to VisibleWinButtons - 1 do
  920.     if ((Align in [alLeft, alRight]) and PtInRect(Bounds(BtnRect.Left,
  921.       BtnRect.Top + (BW * i), BW, BW), Point(X, Y))) or ((Align in [alTop,
  922.       alBottom]) and PtInRect(Bounds(BtnRect.Left + (BW * i), BtnRect.Top, BW,
  923.       BW), Point(X, Y))) then
  924.     begin
  925.       Result := WinButton[i];
  926.       break;
  927.     end;
  928. end;
  929.  
  930. function TdfsSplitter.ButtonHitTest(X, Y: integer): boolean;
  931. begin
  932.   // We use FLastKnownButtonRect here so that we don't have to recalculate the
  933.   // button rect with GetButtonRect every time the mouse moved.  That would be
  934.   // EXTREMELY inefficient.
  935.   Result := PtInRect(FLastKnownButtonRect, Point(X, Y));
  936.   if Align in [alLeft, alRight] then
  937.   begin
  938.     if (not AllowDrag) or ((Y >= FLastKnownButtonRect.Top) and
  939.       (Y <= FLastKnownButtonRect.Bottom)) then
  940.       Cursor := FButtonCursor
  941.     else
  942.       Cursor := crHSplit;
  943.   end else begin
  944.     if (not AllowDrag) or ((X >= FLastKnownButtonRect.Left) and
  945.       (X <= FLastKnownButtonRect.Right)) then
  946.       Cursor := FButtonCursor
  947.     else
  948.       Cursor := crVSplit;
  949.   end;
  950. end;
  951.  
  952. procedure TdfsSplitter.DoMaximize;
  953. begin
  954.   if assigned(FOnMaximize) then
  955.     FOnMaximize(Self);
  956. end;
  957.  
  958.  
  959. procedure TdfsSplitter.DoRestore;
  960. begin
  961.   if assigned(FOnRestore) then
  962.     FOnRestore(Self);
  963. end;
  964.  
  965. //DoClose
  966.  
  967. procedure TdfsSplitter.SetMaximized(const Value: boolean);
  968. begin
  969.   if Value <> FMaximized then
  970.   begin
  971.  
  972.     if csLoading in ComponentState then
  973.     begin
  974.       FMaximized := Value;
  975.       exit;
  976.     end;
  977.  
  978.     FindControl;
  979.     if FControl = NIL then
  980.       exit;
  981.  
  982.     if Value then
  983.     begin
  984.       if FMinimized then
  985.         FMinimized := FALSE
  986.       else
  987.       begin
  988.         case Align of
  989.           alLeft,
  990.           alRight:  FRestorePos := FControl.Width;
  991.           alTop,
  992.           alBottom: FRestorePos := FControl.Height;
  993.         else
  994.           exit;
  995.         end;
  996.       end;
  997.       if ButtonStyle = bsNetscape then
  998.         UpdateControlSize(-3000)
  999.       else
  1000.         case Align of
  1001.           alLeft,
  1002.           alBottom: UpdateControlSize(3000);
  1003.           alRight,
  1004.           alTop: UpdateControlSize(-3000);
  1005.         else
  1006.           exit;
  1007.         end;
  1008.       FMaximized := Value;
  1009.       DoMaximize;
  1010.     end
  1011.     else
  1012.     begin
  1013.       UpdateControlSize(FRestorePos);
  1014.       FMaximized := Value;
  1015.       DoRestore;
  1016.     end;
  1017.   end;
  1018. end;
  1019.  
  1020. procedure TdfsSplitter.SetMinimized(const Value: boolean);
  1021. begin
  1022.   if Value <> FMinimized then
  1023.   begin
  1024.  
  1025.     if csLoading in ComponentState then
  1026.     begin
  1027.       FMinimized := Value;
  1028.       exit;
  1029.     end;
  1030.  
  1031.     FindControl;
  1032.     if FControl = NIL then
  1033.       exit;
  1034.  
  1035.     if Value then
  1036.     begin
  1037.       if FMaximized then
  1038.         FMaximized := FALSE
  1039.       else
  1040.       begin
  1041.         case Align of
  1042.           alLeft,
  1043.           alRight:  FRestorePos := FControl.Width;
  1044.           alTop,
  1045.           alBottom: FRestorePos := FControl.Height;
  1046.         else
  1047.           exit;
  1048.         end;
  1049.       end;
  1050.       FMinimized := Value;
  1051.       // Just use something insanely large to get it to move to the other extreme
  1052.       case Align of
  1053.         alLeft,
  1054.         alBottom: UpdateControlSize(-3000);
  1055.         alRight,
  1056.         alTop: UpdateControlSize(3000);
  1057.       else
  1058.         exit;
  1059.       end;
  1060.       DoMinimize;
  1061.     end
  1062.     else
  1063.     begin
  1064.       FMinimized := Value;
  1065.       UpdateControlSize(FRestorePos);
  1066.       DoRestore;
  1067.     end;
  1068.   end;
  1069. end;
  1070.  
  1071. function TdfsSplitter.GetAlign: TAlign;
  1072. begin
  1073.   Result := inherited Align;
  1074. end;
  1075.  
  1076. procedure TdfsSplitter.SetAlign(Value: TAlign);
  1077. begin
  1078.   inherited Align := Value;
  1079.  
  1080.   Invalidate; // Direction changing, redraw arrows.
  1081.   {$IFNDEF DFS_COMPILER_4_UP}
  1082.   // D4 does this already
  1083.   if (Cursor <> crVSplit) and (Cursor <> crHSplit) then Exit;
  1084.   if Align in [alBottom, alTop] then
  1085.     Cursor := crVSplit
  1086.   else
  1087.     Cursor := crHSplit;
  1088.   {$ENDIF}
  1089. end;
  1090.  
  1091.  
  1092. procedure TdfsSplitter.FindControl;
  1093. var
  1094.   P: TPoint;
  1095.   I: Integer;
  1096.   R: TRect;
  1097. begin
  1098.   if Parent = NIL then
  1099.     exit;
  1100.   FControl := NIL;
  1101.   P := Point(Left, Top);
  1102.   case Align of
  1103.     alLeft: Dec(P.X);
  1104.     alRight: Inc(P.X, Width);
  1105.     alTop: Dec(P.Y);
  1106.     alBottom: Inc(P.Y, Height);
  1107.   else
  1108.     Exit;
  1109.   end;
  1110.   for I := 0 to Parent.ControlCount - 1 do
  1111.   begin
  1112.     FControl := Parent.Controls[I];
  1113.     if FControl.Visible and FControl.Enabled then
  1114.     begin
  1115.       R := FControl.BoundsRect;
  1116.       if (R.Right - R.Left) = 0 then
  1117.         Dec(R.Left);
  1118.       if (R.Bottom - R.Top) = 0 then
  1119.         Dec(R.Top);
  1120.       if PtInRect(R, P) then
  1121.         Exit;
  1122.     end;
  1123.   end;
  1124.   FControl := NIL;
  1125. end;
  1126.  
  1127.  
  1128. procedure TdfsSplitter.UpdateControlSize(NewSize: integer);
  1129.   procedure MoveViaMouse(FromPos, ToPos: integer; Horizontal: boolean);
  1130.   begin
  1131.     if Horizontal then
  1132.     begin
  1133.       MouseDown(mbLeft, [ssLeft], FromPos, 0);
  1134.       MouseMove([ssLeft], ToPos, 0);
  1135.       MouseUp(mbLeft, [ssLeft], ToPos, 0);
  1136.     end
  1137.     else
  1138.     begin
  1139.       MouseDown(mbLeft, [ssLeft], 0, FromPos);
  1140.       MouseMove([ssLeft], 0, ToPos);
  1141.       MouseUp(mbLeft, [ssLeft], 0, ToPos);
  1142.     end;
  1143.   end;
  1144. begin
  1145.   if (FControl <> NIL) then
  1146.   begin
  1147.     { You'd think that using FControl directly would be the way to change it's
  1148.       position (and thus the splitter's position), wouldn't you?  But, TSplitter
  1149.       has this nutty idea that the only way a control's size will change is if
  1150.       the mouse moves the splitter.  If you size the control manually, the
  1151.       splitter has an internal variable (FOldSize) that will not get updated.
  1152.       Because of this, if you try to then move the newly positioned splitter
  1153.       back to the old position, it won't go there (NewSize <> OldSize must be
  1154.       true).  Now, what are the odds that the user will move the splitter back
  1155.       to the exact same pixel it used to be on?  Normally, extremely low.  But,
  1156.       if the splitter has been restored from it's minimized position, it then
  1157.       becomes quite likely:  i.e. they drag it back all the way to the min
  1158.       position.  What a pain. }
  1159.     case Align of
  1160.       alLeft: MoveViaMouse(Left, FControl.Left + NewSize, TRUE);
  1161.               // alLeft: FControl.Width := NewSize;
  1162.       alTop: MoveViaMouse(Top, FControl.Top + NewSize, FALSE);
  1163.              // FControl.Height := NewSize;
  1164.       alRight: MoveViaMouse(Left, (FControl.Left + FControl.Width - Width) - NewSize, TRUE);
  1165.         {begin
  1166.           Parent.DisableAlign;
  1167.           try
  1168.             FControl.Left := FControl.Left + (FControl.Width - NewSize);
  1169.             FControl.Width := NewSize;
  1170.           finally
  1171.             Parent.EnableAlign;
  1172.           end;
  1173.         end;}
  1174.       alBottom: MoveViaMouse(Top, (FControl.Top + FControl.Height - Height) - NewSize, FALSE);
  1175.         {begin
  1176.           Parent.DisableAlign;
  1177.           try
  1178.             FControl.Top := FControl.Top + (FControl.Height - NewSize);
  1179.             FControl.Height := NewSize;
  1180.           finally
  1181.             Parent.EnableAlign;
  1182.           end;
  1183.         end;}
  1184.     end;
  1185.     Update;
  1186.   end;
  1187. end;
  1188.  
  1189. procedure TdfsSplitter.SetArrowColor(const Value: TColor);
  1190. begin
  1191.   if FArrowColor <> Value then
  1192.   begin
  1193.     FArrowColor := Value;
  1194.     if (ButtonStyle = bsNetscape) and ShowButton then
  1195.       Invalidate;
  1196.   end;
  1197. end;
  1198.  
  1199. procedure TdfsSplitter.SetButtonColor(const Value: TColor);
  1200. begin
  1201.   if FButtonColor <> Value then
  1202.   begin
  1203.     FButtonColor := Value;
  1204.     if (ButtonStyle = bsNetscape) and ShowButton then
  1205.       Invalidate;
  1206.   end;
  1207. end;
  1208.  
  1209. procedure TdfsSplitter.SetButtonHighlightColor(const Value: TColor);
  1210. begin
  1211.   if FButtonHighlightColor <> Value then
  1212.   begin
  1213.     FButtonHighlightColor := Value;
  1214.     if (ButtonStyle = bsNetscape) and ShowButton then
  1215.       Invalidate;
  1216.   end;
  1217. end;
  1218.  
  1219. procedure TdfsSplitter.SetAutoHighlightColor(const Value: boolean);
  1220. begin
  1221.   if FAutoHighLightColor <> Value then
  1222.   begin
  1223.     FAutoHighLightColor := Value;
  1224.     if FAutoHighLightColor then
  1225.       FButtonHighLightColor := GrabBarColor
  1226.     else
  1227.       FButtonHighLightColor := DEF_BUTTON_HIGHLIGHT_COLOR;
  1228.     if (ButtonStyle = bsNetscape) and ShowButton then
  1229.       Invalidate;
  1230.   end;
  1231. end;
  1232.  
  1233. procedure TdfsSplitter.SetTextureColor1(const Value: TColor);
  1234. begin
  1235.   if FTextureColor1 <> Value then
  1236.   begin
  1237.     FTextureColor1 := Value;
  1238.     if (ButtonStyle = bsNetscape) and ShowButton then
  1239.       Invalidate;
  1240.   end;
  1241. end;
  1242.  
  1243. procedure TdfsSplitter.SetTextureColor2(const Value: TColor);
  1244. begin
  1245.   if FTextureColor2 <> Value then
  1246.   begin
  1247.     FTextureColor2 := Value;
  1248.     if (ButtonStyle = bsNetscape) and ShowButton then
  1249.       Invalidate;
  1250.   end;
  1251. end;
  1252.  
  1253. function TdfsSplitter.GetVersion: string;
  1254. begin
  1255.   Result := DFS_COMPONENT_VERSION;
  1256. end;
  1257.  
  1258. procedure TdfsSplitter.SetVersion(const Val: string);
  1259. begin
  1260.   { empty write method, just needed to get it to show up in Object Inspector }
  1261. end;
  1262.  
  1263.  
  1264. procedure TdfsSplitter.Loaded;
  1265. begin
  1266.   inherited Loaded;
  1267.   if FRestorePos = -1 then
  1268.   begin
  1269.     FindControl;
  1270.     if FControl <> NIL then
  1271.       case Align of
  1272.         alLeft,
  1273.         alRight:  FRestorePos := FControl.Width;
  1274.         alTop,
  1275.         alBottom: FRestorePos := FControl.Height;
  1276.       end;
  1277.   end;
  1278. {  if FMaximized then
  1279.   begin
  1280.     FMaximized := FALSE;
  1281.     Maximized := TRUE;
  1282.   end
  1283.   else
  1284.   if FMinimized then
  1285.   begin
  1286.     FMinimized := FALSE;
  1287.     Minimized := TRUE;
  1288.   end;}
  1289. end;
  1290.  
  1291. procedure TdfsSplitter.SetBounds(ALeft, ATop, AWidth, AHeight: Integer);
  1292. begin
  1293.   inherited SetBounds(ALeft, ATop, AWidth, AHeight);
  1294.   if FRestorePos < 0 then
  1295.   begin
  1296.     FindControl;
  1297.     if FControl <> NIL then
  1298.       case Align of
  1299.         alLeft,
  1300.         alRight:  FRestorePos := FControl.Width;
  1301.         alTop,
  1302.         alBottom: FRestorePos := FControl.Height;
  1303.       end;
  1304.   end;
  1305. end;
  1306.  
  1307. procedure TdfsSplitter.SetAllowDrag(const Value: boolean);
  1308. var
  1309.   Pt: TPoint;
  1310. begin
  1311.   if FAllowDrag <> Value then
  1312.   begin
  1313.     FAllowDrag := Value;
  1314.     // Have to reset cursor in case it's on the splitter at the moment
  1315.     GetCursorPos(Pt);
  1316.     Pt := ScreenToClient(Pt);
  1317.     ButtonHitTest(Pt.x, Pt.y);
  1318.   end;
  1319. end;
  1320.  
  1321. function TdfsSplitter.VisibleWinButtons: integer;
  1322. var
  1323.   x: TdfsWindowsButton;
  1324. begin
  1325.   Result := 0;
  1326.   for x := Low(TdfsWindowsButton) to High(TdfsWindowsButton) do
  1327.     if x in WindowsButtons then
  1328.       inc(Result);
  1329. end;
  1330.  
  1331. procedure TdfsSplitter.SetButtonStyle(const Value: TdfsButtonStyle);
  1332. begin
  1333.   FButtonStyle := Value;
  1334.   if ShowButton then
  1335.     Invalidate;
  1336. end;
  1337.  
  1338. procedure TdfsSplitter.SetWindowsButtons(const Value: TdfsWindowsButtons);
  1339. begin
  1340.   FWindowsButtons := Value;
  1341.   if (ButtonStyle = bsWindows) and ShowButton then
  1342.     Invalidate;
  1343. end;
  1344.  
  1345. procedure TdfsSplitter.DoMinimize;
  1346. begin
  1347.   if assigned(FOnMinimize) then
  1348.     FOnMinimize(Self);
  1349. end;
  1350.  
  1351. procedure TdfsSplitter.DoClose;
  1352. begin
  1353.   if Assigned(FOnClose) then
  1354.     FOnClose(Self);
  1355. end;
  1356.  
  1357. procedure TdfsSplitter.SetButtonCursor(const Value: TCursor);
  1358. begin
  1359.   FButtonCursor := Value;
  1360. end;
  1361.  
  1362. procedure TdfsSplitter.LoadOtherProperties(Reader: TReader);
  1363. begin
  1364.   RestorePos := Reader.ReadInteger;
  1365. end;
  1366.  
  1367.  
  1368. procedure TdfsSplitter.StoreOtherProperties(Writer: TWriter);
  1369. begin
  1370.   Writer.WriteInteger(RestorePos);
  1371. end;
  1372.  
  1373. procedure TdfsSplitter.DefineProperties(Filer: TFiler);
  1374. begin
  1375.   inherited;
  1376.   Filer.DefineProperty('RestorePos', LoadOtherProperties, StoreOtherProperties,
  1377.     Minimized or Maximized);
  1378. end;
  1379.  
  1380. end.
  1381.  
  1382.