From 91ccba3b91223dea295b4179efde8dce99b2a5ec Mon Sep 17 00:00:00 2001 From: dodi Date: Sat, 21 Nov 2009 13:08:42 +0000 Subject: [PATCH] dockmanager example: restructure package git-svn-id: trunk@22697 - --- examples/dockmanager/elasticsite/MakeSite.lpi | 347 +++++++++--------- examples/dockmanager/elasticsite/MakeSite.lpr | 3 +- examples/dockmanager/package/easydockmgr.lpk | 18 +- examples/dockmanager/package/easydockmgr.pas | 2 +- examples/dockmanager/package/easydocksite.pas | 2 +- examples/dockmanager/package/umakesite.pas | 238 ++++++++---- 6 files changed, 354 insertions(+), 256 deletions(-) diff --git a/examples/dockmanager/elasticsite/MakeSite.lpi b/examples/dockmanager/elasticsite/MakeSite.lpi index 6bf6f8f600..8ec328b33f 100644 --- a/examples/dockmanager/elasticsite/MakeSite.lpi +++ b/examples/dockmanager/elasticsite/MakeSite.lpi @@ -8,7 +8,7 @@ - + @@ -40,7 +40,7 @@ - + @@ -48,29 +48,31 @@ - - + + - + - - - + + - + + + + - - + + - + @@ -78,7 +80,7 @@ - + @@ -88,13 +90,15 @@ - + - - - + + + + + @@ -106,34 +110,34 @@ - + - + - + - + - + - + @@ -145,41 +149,41 @@ - + - - + + - + - + - + - + @@ -187,10 +191,10 @@ - - + + - + @@ -202,10 +206,7 @@ - - - - + @@ -214,7 +215,7 @@ - + @@ -224,7 +225,7 @@ - + @@ -233,66 +234,68 @@ - + - + - + - - - + + + + + - - - - + + + + - - + + - + - - + + - - + + - - + + @@ -300,130 +303,130 @@ - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/dockmanager/elasticsite/MakeSite.lpr b/examples/dockmanager/elasticsite/MakeSite.lpr index 4add407ce7..12b26c8764 100644 --- a/examples/dockmanager/elasticsite/MakeSite.lpr +++ b/examples/dockmanager/elasticsite/MakeSite.lpr @@ -7,8 +7,7 @@ uses cthreads, {$ENDIF}{$ENDIF} Interfaces, // this includes the LCL widgetset - Forms, fMasterSite, fclientform, EasyDockMgr, LResources, uMakeSite - { you can add units after this }; + Forms, fMasterSite, fclientform, EasyDockMgr, LResources; {$IFDEF WINDOWS}{$R MakeSite.rc}{$ENDIF} diff --git a/examples/dockmanager/package/easydockmgr.lpk b/examples/dockmanager/package/easydockmgr.lpk index 256632a2ee..a4b360d2da 100644 --- a/examples/dockmanager/package/easydockmgr.lpk +++ b/examples/dockmanager/package/easydockmgr.lpk @@ -17,7 +17,7 @@ - + @@ -55,6 +55,22 @@ + + + + + + + + + + + + + + + + diff --git a/examples/dockmanager/package/easydockmgr.pas b/examples/dockmanager/package/easydockmgr.pas index 3c0e456fa4..187111fa5b 100644 --- a/examples/dockmanager/package/easydockmgr.pas +++ b/examples/dockmanager/package/easydockmgr.pas @@ -8,7 +8,7 @@ interface uses EasyDockSite, fDockBook, fFloatingSite, fElasticSite, uMiniRestore, - LazarusPackageIntf; + fPageFrame, uMakeSite, LazarusPackageIntf; implementation diff --git a/examples/dockmanager/package/easydocksite.pas b/examples/dockmanager/package/easydocksite.pas index 51552700de..e80a7019ee 100644 --- a/examples/dockmanager/package/easydocksite.pas +++ b/examples/dockmanager/package/easydocksite.pas @@ -58,7 +58,7 @@ LCL TODO: //depending on widgetset or patched LCL {.$DEFINE NoDrop} //applied DoDiPatch1? -{.$DEFINE PageFrame} //problem: notebook frame cannot Release itself +{$DEFINE PageFrame} //problem: notebook frame cannot Release itself {$DEFINE replace} //using ReplaceDockedControl? interface diff --git a/examples/dockmanager/package/umakesite.pas b/examples/dockmanager/package/umakesite.pas index 18fe67c958..fc9b2559ab 100644 --- a/examples/dockmanager/package/umakesite.pas +++ b/examples/dockmanager/package/umakesite.pas @@ -1,11 +1,27 @@ unit uMakeSite; +(* Create elastic dock sites within a form, make forms dockable. + +Problems: + +Forms are not (easily) dockable on all platforms, + we add a grabber icon to each dockable form, + and wrap them in a managed floating form. + +Default floating sites are owned by Application, + we have to create the floating sites in the form.OnEndDock event. + + Owning panels is dangerous, they are not destroyed with their parent form! +*) {$mode objfpc}{$H+} +{$DEFINE ownSites} //floating sites owned by TDockMaster? + interface uses - Classes, SysUtils, Controls, Forms, ExtCtrls, EasyDockSite; + Classes, SysUtils, Controls, Forms, ExtCtrls, EasyDockSite, + fFloatingSite; type sDockSides = TAlignSet; @@ -25,13 +41,15 @@ type public end; -//the owner of all docksites +//the owner of all docksites (if ownSites is defined) TDockMaster = class(TComponent) protected //event handlers procedure DockHandleMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure FormEndDock(Sender, Target: TObject; X, Y: Integer); + function WrapDockable(Client: TControl): TFloatingSite; public + Factory: TComponent; //generic owner procedure AddElasticSites(AForm: TCustomForm; Sides: sDockSides); function CreateDockable(const AName: string; fMultiInst: boolean): TForm; procedure DumpSites; @@ -40,9 +58,19 @@ type implementation uses - LCLIntf, LCLProc, + LCLIntf, LCLProc; //fMasterSite, - fFloatingSite; + +type + TWinControlAccess = class(TWinControl) + end; + +const + PanelNames: array[TAlign] of string = ( + '', '', //alNone, alTop, + 'pnlBottom', 'pnlLeft', 'pnlRight', + '', '' //alClient, alCustom + ); { TDockMaster } @@ -57,30 +85,41 @@ const begin for side := low(side) to high(side) do begin if (side in AllowedSides) and (side in Sides) then begin - //create the components - pnl := TDockPanel.Create(self); //owned by? - pnl.Parent := AForm; - pnl.Align := side; - pnl.BorderWidth := 1; - pnl.BorderStyle := bsSingle; // does not properly handle the size - dm := TEasyTree.Create(pnl); - dm.SetStyle(hsForm); - pnl.DockSite := True; - pnl.UseDockManager := True; - pnl.Visible := True; - spl := TSplitter.Create(AForm); - spl.Parent := AForm; - spl.Align := side; - //size components - pnl.Splitter := spl; - if side in [alLeft,alRight] then - pnl.Width := 0 - else - pnl.Height := 0; - pnl.OnDockDrop := @pnl.pnlDockDrop; - pnl.OnDockOver := @pnl.pnlDockOver; - pnl.OnUnDock := @pnl.pnlUnDock; - pnl.OnGetSiteInfo := @pnl.pnlGetSiteInfo; + //TWinControlAccess(AForm).ReloadDockedControl(PanelNames[side], pnl); + TComponent(pnl) := AForm.FindComponent(PanelNames[side]); + if pnl = nil then begin + //create the components + {$IFDEF ownSites} + pnl := TDockPanel.Create(self); //owned by? + {$ELSE} + pnl := TDockPanel.Create(AForm); //owned by? + {$ENDIF} + pnl.Name := PanelNames[side]; + pnl.Parent := AForm; + pnl.Align := side; + pnl.BorderWidth := 1; + pnl.BorderStyle := bsSingle; // does not properly handle the size + dm := TEasyTree.Create(pnl); + dm.SetStyle(hsForm); + pnl.DockSite := True; + pnl.UseDockManager := True; + pnl.Visible := True; + spl := TSplitter.Create(AForm); + spl.Parent := AForm; + spl.Align := side; + spl.BorderStyle := bsSingle; + //size components + pnl.Splitter := spl; + if side in [alLeft,alRight] then + pnl.Width := 0 + else + pnl.Height := 0; + //handlers required for elastic sites + pnl.OnDockDrop := @pnl.pnlDockDrop; + pnl.OnDockOver := @pnl.pnlDockOver; + pnl.OnUnDock := @pnl.pnlUnDock; + pnl.OnGetSiteInfo := @pnl.pnlGetSiteInfo; + end; end; end; end; @@ -94,6 +133,7 @@ var img: TImage; r: TRect; Site: TFloatingSite; + ctl: TControl; const digits = ['0'..'9']; begin @@ -128,12 +168,20 @@ begin instno := 1; //default instance number for forms //lookup existing instance instname := basename + IntToStr(instno); + {$IFDEF old} + if false then + TWinControlAccess(Site).ReloadDockedControl(instname, ctl); //Result := nil; for i := 0 to ComponentCount - 1 do begin Result := TForm(Components[i]); if Result.Name = instname then exit; //found it end; + {$ELSE} + //Factory.ReloadDockedControl + {$ENDIF} + if FindComponent(instname) <> nil then + exit; //create new instance basename := 'T' + basename; fc := TFormClass(GetClass(basename)); //must be registered class name! @@ -148,20 +196,7 @@ begin Result.DragKind := dkDock; Result.OnEndDock := @FormEndDock; //float into default host site //wrap into dock site - Site := TFloatingSite.Create(self); - Site.BoundsRect := Result.BoundsRect; - Result.Align := alClient; - Result.Visible := True; //otherwise docking may be rejected - Result.ManualDock(Site); - { - //Result.ManualDock(nil); - //Result.ManualFloat(Result.BoundsRect, False); - //TObject(Site) := Result.HostDockSite; - if Site = nil then begin - DebugLn('View not docked --------------'); - exit; - end; - } + Site := WrapDockable(Result); //create a docking handle - should become a component? img := TImage.Create(Result); img.Parent := Result; @@ -179,6 +214,41 @@ begin //Result.OnEndDock(); end; +procedure TDockMaster.FormEndDock(Sender, Target: TObject; X, Y: Integer); +var + ctl: TControl; + Site: TFloatingSite; +begin +(* Handler for Form.OnEndDock. + When a form becomes floating, dock immediately into a new floating host docksite. +*) + if Target <> nil then + exit; //docked, not floating + ctl := Sender as TControl; + if ctl.HostDockSite = nil then begin + //DebugLn('--- floating'); + WrapDockable(ctl); + end else begin + //DebugLn('--- in ' + HostDockSite.Name); + end; +end; + +function TDockMaster.WrapDockable(Client: TControl): TFloatingSite; +var + Site: TForm absolute Result; +begin + {$IFDEF ownSites} + Site := TFloatingSite.Create(Self); //the new site + {$ELSE} + Site := TFloatingSite.Create(Application); //the new site + {$ENDIF} + Site.BoundsRect := Client.BoundsRect; //the new position and extension + Client.Align := alClient; + Client.Visible := True; //otherwise docking may be rejected + Client.ManualDock(Site); + //Site.DockManager.ResetBounds(True); //does not work on first attempt? +end; + procedure TDockMaster.DockHandleMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var @@ -200,6 +270,7 @@ var ctl: TControl; cmp: TComponent; n, s: string; + hds: boolean; const OrientString: array[TDockOrientation] of char = ( 'N','H','V' {$IFDEF FPC} ,'P' {$ENDIF} @@ -208,6 +279,16 @@ const //(alNone, alTop, alBottom, alLeft, alRight, alClient, alCustom); 'n', 't', 'B', 'L', 'R', 'C', 'c' ); + + function SiteName(ph: TControl): string; + begin + if ph = nil then + exit(''); + Result := ph.Name; + if Result = '' then + Result := '<' + ph.ClassName + '>'; + end; + begin (* Dump registered docking sites. Elastic panels have no name. @@ -219,53 +300,52 @@ begin dock sites[] and clients[] contents[] *) + DebugLn('--- dump sites ---'); for i := 0 to ComponentCount - 1 do begin cmp := Components[i]; if cmp is TWinControl then begin + //path Site := TWinControl(cmp); - if Site.Parent <> nil then begin - s := Site.Parent.Name; - if s = '' then - s := Site.Parent.ClassName; - s := ' in ' + s + '@'; - s := s + AlignString[Site.Align]; - end else - s := ''; - DebugLn('Site=%s (%d,%d)[%d,%d] %s', [Site.Name, - site.Top, site.Left, site.Width, site.Height, s]); - for j := 0 to site.DockClientCount - 1 do begin - ctl := site.DockClients[j]; - s := OrientString[ctl.DockOrientation]; - DebugLn(' Client=%s@%s (%d,%d)[%d,%d]', [ctl.Name, s, - ctl.Top, ctl.Left, ctl.Width, ctl.Height]); + if Site.DockSite then begin + //reached only when ownSites is defined! + ctl := Site; + s := Format('Site=%s (%d,%d)[%d,%d]', [SiteName(ctl), + ctl.Left, ctl.Top, ctl.Width, ctl.Height]); + while ctl <> nil do begin + hds := ctl.HostDockSite <> nil; + if hds then begin + Site := ctl.HostDockSite; + if Site <> nil then + n := ' in ' + SiteName(Site) + '@' + OrientString[ctl.DockOrientation]; + end else begin + Site := ctl.Parent; + if Site <> nil then + n := ' at ' + SiteName(Site) + '@' + AlignString[ctl.Align]; + end; + if Site = nil then + break; + s := s + n; + ctl := Site; + end; + DebugLn(s); + //clients + Site := TWinControl(cmp); + for j := 0 to site.DockClientCount - 1 do begin + ctl := site.DockClients[j]; + s := OrientString[ctl.DockOrientation]; + DebugLn(' Client=%s@%s (%d,%d)[%d,%d]', [SiteName(ctl), s, + ctl.Left, ctl.Top, ctl.Width, ctl.Height]); + end; + end else begin + ctl := Site; + DebugLn('Client=%s in %s (%d,%d)[%d,%d]', [SiteName(ctl), SiteName(ctl.HostDockSite), + ctl.Left, ctl.Top, ctl.Width, ctl.Height]); end; end; end; DebugLn('--- end dump ---'); end; -procedure TDockMaster.FormEndDock(Sender, Target: TObject; X, Y: Integer); -var - ctl: TControl; - Site: TFloatingSite; -begin -(* Handler for Form.OnEndDock. - When a form becomes floating, dock immediately into a new floating host docksite. -*) - if Target <> nil then - exit; //docked, not floating - ctl := Sender as TControl; - if ctl.HostDockSite = nil then begin - //DebugLn('--- floating'); - Site := TFloatingSite.Create(Application); //the new site - Site.BoundsRect := ctl.BoundsRect; //the new position and extension - ctl.ManualDock(Site); - //Site.DockManager.ResetBounds(True); //does not work on first attempt? - end else begin - //DebugLn('--- in ' + HostDockSite.Name); - end; -end; - { TDockPanel }