{ ------------------------------------------------------------- }
{ Purpose : NextLayout 6                                        }
{ By      : Bojan Nikolic                                       }
{ For     : BergSoft                                            }
{ ------------------------------------------------------------- }
{ Copyright (C) BergSoft.net 2013. All Rights Reserved.         }
{ ------------------------------------------------------------- }
{$I '..\NxSuite6.inc'}
unit NxLayoutNodes6;

interface

uses
  { Standard }
  Types, Classes, Windows, Controls, Graphics, StdCtrls, ExtCtrls, ImgList,
  {$IFDEF UI_TYPES}UITypes,{$ENDIF}
  { Next Standard 6 }
  NxConsts6, NxTypes6, NxClasses6, NxEdit6, NxIntf6, NxNodes6, NxAssociates6,
  { NextLayout 6 }
  NxLayoutIntf6, NxLayoutStylePaint6;

const
  clDarkBtnFace = $00404040;
  clDarkBtnShadow = $00303030;
  clDarkBtnHighlight = $00484848;

type
  TNxLayoutNode6 = class;
  TNxLayoutNodeClass = class of TNxLayoutNode6;

  TNxLayoutNodeView = class;
  TNxLayoutNodeViewClass = class of TNxLayoutNodeView;

  TNxNodeViewStyle = set of (ntFocused);
  TNxNodeViewOptions = set of (npShowBounds);

  TNxClearing = set of (clLeft, clRight);

  TNxNodeEntity = (enNone, enToggleButton, enEdit, enIconBefore, enTextBefore,
    enContent, enIconAfter, enTextAfter);

  TNxLayoutNodeEntity = enIconBefore..enTextAfter;
  TNxLayoutNodeEntities = set of TNxLayoutNodeEntity;

  TNxLayoutNodeState = set of (nsReadingProperty);

  TNxProcNodesOperation = set of (noPaint, noCalc, noHitTest);

  TNxNodeViewResult = record
    Result: Boolean;
    Rect: TRect;
    Element: TNxNodeEntity;
  end;

  { INxLayoutControl }

  INxLayoutControl = interface
    ['{D16CBE23-00FB-4E11-AB16-47278F5D043A}']
    procedure DoClear;
    procedure DoSetProperty(Node: TNxLayoutNode6);
    function EditNode(Node: TNxLayoutNode6): Boolean;
    function GetAssociates: TNxAssociates6;
    procedure SetActiveNode(const Value: TNxLayoutNode6);
    procedure ActivateHint(Location: TPoint; Text: WideString);
    procedure DeactivateHint;
    procedure Invalidate;
    procedure NodeChanged(Node: TNxLayoutNode6; Element: TNxNodeEntity);
    property Associates: TNxAssociates6 read GetAssociates;
  end;

  { TNxLayoutNodeList }

  TNxLayoutNodeList = class
  private
    FControl: INxLayoutControl;
    FNodeList: TList;
    FOwnerNode: TNxLayoutNode6;
    { Property Accessors }
    function GetCount: Integer;
    function GetNode(const IndexOrName: Variant): TNxLayoutNode6; overload;
  public
    constructor Create(AOwnerNode: TNxLayoutNode6); virtual;
    destructor Destroy; override;
    { Methods }
    function Add(ClassType: TNxLayoutNodeClass): TNxLayoutNode6; overload;
    procedure Add(Node: TNxLayoutNode6); overload;
    procedure Clear;
    procedure Delete(Index: Integer);
    function Insert(ClassType: TNxLayoutNodeClass; Index: Integer): TNxLayoutNode6; overload;
    procedure Remove(Node: TNxLayoutNode6);
    function HasChildren: Boolean;
    function IndexOf(const Node: TNxLayoutNode6): Integer;
    { Properties }
    property Control: INxLayoutControl read FControl write FControl;
    property Count: Integer read GetCount;
    property Node[const IndexOrName: Variant]: TNxLayoutNode6 read GetNode; default;
    property OwnerNode: TNxLayoutNode6 read FOwnerNode;
  end;

  TNxCustomDrawNodeContentEvent = procedure (Sender: TObject; ContentRect: TRect) of object;

  { TNxLayoutNode6 }

  TNxLayoutNode6 = class(TNxNodeComponent)
  private
    { Property Fields }
    FBindProperty: string;
    FChildNodes: TNxLayoutNodeList;
    FClearing: TNxClearing;
    FClientWidth: Integer;
    FColor: TColor;
    FEnabled: Boolean;
    FExpanded: Boolean;
    FExpandLock: Boolean;
    FFocusing: Boolean;
    FHeight: Integer;
    FHint: WideString;
    FIconIndexAfter: TImageIndex;
    FIconIndexBefore: TImageIndex;
    FInplaceEdit: INxInplaceEdit;
    FLineHeight: Integer;
    FMargins: TMargins;
    FOnChange: TNotifyEvent;
    FOnCustomDrawContent: TNxCustomDrawNodeContentEvent;
    FOnImageAfterClick: TNotifyEvent;
    FOnImageBeforeClick: TNotifyEvent;
    FPadding: TPadding;
    FParentColor: Boolean;
    FParentList: TNxLayoutNodeList;
    FParentNode: TNxLayoutNode6;
    FState: TNxLayoutNodeState;
    FTextAfter: WideString;
    FTextAfterWidth: Integer;
    FTextBefore: WideString;
    FTextBeforeAlignment: TAlignment;
    FTextBeforeWidth: Integer;
    FView: TNxLayoutNodeView;
    FVisibleEntities: TNxLayoutNodeEntities;
    FWidth: Integer;
    { Property Accessors }
    function GetBestSize: TSize;
    function GetClientWidth: Integer;
    function GetControl: INxLayoutControl;
    procedure SetBindProperty(const Value: string);
    procedure SetClearing(const Value: TNxClearing);
    procedure SetClientWidth(const Value: Integer);
    procedure SetColor(const Value: TColor);
    procedure SetEnabled(const Value: Boolean);
    procedure SetExpanded(const Value: Boolean);
    procedure SetExpandLock(const Value: Boolean);
    procedure SetFocusing(const Value: Boolean);
    procedure SetHeight(const Value: Integer);
    procedure SetHint(const Value: WideString);
    procedure SetIconIndexAfter(const Value: TImageIndex);
    procedure SetIconIndexBefore(const Value: TImageIndex);
    procedure SetInplaceEdit(const Value: INxInplaceEdit);
    procedure SetLineHeight(const Value: Integer);
    procedure SetMargins(const Value: TMargins);
    procedure SetPadding(const Value: TPadding);
    procedure SetParentColor(const Value: Boolean);
    procedure SetParentLayoutNode(const Value: TNxLayoutNode6);
    procedure SetTextAfter(const Value: WideString);
    procedure SetTextAfterWidth(const Value: Integer);
    procedure SetTextBefore(const Value: WideString);
    procedure SetTextBeforeAlignment(const Value: TAlignment);
    procedure SetTextBeforeWidth(const Value: Integer);
    procedure SetVisibleEntities(const Value: TNxLayoutNodeEntities);
    procedure SetWidth(const Value: Integer);
  protected
    { DFM }
    procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
    procedure SetParentComponent(Value: TComponent); override;
    { Property Accessors }
    function GetChildCount: Integer; override;
    function GetChildNodes: INxNodeList; override;
    function GetIndex: Integer; override;
    function GetLevel: Integer; override;
    { INxBase }
    function GetAsBoolean: Boolean; override;
    function GetAsDateTime: TDateTime; override;
    function GetAsFloat: Double; override;
    function GetAsInteger: Integer; override;
    function GetAsString: WideString; override;
    function GetAsUTF8String: UTF8String; override;
    procedure SetAsBoolean(const Value: Boolean); override;
    procedure SetAsDateTime(const Value: TDateTime); override;
    procedure SetAsFloat(const Value: Double); override;
    procedure SetAsInteger(const Value: Integer); override;
    procedure SetAsString(const Value: WideString); override;
    procedure SetAsUTF8String(const Value: UTF8String); override;
    { INxNode }
    function GetHidden: Boolean;
    { Event Handlers }
    procedure DoChange; dynamic;
    procedure DoChildAdd(const Node: INxNode); override;
    procedure DoCustomDrawContent(ContentRect: TRect); dynamic;
    procedure DoIconAfterClick; dynamic;
    procedure DoIconBeforeClick; dynamic;
    { Methods }
    procedure Changed(Entity: TNxNodeEntity = enContent);
    function GetViewClass: TNxLayoutNodeViewClass; virtual;
    procedure PrepareEdit; virtual;
    procedure ValueChanged;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { DFM }
    function GetParentComponent: TComponent; override;
    function HasParent: Boolean; override;
    { Methods }
    procedure AssignEditing; virtual; abstract;
    procedure AssignValue(Source: INxBase); virtual;
    function BeginEdit: Boolean; virtual;
    function CanEdit: Boolean; virtual;
    function CanFocus: Boolean; virtual;
    function CreateInplaceEdit: INxInplaceEdit; virtual;
    function EndEdit(Assign: Boolean): Boolean; virtual;
    function IsTopLevel: Boolean;
    { Properties }
    property AsBoolean: Boolean read GetAsBoolean write SetAsBoolean;
    property AsDateTime: TDateTime read GetAsDateTime write SetAsDateTime;
    property AsFloat: Double read GetAsFloat write SetAsFloat;
    property AsInteger: Integer read GetAsInteger write SetAsInteger;
    property AsString: WideString read GetAsString write SetAsString;
    property AsUTF8String: UTF8String read GetAsUTF8String write SetAsUTF8String;
    property Level: Integer read GetLevel;
    property ParentList: TNxLayoutNodeList read FParentList;
    property ParentNode: TNxLayoutNode6 read FParentNode write SetParentLayoutNode;
    property State: TNxLayoutNodeState read FState write FState;
    property View: TNxLayoutNodeView read FView;
  published
    { Properties }
    property BestSize: TSize read GetBestSize;
    property BindProperty: string read FBindProperty write SetBindProperty;
    property Color: TColor read FColor write SetColor default clNone;
    property Clearing: TNxClearing read FClearing write SetClearing default [];
    property ClientWidth: Integer read GetClientWidth write SetClientWidth default 0;
    property ChildNodes: TNxLayoutNodeList read FChildNodes;
    property Control: INxLayoutControl read GetControl;
    property Enabled: Boolean read FEnabled write SetEnabled default True;
    property Expanded: Boolean read FExpanded write SetExpanded default True;
    property ExpandLock: Boolean read FExpandLock write SetExpandLock default False;
    property Focusing: Boolean read FFocusing write SetFocusing default True;
    property Height: Integer read FHeight write SetHeight default 0;
    property Hint: WideString read FHint write SetHint;
    property IconIndexAfter: TImageIndex read FIconIndexAfter write SetIconIndexAfter default -1;
    property IconIndexBefore: TImageIndex read FIconIndexBefore write SetIconIndexBefore default -1;
    property InplaceEdit: INxInplaceEdit read FInplaceEdit write SetInplaceEdit;
    property LineHeight: Integer read FLineHeight write SetLineHeight default 20;
    property Margins: TMargins read FMargins write SetMargins;
    property Padding: TPadding read FPadding write SetPadding;
    property ParentColor: Boolean read FParentColor write SetParentColor default True;
    property TextAfter: WideString read FTextAfter write SetTextAfter;
    property TextAfterWidth: Integer read FTextAfterWidth write SetTextAfterWidth default 0;
    property TextBefore: WideString read FTextBefore write SetTextBefore;
    property TextBeforeAlignment: TAlignment read FTextBeforeAlignment write SetTextBeforeAlignment default taRightJustify;
    property TextBeforeWidth: Integer read FTextBeforeWidth write SetTextBeforeWidth default 0;
    property VisibleEntities: TNxLayoutNodeEntities read FVisibleEntities
      write SetVisibleEntities default [enIconBefore, enTextBefore, enIconAfter, enTextAfter];
    property Width: Integer read FWidth write SetWidth default 75;
    { Events }
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
    property OnCustomDrawContent: TNxCustomDrawNodeContentEvent read FOnCustomDrawContent write FOnCustomDrawContent;
    property OnImageAfterClick: TNotifyEvent read FOnImageAfterClick write FOnImageAfterClick;
    property OnImageBeforeClick: TNotifyEvent read FOnImageBeforeClick write FOnImageBeforeClick;
  end;

  { TNxLayoutNodeView }

  TNxLayoutNodeView = class(TNxObjectView)
  private
    FCaptured: Boolean;
    FImages: TImageList;
    FLineHeight: Integer;
    FNode: TNxLayoutNode6;
    FNodeStyle: TNxNodeViewStyle;
    FOptions: TNxNodeViewOptions;
    FState: TNxButtonState;
    FStylePaint: INxLayoutStylePaint;
    FColor: TColor;
    { Property Accessors }
    function GetAfterSize: TSize;
    function GetBeforeSize: TSize;
    function GetCaptured: Boolean;
    function GetContentHeight: Integer;
    function GetContentRect: TRect;
    function GetToggleButtonRect: TRect;
    function GetImages: TImageList;
    function GetNode: TNxLayoutNode6;
    function GetNodeStyle: TNxNodeViewStyle;
    function GetOptions: TNxNodeViewOptions;
    function GetTextAfterWidth: Integer;
    function GetTextBeforeWidth: Integer;
    procedure SetCaptured(const Value: Boolean);
    procedure SetImages(const Value: TImageList);
    procedure SetNodeStyle(const Value: TNxNodeViewStyle);
    procedure SetOptions(const Value: TNxNodeViewOptions);
    procedure SetState(const Value: TNxButtonState);
  protected
    function GetContentBestSize: TSize; virtual;
    function GetEntityRect(Entity: TNxNodeEntity): TRect; virtual;
    function GetNodeSize: TSize; virtual;
    function GetState: TNxButtonState; virtual;
    function ProcNode(Operations: TNxProcNodesOperation; const X, Y: Integer): TNxNodeViewResult;
    { Painting Methods }
    procedure PaintContent; virtual;
    procedure PaintToggleButton;
    { Misc. }
    procedure StateChanged; virtual;
  public
    constructor Create(ANode: TNxLayoutNode6); virtual;
    destructor Destroy; override;
    function IsIndexValid(Value: TImageIndex): Boolean;
    { Mouse & Keyb. }
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    { Painting Methods }
    procedure Paint; override;
    { Properties }
    property AfterSize: TSize read GetAfterSize;
    property BeforeSize: TSize read GetBeforeSize;
    property Captured: Boolean read GetCaptured write SetCaptured;
    property Color: TColor read FColor write FColor;
    property ContentBestSize: TSize read GetContentBestSize;
    property ContentHeight: Integer read GetContentHeight;
    property ContentRect: TRect read GetContentRect;
    property EntityRect[Entity: TNxNodeEntity]: TRect read GetEntityRect;
    property Images: TImageList read GetImages write SetImages;
    property LineHeight: Integer read FLineHeight write FLineHeight;
    property Node: TNxLayoutNode6 read GetNode;
    property NodeSize: TSize read GetNodeSize;
    property NodeStyle: TNxNodeViewStyle read GetNodeStyle write SetNodeStyle;
    property Options: TNxNodeViewOptions read GetOptions write SetOptions;
    property State: TNxButtonState read GetState write SetState;
    property StylePaint: INxLayoutStylePaint read FStylePaint write FStylePaint;
    property TextAfterWidth: Integer read GetTextAfterWidth;
    property TextBeforeWidth: Integer read GetTextBeforeWidth;
    property ToggleButtonRect: TRect read GetToggleButtonRect;
  end;

  { TNxStringLayoutNode6 }

  TNxStringLayoutNode6 = class(TNxLayoutNode6)
  private
    FValue: WideString;
    { Property Accessors }
    procedure SetValue(const Value: WideString);
  protected
    { INxBase }
    function GetAsFloat: Double; override;
    function GetAsInteger: Integer; override;
    function GetAsString: WideString; override;
    procedure SetAsInteger(const Value: Integer); override;
    procedure SetAsFloat(const Value: Double); override;
    procedure SetAsString(const Value: WideString); override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Value: WideString read FValue write SetValue;
  end;

  { TNxFloatLayoutNode6 }

  TNxFloatLayoutNode6 = class(TNxLayoutNode6)
  private
    FMax: Double;
    FMin: Double;
    FValue: Double;
    { Property Accessors }
    procedure SetMax(const Value: Double);
    procedure SetMin(const Value: Double);
    procedure SetValue(const Value: Double);
  protected
    { INxBase }
    function GetAsFloat: Double; override;
    function GetAsInteger: Integer; override;
    function GetAsString: WideString; override;
    procedure SetAsInteger(const Value: Integer); override;
    procedure SetAsFloat(const Value: Double); override;
    procedure SetAsString(const Value: WideString); override;
  public
    constructor Create(AOwner: TComponent); override;
    function CheckRange: Boolean; virtual;
  published
    property Max: Double read FMax write SetMax;
    property Min: Double read FMin write SetMin;
    property Value: Double read FValue write SetValue;
  end;

  { TNxLabelLayoutNode6 }

  TNxLabelLayoutNode6 = class(TNxStringLayoutNode6)
  public
    function CanFocus: Boolean; override;
  end;

  { TNxButtonLayoutNode6 }

  TNxButtonLayoutNodeView = class(TNxLayoutNodeView)
  private
    FButtonState: TNxButtonState;
    procedure SetButtonState(const Value: TNxButtonState);
  protected
    property ButtonState: TNxButtonState read FButtonState write SetButtonState;
  public
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseLeave; override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); overload; override;
    procedure MouseUp; overload; override;
    procedure PaintContent; override;
  end;

  TNxButtonLayoutNode6 = class(TNxStringLayoutNode6)
  private
    FOnButtonClick: TNotifyEvent;
  protected
    procedure DoButtonClick; dynamic;
    function GetViewClass: TNxLayoutNodeViewClass; override;
  published
    property OnButtonClick: TNotifyEvent read FOnButtonClick write FOnButtonClick;
  end;

  { TNxEditLayoutNode6 }

  TNxEditLayoutNodeView = class(TNxLayoutNodeView)
  private
    function GetEditRect: TRect;
  protected
    function GetEntityRect(Entity: TNxNodeEntity): TRect; override;
  public
    procedure PaintContent; override;
    { Properties }
    property EditRect: TRect read GetEditRect;
  end;

  TNxEditLayoutNode6 = class(TNxLayoutNode6)
  private
    FEditWidth: Integer;
    FValue: WideString;
    procedure SetEditWidth(const Value: Integer);
    procedure SetValue(const Value: WideString);
  protected
    function GetViewClass: TNxLayoutNodeViewClass; override;
    procedure PrepareEdit; override;
    { INxBase }
    function GetAsFloat: Double; override;
    function GetAsInteger: Integer; override;
    function GetAsString: WideString; override;
    procedure SetAsFloat(const Value: Double); override;
    procedure SetAsInteger(const Value: Integer); override;
    procedure SetAsString(const Value: WideString); override;
  public
    constructor Create(AOwner: TComponent); override;
    procedure AssignEditing; override;
    function CanEdit: Boolean; override;
    function CanFocus: Boolean; override;
    function CreateInplaceEdit: INxInplaceEdit; override;
  published
    property EditWidth: Integer read FEditWidth write SetEditWidth default 60;
    property Value: WideString read FValue write SetValue;
  end;

  { TNxSpinLayoutNode6 }

  TNxSpinLayoutNodeView = class(TNxLayoutNodeView)
  private
    function GetEditRect: TRect;
  protected
    function GetEntityRect(Entity: TNxNodeEntity): TRect; override;
  public
    procedure PaintContent; override;
    { Properties }
    property EditRect: TRect read GetEditRect;
  end;

  TNxSpinLayoutNode6 = class(TNxFloatLayoutNode6)
  private
    FPrecision: Integer;
    procedure SetPrecision(const Value: Integer);
  protected
    function GetViewClass: TNxLayoutNodeViewClass; override;
    procedure PrepareEdit; override;
  public
    procedure AssignEditing; override;
    constructor Create(AOwner: TComponent); override;
    function CreateInplaceEdit: INxInplaceEdit; override;
  published
    property Precision: Integer read FPrecision write SetPrecision default 2;
  end;

  { TNxSeparatorLayoutNode6 }

  TNxSeparatorLayoutNodeView = class(TNxLayoutNodeView)
  protected
    function GetContentBestSize: TSize; override;
    procedure PaintContent; override;
  end;

  TNxSeparatorLayoutNode6 = class(TNxLayoutNode6)
  public
    constructor Create(AOwner: TComponent); override;
  protected
    function GetViewClass: TNxLayoutNodeViewClass; override;
  end;

  { TNxCheckBoxLayoutNode6 }

  INxCheckBoxNode = interface
    ['{0E370A47-FBAB-4498-958D-84BC77B601D7}']
    function GetButton: Boolean;
    function GetButtonImageIndex: TImageIndex;
    property Button: Boolean read GetButton;
    property ButtonImageIndex: TImageIndex read GetButtonImageIndex;
  end;

  TNxCheckBoxLayoutNodeView = class(TNxLayoutNodeView)
  private
    function GetCheckBox: INxCheckBoxNode;
    function GetCheckRect: TRect;
    function GetCheckBoxState: TCheckBoxState;
  protected
    function GetContentBestSize: TSize; override;
    function GetState: TNxButtonState; override;
    procedure PaintContent; override;
    procedure StateChanged; override;
    { Properties }
    property CheckBox: INxCheckBoxNode read GetCheckBox;
  public
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseLeave; override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    { Properties }
    property CheckRect: TRect read GetCheckRect;
    property CheckBoxState: TCheckBoxState read GetCheckBoxState;
  end;

  TNxCheckBoxLayoutNode6 = class(TNxLayoutNode6, INxCheckBoxNode)
  private
    FButton: Boolean;
    FButtonImageIndex: TImageIndex;
{$HINTS OFF}
    FOnButtonClick: TNotifyEvent;
{$HINTS ON}
    FValue: Boolean;
    { Property Accessors }
    function GetButton: Boolean;
    function GetButtonImageIndex: TImageIndex;
    procedure SetButton(const Value: Boolean);
    procedure SetButtonImageIndex(const Value: TImageIndex);
    procedure SetValue(const Value: Boolean);
  protected
    function GetAsBoolean: Boolean; override;
    function GetAsString: WideString; override;
    function GetViewClass: TNxLayoutNodeViewClass; override;
    procedure SetAsBoolean(const Value: Boolean); override;
    procedure SetAsString(const Value: WideString); override;
  public
    constructor Create(AOwner: TComponent); override;
    function CanFocus: Boolean; override;
    { Properties }
  published
    { Properties }
    property Button: Boolean read GetButton write SetButton default False;
    property ButtonImageIndex: TImageIndex read GetButtonImageIndex write SetButtonImageIndex default -1;
    property Value: Boolean read FValue write SetValue default False;
    { Events }
  end;

  { TNxTrackBarLayoutNode6 }

  TNxTrackBarLayoutNode6 = class;

  TNxTrackBarLayoutNodeView = class(TNxLayoutNodeView)
  private
    FAsInteger: Integer;
    function GetTrackBarNode: TNxTrackBarLayoutNode6;
    function GetTrackRect: TRect;
    procedure SetAsInteger(const Value: Integer);
  protected
    function GetContentBestSize: TSize; override;
    function GetSliderRect: TRect; virtual;
    function GetSliderSize: TSize; virtual;
    procedure PaintContent; override;
    procedure StateChanged; override;
  public
    function GetPositionAtPos(X, Y: Integer): Integer;
    { Mouse & Keyboard }
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseLeave; override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    { Properties }
    property AsInteger: Integer read FAsInteger write SetAsInteger;
    property TrackBarNode: TNxTrackBarLayoutNode6 read GetTrackBarNode;
    property TrackRect: TRect read GetTrackRect;
  end;

  TNxTrackBarLayoutNode6 = class(TNxFloatLayoutNode6)
  private
    FTrackHeight: Integer;
    { Property Accessors }
    procedure SetTrackHeight(const Value: Integer);
  protected
    function GetViewClass: TNxLayoutNodeViewClass; override;
  public
    constructor Create(AOwner: TComponent); override;
    function CanFocus: Boolean; override;
    function CheckRange: Boolean; override;
  published
    { Properties }
    property TrackHeight: Integer read FTrackHeight write SetTrackHeight default 4;
  end;

  { TNxToolbarFormNode }

  TNxToolbarLayoutNode6 = class;
  TNxToolbarNodeButton = class;
  TNxToolbarNodeButtons = class;

  TNxToolbarLayoutNodeView = class(TNxLayoutNodeView)
  private
    FButtonHint: THintWindow;
    FDownButton: Integer;
    FHintDelayTimer: TTimer;
    FHoverButton: Integer;
    { Property Acessors }
    function GetButton(Index: Integer): TNxToolbarNodeButton;
    function GetToolbarNode: TNxToolbarLayoutNode6;
    procedure SetDownButton(const Value: Integer);
    procedure SetHoverButton(const Value: Integer);
  protected
    procedure ActivateButtonHint(Button: TNxToolbarNodeButton);
    procedure DoHintDelayTimer(Sender: TObject);
    function GetContentBestSize: TSize; override;
    procedure PaintButton(ButtonRect: TRect; Text: WideString;
      ButtonState: TNxButtonState; ImageIndex: TImageIndex);
    procedure PaintContent; override;
    procedure PaintDivider(DividerRect: TRect);
    procedure ReleaseButtonHint;
  public
    constructor Create(ANode: TNxLayoutNode6); override;
    destructor Destroy; override;
    function GetButtonAtPos(Location: TPoint): Integer;
    function GetButtonRect(const Index: Integer): TRect;
    function GetButtonWidth(const Index: Integer): Integer; virtual;
    { Overrided Methods }
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseLeave; override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); overload; override;
    procedure MouseUp; overload; override;
    { Methods }
    procedure RefreshButton(const Index: Integer);
    { Properties }
    property Button[Index: Integer]: TNxToolbarNodeButton read GetButton;
    property DownButton: Integer read FDownButton write SetDownButton;
    property HoverButton: Integer read FHoverButton write SetHoverButton;
    property ToolbarNode: TNxToolbarLayoutNode6 read GetToolbarNode;
  end;

  TNxToolbarNodeButton = class(TCollectionItem)
  private
    FBindValue: WideString;
    FChecked: Boolean;
    FDivider: Boolean;
    FHint: WideString;
    FImageIndex: TImageIndex;
    FText: WideString;
    { Property Accessors }
    function GetButtons: TNxToolbarNodeButtons;
    procedure SetChecked(const Value: Boolean);
    procedure SetDivider(const Value: Boolean);
    procedure SetImageIndex(const Value: TImageIndex);
    procedure SetText(const Value: WideString);
  public
    { Overrided Methods }
    procedure Assign(Source: TPersistent); override;
    constructor Create(Collection: TCollection); override;
    { Methods }
    procedure ToggleChecked;
    property Buttons: TNxToolbarNodeButtons read GetButtons;
  published
    property Checked: Boolean read FChecked write SetChecked default False;
    property BindValue: WideString read FBindValue write FBindValue;
    property Divider: Boolean read FDivider write SetDivider default False;
    property Hint: WideString read FHint write FHint;
    property ImageIndex: TImageIndex read FImageIndex write SetImageIndex default Undefined;
    property Text: WideString read FText write SetText;
  end;

  TNxToolbarNodeButtons = class(TCollection)
  private
    FOwner: TNxToolbarLayoutNode6;
    function GetCheckedCount: Integer;
    function GetItem(Index: Integer): TNxToolbarNodeButton;
{$HINTS OFF}
    procedure Check(Button: TNxToolbarNodeButton);
{$HINTS ON}
    procedure SetItem(Index: Integer; const Value: TNxToolbarNodeButton);
  protected
    function CanUncheck: Boolean;
    function GetOwner: TPersistent; override;
  public
    constructor Create(AOwner: TNxToolbarLayoutNode6);
    function Add: TNxToolbarNodeButton;
    function IsGrouped: Boolean;
    procedure RefreshButton(const Index: Integer);
    procedure UncheckAll;
    procedure UncheckOther(Leave: TNxToolbarNodeButton);
    { Properties }
    property CheckedCount: Integer read GetCheckedCount;
    property Items[Index: Integer]: TNxToolbarNodeButton read GetItem write SetItem; default;
  end;

  TNxToolButtonClickEvent = procedure (Sender: TObject; Index: Integer) of object;

  TNxToolbarLayoutNode6 = class(TNxLayoutNode6)
  private
    { Property Fields }
    FAllowAlUp: Boolean;
    FButtons: TNxToolbarNodeButtons;
    FGrouped: Boolean;
    FImages: TImageList;
    FOnButtonClick: TNxToolButtonClickEvent;
    { Property Accessors }
    function GetCount: Integer;
    procedure SetImages(const Value: TImageList);
    procedure SetItems(const Value: TNxToolbarNodeButtons);
  protected
    { INxBase }
    function GetAsString: WideString; override;
    procedure SetAsString(const Value: WideString); override;
    { Overrided }
    function GetViewClass: TNxLayoutNodeViewClass; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    { Event Handlers }
    procedure DoButtonClick(Index: Integer); dynamic;
    { Overrided Methods }
    procedure Assign(Source: TPersistent); override;
    procedure RefreshButton(const Index: Integer);
  published
    property AllowAlUp: Boolean read FAllowAlUp write FAllowAlUp default True;
    property Buttons: TNxToolbarNodeButtons read FButtons write SetItems;
    property Count: Integer read GetCount;
    property Grouped: Boolean read FGrouped write FGrouped default False;
    property Images: TImageList read FImages write SetImages;
    { Events }
    property OnButtonClick: TNxToolButtonClickEvent read FOnButtonClick write FOnButtonClick;
  end;

implementation

uses
  { Standard }
  SysUtils, Math, Forms,
  { Next Standard 6 }
  NxGraphics6,
  { Next Layout 6 }
  NxLayout6;

{ TNxLayoutNodeList }

function TNxLayoutNodeList.Add(ClassType: TNxLayoutNodeClass): TNxLayoutNode6;
begin
  Result := ClassType.Create(nil);

  Add(Result);
end;

procedure TNxLayoutNodeList.Add(Node: TNxLayoutNode6);
begin
  { Is list is owned by Node? }
  if Assigned(OwnerNode) then
  begin

    { This node is Parent now }
    Node.ParentNode := OwnerNode;
    Node.ParentColor := True;

  end else
  begin
    Node.FParentList := Self;

    FNodeList.Add(Node);

    Node.FChildNodes.FControl := FControl;
  end;

  FControl.Invalidate;
end;

procedure TNxLayoutNodeList.Clear;
var
  i: Integer;
begin
  i := 0;
  while i < FNodeList.Count do Node[i].Free;
end;

constructor TNxLayoutNodeList.Create(AOwnerNode: TNxLayoutNode6);
begin
  FNodeList := TList.Create;
  FOwnerNode := AOwnerNode;
end;

procedure TNxLayoutNodeList.Delete(Index: Integer);
begin
  FNodeList.Delete(Index);
end;

destructor TNxLayoutNodeList.Destroy;
begin
  Clear;
  FreeAndNil(FNodeList);
  inherited;
end;

function TNxLayoutNodeList.GetCount: Integer;
begin
  Result := FNodeList.Count;
end;

function TNxLayoutNodeList.GetNode(const IndexOrName: Variant): TNxLayoutNode6;
begin
  Result := TNxLayoutNode6(FNodeList[IndexOrName]);
end;

function TNxLayoutNodeList.HasChildren: Boolean;
begin
  Result := FNodeList.Count > 0;
end;

function TNxLayoutNodeList.IndexOf(const Node: TNxLayoutNode6): Integer;
begin
  Result := FNodeList.IndexOf(Node);
end;

function TNxLayoutNodeList.Insert(ClassType: TNxLayoutNodeClass; Index: Integer): TNxLayoutNode6;
begin
  Result := nil;
end;

procedure TNxLayoutNodeList.Remove(Node: TNxLayoutNode6);
begin
  FNodeList.Remove(Node);
end;

{ TNxLayoutNode6 }

procedure TNxLayoutNode6.AssignValue(Source: INxBase);
begin

end;

function TNxLayoutNode6.BeginEdit: Boolean;
begin
  if FInplaceEdit = nil then
  begin
    FInplaceEdit := CreateInplaceEdit;
  end;

  if Assigned(FInplaceEdit) then
  begin
    PrepareEdit;
  end;

  Result := FInplaceEdit <> nil;
end;

function TNxLayoutNode6.CanEdit: Boolean;
begin
  Result := Enabled;
end;

function TNxLayoutNode6.CanFocus: Boolean;
begin
  Result := Enabled and Focusing;
end;

procedure TNxLayoutNode6.Changed;
begin
  Control.NodeChanged(Self, Entity);
end;

constructor TNxLayoutNode6.Create(AOwner: TComponent);
begin
  inherited;
  FBindProperty := EmptyStr;
  FChildNodes := TNxLayoutNodeList.Create(Self);
  FClearing := [];
  FColor := clWindow;
  FEnabled := True;
  FExpanded := True;
  FExpandLock := False;
  FFocusing := False;
  FHeight := 0;
  FHint := EmptyStr;
  FIconIndexAfter := -1;
  FIconIndexBefore := -1;
  FInplaceEdit := nil;
  FLineHeight := 20;
  FMargins := TMargins.Create(nil);
  FMargins.SetBounds(0, 0, pdDouble, pdDouble);
  FPadding := TPadding.Create(nil);
  FParentColor := True;
  FState := [];
  FTextAfter := EmptyStr;
  FTextAfterWidth := 0;
  FTextBefore := EmptyStr;
  FTextBeforeAlignment := taRightJustify;
  FTextBeforeWidth := 0;
  FView := GetViewClass.Create(Self);
  FVisibleEntities := [enIconBefore, enTextBefore, enIconAfter, enTextAfter];
  FWidth := 0;
end;

function TNxLayoutNode6.CreateInplaceEdit: INxInplaceEdit;
begin
  Result := nil;
end;

destructor TNxLayoutNode6.Destroy;
begin
  //TODO: FView should be Interface
  FreeAndNil(FView);

  FChildNodes.Free;
  FParentList.Remove(Self);

  FMargins.Free;
  FPadding.Free;

  inherited;
end;

procedure TNxLayoutNode6.DoChange;
begin
  if Assigned(FOnChange) then FOnChange(Self);
end;

procedure TNxLayoutNode6.DoChildAdd(const Node: INxNode);
begin
  Control.Invalidate;
end;

procedure TNxLayoutNode6.DoCustomDrawContent(ContentRect: TRect);
begin
  if Assigned(FOnCustomDrawContent) then FOnCustomDrawContent(Self, ContentRect);
end;

procedure TNxLayoutNode6.DoIconAfterClick;
begin
  if Assigned(FOnImageAfterClick) then FOnImageAfterClick(Self);
end;

procedure TNxLayoutNode6.DoIconBeforeClick;
begin
  if Assigned(FOnImageBeforeClick) then FOnImageBeforeClick(Self);
end;

function TNxLayoutNode6.EndEdit(Assign: Boolean): Boolean;
begin
  Result := False;
  if Assigned(FInplaceEdit) then
  begin
    if Assign then AssignEditing;

//    WinControl := InplaceEditControl(FInplaceEdit);

    if Assigned(FInplaceEdit) then
    begin
      ShowWindow(FInplaceEdit.Handle, SW_HIDE);

      FInplaceEdit := nil;
    end;


//    if Assigned(WinControl) then
//    begin
//      ShowWindow(WinControl.Handle, SW_HIDE);
//      WinControl.Free;
//    end;

    Result := True;
  end;
end;

function TNxLayoutNode6.GetAsBoolean: Boolean;
begin
  Result := False;
end;

function TNxLayoutNode6.GetAsDateTime: TDateTime;
begin
  Result := 0;
end;

function TNxLayoutNode6.GetAsFloat: Double;
begin
  Result := 0;
end;

function TNxLayoutNode6.GetAsInteger: Integer;
begin
  Result := 0;
end;

function TNxLayoutNode6.GetAsString: WideString;
begin
  Result := '';
end;

function TNxLayoutNode6.GetAsUTF8String: UTF8String;
begin
  Result := UTF8String(AsString);
end;

function TNxLayoutNode6.GetBestSize: TSize;
begin
  Result := FView.NodeSize;
end;

function TNxLayoutNode6.GetChildCount: Integer;
begin
  Result := FChildNodes.Count;
end;

function TNxLayoutNode6.GetChildNodes: INxNodeList;
begin
  Supports(FChildNodes, INxNodeList, Result);
end;

procedure TNxLayoutNode6.GetChildren(Proc: TGetChildProc; Root: TComponent);
var
  i: Integer;
begin
  for i := 0 to Pred(ChildCount) do
    Proc(ChildNodes[i]);
end;

function TNxLayoutNode6.GetClientWidth: Integer;
begin
  Result := FClientWidth;
end;

function TNxLayoutNode6.GetControl: INxLayoutControl;
begin
  Result := FParentList.Control;
end;

function TNxLayoutNode6.GetHidden: Boolean;
begin
  Result := False;
end;

function TNxLayoutNode6.GetIndex: Integer;
begin
  if Assigned(FParentNode) then Result := FParentNode.ChildNodes.IndexOf(Self)
    else Result := ParentList.IndexOf(Self);
end;

function TNxLayoutNode6.GetLevel: Integer;
begin
  if ParentNode = nil then Result := 0
    else Result := Succ(ParentNode.Level);
end;

function TNxLayoutNode6.GetParentComponent: TComponent;
begin
  if FParentNode = nil then Result := GetComponent(FParentList.FControl)
    else Result := FParentNode;
end;

function TNxLayoutNode6.GetViewClass: TNxLayoutNodeViewClass;
begin
  Result := TNxLayoutNodeView;
end;

function TNxLayoutNode6.HasParent: Boolean;
begin
  Result := True;
end;

function TNxLayoutNode6.IsTopLevel: Boolean;
begin
  Result := Level = 0;
end;

procedure TNxLayoutNode6.PrepareEdit;
begin

end;

procedure TNxLayoutNode6.SetAsBoolean(const Value: Boolean);
begin
  ValueChanged;

  { Repaint }
  Changed(enContent);
end;

procedure TNxLayoutNode6.SetAsDateTime(const Value: TDateTime);
begin
  ValueChanged;

  { Repaint }
  Changed(enContent);
end;

procedure TNxLayoutNode6.SetAsFloat(const Value: Double);
begin
  ValueChanged;

  { Repaint }
  Changed(enContent);
end;

procedure TNxLayoutNode6.SetAsInteger(const Value: Integer);
begin
  ValueChanged;

  { Repaint }
  Changed(enContent);
end;

procedure TNxLayoutNode6.SetAsString(const Value: WideString);
begin
  ValueChanged;

  { Repaint }
  Changed(enContent);
end;

procedure TNxLayoutNode6.SetAsUTF8String(const Value: UTF8String);
begin
{$IFDEF UTF8DECODE_DEPRECATED}
  AsString := UTF8ToWideString(Value);
{$ELSE}
  AsString := UTF8Decode(Value);
{$ENDIF}
end;

procedure TNxLayoutNode6.SetBindProperty(const Value: string);
begin
  if Value <> FBindProperty then
  begin
    FBindProperty := Value;
//    GetPropValue();
  end;
end;

procedure TNxLayoutNode6.SetClearing(const Value: TNxClearing);
begin
  if Value <> FClearing then
  begin
    FClearing := Value;
  end;
end;

procedure TNxLayoutNode6.SetClientWidth(const Value: Integer);
begin
  if Value <> FClientWidth then
  begin
    FClientWidth := Value;
  end;
end;

procedure TNxLayoutNode6.SetColor(const Value: TColor);
begin
  if Value <> FColor then
  begin
    FColor := Value;
    Changed;
  end;
end;

procedure TNxLayoutNode6.SetEnabled(const Value: Boolean);
begin
  if Value <> FEnabled then
  begin
    FEnabled := Value;
    Changed;
  end;
end;

procedure TNxLayoutNode6.SetExpanded(const Value: Boolean);
begin
  if Value <> FExpanded then
  begin
    FExpanded := Value;
    Changed(enToggleButton);
  end;
end;

procedure TNxLayoutNode6.SetExpandLock(const Value: Boolean);
begin
  if Value <> FExpandLock then
  begin
    FExpandLock := Value;
    Changed;
  end;
end;

procedure TNxLayoutNode6.SetFocusing(const Value: Boolean);
begin
  FFocusing := Value;
end;

procedure TNxLayoutNode6.SetHeight(const Value: Integer);
begin
  if Value <> FHeight then
  begin
    FHeight := Value;
  end;
end;

procedure TNxLayoutNode6.SetHint(const Value: WideString);
begin
  FHint := Value;
end;

procedure TNxLayoutNode6.SetIconIndexAfter(const Value: TImageIndex);
begin
  if Value <> FIconIndexAfter then
  begin
    FIconIndexAfter := Value;
    Changed(enIconAfter);
  end;
end;

procedure TNxLayoutNode6.SetIconIndexBefore(const Value: TImageIndex);
begin
  if Value <> FIconIndexBefore then
  begin
    FIconIndexBefore := Value;
    Changed(enIconBefore);
  end;
end;

procedure TNxLayoutNode6.SetInplaceEdit(const Value: INxInplaceEdit);
begin

end;

procedure TNxLayoutNode6.SetLineHeight(const Value: Integer);
begin
  if Value <> FLineHeight then
  begin
    FLineHeight := Value;
    Changed;
  end;
end;

procedure TNxLayoutNode6.SetMargins(const Value: TMargins);
begin
  FMargins.Assign(Value);
end;

procedure TNxLayoutNode6.SetPadding(const Value: TPadding);
begin
  FPadding.Assign(Value);
end;

procedure TNxLayoutNode6.SetParentColor(const Value: Boolean);
begin
  FParentColor := Value;
  if Assigned(FParentNode) and FParentColor then
  begin
    Color := ParentNode.Color;
  end;
end;

procedure TNxLayoutNode6.SetParentComponent(Value: TComponent);
begin
  if Value is TNxLayoutNode6 then
  begin
    (Value as TNxLayoutNode6).ChildNodes.Add(Self);
  end else
  begin
    TNextLayout6(Value).Nodes.Add(Self);
  end;
end;

procedure TNxLayoutNode6.SetParentLayoutNode(const Value: TNxLayoutNode6);
begin
  if Value <> FParentNode then
  begin
    FParentNode := Value;
    if Assigned(Value) then
    begin
      FParentList := FParentNode.ChildNodes;
      FChildNodes.FControl := FParentList.FControl;

      { Add to TList }
      FParentList.FNodeList.Add(Self);
    end;
  end;
end;

procedure TNxLayoutNode6.SetTextAfter(const Value: WideString);
begin
  if Value <> FTextAfter then
  begin
    FTextAfter := Value;
    Changed(enTextAfter);
  end;
end;

procedure TNxLayoutNode6.SetTextAfterWidth(const Value: Integer);
begin
  if Value <> FTextAfterWidth then
  begin
    FTextAfterWidth := Value;
  end;
end;

procedure TNxLayoutNode6.SetTextBefore(const Value: WideString);
begin
  if Value <> FTextBefore then
  begin
    FTextBefore := Value;
    Changed(enTextBefore);
  end;
end;

procedure TNxLayoutNode6.SetTextBeforeAlignment(const Value: TAlignment);
begin
  if Value <> FTextBeforeAlignment then
  begin
    FTextBeforeAlignment := Value;
    Changed(enTextBefore);
  end;
end;

procedure TNxLayoutNode6.SetTextBeforeWidth(const Value: Integer);
begin
  if Value <> FTextBeforeWidth then
  begin
    FTextBeforeWidth := Value;
  end;
end;

procedure TNxLayoutNode6.SetVisibleEntities(const Value: TNxLayoutNodeEntities);
begin
  if Value <> FVisibleEntities then
  begin
    FVisibleEntities := Value;
  end;
end;

procedure TNxLayoutNode6.SetWidth(const Value: Integer);
begin
  if Value <> FWidth then
  begin
    FWidth := Value;
  end;
end;

procedure TNxLayoutNode6.ValueChanged;
begin
  if not (nsReadingProperty in State) then
  begin

    { Change back Prop. }
    try
      Control.Associates.SetPropValue(BindProperty, Self as INxBase);
    except
      raise Exception.Create('Error setting property: ' + BindProperty);
    end;

    { Update }
    Control.DoSetProperty(Self);

    { Call event }
    DoChange;
  end;
end;

{ TNxLayoutNodeView }

constructor TNxLayoutNodeView.Create(ANode: TNxLayoutNode6);
begin
  FNode := ANode;
  FOptions := [];
end;

destructor TNxLayoutNodeView.Destroy;
begin
  FStylePaint := nil;
  inherited Destroy;
end;

function TNxLayoutNodeView.GetAfterSize: TSize;
var
  AddSpace: Boolean;
begin
  { Starting }
  Result.cx := 0;
  Result.cy := ClientRect.Bottom - ClientRect.Top;

  AddSpace := False;

  { Image-after }
  if enIconAfter in Node.VisibleEntities then
    if IsIndexValid(Node.IconIndexAfter) then
    begin
      Inc(Result.cx, Images.Width);

      AddSpace := True;
    end;

  { Text-after }
  if (enTextAfter in Node.VisibleEntities)
    and (TextAfterWidth > 0) then
  begin
    if AddSpace then Inc(Result.cx, pdStandard);

    Inc(Result.cx, TextAfterWidth);
  end;

  if Result.cx > 0 then
    { Space betw. content }
    Inc(Result.cx, pdDouble);
end;

function TNxLayoutNodeView.GetBeforeSize: TSize;
var
  AddSpace: Boolean;
begin
  { Default }
  AddSpace := False;

  { Starting }
  Result.cx := 0;
  Result.cy := ClientRect.Bottom - ClientRect.Top;

  { Toggle button }
  if Node.HasChildren
    and not Node.ExpandLock then
  begin
    Inc(Result.cx, pdDouble);

    Inc(Result.cx, RectWidth(ToggleButtonRect));

    Inc(Result.cx, pdDouble);
  end;

  { Icon-before }
  if enIconBefore in Node.VisibleEntities then
    if IsIndexValid(Node.IconIndexBefore) then
    begin
      Inc(Result.cx, Images.Width);

      AddSpace := True;
    end;

  { Text-before }
  if (enTextBefore in Node.VisibleEntities)
    and (TextBeforeWidth > 0) then
  begin

    if AddSpace then
    begin
      Inc(Result.cx, pdStandard);
    end;

    Inc(Result.cx, TextBeforeWidth);
  end;

  { Spacing to the content }
  if Result.cx > 0
    then Inc(Result.cx, pdDouble);
end;

function TNxLayoutNodeView.GetCaptured: Boolean;
begin
  Result := FCaptured;
end;

function TNxLayoutNodeView.GetContentBestSize: TSize;
begin
  Result := Size(Node.ClientWidth, ContentHeight);
end;

function TNxLayoutNodeView.GetContentHeight: Integer;
begin
  Result := ContentRect.Bottom - ContentRect.Top;
end;

function TNxLayoutNodeView.GetContentRect: TRect;
begin
  Result := ClientRect;

  Inc(Result.Left, BeforeSize.cx);
  Dec(Result.Right, AfterSize.cx);
end;

function TNxLayoutNodeView.GetEntityRect(Entity: TNxNodeEntity): TRect;
begin
  Result := Rect(0, 0, 0, 0);
  case Entity of
    enNone: ;
    enToggleButton: ;
    enIconBefore: ;
    enTextBefore: ;
    enContent: Result := ContentRect;
    enIconAfter: ;
    enTextAfter: ;
    enEdit: ;
  end;
end;

function TNxLayoutNodeView.GetToggleButtonRect: TRect;
var
  BtnPos: TPoint;
  BtnSize: TSize;
begin
  BtnSize := FStylePaint.GetToggleButtonSize(LineHeight);

  BtnPos := PosInRect(BtnSize.cx, BtnSize.cy, ClientRect,
    taLeftJustify, taVerticalCenter);

  Result := Bounds(BtnPos.X + pdDouble, BtnPos.Y, BtnSize.cx, BtnSize.cy);
end;

function TNxLayoutNodeView.GetImages: TImageList;
begin
  Result := FImages;
end;

function TNxLayoutNodeView.GetNode: TNxLayoutNode6;
begin
  Result := FNode;
end;

function TNxLayoutNodeView.GetNodeSize: TSize;
begin

  with Result do
  begin

    { Default }
    cx := Node.Width;
    cy := Node.Height;

    if Node.Width = 0 then
    begin
      cx := BeforeSize.cx + ContentBestSize.cx + AfterSize.cx;
    end;

  end;

end;

function TNxLayoutNodeView.GetNodeStyle: TNxNodeViewStyle;
begin
  Result := FNodeStyle;
end;

function TNxLayoutNodeView.GetOptions: TNxNodeViewOptions;
begin
  Result := FOptions;
end;

function TNxLayoutNodeView.GetState: TNxButtonState;
begin
  Result := FState;
end;

function TNxLayoutNodeView.GetTextAfterWidth: Integer;
begin
  if Node.TextAfterWidth = 0
    then Result := GetTextWidth(Canvas, Node.TextAfter, wkNone)
    else Result := Node.TextAfterWidth;
end;

function TNxLayoutNodeView.GetTextBeforeWidth: Integer;
begin
  if Node.TextBeforeWidth = 0
    then Result := GetTextWidth(Canvas, Node.TextBefore, wkNone)
    else Result := Node.TextBeforeWidth;
end;

function TNxLayoutNodeView.IsIndexValid(Value: TImageIndex): Boolean;
begin
  Result := Assigned(Images) and InRange(Value, 0, Pred(Images.Count));
end;

procedure TNxLayoutNodeView.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
  Result: TNxNodeViewResult;
begin
  inherited;
  Result := ProcNode([noCalc], X, Y);

  { Hit-test }
  case Result.Element of
    enToggleButton: Node.Expanded := not Node.Expanded;
    enIconAfter: Node.DoIconAfterClick;
    enIconBefore: Node.DoIconBeforeClick;
    else
      if PtInRect(ContentRect, Point(X, Y))
        and Node.CanEdit
        then Node.Control.SetActiveNode(Node);

  end;
end;

procedure TNxLayoutNodeView.Paint;
begin
  ProcNode([noPaint], 0, 0);

  PaintContent;

  Node.DoCustomDrawContent(ContentRect);
end;

procedure TNxLayoutNodeView.PaintContent;
begin
  Canvas.Brush.Color := Color;
  Canvas.Font.Assign(Font);

  if not Node.IsTopLevel then
  begin
    Canvas.FillRect(ContentRect);
  end;

//
//  SetFontQuality(Canvas.Font, NONANTIALIASED_QUALITY);
end;

procedure TNxLayoutNodeView.PaintToggleButton;
begin
  StylePaint.DrawToggleButton(ToggleButtonRect, Node.Expanded);
end;

function TNxLayoutNodeView.ProcNode(Operations: TNxProcNodesOperation;
  const X, Y: Integer): TNxNodeViewResult;
var
  Pos, IconLocation: TPoint;
  R: TRect;
  AddSpace: Boolean;
begin
  { Init. result }
  Result.Result := False;
  Result.Rect := Bounds(0, 0, 0, 0);
  Result.Element := enNone;

  { Defaults }
  AddSpace := False;

  Pos := ClientRect.TopLeft;

  with Canvas do
  begin
    Brush.Color := Node.Color;

    if noPaint in Operations then
    begin
      FillRect(Bounds(ClientRect.Left, ClientRect.Top, BeforeSize.cx, BeforeSize.cy));
      FillRect(Bounds(ClientRect.Right -AfterSize.cx, ClientRect.Top, AfterSize.cx, AfterSize.cy));
    end;

    if noPaint in Operations then
    begin
      if Node.Level = 0 then
      begin
        StylePaint.DrawTopLevel(ClientRect);
      end;

      if npShowBounds in Options then
      begin
        Brush.Color := $00666666;
        FrameRect(ClientRect);
      end;

    end;

    { +/- button }
    if Node.HasChildren
      and not Node.ExpandLock then
    begin
      Inc(Pos.X, pdDouble);

      if noPaint in Operations
        then PaintToggleButton;

      if PtInRect(ToggleButtonRect, Point(X, Y)) then
      begin
        Result.Element := enToggleButton;

        { Done }
        Exit;
      end;

      Inc(Pos.X, ToggleButtonRect.Right - ToggleButtonRect.Left);
      Inc(Pos.X, pdDouble);
    end;

    if enIconBefore in Node.VisibleEntities then
    begin
      if Assigned(Images) and InRange(Node.IconIndexBefore, 0, Pred(Images.Count)) then
      begin

        IconLocation := PosInRect(Images.Width, Images.Height, ClientRect, taLeftJustify, taVerticalCenter);

        if noPaint in Operations
          then Images.Draw(Canvas, Pos.X, IconLocation.Y, Node.IconIndexBefore);

        Result.Rect := Bounds(Pos.X, Pos.Y, Images.Width, Images.Height);

        if noCalc in Operations then
        begin

          if PtInRect(Result.Rect, Point(X, Y)) then
          begin
            Result.Element := enIconBefore;

            { Done }
            if Operations = [noCalc]
              then Exit;
          end;

        end;


        Inc(Pos.X, Images.Width);

        AddSpace := True;
      end;
    end;

    if (enTextBefore in Node.VisibleEntities)
      and (TextBeforeWidth > 0) then
    begin

      if AddSpace then
      begin
        Inc(Pos.X, pdStandard);
        AddSpace := False;
      end;

      R := Bounds(Pos.X, Pos.Y, TextBeforeWidth, ClientRect.Bottom - ClientRect.Top);

      if noPaint in Operations then
      begin
        if npShowBounds in Options then
        begin
          if Node.TextBeforeWidth = 0
          then
            Brush.Color := clRed
          else
            Brush.Color := clBlue;

          FrameRect(R);
        end;

        Font.Color := clWindowText;
        DrawTextRect(Canvas, R, Node.TextBeforeAlignment, taVerticalCenter, Node.TextBefore, wkNone);
      end;

    end;

    { After }

    Pos.X := ContentRect.Right;

    Inc(Pos.X, pdDouble);

    if enIconAfter in Node.VisibleEntities then
      if IsIndexValid(Node.IconIndexAfter) then
      begin

        IconLocation := PosInRect(Images.Width, Images.Height, ClientRect, taLeftJustify, taVerticalCenter);

        Images.Draw(Canvas, Pos.X, IconLocation.Y, Node.IconIndexAfter);

        Result.Rect := Bounds(Pos.X, Pos.Y, Images.Width, Images.Height);

        if noCalc in Operations then
        begin

          if PtInRect(Result.Rect, Point(X, Y)) then
          begin
            Result.Element := enIconAfter;

            { Done }
            if Operations = [noCalc]
              then Exit;
          end;

        end;

        Inc(Pos.X, Images.Width);

        AddSpace := True;
      end;

    if (enTextAfter in Node.VisibleEntities)
      and (TextAfterWidth > 0) then
    begin
      if AddSpace then Inc(Pos.X, pdStandard);

      R := Bounds(Pos.X, Pos.Y, TextAfterWidth, ClientRect.Bottom - ClientRect.Top);

      if noPaint in Operations then
      begin

        if npShowBounds in Options then
        begin
          if Node.TextBeforeWidth = 0
          then
            Brush.Color := clRed
          else
            Brush.Color := clBlue;

          FrameRect(R);
        end;

        DrawTextRect(Canvas, R, taLeftJustify, taVerticalCenter, Node.TextAfter, wkNone);
      end;

    end;

  end;

end;

procedure TNxLayoutNodeView.SetCaptured(const Value: Boolean);
begin
  FCaptured := Value;
end;

procedure TNxLayoutNodeView.SetImages(const Value: TImageList);
begin
  FImages := Value;
end;

procedure TNxLayoutNodeView.SetNodeStyle(const Value: TNxNodeViewStyle);
begin
  FNodeStyle := Value;
end;

procedure TNxLayoutNodeView.SetOptions(const Value: TNxNodeViewOptions);
begin
  FOptions := Value;
end;

procedure TNxLayoutNodeView.SetState(const Value: TNxButtonState);
begin
  if Value <> FState then
  begin
    FState := Value;
    StateChanged;
  end;
end;

procedure TNxLayoutNodeView.StateChanged;
begin

end;

{ TNxStringLayoutNode6 }

constructor TNxStringLayoutNode6.Create(AOwner: TComponent);
begin
  inherited;
  FValue := EmptyStr;
end;

function TNxStringLayoutNode6.GetAsFloat: Double;
begin
  Result := StrToFloatDef(AsString, 0);
end;

function TNxStringLayoutNode6.GetAsInteger: Integer;
begin
  Result := StrToIntDef(AsString, 0);
end;

function TNxStringLayoutNode6.GetAsString: WideString;
begin
  Result := FValue;
end;

procedure TNxStringLayoutNode6.SetAsFloat(const Value: Double);
begin
  AsString := FloatToStr(Value);
end;

procedure TNxStringLayoutNode6.SetAsInteger(const Value: Integer);
begin
  AsString := IntToStr(Value);
end;

procedure TNxStringLayoutNode6.SetAsString(const Value: WideString);
begin
  if Value <> FValue then
  begin
    FValue := Value;

    { Changed }
    inherited;
  end;
end;

procedure TNxStringLayoutNode6.SetValue(const Value: WideString);
begin
  AsString := Value;
end;

{ TNxFloatLayoutNode6 }

function TNxFloatLayoutNode6.CheckRange: Boolean;
begin
  Result := (FMax <> 0) or (FMin <> 0);
end;

constructor TNxFloatLayoutNode6.Create(AOwner: TComponent);
begin
  inherited;
  FMax := 100;
  FMin := 0;
  FValue := 0;
end;

function TNxFloatLayoutNode6.GetAsFloat: Double;
begin
  Result := FValue;
end;

function TNxFloatLayoutNode6.GetAsInteger: Integer;
begin
  Result := Round(FValue);
end;

function TNxFloatLayoutNode6.GetAsString: WideString;
begin
  Result := FloatToStr(FValue);
end;

procedure TNxFloatLayoutNode6.SetAsFloat(const Value: Double);
var
  NewValue: Double;
begin
  if Value <> FValue then
  begin
    NewValue := Value;
    if CheckRange then
    begin
      if NewValue < FMin then NewValue := FMin;
      if NewValue > FMax then NewValue := FMax;
    end;
    if NewValue <> FValue then
    begin
      FValue := NewValue;
      inherited; { Changed }
    end;
  end;
end;

procedure TNxFloatLayoutNode6.SetAsInteger(const Value: Integer);
begin
  AsFloat := Value;
end;

procedure TNxFloatLayoutNode6.SetAsString(const Value: WideString);
begin
  AsFloat := StrToFloatDef(AsString, 0);
end;

procedure TNxFloatLayoutNode6.SetMax(const Value: Double);
begin
  FMax := Value;
end;

procedure TNxFloatLayoutNode6.SetMin(const Value: Double);
begin
  FMin := Value;
end;

procedure TNxFloatLayoutNode6.SetValue(const Value: Double);
begin
  FValue := Value;
end;

{ TNxLabelLayoutNode6 }

function TNxLabelLayoutNode6.CanFocus: Boolean;
begin
  Result := False;
end;

{ TNxButtonLayoutNodeView }

procedure TNxButtonLayoutNodeView.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if PtInRect(ContentRect, Point(X, Y)) then
  begin
    ButtonState := ButtonState + [bsPressed];
  end;
end;

procedure TNxButtonLayoutNodeView.MouseLeave;
begin
  inherited;
  if bsHover in ButtonState then ButtonState := ButtonState - [bsHover];
end;

procedure TNxButtonLayoutNodeView.MouseMove(Shift: TShiftState; X,
  Y: Integer);
begin
  inherited;
  if PtInRect(ContentRect, Point(X, Y)) then
  begin
    ButtonState := ButtonState + [bsHover];
  end else
  begin
    ButtonState := ButtonState - [bsHover];
  end;
end;

procedure TNxButtonLayoutNodeView.MouseUp;
begin
  inherited;
  if bsPressed in ButtonState then ButtonState := ButtonState - [bsPressed];
end;

procedure TNxButtonLayoutNodeView.MouseUp(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if bsPressed in ButtonState then
  begin
    ButtonState := ButtonState - [bsPressed];
    TNxButtonLayoutNode6(Node).DoButtonClick;
  end;
end;

procedure TNxButtonLayoutNodeView.PaintContent;
begin
  inherited;
  StylePaint.PaintPushButton(ContentRect, ButtonState);
  DrawTextRect(Canvas, ContentRect, Classes.taCenter, taVerticalCenter,
    Node.AsString, wkEllipsis);
end;

procedure TNxButtonLayoutNodeView.SetButtonState(
  const Value: TNxButtonState);
begin
  if Value <> FButtonState then
  begin
    FButtonState := Value;
    InvalidateRect(ContentRect);
  end;
end;

{ TNxButtonLayoutNode6 }

procedure TNxButtonLayoutNode6.DoButtonClick;
begin
  if Assigned(FOnButtonClick) then FOnButtonClick(Self);
end;

function TNxButtonLayoutNode6.GetViewClass: TNxLayoutNodeViewClass;
begin
  Result := TNxButtonLayoutNodeView;
end;

{ TNxEditFormNodeView }

function TNxEditLayoutNodeView.GetEditRect: TRect;
var
  Location: TPoint;
begin
  Location := CenterInRect(ContentRect, 18);

  Result := Rect(ContentRect.Left + 1, Location.Y, ContentRect.Right - 1, Location.Y + 18);
end;

function TNxEditLayoutNodeView.GetEntityRect(Entity: TNxNodeEntity): TRect;
begin
  if Entity = enEdit then
    Result := EditRect
  else
    Result := inherited GetEntityRect(Entity);
end;

procedure TNxEditLayoutNodeView.PaintContent;
var
  R, R1: TRect;
begin
  inherited;
  with Canvas do
  begin
    Pen.Color := ColorOf(seDivider);
    Brush.Color := clWindow;
    R := EditRect;
    InflateRect(R, 1, 1);
    Rectangle(R);
    R1 := EditRect;
    Inc(R1.Left, pdStandard + 1);
    DrawTextRect(Canvas, R1, taLeftJustify, taVerticalCenter, Node.AsString, wkEllipsis);
  end;
end;

{ TNxEditLayoutNode6 }

procedure TNxEditLayoutNode6.AssignEditing;
var
  PropertyIntf: INxProperty;
begin
  if Supports(InplaceEdit, INxProperty, PropertyIntf) then
  begin
    AsString := PropertyIntf.AsString;
  end
  else AsString := InplaceEdit.Text;
end;

function TNxEditLayoutNode6.CanEdit: Boolean;
begin
  Result := True and inherited CanEdit;
end;

function TNxEditLayoutNode6.CanFocus: Boolean;
begin
  Result := True and inherited CanFocus;
end;

constructor TNxEditLayoutNode6.Create(AOwner: TComponent);
begin
  inherited;
  FEditWidth := 60;
  FFocusing := True;
end;

function TNxEditLayoutNode6.CreateInplaceEdit: INxInplaceEdit;
begin
  Result := TNxEdit6.Create(nil);
end;

function TNxEditLayoutNode6.GetAsFloat: Double;
begin
  Result := StrToFloatDef(FValue, 0);
end;

function TNxEditLayoutNode6.GetAsInteger: Integer;
begin
  Result := StrToIntDef(FValue, 0);
end;

function TNxEditLayoutNode6.GetAsString: WideString;
begin
  Result := FValue;
end;

function TNxEditLayoutNode6.GetViewClass: TNxLayoutNodeViewClass;
begin
  Result := TNxEditLayoutNodeView;
end;

procedure TNxEditLayoutNode6.PrepareEdit;
var
  PropertyIntf: INxProperty;
begin
  if Supports(InplaceEdit, INxProperty, PropertyIntf) then
  begin
    PropertyIntf.AsString := Value;
  end
  else InplaceEdit.Text := Value;
end;

procedure TNxEditLayoutNode6.SetAsFloat(const Value: Double);
begin
  AsString := FloatToStr(Value);
end;

procedure TNxEditLayoutNode6.SetAsInteger(const Value: Integer);
begin
  AsString := IntToStr(Value);
end;

procedure TNxEditLayoutNode6.SetAsString(const Value: WideString);
begin
  if Value <> FValue then
  begin
    FValue := Value;

    { Changed }
    inherited;
  end;
end;

procedure TNxEditLayoutNode6.SetEditWidth(const Value: Integer);
begin
  if Value <> FEditWidth then
  begin
    FEditWidth := Value;
  end;
end;

procedure TNxEditLayoutNode6.SetValue(const Value: WideString);
begin
  FValue := Value;
end;

{ TNxSpinEditNodeView }

function TNxSpinLayoutNodeView.GetEditRect: TRect;
var
  Location: TPoint;
begin
  Location := CenterInRect(ContentRect, 18);

  Result := Rect(ContentRect.Left + 1, Location.Y, ContentRect.Right - 1, Location.Y + 18);
end;

function TNxSpinLayoutNodeView.GetEntityRect(Entity: TNxNodeEntity): TRect;
begin
  if Entity = enEdit then
    Result := EditRect
  else
    Result := inherited GetEntityRect(Entity);
end;

procedure TNxSpinLayoutNodeView.PaintContent;
var
  R, R1: TRect;
begin
  inherited;
  with Canvas do
  begin
    Pen.Color := ColorOf(seDivider);
    Brush.Color := clWindow;
    R := EditRect;
    InflateRect(R, 1, 1);
    Rectangle(R);
    R1 := EditRect;
    Inc(R1.Left, pdStandard + 1);
    DrawTextRect(Canvas, R1, taLeftJustify, taVerticalCenter, Node.AsString, wkEllipsis);
  end;
end;

{ TNxSpinLayoutNode6 }

procedure TNxSpinLayoutNode6.AssignEditing;
var
  PropertyIntf: INxProperty;
begin
  if Supports(InplaceEdit, INxProperty, PropertyIntf) then
  begin
    AsFloat := PropertyIntf.AsFloat;
  end else
  begin
    AsFloat := StrToFloatDef(InplaceEdit.Text, 0);
  end;
end;

constructor TNxSpinLayoutNode6.Create(AOwner: TComponent);
begin
  inherited;
  FFocusing := True;
  FPrecision := 2;
end;

function TNxSpinLayoutNode6.CreateInplaceEdit: INxInplaceEdit;
begin
  Result := TNxSpinEdit6.Create(nil);
end;

function TNxSpinLayoutNode6.GetViewClass: TNxLayoutNodeViewClass;
begin
  Result := TNxSpinLayoutNodeView;
end;

procedure TNxSpinLayoutNode6.PrepareEdit;
var
  PropertyIntf: INxProperty;
begin
  { Assign value to InplaceEdit }
  if Supports(InplaceEdit, INxProperty, PropertyIntf) then
  begin
    PropertyIntf.AsFloat := AsFloat;
  end else
  begin
    InplaceEdit.Text := AsString;
  end;

  with TNxSpinEdit6(GetComponent(InplaceEdit)) do
  begin
    Max := Self.Max;
    Min := Self.Min;
    Precision := Self.Precision;
  end;
end;

procedure TNxSpinLayoutNode6.SetPrecision(const Value: Integer);
begin
  FPrecision := Value;
end;

{ TNxSeparatorNodeView }

function TNxSeparatorLayoutNodeView.GetContentBestSize: TSize;
begin
  Result := inherited GetContentBestSize;
  Result.cx := 0;
end;

procedure TNxSeparatorLayoutNodeView.PaintContent;
begin
  inherited;
  StylePaint.DrawHorzSeparator(ContentRect);
end;

{ TNxSeparatorNode }

constructor TNxSeparatorLayoutNode6.Create(AOwner: TComponent);
begin
  inherited;
  Clearing := [clLeft, clRight];
  Height := 10;
  VisibleEntities := [];
end;

function TNxSeparatorLayoutNode6.GetViewClass: TNxLayoutNodeViewClass;
begin
  Result := TNxSeparatorLayoutNodeView;
end;

{ TNxCheckBoxFormNodeView }

function TNxCheckBoxLayoutNodeView.GetCheckBox: INxCheckBoxNode;
begin
  Supports(Node, INxCheckBoxNode, Result);
end;

function TNxCheckBoxLayoutNodeView.GetCheckRect: TRect;
var
  Point: TPoint;
begin
  Result := ContentRect;

  if not CheckBox.Button then
  begin
    Point := PosInRect(13, 13, ContentRect, taLeftJustify, taVerticalCenter);
    Result := Bounds(Point.X, Point.Y, 13, 13);
  end;
end;

function TNxCheckBoxLayoutNodeView.GetCheckBoxState: TCheckBoxState;
begin
  if Node.AsBoolean then Result := cbChecked
    else Result := cbUnchecked;
end;

function TNxCheckBoxLayoutNodeView.GetContentBestSize: TSize;
begin
  Result := inherited GetContentBestSize;
  Result.cx := IfThen(CheckBox.Button, 20, 13);
end;

function TNxCheckBoxLayoutNodeView.GetState: TNxButtonState;
begin
  Result := inherited GetState;

  { Checked? }
  if Node.AsBoolean then Include(Result, bsChecked)
    else Exclude(Result, bsChecked);
end;

procedure TNxCheckBoxLayoutNodeView.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if PtInRect(CheckRect, Point(X, Y)) then
  begin
    State := State + [bsPressed];
  end;
end;

procedure TNxCheckBoxLayoutNodeView.MouseLeave;
begin
  inherited;
  State := State - [bsHover];
end;

procedure TNxCheckBoxLayoutNodeView.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  if PtInRect(CheckRect, Point(X, Y))
    then State := State + [bsHover]
      else State := State - [bsHover];
end;

procedure TNxCheckBoxLayoutNodeView.MouseUp(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if PtInRect(CheckRect, Point(X, Y)) then
  begin
    Node.AsBoolean := not Node.AsBoolean;
  end;

  State := State - [bsPressed];
end;

procedure TNxCheckBoxLayoutNodeView.PaintContent;
begin
  inherited;

  if CheckBox.Button then
  begin
    StylePaint.PaintToolButton(CheckRect, State);

    if Assigned(Images) and
     InRange(CheckBox.ButtonImageIndex, 0, Pred(Images.Count)) then

    DrawImage(Canvas, CheckRect, Images, Classes.taCenter, taVerticalCenter, CheckBox.ButtonImageIndex);
  end
  else
    StylePaint.PaintCheckBox(CheckRect, CheckBoxState, State);

end;

procedure TNxCheckBoxLayoutNodeView.StateChanged;
begin
  inherited;
  InvalidateRect(CheckRect);
end;

{ TNxCheckBoxFormNode }

function TNxCheckBoxLayoutNode6.CanFocus: Boolean;
begin
  Result := False;
end;

constructor TNxCheckBoxLayoutNode6.Create(AOwner: TComponent);
begin
  inherited;
  FButton := False;
  FButtonImageIndex := -1;
  FValue := False;
end;

function TNxCheckBoxLayoutNode6.GetAsBoolean: Boolean;
begin
  Result := FValue;
end;

function TNxCheckBoxLayoutNode6.GetAsString: WideString;
begin
  Result := BoolToStr(FValue, True);
end;

function TNxCheckBoxLayoutNode6.GetButton: Boolean;
begin
  Result := FButton;
end;

function TNxCheckBoxLayoutNode6.GetButtonImageIndex: TImageIndex;
begin
  Result := FButtonImageIndex;
end;

function TNxCheckBoxLayoutNode6.GetViewClass: TNxLayoutNodeViewClass;
begin
  Result := TNxCheckBoxLayoutNodeView;
end;

procedure TNxCheckBoxLayoutNode6.SetAsBoolean(const Value: Boolean);
begin
  if Value <> FValue then
  begin
    FValue := Value;

    { Changed }
    inherited;
  end;
end;

procedure TNxCheckBoxLayoutNode6.SetAsString(const Value: WideString);
begin
  AsBoolean := StrToBoolEx(Value);
end;

procedure TNxCheckBoxLayoutNode6.SetButton(const Value: Boolean);
begin
  if Value <> FButton then
  begin
    FButton := Value;
  end;
end;

procedure TNxCheckBoxLayoutNode6.SetButtonImageIndex(const Value: TImageIndex);
begin
  if Value <> FButtonImageIndex then
  begin
    FButtonImageIndex := Value;
    Changed;
  end;
end;

procedure TNxCheckBoxLayoutNode6.SetValue(const Value: Boolean);
begin
  if Value <> FValue then
  begin
    FValue := Value;
    Changed;
  end;
end;

{ TNxTrackBarLayoutNodeView }

function TNxTrackBarLayoutNodeView.GetContentBestSize: TSize;
begin
  Result := Size(80, ContentHeight);
end;

function TNxTrackBarLayoutNodeView.GetPositionAtPos(X, Y: Integer): Integer;
var
  Spot: Integer;
begin
  with TrackbarNode do
  begin
    Spot := X - TrackRect.Left;
    Result := Round(Spot / RectWidth(TrackRect) * (Max - Min) + Min);
  end;
end;

function TNxTrackBarLayoutNodeView.GetSliderRect: TRect;
var
  Distance: Integer;
  TrackSize, SliderSize: TSize;
begin
  TrackSize.cx := TrackRect.Right - TrackRect.Left;
  TrackSize.cy := TrackRect.Bottom - TrackRect.Top;

  with TNxTrackBarLayoutNode6(Node) do
  begin
    Distance := Round(TrackSize.cx * (Value - Min) / (Max - Min));
  end;

  SliderSize := GetSliderSize;

  with Result do
  begin
    Left := TrackRect.Left + Distance - SliderSize.cx div 2;
    Top := TrackSize.cy div 2 - SliderSize.cy div 2 + TrackRect.Top;
    Right := Left + SliderSize.cx;
    Bottom := Top + SliderSize.cy;
  end;
end;

function TNxTrackBarLayoutNodeView.GetSliderSize: TSize;
begin
  Result := Size(6, 10);
end;

function TNxTrackBarLayoutNodeView.GetTrackBarNode: TNxTrackBarLayoutNode6;
begin
  Result := TNxTrackBarLayoutNode6(Node);
end;

function TNxTrackBarLayoutNodeView.GetTrackRect: TRect;
begin
  Result := ContentRect;

  { Half-size of Slider left }
  Inc(Result.Left, GetSliderSize.cx div 2);

  { Half-size of Slider right }
  Dec(Result.Right, GetSliderSize.cx div 2);

  { Apply Padding }
  with Result, TNxTrackBarLayoutNode6(Node) do
  begin
    Top := Top + (Bottom - Top) div 2 - TrackHeight div 2;
    Bottom := Top + TrackHeight;
  end;

end;

procedure TNxTrackBarLayoutNodeView.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if ssDouble in Shift then
  begin
    { Snap to 10% }
    AsInteger := Round(FAsInteger / (TrackbarNode.Max - TrackbarNode.Min) * 100) div 10 * 10;
  end
  else
  begin
    AsInteger := GetPositionAtPos(X, Y);

    { Activate Hint too }
    State := State + [bsPressed];
  end;
end;

procedure TNxTrackBarLayoutNodeView.MouseLeave;
begin
  State := State - [bsHover];
end;

procedure TNxTrackBarLayoutNodeView.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if PtInRect(GetSliderRect, Point(X, Y)) then
  begin
    State := State + [bsHover];
  end
  else State := State - [bsHover];

  if bsPressed in State then
  begin
    AsInteger := GetPositionAtPos(X, Y);

    { Repositionate Hint }
//    if TrackbarNode.ShowHint then UpdateSliderHint;
  end;
end;

procedure TNxTrackBarLayoutNodeView.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  State := State - [bsPressed];
end;

procedure TNxTrackBarLayoutNodeView.PaintContent;
begin
  inherited;
  StylePaint.PaintTrack(TrackRect);
  StylePaint.PaintTrackThumb(GetSliderRect, State);
end;

procedure TNxTrackBarLayoutNodeView.SetAsInteger(const Value: Integer);
begin
  FAsInteger := Value;
  Node.AsInteger := FAsInteger;
end;

procedure TNxTrackBarLayoutNodeView.StateChanged;
begin
  InvalidateRect(GetSliderRect);
end;

{ TNxTrackBarFormNode }

function TNxTrackBarLayoutNode6.CanFocus: Boolean;
begin
  Result := True and inherited CanFocus;
end;

function TNxTrackBarLayoutNode6.CheckRange: Boolean;
begin
  Result := True;
end;

constructor TNxTrackBarLayoutNode6.Create(AOwner: TComponent);
begin
  inherited;
  FTrackHeight := 4;
  FValue := 0;
end;

function TNxTrackBarLayoutNode6.GetViewClass: TNxLayoutNodeViewClass;
begin
  Result := TNxTrackBarLayoutNodeView;
end;

procedure TNxTrackBarLayoutNode6.SetTrackHeight(const Value: Integer);
begin
  if Value <> FTrackHeight then
  begin
    FTrackHeight := Value;
  end;
end;

{ TNxToolbarFormNodeView }

procedure TNxToolbarLayoutNodeView.ActivateButtonHint(
  Button: TNxToolbarNodeButton);
var
  ButtonRect, HintRect: TRect;
begin
  if Assigned(Button)
    and (Button.Hint <> EmptyStr) then
  begin
    FButtonHint := HintWindowClass.Create(Control);
    FButtonHint.Color := clInfoBk;

    { Calculate Rect }
    ButtonRect := GetButtonRect(Button.Index);
    HintRect := FButtonHint.CalcHintRect(Screen.Width, Button.Hint, nil);

    { Cordinates must be "Screen" }
    HintRect.TopLeft := Control.ClientToScreen(ButtonRect.TopLeft);

    { Move Hint bellow Button }
    Inc(HintRect.Top, ButtonRect.Bottom - ButtonRect.Top);

    HintRect.Bottom := HintRect.Top + HintRect.Bottom;
    HintRect.Right := HintRect.Left + HintRect.Right;

    { Show Hint }
    FButtonHint.ActivateHint(HintRect, Button.Hint);
  end;
end;

constructor TNxToolbarLayoutNodeView.Create(ANode: TNxLayoutNode6);
begin
  inherited;
  FDownButton := -1;
  FHoverButton := -1;
end;

destructor TNxToolbarLayoutNodeView.Destroy;
begin
  FreeAndNil(FHintDelayTimer);
  inherited;
end;

procedure TNxToolbarLayoutNodeView.DoHintDelayTimer(Sender: TObject);
begin
  { Stop Timer }
  FHintDelayTimer.Enabled := False;

  if InRange(FHoverButton, 0, Pred(ToolbarNode.Count)) then
  begin
    ActivateButtonHint(Button[FHoverButton]);
  end;
end;

function TNxToolbarLayoutNodeView.GetButton(Index: Integer): TNxToolbarNodeButton;
begin
  Result := ToolbarNode.Buttons[Index];
end;

function TNxToolbarLayoutNodeView.GetButtonAtPos(Location: TPoint): Integer;
var
  i, ButtonWidth: Integer;
  Pos: TPoint;
  ButtonRect: TRect;
begin
  { Default }
  Result := Undefined;

  { Start Pos. }
  Pos := ContentRect.TopLeft;

  for i := 0 to Pred(ToolbarNode.Count) do
  begin
    ButtonWidth := GetButtonWidth(i);

    { Build Rect }
    ButtonRect := Bounds(Pos.X, Pos.Y, ButtonWidth, ContentRect.Bottom - ContentRect.Top);

    if PtInRect(ButtonRect, Location) then
    begin
      Result := i;

      Exit; { Done }
    end;

    { Shift Pos. }
    Inc(Pos.X, ButtonWidth);
  end;

end;

function TNxToolbarLayoutNodeView.GetButtonRect(const Index: Integer): TRect;
var
  i, ButtonWidth: Integer;
  Pos: TPoint;
begin
  { Init. }
  ButtonWidth := 0;

  if InRange(Index, 0, Pred(ToolbarNode.Count)) then
  begin
    { Start Pos. }
    Pos := ContentRect.TopLeft;

    for i := 0 to Index do
    begin
      ButtonWidth := GetButtonWidth(i);

      if i < Index then
      begin
        { Shift Pos. }
        Inc(Pos.X, ButtonWidth);
      end;
    end;

    { Build Rect }
    Result := Bounds(Pos.X, Pos.Y, ButtonWidth, ContentRect.Bottom - ContentRect.Top);
  end;

end;

function TNxToolbarLayoutNodeView.GetButtonWidth(const Index: Integer): Integer;
begin
  if Button[Index].Divider then Result := pdStandard * 2 + 1 else
  begin
    Result := GetTextSize(Canvas, Button[Index].Text, True).cx;

    if Assigned(ToolbarNode.Images)
      and (Button[Index].ImageIndex <> Undefined) then
    begin
      Inc(Result, ToolbarNode.Images.Width);

      if Button[Index].Text <> EmptyStr
        then Inc(Result, pdStandard);
    end;

    { Add Padding }
    Inc(Result, 4);
  end;
end;

function TNxToolbarLayoutNodeView.GetContentBestSize: TSize;
var
  i: Integer;
begin
  Result.cx := 0;
  for i := 0 to Pred(ToolbarNode.Count) do
    Inc(Result.cx, GetButtonWidth(i));
end;

function TNxToolbarLayoutNodeView.GetToolbarNode: TNxToolbarLayoutNode6;
begin
  Result := TNxToolbarLayoutNode6(Node);
end;

procedure TNxToolbarLayoutNodeView.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if Button = mbLeft then
  begin
    DownButton := GetButtonAtPos(Point(X, Y));
  end;
end;

procedure TNxToolbarLayoutNodeView.MouseLeave;
begin
  inherited;
  HoverButton := -1;
end;

procedure TNxToolbarLayoutNodeView.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  HoverButton := GetButtonAtPos(Point(X, Y));
end;

procedure TNxToolbarLayoutNodeView.MouseUp;
begin
  DownButton := Undefined;
end;

procedure TNxToolbarLayoutNodeView.MouseUp(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  UpButton, PrevDownButton: Integer;
begin
  { Temp. Var }
  PrevDownButton := DownButton;

  { Release Pressed }
  DownButton := Undefined;

  if Button = mbLeft then
  begin

    UpButton := GetButtonAtPos(Point(X, Y));

    if InRange(UpButton, 0, Pred(ToolbarNode.Count))
      and (UpButton = PrevDownButton)
      and not Self.Button[UpButton].Divider then
    begin
      Self.Button[UpButton].ToggleChecked;

      { Trigger Event }
      ToolbarNode.DoButtonClick(UpButton);
    end;

  end;

end;

procedure TNxToolbarLayoutNodeView.PaintButton(ButtonRect: TRect;
  Text: WideString; ButtonState: TNxButtonState; ImageIndex: TImageIndex);
var
  ImagePos: TPoint;
  TextRect: TRect;
begin
  StylePaint.PaintToolButton(ButtonRect, ButtonState);

  TextRect := ButtonRect;

  { Draw Image }
  if Assigned(ToolbarNode.Images)
    and (ImageIndex <> Undefined) then
  begin
    ImagePos := ButtonRect.TopLeft;

    Inc(ImagePos.X, (ButtonRect.Right - ButtonRect.Left) div 2 - ToolbarNode.Images.Width div 2);

    Inc(ImagePos.Y, ContentHeight div 2 - ToolbarNode.Images.Height div 2);

    ToolbarNode.Images.Draw(Canvas, ImagePos.X, ImagePos.Y, ImageIndex);

    Inc(TextRect.Left, ToolbarNode.Images.Width + 4);
  end;

  Canvas.Font.Color := StylePaint.GetButtonTextColor;

  { Draw Text }
  DrawTextRect(Canvas, TextRect, Classes.taCenter, taVerticalCenter, Text, wkNone);
end;

procedure TNxToolbarLayoutNodeView.PaintContent;
var
  i, ButtonWidth: Integer;
  ButtonRect: TRect;
  ButtonState: TNxButtonState;
  Pos: TPoint;
begin
  inherited;

  { Starting Pos }
  Pos := ContentRect.TopLeft;

  for i := 0 to Pred(ToolbarNode.Count) do
  begin
    ButtonWidth := GetButtonWidth(i);
    ButtonRect := Bounds(Pos.X, Pos.Y, ButtonWidth, ContentRect.Bottom - ContentRect.Top);

    if Button[i].Divider
      then PaintDivider(ButtonRect) else
    begin
      { Set State }
      ButtonState := [];

      { Hot or pressed }
      if FHoverButton = i then Include(ButtonState, bsHover);
      if FDownButton = i then Include(ButtonState, bsPressed);

      { Checked? }
      if Button[i].Checked then Include(ButtonState, bsChecked);

      { Paint }
      PaintButton(ButtonRect, Button[i].Text, ButtonState, ToolbarNode.Buttons[i].ImageIndex);
    end;

    { Shift Pos. }
    Inc(Pos.X, ButtonWidth);
  end;
end;

procedure TNxToolbarLayoutNodeView.PaintDivider(DividerRect: TRect);
var
  Middle: Integer;
begin
  Middle := DividerRect.Left + (DividerRect.Right - DividerRect.Left) div 2;

  with Canvas do
  begin
    Pen.Color := clSilver;
    Polyline([
      Point(Middle, DividerRect.Top + pdStandard),
      Point(Middle, DividerRect.Bottom - pdStandard)
    ]);
  end;
end;

procedure TNxToolbarLayoutNodeView.RefreshButton(const Index: Integer);
begin
  if InRange(Index, 0, Pred(ToolbarNode.Count))
    and not Button[Index].Divider
      then InvalidateRect(GetButtonRect(Index));
end;

procedure TNxToolbarLayoutNodeView.ReleaseButtonHint;
begin
  if Assigned(FButtonHint) then
  begin
    FButtonHint.ReleaseHandle; { Required }

    { Free }
    FreeAndNil(FButtonHint);
  end;
end;

procedure TNxToolbarLayoutNodeView.SetDownButton(const Value: Integer);
begin
  if FDownButton <> Value then
  begin
    Captured := False;

    RefreshButton(FDownButton);

    FDownButton := Value;

    if InRange(FDownButton, 0, Pred(ToolbarNode.Count)) then
      Captured := True;

    RefreshButton(FDownButton);
  end;
end;

procedure TNxToolbarLayoutNodeView.SetHoverButton(const Value: Integer);
begin
  if FHoverButton <> Value then
  begin
    { Since new Button become hover, destroy Hint }
    ReleaseButtonHint;

    RefreshButton(FHoverButton);
    FHoverButton := Value;
    RefreshButton(FHoverButton);

    { Create Timer }
    if not Assigned(FHintDelayTimer) then
    begin
      FHintDelayTimer := TTimer.Create(nil);
      FHintDelayTimer.Interval := Application.HintPause;
      FHintDelayTimer.OnTimer := DoHintDelayTimer;
    end;

    { Start Timer }
    FHintDelayTimer.Enabled := True;
  end;
end;

{ TNxToolbarNodeButton }

procedure TNxToolbarNodeButton.Assign(Source: TPersistent);
begin
  inherited;

end;

constructor TNxToolbarNodeButton.Create(Collection: TCollection);
begin
  inherited;
  FBindValue := EmptyStr;
  FChecked := False;
  FDivider := False;
  FImageIndex := -1;
  FText := EmptyStr;
end;

function TNxToolbarNodeButton.GetButtons: TNxToolbarNodeButtons;
begin
  Result := TNxToolbarNodeButtons(Collection);
end;

procedure TNxToolbarNodeButton.SetChecked(const Value: Boolean);
begin
  if Value <> FChecked then
  begin
    if Value then
    begin
      FChecked := Value;
      if Buttons.IsGrouped then Buttons.UncheckOther(Self);
    end
    else if not Buttons.CanUncheck then Exit;

    { Set value }
    FChecked := Value;

    Buttons.RefreshButton(Index);
  end;
end;

procedure TNxToolbarNodeButton.SetDivider(const Value: Boolean);
begin
  if Value <> FDivider then
  begin
    FDivider := Value;
  end;
end;

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

procedure TNxToolbarNodeButton.SetText(const Value: WideString);
begin
  if Value <> FText then
  begin
    FText := Value;
  end;
end;

procedure TNxToolbarNodeButton.ToggleChecked;
begin
  Checked := not Checked;
end;

{ TNxToolbarNodeButtons }

function TNxToolbarNodeButtons.Add: TNxToolbarNodeButton;
begin
  Result := TNxToolbarNodeButton(inherited Add);
end;

function TNxToolbarNodeButtons.CanUncheck: Boolean;
begin
  Result := FOwner.AllowAlUp or (CheckedCount > 1);
end;

procedure TNxToolbarNodeButtons.Check(Button: TNxToolbarNodeButton);
begin

end;

constructor TNxToolbarNodeButtons.Create(AOwner: TNxToolbarLayoutNode6);
begin
  inherited Create(TNxToolbarNodeButton);
  FOwner := AOwner;
end;

function TNxToolbarNodeButtons.GetCheckedCount: Integer;
var
  i: Integer;
begin
  Result := 0;

  for i := 0 to Pred(Count) do
    if Items[i].Checked then Inc(Result);
end;

function TNxToolbarNodeButtons.GetItem(Index: Integer): TNxToolbarNodeButton;
begin
  Result := TNxToolbarNodeButton(inherited GetItem(Index));
end;

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

function TNxToolbarNodeButtons.IsGrouped: Boolean;
begin
  Result := FOwner.Grouped;
end;

procedure TNxToolbarNodeButtons.RefreshButton(const Index: Integer);
begin
  FOwner.RefreshButton(Index);
end;

procedure TNxToolbarNodeButtons.SetItem(Index: Integer;
  const Value: TNxToolbarNodeButton);
begin
  inherited SetItem(Index, Value);
end;

procedure TNxToolbarNodeButtons.UncheckAll;
var
  i: Integer;
begin
  for i := 0 to Pred(Count) do Items[i].Checked := False;
end;

procedure TNxToolbarNodeButtons.UncheckOther(Leave: TNxToolbarNodeButton);
var
  i: Integer;
begin
  for i := 0 to Pred(Count) do if Items[i] <> Leave then Items[i].Checked := False;
end;

{ TNxToolbarFormNode6 }

procedure TNxToolbarLayoutNode6.Assign(Source: TPersistent);
begin
  inherited;

end;

constructor TNxToolbarLayoutNode6.Create(AOwner: TComponent);
begin
  inherited;
  FAllowAlUp := True;
  FGrouped := False;
  FButtons := TNxToolbarNodeButtons.Create(Self);
  Focusing := False;
end;

destructor TNxToolbarLayoutNode6.Destroy;
begin
  FreeAndNil(FButtons);
  inherited;
end;

procedure TNxToolbarLayoutNode6.DoButtonClick(Index: Integer);
begin
  { Trigger event }
  if Assigned(FOnButtonClick) then FOnButtonClick(Self, Index);

  ValueChanged;
end;

function TNxToolbarLayoutNode6.GetAsString: WideString;
var
  i: Integer;
begin
  Result := EmptyStr;

  for i := 0 to Pred(Count) do
    if Buttons[i].Checked then
    begin
      if Result <> EmptyStr
        then Result := Result + ',';

      Result := Result + Buttons[i].BindValue;
    end;
end;

function TNxToolbarLayoutNode6.GetCount: Integer;
begin
  Result := FButtons.Count;
end;

function TNxToolbarLayoutNode6.GetViewClass: TNxLayoutNodeViewClass;
begin
  Result := TNxToolbarLayoutNodeView;
end;

procedure TNxToolbarLayoutNode6.RefreshButton(const Index: Integer);
begin
  TNxToolbarLayoutNodeView(View.ToObject).RefreshButton(Index);
end;

procedure TNxToolbarLayoutNode6.SetAsString(const Value: WideString);
var
  i: Integer;
begin
  inherited;

  if not AllowAlUp then
  begin
    for i := 0 to Pred(Count) do
      if Value = Buttons[i].BindValue then
      begin
        Buttons[i].Checked := True;

        Exit;
      end;
  end else
  begin

  end;

end;

procedure TNxToolbarLayoutNode6.SetImages(const Value: TImageList);
begin
  if Value <> FImages then
  begin
    FImages := Value;
  end;
end;

procedure TNxToolbarLayoutNode6.SetItems(const Value: TNxToolbarNodeButtons);
begin

end;

end.
