mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-18 08:19:29 +02:00
dockmanager example: improved streaming interface
git-svn-id: trunk@25039 -
This commit is contained in:
parent
c4206d5f9a
commit
eab9a88328
@ -16,11 +16,9 @@ Possible extensions:
|
|||||||
- separate docking management and dock site layout
|
- separate docking management and dock site layout
|
||||||
+ various dock headers
|
+ various dock headers
|
||||||
- multiple splitters (on zones without controls)
|
- multiple splitters (on zones without controls)
|
||||||
+ persistence (requires application wide management of dock sources!)
|
+ persistence (requires application-wide management of dock sources!)
|
||||||
- purpose of Restore button?
|
- purpose of Restore button?
|
||||||
|
- purpose of Close button? (currently: undock)
|
||||||
Known bugs:
|
|
||||||
+ Problem with dragging header, seems to interfere with dragmanager (capture)?
|
|
||||||
|
|
||||||
More issues, concerning the rest of the LCL (mainly unit Controls):
|
More issues, concerning the rest of the LCL (mainly unit Controls):
|
||||||
|
|
||||||
@ -53,7 +51,7 @@ LCL TODO:
|
|||||||
|
|
||||||
{$mode objfpc}{$H+}
|
{$mode objfpc}{$H+}
|
||||||
|
|
||||||
{$DEFINE ctlType} //save <name>:<classname>
|
{$DEFINE ctlType} //save <name>:<classname>=<caption>
|
||||||
{$DEFINE RootDock} //allow docking into the root zone?
|
{$DEFINE RootDock} //allow docking into the root zone?
|
||||||
//{$DEFINE newSplitter} //exclude splitter from remaining zone
|
//{$DEFINE newSplitter} //exclude splitter from remaining zone
|
||||||
{.$DEFINE handle_existing} //dock controls existing in the dock site?
|
{.$DEFINE handle_existing} //dock controls existing in the dock site?
|
||||||
@ -276,22 +274,26 @@ type
|
|||||||
1) TCustomDockSite (notebooks...)
|
1) TCustomDockSite (notebooks...)
|
||||||
2) AppLoadStore
|
2) AppLoadStore
|
||||||
3) OnSave/Reload
|
3) OnSave/Reload
|
||||||
4) default (Delphi) compatible handling.
|
4) Owner of DockMaster (Application)
|
||||||
|
5) default (Delphi) compatible handling.
|
||||||
|
|
||||||
Customization is provided by OnSave/Restore handlers.
|
Customization is provided by OnSave/Restore handlers.
|
||||||
Further customization is feasable using the AppLoadStore variable (below).
|
Further customization is feasable using the AppLoadStore variable (below).
|
||||||
|
At the time of an call, DockLoader contains the full control description
|
||||||
|
(ControlDescriptor)
|
||||||
|
|
||||||
The DockLoader variable is initialized to a default TCustomDockMaster instance,
|
The DockLoader variable is initialized to a default TCustomDockMaster instance,
|
||||||
but can be overridden by the application. This variable is not free'd.
|
owned by Application. It can be overridden by the application.
|
||||||
uMakeSite.DockMaster represents the full interface.
|
uMakeSite.DockMaster represents the full interface.
|
||||||
*)
|
*)
|
||||||
RControl = record
|
RControlDescriptor = record
|
||||||
|
Ctrl: TControl;
|
||||||
Name, ClassName, Caption: string;
|
Name, ClassName, Caption: string;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TCustomDockMaster = class(TComponent)
|
TCustomDockMaster = class(TComponent)
|
||||||
protected
|
protected
|
||||||
rc: RControl;
|
rc: RControlDescriptor;
|
||||||
FOnSave: TOnSaveControl;
|
FOnSave: TOnSaveControl;
|
||||||
FOnRestore: TOnReloadControl;
|
FOnRestore: TOnReloadControl;
|
||||||
procedure CtlToRec(ctl: TControl);
|
procedure CtlToRec(ctl: TControl);
|
||||||
@ -303,6 +305,7 @@ type
|
|||||||
function ReloadControl(const AName: string; Site: TWinControl): TControl; virtual;
|
function ReloadControl(const AName: string; Site: TWinControl): TControl; virtual;
|
||||||
property OnSave: TOnSaveControl read FOnSave write FOnSave;
|
property OnSave: TOnSaveControl read FOnSave write FOnSave;
|
||||||
property OnRestore: TOnReloadControl read FOnRestore write FOnRestore;
|
property OnRestore: TOnReloadControl read FOnRestore write FOnRestore;
|
||||||
|
property ControlDescriptor: RControlDescriptor read rc;
|
||||||
end;
|
end;
|
||||||
var
|
var
|
||||||
DockLoader: TCustomDockMaster;
|
DockLoader: TCustomDockMaster;
|
||||||
@ -341,6 +344,7 @@ function NoteBookCreate: TCustomDockSite;
|
|||||||
procedure NoteBookAdd(ABook: TCustomDockSite; AItem: TControl); //to be removed
|
procedure NoteBookAdd(ABook: TCustomDockSite; AItem: TControl); //to be removed
|
||||||
function TryRename(AComp: TComponent; const NewName: string): boolean;
|
function TryRename(AComp: TComponent; const NewName: string): boolean;
|
||||||
function CreateUniqueComponentName(const AClassName: string; OwnerComponent: TComponent): string;
|
function CreateUniqueComponentName(const AClassName: string; OwnerComponent: TComponent): string;
|
||||||
|
function FindOwnedComponent(const AName: string; AOwner: TComponent): TComponent;
|
||||||
|
|
||||||
const
|
const
|
||||||
CustomDockSiteID = 1;
|
CustomDockSiteID = 1;
|
||||||
@ -430,11 +434,27 @@ begin
|
|||||||
Result.Bottom := Result.Top + ACtrl.Height;
|
Result.Bottom := Result.Top + ACtrl.Height;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function FindOwnedComponent(const AName: string; AOwner: TComponent): TComponent;
|
||||||
|
var
|
||||||
|
i: integer;
|
||||||
|
begin
|
||||||
|
if assigned(AOwner) then begin
|
||||||
|
for i := 0 to AOwner.ComponentCount - 1 do begin
|
||||||
|
Result := AOwner.Components[i];
|
||||||
|
if CompareText(Result.Name, AName) = 0 then
|
||||||
|
exit; //found
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
//not found
|
||||||
|
Result := nil;
|
||||||
|
end;
|
||||||
|
|
||||||
//from CustomFormEditor.pp
|
//from CustomFormEditor.pp
|
||||||
function {TCustomFormEditor.}CreateUniqueComponentName(const AClassName: string;
|
function {TCustomFormEditor.}CreateUniqueComponentName(const AClassName: string;
|
||||||
OwnerComponent: TComponent): string;
|
OwnerComponent: TComponent): string;
|
||||||
var
|
var
|
||||||
i, j: integer;
|
inst: integer;
|
||||||
|
basename: string;
|
||||||
begin
|
begin
|
||||||
(* Add instance number until unique.
|
(* Add instance number until unique.
|
||||||
<T><basename> ==> <basename><_><number>
|
<T><basename> ==> <basename><_><number>
|
||||||
@ -442,24 +462,22 @@ begin
|
|||||||
and stripping trailing digits and (optionally) '_'.
|
and stripping trailing digits and (optionally) '_'.
|
||||||
*)
|
*)
|
||||||
Result:=AClassName;
|
Result:=AClassName;
|
||||||
if (OwnerComponent=nil) or (Result='') then exit;
|
//strip leading 'T'
|
||||||
i:=1;
|
if (length(Result)>1) and (Result[1]='T') then
|
||||||
|
Result:=RightStr(Result,length(Result)-1);
|
||||||
|
if (OwnerComponent=nil) or (Result='') then
|
||||||
|
exit;
|
||||||
|
//if trailing digit, append '_'
|
||||||
|
if Result[length(Result)] in ['0'..'9'] then
|
||||||
|
Result:=Result+'_';
|
||||||
|
basename := Result;
|
||||||
|
inst := 1;
|
||||||
while true do begin
|
while true do begin
|
||||||
Result:=AClassName;
|
|
||||||
//strip leading 'T'
|
|
||||||
if (length(Result)>1) and (Result[1]='T') then
|
|
||||||
Result:=RightStr(Result,length(Result)-1);
|
|
||||||
//if trailing digit, append '_'
|
|
||||||
if Result[length(Result)] in ['0'..'9'] then
|
|
||||||
Result:=Result+'_';
|
|
||||||
Result:=Result+IntToStr(i);
|
|
||||||
//append instance number
|
//append instance number
|
||||||
j:=OwnerComponent.ComponentCount-1;
|
Result := basename + IntToStr(inst);
|
||||||
while (j>=0)
|
if FindOwnedComponent(Result, OwnerComponent) = nil then
|
||||||
and (CompareText(Result,OwnerComponent.Components[j].Name)<>0) do
|
break;
|
||||||
dec(j);
|
inc(inst);
|
||||||
if j<0 then exit;
|
|
||||||
inc(i);
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1164,7 +1182,7 @@ procedure TEasyTree.LoadFromStream(Stream: TStream);
|
|||||||
*)
|
*)
|
||||||
for i := FDockSite.DockClientCount - 1 downto 0 do begin
|
for i := FDockSite.DockClientCount - 1 downto 0 do begin
|
||||||
ctl := FDockSite.DockClients[i];
|
ctl := FDockSite.DockClients[i];
|
||||||
ctl.Visible := True;
|
ctl.Visible := True; //False?
|
||||||
ctl.ManualDock(nil); //restore undocked position and extent
|
ctl.ManualDock(nil); //restore undocked position and extent
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
@ -1195,7 +1213,7 @@ procedure TEasyTree.LoadFromStream(Stream: TStream);
|
|||||||
if NewCtl <> nil then begin
|
if NewCtl <> nil then begin
|
||||||
NewCtl.Visible := True;
|
NewCtl.Visible := True;
|
||||||
NewZone.ChildControl := NewCtl;
|
NewZone.ChildControl := NewCtl;
|
||||||
SetReplacingControl(NewCtl);
|
SetReplacingControl(NewCtl); //prevent DockManager actions
|
||||||
NewCtl.ManualDock(DockSite);
|
NewCtl.ManualDock(DockSite);
|
||||||
NewCtl.Width := ZoneRec.BottomRight.x;
|
NewCtl.Width := ZoneRec.BottomRight.x;
|
||||||
NewCtl.Height := ZoneRec.BottomRight.y;
|
NewCtl.Height := ZoneRec.BottomRight.y;
|
||||||
@ -1263,7 +1281,7 @@ procedure TEasyTree.SaveToStream(Stream: TStream);
|
|||||||
if child = nil then
|
if child = nil then
|
||||||
ZoneName := ''
|
ZoneName := ''
|
||||||
else
|
else
|
||||||
ZoneName := SaveDockedControl(child);
|
ZoneName := SaveDockedControl(child); //ctrl or entire site
|
||||||
//write descriptor
|
//write descriptor
|
||||||
Stream.Write(ZoneRec, sizeof(ZoneRec));
|
Stream.Write(ZoneRec, sizeof(ZoneRec));
|
||||||
Stream.WriteAnsiString(ZoneName);
|
Stream.WriteAnsiString(ZoneName);
|
||||||
@ -1272,7 +1290,6 @@ procedure TEasyTree.SaveToStream(Stream: TStream);
|
|||||||
DoSaveZone(Zone.FirstChild, Level + 1); //all children of Level
|
DoSaveZone(Zone.FirstChild, Level + 1); //all children of Level
|
||||||
// recurse into next sibling
|
// recurse into next sibling
|
||||||
Zone := Zone.NextSibling;
|
Zone := Zone.NextSibling;
|
||||||
//if Zone <> nil then DoSaveZone(Zone, Level); //all siblings of Level
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1281,7 +1298,6 @@ begin
|
|||||||
DoSaveZone(FTopZone, 1);
|
DoSaveZone(FTopZone, 1);
|
||||||
//write end marker (dummy record of level 0)
|
//write end marker (dummy record of level 0)
|
||||||
ZoneRec.Level := 0;
|
ZoneRec.Level := 0;
|
||||||
//ZoneRec.NameLen := 0;
|
|
||||||
Stream.Write(ZoneRec, sizeof(ZoneRec));
|
Stream.Write(ZoneRec, sizeof(ZoneRec));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -2168,15 +2184,17 @@ end;
|
|||||||
procedure TCustomDockMaster.CtlToRec(ctl: TControl);
|
procedure TCustomDockMaster.CtlToRec(ctl: TControl);
|
||||||
begin
|
begin
|
||||||
//fill record with all names
|
//fill record with all names
|
||||||
|
rc.Ctrl := ctl;
|
||||||
rc.ClassName := ctl.ClassName;
|
rc.ClassName := ctl.ClassName;
|
||||||
rc.Name := ctl.Name;
|
rc.Name := ctl.Name;
|
||||||
rc.Caption := ctl.Caption; //obsolete
|
rc.Caption := ctl.Caption; //general purpose
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCustomDockMaster.IdToRec(const ID: string);
|
procedure TCustomDockMaster.IdToRec(const ID: string);
|
||||||
var
|
var
|
||||||
i: integer;
|
i: integer;
|
||||||
begin
|
begin
|
||||||
|
rc.Ctrl := nil; //flag: not yet found/created
|
||||||
//split <Name>':'<ClassName>'='<Caption>
|
//split <Name>':'<ClassName>'='<Caption>
|
||||||
i := Pos(':', ID);
|
i := Pos(':', ID);
|
||||||
if i > 0 then begin
|
if i > 0 then begin
|
||||||
@ -2231,11 +2249,12 @@ begin
|
|||||||
- saved site info (if CustomDockSite)
|
- saved site info (if CustomDockSite)
|
||||||
- AppLoadStore
|
- AppLoadStore
|
||||||
- OnRestore
|
- OnRestore
|
||||||
|
- Owner
|
||||||
- create from descriptor
|
- create from descriptor
|
||||||
- DockSite
|
- DockSite
|
||||||
*)
|
*)
|
||||||
Result := nil;
|
Result := nil;
|
||||||
IdToRec(AName);
|
IdToRec(AName); //make all information accessible to external subroutines
|
||||||
//first check for special CustomDockSite format
|
//first check for special CustomDockSite format
|
||||||
if ord(AName[1]) = CustomDockSiteID then
|
if ord(AName[1]) = CustomDockSiteID then
|
||||||
Result := TCustomDockSite.ReloadSite(AName, Site)
|
Result := TCustomDockSite.ReloadSite(AName, Site)
|
||||||
@ -2246,18 +2265,25 @@ begin
|
|||||||
Result := FOnRestore(rc.Name, Site);
|
Result := FOnRestore(rc.Name, Site);
|
||||||
if Result <> nil then
|
if Result <> nil then
|
||||||
exit;
|
exit;
|
||||||
|
//check existing control
|
||||||
|
fo := Owner; //assume all freely dockable controls are owned by our owner (Application)
|
||||||
|
cmp := FindOwnedComponent(rc.Name, fo);
|
||||||
|
//if Result <> nil then
|
||||||
|
if Result is TControl then
|
||||||
|
exit;
|
||||||
|
Result := nil; //exclude non-controls
|
||||||
//load from descriptor
|
//load from descriptor
|
||||||
fc := TWinControlClass(GetClass(rc.ClassName));
|
fc := TWinControlClass(GetClass(rc.ClassName));
|
||||||
if not assigned(fc) then begin
|
if not assigned(fc) then begin
|
||||||
DebugLn(rc.ClassName, ' is not a registered class');
|
DebugLn(rc.ClassName, ' is not a registered class');
|
||||||
//exit(nil); //bad form name
|
//exit(nil); //bad form name
|
||||||
end else begin
|
end else begin
|
||||||
fo := Owner;
|
//init from descriptor
|
||||||
Result := fc.Create(fo);
|
Result := fc.Create(fo);
|
||||||
if Result.Name <> rc.Name then
|
if Result.Name <> rc.Name then
|
||||||
TryRename(Result, rc.Name);
|
TryRename(Result, rc.Name);
|
||||||
if Result.Caption <> rc.Caption then
|
if Result.Caption <> rc.Caption then
|
||||||
Result.Caption := rc.Caption;
|
Result.Caption := rc.Caption; //really?
|
||||||
end;
|
end;
|
||||||
//last resort
|
//last resort
|
||||||
if Result = nil then
|
if Result = nil then
|
||||||
@ -2272,7 +2298,7 @@ initialization
|
|||||||
DockLoader := TCustomDockMaster.Create(Application);
|
DockLoader := TCustomDockMaster.Create(Application);
|
||||||
finalization
|
finalization
|
||||||
DestroyDockHeaderImages;
|
DestroyDockHeaderImages;
|
||||||
//FreeAndNil(LoadStore);
|
//FreeAndNil(LoadStore); - by owner!
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user