{********************************************************************}
{                                                                    }
{ written by TMS Software                                            }
{            copyright © 2013                                        }
{            Email : info@tmssoftware.com                            }
{            Web : http://www.tmssoftware.com                        }
{                                                                    }
{ The source code is given as is. The author is not responsible      }
{ for any possible damage done due to the use of this code.          }
{ The complete source code remains property of the author and may    }
{ not be distributed, published, given or sold in any form as such.  }
{ No parts of the source code can be included in any other component }
{ or application without written authorization of the author.        }
{********************************************************************}

unit FMX.TMSNavBar;

interface

{$I TMSDEFS.INC}

uses
  SysUtils, Classes, FMX.Types, FMX.Controls, FMX.Objects, Types, Math,
  UITypes, FMX.TMSBaseControl, FMX.TMSBitmapContainer, FMX.TMSHTMLText, FMX.TMSBitmap
  , FMX.StdCtrls, UIConsts, FMX.Styles,Generics.Collections
  {$IFDEF DELPHIXE5_LVL}
  , FMX.Graphics
  {$ENDIF}
  ;

const
  MAJ_VER = 1; // Major version nr.
  MIN_VER = 5; // Minor version nr.
  REL_VER = 0; // Release nr.
  BLD_VER = 0; // Build nr.

  //v1.0.0.1 : Fixed: Issue with autosizing and client-aligned captions
  //v1.0.0.2 : Fixed: Issue with list read access
  //v1.0.0.3 : Fixed: Issue with Tab minimum height
  //v1.5.0.0 : New : support for XE4
  //v1.5.0.1 : Fixed : Memory leak with panel list

  DEFAULT_TABHEIGHT = 35;
  DEFAULT_TABBUTTONHEIGHT = 30;
  DEFAULT_TABBUTTONWIDTH = 18;
  DEFAULT_SPLITTERHEIGHT = 7;
  DEFAULT_SECCAPTIONHEIGHT = 16;

type
  TTMSFMXNavBar = class;
  TTMSFMXNavBarPanel = class;
  TTMSFMXNavBarTabShape = class;
  TTMSFMXNavBarTabButtonShape = class;
  TTMSFMXNavBarPanelSectionShape = class;

  TTMSFMXNavBarButtonShape = class(TRectangle)
  private
    FNavBarPanel: TTMSFMXNavBarPanel;
    FFillDown: TBrush;
    FStrokeDown: TBrush;
    FStrokeHot: TBrush;
    FFillHot: TBrush;
    procedure SetFillDown(const Value: TBrush);
    procedure SetStrokeDown(const Value: TBrush);
    function GetIsHot: Boolean;
    procedure SetFillHot(const Value: TBrush);
    procedure SetStrokeHot(const Value: TBrush);
  protected
    procedure DoMouseEnter; override;
    procedure DoMouseLeave; override;
    procedure Click; override;
    function ShapeImage: TTMSFMXBitmap;
    property IsHot: Boolean read GetIsHot;
    property NavBarPanel: TTMSFMXNavBarPanel read FNavBarPanel write FNavBarPanel;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Paint; override;
  published
    property StrokeDown: TBrush read FStrokeDown write SetStrokeDown;
    property FillDown: TBrush read FFillDown write SetFillDown;
    property StrokeHot: TBrush read FStrokeHot write SetStrokeHot;
    property FillHot: TBrush read FFillHot write SetFillHot;
    property Fill;
    property Stroke;
    property StrokeThickness;
    property StrokeCap;
    property StrokeDash;
    property StrokeJoin;
  end;

  TNavBarScroller = class(TObject)
  private
    FMin: integer;
    FMax: integer;
    FPosition: integer;
    FVisible: Boolean;
    procedure SetMax(const Value: integer);
    procedure SetMin(const Value: integer);
    procedure SetPosition(const Value: integer);
    procedure SetVisible(const Value: Boolean);
  public
    constructor Create;
    function CanGoForward: Boolean;
    function CanGoBack: Boolean;
    property Min: integer read FMin write SetMin;
    property Max: integer read FMax write SetMax;
    property Position: integer read FPosition write SetPosition;
    property Visible: Boolean read FVisible write SetVisible;
  end;

  TTMSFMXNavBarPanelSection = class(TCollectionItem)
  private
    FHeight: Integer;
    FCaption: string;
    FTag: Integer;
    FControl: TControl;
    FSectionShape: TTMSFMXNavBarPanelSectionShape;
    procedure SetCaption(const Value: string);
    procedure SetHeight(const Value: Integer);
    procedure SetControl(const Value: TControl);
  protected
    function GetOwnerPanel: TTMSFMXNavBarPanel;
    procedure UpdateCaption;
    procedure UpdateControlBounds;
    property SectionShape: TTMSFMXNavBarPanelSectionShape read FSectionShape write FSectionShape;
  public
    constructor Create(Collection: TCollection); override;
    destructor Destroy; override;
    procedure Assign(Source: TPersistent); override;
  published
    property Caption: string read FCaption write SetCaption;
    property Control:TControl read FControl write SetControl;
    property Height: Integer read FHeight write SetHeight default 48;
    property Tag: Integer read FTag write FTag default 0;
  end;

  TTMSFMXNavBarPanelSections = class(TTMSFMXBaseCollection)
  private
    FOwner: TTMSFMXNavBarPanel;
    function GetItem(Index: Integer): TTMSFMXNavBarPanelSection;
    procedure SetItem(Index: Integer; const Value: TTMSFMXNavBarPanelSection);
  protected
    function GetOwner: TPersistent; override;
  public
    constructor Create(AOwner: TTMSFMXNavBarPanel);
    function Add: TTMSFMXNavBarPanelSection;
    function Insert(Index: Integer): TTMSFMXNavBarPanelSection;
    property Items[Index: Integer]: TTMSFMXNavBarPanelSection read GetItem write SetItem; default;
  end;

  TTMSFMXNavBarPanelSectionShape = class(TRoundRect)
  private
    FNavBarPanel: TTMSFMXNavBarPanel;
  protected
    function ShapeCaption: TTMSFMXHTMLText;
    property NavBarPanel: TTMSFMXNavBarPanel read FNavBarPanel write FNavBarPanel;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Paint; override;
  published
    property Fill;
    property Stroke;
    property StrokeThickness;
  end;

  TTMSFMXNavBarPanel = class(TPanel)
  private
    FUpdatingParent: Boolean;
    FNavBar: TTMSFMXNavBar;
    FCaption: string;
    FTab: TTMSFMXNavBarTabShape;
    FSections: TTMSFMXNavBarPanelSections;
    FInternalBoundSet: Boolean;
    FTabButton: TTMSFMXNavBarTabButtonShape;
    FBitmap: TBitmap;
    FBitmapName: String;
    FSmallBitmapName: String;
    FPanelIndex: Integer;
    procedure SetCaption(const Value: string);
    procedure SetNavBar(const Value: TTMSFMXNavBar);
    procedure SetSections(const Value: TTMSFMXNavBarPanelSections);
    function GetIsSelected: Boolean;
    procedure SetBitmap(const Value: TBitmap);
    procedure SetBitmapName(const Value: String);
    procedure BitmapChanged(Sender: TObject);
    procedure SetSmallBitmapName(const Value: String);
    function GetPanelIndex: Integer;
    procedure SetPanelIndex(const Value: Integer);
  protected
    procedure ApplyStyle; override;
    procedure SetParentComponent(Value: TComponent); override;
    procedure ReadState(Reader: TReader); override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure SetVisible(const Value: Boolean); override;
    function ShapeLeftRectangleImage: TTMSFMXBitmap;
    function ShapeLeftRectangle: TRectangle;
    function TabButtonShapeImage: TTMSFMXBitmap;
    function ShapeCaption: TText;
    procedure AssignBitmapContainer;
    procedure UpdateBitmap;
    procedure UpdateCaption;
    procedure UpdateAllSections;
    procedure UpdateSectionsPos;
    procedure UpdateControlBounds;
    procedure SetSelected;
    procedure CloneChildren(Source, Destination: TFMXObject);
    function IsSection(AObject: TFmxObject): Boolean;
    function AsSection(AObject: TFmxObject): TTMSFMXNavBarPanelSectionShape;
    function DoesSectionExist(ParentElement: TControl; SecName: String): TTMSFMXNavBarPanelSectionShape;
    procedure AddSection(ASection: TTMSFMXNavBarPanelSection); overload;
    procedure AddSection(ASection: TTMSFMXNavBarPanelSection; SecElement, ParentElement: TControl); overload;
    procedure ClearSections(ParentElement: TControl);
    function IsVisible: Boolean;
    function GetSectionShape(Section: TTMSFMXNavBarPanelSection): TTMSFMXNavBarPanelSectionShape;
    property Tab: TTMSFMXNavBarTabShape read FTab write FTab;
    property TabButton: TTMSFMXNavBarTabButtonShape read FTabButton write FTabButton;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure SetBounds(X, Y, AWidth, AHeight: Single); override;
    property NavBar: TTMSFMXNavBar read FNavBar write SetNavBar;
    property IsSelected: Boolean read GetIsSelected;
  published
    property Caption: string read FCaption write SetCaption;
    property BitmapName: String read FBitmapName write SetBitmapName;
    property SmallBitmapName: String read FSmallBitmapName write SetSmallBitmapName;
    property Sections: TTMSFMXNavBarPanelSections read FSections write SetSections;
    property Bitmap: TBitmap read FBitmap write SetBitmap;
    property PanelIndex: Integer read GetPanelIndex write SetPanelIndex;
  end;

  TSizeGripStyle = (gsNone, gsDots);

  TTMSFMXNavBarSplitterShape = class(TRectangle)
  private
    FNavBar: TTMSFMXNavBar;
    FFillHot: TBrush;
    FStrokeHot: TBrush;
    FDownPos: TPointF;
    FMovePos: TPointF;
    FOldSplitterPos: Integer;
    FDefTabHeight: Integer;
    FSizeGrip: TSizeGripStyle;
    FSizeGripColor: TAlphaColor;
    procedure SetFillHot(const Value: TBrush);
    procedure SetStrokeHot(const Value: TBrush);
    function GetIsHot: Boolean;
    procedure SetSizeGrip(const Value: TSizeGripStyle);
    procedure SetSizeGripColor(const Value: TAlphaColor);
  protected
    procedure DoMouseEnter; override;
    procedure DoMouseLeave; override;
    procedure Click; override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Single); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Single); override;
    property NavBar: TTMSFMXNavBar read FNavBar write FNavBar;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Paint; override;
    property IsHot: Boolean read GetIsHot;
  published
    property SizeGrip: TSizeGripStyle read FSizeGrip write SetSizeGrip default gsDots;
    property SizeGripColor: TAlphaColor read FSizeGripColor write SetSizeGripColor default claBlack;
    property StrokeHot: TBrush read FStrokeHot write SetStrokeHot;
    property FillHot: TBrush read FFillHot write SetFillHot;
    property Fill;
    property Stroke;
    property StrokeThickness;
    property StrokeCap;
    property StrokeDash;
    property StrokeJoin;
  end;

  TTMSFMXNavBarTabShape = class(TRectangle)
  private
    FNavBarPanel: TTMSFMXNavBarPanel;
    FFillSelected: TBrush;
    FStrokeSelected: TBrush;
    FStrokeHot: TBrush;
    FFillHot: TBrush;
    procedure SetFillSelected(const Value: TBrush);
    procedure SetStrokeSelected(const Value: TBrush);
    function GetIsHot: Boolean;
    procedure SetFillHot(const Value: TBrush);
    procedure SetStrokeHot(const Value: TBrush);
    function GetIsSelected: Boolean;
  protected
    procedure DoMouseEnter; override;
    procedure DoMouseLeave; override;
    procedure Click; override;
    function ShapeLeftRectangle: TRectangle;
    function ShapeLeftRectangleImage: TTMSFMXBitmap;
    property IsHot: Boolean read GetIsHot;
    property NavBarPanel: TTMSFMXNavBarPanel read FNavBarPanel write FNavBarPanel;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Paint; override;
    function ShapeCaption: TText;
    property IsSelected: Boolean read GetIsSelected;
  published
    property StrokeSelected: TBrush read FStrokeSelected write SetStrokeSelected;
    property FillSelected: TBrush read FFillSelected write SetFillSelected;
    property StrokeHot: TBrush read FStrokeHot write SetStrokeHot;
    property FillHot: TBrush read FFillHot write SetFillHot;
    property Fill;
    property Stroke;
    property StrokeThickness;
    property StrokeCap;
    property StrokeDash;
    property StrokeJoin;
  end;

  TTMSFMXNavBarTabButtonShape = class(TRectangle)
  private
    FNavBarPanel: TTMSFMXNavBarPanel;
    FFillSelected: TBrush;
    FStrokeSelected: TBrush;
    FStrokeHot: TBrush;
    FFillHot: TBrush;
    procedure SetFillSelected(const Value: TBrush);
    procedure SetStrokeSelected(const Value: TBrush);
    function GetIsHot: Boolean;
    procedure SetFillHot(const Value: TBrush);
    procedure SetStrokeHot(const Value: TBrush);
    function GetIsSelected: Boolean;
  protected
    procedure DoMouseEnter; override;
    procedure DoMouseLeave; override;
    procedure Click; override;
    function ShapeImage: TTMSFMXBitmap;
    property IsHot: Boolean read GetIsHot;
    property NavBarPanel: TTMSFMXNavBarPanel read FNavBarPanel write FNavBarPanel;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Paint; override;
    property IsSelected: Boolean read GetIsSelected;
  published
    property StrokeSelected: TBrush read FStrokeSelected write SetStrokeSelected;
    property FillSelected: TBrush read FFillSelected write SetFillSelected;
    property StrokeHot: TBrush read FStrokeHot write SetStrokeHot;
    property FillHot: TBrush read FFillHot write SetFillHot;
    property Fill;
    property Stroke;
    property StrokeThickness;
    property StrokeCap;
    property StrokeDash;
    property StrokeJoin;
  end;

  TPanelActivate = procedure(Sender: TObject; OldActivePanel: Integer; NewActivePanel: Integer; var Allow: Boolean) of object;

  TPanelList = TList<TTMSFMXNavBarPanel>;

  [ComponentPlatformsAttribute(TMSPlatforms)]
  TTMSFMXNavBar = class(TTMSFMXBaseControl)
  private
    FPanels: TPanelList;
    FUpdateCount: Integer;
    FBitmapContainer: TTMSFMXBitmapContainer;
    FActiveTabIndex: Integer;
    FInternalCall: Boolean;
    FOnPanelActivate: TPanelActivate;
    FOnChange: TNotifyEvent;
    FMinPanelHeight: Integer;
    FSplitterPosition: integer;
    FCaptionVisible: Boolean;
    FShowSplitter: Boolean;
    FTabButtonScroller: TNavBarScroller;
    FDefaultCaption: string;
    procedure OnContainerResize(Sender: TObject);
    function GetVersion: String;
    function GetVersionNr: Integer;
    procedure SetVersion(const Value: String);
    function GetPanel(Index: Integer): TTMSFMXNavBarPanel;
    function GetPanelCount: Integer;
    function GetActivePanel: TTMSFMXNavBarPanel;
    procedure SetActivePanel(const Value: TTMSFMXNavBarPanel);
    function GetActiveTabIndex: integer;
    procedure SetActiveTabIndex(const Value: integer);
    procedure SetMinPanelHeight(const Value: Integer);
    procedure SetSplitterPosition(const Value: integer);
    procedure SetCaptionVisible(const Value: Boolean);
    procedure SetShowSplitter(const Value: Boolean);
    procedure ScrollLeftBtnClick(Sender: TObject);
    procedure ScrollRightBtnClick(Sender: TObject);
    procedure AssignEvents;
    procedure SetBitmapContainer(const Value: TTMSFMXBitmapContainer);
    procedure SetDefaultCaption(const Value: string);
    procedure UpdatePanelIndex;
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    function GetInstance: NativeUInt; override;
    procedure ApplyStyle; override;
    function IsTab(AObject: TFmxObject): Boolean;
    function AsTab(AObject: TFmxObject): TTMSFMXNavBarTabShape;
    function DoesTabExist(ParentElement: TControl; TabName: String): TTMSFMXNavBarTabShape;
    function IsTabButton(AObject: TFmxObject): Boolean;
    function AsTabButton(AObject: TFmxObject): TTMSFMXNavBarTabButtonShape;
    function DoesTabButtonExist(ParentElement: TControl; TabButtonName: String): TTMSFMXNavBarTabButtonShape;
    procedure CloneChildren(Source, Destination: TFMXObject);
    function CanClone(Source: TFMXObject): Boolean;
    procedure AddTab(APanel: TTMSFMXNavBarPanel); overload;
    procedure AddTab(APanel: TTMSFMXNavBarPanel; TabElement, ParentElement: TControl); overload;
    procedure ClearTabs(ParentElement: TControl);
    procedure AddTabButton(APanel: TTMSFMXNavBarPanel); overload;
    procedure AddTabButton(APanel: TTMSFMXNavBarPanel; TabButtonElement, ParentElement: TControl); overload;
    procedure ClearTabButtons(ParentElement: TControl);
    function GetContainer: TControl;
    function GetDefaultTabShape: TControl;
    function GetDefaultTabButtonShape: TControl;
    function GetDefaultSectionShape: TControl;
    function GetSplitter: TControl;
    function GetHeader: TControl;
    function GetHeaderText: TText;
    function GetFooter: TControl;
    function GetRightScrollButton: TTMSFMXNavBarButtonShape;
    function GetLeftScrollButton: TTMSFMXNavBarButtonShape;
    function GetPanelRect: TRectF;
    function GetSplitterRect: TRectF;
    function GetTabHeight: Integer;
    function GetContainerRect: TRectF;
    function GetVisiblePanelCount: Integer;
    procedure UpdateSplitterPosCount;
    procedure UpdateCaption;
    procedure UpdateAllTabs;
    procedure UpdateTabsAndSplitter;   // update tabs, splitter and tabbutton scroller
    procedure UpdateTabButtonScroller;
    procedure UpdateBitmaps;
    procedure SetPanelsBound;
    procedure DoChange; virtual;
    procedure ShowNavBarPanel(PanelIndex: Integer);
    function GetVisiblePanelList: TPanelList;
    procedure Resize; override;
    procedure SetWidth(const Value: Single); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure BeginUpdate; override;
    procedure EndUpdate; override;
    procedure SetBounds(X, Y, AWidth, AHeight: Single); override;
    function GetUpdateCount: Integer;

    function CreatePanel: TTMSFMXNavBarPanel; virtual;
    function AddPanel(APanel: TTMSFMXNavBarPanel): Integer; overload;
    function AddPanel(PanelCaption: String): TTMSFMXNavBarPanel; overload;
    function InsertPanel(Index: Integer): TTMSFMXNavBarPanel;
    procedure RemovePanel(APanel: TTMSFMXNavBarPanel);
    function IndexOfPanel(APanel: TTMSFMXNavBarPanel): Integer;
    procedure MovePanel(FromIndex, ToIndex: Integer);
    procedure SelectNextPanel;
    procedure SelectPreviousPanel;
    function FindNextPanelIndex(CurIndex: Integer; GoForward: Boolean): integer;
    function FindNextPanel(CurPanel: TTMSFMXNavBarPanel; GoForward: Boolean): TTMSFMXNavBarPanel;
    property Panels[Index: Integer]: TTMSFMXNavBarPanel read GetPanel;
    property PanelCount: Integer read GetPanelCount;
    property ActivePanel: TTMSFMXNavBarPanel read GetActivePanel write SetActivePanel;
  published
    property ActiveTabIndex: Integer read GetActiveTabIndex write SetActiveTabIndex;
    property BitmapContainer: TTMSFMXBitmapContainer read FBitmapContainer write SetBitmapContainer;
    property CaptionVisible: Boolean read FCaptionVisible write SetCaptionVisible default True;
    property DefaultCaption: string read FDefaultCaption write SetDefaultCaption;
    property MinPanelHeight: Integer read FMinPanelHeight write SetMinPanelHeight default 100;
    property Version: String read GetVersion write SetVersion;
    property SplitterPosition: integer read FSplitterPosition write SetSplitterPosition;
    property ShowSplitter: Boolean read FShowSplitter write SetShowSplitter default true;
    property OnPanelActivate: TPanelActivate read FOnPanelActivate write FOnPanelActivate;
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;


implementation

{$R FMX.TMSNavBar.res}

{ TTMSFMXNavBarPanelSection }

procedure TTMSFMXNavBarPanelSection.Assign(Source: TPersistent);
begin
  if (Source is TTMSFMXNavBarPanelSection) then
  begin
    FCaption := (Source as TTMSFMXNavBarPanelSection).Caption;
    FControl := (Source as TTMSFMXNavBarPanelSection).Control;
    FHeight := (Source as TTMSFMXNavBarPanelSection).Height;
    FTag := (Source as TTMSFMXNavBarPanelSection).Tag;
  end;
end;

//------------------------------------------------------------------------------

constructor TTMSFMXNavBarPanelSection.Create(Collection: TCollection);
var
  Panel: TTMSFMXNavBarPanel;
begin
  inherited;
  FHeight := 48;
  FSectionShape := nil;
  Panel := GetOwnerPanel;
  if Assigned(Panel) then
  begin
    Panel.AddSection(Self);
    Panel.UpdateSectionsPos;
    Panel.UpdateControlBounds;
  end;
end;

//------------------------------------------------------------------------------

destructor TTMSFMXNavBarPanelSection.Destroy;
var
  Panel: TTMSFMXNavBarPanel;
begin
  Panel := GetOwnerPanel;
  if Assigned(Panel) and not (csDestroying in Panel.ComponentState) then
  begin
    FSectionShape.Free;
    FSectionShape := nil;
    Panel.UpdateSectionsPos;
    Panel.UpdateControlBounds;
  end;

  inherited;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanelSection.SetCaption(const Value: string);
begin
  if (FCaption <> Value) then
  begin
    FCaption := Value;
    UpdateCaption;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanelSection.UpdateCaption;
var
  Panel: TTMSFMXNavBarPanel;
begin
  Panel := GetOwnerPanel;
  if Assigned(Panel) and Assigned(FSectionShape) then
  begin
    FSectionShape.ShapeCaption.Text := FCaption;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanelSection.UpdateControlBounds;
var
  i, SecCaptionHeight: Integer;
  ARect, br: TRectF;
  Panel: TTMSFMXNavBarPanel;
  SecShape: TTMSFMXNavBarPanelSectionShape;
  function IsEqualRect(const R1, R2: TRectF): Boolean;
  begin
    Result := (R1.Left = R2.Left) and (R1.Right = R2.Right) and
      (R1.Top = R2.Top) and (R1.Bottom = R2.Bottom);
  end;
begin
  Panel := GetOwnerPanel;
  if Assigned(FControl) and Assigned(Panel) then
  begin
    ARect := Panel.LocalRect;
    ARect.Left := ARect.Left + 1;
    ARect.Right := ARect.Right - 1;

    SecShape := FSectionShape; // Panel.GetSectionShape(Self);
    if Assigned(SecShape) then
      SecCaptionHeight := Round(SecShape.Height)
    else
      SecCaptionHeight := DEFAULT_SECCAPTIONHEIGHT;

    for i := 0 to Index - 1 do
    begin
      ARect.Top := ARect.Top + Panel.Sections[i].FHeight;
    end;

    ARect.Top := ARect.Top + SecCaptionHeight + 2; //Two more for this section....

    if Index <> Panel.Sections.Count - 1 then
    begin //if NOT the last panel, set bottom, otherwise use ClientRect bottom
      ARect.Bottom := ARect.Top + FHeight - SecCaptionHeight - 1;
    end;

    br := FControl.BoundsRect;
    if not IsEqualRect(br,ARect) then
    begin
      FControl.BoundsRect := ARect;
      Panel.Repaint;
    end;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanelSection.SetControl(const Value:TControl);
var
  i: Integer;
  Panel: TTMSFMXNavBarPanel;
begin
  if (FControl <> Value) then
  begin
    if Assigned(Value) then
    begin
      Panel := GetOwnerPanel;

      for i := 0 to Panel.Sections.Count - 1 do
      begin
        //Maybe they set the control to another section in this panel and want to move it...
        //Let's make sure that it's not duped.
        if Panel.Sections[i].Control = Value then
          Panel.Sections[i].Control := nil;
      end;

      //Now that dupe ownership is resolved, let's move the parent to here....
      if Value.Parent <> Panel then
        Value.Parent := Panel;
    end;

    FControl := Value;

    if Assigned(FControl) then
      UpdateControlBounds;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanelSection.GetOwnerPanel: TTMSFMXNavBarPanel;
begin
  Result := nil;
  if Assigned(Collection) then
    Result := TTMSFMXNavBarPanel(Collection.Owner);
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanelSection.SetHeight(const Value: Integer);
var
  Panel: TTMSFMXNavBarPanel;
begin
  if (FHeight <> Value) then
  begin
    FHeight := Value;

    Panel := GetOwnerPanel;
    if Assigned(Panel) and not (csReading in Panel.ComponentState) and not (csLoading in Panel.ComponentState) then
    begin
      Panel.UpdateSectionsPos;
      Panel.UpdateControlBounds;
    end;
  end;
end;

//------------------------------------------------------------------------------

{ TTMSFMXNavBarPanelSections }

function TTMSFMXNavBarPanelSections.Add: TTMSFMXNavBarPanelSection;
begin
  Result := TTMSFMXNavBarPanelSection(inherited Add);
end;

//------------------------------------------------------------------------------

constructor TTMSFMXNavBarPanelSections.Create(AOwner: TTMSFMXNavBarPanel);
begin
  inherited Create(TTMSFMXNavBarPanelSection);
  FOwner := AOwner;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanelSections.GetItem(
  Index: Integer): TTMSFMXNavBarPanelSection;
begin
  Result := TTMSFMXNavBarPanelSection(inherited Items[Index]);
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanelSections.GetOwner: TPersistent;
begin
  Result := FOwner;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanelSections.Insert(
  Index: Integer): TTMSFMXNavBarPanelSection;
begin
  Result := TTMSFMXNavBarPanelSection(inherited Insert(Index));
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanelSections.SetItem(Index: Integer;
  const Value: TTMSFMXNavBarPanelSection);
begin
  inherited Items[Index] := Value;
end;

//------------------------------------------------------------------------------

{ TTMSFMXNavBar }

constructor TTMSFMXNavBar.Create(AOwner: TComponent);
begin
  inherited;
  FActiveTabIndex := -1;
  FMinPanelHeight := 100;
  FSplitterPosition := 0;
  FCaptionVisible := True;
  FShowSplitter := True;
  FPanels := TPanelList.Create;
  FTabButtonScroller := TNavBarScroller.Create;
  CanFocus := True;
  {$IFDEF DELPHIXE6_LVL}
  Fill.Kind := TBrushKind.Solid;
  Stroke.Kind := TBrushKind.Solid;
  {$ELSE}
  Fill.Kind := TBrushKind.bkSolid;
  Stroke.Kind := TBrushKind.bkSolid;
  {$ENDIF}
  Width := 320;
  Height := 480;
  FDefaultCaption := 'Caption';

  if (csDesigning in ComponentState) and not
    ((csReading in Owner.ComponentState) or (csLoading in Owner.ComponentState)) then
  begin
   {
    BeginUpdate;
    for I := 0 to 4 do
    begin
      with Items.Add do
      begin
        Caption := 'Item ' + inttostr(I);
      end;
    end;
    EndUpdate;
    }
  end;
end;

//------------------------------------------------------------------------------

destructor TTMSFMXNavBar.Destroy;
begin
  FTabButtonScroller.Free;
  FPanels.Free;
  inherited;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.BeginUpdate;
begin
  inherited;
  Inc(FUpdateCount);
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.EndUpdate;
begin
  Dec(FUpdateCount);
  if not (csDesigning in ComponentState) and not (csLoading in ComponentState) and not not (csReading in ComponentState) then
  begin
    UpdateAllTabs;
    UpdateSplitterPosCount;
    UpdateTabsAndSplitter;
    SetPanelsBound;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.FindNextPanel(CurPanel: TTMSFMXNavBarPanel;
  GoForward: Boolean): TTMSFMXNavBarPanel;
var
  i: integer;
begin
  Result := CurPanel;
  if CurPanel = nil then
    Exit;

  i := FPanels.IndexOf(CurPanel);

  i := FindNextPanelIndex(i, GoForward);

  if i >= 0 then
    Result := TTMSFMXNavBarPanel(FPanels[i])
  else
    Result := nil;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.FindNextPanelIndex(CurIndex: Integer;
  GoForward: Boolean): Integer;
var
  I: Integer;
begin
  Result := CurIndex;

  if (FPanels.Count <= 1) or (CurIndex < 0) then
    Exit;

  if GoForward then
  begin
    for I := CurIndex + 1 to FPanels.Count - 1 do
    begin
      if Panels[I].IsVisible then
      begin
        CurIndex := I;
        Break;
      end;
    end;

    if CurIndex = Result then
    begin
      for I := 0 to FPanels.Count - 1 do
      begin
        if Panels[I].IsVisible then
        begin
          CurIndex := I;
          Break;
        end;
      end;
    end;
  end
  else
  begin
    for I := CurIndex - 1 downto 0 do
    begin
      if Panels[I].IsVisible then
      begin
        CurIndex := I;
        Break;
      end;
    end;
    if CurIndex = Result then
    begin
      for I := FPanels.Count - 1 downto 0 do
      begin
        if Panels[I].IsVisible then
        begin
          CurIndex := I;
          Break;
        end;
      end;
    end;
  end;
  Result := CurIndex;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SelectNextPanel;
begin
  FInternalCall := true;
  ActiveTabIndex := FindNextPanelIndex(FActiveTabIndex, true);
  FInternalCall := false;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SelectPreviousPanel;
begin
  FInternalCall := true;
  ActiveTabIndex := FindNextPanelIndex(FActiveTabIndex, false);
  FInternalCall := false;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetActivePanel: TTMSFMXNavBarPanel;
begin
  Result := nil;
  if (FActiveTabIndex >= 0) and (FActiveTabIndex < FPanels.Count) then
    Result := Panels[FActiveTabIndex];
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetActivePanel(const Value: TTMSFMXNavBarPanel);
var
  AllowActivate: Boolean;
  i: integer;
begin
  if Value = nil then
  begin
    FActiveTabIndex := -1;
    UpdateCaption;
  end
  else
    if Value <> ActivePanel then
    begin
      AllowActivate := true;
      i := FPanels.IndexOf(Value);
      if i < 0 then
        raise Exception.Create('Invalid TMSFMXNavBarPanel');

      if not Value.Visible then
        Exit;

      if Assigned(FOnPanelActivate) then
        FOnPanelActivate(self, FActiveTabIndex, i, AllowActivate);

      if AllowActivate then
      begin
        FActiveTabIndex := i;
        UpdateCaption;
        ShowNavBarPanel(FActiveTabIndex);
        DoChange;
        Repaint;
      end;
    end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetActiveTabIndex(const Value: integer);
begin
  if (csLoading in ComponentState) then
  begin
    FActiveTabIndex := Value;
    Exit;
  end;

  if (Value < 0) then
    ActivePanel := nil
  else if (Value < FPanels.Count) then
    ActivePanel := Panels[Value];
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetActiveTabIndex: integer;
begin
  Result := FActiveTabIndex;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.DoChange;
begin
  if Assigned(FOnChange) then
    FOnChange(self);
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.ShowNavBarPanel(PanelIndex: Integer);
//var
  //i: Integer;
begin
  if (PanelIndex < 0) or (PanelIndex >= FPanels.Count) then
    Exit;

  //for I := 0 to FPanels.Count -1 do
  //begin
    //if (i = PanelIndex) then
    //begin
      //Panels[PanelIndex].Visible := True;
      Panels[PanelIndex].BringToFront;
    //end;
    //else
      //Panels[i].Visible := False;
  //end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetContainer: TControl;
var
  fmxobj: TFMXObject;
begin
  Result := nil;
  fmxobj := FindStyleResource('container');
  if fmxobj is TControl then
    Result := fmxobj as TControl;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetSplitter: TControl;
var
  fmxobj: TFMXObject;
  E: TControl;
begin
  Result := nil;
  E := GetContainer;
  if Assigned(E) then
  begin
    fmxobj := E.FindStyleResource('splitter');
    if fmxobj is TControl then
      Result := fmxobj as TControl;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetDefaultTabButtonShape: TControl;
var
  fmxobj: TFMXObject;
begin
  Result := nil;
  fmxobj := FindStyleResource('defaulttabbutton');
  if fmxobj is TControl then
    Result := fmxobj as TControl;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetDefaultTabShape: TControl;
var
  fmxobj: TFMXObject;
begin
  Result := nil;
  fmxobj := FindStyleResource('defaulttab');
  if fmxobj is TControl then
    Result := fmxobj as TControl;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetDefaultSectionShape: TControl;
var
  fmxobj: TFMXObject;
begin
  Result := nil;
  fmxobj := FindStyleResource('defaultsection');
  if fmxobj is TControl then
    Result := fmxobj as TControl;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetHeader: TControl;
var
  fmxobj: TFMXObject;
begin
  Result := nil;
  fmxobj := FindStyleResource('header');
  if fmxobj is TControl then
    Result := fmxobj as TControl;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetHeaderText: TText;
var
  fmxobj: TFMXObject;
  c: TControl;
begin
  Result := nil;
  c := GetHeader;
  if Assigned(c) then
  begin
    fmxobj := c.FindStyleResource('headertext');
    if fmxobj is TText then
      Result := fmxobj as TText;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetFooter: TControl;
var
  fmxobj: TFMXObject;
begin
  Result := nil;
  fmxobj := FindStyleResource('footer');
  if fmxobj is TControl then
    Result := fmxobj as TControl;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetLeftScrollButton: TTMSFMXNavBarButtonShape;
var
  fmxobj: TFMXObject;
  c: TControl;
begin
  Result := nil;
  c := GetFooter;
  if Assigned(c) then
  begin
    fmxobj := c.FindStyleResource('scrollleftbutton');
    if fmxobj is TTMSFMXNavBarButtonShape then
      Result := fmxobj as TTMSFMXNavBarButtonShape;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetRightScrollButton: TTMSFMXNavBarButtonShape;
var
  fmxobj: TFMXObject;
  c: TControl;
begin
  Result := nil;
  c := GetFooter;
  if Assigned(c) then
  begin
    fmxobj := c.FindStyleResource('scrollrightbutton');
    if fmxobj is TTMSFMXNavBarButtonShape then
      Result := fmxobj as TTMSFMXNavBarButtonShape;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetTabHeight: Integer;
var
  c: TControl;
begin
  Result := DEFAULT_TABHEIGHT;
  c := GetDefaultTabShape;
  if Assigned(c) then
  begin
    Result := Round(c.Height);
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetContainerRect: TRectF;
var
  c: TControl;
begin
  Result := LocalRect;
  c := GetContainer;
  if Assigned(c) then
  begin
    Result := c.LocalRect;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetInstance: NativeUInt;
begin
  Result := HInstance;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.ApplyStyle;
var
  i: Integer;
begin
  inherited;
  ClearTabs(GetContainer);
  UpdatePanelIndex;
  UpdateAllTabs;
  UpdateSplitterPosCount;
  UpdateTabsAndSplitter;
  SetPanelsBound;
  AssignEvents;
  if (GetVisiblePanelCount <= 0) then
    ActiveTabIndex := -1
  else if (PanelCount > 0) then
  begin
    if (ActiveTabIndex >= 0) then
    begin
      i := ActiveTabIndex;
      FActiveTabIndex := -1;
      ActiveTabIndex := i;
    end;
  end
  else
    UpdateCaption;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetUpdateCount: Integer;
begin
  Result := FUpdateCount;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetVersion: string;
var
  vn: Integer;
begin
  vn := GetVersionNr;
  Result := IntToStr(Hi(Hiword(vn)))+'.'+IntToStr(Lo(Hiword(vn)))+'.'+IntToStr(Hi(Loword(vn)))+'.'+IntToStr(Lo(Loword(vn)));
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetVersionNr: integer;
begin
  Result := MakeLong(MakeWord(BLD_VER,REL_VER),MakeWord(MIN_VER,MAJ_VER));
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.CanClone(Source: TFMXObject): Boolean;
begin
  Result := True;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.CloneChildren(Source, Destination: TFMXObject);
var
  i: integer;
  fmxclone: TFmxObject;
begin
  for I := 0 to Source.ChildrenCount - 1 do
  begin
    if CanClone(Source.Children[I]) then
    begin
      fmxclone := Source.Children[I].Clone(Destination);
      {
      if Assigned(fmxclone) and (fmxclone is TTMSFMXBitmap) then
      begin
        if (fmxclone as TTMSFMXBitmap).StyleName = 'itemeditchecked' then
          (fmxclone as TTMSFMXBitmap).LinkedImage := GetEditcheckedDefaultImage;
      end;
      }
      Destination.AddObject(fmxclone);
      CloneChildren(Source.Children[I], fmxclone);
    end;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.IsTab(AObject: TFmxObject): Boolean;
begin
  Result := Assigned(AObject) and (AObject is TTMSFMXNavBarTabShape);
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.AsTab(AObject: TFmxObject): TTMSFMXNavBarTabShape;
begin
  Result := AObject as TTMSFMXNavBarTabShape;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.DoesTabExist(ParentElement: TControl;
  TabName: String): TTMSFMXNavBarTabShape;
var
  i: integer;
  ctrl: TFMXObject;
  l: TTMSFMXNavBarTabShape;
begin
  Result := nil;
  if Assigned(ParentElement) then
  begin
    for I := 0 to ParentElement.ChildrenCount - 1 do
    begin
      ctrl := ParentElement.Children[i];
      if IsTab(ctrl) then
      begin
        l := AsTab(ctrl);
        if UpperCase(l.StyleName) = UpperCase(TabName) then
        begin
          Result := l;
          Break;
        end;
      end;
    end;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.IsTabButton(AObject: TFmxObject): Boolean;
begin
  Result := Assigned(AObject) and (AObject is TTMSFMXNavBarTabButtonShape);
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.AsTabButton(
  AObject: TFmxObject): TTMSFMXNavBarTabButtonShape;
begin
  Result := AObject as TTMSFMXNavBarTabButtonShape;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.DoesTabButtonExist(ParentElement: TControl;
  TabButtonName: String): TTMSFMXNavBarTabButtonShape;
var
  i: integer;
  ctrl: TFMXObject;
  tb: TTMSFMXNavBarTabButtonShape;
begin
  Result := nil;
  if Assigned(ParentElement) then
  begin
    for I := 0 to ParentElement.ChildrenCount - 1 do
    begin
      ctrl := ParentElement.Children[i];
      if IsTabButton(ctrl) then
      begin
        tb := AsTabButton(ctrl);
        if UpperCase(tb.StyleName) = UpperCase(TabButtonName) then
        begin
          Result := tb;
          Break;
        end;
      end;
    end;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.AddTab(APanel: TTMSFMXNavBarPanel);
begin
  AddTab(APanel, GetDefaultTabShape, GetContainer);
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.AddTab(APanel: TTMSFMXNavBarPanel; TabElement,
  ParentElement: TControl);
var
  sn: String;
  newsec, sec: TTMSFMXNavBarTabShape;
  //shpr: TRectangle;
  //shpimg: TTMSFMXBitmap;
  shptxt: TText;
begin
  if not Assigned(APanel) or not Assigned(TabElement) or not Assigned(ParentElement) then
    Exit;

  sn := 'FMXNavBarTab'+inttostr(IndexOFPanel(APanel));
  sec := DoesTabExist(ParentElement, sn);
  if Assigned(sec) then
  begin
    newsec := sec;
    newsec.BeginUpdate;
  end
  else
  begin
    newsec := AsTab(TabElement.Clone(ParentElement));
    newsec.BeginUpdate;
    CloneChildren(TabElement, newsec);
    //newsec.Align := TAlignLayout.alBottom;
    newsec.HitTest := True;
    newsec.StyleName := sn;
    newsec.Name := sn + 'Name';
    newsec.Visible := True;
  end;

  APanel.Tab := newsec;
  newsec.NavBarPanel := APanel;
  newsec.Position.Y := 10;
  newsec.Position.X := 0;
  newsec.Width := ParentElement.Width;

  if not ParentElement.IsChild(newsec) then
    ParentElement.AddObject(newsec);
  newsec.EndUpdate;

  shptxt := newsec.ShapeCaption;
  if Assigned(shptxt) and (shptxt is TTMSFMXHTMLText) then
    shptxt.Text := APanel.Caption;

  APanel.AssignBitmapContainer;
  APanel.UpdateBitmap;
  {
  shpimg := newsec.ShapeLeftRectangleImage;
  if Assigned(shpimg) then
  begin
    if ((csDesigning in ComponentState) and not Assigned(shpimg.BitmapContainer)) or (shpimg.Bitmap.IsEmpty and ((shpimg.BitmapName = '') or not Assigned(shpimg.BitmapContainer))) then
    begin
      shpr := newsec.ShapeLeftRectangle;
      if Assigned(shpr) then
        shpr.Visible := False;
    end;

  end;}
  {
  shptxt := AItem.ShapeDescription;
  if Assigned(shptxt) and (shptxt is TTMSFMXHTMLText) then
  begin
    shptxt.Text := AItem.Description;
    (shptxt as TTMSFMXHTMLText).OnAnchorClick := AItem.DoAnchorClickItemDescription;
  end;
  }
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.ClearTabs(ParentElement: TControl);
var
  str: TStringList;
  lName: String;
  i: integer;
  ctrl: TFMXObject;
  l: TTMSFMXNavBarTabShape;
begin
  if not Assigned(ParentElement) then
    Exit;

  str := TStringList.Create;
  for i := 0 to FPanels.Count - 1 do
  begin
    lName := 'FMXNavBarTab'+inttostr(IndexOFPanel(Panels[i]));
    str.Add(UpperCase(lName+'Name'));
  end;

  if Assigned(ParentElement) then
  begin
    for I := ParentElement.ChildrenCount - 1 downto 0 do
    begin
      ctrl := ParentElement.Children[i];
      if IsTab(ctrl) then
      begin
        l := AsTab(ctrl);
        if str.IndexOf(UpperCase(l.Name)) = -1 then
        begin
          {$IFDEF DELPHI_LLVM}
          l.Release;
          {$ELSE}
          l.Free;
          {$ENDIF}
        end;
      end;
    end;
  end;

  for i := 0 to FPanels.Count - 1 do
  begin
    Panels[i].FTab := nil;
  end;

  str.Free;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetBitmapContainer(const Value: TTMSFMXBitmapContainer);
begin
  FBitmapContainer := Value;
  UpdateBitmaps;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.AddTabButton(APanel: TTMSFMXNavBarPanel);
begin
  AddTabButton(APanel, GetDefaultTabButtonShape, GetFooter);
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.AddTabButton(APanel: TTMSFMXNavBarPanel;
  TabButtonElement, ParentElement: TControl);
var
  sn: String;
  newsec, sec: TTMSFMXNavBarTabButtonShape;
  //shpimg: TTMSFMXBitmap;
  //shptxt: TText;
begin
  if not Assigned(APanel) or not Assigned(TabButtonElement) or not Assigned(ParentElement) then
    Exit;

  sn := 'FMXNavBarTabButton'+inttostr(IndexOFPanel(APanel));
  sec := DoesTabButtonExist(ParentElement, sn);
  if Assigned(sec) then
  begin
    newsec := sec;
    newsec.BeginUpdate;
  end
  else
  begin
    newsec := AsTabButton(TabButtonElement.Clone(ParentElement));
    newsec.BeginUpdate;
    CloneChildren(TabButtonElement, newsec);
    //newsec.Align := TAlignLayout.alBottom;
    newsec.HitTest := True;
    newsec.StyleName := sn;
    newsec.Name := sn + 'Name';
    newsec.Visible := True;
  end;

  APanel.TabButton := newsec;
  newsec.NavBarPanel := APanel;
  newsec.Position.Y := 1;
  newsec.Position.X := 0;
  newsec.Width := ParentElement.Width;

  if not ParentElement.IsChild(newsec) then
    ParentElement.AddObject(newsec);
  newsec.EndUpdate;
  //shptxt := newsec.ShapeCaption;
  //if Assigned(shptxt) and (shptxt is TTMSFMXHTMLText) then
    //shptxt.Text := APanel.Caption;
  //APanel.AssignBitmapContainer;
  APanel.UpdateBitmap;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.ClearTabButtons(ParentElement: TControl);
var
  str: TStringList;
  lName: String;
  i: integer;
  ctrl: TFMXObject;
  l: TTMSFMXNavBarTabShape;
begin
  if not Assigned(ParentElement) then
    Exit;

  str := TStringList.Create;
  for i := 0 to FPanels.Count - 1 do
  begin
    lName := 'FMXNavBarTabButton'+inttostr(IndexOFPanel(Panels[i]));
    str.Add(UpperCase(lName+'Name'));
  end;

  if Assigned(ParentElement) then
  begin
    for I := ParentElement.ChildrenCount - 1 downto 0 do
    begin
      ctrl := ParentElement.Children[i];
      if IsTab(ctrl) then
      begin
        l := AsTab(ctrl);
        if str.IndexOf(UpperCase(l.Name)) = -1 then
        begin
          {$IFDEF DELPHI_LLVM}
          l.Release;
          {$ELSE}
          l.Free;
          {$ENDIF}
        end;
      end;
    end;
  end;

  for i := 0 to FPanels.Count - 1 do
  begin
    Panels[i].FTab := nil;
  end;

  str.Free;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.UpdatePanelIndex;
var
  i: Integer;
  pl: TPanelList;
begin
  //--- updating panel index
  if not (csReading in ComponentState) and not (csLoading in ComponentState) then
  begin
    pl := TPanelList.Create;
    for I := 0 to FPanels.Count - 1 do
    begin
      pl.Add(FPanels[i]);
    end;

    for I := 0 to pl.Count - 1 do
    begin
      if (TTMSFMXNavBarPanel(pl[i]).FPanelIndex >= 0) and (TTMSFMXNavBarPanel(pl[i]).FPanelIndex < PanelCount) then
        FPanels[TTMSFMXNavBarPanel(pl[i]).FPanelIndex] := TTMSFMXNavBarPanel(pl[i]);
        //FPanels.Move(TTMSFMXNavBarPanel(pl[i]).PanelIndex, TTMSFMXNavBarPanel(pl[i]).FPanelIndex);
    end;
    pl.Free;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.UpdateSplitterPosCount;
begin
  if not (csReading in ComponentState) and not (csLoading in ComponentState) then
  begin
    if (FSplitterPosition > GetVisiblePanelCount) then
      FSplitterPosition := GetVisiblePanelCount
    else if (FSplitterPosition < 0) then
      FSplitterPosition := 0;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.UpdateAllTabs;
var
  i: Integer;
begin
  //--- adding tabs if not added already
  for I := 0 to FPanels.Count - 1 do
  begin
    AddTab(Panels[i]);
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.UpdateBitmaps;
var
  i: Integer;
begin
  for I := 0 to FPanels.Count - 1 do
  begin
    Panels[i].UpdateBitmap;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.UpdateTabsAndSplitter;
var
  th, ch, sh, avs, MaxTabC, i, y: Integer;
  C: TControl;
  CRF: TRectF;
  DisList: TPanelList;
  APanel: TTMSFMXNavBarPanel;
begin
  if (csDestroying in ComponentState) then
    Exit;

  if (FPanels.Count <= 0) then
  begin
    C := GetSplitter;
    if Assigned(C) and (C is TTMSFMXNavBarSplitterShape) then
      (C as TTMSFMXNavBarSplitterShape).Visible := False;

    Exit;
  end;

  th := GetTabHeight;
  CRF := GetContainerRect;

  ch := Round(CRF.Height);
  sh := Round(GetSplitterRect.Height);
  avs := ch - MinPanelHeight - sh;
  avs := Max(0, avs);

  MaxTabC := avs div th;
  if (FSplitterPosition > MaxTabC) then
    FSplitterPosition := MaxTabC;

  for I := 0 to FPanels.Count - 1 do
  begin
    if not Panels[i].IsVisible then
    begin
      if Assigned(Panels[i].Tab) then
        Panels[i].Tab.Visible := False;
      if Assigned(Panels[i].TabButton) then
        Panels[i].TabButton.Visible := False;
    end;
  end;

  DisList := GetVisiblePanelList;
  y := ch;
  for I := 0 to DisList.Count - 1 do
  begin
    if (I >= (DisList.Count - FSplitterPosition)) then
    begin
      APanel := TTMSFMXNavBarPanel(DisList[i]);
      if Assigned(APanel.Tab) then
      begin
        if APanel.IsVisible then
        begin
          y := y - th;
          if not APanel.Tab.Visible then
            APanel.Tab.Visible := True;
          APanel.Tab.SetBounds(1, y, CRF.Width - 2, th);
          if Assigned(APanel.TabButton) then
            APanel.TabButton.Visible := False;
        end
        else
        begin
          APanel.Tab.Visible := False;
        end;
      end;
    end
    else // tab button
    begin
      // do nothing
    end;
  end;
  DisList.Free;

  UpdateTabButtonScroller;

  C := GetSplitter;
  if Assigned(C) and (C is TTMSFMXNavBarSplitterShape) then
  begin
    (C as TTMSFMXNavBarSplitterShape).NavBar := Self;
    (C as TTMSFMXNavBarSplitterShape).SetBounds(1, y - C.Height, CRF.Width - 2, C.Height);
    //TTMSFMXNavBarSplitterShape(C).Position.Y := y + 10;
    (C as TTMSFMXNavBarSplitterShape).Visible := ShowSplitter and (PanelCount > 0);
    (C as TTMSFMXNavBarSplitterShape).BringToFront;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.UpdateTabButtonScroller;
var
  bx, tbw, tbh, i, j, k, ct, b: Integer;
  C: TControl;
  lsb, rsb: TTMSFMXNavBarButtonShape;
  CRF, CR: TRectF;
  ScrollerVisible: Boolean;
  DisList: TPanelList;
  APanel: TTMSFMXNavBarPanel;
begin
  if (csDestroying in ComponentState) then
    Exit;

  CRF := GetContainerRect;
  C := GetDefaultTabButtonShape;
  if Assigned(c) then
  begin
    tbw := Round(C.Width) + 1;
    tbh := Round(C.Height);
  end
  else
  begin
    tbw := DEFAULT_TABBUTTONWIDTH + 1;
    tbh := DEFAULT_TABBUTTONHEIGHT;
  end;

  CR := RectF(CRF.Left, CRF.Top, CRF.Right, CRF.Bottom);
  lsb := GetLeftScrollButton;
  if Assigned(lsb) then
    CR.Left := CR.Left + Round(lsb.Width) + 2
  else
    CR.Left := CR.Left + DEFAULT_TABBUTTONWIDTH + 2;

  rsb := GetRightScrollButton;
  if Assigned(rsb) then
    CR.Right := CR.Right - Round(rsb.Width) - 2
  else
    CR.Right := CR.Right - DEFAULT_TABBUTTONWIDTH - 2;

  DisList := GetVisiblePanelList;

  j := (DisList.Count - FSplitterPosition);  // Tab button count
  k := Round(CR.Width) div tbw;              // max tab button count
  if (j > k) then
  begin
    ScrollerVisible := True;
    FTabButtonScroller.Min := 0;
    FTabButtonScroller.Max := j - k;
    //bx := Round(CRF.Width) - (k * tbw);
  end
  else
  begin
    ScrollerVisible := False;
    FTabButtonScroller.Min := 0;
    FTabButtonScroller.Max := 0;
    FTabButtonScroller.Position := 0;
    //bx := Round(CRF.Width) - (j * tbw);
  end;
  bx := Round(CR.Left) + Round(CR.Width);

  ct := (DisList.Count - FSplitterPosition) - 1;

  b := 0;
  for I := ct downto 0 do
  begin
    if (I >= 0) and (I <= DisList.Count - 1) then
    begin
      APanel := TTMSFMXNavBarPanel(DisList[I]);
      if APanel.IsVisible and (not ScrollerVisible or ((i <= (ct - FTabButtonScroller.Position)) and (b < k))) then
      begin
        if Assigned(APanel.Tab) then
          APanel.Tab.Visible := False;
        if not Assigned(APanel.TabButton) then
          AddTabButton(APanel);

        if Assigned(APanel.TabButton) then
        begin
          bx := bx - tbw;
          APanel.TabButton.Visible := True;
          APanel.TabButton.SetBounds(bx, 3, tbw, tbh);
        end;

        Inc(b);
      end
      else
      begin
        if Assigned(APanel.Tab) then
          APanel.Tab.Visible := False;
        if Assigned(APanel.TabButton) then
          APanel.TabButton.Visible := False;
      end;
    end;
  end;

  DisList.Free;

  if Assigned(lsb) then
  begin
    lsb.Visible := ScrollerVisible;
    lsb.HitTest := ScrollerVisible;
    lsb.Enabled := FTabButtonScroller.CanGoForward;
    lsb.OnClick := scrollLeftBtnClick;
  end;
  if Assigned(rsb) then
  begin
    rsb.Visible := ScrollerVisible;
    rsb.HitTest := ScrollerVisible;
    rsb.Enabled := FTabButtonScroller.CanGoBack;
    rsb.OnClick := scrollRightBtnClick;
  end;
  FTabButtonScroller.Visible := ScrollerVisible;

end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.AssignEvents;
var
  C: TControl;
begin
  C := GetContainer;
  if Assigned(C) then
  begin
    C.OnResize := OnContainerResize;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetShowSplitter(const Value: Boolean);
var
  c: TControl;
begin
  if (FShowSplitter <> Value) then
  begin
    FShowSplitter := Value;
    c := GetSplitter;
    if Assigned(c) then
      c.Visible := FShowSplitter;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetSplitterPosition(const Value: integer);
begin
  if (FSplitterPosition <> Value) then
  begin
    FSplitterPosition := Value;
    if (csReading in ComponentState) or (csLoading in ComponentState) then
      Exit;

    if (FSplitterPosition > GetVisiblePanelCount) then
      FSplitterPosition := GetVisiblePanelCount
    else if (Value < 0) then
      FSplitterPosition := 0;
    UpdateTabsAndSplitter;
    SetPanelsBound;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.CreatePanel: TTMSFMXNavBarPanel;
begin
  Result := TTMSFMXNavBarPanel.Create(Self);
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.AddPanel(PanelCaption: String): TTMSFMXNavBarPanel;
begin
  Result := CreatePanel;
  Result.Caption := PanelCaption;
  AddPanel(Result);
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.AddPanel(APanel: TTMSFMXNavBarPanel): Integer;
begin
  Result := -1;
  if not Assigned(APanel) then
    Exit;

  Result := FPanels.IndexOf(APanel);
  if (FPanels.IndexOf(APanel) < 0) then
  begin
    FPanels.Add(APanel);
    Result := FPanels.Count - 1;
    if not (csReading in ComponentState) and not (csLoading in ComponentState) then
      APanel.FPanelIndex := Result;

    AddTab(APanel);
    if not (csLoading in ComponentState) and not (csREading in ComponentState) then
    begin
      FSplitterPosition := FSplitterPosition + 1;
      if (ActiveTabIndex < 0)  then
        FActiveTabIndex := Result;
    end;
  end;

  if (APanel.Parent <> Self) then
    APanel.Parent := Self;
  APanel.FNavBar := Self;

  UpdateTabsAndSplitter;
  SetPanelsBound;

  if Assigned(ActivePanel) then
    ActivePanel.BringToFront;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.IndexOfPanel(APanel: TTMSFMXNavBarPanel): Integer;
begin
  Result := FPanels.IndexOf(APanel);
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.InsertPanel(Index: Integer): TTMSFMXNavBarPanel;
begin
  Result := CreatePanel;
  Result.NavBar := Self;
  FPanels.Insert(Index, Result);
  SetPanelsBound;
  //FInternalCall := true;
  //ActiveTabIndex := FAdvNavBarPanel.Count - 1;
  //FInternalCall := false;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.RemovePanel(APanel: TTMSFMXNavBarPanel);
var
  aNavBarPanel: TTMSFMXNavBarPanel;
  i, j: Integer;
begin
  if not Assigned(APanel) then
    Exit;

  Inc(FUpdateCount);

  aNavBarPanel := ActivePanel;
  if APanel = ActivePanel then
    aNavBarPanel := FindNextPanel(APanel, true);

  if aNavBarPanel = APanel then
    aNavBarPanel := nil;

  j := FPanels.IndexOf(APanel);
  FPanels.Remove(APanel);

  APanel.FNavBar := nil;

  if (j >= 0) then
  begin
    for I := 0 to FPanels.Count - 1 do
      Panels[i].FPanelIndex := i;
  end;

  if Assigned(APanel.FTab) then
  begin
    APanel.FTab.Free;
    APanel.FTab := nil;
  end;
  if Assigned(APanel.FTabButton) then
  begin
    APanel.FTabButton.Free;
    APanel.FTabButton := nil;
  end;

  Dec(FUpdateCount);

  ClearTabs(GetContainer);
  ClearTabButtons(GetFooter);
  UpdateAllTabs;
  UpdateSplitterPosCount;
  UpdateTabsAndSplitter;
  SetPanelsBound;

  ActivePanel := nil;
  ActivePanel := aNavBarPanel;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.OnContainerResize(Sender: TObject);
begin
  SetPanelsBound;
  UpdateTabsAndSplitter;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.Resize;
begin
  inherited;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetWidth(const Value: Single);
begin
  inherited;
  SetPanelsBound;
  //if (Height < MinPanelHeight + 100) and (SplitterPosition <> 0) then
  UpdateTabsAndSplitter;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetVisiblePanelCount: Integer;
var
  I: Integer;
begin
  Result := 0;
  for I := 0 to FPanels.Count - 1 do
  begin
    if (csDesigning in ComponentState) or (Panels[i].Visible) then
      Inc(Result);
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetVisiblePanelList: TPanelList;
var
  I: Integer;
begin
  Result := TPanelList.Create;
  for I := 0 to FPanels.Count - 1 do
  begin
    if (csDesigning in ComponentState) or (Panels[i].Visible) then
      Result.Add(FPanels[i]);
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetPanel(Index: Integer): TTMSFMXNavBarPanel;
begin
  Result := nil;
  if (FPanels.Count > Index) and (Index >= 0) then
    Result := TTMSFMXNavBarPanel(FPanels.Items[Index]);
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetPanelCount: Integer;
begin
  Result := FPanels.Count;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.MovePanel(FromIndex, ToIndex: Integer);
begin
  FPanels.Move(FromIndex, ToIndex);
  ActiveTabIndex := ActiveTabIndex;

  if ActiveTabIndex < FPanels.Count then
    ActivePanel := TTMSFMXNavBarPanel(FPanels[ActiveTabIndex]);
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetBounds(X, Y, AWidth, AHeight: Single);
begin
  inherited;

end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetCaptionVisible(const Value: Boolean);
var
  c: TControl;
begin
  if (FCaptionVisible <> Value) then
  begin
    FCaptionVisible := Value;
    c := GetHeader;
    if Assigned(c) then
      c.Visible := FCaptionVisible;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetDefaultCaption(const Value: string);
begin
  if (FDefaultCaption <> Value) then
  begin
    FDefaultCaption := Value;
    UpdateCaption;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.UpdateCaption;
var
  ht: TText;
  s: string;
begin
  if (FActiveTabIndex >= 0) and (FActiveTabIndex < FPanels.Count) then
    s := Panels[FActiveTabIndex].Caption
  else
    s := DefaultCaption;

  ht := GetHeaderText;
  if Assigned(ht) then
    ht.Text := s;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetMinPanelHeight(const Value: Integer);
begin
  if (FMinPanelHeight <> Value) then
  begin
    FMinPanelHeight := Value;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetPanelRect: TRectF;
var
  C: TControl;
  h: Integer;
begin
  Result := LocalRect;
  C := GetHeader;
  if Assigned(C) then
  begin
    Result.Top := C.Height;
    h := Round(Result.Height);
    //--- Container
    C := GetContainer;
    if Assigned(C) then
      h := Round(C.Height);

    //--- Splitter
    C := GetSplitter;
    if Assigned(C) and C.Visible then
      h := h - Round(C.Height);

    h := h - (FSplitterPosition * GetTabHeight) + Round(Result.Top);
    Result := RectF(Result.Left, Result.Top - 1, Result.Width, h - 1);
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetPanelsBound;
var
  i: Integer;
  R: TRectF;
begin
  R := GetPanelRect;
  for I := 0 to FPanels.Count - 1 do
  begin
    Panels[i].FInternalBoundSet := True;
    Panels[i].SetBounds(R.Left, R.Top, R.Width, R.Height);
    Panels[i].FInternalBoundSet := False;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.SetVersion(const Value: String);
begin

end;

//------------------------------------------------------------------------------

function TTMSFMXNavBar.GetSplitterRect: TRectF;
var
  c: TControl;
begin
  Result := LocalRect;
  Result.Height := DEFAULT_SPLITTERHEIGHT;
  c := GetSplitter;
  if Assigned(c) then
    Result := c.BoundsRect;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.Notification(AComponent: TComponent;
  Operation: TOperation);
var
  i: Integer;
begin
  if (Operation = opRemove) and (AComponent = FBitmapContainer) then
    FBitmapContainer := nil;

  inherited;

  if (Operation = opRemove) and not (csDestroying in ComponentState) then
  begin
    i := 0;
    while (i < FPanels.Count) do
    begin
      if Panels[i] = AComponent then
      begin
        RemovePanel(TTMSFMXNavBarPanel(AComponent));
        Break;
      end
      else
        inc(i);
    end;
  end;

end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.ScrollLeftBtnClick(Sender: TObject);
begin
  if FTabButtonScroller.CanGoForward then
  begin
    FTabButtonScroller.Position := FTabButtonScroller.Position + 1;
    UpdateTabButtonScroller;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBar.ScrollRightBtnClick(Sender: TObject);
begin
  if FTabButtonScroller.CanGoBack then
  begin
    FTabButtonScroller.Position := FTabButtonScroller.Position - 1;
    UpdateTabButtonScroller;
  end;
end;

//------------------------------------------------------------------------------

{ TTMSFMXNavBarPanel }

constructor TTMSFMXNavBarPanel.Create(AOwner: TComponent);
begin
  inherited;
  FBitmap := TBitmap.Create(0, 0);
  FBitmap.OnChange := BitmapChanged;
  FSections := TTMSFMXNavBarPanelSections.Create(Self);
  FPanelIndex := -1;
end;

//------------------------------------------------------------------------------

destructor TTMSFMXNavBarPanel.Destroy;
begin
  FSections.Free;
  FBitmap.Free;
  inherited;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanel.GetIsSelected: Boolean;
begin
  Result := False;
  if Assigned(NavBar) then
    Result := NavBar.ActivePanel = Self;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.ApplyStyle;
begin
  inherited;
  ClearSections(Self);
  UpdateAllSections;
  UpdateSectionsPos;
  UpdateControlBounds;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.ReadState(Reader: TReader);
begin
  inherited ReadState(Reader);
  if Reader.Parent is TTMSFMXNavBar then
    NavBar := TTMSFMXNavBar(Reader.Parent);
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.SetVisible(const Value: Boolean);
var
  aNavBarPanel: TTMSFMXNavBarPanel;
  OldValue: Boolean;
begin
  OldValue := Visible;
  inherited;
  if Assigned(NavBar) then
  begin
    if not Value and not (csDesigning in ComponentState) and not (csReading in ComponentState)
      and not (csLoading in ComponentState) and (NavBar.ActivePanel = Self) then
    begin
      aNavBarPanel := NavBar.FindNextPanel(Self, true);
      if aNavBarPanel = Self then
        aNavBarPanel := nil;

      NavBar.ActivePanel := aNavBarPanel;
    end;
    NavBar.UpdateAllTabs;
    if (OldValue <> Visible) and Visible then
      NavBar.FSplitterPosition := NavBar.FSplitterPosition + 1;
    NavBar.UpdateSplitterPosCount;
    NavBar.UpdateTabsAndSplitter;
    NavBar.SetPanelsBound;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanel.IsVisible: Boolean;
begin
  Result := Visible or (csDesigning in ComponentState);
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.SetBitmap(const Value: TBitmap);
begin
  if FBitmap <> Value then
  begin
    FBitmap := Value;
    if Assigned(NavBar) and (NavBar.GetUpdateCount = 0) then
      UpdateBitmap;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.SetBitmapName(const Value: String);
begin
  if FBitmapName <> Value then
  begin
    FBitmapName := Value;
    if Assigned(NavBar) and (NavBar.GetUpdateCount = 0) then
      UpdateBitmap;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.SetSmallBitmapName(const Value: String);
begin
  if FSmallBitmapName <> Value then
  begin
    FSmallBitmapName := Value;
    if Assigned(NavBar) and (NavBar.GetUpdateCount = 0) then
      UpdateBitmap;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.AssignBitmapContainer;
var
  shpcap: TTMSFMXHTMLText;
begin
  shpcap := ShapeCaption as TTMSFMXHTMLText;
  if Assigned(shpcap) and Assigned(NavBar) then
    shpcap.BitmapContainer := NavBar.BitmapContainer;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.UpdateBitmap;
var
  shpimg: TTMSFMXBitmap;
  shpr: TRectangle;
begin
  shpimg := ShapeLeftRectangleImage;
  if Assigned(shpimg) and Assigned(NavBar) then
  begin
    shpimg.BitmapContainer := NavBar.BitmapContainer;
    shpimg.BitmapName := BitmapName;
    shpimg.Bitmap.Assign(Bitmap);

    shpr := ShapeLeftRectangle;
    if Assigned(shpr) and not (csDesigning in ComponentState) then
      shpr.Visible := (Assigned(shpimg.BitmapContainer) and (BitmapName <> '')) or not shpimg.Bitmap.IsEmpty;
  end;

  shpimg := TabButtonShapeImage;
  if Assigned(shpimg) and Assigned(NavBar) then
  begin
    shpimg.BitmapContainer := NavBar.BitmapContainer;
    if (SmallBitmapName <> '') then
    begin
      shpimg.BitmapName := SmallBitmapName;
      shpimg.Stretch := False;
    end
    else
    begin
      shpimg.BitmapName := BitmapName;
      shpimg.Stretch := True;
    end;
    shpimg.Bitmap.Assign(Bitmap);
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.BitmapChanged(Sender: TObject);
begin
  UpdateBitmap;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.UpdateCaption;
var
  shp: TText;
begin
  shp := ShapeCaption;
  if Assigned(shp) then
    shp.Text := FCaption;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanel.ShapeCaption: TText;
var
  shp: TTMSFMXNavBarTabShape;
begin
  Result := nil;
  shp := FTab;
  if Assigned(shp) then
    Result := shp.ShapeCaption;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.SetBounds(X, Y, AWidth, AHeight: Single);
var
  R: TRectF;
begin
  if FInternalBoundSet or not Assigned(NavBar) or (csLoading in ComponentState) then
  begin
    inherited SetBounds(X, Y, AWidth, AHeight);
    if not (csReading in ComponentState) and not (csLoading in ComponentState) then
    begin
      //UpdateAllSections;
      UpdateSectionsPos;
      UpdateControlBounds;
    end;
  end
  else
  begin
    R := NavBar.GetPanelRect;
    inherited SetBounds(R.Left, R.Top, R.Width, R.Height);
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.SetCaption(const Value: string);
begin
  if (FCaption <> Value) then
  begin
    FCaption := Value;
    if Assigned(NavBar) and (NavBar.GetUpdateCount = 0) then
      UpdateCaption;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.SetPanelIndex(const Value: Integer);
begin
  FPanelIndex := Value;
  if (csReading in ComponentState) or (csLoading in ComponentState) then
    Exit;

  if Assigned(FNavBar) and (Value >= 0) and (Value < FNavBar.PanelCount) then
    FNavBar.MovePanel(FNavBar.IndexOfPanel(Self), Value);
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanel.GetPanelIndex: Integer;
begin
  if Assigned(FNavBar) then
    Result := FNavBar.IndexOfPanel(Self)
  else
    Result := FPanelIndex;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.SetNavBar(const Value: TTMSFMXNavBar);
begin
  if (FNavBar <> Value) then
  begin
    if FNavBar <> nil then FNavBar.RemovePanel(Self);
    Parent := Value;
    if (Value <> nil) then
    begin
      Value.AddPanel(Self);
      if not (csLoading in ComponentState) then
      begin
        if Value.PanelCount > 1 then
        begin
          // assign panel properties
        end;
      end;
    end;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.SetParentComponent(Value: TComponent);
var
  ci, ni: Integer;
  ANavBar: TTMSFMXNavBar;
begin
  if ((Value is TTMSFMXNavBarPanel) or (Value is TTMSFMXNavBar)) and not (FUpdatingParent) then
  begin
    ANavBar := nil;
    if (Value is TTMSFMXNavBarPanel) then
    begin
      ANavBar := TTMSFMXNavBarPanel(Value).FNavBar;
    end
    else if (Value is TTMSFMXNavBar) then
    begin
      ANavBar := TTMSFMXNavBar(Value);
    end;

    if Assigned(ANavBar) then
    begin
      if (FNavBar <> ANavBar) then
      begin
        FUpdatingParent := True;
        NavBar := ANavBar;
        FUpdatingParent := False;
      end;

      if (FNavBar = ANavBar) then
      begin
        if (Value is TTMSFMXNavBarPanel) then
        begin
          ci := FNavBar.IndexOfPanel(self);
          ni := FNavBar.IndexOfPanel(TTMSFMXNavBarPanel(Value));
          Value := ANavBar;
          if (ci >= 0) and (ci < FNavBar.FPanels.Count) and
             (ni >= 0) and (ni < FNavBar.FPanels.Count) then
          begin
            FNavBar.MovePanel(ci, ni);
          end
          else
            raise Exception.Create('Invalid Parent '+inttostr(ci)+':'+inttostr(ni));
        end
        else if (Value is TTMSFMXNavBar) then
        begin
          Value := ANavBar;
        end;
      end
      else
        raise Exception.Create('Invalid Parent');
    end;
  end;
  inherited;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.SetSections(
  const Value: TTMSFMXNavBarPanelSections);
begin
  FSections.Assign(Value);
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.SetSelected;
begin
  if Assigned(NavBar) and (NavBar.ActivePanel <> Self) then
  begin
    NavBar.ActivePanel := Self;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanel.ShapeLeftRectangle: TRectangle;
var
  shp: TTMSFMXNavBarTabShape;
begin
  Result := nil;
  shp := FTab;
  if Assigned(shp) then
    Result := shp.ShapeLeftRectangle;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanel.ShapeLeftRectangleImage: TTMSFMXBitmap;
var
  shp: TTMSFMXNavBarTabShape;
begin
  Result := nil;
  shp := FTab;
  if Assigned(shp) then
    Result := shp.ShapeLeftRectangleImage;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanel.TabButtonShapeImage: TTMSFMXBitmap;
var
  shp: TTMSFMXNavBarTabButtonShape;
begin
  Result := nil;
  shp := FTabButton;
  if Assigned(shp) then
    Result := shp.ShapeImage;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanel.GetSectionShape(
  Section: TTMSFMXNavBarPanelSection): TTMSFMXNavBarPanelSectionShape;
var
  sn: string;
begin
  Result := nil;
  if Assigned(Section) then
  begin
    sn := 'FMXNavBarPanelSec'+inttostr(Section.Index);
    Result := DoesSectionExist(Self, sn);
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.Notification(AComponent: TComponent;
  Operation: TOperation);
var
  i: Integer;
begin
  inherited;

  if (Operation = opRemove) and not (csDestroying in ComponentState) then
  begin
    for i := 0 to Sections.Count - 1 do
    begin
      if AComponent = Sections[i].FControl then
      begin
        Sections[i].FControl := nil;
        Break;
      end;
    end;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.UpdateControlBounds;
var
  i: Integer;
begin
  for i := 0 to Sections.Count - 1 do
  begin
     Sections[i].UpdateControlBounds;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.UpdateAllSections;
var
  i: Integer;
begin
  for I := 0 to Sections.Count - 1  do
  begin
    AddSection(Sections[i]);
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.UpdateSectionsPos;
var
  i: Integer;
  //sn: String;
  sec: TTMSFMXNavBarPanelSectionShape;
  R: TRectF;
begin
  R := RectF(LocalRect.Left + Margins.Left + 1, LocalRect.Top + Margins.Top + 1,
             LocalRect.Right - Margins.Right - 1, DEFAULT_SECCAPTIONHEIGHT);
  for I := 0 to Sections.Count - 1  do
  begin
    //if (csDEsigning in ComponentState) then
      sec := Sections[i].FSectionShape;
    {else
    begin
      sn := 'FMXNavBarPanelSec'+inttostr(i);
      sec := DoesSectionExist(Self, sn);
    end;}

    if Assigned(sec) then
    begin
      sec.SetBounds(R.Left, R.Top, R.Width, Sec.Height);
      sec.Position.Y := R.Top;
      R.Top := R.Top + Sections[i].Height + 1;
    end
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanel.IsSection(
  AObject: TFmxObject): Boolean;
begin
  Result := Assigned(AObject) and (AObject is TTMSFMXNavBarPanelSectionShape);
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanel.AsSection(
  AObject: TFmxObject): TTMSFMXNavBarPanelSectionShape;
begin
  Result := AObject as TTMSFMXNavBarPanelSectionShape;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanel.DoesSectionExist(ParentElement: TControl;
  SecName: String): TTMSFMXNavBarPanelSectionShape;
var
  i: integer;
  ctrl: TFMXObject;
  l: TTMSFMXNavBarPanelSectionShape;
begin
  Result := nil;
  if Assigned(ParentElement) then
  begin
    for I := 0 to ParentElement.ChildrenCount - 1 do
    begin
      ctrl := ParentElement.Children[i];
      if IsSection(ctrl) then
      begin
        l := AsSection(ctrl);
        if UpperCase(l.StyleName) = UpperCase(SecName) then
        begin
          Result := l;
          Break;
        end;
      end;
    end;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.CloneChildren(Source, Destination: TFMXObject);
var
  i: integer;
  fmxclone: TFmxObject;
begin
  for I := 0 to Source.ChildrenCount - 1 do
  begin
    fmxclone := Source.Children[I].Clone(Destination);
    Destination.AddObject(fmxclone);
    CloneChildren(Source.Children[I], fmxclone);
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.AddSection(ASection: TTMSFMXNavBarPanelSection);
begin
  if Assigned(NavBar) then
    AddSection(ASection, NavBar.GetDefaultSectionShape, Self);
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.AddSection(ASection: TTMSFMXNavBarPanelSection;
  SecElement, ParentElement: TControl);
var
  sn: String;
  newsec, sec: TTMSFMXNavBarPanelSectionShape;
  shptxt: TTMSFMXHTMLText;
begin
  if not Assigned(ASection) or not Assigned(SecElement) or not Assigned(ParentElement) then
    Exit;

  if (csDestroying in ComponentState) or (csLoading in ComponentState) then
    Exit;

  sn := 'FMXNavBarPanelSec'+inttostr(ASection.Index);
  sec := DoesSectionExist(ParentElement, sn);
  if Assigned(sec) then
  begin
    newsec := sec;
    newsec.BeginUpdate;
  end
  else
  begin
    newsec := AsSection(SecElement.Clone(ParentElement));
    newsec.BeginUpdate;
    CloneChildren(SecElement, newsec);
    //newsec.Align := TAlignLayout.alBottom;
    newsec.HitTest := False;
    newsec.StyleName := sn;
    if (Index >= 0) then
      newsec.Name := sn + 'Name' + Inttostr(Index);
    newsec.Visible := True;
  end;

  ASection.SectionShape := newsec;
  newsec.NavBarPanel := Self;
  newsec.Position.Y := 0;
  newsec.Position.X := 0;
  newsec.Width := ParentElement.Width;

  if not ParentElement.IsChild(newsec) then
    ParentElement.AddObject(newsec);
  newsec.EndUpdate;

  shptxt := newsec.ShapeCaption;
  if Assigned(shptxt) and (shptxt is TTMSFMXHTMLText) then
  begin
    shptxt.Text := ASection.Caption;
    if Assigned(NavBar) then
      shptxt.BitmapContainer := NavBar.BitmapContainer;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanel.ClearSections(ParentElement: TControl);
var
  str: TStringList;
  lName: String;
  i: integer;
  ctrl: TFMXObject;
  l: TTMSFMXNavBarPanelSectionShape;
begin
  str := TStringList.Create;
  for i := 0 to FSections.Count - 1 do
  begin
    lName := 'FMXNavBarPanelSec'+inttostr(Sections[i].Index);
    str.Add(UpperCase(lName+'Name'+ Inttostr(Index)));
  end;

  if Assigned(ParentElement) then
  begin
    for I := ParentElement.ChildrenCount - 1 downto 0 do
    begin
      ctrl := ParentElement.Children[i];
      if IsSection(ctrl) then
      begin
        l := AsSection(ctrl);
        if str.IndexOf(UpperCase(l.Name)) = -1 then
        begin
          {$IFDEF DELPHI_LLVM}
          l.Release;
          {$ELSE}
          l.Free;
          {$ENDIF}
        end;
      end;
    end;
  end;

  for i := 0 to FSections.Count - 1 do
  begin
    Sections[i].FSectionShape := nil;
  end;

  str.Free;
end;

//------------------------------------------------------------------------------

{ TTMSFMXNavBarTabShape }

constructor TTMSFMXNavBarTabShape.Create(AOwner: TComponent);
begin
  inherited;
  Height := DEFAULT_TABHEIGHT;
  if (csDesigning in ComponentState) and not
    ((csReading in Owner.ComponentState) or (csLoading in Owner.ComponentState)) then
  begin
    //Fill.Color := MakeColor(247, 247, 247);
    //Stroke.Color := MakeColor(224, 224, 224);
    //StrokeThickness := 2;
    //Corners := [];
  end;
  //DesignVisible := True;
  //HitTest := True;
  Corners := AllCorners;
  {$IFDEF DELPHIXE6_LVL}
  FFillSelected := TBrush.Create(TBrushKind.Solid, claWhite);
  FStrokeSelected := TBrush.Create(TBrushKind.Solid, claBlack);
  FFillHot := TBrush.Create(TBrushKind.Solid, claWhite);
  FStrokeHot := TBrush.Create(TBrushKind.Solid, claBlack);
  {$ELSE}
  FFillSelected := TBrush.Create(TBrushKind.bkSolid, claWhite);
  FStrokeSelected := TBrush.Create(TBrushKind.bkSolid, claBlack);
  FFillHot := TBrush.Create(TBrushKind.bkSolid, claWhite);
  FStrokeHot := TBrush.Create(TBrushKind.bkSolid, claBlack);
  {$ENDIF}
end;

//------------------------------------------------------------------------------

destructor TTMSFMXNavBarTabShape.Destroy;
begin
  FStrokeSelected.Free;
  FFillSelected.Free;
  FStrokeHot.Free;
  FFillHot.Free;
  inherited;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabShape.Click;
begin
  inherited;
  if Assigned(NavBarPanel) then
    NavBarPanel.SetSelected;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabShape.DoMouseEnter;
begin
  inherited;
  Repaint;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabShape.DoMouseLeave;
begin
  inherited;
  Repaint;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabShape.Paint;
var
  R: TRectF;
begin
  if IsSelected then
  begin
    Canvas.Fill.Assign(FillSelected);
    Canvas.Stroke.Assign(StrokeSelected);
  end
  else if IsHot then
  begin
    Canvas.Fill.Assign(FillHot);
    Canvas.Stroke.Assign(StrokeHot);
  end
  else
  begin
    Canvas.Stroke.Assign(Stroke);
    Canvas.Fill.Assign(Fill);
  end;

  R := BoundsRect;
  Canvas.FillRect(R, XRadius, YRadius, Corners, Opacity);
  Canvas.DrawRectSides(r, XRadius, YRadius, Corners, Opacity, Sides);
  //Canvas.FillRect(R, XRadius, YRadius, Corners, AbsoluteOpacity, CornerType);
  //Canvas.DrawRect(R, XRadius, YRadius, Corners, AbsoluteOpacity, CornerType);
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarTabShape.GetIsHot: Boolean;
begin
  Result := IsMouseOver;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarTabShape.GetIsSelected: Boolean;
begin
  Result := False;
  if Assigned(NavBarPanel) then
    Result := NavBarPanel.IsSelected;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabShape.SetFillHot(const Value: TBrush);
begin
  if FFillHot <> Value then
  begin
    FFillHot.Assign(Value);
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabShape.SetFillSelected(const Value: TBrush);
begin
  if FFillSelected <> Value then
  begin
    FFillSelected.Assign(Value);
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabShape.SetStrokeHot(const Value: TBrush);
begin
  if FStrokeHot <> Value then
  begin
    FStrokeHot.Assign(Value);
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabShape.SetStrokeSelected(const Value: TBrush);
begin
  if FStrokeSelected <> Value then
  begin
    FStrokeSelected.Assign(Value);
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarTabShape.ShapeCaption: TText;
var
  shp: TTMSFMXNavBarTabShape;
  fmxobj: TFMXObject;
begin
  Result := nil;
  shp := Self;
  if Assigned(shp) then
  begin
    fmxobj := shp.FindStyleResource('tabcaption');
    if fmxobj is TText then
      Result := fmxobj as TText;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarTabShape.ShapeLeftRectangle: TRectangle;
var
  shp: TTMSFMXNavBarTabShape;
  fmxobj: TFMXObject;
begin
  Result := nil;
  shp := Self;
  if Assigned(shp) then
  begin
    fmxobj := shp.FindStyleResource('tableftrectangle');
    if fmxobj is TRectangle then
      Result := fmxobj as TRectangle;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarTabShape.ShapeLeftRectangleImage: TTMSFMXBitmap;
var
  shp: TRectangle;
  fmxobj: TFMXObject;
begin
  Result := nil;
  shp := ShapeLeftRectangle;
  if Assigned(shp) then
  begin
    fmxobj := shp.FindStyleResource('tableftrectangleimage');
    if fmxobj is TTMSFMXBitmap then
      Result := fmxobj as TTMSFMXBitmap;
  end;
end;

//------------------------------------------------------------------------------

{ TTMSFMXNavBarTabButtonShape }

constructor TTMSFMXNavBarTabButtonShape.Create(AOwner: TComponent);
begin
  inherited;
  Height := DEFAULT_TABBUTTONHEIGHT;
  Width := 18;
  if (csDesigning in ComponentState) and not
    ((csReading in Owner.ComponentState) or (csLoading in Owner.ComponentState)) then
  begin
    //Fill.Color := MakeColor(247, 247, 247);
    //Stroke.Color := MakeColor(224, 224, 224);
    //StrokeThickness := 2;
    //Corners := [];
  end;
  //DesignVisible := True;
  //HitTest := True;
  Corners := AllCorners;
  {$IFDEF DELPHIXE6_LVL}
  FFillSelected := TBrush.Create(TBrushKind.Solid, claWhite);
  FStrokeSelected := TBrush.Create(TBrushKind.Solid, claBlack);
  FFillHot := TBrush.Create(TBrushKind.Solid, claWhite);
  FStrokeHot := TBrush.Create(TBrushKind.Solid, claBlack);
  {$ELSE}
  FFillSelected := TBrush.Create(TBrushKind.bkSolid, claWhite);
  FStrokeSelected := TBrush.Create(TBrushKind.bkSolid, claBlack);
  FFillHot := TBrush.Create(TBrushKind.bkSolid, claWhite);
  FStrokeHot := TBrush.Create(TBrushKind.bkSolid, claBlack);
  {$ENDIF}
end;

//------------------------------------------------------------------------------

destructor TTMSFMXNavBarTabButtonShape.Destroy;
begin
  FStrokeSelected.Free;
  FFillSelected.Free;
  FStrokeHot.Free;
  FFillHot.Free;
  inherited;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabButtonShape.Click;
begin
  inherited;
  if Assigned(NavBarPanel) then
    NavBarPanel.SetSelected;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabButtonShape.DoMouseEnter;
begin
  inherited;
  Repaint;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabButtonShape.DoMouseLeave;
begin
  inherited;
  Repaint;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabButtonShape.Paint;
var
  R: TRectF;
begin
  if IsSelected then
  begin
    Canvas.Fill.Assign(FillSelected);
    Canvas.Stroke.Assign(StrokeSelected);
  end
  else if IsHot then
  begin
    Canvas.Fill.Assign(FillHot);
    Canvas.Stroke.Assign(StrokeHot);
  end
  else
  begin
    Canvas.Stroke.Assign(Stroke);
    Canvas.Fill.Assign(Fill);
  end;

  R := BoundsRect;
  Canvas.FillRect(R, XRadius, YRadius, Corners, Opacity);
  Canvas.DrawRectSides(r, XRadius, YRadius, Corners, Opacity, Sides);
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarTabButtonShape.GetIsHot: Boolean;
begin
  Result := IsMouseOver;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarTabButtonShape.GetIsSelected: Boolean;
begin
  Result := False;
  if Assigned(NavBarPanel) then
    Result := NavBarPanel.IsSelected;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabButtonShape.SetFillHot(const Value: TBrush);
begin
  if FFillHot <> Value then
  begin
    FFillHot.Assign(Value);
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabButtonShape.SetFillSelected(const Value: TBrush);
begin
  if FFillSelected <> Value then
  begin
    FFillSelected.Assign(Value);
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabButtonShape.SetStrokeHot(const Value: TBrush);
begin
  if FStrokeHot <> Value then
  begin
    FStrokeHot.Assign(Value);
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarTabButtonShape.SetStrokeSelected(const Value: TBrush);
begin
  if FStrokeSelected <> Value then
  begin
    FStrokeSelected.Assign(Value);
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarTabButtonShape.ShapeImage: TTMSFMXBitmap;
var
  fmxobj: TFMXObject;
begin
  Result := nil;
  fmxobj := FindStyleResource('tabbuttonimage');
  if fmxobj is TTMSFMXBitmap then
    Result := fmxobj as TTMSFMXBitmap;
end;

//------------------------------------------------------------------------------

{ TTMSFMXNavBarSplitterShape }

constructor TTMSFMXNavBarSplitterShape.Create(AOwner: TComponent);
begin
  inherited;
  Height := DEFAULT_SPLITTERHEIGHT;
  if (csDesigning in ComponentState) and not
    ((csReading in Owner.ComponentState) or (csLoading in Owner.ComponentState)) then
  begin
    //Fill.Color := MakeColor(247, 247, 247);
    //Stroke.Color := MakeColor(224, 224, 224);
    //StrokeThickness := 2;
    //Corners := [];
  end;
  FSizeGrip := gsDots;
  FSizeGripColor := claBlack;
  {$IFDEF DELPHIXE6_LVL}
  FFillHot := TBrush.Create(TBrushKind.Solid, claWhite);
  FStrokeHot := TBrush.Create(TBrushKind.Solid, claBlack);
  {$ELSE}
  FFillHot := TBrush.Create(TBrushKind.bkSolid, claWhite);
  FStrokeHot := TBrush.Create(TBrushKind.bkSolid, claBlack);
  {$ENDIF}
end;

//------------------------------------------------------------------------------

destructor TTMSFMXNavBarSplitterShape.Destroy;
begin
  FStrokeHot.Free;
  FFillHot.Free;
  inherited;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarSplitterShape.Click;
begin
  inherited;

end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarSplitterShape.DoMouseEnter;
begin
  inherited;
  Repaint;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarSplitterShape.DoMouseLeave;
begin
  inherited;
  Repaint;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarSplitterShape.Paint;
var
  r, dr: TRectF;
  PS, i: Integer;
begin
  if IsHot then
  begin
    Canvas.Fill.Assign(FillHot);
    Canvas.Stroke.Assign(StrokeHot);
  end
  else
  begin
    Canvas.Stroke.Assign(Stroke);
    Canvas.Fill.Assign(Fill);
  end;

  r := LocalRect;
  Canvas.FillRect(R, XRadius, YRadius, Corners, Opacity);
  Canvas.DrawRectSides(r, XRadius, YRadius, Corners, Opacity, Sides);

  if (SizeGrip = gsDots) and (SizeGripColor <> claNull) then
  begin
    Canvas.Fill.Color := claWhite;
    {$IFDEF DELPHIXE6_LVL}
    Canvas.Stroke.Kind := TBrushKind.None;
    {$ELSE}
    Canvas.Stroke.Kind := TBrushKind.bkNone;
    {$ENDIF}

    PS := (Round(Width) - 34 {Dots Length}) div 2;
    dr := RectF(PS + 1, R.Top + 3, PS + 3, R.Top + 5);
    for i := 1 to 9 do
    begin
      Canvas.FillRect(dr, XRadius, YRadius, AllCorners, AbsoluteOpacity);
      dr := RectF(dr.Left + 4, dr.Top, dr.Left + 6, dr.Bottom);
    end;

    Canvas.Fill.Color := SizeGripColor;
    {$IFDEF DELPHIXE6_LVL}
    Canvas.Stroke.Kind := TBrushKind.Solid;
    {$ELSE}
    Canvas.Stroke.Kind := TBrushKind.bkSolid;
    {$ENDIF}
    Canvas.Stroke.Color := SizeGripColor;
    dr := RectF(PS, dr.Top - 1, PS + 2, dr.Top + 1);
    for i := 1 to 9 do
    begin
      Canvas.FillRect(dr, XRadius, YRadius, AllCorners, AbsoluteOpacity);
      dr := RectF(dr.Left + 4, dr.Top, dr.Left + 6, dr.Bottom);
    end;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarSplitterShape.SetFillHot(const Value: TBrush);
begin
  if FFillHot <> Value then
  begin
    FFillHot.Assign(Value);
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarSplitterShape.GetIsHot: Boolean;
begin
  Result := IsMouseOver;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarSplitterShape.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  inherited;
  if FPressed then
  begin
    Capture;
    FDownPos := PointF(X, Y);
    if Assigned(NavBar) then
    begin
      FDefTabHeight := NavBar.GetTabHeight;
      FOldSplitterPos := NavBar.SplitterPosition;
    end
    else
    begin
      FDefTabHeight := DEFAULT_TABHEIGHT;
      FOldSplitterPos := -1;
    end;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarSplitterShape.MouseMove(Shift: TShiftState; X,
  Y: Single);
var
  i: Integer;
begin
  inherited;
  if FPressed and (FOldSplitterPos >= 0) and (FDefTabHeight > 0) and Assigned(NavBar) and (abs(FMovePos.Y - Y) >= 5) then
  begin
    FMovePos := PointF(X, Y);
    i := round(Y - FDownPos.Y) div (FDefTabHeight);
    //OutputDebugString(PChar('++ i:'+inttostr(i) + ' FDownPos.Y: ' + inttostr(Round(FDownPos.Y)) + ' Y:'+inttostr(Round(Y))));
    if (i <> 0) then
    begin
      NavBar.SplitterPosition := NavBar.SplitterPosition - i;  // here i could be -ve
      //OutputDebugString(PChar('---FOldSplitterPos: ' + inttostr(FOldSplitterPos) + ' i:'+inttostr(i) + ' FDownPos.Y: ' + inttostr(Round(FDownPos.Y)) + ' Y:'+inttostr(Round(Y))));
    end;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarSplitterShape.MouseUp(Button: TMouseButton;
  Shift: TShiftState; X, Y: Single);
begin
  inherited;
  ReleaseCapture;
  Repaint;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarSplitterShape.SetSizeGrip(const Value: TSizeGripStyle);
begin
  if (FSizeGrip <> Value) then
  begin
    FSizeGrip := Value;
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarSplitterShape.SetSizeGripColor(const Value: TAlphaColor);
begin
  if (FSizeGripColor <> Value) then
  begin
    FSizeGripColor := Value;
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarSplitterShape.SetStrokeHot(const Value: TBrush);
begin
  if FStrokeHot <> Value then
  begin
    FStrokeHot.Assign(Value);
    Repaint;
  end;
end;

//------------------------------------------------------------------------------

{ TTMSFMXNavBarButtonShape }

constructor TTMSFMXNavBarButtonShape.Create(AOwner: TComponent);
begin
  inherited;
  Height := DEFAULT_TABBUTTONHEIGHT;
  Width := 20;
  DesignVisible := True;
  HitTest := True;
  Corners := AllCorners;
  {$IFDEF DELPHIXE6_LVL}
  FFillDown := TBrush.Create(TBrushKind.Solid, claWhite);
  FStrokeDown := TBrush.Create(TBrushKind.Solid, claBlack);
  FFillHot := TBrush.Create(TBrushKind.Solid, claWhite);
  FStrokeHot := TBrush.Create(TBrushKind.Solid, claBlack);
  {$ELSE}
  FFillDown := TBrush.Create(TBrushKind.bkSolid, claWhite);
  FStrokeDown := TBrush.Create(TBrushKind.bkSolid, claBlack);
  FFillHot := TBrush.Create(TBrushKind.bkSolid, claWhite);
  FStrokeHot := TBrush.Create(TBrushKind.bkSolid, claBlack);
  {$ENDIF}
end;

//------------------------------------------------------------------------------

destructor TTMSFMXNavBarButtonShape.Destroy;
begin
  FStrokeDown.Free;
  FFillDown.Free;
  FStrokeHot.Free;
  FFillHot.Free;
  inherited;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarButtonShape.Click;
begin
  inherited;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarButtonShape.DoMouseEnter;
begin
  inherited;
  if Enabled then
    Repaint;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarButtonShape.DoMouseLeave;
begin
  inherited;
  if Enabled then
    Repaint;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarButtonShape.GetIsHot: Boolean;
begin
  Result := IsMouseOver and Enabled;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarButtonShape.Paint;
var
  R: TRectF;
begin
  if FPressed then
  begin
    Canvas.Fill.Assign(FillDown);
    Canvas.Stroke.Assign(StrokeDown);
  end
  else if IsHot then
  begin
    Canvas.Fill.Assign(FillHot);
    Canvas.Stroke.Assign(StrokeHot);
  end
  else
  begin
    Canvas.Stroke.Assign(Stroke);
    Canvas.Fill.Assign(Fill);
  end;

  R := BoundsRect;
  Canvas.FillRect(R, XRadius, YRadius, Corners, Opacity);
  Canvas.DrawRectSides(r, XRadius, YRadius, Corners, Opacity, Sides);
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarButtonShape.SetFillDown(const Value: TBrush);
begin
  FFillDown.Assign(Value);
  Repaint;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarButtonShape.SetFillHot(const Value: TBrush);
begin
  FFillHot.Assign(Value);
  Repaint;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarButtonShape.SetStrokeDown(const Value: TBrush);
begin
  FStrokeDown.Assign(Value);
  Repaint;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarButtonShape.SetStrokeHot(const Value: TBrush);
begin
  FStrokeHot.Assign(Value);
  Repaint;
end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarButtonShape.ShapeImage: TTMSFMXBitmap;
var
  fmxobj: TFMXObject;
begin
  Result := nil;
  fmxobj := FindStyleResource('buttonimage');
  if fmxobj is TTMSFMXBitmap then
    Result := fmxobj as TTMSFMXBitmap;
end;

//------------------------------------------------------------------------------

{ TNavBarScroller }

constructor TNavBarScroller.Create;
begin
  inherited;
  FMin := 0;
  FMax := 0;
  FPosition := 0;
  FVisible := False;
end;

//------------------------------------------------------------------------------

function TNavBarScroller.CanGoBack: Boolean;
begin
  Result := Position > Min;
end;

//------------------------------------------------------------------------------

function TNavBarScroller.CanGoForward: Boolean;
begin
  Result := Position < Max;
end;

//------------------------------------------------------------------------------

procedure TNavBarScroller.SetMax(const Value: integer);
begin
  if Value >= FMin then FMax := Value;
  if (FPosition > FMax) then
    FPosition := FMax;
end;

//------------------------------------------------------------------------------

procedure TNavBarScroller.SetMin(const Value: integer);
begin
  if Value <= FMax then FMin := Value;
  if (FPosition < FMin) then
    FPosition := FMin;
end;

//------------------------------------------------------------------------------

procedure TNavBarScroller.SetPosition(const Value: integer);
begin
  FPosition := Value;
  if (FPosition < FMin) then
    FPosition := FMin;
  if (FPosition > FMax) then
    FPosition := FMax;
end;

//------------------------------------------------------------------------------

procedure TNavBarScroller.SetVisible(const Value: Boolean);
begin
  FVisible := Value;
end;

//------------------------------------------------------------------------------

{ TTMSFMXNavBarPanelSectionShape }

constructor TTMSFMXNavBarPanelSectionShape.Create(AOwner: TComponent);
begin
  inherited;
  Height := 16;
  Width := 290;
  Corners := [];
end;

//------------------------------------------------------------------------------

destructor TTMSFMXNavBarPanelSectionShape.Destroy;
begin

  inherited;
end;

//------------------------------------------------------------------------------

procedure TTMSFMXNavBarPanelSectionShape.Paint;
begin
  inherited;

end;

//------------------------------------------------------------------------------

function TTMSFMXNavBarPanelSectionShape.ShapeCaption: TTMSFMXHTMLText;
var
  shp: TTMSFMXNavBarPanelSectionShape;
  fmxobj: TFMXObject;
begin
  Result := nil;
  shp := Self;
  if Assigned(shp) then
  begin
    fmxobj := shp.FindStyleResource('sectioncaption');
    if fmxobj is TTMSFMXHTMLText then
      Result := fmxobj as TTMSFMXHTMLText;
  end;
end;

//------------------------------------------------------------------------------


initialization
begin
  RegisterFmxClasses([TTMSFMXNavBar, TTMSFMXNavBarPanel, TTMSFMXNavBarTabShape,
                      TTMSFMXNavBarSplitterShape, TTMSFMXNavBarTabButtonShape,
                      TTMSFMXNavBarButtonShape, TTMSFMXNavBarPanelSectionShape]);
end;

end.
