[Lazarus] Desktops and multiple source editors
Ondrej Pokorny
lazarus at kluug.net
Thu Sep 10 00:13:24 CEST 2015
Now I think I got the multiple source editors handling correct:
1.) The position of editor windows is controlled by the desktop.
2.) The visibility of editor windows is controlled by the current project.
This corresponds with the old pre-desktop Lazarus behavior and is also
logical.
The above applies to non-docked environment.
The docked environment is more a problem because e.g. the secondary
editor window doesn't get closed when you close all the tabs. Also the
project doesn't handle the visibility of the secondary editor window. I
assume it was the same in pre-desktop Lazarus. I don't know if it is a
feature or a bug.
The Package editors:
1.) Position is controlled by the desktop for every package separately.
This means if you open a package and save the desktop, the next time you
open the package having the same desktop active in the IDE, it will be
correctly placed.
2.) The visibility is controlled by the fact if the package is open or
not. The desktop cannot reopen packages, obviously. It doesn't store the
file info of the package. It is also not expected.
Again, the above applies to non-docked environment. Packages are a
problem in the docked environment. When you change the desktop, there is
a docked package and there is no docking information about it in the new
desktop, where should it be placed? IMO, it has to be detached from the
dock and placed in a window. Now it gets closed. Maybe it is easier to
disable docking capabilities for packages. Then the docked environment
would just ignore them.
I am not using AnchorDocking personally so somebody else should care of
the problems in AnchorDocking.
---
Patch attached.
+ I tested Windows 10 only. It seems to work pretty well for me.
Ondrej
-------------- next part --------------
Index: components/ideintf/idewindowintf.pas
===================================================================
--- components/ideintf/idewindowintf.pas (revision 49801)
+++ components/ideintf/idewindowintf.pas (working copy)
@@ -209,16 +209,12 @@
FDefaultWidth: integer;
FDefaultHeight: integer;
FWindowState: TIDEWindowState;
- FForm: TCustomForm;
FFormID: string;
FDefaultWindowPlacement: TIDEWindowPlacement;
FDividers: TSimpleWindowLayoutDividerPosList;
+ function GetForm: TCustomForm;
function GetFormCaption: string;
- function GetFormID: string;
- procedure SetForm(const AValue: TCustomForm);
procedure OnFormClose(Sender: TObject; var {%H-}CloseAction: TCloseAction);
- protected
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
constructor Create(AFormID: string); reintroduce;
destructor Destroy; override;
@@ -233,11 +229,13 @@
procedure LoadFromConfig(Config: TConfigStorage; const Path: string);
procedure SaveToConfig(Config: TConfigStorage; const Path: string);
function CustomCoordinatesAreValid: boolean;
+ function DefaultCoordinatesAreValid: boolean;
procedure CloseForm;
+ procedure SetForm(const AForm: TCustomForm);
function ValidateAndSetCoordinates(const aForce: Boolean = False): Boolean;
procedure SetDefaultPosition(const AForm: TCustomForm);
public
- property FormID: string read GetFormID write FFormID;
+ property FormID: string read FFormID write FFormID;
function FormBaseID(out SubIndex: Integer): String; // split FormID into name+number
property FormCaption: string read GetFormCaption;
property WindowPlacement: TIDEWindowPlacement read fWindowPlacement write FWindowPlacement;
@@ -252,7 +250,7 @@
property DefaultWidth: integer read FDefaultWidth write FDefaultWidth;
property DefaultHeight: integer read FDefaultHeight write FDefaultHeight;
property WindowState: TIDEWindowState read FWindowState write FWindowState;
- property Form: TCustomForm read FForm write SetForm;
+ property Form: TCustomForm read GetForm;
property Visible: boolean read FVisible write FVisible;
property Applied: boolean read FApplied write FApplied;
property Dividers: TSimpleWindowLayoutDividerPosList read FDividers;
@@ -281,8 +279,7 @@
AMoveToVisbleMode: TLayoutMoveToVisbleMode = vmAlwaysMoveToVisible);
procedure StoreWindowPositions;
procedure SetDefaultPosition(const AForm: TCustomForm);
- procedure Assign(SrcList: TSimpleWindowLayoutList; AssignOnlyNewlyCreated,
- DestroyNotAssigned, AssignOrder: Boolean);
+ procedure CopyItemsFrom(SrcList: TSimpleWindowLayoutList);
function Add(ALayout: TSimpleWindowLayout): integer;
function CreateWindowLayout(const TheFormID: string): TSimpleWindowLayout;
function CreateWindowLayout(const TheForm: TCustomForm): TSimpleWindowLayout;
@@ -477,6 +474,22 @@
property HideSimpleLayoutOptions: boolean read FHideSimpleLayoutOptions;
end;
+ TIDEWindowGlobalOption = class
+ public
+ CanSetVisibility: Boolean;
+ end;
+
+ TIDEWindowsGlobalOptions = class
+ private
+ FList: TStringList;
+ public
+ constructor Create;
+ destructor Destroy; override;
+ public
+ procedure Add(const aFormIDPrefix: string; CanSetVisibility: Boolean);
+ function CanSetVisibility(const aFormID: string): Boolean;
+ end;
+
var
IDEDockMaster: TIDEDockMaster = nil; // can be set by a package
@@ -483,6 +496,7 @@
procedure MakeIDEWindowDockable(AControl: TWinControl);
procedure MakeIDEWindowDockSite(AForm: TCustomForm);
procedure CloseAllForms;
+function IDEWindowsGlobalOptions: TIDEWindowsGlobalOptions;
procedure Register;
@@ -491,6 +505,9 @@
uses
LazIDEIntf;
+var
+ FIDEWindowsGlobalOptions: TIDEWindowsGlobalOptions = nil;
+
function StrToIDEWindowPlacement(const s: string): TIDEWindowPlacement;
begin
for Result:=Low(TIDEWindowPlacement) to High(TIDEWindowPlacement) do
@@ -551,11 +568,62 @@
end;
end;
+function IDEWindowsGlobalOptions: TIDEWindowsGlobalOptions;
+begin
+ if not Assigned(FIDEWindowsGlobalOptions) then
+ FIDEWindowsGlobalOptions := TIDEWindowsGlobalOptions.Create;
+
+ Result := FIDEWindowsGlobalOptions;
+end;
+
procedure Register;
begin
RegisterComponents('Misc',[TIDEDialogLayoutStorage]);
end;
+{ TIDEWindowsGlobalOptions }
+
+procedure TIDEWindowsGlobalOptions.Add(const aFormIDPrefix: string;
+ CanSetVisibility: Boolean);
+var
+ xIndex: Integer;
+begin
+ xIndex := FList.Add(aFormIDPrefix);
+ if FList.Objects[xIndex] = nil then
+ FList.Objects[xIndex] := TIDEWindowGlobalOption.Create;
+
+ TIDEWindowGlobalOption(FList.Objects[xIndex]).CanSetVisibility := CanSetVisibility;
+end;
+
+function TIDEWindowsGlobalOptions.CanSetVisibility(const aFormID: string
+ ): Boolean;
+var
+ I: Integer;
+begin
+ for I := 0 to FList.Count-1 do
+ if Copy(aFormID, 1, Length(FList[I])) = FList[I] then
+ begin
+ Result := TIDEWindowGlobalOption(FList.Objects[I]).CanSetVisibility;
+ Exit;
+ end;
+ Result := True;//default is true
+end;
+
+constructor TIDEWindowsGlobalOptions.Create;
+begin
+ inherited Create;
+
+ FList := TStringList.Create;
+ FList.Sorted := True;
+ FList.OwnsObjects := True;
+end;
+
+destructor TIDEWindowsGlobalOptions.Destroy;
+begin
+ FList.Free;
+ inherited Destroy;
+end;
+
{ TSimpleWindowLayoutDividerPosList }
function TSimpleWindowLayoutDividerPosList.GetItems(Index: Integer): TSimpleWindowLayoutDividerPos;
@@ -1110,7 +1178,6 @@
destructor TSimpleWindowLayout.Destroy;
begin
- Form:=nil;
inherited Destroy;
FDividers.Free;
end;
@@ -1182,27 +1249,19 @@
GetCurrentPosition;
end;
-procedure TSimpleWindowLayout.Notification(AComponent: TComponent;
- Operation: TOperation);
+function TSimpleWindowLayout.CustomCoordinatesAreValid: boolean;
begin
- inherited Notification(AComponent, Operation);
- if Operation=opRemove then begin
- if fForm=AComponent then begin
- fForm:=nil;
- Applied:=false;
- end;
- end;
+ Result:=(Width>0) and (Height>0); // and (Left>10-Width) and (Top>10-Height);
end;
-function TSimpleWindowLayout.CustomCoordinatesAreValid: boolean;
+function TSimpleWindowLayout.DefaultCoordinatesAreValid: boolean;
begin
- Result:=(Width>0) and (Height>0); // and (Left>10-Width) and (Top>10-Height);
+ Result:=(DefaultWidth>0) and (DefaultHeight>0);
end;
procedure TSimpleWindowLayout.CloseForm;
begin
GetCurrentPosition;
- Form:=nil;
end;
function TSimpleWindowLayout.ValidateAndSetCoordinates(const aForce: Boolean
@@ -1210,12 +1269,19 @@
var
i: Integer;
NewBounds: TRect;
+ xForm: TCustomForm;
begin
Result := False;
- if aForce or CustomCoordinatesAreValid then begin
+ xForm := Form;
+ if Assigned(xForm) and
+ (aForce or CustomCoordinatesAreValid) then
+ begin
if not CustomCoordinatesAreValid then//default position
+ begin
+ if not DefaultCoordinatesAreValid then//don't change the coordinates if default position is invalid
+ Exit;
NewBounds := Bounds(DefaultLeft, DefaultTop, DefaultWidth, DefaultHeight)
- else// explicit position
+ end else// explicit position
NewBounds := Bounds(Left, Top, Width, Height);
// set minimum size
@@ -1248,7 +1314,7 @@
end;
// set bounds (do not use SetRestoredBounds - that flickers with the current LCL implementation)
- FForm.SetBounds(NewBounds.Left, NewBounds.Top,
+ xForm.SetBounds(NewBounds.Left, NewBounds.Top,
NewBounds.Right - NewBounds.Left,
NewBounds.Bottom - NewBounds.Top);
Result := True;
@@ -1270,33 +1336,17 @@
Result := copy(Result, 1, i);
end;
-procedure TSimpleWindowLayout.SetForm(const AValue: TCustomForm);
+procedure TSimpleWindowLayout.SetForm(const AForm: TCustomForm);
begin
- if fForm=AValue then exit;
- if Assigned(Form) then
+ if Assigned(AForm) then
begin
- RemoveFreeNotification(Form);
- Form.RemoveHandlerClose(@OnFormClose);
- end;
- fForm:=AValue;
- if Assigned(Form) then
- begin
- fFormID := Form.Name;
- FFormCaption := Form.Caption;
- FreeNotification(Form);
- Form.AddHandlerClose(@OnFormClose);
+ fFormID := AForm.Name;
+ FFormCaption := AForm.Caption;
+ AForm.AddHandlerClose(@OnFormClose);
Applied:=false;
end;
end;
-function TSimpleWindowLayout.GetFormID: string;
-begin
- if Form=nil then
- Result:=fFormID
- else
- Result:=Form.Name;
-end;
-
function TSimpleWindowLayout.GetFormCaption: string;
begin
if Form<>nil then
@@ -1370,10 +1420,12 @@
i, j: Integer;
f: Boolean;
Creator: TIDEWindowCreator;
+ xForm: TCustomForm;
begin
Creator:=IDEWindowCreators.FindWithName(FormID);
if (Creator = nil) or (Creator.OnGetDividerSize = nil) then exit;
- if fForm = nil then exit;
+ xForm := Form;
+ if xForm = nil then exit;
for i := 0 to FDividers.Count - 1 do begin
if FDividers[i].FId < 0 then continue;
f := AForce;
@@ -1385,7 +1437,7 @@
end;
if f then begin
j:=-1;
- if Creator.OnGetDividerSize(fForm, FDividers[i].Id, j) then
+ if Creator.OnGetDividerSize(xForm, FDividers[i].Id, j) then
FDividers[i].Size := j
else
FDividers[i].Size := -1; // Default / Not Changed / Unavailable
@@ -1405,10 +1457,26 @@
//debugln('TSimpleWindowLayout.GetCurrentPosition ',DbgSName(Self),' ',FormID,' Width=',dbgs(Width));
end;
+function TSimpleWindowLayout.GetForm: TCustomForm;
+var
+ I: Integer;
+begin
+ for I := 0 to Screen.CustomFormCount-1 do
+ if Screen.CustomForms[I].Name = FFormID then
+ begin
+ Result := Screen.CustomForms[I];
+ Exit;
+ end;
+ Result := nil;
+end;
+
function TSimpleWindowLayout.Apply(const aForce: Boolean): Boolean;
+var
+ xForm: TCustomForm;
begin
Result := False;
- if fForm = nil then exit;
+ xForm := Form;
+ if xForm = nil then exit;
Applied:=true;
{$IFDEF VerboseIDEDocking}
debugln(['TSimpleWindowLayoutList.ApplyAndShow restore ',
@@ -1421,8 +1489,8 @@
begin
//DebugLn(['TMainIDE.OnApplyWindowLayout ',IDEWindowStateNames[WindowState]]);
case WindowState of
- iwsMinimized: FForm.WindowState:=wsMinimized;
- iwsMaximized: FForm.WindowState:=wsMaximized;
+ iwsMinimized: xForm.WindowState:=wsMinimized;
+ iwsMaximized: xForm.WindowState:=wsMaximized;
end;
Result := ValidateAndSetCoordinates(aForce); // Adjust bounds to screen area and apply them.
if WindowState in [iwsMinimized, iwsMaximized] then
@@ -1453,7 +1521,7 @@
f := WindowPlacement in [iwpRestoreWindowGeometry, iwpRestoreWindowSize];
end;
if f then
- Creator.OnSetDividerSize(fForm, FDividers[i].Id, FDividers[i].Size);
+ Creator.OnSetDividerSize(Form, FDividers[i].Id, FDividers[i].Size);
end;
end;
end;
@@ -1504,7 +1572,7 @@
function TSimpleWindowLayoutList.IndexOf(const FormID: string): integer;
begin
Result:=Count-1;
- while (Result>=0) and (FormID<>Items[Result].GetFormID) do dec(Result);
+ while (Result>=0) and (FormID<>Items[Result].FormID) do dec(Result);
end;
function TSimpleWindowLayoutList.IndexOf(const AForm: TCustomForm): integer;
@@ -1649,7 +1717,7 @@
ALayout:=ItemByFormID(AForm.Name);
if ALayout<>nil then
begin
- ALayout.Form:=AForm;
+ ALayout.SetForm(AForm);
if ALayout.Applied then exit;
if ALayout.Apply then exit;
end;
@@ -1789,42 +1857,22 @@
end;
end;
-procedure TSimpleWindowLayoutList.Assign(SrcList: TSimpleWindowLayoutList;
- AssignOnlyNewlyCreated, DestroyNotAssigned, AssignOrder: Boolean);
+procedure TSimpleWindowLayoutList.CopyItemsFrom(SrcList: TSimpleWindowLayoutList);
var
- i: integer;
- xItemIndex: Integer;
- xNewlyCreated: Boolean;
+ SrcI: Integer;//index in SrcList
+ SelfI: Integer;//index in Self
begin
if SrcList=nil then exit;
- for i:=0 to SrcList.Count-1 do begin
- xNewlyCreated := False;
- if (i >= Self.Count) or (Self.Items[i].FormID <> SrcList[i].FormID) then
- begin//the target item has not the same index, find it!
- xItemIndex := IndexOf(SrcList[i].FormID);
- if xItemIndex < 0 then
- begin
- xItemIndex := Self.Add(TSimpleWindowLayout.Create(SrcList[i].FormID));//not found, create
- xNewlyCreated := True;
- end;
- if (xItemIndex<>i) and (AssignOrder) then
- begin
- Self.fItems.Move(xItemIndex, i);//move it to right position
- xItemIndex := i;
- end;
- end else
- xItemIndex := i;
- if not AssignOnlyNewlyCreated or xNewlyCreated then
- Self.Items[xItemIndex].Assign(SrcList[i])
- end;
- for i := Count-1 downto 0 do
- if SrcList.IndexOf(Items[i].FormID) = -1 then
+ //do not clear self, always copy items
+ for SrcI:=0 to SrcList.Count-1 do
begin
- if DestroyNotAssigned then
- Delete(i)
- else
- Items[i].Clear;
+ SelfI := IndexOf(SrcList[SrcI].FormID);
+ if SelfI < 0 then
+ SelfI := Self.Add(TSimpleWindowLayout.Create(SrcList[SrcI].FormID));//not found, create
+ Self.fItems.Move(SelfI, SrcI);//move it to right position
+ SelfI := SrcI;
+ Self.Items[SelfI].Assign(SrcList[SrcI])
end;
end;
@@ -1850,7 +1898,7 @@
): TSimpleWindowLayout;
begin
Result:=CreateWindowLayout(TheForm.Name);
- Result.Form:=TheForm;
+ Result.SetForm(TheForm);
end;
{ TIDEWindowCreator }
@@ -2199,7 +2247,7 @@
SimpleLayoutStorage.CreateWindowLayout(AForm);
end
else
- Layout.Form:=AForm;
+ Layout.SetForm(AForm);
if (IDEDockMaster<>nil) and (not (csDesigning in AForm.ComponentState))
and (FindWithName(AForm.Name)<>nil) then
@@ -2240,6 +2288,7 @@
ALayout: TSimpleWindowLayout;
AForm: TCustomForm;
HasChanged: Boolean;
+ AChangeVisibility: Boolean;
begin
if IDEDockMaster=nil then
begin
@@ -2247,14 +2296,22 @@
for i:=SimpleLayoutStorage.Count-1 downto 0 do//loop down in order to keep z-order of the forms
begin
ALayout:=SimpleLayoutStorage[i];
- AForm:=GetForm(ALayout.FormID,ALayout.Visible);
+ AChangeVisibility := IDEWindowsGlobalOptions.CanSetVisibility(ALayout.FormID);
+ AForm:=GetForm(ALayout.FormID,AChangeVisibility and ALayout.Visible);
if AForm=nil then Continue;
HasChanged:=true;
- ALayout.Apply(True);
- if ALayout.Visible or (AForm=Application.MainForm) then
- ShowForm(AForm,true)
- else if AForm.Visible then
- AForm.Close;
+ ALayout.Apply(AChangeVisibility);
+ if AChangeVisibility then
+ begin
+ if ALayout.Visible or (AForm=Application.MainForm) then
+ ShowForm(AForm,true)
+ else if AForm.Visible then
+ AForm.Close;
+ end else
+ begin//do not change visibility
+ if AForm.Visible then//Only make sure their z-index is OK if they are already visible
+ ShowForm(AForm,true)
+ end;
end;
if HasChanged then
LayoutChanged;
@@ -2298,6 +2355,7 @@
finalization
FreeAndNil(IDEWindowCreators);
FreeAndNil(IDEDialogLayoutList);
+ FreeAndNil(FIDEWindowsGlobalOptions);
end.
Index: ide/environmentopts.pp
===================================================================
--- ide/environmentopts.pp (revision 49801)
+++ ide/environmentopts.pp (working copy)
@@ -1009,7 +1009,7 @@
FIDEDialogLayoutList:=TIDEDialogLayoutList.Create;
FIDEWindowCreatorsLayoutList:=TSimpleWindowLayoutList.Create(False);
FIDEDialogLayoutList.Assign(IDEWindowIntf.IDEDialogLayoutList);
- FIDEWindowCreatorsLayoutList.Assign(IDEWindowIntf.IDEWindowCreators.SimpleLayoutStorage, True, True, True);
+ FIDEWindowCreatorsLayoutList.CopyItemsFrom(IDEWindowIntf.IDEWindowCreators.SimpleLayoutStorage);
end;
end;
@@ -1043,9 +1043,7 @@
raise Exception.Create('Internal error: TDesktopOpt.Assign mixed docked/undocked desktops.');
// window layout
- if Source.FIDEWindowCreatorsLayoutList <> IDEWindowCreators.SimpleLayoutStorage then
- Source.FIDEWindowCreatorsLayoutList.Assign(IDEWindowCreators.SimpleLayoutStorage, True, True, False);
- FIDEWindowCreatorsLayoutList.Assign(Source.FIDEWindowCreatorsLayoutList, False, False, True);
+ FIDEWindowCreatorsLayoutList.CopyItemsFrom(Source.FIDEWindowCreatorsLayoutList);
FIDEDialogLayoutList.Assign(Source.FIDEDialogLayoutList);
FSingleTaskBarButton := Source.FSingleTaskBarButton;
FHideIDEOnRun := Source.FHideIDEOnRun;
Index: ide/frames/window_options.pas
===================================================================
--- ide/frames/window_options.pas (revision 49801)
+++ ide/frames/window_options.pas (working copy)
@@ -151,7 +151,7 @@
ProjectDirInIdeTitleCheckBox.Checked:=IDEProjectDirectoryInIdeTitle;
end;
- FLayouts.Assign(IDEWindowCreators.SimpleLayoutStorage, False, True, True);
+ FLayouts.CopyItemsFrom(IDEWindowCreators.SimpleLayoutStorage);
if FShowSimpleLayout then begin
// Window Positions
@@ -220,8 +220,7 @@
procedure TWindowOptionsFrame.WriteSettings(AOptions: TAbstractIDEOptions);
begin
SaveLayout;
- FLayouts.Assign(IDEWindowCreators.SimpleLayoutStorage, True, True, False);
- IDEWindowCreators.SimpleLayoutStorage.Assign(FLayouts, False, False, True);
+ IDEWindowCreators.SimpleLayoutStorage.CopyItemsFrom(FLayouts);
with (AOptions as TEnvironmentOptions).Desktop do
begin
Index: ide/sourceeditor.pp
===================================================================
--- ide/sourceeditor.pp (revision 49801)
+++ ide/sourceeditor.pp (working copy)
@@ -6710,7 +6710,7 @@
// => disconnect first
Layout:=IDEWindowCreators.SimpleLayoutStorage.ItemByForm(Self);
if Layout<>nil then
- Layout.Form:=nil;
+ Layout.SetForm(nil);
Name := Name + '___' + IntToStr({%H-}PtrUInt(Pointer(Self)));
CloseAction := caFree;
end
@@ -8574,6 +8574,8 @@
SRCED_OPEN := DebugLogger.RegisterLogGroup('SRCED_OPEN' {$IFDEF SRCED_OPEN} , True {$ENDIF} );
SRCED_CLOSE := DebugLogger.RegisterLogGroup('SRCED_CLOSE' {$IFDEF SRCED_CLOSE} , True {$ENDIF} );
SRCED_PAGES := DebugLogger.RegisterLogGroup('SRCED_PAGES' {$IFDEF SRCED_PAGES} , True {$ENDIF} );
+
+ IDEWindowsGlobalOptions.Add(NonModalIDEWindowNames[nmiwSourceNoteBookName], False);
end;
procedure InternalFinal;
Index: packager/packageeditor.pas
===================================================================
--- packager/packageeditor.pas (revision 49801)
+++ packager/packageeditor.pas (working copy)
@@ -42,7 +42,7 @@
IDEImagesIntf, MenuIntf, LazIDEIntf, ProjectIntf, CodeToolsStructs,
FormEditingIntf, PackageIntf, IDEHelpIntf, IDEOptionsIntf,
IDEExternToolIntf,
- NewItemIntf,
+ NewItemIntf, IDEWindowIntf,
// IDE
IDEDialogs, IDEProcs, LazarusIDEStrConsts, IDEDefs, CompilerOptions,
ComponentReg, UnitResources, EnvironmentOpts, DialogProcs, InputHistory,
@@ -3551,6 +3551,7 @@
initialization
PackageEditors:=nil;
+ IDEWindowsGlobalOptions.Add(PackageEditorWindowPrefix, False);
end.
More information about the Lazarus
mailing list