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

interface

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

const
  { MS Office }
  StatusBarHeight = 22;

type
  TNxAnchor = (anLeft, anRight);

  TNxBarControl6 = class;
  TNxBarControlClass = class of TNxBarControl6;

  { TNxBarControlPadding }

  TNxBarControlPadding = class(TPadding)
  published
    property Left default 4;
    property Right default 4;
  end;

  { TNextBar6 }

  TNextBar6 = class(TNxCollectionControl6)
  private
    FImages: TCustomImageList;
    FStyle: TNxAppearanceStyle;
    FUserDefinedStyleColors: TNxUserDefinedColorPalette;
    { Property Accessors }
    procedure SetImages(const Value: TCustomImageList);
    procedure SetStyle(const Value: TNxAppearanceStyle);
    procedure SetUserDefinedColorPalette(const Value: TNxUserDefinedColorPalette);
  protected
    function HasImageIndex(ImageIndex: TImageIndex): Boolean;
    procedure Paint; override;
    { Event Handlers }
    procedure DoUserDefinedStyleColorsChanged(Sender: TObject); virtual;
  public
    function AddControl(ControlClass: TNxBarControlClass): TNxBarControl6; overload;
    procedure AddControl(Control: TNxBarControl6); overload;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Properties }
    property Images: TCustomImageList read FImages write SetImages;
    property ParentColor default False;
    property Style: TNxAppearanceStyle read FStyle write SetStyle default stNative;
    property UserDefinedColorPalette: TNxUserDefinedColorPalette read FUserDefinedStyleColors write SetUserDefinedColorPalette;
  end;

  { TNxBarControl6 }

  TNxBarControl6 = class(TGraphicControl)
  private
    FAnchor: TNxAnchor;
    FBorderStyle: TNxBorderStyle;
    FBorderSize: Integer;
    FBorderColor: TColor;
    FPadding: TPadding;
    FTransparent: Boolean;
    { Property Setters }
    function GetBar: TNextBar6;
    function GetContentRect: TRect;
    function GetStyleOptions: TNxStyleOptions;
    procedure SetAnchor(const Value: TNxAnchor);
    procedure SetBorderColor(const Value: TColor);
    procedure SetBorderSize(const Value: Integer);
    procedure SetBorderStyle(const Value: TNxBorderStyle);
    procedure SetPadding(const Value: TPadding);
    procedure SetTransparent(const Value: Boolean);
  protected
    function CanAutoSize(var NewWidth, NewHeight: Integer): Boolean; override;
    procedure DoPaddingChange(Sender: TObject);
    procedure Paint; override;
    procedure PaintBackground; virtual;
    procedure PaintBorder(BorderRect: TRect);
    procedure PaintContent(ContentRect: TRect); virtual;
    { Windows Messages }
    procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBKGND;
    { Properties }
    property ContentRect: TRect read GetContentRect;
    property Bar: TNextBar6 read GetBar;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    property StyleOptions: TNxStyleOptions read GetStyleOptions;
  published
    { Properties }
    property Anchor: TNxAnchor read FAnchor write SetAnchor default anLeft;
    property AutoSize;
    property BorderColor: TColor read FBorderColor write SetBorderColor
      default clBtnShadow;
    property BorderSize: Integer read FBorderSize write SetBorderSize default 0;
    property BorderStyle: TNxBorderStyle read FBorderStyle write SetBorderStyle
      default btSolid;
    property Color;
    property Hint;
    property DragCursor;
    property DragKind;
    property DragMode;
    property Enabled;
    property Font;
    property Padding: TPadding read FPadding write SetPadding;
    property ParentColor;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ShowHint;
    property Transparent: Boolean read FTransparent write SetTransparent default True;
    { Events }
    property OnClick;
    property OnContextPopup;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDock;
    property OnEndDrag;
{$IFDEF GESTURES}
    property OnGesture;
{$ENDIF}
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
    property OnStartDock;
    property OnStartDrag;
  end;

  { TNxBarLabel6 }

  TNxBarLabel6 = class(TNxBarControl6)
  private
    FAlignment: TAlignment;
    FCaption: WideString;
    FVerticalAlignment: TVerticalAlignment;
    FWrapKind: TNxWrapKind;
    procedure SetAlignment(const Value: TAlignment);
    procedure SetCaption(const Value: WideString);
    procedure SetVerticalAlignment(const Value: TVerticalAlignment);
    procedure SetWrapKind(const Value: TNxWrapKind);
  protected
    function CanAutoSize(var NewWidth, NewHeight: Integer): Boolean; override;
    procedure PaintContent(ContentRect: TRect); override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
    property Caption: WideString read FCaption write SetCaption;
    property VerticalAlignment: TVerticalAlignment read FVerticalAlignment write SetVerticalAlignment
      default taVerticalCenter;
    property WrapKind: TNxWrapKind read FWrapKind write SetWrapKind default wkEllipsis;
  end;

  { TNxBarButton6 }

  TNxBarButton6 = class(TNxBarControl6)
  private
    FAlignment: TAlignment;
    FAllowUncheck: Boolean;
    FAutoCheck: Boolean;
    FButtonState: TNxButtonState;
    FCaption: WideString;
    FChecked: Boolean;
    FDropDownMenu: TPopupMenu;
    FGlyph: TPicture;
    FGlyphTransparent: Boolean;
    FGroupIndex: Integer;
    FImageIndex: Integer;
    FOnCheckedChange: TNotifyEvent;
    procedure SetAlignment(const Value: TAlignment);
    procedure SetAllowUncheck(const Value: Boolean);
    procedure SetButtonState(const Value: TNxButtonState);
    procedure SetCaption(const Value: WideString);
    procedure SetChecked(const Value: Boolean);
    procedure SetDropDownMenu(const Value: TPopupMenu);
    procedure SetGlyph(const Value: TPicture);
    procedure SetGlyphTransparent(const Value: Boolean);
    procedure SetGroupIndex(const Value: Integer);
    procedure SetImageIndex(const Value: Integer);
  protected
    procedure AssignTransparentColor;
    function CanAutoSize(var NewWidth, NewHeight: Integer): Boolean; override;
    procedure DoCheckedChange; dynamic;
    procedure DoGlyphChange(Sender: TObject);
    function GetArrowSize: TSize;
    { Mouse }
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    { Painting }
    procedure DrawDropDownIndicator(Dest: TRect; Size: TSize); virtual;
    procedure PaintBackground; override;
    procedure PaintContent(ContentRect: TRect); override;
    { Delphi Messages }
    procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
    procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function ContentSize: TSize;
    procedure UncheckOther;
    { Properties }
    property ButtonState: TNxButtonState read FButtonState write SetButtonState;
  published
    property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
    property AllowUncheck: Boolean read FAllowUncheck write SetAllowUncheck default True;
    property AutoCheck: Boolean read FAutoCheck write FAutoCheck default False;
    property Caption: WideString read FCaption write SetCaption;
    property Checked: Boolean read FChecked write SetChecked default False;
    property DropDownMenu: TPopupMenu read FDropDownMenu write SetDropDownMenu;
    property ImageIndex: Integer read FImageIndex write SetImageIndex default -1;
    property GroupIndex: Integer read FGroupIndex write SetGroupIndex default -1;
    property Glyph: TPicture read FGlyph write SetGlyph;
    property GlyphTransparent: Boolean read FGlyphTransparent write SetGlyphTransparent default True;
    property OnCheckedChange: TNotifyEvent read FOnCheckedChange write FOnCheckedChange;
  end;

  { TNxBarRangeControl6 }

  TNxBarRangeControl6 = class(TNxBarControl6)
  private
    FMax: Double;
    FMin: Double;
    FOnChange: TNotifyEvent;
    FPosition: Double;
    procedure SetMax(const Value: Double);
    procedure SetMin(const Value: Double);
    procedure SetPosition(const Value: Double);
  protected
    procedure DoChange; dynamic;
  public
    constructor Create(AOwner: TComponent); override;
  published
    { Properties }
    property Max: Double read FMax write SetMax;
    property Min: Double read FMin write SetMin;
    property Position: Double read FPosition write SetPosition;
    { Events }
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
  end;

  { TNxBarProgressBar6 }

  TNxBarProgressBar6 = class(TNxBarRangeControl6)
  private
// TODO: Add
//    FOnChange: TNotifyEvent;
    FProgressHeight: Integer;
    FProgressBorderColor: TColor;
    FShowText: Boolean;
    FTextWidth: Integer;
    FTextAfter: WideString;
    procedure SetProgressHeight(const Value: Integer);
    procedure SetProgressBorderColor(const Value: TColor);
    procedure SetShowText(const Value: Boolean);
    procedure SetTextAfter(const Value: WideString);
    procedure SetTextWidth(const Value: Integer);
  protected
    { Painting }
    procedure PaintContent(ContentRect: TRect); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Properties }
    property ProgressBorderColor: TColor read FProgressBorderColor
      write SetProgressBorderColor default clWhite;
    property ProgressHeight: Integer read FProgressHeight write SetProgressHeight default 8;
    property ShowText: Boolean read FShowText write SetShowText default False;
    property TextAfter: WideString read FTextAfter write SetTextAfter;
    property TextWidth: Integer read FTextWidth write SetTextWidth default 40;
  end;

  { TNxBarTrackBar6 }

  TNxBarTrackBar6 = class(TNxBarRangeControl6)
  private
    FState: TNxButtonState;
    FStep: Double;
    function GetMinusRect: TRect;
    function GetPlusRect: TRect;
    function GetSliderRect: TRect;
    function GetSliderSize: TSize;
    function GetTrackRect: TRect;
    function GetTrackTouchRect: TRect;
    procedure SetState(const Value: TNxButtonState);
    procedure SetStep(const Value: Double);
  protected
    { Mouse }
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); overload; override;
    { Painting }
    procedure PaintContent(ContentRect: TRect); override;
    procedure PaintMinus(Dest: TRect);
    procedure PaintPlus(Dest: TRect);
    { Properties }
    property State: TNxButtonState read FState write SetState;
  public
    constructor Create(AOwner: TComponent); override;
    function GetPositionAtPos(const X, Y: Integer): Double;
    { Properties }
    property MinusRect: TRect read GetMinusRect;
    property PlusRect: TRect read GetPlusRect;
    property SliderRect: TRect read GetSliderRect;
    property TrackTouchRect: TRect read GetTrackTouchRect;
    property TrackRect: TRect read GetTrackRect;
  published
    property Step: Double read FStep write SetStep;
  end;

  { TNxBarImageListImage6 }

  TNxBarImageListImage6 = class(TNxBarControl6)
  private
    FAlignment: TAlignment;
    FImageIndex: TImageIndex;
    FImageList: TImageList;
    FVerticalAlignment: TVerticalAlignment;
    procedure SetAlignment(const Value: TAlignment);
    procedure SetImageIndex(const Value: TImageIndex);
    procedure SetImageList(const Value: TImageList);
    procedure SetVerticalAlignment(const Value: TVerticalAlignment);
  protected
    function CanAutoSize(var NewWidth, NewHeight: Integer): Boolean; override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure PaintContent(ContentRect: TRect); override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
    property ImageList: TImageList read FImageList write SetImageList;
    property ImageIndex: TImageIndex read FImageIndex write SetImageIndex default -1;
    property VerticalAlignment: TVerticalAlignment read FVerticalAlignment write SetVerticalAlignment
      default taVerticalCenter;
  end;

  { TNxBarSeparator6 }

  TNxBarSeparator6 = class(TNxBarControl6)
  protected
    procedure PaintBackground; override;
  public
    constructor Create(AOwner: TComponent); override;
  end;

implementation

uses
  { Standard }
  Dialogs, ExtCtrls, SysUtils, Math,
  { Next Standard 6 }
  NxGraphics6, NxTheme6;

{ TNextBar6 }

function TNextBar6.AddControl(ControlClass: TNxBarControlClass): TNxBarControl6;
begin
  Result := ControlClass.Create(Self);
  AddControl(Result);
end;

procedure TNextBar6.AddControl(Control: TNxBarControl6);
begin
  Control.Parent := Self;
  Control.Align := alLeft;
end;

constructor TNextBar6.Create(AOwner: TComponent);
begin
  inherited;
  FImages := nil;
  FStyle := stNative;
  FUserDefinedStyleColors := TNxUserDefinedColorPalette.Create;
  FUserDefinedStyleColors.OnChanged := DoUserDefinedStyleColorsChanged;
  Align := alBottom;
  ParentColor := False;
  Color := clWindow;
  Height := StatusBarHeight;
  Width := 160;
end;

destructor TNextBar6.Destroy;
begin
  FUserDefinedStyleColors.Free;
  inherited;
end;

procedure TNextBar6.DoUserDefinedStyleColorsChanged(Sender: TObject);
begin
  Invalidate;
end;

function TNextBar6.HasImageIndex(ImageIndex: TImageIndex): Boolean;
begin
  Result := Assigned(Images) and InRange(ImageIndex, 0, Pred(Images.Count));
end;

procedure TNextBar6.Paint;
begin
  inherited;
  with Canvas do
  begin
    case Style of
      stModern:
      begin
        Brush.Color := ColorOf(seStatusWindow);
        FillRect(ClientRect);
      end;
      stNative:
      begin
        Brush.Color := Color;
        if TNxToolbarStyle6.StyleClient(Self) then
        begin
          TNxToolbarStyle6.PaintToolbar(Canvas, Self.Handle, ClientRect, StyleOptions);
        end else
        begin
          Brush.Color := Color;
          FillRect(ClientRect);
        end;
      end;
      stUserDefined:
      begin
        Brush.Color := Color;
        FillRect(ClientRect);
      end;
    end;
  end;
end;

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

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

procedure TNextBar6.SetUserDefinedColorPalette(const Value: TNxUserDefinedColorPalette);
begin

end;

{ TNxBarControl6 }

function TNxBarControl6.CanAutoSize(var NewWidth, NewHeight: Integer): Boolean;
begin
  Result := inherited CanAutoSize(NewWidth, NewWidth);
  NewWidth := DotToPixel(Padding.Left + Padding.Right) + (BorderSize * 2);
  NewHeight := DotToPixel(Padding.Top + Padding.Bottom);
end;

constructor TNxBarControl6.Create(AOwner: TComponent);
begin
  inherited;
  FAnchor := anLeft;
  FBorderColor := clBtnShadow;
  FBorderSize := 0;
  FBorderStyle := btSolid;
  FPadding := TNxBarControlPadding.Create(nil);
  FPadding.SetBounds(pdDouble, 0, pdDouble, 0);
  FPadding.OnChange := DoPaddingChange;
  FTransparent := True;
  ControlStyle := ControlStyle - [csOpaque];
  Align := alLeft;
  Width := 75;
end;

destructor TNxBarControl6.Destroy;
begin
  FreeAndNil(FPadding);
  inherited;
end;

procedure TNxBarControl6.DoPaddingChange(Sender: TObject);
begin
  Invalidate;
end;

function TNxBarControl6.GetBar: TNextBar6;
begin
  // TODO: Add container validation
  Result := TNextBar6(Parent);
end;

function TNxBarControl6.GetContentRect: TRect;
begin
  Result := ClientRect;
  InflateRect(Result, -BorderSize, -BorderSize);
  InsetRect(Result, ScalePadding(Padding));
end;

function TNxBarControl6.GetStyleOptions: TNxStyleOptions;
begin
  if Assigned(Bar) then Result := Bar.StyleOptions;
end;

procedure TNxBarControl6.Paint;
begin
  inherited;
  PaintBackground;
  PaintBorder(ClientRect);
  PaintContent(ContentRect);
end;

procedure TNxBarControl6.PaintBackground;
begin
  if not Transparent then
  begin
    Canvas.Brush.Color := Color;
    Canvas.FillRect(ClientRect);
  end;
end;

procedure TNxBarControl6.PaintBorder(BorderRect: TRect);
var
  i: Integer;
begin
  case BorderStyle of
    btSolid:
    with Canvas do
    begin
      Brush.Color := BorderColor;
      for i := 1 to BorderSize do
      begin
        FrameRect(BorderRect);
        InflateRect(BorderRect, -1, -1);
      end;
    end;
    btLowered: Frame3D(Canvas, BorderRect, clBtnShadow, clBtnHighlight, BorderSize);
    btRaised: Frame3D(Canvas, BorderRect, clBtnHighlight, clBtnShadow, BorderSize);
  end;
end;

procedure TNxBarControl6.PaintContent(ContentRect: TRect);
begin

end;

procedure TNxBarControl6.SetAnchor(const Value: TNxAnchor);
begin
  if Value <> FAnchor then
  begin
    FAnchor := Value;
  end;
  case FAnchor of
    anLeft: Align := alLeft;
    anRight: Align := alRight;
  end;
end;

procedure TNxBarControl6.SetBorderColor(const Value: TColor);
begin
  if Value <> FBorderColor then
  begin
    FBorderColor := Value;
    Invalidate;
  end;
end;

procedure TNxBarControl6.SetBorderSize(const Value: Integer);
begin
  if Value <> FBorderSize then
  begin
    FBorderSize := Value;
    Invalidate;
  end;
end;

procedure TNxBarControl6.SetBorderStyle(const Value: TNxBorderStyle);
begin
  if Value <> FBorderStyle then
  begin
    FBorderStyle := Value;
    Invalidate;
  end;
end;

procedure TNxBarControl6.SetPadding(const Value: TPadding);
begin
  FPadding.Assign(Value);
  FPadding.OnChange := DoPaddingChange;
end;

procedure TNxBarControl6.SetTransparent(const Value: Boolean);
begin
  if Value <> FTransparent then
  begin
    FTransparent := Value;
    Invalidate;
  end;
end;

procedure TNxBarControl6.WMEraseBkgnd(var Message: TWmEraseBkgnd);
begin
  Message.Result := 1;
end;

{ TNxBarLabel6 }

function TNxBarLabel6.CanAutoSize(var NewWidth, NewHeight: Integer): Boolean;
var
  CaptionSize: TSize;
begin
  Result := inherited CanAutoSize(NewWidth, NewHeight);
  Canvas.Font.Assign(Font);
  CaptionSize := GetTextSize(Canvas, Caption, True);
  Inc(NewWidth, CaptionSize.cx);
end;

constructor TNxBarLabel6.Create(AOwner: TComponent);
begin
  inherited;
  ControlStyle := ControlStyle + [csSetCaption];
  FAlignment := taLeftJustify;
  FCaption := 'Label';
  FVerticalAlignment := taVerticalCenter;
  FWrapKind := wkEllipsis;
end;

procedure TNxBarLabel6.PaintContent(ContentRect: TRect);
begin
  inherited;
  Canvas.Font.Assign(Font);
  DrawTextRect(Canvas, ContentRect, Alignment, VerticalAlignment, Caption, WrapKind);
end;

procedure TNxBarLabel6.SetAlignment(const Value: TAlignment);
begin
  if Value <> FAlignment then
  begin
    FAlignment := Value;
    Invalidate;
  end;
end;

procedure TNxBarLabel6.SetCaption(const Value: WideString);
begin
  if Value <> FCaption then
  begin
    FCaption := Value;
    RequestAlign;
    Invalidate;
  end;
end;

procedure TNxBarLabel6.SetVerticalAlignment(const Value: TVerticalAlignment);
begin
  if Value <> FVerticalAlignment then
  begin
    FVerticalAlignment := Value;
    Invalidate;
  end;
end;

procedure TNxBarLabel6.SetWrapKind(const Value: TNxWrapKind);
begin
  if Value <> FWrapKind then
  begin
    FWrapKind := Value;
    Invalidate;
  end;
end;

{ TNxLabelBarControl }

function TNxBarButton6.GetArrowSize: TSize;
begin
  case Bar.Style of
    stModern: Result := Size(6, 3);
    else Result := Size(8, 4);
  end;
end;

procedure TNxBarButton6.AssignTransparentColor;
var
  Bitmap: TBitmap;
begin
  if Assigned(FGlyph.Graphic)
    and not FGlyph.Graphic.Empty then
  begin
    FGlyph.Graphic.Transparent := FGlyphTransparent;
    if FGlyphTransparent then
    begin
      if FGlyph.Graphic is TBitmap then
      begin
        Bitmap := TBitmap(Glyph.Graphic);
        Bitmap.TransparentColor := Bitmap.Canvas.Pixels[0, Bitmap.Height - 1];
      end;
    end;
  end;
end;

function TNxBarButton6.CanAutoSize(var NewWidth,
  NewHeight: Integer): Boolean;
begin
  Result := inherited CanAutoSize(NewWidth, NewHeight);
  Inc(NewWidth, ContentSize.cx);
end;

procedure TNxBarButton6.CMEnabledChanged(var Message: TMessage);
begin
  inherited;
  if Enabled then Exclude(FButtonState, bsDisabled) else
    Include(FButtonState, bsDisabled);
end;

procedure TNxBarButton6.CMMouseLeave(var Message: TMessage);
begin
  ButtonState := ButtonState - [bsHover];
end;

function TNxBarButton6.ContentSize: TSize;
begin
  Unset(Result);

  { Calculate Glyph }
  if Assigned(Glyph.Graphic) and not Glyph.Graphic.Empty
    then Result.cx := Glyph.Graphic.Width
  else if Bar.HasImageIndex(ImageIndex)
    then Result.cx := Bar.Images.Width;

  { Calculate Caption }
  if Caption <> '' then
  begin
    if Result.cx > 0 then
      Inc(Result.cx, DotToPixel(pdTextToIcon));

    Canvas.Font.Assign(Font);
    Inc(Result.cx, GetTextSize(Canvas, Caption, True).cx);
  end;
end;

constructor TNxBarButton6.Create(AOwner: TComponent);
begin
  inherited;
  FAlignment := taLeftJustify;
  FAllowUncheck := True;
  FAutoCheck := False;
  FButtonState := [];
  FCaption := Name;
  FChecked := False;
  FGlyph := TPicture.Create;
  FGlyph.OnChange := DoGlyphChange;
  FGlyphTransparent := True;
  FGroupIndex := -1;
  FImageIndex := -1;
  Width := 32;
end;

destructor TNxBarButton6.Destroy;
begin
  FreeAndNil(FGlyph);
  inherited;
end;

procedure TNxBarButton6.DoCheckedChange;
begin
  if Assigned(FOnCheckedChange) then FOnCheckedChange(Self);
end;

procedure TNxBarButton6.DoGlyphChange(Sender: TObject);
begin
  AssignTransparentColor;
  Invalidate;
end;

procedure TNxBarButton6.DrawDropDownIndicator(Dest: TRect; Size: TSize);
var
  ShapeRect: TRect;
begin
  ShapeRect := CenteredRect(Dest, Bounds(0, 0, Size.cx, Size.cy));
  with Canvas, ShapeRect do
  begin
    case Bar.Style of
      stModern: Brush.Color := ColorOf(seStatusText);
      else Brush.Color := Self.Font.Color;
    end;
    Pen.Color := Brush.Color;
    Polygon([
      Point(Left, Top),
      Point(Right, Top),
      Point(Left + (Right - Left) div 2, Bottom)
    ]);
  end;
end;

procedure TNxBarButton6.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  ScreenPoint: TPoint;
begin
  inherited;
  if (Button = mbLeft) and PtInRect(ContentRect, Point(X, Y)) then
  begin
    ButtonState := ButtonState + [bsPressed];

    if Assigned(DropDownMenu) then
    begin
      ScreenPoint := ClientToScreen(Point(0, Height));
      DropDownMenu.Popup(ScreenPoint.X, ScreenPoint.Y);
      ButtonState := ButtonState - [bsPressed];
    end;
  end;
end;

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

procedure TNxBarButton6.MouseUp(Button: TMouseButton; Shift: TShiftState;
  X, Y: Integer);
var
  NewChecked: Boolean;
begin
  inherited;
  if bsPressed in ButtonState then
  begin
    ButtonState := ButtonState - [bsPressed];
    if AutoCheck then
    begin
      NewChecked := not Checked;
      if NewChecked or AllowUncheck then Checked := NewChecked;
    end;
  end;
end;

procedure TNxBarButton6.Notification(AComponent: TComponent; Operation: TOperation);
begin
  inherited;
  if Operation = opRemove then
  begin
    if AComponent = DropDownMenu then DropDownMenu := nil;
  end;
end;

procedure TNxBarButton6.PaintBackground;
var
  ButtonRect: TRect;
begin
  ButtonRect := ClientRect;

  if csDesigning in ComponentState then
  begin
    Include(FButtonState, bsHover);
  end;

  InflateRect(ButtonRect, -BorderSize, -BorderSize);
  case Bar.Style of
    { Office 365 }
    stModern:
      with Canvas do
        if (bsHover in ButtonState)
          or (bsChecked in ButtonState) then
        begin
          Brush.Color := ColorOf(seStatusBtnFace);
          if (bsPressed in ButtonState)
            or (bsChecked in ButtonState) then
          begin
            Brush.Color := ColorOf(seStatusBtnFacePressed);
          end;
          FillRect(ButtonRect);
        end;
    { Native (Delphi Style, Windows Style, or Classic) }
    stNative:
    begin
      TNxToolbarStyle6.Paint(Canvas, Parent.Handle, ButtonRect,
        ButtonState, Bar.StyleOptions, False);
    end;
    stUserDefined:
    begin
      with Canvas do
        if (bsHover in ButtonState)
          or (bsChecked in ButtonState) then
        begin
          Brush.Color := Bar.UserDefinedColorPalette.ButtonHoverColor;
          if (bsPressed in ButtonState)
            or (bsChecked in ButtonState) then
          begin
            Brush.Color := Bar.UserDefinedColorPalette.ButtonPressedColor;
          end;
          FillRect(ButtonRect);
        end;
    end;
  end;
end;

procedure TNxBarButton6.PaintContent(ContentRect: TRect);
var
  Location: TPoint;
  IconRect, CaptionRect, ArrowRect: TRect;
  CaptionSize: TSize;
begin
  inherited;

  Location := ContentRect.TopLeft;
  CaptionSize := Size(0, 0);

  case Alignment of
    taLeftJustify: ;
    taRightJustify: Location.X := ContentRect.Right - ContentSize.cx;
    Classes.taCenter: Location.X := RectWidth(ContentRect) div 2 - ContentSize.cx div 2;
  end;

  with Canvas do
  begin
    CaptionRect := ContentRect;

    { Icon }
    if Assigned(Glyph.Graphic)
      and not Glyph.Graphic.Empty then
    begin
      IconRect := Bounds(Location.X, Location.Y, Glyph.Width, Glyph.Height);

      OffsetRect(IconRect, 0, RectHeight(ContentRect) div 2 - RectHeight(IconRect) div 2);

      if not Enabled and Assigned(Glyph.Bitmap) then
      begin
        DrawGrayscaleBitmap(Canvas, IconRect.Left, IconRect.Top, Glyph.Bitmap);
      end else
      begin
        Draw(IconRect.Left, IconRect.Top, Glyph.Graphic);
      end;

      CaptionRect.Left := IconRect.Right + DotToPixel(pdTextToIcon);
    end
    else if Bar.HasImageIndex(ImageIndex) then
    begin
      IconRect := Bounds(Location.X, Location.Y, Bar.Images.Width, Bar.Images.Height);

      OffsetRect(IconRect, 0, RectHeight(ContentRect) div 2 - RectHeight(IconRect) div 2);

      Bar.Images.Draw(Canvas, IconRect.Left, IconRect.Top, ImageIndex);

      CaptionRect.Left := IconRect.Right + DotToPixel(pdTextToIcon);
    end;

    if Caption <> EmptyStr then
    begin

      { Text }
      Font.Assign(Self.Font);

      case Bar.Style of
        stModern: Font.Color := ColorOf(seStatusText);
      end;

      if not Enabled then Font.Color := clGrayText;

      DrawTextRect(Canvas, CaptionRect, taLeftJustify, taVerticalCenter, Caption, wkEllipsis);

      CaptionSize := GetTextSize(Canvas, Caption, True);
    end;

    if Assigned(DropDownMenu) then
    begin
      ArrowRect := Bounds(CaptionRect.Left + CaptionSize.cx, CaptionRect.Top, 16, ClientHeight);

      DrawDropDownIndicator(ArrowRect, GetArrowSize);
    end;
  end;
end;

procedure TNxBarButton6.SetAlignment(const Value: TAlignment);
begin
  if Value <> FAlignment then
  begin
    FAlignment := Value;
    Invalidate;
  end;
end;

procedure TNxBarButton6.SetAllowUncheck(const Value: Boolean);
begin
  FAllowUncheck := Value;
end;

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

procedure TNxBarButton6.SetChecked(const Value: Boolean);
begin
  if Value <> FChecked then
  begin
    FChecked := Value;
    if FChecked then
      ButtonState := ButtonState + [bsChecked]
    else
      ButtonState := ButtonState - [bsChecked];

    DoCheckedChange;

    if GroupIndex <> -1 then
    begin
      if FChecked then
      begin
        UncheckOther;
      end;

    end;
  end;
end;

procedure TNxBarButton6.SetDropDownMenu(const Value: TPopupMenu);
begin
  if Value <> FDropDownMenu then
  begin
    if Assigned(FDropDownMenu) then FDropDownMenu.RemoveFreeNotification(Self);
    FDropDownMenu := Value;
    if Assigned(FDropDownMenu) then FDropDownMenu.FreeNotification(Self);
    Invalidate;
  end;
end;

procedure TNxBarButton6.SetGlyph(const Value: TPicture);
begin
  FGlyph.Assign(Value);
  FGlyph.OnChange := DoGlyphChange;
  AssignTransparentColor;
end;

procedure TNxBarButton6.SetGlyphTransparent(const Value: Boolean);
begin
  if Value <> FGlyphTransparent then
  begin
    FGlyphTransparent := Value;
    FGlyph.Graphic.Transparent := FGlyphTransparent;
    Invalidate;
  end;
end;

procedure TNxBarButton6.SetGroupIndex(const Value: Integer);
begin
  FGroupIndex := Value;
end;

procedure TNxBarButton6.SetImageIndex(const Value: Integer);
begin
  if Value <> FImageIndex then
  begin
    FImageIndex := Value;
    Invalidate;
  end;
end;

procedure TNxBarButton6.UncheckOther;
var
  i: Integer;
  BarButton: TNxBarButton6;
begin
  for i := 0 to Pred(Bar.ControlCount) do
    if Bar.Controls[i] is TNxBarButton6 then
    begin
      BarButton := TNxBarButton6(Bar.Controls[i]);
      if (BarButton.GroupIndex = GroupIndex)
        and (BarButton <> Self) then BarButton.Checked := False;
    end;
end;

procedure TNxBarButton6.SetButtonState(const Value: TNxButtonState);
begin
  if Value <> FButtonState then
  begin
    FButtonState := Value;
    Invalidate;
  end;
end;

{ TNxBarRangeControl6 }

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

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

procedure TNxBarRangeControl6.SetMax(const Value: Double);
begin
  if Value <> FMax then
  begin
    FMax := Value;
    Invalidate;
  end;
end;

procedure TNxBarRangeControl6.SetMin(const Value: Double);
begin
  if Value <> FMin then
  begin
    FMin := Value;
    Invalidate;
  end;
end;

procedure TNxBarRangeControl6.SetPosition(const Value: Double);
begin
  if Value <> FPosition then
  begin
    FPosition := Value;
    if FPosition > FMax then FPosition := FMax;
    if FPosition < FMin then FPosition := FMin;
    DoChange;
    Invalidate;
  end;
end;

{ TNxBarProgressBar6 }

constructor TNxBarProgressBar6.Create(AOwner: TComponent);
begin
  inherited;
  FProgressBorderColor := clWhite;
  FProgressHeight := 8;
  FShowText := False;
  FTextAfter := '%';
  FTextWidth := 40;
  Width := 80;
end;

destructor TNxBarProgressBar6.Destroy;
begin

  inherited;
end;

procedure TNxBarProgressBar6.PaintContent(ContentRect: TRect);
var
  BoxRect, BarRect, CaptionRect: TRect;
  Distance: Integer;
begin
  BoxRect := ContentRect;
  BoxRect.Bottom := BoxRect.Top + DotToPixel(ProgressHeight);

  { Vert. align rect }
  OffsetRect(BoxRect, 0, RectHeight(ContentRect) div 2 - RectHeight(BoxRect) div 2);

  with Canvas do
  begin
    Brush.Color := ProgressBorderColor;
    if ShowText then Dec(BoxRect.Right, FTextWidth);

    BarRect := BoxRect;
    InflateRect(BarRect, -1, -1);
    Distance := Round((BarRect.Right - BarRect.Left) * (Position - Min) / (Max - Min));

    BarRect := Bounds(BarRect.Left, BarRect.Top, Distance, RectHeight(BarRect));

    case Bar.Style of
      stNative:
      begin
        TNxProgressStyledView6.Paint(Canvas, Bar.Handle, BoxRect, Bar.StyleOptions);
        TNxProgressStyledView6.PaintChunk(Canvas, Bar.Handle, BarRect, Bar.StyleOptions);
      end;
      stModern:
      begin
        FrameRect(BoxRect);
        FillRect(BarRect);
      end;
    end;


    if ShowText then
    begin
      CaptionRect := Rect(BoxRect.Right, ContentRect.Top, ContentRect.Right, ContentRect.Bottom);
      Inc(CaptionRect.Left, DotToPixel(pdTextToIcon));

      { Text }
      Font.Assign(Self.Font);

      case Bar.Style of
        stModern: Font.Color := ColorOf(seStatusText);
        stNative: ;
      end;

      DrawTextRect(Canvas, CaptionRect, taLeftJustify, taVerticalCenter, FloatToStr(Position) + TextAfter, wkEllipsis);
    end;
  end;


end;

procedure TNxBarProgressBar6.SetProgressBorderColor(const Value: TColor);
begin
  if Value <> FProgressBorderColor then
  begin
    FProgressBorderColor := Value;
    Invalidate;
  end;
end;

procedure TNxBarProgressBar6.SetProgressHeight(const Value: Integer);
begin
  if Value <> FProgressHeight then
  begin
    FProgressHeight := Value;
    Invalidate;
  end;
end;

procedure TNxBarProgressBar6.SetShowText(const Value: Boolean);
begin
  if Value <> FShowText then
  begin
    FShowText := Value;
    Invalidate;
  end;
end;

procedure TNxBarProgressBar6.SetTextAfter(const Value: WideString);
begin
  if Value <> FTextAfter then
  begin
    FTextAfter := Value;
    Invalidate;
  end;
end;

procedure TNxBarProgressBar6.SetTextWidth(const Value: Integer);
begin
  if Value <> FTextWidth then
  begin
    FTextWidth := Value;
    Invalidate;
  end;
end;

{ TNxBarTrackBar6 }

constructor TNxBarTrackBar6.Create(AOwner: TComponent);
begin
  inherited;
  FStep := 1;
end;

function TNxBarTrackBar6.GetSliderRect: TRect;
var
  Distance: Integer;
  TrackSize, SliderSize: TSize;
begin
  TrackSize := Size(RectWidth(TrackRect), RectHeight(TrackRect));

  Distance := Round(TrackSize.cx * (Position - Min) / (Max - Min));

  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 TNxBarTrackBar6.GetSliderSize: TSize;
begin
  case Bar.Style of
    stNative: Result := Size(8, 13);
    stModern: Result := Size(4, 11);
    stUserDefined: Result := Size(4, 11);
  end;
  Result := DotToPixel(Result);
end;

function TNxBarTrackBar6.GetMinusRect: TRect;
begin
  with ContentRect do
  begin
    Result := Bounds(Left, 0, DotToPixel(6), DotToPixel(2));
    OffsetRect(Result, Top, ClientHeight div 2 - RectHeight(Result) div 2);
  end;
end;

function TNxBarTrackBar6.GetPlusRect: TRect;
begin
  with ContentRect do
  begin
    Result := Bounds(Right - DotToPixel(8), 0, DotToPixel(8), DotToPixel(8));
    OffsetRect(Result, Top, ClientHeight div 2 - RectHeight(Result) div 2);
  end;
end;

function TNxBarTrackBar6.GetPositionAtPos(const X, Y: Integer): Double;
var
  Spot: Integer;
begin
  Spot := X - TrackRect.Left;
  Result := Spot / RectWidth(TrackRect) * (Max - Min) + Min;

  if Result > Max then Result := Max;
  if Result < Min then Result := Min;
end;

function TNxBarTrackBar6.GetTrackRect: TRect;
begin
  Result.Left := MinusRect.Right + DotToPixel(4);
  Result.Right := PlusRect.Left - DotToPixel(4);
  Result.Bottom := MinusRect.Bottom;
  Result.Top := Result.Bottom - DotToPixel(1);
end;

function TNxBarTrackBar6.GetTrackTouchRect: TRect;
begin
  Result := TrackRect;
  Result.Top := SliderRect.Top;
  Result.Bottom := SliderRect.Bottom;
end;

procedure TNxBarTrackBar6.MouseDown(Button: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
begin
  inherited;
  if Button = mbLeft then
  begin
    if PtInRect(MinusRect, Point(X, Y)) then
    begin
      Position := Position - Step;
    end
    else if PtInRect(PlusRect, Point(X, Y)) then
    begin
      Position := Position + Step;
    end
    else if PtInRect(TrackTouchRect, Point(X, Y))
      or PtInRect(SliderRect, Point(X, Y)) then
    begin
      Position := GetPositionAtPos(X, Y);

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

procedure TNxBarTrackBar6.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
  inherited;
  if bsPressed in State then Position := GetPositionAtPos(X, Y);

  if PtInRect(SliderRect, Point(X, Y))
    then State := State + [bsHover]
    else State := State - [bsHover];
end;

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

procedure TNxBarTrackBar6.PaintContent(ContentRect: TRect);
begin
  inherited;
  PaintMinus(MinusRect);
  PaintPlus(PlusRect);

  with Canvas do
  begin
    case Bar.Style of
      stNative:
      begin
        TNxTrackBarStyle6.PaintTrack(Canvas, Parent.Handle, TrackRect, StyleOptions);
        TNxTrackBarStyle6.PaintThumb(Canvas, Parent.Handle, SliderRect, State, StyleOptions);
      end;
      stModern:
      begin
        FillRect(TrackRect);
        if (bsHover in State) or (bsPressed in State)
          then Brush.Color := ColorOf(seTrackBar);
        FillRect(SliderRect);
      end;
      stUserDefined:
      begin
        Brush.Color := Bar.UserDefinedColorPalette.GeometryColor;
        FillRect(TrackRect);
        FillRect(SliderRect);
      end;
    end;
  end;
end;

procedure TNxBarTrackBar6.PaintMinus(Dest: TRect);
begin
  with Canvas, Brush do
  begin
    case Bar.Style of
      stNative: Color := clGray;
      stModern: Color := clWhite;
      stUserDefined: Color := Bar.UserDefinedColorPalette.GeometryColor;
    end;
    FillRect(Dest);
  end;
end;

procedure TNxBarTrackBar6.PaintPlus(Dest: TRect);
var
  Delta: Integer;
  Center: TPoint;
begin
  Delta := DotToPixel(1);
  Center := CenterPoint(Dest);
  with Canvas, Center do
  begin
    case Bar.Style of
      stNative: Pen.Color := clGray;
      stModern: Pen.Color := clWhite;
      stUserDefined: Pen.Color := Bar.UserDefinedColorPalette.GeometryColor;
    end;
    Brush.Color := Pen.Color;
    Polygon([
      Point(Dest.Left, Y - Delta),
      Point(X - Delta, Y - Delta),
      Point(X - Delta, Dest.Top),
      Point(X + Delta - 1, Dest.Top),
      Point(X + Delta - 1, Y - Delta),
      Point(Dest.Right - 1, Y - Delta),
      Point(Dest.Right - 1, Y + Delta - 1),
      Point(X + Delta - 1, Y + Delta - 1),
      Point(X + Delta - 1, Dest.Bottom - 1),
      Point(X - Delta, Dest.Bottom - 1),
      Point(X - Delta, Y + Delta - 1),
      Point(Dest.Left, Y + Delta - 1)
    ]);
  end;
end;

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

procedure TNxBarTrackBar6.SetStep(const Value: Double);
begin
  FStep := Value;
end;

{ TNxBarImageListImage6 }

function TNxBarImageListImage6.CanAutoSize(var NewWidth, NewHeight: Integer): Boolean;
begin
  Result := inherited CanAutoSize(NewWidth, NewHeight);
  if Assigned(ImageList) then Inc(NewWidth, ImageList.Width);
end;

constructor TNxBarImageListImage6.Create(AOwner: TComponent);
begin
  inherited;
  FAlignment := taLeftJustify;
  FImageList := nil;
  FImageIndex := -1;
  FVerticalAlignment := taVerticalCenter;
end;

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

procedure TNxBarImageListImage6.PaintContent(ContentRect: TRect);
var
  Position: TPoint;
begin
  inherited;
  if Assigned(ImageList) and InRange(ImageIndex, 0, Pred(ImageList.Count)) then
  begin
    Position := PosInRect(ImageList.Width, ImageList.Height, ContentRect, Alignment, VerticalAlignment);
    ImageList.Draw(Canvas, Position.X, Position.Y, FImageIndex);
  end else
    if csDesigning in ComponentState then
      with Canvas do
      begin
        Pen.Style := psDot;
        Pen.Color := clGrayText;
        Brush.Style := bsClear;
        Rectangle(ClientRect);
        Pen.Style := psSolid;
        Brush.Style := bsSolid;
      end;
end;

procedure TNxBarImageListImage6.SetAlignment(const Value: TAlignment);
begin
  if Value <> FAlignment then
  begin
    FAlignment := Value;
    Invalidate;
  end;
end;

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

procedure TNxBarImageListImage6.SetImageList(const Value: TImageList);
begin
  if Value <> FImageList then
  begin
    if Assigned(FImageList) then FImageList.RemoveFreeNotification(Self);
    FImageList := Value;
    if Assigned(FImageList) then FImageList.FreeNotification(Self);
  end;
end;

procedure TNxBarImageListImage6.SetVerticalAlignment(const Value: TVerticalAlignment);
begin
  if Value <> FVerticalAlignment then
  begin
    FVerticalAlignment := Value;
    Invalidate;
  end;
end;

{ TNxBarSeparator6 }

constructor TNxBarSeparator6.Create(AOwner: TComponent);
begin
  inherited;
  Width := 32;
end;

procedure TNxBarSeparator6.PaintBackground;
begin
  inherited;
  if csDesigning in ComponentState then
    with Canvas do
    begin
      Pen.Style := psDot;
      Pen.Color := clGrayText;
      Brush.Style := bsClear;
      Rectangle(ClientRect);
      Pen.Style := psSolid;
      Brush.Style := bsSolid;
    end;
end;

end.
