File: kascomctrls.pas

package info (click to toggle)
doublecmd 1.1.30-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 43,968 kB
  • sloc: pascal: 374,335; sh: 1,180; ansic: 724; makefile: 132; python: 52; xml: 16
file content (312 lines) | stat: -rw-r--r-- 8,207 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
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.