lazarus/components/sparta/dockedformeditor/source/sparta_mainide.pas
juha b68f02c182 Sparta: Formatting.
git-svn-id: trunk@62080 -
2019-10-18 21:49:33 +00:00

1358 lines
41 KiB
ObjectPascal

{
*****************************************************************************
See the file COPYING.modifiedLGPL.txt, included in this distribution,
for details about the license.
*****************************************************************************
Author: Maciej Izak
DaThoX 2004-2015
FreeSparta.com
}
unit sparta_MainIDE;
{$mode delphi}{$H+}
interface
uses
Classes, SysUtils,
{$IF FPC_FULLVERSION>=30200}
Generics.Collections, Generics.Defaults,
{$ELSE}
sparta_Generics.Collections, sparta_Generics.Defaults,
{$ENDIF}
contnrs,
// LCL
LCLIntf, LCLType, LMessages, ComCtrls, Controls, Forms, ExtCtrls, Graphics,
// IdeIntf
SrcEditorIntf, LazIDEIntf, FormEditingIntf, PropEdits, PropEditUtils, ComponentEditors,
// Sparta
sparta_InterfacesMDI, sparta_strconsts, sparta_DesignedForm, sparta_resizer,
sparta_FakeForm, sparta_FakeFrame, sparta_FakeCustom;
const
WM_SETNOFRAME = WM_USER;
WM_BOUNDTODESIGNTABSHEET = WM_USER + 1;
type
{ TDesignFormData }
TDesignFormData = class(TComponent, IDesignedForm, IDesignedFormIDE)
private
FWndMethod: TWndMethod;
FForm: IDesignedFormIDE;
FLastScreenshot: TBitmap;
FPopupParent: TSourceEditorWindowInterface;
FHiding: boolean;
FFormImages: TList<TImage>;
procedure WndMethod(var Msg: TLMessage);
procedure SetPopupParent(AVal: TSourceEditorWindowInterface);
procedure DoAddForm;
procedure FormChangeBounds(Sender: TObject);
public
class var AddFormEvents: TList<TNotifyEvent>;
class constructor Init;
class destructor Finit;
procedure AddFormImage(AImage: TImage);
procedure RemoveFormImage(AImage: TImage);
procedure RepaintFormImages;
property Form: IDesignedFormIDE read FForm implements IDesignedForm, IDesignedFormIDE;
property LastScreenshot: TBitmap read FLastScreenshot;
property PopupParent: TSourceEditorWindowInterface read FPopupParent write SetPopupParent;
constructor Create(AForm: TCustomForm); reintroduce;
destructor Destroy; override;
end;
{ TModulePageControl }
TModulePageControl = class(TPageControl)
private
FResizer: TResizer;
FDesignFormData: TDesignFormData;
protected
procedure SetDesignFormData(const AValue: TDesignFormData); virtual;
public
destructor Destroy; override;
procedure ShowDesignPage;
procedure HideDesignPage;
procedure BoundToDesignTabSheet;
property Resizer: TResizer read FResizer;
property DesignFormData: TDesignFormData read FDesignFormData write SetDesignFormData;
end;
{ TSourceEditorWindowData }
TSourceEditorWindowData = class
private
FActiveDesignFormData: TDesignFormData;
FForm: TSourceEditorWindowInterface;
FPageCtrlList: TDictionary<TSourceEditorInterface, TModulePageControl>;
FLastTopParent: TControl;
procedure SetActiveDesignFormData(const AValue: TDesignFormData);
procedure OnChangeBounds(Sender: TObject);
procedure AddPageCtrl(ASrcEditor: TSourceEditorInterface; APage: TModulePageControl);
procedure RemovePageCtrl(ASrcEditor: TSourceEditorInterface);
public
constructor Create(AForm: TSourceEditorWindowInterface);
destructor Destroy; override;
property ActiveDesignFormData: TDesignFormData read FActiveDesignFormData write SetActiveDesignFormData;
procedure BoundToDesignTabSheet;
end;
{ TDTXTabMaster }
TDTXTabMaster = class(TIDETabMaster)
private
FAutoSizeControlList: TObjectList;
protected
function GetTabDisplayState: TTabDisplayState; override;
function GetTabDisplayStateEditor(Index: TSourceEditorInterface): TTabDisplayState; override;
public
constructor Create;
destructor Destroy; override;
function AutoSizeInShowDesigner(AControl: TControl): Boolean; override;
procedure EnableAutoSizing(AControl: TControl);
procedure ToggleFormUnit; override;
procedure JumpToCompilerMessage(ASourceEditor: TSourceEditorInterface); override;
procedure ShowCode(ASourceEditor: TSourceEditorInterface); override;
procedure ShowDesigner(ASourceEditor: TSourceEditorInterface; {%H-}AIndex: Integer = 0); override;
procedure ShowForm(AForm: TCustomForm); override;
end;
{ TDTXComponentsMaster }
TDTXComponentsMaster = class(TIDEComponentsMaster)
function DrawNonVisualComponents(ALookupRoot: TComponent): Boolean; override;
end;
TFormHack = class(TCustomForm);
{ TSpartaMainIDE }
TSpartaMainIDE = class(TObject)
public
class function GetCurrentResizer: TResizer;
class procedure TryFreeFormData(Form: TCustomForm);
class procedure Screen_FormAdded(Sender: TObject; Form: TCustomForm);
class procedure Screen_FormDel(Sender: TObject; Form: TCustomForm);
class procedure WindowCreate(Sender: TObject);
class procedure WindowDestroy(Sender: TObject);
class procedure WindowShow(Sender: TObject);
class procedure WindowHide(Sender: TObject);
class procedure EditorActivated(Sender: TObject);
class procedure EditorDestroyed(Sender: TObject);
class procedure EditorCreate(Sender: TObject);
class procedure TabChange(Sender: TObject);
class procedure GlobalOnChangeBounds(Sender: TObject);
class procedure GlobalSNOnChangeBounds(Sender: TObject);
class procedure OnShowDesignerForm(Sender: TObject; {%H-}AEditor: TSourceEditorInterface;
AComponentPaletteClassSelected: Boolean);
class procedure OnShowSrcEditor(Sender: TObject);
class procedure OnShowMethod(const Name: String);
class procedure OnDesignRefreshPropertyValues;
class procedure OnModifiedPersistentAdded({%H-}APersistent: TPersistent; {%H-}Select: Boolean);
class procedure OnModifiedSender(Sender: TObject);
class procedure OnModified;
class procedure DesignerSetFocus;
class procedure OnDesignMouseDown(Sender: TObject; {%H-}Button: TMouseButton;
{%H-}Shift: TShiftState; {%H-}X, {%H-}Y: Integer);
end;
var
normForms: Classes.TList; // normal forms
dsgnForms: Classes.TList; // design forms
SourceEditorWindows: TObjectDictionary<TSourceEditorWindowInterface, TSourceEditorWindowData>;
LastActiveSourceEditorWindow: TSourceEditorWindowInterface = nil;
LastActiveSourceEditor: TSourceEditorInterface = nil;
BoundInitialized: Boolean;
function FindModulePageControl(AForm: TSourceEditorWindowInterface): TModulePageControl; overload;
function FindSourceEditorForDesigner(ADesigner: TIDesigner): TSourceEditorInterface;
implementation
uses
sparta_ResizerFrame;
// FUTURE USE
//
//function FindDesignForm(ADesigner: TIDesigner): TCustomForm;
//var
// f: TDesignFormData;
//begin
// for Pointer(f) in dsgnForms do
// with f as IDesignedForm do
// if Form.Designer = ADesigner then
// Exit(Form);
//
// Result := nil;
//end;
//
//function FindDesignFormData(AForm: TSourceEditorWindowInterface): TDesignFormData; overload;
//begin
// Result := FindDesignFormData(
// FindModulePageControl(AForm)
// );
//end;
//
//procedure HideAllForms;
//var
// f: TDesignFormData;
//begin
// for Pointer(f) in dsgnForms do
// ShowWindow(f.Form.Form.Handle, SW_HIDE);
//end;
function FindModulePageControl(ASourceEditor: TSourceEditorInterface): TModulePageControl; overload;
var
LParent: TWinControl;
begin
if ASourceEditor = nil then
Exit(nil);
LParent := ASourceEditor.EditorControl.Parent;
while LParent <> nil do
begin
if LParent is TModulePageControl then
Exit(TModulePageControl(LParent));
LParent := LParent.Parent;
end;
Result := nil;
end;
function FindModulePageControl(AForm: TSourceEditorWindowInterface): TModulePageControl; overload;
begin
Result := FindModulePageControl(AForm.ActiveEditor);
end;
function AbsoluteFindModulePageControl(ASrcEditor: TSourceEditorInterface): TModulePageControl;
var
LSEWD: TSourceEditorWindowData;
begin
Result := nil;
for LSEWD in SourceEditorWindows.Values do
if LSEWD.FPageCtrlList.ContainsKey(ASrcEditor) then
Exit(LSEWD.FPageCtrlList[ASrcEditor]);
end;
function FindSourceEditorForDesigner(ADesigner: TIDesigner): TSourceEditorInterface;
var
i: Integer;
begin
for i := 0 to SourceEditorManagerIntf.SourceEditorCount - 1 do
if SourceEditorManagerIntf.SourceEditors[i].GetDesigner(False) = ADesigner then
Exit(SourceEditorManagerIntf.SourceEditors[i]);
Result := nil;
end;
function FindDesignFormData(ADesigner: TIDesigner): TDesignFormData; overload;
var
p: Pointer;
f: TDesignFormData absolute p;
fi: IDesignedForm = nil;
begin
Result := nil;
if ADesigner = nil then
Exit;
for p in dsgnForms do
begin
fi := f.FForm;
if (fi.Form.Designer = ADesigner) then
Exit(f);
end;
end;
procedure RefreshAllSourceWindowsModulePageControl;
var
LWindow: TSourceEditorWindowInterface;
LPageCtrl: TModulePageControl;
begin
for LWindow in SourceEditorWindows.Keys do
begin
LPageCtrl := FindModulePageControl(LWindow);
// for example LPageCtrl is nil when we clone module to new window
if (LPageCtrl = nil) or (csDestroying in LWindow.ComponentState) then
Continue;
if LWindow.ActiveEditor = nil then
LPageCtrl.HideDesignPage
else
if LWindow.ActiveEditor.GetDesigner(True) <> nil then
// TODO some check function: is displayed right form?
LPageCtrl.ShowDesignPage
else
LPageCtrl.HideDesignPage;
end;
end;
// sometimes at some level of initialization form can not contain TIDesigner
// (during ide run and when is oppened default project with some TForm1)
function FindDesignFormData(AForm: TCustomForm): TDesignFormData; overload;
var
f: TDesignFormData;
begin
Result := nil;
if AForm = nil then
Exit;
for Pointer(f) in dsgnForms do
if (f as IDesignedForm).Form = AForm then
Exit(f);
end;
function FindDesignFormData(AModulePageCtrl: TModulePageControl): TDesignFormData; overload;
var
LSourceWindow: TSourceEditorWindowInterface;
LSourceEditor: TSourceEditorInterface;
begin
Result := nil;
if AModulePageCtrl = nil then
Exit;
for LSourceWindow in SourceEditorWindows.Keys do
begin
if AModulePageCtrl.Owner = LSourceWindow then
begin
LSourceEditor := LSourceWindow.ActiveEditor;
if LSourceEditor = nil then
Exit;
Result := FindDesignFormData(LSourceEditor.GetDesigner(True));
Exit;
end;
end;
end;
{ TDesignFormData }
procedure TDesignFormData.WndMethod(var Msg: TLMessage);
// Without this button F12 don't work. (after creating new for editor is inactive) :<
procedure FixF12_ActiveEditor;
var
i: Integer;
begin
// Just do it for new created forms or the last loaded form becomes the active
// source editor after reopening a project.
if Form.Form.Designer <> SourceEditorManagerIntf.ActiveEditor.GetDesigner(True) then Exit;
SourceEditorManagerIntf.ActiveEditor := nil;
for i := 0 to SourceEditorManagerIntf.UniqueSourceEditorCount - 1 do
if Form.Form.Designer = SourceEditorManagerIntf.UniqueSourceEditors[i].GetDesigner(True) then
begin
SourceEditorManagerIntf.ActiveEditor := SourceEditorManagerIntf.UniqueSourceEditors[i];
Break;
end;
end;
var
Timer: TLMTimer;
begin
if Msg.msg = LM_TIMER then
begin
Timer := TLMTimer(Msg);
if Timer.TimerID = WM_SETNOFRAME then
begin
KillTimer(FForm.Form.Handle, WM_SETNOFRAME);
ShowWindow(Form.Form.Handle, SW_HIDE);
FHiding := False;
FixF12_ActiveEditor;
if Form.Form is TFakeForm then
RepaintFormImages;
Exit;
end;
if Timer.TimerID = WM_BOUNDTODESIGNTABSHEET then
begin
KillTimer(FForm.Form.Handle, WM_BOUNDTODESIGNTABSHEET);
SourceEditorWindows[Form.LastActiveSourceWindow].BoundToDesignTabSheet;
Exit;
end;
end;
// we need to correct ActiveEditor to right form
// this code works correctly on Windows platform
// (is necessery for selecting controls after form resizing).
// in Linux platforms below code brings problems with QT (inactive form)
{$IFDEF WINDOWS}
case Msg.msg of
LM_LBUTTONDOWN, LM_RBUTTONDOWN, LM_MBUTTONDOWN, LM_XBUTTONDOWN:
if Form.LastActiveSourceWindow <> nil then
begin
SourceEditorManagerIntf.ActiveSourceWindow := Form.LastActiveSourceWindow;
SourceEditorManagerIntf.ActiveEditor := Form.LastActiveSourceWindow.ActiveEditor;
end;
end;
{$ENDIF}
FWndMethod(Msg);
end;
procedure TDesignFormData.SetPopupParent(AVal: TSourceEditorWindowInterface);
begin
FPopupParent := AVal;
Form.RealPopupParent := FPopupParent;
end;
class constructor TDesignFormData.Init;
begin
AddFormEvents := TList<TNotifyEvent>.Create;
end;
class destructor TDesignFormData.Finit;
begin
AddFormEvents.Free;
end;
procedure TDesignFormData.AddFormImage(AImage: TImage);
begin
if FFormImages <> nil then
FFormImages.Add(AImage);
end;
procedure TDesignFormData.RemoveFormImage(AImage: TImage);
begin
if FFormImages <> nil then
FFormImages.Remove(AImage);
end;
procedure TDesignFormData.RepaintFormImages;
var
LImage: TImage;
begin
if FFormImages <> nil then
for LImage in FFormImages do
LImage.OnResize(LImage);
end;
procedure TDesignFormData.DoAddForm;
var
ne: TNotifyEvent;
begin
for ne in AddFormEvents do
ne(Self);
end;
procedure TDesignFormData.FormChangeBounds(Sender: TObject);
begin
if not FForm.Update then
SetTimer(FForm.Form.Handle, WM_BOUNDTODESIGNTABSHEET, 10, nil);
end;
constructor TDesignFormData.Create(AForm: TCustomForm);
begin
FForm := TDesignedFormImpl.Create(Self, AForm);
AForm.AddHandlerOnChangeBounds(FormChangeBounds);
FLastScreenshot := TBitmap.Create;
FWndMethod := FForm.Form.WindowProc;
FForm.Form.WindowProc := WndMethod;
if FForm.Form is TFakeForm then
begin
FFormImages := TList<TImage>.Create;
DoAddForm;
end;
end;
destructor TDesignFormData.Destroy;
var
LImage: TImage;
begin
FForm.Form.WindowProc := FWndMethod; // ! important risky point :P
if FFormImages <> nil then
begin
for LImage in FFormImages do
LImage.Free;
FreeAndNil(FFormImages);
end;
FLastScreenshot.Free;
inherited Destroy;
Pointer(FForm) := nil;
end;
{ TModulePageControl }
procedure TModulePageControl.SetDesignFormData(const AValue: TDesignFormData);
begin
if (AValue = FDesignFormData) then
// for show lfm code, if we want after editing lfm go back to form without any error
// (when we restart IDE some error can be raised )
if (FResizer=Nil)
or ((AValue <> nil) and (FResizer.DesignedForm = AValue as IDesignedForm)) then
Exit;
FDesignFormData := AValue;
if AValue = nil then
begin
//find
if Assigned(FResizer) then
FResizer.DesignedForm := nil;
end
else
begin
AValue.Form.LastActiveSourceWindow := Owner as TSourceEditorWindowInterface;
if Assigned(FResizer) then
FResizer.DesignedForm := AValue;
BoundToDesignTabSheet;
end;
end;
destructor TModulePageControl.Destroy;
begin
DesignFormData := nil;
inherited Destroy;
end;
procedure TModulePageControl.ShowDesignPage;
begin
Pages[1].TabVisible := True;
end;
procedure TModulePageControl.HideDesignPage;
begin
Pages[1].TabVisible := False;
end;
procedure TModulePageControl.BoundToDesignTabSheet;
begin
if (ActivePageIndex <> 1) then
Exit;
if Assigned(FResizer) then
FResizer.TryBoundSizerToDesignedForm(nil);
end;
{ TSourceEditorWindowData }
procedure TSourceEditorWindowData.SetActiveDesignFormData(
const AValue: TDesignFormData);
var
LPageCtrl: TModulePageControl;
begin
if FActiveDesignFormData = AValue then
Exit;
if FActiveDesignFormData <> nil then
// don't hide now if soon form will be hidden (for example on the IDE start)
if not FActiveDesignFormData.FHiding then
FActiveDesignFormData.FForm.HideWindow;
FActiveDesignFormData := AValue;
LPageCtrl := FindModulePageControl(FForm);
if (AValue <> nil) then
begin
{with AValue as IDesignedForm do
if not AValue.FHiding and (RealBorderStyle <> bsNone) then
begin
//BeginUpdate;
//RealBorderIcons := [];
//RealBorderStyle := bsNone;
//Form.Show;
//EndUpdate;
end;}
// important when we want back to tab where was oppened form :<
LazarusIDE.DoShowDesignerFormOfSrc(FForm.ActiveEditor);
end;
// when is fired DestroyEditor - from this place we can't navigate to pagecontrol by FForm (we need to handle lastactiveeditor)
if LPageCtrl = nil then
Exit;
LPageCtrl.DesignFormData := AValue;
// for USE_POPUP_PARENT_DESIGNER to eliminate form over code << maybe not needed any more since USE_POPUP_PARENT_DESIGNER isn't supported any more
LPageCtrl.OnChange(LPageCtrl);
end;
constructor TSourceEditorWindowData.Create(AForm: TSourceEditorWindowInterface);
begin
FForm := AForm;
FPageCtrlList := TDictionary<TSourceEditorInterface, TModulePageControl>.Create;
end;
destructor TSourceEditorWindowData.Destroy;
begin
FPageCtrlList.Free;
inherited Destroy;
end;
procedure TSourceEditorWindowData.BoundToDesignTabSheet;
var
LPageCtrl: TModulePageControl;
begin
LPageCtrl := FindModulePageControl(FForm);
if LPageCtrl <> nil then
LPageCtrl.BoundToDesignTabSheet;
end;
procedure TSourceEditorWindowData.OnChangeBounds(Sender: TObject);
//var
// LPageCtrl: TModulePageControl;
begin
// LPageCtrl := FindModulePageControl(FForm);
// if LPageCtrl <> nil then
// LPageCtrl.BoundToDesignTabSheet;
end;
procedure TSourceEditorWindowData.AddPageCtrl(ASrcEditor: TSourceEditorInterface; APage: TModulePageControl);
begin
FPageCtrlList.Add(ASrcEditor, APage);
APage.Pages[1].OnChangeBounds:=OnChangeBounds;
end;
procedure TSourceEditorWindowData.RemovePageCtrl(ASrcEditor: TSourceEditorInterface);
begin
FPageCtrlList.Remove(ASrcEditor);
end;
{ TDTXTabMaster }
function TDTXTabMaster.GetTabDisplayState: TTabDisplayState;
begin
Result := GetTabDisplayStateEditor(SourceEditorManagerIntf.ActiveEditor);
end;
function TDTXTabMaster.GetTabDisplayStateEditor(Index: TSourceEditorInterface
): TTabDisplayState;
var
LPageCtrl: TModulePageControl;
begin
if Index = nil then
Exit(tdsNone);
LPageCtrl := FindModulePageControl(Index);
if LPageCtrl = nil then
Exit(tdsNone);
case LPageCtrl.PageIndex of
0: Exit(tdsCode);
1: Exit(tdsDesign);
else
Exit(tdsOther);
end;
end;
constructor TDTXTabMaster.Create;
begin
FAutoSizeControlList := TObjectList.Create(False);
end;
destructor TDTXTabMaster.Destroy;
begin
FAutoSizeControlList.Free;
inherited Destroy;
end;
function TDTXTabMaster.AutoSizeInShowDesigner(AControl: TControl): Boolean;
begin
FAutoSizeControlList.Add(AControl);
Result := True;
end;
procedure TDTXTabMaster.EnableAutoSizing(AControl: TControl);
var
AIndex: Integer;
AutoSizeControl: TControl;
begin
if not Assigned(AControl) then Exit;
AutoSizeControl := nil;
if AControl is TNonFormProxyDesignerForm then
begin
if (TNonFormProxyDesignerForm(AControl).LookupRoot is TControl) then
AutoSizeControl := TControl(TNonFormProxyDesignerForm(AControl).LookupRoot);
end
else
AutoSizeControl := AControl;
AIndex := FAutoSizeControlList.IndexOf(AutoSizeControl);
if (AIndex >= 0) then
begin
FAutoSizeControlList.Delete(AIndex);
AutoSizeControl.EnableAutoSizing{$IFDEF DebugDisableAutoSizing}('TAnchorDockMaster Delayed'){$ENDIF};
end;
end;
procedure TDTXTabMaster.ToggleFormUnit;
begin
case TabDisplayState of
tdsCode:
ShowDesigner(SourceEditorManagerIntf.ActiveEditor);
tdsDesign:
ShowCode(SourceEditorManagerIntf.ActiveEditor);
end;
end;
procedure TDTXTabMaster.JumpToCompilerMessage(
ASourceEditor: TSourceEditorInterface);
begin
SourceEditorManagerIntf.ActiveEditor := ASourceEditor;
ShowCode(ASourceEditor);
end;
procedure TDTXTabMaster.ShowCode(ASourceEditor: TSourceEditorInterface);
begin
if ASourceEditor = nil then
Exit;
FindModulePageControl(ASourceEditor).PageIndex := 0;
end;
procedure TDTXTabMaster.ShowDesigner(ASourceEditor: TSourceEditorInterface; AIndex: Integer);
var
LPageCtrl: TModulePageControl;
begin
if ASourceEditor = nil then
Exit;
LPageCtrl := FindModulePageControl(ASourceEditor);
if not LPageCtrl.Pages[1].TabVisible then
Exit;
LPageCtrl.PageIndex := 1;
LPageCtrl.OnChange(LPageCtrl);
end;
procedure TDTXTabMaster.ShowForm(AForm: TCustomForm);
var
LEditor: TSourceEditorInterface;
begin
LEditor := FindSourceEditorForDesigner(AForm.Designer);
SourceEditorManagerIntf.ActiveEditor := LEditor;
ShowDesigner(LEditor);
end;
{ TDTXComponentsMaster }
function TDTXComponentsMaster.DrawNonVisualComponents(ALookupRoot: TComponent): Boolean;
var
LFormData: TDesignFormData;
LPageCtrl: TModulePageControl;
begin
Result := True;
LFormData := FindDesignFormData(FormEditingHook.GetDesignerForm(ALookupRoot){ALookupRoot as TCustomForm});
if LFormData = nil then
Exit;
LPageCtrl := FindModulePageControl(LFormData.Form.LastActiveSourceWindow);
if (LPageCtrl = nil) or (LPageCtrl.Resizer = nil) or (LPageCtrl.Resizer.MainDTU = nil) then
Exit;
Result := LPageCtrl.Resizer.MainDTU.ShowNonVisualComponents;
end;
{ TSpartaMainIDE }
class procedure TSpartaMainIDE.Screen_FormAdded(Sender: TObject; Form: TCustomForm);
var
LSourceEditor: TSourceEditorInterface;
LFormData: TDesignFormData;
//i: Integer;
LPageCtrl: TModulePageControl;
begin
if IsFormDesign(Form) then
begin
// Form like TForm1 etc...
if (csDesignInstance in Form.ComponentState) or (Form is TNonFormProxyDesignerForm) then
begin
LFormData := TDesignFormData.Create(Form);
LFormData.FHiding:=True;
dsgnForms.Add(LFormData);
LSourceEditor := FindSourceEditorForDesigner(Form.Designer);
if LSourceEditor <> nil then
begin
LPageCtrl := FindModulePageControl(LSourceEditor);
if LPageCtrl <> nil then
begin
LPageCtrl.ShowDesignPage;
LPageCtrl.DesignFormData := LFormData;
end;
end;
SetTimer(Form.Handle, WM_SETNOFRAME, 10, nil);
end;
end
else
begin
// ONDREJ: the following code marged with (on-del) seems to help with nothing
// but slows down loading forms and make them flicker.
// I therefore commented it out. Please revert if there'll be regressions.
{ // (on-del)
if not BoundInitialized then
begin
for i := 0 to Screen.FormCount - 1 do
if Screen.Forms[i] = Form then
Continue
else
begin
Screen.Forms[i].AddHandlerOnChangeBounds(GlobalOnChangeBounds);
end;
BoundInitialized := True;
end;}
if Form is TSourceEditorWindowInterface then
begin
Form.AddHandlerOnChangeBounds(GlobalSNOnChangeBounds);
//Form.PopupMode := pmExplicit; // (on-del)
normForms.Add(Form); // (on-del)
end
else
begin
//Form.AddHandlerOnChangeBounds(GlobalOnChangeBounds); // (on-del)
end;
//Forms.Add(Form); // (on-del)
end;
end;
class procedure TSpartaMainIDE.TryFreeFormData(Form: TCustomForm);
var
LSEWD: TSourceEditorWindowData;
mpc: TModulePageControl;
LFormData: TDesignFormData;
begin
Form.Parent := nil;
Application.ProcessMessages; // For TFrame - System Error. Code: 1400. Invalid window handle.
LFormData := FindDesignFormData(Form);
dsgnForms.Remove(LFormData);
for LSEWD in SourceEditorWindows.Values do
begin
if LSEWD.ActiveDesignFormData <> nil then
if LSEWD.ActiveDesignFormData.Form.Form = Form then
LSEWD.FActiveDesignFormData := nil; // important - we can't call OnChange tab, because tab don't exist anymore
for mpc in LSEWD.FPageCtrlList.Values do
if mpc.DesignFormData <> nil then
if mpc.DesignFormData.Form.Form = Form then
mpc.DesignFormData := nil;
end;
LFormData.Free;
end;
class procedure TSpartaMainIDE.Screen_FormDel(Sender: TObject; Form: TCustomForm);
begin
if not IsFormDesign(Form) then
begin
if Form is TSourceEditorWindowInterface then
Form.RemoveHandlerOnChangeBounds(GlobalSNOnChangeBounds)
else
Form.RemoveHandlerOnChangeBounds(GlobalOnChangeBounds)
end
else
TryFreeFormData(Form);
end;
class procedure TSpartaMainIDE.WindowCreate(Sender: TObject);
var
LSourceEditorWindow: TSourceEditorWindowInterface;
begin
if Sender.ClassNameIs('TSourceNotebook') then
begin
LSourceEditorWindow := Sender as TSourceEditorWindowInterface;
SourceEditorWindows.Add(LSourceEditorWindow, TSourceEditorWindowData.Create(LSourceEditorWindow));
end;
end;
class procedure TSpartaMainIDE.WindowDestroy(Sender: TObject);
var
p: Pointer;
f: TDesignFormData absolute p;
begin
for p in dsgnForms do
if f.FForm.LastActiveSourceWindow = Sender then
f.FForm.LastActiveSourceWindow := nil;
SourceEditorWindows.Remove(Sender as TSourceEditorWindowInterface);
if LastActiveSourceEditorWindow = Sender then
LastActiveSourceEditorWindow := nil;
end;
class procedure TSpartaMainIDE.WindowShow(Sender: TObject);
var
LWindow: TSourceEditorWindowInterface;
LWindowData: TSourceEditorWindowData;
LDesignedForm: IDesignedForm;
begin
LWindow := Sender as TSourceEditorWindowInterface;
if not SourceEditorWindows.TryGetValue(LWindow, LWindowData) or
(LWindowData.ActiveDesignFormData = nil)
then
Exit;
LDesignedForm := LWindowData.ActiveDesignFormData as IDesignedForm;
LDesignedForm.ShowWindow;
end;
class procedure TSpartaMainIDE.WindowHide(Sender: TObject);
var
LWindow: TSourceEditorWindowInterface;
LWindowData: TSourceEditorWindowData;
LDesignedForm: IDesignedForm;
begin
LWindow := Sender as TSourceEditorWindowInterface;
if not SourceEditorWindows.TryGetValue(LWindow, LWindowData) or
(LWindowData.ActiveDesignFormData = nil)
then
Exit;
LDesignedForm := LWindowData.ActiveDesignFormData as IDesignedForm;
LDesignedForm.HideWindow;
end;
class procedure TSpartaMainIDE.DesignerSetFocus;
var
LResizer: TResizer;
begin
LResizer := GetCurrentResizer;
if LResizer<>nil then
LResizer.ActiveResizeFrame.DesignerSetFocus;
end;
class procedure TSpartaMainIDE.EditorActivated(Sender: TObject);
var
LDesigner: TIDesigner;
LSourceEditor: TSourceEditorInterface;
function LastSourceEditorNotFound: boolean;
var
i: Integer;
se: TSourceEditorInterface;
begin
if (LastActiveSourceEditorWindow = nil) or (LastActiveSourceEditor = nil) then
Exit(False);
for se in SourceEditorWindows[LastActiveSourceEditorWindow].FPageCtrlList.Keys do
begin
Result := True;
for i := 0 to LastActiveSourceEditorWindow.Count - 1 do
if se = LastActiveSourceEditorWindow.Items[i] then
begin
Result := False;
Break;
end;
if Result then
begin
LastActiveSourceEditor := se; // after moving code editor into other window, sometimes IDE switch to other tab :\ damn... this line prevent this.
Exit;
end;
end;
Result := False;
end;
var
LPageCtrl: TModulePageControl;
LSourceEditorWindow: TSourceEditorWindowInterface;
LDesignFormData: TDesignFormData;
begin
if Sender is TSourceEditorInterface then
begin
LSourceEditor := TSourceEditorInterface(Sender);
// if we create directly new project then Activate is called without EditorCreate...
if not (LSourceEditor.EditorControl.Parent.Parent is TModulePageControl) then
begin
// possible is situation when we moved tab into other window
// then was not called event EditorDestroy - that generates problems with switching tabs
// or when we moving tab to first window ( then is raising : duplicates not allowed in dictionary).
if LastSourceEditorNotFound then
EditorDestroyed(nil);
EditorCreate(Sender);
end;
LDesigner := LSourceEditor.GetDesigner(True);
// should be performed during EditorCreate (parent of parent is module page ctrl)
LPageCtrl := TModulePageControl(LSourceEditor.EditorControl.Parent.Parent);
if LPageCtrl = nil then
Exit;
if LDesigner = nil then
LPageCtrl.HideDesignPage
else
begin
if LPageCtrl.Resizer = nil then
LPageCtrl.FResizer := TResizer.Create(LPageCtrl.Pages[1], TResizerFrame);
LPageCtrl.ShowDesignPage;
end;
LSourceEditorWindow := TSourceEditorWindowInterface(LPageCtrl.Owner);
LastActiveSourceEditorWindow := LSourceEditorWindow;
LastActiveSourceEditor := LSourceEditor;
LDesignFormData := FindDesignFormData(LPageCtrl);
// when we switch tab, design form should be hidden
if (LDesigner = nil) or (LDesignFormData = nil) then
SourceEditorWindows[LSourceEditorWindow].ActiveDesignFormData := nil
else
begin
// during form loading for example from package, ActiveDesignFormData assignment,
// blocks the message queue responsible for hiding form
// We can't check it because there are some forms where designing is not handled yet.
// (for that kind of forms is returned empty designformdata)
// maybe we can fix this in future
if not LDesignFormData.FHiding then
// Prevent unexpected events (when is deactivated some control outside designed form)
if (LDesignFormData.Form.LastActiveSourceWindow = LSourceEditorWindow)
// important!!! for many error - switching between editors...
and (LPageCtrl.PageIndex = 1) then
SourceEditorWindows[LSourceEditorWindow].ActiveDesignFormData := LDesignFormData
else
SourceEditorWindows[LSourceEditorWindow].ActiveDesignFormData := nil;
end;
case LPageCtrl.PageIndex of
0: if LDesignFormData <> nil then LDesignFormData.Form.HideWindow;
1:
begin
// Michl: I comment the next line, as it breaks other editors
// (like Actionlist Editor). Imho in all cases all designer
// were already active, so it isn't needed. See issue #33872
// LazarusIDE.DoShowDesignerFormOfSrc(LSourceEditorWindow.ActiveEditor);
// for lfm edition...
with LDesignFormData as IDesignedForm do
if not LDesignFormData.FHiding {and (RealBorderStyle <> bsNone)} then
begin
//BeginUpdate;
//RealBorderIcons := [];
//RealBorderStyle := bsNone;
//Form.Show;
//EndUpdate;
LPageCtrl.BoundToDesignTabSheet;
SetTimer(Form.Handle, WM_BOUNDTODESIGNTABSHEET, 10, nil);
end;
end;
end;
end
else
RefreshAllSourceWindowsModulePageControl;
end;
class procedure TSpartaMainIDE.EditorDestroyed(Sender: TObject);
var
LSourceEditor: TSourceEditorInterface;
LPageCtrl: TModulePageControl;
LSourceEditorWindow: TSourceEditorWindowInterface;
LFormData: TDesignFormData;
begin
// sender is here as special parameter, because is possible situation where is moved editor
// to another window and was not triggered EditorDestroy - for more info goto editoractivate
if Sender = nil then
LSourceEditor := LastActiveSourceEditor
else
LSourceEditor := TSourceEditorInterface(Sender);
// parent don't exist anymore and we must search in each window...
if Sender = nil then // but not for Sender = nil :P
LPageCtrl := SourceEditorWindows[LastActiveSourceEditorWindow].FPageCtrlList[LastActiveSourceEditor]
else
LPageCtrl := AbsoluteFindModulePageControl(LSourceEditor);
if LPageCtrl = nil then
Exit;
LFormData := FindDesignFormData(LSourceEditor.GetDesigner(False));
// goto first comment (forced destroy)
if Sender = nil then
LSourceEditorWindow := LastActiveSourceEditorWindow
else
LSourceEditorWindow := TSourceEditorWindowInterface(LPageCtrl.Owner);
if LFormData <> nil then
begin
SourceEditorWindows[LSourceEditorWindow].ActiveDesignFormData := nil;
LFormData.Form.LastActiveSourceWindow := nil;
end;
SourceEditorWindows[LSourceEditorWindow].RemovePageCtrl(LSourceEditor);
LPageCtrl.Free;
if LastActiveSourceEditor = LSourceEditor then
LastActiveSourceEditor := nil;
end;
class function TSpartaMainIDE.GetCurrentResizer: TResizer;
var
LForm: TCustomForm;
LFormData: TDesignFormData;
LSourceWindow: TSourceEditorWindowInterface;
LPageCtrl: TModulePageControl;
begin
Result := nil;
Application.ProcessMessages;
if (FormEditingHook = nil) or (GlobalDesignHook = nil) then
Exit;
LForm := FormEditingHook.GetDesignerForm(GlobalDesignHook.LookupRoot);
LFormData := FindDesignFormData(LForm);
if LFormData=nil then Exit;
LSourceWindow := (LFormData as IDesignedFormIDE).LastActiveSourceWindow;
LPageCtrl := FindModulePageControl(LSourceWindow);
Result := LPageCtrl.Resizer;
end;
class procedure TSpartaMainIDE.EditorCreate(Sender: TObject);
var
LSourceEditor: TSourceEditorInterface;
function CreateModulePageControl: TModulePageControl;
var
LNewTabSheet: TTabSheet;
LSourceEditorWindow: TSourceEditorWindowInterface;
LParent: TWinControl;
begin
Result := TModulePageControl.Create(LSourceEditor.EditorControl.Owner);
Result.TabPosition := tpBottom;
Result.Align:=alClient;
LParent := LSourceEditor.EditorControl.Parent;
LNewTabSheet := TTabSheet.Create(Result);
LNewTabSheet.PageControl := Result;
LNewTabSheet.Caption := SCode;
LSourceEditor.EditorControl.Parent := LNewTabSheet; // ! SynEdit :)
LNewTabSheet := TTabSheet.Create(Result);
LNewTabSheet.PageControl := Result;
LNewTabSheet.Caption := SDesigner;
Result.OnChange := TabChange;
Result.Parent := LParent;
LSourceEditorWindow := TSourceEditorWindowInterface(Result.Owner);
SourceEditorWindows[LSourceEditorWindow].AddPageCtrl(LSourceEditor, Result)
end;
begin
LSourceEditor := Sender as TSourceEditorInterface;
if not (LSourceEditor.EditorControl.Parent.Parent is TModulePageControl) then
CreateModulePageControl;
end;
class procedure TSpartaMainIDE.TabChange(Sender: TObject);
var
LActiveSourceWindow: TSourceEditorWindowInterface;
w: TSourceEditorWindowInterface;
p: TPair<TSourceEditorInterface, TModulePageControl>;
LDesigner: TIDesigner;
LFormData: TDesignFormData;
LPageCtrl: TModulePageControl;
LSourceWndData: TSourceEditorWindowData;
begin
// activate proper source editor window when user is clicking on page.
// (at clicking time can be active other source window)
LActiveSourceWindow := TComponent(Sender).Owner as TSourceEditorWindowInterface;
if LActiveSourceWindow <> SourceEditorManagerIntf.ActiveSourceWindow then
SourceEditorManagerIntf.ActiveSourceWindow := LActiveSourceWindow;
LPageCtrl := TModulePageControl(Sender);
// in case there is no module and is visible page other than code page.
if (LActiveSourceWindow.ActiveEditor <> nil) and (LPageCtrl <> nil) then
begin
LDesigner := LActiveSourceWindow.ActiveEditor.GetDesigner(True);
LFormData := FindDesignFormData(LDesigner);
if (LFormData <> nil)
and SourceEditorWindows.TryGetValue(LActiveSourceWindow, LSourceWndData) then
begin
case LPageCtrl.ActivePageIndex of
0: LSourceWndData.ActiveDesignFormData := nil;
1: begin // deactivate design tab in other page control :)
for w in SourceEditorWindows.Keys do
if w = LActiveSourceWindow then
Continue
else
for p in SourceEditorWindows[w].FPageCtrlList do
if (p.Value.DesignFormData = LFormData) and (p.Value <> Sender) then
IDETabMaster.ShowCode(p.Key);
LSourceWndData.ActiveDesignFormData := LFormData;
// enable autosizing after creating a new form
TDTXTabMaster(IDETabMaster).EnableAutoSizing(LFormData.Form.Form);
// to handle windows with different size
LPageCtrl.BoundToDesignTabSheet;
end;
end;
end;
end;
end;
class procedure TSpartaMainIDE.GlobalOnChangeBounds(Sender: TObject);
var
sewd: TSourceEditorWindowData;
begin
for sewd in SourceEditorWindows.Values do
sewd.OnChangeBounds(Sender);
end;
class procedure TSpartaMainIDE.GlobalSNOnChangeBounds(Sender: TObject);
var
LWindow: TSourceEditorWindowInterface;
LWindowData: TSourceEditorWindowData;
LDesignForm: TDesignFormData;
begin
// Check parent. Maybe is different? If yes then window changed state (docked/undocked) and we need to perform few actions
LWindow := Sender as TSourceEditorWindowInterface;
// dock/undock event :)
if not SourceEditorWindows.TryGetValue(LWindow, LWindowData) then
Exit;
if LWindowData.FLastTopParent <> LWindow.GetTopParent then
begin
LWindowData.FLastTopParent := LWindow.GetTopParent;
// refresh for popupparent
LDesignForm := LWindowData.ActiveDesignFormData;
LWindowData.ActiveDesignFormData := nil;
LWindowData.ActiveDesignFormData := LDesignForm;
if LDesignForm <> nil then
begin
LDesignForm.Form.Form.Parent := FindModulePageControl(LWindow).Resizer.ActiveResizeFrame.FormHandler;
SetTimer(LDesignForm.Form.Form.Handle, WM_BOUNDTODESIGNTABSHEET, 10, nil);
end;
end;
LWindowData.OnChangeBounds(Sender);
end;
class procedure TSpartaMainIDE.OnDesignMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
DesignerSetFocus;
end;
class procedure TSpartaMainIDE.OnModifiedSender(Sender: TObject);
begin
OnModified;
end;
class procedure TSpartaMainIDE.OnModified;
var
LResizer: TResizer;
begin
LResizer := GetCurrentResizer;
if LResizer<>nil then
LResizer.ActiveResizeFrame.OnModified;
end;
class procedure TSpartaMainIDE.OnModifiedPersistentAdded(
APersistent: TPersistent; Select: Boolean);
begin
OnModified;
end;
class procedure TSpartaMainIDE.OnShowDesignerForm(Sender: TObject; AEditor: TSourceEditorInterface;
AComponentPaletteClassSelected: Boolean);
var
LForm: TDesignFormData;
LPageCtrl, p: TModulePageControl;
w: TSourceEditorWindowInterface;
e: TSourceEditorInterface;
begin
LForm := FindDesignFormData(TCustomForm(Sender).Designer);
if (LForm = nil) or LForm.FHiding then
Exit;
LPageCtrl := FindModulePageControl(SourceEditorManagerIntf.ActiveEditor);
if LPageCtrl = nil then
Exit; // it should not happen but who knows :P Lazarus IDE is sometimes mischievous
if AComponentPaletteClassSelected then
begin
// if form is already opened do nothing, if not then show form for active module.
for w in SourceEditorWindows.Keys do
begin
e := w.ActiveEditor;
if (e = nil) or (e.GetDesigner(True) <> LForm.Form.Form.Designer) then
Continue;
p := FindModulePageControl(e);
if p.PageIndex = 1 then
Exit;
end;
end;
IDETabMaster.ShowDesigner(SourceEditorManagerIntf.ActiveEditor);
end;
class procedure TSpartaMainIDE.OnShowSrcEditor(Sender: TObject);
begin
IDETabMaster.ShowCode(Sender as TSourceEditorInterface);
end;
class procedure TSpartaMainIDE.OnShowMethod(const Name: String);
var
LForm: TDesignFormData;
LSecondEditor: TSourceEditorInterface = nil;
i: Integer;
LSourceWindow: TSourceEditorWindowInterface;
begin
if FormEditingHook = nil then
Exit;
LForm := FindDesignFormData(FormEditingHook.GetCurrentDesigner);
if LForm = nil then
Exit;
for i := 0 to SourceEditorManagerIntf.SourceWindowCount - 1 do
begin
LSourceWindow := SourceEditorManagerIntf.SourceWindows[i];
if LForm.Form.LastActiveSourceWindow = LSourceWindow then
Continue;
if LSourceWindow.ActiveEditor <> nil then
if LSourceWindow.ActiveEditor.GetDesigner(True) = LForm.Form.Form.Designer then
begin
LSecondEditor := LSourceWindow.ActiveEditor;
Break;
end;
end;
if Assigned(LSecondEditor) then
begin
IDETabMaster.ShowCode(LSecondEditor);
LazarusIDE.DoShowMethod(LSecondEditor, Name);
end
else
if Assigned(LForm.Form.LastActiveSourceWindow) then
IDETabMaster.ShowCode(LForm.Form.LastActiveSourceWindow.ActiveEditor);
end;
class procedure TSpartaMainIDE.OnDesignRefreshPropertyValues;
var
LForm: TCustomForm;
LSourceWindow: TSourceEditorWindowInterface;
LFormData: TDesignFormData;
LPageCtrl: TModulePageControl;
function RootIsSelected: Boolean;
var
LSelection: TPersistentSelectionList;
i: integer;
begin
Result := False;
LSelection := TPersistentSelectionList.Create;
GlobalDesignHook.GetSelection(LSelection);
for i := 0 to LSelection.Count - 1 do
if LSelection.Items[i] = GlobalDesignHook.LookupRoot then
begin
Result := True;
Break;
end;
LSelection.Free;
end;
begin
if (GlobalDesignHook.LookupRoot is TCustomFrame) then
begin
if not RootIsSelected then
Exit;
LForm := FormEditingHook.GetDesignerForm(GlobalDesignHook.LookupRoot);
LFormData := FindDesignFormData(LForm);
LSourceWindow := (LFormData as IDesignedFormIDE).LastActiveSourceWindow;
LPageCtrl := FindModulePageControl(LSourceWindow);
TFakeFrame(LForm).SetBounds(LForm.Left-1,LForm.Top-1,TFakeFrame(LForm).Width,TFakeFrame(LForm).Height);
//LPageCtrl.BoundToDesignTabSheet;
end
else
if (GlobalDesignHook.LookupRoot is TCustomForm) then
begin
if not RootIsSelected then
Exit;
LForm := TCustomForm(GlobalDesignHook.LookupRoot);
LFormData := FindDesignFormData(LForm);
LFormData.RepaintFormImages;
end;
end;
initialization
dsgnForms := Classes.TList.Create;
SourceEditorWindows := TObjectDictionary<TSourceEditorWindowInterface, TSourceEditorWindowData>.Create([doOwnsValues]);
normForms := Classes.TList.Create;
finalization
normForms.Free;
SourceEditorWindows.Free;
FreeAndNil(dsgnForms);
end.