doublecmd/components/KASToolBar/kascomctrls.pas
Alexander Koblov f2634f4d10 FIX: Viewer - wrong toolbar buttons sequence
(cherry picked from commit 3a4700e991)
(cherry picked from commit b6128fae02)
2025-05-25 13:32:12 +03:00

312 lines
8 KiB
ObjectPascal

unit KASComCtrls;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Controls, ComCtrls, Graphics, Dialogs;
type
{ TToolButtonClr }
TToolButtonClr = class(TToolButton)
private
FButtonColor: TColor;
FColorDialog: TColorDialog;
procedure SetButtonColor(AValue: TColor);
protected
procedure Paint; override;
procedure ShowColorDialog;
public
constructor Create(TheOwner: TComponent); override;
procedure Click; override;
property ButtonColor: TColor read FButtonColor write SetButtonColor;
end;
{ TToolBarAdv }
TToolBarAdv = class(TToolBar)
private
FToolBarFlags: TToolBarFlags;
protected
procedure CalculatePreferredSize(var PreferredWidth,
PreferredHeight: Integer;
{%H-}WithThemeSpace: Boolean); override;
procedure AlignControls({%H-}AControl: TControl;
var RemainingClientRect: TRect); override;
function WrapButtons(UseSize: Integer; out NewWidth,
NewHeight: Integer; Simulate: Boolean): Boolean;
end;
procedure Register;
implementation
uses
Math;
{ TToolButtonClr }
procedure TToolButtonClr.SetButtonColor(AValue: TColor);
begin
if FButtonColor <> AValue then
begin
FButtonColor:= AValue;
Invalidate;
end;
end;
procedure TToolButtonClr.Paint;
var
ARect, IconRect: TRect;
begin
inherited Paint;
if (FToolBar <> nil) and (ClientWidth > 0) and (ClientHeight > 0) then
begin
ARect:= ClientRect;
IconRect.Left:= (ARect.Width - FToolBar.ImagesWidth) div 2;
IconRect.Top:= (ARect.Height - FToolBar.ImagesWidth) div 2;
IconRect.Right:= IconRect.Left + FToolBar.ImagesWidth;
IconRect.Bottom:= IconRect.Top + FToolBar.ImagesWidth;
if Enabled then
begin
Canvas.Brush.Style:= bsSolid;
Canvas.Brush.Color:= FButtonColor
end
else begin
Canvas.Brush.Color:= clGrayText;
Canvas.Brush.Style:= bsDiagCross;
end;
Canvas.Pen.Color:= clBtnText;
Canvas.Rectangle(IconRect);
end;
end;
procedure TToolButtonClr.ShowColorDialog;
begin
if not Enabled then Exit;
if (FColorDialog = nil) then
begin
FColorDialog := TColorDialog.Create(Self);
end;
FColorDialog.Color := ButtonColor;
if FColorDialog.Execute then
begin
ButtonColor := FColorDialog.Color;
end;
end;
constructor TToolButtonClr.Create(TheOwner: TComponent);
begin
FButtonColor:= clRed;
inherited Create(TheOwner);
end;
procedure TToolButtonClr.Click;
begin
inherited Click;
ShowColorDialog;
end;
{ TToolBarAdv }
procedure TToolBarAdv.CalculatePreferredSize(var PreferredWidth,
PreferredHeight: Integer; WithThemeSpace: Boolean);
begin
if IsVertical then
WrapButtons(Height, PreferredWidth, PreferredHeight, True)
else
WrapButtons(Width, PreferredWidth, PreferredHeight, True);
end;
procedure TToolBarAdv.AlignControls(AControl: TControl;
var RemainingClientRect: TRect);
var
NewWidth, NewHeight: integer;
begin
if tbfPlacingControls in FToolBarFlags then exit;
Include(FToolBarFlags, tbfPlacingControls);
DisableAlign;
try
AdjustClientRect(RemainingClientRect);
if IsVertical then
WrapButtons(Height, NewWidth, NewHeight, False)
else
WrapButtons(Width, NewWidth, NewHeight, False);
finally
Exclude(FToolBarFlags, tbfPlacingControls);
EnableAlign;
end;
end;
function TToolBarAdv.WrapButtons(UseSize: Integer; out NewWidth,
NewHeight: Integer; Simulate: Boolean): Boolean;
var
ARect: TRect;
X, Y: Integer;
Vertical: Boolean;
LeftToRight: Boolean;
CurControl: TControl;
StartX, StartY: Integer;
FRowWidth, FRowHeight: Integer;
procedure CalculatePosition;
var
NewBounds: TRect;
StartedAtRowStart: Boolean;
begin
if IsVertical then
begin
NewBounds := Bounds(X, Y, FRowWidth, CurControl.Height);
repeat
if (not Wrapable) or
(NewBounds.Top = StartY) or
(NewBounds.Bottom <= ARect.Bottom) then
begin
// control fits into the column
X := NewBounds.Left;
Y := NewBounds.Top;
Break;
end;
// try next column
NewBounds.Top := StartY;
NewBounds.Bottom := NewBounds.Top + CurControl.Height;
Inc(NewBounds.Left, FRowWidth);
Inc(NewBounds.Right, FRowWidth);
until False;
end
else begin
StartedAtRowStart := (X = StartX);
if LeftToRight then
NewBounds := Bounds(X, Y, CurControl.Width, FRowHeight)
else begin
NewBounds := Bounds(X - CurControl.Width, Y, CurControl.Width, FRowHeight);
end;
repeat
if (not Wrapable) or
(StartedAtRowStart) or
(LeftToRight and ((NewBounds.Left = StartX) or (NewBounds.Right <= ARect.Right))) or
((not LeftToRight) and ((NewBounds.Right = StartX) or (NewBounds.Left >= ARect.Left))) then
begin
// control fits into the row
X := NewBounds.Left;
Y := NewBounds.Top;
Break;
end;
StartedAtRowStart := True;
// try next row
if LeftToRight then
begin
NewBounds.Left := StartX;
NewBounds.Right := NewBounds.Left + CurControl.Width;
end else begin
NewBounds.Right := StartX;
NewBounds.Left := NewBounds.Right - CurControl.Width;
end;
Inc(NewBounds.Top, FRowHeight);
Inc(NewBounds.Bottom, FRowHeight);
until False;
end;
end;
var
I: Integer;
W, H: Integer;
CurClientRect: TRect;
AdjustClientFrame: TRect;
begin
NewWidth := 0;
NewHeight := 0;
Result := True;
Vertical := IsVertical;
FRowWidth:= ButtonWidth;
FRowHeight:= ButtonHeight;
if Vertical then
begin
LeftToRight := True;
end
else begin
LeftToRight := not UseRightToLeftAlignment;
end;
DisableAlign;
BeginUpdate;
try
CurClientRect := ClientRect;
if Vertical then
Inc(CurClientRect.Bottom, UseSize - Height)
else begin
Inc(CurClientRect.Right, UseSize - Width);
end;
ARect := CurClientRect;
AdjustClientRect(ARect);
AdjustClientFrame.Left := ARect.Left - CurClientRect.Left;
AdjustClientFrame.Top := ARect.Top - CurClientRect.Top;
AdjustClientFrame.Right := CurClientRect.Right - ARect.Right;
AdjustClientFrame.Bottom := CurClientRect.Bottom - ARect.Bottom;
//DebugLn(['TToolBar.WrapButtons ',DbgSName(Self),' ARect=',dbgs(ARect)]);
// important: top, left button must start in the AdjustClientRect top, left
// otherwise Toolbar.AutoSize=true will create an endless loop
if Vertical or LeftToRight then
StartX := ARect.Left
else begin
StartX := ARect.Right;
end;
StartY := ARect.Top;
X := StartX;
Y := StartY;
for I := 0 to ButtonList.Count - 1 do
begin
CurControl := TControl(ButtonList[I]);
if not CurControl.IsControlVisible then
Continue;
CalculatePosition;
W := CurControl.Width;
H := CurControl.Height;
if (not Simulate) and ((CurControl.Left <> X) or (CurControl.Top <> Y)) then
begin
CurControl.SetBounds(X, Y, W, H); // Note: do not use SetBoundsKeepBase
end;
// adjust NewWidth, NewHeight
if LeftToRight then
NewWidth := Max(NewWidth, X + W + AdjustClientFrame.Right)
else begin
NewWidth := Max(NewWidth, ARect.Right - X + ARect.Left + AdjustClientFrame.Right);
end;
NewHeight := Max(NewHeight, Y + H + AdjustClientFrame.Bottom);
// step to next position
if IsVertical then
Inc(Y, H)
else if LeftToRight then
Inc(X, W);
end;
finally
EndUpdate;
EnableAlign;
end;
end;
procedure Register;
begin
RegisterComponents('KASComponents', [TToolBarAdv]);
RegisterNoIcon([TToolButtonClr]);
end;
end.