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.