123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- unit frmmain;
- {$mode objfpc}{$H+}
- interface
- uses
- Classes, SysUtils, webideintf, Forms, Controls, Graphics, Dialogs, EditBtn,
- ExtCtrls, ComCtrls, StdCtrls, ActnList, LazFileUtils, GlobalCefApplication,
- {$IFDEF DARWIN} uCEFLazarusCocoa, {$ENDIF}
- {$IFDEF WINDOWS}
- Windows, Messages,
- {$ENDIF}
- uCEFChromium, uCEFWindowParent, uCEFChromiumWindow, uCEFTypes, uCEFInterfaces,
- uCEFWinControl, uCEFApplication, uCEFWorkScheduler, uCEFBrowserWindow, fpJSON, uCEFChromiumEvents;
- type
- { TMainForm }
- TMainForm = class(TForm)
- AOpenDev: TAction;
- AGoExternal: TAction;
- AGo: TAction;
- ALWidgets: TActionList;
- BrowserWindow1: TBrowserWindow;
- FEProject: TFileNameEdit;
- ILWidgets: TImageList;
- BLog: TMemo;
- MLog: TMemo;
- Panel1: TPanel;
- PnlLog: TPanel;
- PnlBLog: TPanel;
- PCDesigner: TPageControl;
- Project: TLabel;
- PBottom: TPanel;
- BrowserLog: TTabSheet;
- Splitter1: TSplitter;
- Splitter2: TSplitter;
- TBExternalGo: TToolButton;
- TBExternalGo1: TToolButton;
- TSInspector: TTabSheet;
- TSBrowser: TTabSheet;
- TSLog: TTabSheet;
- TBWidgets: TToolBar;
- TBGo: TToolButton;
- ToolButton1: TToolButton;
- procedure AGoExecute(Sender: TObject);
- procedure AGoExternalExecute(Sender: TObject);
- procedure AGoUpdate(Sender: TObject);
- procedure AOpenDevExecute(Sender: TObject);
- procedure BrowserWindow1BrowserClosed(Sender: TObject);
- procedure BrowserWindow1BrowserCreated(Sender: TObject);
- procedure ChromiumConsoleMessage(Sender: TObject;
- const browser: ICefBrowser; level: TCefLogSeverity; const message,
- source: ustring; line: Integer; out Result: Boolean);
- procedure cwOnBeforePopup(Sender: TObject;
- const browser: ICefBrowser; const frame: ICefFrame; const targetUrl,
- targetFrameName: ustring; targetDisposition: TCefWindowOpenDisposition;
- userGesture: Boolean; const popupFeatures: TCefPopupFeatures;
- var windowInfo: TCefWindowInfo; var client: ICefClient;
- var settings: TCefBrowserSettings;
- var extra_info: ICefDictionaryValue;
- var noJavascriptAccess: Boolean;
- var Result: Boolean);
- procedure DEProjectEditingDone(Sender: TObject);
- procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
- procedure FormCreate(Sender: TObject);
- procedure Panel1Resize(Sender: TObject);
- private
- FFormClosing: Boolean;
- FClientID : Int64; // Just one for now
- FDesignCaption : String;
- FWebIDEIntf : TIDEServer;
- FWidgetCount : Integer;
- FWidgets : Array of String;
- FAllowGo: Boolean;
- {$IFDEF WINDOWS}
- procedure WMEnterMenuLoop(var aMessage: TMessage); message WM_ENTERMENULOOP;
- procedure WMExitMenuLoop(var aMessage: TMessage); message WM_EXITMENULOOP;
- {$ENDIF}
- function GetProjectURL: String;
- procedure DoAddWidget(Sender: TObject);
- procedure DoAction(Sender: TObject; aExchange: TIDEExchange);
- procedure DoClientCame(Sender: TObject; aClient: TIDEClient);
- procedure DoClientLeft(Sender: TObject; aClient: TIDEClient);
- procedure DoLogRequest(Sender: TObject; aURL: String);
- procedure IsWidgetEnabled(Sender: TObject);
- Procedure RegisterWidgets;
- Procedure RegisterWidget(aWidget: String; aImageIndex : Integer);
- public
- Procedure Log(Msg : String);
- Procedure Log(Fmt : String; Args : Array of const);
- end;
- var
- MainForm: TMainForm;
- implementation
- uses lclintf, fpmimetypes;
- {$R *.lfm}
- type
- { TLogMsg }
- TLogMsg = class
- private
- FMsg: String;
- public
- constructor Create(AMsg: String);
- procedure DoBrowserMsg(Data: PtrInt);
- procedure DoLog(Data: PtrInt);
- end;
- { TLogMsg }
- constructor TLogMsg.Create(AMsg: String);
- begin
- FMsg := AMsg;
- end;
- procedure TLogMsg.DoBrowserMsg(Data: PtrInt);
- begin
- if MainForm <> nil then
- MainForm.BLog.Append(FMsg);
- Free;
- end;
- procedure TLogMsg.DoLog(Data: PtrInt);
- begin
- if MainForm <> nil then
- MainForm.Log(FMsg);
- Free;
- end;
- { TMainForm }
- procedure TMainForm.DEProjectEditingDone(Sender: TObject);
- begin
- FWebIDEIntf.ProjectDir:=ExtractFilePath(FEProject.FileName);
- end;
- procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: boolean);
- begin
- FWebIDEIntf.Active:=False;
- FFormClosing := True;
- BrowserWindow1.CloseBrowser(True);
- CanClose:=BrowserWindow1.IsClosed;
- Visible := False;
- end;
- Function TMainForm.GetProjectURL : String;
- begin
- Result:=Format('http://localhost:%d/Project/%s',[FWebIDEIntf.Port,ExtractFileName(FEProject.FileName)]);
- end;
- procedure TMainForm.AGoExecute(Sender: TObject);
- Var
- URL : String;
- begin
- URL:=GetProjectURL;
- Log('Going to URL: %s',[URL]);
- BrowserWindow1.LoadURL(URL);
- end;
- procedure TMainForm.AGoExternalExecute(Sender: TObject);
- Var
- URL : String;
- begin
- URL:=GetProjectURL;
- Log('Going to URL: %s',[URL]);
- OpenURL(URL);
- end;
- procedure TMainForm.AGoUpdate(Sender: TObject);
- begin
- (Sender as Taction).Enabled:=FAllowGo;
- end;
- procedure TMainForm.AOpenDevExecute(Sender: TObject);
- var
- p: TPoint;
- begin
- p.X := 0;
- p.Y := 0;
- BrowserWindow1.Chromium.ShowDevTools(p,nil);
- end;
- procedure TMainForm.BrowserWindow1BrowserClosed(Sender: TObject);
- begin
- Close;
- end;
- procedure TMainForm.BrowserWindow1BrowserCreated(Sender: TObject);
- begin
- // Now the browser is fully initialized we can load the initial web page.
- FAllowGo:=True;
- end;
- procedure TMainForm.ChromiumConsoleMessage(Sender: TObject;
- const browser: ICefBrowser; level: TCefLogSeverity; const message,
- source: ustring; line: Integer; out Result: Boolean);
- var
- m: TLogMsg;
- begin
- if FFormClosing then
- exit;
- m := TLogMsg.Create(Format('%s [%s %d]', [message, source, line]));
- Application.QueueAsyncCall(@m.DoBrowserMsg, 0);
- // Issue https://gitlab.com/freepascal.org/fpc/source/-/issues/39367
- //Application.QueueAsyncCall(@TLogMsg.Create(Format('%s [%s %d]', [message, source, line])).DoBrowserMsg, 0);
- end;
- procedure TMainForm.FormCreate(Sender: TObject);
- var
- s: String;
- begin
- FAllowGo:=False;
- FDesignCaption:=Caption;
- MimeTypes.LoadKnownTypes;
- s := ExtractFilePath(Paramstr(0));
- if pos('nativedesign', s) > 0 then
- s := StringReplace(s, 'nativedesign', 'designdemo', [rfReplaceAll, rfIgnoreCase])
- else
- s := s+'designdemo';
- s := AppendPathDelim(s)+'designdemo.html';
- FEProject.FileName:=s;
- FWebIDEIntf:=TIDEServer.Create(Self);
- FWebIDEIntf.ProjectDir:=ExtractFilePath(FEProject.FileName);
- FWebIDEIntf.OnClientAdded:=@DoClientCame;
- FWebIDEIntf.OnClientRemoved:=@DoClientLeft;
- FWebIDEIntf.OnRequest:=@DoLogRequest;
- FWebIDEIntf.OnAction:=@DoAction;
- FWebIDEIntf.Active:=True;
- TSInspector.TabVisible:=False;
- RegisterWidgets;
- end;
- procedure TMainForm.Panel1Resize(Sender: TObject);
- begin
- //if not Visible then
- // exit;
- if Width = 0 then begin
- if MLog.Parent = PnlLog then begin
- MLog.Parent := TSLog;
- TSLog.TabVisible := True;
- end;
- if BLog.Parent = PnlBLog then begin
- BLog.Parent := BrowserLog;
- BrowserLog.TabVisible := True;
- end;
- end
- else begin
- if MLog.Parent = TSLog then begin
- MLog.Parent := PnlLog;
- TSLog.TabVisible := False;
- end;
- if BLog.Parent = BrowserLog then begin
- BLog.Parent := PnlBLog;
- BrowserLog.TabVisible := False;
- end;
- end;
- end;
- {$IFDEF WINDOWS}
- procedure TMainForm.WMEnterMenuLoop(var aMessage: TMessage);
- begin
- inherited;
- if (aMessage.wParam = 0) and (GlobalCEFApp <> nil) then
- GlobalCEFApp.OsmodalLoop := True;
- end;
- procedure TMainForm.WMExitMenuLoop(var aMessage: TMessage);
- begin
- inherited;
- if (aMessage.wParam = 0) and (GlobalCEFApp <> nil) then
- GlobalCEFApp.OsmodalLoop := False;
- end;
- {$ENDIF}
- procedure TMainForm.cwOnBeforePopup(Sender: TObject;
- const browser: ICefBrowser; const frame: ICefFrame; const targetUrl,
- targetFrameName: ustring; targetDisposition: TCefWindowOpenDisposition;
- userGesture: Boolean; const popupFeatures: TCefPopupFeatures;
- var windowInfo: TCefWindowInfo; var client: ICefClient;
- var settings: TCefBrowserSettings;
- var extra_info: ICefDictionaryValue;
- var noJavascriptAccess: Boolean;
- var Result: Boolean);
- begin
- // For simplicity, this demo blocks all popup windows and new tabs
- Result := (targetDisposition in [WOD_NEW_FOREGROUND_TAB, WOD_NEW_BACKGROUND_TAB, WOD_NEW_POPUP, WOD_NEW_WINDOW]);
- end;
- procedure TMainForm.DoAction(Sender: TObject; aExchange: TIDEExchange);
- var
- PayJSON : TJSONObject;
- begin
- payJSON:=Nil;
- if Not (aExchange.Payload is TJSONObject) then
- begin
- Log('Payload is not JSON Object');
- exit;
- end;
- payJSON:=aExchange.Payload as TJSONObject;
- with aExchange do
- case Name of
- 'create':
- Log('Browser created widget of class %s, name %s',[PayJSON.Get('class',''),PayJSON.Get('widget','')]);
- 'select':
- begin
- Log('Browser selected widget of class %s, name %s',[PayJSON.Get('class',''),PayJSON.Get('widget','')]);
- Log('Selected widget state: '+PayJSON.Get('state',''));
- end;
- end;
- end;
- procedure TMainForm.DoClientCame(Sender: TObject; aClient: TIDEClient);
- begin
- if FClientID>0 then
- Log('Ignoring second client (id: %d) attachment.',[aClient.ID])
- else
- begin
- FClientID:=aClient.ID;
- Caption:=FDesignCaption+Format(' [Client: %d]',[FClientID]);
- end;
- end;
- procedure TMainForm.DoAddWidget(Sender: TObject);
- Var
- Cmd : TIDECommand;
- aName : String;
- begin
- aName:=FWidgets[(Sender as TAction).Tag];
- Cmd:=TIDECommand.Create;
- Cmd.NeedsConfirmation:=True;
- Cmd.ClientID:=FClientID;
- Cmd.name:='addWidget';
- Cmd.PayLoad:=TJSONObject.Create(['class','T'+aName+'Widget']);
- FWebIDEIntf.SendCommand(cmd);
- end;
- procedure TMainForm.DoClientLeft(Sender: TObject; aClient: TIDEClient);
- begin
- if (aClient.ID=FClientID) then
- begin
- FClientID:=-1;
- Caption:=FDesignCaption;
- end;
- end;
- procedure TMainForm.DoLogRequest(Sender: TObject; aURL: String);
- var
- m: TLogMsg;
- begin
- if FFormClosing then
- exit;
- m := TLogMsg.Create('Internal server request received: '+aURL);
- Application.QueueAsyncCall(@m.DoLog, 0);
- // Issue https://gitlab.com/freepascal.org/fpc/source/-/issues/39367
- //Application.QueueAsyncCall(@TLogMsg.Create('Internal server request received: '+FURL).DoLog, 0);
- end;
- procedure TMainForm.IsWidgetEnabled(Sender: TObject);
- begin
- (Sender as TAction).Enabled:=(FClientID<>-1);
- end;
- procedure TMainForm.RegisterWidgets;
- begin
- SetLength(FWidgets,9);
- FWidgetCount:=0;
- RegisterWidget('Button',2);
- RegisterWidget('CheckBoxInput',3);
- RegisterWidget('RadioInput',4);
- RegisterWidget('TextInput',5);
- RegisterWidget('Image',6);
- RegisterWidget('TextArea',7);
- RegisterWidget('Select',8);
- RegisterWidget('Container',9);
- RegisterWidget('Jumbo',10);
- end;
- procedure TMainForm.RegisterWidget(aWidget: String; aImageIndex: Integer);
- Var
- A : TAction;
- B : TToolButton;
- L,i : Integer;
- begin
- FWidgets[FWidgetCount]:=aWidget;
- A:=TAction.Create(Self);
- A.ActionList:=ALWidgets;
- A.Name:='AAdd'+aWidget;
- A.Hint:='Add '+aWidget;
- A.Caption:='Add '+aWidget;
- A.ImageIndex:=aImageIndex;
- A.Tag:=FWidgetCount;
- A.OnExecute:=@DoAddWidget;
- A.OnUpdate:=@IsWidgetEnabled;
- L:=0;
- For I:=0 to TBWidgets.ControlCount-1 do
- if TBWidgets.Controls[i].BoundsRect.Right>L then
- L:=TBWidgets.Controls[i].BoundsRect.Right;
- B:=TToolButton.Create(Self);
- B.Parent:=TBWidgets;
- B.Left:=L;
- B.Height:=32;
- B.Action:=A;
- inc(FWidgetCount);
- // TBWidgets.AddControl;
- end;
- procedure TMainForm.Log(Msg: String);
- begin
- MLog.Lines.Add(Msg);
- end;
- procedure TMainForm.Log(Fmt: String; Args: array of const);
- begin
- Log(Format(Fmt,Args));
- end;
- initialization
- {$IFDEF DARWIN}
- AddCrDelegate;
- {$ENDIF}
- if GlobalCEFApp = nil then begin
- CreateGlobalCEFApp;
- if not GlobalCEFApp.StartMainProcess then begin
- DestroyGlobalCEFApp;
- DestroyGlobalCEFWorkScheduler;
- halt(0); // exit the subprocess
- end;
- end;
- finalization
- (* Destroy from this unit, which is used after "Interfaces". So this happens before the Application object is destroyed *)
- if GlobalCEFWorkScheduler <> nil then
- GlobalCEFWorkScheduler.StopScheduler;
- DestroyGlobalCEFApp;
- DestroyGlobalCEFWorkScheduler;
- end.
|