1809 lines
52 KiB
ObjectPascal

unit spkt_Buttons;
{$mode delphi}
{.$Define EnhancedRecordSupport}
(*******************************************************************************
* *
* File: spkt_Buttons.pas *
* Description: A module containing button components for the toolbar. *
* Copyright: (c) 2009 by Spook. *
* License: Modified LGPL (with linking exception, like Lazarus LCL) *
' See "license.txt" in this installation *
* *
*******************************************************************************)
interface
uses
Graphics, Classes, Types, Controls, Menus, ActnList, Math,
Dialogs, ImgList, Forms,
SpkGUITools, SpkGraphTools, SpkMath,
spkt_Const, spkt_BaseItem, spkt_Tools;
type
TSpkMouseButtonElement = (beNone, beButton, beDropdown);
TSpkButtonKind = (bkButton, bkButtonDropdown, bkDropdown, bkToggle);
TSpkBaseButton = class;
TSpkButtonActionLink = class(TActionLink)
protected
FClient: TSpkBaseButton;
procedure AssignClient(AClient: TObject); override;
function IsOnExecuteLinked: Boolean; override;
procedure SetCaption(const Value: string); override;
procedure SetChecked(Value: Boolean); override;
procedure SetEnabled(Value: Boolean); override;
procedure SetGroupIndex(Value: Integer); override;
procedure SetImageIndex(Value: integer); override;
procedure SetVisible(Value: Boolean); override;
procedure SetOnExecute({%H-}Value: TNotifyEvent); override;
public
function IsCaptionLinked: Boolean; override;
function IsCheckedLinked: Boolean; override;
function IsEnabledLinked: Boolean; override;
function IsGroupIndexLinked: Boolean; override;
function IsImageIndexLinked: Boolean; override;
function IsVisibleLinked: Boolean; override;
end;
{ TSpkBaseButton }
TSpkBaseButton = class abstract(TSpkBaseItem)
private
FMouseHoverElement: TSpkMouseButtonElement;
FMouseActiveElement: TSpkMouseButtonElement;
// Getters and Setters
function GetAction: TBasicAction;
procedure SetAllowAllUp(const Value: Boolean);
procedure SetButtonKind(const Value: TSpkButtonKind);
procedure SetCaption(const Value: string);
procedure SetDropdownMenu(const Value: TPopupMenu);
procedure SetGroupIndex(const Value: Integer);
protected
FCaption: string;
FOnClick: TNotifyEvent;
FActionLink: TSpkButtonActionLink;
FButtonState: TSpkButtonState;
FButtonRect: T2DIntRect;
FDropdownRect: T2DIntRect;
FButtonKind: TSpkButtonKind;
FChecked: Boolean;
FGroupIndex: Integer;
FAllowAllUp: Boolean;
FDropdownMenu: TPopupMenu;
// *** Drawing support ***
// The task of the method in inherited classes is to calculate the
// button's rectangle and the dropdown menu depending on FButtonState
procedure CalcRects; virtual; abstract;
function GetDropdownPoint: T2DIntPoint; virtual; abstract;
// *** Action support ***
procedure ActionChange(Sender: TObject; CheckDefaults: Boolean); virtual;
procedure Click; virtual;
procedure DoActionChange(Sender: TObject);
function GetDefaultCaption: String; virtual;
function SiblingsChecked: Boolean; virtual;
procedure UncheckSiblings; virtual;
procedure DrawDropdownArrow(ABuffer: TBitmap; ARect: TRect; AColor: TColor);
// Getters and Setters
function GetChecked: Boolean; virtual;
procedure SetAction(const Value: TBasicAction); virtual;
procedure SetChecked(const Value: Boolean); virtual;
procedure SetEnabled(const Value: boolean); override;
procedure SetRect(const Value: T2DIntRect); override;
property AllowAllUp: Boolean read FAllowAllUp write SetAllowAllUp default false;
property ButtonKind: TSpkButtonKind read FButtonKind write SetButtonKind default bkButton;
property Checked: Boolean read GetChecked write SetChecked default false;
property DropdownMenu: TPopupMenu read FDropdownMenu write SetDropdownMenu;
property GroupIndex: Integer read FGroupIndex write SetGroupIndex default 0;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
procedure MouseLeave; override;
procedure MouseDown(Button: TMouseButton; {%H-}Shift: TShiftState;
{%H-}X, {%H-}Y: Integer); override;
procedure MouseMove({%H-}Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
{%H-}X, {%H-}Y: Integer); override;
function GetRootComponent: TComponent;
published
property Action: TBasicAction read GetAction write SetAction;
property Caption: string read FCaption write SetCaption;
property OnClick: TNotifyEvent read FOnClick write FOnClick;
end;
{ TSpkLargeButton }
TSpkLargeButton = class(TSpkBaseButton)
private
FLargeImageIndex: TImageIndex;
procedure FindBreakPlace(s: string; out Position: integer; out Width: integer);
procedure SetLargeImageIndex(const Value: TImageIndex);
protected
procedure CalcRects; override;
function GetDropdownPoint : T2DIntPoint; override;
public
constructor Create(AOwner: TComponent); override;
procedure Draw(ABuffer: TBitmap; ClipRect: T2DIntRect); override;
function GetGroupBehaviour: TSpkItemGroupBehaviour; override;
function GetSize: TSpkItemSize; override;
function GetTableBehaviour: TSpkItemTableBehaviour; override;
function GetWidth: integer; override;
published
property LargeImageIndex: TImageIndex
read FLargeImageIndex write SetLargeImageIndex default -1;
property AllowAllUp;
property ButtonKind;
property Checked;
property DropdownMenu;
property GroupIndex;
end;
{ TSpkSmallButton }
TSpkSmallButton = class(TSpkBaseButton)
private
FImageIndex: TImageIndex;
FTableBehaviour: TSpkItemTableBehaviour;
FGroupBehaviour: TSPkItemGroupBehaviour;
FHideFrameWhenIdle: boolean;
FShowCaption: boolean;
procedure ConstructRects(out BtnRect, DropRect: T2DIntRect);
procedure SetGroupBehaviour(const Value: TSpkItemGroupBehaviour);
procedure SetHideFrameWhenIdle(const Value: boolean);
procedure SetImageIndex(const Value: TImageIndex);
procedure SetShowCaption(const Value: boolean);
procedure SetTableBehaviour(const Value: TSpkItemTableBehaviour);
protected
procedure CalcRects; override;
function GetDropdownPoint: T2DIntPoint; override;
public
constructor Create(AOwner: TComponent); override;
procedure Draw(ABuffer: TBitmap; ClipRect: T2DIntRect); override;
function GetGroupBehaviour: TSpkItemGroupBehaviour; override;
function GetSize: TSpkItemSize; override;
function GetTableBehaviour: TSpkItemTableBehaviour; override;
function GetWidth: integer; override;
published
property GroupBehaviour: TSpkItemGroupBehaviour
read FGroupBehaviour write SetGroupBehaviour default gbSingleItem;
property HideFrameWhenIdle: boolean
read FHideFrameWhenIdle write SetHideFrameWhenIdle default false;
property ImageIndex: TImageIndex
read FImageIndex write SetImageIndex default -1;
property ShowCaption: boolean
read FShowCaption write SetShowCaption default true;
property TableBehaviour: TSpkItemTableBehaviour
read FTableBehaviour write SetTableBehaviour default tbContinuesRow;
property AllowAllUp;
property ButtonKind;
property Checked;
property DropdownMenu;
property GroupIndex;
end;
implementation
uses
LCLType, LCLIntf, LCLProc, LCLVersion, SysUtils,
spkt_Pane, spkt_Appearance;
{ TSpkButtonActionLink }
procedure TSpkButtonActionLink.AssignClient(AClient: TObject);
begin
inherited AssignClient(AClient);
FClient := TSpkBaseButton(AClient);
end;
function TSpkButtonActionLink.IsCaptionLinked: Boolean;
begin
Result := inherited IsCaptionLinked and Assigned(FClient) and
(FClient.Caption = (Action as TCustomAction).Caption);
end;
function TSpkButtonActionLink.IsCheckedLinked: Boolean;
begin
Result := inherited IsCheckedLinked and Assigned(FClient) and
(FClient.Checked = (Action as TCustomAction).Checked);
end;
function TSpkButtonActionLink.IsEnabledLinked: Boolean;
begin
Result := inherited IsEnabledLinked and Assigned(FClient) and
(FClient.Enabled = (Action as TCustomAction).Enabled);
end;
function TSpkButtonActionLink.IsGroupIndexLinked: Boolean;
begin
Result := inherited IsGroupIndexLinked and Assigned(FClient) and
(FClient.GroupIndex = (Action as TCustomAction).GroupIndex);
end;
function TSpkButtonActionLink.IsImageIndexLinked: Boolean;
begin
Result := inherited IsImageIndexLinked;
if (FClient is TSpkSmallButton) then
Result := Result and (TSpkSmallButton(FClient).ImageIndex = (Action as TCustomAction).ImageIndex)
else
if (FClient is TSpkLargeButton) then
Result := Result and (TSpkLargeButton(FClient).LargeImageIndex = (Action as TCustomAction).ImageIndex)
else
Result := false;
end;
function TSpkButtonActionLink.IsOnExecuteLinked: Boolean;
begin
Result := inherited IsOnExecuteLinked;
//and
// (@TSpkBaseButton(FClient).OnClick = @Action.OnExecute);
end;
function TSpkButtonActionLink.IsVisibleLinked: Boolean;
begin
Result := inherited IsVisibleLinked and Assigned(FClient) and
(FClient.Visible = (Action as TCustomAction).Visible);
end;
procedure TSpkButtonActionLink.SetCaption(const Value: string);
begin
if IsCaptionLinked then
FClient.Caption := Value;
end;
procedure TSpkButtonActionLink.SetChecked(Value: Boolean);
begin
if IsCheckedLinked then
FClient.Checked := Value;
end;
procedure TSpkButtonActionLink.SetEnabled(Value: Boolean);
begin
if IsEnabledLinked then
FClient.Enabled := Value;
end;
procedure TSpkButtonActionLink.SetGroupIndex(Value: Integer);
begin
if IsGroupIndexLinked then
FClient.GroupIndex := Value;
end;
procedure TSpkButtonActionLink.SetImageIndex(Value: integer);
begin
if IsImageIndexLinked then begin
if (FClient is TSpkSmallButton) then
(TSpkSmallButton(FClient)).ImageIndex := Value
else
if (FClient is TSpkLargeButton) then
(TSpkLargeButton(FClient)).LargeImageIndex := Value;
end;
end;
procedure TSpkButtonActionLink.SetOnExecute(Value: TNotifyEvent);
begin
// Note: formerly this changed FClient.OnClick, but that is unneeded, because
// TControl.Click executes Action
end;
procedure TSpkButtonActionLink.SetVisible(Value: Boolean);
begin
if IsVisibleLinked then
FClient.Visible := Value;
end;
{ TSpkBaseButton }
constructor TSpkBaseButton.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FCaption := GetDefaultCaption;
FButtonState := bsIdle;
FButtonKind := bkButton;
{$IFDEF EnhancedRecordSupport}
FButtonRect := T2DIntRect.Create(0, 0, 1, 1);
FDropdownRect := T2DIntRect.Create(0, 0, 1, 1);
{$ELSE}
FButtonRect.Create(0, 0, 1, 1);
FDropdownRect.Create(0, 0, 1, 1);
{$ENDIF}
FMouseHoverElement := beNone;
FMouseActiveElement := beNone;
end;
destructor TSpkBaseButton.Destroy;
begin
FreeAndNil(FActionLink);
inherited Destroy;
end;
procedure TSpkBaseButton.ActionChange(Sender: TObject; CheckDefaults: Boolean);
var
newAction: TCustomAction;
begin
if Sender is TCustomAction then begin
newAction := TCustomAction(Sender);
if (not CheckDefaults) or (Caption = '') or (Caption = Name) then
Caption := newAction.Caption;
if not CheckDefaults or Enabled then
Enabled := newAction.Enabled;
{ wp: !!! Hints not yet supported !!!
if not CheckDefaults or (Hint = '') then
Hint := newAction.Hint;
}
if not CheckDefaults or Visible then
Visible := newAction.Visible;
if not CheckDefaults or Checked then
Checked := newAction.Checked;
if not CheckDefaults or (GroupIndex > 0) then
GroupIndex := newAction.GroupIndex;
{ !!! wp: Actions don't have an AllowAllUp property !!!
if not CheckDefaults or not AllowAllUp then
AllowAllUp := newAction.AllowAllUp;
}
if self is TSpkSmallButton then begin
if not CheckDefaults or (TSpkSmallButton(self).ImageIndex < 0) then
TSpkSmallButton(self).ImageIndex := newAction.ImageIndex;
end;
if self is TSpkLargeButton then begin
if not CheckDefaults or (TSpkLargeButton(self).LargeImageIndex < 0) then
TSpkLargeButton(self).LargeImageIndex := newAction.ImageIndex;
end;
{ wp: !!! Helpcontext not yet supported !!!
if not CheckDefaults or (Self.HelpContext = 0) then
Self.HelpContext := HelpContext;
if not CheckDefaults or (Self.HelpKeyword = '') then
Self.HelpKeyword := HelpKeyword;
// HelpType is set implicitly when assigning HelpContext or HelpKeyword
}
end;
end;
(* wp: Thid is the old part (before avoiding OnExecute = OnClick) - just for reference.
with TCustomAction(Sender) do
begin
if not CheckDefaults or (Self.Caption = '') or (Self.Caption = GetDefaultCaption) then
Self.Caption := Caption;
if not CheckDefaults or Self.Enabled then
Self.Enabled := Enabled;
if not CheckDefaults or (Self.Visible = True) then
Self.Visible := Visible;
if not CheckDefaults or Self.Checked then
Self.Checked := Checked;
if not CheckDefaults or (Self.GroupIndex > 0) then
Self.GroupIndex := GroupIndex;
if not CheckDefaults or not Self.AllowAllUp then
Self.AllowAllUp := AllowAllUp;
{
if not CheckDefaults or not Assigned(Self.OnClick) then
Self.OnClick := OnExecute;
}
if self is TSpkSmallButton then begin
if not CheckDefaults or (TSpkSmallButton(self).ImageIndex < 0) then
TSpkSmallButton(self).ImageIndex := ImageIndex;
end;
if self is TSpkLargeButton then begin
if not CheckDefaults or (TSpkLargeButton(self).LargeImageIndex < 0) then
TSpkLargeButton(Self).LargeImageIndex := ImageIndex;
end;
end;
end;
*)
procedure TSpkBaseButton.Click;
begin
// first call our own OnClick
if Assigned(FOnClick) then
FOnClick(Self)
else
// otherwise trigger the action
if (not (csDesigning in ComponentState)) and (FActionLink <> nil) then
FActionLink.Execute(Self);
end;
procedure TSpkBaseButton.DoActionChange(Sender: TObject);
begin
if Sender = Action then
ActionChange(Sender, False);
end;
{ Draw a downward-facing filled triangle as dropdown arrow }
procedure TSpkBaseButton.DrawDropdownArrow(ABuffer: TBitmap; ARect: TRect;
AColor: TColor);
var
P: array[0..3] of TPoint;
begin
P[2].x := ARect.Left + (ARect.Right - ARect.Left) div 2;
P[2].y := ARect.Top + (ARect.Bottom - ARect.Top + DropDownArrowHeight) div 2 - 1;
P[0] := Point(P[2].x - DropDownArrowWidth div 2, P[2].y - DropDownArrowHeight div 2);
P[1] := Point(P[2].x + DropDownArrowWidth div 2, P[0].y);
P[3] := P[0];
ABuffer.Canvas.Brush.Color := AColor;
ABuffer.Canvas.Pen.Style := psClear;
ABuffer.Canvas.Polygon(P);
end;
function TSpkBaseButton.GetAction: TBasicAction;
begin
if Assigned(FActionLink) then
Result := FActionLink.Action
else
Result := nil;
end;
function TSpkBaseButton.GetChecked: Boolean;
begin
Result := FChecked;
end;
function TSpkBaseButton.GetDefaultCaption: String;
begin
Result := 'Button';
end;
function TSpkBaseButton.GetRootComponent: TComponent;
var
pane: TSpkBaseItem;
tab: TSpkBaseItem;
begin
result := nil;
if Collection <> nil then
pane := TSpkBaseItem(Collection.RootComponent)
else
exit;
if (pane <> nil) and (pane.Collection <> nil) then
tab := TSpkBaseItem(pane.Collection.RootComponent)
else
exit;
if (tab <> nil) and (tab.Collection <> nil) then
result := tab.Collection.RootComponent;
end;
procedure TSpkBaseButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
if FEnabled then
begin
// The buttons react only to the left mouse button
if Button <> mbLeft then
exit;
if (FButtonKind = bkToggle) and ((Action = nil) or
((Action is TCustomAction) and not TCustomAction(Action).AutoCheck))
then
Checked := not Checked;
if FMouseActiveElement = beButton then
begin
if FButtonState <> bsBtnPressed then
begin
FButtonState := bsBtnPressed;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end else
if FMouseActiveElement = beDropdown then
begin
if FButtonState <> bsDropdownPressed then
begin
FButtonState := bsDropdownPressed;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end else
if FMouseActiveElement = beNone then
begin
if FMouseHoverElement = beButton then
begin
FMouseActiveElement := beButton;
if FButtonState <> bsBtnPressed then
begin
FButtonState := bsBtnPressed;
if FToolbarDispatch <> nil then
FToolbarDispatch.NotifyVisualsChanged;
end;
end else
if FMouseHoverElement = beDropdown then
begin
FMouseActiveElement := beDropdown;
if FButtonState <> bsDropdownPressed then
begin
FButtonState := bsDropdownPressed;
if FToolbarDispatch <> nil then
FToolbarDispatch.NotifyVisualsChanged;
end;
end;
end;
end // if FEnabled
else
begin
FMouseHoverElement := beNone;
FMouseActiveElement := beNone;
if FButtonState <> bsIdle then
begin
FButtonState := bsIdle;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end;
end;
procedure TSpkBaseButton.MouseLeave;
begin
if FEnabled then
begin
if FMouseActiveElement = beNone then
begin
if FMouseHoverElement = beButton then
begin
// Placeholder, if there is a need to handle this event
end else
if FMouseHoverElement = beDropdown then
begin
// Placeholder, if there is a need to handle this event
end;
end;
if FButtonState <> bsIdle then
begin
FButtonState := bsIdle;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end // if FEnabled
else
begin
FMouseHoverElement := beNone;
FMouseActiveElement := beNone;
if FButtonState <> bsIdle then
begin
FButtonState := bsIdle;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end;
end;
procedure TSpkBaseButton.MouseMove(Shift: TShiftState; X, Y: Integer);
var
NewMouseHoverElement: TSpkMouseButtonElement;
begin
if FEnabled then
begin
{$IFDEF EnhancedRecordSupport}
if FButtonRect.Contains(T2DIntPoint.Create(X,Y)) then
{$ELSE}
if FButtonRect.Contains(X,Y)
{$ENDIF}
then
NewMouseHoverElement := beButton
else
if (FButtonKind = bkButtonDropdown) and
{$IFDEF EnhancedRecordSupport}
(FDropdownRect.Contains(T2DIntPoint.Create(X,Y))) then
{$ELSE}
(FDropdownRect.Contains(X,Y))
{$ENDIF}
then
NewMouseHoverElement := beDropdown
else
NewMouseHoverElement := beNone;
if FMouseActiveElement = beButton then
begin
if (NewMouseHoverElement = beNone) and (FButtonState <> bsIdle) then
begin
FButtonState := bsIdle;
if FToolbarDispatch <> nil then
FToolbarDispatch.NotifyVisualsChanged;
end else
if (NewMouseHoverElement = beButton) and (FButtonState <> bsBtnPressed) then
begin
FButtonState := bsBtnPressed;
if FToolbarDispatch <> nil then
FToolbarDispatch.NotifyVisualsChanged;
end;
end else
if FMouseActiveElement = beDropdown then
begin
if (NewMouseHoverElement = beNone) and (FButtonState <> bsIdle) then
begin
FButtonState := bsIdle;
if FToolbarDispatch <> nil then
FToolbarDispatch.NotifyVisualsChanged;
end else
if (NewMouseHoverElement = beDropdown) and (FButtonState <> bsDropdownPressed) then
begin
FButtonState := bsDropdownPressed;
if FToolbarDispatch <> nil then
FToolbarDispatch.NotifyVisualsChanged;
end;
end else
if FMouseActiveElement = beNone then
begin
// Due to the simplified mouse support in the button, there is no need to
// inform the previous element that the mouse has left its area.
if NewMouseHoverElement = beButton then
begin
if FButtonState <> bsBtnHottrack then
begin
FButtonState := bsBtnHottrack;
if FToolbarDispatch <> nil then
FToolbarDispatch.NotifyVisualsChanged;
end;
end else
if NewMouseHoverElement = beDropdown then
begin
if FButtonState <> bsDropdownHottrack then
begin
FButtonState := bsDropdownHottrack;
if FToolbarDispatch <> nil then
FToolbarDispatch.NotifyVisualsChanged;
end;
end;
end;
FMouseHoverElement := NewMouseHoverElement;
end // if FEnabled
else
begin
FMouseHoverElement := beNone;
FMouseActiveElement := beNone;
if FButtonState <> bsIdle then
begin
FButtonState := bsIdle;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end;
end;
procedure TSpkBaseButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
var
ClearActive: boolean;
DropPoint: T2DIntPoint;
begin
if FEnabled then
begin
// The buttons react only to the left mouse button
if Button <> mbLeft then
exit;
ClearActive := not (ssLeft in Shift);
if FMouseActiveElement = beButton then
begin
// The event only works when the mouse button is released above the button
if FMouseHoverElement = beButton then
begin
if FButtonKind in [bkButton, bkButtonDropdown, bkToggle] then
begin
FButtonState := bsBtnHottrack;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
Click;
end else
if FButtonKind = bkDropdown then
begin
if Assigned(FDropdownMenu) then
begin
DropPoint := FToolbarDispatch.ClientToScreen(GetDropdownPoint);
FDropdownMenu.Popup(DropPoint.x, DropPoint.y);
FButtonState := bsBtnHottrack;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end;
end;
end else
if FMouseActiveElement = beDropDown then
begin
// The event only works if the mouse button has been released above the
// DropDown button
if FMouseHoverElement = beDropDown then
begin
if Assigned(FDropdownMenu) then
begin
DropPoint := FToolbarDispatch.ClientToScreen(GetDropdownPoint);
FDropdownMenu.Popup(DropPoint.x, DropPoint.y);
FButtonState := bsBtnHottrack;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end;
end;
if ClearActive and (FMouseActiveElement <> FMouseHoverElement) then
begin
// Due to the simplified handling, there is no need to inform the
// previous element that the mouse has left its area.
if FMouseHoverElement = beButton then
begin
if FButtonState <> bsBtnHottrack then
begin
FButtonState := bsBtnHottrack;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end else
if FMouseHoverElement = beDropdown then
begin
if FButtonState <> bsDropdownHottrack then
begin
FButtonState := bsDropdownHottrack;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end else
if FMouseHoverElement = beNone then
begin
if FButtonState <> bsIdle then
begin
FButtonState := bsIdle;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end;
end;
if ClearActive then
begin
FMouseActiveElement := beNone;
end;
end // if FEnabled
else
begin
FMouseHoverElement := beNone;
FMouseActiveElement := beNone;
if FButtonState <> bsIdle then
begin
FButtonState := bsIdle;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end;
end;
procedure TSpkBaseButton.SetAction(const Value: TBasicAction);
begin
if Value = nil then
begin
FActionLink.Free;
FActionLink := nil;
end else
begin
if FActionLink = nil then
FActionLink := TSpkButtonActionLink.Create(self);
FActionLink.Action := Value;
FActionLink.OnChange := DoActionChange;
ActionChange(Value, csLoading in Value.ComponentState);
end;
end;
procedure TSpkBaseButton.SetAllowAllUp(const Value: Boolean);
begin
FAllowAllUp := Value;
end;
procedure TSpkBaseButton.SetButtonKind(const Value: TSpkButtonKind);
begin
FButtonKind := Value;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyMetricsChanged;
end;
procedure TSpkBaseButton.SetCaption(const Value: string);
begin
FCaption := Value;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyMetricsChanged;
end;
procedure TSpkBaseButton.SetChecked(const Value: Boolean);
begin
if FChecked = Value then
exit;
if FGroupIndex > 0 then
begin
if FAllowAllUp or ((not FAllowAllUp) and Value) then
UncheckSiblings;
if not FAllowAllUp and (not Value) and not SiblingsChecked then
exit;
end;
FChecked := Value;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
if not (csDesigning in ComponentState) and (Action <> nil) then
(Action as TCustomAction).Checked := Value;
end;
procedure TSpkBaseButton.SetDropdownMenu(const Value: TPopupMenu);
begin
FDropdownMenu := Value;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyMetricsChanged;
end;
procedure TSpkBaseButton.SetEnabled(const Value: boolean);
begin
inherited;
if not FEnabled then
begin
// If the button has been switched off, it is immediately switched into
// the Idle state and the active and under the mouse are reset.
// If it has been enabled, its status will change during the first
// mouse action.
// Original comment:
// Jeœli przycisk zosta³ wy³¹czony, zostaje natychmiast prze³¹czony
// w stan Idle i zerowane s¹ elementy aktywne i pod mysz¹. Jeœli zosta³
// w³¹czony, jego stan zmieni siê podczas pierwszej akcji myszy.
FMouseHoverElement := beNone;
FMouseActiveElement := beNone;
if FButtonState <> bsIdle then
begin
FButtonState := bsIdle;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
end;
end;
procedure TSpkBaseButton.SetGroupIndex(const Value: Integer);
begin
if FGroupIndex = Value then
exit;
FGroupIndex := Value;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
procedure TSpkBaseButton.SetRect(const Value: T2DIntRect);
begin
inherited;
CalcRects;
end;
function TSpkBaseButton.SiblingsChecked: Boolean;
var
i: Integer;
pane: TSpkPane;
btn: TSpkBaseButton;
begin
if (Parent is TSpkPane) then
begin
pane := TSpkPane(Parent);
for i:=0 to pane.Items.Count-1 do
if pane.Items[i] is TSpkBaseButton then
begin
btn := TSpkBaseButton(pane.Items[i]);
if (btn <> self) and (btn.ButtonKind = bkToggle) and
(btn.GroupIndex = FGroupIndex) and btn.Checked then
begin
Result := true;
exit;
end;
end;
end;
Result := false;
end;
procedure TSpkBaseButton.UncheckSiblings;
var
i: Integer;
pane: TSpkPane;
btn: TSpkBaseButton;
begin
if (Parent is TSpkPane) then begin
pane := TSpkPane(Parent);
for i:=0 to pane.Items.Count-1 do
if pane.Items[i] is TSpkBasebutton then
begin
btn := TSpkBaseButton(pane.Items[i]);
if (btn <> self) and (btn.ButtonKind = bkToggle) and (btn.GroupIndex = FGroupIndex) then
btn.FChecked := false;
end;
end;
end;
{ TSpkLargeButton }
procedure TSpkLargeButton.CalcRects;
begin
{$IFDEF EnhancedRecordSupport}
if FButtonKind = bkButtonDropdown then
begin
FButtonRect := T2DIntRect.Create(FRect.Left, FRect.Top, FRect.Right, FRect.Bottom - LargeButtonDropdownFieldSize);
FDropdownRect := T2DIntRect.Create(FRect.Left, FRect.Bottom - LargeButtonDropdownFieldSize, FRect.Right, FRect.Bottom);
//FDropdownRect := T2DIntRect.Create(FRect.Left, FRect.Bottom - LargeButtonDropdownFieldSize + 1, FRect.Right, FRect.Bottom);
end else
begin
FButtonRect := FRect;
FDropdownRect := T2DIntRect.Create(0, 0, 0, 0);
end;
{$ELSE}
if FButtonKind = bkButtonDropdown then
begin
FButtonRect.Create(FRect.Left, FRect.Top, FRect.Right, FRect.Bottom - LargeButtonDropdownFieldSize);
FDropdownRect.Create(FRect.Left, FRect.Bottom - LargeButtonDropdownFieldSize, FRect.Right, FRect.Bottom);
// FDropdownRect.Create(FRect.Left, FRect.Bottom - LargeButtonDropdownFieldSize + 1, FRect.Right, FRect.Bottom);
end else
begin
FButtonRect := FRect;
FDropdownRect.Create(0, 0, 0, 0);
end;
{$ENDIF}
end;
constructor TSpkLargeButton.Create(AOwner: TComponent);
begin
inherited;
FLargeImageIndex := -1;
end;
procedure TSpkLargeButton.Draw(ABuffer: TBitmap; ClipRect: T2DIntRect);
var
fontColor, frameColor: TColor;
gradientFromColor, gradientToColor: TColor;
innerLightColor, innerDarkColor: TColor;
gradientKind: TBackgroundKind;
x: Integer;
y: Integer;
delta: Integer;
cornerRadius: Integer;
imgList: TImageList;
imgSize: TSize;
txtHeight: Integer;
breakPos, breakWidth: Integer;
s: String;
P: T2DIntPoint;
drawBtn: Boolean;
ppi: Integer;
R: TRect;
begin
if FToolbarDispatch = nil then
exit;
if FAppearance = nil then
exit;
if (FRect.Width < 2*LargeButtonRadius) or (FRect.Height < 2*LargeButtonRadius) then
exit;
delta := FAppearance.Element.HotTrackBrightnessChange;
case FAppearance.Element.Style of
esRounded:
cornerRadius := LargeButtonRadius;
esRectangle:
cornerRadius := 0;
end;
// Prepare text color
fontColor := clNone;
case FButtonState of
bsIdle:
fontColor := FAppearance.Element.IdleCaptionColor;
bsBtnHottrack,
bsDropdownHottrack:
fontColor := FAppearance.Element.HotTrackCaptionColor;
bsBtnPressed,
bsDropdownPressed:
fontColor := FAppearance.ELement.ActiveCaptionColor;
end;
if not FEnabled then
fontColor := TColorTools.ColorToGrayscale(fontColor);
// Dropdown button
// Draw full rect, otherwise the DropDownRect will contain the full gradient
if FButtonKind = bkButtonDropdown then
begin
drawBtn := true;
if (FButtonState in [bsBtnHotTrack, bsBtnPressed]) then
begin
FAppearance.Element.GetHotTrackColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind,
delta);
end else
if (FButtonState = bsDropdownHottrack) then
begin
FAppearance.Element.GetHotTrackColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind);
end else
if (FButtonState = bsDropdownPressed) then
begin
FAppearance.Element.GetActiveColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind);
end else
drawBtn := false;
if drawBtn then begin
TButtonTools.DrawButton(
ABuffer,
FRect,
frameColor,
innerLightColor,
innerDarkColor,
gradientFromColor,
gradientToColor,
gradientKind,
false,
false,
false,
false,
cornerRadius,
ClipRect
);
end;
end;
// Button (Background and frame)
drawBtn := true;
if FButtonState = bsBtnHottrack then
begin
FAppearance.Element.GetHotTrackColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind);
end else
if FButtonState = bsBtnPressed then
begin
FAppearance.Element.GetActiveColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientkind);
end else
if (FButtonState in [bsDropdownHotTrack, bsDropdownPressed]) then
begin
FAppearance.Element.GetHotTrackColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind,
delta);
end else
if (FButtonState = bsIdle) and Checked then
begin
FAppearance.Element.GetActiveColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind
);
end else
drawBtn := false;
if drawBtn then
begin
TButtonTools.DrawButton(
ABuffer,
FButtonRect, // draw button part only
frameColor,
innerLightColor,
innerDarkColor,
gradientFromColor,
gradientToColor,
gradientKind,
false,
false,
false,
FButtonKind = bkButtonDropdown,
cornerRadius,
ClipRect
);
end;
// Dropdown button - draw horizontal dividing line
if FButtonKind = bkButtonDropdown then
begin
drawBtn := true;
if (FButtonState in [bsDropdownHotTrack, bsBtnHotTrack]) then
frameColor := FAppearance.element.HotTrackFrameColor
else
if (FButtonState in [bsDropDownPressed, bsBtnPressed]) then
frameColor := FAppearance.Element.ActiveFrameColor
else
drawBtn := false;
if drawBtn then
TGuiTools.DrawHLine(
ABuffer,
FDropDownRect.Left,
FDropDownRect.Right,
FDropDownRect.Top,
frameColor,
ClipRect
);
end;
// Icon
if not FEnabled and (FDisabledLargeImages <> nil) then
imgList := FDisabledLargeImages
else
imgList := FLargeImages;
if (imgList <> nil) and (FLargeImageIndex >= 0) and (FLargeImageIndex < imgList.Count) then
begin
ppi := FAppearance.Element.CaptionFont.PixelsPerInch;
{$IF LCL_FULLVERSION >= 1090000}
imgSize := imgList.SizeForPPI[FLargeImagesWidth, ppi];
{$ELSE}
imgSize := Size(imgList.Width, imgList.Height);
{$ENDIF}
P := {$IFDEF EnhancedRecordSupport}T2DIntPoint.Create{$ELSE}Create2DIntPoint{$ENDIF}(
FButtonRect.Left + (FButtonRect.Width - imgSize.CX) div 2,
FButtonRect.Top + LargeButtonBorderSize + LargeButtonGlyphMargin
);
TGUITools.DrawImage(ABuffer.Canvas, imgList, FLargeImageIndex, P, ClipRect,
FLargeImagesWidth, ppi, 1.0);
end;
// Text
ABuffer.Canvas.Font.Assign(FAppearance.Element.CaptionFont);
ABuffer.Canvas.Font.Color := fontColor;
if FButtonKind in [bkButton, bkToggle] then
FindBreakPlace(FCaption, breakPos, breakWidth)
else
breakPos := 0;
txtHeight := ABuffer.Canvas.TextHeight('Wy');
if breakPos > 0 then
begin
s := Copy(FCaption, 1, breakPos - 1);
x := FRect.Left + (FRect.Width - ABuffer.Canvas.Textwidth(s)) div 2;
y := FRect.Top + LargeButtonCaptionTopRail - txtHeight div 2;
TGUITools.DrawText(ABuffer.Canvas, x, y, s, fontColor, ClipRect);
s := Copy(FCaption, breakPos+1, Length(FCaption) - breakPos);
x := FRect.Left + (FRect.Width - ABuffer.Canvas.Textwidth(s)) div 2;
y := FRect.Top + LargeButtonCaptionButtomRail - txtHeight div 2;
TGUITools.DrawText(ABuffer.Canvas, x, y, s, fontColor, ClipRect);
end else
begin
// The text is not broken
x := FButtonRect.Left + (FButtonRect.Width - ABuffer.Canvas.Textwidth(FCaption)) div 2;
y := FRect.Top + LargeButtonCaptionTopRail - txtHeight div 2;
TGUITools.DrawText(ABuffer.Canvas, x, y, FCaption, FontColor, ClipRect);
end;
// Dropdown arrow
if FButtonKind = bkDropdown then
begin
y := FButtonRect.Bottom - ABuffer.Canvas.TextHeight('Tg') - 1;
R := Classes.Rect(FButtonRect.Left, y, FButtonRect.Right, FButtonRect.Bottom);
DrawDropdownArrow(ABuffer, R, fontcolor);
end else
if FButtonKind = bkButtonDropdown then
begin
y := FDropdownRect.Bottom - ABuffer.Canvas.TextHeight('Tg') - 1;
R := Classes.Rect(FDropdownRect.Left, y, FDropDownRect.Right, FDropdownRect.Bottom);
DrawDropdownArrow(ABuffer, R, fontcolor);
end;
end;
procedure TSpkLargeButton.FindBreakPlace(s: string; out Position: integer; out Width: integer);
var
i: integer;
Bitmap: TBitmap;
BeforeWidth, AfterWidth: integer;
begin
Position := -1;
Width := -1;
if FToolbarDispatch=nil then
exit;
if FAppearance=nil then
exit;
Bitmap := FToolbarDispatch.GetTempBitmap;
if Bitmap=nil then
exit;
Bitmap.Canvas.Font.Assign(FAppearance.Element.CaptionFont);
Width := Bitmap.Canvas.TextWidth(FCaption);
for i := 1 to Length(s) do
if s[i] = ' ' then
begin
if i > 1 then
BeforeWidth := Bitmap.Canvas.TextWidth(Copy(s, 1, i-1))
else
BeforeWidth := 0;
if i < Length(s) then
AfterWidth := Bitmap.Canvas.TextWidth(Copy(s, i+1, Length(s)-i))
else
AfterWidth := 0;
if (Position = -1) or (Max(BeforeWidth, AfterWidth) < Width) then
begin
Width := Max(BeforeWidth, AfterWidth);
Position := i;
end;
end;
end;
function TSpkLargeButton.GetDropdownPoint: T2DIntPoint;
begin
{$IFDEF EnhancedRecordSupport}
case FButtonKind of
bkDropdown : Result := T2DIntPoint.Create(FButtonRect.left, FButtonRect.Bottom+1);
bkButtonDropdown : Result := T2DIntPoint.Create(FDropdownRect.left, FDropdownRect.Bottom+1);
else
Result := T2DIntPoint.Create(0,0);
end;
{$ELSE}
case FButtonKind of
bkDropdown : Result.Create(FButtonRect.left, FButtonRect.Bottom+1);
bkButtonDropdown : Result.Create(FDropdownRect.left, FDropdownRect.Bottom+1);
else
Result.Create(0,0);
end;
{$ENDIF}
end;
function TSpkLargeButton.GetGroupBehaviour: TSpkItemGroupBehaviour;
begin
Result := gbSingleItem;
end;
function TSpkLargeButton.GetSize: TSpkItemSize;
begin
Result := isLarge;
end;
function TSpkLargeButton.GetTableBehaviour: TSpkItemTableBehaviour;
begin
Result := tbBeginsColumn;
end;
function TSpkLargeButton.GetWidth: integer;
var
GlyphWidth: integer;
TextWidth: integer;
Bitmap: TBitmap;
BreakPos, RowWidth: integer;
begin
Result := -1;
if FToolbarDispatch = nil then
exit;
if FAppearance = nil then
exit;
Bitmap := FToolbarDispatch.GetTempBitmap;
if Bitmap = nil then
exit;
// Glyph
if FLargeImages <> nil then
GlyphWidth := 2 * LargeButtonGlyphMargin + FLargeImages.Width
else
GlyphWidth := 0;
// Text
if FButtonKind in [bkButton, bkToggle] then
begin
// Label
FindBreakPlace(FCaption,BreakPos,RowWidth);
TextWidth := 2 * LargeButtonCaptionHMargin + RowWidth;
end else
begin
// do not break the label
Bitmap.Canvas.Font.Assign(FAppearance.Element.CaptionFont);
TextWidth := 2 * LargeButtonCaptionHMargin + Bitmap.Canvas.TextWidth(FCaption);
end;
Result := Max(LargeButtonMinWidth, Max(GlyphWidth, TextWidth));
end;
procedure TSpkLargeButton.SetLargeImageIndex(const Value: TImageIndex);
begin
FLargeImageIndex := Value;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyMetricsChanged;
end;
{ TSpkSmallButton }
constructor TSpkSmallButton.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FImageIndex := -1;
FTableBehaviour := tbContinuesRow;
FGroupBehaviour := gbSingleItem;
FHideFrameWhenIdle := false;
FShowCaption := true;
end;
procedure TSpkSmallButton.CalcRects;
var
RectVector: T2DIntVector;
begin
ConstructRects(FButtonRect, FDropdownRect);
{$IFDEF EnhancedRecordSupport}
RectVector := T2DIntVector.Create(FRect.Left, FRect.Top);
{$ELSE}
RectVector.Create(FRect.Left, FRect.Top);
{$ENDIF}
FButtonRect := FButtonRect + RectVector;
FDropdownRect := FDropdownRect + RectVector;
end;
procedure TSpkSmallButton.ConstructRects(out BtnRect, DropRect: T2DIntRect);
var
BtnWidth: integer;
DropdownWidth: Integer;
Bitmap: TBitmap;
TextWidth: Integer;
AdditionalPadding: Boolean;
begin
{$IFDEF EnhancedRecordSupport}
BtnRect := T2DIntRect.Create(0, 0, 0, 0);
DropRect := T2DIntRect.Create(0, 0, 0, 0);
{$ELSE}
BtnRect.Create(0, 0, 0, 0);
DropRect.Create(0, 0, 0, 0);
{$ENDIF}
if not Assigned(FToolbarDispatch) then
exit;
if not Assigned(FAppearance) then
exit;
Bitmap := FToolbarDispatch.GetTempBitmap;
if not Assigned(Bitmap) then
exit;
// *** Regardless of the type, there must be room for the icon and / or text ***
BtnWidth := 0;
AdditionalPadding := false;
// Icon
if FImageIndex <> -1 then
begin
BtnWidth := BtnWidth + SmallButtonPadding + SmallButtonGlyphWidth;
AdditionalPadding := true;
end;
// Text
if FShowCaption then
begin
Bitmap.Canvas.Font.Assign(FAppearance.Element.CaptionFont);
TextWidth := Bitmap.Canvas.TextWidth(FCaption);
BtnWidth := BtnWidth + SmallButtonPadding + TextWidth;
AdditionalPadding := true;
end;
// Padding behind the text or icon
if AdditionalPadding then
BtnWidth := BtnWidth + SmallButtonPadding;
// The width of the button content must be at least SMALLBUTTON_MIN_WIDTH
BtnWidth := Max(SmallButtonMinWidth, BtnWidth);
// *** Dropdown ***
case FButtonKind of
bkButton, bkToggle:
begin
// Left edge of the button
if FGroupBehaviour in [gbContinuesGroup, gbEndsGroup] then
BtnWidth := BtnWidth + SmallButtonHalfBorderWidth
else
BtnWidth := BtnWidth + SmallButtonBorderWidth;
// Right edge of the button
if (FGroupBehaviour in [gbBeginsGroup, gbContinuesGroup]) then
BtnWidth := BtnWidth + SmallButtonHalfBorderWidth
else
BtnWidth := BtnWidth + SmallButtonBorderWidth;
{$IFDEF EnhancedRecordSupport}
BtnRect := T2DIntRect.Create(0, 0, BtnWidth - 1, SpkLayoutSizes.PANE_ROW_HEIGHT - 1);
DropRect := T2DIntRect.Create(0, 0, 0, 0);
{$ELSE}
BtnRect.Create(0, 0, BtnWidth - 1, PaneRowHeight - 1);
DropRect.Create(0, 0, 0, 0);
{$ENDIF}
end;
bkButtonDropdown:
begin
// Left edge of the button
if FGroupBehaviour in [gbContinuesGroup, gbEndsGroup] then
BtnWidth := BtnWidth + SmallButtonHalfBorderWidth
else
BtnWidth := BtnWidth + SmallButtonBorderWidth;
// Right edge of the button
BtnWidth := BtnWidth + SmallButtonHalfBorderWidth;
// Left edge and dropdown field content
DropdownWidth := SmallButtonHalfBorderWidth + SmallButtonDropdownWidth;
// Right edge of the dropdown field
if (FGroupBehaviour in [gbBeginsGroup, gbContinuesGroup]) then
DropdownWidth := DropdownWidth + SmallButtonHalfBorderWidth
else
DropdownWidth := DropdownWidth + SmallButtonBorderWidth;
{$IFDEF EnhancedRecordSupport}
BtnRect := T2DIntRect.Create(0, 0, BtnWidth - 1, PaneRowHeightT - 1);
DropRect := T2DIntRect.Create(BtnRect.Right+1, 0, BtnRect.Right+DropdownWidth, PaneRowHeight - 1);
{$ELSE}
BtnRect.Create(0, 0, BtnWidth - 1, PaneRowHeight - 1);
DropRect.Create(BtnRect.Right+1, 0, BtnRect.Right+DropdownWidth, PaneRowHeight - 1);
{$ENDIF}
end;
bkDropdown:
begin
// Left edge of the button
if FGroupBehaviour in [gbContinuesGroup, gbEndsGroup] then
BtnWidth := BtnWidth + SmallButtonHalfBorderWidth
else
BtnWidth := BtnWidth + SmallButtonBorderWidth;
// Right edge of the button
if (FGroupBehaviour in [gbBeginsGroup, gbContinuesGroup]) then
BtnWidth := BtnWidth + SmallButtonHalfBorderWidth
else
BtnWidth := BtnWidth + SmallButtonBorderWidth;
// Additional area for dropdown + place for the central edge,
// for dimensional compatibility with dkButtonDropdown
BtnWidth := BtnWidth + SmallButtonBorderWidth + SmallButtonDropdownWidth;
{$IFDEF EnhancedRecordSupport}
BtnRect := T2DIntRect.Create(0, 0, BtnWidth - 1, PaneRowHeight - 1);
DropRect := T2DIntRect.Create(0, 0, 0, 0);
{$ELSE}
BtnRect.Create(0, 0, BtnWidth - 1, PaneRowHeight - 1);
DropRect.Create(0, 0, 0, 0);
{$ENDIF}
end;
end;
end;
procedure TSpkSmallButton.Draw(ABuffer: TBitmap; ClipRect: T2DIntRect);
var
fontColor: TColor;
frameColor, innerLightColor, innerDarkColor: TColor;
gradientFromColor, gradientToColor: TColor;
gradientKind: TBackgroundKind;
P: T2DIntPoint;
x, y: Integer;
delta: Integer;
cornerRadius: Integer;
imgList: TImageList;
imgSize: TSize;
drawBtn: Boolean;
R: TRect;
dx: Integer;
ppi: Integer;
begin
if (FToolbarDispatch = nil) or (FAppearance = nil) then
exit;
if (FRect.Width < 2*SmallButtonRadius) or (FRect.Height < 2*SmallButtonRadius) then
exit;
delta := FAppearance.Element.HotTrackBrightnessChange;
case FAppearance.Element.Style of
esRounded:
cornerRadius := SmallButtonRadius;
esRectangle:
cornerRadius := 0;
end;
// Button (Background and frame)
drawBtn := true;
if (FButtonState = bsIdle) and (not FHideFrameWhenIdle) then
begin
FAppearance.Element.GetIdleColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind
);
end else
if FButtonState = bsBtnHottrack then
begin
FAppearance.Element.GetHotTrackColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind
);
end else
if FButtonState = bsBtnPressed then
begin
FAppearance.Element.GetActiveColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind
);
end else
if (FButtonState in [bsDropdownHotTrack, bsDropdownPressed]) then
begin
FAppearance.Element.GetHotTrackColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind,
delta
);
end else
drawBtn := false;
if drawBtn then
begin
TButtonTools.DrawButton(
ABuffer,
FButtonRect, // draw button part only
frameColor,
innerLightColor,
innerDarkColor,
gradientFromColor,
gradientToColor,
gradientKind,
(FGroupBehaviour in [gbContinuesGroup, gbEndsGroup]),
(FGroupBehaviour in [gbBeginsGroup, gbContinuesGroup]) or (FButtonKind = bkButtonDropdown),
false,
false,
cornerRadius,
ClipRect
);
end;
// Icon
if not FEnabled and (FDisabledImages <> nil) then
imgList := FDisabledImages
else
imgList := FImages;
if (imgList <> nil) and (FImageIndex >= 0) and (FImageIndex < imgList.Count) then
begin
ppi := FAppearance.Element.CaptionFont.PixelsPerInch;
{$IF LCL_FULLVERSION >= 1090000}
imgSize := imgList.SizeForPPI[FImagesWidth, ppi];
{$ELSE}
imgSize := Size(imgList.Width, imgList.Height);
{$ENDIF}
if (FGroupBehaviour in [gbContinuesGroup, gbEndsGroup]) then
x := FButtonRect.Left + SmallButtonHalfBorderWidth + SmallButtonPadding
else
x := FButtonRect.Left + SmallButtonBorderWidth + SmallButtonPadding;
y := FButtonRect.top + (FButtonRect.height - imgSize.CY) div 2;
P := {$IFDEF EnhancedRecordSupport}T2DIntPoint.Create{$ELSE}Create2DIntPoint{$ENDIF}(x, y);
TGUITools.DrawImage(
ABuffer.Canvas,
imgList,
FImageIndex,
P,
ClipRect,
FImagesWidth,
ppi, 1.0
);
end;
// Prepare font and chevron color
fontColor := clNone;
case FButtonState of
bsIdle:
fontColor := FAppearance.Element.IdleCaptionColor;
bsBtnHottrack,
bsDropdownHottrack:
fontColor := FAppearance.Element.HotTrackCaptionColor;
bsBtnPressed,
bsDropdownPressed:
fontColor := FAppearance.ELement.ActiveCaptionColor;
end;
if not FEnabled then
fontColor := TColorTools.ColorToGrayscale(fontColor);
// Text
if FShowCaption then
begin
ABuffer.Canvas.Font.Assign(FAppearance.Element.CaptionFont);
ABuffer.Canvas.Font.Color := fontColor;
if (FGroupBehaviour in [gbContinuesGroup, gbEndsGroup]) then
x := FButtonRect.Left + SmallButtonHalfBorderWidth
else
x := FButtonRect.Left + SmallButtonBorderWidth;
if FImageIndex <> -1 then
x := x + 2 * SmallButtonPadding + SmallButtonGlyphWidth
else
x := x + SmallButtonPadding;
y := FButtonRect.Top + (FButtonRect.Height - ABuffer.Canvas.TextHeight('Wy')) div 2;
TGUITools.DrawText(ABuffer.Canvas, x, y, FCaption, fontColor, ClipRect);
end;
// Dropdown button
if FButtonKind = bkButtonDropdown then
begin
drawBtn := true;
if (FButtonState = bsIdle) and (not FHideFrameWhenIdle) then
begin
FAppearance.Element.GetIdleColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientkind
);
end else
if (FButtonState in [bsBtnHottrack, bsBtnPressed]) then
begin
FAppearance.Element.GetHotTrackColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind,
delta
);
end else
if (FButtonState = bsDropdownHottrack) then
begin
FAppearance.Element.GetHotTrackColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientkind
);
end else
if (FButtonState = bsDropdownPressed) then
begin
FAppearance.Element.GetActiveColors(Checked,
frameColor, innerLightColor, innerDarkColor,
gradientFromColor, gradientToColor, gradientKind
);
end else
drawBtn := false;
if drawBtn then begin
TButtonTools.DrawButton(
ABuffer,
FDropdownRect,
frameColor,
innerLightColor,
innerDarkColor,
gradientFromColor,
gradientToColor,
gradientKind,
true,
(FGroupBehaviour in [gbBeginsGroup, gbContinuesGroup]),
false,
false,
cornerRadius,
ClipRect
);
end;
end;
// Dropdown arrow
if FButtonKind in [bkDropdown, bkButtonDropdown] then begin
dx := SmallButtonDropdownWidth;
if FGroupBehaviour in [gbBeginsGroup, gbContinuesGroup] then
inc(dx, SmallButtonHalfBorderWidth)
else
inc(dx, SmallButtonBorderWidth);
if FButtonKind = bkDropdown then
R := Classes.Rect(FButtonRect.Right-dx, FButtonRect.Top, FButtonRect.Right, FButtonRect.Bottom)
else
R := Classes.Rect(FDropdownRect.Right-dx, FDropdownRect.Top, FDropdownRect.Right, FDropdownRect.Bottom);
DrawdropdownArrow(ABuffer, R, fontcolor);
end;
end;
function TSpkSmallButton.GetDropdownPoint: T2DIntPoint;
begin
{$IFDEF EnhancedRecordSupport}
if FButtonKind in [bkButtonDropdown, bkDropdown] then
Result := T2DIntPoint.Create(FButtonRect.Left, FButtonRect.Bottom+1)
else
Result := T2DIntPoint.Create(0,0);
{$ELSE}
if FButtonKind in [bkButtonDropdown, bkDropdown] then
Result.Create(FButtonRect.Left, FButtonRect.Bottom+1)
else
Result.Create(0,0);
{$ENDIF}
end;
function TSpkSmallButton.GetGroupBehaviour: TSpkItemGroupBehaviour;
begin
Result := FGroupBehaviour;
end;
function TSpkSmallButton.GetSize: TSpkItemSize;
begin
Result := isNormal;
end;
function TSpkSmallButton.GetTableBehaviour: TSpkItemTableBehaviour;
begin
Result := FTableBehaviour;
end;
function TSpkSmallButton.GetWidth: integer;
var
BtnRect, DropRect: T2DIntRect;
begin
Result := -1;
if FToolbarDispatch = nil then
exit;
if FAppearance = nil then
exit;
ConstructRects(BtnRect, DropRect);
if FButtonKind = bkButtonDropdown then
Result := DropRect.Right+1
else
Result := BtnRect.Right+1;
end;
procedure TSpkSmallButton.SetGroupBehaviour(const Value: TSpkItemGroupBehaviour);
begin
FGroupBehaviour := Value;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyMetricsChanged;
end;
procedure TSpkSmallButton.SetHideFrameWhenIdle(const Value: boolean);
begin
FHideFrameWhenIdle := Value;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyVisualsChanged;
end;
procedure TSpkSmallButton.SetImageIndex(const Value: TImageIndex);
begin
FImageIndex := Value;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyMetricsChanged;
end;
procedure TSpkSmallButton.SetShowCaption(const Value: boolean);
begin
FShowCaption := Value;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyMetricsChanged;
end;
procedure TSpkSmallButton.SetTableBehaviour(const Value: TSpkItemTableBehaviour);
begin
FTableBehaviour := Value;
if Assigned(FToolbarDispatch) then
FToolbarDispatch.NotifyMetricsChanged;
end;
end.