{ ------------------------------------------------------------- }
{ Purpose : Next Collection 6                                   }
{ By      : Bojan Nikolic                                       }
{ For     : BergSoft                                            }
{ ------------------------------------------------------------- }
{ Copyright (C) BergSoft.net 2019. All Rights Reserved.         }
{ ------------------------------------------------------------- }
{ mm/dd/yy comment                                              }
{ -------- ---------------------------------------------------- }
{ 03/19/15 Initial code                                         }
{ ------------------------------------------------------------- }
{$I '..\NxSuite6.inc'}
unit NxPageControl6;

interface

uses
  { Standard }
  Classes, Types, Windows, Graphics, Controls, Messages, ImgList, Menus,
  {$IFDEF UI_TYPES}UITypes,{$ENDIF}
  { Next Standard 6 }
  NxConsts6, NxTypes6, NxIntf6, NxClasses6,
  { Next Collection 6 }
  NxCollection6, NxNotebook6;

const
  TabMovingTreshold = 5;

type
  TNxPageControl6 = class;
  TNxPageSheet6 = class;

  { TNxPageSheet6 }

  TNxPageSheetEvent = procedure (Sender: TNxPageSheet6) of object;

  TNxPageSheet6 = class(TNxNotebookSheet6)
  private
    FCaption: WideString;
    FImageIndex: TImageIndex;
    FTabVisible: Boolean;
    FTabColor: TColor;
    FOnTabChange: TNxPageSheetEvent;
    FTabEnabled: Boolean;
    FTabWidth: Integer;
    FTabFont: TFont;
    FParentTabFont: Boolean;
    procedure SetTabVisible(const Value: Boolean);
    procedure SetCaption(const Value: WideString);
    procedure SetImageIndex(const Value: TImageIndex);
    procedure SetTabColor(const Value: TColor);
    procedure SetTabEnabled(const Value: Boolean);
    procedure SetTabWidth(const Value: Integer);
    procedure SetTabFont(const Value: TFont);
    procedure SetParentTabFont(const Value: Boolean);
  protected
    procedure DoTabChange; dynamic;
    procedure DoTabFontChange(Sender: TObject);
    { Events }
    property OnTabChange: TNxPageSheetEvent read FOnTabChange write FOnTabChange;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Caption: WideString read FCaption write SetCaption;
    property ImageIndex: TImageIndex read FImageIndex write SetImageIndex;
    property ParentTabFont: Boolean read FParentTabFont write SetParentTabFont default True;
    property TabColor: TColor read FTabColor write SetTabColor default clBtnFace;
    property TabEnabled: Boolean read FTabEnabled write SetTabEnabled default True;
    property TabFont: TFont read FTabFont write SetTabFont;
    property TabVisible: Boolean read FTabVisible write SetTabVisible default True;
    property TabWidth: Integer read FTabWidth write SetTabWidth default 0;
  end;

  TNxCloseButtonLocation = (cbBeside, cbTab);
  TNxCloseButtonAction = (caHide, caDestroy);
  TNxPageControlButtons = set of (pbClose, pbScrolling, pbTabsPopup);
  TNxPageControlOptions = set of (poBoldActiveCaption);

  TNxPageCloseQueryEvent = procedure (Sender: TObject; Page: TNxPageSheet6;
    var CanClose: Boolean) of object;

  TNxTabMoveEvent = procedure (Sender: TObject; FromIndex, ToIndex: Integer) of object;

  TNxTabMouseEvent = procedure (Sender: TObject; Page: TNxPageSheet6;
    Button: TMouseButton; Shift: TShiftState; X, Y: Integer) of object;

  TNxDrawTabEvent = procedure (Sender: TObject; PageSheet: TNxPageSheet6;
    TabCanvas: TCanvas; TabRect: TRect; TabState: TNxButtonState; var OwnerDraw: Boolean) of object;

  { TNxPageControlStylePainter }

  TNxPageControlStylePainter = class
  private
    FPageControl: TNxPageControl6;
    function GetCanvas: TCanvas;
  public
    constructor Create(PageControl: TNxPageControl6);
    function GetTabsBackgroundColor: TColor; virtual;
    function GetTabTextColor: TColor; virtual;
    procedure PaintButton(ButtonRect: TRect; State: TNxButtonState); virtual; abstract;
    procedure PaintTab(TabRect: TRect; State: TNxButtonState); virtual; abstract;
    procedure PaintTabsBackground(BackgroundRect: TRect); virtual;
    procedure PaintTabsSeparator(SeparatorRect: TRect); virtual; abstract;
    { Properties }
    property Canvas: TCanvas read GetCanvas;
    property TabsBackgroundColor: TColor read GetTabsBackgroundColor;
    property TabTextColor: TColor read GetTabTextColor;
  end;

  { TNxPageControl6 }

  TNxPageControl6 = class(TNxCustomNotebook6)
  private
    FActiveTabColor: TColor;
    FActiveTabTextColor: TColor;
    FButtons: TNxPageControlButtons;
    FCloseButtonAction: TNxCloseButtonAction;
    FCloseButtonHint: WideString;
    FCloseButtonLocation: TNxCloseButtonLocation;
    FCloseButtonState: TNxButtonState;
    FDefaultCaption: WideString;
    FHotPageTab: TNxPageSheet6;
    FImages: TImageList;
    FMouseLocation: TPoint;
    FMoving: Boolean;
    FOldHeight: Integer;
    FOldWidth: Integer;
    FOnAfterTabMoving: TNotifyEvent;
    FOnDrawTabBackground: TNxDrawTabEvent;
    FOnPageCloseQuery: TNxPageCloseQueryEvent;
    FOnTabClick: TNxTabMouseEvent;
    FOnTabMove: TNxTabMoveEvent;
    FOptions: TNxPageControlOptions;
    FParentTabFont: Boolean;
    FPosition: Integer;
    FPreciseScrolling: Boolean;
    FPressedPageTab: TNxPageSheet6;
    FShowImages: Boolean;
    FShowTabs: Boolean;
    FStyle: TNxAppearanceStyle;
    FStyleColors: Boolean;
    FStylePainter: TNxPageControlStylePainter;
    FTabFont: TFont;
    FTabMoving: Boolean;
    FTabPadding: TPadding;
    FTabsBackgroundColor: TColor;
    FTabsHeight: Integer;
    FTabsLocation: TNxTabsLocation;
    FTabsPadding: TPadding;
    FTabsPopup: TPopupMenu;
    FTabsPopupBtnState: TNxButtonState;
    FTabsSpacing: Integer;
    FTabsWidth: Integer;
    FTabWidth: Integer;
    FSeparatorSize: Integer;
    function GetButtonSize: TSize;
    function GetCloseButtonRect: TRect;
    function GetHasSideButtons: Boolean;
    function GetNextButtonRect: TRect;
    function GetPage(const Index: Integer): TNxPageSheet6;
    function GetPageCaption(const Index: Integer): WideString;
    function GetPrevButtonRect: TRect;
    function GetTabsBackgroundRect: TRect;
    function GetTabsBackgroundSize: TSize;
    function GetTabSize: TSize;
    function GetTabsNCRect: TRect;
    function GetTabsOrientation: TNxOrientation;
    function GetTabsPopupBtnRect: TRect;
    function GetTabsRect: TRect;
    function GetTabsSize: TSize;
    procedure SetActiveTabColor(const Value: TColor);
    procedure SetActiveTabTextColor(const Value: TColor);
    procedure SetButtons(const Value: TNxPageControlButtons);
    procedure SetCloseButtonLocation(const Value: TNxCloseButtonLocation);
    procedure SetCloseButtonState(const Value: TNxButtonState);
    procedure SetDefaultCaption(const Value: WideString);
    procedure SetHotPageTab(const Value: TNxPageSheet6);
    procedure SetImages(const Value: TImageList);
    procedure SetMoving(const Value: Boolean);
    procedure SetOptions(const Value: TNxPageControlOptions);
    procedure SetParentTabFont(const Value: Boolean);
    procedure SetPreciseScrolling(const Value: Boolean);
    procedure SetPressedPageTab(const Value: TNxPageSheet6);
    procedure SetShowImages(const Value: Boolean);
    procedure SetShowTabs(const Value: Boolean);
    procedure SetStyle(const Value: TNxAppearanceStyle);
    procedure SetStyleColors(const Value: Boolean);
    procedure SetTabFont(const Value: TFont);
    procedure SetTabPadding(const Value: TPadding);
    procedure SetTabsBackgroundColor(const Value: TColor);
    procedure SetTabsBtnPopupState(const Value: TNxButtonState);
    procedure SetTabsHeight(const Value: Integer);
    procedure SetTabsLocation(const Value: TNxTabsLocation);
    procedure SetTabsPadding(const Value: TPadding);
    procedure SetTabsSpacing(const Value: Integer);
    procedure SetTabsWidth(const Value: Integer);
    procedure SetTabWidth(const Value: Integer);
    procedure SetSeparatorSize(const Value: Integer);
  protected
    procedure AdjustClientRect(var Rect: TRect); override;
    procedure AdjustTabFont(const TabFont: TFont; const Index: Integer); overload;
    procedure AdjustTabFont(const TabFont: TFont; const PageSheet: TNxPageSheet6); overload;
    procedure CreateWnd; override;
    { Event Handlers }
    procedure DoActiveChange(Sheet: TNxNotebookSheet6); override;
    procedure DoClosePageQuery(Page: TNxPageSheet6; var CanClose: Boolean); dynamic;
    procedure DoDrawTabBackground(PageSheet: TNxPageSheet6; TabCanvas: TCanvas; TabRect: TRect; TabState: TNxButtonState; var OwnerDraw: Boolean); dynamic;
    procedure DoPageAdded(Sheet: TNxNotebookSheet6); override;
    procedure DoPopupTabClick(Sender: TObject);
    procedure DoTabChange(Sender: TNxPageSheet6);
    procedure DoTabClick(Page: TNxPageSheet6; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer); dynamic;
    procedure DoTabFontChange(Sender: TObject);
    procedure DoTabMove(FromIndex, ToIndex: Integer); dynamic;
    procedure DoTabsChange(Sender: TObject);
    { Overr. Methods }
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    { Painting }
    procedure Paint; override;
    procedure PaintCloseButton(ButtonRect: TRect; ButtonState: TNxButtonState);
    procedure PaintTabBackground(PageSheet: TNxPageSheet6; TabRect: TRect; State: TNxButtonState); virtual;
    procedure PaintTabsBackground(BackgroundRect: TRect); virtual;
    procedure PaintTab(TabRect: TRect; PageSheet: TNxPageSheet6;
      State: TNxButtonState);
    procedure PaintTabs;
    procedure PaintTabsPopupBtn(BtnRect: TRect; BtnState: TNxButtonState);
    procedure PaintTabsSeparator;
    procedure ValidateInsert(AComponent: TComponent); override;
    { Overrides }
    procedure PageActiveChange(Sheet: TNxNotebookSheet6); override;
    { Delphi Messages }
    procedure CMDesignHitTest(var Message: TCMDesignHitTest); message CM_DESIGNHITTEST;
    procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
    { WinApi Messages }
    procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
    procedure WMKillFocus(var Message: TWMSetFocus); message WM_KILLFOCUS;
    procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
    procedure WMSize(var Message: TWMSize); message WM_SIZE;
    { Properties }
    property CloseButtonRect: TRect read GetCloseButtonRect;
    property ButtonSize: TSize read GetButtonSize;
    property HasSideButtons: Boolean read GetHasSideButtons;
    property Moving: Boolean read FMoving write SetMoving;
    property NextButtonRect: TRect read GetNextButtonRect;
    property PrevButtonRect: TRect read GetPrevButtonRect;
    property TabSize: TSize read GetTabSize;
    property TabsBackgroundRect: TRect read GetTabsBackgroundRect;
    property TabsBackgroundSize: TSize read GetTabsBackgroundSize;
    property TabsNCRect: TRect read GetTabsNCRect;
    property TabsPopupBtnState: TNxButtonState read FTabsPopupBtnState
      write SetTabsBtnPopupState;
    property TabsPopupBtnRect: TRect read GetTabsPopupBtnRect;
    property TabsRect: TRect read GetTabsRect;
    property TabsSize: TSize read GetTabsSize;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Methods }
    function AddPage(Active: Boolean = False): TNxPageSheet6; overload;
    function AddPage(Caption: WideString; Active: Boolean = False): TNxPageSheet6; overload;
    function ClosePage(PageSheet: TNxPageSheet6): Boolean;
    function CreateStylePainter(AStyle: TNxAppearanceStyle): TNxPageControlStylePainter;
    function GetNearestTabAtPos(const Location: TPoint): TNxPageSheet6;
    function GetPageTabSize(const Index: Integer): TSize;
    function GetTabAtPos(const Location: TPoint): TNxPageSheet6;
    function GetTabCloseButtonRect(PageSheet: TNxPageSheet6): TRect;
    function GetTabSheetClass: TNxSheetClass; override;
    function GetTabRect(const PageSheet: TNxPageSheet6): TRect;
    procedure RefreshPageTab(PageSheet: TNxPageSheet6);
    procedure ScrollToTab(const PageSheet: TNxPageSheet6); overload;
    procedure ScrollToTab(const Index: Integer); overload;
    procedure ShowTabsPopup;
    { Properties }
    property CloseButtonState: TNxButtonState read FCloseButtonState write SetCloseButtonState;
    property HotPageTab: TNxPageSheet6 read FHotPageTab write SetHotPageTab;
    property Page[const Index: Integer]: TNxPageSheet6 read GetPage;
    property PageCaption[const Index: Integer]: WideString read GetPageCaption;
    property Painter: TNxPageControlStylePainter read FStylePainter;
    property PressedPageTab: TNxPageSheet6 read FPressedPageTab write SetPressedPageTab;
    property TabsOrientation: TNxOrientation read GetTabsOrientation;
  published
    property ActiveTabColor: TColor read FActiveTabColor write SetActiveTabColor default clHighlight;
    property ActiveTabTextColor: TColor read FActiveTabTextColor write SetActiveTabTextColor default clHighlightText;
    property CloseButtonAction: TNxCloseButtonAction read FCloseButtonAction
      write FCloseButtonAction default caHide;
    property CloseButtonHint: WideString read FCloseButtonHint write FCloseButtonHint;
    property CloseButtonLocation: TNxCloseButtonLocation read FCloseButtonLocation
      write SetCloseButtonLocation default cbBeside;
    property DefaultCaption: WideString read FDefaultCaption write SetDefaultCaption;
    property Images: TImageList read FImages write SetImages;
    property Options: TNxPageControlOptions read FOptions write SetOptions default [];
    property ParentTabFont: Boolean read FParentTabFont write SetParentTabFont default True;
    property PreciseScrolling: Boolean read FPreciseScrolling write SetPreciseScrolling default True;
    property SeparatorSize: Integer read FSeparatorSize write SetSeparatorSize default 2;
    property ShowImages: Boolean read FShowImages write SetShowImages default True;
    property ShowTabs: Boolean read FShowTabs write SetShowTabs default True;
    property Style: TNxAppearanceStyle read FStyle write SetStyle default stModern;
    property StyleColors: Boolean read FStyleColors write SetStyleColors default True;
    property TabFont: TFont read FTabFont write SetTabFont;
    property TabMoving: Boolean read FTabMoving write FTabMoving default True;
    property TabPadding: TPadding read FTabPadding write SetTabPadding;
//  property TabsAlignment
    property TabsBackgroundColor: TColor read FTabsBackgroundColor write SetTabsBackgroundColor
      default clBtnFace;
    property TabsHeight: Integer read FTabsHeight write SetTabsHeight default 20;
    property TabsWidth: Integer read FTabsWidth write SetTabsWidth default 80;
    property TabsLocation: TNxTabsLocation read FTabsLocation
      write SetTabsLocation default tbTop;
    property TabsPadding: TPadding read FTabsPadding write SetTabsPadding;
    property TabsSpacing: Integer read FTabsSpacing write SetTabsSpacing default 0;
    property TabWidth: Integer read FTabWidth write SetTabWidth default 0;
    property VisibleButtons: TNxPageControlButtons read FButtons write SetButtons
      default [pbClose, pbTabsPopup];

    property OnAfterTabMoving: TNotifyEvent read FOnAfterTabMoving write FOnAfterTabMoving;
    property OnDrawTabBackground: TNxDrawTabEvent read FOnDrawTabBackground write FOnDrawTabBackground;
    property OnPageCloseQuery: TNxPageCloseQueryEvent read FOnPageCloseQuery write FOnPageCloseQuery;
    property OnTabClick: TNxTabMouseEvent read FOnTabClick write FOnTabClick;
    property OnTabMove: TNxTabMoveEvent read FOnTabMove write FOnTabMove;
  end;

  { TNxModernPageControlStylePainter }

  TNxModernPageControlStylePainter = class(TNxPageControlStylePainter)
  public
    function GetTabsBackgroundColor: TColor; override;
    function GetTabTextColor: TColor; override;
    procedure PaintButton(ButtonRect: TRect; State: TNxButtonState); override;
    procedure PaintTab(TabRect: TRect; State: TNxButtonState); override;
    procedure PaintTabsSeparator(SeparatorRect: TRect); override;
  end;

  { TNxNativePageControl }

  TNxNativePageControlStylePainter = class(TNxPageControlStylePainter)
  public
    function GetTabsBackgroundColor: TColor; override;
    procedure PaintButton(ButtonRect: TRect; State: TNxButtonState); override;
    procedure PaintTab(TabRect: TRect; State: TNxButtonState); override;
    procedure PaintTabsBackground(BackgroundRect: TRect); override;
    procedure PaintTabsSeparator(SeparatorRect: TRect); override;
  end;

  { TNxUserDefinedPageControlStylePainter }

  TNxUserDefinedPageControlStylePainter = class(TNxPageControlStylePainter)
  public
    procedure PaintButton(ButtonRect: TRect; State: TNxButtonState); override;
    procedure PaintTab(TabRect: TRect; State: TNxButtonState); override;
    procedure PaintTabsSeparator(SeparatorRect: TRect); override;
  end;

implementation

uses
  { Standard }
  SysUtils, Math, ExtCtrls, Forms,
  NxGraphics6, NxStyles6;

{ TNxPageSheet6 }

constructor TNxPageSheet6.Create(AOwner: TComponent);
begin
  inherited;
  FCaption := '';
  FParentTabFont := True;
  FTabColor := clBtnFace;
  FTabEnabled := True;
  FTabFont := TFont.Create;
  FTabFont.OnChange := DoTabFontChange;
  FTabVisible := True;
end;

destructor TNxPageSheet6.Destroy;
begin
  FTabFont.Free;
  inherited;
end;

procedure TNxPageSheet6.DoTabChange;
begin
  if Assigned(FOnTabChange) then FOnTabChange(Self);
end;

procedure TNxPageSheet6.DoTabFontChange(Sender: TObject);
begin
  ParentTabFont := False;
  DoTabChange;
end;

procedure TNxPageSheet6.SetCaption(const Value: WideString);
begin
  if Value <> FCaption then
  begin
    FCaption := Value;
    DoTabChange;
  end;
end;

procedure TNxPageSheet6.SetImageIndex(const Value: TImageIndex);
begin
  if Value <> FImageIndex then
  begin
    FImageIndex := Value;
    DoTabChange;
  end;
end;

procedure TNxPageSheet6.SetParentTabFont(const Value: Boolean);
begin
  FParentTabFont := Value;
  if FParentTabFont then
  begin
    { Detach event as event set FParentTabFont to False }
    FTabFont.OnChange := nil;
    FTabFont.Assign((Parent as TNxPageControl6).TabFont);
    FTabFont.OnChange := DoTabFontChange;
    DoTabChange;
  end;
end;

procedure TNxPageSheet6.SetTabColor(const Value: TColor);
begin
  if Value <> FTabColor then
  begin
    FTabColor := Value;
    DoTabChange;
  end;
end;

procedure TNxPageSheet6.SetTabEnabled(const Value: Boolean);
begin
  if Value <> FTabEnabled then
  begin
    FTabEnabled := Value;
    DoTabChange;
  end;
end;

procedure TNxPageSheet6.SetTabFont(const Value: TFont);
begin
  FTabFont.Assign(Value);
  FTabFont.OnChange := DoTabFontChange;
end;

procedure TNxPageSheet6.SetTabVisible(const Value: Boolean);
begin
  if Value <> FTabVisible then
  begin
    FTabVisible := Value;
    DoTabChange;
  end;
end;

procedure TNxPageSheet6.SetTabWidth(const Value: Integer);
begin
  if (Value <> FTabWidth) and (Value > 0) then
  begin
    FTabWidth := Value;
    DoTabChange;
  end;
end;

{ TNxPageControl6 }

function TNxPageControl6.AddPage(Active: Boolean): TNxPageSheet6;
begin
  Result := TNxPageSheet6(Add(Active));
  Result.TabFont.Assign(TabFont);
end;

function TNxPageControl6.AddPage(Caption: WideString;
  Active: Boolean): TNxPageSheet6;
begin
  Result := AddPage(Active);
  Result.Caption := Caption;
end;

procedure TNxPageControl6.AdjustClientRect(var Rect: TRect);
begin
  inherited;
  if ShowTabs then
  begin
    case TabsLocation of
      tbTop: Inc(Rect.Top, TabsBackgroundSize.cy + SeparatorSize);
      tbBottom: Dec(Rect.Bottom, TabsBackgroundSize.cy + SeparatorSize);
      tbLeft: Inc(Rect.Left, TabsBackgroundSize.cx + SeparatorSize);
      tbRight: Dec(Rect.Right, TabsBackgroundSize.cx + SeparatorSize);
    end;
  end;
end;

procedure TNxPageControl6.AdjustTabFont(const TabFont: TFont; const PageSheet: TNxPageSheet6);
begin
  if (poBoldActiveCaption in FOptions) and (PageSheet = ActivePage) then
    TabFont.Style := TabFont.Style + [fsBold];
end;

procedure TNxPageControl6.AdjustTabFont(const TabFont: TFont; const Index: Integer);
begin
  if (poBoldActiveCaption in FOptions) and (Index = ActivePageIndex) then
    TabFont.Style := TabFont.Style + [fsBold];
end;

function TNxPageControl6.ClosePage(PageSheet: TNxPageSheet6): Boolean;
begin
  Result := False;
  if Assigned(PageSheet) then
  begin

    if PageSheet.Parent <> Self then
      raise EAccessViolation.Create('PageSheet can not be found');

    Result := True;

    { Var arg in event }
    DoClosePageQuery(PageSheet, Result);

    { Can still close tab? }
    if Result then
      case CloseButtonAction of
        caHide:
          begin
            PageSheet.TabVisible := False;
            Invalidate;
          end;
        caDestroy:
          begin
            FreeAndNil(PageSheet);
            Invalidate;
          end;
      end;

  end else raise EAccessViolation.Create('PageSheet can not be nil');
end;

procedure TNxPageControl6.CMDesignHitTest(var Message: TCMDesignHitTest);
var
  Page: TNxPageSheet6;
begin
  inherited;
  Page := GetTabAtPos(Point(Message.XPos, Message.YPos));
  if Assigned(Page) and (Page <> ActivePage)
    then Message.Result := 1 else Message.Result := 0;
end;

procedure TNxPageControl6.CMFontChanged(var Message: TMessage);
begin
  inherited;
  ParentTabFont := ParentTabFont;
end;

procedure TNxPageControl6.CMMouseLeave(var Message: TMessage);
begin
  inherited;
  HotPageTab := nil;
  TabsPopupBtnState := TabsPopupBtnState - [bsHover];
  CloseButtonState := CloseButtonState - [bsHover];
end;

constructor TNxPageControl6.Create(AOwner: TComponent);
begin
  inherited;
  FActiveTabColor := clHighlight;
  FActiveTabTextColor := clHighlightText;
  FButtons := [pbClose, pbTabsPopup];
  FCloseButtonAction := caHide;
  FCloseButtonHint := '';
  FCloseButtonLocation := cbBeside;
  FDefaultCaption := '<default>';
  FHotPageTab := nil;
  FImages := nil;
  FMoving := False;
  FOptions := [];
  FPosition := 0;
  FPreciseScrolling := True;
  FPressedPageTab := nil;
  FSeparatorSize := 2;
  FStyleColors := True;
  FShowImages := True;
  FShowTabs := True;
  FStyle := stModern;
  FStylePainter := CreateStylePainter(FStyle);
  FTabFont := TFont.Create;
  FTabFont.OnChange := DoTabFontChange;
  FTabMoving := True;
  FTabPadding := TPadding.Create(nil);
  FTabPadding.SetBounds(4, 2, 4, 2);
  FTabPadding.OnChange := DoTabsChange;
  FTabsBackgroundColor := clBtnFace;
  FTabsHeight := 20;
  FTabsLocation := tbTop;
  FTabsPadding := TPadding.Create(nil);
  FTabsPadding.SetBounds(8, 4, 8, 0);
  FTabsPadding.OnChange := DoTabsChange;
  FTabsPopup := TPopupMenu.Create(Self);
  FTabsSpacing := 0;
  FTabsWidth := 80;
  FTabWidth := 0;
  ControlStyle := ControlStyle + [csCaptureMouse];
  ParentTabFont := True;
  Width := 320;
  Height := 240;
end;

function TNxPageControl6.CreateStylePainter(
  AStyle: TNxAppearanceStyle): TNxPageControlStylePainter;
begin
  case AStyle of
    stModern: Result := TNxModernPageControlStylePainter.Create(Self);
    stNative: Result := TNxNativePageControlStylePainter.Create(Self);
    else Result := TNxUserDefinedPageControlStylePainter.Create(Self);
  end;
end;

procedure TNxPageControl6.CreateWnd;
begin
  inherited;
end;

destructor TNxPageControl6.Destroy;
begin
  FreeAndNil(FStylePainter);
  FreeAndNil(FTabFont);
  FreeAndNil(FTabPadding);
  FreeAndNil(FTabsPadding);
  FreeAndNil(FTabsPopup);
  inherited;
end;

procedure TNxPageControl6.DoActiveChange(Sheet: TNxNotebookSheet6);
begin
  inherited;
  if Assigned(ActivePage) then
  begin
    ScrollToTab(ActivePage as TNxPageSheet6);
  end;
end;

procedure TNxPageControl6.DoClosePageQuery(Page: TNxPageSheet6;
  var CanClose: Boolean);
begin
  if Assigned(FOnPageCloseQuery) then FOnPageCloseQuery(Self, Page, CanClose);
end;

procedure TNxPageControl6.DoDrawTabBackground(PageSheet: TNxPageSheet6;
  TabCanvas: TCanvas; TabRect: TRect; TabState: TNxButtonState;
  var OwnerDraw: Boolean);
begin
  if Assigned(FOnDrawTabBackground) then FOnDrawTabBackground(Self, PageSheet, TabCanvas, TabRect, TabState, OwnerDraw);
end;

procedure TNxPageControl6.DoPageAdded(Sheet: TNxNotebookSheet6);
begin
  inherited;
  with Sheet as TNxPageSheet6 do
  begin
    OnTabChange := Self.DoTabChange;
  end;
end;

procedure TNxPageControl6.DoPopupTabClick(Sender: TObject);
begin
  with Sender as TMenuItem do
  begin
    ActivePageIndex := Tag;
  end;
end;

procedure TNxPageControl6.DoTabChange(Sender: TNxPageSheet6);
begin
  Invalidate;
end;

procedure TNxPageControl6.DoTabClick(Page: TNxPageSheet6; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Assigned(FOnTabClick) then FOnTabClick(Self, Page, Button, Shift, X, Y);
end;

procedure TNxPageControl6.DoTabFontChange(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to Pred(Count) do
    if Page[i].ParentTabFont
      then Page[i].ParentTabFont := True;
  Invalidate;
  Realign;
end;

procedure TNxPageControl6.DoTabMove(FromIndex, ToIndex: Integer);
begin
  if Assigned(FOnTabMove) then FOnTabMove(Self, FromIndex, ToIndex);
end;

procedure TNxPageControl6.DoTabsChange(Sender: TObject);
begin
  Invalidate;
  Realign;
end;

function TNxPageControl6.GetButtonSize: TSize;
begin
  Result := DotToPixel(Size(16, 16));
end;

function TNxPageControl6.GetCloseButtonRect: TRect;
var
  X: Integer;
begin
  case TabsOrientation of
    orHorizontal:
    begin
      X := TabsRect.Right;
      if pbTabsPopup in VisibleButtons then Inc(X, ButtonSize.cx);

      Result := Bounds(X, TabsRect.Top, ButtonSize.cx, ButtonSize.cy);
      OffsetRect(Result, 0, Round(RectHeight(TabsRect) / 2 - RectHeight(Result) / 2));
    end;
    orVertical:
    begin
      X := TabsRect.Left;
      if pbTabsPopup in VisibleButtons then Inc(X, ButtonSize.cx);
      Result := Bounds(X, TabsRect.Bottom, ButtonSize.cx, ButtonSize.cy);
    end;
  end;
end;

function TNxPageControl6.GetHasSideButtons: Boolean;
var
  Count: Integer;
begin
  Count := 0;
  if pbScrolling in VisibleButtons then Inc(Count);
  if pbTabsPopup in VisibleButtons then Inc(Count);
  if (pbClose in VisibleButtons) and (CloseButtonLocation = cbBeside) then Inc(Count);
  Result := Count > 0;
end;

function TNxPageControl6.GetNearestTabAtPos(
  const Location: TPoint): TNxPageSheet6;
var
  i, X, Y, First, MidX: Integer;
  TabRect: TRect;
  TabSize: TSize;
begin
  Result := nil;

  if PtInRect(TabsRect, Location) then
  begin
    First := 0;
    X := TabsRect.Left;
    Y := TabsRect.Top;

    if PreciseScrolling then
    begin
      Dec(X, FPosition);
    end else First := FPosition;

    for i := First to Pred(Count) do
      if Page[i].TabVisible then
      begin
        TabSize := GetPageTabSize(i);
        TabRect := Bounds(X, Y, TabSize.cx, TabSize.cy);

        MidX := TabRect.Left + RectWidth(TabRect) div 2;

        if PtInRect(TabRect, Location) then
        begin
          Result := Page[i];
          if Location.X > MidX then Result := Page[Min(Pred(Count), i + 1)];
          Exit;
        end;

        case TabsOrientation of
          orVertical:
            begin
              Inc(Y, TabSize.cy);
              Inc(Y, TabsSpacing);
            end;
          orHorizontal:
            begin
              Inc(X, TabSize.cx);
              Inc(X, TabsSpacing);
            end;
        end;

      end;

  end; { PtIn TabsRect}
end;

function TNxPageControl6.GetNextButtonRect: TRect;
begin

end;

function TNxPageControl6.GetPage(const Index: Integer): TNxPageSheet6;
begin
  Result := TNxPageSheet6(Controls[Index]);
end;

function TNxPageControl6.GetPageCaption(const Index: Integer): WideString;
begin
  Result := Page[Index].Caption;
  if Result = '' then Result := DefaultCaption;
end;

function TNxPageControl6.GetPageTabSize(const Index: Integer): TSize;
var
  APage: TNxPageSheet6;
  CaptionSize: TSize;
begin
  APage := Page[Index];
  with Result do
  begin
    { Equal in both orientations. }
    cy := TabSize.cy;

    case TabsLocation of
      tbLeft, tbRight:
      begin
        cx := TabsSize.cx;
      end;
      else
        begin
          { Specific tab }
          if APage.TabWidth <> 0 then
          begin
            cx := Page[Index].TabWidth;
            Exit;
          end;

          { All tabs }
          if TabWidth <> 0 then
          begin
            cx := TabWidth;
            Exit;
          end;

          cx := TabPadding.Left + TabPadding.Right;

          Canvas.Font.Assign(APage.TabFont);

          { E.g. bold captions }
          AdjustTabFont(Canvas.Font, Index);

          CaptionSize := GetTextSize(Canvas, PageCaption[Index], False);
          Inc(cx, CaptionSize.cx);

          if Assigned(Images) and ShowImages
            and InRange(APage.ImageIndex, 0, Pred(Images.Count)) then
          begin
            Inc(cx, Images.Width);
            if CaptionSize.cx > 0 then Inc(cx, pdTextToIcon);
          end;

          if CloseButtonLocation = cbTab then
          begin
            Inc(cx, ButtonSize.cx + pdDouble);
          end;
        end;
    end;
  end;
end;

function TNxPageControl6.GetPrevButtonRect: TRect;
begin
  case TabsLocation of
    tbLeft, tbRight: Result := Bounds(TabsRect.Left, TabsRect.Bottom, TabsSize.cx, ButtonSize.cy);
    tbTop, tbBottom: Result := Bounds(TabsRect.Right, TabsRect.Top, ButtonSize.cx, TabsSize.cy);
  end;
end;

function TNxPageControl6.GetTabSheetClass: TNxSheetClass;
begin
  Result := TNxPageSheet6;
end;

function TNxPageControl6.GetTabAtPos(const Location: TPoint): TNxPageSheet6;
var
  i, X, Y, First: Integer;
  TabRect: TRect;
  TabSize: TSize;
begin
  Result := nil;

  if PtInRect(TabsRect, Location) then
  begin
    First := 0;
    X := TabsRect.Left;
    Y := TabsRect.Top;

    if PreciseScrolling then
    begin
      Dec(X, FPosition);
    end else First := FPosition;

    for i := First to Pred(Count) do
      if Page[i].TabVisible then
      begin
        TabSize := GetPageTabSize(i);
        TabRect := Bounds(X, Y, TabSize.cx, TabSize.cy);

        if PtInRect(TabRect, Location) then
          Result := Page[i];

        case TabsLocation of
          tbLeft, tbRight:
          begin
            Inc(Y, TabSize.cy);
            Inc(Y, TabsSpacing);
          end;
          else
          begin
            Inc(X, TabSize.cx);
            Inc(X, TabsSpacing);
          end;
        end;
      end;

  end; { PtIn TabsRect}
end;

function TNxPageControl6.GetTabCloseButtonRect(PageSheet: TNxPageSheet6): TRect;
begin
  Result := GetTabRect(PageSheet);
  SetPadding(Result, TabPadding);
  with Result do
  begin
    Left := Right - ButtonSize.cx;
    Inc(Top, RectHeight(Result) div 2 - ButtonSize.cy div 2);
    Bottom := Top + ButtonSize.cy;
  end;
end;

function TNxPageControl6.GetTabRect(const PageSheet: TNxPageSheet6): TRect;
var
  i, X, Y, First: Integer;
  TabSize: TSize;
begin
  First := 0;
  X := TabsRect.Left;
  Y := TabsRect.Top;

  if PreciseScrolling then
  begin
    Dec(X, FPosition);
  end else First := FPosition;

  for i := First to Pred(Count) do
    if Page[i].TabVisible then
    begin
      TabSize := GetPageTabSize(i);
      Result := Bounds(X, Y, TabSize.cx, TabSize.cy);

      if Page[i] = PageSheet then Exit;

      case TabsLocation of
        tbLeft, tbRight:
        begin
          Inc(Y, TabSize.cy);
          Inc(Y, TabsSpacing);
        end;
        else
        begin
          Inc(X, TabSize.cx);
          Inc(X, TabsSpacing);
        end;
      end;
    end;
end;

///<summary>
/// Tabs client rect
///</summary>
function TNxPageControl6.GetTabsBackgroundRect: TRect;
begin
  case TabsLocation of
    tbTop, tbLeft:
      Result := Bounds(0, 0, TabsBackgroundSize.cx, TabsBackgroundSize.cy);
    tbRight:
      Result := Bounds(ClientWidth - TabsBackgroundSize.cx, 0, TabsBackgroundSize.cx, TabsBackgroundSize.cy);
    else
      Result := Bounds(0, ClientHeight - TabsBackgroundSize.cy, TabsBackgroundSize.cx, TabsBackgroundSize.cy)
  end;
end;

function TNxPageControl6.GetTabsBackgroundSize: TSize;
begin
  with Result do
    case TabsLocation of
      tbLeft, tbRight:
        begin
          cx := TabSize.cx + TabsPadding.Top + TabsPadding.Bottom;
          cy := ClientHeight;
        end;
      else
        begin
          cx := ClientWidth;
          cy := TabSize.cy + TabsPadding.Top + TabsPadding.Bottom;
        end;
    end;
end;

function TNxPageControl6.GetTabSize: TSize;
begin
  with Result do
  begin
    cx := 0;
    case TabsLocation of
      tbLeft, tbRight:
        begin
          cx := TabsWidth;
          Inc(cx, TabPadding.Left);
          Inc(cx, TabPadding.Right);
        end;
    end;
    cy := TabsHeight;
    Inc(cy, TabPadding.Top);
    Inc(cy, TabPadding.Bottom);
  end;
end;

function TNxPageControl6.GetTabsNCRect: TRect;
begin
  Result := TabsBackgroundRect;
  case FTabsLocation of
    tbTop: Inc(Result.Bottom, SeparatorSize);
    tbLeft: Inc(Result.Right, SeparatorSize);
    tbRight: Dec(Result.Left, SeparatorSize);
    tbBottom: Dec(Result.Top, SeparatorSize);
  end;
end;

function TNxPageControl6.GetTabsOrientation: TNxOrientation;
begin
  case TabsLocation of
    tbLeft, tbRight: Result := orVertical;
    else Result := orHorizontal;
  end;
end;

function TNxPageControl6.GetTabsPopupBtnRect: TRect;
begin
  case TabsOrientation of
    orHorizontal:
    begin
      Result := Bounds(TabsRect.Right, TabsRect.Top, ButtonSize.cx, ButtonSize.cy);
      OffsetRect(Result, 0, Round(RectHeight(TabsRect) / 2 - RectHeight(Result) / 2));
    end;
    orVertical: Result := Bounds(TabsRect.Left, TabsRect.Bottom, ButtonSize.cx, ButtonSize.cy);
  end;
end;

///<summary>
/// Client tabs rect without padding.
///</summary>
function TNxPageControl6.GetTabsRect: TRect;
begin
  with TabsSize do
  begin
    case TabsLocation of
      tbTop: Result := Bounds(TabsPadding.Left, TabsBackgroundRect.Top + TabsPadding.Top, cx, cy);
      tbBottom: Result := Bounds(TabsPadding.Left, TabsBackgroundRect.Top + TabsPadding.Bottom, cx, cy);
      tbLeft: Result := Bounds(TabsPadding.Top, TabsBackgroundRect.Top + TabsPadding.Left, cx, cy);
      tbRight: Result := Bounds(TabsBackgroundRect.Left + TabsPadding.Bottom, TabsBackgroundRect.Top + TabsPadding.Left, cx, cy);
    end;
  end;
end;

function TNxPageControl6.GetTabsSize: TSize;
begin
  with Result do
    case TabsLocation of
      tbLeft, tbRight:
        begin
          cy := ClientHeight;
          Dec(cy, TabsPadding.Left);
          Dec(cy, TabsPadding.Right);

          { Popup, Close Buttons }
          if pbTabsPopup in VisibleButtons then Dec(cy, ButtonSize.cx);
          if pbClose in VisibleButtons then
            if CloseButtonLocation = cbBeside then Dec(cy, ButtonSize.cx);

          cx := TabSize.cx;
        end;

      else
        begin
          cx := ClientWidth;
          Dec(cx, TabsPadding.Left);
          Dec(cx, TabsPadding.Right);

          { Popup, Close Buttons }
          if pbTabsPopup in VisibleButtons then Dec(cx, ButtonSize.cx);
          if pbClose in VisibleButtons then
            if CloseButtonLocation = cbBeside then Dec(cx, ButtonSize.cx);

          cy := TabSize.cy;
        end;
    end;
end;

procedure TNxPageControl6.KeyDown(var Key: Word; Shift: TShiftState);
begin
  inherited;
  case Key of
    VK_LEFT: ActivePageIndex := ActivePageIndex - 1;
    VK_RIGHT: ActivePageIndex := ActivePageIndex + 1;
  end;
end;

procedure TNxPageControl6.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
  TabAtPos: TNxPageSheet6;
begin
  inherited;

  TabAtPos := GetTabAtPos(Point(X, Y));
  PressedPageTab := TabAtPos;

  if Button = mbLeft then
  begin

    if Assigned(TabAtPos) and (TabAtPos.TabEnabled or (csDesigning in ComponentState)) then
    begin
      ActivePage := TabAtPos;
      FMouseLocation := Point(X, Y);
    end;

    if pbTabsPopup in VisibleButtons then
      if PtInRect(TabsPopupBtnRect, Point(X, Y)) then
        TabsPopupBtnState := TabsPopupBtnState + [bsPressed];

    { close btn. hit-test }
    if pbClose in VisibleButtons then
      case CloseButtonLocation of
        cbBeside:
          if PtInRect(CloseButtonRect, Point(X, Y))
            then CloseButtonState := CloseButtonState + [bsPressed];
        cbTab:
          if Assigned(TabAtPos)
            and PtInRect(GetTabCloseButtonRect(TabAtPos), Point(X, Y)) then
          begin
            CloseButtonState := CloseButtonState + [bsPressed];
          end;
      end;

  end; { Button }

end;

procedure TNxPageControl6.MouseMove(Shift: TShiftState; X, Y: Integer);
var
  NearestTab: TNxPageSheet6;
  Changed: Boolean;
  OldIndex, NewIndex: Integer;
begin
  inherited;

  { Ignore while in design state }
  if not (csDesigning in ComponentState) then
  begin

    { Tab Moving code }
    if Assigned(PressedPageTab) and TabMoving then
    begin
      { Already Moving }
      if FMoving then
      begin
        NearestTab := GetTabAtPos(Point(X, Y));
        if NearestTab <> nil then
        begin
          Changed := NearestTab <> ActivePage;
          OldIndex := ActivePage.Index;
          NewIndex := NearestTab.Index;

          { Assign new }
          ActivePage.Index := NearestTab.Index;

          { Event }
          if Changed then DoTabMove(OldIndex, NewIndex);
        end;
        Exit;
      end;

      { Can start Moving? }
      if (Abs(FMouseLocation.X - X) > TabMovingTreshold) or
        (Abs(FMouseLocation.Y - Y) > TabMovingTreshold) then
      begin
        Moving := True;
        Exit;
      end;
    end;

    { Tabs popup }
    if pbTabsPopup in VisibleButtons then
    begin

      if PtInRect(TabsPopupBtnRect, Point(X, Y)) then
        TabsPopupBtnState := TabsPopupBtnState + [bsHover]
      else
        TabsPopupBtnState := TabsPopupBtnState - [bsHover];

    end;


    if pbClose in VisibleButtons then
      case CloseButtonLocation of
        cbBeside:
          if PtInRect(CloseButtonRect, Point(X, Y))
          then
            CloseButtonState := CloseButtonState + [bsHover]
          else
            CloseButtonState := CloseButtonState - [bsHover];
        cbTab:
          begin
            if Assigned(HotPageTab) then
              if PtInRect(GetTabCloseButtonRect(HotPageTab), Point(X, Y)) then
              begin
                CloseButtonState := CloseButtonState + [bsHover];
              end
              else
                CloseButtonState := CloseButtonState - [bsHover];

          end;
      end;

  end;

  HotPageTab := GetTabAtPos(Point(X, Y));
end;

procedure TNxPageControl6.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  inherited;

  { Change cursor back }
  Moving := False;

  if Assigned(PressedPageTab)
    and (PressedPageTab = HotPageTab) then
  begin
    DoTabClick(PressedPageTab, Button, Shift, X, Y);
  end;

  if Button = mbLeft then
  begin

    if pbTabsPopup in VisibleButtons then
      if bsPressed in TabsPopupBtnState then
      begin
        ShowTabsPopup;
      end;

    { close btn. hit-test }
    if pbClose in VisibleButtons then

      if bsPressed in CloseButtonState then

        case CloseButtonLocation of
          cbBeside:
            if PtInRect(CloseButtonRect, Point(X, Y))
              then ClosePage(ActivePage as TNxPageSheet6);

          cbTab:
            if Assigned(HotPageTab) and Assigned(PressedPageTab)
              and (HotPageTab = PressedPageTab)
              and PtInRect(GetTabCloseButtonRect(PressedPageTab), Point(X, Y)) then
            begin
              ClosePage(PressedPageTab);
            end;

        end;

  end;

  TabsPopupBtnState := TabsPopupBtnState - [bsPressed];
  CloseButtonState := CloseButtonState - [bsPressed];
  PressedPageTab := nil;
end;

procedure TNxPageControl6.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited;
  if AComponent = Images
    then Images := nil;
end;

procedure TNxPageControl6.PageActiveChange(Sheet: TNxNotebookSheet6);
begin
  inherited;
  if poBoldActiveCaption in Options then InvalidateRect(TabsRect)
    else RefreshPageTab(Sheet as TNxPageSheet6);
end;

procedure TNxPageControl6.Paint;
begin
  inherited;
  with Canvas do
  begin
    Brush.Color := Painter.GetTabsBackgroundColor;
    PaintTabsBackground(TabsBackgroundRect);

    try
      SetClipRect(Canvas, TabsRect);
      PaintTabs;
    finally
      SetClipRect(Canvas, ClientRect);
    end;

    PaintTabsSeparator;

    if pbTabsPopup in VisibleButtons then
    begin
      PaintTabsPopupBtn(TabsPopupBtnRect, TabsPopupBtnState);
    end;

    if (pbClose in VisibleButtons)
      and (CloseButtonLocation = cbBeside) then
    begin
      PaintCloseButton(CloseButtonRect, CloseButtonState);
    end;
  end;
end;

procedure TNxPageControl6.PaintCloseButton(ButtonRect: TRect;
  ButtonState: TNxButtonState);

var
  ShapeRect: TRect;
begin
  with Canvas do
  begin
    Painter.PaintButton(ButtonRect, ButtonState);

    ShapeRect := CenteredRect(ButtonRect, Bounds(0, 0, 10, 10));
    DrawCloseSign(Canvas, ShapeRect.Left, ShapeRect.Top);
  end;
end;

procedure TNxPageControl6.PaintTab(TabRect: TRect;
  PageSheet: TNxPageSheet6; State: TNxButtonState);
var
  CaptionRect, ButtonRect: TRect;
  X, Y: Integer;
begin
  with Canvas do
  begin
    CaptionRect := TabRect;
    Inc(CaptionRect.Left, TabPadding.Left);
    Dec(CaptionRect.Right, TabPadding.Right);

    { User specified colors }
    Brush.Color := clNone;
    if not StyleColors then Brush.Color := PageSheet.TabColor;
    if bsSelected in State then Brush.Color := ActiveTabColor;

    { Fill Tab's Background }
    PaintTabBackground(PageSheet, TabRect, State);

    { Icon }
    if Assigned(Images) and ShowImages
      and InRange(PageSheet.ImageIndex, 0, Pred(Images.Count)) then
    begin
      X := CaptionRect.Left;
      Y := TabRect.Top;
      Inc(Y, RectHeight(CaptionRect) div 2 - Images.Height div 2);
      Images.Draw(Canvas, X, Y, PageSheet.ImageIndex);
      Inc(CaptionRect.Left, Images.Width);
      Inc(CaptionRect.Left, pdTextToIcon);
    end;

    if pbClose in VisibleButtons then
      if CloseButtonLocation = cbTab then
      begin
        ButtonRect := Bounds(CaptionRect.Right - ButtonSize.cx, CaptionRect.Top,
          ButtonSize.cx, ButtonSize.cy);

        OffsetRect(ButtonRect, 0, Round(RectHeight(TabRect) / 2 - RectHeight(ButtonRect) / 2));

        if (bsSelected in State) or (bsHover in State) then
        begin
          if bsSelected in State then
            Include(FCloseButtonState, bsSelected);

          PaintCloseButton(ButtonRect, CloseButtonState);
        end;
        Dec(CaptionRect.Right, ButtonSize.cx);
      end;

    { Caption }
    Font.Assign(PageSheet.TabFont);
    AdjustTabFont(Font, PageSheet);

    if not (bsSelected in State) then
    begin
      if StyleColors then
      begin
        Font.Color := Painter.TabTextColor;
      end;
    end else
    begin
      if StyleColors then
      begin

      end
      else Font.Color := ActiveTabTextColor;
    end;

    if bsDisabled in State then Font.Color := clGrayText;

    DrawTextRect(Canvas, CaptionRect, taLeftJustify, taVerticalCenter,
      PageCaption[PageSheet.Index], wkEllipsis);

    { Paint focus indicator }
    if Focused
      and (bsSelected in State) then
    begin
      DrawFocusRect(TabRect);
    end;

  end;
end;

procedure TNxPageControl6.PaintTabBackground(PageSheet: TNxPageSheet6; TabRect: TRect;
  State: TNxButtonState);
var
  OwnerDraw: Boolean;
begin
  OwnerDraw := False;
  DoDrawTabBackground(PageSheet, Canvas, TabRect, State, OwnerDraw);
  if not OwnerDraw then Painter.PaintTab(TabRect, State);
end;

procedure TNxPageControl6.PaintTabs;
var
  i, X, Y, First: Integer;
  TabRect: TRect;
  TabSize: TSize;
  TabState: TNxButtonState;
begin
  First := 0;
  X := TabsRect.Left;
  Y := TabsRect.Top;

  if PreciseScrolling then
  begin
    Dec(X, FPosition);
  end else First := FPosition;

  for i := First to Pred(Count) do
    if Page[i].TabVisible then
    begin
      TabSize := GetPageTabSize(i);
      TabRect := Bounds(X, Y, TabSize.cx, TabSize.cy);

      TabState := [];
      if not Page[i].TabEnabled then Include(TabState, bsDisabled);
      if Page[i] = ActivePage then Include(TabState, bsSelected);
      if Page[i] = HotPageTab then Include(TabState, bsHover);
      if Page[i] = PressedPageTab then Include(TabState, bsPressed);

      PaintTab(TabRect, Page[i], TabState);

      case TabsLocation of
        tbLeft, tbRight:
        begin
          Inc(Y, TabSize.cy);
          Inc(Y, TabsSpacing);
        end;
        else
        begin
          Inc(X, TabSize.cx);
          Inc(X, TabsSpacing);
        end;
      end;
    end;
end;

procedure TNxPageControl6.PaintTabsBackground(BackgroundRect: TRect);
begin
  Painter.PaintTabsBackground(BackgroundRect);
end;

procedure TNxPageControl6.PaintTabsPopupBtn(BtnRect: TRect;
  BtnState: TNxButtonState);
var
  X, Y: Integer;
begin
  with Canvas do
  begin
    FStylePainter.PaintButton(BtnRect, BtnState);
    X := BtnRect.Left + RectWidth(BtnRect) div 2 - 4;
    Y := BtnRect.Top + RectHeight(BtnRect) div 2 - 3;
    Polygon([
      Point(X, Y),
      Point(X + 4, Y + 4),
      Point(X + 8, Y)
    ]);
  end;
end;

procedure TNxPageControl6.PaintTabsSeparator;
var
  SeparatorRect: TRect;
begin
  case TabsLocation of
    tbTop: SeparatorRect := Bounds(0, TabsRect.Bottom, ClientWidth, SeparatorSize);
    tbLeft: SeparatorRect := Bounds(TabsRect.Right, 0, SeparatorSize, ClientHeight);
    tbRight: SeparatorRect := Bounds(TabsRect.Left - SeparatorSize, 0, SeparatorSize, ClientHeight);
    tbBottom: SeparatorRect := Bounds(0, TabsRect.Top - SeparatorSize, ClientWidth, SeparatorSize);
  end;
  Painter.PaintTabsSeparator(SeparatorRect);
end;

procedure TNxPageControl6.RefreshPageTab(PageSheet: TNxPageSheet6);
var
  TabRect: TRect;
begin
  TabRect := GetTabRect(PageSheet);
  InvalidateRect(TabRect);
end;

procedure TNxPageControl6.ScrollToTab(const PageSheet: TNxPageSheet6);
var
  TabRect: TRect;
begin
  TabRect := Self.GetTabRect(PageSheet);

  if (TabRect.Left < TabsRect.Left) or
    (TabRect.Right > TabsRect.Right) then
  begin

    if PreciseScrolling then
    begin


      if TabRect.Left < TabsRect.Left
        then Dec(FPosition, TabsRect.Left - TabRect.Left)
          else Inc(FPosition, TabRect.Right - TabsRect.Right);

    end else
    begin

    end;

{$IFDEF BETA_VER}
    WritelnDebug(IntToStr(FPosition));
{$ENDIF}

    Invalidate;
  end;
end;

procedure TNxPageControl6.ScrollToTab(const Index: Integer);
begin
  ScrollToTab(Page[Index]);
end;

procedure TNxPageControl6.SetActiveTabColor(const Value: TColor);
begin
  if Value <> FActiveTabColor then
  begin
    FActiveTabColor := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetActiveTabTextColor(const Value: TColor);
begin
  if Value <> FActiveTabTextColor then
  begin
    FActiveTabTextColor := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetButtons(const Value: TNxPageControlButtons);
begin
  if Value <> FButtons then
  begin
    FButtons := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetCloseButtonLocation(
  const Value: TNxCloseButtonLocation);
begin
  if Value <> FCloseButtonLocation then
  begin
    FCloseButtonLocation := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetCloseButtonState(const Value: TNxButtonState);
const
  HintTag = 'CloseButton';
var
  BtnRect: TRect;
  HintLocation: TPoint;
begin
  if FCloseButtonState <> Value then
  begin
    FCloseButtonState := Value;

    case CloseButtonLocation of
      cbBeside: BtnRect := CloseButtonRect;
      cbTab: if Assigned(HotPageTab)
              then BtnRect := GetTabCloseButtonRect(HotPageTab) else Exit;
    end;

    InvalidateRect(BtnRect);
    HintLocation := Point(BtnRect.Right, BtnRect.Bottom);
    if bsHover in Value then
      ActivateHint(HintLocation, CloseButtonHint, HintTag)
    else
      DeactivateHint(HintTag);
  end;
end;

procedure TNxPageControl6.SetDefaultCaption(const Value: WideString);
begin
  if Value <> FDefaultCaption then
  begin
    FDefaultCaption := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetHotPageTab(const Value: TNxPageSheet6);
var
  T: TNxPageSheet6;
begin
  if Value <> FHotPageTab then
  begin
    CloseButtonState := [];
    T := FHotPageTab;
    if Assigned(T) then RefreshPageTab(T);

    if Assigned(Value)
      and Value.TabEnabled then
    begin
      FHotPageTab := Value;
      RefreshPageTab(FHotPageTab);
    end
    else FHotPageTab := nil;
  end;
end;

procedure TNxPageControl6.SetImages(const Value: TImageList);
begin
  if Value <> FImages then
  begin
    if Assigned(FImages) then FImages.RemoveFreeNotification(Self);
    FImages := Value;
    if Assigned(FImages) then FImages.FreeNotification(Self);
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetMoving(const Value: Boolean);
begin
  if Value <> FMoving then
  begin
    FMoving := Value;
    if FMoving then Screen.Cursor := crDrag
      else Screen.Cursor := crDefault;
    { Event }
    if not FMoving then
      if Assigned(FOnAfterTabMoving) then FOnAfterTabMoving(Self);
  end;
end;

procedure TNxPageControl6.SetOptions(const Value: TNxPageControlOptions);
begin
  if Value <> FOptions then
  begin
    FOptions := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetParentTabFont(const Value: Boolean);
begin
  FParentTabFont := Value;
  if FParentTabFont then
  begin
    FTabFont.Assign(Font);
    FTabFont.OnChange := DoTabFontChange;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetPreciseScrolling(const Value: Boolean);
begin
  if Value <> FPreciseScrolling then
  begin
    FPreciseScrolling := Value;
    FPosition := 0;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetPressedPageTab(const Value: TNxPageSheet6);
var
  T: TNxPageSheet6;
begin
  if Value <> FPressedPageTab then
  begin
    T := FPressedPageTab;
    if Assigned(T) then RefreshPageTab(T);

    if not Assigned(Value)
      or Value.TabEnabled then
    begin
      FPressedPageTab := Value;
      if Assigned(FPressedPageTab) then RefreshPageTab(FPressedPageTab);
    end;
  end;
end;

procedure TNxPageControl6.SetStyleColors(const Value: Boolean);
begin
  if Value <> FStyleColors then
  begin
    FStyleColors := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetSeparatorSize(const Value: Integer);
begin
  if Value <> FSeparatorSize then
  begin
    FSeparatorSize := Value;
    Realign;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetShowImages(const Value: Boolean);
begin
  if Value <> FShowImages then
  begin
    FShowImages := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetShowTabs(const Value: Boolean);
begin
  if Value <> FShowTabs then
  begin
    FShowTabs := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetStyle(const Value: TNxAppearanceStyle);
begin
  if Value <> FStyle then
  begin
    FStyle := Value;

    { Destroy old Painter }
    FreeAndNil(FStylePainter);

    { Create & set Painter }
    FStylePainter := CreateStylePainter(FStyle);

    Invalidate;
  end;
end;

procedure TNxPageControl6.SetTabFont(const Value: TFont);
begin
  FTabFont.Assign(Value);
  FTabFont.OnChange := DoTabFontChange;
  FParentTabFont := False;
  Invalidate;
end;

procedure TNxPageControl6.SetTabPadding(const Value: TPadding);
begin
  if (Value <> FTabPadding)
    and Assigned(Value) then
  begin
    FTabPadding.Assign(Value);
    FTabPadding.OnChange := DoTabsChange;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetTabsBackgroundColor(const Value: TColor);
begin
  if Value <> FTabsBackgroundColor then
  begin
    FTabsBackgroundColor := Value;
    InvalidateRect(TabsBackgroundRect);
  end;
end;

procedure TNxPageControl6.SetTabsBtnPopupState(const Value: TNxButtonState);
begin
  if Value <> FTabsPopupBtnState then
  begin
    FTabsPopupBtnState := Value;
    InvalidateRect(TabsPopupBtnRect);
  end;
end;

procedure TNxPageControl6.SetTabsHeight(const Value: Integer);
begin
  if Value <> FTabsHeight then
  begin
    FTabsHeight := Value;
    Realign;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetTabsLocation(const Value: TNxTabsLocation);
begin
  if Value <> FTabsLocation then
  begin
    FTabsLocation := Value;
    FPosition := 0;
    Realign;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetTabsPadding(const Value: TPadding);
begin
  if (Value <> FTabsPadding)
    and Assigned(Value) then
  begin
    FTabsPadding.Assign(Value);
    FTabsPadding.OnChange := DoTabsChange;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetTabsSpacing(const Value: Integer);
begin
  if Value <> FTabsSpacing then
  begin
    FTabsSpacing := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetTabsWidth(const Value: Integer);
begin
  if Value <> FTabsWidth then
  begin
    FTabsWidth := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.SetTabWidth(const Value: Integer);
begin
  if (Value <> FTabWidth) and (Value > 0) then
  begin
    FTabWidth := Value;
    Invalidate;
  end;
end;

procedure TNxPageControl6.ShowTabsPopup;
var
  i: Integer;
  PopupPoint: TPoint;
  MenuItem: TMenuItem;
begin
  { Popup Point }
  with TabsPopupBtnRect
    do PopupPoint := ClientToScreen(Point(Left, Bottom));

  FTabsPopup := TPopupMenu.Create(Self);

  { Set Images }
  FTabsPopup.Items.Clear;
  FTabsPopup.Images := FImages;

  { Add Items }
  for i := 0 to Pred(Count) do
    if Page[i].TabVisible then
    begin
      MenuItem := TMenuItem.Create(FTabsPopup);
      MenuItem.Caption := PageCaption[i];
      MenuItem.OnClick := DoPopupTabClick;
      MenuItem.Tag := i;
      MenuItem.ImageIndex := Page[i].ImageIndex;
      FTabsPopup.Items.Add(MenuItem);
    end;

  { Popup }
  FTabsPopup.Popup(PopupPoint.X, PopupPoint.Y);
end;

procedure TNxPageControl6.ValidateInsert(AComponent: TComponent);
begin
  inherited;
  if AComponent is TNxPageSheet6 then
    TNxPageSheet6(AComponent).OnTabChange := Self.DoTabChange;
end;

procedure TNxPageControl6.WMGetDlgCode(var Message: TWMGetDlgCode);
begin
  inherited;
  Message.Result := Message.Result or DLGC_WANTCHARS or DLGC_WANTARROWS;
end;

procedure TNxPageControl6.WMKillFocus(var Message: TWMSetFocus);
begin
  inherited;
  if Assigned(ActivePage) then RefreshPageTab(ActivePage as TNxPageSheet6);
end;

procedure TNxPageControl6.WMSetFocus(var Message: TWMSetFocus);
begin
  inherited;
  if Assigned(ActivePage) then RefreshPageTab(ActivePage as TNxPageSheet6);
end;

procedure TNxPageControl6.WMSize(var Message: TWMSize);
var
  InvalidationSize: TSize;
  InvalidationRect: TRect;
begin
  InvalidationSize.cx := ClientWidth - FOldWidth;
  InvalidationSize.cy := ClientHeight - FOldHeight;

  { Horizontal }

  if InvalidationSize.cx <> 0 then
  begin
    case TabsLocation of
      tbTop, tbBottom:
      begin
        InvalidationRect := Bounds(TabsRect.Right - InvalidationSize.cx, TabsRect.Top,
          InvalidationSize.cx, RectHeight(TabsRect));

        InvalidateRect(InvalidationRect);

        { Buttons }
        if HasSideButtons then
        begin
          InvalidationRect.Left := InvalidationRect.Right;
          InvalidationRect.Right := ClientWidth;
          InvalidateRect(InvalidationRect);
        end;
      end;
      tbRight: InvalidateRect(TabsNCRect);
    end;
  end;

  { Vertical }

  if InvalidationSize.cy <> 0 then
  begin
    case TabsLocation of
      tbTop: ;
      else InvalidateRect(TabsNCRect);
    end;
  end;

  { Calc. Delta }
  FOldWidth := ClientWidth;
  FOldHeight := ClientHeight;

  inherited;

  { Update }

end;

{ TNxPageControlStylePainter }

constructor TNxPageControlStylePainter.Create(PageControl: TNxPageControl6);
begin
  FPageControl := PageControl;
end;

function TNxPageControlStylePainter.GetCanvas: TCanvas;
begin
  Result := FPageControl.Canvas;
end;

function TNxPageControlStylePainter.GetTabsBackgroundColor: TColor;
begin
  Result := FPageControl.FTabsBackgroundColor;
end;

function TNxPageControlStylePainter.GetTabTextColor: TColor;
begin
  Result := Canvas.Font.Color;
end;

procedure TNxPageControlStylePainter.PaintTabsBackground(BackgroundRect: TRect);
begin
  with Canvas do
  begin
    Brush.Color := TabsBackgroundColor;
    FillRect(BackgroundRect);
  end;
end;

{ TNxModernPageControlStylePainter }

function TNxModernPageControlStylePainter.GetTabsBackgroundColor: TColor;
begin
  Result := ColorOf(seAppWorkSpace);
end;

function TNxModernPageControlStylePainter.GetTabTextColor: TColor;
begin
  Result := ColorOf(seTabText);
end;

procedure TNxModernPageControlStylePainter.PaintButton(ButtonRect: TRect;
  State: TNxButtonState);
begin
  with FPageControl.Canvas do
  begin
    if bsHover in State then
    begin
      Brush.Color := ColorOf(seTabBtnFace);
      Pen.Color := ColorOf(seBtnFrame);

      if bsPressed in State then
      begin
        Brush.Color := ColorOf(seBtnFace);
        Pen.Color := ColorOf(seBtnFrame);
      end;
      Rectangle(ButtonRect);
    end;

    Pen.Color := clBlack;
    if not (bsSelected in State)
      and not (bsHover in State) then
    begin
      Pen.Color := ColorOf(seTabText);
    end;
    Brush.Color := Pen.Color;
  end;
end;

procedure TNxModernPageControlStylePainter.PaintTab(TabRect: TRect;
  State: TNxButtonState);
begin
  with FPageControl.Canvas do
  begin
    if FPageControl.StyleColors then
    begin
      Brush.Color := ColorOf(seTabFace);
      if bsHover in State then Brush.Color := ColorOf(seTabFaceHot);
      if bsPressed in State then Brush.Color := ColorOf(seBtnFacePressed);
      if bsSelected in State then Brush.Color := ColorOf(seBtnFaceChecked);
    end;
    FillRect(TabRect);
  end;
end;

procedure TNxModernPageControlStylePainter.PaintTabsSeparator(
  SeparatorRect: TRect);
begin
  with Canvas do
  begin
    Brush.Color := ColorOf(seBtnFaceChecked);
    FillRect(SeparatorRect);
  end;
end;

{ TNxNativePageControlStylePainter }

function TNxNativePageControlStylePainter.GetTabsBackgroundColor: TColor;
begin
  Result := FPageControl.Color;
end;

procedure TNxNativePageControlStylePainter.PaintButton(ButtonRect: TRect;
  State: TNxButtonState);
begin
  TNxPageControlStyle6.PaintButton(Canvas, FPageControl.Handle, ButtonRect,
    State, FPageControl.StyleOptions);
  with Canvas do
  begin
    Pen.Color := clBlack;
    Brush.Color := clBlack;
  end;
end;

procedure TNxNativePageControlStylePainter.PaintTab(TabRect: TRect;
  State: TNxButtonState);
begin
  TNxPageControlStyle6.PaintTab(Canvas, FPageControl.Handle,
    TabRect, State, FPageControl.StyleOptions, FPageControl.TabsLocation);
end;

procedure TNxNativePageControlStylePainter.PaintTabsBackground(BackgroundRect: TRect);
begin
  TNxPageControlStyle6.PaintBackground(Canvas, FPageControl.Handle, BackgroundRect, FPageControl.StyleOptions);
end;

procedure TNxNativePageControlStylePainter.PaintTabsSeparator(
  SeparatorRect: TRect);
begin
  with Canvas do
  begin
    Frame3D(Canvas, SeparatorRect, clBtnHighlight, clBtnShadow, 1);
    Brush.Color := TabsBackgroundColor;
  end;
end;

{ TNxUserDefinedPageControlStylePainter }

procedure TNxUserDefinedPageControlStylePainter.PaintButton(ButtonRect: TRect; State: TNxButtonState);
begin
  with Canvas do
  begin
    if bsHover in State then
    begin
      Brush.Color := FPageControl.ActiveTabColor;
      FillRect(ButtonRect);
    end;
    Pen.Color := clBlack;
    Brush.Color := clBlack;
  end;
end;

procedure TNxUserDefinedPageControlStylePainter.PaintTab(TabRect: TRect; State: TNxButtonState);
begin
  with Canvas do
  begin
    if bsSelected in State then Brush.Color := FPageControl.ActiveTabColor;
    if Brush.Color <> clNone then FillRect(TabRect);
  end;
end;

procedure TNxUserDefinedPageControlStylePainter.PaintTabsSeparator(SeparatorRect: TRect);
begin
  with Canvas do
  begin
    Brush.Color := FPageControl.ActiveTabColor;
    FillRect(SeparatorRect);
  end;
end;

end.
