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

View File

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