home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d56 / RMCTL.ZIP / rmTabs3x.pas < prev    next >
Pascal/Delphi Source File  |  2001-06-22  |  46KB  |  1,654 lines

  1. {================================================================================
  2. Copyright (C) 1997-2001 Mills Enterprise
  3.  
  4. Unit     : rmTabs3x
  5. Purpose  : Rewrite of the original Delphi Win3x tab with future enhancements
  6.            (Win2k)
  7. Date     : 05-15-1999
  8. Author   : Ryan J. Mills
  9. Version  : 1.80
  10. ================================================================================}
  11.  
  12. unit rmTabs3x;
  13.  
  14. interface
  15.  
  16. {$I CompilerDefines.INC}
  17.  
  18. uses Windows, Classes, Graphics, Forms, Controls, Messages;
  19.  
  20. type
  21.   TScrollBtn = (sbLeft, sbRight);
  22.   TTabType = (ttWin3x, ttWin2k);
  23.  
  24.   TrmScroller = class(TCustomControl)
  25.   private
  26.     { property usage }
  27.     FMin: Longint;
  28.     FMax: Longint;
  29.     FPosition: Longint;
  30.     FOnClick: TNotifyEvent;
  31.     FChange: Integer;
  32.  
  33.     { private usage }
  34.     Bitmap: TBitmap;
  35.     Pressed: Boolean;
  36.     Down: Boolean;
  37.     Current: TScrollBtn;
  38.     pWidth: Integer;
  39.     pHeight: Integer;
  40.  
  41.     { property access methods }
  42.     procedure SetMin(Value: Longint);
  43.     procedure SetMax(Value: Longint);
  44.     procedure SetPosition(Value: Longint);
  45.  
  46.     { private methods }
  47.     function CanScrollLeft: Boolean;
  48.     function CanScrollRight: Boolean;
  49.     procedure DoMouseDown(X: Integer);
  50.     procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
  51.     procedure WMLButtonDblClk(var Message: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;
  52.     procedure WMMouseMove(var Message: TWMMouseMove); message WM_MOUSEMOVE;
  53.     procedure WMLButtonUp(var Message: TWMLButtonUp); message WM_LBUTTONUP;
  54.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  55.   public
  56.     constructor Create(AOwner: TComponent); override;
  57.     destructor Destroy; override;
  58.     procedure Paint; override;
  59.   published
  60.     property OnClick: TNotifyEvent read FOnClick write FOnClick;
  61.     property Min: Longint read FMin write SetMin default 0;
  62.     property Max: Longint read FMax write SetMax default 0;
  63.     property Position: Longint read FPosition write SetPosition default 0;
  64.     property Change: Integer read FChange write FChange default 1;
  65.   end;
  66.  
  67.   TrmTabSet = class;
  68.  
  69.   TrmTabList = class(TStringList)
  70.   private
  71.     Tabs: TrmTabSet;
  72.   public
  73.     procedure Insert(Index: Integer; const S: string); override;
  74.     procedure Delete(Index: Integer); override;
  75.     function Add(const S: string): Integer; override;
  76.     procedure Put(Index: Integer; const S: string); override;
  77.     procedure Clear; override;
  78.     procedure AddStrings(Strings: TStrings); override;
  79.   end;
  80.  
  81.   { eash TEdgeType is made up of one or two of these parts }
  82.   TEdgePart = (epSelectedLeft, epUnselectedLeft, epSelectedRight,
  83.     epUnselectedRight);
  84.  
  85.   { represents the intersection between two tabs, or the edge of a tab }
  86.   TEdgeType = (etNone, etFirstIsSel, etFirstNotSel, etLastIsSel, etLastNotSel,
  87.     etNotSelToSel, etSelToNotSel, etNotSelToNotSel);
  88.  
  89.   TTabStyle = (tsStandard, tsOwnerDraw);
  90.  
  91.   TMeasureTabEvent = procedure(Sender: TObject; Index: Integer; var TabWidth: Integer) of object;
  92.   TDrawTabEvent = procedure(Sender: TObject; TabCanvas: TCanvas; R: TRect; Index: Integer; Selected: Boolean) of object;
  93.   TTabChangeEvent = procedure(Sender: TObject; NewTab: Integer; var AllowChange: Boolean) of object;
  94.  
  95.   TrmTabSet = class(TCustomControl)
  96.   private
  97.     { property instance variables }
  98.     FStartMargin: Integer;
  99.     FEndMargin: Integer;
  100.     FTabs: TStrings;
  101.     FTabIndex: Integer;
  102.     FFirstIndex: Integer;
  103.     FVisibleTabs: Integer;
  104.     FSelectedColor: TColor;
  105.     FUnselectedColor: TColor;
  106.     FBackgroundColor: TColor;
  107.     FDitherBackground: Boolean;
  108.     FAutoScroll: Boolean;
  109.     FStyle: TTabStyle;
  110.     FOwnerDrawHeight: Integer;
  111.     FOnMeasureTab: TMeasureTabEvent;
  112.     FOnDrawTab: TDrawTabEvent;
  113.     FOnChange: TTabChangeEvent;
  114.     FTabType: TTabType;
  115.  
  116.     { private instance variables }
  117.     TabPositions: TList;
  118.     FTabHeight: Integer;
  119. {    FTopEdge, FBottomEdge: integer;}
  120.     FScroller: TrmScroller;
  121.     FDoFix: Boolean;
  122.     FDisabledTabs: TStrings;
  123.     fEdgeWidth: integer;
  124.  
  125.     { property access methods }
  126.     procedure SetSelectedColor(Value: TColor);
  127.     procedure SetUnselectedColor(Value: TColor);
  128.     procedure SetBackgroundColor(Value: TColor);
  129.     procedure SetDitherBackground(Value: Boolean);
  130.     procedure SetAutoScroll(Value: Boolean);
  131.     procedure SetStartMargin(Value: Integer);
  132.     procedure SetEndMargin(Value: Integer);
  133.     procedure SetTabIndex(Value: Integer);
  134.     procedure SetFirstIndex(Value: Integer);
  135.     procedure SetTabList(Value: TStrings);
  136.     procedure SetTabStyle(Value: TTabStyle);
  137.     procedure SetTabHeight(Value: Integer);
  138.     procedure SetTabType(const Value: TTabType);
  139.     procedure SetDisabledTabList(const Value: TStrings);
  140.  
  141.     { private methods }
  142.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  143.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  144.     procedure PaintEdge(Canvas: TCanvas; X, Y, H: Integer; Edge: TEdgeType);
  145.     procedure CreateBrushPattern(Bitmap: TBitmap);
  146.     function Calc3xTabPositions(Start, Stop: Integer; Canvas: TCanvas; First: Integer): Integer;
  147.     function Calc2kTabPositions(Start, Stop: Integer; Canvas: TCanvas; First: Integer): Integer;
  148.     procedure CreateScroller;
  149.     procedure FixTabPos;
  150.     procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
  151.     procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR;
  152.     procedure ScrollClick(Sender: TObject);
  153.     procedure ReadIntData(Reader: TReader);
  154.     procedure ReadBoolData(Reader: TReader);
  155.     procedure SetEdgeWidth(const Value: integer);
  156.   protected
  157.     procedure CreateParams(var Params: TCreateParams); override;
  158.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  159.     procedure Paint; override;
  160.     procedure DrawTab(TabCanvas: TCanvas; R: TRect; Index: Integer; Selected: Boolean); virtual;
  161.     function CanChange(NewIndex: Integer): Boolean;
  162.     procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  163.     procedure MeasureTab(Index: Integer; var TabWidth: Integer); virtual;
  164.     procedure DefineProperties(Filer: TFiler); override;
  165.     procedure Paint2k;
  166.     procedure Paint3x;
  167.     function TabEnabled(index:integer):boolean;
  168.   public
  169.     constructor Create(AOwner: TComponent); override;
  170.     destructor Destroy; override;
  171.     function ItemAtPos(Pos: TPoint): Integer;
  172.     function ItemRect(Item: Integer): TRect;
  173.     procedure SelectNext(Direction: Boolean);
  174.     property Canvas;
  175.     property FirstIndex: Integer read FFirstIndex write SetFirstIndex default 0;
  176.  
  177.   published
  178.     property Align;
  179.     property Anchors;
  180.     property AutoScroll: Boolean read FAutoScroll write SetAutoScroll default True;
  181.     property BackgroundColor: TColor read FBackgroundColor write SetBackgroundColor default clBtnFace;
  182.     property Constraints;
  183.     property DitherBackground: Boolean read FDitherBackground write SetDitherBackground default True;
  184.     property DragCursor;
  185.     property DragKind;
  186.     property DragMode;
  187.     property EdgeWidth : integer read fEdgeWidth write SetEdgeWidth default 9; //This controls the angle of the tab edges
  188.     property Enabled;
  189.     property DisabledTabs: TStrings read FDisabledTabs write SetDisabledTabList;
  190.     property EndMargin: Integer read FEndMargin write SetEndMargin default 5;
  191.     property Font;
  192.     property ParentShowHint;
  193.     property PopupMenu;
  194.     property ShowHint;
  195.     property StartMargin: Integer read FStartMargin write SetStartMargin default 5;
  196.     property SelectedColor: TColor read FSelectedColor write SetSelectedColor default clBtnFace;
  197.     property Style: TTabStyle read FStyle write SetTabStyle default tsStandard;
  198.     property TabHeight: Integer read FOwnerDrawHeight write SetTabHeight default 20;
  199.     property Tabs: TStrings read FTabs write SetTabList;
  200.     property TabIndex: Integer read FTabIndex write SetTabIndex default -1;
  201.     property TabType: TTabType read fTabType write SetTabType default ttWin3x;
  202.     property UnselectedColor: TColor read FUnselectedColor write SetUnselectedColor default clWindow;
  203.     property Visible;
  204.     property VisibleTabs: Integer read FVisibleTabs;
  205.     property OnClick;
  206.     property OnChange: TTabChangeEvent read FOnChange write FOnChange;
  207.     property OnDragDrop;
  208.     property OnDragOver;
  209.     property OnDrawTab: TDrawTabEvent read FOnDrawTab write FOnDrawTab;
  210.     property OnEndDock;
  211.     property OnEndDrag;
  212.     property OnEnter;
  213.     property OnExit;
  214.     property OnMouseDown;
  215.     property OnMouseMove;
  216.     property OnMouseUp;
  217.     property OnMeasureTab: TMeasureTabEvent read FOnMeasureTab write FOnMeasureTab;
  218.     property OnStartDock;
  219.     property OnStartDrag;
  220.   end;
  221.  
  222. implementation
  223.  
  224. uses Consts, SysUtils, rmLibrary;
  225.  
  226. {$R rmTabs3x.RES}
  227.  
  228. type
  229.   TTabPos = record
  230.     Size, StartPos: Word;
  231.   end;
  232.  
  233. { TrmScroller }
  234.  
  235. constructor TrmScroller.Create(AOwner: TComponent);
  236. begin
  237.   inherited Create(AOwner);
  238.   ControlStyle := ControlStyle + [csOpaque];
  239.   Bitmap := TBitmap.Create;
  240.   pWidth := 24;
  241.   pHeight := 13;
  242.   FMin := 0;
  243.   FMax := 0;
  244.   FPosition := 0;
  245.   FChange := 1;
  246. end;
  247.  
  248. destructor TrmScroller.Destroy;
  249. begin
  250.   Bitmap.Free;
  251.   inherited Destroy;
  252. end;
  253.  
  254. procedure TrmScroller.Paint;
  255. begin
  256.   with Canvas do
  257.   begin
  258.     { paint left button }
  259.     if CanScrollLeft then
  260.     begin
  261.       if Down and (Current = sbLeft) then
  262.         Bitmap.Handle := LoadBitmap(HInstance, 'RMSBLEFTDN')
  263.       else
  264.         Bitmap.Handle := LoadBitmap(HInstance, 'RMSBLEFT');
  265.     end
  266.     else
  267.       Bitmap.Handle := LoadBitmap(HInstance, 'RMSBLEFTDIS');
  268.     Draw(0, 0, Bitmap);
  269.  
  270.     { paint right button }
  271.     if CanScrollRight then
  272.     begin
  273.       if Down and (Current = sbRight) then
  274.         Bitmap.Handle := LoadBitmap(HInstance, 'RMSBRIGHTDN')
  275.       else
  276.         Bitmap.Handle := LoadBitmap(HInstance, 'RMSBRIGHT');
  277.     end
  278.     else
  279.       Bitmap.Handle := LoadBitmap(HInstance, 'RMSBRIGHTDIS');
  280.     Draw((pWidth div 2) - 1, 0, Bitmap);
  281.   end;
  282. end;
  283.  
  284. procedure TrmScroller.WMSize(var Message: TWMSize);
  285. begin
  286.   inherited;
  287.   Width := pWidth - 1;
  288.   Height := pHeight;
  289. end;
  290.  
  291. procedure TrmScroller.SetMin(Value: Longint);
  292. begin
  293.   if Value < FMax then FMin := Value;
  294. end;
  295.  
  296. procedure TrmScroller.SetMax(Value: Longint);
  297. begin
  298.   if Value > FMin then FMax := Value;
  299. end;
  300.  
  301. procedure TrmScroller.SetPosition(Value: Longint);
  302. begin
  303.   if Value <> FPosition then
  304.   begin
  305.     if Value < Min then Value := Min;
  306.     if Value > Max then Value := Max;
  307.     FPosition := Value;
  308.     Invalidate;
  309.     if Assigned(FOnClick) then
  310.       FOnClick(Self);
  311.   end;
  312. end;
  313.  
  314. function TrmScroller.CanScrollLeft: Boolean;
  315. begin
  316.   Result := Position > Min;
  317. end;
  318.  
  319. function TrmScroller.CanScrollRight: Boolean;
  320. begin
  321.   Result := Position < Max;
  322. end;
  323.  
  324. procedure TrmScroller.DoMouseDown(X: Integer);
  325. begin
  326.   if X < pWidth div 2 then
  327.     Current := sbLeft
  328.   else
  329.     Current := sbRight;
  330.   case Current of
  331.     sbLeft:
  332.       if not CanScrollLeft then Exit;
  333.     sbRight:
  334.       if not CanScrollRight then Exit;
  335.   end;
  336.   Pressed := True;
  337.   Down := True;
  338.   Invalidate;
  339.   SetCapture(Handle);
  340. end;
  341.  
  342. procedure TrmScroller.WMLButtonDown(var Message: TWMLButtonDown);
  343. begin
  344.   DoMouseDown(Message.XPos);
  345. end;
  346.  
  347. procedure TrmScroller.WMLButtonDblClk(var Message: TWMLButtonDblClk);
  348. begin
  349.   DoMouseDown(Message.XPos);
  350. end;
  351.  
  352. procedure TrmScroller.WMMouseMove(var Message: TWMMouseMove);
  353. var
  354.   P: TPoint;
  355.   R: TRect;
  356. begin
  357.   if Pressed then
  358.   begin
  359.     P := Point(Message.XPos, Message.YPos);
  360.     R := Rect(0, 0, pWidth div 2, pHeight);
  361.     if Current = sbRight then OffsetRect(R, pWidth div 2, 0);
  362.     if PtInRect(R, P) <> Down then
  363.     begin
  364.       Down := not Down;
  365.       Invalidate;
  366.     end;
  367.   end;
  368. end;
  369.  
  370. procedure TrmScroller.WMLButtonUp(var Message: TWMLButtonUp);
  371. var
  372.   NewPos: Longint;
  373. begin
  374.   ReleaseCapture;
  375.   Pressed := False;
  376.  
  377.   if Down then
  378.   begin
  379.     Down := False;
  380.     NewPos := Position;
  381.     case Current of
  382.       sbLeft: Dec(NewPos, Change);
  383.       sbRight: Inc(NewPos, Change);
  384.     end;
  385.     Position := NewPos;
  386.   end;
  387. end;
  388.  
  389. { TrmTabList }
  390.  
  391. function TrmTabList.Add(const S: string): Integer;
  392. begin
  393.   Result := inherited Add(S);
  394.   if Tabs <> nil then
  395.     Tabs.Invalidate;
  396. end;
  397.  
  398. procedure TrmTabList.Insert(Index: Integer; const S: string);
  399. begin
  400.   inherited Insert(Index, S);
  401.   if Tabs <> nil then
  402.   begin
  403.     if Index <= Tabs.FTabIndex then Inc(Tabs.FTabIndex);
  404.     Tabs.Invalidate;
  405.   end;
  406. end;
  407.  
  408. procedure TrmTabList.Delete(Index: Integer);
  409. var
  410.   OldIndex: Integer;
  411. begin
  412.   OldIndex := Tabs.Tabindex;
  413.   inherited Delete(Index);
  414.  
  415.   if OldIndex < Count then
  416.     Tabs.FTabIndex := OldIndex
  417.   else
  418.     Tabs.FTabIndex := Count - 1;
  419.   Tabs.Invalidate;
  420.   Tabs.Invalidate;
  421.   if OldIndex = Index then Tabs.Click; { deleted selected tab }
  422. end;
  423.  
  424. procedure TrmTabList.Put(Index: Integer; const S: string);
  425. begin
  426.   inherited Put(Index, S);
  427.   if Tabs <> nil then
  428.     Tabs.Invalidate;
  429. end;
  430.  
  431. procedure TrmTabList.Clear;
  432. begin
  433.   inherited Clear;
  434.   Tabs.FTabIndex := -1;
  435.   Tabs.Invalidate;
  436. end;
  437.  
  438. procedure TrmTabList.AddStrings(Strings: TStrings);
  439. begin
  440.   SendMessage(Tabs.Handle, WM_SETREDRAW, 0, 0);
  441.   inherited AddStrings(Strings);
  442.   SendMessage(Tabs.Handle, WM_SETREDRAW, 1, 0);
  443.   Tabs.Invalidate;
  444. end;
  445.  
  446. { TrmTabSet }
  447.  
  448. constructor TrmTabSet.Create(AOwner: TComponent);
  449. begin
  450.   inherited Create(AOwner);
  451.   ControlStyle := [csCaptureMouse, csDoubleClicks, csOpaque];
  452.   fEdgeWidth := 9;
  453.   Width := 185;
  454.   Height := 21;
  455.  
  456.   TabPositions := TList.Create;
  457.   fTabHeight := 20;
  458.  
  459.   FTabs := TrmTabList.Create;
  460.   TrmTabList(FTabs).Tabs := Self;
  461.   FDisabledTabs := TStringList.create;
  462.  
  463.   CreateScroller;
  464.  
  465.   FTabIndex := -1;
  466.   FFirstIndex := 0;
  467.   FVisibleTabs := 0; { set by draw routine }
  468.   FStartMargin := 5;
  469.   FEndMargin := 5;
  470.  
  471.   { initialize default values }
  472.   FSelectedColor := clBtnFace;
  473.   FUnselectedColor := clWindow;
  474.   FBackgroundColor := clBtnFace;
  475.   FDitherBackground := True;
  476.   fTabType := ttWin3x;
  477.   FAutoScroll := True;
  478.   FStyle := tsStandard;
  479.   FOwnerDrawHeight := 20;
  480.  
  481.   ParentFont := False;
  482.   Font.Name := DefFontData.Name;
  483.   Font.Height := DefFontData.Height;
  484.   Font.Style := [];
  485.  
  486.   { create the edge bitmaps }
  487. end;
  488.  
  489. procedure TrmTabSet.CreateParams(var Params: TCreateParams);
  490. begin
  491.   inherited CreateParams(Params);
  492.   with Params.WindowClass do
  493.     style := style and not (CS_VREDRAW or CS_HREDRAW);
  494. end;
  495.  
  496. procedure TrmTabSet.CreateScroller;
  497. begin
  498.   FScroller := TrmScroller.Create(Self);
  499.   with FScroller do
  500.   begin
  501.     Parent := Self;
  502.     Top := 3;
  503.     Min := 0;
  504.     Max := 0;
  505.     Position := 0;
  506.     Visible := False;
  507.     OnClick := ScrollClick;
  508.   end;
  509. end;
  510.  
  511. destructor TrmTabSet.Destroy;
  512. begin
  513.   FTabs.Free;
  514.   TabPositions.Free;
  515.   inherited Destroy;
  516. end;
  517.  
  518. procedure TrmTabSet.ScrollClick(Sender: TObject);
  519. begin
  520.   FirstIndex := TrmScroller(Sender).Position;
  521. end;
  522.  
  523. { cache the tab position data, and return number of visible tabs }
  524.  
  525. function TrmTabSet.Calc3xTabPositions(Start, Stop: Integer; Canvas: TCanvas;
  526.   First: Integer): Integer;
  527. var
  528.   Index: Integer;
  529.   TabPos: TTabPos;
  530.   W: Integer;
  531. begin
  532.   TabPositions.Count := 0; { erase all previously cached data }
  533.   Index := First;
  534.   while (Start < Stop) and (Index < Tabs.Count) do
  535.   begin
  536.     with Canvas do
  537.     begin
  538.       TabPos.StartPos := Start;
  539.       W := TextWidth(Tabs[Index]);
  540.  
  541.       { Owner }
  542.       if (FStyle = tsOwnerDraw) then MeasureTab(Index, W);
  543.  
  544.       TabPos.Size := W;
  545.       Inc(Start, TabPos.Size + EdgeWidth); { next usable position }
  546.  
  547.       if Start <= Stop then
  548.       begin
  549.         TabPositions.Add(Pointer(TabPos)); { add to list }
  550.         Inc(Index);
  551.       end;
  552.     end;
  553.   end;
  554.   Result := Index - First;
  555. end;
  556.  
  557. function TrmTabSet.ItemAtPos(Pos: TPoint): Integer;
  558. var
  559.   TabPos: TTabPos;
  560.   I: Integer;
  561. begin
  562.   Result := -1;
  563.   if (Pos.Y < 0) or (Pos.Y > ClientHeight) then Exit;
  564.   for I := 0 to TabPositions.Count - 1 do
  565.   begin
  566.     Pointer(TabPos) := TabPositions[I];
  567.     if (Pos.X >= TabPos.StartPos) and (Pos.X <= TabPos.StartPos + TabPos.Size) then
  568.     begin
  569.       Result := I;
  570.       Exit;
  571.     end;
  572.   end;
  573. end;
  574.  
  575. function TrmTabSet.ItemRect(Item: Integer): TRect;
  576. var
  577.   TabPos: TTabPos;
  578.   wYPos : integer;
  579. begin
  580.   wyPos := 0;
  581.   if align = altop then
  582.      wypos := clientheight - fTabHeight;
  583.  
  584.   if (TabPositions.Count > 0) and (Item >= 0) and (Item < TabPositions.Count) then
  585.   begin
  586.     Pointer(TabPos) := TabPositions[Item];
  587.     Result := Rect(TabPos.StartPos, wYPos, TabPos.StartPos + TabPos.Size, wYPos+FTabHeight);
  588.     InflateRect(Result, 1, -2);
  589.   end
  590.   else
  591.     Result := Rect(0, 0, 0, 0);
  592. end;
  593.  
  594. procedure TrmTabSet.Paint;
  595. begin
  596.   case ftabtype of
  597.     ttWin3x: Paint3x;
  598.     ttWin2k: Paint2k;
  599.   end;
  600. end;
  601.  
  602. procedure TrmTabSet.Paint3x;
  603. var
  604.   MemBitmap, BrushBitmap: TBitmap;
  605.   TabStart, LastTabPos: Integer;
  606.   TabPos: TTabPos;
  607.   Tab: Integer;
  608.   Leading: TEdgeType;
  609.   Trailing: TEdgeType;
  610.   isFirst, isLast, isSelected, isPrevSelected: Boolean;
  611.   R: TRect;
  612.   wYPos : integer;
  613. begin
  614.   if not HandleAllocated then Exit;
  615.  
  616.   MemBitmap := TBitmap.create;
  617.   try
  618.      { Set the size of the off-screen bitmap.  Make sure that it is tall enough to
  619.        display the entire tab, even if the screen won't display it all.  This is
  620.        required to avoid problems with using FloodFill. }
  621.     MemBitmap.Width := ClientWidth;
  622.     if ClientHeight < FTabHeight + 5 then
  623.       MemBitmap.Height := FTabHeight + 5
  624.     else
  625.       MemBitmap.Height := ClientHeight;
  626.  
  627.     wyPos := 0;
  628.     if align = altop then
  629.        wypos := clientheight - fTabHeight;
  630.  
  631.     MemBitmap.Canvas.Font := Self.Canvas.Font;
  632.  
  633.     TabStart := StartMargin + EdgeWidth; { where does first text appear? }
  634.     LastTabPos := Width - EndMargin; { tabs draw until this position }
  635.     FScroller.Left := Width - FScroller.Width - 2;
  636.  
  637.      { do initial calculations for how many tabs are visible }
  638.     FVisibleTabs := Calc3xTabPositions(TabStart, LastTabPos, MemBitmap.Canvas,
  639.       FirstIndex);
  640.  
  641.      { enable the scroller if FAutoScroll = True and not all tabs are visible }
  642.     if AutoScroll and (FVisibleTabs < Tabs.Count) then
  643.     begin
  644.       Dec(LastTabPos, FScroller.Width - 4);
  645.        { recalc the tab positions }
  646.       FVisibleTabs := Calc3xTabPositions(TabStart, LastTabPos, MemBitmap.Canvas,
  647.         FirstIndex);
  648.  
  649.        { set the scroller's range }
  650.       FScroller.Visible := True;
  651.       ShowWindow(FScroller.Handle, SW_SHOW);
  652.       FScroller.Min := 0;
  653.       FScroller.Max := Tabs.Count - VisibleTabs;
  654.       FScroller.Position := FirstIndex;
  655.     end
  656.     else if VisibleTabs >= Tabs.Count then
  657.     begin
  658.       FScroller.Visible := False;
  659.       ShowWindow(FScroller.Handle, SW_HIDE);
  660.     end;
  661.  
  662.     if FDoFix then
  663.     begin
  664.       FixTabPos;
  665.       FVisibleTabs := Calc3xTabPositions(TabStart, LastTabPos, MemBitmap.Canvas,
  666.         FirstIndex);
  667.     end;
  668.     FDoFix := False;
  669.  
  670.      { draw background of tab area }
  671.     with MemBitmap.Canvas do
  672.     begin
  673.       BrushBitmap := TBitmap.create;
  674.       try
  675.         CreateBrushPattern(BrushBitmap);
  676.         Brush.Bitmap := BrushBitmap;
  677.         FillRect(Rect(0, 0, MemBitmap.Width, MemBitmap.Height));
  678.  
  679.         Pen.Width := 1;
  680.         if align <> alTop then
  681.         begin
  682.            Pen.Color := clBtnShadow;
  683.            MoveTo(0, 0);
  684.            LineTo(MemBitmap.Width + 1, 0);
  685.  
  686.            Pen.Color := clWindowFrame;
  687.            MoveTo(0, 1);
  688.            LineTo(MemBitmap.Width + 1, 1);
  689.         end
  690.         else 
  691.         begin
  692.            Pen.Color := clBtnHighlight;
  693.            MoveTo(0, height-1);
  694.            LineTo(MemBitmap.Width + 1, height-1);
  695.  
  696.            Pen.Color := cl3DLight;
  697.            MoveTo(0, height);
  698.            LineTo(MemBitmap.Width + 1, height);
  699.         end
  700.       finally
  701.         BrushBitmap.free;
  702.       end;
  703.     end;
  704.  
  705.     for Tab := 0 to TabPositions.Count - 1 do
  706.     begin
  707.       Pointer(TabPos) := TabPositions[Tab];
  708.  
  709.       isFirst := Tab = 0;
  710.       isLast := Tab = VisibleTabs - 1;
  711.       isSelected := Tab + FirstIndex = TabIndex;
  712.       isPrevSelected := (Tab + FirstIndex) - 1 = TabIndex;
  713.  
  714.        { Rule: every tab paints its leading edge, only the last tab paints a
  715.          trailing edge }
  716.       Trailing := etNone;
  717.  
  718.       if isLast then
  719.       begin
  720.         if isSelected then
  721.           Trailing := etLastIsSel
  722.         else
  723.           Trailing := etLastNotSel;
  724.       end;
  725.  
  726.       if isFirst then
  727.       begin
  728.         if isSelected then
  729.           Leading := etFirstIsSel
  730.         else
  731.           Leading := etFirstNotSel;
  732.       end
  733.       else { not first }
  734.       begin
  735.         if isPrevSelected then
  736.           Leading := etSelToNotSel
  737.         else if isSelected then
  738.           Leading := etNotSelToSel
  739.         else
  740.           Leading := etNotSelToNotSel;
  741.       end;
  742.  
  743.        { draw leading edge }
  744.       if Leading <> etNone then
  745.         PaintEdge(MemBitmap.Canvas, TabPos.StartPos - EdgeWidth, wypos, FTabHeight - 1, Leading);
  746.  
  747.        { set up the canvas }
  748.       R := Rect(TabPos.StartPos, wypos, TabPos.StartPos + TabPos.Size, wypos+FTabHeight);
  749.       with MemBitmap.Canvas do
  750.       begin
  751.         if isSelected then
  752.           Brush.Color := SelectedColor
  753.         else
  754.           Brush.Color := UnselectedColor;
  755.         ExtTextOut(Handle, TabPos.StartPos, wypos, ETO_OPAQUE, @R,
  756.           nil, 0, nil);
  757.       end;
  758.  
  759.        { restore font for drawing the text }
  760.       MemBitmap.Canvas.Font := Self.Canvas.Font;
  761.  
  762.        { Owner }
  763.       if (FStyle = tsOwnerDraw) then
  764.         DrawTab(MemBitmap.Canvas, R, Tab + FirstIndex, isSelected)
  765.       else
  766.       begin
  767.         with MemBitmap.Canvas do
  768.         begin
  769.           Inc(R.Top, 2);
  770.  
  771.           if TabEnabled(Tab + FirstIndex) then
  772.              Font.Color := clWindowText
  773.           else
  774.              Font.Color := clGrayText;
  775.  
  776.           DrawText(Handle, PChar(Tabs[Tab + FirstIndex]),
  777.             Length(Tabs[Tab + FirstIndex]), R, DT_CENTER);
  778.         end;
  779.       end;
  780.  
  781.        { draw trailing edge  }
  782.       if Trailing <> etNone then
  783.         PaintEdge(MemBitmap.Canvas, TabPos.StartPos + TabPos.Size, wypos, FTabHeight - 1, Trailing);
  784.  
  785.        { draw connecting lines above and below the text }
  786.  
  787.       with MemBitmap.Canvas do
  788.       begin
  789.         Pen.Color := clWindowFrame;
  790.         if align<>alTop then
  791.         begin
  792.            MoveTo(TabPos.StartPos, FTabHeight-1);
  793.            LineTo(TabPos.StartPos + TabPos.Size, FTabHeight-1);
  794.  
  795.            if isSelected then
  796.            begin
  797.              Pen.Color := clBtnShadow;
  798.              MoveTo(TabPos.StartPos, FTabHeight - 2);
  799.              LineTo(TabPos.StartPos + TabPos.Size, FTabHeight - 2);
  800.            end
  801.            else
  802.            begin
  803.              Pen.Color := clWindowFrame;
  804.              MoveTo(TabPos.StartPos, 1);
  805.              LineTo(TabPos.StartPos + TabPos.Size, 1);
  806.  
  807.              Pen.Color := clBtnShadow;
  808.              MoveTo(TabPos.StartPos, 0);
  809.              LineTo(TabPos.StartPos + TabPos.Size + 1, 0);
  810.            end;
  811.         end
  812.         else
  813.         begin
  814.            MoveTo(TabPos.StartPos, wypos);
  815.            LineTo(TabPos.StartPos + TabPos.Size, wypos);
  816.  
  817.            if isSelected then
  818.            begin
  819.              Pen.Color := clBtnHighlight;
  820.              MoveTo(TabPos.StartPos, wypos+1);
  821.              LineTo(TabPos.StartPos + TabPos.Size, wypos+1);
  822.            end;
  823.         end
  824.       end;
  825.     end;
  826.  
  827.      { draw onto the screen }
  828.     Canvas.Draw(0, 0, MemBitmap);
  829.   finally
  830.     MemBitmap.free;
  831.   end;
  832. end;
  833.  
  834. procedure TrmTabSet.Paint2k;
  835. var
  836.   MemBitmap: TBitmap;
  837.   TabStart, LastTabPos: Integer;
  838.   TabPos: TTabPos;
  839.   Tab: Integer;
  840.   isFirst, isSelected: Boolean;
  841.   R: TRect;
  842.   loop: integer;
  843.   wYPos : integer;
  844. begin
  845.   if not HandleAllocated then Exit;
  846.  
  847.   MemBitmap := TBitmap.create;
  848.   try
  849.      { Set the size of the off-screen bitmap.  Make sure that it is tall enough to
  850.        display the entire tab, even if the screen won't display it all.  This is
  851.        required to avoid problems with using FloodFill. }
  852.     MemBitmap.Width := ClientWidth;
  853.     if ClientHeight < FTabHeight + 5 then
  854.       MemBitmap.Height := FTabHeight + 5
  855.     else
  856.       MemBitmap.Height := ClientHeight;
  857.  
  858.     wyPos := 0;
  859.     if align = altop then
  860.        wypos := clientheight - fTabHeight;
  861.  
  862.     MemBitmap.Canvas.Font := Self.Canvas.Font;
  863.  
  864.     TabStart := StartMargin + EdgeWidth; { where does first text appear? }
  865.     LastTabPos := Width - EndMargin; { tabs draw until this position }
  866.     FScroller.Left := Width - FScroller.Width - 2;
  867.  
  868.      { do initial calculations for how many tabs are visible }
  869.     FVisibleTabs := Calc2kTabPositions(TabStart, LastTabPos, MemBitmap.Canvas, FirstIndex);
  870.  
  871.      { enable the scroller if FAutoScroll = True and not all tabs are visible }
  872.     if AutoScroll and (FVisibleTabs < Tabs.Count) then
  873.     begin
  874.       Dec(LastTabPos, FScroller.Width - 4);
  875.        { recalc the tab positions }
  876.       FVisibleTabs := Calc2kTabPositions(TabStart, LastTabPos, MemBitmap.Canvas, FirstIndex);
  877.  
  878.        { set the scroller's range }
  879.       FScroller.Visible := True;
  880.       ShowWindow(FScroller.Handle, SW_SHOW);
  881.       FScroller.Min := 0;
  882.       FScroller.Max := Tabs.Count - VisibleTabs;
  883.       FScroller.Position := FirstIndex;
  884.     end
  885.     else if VisibleTabs >= Tabs.Count then
  886.     begin
  887.       FScroller.Visible := False;
  888.       ShowWindow(FScroller.Handle, SW_HIDE);
  889.     end;
  890.  
  891.     if FDoFix then
  892.     begin
  893.       FixTabPos;
  894.       FVisibleTabs := Calc2kTabPositions(TabStart, LastTabPos, MemBitmap.Canvas, FirstIndex);
  895.     end;
  896.     FDoFix := False;
  897.  
  898.      { draw background of tab area }
  899.     with MemBitmap.Canvas do
  900.     begin
  901.       Brush.Color := clBtnShadow;
  902.       FillRect(Rect(0, 0, MemBitmap.Width, MemBitmap.Height));
  903.  
  904.       if align<>altop then
  905.       begin
  906.          Pen.Color := clbtnFace;
  907.          for loop := 0 to 1 do
  908.          begin
  909.            MoveTo(0, loop);
  910.            LineTo(MemBitmap.Width + 1, loop);
  911.          end;
  912.  
  913.          Pen.Color := clWindowFrame;
  914.          MoveTo(0, 2);
  915.          LineTo(MemBitmap.Width + 1, 2);
  916.       end
  917.       else
  918.       begin
  919.          Pen.Color := clbtnFace;
  920.          for loop := clientheight-2 to clientheight do
  921.          begin
  922.            MoveTo(0, loop);
  923.            LineTo(MemBitmap.Width + 1, loop);
  924.          end;
  925.  
  926.          Pen.Color := clBtnHighlight;
  927.          MoveTo(0, clientHeight-3);
  928.          LineTo(MemBitmap.Width + 1, clientheight-3);
  929.       end;
  930.     end;
  931.  
  932.     for Tab := 0 to TabPositions.Count - 1 do
  933.     begin
  934.       if not TabEnabled(Tab + FirstIndex) then
  935.          continue;
  936.           
  937.       Pointer(TabPos) := TabPositions[Tab];
  938.  
  939.       isFirst := Tab = 0;
  940.       isSelected := Tab + FirstIndex = TabIndex;
  941.  
  942.       R := Rect(TabPos.StartPos - (EdgeWidth div 2), wypos, (TabPos.StartPos + TabPos.Size) + (EdgeWidth div 2), wypos+FTabHeight);
  943.  
  944.       with MemBitmap.Canvas do
  945.       begin
  946.         if isSelected then
  947.         begin
  948.           Brush.Color := clBtnFace;
  949.           FillRect(R);
  950.  
  951.           Font.Color := clBtnText;
  952.           Inc(R.Top, 1);
  953.           R := Rect(TabPos.StartPos, wypos+2, TabPos.StartPos + TabPos.Size, wypos+FTabHeight);
  954.           DrawText(Handle, PChar(Tabs[Tab + FirstIndex]), Length(Tabs[Tab + FirstIndex]), R, DT_CENTER);
  955.  
  956.           Pen.Color := clBtnHighlight;
  957.           if align <> alTop then
  958.           begin
  959.              MoveTo(TabPos.StartPos - (EdgeWidth div 2), wYpos+2);
  960.              LineTo(TabPos.StartPos - (EdgeWidth div 2), wYpos+FTabHeight);
  961.  
  962.              Pen.Color := cl3DDkShadow;
  963.              MoveTo(TabPos.StartPos + TabPos.Size + (EdgeWidth div 2), wYpos+2);
  964.              LineTo(TabPos.StartPos + TabPos.Size + (EdgeWidth div 2), wYpos+FTabHeight);
  965.  
  966.              MoveTo(TabPos.StartPos - (EdgeWidth div 2), wYpos+FTabHeight);
  967.              LineTo(TabPos.StartPos + TabPos.Size + (EdgeWidth div 2), wYpos+FTabHeight);
  968.  
  969.              Pen.Color := clBtnShadow;
  970.              MoveTo(TabPos.StartPos - (EdgeWidth div 2)+1, FTabHeight - 1);
  971.              LineTo(TabPos.StartPos + TabPos.Size + (EdgeWidth div 2)-1, FTabHeight - 1);
  972.           end
  973.           else
  974.           begin
  975.              MoveTo(TabPos.StartPos - (EdgeWidth div 2), wYpos);
  976.              LineTo(TabPos.StartPos - (EdgeWidth div 2), wYpos+FTabHeight-2);
  977.  
  978.              MoveTo(TabPos.StartPos - (EdgeWidth div 2) + 1, wypos);
  979.              LineTo(TabPos.StartPos + TabPos.Size + (EdgeWidth div 2) - 1, wypos);
  980.  
  981.              Pen.Color := cl3DDkShadow;
  982.              MoveTo(TabPos.StartPos + TabPos.Size + (EdgeWidth div 2), wYpos);
  983.              LineTo(TabPos.StartPos + TabPos.Size + (EdgeWidth div 2), wYpos+FTabHeight-2);
  984.           end;
  985.         end
  986.         else
  987.         begin
  988.           R := Rect(TabPos.StartPos, wypos+2, TabPos.StartPos + TabPos.Size, wypos+FTabHeight);
  989.           Brush.Style := bsClear;
  990.  
  991.           if TabEnabled(Tab + FirstIndex) then
  992.              Font.Color := clBtnHighlight
  993.           else
  994.              Font.Color := cl3DDkShadow;
  995.  
  996.           Inc(R.Top, 1);
  997.           DrawText(Handle, PChar(Tabs[Tab + FirstIndex]), Length(Tabs[Tab + FirstIndex]), R, DT_CENTER);
  998.  
  999.           if align <> altop then
  1000.           begin
  1001.              Pen.Color := clBtnHighlight;
  1002.              if isFirst then
  1003.              begin
  1004.                MoveTo(TabPos.StartPos - (EdgeWidth div 2), 5);
  1005.                LineTo(TabPos.StartPos - (EdgeWidth div 2), (2 + FTabHeight) - 3);
  1006.              end;
  1007.  
  1008.              MoveTo(TabPos.StartPos + TabPos.Size + (EdgeWidth div 2) + 1, 5);
  1009.              LineTo(TabPos.StartPos + TabPos.Size + (EdgeWidth div 2) + 1, (2 + FTabHeight) - 3);
  1010.           end
  1011.           else
  1012.           begin
  1013.              Pen.Color := clBtnHighlight;
  1014.              if isFirst then
  1015.              begin
  1016.                MoveTo(TabPos.StartPos - (EdgeWidth div 2), wypos);
  1017.                LineTo(TabPos.StartPos - (EdgeWidth div 2), wypos + FTabHeight - 5);
  1018.              end;
  1019.  
  1020.              MoveTo(TabPos.StartPos + TabPos.Size + (EdgeWidth div 2) + 1, wypos);
  1021.              LineTo(TabPos.StartPos + TabPos.Size + (EdgeWidth div 2) + 1, wypos + fTabHeight - 5);
  1022.           end;
  1023.  
  1024.           Pen.Color := clWindowFrame;
  1025.           if align<>alTop then
  1026.           begin
  1027.              MoveTo(TabPos.StartPos, 2);
  1028.              LineTo(TabPos.StartPos + TabPos.Size, 2);
  1029.           end;
  1030.         end;
  1031.       end;
  1032.     end;
  1033.  
  1034.      { draw onto the screen }
  1035.     Canvas.Draw(0, 0, MemBitmap);
  1036.   finally
  1037.     MemBitmap.free;
  1038.   end;
  1039. end;
  1040.  
  1041. procedure TrmTabSet.PaintEdge(Canvas: TCanvas; X, Y, H: Integer; Edge: TEdgeType);
  1042.  
  1043.   procedure DrawBR(Canvas: TCanvas; X, Y, H: integer; FillColor:TColor);
  1044.   begin
  1045.     with Canvas do
  1046.     begin
  1047.       Pen.Color := FillColor;
  1048.       Brush.Color := FillColor;
  1049.       Polygon([ Point(X + EdgeWidth, Y),
  1050.                 Point(X + 1, Y + H),
  1051.                 Point(X, Y + H),
  1052.                 Point(X, Y),
  1053.                 Point(X + EdgeWidth, Y)]);
  1054.  
  1055.       Pen.Color := clWindowFrame;
  1056.       PolyLine([Point(X + EdgeWidth, Y), Point(X, Y + H)]);
  1057.  
  1058.       if FillColor = SelectedColor then
  1059.       begin
  1060.          Pen.Color := clBtnShadow;
  1061.          PolyLine([Point(X + EdgeWidth - 1, Y), Point(X - 1, Y + H)]);
  1062.       end
  1063.       else
  1064.       begin
  1065.          Pen.Color := clBtnShadow;
  1066.          PolyLine([Point(X, 0), Point(X + EdgeWidth+1, 0)]);
  1067.          Pen.Color := clWindowFrame;
  1068.          PolyLine([Point(X, 1), Point(X + EdgeWidth+1, 1)]);
  1069.       end;
  1070.     end;
  1071.   end;
  1072.  
  1073.   procedure DrawBL(Canvas: TCanvas; X, Y, H: integer; FillColor:TColor);
  1074.   begin
  1075.     with Canvas do
  1076.     begin
  1077.       Pen.Color := FillColor;
  1078.       Brush.Color := FillColor;
  1079.       Polygon([ Point(X, Y),
  1080.                 Point(X + EdgeWidth - 1, Y + H),
  1081.                 Point(X + EdgeWidth, Y + H),
  1082.                 Point(X + EdgeWidth, Y),
  1083.                 Point(X, Y)]);
  1084.  
  1085.       Pen.Color := clWindowFrame;
  1086.       PolyLine([Point(X, Y), Point(X + EdgeWidth, Y + H)]);
  1087.  
  1088.       if Fillcolor = SelectedColor then
  1089.       begin
  1090.          Pen.Color := clBtnHighlight;
  1091.          PolyLine([Point(X + 1, Y), Point(X + EdgeWidth + 1, Y + H)]);
  1092.       end
  1093.       else
  1094.       begin
  1095.          Pen.Color := clBtnShadow;
  1096.          PolyLine([Point(X, 0), Point(X + EdgeWidth+1, 0)]);
  1097.  
  1098.          Pen.Color := clWindowFrame;
  1099.          PolyLine([Point(X, 1), Point(X + EdgeWidth+1, 1)]);
  1100.       end;
  1101.  
  1102.     end;
  1103.   end;
  1104.  
  1105.   procedure DrawTR(Canvas: TCanvas; X, Y, H: integer; FillColor:TColor);
  1106.   begin
  1107.     with Canvas do
  1108.     begin
  1109.       Pen.Color := FillColor;
  1110.       Brush.Color := FillColor;
  1111.       Polygon([ Point(X + EdgeWidth, Y + H),
  1112.                 Point(X+1, Y),
  1113.                 Point(X, Y),
  1114.                 Point(X, Y + H),
  1115.                 Point(X + EdgeWidth, Y + H)]);
  1116.  
  1117.       Pen.Color := clWindowFrame;
  1118.       PolyLine([ Point(X, Y), Point(X+EdgeWidth, Y + h)]);
  1119.  
  1120.       if FillColor = SelectedColor then
  1121.       begin
  1122.          Pen.Color := clBtnShadow;
  1123.          PolyLine([ Point(X-1, Y), Point(X+EdgeWidth-1, Y + h)]);
  1124.       end;
  1125.     end;
  1126.   end;
  1127.  
  1128.   procedure DrawTL(Canvas: TCanvas; X, Y, H: integer; FillColor:TColor);
  1129.   begin
  1130.     with Canvas do
  1131.     begin
  1132.       Pen.Color := FillColor;
  1133.       Brush.Color := FillColor;
  1134.       Polygon([ Point(X, Y + H),
  1135.                 Point(X + EdgeWidth - 1, Y),
  1136.                 Point(X + EdgeWidth, Y),
  1137.                 Point(X + EdgeWidth, Y + H),
  1138.                 Point(X, Y + H)]);
  1139.  
  1140.       Pen.Color := clWindowFrame;
  1141.       PolyLine([ Point(X+EdgeWidth, Y), Point(X, Y + h)]);
  1142.  
  1143.       if Fillcolor = SelectedColor then
  1144.       begin
  1145.          Pen.Color := clBtnHighlight;
  1146.          PolyLine([Point(x+edgewidth+1,y), Point(x+1,y+h)]);
  1147.       end;
  1148.     end;
  1149.   end;
  1150.  
  1151.  
  1152. begin
  1153.   Canvas.Brush.Color := clWhite;
  1154.   Canvas.Font.Color := clBlack;
  1155.   case align of
  1156.     alTop:
  1157.       begin
  1158.          case Edge of
  1159.            etFirstIsSel:
  1160.              DrawTL(Canvas, X, Y, H, SelectedColor);
  1161.            etLastIsSel:
  1162.              DrawTR(Canvas, X, Y, H, SelectedColor);
  1163.            etFirstNotSel:
  1164.              DrawTL(Canvas, X, Y, H, UnselectedColor);
  1165.            etLastNotSel:
  1166.              DrawTR(Canvas, X, Y, H, UnselectedColor);
  1167.            etNotSelToSel:
  1168.              begin
  1169.                DrawTR(Canvas, X, Y, H, UnselectedColor);
  1170.                DrawTL(Canvas, X, Y, H, SelectedColor);
  1171.              end;
  1172.            etSelToNotSel:
  1173.              begin
  1174.                DrawTL(Canvas, X, Y, H, UnselectedColor);
  1175.                DrawTR(Canvas, X, Y, H, SelectedColor);
  1176.              end;
  1177.            etNotSelToNotSel:
  1178.              begin
  1179.                DrawTL(Canvas, X, Y, H, UnselectedColor);
  1180.                DrawTR(Canvas, X, Y, H, UnselectedColor);
  1181.              end;
  1182.          end;
  1183.       end;
  1184.   else
  1185.     begin
  1186.        case Edge of
  1187.          etFirstIsSel:
  1188.            DrawBL(Canvas, X, Y, H, SelectedColor);
  1189.          etLastIsSel:
  1190.            DrawBR(Canvas, X, Y, H, SelectedColor);
  1191.          etFirstNotSel:
  1192.            DrawBL(Canvas, X, Y, H, UnselectedColor);
  1193.          etLastNotSel:
  1194.            DrawBR(Canvas, X, Y, H, UnselectedColor);
  1195.          etNotSelToSel:
  1196.            begin
  1197.              DrawBR(Canvas, X, Y, H, UnselectedColor);
  1198.              DrawBL(Canvas, X, Y, H, SelectedColor);
  1199.            end;
  1200.          etSelToNotSel:
  1201.            begin
  1202.              DrawBL(Canvas, X, Y, H, UnselectedColor);
  1203.              DrawBR(Canvas, X, Y, H, SelectedColor);
  1204.            end;
  1205.          etNotSelToNotSel:
  1206.            begin
  1207.              DrawBL(Canvas, X, Y, H, UnselectedColor);
  1208.              DrawBR(Canvas, X, Y, H, UnselectedColor);
  1209.            end;
  1210.        end;
  1211.     end;
  1212.   end;
  1213. end;
  1214.  
  1215. procedure TrmTabSet.CreateBrushPattern(Bitmap: TBitmap);
  1216. var
  1217.   X, Y: Integer;
  1218. begin
  1219.   Bitmap.Width := 8;
  1220.   Bitmap.Height := 8;
  1221.   with Bitmap.Canvas do
  1222.   begin
  1223.     Brush.Style := bsSolid;
  1224.     Brush.Color := FBackgroundColor;
  1225.     FillRect(Rect(0, 0, Width, Height));
  1226.     if FDitherBackground then
  1227.       for Y := 0 to 7 do
  1228.         for X := 0 to 7 do
  1229.           if (Y mod 2) = (X mod 2) then { toggles between even/odd pixles }
  1230.             Pixels[X, Y] := clWhite; { on even/odd rows }
  1231.   end;
  1232. end;
  1233.  
  1234. procedure TrmTabSet.FixTabPos;
  1235. var
  1236.   FLastVisibleTab: Integer;
  1237.  
  1238.   function GetRightSide: Integer;
  1239.   begin
  1240.     Result := Width - EndMargin;
  1241.     if AutoScroll and (FVisibleTabs < Tabs.Count - 1) then
  1242.       Dec(Result, FScroller.Width + 4);
  1243.   end;
  1244.  
  1245.   function ReverseCalcNumTabs(Start, Stop: Integer; Canvas: TCanvas;
  1246.     Last: Integer): Integer;
  1247.   var
  1248.     W: Integer;
  1249.   begin
  1250.     if HandleAllocated then
  1251.     begin
  1252.       Result := Last;
  1253.       while (Start >= Stop) and (Result >= 0) do
  1254.         with Canvas do
  1255.         begin
  1256.           W := TextWidth(Tabs[Result]);
  1257.           if (FStyle = tsOwnerDraw) then MeasureTab(Result, W);
  1258.           Dec(Start, W + EdgeWidth); { next usable position }
  1259.           if Start >= Stop then Dec(Result);
  1260.         end;
  1261.       if (Start < Stop) or (Result < 0) then Inc(Result);
  1262.     end
  1263.     else
  1264.       Result := FFirstIndex;
  1265.   end;
  1266.  
  1267. begin
  1268.   if Tabs.Count > 0 then
  1269.   begin
  1270.     FLastVisibleTab := FFirstIndex + FVisibleTabs - 1;
  1271.     if FTabIndex > FLastVisibleTab then
  1272.       FFirstIndex := ReverseCalcNumTabs(GetRightSide, StartMargin + EdgeWidth,
  1273.         Canvas, FTabIndex)
  1274.     else if (FTabIndex >= 0) and (FTabIndex < FFirstIndex) then
  1275.       FFirstIndex := FTabIndex;
  1276.   end;
  1277. end;
  1278.  
  1279. procedure TrmTabSet.SetSelectedColor(Value: TColor);
  1280. begin
  1281.   if Value <> FSelectedColor then
  1282.   begin
  1283.     FSelectedColor := Value;
  1284.     Invalidate;
  1285.   end;
  1286. end;
  1287.  
  1288. procedure TrmTabSet.SetUnselectedColor(Value: TColor);
  1289. begin
  1290.   if Value <> FUnselectedColor then
  1291.   begin
  1292.     FUnselectedColor := Value;
  1293.     Invalidate;
  1294.   end;
  1295. end;
  1296.  
  1297. procedure TrmTabSet.SetBackgroundColor(Value: TColor);
  1298. begin
  1299.   if Value <> FBackgroundColor then
  1300.   begin
  1301.     FBackgroundColor := Value;
  1302.     Invalidate;
  1303.   end;
  1304. end;
  1305.  
  1306. procedure TrmTabSet.SetDitherBackground(Value: Boolean);
  1307. begin
  1308.   if Value <> FDitherBackground then
  1309.   begin
  1310.     FDitherBackground := Value;
  1311.     Invalidate;
  1312.   end;
  1313. end;
  1314.  
  1315. procedure TrmTabSet.SetAutoScroll(Value: Boolean);
  1316. begin
  1317.   if Value <> FAutoScroll then
  1318.   begin
  1319.     FAutoScroll := Value;
  1320.     FScroller.Visible := False;
  1321.     ShowWindow(FScroller.Handle, SW_HIDE);
  1322.     Invalidate;
  1323.   end;
  1324. end;
  1325.  
  1326. procedure TrmTabSet.SetStartMargin(Value: Integer);
  1327. begin
  1328.   if Value <> FStartMargin then
  1329.   begin
  1330.     FStartMargin := Value;
  1331.     Invalidate;
  1332.   end;
  1333. end;
  1334.  
  1335. procedure TrmTabSet.SetEndMargin(Value: Integer);
  1336. begin
  1337.   if Value <> FEndMargin then
  1338.   begin
  1339.     FEndMargin := Value;
  1340.     Invalidate;
  1341.   end;
  1342. end;
  1343.  
  1344. function TrmTabSet.CanChange(NewIndex: Integer): Boolean;
  1345. begin
  1346.   if TabEnabled(NewIndex) then
  1347.   begin
  1348.      Result := true;
  1349.      if Assigned(FOnChange) then
  1350.        FOnChange(Self, NewIndex, Result);
  1351.   end
  1352.   else
  1353.   result := false;
  1354. end;
  1355.  
  1356. procedure TrmTabSet.SetTabIndex(Value: Integer);
  1357. var
  1358.    newValue:integer;
  1359.    found : boolean;
  1360. begin
  1361.   if Value <> FTabIndex then
  1362.   begin
  1363.     if (Value < -1) or (Value >= Tabs.Count) then
  1364.       raise Exception.Create(SInvalidTabIndex);
  1365.  
  1366.     if CanChange(Value) then
  1367.     begin
  1368.       FTabIndex := Value;
  1369.       FixTabPos;
  1370.       Click;
  1371.       Invalidate;
  1372.     end
  1373.     else
  1374.     begin
  1375.        found := false;
  1376.        newValue := Value+1;
  1377.        while newValue <> Value do
  1378.        begin
  1379.           if newValue >= fTabs.count then
  1380.              newValue := 0;
  1381.           if (newValue < fTabs.count) and (not TabEnabled(newValue)) then
  1382.              inc(newValue)
  1383.           else
  1384.           begin
  1385.              found := true;
  1386.              break;
  1387.           end
  1388.        end;
  1389.        if found and CanChange(newValue) then
  1390.        begin
  1391.          FTabIndex := newValue;
  1392.          FixTabPos;
  1393.          Click;
  1394.          Invalidate;
  1395.        end;
  1396.     end;
  1397.   end;
  1398. end;
  1399.  
  1400. procedure TrmTabSet.SelectNext(Direction: Boolean);
  1401. var
  1402.   NewIndex: Integer;
  1403. begin
  1404.   if Tabs.Count > 1 then
  1405.   begin
  1406.     NewIndex := TabIndex;
  1407.     if Direction then
  1408.       Inc(NewIndex)
  1409.     else
  1410.       Dec(NewIndex);
  1411.     if NewIndex = Tabs.Count then
  1412.       NewIndex := 0
  1413.     else if NewIndex < 0 then
  1414.       NewIndex := Tabs.Count - 1;
  1415.     SetTabIndex(NewIndex);
  1416.   end;
  1417. end;
  1418.  
  1419. procedure TrmTabSet.SetFirstIndex(Value: Integer);
  1420. begin
  1421.   if (Value >= 0) and (Value < Tabs.Count) then
  1422.   begin
  1423.     FFirstIndex := Value;
  1424.     Invalidate;
  1425.   end;
  1426. end;
  1427.  
  1428. procedure TrmTabSet.SetTabList(Value: TStrings);
  1429. begin
  1430.   FTabs.Assign(Value);
  1431.   FTabIndex := -1;
  1432.   if FTabs.Count > 0 then
  1433.     TabIndex := 0
  1434.   else
  1435.     Invalidate;
  1436. end;
  1437.  
  1438. procedure TrmTabSet.SetTabStyle(Value: TTabStyle);
  1439. begin
  1440.   if Value <> FStyle then
  1441.   begin
  1442.     FStyle := Value;
  1443.     Invalidate;
  1444.   end;
  1445. end;
  1446.  
  1447. procedure TrmTabSet.SetTabHeight(Value: Integer);
  1448. var
  1449.   SaveHeight: Integer;
  1450. begin
  1451.   if Value <> FOwnerDrawHeight then
  1452.   begin
  1453.     SaveHeight := FOwnerDrawHeight;
  1454.     try
  1455.       FOwnerDrawHeight := Value;
  1456.       FTabHeight := value;
  1457.       Invalidate;
  1458.     except
  1459.       FOwnerDrawHeight := SaveHeight;
  1460.       fTabHeight := SaveHeight;
  1461.       raise;
  1462.     end;
  1463.   end;
  1464. end;
  1465.  
  1466. procedure TrmTabSet.DrawTab(TabCanvas: TCanvas; R: TRect; Index: Integer;
  1467.   Selected: Boolean);
  1468. begin
  1469.   if Assigned(FOnDrawTab) then
  1470.     FOnDrawTab(Self, TabCanvas, R, Index, Selected);
  1471. end;
  1472.  
  1473. procedure TrmTabSet.GetChildren(Proc: TGetChildProc; Root: TComponent);
  1474. begin
  1475. end;
  1476.  
  1477. procedure TrmTabSet.MeasureTab(Index: Integer; var TabWidth: Integer);
  1478. begin
  1479.   if Assigned(FOnMeasureTab) then
  1480.     FOnMeasureTab(Self, Index, TabWidth);
  1481. end;
  1482.  
  1483. procedure TrmTabSet.MouseDown(Button: TMouseButton; Shift: TShiftState;
  1484.   X, Y: Integer);
  1485. var
  1486.   TabPos: TTabPos;
  1487.   I: Integer;
  1488.   Extra: Integer;
  1489.   MinLeft: Integer;
  1490.   MaxRight: Integer;
  1491. begin
  1492.   inherited MouseDown(Button, Shift, X, Y);
  1493.   if (Button = mbLeft) and (((align<>alTop) and (Y <= FTabHeight)) or ((align=alTop) and (y >= clientheight-FTabHeight))) then
  1494.   begin
  1495.     if Y < FTabHeight div 2 then
  1496.       Extra := EdgeWidth div 3
  1497.     else
  1498.       Extra := EdgeWidth div 2;
  1499.  
  1500.     for I := 0 to TabPositions.Count - 1 do
  1501.     begin
  1502.       Pointer(TabPos) := TabPositions[I];
  1503.       MinLeft := TabPos.StartPos - Extra;
  1504.       MaxRight := TabPos.StartPos + TabPos.Size + Extra;
  1505.       if (X >= MinLeft) and (X <= MaxRight) and TabEnabled(FirstIndex + I) then
  1506.       begin
  1507.         SetTabIndex(FirstIndex + I);
  1508.         Break;
  1509.       end;
  1510.     end;
  1511.   end;
  1512. end;
  1513.  
  1514. procedure TrmTabSet.WMSize(var Message: TWMSize);
  1515. var
  1516.   NumVisTabs, LastTabPos: Integer;
  1517.  
  1518.   function CalcNumTabs(Start, Stop: Integer; Canvas: TCanvas;
  1519.     First: Integer): Integer;
  1520.   var
  1521.     W: Integer;
  1522.   begin
  1523.     Result := First;
  1524.     while (Start < Stop) and (Result < Tabs.Count) do
  1525.       with Canvas do
  1526.       begin
  1527.         W := TextWidth(Tabs[Result]);
  1528.         if (FStyle = tsOwnerDraw) then MeasureTab(Result, W);
  1529.         Inc(Start, W + EdgeWidth); { next usable position }
  1530.         if Start <= Stop then Inc(Result);
  1531.       end;
  1532.   end;
  1533.  
  1534. begin
  1535.   inherited;
  1536.   if Tabs.Count > 1 then
  1537.   begin
  1538.     LastTabPos := Width - EndMargin;
  1539.     NumVisTabs := CalcNumTabs(StartMargin + EdgeWidth, LastTabPos, Canvas, 0);
  1540.     if (FTabIndex = Tabs.Count) or (NumVisTabs > FVisibleTabs) or
  1541.       (NumVisTabs = Tabs.Count) then FirstIndex := Tabs.Count - NumVisTabs;
  1542.     FDoFix := True;
  1543.   end;
  1544.   Invalidate;
  1545. end;
  1546.  
  1547. procedure TrmTabSet.CMFontChanged(var Message: TMessage);
  1548. begin
  1549.   inherited;
  1550.   Canvas.Font := Font;
  1551.   Invalidate;
  1552. end;
  1553.  
  1554. procedure TrmTabSet.WMGetDlgCode(var Message: TWMGetDlgCode);
  1555. begin
  1556.   Message.Result := DLGC_WANTALLKEYS;
  1557. end;
  1558.  
  1559. procedure TrmTabSet.CMDialogChar(var Message: TCMDialogChar);
  1560. var
  1561.   I: Integer;
  1562. begin
  1563.   for I := 0 to FTabs.Count - 1 do
  1564.   begin
  1565.     if IsAccel(Message.CharCode, FTabs[I]) then
  1566.     begin
  1567.       Message.Result := 1;
  1568.       if FTabIndex <> I then
  1569.         SetTabIndex(I);
  1570.       Exit;
  1571.     end;
  1572.   end;
  1573.   inherited;
  1574. end;
  1575.  
  1576. procedure TrmTabSet.DefineProperties(Filer: TFiler);
  1577. begin
  1578.   { Can be removed after version 1.0 }
  1579.   if Filer is TReader then inherited DefineProperties(Filer);
  1580.   Filer.DefineProperty('TabOrder', ReadIntData, nil, False);
  1581.   Filer.DefineProperty('TabStop', ReadBoolData, nil, False);
  1582. end;
  1583.  
  1584. procedure TrmTabSet.ReadIntData(Reader: TReader);
  1585. begin
  1586.   Reader.ReadInteger;
  1587. end;
  1588.  
  1589. procedure TrmTabSet.ReadBoolData(Reader: TReader);
  1590. begin
  1591.   Reader.ReadBoolean;
  1592. end;
  1593.  
  1594. procedure TrmTabSet.SetTabType(const Value: TTabType);
  1595. begin
  1596.   fTabType := Value;
  1597.   Invalidate;
  1598. end;
  1599.  
  1600. procedure TrmTabSet.SetDisabledTabList(const Value: TStrings);
  1601. begin
  1602.   FDisabledTabs.Assign(Value);
  1603.   Invalidate;
  1604. end;
  1605.  
  1606. function TrmTabSet.TabEnabled(index: integer): boolean;
  1607. begin
  1608.    result := FDisabledTabs.IndexOf(fTabs[index]) = -1;
  1609. end;
  1610.  
  1611. function TrmTabSet.Calc2kTabPositions(Start, Stop: Integer;
  1612.   Canvas: TCanvas; First: Integer): Integer;
  1613. var
  1614.   Index: Integer;
  1615.   TabPos: TTabPos;
  1616.   W: Integer;
  1617. begin
  1618.   TabPositions.Count := 0; { erase all previously cached data }
  1619.   Index := First;
  1620.   while (Start < Stop) and (Index < Tabs.Count) do
  1621.   begin
  1622.     with Canvas do
  1623.     begin
  1624.       if TabEnabled(index) then
  1625.       begin
  1626.          TabPos.StartPos := Start;
  1627.          W := TextWidth(Tabs[Index]);
  1628.  
  1629.          { Owner }
  1630.          if (FStyle = tsOwnerDraw) then MeasureTab(Index, W);
  1631.  
  1632.          TabPos.Size := W;
  1633.          Inc(Start, TabPos.Size + EdgeWidth); { next usable position }
  1634.       end;
  1635.  
  1636.       if Start <= Stop then
  1637.       begin
  1638.         TabPositions.Add(Pointer(TabPos)); { add to list }
  1639.         Inc(Index);
  1640.       end;
  1641.     end;
  1642.   end;
  1643.   Result := Index - First;
  1644. end;
  1645.  
  1646. procedure TrmTabSet.SetEdgeWidth(const Value: integer);
  1647. begin
  1648.   fEdgeWidth := Value;
  1649.   Invalidate;
  1650. end;
  1651.  
  1652. end.
  1653.  
  1654.