fixed fpc 2.1.1 compilation, docking: implemented shrinking to get space for docked control

git-svn-id: trunk@9718 -
This commit is contained in:
mattias 2006-08-12 10:55:22 +00:00
parent be5b78fb47
commit ac5ae3b17e
10 changed files with 277 additions and 117 deletions

View File

@ -192,7 +192,6 @@ type
procedure DoEnableChange; virtual; procedure DoEnableChange; virtual;
procedure DoHit(const ACount: Integer; var AContinue: Boolean); virtual; procedure DoHit(const ACount: Integer; var AContinue: Boolean); virtual;
procedure SetHitCount(const AValue: Integer); procedure SetHitCount(const AValue: Integer);
procedure SetLocation(const ASource: String; const ALine: Integer); virtual;
procedure SetValid(const AValue: TValidState); procedure SetValid(const AValue: TValidState);
protected protected
@ -210,6 +209,7 @@ type
procedure SetInitialEnabled(const AValue: Boolean); virtual; procedure SetInitialEnabled(const AValue: Boolean); virtual;
public public
constructor Create(ACollection: TCollection); override; constructor Create(ACollection: TCollection); override;
procedure SetLocation(const ASource: String; const ALine: Integer); virtual;// PublicProtectedFix ide/debugmanager.pas(867,32) Error: identifier idents no member "SetLocation"
property Enabled: Boolean read GetEnabled write SetEnabled; property Enabled: Boolean read GetEnabled write SetEnabled;
property Expression: String read GetExpression write SetExpression; property Expression: String read GetExpression write SetExpression;
property HitCount: Integer read GetHitCount; property HitCount: Integer read GetHitCount;

View File

@ -94,6 +94,7 @@ begin
DockingManager.WriteDebugReport; DockingManager.WriteDebugReport;
Form2:=CreateNewForm; Form2:=CreateNewForm;
DebugLn(['TMainForm.FormCreate =============================================================']);
Form3:=CreateNewForm; Form3:=CreateNewForm;
if not UseConfig then begin if not UseConfig then begin

View File

@ -85,7 +85,7 @@ uses
// help manager // help manager
IDEContextHelpEdit, HelpManager, IDEContextHelpEdit, HelpManager,
// designer // designer
ComponentPalette, ComponentReg, ObjInspExt, JITForm, ComponentPalette, ComponentReg, ObjInspExt,
Designer, FormEditor, CustomFormEditor, Designer, FormEditor, CustomFormEditor,
ControlSelection, AnchorEditor, ControlSelection, AnchorEditor,
{$DEFINE UseNewMenuEditor} {$DEFINE UseNewMenuEditor}
@ -2153,8 +2153,7 @@ end;
Procedure TMainIDE.SetDesigning(AComponent: TComponent; Value: Boolean); Procedure TMainIDE.SetDesigning(AComponent: TComponent; Value: Boolean);
Begin Begin
AComponent.SetDesigning(Value); SetComponentDesignMode(AComponent,Value);
//TODO: Remove widgetset from this code
if Value then WidgetSet.SetDesigning(AComponent); if Value then WidgetSet.SetDesigning(AComponent);
end; end;

View File

@ -1499,7 +1499,7 @@ end;
function TPointerToPointerTree.FindNode(const Key: Pointer): TAvgLvlTreeNode; function TPointerToPointerTree.FindNode(const Key: Pointer): TAvgLvlTreeNode;
begin begin
Result:=FItems.FindKey(@Key,@ComparePointerWithPtrToPtrItem) Result:=FItems.FindKey(Key,@ComparePointerWithPtrToPtrItem)
end; end;
function TPointerToPointerTree.GetNode(Node: TAvgLvlTreeNode; out Key, function TPointerToPointerTree.GetNode(Node: TAvgLvlTreeNode; out Key,

View File

@ -1123,6 +1123,7 @@ type
procedure AnchorToCompanion(Side: TAnchorKind; Space: integer; procedure AnchorToCompanion(Side: TAnchorKind; Space: integer;
Sibling: TControl; Sibling: TControl;
FreeCompositeSide: boolean = true); FreeCompositeSide: boolean = true);
procedure AnchorSame(Side: TAnchorKind; Sibling: TControl);
function AnchoredControlCount: integer; function AnchoredControlCount: integer;
property AnchoredControls[Index: integer]: TControl read GetAnchoredControls; property AnchoredControls[Index: integer]: TControl read GetAnchoredControls;
procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); virtual; procedure SetBounds(aLeft, aTop, aWidth, aHeight: integer); virtual;

View File

@ -3690,6 +3690,15 @@ begin
end; end;
end; end;
procedure TControl.AnchorSame(Side: TAnchorKind; Sibling: TControl);
begin
if Side in Sibling.Anchors then
Anchors:=Anchors+[Side]
else
Anchors:=Anchors-[Side];
AnchorSide[Side].Assign(Sibling.AnchorSide[Side]);
end;
function TControl.AnchoredControlCount: integer; function TControl.AnchoredControlCount: integer;
begin begin
if fAnchoredControls=nil then if fAnchoredControls=nil then

View File

@ -27,8 +27,8 @@
{ $DEFINE CHECK_POSITION} { $DEFINE CHECK_POSITION}
{$IFDEF CHECK_POSITION} {$IFDEF CHECK_POSITION}
const CheckPostionClassName = 'TButton'; const CheckPostionClassName = 'TButtonX';
const CheckPostionName = 'WhereRadioGroup'; const CheckPostionName = 'MainForm';
function CheckPosition(AControl: TControl): boolean; function CheckPosition(AControl: TControl): boolean;
begin begin
@ -1316,7 +1316,7 @@ var
{$IFDEF CHECK_POSITION} {$IFDEF CHECK_POSITION}
//if csDesigning in ComponentState then //if csDesigning in ComponentState then
if CheckPosition(Control) then if CheckPosition(Control) then
with Control do with Control do begin
DebugLn('[TWinControl.AlignControls.DoPosition] After Anchoring', DebugLn('[TWinControl.AlignControls.DoPosition] After Anchoring',
' ',Name,':',ClassName, ' ',Name,':',ClassName,
' Align=',AlignNames[AAlign], ' Align=',AlignNames[AAlign],
@ -1324,6 +1324,8 @@ var
' Old=',DbgS(Left,Top,Width,Height), ' Old=',DbgS(Left,Top,Width,Height),
' New=',DbgS(NewLeft,NewTop,NewWidth,NewHeight), ' New=',DbgS(NewLeft,NewTop,NewWidth,NewHeight),
''); '');
DebugLn(['DoPosition akRight=',akRight in CurAnchors,' ',GetAnchorSidePosition(akRight,NewRight)]);
end;
{$ENDIF} {$ENDIF}
end; end;
@ -1648,14 +1650,14 @@ begin
RemainingBorderSpace:=Rect(0,0,0,0); RemainingBorderSpace:=Rect(0,0,0,0);
// adjust RemainingClientRect by ChildSizing properties // adjust RemainingClientRect by ChildSizing properties
AdjustBorderSpace(RemainingClientRect,RemainingBorderSpace, AdjustBorderSpace(RemainingClientRect,RemainingBorderSpace,
ChildSizing.LeftRightSpacing,ChildSizing.TopBottomSpacing, ChildSizing.LeftRightSpacing,ChildSizing.TopBottomSpacing,
ChildSizing.LeftRightSpacing,ChildSizing.TopBottomSpacing); ChildSizing.LeftRightSpacing,ChildSizing.TopBottomSpacing);
//DebugLn('[TWinControl.AlignControls] ',Name,':',Classname,' ',Left,',',Top,',',Width,',',Height,' ClientRect=',RemainingClientRect.Left,',',RemainingClientRect.Top,',',RemainingClientRect.Right,',',RemainingClientRect.Bottom); //DebugLn('[TWinControl.AlignControls] ',Name,':',Classname,' ',Left,',',Top,',',Width,',',Height,' ClientRect=',RemainingClientRect.Left,',',RemainingClientRect.Top,',',RemainingClientRect.Right,',',RemainingClientRect.Bottom);
AlignList := TFPList.Create; AlignList := TFPList.Create;
try try
// Auto aligning/anchoring can be very interdependent. // Auto aligning/anchoring can be very interdependent.
// In worst case the n-2 depends on the n-1, the n-3 depends on n-2 // In worst case the n-2 depends on the n-1, the n-3 depends on n-2
// and so forth. This is allowed, so do up to n steps. // and so forth. This is allowed, so do up to n loop step.
// Do not more, to avoid endless loops, if there are circle // Do not more, to avoid endless loops, if there are circle
// dependencies. // dependencies.
for i:=0 to ControlCount-1 do begin for i:=0 to ControlCount-1 do begin

View File

@ -750,7 +750,7 @@ var
begin begin
i:=Count; i:=Count;
while NextDownIndex(i) do while NextDownIndex(i) do
TNotifyEvent(Items[i])(Self); TNotifyEvent(Items[i])(Sender);
end; end;
{------------------------------------------------------------------------------ {------------------------------------------------------------------------------

View File

@ -37,8 +37,8 @@ interface
uses uses
Classes, Math, SysUtils, TypInfo, LCLProc, Controls, Forms, Menus, Classes, Math, SysUtils, TypInfo, LCLProc, Controls, Forms, Menus,
LCLStrConsts, AvgLvlTree, StringHashList, LazConfigStorage, LDockCtrlEdit, LCLStrConsts, AvgLvlTree, StringHashList, ExtCtrls, LazConfigStorage,
LDockTree; LDockCtrlEdit, LDockTree;
type type
TNonDockConfigNames = ( TNonDockConfigNames = (
@ -226,6 +226,8 @@ type
Side: TAnchorKind): boolean; Side: TAnchorKind): boolean;
procedure FixControlBounds(Layout: TLazDockConfigNode; procedure FixControlBounds(Layout: TLazDockConfigNode;
AddedControl: TControl); AddedControl: TControl);
procedure ShrinkNeighbourhood(Layout: TLazDockConfigNode;
AControl: TControl);
public public
constructor Create(TheOwner: TComponent); override; constructor Create(TheOwner: TComponent); override;
procedure ShowDockingEditor; virtual; procedure ShowDockingEditor; virtual;
@ -439,7 +441,7 @@ end;
procedure TCustomLazControlDocker.ControlVisibleChanged(Sender: TObject); procedure TCustomLazControlDocker.ControlVisibleChanged(Sender: TObject);
begin begin
DebugLn(['TCustomLazControlDocker.ControlVisibleChanged Sender=',DbgSName(Sender)]); DebugLn(['TCustomLazControlDocker.ControlVisibleChanged Sender=',DbgSName(Sender)]);
DumpStack; //DumpStack;
end; end;
function TCustomLazControlDocker.CreateFormAndDockWithSplitter( function TCustomLazControlDocker.CreateFormAndDockWithSplitter(
@ -460,54 +462,98 @@ var
SplitterNode: TLazDockConfigNode; SplitterNode: TLazDockConfigNode;
NeighbourNode: TLazDockConfigNode; NeighbourNode: TLazDockConfigNode;
NeighbourControl: TControl; NeighbourControl: TControl;
NewParent: TLazDockForm; NewParent: TWinControl;
Splitter: TLazDockSplitter; Splitter: TLazDockSplitter;
a: TAnchorKind; a: TAnchorKind;
NewParentCreated: Boolean;
SplitterSize: LongInt;
begin begin
Result:=false; Result:=false;
DebugLn(['TCustomLazControlDocker.CreateFormAndDockWithSplitter DockerName="',DockerName,'"']);
SelfNode:=Layout.FindByName(DockerName,true); SelfNode:=Layout.FindByName(DockerName,true);
SplitterNode:=Layout.FindByName(SelfNode.Sides[Side]); SplitterNode:=Layout.FindByName(SelfNode.Sides[Side]);
NeighbourNode:=Layout.FindByName(SplitterNode.Sides[Side]); NeighbourNode:=SplitterNode.FindNeighbour(OppositeAnchor[Side],true);
NeighbourControl:=Manager.FindControlByDockerName(NeighbourNode.Name); NeighbourControl:=Manager.FindControlByDockerName(NeighbourNode.Name);
if NeighbourControl.Parent=nil then begin if NeighbourControl.Parent=nil then begin
// create a new TLazDockForm and put both controls into it // NeighbourControl is a standalone control (e.g. an undocked form)
// => create a new TLazDockForm and put both controls into it
NewParent:=TLazDockForm.Create(nil); NewParent:=TLazDockForm.Create(nil);
NewParent.DisableAlign; NewParentCreated:=true;
try end else begin
// move Control and Neighbour to the new parent // NeighbourControl is docked
NewParent:=NeighbourControl.Parent;
NewParentCreated:=false;
end;
NewParent.DisableAlign;
try
// create a splitter
Splitter:=TLazDockSplitter.Create(nil);
Splitter.Align:=alNone;
Splitter.Beveled:=true;
Splitter.ResizeAnchor:=Side;
Splitter.Parent:=NewParent;
if Side in [akLeft,akRight] then
SplitterSize:=Manager.Manager.GetSplitterWidth(Splitter)
else
SplitterSize:=Manager.Manager.GetSplitterHeight(Splitter);
if Side in [akLeft,akRight] then
Splitter.Width:=SplitterSize
else
Splitter.Height:=SplitterSize;
DebugLn(['TCustomLazControlDocker.CreateFormAndDockWithSplitter Splitter=',DbgSName(Splitter),' ',dbgs(Splitter.BoundsRect)]);
if NewParentCreated then begin
// resize NewParent to bounds of NeighbourControl
NewParent.BoundsRect:=NeighbourControl.BoundsRect;
NeighbourControl.Parent:=NewParent; NeighbourControl.Parent:=NewParent;
Control.Parent:=NewParent; end;
DebugLn(['TCustomLazControlDocker.CreateFormAndDockWithSplitter NewParent=',DbgSName(NewParent),' ',dbgs(NewParent.BoundsRect)]);
DebugLn(['TCustomLazControlDocker.CreateFormAndDockWithSplitter NeighbourControl=',DbgSName(NeighbourControl),' ',dbgs(NeighbourControl.BoundsRect)]);
// create a splitter // move Control to the new parent
Splitter:=TLazDockSplitter.Create(nil); Control.Parent:=NewParent;
Splitter.Align:=alNone; Control.BoundsRect:=SelfNode.Bounds;
Splitter.Beveled:=true; DebugLn(['TCustomLazControlDocker.CreateFormAndDockWithSplitter Control=',DbgSName(Control),' ',dbgs(Control.BoundsRect)]);
Splitter.ResizeAnchor:=Side;
Splitter.Parent:=NewParent;
if NewParentCreated then begin
for a:=Low(TAnchorKind) to High(TAnchorKind) do begin for a:=Low(TAnchorKind) to High(TAnchorKind) do begin
// anchor Neighbour
if a=OppositeAnchor[Side] then
NeighbourControl.AnchorParallel(a,0,Splitter)
else
NeighbourControl.AnchorParallel(a,0,NewParent);
// anchor Control // anchor Control
if a=Side then if a=Side then
Control.AnchorParallel(a,0,Splitter) Control.AnchorToNeighbour(a,0,Splitter)
else else
Control.AnchorParallel(a,0,NewParent); Control.AnchorParallel(a,0,NewParent);
// anchor Splitter // anchor Splitter
if (Side in [akLeft,akRight]) <> (a in [akLeft,akRight]) then if (Side in [akLeft,akRight]) <> (a in [akLeft,akRight]) then
Splitter.AnchorParallel(a,0,NewParent); Splitter.AnchorParallel(a,0,NewParent);
// anchor Neighbour
if a=OppositeAnchor[Side] then
NeighbourControl.AnchorToNeighbour(a,0,Splitter)
else
NeighbourControl.AnchorParallel(a,0,NewParent);
end; end;
end else begin
FixControlBounds(Layout,Control); for a:=Low(TAnchorKind) to High(TAnchorKind) do begin
// anchor Control
finally if a=Side then
NewParent.EnableAlign; Control.AnchorToNeighbour(a,0,Splitter)
else
Control.AnchorSame(a,NeighbourControl);
// anchor Splitter
if (Side in [akLeft,akRight]) <> (a in [akLeft,akRight]) then
Splitter.AnchorSame(a,NeighbourControl);
end;
// anchor Neighbour
NeighbourControl.AnchorToNeighbour(OppositeAnchor[Side],0,Splitter);
end; end;
end else begin
ShrinkNeighbourhood(Layout,Control);
FixControlBounds(Layout,Control);
finally
NewParent.EnableAlign;
NewParent.Visible:=true;
end; end;
Result:=true; Result:=true;
@ -568,6 +614,8 @@ var
Result^.Node:= Result^.Node:=
Layout.FindByName(Manager.GetControlConfigName(AControl),true); Layout.FindByName(Manager.GetControlConfigName(AControl),true);
ControlToInfo[AControl]:=Result; ControlToInfo[AControl]:=Result;
if ControlToInfo[AControl]<>Result then
RaiseGDBException('');
end; end;
end; end;
@ -579,6 +627,7 @@ var
begin begin
if Neighbour=nil then exit; if Neighbour=nil then exit;
if Neighbour.Parent<>AControl.Parent then exit; if Neighbour.Parent<>AControl.Parent then exit;
//DebugLn(['Left Improve AControl=',DbgSName(AControl),' Neighbour=',DbgSName(Neighbour)]);
Info^.MinLeft:=Max(Info^.MinLeft, Info^.MinLeft:=Max(Info^.MinLeft,
CalculateMinimumLeft(Neighbour)+Neighbour.Width); CalculateMinimumLeft(Neighbour)+Neighbour.Width);
end; end;
@ -589,8 +638,9 @@ var
begin begin
Info:=GetInfo(AControl); Info:=GetInfo(AControl);
if not Info^.MinLeftValid then begin if not Info^.MinLeftValid then begin
//DebugLn(['CalculateMinimumLeft ',DbgSName(AControl)]);
if Info^.MinLeftCalculating then if Info^.MinLeftCalculating then
raise Exception.Create('anchor circle'); raise Exception.Create('anchor circle (left)');
Info^.MinLeftCalculating:=true; Info^.MinLeftCalculating:=true;
Info^.MinLeft:=0; Info^.MinLeft:=0;
@ -599,14 +649,16 @@ var
if AControl.Parent<>nil then begin if AControl.Parent<>nil then begin
for i:=0 to AControl.Parent.ControlCount-1 do begin for i:=0 to AControl.Parent.ControlCount-1 do begin
Sibling:=AControl.Parent.Controls[i]; Sibling:=AControl.Parent.Controls[i];
if Sibling=AControl then continue;
if (akRight in Sibling.Anchors) if (akRight in Sibling.Anchors)
and (Sibling.AnchorSide[akRight].Control=AControl) then and (Sibling.AnchorSide[akRight].Control=AControl) then
Improve(Sibling.AnchorSide[akRight].Control); Improve(Sibling);
end; end;
end; end;
Info^.MinLeftCalculating:=true; Info^.MinLeftCalculating:=false;
Info^.MinLeftValid:=true; Info^.MinLeftValid:=true;
//DebugLn(['CalculateMinimumLeft END ',DbgSName(AControl),' ',GetInfo(AControl)^.MinLeftValid]);
end; end;
Result:=Info^.MinLeft; Result:=Info^.MinLeft;
end; end;
@ -630,7 +682,7 @@ var
Info:=GetInfo(AControl); Info:=GetInfo(AControl);
if not Info^.MinTopValid then begin if not Info^.MinTopValid then begin
if Info^.MinTopCalculating then if Info^.MinTopCalculating then
raise Exception.Create('anchor circle'); raise Exception.Create('anchor circle (top)');
Info^.MinTopCalculating:=true; Info^.MinTopCalculating:=true;
Info^.MinTop:=0; Info^.MinTop:=0;
@ -639,13 +691,14 @@ var
if AControl.Parent<>nil then begin if AControl.Parent<>nil then begin
for i:=0 to AControl.Parent.ControlCount-1 do begin for i:=0 to AControl.Parent.ControlCount-1 do begin
Sibling:=AControl.Parent.Controls[i]; Sibling:=AControl.Parent.Controls[i];
if Sibling=AControl then continue;
if (akBottom in Sibling.Anchors) if (akBottom in Sibling.Anchors)
and (Sibling.AnchorSide[akBottom].Control=AControl) then and (Sibling.AnchorSide[akBottom].Control=AControl) then
Improve(Sibling.AnchorSide[akBottom].Control); Improve(Sibling);
end; end;
end; end;
Info^.MinTopCalculating:=true; Info^.MinTopCalculating:=false;
Info^.MinTopValid:=true; Info^.MinTopValid:=true;
end; end;
Result:=Info^.MinTop; Result:=Info^.MinTop;
@ -653,50 +706,53 @@ var
function CalculateClientSize(AControl: TControl): TPoint; function CalculateClientSize(AControl: TControl): TPoint;
var var
Info: PControlInfo;
AWinControl: TWinControl; AWinControl: TWinControl;
i: Integer; i: Integer;
ChildControl: TControl; ChildControl: TControl;
begin begin
Info:=GetInfo(AControl); Result:=Point(0,0);
if not Info^.MinClientSizeValid then begin if AControl is TWinControl then begin
Info^.MinClientSizeValid:=true; AWinControl:=TWinControl(AControl);
Info^.MinClientSize:=Point(0,0); for i:=0 to AWinControl.ControlCount-1 do begin
if AControl is TWinControl then begin ChildControl:=AWinControl.Controls[i];
AWinControl:=TWinControl(AControl); Result.X:=Max(Result.X,CalculateMinimumLeft(ChildControl)
for i:=0 to AWinControl.ControlCount-1 do begin +ChildControl.Width);
ChildControl:=AWinControl.Controls[i]; Result.Y:=Max(Result.Y,CalculateMinimumTop(ChildControl)
Info^.MinClientSize.X:=Max(Info^.MinClientSize.X, +ChildControl.Height);
CalculateMinimumLeft(ChildControl));
Info^.MinClientSize.Y:=Max(Info^.MinClientSize.Y,
CalculateMinimumTop(ChildControl));
end;
end; end;
end; end;
Result:=Info^.MinClientSize;
end; end;
procedure ApplyBounds; procedure ApplyBounds(ParentClientWidth, ParentClientHeight: Integer);
var var
i: Integer; i: Integer;
Sibling: TControl; Sibling: TControl;
Info: PControlInfo; Info: PControlInfo;
NewRect: TRect; NewRect: TRect;
OldRect: TRect; OldRect: TRect;
SideControl: TControl;
begin begin
for i:=0 to AddedControl.Parent.ControlCount-1 do begin for i:=0 to AddedControl.Parent.ControlCount-1 do begin
Sibling:=AddedControl.Parent.Controls[i]; Sibling:=AddedControl.Parent.Controls[i];
Info:=GetInfo(Sibling); Info:=GetInfo(Sibling);
NewRect.Left:=Info^.MinLeft; NewRect.Left:=Info^.MinLeft;
NewRect.Right:=NewRect.Left+Sibling.Width; NewRect.Right:=NewRect.Left+Sibling.Width;
if (akRight in Sibling.Anchors) SideControl:=Sibling.AnchorSide[akRight].Control;
and (Sibling.AnchorSide[akRight].Control<>nil) then if (akRight in Sibling.Anchors) and (SideControl<>nil) then begin
NewRect.Right:=CalculateMinimumLeft(Sibling.AnchorSide[akRight].Control); if SideControl=AddedControl.Parent then
NewRect.Right:=ParentClientWidth
else if SideControl.Parent=AddedControl.Parent then
NewRect.Right:=CalculateMinimumLeft(SideControl);
end;
NewRect.Top:=Info^.MinTop; NewRect.Top:=Info^.MinTop;
NewRect.Bottom:=NewRect.Top+Sibling.Height; NewRect.Bottom:=NewRect.Top+Sibling.Height;
if (akBottom in Sibling.Anchors) SideControl:=Sibling.AnchorSide[akBottom].Control;
and (Sibling.AnchorSide[akBottom].Control<>nil) then if (akBottom in Sibling.Anchors) and (SideControl<>nil) then begin
NewRect.Bottom:=CalculateMinimumTop(Sibling.AnchorSide[akBottom].Control); if SideControl=AddedControl.Parent then
NewRect.Bottom:=ParentClientHeight
else if SideControl.Parent=AddedControl.Parent then
NewRect.Bottom:=CalculateMinimumTop(SideControl);
end;
OldRect:=Sibling.BoundsRect; OldRect:=Sibling.BoundsRect;
if not CompareRect(@OldRect,@NewRect) then begin if not CompareRect(@OldRect,@NewRect) then begin
DebugLn(['ApplyBounds Sibling=',DbgSName(Sibling),' NewRect=',dbgs(NewRect)]); DebugLn(['ApplyBounds Sibling=',DbgSName(Sibling),' NewRect=',dbgs(NewRect)]);
@ -713,6 +769,10 @@ var
begin begin
DebugLn(['TCustomLazControlDocker.FixControlBounds ',DbgSName(AddedControl)]); DebugLn(['TCustomLazControlDocker.FixControlBounds ',DbgSName(AddedControl)]);
CurParent:=AddedControl.Parent; CurParent:=AddedControl.Parent;
if CurParent=nil then begin
DebugLn(['TCustomLazControlDocker.FixControlBounds WARNING: no parent']);
exit;
end;
CurParent.DisableAlign; CurParent.DisableAlign;
try try
InitInfos; InitInfos;
@ -722,7 +782,9 @@ begin
DiffHeight:=ParentSize.Y-CurParent.ClientHeight; DiffHeight:=ParentSize.Y-CurParent.ClientHeight;
if (DiffWidth<>0) or (DiffHeight<>0) then begin if (DiffWidth<>0) or (DiffHeight<>0) then begin
// parent needs resizing // parent needs resizing
CurParent.Parent.DisableAlign; DebugLn(['TCustomLazControlDocker.FixControlBounds Parent=',DbgSName(AddedControl.Parent),' needs resizing to ',dbgs(ParentSize)]);
if CurParent.Parent<>nil then
CurParent.Parent.DisableAlign;
try try
CurParent.ClientWidth:=ParentSize.X; CurParent.ClientWidth:=ParentSize.X;
CurParent.ClientHeight:=ParentSize.Y; CurParent.ClientHeight:=ParentSize.Y;
@ -737,16 +799,112 @@ begin
DebugLn(['TCustomLazControlDocker.FixControlBounds TODO move parent ',DbgSName(CurParent)]); DebugLn(['TCustomLazControlDocker.FixControlBounds TODO move parent ',DbgSName(CurParent)]);
end; end;
finally finally
CurParent.Parent.EnableAlign; if CurParent.Parent<>nil then
CurParent.Parent.EnableAlign;
end; end;
end; end;
ApplyBounds; ApplyBounds(ParentSize.X,ParentSize.Y);
finally finally
FreeInfos; FreeInfos;
CurParent.EnableAlign; CurParent.EnableAlign;
end; end;
end; end;
procedure TCustomLazControlDocker.ShrinkNeighbourhood(
Layout: TLazDockConfigNode; AControl: TControl);
{ shrink neighbour controls according to Layout
A neighbour is the first control left or top of AControl, that can be shrinked
and is only anchored to AControl.
}
function CountAnchoredControls(CurControl: TControl; Side: TAnchorKind
): Integer;
{ return the number of siblings, that are anchored on Side of CurControl
For example: if Side=akLeft it will return the number of controls, which
right side is anchored to the left of CurControl }
var
i: Integer;
Neighbour: TControl;
begin
Result:=0;
for i:=0 to CurControl.Parent.ControlCount-1 do begin
Neighbour:=CurControl.Parent.Controls[i];
if Neighbour=CurControl then continue;
if (OppositeAnchor[Side] in Neighbour.Anchors)
and (Neighbour.AnchorSide[OppositeAnchor[Side]].Control=CurControl) then
inc(Result);
end;
end;
procedure ShrinkControl(CurControl: TControl; Side: TAnchorKind); forward;
procedure ShrinkNeighboursOnSide(CurControl: TControl; Side: TAnchorKind);
// shrink all controls, that are anchored on Side of CurControl
var
Neighbour: TControl;
i: Integer;
begin
DebugLn(['ShrinkNeighboursOnSide START ',DbgSName(CurControl),' ',AnchorNames[Side]]);
if Side in CurControl.Anchors then begin
Neighbour:=CurControl.AnchorSide[Side].Control;
DebugLn(['ShrinkNeighboursOnSide Neighbour=',DbgSName(Neighbour)]);
ShrinkControl(Neighbour,Side);
end;
for i:=0 to CurControl.Parent.ControlCount-1 do begin
Neighbour:=CurControl.Parent.Controls[i];
if (OppositeAnchor[Side] in Neighbour.Anchors)
and (Neighbour.AnchorSide[OppositeAnchor[Side]].Control=CurControl)
then
ShrinkControl(Neighbour,Side);
end;
end;
procedure ShrinkControl(CurControl: TControl; Side: TAnchorKind);
var
NodeName: String;
Node: TLazDockConfigNode;
CurBounds: TRect;
begin
DebugLn(['ShrinkControl START ',DbgSName(CurControl),' Side=',AnchorNames[Side]]);
if (CurControl=nil) or (CurControl=AControl)
or (CurControl.Parent<>AControl.Parent) then
exit;
if CountAnchoredControls(CurControl,OppositeAnchor[Side])>1 then begin
// CurControl is not only anchored at AControl
// do not shrink it
exit;
end;
if CurControl is TCustomSplitter then begin
// a splitter can not be shrinked
// => try to shrink the controls on the other side of the splitter
ShrinkNeighboursOnSide(CurControl,Side);
exit;
end;
// shrink accoring to Layout
NodeName:=Manager.GetControlConfigName(CurControl);
if NodeName='' then exit;
Node:=Layout.FindByName(NodeName,true);
if Node=nil then exit;
CurBounds:=Node.Bounds;
DebugLn(['ShrinkControl ',DbgSName(CurControl),' Side=',AnchorNames[Side],' LayoutBounds=',dbgs(CurBounds)]);
if Side in [akLeft,akRight] then
CurControl.Width:=Min(CurControl.Width,CurBounds.Right-CurBounds.Left)
else
CurControl.Height:=Min(CurControl.Height,CurBounds.Bottom-CurBounds.Top);
end;
var
a: TAnchorKind;
begin
DebugLn(['TCustomLazControlDocker.ShrinkNeighbourhood AControl=',DbgSName(AControl)]);
AControl.Parent.DisableAlign;
try
for a:=Low(TAnchorKind) to High(TAnchorKind) do
ShrinkNeighboursOnSide(AControl,a);
finally
AControl.Parent.EnableAlign;
end;
end;
function TCustomLazControlDocker.GetControlName(AControl: TControl): string; function TCustomLazControlDocker.GetControlName(AControl: TControl): string;
var var
i: Integer; i: Integer;
@ -1101,39 +1259,6 @@ var
Result:=Manager.FindControlByDockerName(ADockerName); Result:=Manager.FindControlByDockerName(ADockerName);
end; end;
function DockWithOwnSplitter(Side: TAnchorKind): boolean;
{ Add a splitter to Side and dock to it. For example:
--------+ -----------+
---+| ----+#+---+|
B || -> B |#| A ||
---+| ----+#+---+|
--------+ -----------+
If B has no parent, a TLazDockForm is created.
To get space for A, either B is shrinked and/or the parent of B is enlarged
(including the grand parents of B).
}
var
SplitterNode: TLazDockConfigNode;
NeighbourNode: TLazDockConfigNode;
NeighbourControl: TControl;
begin
// TODO
SplitterNode:=FindNode(SelfNode.Sides[Side]);
NeighbourNode:=SplitterNode.FindNeighbour(OppositeAnchor[Side],true);
NeighbourControl:=FindControl(NeighbourNode.Name);
if NeighbourControl=nil then RaiseGDBException('inconsistency');
if NeighbourNode.Parent=nil then begin
// Neighbour is a standalone control
// => combine Neighbour and Self onto a dummy form
Result:=CreateFormAndDockWithSplitter(Layout,Side);
exit;
end else begin
end;
Result:=false;
end;
function DockWithSpiralSpltter: boolean; function DockWithSpiralSpltter: boolean;
begin begin
// TODO // TODO
@ -1153,7 +1278,7 @@ var
and (SideNode.TheType in [ldcntSplitterLeftRight,ldcntSplitterUpDown]) and (SideNode.TheType in [ldcntSplitterLeftRight,ldcntSplitterUpDown])
then begin then begin
if SideNode.IsTheOnlyNeighbour(SelfNode,a) if SideNode.IsTheOnlyNeighbour(SelfNode,a)
and DockWithOwnSplitter(a) then and CreateFormAndDockWithSplitter(Layout,a) then
exit(true); exit(true);
inc(SplitterCount); inc(SplitterCount);
if (SplitterCount=4) and DockWithSpiralSpltter then if (SplitterCount=4) and DockWithSpiralSpltter then
@ -1493,6 +1618,7 @@ function TCustomLazDockingManager.CreateLayout(const DockerName: string;
// create a usable config // create a usable config
// This means: search a config, create a copy // This means: search a config, create a copy
// and remove all nodes without visible controls. // and remove all nodes without visible controls.
{$DEFINE VerboseAnchorDockCreateLayout}
var var
Root: TLazDockConfigNode; Root: TLazDockConfigNode;
CurDockControl: TControl; CurDockControl: TControl;
@ -1683,7 +1809,7 @@ var
a: TAnchorKind; a: TAnchorKind;
OldFormNode: TLazDockConfigNode; OldFormNode: TLazDockConfigNode;
begin begin
DebugLn(['SimplifyOneChildForm ',dbgs(FormNode)]); //DebugLn(['SimplifyOneChildForm ',dbgs(FormNode)]);
if FormNode<>Root then RaiseGDBException(''); if FormNode<>Root then RaiseGDBException('');
if FormNode.ChildCount<>1 then RaiseGDBException(''); if FormNode.ChildCount<>1 then RaiseGDBException('');
FormBounds:=FormNode.Bounds; FormBounds:=FormNode.Bounds;
@ -1716,7 +1842,9 @@ var
Child: TLazDockConfigNode; Child: TLazDockConfigNode;
begin begin
if Node=nil then exit; if Node=nil then exit;
{$IFDEF VerboseAnchorDockCreateLayout}
DebugLn(['RemoveEmptyNodes ',Node.Name,' Node.ChildCount=',Node.ChildCount]); DebugLn(['RemoveEmptyNodes ',Node.Name,' Node.ChildCount=',Node.ChildCount]);
{$ENDIF}
// remove unneeded childs // remove unneeded childs
i:=Node.ChildCount-1; i:=Node.ChildCount-1;
@ -1734,25 +1862,33 @@ var
// if the associated control does not exist or is not visible, // if the associated control does not exist or is not visible,
// then delete the node // then delete the node
if (Docker=nil) then begin if (Docker=nil) then begin
{$IFDEF VerboseAnchorDockCreateLayout}
DebugLn(['RemoveEmptyNodes delete unknown node: ',dbgs(Node)]); DebugLn(['RemoveEmptyNodes delete unknown node: ',dbgs(Node)]);
{$ENDIF}
DeleteNode(Node); DeleteNode(Node);
end end
else if not ControlIsVisible(Docker.Control) then begin else if not ControlIsVisible(Docker.Control) then begin
{$IFDEF VerboseAnchorDockCreateLayout}
DebugLn(['RemoveEmptyNodes delete invisible node: ',dbgs(Node)]); DebugLn(['RemoveEmptyNodes delete invisible node: ',dbgs(Node)]);
{$ENDIF}
DeleteNode(Node); DeleteNode(Node);
end; end;
end; end;
ldcntPage: ldcntPage:
// these are auto created parent node. If they have no childs: delete // these are auto created parent node. If they have no childs: delete
if Node.ChildCount=0 then begin if Node.ChildCount=0 then begin
{$IFDEF VerboseAnchorDockCreateLayout}
DebugLn(['RemoveEmptyNodes delete node without childs: ',dbgs(Node)]); DebugLn(['RemoveEmptyNodes delete node without childs: ',dbgs(Node)]);
{$ENDIF}
DeleteNode(Node); DeleteNode(Node);
end; end;
ldcntForm: ldcntForm:
// these are auto created parent node. If they have no childs: delete // these are auto created parent node. If they have no childs: delete
// if they have only one child: delete node and move childs up // if they have only one child: delete node and move childs up
if Node.ChildCount=0 then begin if Node.ChildCount=0 then begin
{$IFDEF VerboseAnchorDockCreateLayout}
DebugLn(['RemoveEmptyNodes delete node without childs: ',dbgs(Node)]); DebugLn(['RemoveEmptyNodes delete node without childs: ',dbgs(Node)]);
{$ENDIF}
DeleteNode(Node); DeleteNode(Node);
end else if Node.ChildCount=1 then begin end else if Node.ChildCount=1 then begin
// Only one child left // Only one child left
@ -1762,7 +1898,9 @@ var
// these are auto created parent node. If they have no childs: delete // these are auto created parent node. If they have no childs: delete
// if they have only one child: delete node and move child up // if they have only one child: delete node and move child up
if Node.ChildCount=0 then begin if Node.ChildCount=0 then begin
{$IFDEF VerboseAnchorDockCreateLayout}
DebugLn(['RemoveEmptyNodes delete node without childs: ',dbgs(Node)]); DebugLn(['RemoveEmptyNodes delete node without childs: ',dbgs(Node)]);
{$ENDIF}
DeleteNode(Node); DeleteNode(Node);
end else if Node.ChildCount=1 then begin end else if Node.ChildCount=1 then begin
// Only one child left // Only one child left
@ -1920,15 +2058,23 @@ begin
Root:=nil; Root:=nil;
Config:=GetConfigWithDockerName(DockerName); Config:=GetConfigWithDockerName(DockerName);
DebugLn(['TCustomLazDockingManager.CreateLayout DockerName="',DockerName,'"']); DebugLn(['TCustomLazDockingManager.CreateLayout DockerName="',DockerName,'"']);
config.WriteDebugReport; config.WriteDebugReport;
if (Config=nil) or (Config.Root=nil) then exit;
if (Config=nil) or (Config.Root=nil) then begin
DebugLn(['TCustomLazDockingManager.CreateLayout DockerName="',DockerName,'" No control']);
exit;
end;
CurControl:=FindControlByDockerName(DockerName); CurControl:=FindControlByDockerName(DockerName);
DebugLn(['TCustomLazDockingManager.CreateLayout CurControl=',DbgSName(CurControl)]); if not ControlIsVisible(CurControl) then begin
if not ControlIsVisible(CurControl) then exit; DebugLn(['TCustomLazDockingManager.CreateLayout DockerName="',DockerName,'" CurControl=',DbgSName(CurControl),' control not visible']);
DebugLn(['TCustomLazDockingManager.CreateLayout CurControl is treated as visible']); exit;
if (not ConfigIsCompatible(Config.Root,ExceptionOnError)) then exit; end;
DebugLn(['TCustomLazDockingManager.CreateLayout Config is compatible']); if (not ConfigIsCompatible(Config.Root,ExceptionOnError)) then begin
DebugLn(['TCustomLazDockingManager.CreateLayout DockerName="',DockerName,'" CurControl=',DbgSName(CurControl),' config is not compatible']);
exit;
end;
// create a copy of the config // create a copy of the config
Root:=TLazDockConfigNode.Create(nil); Root:=TLazDockConfigNode.Create(nil);
@ -1937,12 +2083,10 @@ begin
// clean up by removing all invisible, unknown and empty nodes // clean up by removing all invisible, unknown and empty nodes
RemoveEmptyNodes(Root); RemoveEmptyNodes(Root);
DebugLn(['TCustomLazDockingManager.CreateLayout After removing unneeded nodes:']);
Root.WriteDebugReport;
// check if all used controls are on the same dock form // check if all used controls are on the same dock form
if not AllControlsAreOnSameForm then begin if not AllControlsAreOnSameForm then begin
DebugLn(['TCustomLazDockingManager.CreateLayout not all Controls are on the same Form']); DebugLn(['TCustomLazDockingManager.CreateLayout Not all Controls are on the same Form. Using only one form...']);
// the used controls are distributed on different dock forms // the used controls are distributed on different dock forms
// => choose one dock form and remove the nodes of the others // => choose one dock form and remove the nodes of the others
NearestControlNode:=FindNearestControlNode; NearestControlNode:=FindNearestControlNode;
@ -1952,10 +2096,12 @@ begin
CurDockControl:=CurDockControl.GetTopParent; CurDockControl:=CurDockControl.GetTopParent;
// remove nodes of other dock forms // remove nodes of other dock forms
RemoveEmptyNodes(Root); RemoveEmptyNodes(Root);
DebugLn(['TCustomLazDockingManager.CreateLayout After removing nodes of other dock forms:']); //DebugLn(['TCustomLazDockingManager.CreateLayout After removing nodes of other dock forms:']);
Root.WriteDebugReport;
end; end;
DebugLn(['TCustomLazDockingManager.CreateLayout After removing unneeded nodes:']);
Root.WriteDebugReport;
Result:=Root; Result:=Root;
Root:=nil; Root:=nil;
finally finally

View File

@ -97,6 +97,8 @@ begin
DockGroupBox.Caption:='Dock to control'; DockGroupBox.Caption:='Dock to control';
DockControlLabel.Caption:='To control'; DockControlLabel.Caption:='To control';
CancelButton.Caption:='Cancel';
UpdateButtonEnabled; UpdateButtonEnabled;
end; end;