lazarus/components/dockedformeditor/source/dockeddesignform.pas

246 lines
6.1 KiB
ObjectPascal

{
*****************************************************************************
See the file COPYING.modifiedLGPL.txt, included in this distribution,
for details about the license.
*****************************************************************************
Authors: Maciej Izak
Michael W. Vogel
}
unit DockedDesignForm;
{$mode objfpc}{$H+}
{$modeswitch advancedrecords}
{$modeswitch typehelpers}
interface
uses
// RTL
Classes, SysUtils, fgl,
// LCL
LMessages, Forms, LCLType, LCLIntf, Controls,
// IDEIntf
SrcEditorIntf,
// DockedFormEditor
DockedFormAccesses, DockedBasicAnchorDesigner;
const
WM_SETNOFRAME = WM_USER;
WM_BOUNDTODESIGNTABSHEET = WM_USER + 1;
type
{ TDesignForm }
TDesignForm = class(TDesignFormIDE)
private
FHiding: Boolean;
FOnAdjustPageNeeded: TNotifyEvent;
FWndMethod: TWndMethod;
procedure FixF12_ActiveEditor;
procedure FormChangeBounds(Sender: TObject);
procedure WndMethod(var Msg: TLMessage);
public
constructor Create(AForm: TCustomForm); override;
destructor Destroy; override;
public
property Hiding: Boolean read FHiding write FHiding;
property OnAdjustPageNeeded: TNotifyEvent read FOnAdjustPageNeeded write FOnAdjustPageNeeded;
end;
{ TDesignForms }
TDesignForms = class(specialize TFPGList<TDesignForm>)
public
destructor Destroy; override;
procedure DeleteDesignForm(AIndex: Integer);
function Find(AForm: TCustomForm): TDesignForm; overload;
function Find(ADesigner: TIDesigner): TDesignForm; overload;
function IndexOf(AForm: TCustomForm): Integer; overload;
procedure Remove(AForm: TCustomForm); overload;
procedure RemoveAllAnchorDesigner;
end;
var
DesignForms: TDesignForms;
implementation
{ TDesignForm }
procedure TDesignForm.FixF12_ActiveEditor;
var
i: Integer;
begin
// Without this, button F12 don't work. (after creating new for editor is inactive)
// Just do it for new created forms or the last loaded form becomes the active
// source editor after reopening a project.
if Designer <> SourceEditorManagerIntf.ActiveEditor.GetDesigner(True) then Exit;
SourceEditorManagerIntf.ActiveEditor := nil;
for i := 0 to SourceEditorManagerIntf.UniqueSourceEditorCount - 1 do
if Designer = SourceEditorManagerIntf.UniqueSourceEditors[i].GetDesigner(True) then
begin
SourceEditorManagerIntf.ActiveEditor := SourceEditorManagerIntf.UniqueSourceEditors[i];
Break;
end;
end;
procedure TDesignForm.FormChangeBounds(Sender: TObject);
begin
if not Update then
SetTimer(Form.Handle, WM_BOUNDTODESIGNTABSHEET, 10, nil);
end;
procedure TDesignForm.WndMethod(var Msg: TLMessage);
var
Timer: TLMTimer;
begin
if Msg.msg = LM_TIMER then
begin
Timer := TLMTimer(Msg);
case Timer.TimerID of
WM_SETNOFRAME:
begin
KillTimer(Form.Handle, WM_SETNOFRAME);
LCLIntf.ShowWindow(Form.Handle, SW_HIDE);
FHiding := False;
FixF12_ActiveEditor;
Exit;
end;
WM_BOUNDTODESIGNTABSHEET:
begin
KillTimer(Form.Handle, WM_BOUNDTODESIGNTABSHEET);
if Assigned(FOnAdjustPageNeeded) then
FOnAdjustPageNeeded(Self);
Exit;
end;
end;
end;
case Msg.msg of
{$IFDEF LCLWin32}
// 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)
LM_LBUTTONDOWN, LM_RBUTTONDOWN, LM_MBUTTONDOWN, LM_XBUTTONDOWN:
if LastActiveSourceWindow <> nil then
begin
SourceEditorManagerIntf.ActiveSourceWindow := LastActiveSourceWindow;
SourceEditorManagerIntf.ActiveEditor := LastActiveSourceWindow.ActiveEditor;
end;
{$ENDIF}
// Prevent usage of parent hint (SourceEditorWindow), see issue #39217
CM_PARENTSHOWHINTCHANGED:
begin
Msg.Result := 0;
Exit;
end;
end;
FWndMethod(Msg);
end;
constructor TDesignForm.Create(AForm: TCustomForm);
begin
inherited Create(AForm);
AForm.AddHandlerOnChangeBounds(@FormChangeBounds);
FWndMethod := Form.WindowProc;
Form.WindowProc := @WndMethod;
end;
destructor TDesignForm.Destroy;
begin
Form.WindowProc := FWndMethod; // ! important risky point :P
Form.RemoveHandlerOnChangeBounds(@FormChangeBounds);
inherited Destroy;
end;
{ TDesignForms }
destructor TDesignForms.Destroy;
begin
while Count > 0 do
DeleteDesignForm(0);
inherited Destroy;
end;
procedure TDesignForms.DeleteDesignForm(AIndex: Integer);
var
LDesignForm: TDesignForm;
begin
LDesignForm := Self[AIndex];
LDesignForm.Free;
Delete(AIndex);
end;
function TDesignForms.Find(AForm: TCustomForm): TDesignForm;
var
LDesignForm: TDesignForm;
begin
// sometimes at some level of initialization form can not contain TIDesigner
// (during ide run and when is oppened default project with some TForm1)
Result := nil;
if AForm = nil then Exit;
for LDesignForm in Self do
if LDesignForm.Form = AForm then
Exit(LDesignForm);
end;
function TDesignForms.Find(ADesigner: TIDesigner): TDesignForm;
var
LDesignForm: TDesignForm;
begin
Result := nil;
if ADesigner = nil then Exit;
for LDesignForm in Self do
if LDesignForm.Designer = ADesigner then
Exit(LDesignForm);
end;
function TDesignForms.IndexOf(AForm: TCustomForm): Integer;
var
i: Integer;
begin
Result := -1;
for i := 0 to Count - 1 do
if Items[i].Form = AForm then
Exit(i);
end;
procedure TDesignForms.Remove(AForm: TCustomForm);
var
LIndex: Integer;
begin
LIndex := IndexOf(AForm);
if LIndex < 0 then Exit;
Items[LIndex].Free;
Delete(LIndex);
end;
procedure TDesignForms.RemoveAllAnchorDesigner;
var
LDesignForm: TDesignForm;
LAnchorDesigner: TBasicAnchorDesigner;
begin
for LDesignForm in Self do
begin
LAnchorDesigner := LDesignForm.AnchorDesigner;
if not Assigned(LAnchorDesigner) then Continue;
LAnchorDesigner.Free;
LDesignForm.AnchorDesigner := nil;
end;
end;
initialization
DesignForms := TDesignForms.Create;
finalization
FreeAndNil(DesignForms);
end.