fixed anchoring controls

git-svn-id: trunk@2497 -
This commit is contained in:
mattias 2002-08-17 23:41:25 +00:00
parent cb54cc13b8
commit 8fe4e23aa5

View File

@ -44,10 +44,13 @@ Begin
//Not used. It's a virtual procedure that should be overriden. //Not used. It's a virtual procedure that should be overriden.
end; end;
{------------------------------------------------------------------------------} {------------------------------------------------------------------------------
{ TWinControl AlignControls } TWinControl AlignControls
{------------------------------------------------------------------------------}
procedure TWinControl.AlignControls(AControl : TControl; var Rect : TRect); Align child controls
------------------------------------------------------------------------------}
procedure TWinControl.AlignControls(AControl : TControl; var ARect : TRect);
var var
AlignList: TList; AlignList: TList;
@ -59,8 +62,9 @@ var
for I := ControlCount - 1 downto 0 do for I := ControlCount - 1 downto 0 do
begin begin
if (Controls[I].Align <> alNone) or if (Controls[I].Align <> alNone)
(Controls[I].Anchors <> [akLeft, akTop]) then Exit; or (Controls[I].Anchors <> [akLeft, akTop])
then Exit;
end; end;
Result := False; Result := False;
end; end;
@ -80,65 +84,172 @@ var
procedure DoPosition(Control: TControl; AAlign: TAlign); procedure DoPosition(Control: TControl; AAlign: TAlign);
var var
Left2, Top2, Width2, Height2: Integer; NewLeft, NewTop, NewWidth, NewHeight: Integer;
R: TRect; ParentBaseClientSize: TPoint;
CurBaseBounds: TRect;
begin begin
{$IFDEF CHECK_POSITION} {$IFDEF CHECK_POSITION}
with Control do with Control do
writeln('[TWinControl.AlignControls.DoPosition] A Control=',Name,':',ClassName,' ',Left,',',Top,',',Width,',',Height,' recalculate the anchors=',(Control.Anchors <> AnchorAlign[AAlign]),' Align=',AlignNames[AAlign]); writeln('[TWinControl.AlignControls.DoPosition] A Control=',Name,':',ClassName,' ',Left,',',Top,',',Width,',',Height,' recalculate the anchors=',(Control.Anchors <> AnchorAlign[AAlign]),' Align=',AlignNames[AAlign]);
{$ENDIF} {$ENDIF}
with Rect do
begin
{ Just recalculate the anchors
Use Anchors to ensure that a control maintains its current position // get default bounds
relative to an edge of its parent, even if the parent is resized. When with Control do
its parent is resized, the control holds its position relative to the begin
edges to which it is anchored. NewLeft:=Left;
If a control is anchored to opposite edges of its parent, the control NewTop:=Top;
stretches when its parent is resized. For example, if a control has its NewWidth:=Width;
Anchors property set to [akLeft,akRight], the control stretches when the NewHeight:=Height;
width of its parent changes. end;
Anchors is enforced only when the parent is resized. Thus, for example,
if a control is anchored to opposite edges of a form at design time and { Recalculate the anchors
the form is created in a maximized state, the control is not stretched
because the form is not resized after the control is created. Use Anchors to ensure that a control maintains its current position
} relative to an edge of its parent, even if the parent is resized. When
if (AAlign = alNone) or (Control.Anchors <> AnchorAlign[AAlign]) then its parent is resized, the control holds its position relative to the
with Control do edges to which it is anchored.
begin If a control is anchored to opposite edges of its parent, the control
if FLastWidth = 0 then stretches when its parent is resized. For example, if a control has its
Anchors property set to [akLeft,akRight], the control stretches when the
width of its parent changes.
Anchors is enforced only when the parent is resized. Thus, for example,
if a control is anchored to opposite edges of a form at design time and
the form is created in a maximized state, the control is not stretched
because the form is not resized after the control is created.
}
if (AAlign = alNone) or (Control.Anchors <> AnchorAlign[AAlign]) then
begin
with Control do
begin
// Get the base bounds. The base bounds are the user defined bounds
// without automatic aligning and/or anchoring
// get base size of parents client area
ParentBaseClientSize:=FBaseParentClientSize;
if (ParentBaseClientSize.X=0)
and (ParentBaseClientSize.Y=0) then
ParentBaseClientSize:=Point(Parent.ClientWidth,Parent.ClientHeight);
// get base bounds of Control
CurBaseBounds:=FBaseBounds;
if (CurBaseBounds.Right=CurBaseBounds.Left)
and (CurBaseBounds.Bottom=CurBaseBounds.Top) then
CurBaseBounds:=BoundsRect;
{writeln('[TWinControl.AlignControls.DoPosition] Before Anchoring ',
' CurBaseBounds=',CurBaseBounds.Left,',',CurBaseBounds.Top,',',CurBaseBounds.Right-CurBaseBounds.Left,',',CurBaseBounds.Bottom-CurBaseBounds.Top,
' ParBaseClient=',ParentBaseClientSize.X,',',ParentBaseClientSize.Y,
' ParClient=',Parent.ClientWidth,',',Parent.ClientHeight,
'');}
if akLeft in Anchors then begin
// keep distance to left side of parent
NewLeft:=CurBaseBounds.Left;
if akRight in Anchors then begin
// keep distance to right side of parent
// -> change the width
NewWidth:=Parent.ClientWidth
-(ParentBaseClientSize.X-CurBaseBounds.Right)
-NewLeft;
end else begin
// do not anchor to the right
// -> keep new width
NewWidth:=Width;
end;
end else begin
// do not anchor to the left
if akRight in Anchors then begin
// keep distance to right side of parent
// and keep new width
NewWidth:=Width;
NewLeft:=Parent.ClientWidth
-(ParentBaseClientSize.X-CurBaseBounds.Right)
-NewWidth;
end else begin
// do not anchor to the right
// -> keep new width and center horizontally
NewWidth:=Width;
NewLeft:=(Parent.ClientWidth-NewWidth) div 2;
end;
end;
if akTop in Anchors then begin
// keep distance to top side of parent
NewTop:=CurBaseBounds.Top;
if akBottom in Anchors then begin
// keep distance to bottom side of parent
// -> change the height
NewHeight:=Parent.ClientHeight
-(ParentBaseClientSize.Y-CurBaseBounds.Bottom)
-NewTop;
end else begin
// do not anchor to the bottom
// -> keep new height
NewHeight:=Height;
end;
end else begin
// do not anchor to the top
if akBottom in Anchors then begin
// keep distance to bottom side of parent
// and keep new height
NewHeight:=Height;
NewTop:=Parent.ClientHeight
-(ParentBaseClientSize.Y-CurBaseBounds.Bottom)
-NewHeight;
end else begin
// do not anchor to the bottom
// -> keep new height and center vertically
NewHeight:=Height;
NewTop:=(Parent.ClientHeight-NewHeight) div 2;
end;
end;
{if FLastWidth = 0 then
Width2 := Parent.FLastResize.X + Width Width2 := Parent.FLastResize.X + Width
else else
Width2 := Parent.FLastResize.X + FLastWidth; Width2 := Parent.FLastResize.X + FLastWidth;
if FLastHeight = 0 then if FLastHeight = 0 then
Height2 := Parent.FLastResize.Y + Height Height2 := Parent.FLastResize.Y + Height
else else
Height2 := Parent.FLastResize.Y + FLastHeight; Height2 := Parent.FLastResize.Y + FLastHeight;
//writeln(' FLastWidth=',FLastWidth,' akLeft=',akLeft in Anchors,' akRight=',akRight in Anchors,' akTop=',akTop in Anchors); //writeln(' FLastWidth=',FLastWidth,' akLeft=',akLeft in Anchors,' akRight=',akRight in Anchors,' akTop=',akTop in Anchors);
R := BoundsRect; R := BoundsRect;
if not (akLeft in Anchors) then if not (akLeft in Anchors) then
if not (akRight in Anchors) then if not (akRight in Anchors) then
OffsetRect(R, Parent.FLastResize.X div 2, 0) OffsetRect(R, Parent.FLastResize.X div 2, 0)
else else
OffsetRect(R, Parent.FLastResize.X, 0) OffsetRect(R, Parent.FLastResize.X, 0)
else if akRight in Anchors then else if akRight in Anchors then
R.Right := R.Left + Width2; R.Right := R.Left + Width2;
if not (akTop in Anchors) then if not (akTop in Anchors) then
if not (akBottom in Anchors) then if not (akBottom in Anchors) then
OffsetRect(R, 0, Parent.FLastResize.Y div 2) OffsetRect(R, 0, Parent.FLastResize.Y div 2)
else else
OffsetRect(R, 0, Parent.FLastResize.Y) OffsetRect(R, 0, Parent.FLastResize.Y)
else if akBottom in Anchors then else if akBottom in Anchors then
R.Bottom := R.Top + Height2; R.Bottom := R.Top + Height2;
//with R do writeln(' R=',Left,',',Top,',',Right,',',Bottom); //with R do writeln(' R=',Left,',',Top,',',Right,',',Bottom);
BoundsRect := R; BoundsRect := R;
FLastWidth := Width2; FLastWidth := Width2;
FLastHeight := Height2; FLastHeight := Height2;
if AAlign = alNone then Exit; if AAlign = alNone then Exit;
end; }
end;
{with Control do
writeln('[TWinControl.AlignControls.DoPosition] After Anchoring',
' Align=',AlignNames[AAlign],
' Control=',Name,':',ClassName,
' Old=',Left,',',Top,',',Width,',',Height,
' New=',NewLeft,',',NewTop,',',NewWidth,',',NewHeight,
'');}
end;
// set min size
if NewWidth<0 then NewWidth:=0;
if NewHeight<0 then NewHeight:=0;
if AAlign<>alNone then begin
{ Realign { Realign
Use Align to align a control to the top, bottom, left, or right of a Use Align to align a control to the top, bottom, left, or right of a
@ -147,50 +258,84 @@ var
is resized, an aligned control also resizes so that it continues to span is resized, an aligned control also resizes so that it continues to span
the top, bottom, left, or right edge of the parent. the top, bottom, left, or right edge of the parent.
} }
Width2 := Right - Left;
//writeln(' Realign Width2=',Width2,' ',AAlign in [alLeft, alRight],' ',Control.Width); // alLeft, alRight do not fill horizontally
if (Width2 < 0) or (AAlign in [alLeft, alRight]) then if (AAlign in [alLeft, alRight]) then begin
Width2 := Control.Width; if NewWidth>ARect.Right-ARect.Left then
Height2 := Bottom - Top; NewWidth:=ARect.Right-ARect.Left;
if (Height2 < 0) or (AAlign in [alTop, alBottom]) then end else
Height2 := Control.Height; NewWidth := ARect.Right-ARect.Left;
Left2 := Left; if AAlign=alRight then begin
Top2 := Top; NewLeft:=ARect.Right-NewWidth;
if NewLeft<ARect.Left then
NewLeft:=ARect.Left;
end else
NewLeft:=ARect.Left;
// alTop, alBottom do not fill vertically
if (AAlign in [alTop, alBottom]) then begin
if NewHeight > ARect.Bottom-ARect.Top then
NewHeight := ARect.Bottom-ARect.Top;
end else
NewHeight := ARect.Bottom-ARect.Top;
if AAlign=alBottom then begin
NewTop:=ARect.Bottom-NewHeight;
if NewTop<ARect.Top then
NewTop:=ARect.Top;
end else
NewTop:=ARect.Top;
end;
// set the new bounds
if (Control.Left <> NewLeft) or (Control.Top <> NewTop)
or (Control.Width <> NewWidth) or (Control.Height <> NewHeight) then begin
{$IFDEF CHECK_POSITION}
//if csDesigning in Control.ComponentState then
with Control do
writeln('[TWinControl.AlignControls.DoPosition] NEW BOUNDS Control=',Name,':',ClassName,' NewBounds=',NewLeft,',',NewTop,',',NewWidth,',',NewHeight,' Align=',AlignNames[AAlign]);
{$ENDIF}
// lock the base bounds, so that the new automatic bounds do not override
// the user settings
Control.SetAlignedBounds(NewLeft, NewTop, NewWidth, NewHeight);
// Sometimes SetBounds change the bounds. For example due to constraints.
// update the new bounds
with Control do
begin
NewLeft:=Left;
NewTop:=Top;
NewWidth:=Width;
NewHeight:=Height;
end;
{$IFDEF CHECK_POSITION}
//if csDesigning in Control.ComponentState then
with Control do
writeln('[TWinControl.AlignControls.DoPosition] AFTER SETBOUND Control=',Name,':',ClassName,' Bounds=',Left,',',Top,',',Width,',',Height);
{$ENDIF}
end;
// adjust the remaining client area
with ARect do begin
case AAlign of case AAlign of
alTop: alTop:
Inc(Top, Height2); Inc(Top, NewHeight);
alBottom: alBottom:
begin begin
Dec(Bottom, Height2); Dec(Bottom, NewHeight);
Top2 := Bottom; NewTop := Bottom;
end; end;
alLeft: alLeft:
Inc(Left, Width2); Inc(Left, NewWidth);
alRight: alRight:
begin begin
Dec(Right, Width2); Dec(Right, NewWidth);
Left2 := Right; NewLeft := Right;
end; end;
end; end;
end; end;
if (Control.Left <> Left2) or (Control.Top <> Top2)
or (Control.Width <> Width2) or (Control.Height <> Height2) then begin
{$IFDEF CHECK_POSITION}
//if csDesigning in Control.ComponentState then
with Control do
writeln('[TWinControl.AlignControls.DoPosition] B1 Control=',Name,':',ClassName,' ',Left2,',',Top2,',',Width2,',',Height2,' Align=',AlignNames[AAlign]);
{$ENDIF}
Control.SetBounds(Left2, Top2, Width2, Height2);
{$IFDEF CHECK_POSITION}
//if csDesigning in Control.ComponentState then
with Control do
writeln('[TWinControl.AlignControls.DoPosition] B2 Control=',Name,':',ClassName,' ',Left,',',Top,',',Width,',',Height);
{$ENDIF}
end;
{Sometimes the control doesn't resize. This will verifiy that it is the {Sometimes the control doesn't resize. This will verifiy that it is the
size it is assigned to be} size it is assigned to be}
if (Control.Width <> Width2) or (Control.Height <> Height2) then {if (Control.Width <> Width2) or (Control.Height <> Height2) then
with Rect do with Rect do
case AAlign of case AAlign of
alTop: Dec(Top, Height2 - Control.Height); alTop: Dec(Top, Height2 - Control.Height);
@ -202,21 +347,24 @@ var
Inc(Right, Width2 - Control.Width); Inc(Right, Width2 - Control.Width);
Inc(Bottom, Height2 - Control.Height); Inc(Bottom, Height2 - Control.Height);
end; end;
end; end;}
{$IFDEF CHECK_POSITION} {$IFDEF CHECK_POSITION}
with Control do with Control do
writeln('[TWinControl.AlignControls.DoPosition] END Control=',Name,':',ClassName,' ',Left,',',Top,',',Width,',',Height,' Align=',AlignNames[AAlign]); writeln('[TWinControl.AlignControls.DoPosition] END Control=',Name,':',ClassName,' ',Left,',',Top,',',Width,',',Height,' Align=',AlignNames[AAlign]);
{$ENDIF} {$ENDIF}
end; end;
function InsertBefore(Control1, Control2: TControl; AAlign: TAlign): Boolean; function InsertBefore(Control1, Control2: TControl;
AAlign: TAlign): Boolean;
begin begin
Result := False; Result := False;
case AAlign of case AAlign of
alTop: Result := Control1.Top < Control2.Top; alTop: Result := Control1.Top < Control2.Top;
alBottom: Result := (Control1.Top + Control1.Height) >= (Control2.Top + Control2.Height); alBottom: Result := (Control1.Top + Control1.Height)
>= (Control2.Top + Control2.Height);
alLeft: Result := Control1.Left < Control2.Left; alLeft: Result := Control1.Left < Control2.Left;
alRight: Result := (Control1.Left + Control1.Width) >= (Control2.Left + Control2.Width); alRight: Result := (Control1.Left + Control1.Width)
>= (Control2.Left + Control2.Width);
end; end;
end; end;
@ -228,7 +376,8 @@ var
AlignList.Clear; AlignList.Clear;
if (AControl <> nil) if (AControl <> nil)
and (AControl.Align = AAlign) and (AControl.Align = AAlign)
and ((AAlign = alNone) or AControl.Visible and ((AAlign = alNone)
or AControl.Visible
or ((csDesigning in AControl.ComponentState) or ((csDesigning in AControl.ComponentState)
and not (csNoDesignVisible in AControl.ControlStyle))) and not (csNoDesignVisible in AControl.ControlStyle)))
then then
@ -260,29 +409,35 @@ var
end; end;
begin begin
//if csDesigning in ComponentState then if wcfAligningControls in FFlags then exit;
//writeln('[TWinControl.AlignControls] ',Name,':',Classname,' ',Left,',',Top,',',Width,',',Height,' AlignWork=',AlignWork); Include(FFlags,wcfAligningControls);
if AlignWork then try
begin //if csDesigning in ComponentState then
AdjustClientRect(Rect); //writeln('[TWinControl.AlignControls] ',Name,':',Classname,' ',Left,',',Top,',',Width,',',Height,' AlignWork=',AlignWork);
FAdjustClientRectRealized:=Rect; if AlignWork then
{$IFDEF VerboseClientRectBugFix} begin
writeln('[TWinControl.AlignControls] ',Name,':',Classname,' ',Left,',',Top,',',Width,',',Height,' ClientRect=',Rect.Left,',',Rect.Top,',',Rect.Right,',',Rect.Bottom); AdjustClientRect(ARect);
{$ENDIF} FAdjustClientRectRealized:=ARect;
AlignList := TList.Create; {$IFDEF VerboseClientRectBugFix}
try writeln('[TWinControl.AlignControls] ',Name,':',Classname,' ',Left,',',Top,',',Width,',',Height,' ClientRect=',Rect.Left,',',Rect.Top,',',Rect.Right,',',Rect.Bottom);
DoAlign(alTop); {$ENDIF}
DoAlign(alBottom); AlignList := TList.Create;
DoAlign(alLeft); try
DoAlign(alRight); DoAlign(alTop);
DoAlign(alClient); DoAlign(alBottom);
DoAlign(alNone); DoAlign(alLeft);
finally DoAlign(alRight);
AlignList.Free; DoAlign(alClient);
DoAlign(alCustom);
DoAlign(alNone);
ControlsAligned;
finally
AlignList.Free;
end;
end; end;
finally
Exclude(FFlags,wcfAligningControls);
end; end;
FLastResize.X := 0;
FLastResize.Y := 0;
if Showing then AdjustSize; if Showing then AdjustSize;
end; end;
@ -520,8 +675,6 @@ begin
Dec(FAlignLevel); Dec(FAlignLevel);
if FAlignLevel = 0 then begin if FAlignLevel = 0 then begin
if csAlignmentNeeded in ControlState then ReAlign; if csAlignmentNeeded in ControlState then ReAlign;
FLastResize.X := 0;
FLastresize.Y := 0;
end; end;
end; end;
@ -700,7 +853,7 @@ begin
Width:= FWidth; Width:= FWidth;
Height:= FHeight; Height:= FHeight;
{$IFDEF CHECK_POSITION} {$IFDEF CHECK_POSITION}
writeln(' [TControl.ChangeBounds] ',Name,':',ClassName,' SizeMsg Width=',Width,' Height=',Height); writeln(' [TControl.SendMoveSizeMessages] ',Name,':',ClassName,' SizeMsg Width=',Width,' Height=',Height);
{$ENDIF} {$ENDIF}
end; end;
WindowProc(TLMessage(SizeMsg)); WindowProc(TLMessage(SizeMsg));
@ -713,7 +866,7 @@ begin
XPos:= FLeft; XPos:= FLeft;
YPos:= FTop; YPos:= FTop;
{$IFDEF CHECK_POSITION} {$IFDEF CHECK_POSITION}
writeln(' [TControl.ChangeBounds] ',Name,':',ClassName,' MoveMsg XPos=',XPos,' YPos=',YPos); writeln(' [TControl.SendMoveSizeMessages] ',Name,':',ClassName,' MoveMsg XPos=',XPos,' YPos=',YPos);
{$ENDIF} {$ENDIF}
end; end;
WindowProc(TLMessage(MoveMsg)); WindowProc(TLMessage(MoveMsg));
@ -2318,6 +2471,7 @@ begin
CNSendMessage(LM_SETCOLOR, Self, nil); CNSendMessage(LM_SETCOLOR, Self, nil);
Exclude(FFlags,wcfColorChanged); Exclude(FFlags,wcfColorChanged);
end; end;
UpdateBaseBounds;
if wcfReAlignNeeded in FFlags then if wcfReAlignNeeded in FFlags then
ReAlign; ReAlign;
if wcfRequestAlignNeeded in FFlags then if wcfRequestAlignNeeded in FFlags then
@ -2545,6 +2699,11 @@ begin
UpdateControlState; UpdateControlState;
end; end;
procedure TWinControl.ControlsAligned;
begin
end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------
Method: TWinControl.CMShowingChanged Method: TWinControl.CMShowingChanged
Params: Message : not used Params: Message : not used
@ -2578,6 +2737,9 @@ end;
{ ============================================================================= { =============================================================================
$Log$ $Log$
Revision 1.133 2003/06/10 12:28:23 mattias
fixed anchoring controls
Revision 1.132 2003/06/10 00:46:16 mattias Revision 1.132 2003/06/10 00:46:16 mattias
fixed aligning controls fixed aligning controls