LCL: TLazDockTree: implemented RemoveControl, refactored: TDragManager ancestor to TComponent, fixed undocking

git-svn-id: trunk@13673 -
This commit is contained in:
mattias 2008-01-08 23:38:14 +00:00
parent 3d7ced274c
commit 0da528ffe8
7 changed files with 150 additions and 111 deletions

View File

@ -408,7 +408,7 @@ type
{ TDragManager }
TDragManager = class(TPersistent)
TDragManager = class(TComponent)
private
FDragImmediate: Boolean;
FDragThreshold: Integer;
@ -421,7 +421,7 @@ type
procedure MouseUp(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); virtual;abstract;
procedure MouseDown(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); virtual;abstract;
public
constructor Create; virtual;
constructor Create(TheOwner: TComponent); override;
function IsDragging: boolean; virtual;abstract;
function Dragging(AControl: TControl): boolean; virtual;abstract;
@ -1893,6 +1893,7 @@ type
procedure ReplaceChild(OldChild, NewChild: TDockZone);
function GetLastChild: TDockZone;
function GetIndex: Integer;
procedure Remove(ChildZone: TDockZone);
public
property ChildControl: TControl read FChildControl;
property ChildCount: Integer read FChildCount;
@ -2019,6 +2020,7 @@ type
FRootZone: TDockZone;
FUpdateCount: Integer;
procedure DeleteZone(Zone: TDockZone);
procedure SetDockSite(const AValue: TWinControl);
protected
procedure AdjustDockRect(AControl: TControl; var ARect: TRect); virtual;
function HitTest(const MousePos: TPoint; var HTFlag: Integer): TControl; virtual;
@ -2045,7 +2047,7 @@ type
procedure PaintSite(DC: HDC); override;
public
property DockZoneClass: TDockZoneClass read FDockZoneClass;
property DockSite: TWinControl read FDockSite write FDockSite;
property DockSite: TWinControl read FDockSite write SetDockSite;
property RootZone: TDockZone read FRootZone;
end;
@ -3297,8 +3299,9 @@ end;
{ TDragManager }
constructor TDragManager.Create;
constructor TDragManager.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
FDragImmediate := true;
FDragThreshold := 5;
end;
@ -3307,7 +3310,7 @@ initialization
//DebugLn('controls.pp - initialization');
Mouse := TMouse.Create;
DefaultDockTreeClass := TDockTree;
DragManager := TDragManagerDefault.Create;
DragManager := TDragManagerDefault.Create(nil);
RegisterIntegerConsts(TypeInfo(TCursor), @IdentToCursor, @CursorToIdent);
finalization

View File

@ -2116,7 +2116,7 @@ var
AControl: TControl;
begin
AControl:=TheAnchorSide.Owner;
//debugln('TControl.ForeignAnchorSideChanged A ',DbgSName(TheAnchorSide.Owner),' Operation=',dbgs(ord(Operation)),' Anchor=',dbgs(ord(TheAnchorSide.Kind)));
//debugln('TControl.ForeignAnchorSideChanged A Self=',DbgSName(Self),' TheAnchorSide.Owner=',DbgSName(TheAnchorSide.Owner),' Operation=',dbgs(ord(Operation)),' Anchor=',dbgs(TheAnchorSide.Kind));
if TheAnchorSide.Control=Self then begin
if fAnchoredControls=nil then
fAnchoredControls:=TFPList.Create;

View File

@ -38,6 +38,12 @@ begin
Zone.Free; // destroy zone itself
end;
procedure TDockTree.SetDockSite(const AValue: TWinControl);
begin
//DebugLn(['TDockTree.SetDockSite ',DbgSName(AValue)]);
FDockSite:=AValue;
end;
procedure TDockTree.SetDockZoneClass(const AValue: TDockZoneClass);
begin
FDockZoneClass := AValue;
@ -132,11 +138,9 @@ constructor TDockTree.Create(TheDockSite: TWinControl);
begin
if FDockZoneClass = nil then
FDockZoneClass := TDockZone;
FDockSite := TheDockSite;
DockSite := TheDockSite;
inherited Create;
FBorderWidth := 4;
//FGrabberSize := DefaultDockGrabberSize;
//FGrabbersOnTop:=(FDockSite.Align <> alTop) and (FDockSite.Align <> alBottom);
FRootZone := FDockZoneClass.Create(Self, TheDockSite);
end;

View File

@ -260,4 +260,19 @@ begin
end;
end;
procedure TDockZone.Remove(ChildZone: TDockZone);
begin
if ChildZone.Parent<>Self then
raise Exception.Create('TDockZone.Remove');
if ChildZone=FFirstChildZone then FFirstChildZone:=ChildZone.FNextSibling;
if ChildZone.FNextSibling<>nil then
ChildZone.FNextSibling.FPrevSibling:=ChildZone.FPrevSibling;
if ChildZone.FPrevSibling<>nil then
ChildZone.FPrevSibling.FNextSibling:=ChildZone.FNextSibling;
ChildZone.FPrevSibling:=nil;
ChildZone.FNextSibling:=nil;
ChildZone.FParentZone:=nil;
dec(FChildCount);
end;
// included by control.pp

View File

@ -89,8 +89,9 @@ type
procedure CaptureChanged(OldCaptureControl: TControl); override;
procedure MouseUp(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override;
procedure MouseDown(Button: TMouseButton; Shift:TShiftState; X,Y:Integer); override;
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
constructor Create; override;
constructor Create(TheOwner: TComponent); override;
destructor Destroy; override;
//Support methods
@ -386,7 +387,7 @@ procedure TDockPerformer.DragMove(APosition: TPoint);
//Sanity checks..
if not AControl.Showing then continue;
if not AControl.Enabled then continue;
if not AControl.Visible then continue;
if not AControl.IsVisible then continue;
if AControl=FDockObject.Control then continue;
if IsControlChildOfClient(AControl) then continue;
@ -638,10 +639,13 @@ begin
begin
if FDockSites = nil then
FDockSites := TFPList.Create;
if DoRegister then
FDockSites.Add(Site)
else
FDockSites.Remove(Site)
if DoRegister then begin
FDockSites.Add(Site);
Site.FreeNotification(Self);
end else begin
FDockSites.Remove(Site);
Site.RemoveFreeNotification(Self);
end;
end;
end;
@ -667,9 +671,22 @@ begin
//DragStop(true);
end;
constructor TDragManagerDefault.Create;
procedure TDragManagerDefault.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Create;
inherited Notification(AComponent, Operation);
if Operation=opRemove then begin
if FDockSites<>nil then begin
FDockSites.Remove(AComponent);
if FDockSites.Count=0 then
FreeAndNil(FDockSites);
end;
end;
end;
constructor TDragManagerDefault.Create(TheOwner: TComponent);
begin
inherited Create(TheOwner);
FInDragStop := False;
end;

View File

@ -4496,7 +4496,6 @@ begin
if not PtInRect(ClientBounds,Pos) then begin
//debugln(['TWinControl.ControlAtPos OUT OF CLIENTBOUNDS ',DbgSName(Self),' P=',dbgs(Pos),' ClientBounds=',dbgs(ClientBounds)]);
//DumpStack;
Result:=nil;
exit;
end;
@ -4706,10 +4705,12 @@ end;
{------------------------------------------------------------------------------
procedure TWinControl.DoAddDockClient(Client: TControl; const ARect: TRect);
Default method for adding a dock client. Just become the new parent.
Default method for adding a dock client. Become the new parent and break
old anchored controls.
------------------------------------------------------------------------------}
procedure TWinControl.DoAddDockClient(Client: TControl; const ARect: TRect);
begin
//DebugLn(['TWinControl.DoAddDockClient ',DbgSName(Self),' Client=',DbgSName(Client),' OldParent=',DbgSName(Client.Parent),' Client.AnchoredControlCount=',Client.AnchoredControlCount]);
Client.Parent := Self;
end;
@ -4746,6 +4747,7 @@ end;
procedure TWinControl.DoRemoveDockClient(Client: TControl);
begin
// empty (this method exists for descendent overrides)
DebugLn(['TWinControl.DoRemoveDockClient ',DbgSName(Self),' ',DbgSName(Client)]);
end;
{------------------------------------------------------------------------------
@ -4819,6 +4821,7 @@ end;
function TWinControl.CreateDockManager: TDockManager;
begin
if (FDockManager = nil) and DockSite and UseDockManager then
// this control can dock other controls, so it needs a TDockManager
Result := DefaultDockTreeClass.Create(Self)
else
Result := FDockManager;
@ -6864,66 +6867,9 @@ end;
property, which defines how to align DockObject.Control.
------------------------------------------------------------------------------}
procedure TWinControl.DockDrop(DragDockObject: TDragDockObject; X, Y: Integer);
{var
DestRect: TRect;
//ParentForm: TCustomForm;
MappedLeftTop: TPoint;
NewBounds: TRect;}
begin
if DoDockClientMsg(DragDockObject, Point(X, Y)) and Assigned(FOnDockDrop) then
FOnDockDrop(Self, DragDockObject, X, Y);
// get dock destination rectangle and map it to the client area
{DestRect := DockObject.DockRect;
MappedLeftTop:=ScreenToClient(DestRect.TopLeft);
OffsetRect(DestRect,
DestRect.Left-MappedLeftTop.X,DestRect.Top-MappedLeftTop.Y);
DebugLn('TWinControl.DockDrop A ',Name,' DockControl=',DbgSName(DockObject.Control),' DestRect=',dbgs(DestRect));
DisableAlign;
try
if (not UseDockManager) or (DockManager=nil) then begin
// Delphi ignores the DropAlign when no DockManager is available
// Why that?
DockObject.Control.Align:=DockObject.DropAlign;
if DockObject.IncreaseDockArea then begin
NewBounds := BoundsRect;
case DockObject.DropAlign of
alLeft:
dec(NewBounds.Left,DockObject.Control.Width);
alTop:
dec(NewBounds.Top,DockObject.Control.Height);
alRight:
inc(NewBounds.Right,DockObject.Control.Width);
alBottom:
inc(NewBounds.Bottom,DockObject.Control.Height);
end;
if NewBounds.Left<0 then
NewBounds.Left:=0;
if NewBounds.Top<0 then
NewBounds.Top:=0;
if NewBounds.Right>Screen.Width then
NewBounds.Right:=Screen.Width;
if NewBounds.Bottom>Screen.Height then
NewBounds.Bottom:=Screen.Height;
debugln('TWinControl.DockDrop IncreaseDockArea ',DbgSName(Self),' ',dbgs(NewBounds));
SetBoundsKeepBase(NewBounds.Left,NewBounds.Top,
NewBounds.Right-NewBounds.Left,
NewBounds.Bottom-NewBounds.Top);
end;
end;
DockObject.Control.Dock(Self, DestRect);
if UseDockManager and (DockManager <> nil) then
DockManager.InsertControl(DockObject.Control,
DockObject.DropAlign, DockObject.DropOnControl);
finally
EnableAlign;
end;
//ParentForm := GetParentForm(Self);
//if ParentForm<>nil then ParentForm.BringToFront;
if Assigned(FOnDockDrop) then
FOnDockDrop(Self, DockObject, X, Y);}
end;
{------------------------------------------------------------------------------
@ -6973,6 +6919,8 @@ end;
{------------------------------------------------------------------------------
procedure TWinControl.SetDockSite(const NewDockSite: Boolean);
If NewDockSite=true it means, this control can dock other controls.
------------------------------------------------------------------------------}
procedure TWinControl.SetDockSite(const NewDockSite: Boolean);
begin
@ -6999,7 +6947,6 @@ var
begin
with DragDockObject do begin
DestRect := DockRect;
//MapWindowPoints(0, Handle, DestRect, 2);?
DisableAlign;
try
DragDockObject.Control.Dock(Self, DestRect);

View File

@ -74,6 +74,7 @@ type
destructor Destroy; override;
procedure InsertControl(AControl: TControl; InsertAt: TAlign;
DropControl: TControl); override;
procedure RemoveControl(AControl: TControl); override;
procedure BuildDockLayout(Zone: TLazDockZone);
procedure FindBorderControls(Zone: TLazDockZone; Side: TAnchorKind;
var List: TFPList);
@ -583,23 +584,35 @@ end;
procedure TLazDockTree.UndockControlForDocking(AControl: TControl);
var
AWinControl: TWinControl;
Sibling: TControl;
a: TAnchorKind;
i: Integer;
begin
DebugLn(['TLazDockTree.UndockControlForDocking AControl=',DbgSName(AControl),' AControl.Parent=',DbgSName(AControl.Parent)]);
// undock AControl
if AControl is TWinControl then begin
AWinControl:=TWinControl(AControl);
if AWinControl.DockManager<>nil then begin
// TODO
// anything to do here?
end;
end;
if AControl.Parent<>nil then begin
AControl.Parent:=nil;
end;
for i:=AControl.AnchoredControlCount-1 downto 0 do begin
Sibling:=AControl.AnchoredControls[i];
if (Sibling<>AControl.Parent) and (Sibling.Parent<>AControl) then begin
for a:=low(TAnchorKind) to high(TAnchorKind) do
if Sibling.AnchorSide[a].Control=AControl then
Sibling.AnchorSide[a].Control:=nil;
end;
end;
end;
procedure TLazDockTree.BreakAnchors(Zone: TDockZone);
begin
if Zone=nil then exit;
if Zone.ChildControl<>nil then begin
if (Zone.ChildControl<>nil) and (Zone.ChildControl<>DockSite) then begin
Zone.ChildControl.AnchorSide[akLeft].Control:=nil;
Zone.ChildControl.AnchorSide[akTop].Control:=nil;
Zone.ChildControl.Anchors:=[akLeft,akTop];
@ -753,39 +766,52 @@ var
a: TAnchorKind;
SplitterSide: TAnchorKind;
CurControl: TControl;
NewSplitterAnchors: TAnchors;
NewAnchors: TAnchors;
begin
if Zone=nil then exit;
// get outside anchor controls
for a:=Low(TAnchorKind) to High(TAnchorKind) do
AnchorControls[a]:=GetAnchorControl(Zone,a,true);
// anchor splitter
if (Zone.Splitter<>nil) then begin
if Zone.Parent.Orientation=doHorizontal then
SplitterSide:=akLeft
else
SplitterSide:=akTop;
// IMPORTANT: first set the AnchorSide, then set the Anchors
NewAnchors:=[akLeft,akRight,akTop,akBottom]-[SplitterSide];
for a:=Low(TAnchorKind) to High(TAnchorKind) do
if a in NewAnchors then
Zone.Splitter.AnchorSide[a].Control:=AnchorControls[a];
Zone.Splitter.Anchors:=NewAnchors;
AnchorControls[SplitterSide]:=Zone.Splitter;
end;
// anchor pages
if Zone.Pages<>nil then
CurControl:=Zone.Pages
else
CurControl:=Zone.ChildControl;
if CurControl<>nil then begin
// IMPORTANT: first set the AnchorSide, then set the Anchors
//DebugLn(['TLazDockTree.AnchorDockLayout CurControl=',DbgSName(CurControl),' DockSite=',DbgSName(DockSite)]);
if (CurControl<>nil) and (CurControl<>DockSite) then begin
// get outside anchor controls
NewAnchors:=[akLeft,akRight,akTop,akBottom];
for a:=Low(TAnchorKind) to High(TAnchorKind) do
AnchorControls[a]:=GetAnchorControl(Zone,a,true);
// anchor splitter
if (Zone.Splitter<>nil) then begin
if Zone.Parent.Orientation=doHorizontal then
SplitterSide:=akLeft
else
SplitterSide:=akTop;
// IMPORTANT: first set the AnchorSide, then set the Anchors
NewSplitterAnchors:=[akLeft,akRight,akTop,akBottom]-[SplitterSide];
for a:=Low(TAnchorKind) to High(TAnchorKind) do
if a in NewSplitterAnchors then
Zone.Splitter.AnchorSide[a].Control:=AnchorControls[a]
else
Zone.Splitter.AnchorSide[a].Control:=nil;
Zone.Splitter.Anchors:=NewSplitterAnchors;
AnchorControls[SplitterSide]:=Zone.Splitter;
end;
// anchor pages
// IMPORTANT: first set the AnchorSide, then set the Anchors
//DebugLn(['TLazDockTree.AnchorDockLayout CurControl.Parent=',DbgSName(CurControl.Parent),' ',CurControl.Visible]);
for a:=Low(TAnchorKind) to High(TAnchorKind) do begin
CurControl.AnchorSide[a].Control:=AnchorControls[a];
CurControl.Anchors:=[akLeft,akRight,akTop,akBottom];
if (AnchorControls[a]<>nil)
and (AnchorControls[a].Parent=CurControl.Parent) then begin
CurControl.AnchorSide[a].Side:=DefaultSideForAnchorKind[a];
end else begin
CurControl.AnchorSide[a].Side:=DefaultSideForAnchorKind[OppositeAnchor[a]];
end;
end;
CurControl.Anchors:=NewAnchors;
end;
// anchor controls for childs and siblings
@ -861,11 +887,13 @@ procedure TLazDockTree.InsertControl(AControl: TControl; InsertAt: TAlign;
}
procedure PrepareControlForResize(AControl: TControl); inline;
var
a: TAnchorKind;
begin
AControl.Align := alNone;
AControl.Anchors := [akLeft, akTop];
AControl.AnchorSide[akLeft].Control := nil;
AControl.AnchorSide[akTop].Control := nil;
for a:=Low(TAnchorKind) to High(TAnchorKind) do
AControl.AnchorSide[a].Control := nil;
AControl.AutoSize := False;
end;
@ -996,17 +1024,42 @@ begin
end;
AControl.DockOrientation := NewOrientation;
AControl.Parent := NewZone.GetParentControl;
// Build dock layout (anchors, splitters, pages)
BuildDockLayout(RootZone as TLazDockZone);
end;
// Build dock layout (anchors, splitters, pages)
BuildDockLayout(RootZone as TLazDockZone);
end;
procedure TLazDockTree.RemoveControl(AControl: TControl);
var
RemoveZone: TLazDockZone;
begin
RemoveZone:=RootZone.FindZone(AControl) as TLazDockZone;
if RemoveZone.ChildCount>0 then
raise Exception.Create('TLazDockTree.RemoveControl RemoveZone.ChildCount>0');
FreeAndNil(RemoveZone.Splitter);
FreeAndNil(RemoveZone.Page);
FreeAndNil(RemoveZone.Pages);
if RemoveZone.Parent<>nil then
RemoveZone.Parent.Remove(RemoveZone);
RemoveZone.Free;
// Build dock layout (anchors, splitters, pages)
BuildDockLayout(RootZone as TLazDockZone);
end;
procedure TLazDockTree.BuildDockLayout(Zone: TLazDockZone);
begin
BreakAnchors(Zone);
CreateDockLayoutHelperControls(Zone);
AnchorDockLayout(Zone);
if DockSite<>nil then
DockSite.DisableAlign;
try
BreakAnchors(Zone);
CreateDockLayoutHelperControls(Zone);
AnchorDockLayout(Zone);
finally
if DockSite<>nil then
DockSite.EnableAlign;
end;
end;
procedure TLazDockTree.FindBorderControls(Zone: TLazDockZone; Side: TAnchorKind;
@ -1102,7 +1155,7 @@ begin
end;
end;
// search the neigbour zones:
// search the neighbour zones:
Result:=DockSite;
if (Zone.Parent=nil) then exit;
case Zone.Parent.Orientation of