mirror of
https://github.com/doublecmd/doublecmd.git
synced 2026-06-21 09:58:13 +00:00
312 lines
8 KiB
ObjectPascal
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.
|
|
|