~ubuntu-branches/ubuntu/saucy/lazarus/saucy

« back to all changes in this revision

Viewing changes to ideintf/idewindowintf.pas

  • Committer: Package Import Robot
  • Author(s): Paul Gevers, Abou Al Montacir, Bart Martens, Paul Gevers
  • Date: 2013-06-08 14:12:17 UTC
  • mfrom: (1.1.9)
  • Revision ID: package-import@ubuntu.com-20130608141217-7k0cy9id8ifcnutc
Tags: 1.0.8+dfsg-1
[ Abou Al Montacir ]
* New upstream major release and multiple maintenace release offering many
  fixes and new features marking a new milestone for the Lazarus development
  and its stability level.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_fixes_branch
* LCL changes:
  - LCL is now a normal package.
      + Platform independent parts of the LCL are now in the package LCLBase
      + LCL is automatically recompiled when switching the target platform,
        unless pre-compiled binaries for this target are already installed.
      + No impact on existing projects.
      + Linker options needed by LCL are no more added to projects that do
        not use the LCL package.
  - Minor changes in LCL basic classes behaviour
      + TCustomForm.Create raises an exception if a form resource is not
        found.
      + TNotebook and TPage: a new implementation of these classes was added.
      + TDBNavigator: It is now possible to have focusable buttons by setting
        Options = [navFocusableButtons] and TabStop = True, useful for
        accessibility and for devices with neither mouse nor touch screen.
      + Names of TControlBorderSpacing.GetSideSpace and GetSpace were swapped
        and are now consistent. GetSideSpace = Around + GetSpace.
      + TForm.WindowState=wsFullscreen was added
      + TCanvas.TextFitInfo was added to calculate how many characters will
        fit into a specified Width. Useful for word-wrapping calculations.
      + TControl.GetColorResolvingParent and
        TControl.GetRGBColorResolvingParent were added, simplifying the work
        to obtain the final color of the control while resolving clDefault
        and the ParentColor.
      + LCLIntf.GetTextExtentExPoint now has a good default implementation
        which works in any platform not providing a specific implementation.
        However, Widgetset specific implementation is better, when available.
      + TTabControl was reorganized. Now it has the correct class hierarchy
        and inherits from TCustomTabControl as it should.
  - New unit in the LCL:
      + lazdialogs.pas: adds non-native versions of various native dialogs,
        for example TLazOpenDialog, TLazSaveDialog, TLazSelectDirectoryDialog.
        It is used by widgetsets which either do not have a native dialog, or
        do not wish to use it because it is limited. These dialogs can also be
        used by user applications directly.
      + lazdeviceapis.pas: offers an interface to more hardware devices such
        as the accelerometer, GPS, etc. See LazDeviceAPIs
      + lazcanvas.pas: provides a TFPImageCanvas descendent implementing
        drawing in a LCL-compatible way, but 100% in Pascal.
      + lazregions.pas. LazRegions is a wholly Pascal implementation of
        regions for canvas clipping, event clipping, finding in which control
        of a region tree one an event should reach, for drawing polygons, etc.
      + customdrawncontrols.pas, customdrawndrawers.pas,
        customdrawn_common.pas, customdrawn_android.pas and
        customdrawn_winxp.pas: are the Lazarus Custom Drawn Controls -controls
        which imitate the standard LCL ones, but with the difference that they
        are non-native and support skinning.
  - New APIs added to the LCL to improve support of accessibility software
    such as screen readers.
* IDE changes:
  - Many improvments.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/New_IDE_features_since#v1.0_.282012-08-29.29
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes#IDE_Changes
* Debugger / Editor changes:
  - Added pascal sources and breakpoints to the disassembler
  - Added threads dialog.
* Components changes:
  - TAChart: many fixes and new features
  - CodeTool: support Delphi style generics and new syntax extensions.
  - AggPas: removed to honor free licencing. (Closes: Bug#708695)
[Bart Martens]
* New debian/watch file fixing issues with upstream RC release.
[Abou Al Montacir]
* Avoid changing files in .pc hidden directory, these are used by quilt for
  internal purpose and could lead to surprises during build.
[Paul Gevers]
* Updated get-orig-source target and it compinion script orig-tar.sh so that they
  repack the source file, allowing bug 708695 to be fixed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
23
23
interface
24
24
 
25
25
uses
26
 
  Math, Classes, SysUtils, LCLProc, LazConfigStorage, Forms, Controls;
 
26
  Math, types, Classes, SysUtils, LCLProc, LazConfigStorage, Forms, Controls;
27
27
 
28
28
  //----------------------------------------------------------------------------
29
29
  // layout settings of modal forms (dialogs) in the IDE
36
36
 
37
37
  TIDEDialogLayout = class
38
38
  private
39
 
    FHeight: integer;
40
39
    FList: TIDEDialogLayoutList;
41
40
    FModified: boolean;
42
41
    FName: string;
43
42
    FWidth: integer;
44
 
    procedure SetHeight(const AValue: integer);
 
43
    FHeight: integer;
45
44
    procedure SetList(const AValue: TIDEDialogLayoutList);
46
45
    procedure SetModified(const AValue: boolean);
47
46
    procedure SetWidth(const AValue: integer);
 
47
    procedure SetHeight(const AValue: integer);
48
48
  public
49
49
    constructor Create(const TheName: string; TheList: TIDEDialogLayoutList);
50
50
    function SizeValid: boolean;
105
105
  IDEDialogLayoutList: TIDEDialogLayoutList = nil;// set by the IDE
106
106
 
107
107
type
108
 
  { TIDEWindowLayout stores information about the position, min/maximized state
 
108
  { TSimpleWindowLayout stores information about the position, min/maximized state
109
109
    and similar things for an IDE window or dialog, like the source editor,
110
110
    the object inspector, the main bar or the message view.
111
111
  }
123
123
  TIDEWindowState = (iwsNormal, iwsMaximized, iwsMinimized, iwsHidden);
124
124
  TIDEWindowStates = set of TIDEWindowState;
125
125
 
 
126
  TSimpleWindowLayoutDividerPosPlacement = (
 
127
    iwpdDefault,      // set column/row/splitter to the default size
 
128
    iwpdCustomSize,   // set column/row/splitter to the custom size
 
129
    iwpdRestore,      // save column/row/splitter size on exit, and restore
 
130
    iwpdUseWindowSetting
 
131
  );
 
132
 
 
133
  TSimpleWindowLayoutDividerPosSizeGetter =
 
134
    function(AForm: TCustomForm; AColId: Integer; var ASize: Integer): Boolean;
 
135
 
 
136
  TSimpleWindowLayoutDividerPosSizeSetter =
 
137
    procedure(AForm: TCustomForm; AColId: Integer; ASize: Integer);
 
138
 
 
139
  { TSimpleWindowLayoutDividerPos }
 
140
 
 
141
  TSimpleWindowLayoutDividerPos = class
 
142
  private
 
143
    FDefaultSize: integer;
 
144
    FDisplayName: PString;
 
145
    FId: Integer;
 
146
    FIdString: String;
 
147
    FPlacement: TSimpleWindowLayoutDividerPosPlacement;
 
148
    FSize: integer;
 
149
    function GetDisplayName: String;
 
150
  protected
 
151
    procedure SetDisplayName(ADisplayName: PString);
 
152
    procedure SetId(AnId: Integer);
 
153
  public
 
154
    constructor Create(AnIdString: String);
 
155
    constructor Create(AnIdString: String; AnId: Integer; ADisplayName: PString);
 
156
    procedure Assign(ADividerPos: TSimpleWindowLayoutDividerPos); reintroduce;
 
157
    procedure LoadFromConfig(Config: TConfigStorage; const Path: string);
 
158
    function  SaveToConfig(Config: TConfigStorage; const Path: string) : Boolean;
 
159
    procedure Clear;
 
160
    property IdString: String read FIdString;
 
161
    property Id: Integer read FId;
 
162
    property DisplayName: String read GetDisplayName;
 
163
    property Placement: TSimpleWindowLayoutDividerPosPlacement read FPlacement write FPlacement;
 
164
    property Size: integer read FSize write FSize;
 
165
    property DefaultSize: integer read FDefaultSize write FDefaultSize;
 
166
  end;
 
167
 
 
168
  { TSimpleWindowLayoutDividerPosList }
 
169
 
 
170
  TSimpleWindowLayoutDividerPosList = class
 
171
  private
 
172
    FList: TList;
 
173
    function GetItems(Index: Integer): TSimpleWindowLayoutDividerPos;
 
174
    function GetNamedItems(Index: Integer): TSimpleWindowLayoutDividerPos;
 
175
  protected
 
176
    procedure Merge(AnItem: TSimpleWindowLayoutDividerPos);
 
177
  public
 
178
    constructor Create;
 
179
    destructor Destroy; override;
 
180
    procedure Assign(ADividerPosList: TSimpleWindowLayoutDividerPosList); reintroduce;
 
181
    procedure LoadFromConfig(Config: TConfigStorage; const Path: string);
 
182
    procedure SaveToConfig(Config: TConfigStorage; const Path: string);
 
183
    procedure Clear;
 
184
    procedure ClearItems;
 
185
    function Add(AnIdString: String; AnId: Integer; ADisplayName: PString): TSimpleWindowLayoutDividerPos;
 
186
    function Add(AnIdString: String): TSimpleWindowLayoutDividerPos;
 
187
    function Count: Integer;
 
188
    function NamedCount: Integer;
 
189
    function Find(AnId: Integer): TSimpleWindowLayoutDividerPos;
 
190
    function Find(AnIdString: String): TSimpleWindowLayoutDividerPos;
 
191
    function IndexOf(AnId: Integer): Integer;
 
192
    function IndexOf(AnIdString: String): Integer;
 
193
    function IndexOf(AnItem: TSimpleWindowLayoutDividerPos): Integer;
 
194
    property Items[Index: Integer]: TSimpleWindowLayoutDividerPos read GetItems; default;
 
195
    property NamedItems[Index: Integer]: TSimpleWindowLayoutDividerPos read GetNamedItems;
 
196
  end;
 
197
 
126
198
  { TSimpleWindowLayout }
127
199
 
128
200
  TSimpleWindowLayout = class(TComponent)
130
202
    FApplied: boolean;
131
203
    FFormCaption: string;
132
204
    FVisible: boolean;
133
 
    fWindowPlacement: TIDEWindowPlacement;
134
 
    fLeft: integer;
135
 
    fTop: integer;
136
 
    fWidth: integer;
137
 
    fHeight: integer;
138
 
    fWindowState: TIDEWindowState;
139
 
    fForm: TCustomForm;
140
 
    fFormID: string;
141
 
    fDefaultWindowPlacement: TIDEWindowPlacement;
 
205
    FWindowPlacement: TIDEWindowPlacement;
 
206
    FLeft: integer;
 
207
    FTop: integer;
 
208
    FWidth: integer;
 
209
    FHeight: integer;
 
210
    FWindowState: TIDEWindowState;
 
211
    FForm: TCustomForm;
 
212
    FFormID: string;
 
213
    FDefaultWindowPlacement: TIDEWindowPlacement;
 
214
    FDividers: TSimpleWindowLayoutDividerPosList;
142
215
    function GetFormCaption: string;
143
216
    function GetFormID: string;
144
217
    procedure SetForm(const AValue: TCustomForm);
148
221
  public
149
222
    constructor Create(AFormID: string); reintroduce;
150
223
    destructor Destroy; override;
 
224
    function  CreateCopy: TSimpleWindowLayout;
151
225
    procedure Clear;
152
226
    procedure GetCurrentPosition;
 
227
    function  Apply: Boolean;
 
228
    procedure ApplyDivider(AForce: Boolean = False);
153
229
    procedure Assign(Layout: TSimpleWindowLayout); reintroduce;
 
230
    procedure ReadCurrentDividers(AForce: Boolean = False);
154
231
    procedure ReadCurrentCoordinates;
155
232
    procedure ReadCurrentState;
156
233
    procedure LoadFromConfig(Config: TConfigStorage; const Path: string);
157
234
    procedure SaveToConfig(Config: TConfigStorage; const Path: string);
158
235
    function CustomCoordinatesAreValid: boolean;
159
236
    procedure CloseForm;
 
237
    function ValidateAndSetCoordinates: Boolean;
160
238
  public
161
239
    property FormID: string read GetFormID write FFormID;
162
240
    function FormBaseID(out SubIndex: Integer): String; // split FormID into name+number
163
241
    property FormCaption: string read GetFormCaption;
164
242
    property WindowPlacement: TIDEWindowPlacement read fWindowPlacement write FWindowPlacement;
165
243
    property DefaultWindowPlacement: TIDEWindowPlacement
166
 
      read fDefaultWindowPlacement write fDefaultWindowPlacement;
167
 
    property Left: integer read fLeft write FLeft;
168
 
    property Top: integer read fTop write FTop;
169
 
    property Width: integer read fWidth write FWidth;
170
 
    property Height: integer read fHeight write FHeight;
171
 
    property WindowState: TIDEWindowState read fWindowState write FWindowState;
172
 
    property Form: TCustomForm read fForm write SetForm;
 
244
      read FDefaultWindowPlacement write FDefaultWindowPlacement;
 
245
    property Left: integer read FLeft write FLeft;
 
246
    property Top: integer read FTop write FTop;
 
247
    property Width: integer read FWidth write FWidth;
 
248
    property Height: integer read FHeight write FHeight;
 
249
    property WindowState: TIDEWindowState read FWindowState write FWindowState;
 
250
    property Form: TCustomForm read FForm write SetForm;
173
251
    property Visible: boolean read FVisible write FVisible;
174
252
    property Applied: boolean read FApplied write FApplied;
 
253
    property Dividers: TSimpleWindowLayoutDividerPosList read FDividers;
175
254
  end;
176
255
 
177
256
  { TSimpleWindowLayoutList }
250
329
    FBottom: string;
251
330
    FLeft: string;
252
331
    FMulti: boolean;
 
332
    FOnGetDividerSize: TSimpleWindowLayoutDividerPosSizeGetter;
253
333
    FOnGetLayout: TGetDefaultIDEWindowLayoutEvent;
 
334
    FOnSetDividerSize: TSimpleWindowLayoutDividerPosSizeSetter;
254
335
    FState: TIWCState;
255
336
    FTop: string;
256
337
    FRight: string;
 
338
    FDividerTemplate: TSimpleWindowLayoutDividerPosList;
 
339
    function GetDividerTemplate: TSimpleWindowLayoutDividerPosList;
257
340
    procedure SetBottom(const AValue: string);
258
341
    procedure SetLeft(const AValue: string);
259
342
    procedure SetTop(const AValue: string);
260
343
    procedure SetRight(const AValue: string);
 
344
    procedure InitSimpleLayout(ALayout: TSimpleWindowLayout);
261
345
  public
262
346
    constructor Create(aFormName: string); overload;
263
347
    constructor Create(aFormName: string;
268
352
                       aDockAlign: TAlign = alNone;
269
353
                       aMulti: boolean = false;
270
354
               GetLayoutEvent: TGetDefaultIDEWindowLayoutEvent = nil); overload;
 
355
    destructor Destroy; override;
271
356
    property FormName: string read FFormName; // prefix for all forms
272
357
    property Multi: boolean read FMulti; // there can be more than one of this form, e.g. the source editors and the package editors
273
358
    property OnCreateFormMethod: TCreateIDEWindowMethod read FCreateFormMethod write FCreateFormMethod;
286
371
                                                          write FOnGetLayout;
287
372
    procedure CheckBoundValue(s: string);
288
373
    procedure GetDefaultBounds(AForm: TCustomForm; out DefBounds: TRect);
 
374
 
 
375
    function CreateSimpleLayout: TSimpleWindowLayout;
 
376
    // TODO: Need a WindowCreator factory, by class of TForm
 
377
    // then this data can be stored per window class
 
378
    property  DividerTemplate: TSimpleWindowLayoutDividerPosList read GetDividerTemplate;
 
379
    property  OnGetDividerSize: TSimpleWindowLayoutDividerPosSizeGetter read FOnGetDividerSize write FOnGetDividerSize;
 
380
    property  OnSetDividerSize: TSimpleWindowLayoutDividerPosSizeSetter read FOnSetDividerSize write FOnSetDividerSize;
289
381
  end;
290
382
 
291
383
  { TIDEWindowCreatorList }
293
385
  TIDEWindowCreatorList = class
294
386
  private
295
387
    fItems: TFPList; // list of TIDEWindowCreator
296
 
    FOnShowForm: TShowIDEWindowEvent;
 
388
    FScreenMaxSizeForDefaults: TPoint;
297
389
    FSimpleLayoutStorage: TSimpleWindowLayoutList;
298
390
    function GetItems(Index: integer): TIDEWindowCreator;
299
391
    procedure ErrorIfFormExists(FormName: string);
326
418
    procedure CreateForm(var AForm; AFormClass: TCustomFormClass;
327
419
                         DoDisableAutoSizing: boolean; TheOwner: TComponent); // utility function to create a form with delayed autosizing
328
420
 
329
 
    property OnShowForm: TShowIDEWindowEvent read FOnShowForm write FOnShowForm; // set by the IDE to implement a default
330
 
 
331
421
    property SimpleLayoutStorage: TSimpleWindowLayoutList read FSimpleLayoutStorage;
332
422
    procedure RestoreSimpleLayout;
 
423
 
 
424
    property ScreenMaxSizeForDefaults: TPoint read FScreenMaxSizeForDefaults
 
425
                                              write FScreenMaxSizeForDefaults; // on big screens: do not span the whole screen
 
426
    function GetScreenrectForDefaults: TRect;
333
427
  end;
334
428
 
335
429
var
342
436
  { TIDEDockMaster }
343
437
 
344
438
  TIDEDockMaster = class
 
439
  protected
 
440
    FHideSimpleLayoutOptions: boolean;
345
441
  public
346
442
    procedure MakeIDEWindowDockable(AControl: TWinControl); virtual; abstract; // make AControl dockable, it can be docked and other dockable windows can be docked to it, this does not make it visible
347
443
    procedure MakeIDEWindowDockSite(AForm: TCustomForm; ASides: TDockSides = [alBottom]); virtual; abstract; // make AForm a dock site, AForm can not be docked, its Parent must be kept nil, this does not make it visible
348
444
    procedure ShowForm(AForm: TCustomForm; BringToFront: boolean); virtual; abstract; // make a form visible, set BringToFront=true if form should be shown on active screen and on front of other windows, normally this focus the form
349
445
    function AddableInWindowMenu(AForm: TCustomForm): boolean; virtual;
350
446
    procedure CloseAll; virtual; // close all forms, called after IDE has saved all and shuts down
 
447
    property HideSimpleLayoutOptions: boolean read FHideSimpleLayoutOptions;
351
448
  end;
352
449
 
353
450
var
426
523
  RegisterComponents('Misc',[TIDEDialogLayoutStorage]);
427
524
end;
428
525
 
 
526
{ TSimpleWindowLayoutDividerPosList }
 
527
 
 
528
function TSimpleWindowLayoutDividerPosList.GetItems(Index: Integer): TSimpleWindowLayoutDividerPos;
 
529
begin
 
530
  Result := TSimpleWindowLayoutDividerPos(FList[Index]);
 
531
end;
 
532
 
 
533
function TSimpleWindowLayoutDividerPosList.GetNamedItems(Index: Integer): TSimpleWindowLayoutDividerPos;
 
534
var
 
535
  i: Integer;
 
536
begin
 
537
  Result := nil;
 
538
  i := 0;
 
539
  while i < Count do begin
 
540
    if Items[i].DisplayName <> '' then begin
 
541
      if Index = 0 then begin
 
542
        Result := Items[i];
 
543
        exit;
 
544
      end;
 
545
      dec(Index);
 
546
    end;
 
547
    inc(i);
 
548
  end;
 
549
end;
 
550
 
 
551
procedure TSimpleWindowLayoutDividerPosList.Merge(AnItem: TSimpleWindowLayoutDividerPos);
 
552
var
 
553
  i: Integer;
 
554
  old: TSimpleWindowLayoutDividerPos;
 
555
begin
 
556
  i := IndexOf(AnItem.IdString);
 
557
  FList.Add(AnItem);
 
558
  if i < 0 then
 
559
    exit;
 
560
 
 
561
  old := Items[i];
 
562
  if AnItem.Id < 0 then
 
563
    AnItem.SetId(old.Id);
 
564
  if AnItem.DisplayName = '' then
 
565
    AnItem.SetDisplayName(old.FDisplayName);
 
566
  if AnItem.DefaultSize < 0 then
 
567
    AnItem.DefaultSize := old.DefaultSize;
 
568
 
 
569
  FList.Remove(old);
 
570
  old.Free;
 
571
end;
 
572
 
 
573
constructor TSimpleWindowLayoutDividerPosList.Create;
 
574
begin
 
575
  FList := TList.Create;
 
576
end;
 
577
 
 
578
destructor TSimpleWindowLayoutDividerPosList.Destroy;
 
579
begin
 
580
  Clear;
 
581
  inherited Destroy;
 
582
  FreeAndNil(FList);
 
583
end;
 
584
 
 
585
procedure TSimpleWindowLayoutDividerPosList.Assign(ADividerPosList: TSimpleWindowLayoutDividerPosList);
 
586
var
 
587
  i: Integer;
 
588
  tmp: TSimpleWindowLayoutDividerPos;
 
589
begin
 
590
  Clear;
 
591
  for i := 0 to ADividerPosList.Count - 1 do begin
 
592
    tmp := Add('');
 
593
    tmp.Assign(ADividerPosList[i]);
 
594
  end;
 
595
end;
 
596
 
 
597
procedure TSimpleWindowLayoutDividerPosList.LoadFromConfig(Config: TConfigStorage;
 
598
  const Path: string);
 
599
var
 
600
  tmp: TSimpleWindowLayoutDividerPos;
 
601
  c, i: Integer;
 
602
begin
 
603
  ClearItems;
 
604
  c := Config.GetValue(Path+'Count', 0);
 
605
  for i := 0 to c - 1 do begin
 
606
    tmp := TSimpleWindowLayoutDividerPos.Create('');
 
607
    tmp.LoadFromConfig(Config, Path + 'Item' + IntToStr(i) + '/');
 
608
    Merge(tmp);
 
609
  end;
 
610
end;
 
611
 
 
612
procedure TSimpleWindowLayoutDividerPosList.SaveToConfig(Config: TConfigStorage;
 
613
  const Path: string);
 
614
var
 
615
  i, c: Integer;
 
616
begin
 
617
  c := 0;
 
618
  for i := 0 to Count - 1 do
 
619
    if Items[i].SaveToConfig(Config, Path + 'Item' + IntToStr(c) + '/') then
 
620
      inc(c);
 
621
  for i := c to Count - 1 do
 
622
    Config.DeletePath(Path + 'Item' + IntToStr(i) + '/');
 
623
  Config.SetDeleteValue(Path+'Count', c, 0);
 
624
end;
 
625
 
 
626
procedure TSimpleWindowLayoutDividerPosList.Clear;
 
627
begin
 
628
  while FList.Count > 0 do begin
 
629
    TObject(FList[0]).Free;
 
630
    FList.Delete(0);
 
631
  end;
 
632
end;
 
633
 
 
634
procedure TSimpleWindowLayoutDividerPosList.ClearItems;
 
635
var
 
636
  i: Integer;
 
637
begin
 
638
  for i := 0 to Count - 1 do
 
639
    Items[i].Clear;
 
640
end;
 
641
 
 
642
function TSimpleWindowLayoutDividerPosList.Add(AnIdString: String;
 
643
  AnId: Integer; ADisplayName: PString): TSimpleWindowLayoutDividerPos;
 
644
var
 
645
  i: Integer;
 
646
begin
 
647
  i := IndexOf(AnId);
 
648
  if i < 0
 
649
  then begin
 
650
    Result := TSimpleWindowLayoutDividerPos.Create(AnIdString, AnId, ADisplayName);
 
651
    FList.Add(Result);
 
652
  end
 
653
  else begin
 
654
    Result := Items[i];
 
655
    if ADisplayName = nil then
 
656
      Result.SetDisplayName(ADisplayName);
 
657
  end
 
658
end;
 
659
 
 
660
function TSimpleWindowLayoutDividerPosList.Add(AnIdString: String): TSimpleWindowLayoutDividerPos;
 
661
begin
 
662
  Result := Add(AnIdString, -1, nil);
 
663
end;
 
664
 
 
665
function TSimpleWindowLayoutDividerPosList.Count: Integer;
 
666
begin
 
667
  Result := FList.Count;
 
668
end;
 
669
 
 
670
function TSimpleWindowLayoutDividerPosList.NamedCount: Integer;
 
671
var
 
672
  i: Integer;
 
673
begin
 
674
  Result := 0;
 
675
  i := Count - 1;
 
676
  while i >= 0 do begin
 
677
    if Items[i].DisplayName <> '' then inc(Result);
 
678
    dec(i);
 
679
  end;
 
680
end;
 
681
 
 
682
function TSimpleWindowLayoutDividerPosList.Find(AnId: Integer): TSimpleWindowLayoutDividerPos;
 
683
var
 
684
  i: Integer;
 
685
begin
 
686
  Result := nil;
 
687
  i := IndexOf(AnId);
 
688
  if i >= 0 then
 
689
    Result := Items[i];
 
690
end;
 
691
 
 
692
function TSimpleWindowLayoutDividerPosList.Find(AnIdString: String): TSimpleWindowLayoutDividerPos;
 
693
var
 
694
  i: Integer;
 
695
begin
 
696
  Result := nil;
 
697
  i := IndexOf(AnIdString);
 
698
  if i >= 0 then
 
699
    Result := Items[i];
 
700
end;
 
701
 
 
702
function TSimpleWindowLayoutDividerPosList.IndexOf(AnId: Integer): Integer;
 
703
begin
 
704
  Result := Flist.Count-1;
 
705
  while Result >= 0 do begin
 
706
    if Items[Result].Id = AnId then
 
707
      exit;
 
708
    dec(Result);
 
709
  end;
 
710
end;
 
711
 
 
712
function TSimpleWindowLayoutDividerPosList.IndexOf(AnIdString: String): Integer;
 
713
begin
 
714
  Result := Flist.Count-1;
 
715
  while Result >= 0 do begin
 
716
    if Items[Result].IdString = AnIdString then
 
717
      exit;
 
718
    dec(Result);
 
719
  end;
 
720
end;
 
721
 
 
722
function TSimpleWindowLayoutDividerPosList.IndexOf(AnItem: TSimpleWindowLayoutDividerPos): Integer;
 
723
begin
 
724
  Result := FList.IndexOf(AnItem);
 
725
end;
 
726
 
 
727
{ TSimpleWindowLayoutDividerPos }
 
728
 
 
729
function TSimpleWindowLayoutDividerPos.GetDisplayName: String;
 
730
begin
 
731
  if FDisplayName = nil then
 
732
    Result := ''
 
733
  else
 
734
    Result := FDisplayName^;
 
735
end;
 
736
 
 
737
procedure TSimpleWindowLayoutDividerPos.SetDisplayName(ADisplayName: PString);
 
738
begin
 
739
  FDisplayName := ADisplayName;
 
740
end;
 
741
 
 
742
procedure TSimpleWindowLayoutDividerPos.SetId(AnId: Integer);
 
743
begin
 
744
  FId := AnId;
 
745
end;
 
746
 
 
747
constructor TSimpleWindowLayoutDividerPos.Create(AnIdString: String);
 
748
begin
 
749
  Create(AnIdString, -1, nil);
 
750
end;
 
751
 
 
752
constructor TSimpleWindowLayoutDividerPos.Create(AnIdString: String; AnId: Integer;
 
753
  ADisplayName: PString);
 
754
begin
 
755
  FDefaultSize := -1;
 
756
  Clear;
 
757
  FId := AnId;
 
758
  FIdString := AnIdString;
 
759
  FDisplayName := ADisplayName;
 
760
end;
 
761
 
 
762
procedure TSimpleWindowLayoutDividerPos.Assign(ADividerPos: TSimpleWindowLayoutDividerPos);
 
763
begin
 
764
  FDefaultSize := ADividerPos.FDefaultSize;
 
765
  FDisplayName := ADividerPos.FDisplayName;
 
766
  FId          := ADividerPos.FId;
 
767
  FIdString    := ADividerPos.FIdString;
 
768
  FPlacement   := ADividerPos.FPlacement;
 
769
  FSize        := ADividerPos.FSize;
 
770
end;
 
771
 
 
772
procedure TSimpleWindowLayoutDividerPos.LoadFromConfig(Config: TConfigStorage;
 
773
  const Path: string);
 
774
var
 
775
  s: String;
 
776
begin
 
777
  Clear;
 
778
  FIdString := Config.GetValue(Path+'ID', '');
 
779
  FSize := Config.GetValue(Path+'Size', -1);
 
780
  s := Config.GetValue(Path+'Placement', 'iwpdUseWindowSetting');
 
781
  try
 
782
    ReadStr(s, FPlacement);
 
783
  except
 
784
    FPlacement := iwpdUseWindowSetting;
 
785
  end;
 
786
end;
 
787
 
 
788
function TSimpleWindowLayoutDividerPos.SaveToConfig(Config: TConfigStorage;
 
789
  const Path: string): Boolean;
 
790
var
 
791
  s: String;
 
792
begin
 
793
  Result := (FSize <> -1) or (FPlacement <> iwpdUseWindowSetting);
 
794
  if not Result then
 
795
    exit;
 
796
  WriteStr(s, FPlacement);
 
797
  Config.SetDeleteValue(Path+'ID', FIdString, '');
 
798
  Config.SetDeleteValue(Path+'Size', FSize, -1);
 
799
  Config.SetDeleteValue(Path+'Placement', s, 'iwpdUseWindowSetting');
 
800
end;
 
801
 
 
802
procedure TSimpleWindowLayoutDividerPos.Clear;
 
803
begin
 
804
  FSize := FDefaultSize;
 
805
  FPlacement := iwpdUseWindowSetting;
 
806
end;
 
807
 
429
808
{ TIDEDialogLayout }
430
809
 
431
 
procedure TIDEDialogLayout.SetHeight(const AValue: integer);
432
 
begin
433
 
  if FHeight=AValue then exit;
434
 
  FHeight:=AValue;
435
 
  Modified:=true;
436
 
end;
437
 
 
438
810
procedure TIDEDialogLayout.SetList(const AValue: TIDEDialogLayoutList);
439
811
begin
440
812
  if FList=AValue then exit;
455
827
  Modified:=true;
456
828
end;
457
829
 
 
830
procedure TIDEDialogLayout.SetHeight(const AValue: integer);
 
831
begin
 
832
  if FHeight=AValue then exit;
 
833
  FHeight:=AValue;
 
834
  Modified:=true;
 
835
end;
 
836
 
458
837
constructor TIDEDialogLayout.Create(const TheName: string;
459
838
  TheList: TIDEDialogLayoutList);
460
839
begin
597
976
    dec(Result);
598
977
end;
599
978
 
600
 
procedure TIDEDialogLayoutList.LoadFromConfig(Config: TConfigStorage;
601
 
  const Path: string);
 
979
procedure TIDEDialogLayoutList.LoadFromConfig(Config: TConfigStorage; const Path: string);
602
980
var
603
981
  NewCount, i: integer;
604
982
  NewDialogLayout: TIDEDialogLayout;
613
991
  Modified:=false;
614
992
end;
615
993
 
616
 
procedure TIDEDialogLayoutList.SaveToConfig(Config: TConfigStorage;
617
 
  const Path: string);
 
994
procedure TIDEDialogLayoutList.SaveToConfig(Config: TConfigStorage; const Path: string);
618
995
var i: integer;
619
996
begin
620
997
  Config.SetDeleteValue(Path+'Count',Count,0);
627
1004
 
628
1005
procedure TIDEDialogLayoutStorage.OnCreateForm(Sender: TObject);
629
1006
begin
630
 
  if Sender=nil then ;
631
1007
  IDEDialogLayoutList.ApplyLayout(Sender as TControl);
632
1008
end;
633
1009
 
634
1010
procedure TIDEDialogLayoutStorage.OnCloseForm(Sender: TObject;
635
1011
  var CloseAction: TCloseAction);
636
1012
begin
637
 
  if Sender=nil then ;
638
1013
  IDEDialogLayoutList.SaveLayout(Sender as TControl);
639
1014
end;
640
1015
 
643
1018
  Form: TCustomForm;
644
1019
begin
645
1020
  inherited Create(TheOwner);
646
 
  if Owner is TCustomForm then begin
 
1021
  if Owner is TCustomForm then
 
1022
  begin
647
1023
    Form:=TCustomForm(Owner);
648
1024
    Form.AddHandlerCreate(@OnCreateForm);
649
1025
    Form.AddHandlerClose(@OnCloseForm);
654
1030
var
655
1031
  Form: TCustomForm;
656
1032
begin
657
 
  if Owner is TCustomForm then begin
 
1033
  if Owner is TCustomForm then
 
1034
  begin
658
1035
    Form:=TCustomForm(Owner);
659
1036
    Form.RemoveAllHandlersOfObject(Self);
660
1037
  end;
664
1041
{ TSimpleWindowLayout }
665
1042
 
666
1043
constructor TSimpleWindowLayout.Create(AFormID: string);
 
1044
var
 
1045
  Creator: TIDEWindowCreator;
667
1046
begin
668
1047
  inherited Create(nil);
669
 
  FormID:=AFormID;
670
 
  fDefaultWindowPlacement:=iwpRestoreWindowGeometry;
 
1048
  FDividers := TSimpleWindowLayoutDividerPosList.Create;
 
1049
  FormID := AFormID;
 
1050
  fDefaultWindowPlacement := iwpRestoreWindowGeometry;
671
1051
  Clear;
 
1052
  Creator := IDEWindowCreators.FindWithName(AFormID);
 
1053
  if Creator <> nil then
 
1054
    Creator.InitSimpleLayout(Self);
672
1055
end;
673
1056
 
674
1057
destructor TSimpleWindowLayout.Destroy;
675
1058
begin
676
1059
  Form:=nil;
677
1060
  inherited Destroy;
678
 
end;
679
 
 
680
 
procedure TSimpleWindowLayout.LoadFromConfig(Config: TConfigStorage;
681
 
  const Path: string);
 
1061
  FDividers.Free;
 
1062
end;
 
1063
 
 
1064
function TSimpleWindowLayout.CreateCopy: TSimpleWindowLayout;
 
1065
begin
 
1066
  Result := TSimpleWindowLayout.Create(FFormID);
 
1067
  Result.Assign(Self);
 
1068
end;
 
1069
 
 
1070
procedure TSimpleWindowLayout.LoadFromConfig(Config: TConfigStorage; const Path: string);
682
1071
var
683
1072
  P: string;
684
1073
begin
694
1083
  fWindowPlacement:=StrToIDEWindowPlacement(Config.GetValue(
695
1084
    P+'WindowPlacement/Value',IDEWindowPlacementNames[fWindowPlacement]));
696
1085
  // custom position
697
 
  fLeft:=Config.GetValue(P+'CustomPosition/Left',fLeft);
698
 
  fTop:=Config.GetValue(P+'CustomPosition/Top',fTop);
699
 
  fWidth:=Config.GetValue(P+'CustomPosition/Width',fWidth);
700
 
  fHeight:=Config.GetValue(P+'CustomPosition/Height',fHeight);
 
1086
  Left := Config.GetValue(P+'CustomPosition/Left', Left);
 
1087
  Top := Config.GetValue(P+'CustomPosition/Top', Top);
 
1088
  Width := Config.GetValue(P+'CustomPosition/Width', Width);
 
1089
  Height := Config.GetValue(P+'CustomPosition/Height', Height);
701
1090
  // state
702
1091
  fWindowState:=StrToIDEWindowState(Config.GetValue(
703
1092
    P+'WindowState/Value',IDEWindowStateNames[fWindowState]));
704
1093
  FVisible:=Config.GetValue(P+'Visible/Value',false);
705
1094
  //debugln(['TSimpleWindowLayout.LoadFromConfig ',FormID,' ',Left,',',Top,',',Width,',',Height]);
 
1095
  FDividers.LoadFromConfig(Config, P + 'Divider/');
706
1096
end;
707
1097
 
708
1098
procedure TSimpleWindowLayout.SaveToConfig(Config: TConfigStorage;
720
1110
    IDEWindowPlacementNames[fWindowPlacement],
721
1111
    IDEWindowPlacementNames[iwpRestoreWindowSize]);
722
1112
  // custom position
723
 
  Config.SetDeleteValue(P+'CustomPosition/Left',fLeft,0);
724
 
  Config.SetDeleteValue(P+'CustomPosition/Top',fTop,0);
725
 
  Config.SetDeleteValue(P+'CustomPosition/Width',fWidth,0);
726
 
  Config.SetDeleteValue(P+'CustomPosition/Height',fHeight,0);
 
1113
  Config.SetDeleteValue(P+'CustomPosition/Left', Left, 0);
 
1114
  Config.SetDeleteValue(P+'CustomPosition/Top', Top, 0);
 
1115
  Config.SetDeleteValue(P+'CustomPosition/Width', Width, 0);
 
1116
  Config.SetDeleteValue(P+'CustomPosition/Height', Height, 0);
727
1117
  // state
728
1118
  Config.SetValue(P+'WindowState/Value',IDEWindowStateNames[fWindowState]);
729
1119
  Config.SetDeleteValue(P+'Visible/Value',FVisible,false);
 
1120
  FDividers.SaveToConfig(Config, P + 'Divider/');
730
1121
end;
731
1122
 
732
1123
procedure TSimpleWindowLayout.OnFormClose(Sender: TObject;
749
1140
 
750
1141
function TSimpleWindowLayout.CustomCoordinatesAreValid: boolean;
751
1142
begin
752
 
  Result:=(Width>0) and (Height>0) and (Left>10-Width) and (Top>10-Height);
 
1143
  Result:=(Width>0) and (Height>0); // and (Left>10-Width) and (Top>10-Height);
753
1144
end;
754
1145
 
755
1146
procedure TSimpleWindowLayout.CloseForm;
758
1149
  Form:=nil;
759
1150
end;
760
1151
 
 
1152
function TSimpleWindowLayout.ValidateAndSetCoordinates: Boolean;
 
1153
var
 
1154
  i: Integer;
 
1155
  NewBounds: TRect;
 
1156
begin
 
1157
  Result := False;
 
1158
  if CustomCoordinatesAreValid then begin
 
1159
    // explicit position
 
1160
    NewBounds := Bounds(Left, Top, Width, Height);
 
1161
    // set minimum size
 
1162
    if NewBounds.Right - NewBounds.Left < 60 then
 
1163
      NewBounds.Right := NewBounds.Left + 60;
 
1164
    if NewBounds.Bottom - NewBounds.Top < 60 then
 
1165
      NewBounds.Bottom := NewBounds.Top + 60;
 
1166
 
 
1167
    // Move to visible area :
 
1168
    // window is out at left side of screen
 
1169
    if NewBounds.Right < Screen.DesktopLeft + 60 then
 
1170
      OffsetRect(NewBounds, Screen.DesktopLeft + 60 - NewBounds.Right, 0);
 
1171
 
 
1172
    // window is out above the screen
 
1173
    if NewBounds.Bottom < Screen.DesktopTop+60 then
 
1174
      OffsetRect(NewBounds, 0, Screen.DesktopTop + 60 - NewBounds.Bottom);
 
1175
 
 
1176
    // window is out at right side of screen, i = right edge of screen - 60
 
1177
    i := Screen.DesktopWidth + Screen.DesktopLeft - 60;
 
1178
    if NewBounds.Left > i then begin
 
1179
      NewBounds.Left := i;
 
1180
      NewBounds.Right := NewBounds.Right + i - NewBounds.Left;
 
1181
    end;
 
1182
 
 
1183
    // window is out below the screen, i = bottom edge of screen - 60
 
1184
    i := Screen.DesktopHeight + Screen.DesktopTop - 60;
 
1185
    if NewBounds.Top > i then begin
 
1186
      NewBounds.Top := i;
 
1187
      NewBounds.Bottom := NewBounds.Bottom + i - NewBounds.Top;
 
1188
    end;
 
1189
 
 
1190
    // set bounds (do not use SetRestoredBounds - that flickers with the current LCL implementation)
 
1191
    FForm.SetBounds(NewBounds.Left, NewBounds.Top,
 
1192
                    NewBounds.Right - NewBounds.Left,
 
1193
                    NewBounds.Bottom - NewBounds.Top);
 
1194
    Result := True;
 
1195
  end;
 
1196
end;
 
1197
 
761
1198
function TSimpleWindowLayout.FormBaseID(out SubIndex: Integer): String;
762
1199
var
763
1200
  i: Integer;
776
1213
procedure TSimpleWindowLayout.SetForm(const AValue: TCustomForm);
777
1214
begin
778
1215
  if fForm=AValue then exit;
779
 
  if (Form<>nil) then begin
 
1216
  if Assigned(Form) then
 
1217
  begin
780
1218
    RemoveFreeNotification(Form);
781
1219
    Form.RemoveHandlerClose(@OnFormClose);
782
1220
  end;
783
1221
  fForm:=AValue;
784
 
  if (Form<>nil) then begin
 
1222
  if Assigned(Form) then
 
1223
  begin
785
1224
    fFormID := Form.Name;
786
1225
    FFormCaption := Form.Caption;
787
1226
    FreeNotification(Form);
 
1227
    Form.AddHandlerClose(@OnFormClose);
788
1228
    Applied:=false;
789
1229
  end;
790
1230
end;
815
1255
  fWidth:=0;
816
1256
  fHeight:=0;
817
1257
  fWindowState:=iwsNormal;
 
1258
  FDividers.ClearItems;
818
1259
end;
819
1260
 
820
1261
procedure TSimpleWindowLayout.ReadCurrentCoordinates;
850
1291
begin
851
1292
  Clear;
852
1293
  FApplied:=Layout.Applied;
853
 
  Form:=Layout.Form;
854
 
  fWindowPlacement:=Layout.fWindowPlacement;
855
 
  fLeft:=Layout.fLeft;
856
 
  fTop:=Layout.fTop;
857
 
  fWidth:=Layout.fWidth;
858
 
  fHeight:=Layout.fHeight;
859
 
  fWindowState:=Layout.fWindowState;
860
 
  fFormID:=Layout.fFormID;
861
 
  fDefaultWindowPlacement:=Layout.fDefaultWindowPlacement;
 
1294
  FForm:=Layout.FForm;
 
1295
  FWindowPlacement:=Layout.FWindowPlacement;
 
1296
  FLeft:=Layout.FLeft;
 
1297
  FTop:=Layout.FTop;
 
1298
  FWidth:=Layout.FWidth;
 
1299
  FHeight:=Layout.FHeight;
 
1300
  FWindowState:=Layout.FWindowState;
 
1301
  FFormID:=Layout.FFormID;
 
1302
  FDefaultWindowPlacement:=Layout.FDefaultWindowPlacement;
 
1303
  FDividers.Assign(Layout.FDividers);
 
1304
end;
 
1305
 
 
1306
procedure TSimpleWindowLayout.ReadCurrentDividers(AForce: Boolean = False);
 
1307
var
 
1308
  i, j: Integer;
 
1309
  f: Boolean;
 
1310
  Creator: TIDEWindowCreator;
 
1311
begin
 
1312
  Creator:=IDEWindowCreators.FindWithName(FormID);
 
1313
  if (Creator = nil) or (Creator.OnGetDividerSize = nil) then exit;
 
1314
  if fForm = nil then exit;
 
1315
  for i := 0 to FDividers.Count - 1 do begin
 
1316
    if FDividers[i].FId < 0 then continue;
 
1317
    f := AForce;
 
1318
    case FDividers[i].Placement of
 
1319
      iwpdRestore:
 
1320
        f := true;
 
1321
      iwpdUseWindowSetting:
 
1322
        f := WindowPlacement in [iwpRestoreWindowGeometry, iwpRestoreWindowSize];
 
1323
    end;
 
1324
    if f then
 
1325
      if Creator.OnGetDividerSize(fForm, FDividers[i].Id, j) then
 
1326
        FDividers[i].Size := j
 
1327
      else
 
1328
        FDividers[i].Size := -1; // Default / Not Changed / Unavailable
 
1329
  end;
862
1330
end;
863
1331
 
864
1332
procedure TSimpleWindowLayout.GetCurrentPosition;
868
1336
  iwpRestoreWindowGeometry, iwpRestoreWindowSize:
869
1337
    ReadCurrentCoordinates;
870
1338
  end;
 
1339
  ReadCurrentDividers;
871
1340
  ReadCurrentState;
872
1341
  //debugln('TSimpleWindowLayout.GetCurrentPosition ',DbgSName(Self),' ',FormID,' Width=',dbgs(Width));
873
1342
end;
874
1343
 
 
1344
function TSimpleWindowLayout.Apply: Boolean;
 
1345
begin
 
1346
  Result := False;
 
1347
  if fForm = nil then exit;
 
1348
  Applied:=true;
 
1349
  {$IFDEF VerboseIDEDocking}
 
1350
  debugln(['TSimpleWindowLayoutList.ApplyAndShow restore ',
 
1351
          FormID,' ',IDEWindowPlacementNames[WindowPlacement],
 
1352
          ' ',Left,',',Top,',',Width,',',Height]);
 
1353
  {$ENDIF}
 
1354
 
 
1355
  case WindowPlacement of
 
1356
  iwpCustomPosition,iwpRestoreWindowGeometry:
 
1357
    begin
 
1358
      //DebugLn(['TMainIDE.OnApplyWindowLayout ',IDEWindowStateNames[WindowState]]);
 
1359
      case WindowState of
 
1360
        iwsMinimized: FForm.WindowState:=wsMinimized;
 
1361
        iwsMaximized: FForm.WindowState:=wsMaximized;
 
1362
      end;
 
1363
      Result := ValidateAndSetCoordinates;     // Adjust bounds to screen area and apply them.
 
1364
      if WindowState in [iwsMinimized, iwsMaximized] then
 
1365
        Result := True;
 
1366
    end;
 
1367
  iwpUseWindowManagerSetting:
 
1368
    Result := True;
 
1369
  end;
 
1370
 
 
1371
  ApplyDivider;
 
1372
end;
 
1373
 
 
1374
procedure TSimpleWindowLayout.ApplyDivider(AForce: Boolean = False);
 
1375
var
 
1376
  i: Integer;
 
1377
  f: Boolean;
 
1378
  Creator: TIDEWindowCreator;
 
1379
begin
 
1380
  Creator:=IDEWindowCreators.FindWithName(FormID);
 
1381
  if (Creator <> nil) and (Creator.OnSetDividerSize <> nil) then begin
 
1382
    for i := 0 to FDividers.Count - 1 do begin
 
1383
      if (FDividers[i].FId < 0) or (FDividers[i].Size < 0) then continue;
 
1384
      f := AForce;
 
1385
      case FDividers[i].Placement of
 
1386
        iwpdRestore, iwpdCustomSize:
 
1387
          f := true;
 
1388
        iwpdUseWindowSetting:
 
1389
          f := WindowPlacement in [iwpRestoreWindowGeometry, iwpRestoreWindowSize];
 
1390
      end;
 
1391
      if f then
 
1392
        Creator.OnSetDividerSize(fForm, FDividers[i].Id, FDividers[i].Size);
 
1393
    end;
 
1394
  end;
 
1395
end;
 
1396
 
875
1397
{ TSimpleWindowLayoutList }
876
1398
 
877
1399
procedure TSimpleWindowLayoutList.Clear;
878
 
var i: integer;
 
1400
var
 
1401
  i: integer;
879
1402
begin
880
1403
  for i:=0 to Count-1 do Items[i].Free;
881
1404
  fItems.Clear;
918
1441
  while (Result>=0) and (FormID<>Items[Result].GetFormID) do dec(Result);
919
1442
end;
920
1443
 
921
 
procedure TSimpleWindowLayoutList.LoadFromConfig(Config: TConfigStorage;
922
 
  const Path: string);
 
1444
procedure TSimpleWindowLayoutList.LoadFromConfig(Config: TConfigStorage; const Path: string);
 
1445
// do not clear, just add/replace the values from the config
923
1446
var
924
1447
  i: integer;
925
1448
  ID: String;
926
1449
begin
927
 
  // do not clear, just add/replace the values from the config
928
 
 
929
1450
  // create new windows
930
1451
  i := Config.GetValue(Path+'Desktop/FormIdCount', 0);
931
1452
  //debugln(['TSimpleWindowLayoutList.LoadFromConfig ',i]);
941
1462
    Items[i].LoadFromConfig(Config,Path);
942
1463
end;
943
1464
 
944
 
procedure TSimpleWindowLayoutList.SaveToConfig(Config: TConfigStorage;
945
 
  const Path: string);
946
 
var i: integer;
 
1465
procedure TSimpleWindowLayoutList.SaveToConfig(Config: TConfigStorage; const Path: string);
 
1466
var
 
1467
  i: integer;
947
1468
begin
948
1469
  Config.SetDeleteValue(Path+'Desktop/FormIdCount',Count,0);
949
1470
  //debugln(['TSimpleWindowLayoutList.SaveToConfig ',Count]);
959
1480
end;
960
1481
 
961
1482
function TSimpleWindowLayoutList.ItemByForm(AForm: TCustomForm): TSimpleWindowLayout;
962
 
var i: integer;
 
1483
var
 
1484
  i: integer;
963
1485
begin
964
1486
  i:=Count-1;
965
1487
  while (i>=0) do begin
970
1492
  Result:=nil;
971
1493
end;
972
1494
 
973
 
function TSimpleWindowLayoutList.ItemByFormID(const FormID: string
974
 
  ): TSimpleWindowLayout;
975
 
var i: integer;
 
1495
function TSimpleWindowLayoutList.ItemByFormID(const FormID: string): TSimpleWindowLayout;
 
1496
var
 
1497
  i: integer;
976
1498
begin
977
1499
  i:=IndexOf(FormID);
978
1500
  if i>=0 then
981
1503
    Result:=nil;
982
1504
end;
983
1505
 
984
 
function TSimpleWindowLayoutList.ItemByFormCaption(const aFormCaption: string
985
 
  ): TSimpleWindowLayout;
986
 
var i: integer;
 
1506
function TSimpleWindowLayoutList.ItemByFormCaption(const aFormCaption: string): TSimpleWindowLayout;
 
1507
var
 
1508
  i: integer;
987
1509
begin
988
1510
  i := Count - 1;
989
1511
  while i >= 0 do begin
1015
1537
  DockSibling: TCustomForm;
1016
1538
  DockSiblingBounds: TRect;
1017
1539
  Offset: TPoint;
 
1540
  ARestoreVisible: Boolean;
1018
1541
begin
1019
1542
  {$IFDEF VerboseIDEDocking}
1020
 
  debugln(['TSimpleWindowLayoutList.ApplyAndShow Form=',DbgSName(AForm),' ',BringToFront]);
 
1543
  debugln(['TSimpleWindowLayoutList.ApplyAndShow Form=',DbgSName(AForm),' ',BringToFront,
 
1544
           '  DesktopWidth=', Screen.DesktopWidth, '  DesktopHeight=', Screen.DesktopHeight]);
1021
1545
  {$ENDIF}
1022
1546
  try
1023
1547
    ALayout:=ItemByFormID(AForm.Name);
1025
1549
    begin
1026
1550
      ALayout.Form:=AForm;
1027
1551
      if ALayout.Applied then exit;
1028
 
      ALayout.Applied:=true;
1029
 
      {$IFDEF VerboseIDEDocking}
1030
 
      debugln(['TSimpleWindowLayoutList.ApplyAndShow restore ',ALayout.FormID,' ',IDEWindowPlacementNames[ALayout.WindowPlacement],' Valid=',ALayout.CustomCoordinatesAreValid,' ',ALayout.Left,',',ALayout.Top,',',ALayout.Width,',',ALayout.Height]);
1031
 
      {$ENDIF}
1032
 
 
1033
 
      case ALayout.WindowPlacement of
1034
 
      iwpCustomPosition,iwpRestoreWindowGeometry:
1035
 
        begin
1036
 
          //DebugLn(['TMainIDE.OnApplyWindowLayout ',IDEWindowStateNames[ALayout.WindowState]]);
1037
 
          case ALayout.WindowState of
1038
 
          iwsMinimized: AForm.WindowState:=wsMinimized;
1039
 
          iwsMaximized: AForm.WindowState:=wsMaximized;
1040
 
          end;
1041
 
 
1042
 
          if (ALayout.CustomCoordinatesAreValid) then begin
1043
 
            // explicit position
1044
 
            NewBounds:=Bounds(ALayout.Left,ALayout.Top,ALayout.Width,ALayout.Height);
1045
 
            // set minimum size
1046
 
            if NewBounds.Right-NewBounds.Left<20 then
1047
 
              NewBounds.Right:=NewBounds.Left+20;
1048
 
            if NewBounds.Bottom-NewBounds.Top<20 then
1049
 
              NewBounds.Bottom:=NewBounds.Top+20;
1050
 
            // move to visible area
1051
 
            if NewBounds.Right<20 then
1052
 
              OffsetRect(NewBounds,20-NewBounds.Right,0);
1053
 
            if NewBounds.Bottom<20 then
1054
 
              OffsetRect(NewBounds,0,20-NewBounds.Bottom);
1055
 
            if NewBounds.Left>Screen.DesktopWidth-20 then
1056
 
              OffsetRect(NewBounds,NewBounds.Left-(Screen.DesktopWidth-20),0);
1057
 
            if NewBounds.Top>Screen.DesktopHeight-20 then
1058
 
              OffsetRect(NewBounds,NewBounds.Top-(Screen.DesktopHeight-20),0);
1059
 
            // set bounds (do not use SetRestoredBounds - that flickers with the current LCL implementation)
1060
 
            AForm.SetBounds(
1061
 
              NewBounds.Left,NewBounds.Top,
1062
 
              NewBounds.Right-NewBounds.Left,NewBounds.Bottom-NewBounds.Top);
1063
 
            exit;
1064
 
          end;
1065
 
 
1066
 
          if ALayout.WindowState in [iwsMinimized, iwsMaximized] then
1067
 
            exit;
1068
 
        end;
1069
 
 
1070
 
      iwpUseWindowManagerSetting:
1071
 
        begin
1072
 
          exit;
1073
 
        end;
1074
 
      end;
 
1552
      if ALayout.Apply then exit;
1075
1553
    end;
1076
1554
 
1077
1555
    {$IFDEF VerboseIDEDocking}
1078
 
    debugln(['TSimpleWindowLayoutList.ApplyAndShow no stored layout found, layout registered=',ALayout<>nil,' AForm=',DbgSName(AForm)]);
 
1556
    debugln(['TSimpleWindowLayoutList.ApplyAndShow no stored layout found, layout registered=',
 
1557
            ALayout<>nil,' AForm=',DbgSName(AForm)]);
1079
1558
    {$ENDIF}
1080
1559
 
1081
1560
    // no layout found => use default
1144
1623
    end;
1145
1624
  finally
1146
1625
    if (AForm.WindowState in [wsNormal,wsMaximized]) and BringToFront then
1147
 
      AForm.ShowOnTop
1148
 
    else
1149
 
      AForm.Visible:=true;
 
1626
    begin
 
1627
      // do not change Visible property while designing form. issue #20602
 
1628
      // we save it into ARestoreVisible before any changes from here.
 
1629
      if (csDesigning in AForm.ComponentState) and (AForm.Designer <> nil) then
 
1630
        ARestoreVisible := AForm.Visible;
 
1631
 
 
1632
      AForm.ShowOnTop;
 
1633
 
 
1634
      if (csDesigning in AForm.ComponentState) and (AForm.Designer <> nil) then
 
1635
        AForm.Visible := ARestoreVisible;
 
1636
    end else
 
1637
    begin
 
1638
      if (csDesigning in AForm.ComponentState) and (AForm.Designer <> nil) then
 
1639
        ARestoreVisible := AForm.Visible;
 
1640
 
 
1641
      AForm.Visible := True;
 
1642
      if (AForm.WindowState in [wsMinimized]) then
 
1643
      begin
 
1644
        if BringToFront then
 
1645
        begin
 
1646
          // issue #19769
 
1647
          if AForm.Visible and not (fsModal in AForm.FormState) then
 
1648
            AForm.Visible := False;
 
1649
          AForm.ShowOnTop;
 
1650
        end;
 
1651
      end;
 
1652
 
 
1653
      if (csDesigning in AForm.ComponentState) and (AForm.Designer <> nil) then
 
1654
        AForm.Visible := ARestoreVisible;
 
1655
    end;
1150
1656
  end;
1151
1657
end;
1152
1658
 
1158
1664
end;
1159
1665
 
1160
1666
procedure TSimpleWindowLayoutList.Assign(SrcList: TSimpleWindowLayoutList);
1161
 
var i: integer;
1162
 
  NewLayout: TSimpleWindowLayout;
 
1667
var
 
1668
  i: integer;
1163
1669
begin
1164
1670
  Clear;
1165
1671
  if SrcList=nil then exit;
1166
1672
  for i:=0 to SrcList.Count-1 do begin
1167
 
    NewLayout:=TSimpleWindowLayout.Create(SrcList[i].FormID);
1168
 
    NewLayout.Assign(SrcList[i]);
1169
 
    Add(NewLayout);
 
1673
    Add(SrcList[i].CreateCopy);
1170
1674
  end;
1171
1675
end;
1172
1676
 
1202
1706
  FBottom:=AValue;
1203
1707
end;
1204
1708
 
 
1709
function TIDEWindowCreator.GetDividerTemplate: TSimpleWindowLayoutDividerPosList;
 
1710
begin
 
1711
  If FDividerTemplate = nil then
 
1712
    FDividerTemplate := TSimpleWindowLayoutDividerPosList.Create;
 
1713
  Result := FDividerTemplate;
 
1714
end;
 
1715
 
1205
1716
procedure TIDEWindowCreator.SetLeft(const AValue: string);
1206
1717
begin
1207
1718
  CheckBoundValue(AValue);
1244
1755
var
1245
1756
  aRight: LongInt;
1246
1757
  aBottom: LongInt;
 
1758
  ScreenR: TRect;
 
1759
  ScreenW: Integer;
 
1760
  ScreenH: Integer;
1247
1761
begin
 
1762
  ScreenR:=IDEWindowCreators.GetScreenrectForDefaults;
 
1763
  ScreenW:=ScreenR.Right-ScreenR.Left;
 
1764
  ScreenH:=ScreenR.Bottom-ScreenR.Top;
 
1765
 
1248
1766
  // left
1249
1767
  if Left='' then
1250
1768
    DefBounds.Left:=AForm.Left
1251
1769
  else if Left[length(Left)]='%' then
1252
 
    DefBounds.Left:=Screen.Width*StrToIntDef(copy(Left,1,length(Left)-1),0) div 100
 
1770
    DefBounds.Left:=ScreenR.Left+ScreenW*StrToIntDef(copy(Left,1,length(Left)-1),0) div 100
1253
1771
  else
1254
 
    DefBounds.Left:=StrToIntDef(Left,0);
 
1772
    DefBounds.Left:=ScreenR.Left+StrToIntDef(Left,0);
1255
1773
  // top
1256
1774
  if Top='' then
1257
1775
    DefBounds.Top:=AForm.Top
1258
1776
  else if Top[length(Top)]='%' then
1259
 
    DefBounds.Top:=Screen.Height*StrToIntDef(copy(Top,1,length(Top)-1),0) div 100
 
1777
    DefBounds.Top:=ScreenR.Top+ScreenH*StrToIntDef(copy(Top,1,length(Top)-1),0) div 100
1260
1778
  else
1261
 
    DefBounds.Top:=StrToIntDef(Top,0);
 
1779
    DefBounds.Top:=ScreenR.Top+StrToIntDef(Top,0);
1262
1780
  // right
1263
1781
  if Right='' then
1264
1782
    aRight:=DefBounds.Left+AForm.Width
1265
 
  else if Right[length(Right)]='%' then
1266
 
    aRight:=Screen.Width*StrToIntDef(copy(Right,1,length(Right)-1),0) div 100
1267
 
  else
1268
 
    aRight:=StrToIntDef(Right,0);
1269
 
  if aRight<0 then
1270
 
    aRight:=Screen.Width-aRight
1271
 
  else if (Right<>'') and (Right[1]='+') then
1272
 
    inc(aRight,DefBounds.Left);
 
1783
  else begin
 
1784
    // 300 = fixed at 300,
 
1785
    // +300 = Left+300
 
1786
    // 30% = fixed at 30% on screen
 
1787
    // +30% = Left+30% of screen
 
1788
    // -300 = fixed 300 from right border of screen
 
1789
    // -30% = fixed 30% from right border of screen
 
1790
    if Right[length(Right)]='%' then
 
1791
      aRight:=ScreenW*StrToIntDef(copy(Right,1,length(Right)-1),0) div 100
 
1792
    else
 
1793
      aRight:=StrToIntDef(Right,0);
 
1794
    if aRight<0 then
 
1795
      aRight:=ScreenR.Right+aRight // relative to right of screen
 
1796
    else if (Right<>'') and (Right[1]='+') then
 
1797
      inc(aRight,DefBounds.Left) // relative to Left
 
1798
    else
 
1799
      inc(aRight,ScreenR.Left); // relative to left of screen
 
1800
  end;
1273
1801
  DefBounds.Right:=aRight;
1274
1802
  // bottom
1275
1803
  if Bottom='' then
1276
1804
    aBottom:=DefBounds.Top+AForm.Height
1277
 
  else if Bottom[length(Bottom)]='%' then
1278
 
    aBottom:=Screen.Height*StrToIntDef(copy(Bottom,1,length(Bottom)-1),0) div 100
1279
 
  else
1280
 
    aBottom:=StrToIntDef(Bottom,0);
1281
 
  if aBottom<0 then
1282
 
    aBottom:=Screen.Height-aBottom
1283
 
  else if (Bottom<>'') and (Bottom[1]='+') then
1284
 
    inc(aBottom,DefBounds.Top);
 
1805
  else begin
 
1806
    // 300 = fixed at 300,
 
1807
    // +300 = Top+300
 
1808
    // 30% = fixed at 30% on screen
 
1809
    // +30% = Top+30% of screen
 
1810
    // -300 = fixed 300 from bottom border of screen
 
1811
    // -30% = fixed 30% from bottom border of screen
 
1812
    if Bottom[length(Bottom)]='%' then
 
1813
      aBottom:=ScreenH*StrToIntDef(copy(Bottom,1,length(Bottom)-1),0) div 100
 
1814
    else
 
1815
      aBottom:=StrToIntDef(Bottom,0);
 
1816
    if aBottom<0 then
 
1817
      aBottom:=ScreenR.Bottom+aBottom // relative to bottom of screen
 
1818
    else if (Bottom<>'') and (Bottom[1]='+') then
 
1819
      inc(aBottom,DefBounds.Top) // relative to Top
 
1820
    else
 
1821
      inc(aBottom,ScreenR.Top); // relative to top of screen
 
1822
  end;
1285
1823
  DefBounds.Bottom:=aBottom;
1286
1824
end;
1287
1825
 
 
1826
function TIDEWindowCreator.CreateSimpleLayout: TSimpleWindowLayout;
 
1827
begin
 
1828
  Result:=IDEWindowCreators.SimpleLayoutStorage.ItemByFormID(FormName);
 
1829
  if not Assigned(Result) then
 
1830
  begin
 
1831
    Result := IDEWindowCreators.SimpleLayoutStorage.CreateWindowLayout(FormName);
 
1832
    InitSimpleLayout(Result);
 
1833
  end;
 
1834
end;
 
1835
 
 
1836
procedure TIDEWindowCreator.InitSimpleLayout(ALayout: TSimpleWindowLayout);
 
1837
begin
 
1838
  if FDividerTemplate <> nil then
 
1839
    ALayout.Dividers.Assign(FDividerTemplate);
 
1840
end;
 
1841
 
1288
1842
constructor TIDEWindowCreator.Create(aFormName: string);
1289
1843
begin
1290
1844
  FFormName:=aFormName;
 
1845
  FDividerTemplate := nil;
1291
1846
end;
1292
1847
 
1293
1848
constructor TIDEWindowCreator.Create(aFormName: string;
1309
1864
  OnGetLayout:=GetLayoutEvent;
1310
1865
end;
1311
1866
 
 
1867
destructor TIDEWindowCreator.Destroy;
 
1868
begin
 
1869
  inherited Destroy;
 
1870
  FreeAndNil(FDividerTemplate);
 
1871
end;
 
1872
 
1312
1873
function TIDEWindowCreator.NameFits(const AName: string): boolean;
1313
1874
begin
1314
1875
  Result:=CompareText(copy(AName,1,Length(FormName)),FormName)=0;
1332
1893
begin
1333
1894
  fItems:=TFPList.Create;
1334
1895
  FSimpleLayoutStorage:=TSimpleWindowLayoutList.Create;
 
1896
  FScreenMaxSizeForDefaults:=Point(1200,900);
1335
1897
end;
1336
1898
 
1337
1899
destructor TIDEWindowCreatorList.Destroy;
1396
1958
    dec(Result);
1397
1959
end;
1398
1960
 
1399
 
function TIDEWindowCreatorList.FindWithName(FormName: string
1400
 
  ): TIDEWindowCreator;
 
1961
function TIDEWindowCreatorList.FindWithName(FormName: string): TIDEWindowCreator;
1401
1962
var
1402
1963
  i: LongInt;
1403
1964
begin
1440
2001
  end;
1441
2002
end;
1442
2003
 
1443
 
procedure TIDEWindowCreatorList.ShowForm(AForm: TCustomForm;
1444
 
  BringToFront: boolean);
 
2004
procedure TIDEWindowCreatorList.ShowForm(AForm: TCustomForm; BringToFront: boolean);
1445
2005
var
1446
2006
  Layout: TSimpleWindowLayout;
1447
2007
begin
1448
2008
  if (AForm.Name='') or (not IsValidIdent(AForm.Name)) then
1449
2009
    raise Exception.Create('TIDEWindowCreatorList.ShowForm invalid form name '+AForm.Name);
1450
2010
 
1451
 
  // auto create a storage for every shown form
 
2011
  // auto create a layput storage for every shown form
1452
2012
  Layout:=SimpleLayoutStorage.ItemByFormID(AForm.Name);
1453
2013
  if Layout=nil then begin
1454
2014
    if not (csDesigning in AForm.ComponentState) then
1461
2021
  and (FindWithName(AForm.Name)<>nil) then
1462
2022
    // show dockable if it has a creator and is not a designer form
1463
2023
    IDEDockMaster.ShowForm(AForm,BringToFront)
1464
 
  else if Assigned(OnShowForm) then
1465
 
    OnShowForm(Self,AForm,BringToFront)
1466
 
  else if BringToFront then
1467
 
    AForm.ShowOnTop
1468
2024
  else
1469
 
    AForm.Visible:=true;
 
2025
    SimpleLayoutStorage.ApplyAndShow(Self,AForm,BringToFront);
1470
2026
end;
1471
2027
 
1472
2028
function TIDEWindowCreatorList.ShowForm(AFormName: string; BringToFront: boolean
1506
2062
  end;
1507
2063
end;
1508
2064
 
 
2065
function TIDEWindowCreatorList.GetScreenrectForDefaults: TRect;
 
2066
begin
 
2067
  Result:=Screen.WorkAreaRect;
 
2068
  if (Result.Right-Result.Left<10)
 
2069
  or (Result.Bottom-Result.Top<10) then begin
 
2070
    // screen not recognized
 
2071
    Result:=Rect(0,0,Max(Screen.Width,600),Max(Screen.Height,400));
 
2072
  end;
 
2073
  Result.Right:=Min(Result.Right,Result.Left+IDEWindowCreators.ScreenMaxSizeForDefaults.X);
 
2074
  Result.Bottom:=Min(Result.Bottom,Result.Top+IDEWindowCreators.ScreenMaxSizeForDefaults.Y);
 
2075
end;
 
2076
 
1509
2077
{ TIDEDockMaster }
1510
2078
 
1511
2079
function TIDEDockMaster.AddableInWindowMenu(AForm: TCustomForm): boolean;