lcl: fix vertical toolbar button positioning + drawing of vertical separators

git-svn-id: trunk@30921 -
This commit is contained in:
paul 2011-05-27 06:39:29 +00:00
parent a75a29091c
commit de0cfa211a
3 changed files with 201 additions and 76 deletions

View File

@ -1680,7 +1680,8 @@ type
TToolBar = class(TToolWindow) TToolBar = class(TToolWindow)
private private
FButtonHeight: Integer; FButtonHeight: Integer;
FRealizedButtonHeight: integer; FRealizedButtonHeight,
FRealizedButtonWidth: integer;
FButtons: TList; FButtons: TList;
FButtonWidth: Integer; FButtonWidth: Integer;
FDisabledImageChangeLink: TChangeLink; FDisabledImageChangeLink: TChangeLink;
@ -1746,7 +1747,7 @@ type
procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure Notification(AComponent: TComponent; Operation: TOperation); override;
procedure RepositionButton(Index: Integer); procedure RepositionButton(Index: Integer);
procedure RepositionButtons(Index: Integer); procedure RepositionButtons(Index: Integer);
function WrapButtons(UseWidth: integer; function WrapButtons(UseSize: integer;
out NewWidth, NewHeight: Integer; out NewWidth, NewHeight: Integer;
Simulate: boolean): Boolean; Simulate: boolean): Boolean;
procedure CNDropDownClosed(var Message: TLMessage); message CN_DROPDOWNCLOSED; procedure CNDropDownClosed(var Message: TLMessage); message CN_DROPDOWNCLOSED;

View File

@ -19,7 +19,7 @@
} }
function CompareToolBarControl(Control1, Control2: TControl): integer; function CompareToolBarControlHorz(Control1, Control2: TControl): integer;
var var
ToolBar: TToolBar; ToolBar: TToolBar;
Row1: Integer; Row1: Integer;
@ -47,6 +47,34 @@ begin
end; end;
end; end;
function CompareToolBarControlVert(Control1, Control2: TControl): integer;
var
ToolBar: TToolBar;
Col1: Integer;
Col2: Integer;
HalfBtnWidth, BtnWidth: Integer;
begin
Result := 0;
if not (Control1.Parent is TToolBar) then Exit;
ToolBar := TToolBar(Control1.Parent);
BtnWidth := ToolBar.FRealizedButtonWidth;
if BtnWidth <= 0 then BtnWidth := 1;
HalfBtnWidth := BtnWidth div 2;
Col1 := (Control1.Left + HalfBtnWidth) div BtnWidth;
Col2 := (Control2.Left + HalfBtnWidth) div BtnWidth;
Result := CompareValue(Col1, Col2);
if Result = 0 then
Result := CompareValue(Control1.Top, Control2.Top);
if Result = 0 then
begin
Col1 := ToolBar.GetControlIndex(Control1);
Col2 := ToolBar.GetControlIndex(Control2);
Result := CompareValue(Col1, Col2);
end;
end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------
Method: TToolbar.Create Method: TToolbar.Create
Params: AOwner: the owner of the class Params: AOwner: the owner of the class
@ -127,7 +155,10 @@ begin
if tbfPlacingControls in FToolBarFlags then exit; if tbfPlacingControls in FToolBarFlags then exit;
Include(FToolBarFlags, tbfPlacingControls); Include(FToolBarFlags, tbfPlacingControls);
try try
WrapButtons(Width, NewWidth, NewHeight, False); if IsVertical then
WrapButtons(Height, NewWidth, NewHeight, False)
else
WrapButtons(Width, NewWidth, NewHeight, False);
finally finally
Exclude(FToolBarFlags, tbfPlacingControls); Exclude(FToolBarFlags, tbfPlacingControls);
end; end;
@ -211,8 +242,10 @@ end;
function TToolBar.IsVertical: Boolean; function TToolBar.IsVertical: Boolean;
begin begin
// any other logic? if Align = alNone then
Result := Height > Width; Result := Height > Width
else
Result := Align in [alLeft, alRight];
end; end;
class procedure TToolBar.WSRegisterClass; class procedure TToolBar.WSRegisterClass;
@ -506,19 +539,17 @@ end;
If Wrapable=false, then the row is wrapped after the first button with If Wrapable=false, then the row is wrapped after the first button with
Wrap=true. Wrap=true.
------------------------------------------------------------------------------} ------------------------------------------------------------------------------}
function TToolBar.WrapButtons(UseWidth: integer; function TToolBar.WrapButtons(UseSize: integer;
out NewWidth, NewHeight: Integer; Simulate: boolean): Boolean; out NewWidth, NewHeight: Integer; Simulate: boolean): Boolean;
var var
ARect: TRect; ARect: TRect;
x: Integer; x, y, w, h: Integer;
y: Integer; NewControlWidth, NewControlHeight: Integer;
NewControlWidth: Integer;
CurControl: TControl; CurControl: TControl;
ObstacleControls: TFPList; ObstacleControls: TFPList;
FullSizeObstacleControls: TFPList; FullSizeObstacleControls: TFPList;
StartX: Integer; StartX, StartY: Integer;
w: LongInt; Vertical: Boolean;
h: LongInt;
procedure CalculatePosition; procedure CalculatePosition;
var var
@ -526,8 +557,7 @@ var
NewBounds: TRect; NewBounds: TRect;
SiblingBounds: TRect; SiblingBounds: TRect;
j: Integer; j: Integer;
PreferredBtnWidth: Integer; PreferredBtnWidth, PreferredBtnHeight: Integer;
PreferredBtnHeight: Integer;
Intersects: Boolean; Intersects: Boolean;
IntersectsWithLimitedHeightControl: Boolean; IntersectsWithLimitedHeightControl: Boolean;
StartedAtRowStart: Boolean; StartedAtRowStart: Boolean;
@ -538,24 +568,50 @@ var
PreferredBtnWidth := 0; PreferredBtnWidth := 0;
PreferredBtnHeight := 0; PreferredBtnHeight := 0;
CurControl.GetPreferredSize(PreferredBtnWidth, PreferredBtnHeight); CurControl.GetPreferredSize(PreferredBtnWidth, PreferredBtnHeight);
NewControlWidth := PreferredBtnWidth; if Vertical then
begin
NewControlHeight := PreferredBtnHeight;
NewControlWidth := ButtonWidth;
end
else
begin
NewControlHeight := ButtonHeight;
NewControlWidth := PreferredBtnWidth;
end;
if (TToolButton(CurControl).Style in [tbsButton, tbsDropDown, tbsCheck]) then if (TToolButton(CurControl).Style in [tbsButton, tbsDropDown, tbsCheck]) then
begin begin
if Vertical then
if (NewControlHeight < ButtonHeight) then
NewControlHeight := ButtonHeight
else
else
if (NewControlWidth < ButtonWidth) then if (NewControlWidth < ButtonWidth) then
NewControlWidth := ButtonWidth; NewControlWidth := ButtonWidth;
end; end;
end end
else else
if Vertical then
begin
NewControlWidth := ButtonWidth;
NewControlHeight := CurControl.Height;
end
else
begin
NewControlWidth := CurControl.Width; NewControlWidth := CurControl.Width;
NewBounds := Bounds(x, y, NewControlWidth, ButtonHeight); NewControlHeight := ButtonHeight;
end;
NewBounds := Bounds(x, y, NewControlWidth, NewControlHeight);
//DebugLn(['CalculatePosition ',DbgSName(CurControl)]); //DebugLn(['CalculatePosition ',DbgSName(CurControl)]);
StartedAtRowStart:=x=StartX; if Vertical then
StartedAtRowStart := y = StartY
else
StartedAtRowStart := x = StartX;
repeat repeat
// move control to the right, until it does not overlap // move control to the right, until it does not overlap
IntersectsWithLimitedHeightControl:=false; IntersectsWithLimitedHeightControl := False;
j:=0; j := 0;
while j<ObstacleControls.Count do while j < ObstacleControls.Count do
begin begin
AlignedControl := TControl(ObstacleControls[j]); AlignedControl := TControl(ObstacleControls[j]);
SiblingBounds := AlignedControl.BoundsRect; SiblingBounds := AlignedControl.BoundsRect;
@ -563,34 +619,66 @@ var
(SiblingBounds.Left < NewBounds.Right) and (SiblingBounds.Left < NewBounds.Right) and
(SiblingBounds.Bottom > NewBounds.Top) and (SiblingBounds.Bottom > NewBounds.Top) and
(SiblingBounds.Top < NewBounds.Bottom); (SiblingBounds.Top < NewBounds.Bottom);
if Intersects then begin if Intersects then
begin
//DebugLn(['CalculatePosition Move ',NewBounds.Left,'->',SiblingBounds.Right]); //DebugLn(['CalculatePosition Move ',NewBounds.Left,'->',SiblingBounds.Right]);
NewBounds.Left := SiblingBounds.Right; if Vertical then
NewBounds.Right := NewBounds.Left + NewControlWidth; begin
j:=0; // check again, needed, because ObstacleControls are not sorted NewBounds.Top := SiblingBounds.Bottom;
NewBounds.Bottom := NewBounds.Top + NewControlHeight;
end
else
begin
NewBounds.Left := SiblingBounds.Right;
NewBounds.Right := NewBounds.Left + NewControlWidth;
end;
j := 0; // check again, needed, because ObstacleControls are not sorted
// (and can not be sorted, because they can overlap) // (and can not be sorted, because they can overlap)
if FullSizeObstacleControls.IndexOf(AlignedControl)<0 then if FullSizeObstacleControls.IndexOf(AlignedControl) < 0 then
IntersectsWithLimitedHeightControl:=true; IntersectsWithLimitedHeightControl := True;
end else end
else
inc(j); inc(j);
end; end;
if (not Wrapable) if Vertical then
or (NewBounds.Right <= ARect.Right) or (NewBounds.Left = StartX)
or (StartedAtRowStart and not IntersectsWithLimitedHeightControl) then
begin begin
// control fits into the row if (not Wrapable) or
//DebugLn(['CalculatePosition fits: ',DbgSName(CurControl),' ',dbgs(NewBounds)]); (NewBounds.Bottom <= ARect.Bottom) or (NewBounds.Top = StartY) or
x := NewBounds.Left; (StartedAtRowStart and not IntersectsWithLimitedHeightControl) then
y := NewBounds.Top; begin
break; // control fits into the row
end; //DebugLn(['CalculatePosition fits: ',DbgSName(CurControl),' ',dbgs(NewBounds)]);
x := NewBounds.Left;
y := NewBounds.Top;
break;
end;
// try next row // try next row
NewBounds.Left := StartX; NewBounds.Top := StartY;
NewBounds.Right := NewBounds.Left + NewControlWidth; NewBounds.Bottom := NewBounds.Top + NewControlHeight;
inc(NewBounds.Top, ButtonHeight); inc(NewBounds.Left, ButtonWidth);
inc(NewBounds.Bottom, ButtonHeight); inc(NewBounds.Right, ButtonWidth);
StartedAtRowStart:=true; end
else
begin
if (not Wrapable) or
(NewBounds.Right <= ARect.Right) or (NewBounds.Left = StartX) or
(StartedAtRowStart and not IntersectsWithLimitedHeightControl) then
begin
// control fits into the row
//DebugLn(['CalculatePosition fits: ',DbgSName(CurControl),' ',dbgs(NewBounds)]);
x := NewBounds.Left;
y := NewBounds.Top;
break;
end;
// try next row
NewBounds.Left := StartX;
NewBounds.Right := NewBounds.Left + NewControlWidth;
inc(NewBounds.Top, ButtonHeight);
inc(NewBounds.Bottom, ButtonHeight);
end;
StartedAtRowStart := True;
//DebugLn('CalculatePosition Next Row ',DbgSName(CurControl),' ',dbgs(NewBounds)); //DebugLn('CalculatePosition Next Row ',DbgSName(CurControl),' ',dbgs(NewBounds));
until false; until false;
end; end;
@ -618,6 +706,7 @@ var
begin begin
//DebugLn(['WrapButtons ',DbgSName(Self),' Wrapable=',Wrapable,' ',dbgs(BoundsRect)]); //DebugLn(['WrapButtons ',DbgSName(Self),' Wrapable=',Wrapable,' ',dbgs(BoundsRect)]);
Result := True; Result := True;
Vertical := IsVertical;
NewWidth := 0; NewWidth := 0;
NewHeight := 0; NewHeight := 0;
ObstacleControls := TFPList.Create; ObstacleControls := TFPList.Create;
@ -628,7 +717,10 @@ begin
DisableAlign; DisableAlign;
BeginUpdate; BeginUpdate;
try try
GrowSide:=akBottom; if Vertical then
GrowSide := akRight
else
GrowSide := akBottom;
for i:=0 to ControlCount-1 do for i:=0 to ControlCount-1 do
begin begin
CurControl := Controls[i]; CurControl := Controls[i];
@ -654,11 +746,19 @@ begin
// sort OrderedControls // sort OrderedControls
if FRealizedButtonHeight = 0 then if FRealizedButtonHeight = 0 then
FRealizedButtonHeight := FButtonHeight; FRealizedButtonHeight := FButtonHeight;
OrderedControls.Sort(TListSortCompare(@CompareToolBarControl)); if FRealizedButtonWidth = 0 then
FRealizedButtonWidth := FButtonWidth;
if Vertical then
OrderedControls.Sort(TListSortCompare(@CompareToolBarControlVert))
else
OrderedControls.Sort(TListSortCompare(@CompareToolBarControlHorz));
// position OrderedControls // position OrderedControls
CurClientRect := ClientRect; CurClientRect := ClientRect;
inc(CurClientRect.Right, UseWidth - Width); if Vertical then
inc(CurClientRect.Bottom, UseSize - Height)
else
inc(CurClientRect.Right, UseSize - Width);
ARect := CurClientRect; ARect := CurClientRect;
AdjustClientRect(ARect); AdjustClientRect(ARect);
AdjustClientFrame.Left := ARect.Left - CurClientRect.Left; AdjustClientFrame.Left := ARect.Left - CurClientRect.Left;
@ -669,8 +769,9 @@ begin
// important: top, left button must start in the AdjustClientRect top, left // important: top, left button must start in the AdjustClientRect top, left
// otherwise Toolbar.AutoSize=true will create an endless loop // otherwise Toolbar.AutoSize=true will create an endless loop
StartX := ARect.Left; StartX := ARect.Left;
StartY := ARect.Top;
x := StartX; x := StartX;
y := ARect.Top; y := StartY;
for i := 0 to OrderedControls.Count - 1 do for i := 0 to OrderedControls.Count - 1 do
begin begin
CurControl := TControl(OrderedControls[i]); CurControl := TControl(OrderedControls[i]);
@ -678,20 +779,19 @@ begin
Continue; Continue;
CalculatePosition; CalculatePosition;
//DebugLn(['WrapButtons ',CurControl.Name,':',CurControl.ClassName,' ',x,',',y,',',CurControl.Width,'x',CurControl.Height]); //DebugLn(['WrapButtons ',CurControl.Name,':',CurControl.ClassName,' ',x,',',y,',',CurControl.Width,'x',CurControl.Height]);
if ButtonHeight <= 0 then
h := CurControl.Height
else
h := ButtonHeight;
if CurControl.AutoSize then if CurControl.AutoSize then
begin begin
w := CurControl.Width; w := CurControl.Width;
h := CurControl.Height; h := CurControl.Height;
end end
else else
begin
w := NewControlWidth; w := NewControlWidth;
h := NewControlHeight;
end;
w := CurControl.Constraints.MinMaxWidth(w); w := CurControl.Constraints.MinMaxWidth(w);
h := CurControl.Constraints.MinMaxWidth(h); h := CurControl.Constraints.MinMaxHeight(h);
if (CurControl.Left <> x) or (CurControl.Top <> y) or if (CurControl.Left <> x) or (CurControl.Top <> y) or
(CurControl.Width <> w) or (CurControl.Height <> h) then (CurControl.Width <> w) or (CurControl.Height <> h) then
begin begin
@ -709,15 +809,33 @@ begin
NewHeight := Max(NewHeight, y + h + AdjustClientFrame.Bottom); NewHeight := Max(NewHeight, y + h + AdjustClientFrame.Bottom);
// step to next position // step to next position
inc(x,w); if Vertical then
if (not Wrapable) and (CurControl is TToolButton) and
(TToolButton(CurControl).Wrap) then
begin begin
// user forced wrap -> start new line inc(y, h);
x := StartX; if not Wrapable and
inc(y, ButtonHeight); (CurControl is TToolButton) and
if not Simulate then (TToolButton(CurControl).Wrap) then
inc(FRowCount); begin
// user forced wrap -> start new line
y := StartY;
inc(x, ButtonWidth);
if not Simulate then
inc(FRowCount);
end;
end
else
begin
inc(x, w);
if not Wrapable and
(CurControl is TToolButton) and
(TToolButton(CurControl).Wrap) then
begin
// user forced wrap -> start new line
x := StartX;
inc(y, ButtonHeight);
if not Simulate then
inc(FRowCount);
end;
end; end;
end; end;
FRealizedButtonHeight := FButtonHeight; FRealizedButtonHeight := FButtonHeight;

View File

@ -174,18 +174,18 @@ procedure TToolButton.Paint;
// on windows 7 divider can't be less than 4 pixels // on windows 7 divider can't be less than 4 pixels
if FToolBar.IsVertical then if FToolBar.IsVertical then
begin begin
if (ARect.Bottom - ARect.Top) > 4 then if (ARect.Bottom - ARect.Top) > 5 then
begin begin
ARect.Top := (ARect.Top + ARect.Bottom) div 2 - 2; ARect.Top := (ARect.Top + ARect.Bottom) div 2 - 3;
ARect.Bottom := ARect.Top + 4; ARect.Bottom := ARect.Top + 5;
end; end;
end end
else else
begin begin
if (ARect.Right - ARect.Left) > 4 then if (ARect.Right - ARect.Left) > 5 then
begin begin
ARect.Left := (ARect.Left + ARect.Right) div 2 - 2; ARect.Left := (ARect.Left + ARect.Right) div 2 - 3;
ARect.Right := ARect.Left + 4; ARect.Right := ARect.Left + 5;
end; end;
end; end;
ThemeServices.DrawElement(Canvas.GetUpdatedHandle([csBrushValid, csPenValid]), ThemeServices.DrawElement(Canvas.GetUpdatedHandle([csBrushValid, csPenValid]),
@ -202,12 +202,12 @@ procedure TToolButton.Paint;
begin begin
if FToolBar.IsVertical then if FToolBar.IsVertical then
begin begin
if (ARect.Bottom - ARect.Top) > 8 then if (ARect.Bottom - ARect.Top) > 10 then
begin begin
ARect.Top := (ARect.Top + ARect.Bottom) div 2 - 4; ARect.Top := (ARect.Top + ARect.Bottom) div 2 - 5;
ARect.Bottom := ARect.Top + 4; ARect.Bottom := ARect.Top + 5;
DrawDivider(Details, ARect); DrawDivider(Details, ARect);
OffsetRect(ARect, 0, 4); OffsetRect(ARect, 0, 5);
DrawDivider(Details, ARect); DrawDivider(Details, ARect);
end end
else else
@ -215,12 +215,12 @@ procedure TToolButton.Paint;
end end
else else
begin begin
if (ARect.Right - ARect.Left) > 8 then if (ARect.Right - ARect.Left) > 10 then
begin begin
ARect.Left := (ARect.Left + ARect.Right) div 2 - 4; ARect.Left := (ARect.Left + ARect.Right) div 2 - 5;
ARect.Right := ARect.Left + 4; ARect.Right := ARect.Left + 5;
DrawDivider(Details, ARect); DrawDivider(Details, ARect);
OffsetRect(ARect, 4, 0); OffsetRect(ARect, 5, 0);
DrawDivider(Details, ARect); DrawDivider(Details, ARect);
end end
else else
@ -1014,10 +1014,16 @@ begin
end end
else else
if Style = tbsDivider then if Style = tbsDivider then
PreferredWidth := 4 if FToolBar.IsVertical then
PreferredHeight := 5
else
PreferredWidth := 5
else else
if Style = tbsSeparator then if Style = tbsSeparator then
PreferredWidth := 8; if FToolBar.IsVertical then
PreferredHeight := 10
else
PreferredWidth := 10;
end; end;
//DebugLn(['TToolButton.CalculatePreferredSize ',DbgSName(Self),' ',PreferredWidth,',',PreferredHeight,' Caption=',Caption]); //DebugLn(['TToolButton.CalculatePreferredSize ',DbgSName(Self),' ',PreferredWidth,',',PreferredHeight,' Caption=',Caption]);
end; end;