1{%MainUnit ../comctrls.pp}
2
3{******************************************************************************
4                                  TCoolBar
5 ******************************************************************************
6
7 *****************************************************************************
8  This file is part of the Lazarus Component Library (LCL)
9
10  See the file COPYING.modifiedLGPL.txt, included in this distribution,
11  for details about the license.
12 *****************************************************************************
13
14}
15
16{ TCoolBand }
17
18constructor TCoolBand.Create(aCollection: TCollection);
19begin
20  FBreak := True;
21  FColor := clDefault;
22  FControl := Nil;
23  FFixedBackground := True;
24  FImageIndex := -1;
25  FMinHeight := cDefMinHeight;
26  FMinWidth := cDefMinWidth;
27  FParentBitmap := True;
28  FParentColor := True;
29  FVisible := True;
30  FWidth := cDefWidth;
31  inherited Create(aCollection);
32  Assert(aCollection is TCoolBands, 'TCoolBand.Create: aCollection is not TCoolBands');
33  FCoolBar := TCoolBands(aCollection).FCoolBar;
34  FBitmap := TBitmap.Create;
35  FBitmap.OnChange := @InvalidateCoolBar;
36end;
37
38destructor TCoolBand.Destroy;
39begin
40  FBitmap.Free;
41  inherited Destroy;
42end;
43
44procedure TCoolBand.Assign(aSource: TPersistent);
45var src: TCoolBand;
46    SrcCtrl: TWinControl;
47begin
48  if aSource is TCoolBand then begin
49    src := TCoolBand(aSource);
50    Bitmap          := src.Bitmap;
51    Break           := src.Break;
52    Color           := src.Color;
53    FixedBackground := src.FixedBackground;
54    FixedSize       := src.FixedSize;
55    HorizontalOnly  := src.HorizontalOnly;
56    ImageIndex      := src.ImageIndex;
57    MinHeight       := src.MinHeight;
58    MinWidth        := src.MinWidth;
59    ParentBitmap    := src.ParentBitmap;
60    ParentColor     := src.ParentColor;
61    Text            := src.Text;
62    Visible         := src.Visible;
63    SrcCtrl := Nil;
64    if Assigned(src.Control) then
65      SrcCtrl := FCoolBar.Owner.FindComponent(src.Control.Name) as TWinControl;
66    Control         := SrcCtrl;
67  end else
68    inherited Assign(aSource);
69end;
70
71procedure TCoolBand.AutosizeWidth;
72var h, w: Integer;
73begin
74  if Assigned(FControl) and FControl.AutoSize then begin
75    FControl.GetPreferredSize(w, h);
76    if FCoolBar.Vertical then w := h;
77    inc(w, CalcControlLeft+FCoolBar.HorizontalSpacing+cDivider);
78    Width := Math.max(FMinWidth, w);
79  end;
80end;
81
82function TCoolBand.CalcControlLeft: Integer;
83var aImageSize, xHelp: Integer;
84begin
85  Result := cGrabIndent+FCoolBar.GrabWidth+FCoolBar.HorizontalSpacing;
86  xHelp := Result;
87  if (Text <> '') and FCoolBar.ShowText then
88    inc(Result, FTextWidth+FCoolBar.HorizontalSpacing);
89  if Assigned(FCoolBar.Images) then begin
90    if not FCoolBar.Vertical then
91      aImageSize := FCoolBar.Images.WidthForPPI[FCoolBar.ImagesWidth, FCoolBar.Font.PixelsPerInch]
92    else
93      aImageSize := FCoolBar.Images.HeightForPPI[FCoolBar.ImagesWidth, FCoolBar.Font.PixelsPerInch];
94    if ImageIndex >= 0 then
95      inc(Result, aImageSize+FCoolBar.HorizontalSpacing);
96  end;
97  if Result = xHelp then inc(Result, FCoolBar.HorizontalSpacing);
98end;
99
100function TCoolBand.CalcPreferredHeight: Integer;
101begin
102  Result := FMinHeight;
103  if not FCoolBar.Vertical then begin
104    if Assigned(FControl) then
105      Result := max(Result, FControl.Height+2*FCoolBar.VerticalSpacing);
106    if Assigned(FCoolBar.Images) and (ImageIndex >= 0) then
107      Result := max(Result, FCoolBar.Images.HeightForPPI[FCoolBar.ImagesWidth, FCoolBar.Font.PixelsPerInch]+2*FCoolBar.VerticalSpacing);
108  end else begin
109    if Assigned(FControl) then
110      Result := max(Result, FControl.Width+2*FCoolBar.VerticalSpacing);
111    if Assigned(FCoolBar.Images) and (ImageIndex >= 0) then
112      Result := max(Result, FCoolBar.Images.WidthForPPI[FCoolBar.ImagesWidth, FCoolBar.Font.PixelsPerInch]+2*FCoolBar.VerticalSpacing);
113  end;
114  if FCoolBar.FShowText then
115    Result := max(Result, FCoolBar.FTextHeight+2*FCoolBar.VerticalSpacing);
116  //DebugLn('CalcPreferredHeight ', CalcPreferredHeightHor);
117end;
118
119function TCoolBand.CalcPreferredWidth: Integer;
120begin
121  Result := CalcControlLeft;
122  if Assigned(Control) then inc(Result, Control.Width+FCoolBar.HorizontalSpacing);
123  inc(Result, cDivider);
124  Result := max(FMinWidth, Result);
125end;
126
127procedure TCoolBand.CalcTextWidth;
128begin
129  if Assigned(FCoolBar) and not (csLoading in FCoolBar.ComponentState) then
130    FTextWidth := FCoolBar.Canvas.TextWidth(FText);
131end;
132
133function TCoolBand.GetDisplayName: string;
134begin
135  Result := Text;
136  if Result = '' then Result := ClassName;
137end;
138
139function TCoolBand.GetRight: Integer;
140begin
141  Result := FLeft+FWidth;
142end;
143
144function TCoolBand.IsBitmapStored: Boolean;
145begin
146  Result := not ParentBitmap;
147end;
148
149function TCoolBand.IsColorStored: Boolean;
150begin
151  Result := not ParentColor;
152end;
153
154procedure TCoolBand.InvalidateCoolBar(Sender: TObject);
155begin
156  Changed(False);
157end;
158
159function TCoolBand.GetVisible: Boolean;
160begin
161  Result := FVisible and not (FCoolBar.Vertical and FHorizontalOnly);
162end;
163
164procedure TCoolBand.SetBitmap(AValue: TBitmap);
165begin
166  FParentBitmap := False;
167  FBitmap.Assign(AValue);
168  Changed(False);
169end;
170
171procedure TCoolBand.SetBorderStyle(AValue: TBorderStyle);
172begin
173  if FBorderStyle = AValue then Exit;
174  FBorderStyle := AValue;
175  Changed(False);
176end;
177
178procedure TCoolBand.SetBreak(AValue: Boolean);
179begin
180  if FBreak = AValue then Exit;
181  FBreak := AValue;
182  Changed(True);
183end;
184
185procedure TCoolBand.SetColor(AValue: TColor);
186begin
187  if FColor = AValue then Exit;
188  FColor := AValue;
189  FParentColor := False;
190  Changed(False);
191end;
192
193procedure TCoolBand.SetControl(AValue: TControl);
194var aBand: TCoolBand;
195begin
196  if FControl = AValue then Exit;
197  FControl := AValue;
198  if Assigned(AValue) then begin
199    AValue.Align := alNone;
200    aBand := TCoolBands(Collection).FindBand(AValue);
201    if Assigned(aBand) and (aBand <> Self) then aBand.SetControl(Nil);  //remove old association
202    AValue.Parent := FCoolBar;
203  end;
204  Changed(True);
205end;
206
207procedure TCoolBand.SetFixedBackground(AValue: Boolean);
208begin
209  if FFixedBackground = AValue then Exit;
210  FFixedBackground := AValue;
211  Changed(False);
212end;
213
214procedure TCoolBand.SetHorizontalOnly(AValue: Boolean);
215begin
216  if FHorizontalOnly = AValue then Exit;
217  FHorizontalOnly := AValue;
218  Changed(FCoolBar.Vertical);
219end;
220
221procedure TCoolBand.SetImageIndex(AValue: TImageIndex);
222begin
223  if FImageIndex = AValue then Exit;
224  FImageIndex := AValue;
225  Changed(True);
226end;
227
228procedure TCoolBand.SetMinHeight(AValue: Integer);
229begin
230  if FMinHeight = AValue then Exit;
231  FMinHeight := AValue;
232  Changed(False);
233end;
234
235procedure TCoolBand.SetMinWidth(AValue: Integer);
236begin
237  if FMinWidth = AValue then Exit;
238  FMinWidth := AValue;
239  Changed(False);
240end;
241
242procedure TCoolBand.SetParentBitmap(AValue: Boolean);
243begin
244  if FParentBitmap = AValue then Exit;
245  FParentBitmap := AValue;
246  Changed(False);
247end;
248
249procedure TCoolBand.SetParentColor(AValue: Boolean);
250begin
251  if FParentColor = AValue then Exit;
252  FParentColor := AValue;
253  Changed(False);
254end;
255
256procedure TCoolBand.SetText(const AValue: TTranslateString);
257begin
258  if AValue = FText then Exit;
259  FText := AValue;
260  CalcTextWidth;
261  Changed(True);
262end;
263
264procedure TCoolBand.SetVisible(AValue: Boolean);
265begin
266  if FVisible = AValue then Exit;
267  FVisible := AValue;
268  if Assigned(FControl) then FControl.Visible := AValue;
269  Changed(True);
270end;
271
272procedure TCoolBand.SetWidth(AValue: Integer);
273begin
274  if AValue = FWidth then Exit;
275  if AValue < FMinWidth then AValue := FMinWidth;
276  FWidth := AValue;
277  Changed(True);
278end;
279
280{ TCoolBands }
281
282constructor TCoolBands.Create(ACoolBar: TCustomCoolBar);
283begin
284  inherited Create(TCoolBand);
285  FCoolBar := ACoolBar;
286end;
287
288function TCoolBands.Add: TCoolBand;
289begin
290  Result := TCoolBand(inherited Add);
291  //DebugLn('TCoolBands.Add');
292end;
293
294function TCoolBands.FindBand(AControl: TControl): TCoolBand;
295var i: Integer;
296begin
297  Result := Nil;
298  for i := 0 to Count-1 do
299    if GetItem(i).FControl = AControl then
300      Exit(GetItem(i));
301end;
302
303function TCoolBands.FindBandindex(AControl: TControl): Integer;
304var i: Integer;
305begin
306  Result := -1;
307  for i := 0 to Count-1 do
308    if GetItem(i).FControl = AControl then
309      Exit(i);
310end;
311
312procedure TCoolBands.Notify(aItem: TCollectionItem; aAction: TCollectionNotification);
313begin
314  inherited Notify(aItem, aAction);
315  if aAction = cnAdded then begin
316    //DebugLn('TCoolBands.Notify: aAction = cnAdded');
317    TCoolBand(aItem).FCoolBar := FCoolBar;
318  end;
319end;
320
321procedure TCoolBands.Update(aItem: TCollectionItem);
322begin
323  inherited Update(aItem);
324  if Assigned(FCoolBar) then begin
325    //DebugLn('Bands.Update calls CalcAndAlign');
326    if not Assigned(aItem) then FCoolBar.CalculateAndAlign;
327    FCoolBar.Invalidate;
328  end;
329end;
330
331function TCoolBands.GetItem(Index: Integer): TCoolBand;
332begin
333  Result := TCoolBand(inherited GetItem(Index));
334end;
335
336function TCoolBands.GetOwner: TPersistent;
337begin
338  Result := FCoolBar;
339end;
340
341procedure TCoolBands.SetItem(Index: Integer; Value: TCoolBand);
342begin
343  inherited SetItem(Index, Value);
344end;
345
346{ TCustomCoolBar }
347
348constructor TCustomCoolBar.Create(AOwner: TComponent);
349begin
350  FBands := TCoolBands.Create(Self);
351  inherited Create(AOwner);
352  ControlStyle := ControlStyle-[csSetCaption]
353                +[csAcceptsControls, csNoFocus, csOpaque, csParentBackground, csReplicatable];
354  Align := alTop;
355  Height := 75;
356  ParentColor := True;
357  ParentFont := True;
358  FBandBorderStyle := bsSingle;
359  FBandMaximize := bmClick;
360  FBitmap := TBitmap.Create;
361  FBitmap.OnChange := @BitmapOrImageListChange;
362  FBorderEdges := EdgeBorders;
363  FBorderLeft := 2;
364  FBorderTop := 2;
365  FBorderRight := 2;
366  FBorderBottom := 2;
367  FBorderWidth := 2;
368  FGrabStyle := cDefGrabStyle;
369  FGrabWidth := cDefGrabWidth;
370  FHorizontalSpacing := cDefHorSpacing;
371  FImageChangeLink := TChangeLink.Create;
372  FImageChangeLink.OnChange := @BitmapOrImageListChange;
373  FShowText := True;
374  FThemed := True;
375  FVerticalSpacing := cDefVertSpacing;
376  UseDockManager := True;
377end;
378
379destructor TCustomCoolBar.Destroy;
380begin
381  FImageChangeLink.Free;
382  FBitmap.Free;
383  FBands.Free;
384  inherited Destroy;
385end;
386
387function TCustomCoolBar.GetAlign: TAlign;
388begin
389  Result := inherited Align;
390end;
391
392procedure TCustomCoolBar.SetAlign(aValue: TAlign);
393var Old: TAlign;
394begin
395  Old := inherited Align;
396  if aValue = Old then Exit;
397  inherited Align := aValue;
398  if csReading in ComponentState then Exit;
399  Vertical := (aValue in [alLeft, alRight]);
400end;
401
402procedure TCustomCoolBar.SetAutoSize(Value: Boolean);
403begin
404  inherited SetAutoSize(Value);
405  if Value then CalculateAndAlign;
406  Invalidate;
407end;
408
409procedure TCustomCoolBar.SetBandBorderStyle(AValue: TBorderStyle);
410begin
411  if FBandBorderStyle = AValue then Exit;
412  FBandBorderStyle := AValue;
413  Invalidate;
414end;
415
416procedure TCustomCoolBar.SetBands(AValue: TCoolBands);
417begin
418  FBands.Assign(AValue);
419end;
420
421procedure TCustomCoolBar.SetBitmap(AValue: TBitmap);
422begin
423  FBitmap.Assign(AValue);
424end;
425
426procedure TCustomCoolBar.SetCursor(Value: TCursor);
427begin
428  inherited SetCursor(Value);
429  if not FLockCursor then FCursorBkgnd:=Value;
430end;
431
432procedure TCustomCoolBar.SetGrabStyle(AValue: TGrabStyle);
433begin
434  if FGrabStyle = AValue then Exit;
435  FGrabStyle := AValue;
436  Invalidate;
437end;
438
439procedure TCustomCoolBar.SetGrabWidth(AValue: Integer);
440begin
441  if FGrabWidth = AValue then Exit;
442  FGrabWidth := AValue;
443  CalculateAndAlign;
444  Invalidate;
445end;
446
447procedure TCustomCoolBar.SetHorizontalSpacing(AValue: Integer);
448begin
449  if FHorizontalSpacing=AValue then Exit;
450  FHorizontalSpacing:=AValue;
451  CalculateAndAlign;
452  Invalidate;
453end;
454
455procedure TCustomCoolBar.SetImages(AValue: TCustomImageList);
456begin
457  if Assigned(FImages) then
458    FImages.UnRegisterChanges(FImageChangeLink);
459  FImages := AValue;
460  if Assigned(FImages) then begin
461    AValue.RegisterChanges(FImageChangeLink);
462    AValue.FreeNotification(Self);
463  end;
464  CalculateAndAlign;
465  Invalidate;
466end;
467
468procedure TCustomCoolBar.SetImagesWidth(const aImagesWidth: Integer);
469begin
470  if FImagesWidth = aImagesWidth then Exit;
471  FImagesWidth := aImagesWidth;
472  CalculateAndAlign;
473  Invalidate;
474end;
475
476procedure TCustomCoolBar.SetShowText(AValue: Boolean);
477begin
478  if FShowText = AValue then Exit;
479  FShowText := AValue;
480  CalculateAndAlign;
481  Invalidate;
482end;
483
484procedure TCustomCoolBar.SetThemed(AValue: Boolean);
485begin
486  if FThemed = AValue then Exit;
487  FThemed := AValue;
488  Invalidate;
489end;
490
491
492procedure TCustomCoolBar.SetVertical(AValue: Boolean);
493var aRect: TRect;
494begin
495  if FVertical = aValue then Exit;
496  FVertical := AValue;
497  AdjustSize;
498  CalculateAndAlign;
499  Invalidate;
500end;
501
502procedure TCustomCoolBar.SetVerticalSpacing(AValue: Integer);
503begin
504  if FVerticalSpacing=AValue then Exit;
505  FVerticalSpacing:=AValue;
506  CalculateAndAlign;
507  Invalidate;
508end;
509
510procedure TCustomCoolBar.AlignControls(AControl: TControl; var RemainingClientRect: TRect);
511var aAnchor: TAnchorKind;
512    i: Integer;
513begin
514  //DebugLn('AlignControls');
515  if wcfAligningControls in FWinControlFlags then Exit;
516  if not FRightToLeft then
517    aAnchor := akLeft
518  else
519    aAnchor := akRight;
520  for i := 0 to Bands.Count-1 do
521    if Assigned(Bands[i].FControl) then begin
522      Bands[i].Control.Align := alNone;
523      Bands[i].FControl.BorderSpacing.Around := 0;
524      Bands[i].FControl.Anchors := [akTop, aAnchor];
525      if not Vertical then begin
526        Bands[i].FControl.AnchorParallel(aAnchor, Bands[i].FControlLeft, Self);
527        Bands[i].FControl.AnchorParallel(akTop, Bands[i].FControlTop, Self);
528      end else begin
529        Bands[i].FControl.AnchorParallel(akTop, Bands[i].FControlLeft, Self);
530        Bands[i].FControl.AnchorParallel(aAnchor, Bands[i].FControlTop, Self);
531      end;
532    end;
533  inherited AlignControls(AControl, RemainingClientRect);
534end;
535
536procedure TCustomCoolBar.AutosizeBands;
537var i: Integer;
538begin
539  BeginUpdate;
540  for i := 0 to Bands.Count-1 do
541    Bands[i].AutosizeWidth;
542  EndUpdate;
543end;
544
545procedure TCustomCoolBar.BitmapOrImageListChange(Sender: TObject);
546begin
547  Invalidate;
548end;
549
550procedure TCustomCoolBar.CalculateAndAlign;
551var i, x, y, aBandHeight, aBorderLeft, aCountM1, aLeft,
552    aPrefSize, aStartIndex, aTop, aWidth, NewWidth,NewHeight: Integer;
553    aRowEnd: Boolean;
554begin
555  //DebugLn('CalculateAndAlign');
556  if (FUpdateCount > 0) or ([csLoading, csDestroying] * ComponentState <> []) then Exit;
557  aCountM1 := FBands.Count-1;
558  x := 0;
559  for i := 0 to aCountM1 do
560    if FBands[i].Visible then inc(x);
561  SetLength(FVisiBands, x);
562  x := 0;
563  for i := 0 to aCountM1 do
564    if FBands[i].Visible then begin
565      FVisiBands[x] := FBands[i];
566      inc(x);
567    end;
568  aCountM1 := x-1;
569  if not Vertical then begin
570    if not FRightToLeft then
571      aBorderLeft := FBorderLeft
572    else
573      aBorderLeft := FBorderRight;
574    aPrefSize := FBorderTop+FBorderBottom;
575  end else begin
576    aBorderLeft := FBorderTop;
577    aPrefSize := FBorderLeft+FBorderRight-TCoolBand.cDivider;
578  end;
579  //do not use FBands from this point, only FVisiBands
580  aBandHeight := 0;
581  aStartIndex := 0;
582  //set all Bands in row to uniform height
583  aRowEnd := True;
584  aLeft := aBorderLeft;
585  for i := 0 to aCountM1 do begin
586    if aRowEnd or FVisiBands[i].Break then
587      aLeft := aBorderLeft;
588    if FVisiBands[i].Control is TToolBar then
589    begin
590      if TToolBar(FVisiBands[i].Control).IsVertical then
591        TToolBar(FVisiBands[i].Control).WrapButtons(Height,NewWidth,NewHeight,true)
592      else
593        TToolBar(FVisiBands[i].Control).WrapButtons(Width,NewWidth,NewHeight,true);
594      FVisiBands[i].Control.Width:=NewWidth;
595      FVisiBands[i].Control.Height:=NewHeight;
596    end;
597    aBandHeight := Max(aBandHeight, FVisiBands[i].CalcPreferredHeight);
598    aRowEnd := (i = aCountM1);
599    inc(aLeft, FVisiBands[i].Width);
600    aRowEnd := aRowEnd or ((i < aCountM1) and RowEndHelper(ALeft, i));
601    if aRowEnd then begin
602      inc(aPrefSize, aBandHeight+TCoolBand.cDivider);
603      for y := aStartIndex to i do
604        FVisiBands[y].FHeight := aBandHeight;
605      aBandHeight := 0;
606      aStartIndex := i+1;
607    end;
608  end;
609  if not Vertical then
610    aTop := FBorderTop
611  else begin
612    if not FRightToLeft then
613      aTop := FBorderLeft
614    else begin
615      aTop := FBorderRight;
616      if not AutoSize then aPrefSize := Width;
617    end;
618  end;
619  aRowEnd := True;
620  include(FWinControlFlags, wcfAligningControls);
621  for i := 0 to aCountM1 do begin
622    if aRowEnd or FVisiBands[i].Break then
623      aLeft := aBorderLeft;
624    if not FRightToLeft or Vertical then
625      FVisiBands[i].FLeft := aLeft
626    else
627      FVisiBands[i].FLeft := Width-aLeft-FVisiBands[i].Width;
628    FVisiBands[i].FRealLeft := FVisiBands[i].FLeft;
629    if not Vertical or not FRightToLeft then
630      FVisiBands[i].FTop := aTop
631    else
632      FVisiBands[i].FTop := Width-aTop-FVisiBands[i].Height;
633    if Assigned(FVisiBands[i].Control) then begin
634      x := FVisiBands[i].CalcControlLeft;
635      aWidth := FVisiBands[i].Width-x-HorizontalSpacing-TCoolBand.cDivider;
636      if not FRightToLeft then begin
637        inc(x, aLeft);
638        if not Vertical then
639          FVisiBands[i].Control.Left := x
640        else
641          FVisiBands[i].Control.Top := x;
642        FVisiBands[i].FControlLeft := x-aBorderLeft;
643      end else begin
644        if not Vertical then begin
645          x := FVisiBands[i].FLeft+TCoolBand.cDivider+HorizontalSpacing;
646          FVisiBands[i].Control.Left := x;
647          FVisiBands[i].FControlLeft := Width-x-Bands[i].FControl.Width-aBorderLeft;
648        end else begin
649          inc(x, aLeft);
650          FVisiBands[i].Control.Top := x;
651          FVisiBands[i].FControlLeft := x-aBorderLeft;
652        end;
653      end;
654      if not Vertical then begin
655        y := aTop+(FVisiBands[i].FHeight-FVisiBands[i].Control.Height) div 2;
656        FVisiBands[i].FControlTop := y-FBorderTop;
657        FVisiBands[i].Control.Top := FVisiBands[i].FControlTop+FBorderTop;
658        FVisiBands[i].Control.Width := aWidth;
659      end else begin
660        y := aTop+(FVisiBands[i].FHeight-FVisiBands[i].Control.Width) div 2;
661        if not FRightToLeft then begin
662          FVisiBands[i].Control.Left := y;
663          FVisiBands[i].FControlTop := y-FBorderLeft;
664        end else begin
665          FVisiBands[i].Control.Left := aPrefSize-y-FVisiBands[i].Control.Width;
666          FVisiBands[i].FControlTop := y-FBorderRight;
667        end;
668        FVisiBands[i].Control.Height := aWidth;
669      end;
670    end;
671    x := FVisiBands[i].Width;
672    inc(aLeft, x);
673    aRowEnd := IsRowEnd(aLeft, i);
674    if aRowEnd or (i = aCountM1) then begin
675      if not Vertical then begin
676        FVisiBands[i].FRealWidth := x+Width-aLeft-FBorderRight;
677        if FRightToLeft then FVisiBands[i].FRealLeft := FBorderLeft;
678      end else
679        FVisiBands[i].FRealWidth := x+Height-aLeft-FBorderBottom;
680    end else
681      FVisiBands[i].FRealWidth := x;
682    if aRowEnd then inc(aTop, FVisiBands[i].FHeight+TCoolBand.cDivider);
683  end;
684  if AutoSize then begin
685    if aCountM1 >= 0 then DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TCustomCoolBar.CalculateAndAlign'){$ENDIF};
686    inc(FUpdateCount);
687    try
688      InvalidatePreferredSize;
689      AdjustSize;
690    finally
691      if aCountM1 >= 0 then EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TCustomCoolBar.CalculateAndAlign'){$ENDIF};
692      dec(FUpdateCount);
693    end;
694  end;
695  exclude(FWinControlFlags, wcfAligningControls);
696end;
697
698procedure TCustomCoolBar.CalculatePreferredSize(var PreferredWidth,
699  PreferredHeight: integer; WithThemeSpace: Boolean);
700var i, x, aCountM1: Integer;
701begin
702  aCountM1 := length(FVisiBands)-1;
703  if not Vertical then begin
704    if aCountM1 >= 0 then
705      PreferredHeight := FVisiBands[aCountM1].FTop+FVisiBands[aCountM1].FHeight+FBorderBottom
706    else
707      PreferredHeight := FBorderTop+FBorderBottom;
708    PreferredWidth := 0
709  end else begin
710    PreferredHeight := 0;
711    if aCountM1 >= 0 then begin
712      if not FRightToLeft then
713        PreferredWidth := FVisiBands[aCountM1].FTop+FVisiBands[aCountM1].FHeight+FBorderRight
714      else begin
715        PreferredWidth := FBorderLeft+FVisiBands[0].FTop+FVisiBands[0].FHeight-FVisiBands[aCountM1].FTop+FBorderRight;
716        x := FVisiBands[aCountM1].FTop-FBorderLeft;
717        for i := 0 to aCountM1 do
718          FVisiBands[i].FTop := FVisiBands[i].FTop-x;
719      end;
720    end else
721      PreferredWidth := FBorderLeft+FBorderRight;
722  end;
723end;
724
725function TCustomCoolBar.CalculateRealIndex(AVisibleIndex: Integer): Integer;
726var i, aInvisibles, aVisibles: Integer;
727begin
728  aInvisibles := 0;
729  aVisibles := 0;
730  for i:=0 to FBands.Count-1 do begin
731    if not FBands[i].Visible then
732      inc(aInvisibles)
733    else
734      inc(aVisibles);
735    if aVisibles > AVisibleIndex then break;
736  end;
737  Result := AVisibleIndex+aInvisibles;
738end;
739
740procedure TCustomCoolBar.ChangeCursor(ABand, AGrabber: Boolean);
741begin
742  FLockCursor := True;
743  if ABand then begin
744    if not AGrabber then
745      Cursor := crDefault
746    else
747      if not Vertical then
748        Cursor := crHSplit
749      else
750        Cursor := crVSplit;
751  end else
752    Cursor := FCursorBkgnd;
753  FLockCursor := False;
754end;
755
756procedure TCustomCoolBar.CMBiDiModeChanged(var Message: TLMessage);
757begin
758  inherited CMBiDiModeChanged(Message);
759  FRightToLeft := IsRightToLeft;
760  CalculateAndAlign;
761end;
762
763procedure TCustomCoolBar.CreateWnd;
764begin
765  inherited CreateWnd;
766  FCursorBkgnd := Cursor;
767  DoFontChanged;
768  CalculateAndAlign;
769end;
770
771procedure TCustomCoolBar.DoFontChanged;
772var i: Integer;
773begin
774  if not Canvas.HandleAllocated then
775    Exit;
776  FTextHeight := Canvas.TextHeight('Žy|');
777  for i := 0 to FBands.Count-1 do
778    FBands[i].CalcTextWidth;
779end;
780
781procedure TCustomCoolBar.DrawTiledBitmap(ARect: TRect; ABitmap: TBitmap);
782var i, j, x, y, aWidth, aHeight: Integer;
783begin
784  aWidth := ABitmap.Width;
785  aHeight := ABitmap.Height;
786  x := (ARect.Right-ARect.Left) div aWidth;
787  y := (ARect.Bottom-ARect.Top) div aHeight;
788  if ((ARect.Right-ARect.Left) mod aWidth) =0 then dec(x);
789  if ((ARect.Bottom-ARect.Top) mod aHeight) =0 then dec(y);
790  Canvas.Clipping := True;
791  Canvas.ClipRect := ARect;
792  for i := 0 to x do
793    for j := 0 to y do
794      Canvas.Draw(ARect.Left+i*aWidth, ARect.Top+j*aHeight, ABitmap);
795  Canvas.Clipping := False;
796end;
797
798procedure TCustomCoolBar.EndUpdate;
799begin
800  inherited EndUpdate;
801  //DebugLn('EndUpdate calls CalculateAndAlign');
802  if FUpdateCount = 0 then begin
803    DisableAutoSizing{$IFDEF DebugDisableAutoSizing}('TCustomCoolBar.EndUpdate'){$ENDIF};
804    try
805      CalculateAndAlign;
806    finally
807      EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TCustomCoolBar.EndUpdate'){$ENDIF};
808    end;
809    Invalidate;
810  end;
811end;
812
813procedure TCustomCoolBar.FontChanged(Sender: TObject);
814begin
815  inherited FontChanged(Sender);
816  DoFontChanged;
817  //DebugLn('FontChanged calls CalculateAndAlign');
818  CalculateAndAlign;
819end;
820
821procedure TCustomCoolBar.InsertControl(AControl: TControl; Index: integer);
822var aBand: TCoolBand;
823begin
824  inherited InsertControl(AControl, Index);
825  //DebugLn('TCustomCoolBar.InsertControl '+inttostr(FUpdateCount));
826  if (AControl is TWinControl) and not (csLoading in ComponentState) then begin
827    aBand := Bands.FindBand(AControl);
828    if aBand = Nil then begin
829      //DebugLn('TCoolBar.InsertControl: Adding band for Comp=' + AControl.Name + ', class=' + AControl.ClassName);
830      BeginUpdate;
831      aBand := FBands.Add;
832      aBand.Control := AControl;
833      aBand.Width := aBand.CalcPreferredWidth;
834      EndUpdate;
835    end;
836  end;
837end;
838
839procedure TCustomCoolBar.Invalidate;
840var aBorderWidth: Integer;
841begin
842  aBorderWidth := 0;
843  if EdgeOuter <> esNone then inc(aBorderWidth);
844  if EdgeInner <> esNone then inc(aBorderWidth);
845  if (FBorderWidth <> aBorderWidth) or (FBorderEdges <> EdgeBorders) then begin
846    FBorderWidth := aBorderWidth;
847    FBorderEdges := EdgeBorders;
848    if ebLeft in EdgeBorders then
849      FBorderLeft := aBorderWidth
850    else
851      FBorderLeft := 0;
852    if ebTop in EdgeBorders then
853      FBorderTop := aBorderWidth
854    else
855      FBorderTop := 0;
856    if ebRight in EdgeBorders then
857      FBorderRight := aBorderWidth
858    else
859      FBorderRight := 0;
860    if ebBottom in EdgeBorders then
861      FBorderBottom := aBorderWidth
862    else
863      FBorderBottom := 0;
864    CalculateAndAlign;
865    //DebugLn('Change BorderEdge');
866  end;
867  inherited Invalidate;
868end;
869
870function TCustomCoolBar.IsFirstAtRow(ABand: Integer): Boolean;
871begin
872  if not Vertical then begin
873    if not FRightToLeft then
874      Result := (FVisiBands[ABand].FLeft = FBorderLeft)
875    else
876      Result := (FVisiBands[ABand].Right = Width-FBorderRight);
877  end else
878    Result := (FVisiBands[ABand].FLeft = FBorderTop);
879end;
880
881function TCustomCoolBar.IsRowEnd(ALeft, AVisibleIndex: Integer): Boolean;
882begin
883  Result := (AVisibleIndex < length(FVisiBands)-1) and RowEndHelper(ALeft, AVisibleIndex);
884end;
885
886procedure TCustomCoolBar.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
887var aBand: Integer;
888    aGrabber: Boolean;
889begin
890  inherited MouseDown(Button, Shift, X, Y);
891  if Button = mbRight then
892  begin
893    Cursor := crDefault;
894    Exit;
895  end;
896  MouseToBandPos(X, Y, aBand, aGrabber);
897  FDraggedBandIndex := aBand;
898  if (aBand >= 0) and (length(FVisiBands) >= 1) then begin  //hit any Band
899    if not aGrabber or IsFirstAtRow(aBand)
900      or FFixedSize or FVisiBands[aBand-1].FFixedSize then begin
901      if not FFixedOrder then FDragBand := dbMove;  //move Band
902    end else begin  //resize Band
903      if not FFixedSize and not FVisiBands[aBand-1].FFixedSize then begin
904        FDragBand := dbResize;
905        if not Vertical then begin
906          if not FRightToLeft then
907            FDragInitPos := X-FVisiBands[aBand-1].FWidth-FVisiBands[aBand-1].FLeft
908          else
909            FDragInitPos := FVisiBands[aBand-1].FLeft-X;
910        end else
911          FDragInitPos := Y-FVisiBands[aBand-1].FWidth-FVisiBands[aBand-1].FLeft;
912      end;
913    end;
914  end;
915end;
916
917procedure TCustomCoolBar.MouseMove(Shift: TShiftState; X, Y: Integer);
918var aBand: Integer;
919    aGrabber: Boolean;
920begin
921  inherited MouseMove(Shift, X, Y);
922  if length(FVisiBands) > 0 then begin
923    case FDragBand of
924      dbNone: begin
925        MouseToBandPos(X, Y, aBand, aGrabber);
926        if aBand >= 0 then begin
927          if aGrabber and (aBand > 0) and not FVisiBands[aBand-1].FixedSize
928             and not FFixedSize and not IsFirstAtRow(aBand) then
929            ChangeCursor(True, True)
930          else
931            if length(FVisiBands) > 1 then ChangeCursor(not FixedOrder, False);
932        end else
933          ChangeCursor(False, False);
934      end;
935      dbResize: begin
936        if not Vertical then begin
937          if not FRightToLeft then
938            FVisiBands[FDraggedBandIndex-1].Width :=
939              X-FDragInitPos-FVisiBands[FDraggedBandIndex-1].FLeft
940          else
941            FVisiBands[FDraggedBandIndex-1].Width :=
942              -X-FDragInitPos+FVisiBands[FDraggedBandIndex-1].Right;
943        end else
944          FVisiBands[FDraggedBandIndex-1].Width :=
945            Y-FDragInitPos-FVisiBands[FDraggedBandIndex-1].FLeft
946      end;
947      dbMove: begin
948        if FDraggedBandIndex>-1 then begin
949          Cursor := crDrag;
950          if DragManager.CanStartDragging(self,-1,X,Y) then
951          begin
952            DragManager.DragStart(FVisiBands[FDraggedBandIndex].Control, True, -1, True);
953            Cursor := crDefault;
954            FDraggedBandIndex := -1;
955          end;
956        end;
957      end;
958    end;
959  end;
960end;
961
962procedure TCustomCoolBar.MouseToBandPos(X, Y: Integer; out ABand: Integer; out AGrabber: Boolean);
963var i, aCountM1, aLeft, aTop: Integer;
964begin
965  ABand := low(Integer);
966  AGrabber := False;
967  aCountM1 := length(FVisiBands)-1;
968  if Vertical then begin
969    i := Y;
970    Y := X;
971    X := i;
972  end;
973  if aCountM1 >= 0 then begin
974    if not Vertical or not FRightToLeft then begin
975      if Y > (FVisiBands[aCountM1].Top+FVisiBands[aCountM1].Height+TCoolBand.cDivider) then
976        ABand := cNewRowBelow  //new row, i.e. free space below the last row
977      else
978        if Y < 0 then ABand := cNewRowAbove;  //new row, i.e. free space above the first row
979    end else begin
980      if Y < (FVisiBands[aCountM1].Top) then
981        ABand := cNewRowBelow  //new row, i.e. free space below the last row
982      else
983        if Y > Width then ABand := cNewRowAbove;  //new row, i.e. free space space above the first row
984    end;
985    if ABand = low(Integer) then
986      for i := 0 to aCountM1 do begin
987        aLeft := FVisiBands[i].FRealLeft;
988        aTop := FVisiBands[i].FTop;
989        if PtInRect(Rect(aLeft, aTop, aLeft+FVisiBands[i].FRealWidth,
990            aTop+FVisiBands[i].FHeight), Point(X, Y)) then begin
991          ABand := i;
992          //DebugLn('Mouse over Band ', i);
993          if not FRightToLeft or Vertical then
994            AGrabber := (X <= (aLeft+GrabWidth+1))
995          else
996            AGrabber := (X >= (FVisiBands[i].FLeft+FVisiBands[i].Width-GrabWidth-1));
997          //DebugLn('Grabber '+BoolToStr(AGrabber), ' hit', ' not hit');
998          Exit;  //Exit!
999        end;
1000      end;
1001  end;
1002end;
1003
1004procedure TCustomCoolBar.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
1005var aBand, w, h, offs: Integer;
1006    newRowBelow, needRecalc, needBandMaximize, aGrabber: Boolean;
1007begin
1008  inherited MouseUp(Button, Shift, X, Y);
1009  if FBandMaximize<>bmNone then begin
1010    case FBandMaximize of
1011      bmClick:   needBandMaximize:=true;
1012      bmDblClick:needBandMaximize:=ssDouble in Shift;
1013      else       needBandMaximize:=false;
1014    end;
1015    if needBandMaximize then begin
1016      MouseToBandPos(X, Y, aBand, aGrabber);
1017      if aGrabber and Assigned(FVisiBands[aBand].control) then begin
1018        w:=0;
1019        h:=0;
1020        FVisiBands[aBand].control.GetPreferredSize(w,h);
1021        offs:=FVisiBands[aBand].CalcControlLeft
1022             +FVisiBands[aBand].cDivider + HorizontalSpacing;
1023        if vertical then
1024          FVisiBands[aBand].width:=offs+h
1025        else
1026          FVisiBands[aBand].width:=offs+w;
1027        FDraggedBandIndex:=-1;
1028      end;
1029    end;
1030  end;
1031  if (FDragBand = dbMove) and (FDraggedBandIndex <> -1) then begin
1032    needRecalc := False;
1033    MouseToBandPos(X, Y, aBand, newRowBelow);  //newRowBelow is NOT used here
1034    if aBand >= cNewRowAbove then begin
1035      if aBand = cNewRowAbove then begin
1036        if FDraggedBandIndex = 0 then begin
1037          if FVisiBands[0].FTop = FVisiBands[1].FTop then begin
1038            FVisiBands[1].FBreak := True;
1039            needRecalc := True;
1040          end;
1041        end else begin
1042          FVisiBands[1].FBreak := True;
1043          FVisiBands[FDraggedBandIndex].Index := 0;
1044        end;
1045      end else begin
1046        newRowBelow := (aBand = cNewRowBelow);
1047        if newRowBelow then aBand := length(FVisiBands)-1;
1048        if Vertical then X := Y;
1049        if aBand <> FDraggedBandIndex then begin  //move to new position
1050          if FVisiBands[FDraggedBandIndex].FBreak and (FDraggedBandIndex < (length(FVisiBands)-1))
1051            then FVisiBands[FDraggedBandIndex+1].FBreak := True;
1052          if not newRowBelow and (((not FRightToLeft or Vertical)
1053            and (X > (FVisiBands[aBand].FLeft+FVisiBands[aBand].Width)))
1054            or ((FRightToLeft and not Vertical)
1055            and (X < FVisiBands[aBand].FLeft))) then begin  //beyond the last band in row
1056            FVisiBands[FDraggedBandIndex].FBreak := False;
1057            if FDraggedBandIndex > aBand then
1058              FVisiBands[FDraggedBandIndex].Index := CalculateRealIndex(aBand+1)
1059            else
1060              FVisiBands[FDraggedBandIndex].Index := CalculateRealIndex(aBand);
1061            needRecalc := (FDraggedBandIndex = (aBand+1));
1062          end else begin  //on another Band
1063            FVisiBands[FDraggedBandIndex].FBreak := FVisiBands[aBand].Break;
1064            if FDraggedBandIndex > aBand then begin  //move up or left
1065              FVisiBands[aBand].FBreak := False;
1066              FVisiBands[FDraggedBandIndex].Index := CalculateRealIndex(aBand);
1067            end else begin  //move down or right
1068              if not newRowBelow then begin
1069                if (FVisiBands[FDraggedBandIndex].FTop = FVisiBands[aBand].FTop) then begin  //the same row
1070                  FVisiBands[FDraggedBandIndex].FBreak := False;
1071                  FVisiBands[FDraggedBandIndex].Index := CalculateRealIndex(aBand);
1072                end else begin  //other row
1073                  FVisiBands[aBand].FBreak := False;
1074                  FVisiBands[FDraggedBandIndex].Index := CalculateRealIndex(aBand-1);
1075                  needRecalc := (FDraggedBandIndex = (aBand-1));
1076                end;
1077              end else begin  //new row
1078                FVisiBands[FDraggedBandIndex].FBreak := True;
1079                FVisiBands[FDraggedBandIndex].Index := CalculateRealIndex(aBand);
1080              end;
1081            end;
1082          end;
1083        end else
1084          if newRowBelow then begin  //last Band in last row moved to new row
1085            FVisiBands[aBand].FBreak := True;
1086            needRecalc:= True;
1087          end;
1088      end;
1089      if needRecalc then begin  //necessary only when no Index is changed
1090        CalculateAndAlign;
1091        Invalidate;
1092      end;
1093    end;
1094    Cursor := crDefault;
1095    if Assigned(FOnChange) then
1096      FOnChange(Self);
1097  end;
1098  FDragBand := dbNone;
1099end;
1100
1101procedure TCustomCoolBar.Notification(AComponent: TComponent; Operation: TOperation);
1102begin
1103  inherited Notification(AComponent, Operation);
1104  if csDestroying in ComponentState then Exit;
1105  if Operation = opRemove then begin
1106    //DebugLn('TCoolBar.Notification: Operation = opRemove');
1107    if AComponent = FImages then Images := Nil;
1108  end;
1109end;
1110
1111procedure TCustomCoolBar.Paint;
1112var i: Integer;
1113    aGrabDetails,aBackground: TThemedElementDetails;
1114    aGrabStyle: TGrabStyle;
1115    aRaisedBevel: Boolean;
1116    aRect: TRect;
1117const arBevel: array[False..True] of TColor = (clBtnShadow, clBtnHighlight);
1118
1119  function GetCaptionColorDisabled: TColor;
1120  var r1, g1, b1: Byte;
1121      aColor: TColor;
1122  begin
1123    aColor := Font.Color;
1124    if aColor = clDefault then aColor := clBtnText;
1125    GetRGBValues(ColorToRGB(aColor), r1, g1, b1);
1126    i := r1 div 3 + g1 div 3 + b1 div 3;
1127    GetRGBValues(ColorToRGB(Brush.Color), r1, g1, b1);
1128    i := (i+(r1 div 3 + g1 div 3 + b1 div 3)) div 2;
1129    Result := RGBToColor(i, i, i);
1130  end;
1131
1132  procedure PaintGrabber(aRect: TRect);
1133  var l, w: SmallInt;
1134  begin
1135    case aGrabStyle of
1136      gsSimple: begin
1137        Canvas.Pen.Color := clBtnHighlight;
1138        Canvas.Line(aRect.Left, aRect.Top, aRect.Right, aRect.Top);
1139        Canvas.Line(aRect.Left, aRect.Top, aRect.Left, aRect.Bottom+1);
1140        Canvas.Pen.Color := clBtnShadow;
1141        Canvas.Line(aRect.Left, aRect.Bottom, aRect.Right, aRect.Bottom);
1142        Canvas.Line(aRect.Right, aRect.Top, aRect.Right, aRect.Bottom+1);
1143      end;
1144      gsDouble: begin
1145        w := (FGrabWidth-2) div 2;
1146        Canvas.Pen.Color := clBtnHighlight;
1147        if not Vertical then begin
1148          Canvas.Line(aRect.Left, aRect.Top, aRect.Left+w, aRect.Top);
1149          Canvas.Line(aRect.Left, aRect.Top, aRect.Left, aRect.Bottom+1);
1150          Canvas.Line(aRect.Right-w, aRect.Top, aRect.Right, aRect.Top);
1151          Canvas.Line(aRect.Right-w, aRect.Top, aRect.Right-w, aRect.Bottom+1);
1152        end else begin
1153          Canvas.Line(aRect.Left, aRect.Top, aRect.Left, aRect.Top+w);
1154          Canvas.Line(aRect.Left, aRect.Top, aRect.Right+1, aRect.Top);
1155          Canvas.Line(aRect.Left, aRect.Bottom-w, aRect.Right, aRect.Bottom-w);
1156          Canvas.Line(aRect.Left, aRect.Bottom-w, aRect.Left, aRect.Bottom+1);
1157        end;
1158        Canvas.Pen.Color := clBtnShadow;
1159        if not Vertical then begin
1160          Canvas.Line(aRect.Left, aRect.Bottom, aRect.Left+w, aRect.Bottom);
1161          Canvas.Line(aRect.Left+w, aRect.Top, aRect.Left+w, aRect.Bottom+1);
1162          Canvas.Line(aRect.Right-w, aRect.Bottom, aRect.Right, aRect.Bottom);
1163          Canvas.Line(aRect.Right, aRect.Top, aRect.Right, aRect.Bottom+1);
1164        end else begin
1165          Canvas.Line(aRect.Left, aRect.Top+w, aRect.Right, aRect.Top+w);
1166          Canvas.Line(aRect.Right, aRect.Top, aRect.Right, aRect.Top+w+1);
1167          Canvas.Line(aRect.Left, aRect.Bottom, aRect.Right, aRect.Bottom);
1168          Canvas.Line(aRect.Right, aRect.Bottom-w, aRect.Right, aRect.Bottom+1);
1169        end;
1170      end;
1171      gsHorLines: begin
1172        l := (aRect.Bottom-aRect.Top+1) div 3;
1173        inc(aRect.Top);
1174        Canvas.Pen.Color := clBtnShadow;
1175        for w := 0 to l-1 do
1176          Canvas.Line(aRect.Left, aRect.Top+w*3, aRect.Right, aRect.Top+w*3);
1177        Canvas.Pen.Color := clBtnHighlight;
1178        inc(aRect.Top);
1179        for w := 0 to l-1 do
1180          Canvas.Line(aRect.Left, aRect.Top+w*3, aRect.Right, aRect.Top+w*3);
1181      end;
1182      gsVerLines: begin
1183        l := (aRect.Right-aRect.Left+1) div 3;
1184        inc(aRect.Left);
1185        Canvas.Pen.Color := clBtnShadow;
1186        for w := 0 to l-1 do
1187          Canvas.Line(aRect.Left+w*3, aRect.Top, aRect.Left+w*3, aRect.Bottom+1);
1188        Canvas.Pen.Color := clBtnHighlight;
1189        inc(aRect.Left);
1190        for w := 0 to l-1 do
1191          Canvas.Line(aRect.Left+w*3, aRect.Top, aRect.Left+w*3, aRect.Bottom+1);
1192      end;
1193      gsGripper: begin
1194        dec(aRect.Top);
1195        inc(aRect.Bottom);
1196        Canvas.ClipRect := aRect;
1197        Canvas.Clipping := True;
1198        ThemeServices.DrawElement(Canvas.Handle, aGrabDetails, aRect);
1199        Canvas.Clipping := False;
1200      end;
1201      gsButton: begin
1202        dec(aRect.Top);
1203        inc(aRect.Bottom);
1204        ThemeServices.DrawElement(Canvas.Handle, aGrabDetails, aRect);
1205      end;
1206    end;
1207  end;
1208
1209  procedure PaintSeparator(Y: Integer);
1210  begin
1211    //DebugLn('PaintSeparator');
1212    if not Vertical then begin
1213      Canvas.Pen.Color := arBevel[aRaisedBevel];
1214      Canvas.Line(FBorderLeft, Y, Width-FBorderRight, Y);
1215      inc(Y);
1216      Canvas.Pen.Color := arBevel[not aRaisedBevel];
1217      Canvas.Line(FBorderLeft, Y, Width-FBorderRight, Y);
1218    end else begin
1219      Canvas.Pen.Color := arBevel[aRaisedBevel];
1220      Canvas.Line(Y, FBorderTop, Y, Height-FBorderBottom);
1221      inc(Y);
1222      Canvas.Pen.Color := arBevel[not aRaisedBevel];
1223      Canvas.Line(Y, FBorderTop, Y, Height-FBorderBottom);
1224    end;
1225  end;
1226
1227var k, x, aCountM1, aLeft, aTop: Integer;
1228    aRowEnd: Boolean;
1229    aColor: TColor;
1230    aDetails: TThemedElementDetails;
1231    aFlags: Cardinal;
1232    aImageSize: TSize;
1233begin
1234  inherited Paint;
1235  if Assigned(FImages) then
1236    aImageSize := FImages.SizeForPPI[ImagesWidth, Font.PixelsPerInch];
1237  //DebugLn('TCoolBar.Paint');
1238  //draw Bitmap Background
1239  if FBitmap.Width > 0 then
1240    DrawTiledBitmap(ClientRect, FBitmap)
1241  else begin
1242    if FThemed then begin
1243      aBackground:=ThemeServices.GetElementDetails(trRebarRoot);
1244      ThemeServices.DrawElement(Canvas.Handle,aBackground,ClientRect);
1245    end;
1246  end;
1247  aCountM1 := length(FVisiBands)-1;
1248  if aCountM1 >= 0 then begin
1249    aRaisedBevel := (FBandBorderStyle = bsSingle) and
1250                    (EdgeInner = esLowered) and (EdgeOuter = esRaised);
1251    aRowEnd := False;
1252    aGrabStyle := GrabStyle;
1253    if Vertical then
1254      case aGrabStyle of
1255        gsHorLines: aGrabStyle := gsVerLines;
1256        gsVerLines: aGrabStyle := gsHorLines;
1257      end;
1258    case aGrabStyle of
1259      gsGripper: if not Vertical then
1260                   aGrabDetails := ThemeServices.GetElementDetails(trGripper)
1261                 else
1262                   aGrabDetails := ThemeServices.GetElementDetails(trGripperVert);
1263      gsButton: aGrabDetails := ThemeServices.GetElementDetails(tbPushButtonNormal);
1264    end;
1265    if FShowText or Assigned(FImages) then begin
1266      if IsEnabled then
1267        aDetails := ThemeServices.GetElementDetails(tbPushButtonNormal)
1268      else
1269        aDetails := ThemeServices.GetElementDetails(tbPushButtonDisabled);
1270      aFlags := DT_SINGLELINE or DT_VCENTER or DT_NOPREFIX;
1271      if FRightToLeft then aFlags := aFlags or DT_RTLREADING;
1272    end;
1273    if FShowText then begin
1274      if IsEnabled then
1275        Canvas.Font.Color := Font.Color
1276      else
1277        Canvas.Font.Color := GetCaptionColorDisabled;
1278    end;
1279    for i := 0 to aCountM1 do begin
1280      aLeft := FVisiBands[i].FLeft;
1281      aTop := FVisiBands[i].FTop;
1282      aRect := Rect(aLeft, aTop, aLeft+FVisiBands[i].FRealWidth+1, aTop+FVisiBands[i].FHeight);
1283      //paint Band Background
1284      if FVisiBands[i].Bitmap.Width > 0 then
1285        DrawTiledBitmap(aRect, FVisiBands[i].Bitmap)
1286      else begin
1287        if not FVisiBands[i].FixedBackground and FVisiBands[i].ParentBitmap
1288          and (Bitmap.Width > 0) then
1289          DrawTiledBitmap(aRect, Bitmap)
1290        else begin
1291          aColor := FVisiBands[i].FColor;
1292          if (aColor <> clDefault) and (aColor <> clNone) then begin
1293            Canvas.Brush.Color := aColor;
1294            Canvas.FillRect(aRect);
1295          end;
1296        end;
1297      end;
1298      //paint a Grabber
1299      if not FRightToLeft or Vertical then
1300        x := aLeft+TCoolBand.cGrabIndent
1301      else
1302        x := aLeft+FVisiBands[i].Width-GrabWidth-TCoolBand.cGrabIndent;
1303      if not Vertical then
1304        PaintGrabber(Rect(x, aTop+2, x+GrabWidth-1, aTop+FVisiBands[i].FHeight-3))
1305      else
1306        PaintGrabber(Rect(aTop+2, x, aTop+FVisiBands[i].FHeight-3, x+GrabWidth-1));
1307      if not FRightToLeft or Vertical then
1308        x := x+GrabWidth+HorizontalSpacing
1309      else
1310        x := x-HorizontalSpacing;
1311      //paint Image
1312      if Assigned(FImages) and (FVisiBands[i].ImageIndex >= 0) then begin
1313        if FRightToLeft and not Vertical then dec(x, aImageSize.cx);
1314        if not Vertical then
1315          ThemeServices.DrawIcon(Canvas, aDetails,
1316            Point(x, aTop+(FVisiBands[i].FHeight-aImageSize.cy) div 2),
1317            FImages, FVisiBands[i].ImageIndex)
1318        else
1319          ThemeServices.DrawIcon(Canvas, aDetails,
1320            Point(aTop+(FVisiBands[i].FHeight-aImageSize.cx) div 2, x),
1321            FImages, FVisiBands[i].ImageIndex);
1322        if not FRightToLeft or Vertical then
1323          inc(x, aImageSize.cx+HorizontalSpacing)
1324        else
1325          dec(x, HorizontalSpacing);
1326      end;
1327      //paint Text
1328      if FShowText then begin
1329        k := aTop + (FVisiBands[i].FHeight - FTextHeight) div 2;
1330        if not Vertical then begin
1331          if FRightToLeft then dec(x, FVisiBands[i].FTextWidth);
1332          Canvas.Font.Orientation := 0;
1333          aRect := Rect(x, k, x+FVisiBands[i].FTextWidth, k+FTextHeight);
1334        end else begin
1335          Canvas.Font.Orientation := 900;
1336          aRect := Rect(k, x+FVisiBands[i].FTextWidth, k+FVisiBands[i].FTextWidth, x+2*FVisiBands[i].FTextWidth);
1337        end;
1338        Canvas.Brush.Style := bsClear;
1339        Canvas.TextOut(aRect.Left, aRect.Top, FVisiBands[i].Text);
1340      end;
1341      if not FRightToLeft or Vertical then
1342        aRowEnd := IsRowEnd(aLeft, i)
1343      else
1344        aRowEnd := IsRowEnd(Width-x, i);
1345      if BandBorderStyle = bsSingle then begin
1346        //paint a Separator border below the row of bands ____
1347        x := aLeft;
1348        inc(aLeft, FVisiBands[i].Width);
1349        if (aRowEnd or ((i = aCountM1) and not AutoSize)) then begin
1350          if not Vertical or not FRightToLeft then
1351           PaintSeparator(aTop+FVisiBands[i].FHeight)
1352         else
1353           PaintSeparator(aTop-TCoolBand.cDivider);
1354        end;
1355        if not aRowEnd and (i < aCountM1) then begin
1356          //paint Divider |
1357          if not FRightToLeft or Vertical then x := aLeft-TCoolBand.cDivider;
1358          Canvas.Pen.Color := arBevel[not aRaisedBevel];
1359          if not Vertical then
1360            Canvas.Line(x+1, aTop+1, x+1, aTop+FVisiBands[i].FHeight-1)
1361          else
1362            Canvas.Line(aTop+1, x+1, aTop+FVisiBands[i].FHeight-1, x+1);
1363          Canvas.Pen.Color := arBevel[aRaisedBevel];
1364          if not Vertical then
1365            Canvas.Line(x, aTop+1, x, aTop+FVisiBands[i].FHeight-1)
1366          else
1367            Canvas.Line(aTop+1, x, aTop+FVisiBands[i].FHeight-1, x);
1368        end;
1369      end;
1370    end;
1371  end;
1372end;
1373
1374procedure TCustomCoolBar.RemoveControl(AControl: TControl);
1375var aBandIndex:Integer;
1376begin
1377  inherited RemoveControl(AControl);
1378  aBandIndex := Bands.FindBandIndex(AControl);
1379  if aBandIndex > -1 then
1380  begin
1381    //DebugLn('TCoolBar.RemoveControl: Comp=' + AControl.Name + ', class=' + AControl.ClassName);
1382    Bands.Items[aBandIndex].Control := Nil;
1383    FDragBand:=dbNone;
1384    FDraggedBandIndex:=-1;
1385    Bands.Delete(aBandIndex);
1386    CalculateAndAlign;
1387    Invalidate;
1388  end;
1389end;
1390
1391function TCustomCoolBar.RowEndHelper(ALeft, AVisibleIdx: Integer): Boolean;
1392var aLimit: Integer;
1393begin
1394  if not Vertical then
1395    aLimit := Width
1396  else
1397    aLimit := Height;
1398  Result := FVisiBands[AVisibleIdx+1].Break or
1399    (ALeft+FVisiBands[AVisibleIdx+1].Width-TCoolBand.cDivider >= aLimit);
1400end;
1401
1402procedure TCustomCoolBar.WMSize(var Message: TLMSize);
1403begin
1404  //DebugLn('WMSize');
1405  inherited WMSize(Message);
1406  CalculateAndAlign;
1407  Invalidate;  //required by GTK2 and WINDOWS
1408end;
1409
1410