From 12f61e02e73c16c181332c7ebce4c984587a1a09 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Thu, 12 Apr 2018 23:47:24 +0200 Subject: [PATCH] start the terminal widget --- etc/terminal/gtk2term.pas | 130 ++++++++++++ etc/terminal/terminalctrls.pas | 352 +++++++++++++++++++++++++++++++++ lazproj/coedit.lpi | 19 +- lazproj/coedit.lpr | 2 +- src/ce_main.pas | 5 +- src/ce_term.lfm | 9 + src/ce_term.pas | 258 ++++++++++++++++++++++++ 7 files changed, 765 insertions(+), 10 deletions(-) create mode 100644 etc/terminal/gtk2term.pas create mode 100644 etc/terminal/terminalctrls.pas create mode 100644 src/ce_term.lfm create mode 100644 src/ce_term.pas diff --git a/etc/terminal/gtk2term.pas b/etc/terminal/gtk2term.pas new file mode 100644 index 00000000..aca5120a --- /dev/null +++ b/etc/terminal/gtk2term.pas @@ -0,0 +1,130 @@ +unit Gtk2Term; + +{$mode delphi} + +interface + +{$ifdef lclgtk2} + {$ifdef unix} + {$define hasgtk2term} + {$endif} +{$endif} + +{$ifdef hasgtk2term} + +uses + GLib2, Gtk2, dynlibs, gdk2, pango; + +type + GPid = LongWord; + PGPid = ^GPid; + GError = LongWord; + PGError = ^GError; + + TVtePtyFlags = LongWord; + +const + VTE_PTY_DEFAULT = $0; + VTE_PTY_NO_LASTLOG = $1; + VTE_PTY_NO_UTMP = $2; + VTE_PTY_NO_WTMP = $4; + VTE_PTY_NO_HELPER = $8; + VTE_PTY_NO_FALLBACK = $10; + +type + TGSpawnFlags = LongWord; + +const + G_SPAWN_DEFAULT = $0; + G_SPAWN_LEAVE_DESCRIPTORS_OPEN = $1; + G_SPAWN_DO_NOT_REAP_CHILD = $2; + G_SPAWN_SEARCH_PATH = $4; + G_SPAWN_STDOUT_TO_DEV_NULL = $8; + G_SPAWN_STDERR_TO_DEV_NULL = $10; + G_SPAWN_CHILD_INHERITS_STDIN = $20; + G_SPAWN_FILE_AND_ARGV_ZERO = $40; + G_SPAWN_SEARCH_PATH_FROM_ENVP = $80; + G_SPAWN_CLOEXEC_PIPES = $100; + +type + TGSpawnChildSetupFunc = procedure(user_data: Pointer); cdecl; + + PVteTerminal = ^TVteTerminal; + TVteTerminal = record + widget: PGtkWidget; + end; + + VTE_TERMINAL = PVteTerminal; + +var + vte_terminal_new: function: PGtkWidget; cdecl; + + vte_terminal_fork_command_full: function(terminal: PVteTerminal; pty_flags: TVtePtyFlags; + working_directory: PChar; argv, envv: PPChar; spawn_flags: TGSpawnFlags; + child_setup: TGSpawnChildSetupFunc; child_setup_data: Pointer; child_pid: + PGPid; error: PGError): GBoolean; cdecl; + + vte_terminal_set_color_background: procedure(terminal: PVteTerminal; + const background: PGdkColor); cdecl; + + vte_terminal_set_color_foreground: procedure(terminal: PVteTerminal; + const background: PGdkColor); cdecl; + + vte_terminal_set_color_highlight: procedure(terminal: PVteTerminal; + const background: PGdkColor); cdecl; + + vte_terminal_set_color_highlight_foreground: procedure(terminal: PVteTerminal; + const background: PGdkColor); cdecl; + + vte_terminal_set_font: procedure(terminal: PVteTerminal; + const font_desc: PPangoFontDescription); cdecl; + + vte_terminal_feed: procedure(terminal: PVteTerminal; data: PChar; + length: PtrInt); cdecl; + + vte_terminal_feed_child: procedure(terminal: PVteTerminal; data: PChar; length: PtrInt); cdecl; + + vte_get_user_shell: function(): PChar; + +function Gtk2TermLoad: Boolean; + +implementation + +var + Initialized: Boolean; + Loaded: Boolean; + +function Gtk2TermLoad: Boolean; +const + vte = 'libvte.so'; +var + Lib: TLibHandle; +begin + if Initialized then + Exit(Loaded); + Initialized := True; + Lib := LoadLibrary(vte); + if Lib = 0 then + Exit(Loaded); + + @vte_terminal_new := GetProcAddress(Lib, 'vte_terminal_new'); + @vte_terminal_fork_command_full := GetProcAddress(Lib, 'vte_terminal_fork_command_full'); + @vte_terminal_set_color_background := GetProcAddress(Lib, 'vte_terminal_set_color_background'); + @vte_terminal_set_color_foreground := GetProcAddress(Lib, 'vte_terminal_set_color_foreground'); + @vte_terminal_set_color_highlight := GetProcAddress(Lib, 'vte_terminal_set_color_highlight'); + @vte_terminal_set_color_highlight_foreground := GetProcAddress(Lib, 'vte_terminal_set_color_highlight_foreground'); + @vte_terminal_set_font := GetProcAddress(Lib, 'vte_terminal_set_font'); + @vte_terminal_feed := GetProcAddress(Lib, 'vte_terminal_feed'); + @vte_terminal_feed_child := GetProcAddress(Lib, 'vte_terminal_feed_child'); + @vte_get_user_shell := GetProcAddress(Lib, 'vte_get_user_shell'); + + // assume all or none + Loaded := @vte_terminal_new <> nil; + + Result := Loaded; +end; +{$else} +implementation +{$endif} + +end. diff --git a/etc/terminal/terminalctrls.pas b/etc/terminal/terminalctrls.pas new file mode 100644 index 00000000..0f0ea375 --- /dev/null +++ b/etc/terminal/terminalctrls.pas @@ -0,0 +1,352 @@ +unit TerminalCtrls; + +{$mode delphi} + +{$ifdef lclgtk2} + {$ifdef unix} + {$define hasgtk2term} + {$endif} +{$endif} + +interface + +uses + Gtk2Term, Classes, SysUtils, Controls, Graphics; + +type + + TTerminal = class(TCustomControl) + private + FInfo: Pointer; + fTerminalHanlde: PVteTerminal; + fOnTerminate: TNotifyEvent; + fOnTerminalVisibleChanged: TNotifyEvent; + fBackgroundColor: TColor; + fForegroundColor: TColor; + fSelectedColor: TColor; + procedure setBackgroundColor(value: TColor); + procedure setForegroundColor(value: TColor); + procedure setSelectedColor(value: TColor); + protected + // Only used at design-time. + procedure Paint; override; + procedure DoTerminate; virtual; + procedure DoTerminalVisibleChanged; virtual; + procedure FontChanged(Sender: TObject); override; + public + constructor Create(AOwner: TComponent); override; + procedure Restart; + // Sends a command, as it would be manually typed. Line feed is automatically added. + procedure Command(const data: string); + published + // Background color + property backgroundColor: TColor read fBackgroundColor write setBackgroundColor default clBlack; + // Font color + property foregroundColor: TColor read fForegroundColor write setForegroundColor default clWhite; + // Background color for the selection + property selectedColor: TColor read fSelectedColor write setSelectedColor default clWhite; + property Align; + property Anchors; + property Constraints; + property DockSite; + property DragCursor; + property DragKind; + property DragMode; + property DoubleBuffered; + property Enabled; + // The name and height properties are handled. see foregroundColor for Color. + property Font; + property ParentShowHint; + property PopupMenu; + property ShowHint; + property TabOrder; + property TabStop; + property UseDockManager default True; + property Visible; + property OnClick; + property OnContextPopup; + property OnDockDrop; + property OnDockOver; + property OnDblClick; + property OnDragDrop; + property OnDragOver; + property OnEndDock; + property OnEndDrag; + property OnEnter; + property OnExit; + property OnGetSiteInfo; + property OnGetDockCaption; + property OnMouseDown; + property OnMouseEnter; + property OnMouseLeave; + property OnMouseMove; + property OnMouseUp; + property OnMouseWheel; + property OnMouseWheelDown; + property OnMouseWheelUp; + property OnResize; + property OnStartDock; + property OnStartDrag; + property OnUnDock; + property OnTerminate: TNotifyEvent read FOnTerminate write FOnTerminate; + // Note: The hosted widget is there and visual settings can be applied. + // In many cases DoFirstShow, OnShow and likes will happen too quickly. + property OnTerminalVisibleChanged: TNotifyEvent read fOnTerminalVisibleChanged write fOnTerminalVisibleChanged; + end; + +function TerminalAvailable: Boolean; + +implementation + +{$ifdef hasgtk2term} +uses + LCLType, WSControls, WSLCLClasses, GLib2, Gtk2, Gtk2Def, Gtk2Proc, + Gtk2WSControls, gdk2; + +type + + TGtk2WSTerminal = class(TWSCustomControl) + protected + class procedure SetCallbacks(const AGtkWidget: PGtkWidget; + const AWidgetInfo: PWidgetInfo); virtual; + published + class function CreateHandle(const AWinControl: TWinControl; + const AParams: TCreateParams): TLCLIntfHandle; override; + end; + +procedure TerminalExit(Widget: PGtkWidget); cdecl; +var + Info: PWidgetInfo; +begin + Info := PWidgetInfo(g_object_get_data(PGObject(Widget), 'widgetinfo')); + TTerminal(Info.LCLObject).DoTerminate; +end; + +procedure TerminalRefresh(Widget: PGtkWidget); cdecl; +var + Info: PWidgetInfo; +begin + Info := PWidgetInfo(g_object_get_data(PGObject(Widget), 'widgetinfo')); + TTerminal(Info.LCLObject).DoTerminalVisibleChanged; +end; + +class procedure TGtk2WSTerminal.SetCallbacks(const AGtkWidget: PGtkWidget; + const AWidgetInfo: PWidgetInfo); +begin + TGtk2WSWinControl.SetCallbacks(PGtkObject(AGtkWidget), TComponent(AWidgetInfo^.LCLObject)); +end; + +class function TGtk2WSTerminal.CreateHandle(const AWinControl: TWinControl; + const AParams: TCreateParams): TLCLIntfHandle; +var + Info: PWidgetInfo; + Style: PGtkRCStyle; + Args: array[0..1] of PChar = (nil, nil); + Allocation: TGTKAllocation; +const + Flgs: array[boolean] of integer = (GTK_CAN_FOCUS, GTK_CAN_FOCUS or GTK_DOUBLE_BUFFERED); +begin + Args[0] := vte_get_user_shell(); + if Args[0] = nil then + Args[0] := '/bin/bash'; + + { Initialize widget info } + Info := CreateWidgetInfo(gtk_frame_new(nil), AWinControl, AParams); + Info.LCLObject := AWinControl; + Info.Style := AParams.Style; + Info.ExStyle := AParams.ExStyle; + Info.WndProc := {%H-}PtrUInt(AParams.WindowClass.lpfnWndProc); + TTerminal(AWinControl).FInfo := Info; + + { Configure core and client } + gtk_frame_set_shadow_type(PGtkFrame(Info.CoreWidget), GTK_SHADOW_NONE); + Style := gtk_widget_get_modifier_style(Info.CoreWidget); + Style.xthickness := 0; + Style.ythickness := 0; + gtk_widget_modify_style(Info.CoreWidget, Style); + if csDesigning in AWinControl.ComponentState then + Info.ClientWidget := CreateFixedClientWidget(True) + else + begin + Info.ClientWidget := vte_terminal_new(); + TTerminal(AWinControl).fTerminalHanlde := VTE_TERMINAL(Info.ClientWidget); + vte_terminal_fork_command_full(VTE_TERMINAL(Info.ClientWidget), VTE_PTY_DEFAULT, + nil, @Args[0], nil, G_SPAWN_SEARCH_PATH, nil, nil, nil, nil); + end; + GTK_WIDGET_SET_FLAGS(Info.CoreWidget, Flgs[AWinControl.DoubleBuffered]); + gtk_container_add(GTK_CONTAINER(Info.CoreWidget), Info.ClientWidget); + g_object_set_data(PGObject(Info.ClientWidget), 'widgetinfo', Info); + gtk_widget_show_all(Info.CoreWidget); + Allocation.X := AParams.X; + Allocation.Y := AParams.Y; + Allocation.Width := AParams.Width; + Allocation.Height := AParams.Height; + gtk_widget_size_allocate(Info.CoreWidget, @Allocation); + g_signal_connect(Info.ClientWidget, 'child-exited', G_CALLBACK(@TerminalExit), nil); + g_signal_connect(Info.ClientWidget, 'contents-changed', G_CALLBACK(@TerminalRefresh), nil); + SetCallbacks(Info.CoreWidget, Info); + Result := {%H-}TLCLIntfHandle(Info.CoreWidget); +end; +{$endif} + +procedure TTerminal.DoTerminate; +begin + if Assigned(FOnTerminate) then + FOnTerminate(Self); +end; + +procedure TTerminal.DoTerminalVisibleChanged; +begin + if Assigned(fOnTerminalVisibleChanged) then + fOnTerminalVisibleChanged(Self); +end; + +procedure TTerminal.Restart; +{$ifdef hasgtk2term} +var + Info: PWidgetInfo; + Args: array[0..1] of PChar = (nil, nil); +{$endif} +begin + {$ifdef hasgtk2term} + if not HandleAllocated then + Exit; + + Args[0] := vte_get_user_shell(); + if Args[0] = nil then + Args[0] := '/bin/bash'; + Info := PWidgetInfo(FInfo); + gtk_widget_destroy(Info.ClientWidget); + Info.ClientWidget := vte_terminal_new; + fTerminalHanlde := VTE_TERMINAL(Info.ClientWidget); + vte_terminal_fork_command_full(fTerminalHanlde, VTE_PTY_DEFAULT, + nil, @Args[0], nil, G_SPAWN_SEARCH_PATH, nil, nil, nil, nil); + gtk_container_add(GTK_CONTAINER(Info.CoreWidget), Info.ClientWidget); + g_object_set_data(PGObject(Info.ClientWidget), 'widgetinfo', Info); + gtk_widget_show_all(Info.CoreWidget); + g_signal_connect(Info.ClientWidget, 'child-exited', G_CALLBACK(@TerminalExit), nil); + g_signal_connect(Info.ClientWidget, 'contents-changed', G_CALLBACK(@TerminalRefresh), nil); + {$endif} +end; + +procedure TTerminal.Command(const data: string); +begin + {$ifdef hasgtk2term} + if assigned(fTerminalHanlde) and assigned(vte_terminal_feed_child) then + vte_terminal_feed_child(fTerminalHanlde, PChar(data + #10), data.Length + 1); + {$endif} +end; + +function TerminalAvailable: Boolean; +begin + {$ifdef hasgtk2term} + Result := Gtk2TermLoad; + {$else} + Result := false; + {$endif} +end; + +function RegisterTerminal: Boolean; +begin + Result := TerminalAvailable; + if Result then + RegisterWSComponent(TTerminal, TGtk2WSTerminal); +end; + +constructor TTerminal.Create(AOwner: TComponent); +begin + inherited Create(AOwner); + Width := 300; + Height := 200; + fBackgroundColor:= clBlack; + fForegroundColor:= clWhite; + fSelectedColor:= clWhite; + Font.Height:=11; + Font.Name:='Monospace'; +end; + +procedure TTerminal.Paint; +const + s = 'linux@user:~$ bash terminal'; +var + w: integer = 0; + h: integer = 0; +begin + if not (csDesigning in ComponentState) then + exit; + + Canvas.Pen.Style := psDash; + Canvas.Pen.Color := clWhite; + Canvas.Brush.Color := clBlack; + Canvas.Font.Color := clWhite; + Canvas.FillRect(ClientRect); + Canvas.Rectangle(ClientRect); + Canvas.GetTextSize(s, w, h); + Canvas.TextOut((Width - w) div 2, (Height - h) div 2, s); +end; + +procedure TTerminal.setBackgroundColor(value: TColor); +var + c: TGDKColor; +begin + fBackgroundColor:=value; + {$ifdef hasgtk2term} + if assigned(fTerminalHanlde) and assigned(vte_terminal_set_color_background) then + begin + c := TColortoTGDKColor(fBackgroundColor); + vte_terminal_set_color_background(fTerminalHanlde, @c); + end; + {$endif} +end; + +procedure TTerminal.setForegroundColor(value: TColor); +var + c: TGDKColor; +begin + fForegroundColor:=value; + {$ifdef hasgtk2term} + if assigned(fTerminalHanlde) and assigned(vte_terminal_set_color_foreground) then + begin + c := TColortoTGDKColor(fForegroundColor); + vte_terminal_set_color_foreground(fTerminalHanlde, @c); + end; + {$endif} +end; + +procedure TTerminal.setSelectedColor(value: TColor); +var + c: TGDKColor; +begin + fSelectedColor:=value; + {$ifdef hasgtk2term} + if assigned(fTerminalHanlde) and assigned(vte_terminal_set_color_highlight) + and assigned(vte_terminal_set_color_highlight_foreground) then + begin + c := TColortoTGDKColor(fSelectedColor); + vte_terminal_set_color_highlight(fTerminalHanlde, @c); + c := TColortoTGDKColor(InvertColor(fSelectedColor)); + vte_terminal_set_color_highlight_foreground(fTerminalHanlde, @c); + end; + {$endif} +end; + +procedure TTerminal.FontChanged(Sender: TObject); +begin + inherited; + {$ifdef hasgtk2term} + {$push}{$Hints off} + if assigned(fTerminalHanlde) and assigned(vte_terminal_set_font) and + (Handle <> INVALID_HANDLE_VALUE) then + begin + vte_terminal_set_font(fTerminalHanlde, PGtkWidget(Handle).style.font_desc); + end; + {$pop} + {$endif} +end; + +{$ifdef hasgtk2term} +initialization + RegisterTerminal; +{$endif} +end. + diff --git a/lazproj/coedit.lpi b/lazproj/coedit.lpi index 182ecf6d..60aea56d 100644 --- a/lazproj/coedit.lpi +++ b/lazproj/coedit.lpi @@ -403,7 +403,7 @@ - + @@ -433,10 +433,6 @@ - - - - @@ -449,7 +445,7 @@ - + @@ -519,7 +515,7 @@ - + @@ -826,6 +822,13 @@ + + + + + + + @@ -836,7 +839,7 @@ - + diff --git a/lazproj/coedit.lpr b/lazproj/coedit.lpr index b6e344ce..2e37598e 100644 --- a/lazproj/coedit.lpr +++ b/lazproj/coedit.lpr @@ -13,7 +13,7 @@ uses ce_processes, ce_dialogs, ce_dubprojeditor, ce_controls, ce_dfmt, ce_lcldragdrop, ce_stringrange, ce_dlangmaps, ce_projgroup, ce_projutils, ce_d2synpresets, ce_dastworx, ce_dbgitf, ce_ddemangle, ce_dubproject, - ce_halstead, ce_diff, ce_profileviewer, ce_semver; + ce_halstead, ce_diff, ce_profileviewer, ce_semver, ce_term; {$R *.res} diff --git a/src/ce_main.pas b/src/ce_main.pas index f89124bc..4cf09a70 100644 --- a/src/ce_main.pas +++ b/src/ce_main.pas @@ -16,7 +16,7 @@ uses ce_toolseditor, ce_procinput, ce_optionseditor, ce_symlist, ce_mru, ce_processes, ce_infos, ce_dubproject, ce_dialogs, ce_dubprojeditor,{$IFDEF UNIX} ce_gdb,{$ENDIF} ce_dfmt, ce_lcldragdrop, ce_projgroup, ce_projutils, ce_stringrange, ce_dastworx, - ce_halstead, ce_profileviewer, ce_semver, ce_dsgncontrols; + ce_halstead, ce_profileviewer, ce_semver, ce_dsgncontrols, ce_term; type @@ -384,6 +384,7 @@ type fPrjGrpWidg: TCEProjectGroupWidget; {$IFDEF UNIX} fGdbWidg: TCEGdbWidget; + fTermWWidg: TCETermWidget; {$ENDIF} fDfmtWidg: TCEDfmtWidget; fProfWidg: TCEProfileViewerWidget; @@ -1464,6 +1465,7 @@ begin fProfWidg := TCEProfileViewerWidget.create(self); {$IFDEF UNIX} fGdbWidg := TCEGdbWidget.create(self); + fTermWWidg := TCETermWidget.create(self); {$ENDIF} getMessageDisplay(fMsgs); @@ -1487,6 +1489,7 @@ begin fWidgList.addWidget(@fProfWidg); {$IFDEF UNIX} fWidgList.addWidget(@fGdbWidg); + fWidgList.addWidget(@fTermWWidg); {$ENDIF} fWidgList.sort(@CompareWidgCaption); diff --git a/src/ce_term.lfm b/src/ce_term.lfm new file mode 100644 index 00000000..c8335738 --- /dev/null +++ b/src/ce_term.lfm @@ -0,0 +1,9 @@ +inherited CETermWidget: TCETermWidget + Caption = 'Terminal' + inherited Back: TPanel + inherited Content: TPanel + Height = 85 + Top = 36 + end + end +end diff --git a/src/ce_term.pas b/src/ce_term.pas new file mode 100644 index 00000000..e581b0b6 --- /dev/null +++ b/src/ce_term.pas @@ -0,0 +1,258 @@ +unit ce_term; + +{$I ce_defines.inc} + +interface + +uses + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, + ce_widget, TerminalCtrls, ce_interfaces, ce_writableComponent, ce_observer, + ce_common, ce_synmemo; + +type + + // Terminal options + TCETerminalOptionsBase = class(TWritableLfmTextComponent) + private + fBackgroundColor: TColor; + fForegroundColor: TColor; + fSelectedColor: TColor; + fFollowEditors: boolean; + fFollowProjects: boolean; + fFont: TFont; + procedure setFont(value: TFont); + public + constructor create(AOwner: TComponent); override; + destructor destroy; override; + procedure assign(value: TPersistent); override; + published + property backgroundColor: TColor read fBackgroundColor write fBackgroundColor; + property foregroundColor: TColor read fForegroundColor write fForegroundColor; + property selectedColor: TColor read fSelectedColor write fSelectedColor; + property font: TFont read fFont write setFont; + property followEditors: boolean read fFollowEditors write fFollowEditors; + property followProjects: boolean read fFollowProjects write fFollowProjects; + end; + + // Editable and reversible Terminal options + TCETerminalOptions = class(TCETerminalOptionsBase, ICEEditableOptions) + private + fBackup: TCETerminalOptionsBase; + function optionedWantCategory(): string; + function optionedWantEditorKind: TOptionEditorKind; + function optionedWantContainer: TPersistent; + procedure optionedEvent(event: TOptionEditorEvent); + function optionedOptionsModified: boolean; + public + constructor Create(AOwner: TComponent); override; + procedure applyChanges; + end; + + { TCETermWidget } + + TCETermWidget = class(TCEWidget, ICEDocumentObserver, ICEProjectObserver) + procedure FormShow(Sender: TObject); + private + fTerm: TTerminal; + fOpts: TCETerminalOptions; + + procedure docNew(document: TCESynMemo); + procedure docFocused(document: TCESynMemo); + procedure docChanged(document: TCESynMemo); + procedure docClosing(document: TCESynMemo); + + procedure projNew(project: ICECommonProject); + procedure projChanged(project: ICECommonProject); + procedure projClosing(project: ICECommonProject); + procedure projFocused(project: ICECommonProject); + procedure projCompiling(project: ICECommonProject); + procedure projCompiled(project: ICECommonProject; success: boolean); + + public + constructor create(aOwner: TComponent); override; + destructor destroy; override; + end; + +implementation +{$R *.lfm} + +const + optFname = 'terminal.txt'; + +constructor TCETerminalOptionsBase.create(AOwner: TComponent); +begin + inherited; + fFont := TFont.Create; + fBackgroundColor:= clWhite; + fForegroundColor:= clBlack; + fSelectedColor:= clBlack; + fFont.Name:= 'Monospace'; + fFont.Size:= 12; +end; + +destructor TCETerminalOptionsBase.destroy; +begin + fFont.Free; + inherited; +end; + +procedure TCETerminalOptionsBase.setFont(value: TFont); +begin + fFont.Assign(value); +end; + +procedure TCETerminalOptionsBase.assign(value: TPersistent); +var + s: TCETerminalOptionsBase; +begin + if value is TCETerminalOptionsBase then + begin + s := TCETerminalOptionsBase(value); + fBackgroundColor:=s.fbackgroundColor; + fForegroundColor:=s.fForegroundColor; + fSelectedColor:=s.fSelectedColor; + followEditors:=s.fFollowEditors; + fFont.Assign(s.font); + end + else inherited; +end; + +constructor TCETerminalOptions.Create(AOwner: TComponent); +begin + inherited; + fBackup := TCETerminalOptionsBase.Create(self); +end; + +procedure TCETerminalOptions.applyChanges; +var + w: TCETermWidget; +begin + w := TCETermWidget(owner); + w.fTerm.backgroundColor:= backgroundColor; + w.fTerm.foregroundColor:= foregroundColor; + w.fTerm.selectedColor:= selectedColor; + w.fTerm.Font.BeginUpdate; + w.fTerm.Font.Assign(fFont); + w.fTerm.Font.Size := w.fTerm.Font.Size +1; + w.fTerm.Font.Size := w.fTerm.Font.Size -1; + w.fTerm.Font.endUpdate; +end; + +function TCETerminalOptions.optionedWantCategory(): string; +begin + result := 'Terminal'; +end; + +function TCETerminalOptions.optionedWantEditorKind: TOptionEditorKind; +begin + result := oekGeneric; +end; + +function TCETerminalOptions.optionedWantContainer: TPersistent; +begin + result := self; +end; + +procedure TCETerminalOptions.optionedEvent(event: TOptionEditorEvent); +begin + case event of + oeeAccept: + begin + fBackup.assign(self); + applyChanges; + end; + oeeCancel: + begin + self.assign(fBackup); + applyChanges; + end; + oeeChange: + begin + applyChanges; + end; + end; +end; + +function TCETerminalOptions.optionedOptionsModified: boolean; +begin + result := false; +end; + +constructor TCETermWidget.create(aOwner: TComponent); +var + f: string; +begin + inherited; + fTerm := TTerminal.Create(self); + fTerm.Align:= alClient; + fTerm.BorderSpacing.Around:=4; + fterm.Parent := self; + fTerm.OnTerminalVisibleChanged:=@FormShow; + + fOpts:= TCETerminalOptions.Create(self); + + f := getCoeditDocPath + optFname; + if f.fileExists then + fOpts.loadFromFile(f); + + EntitiesConnector.addObserver(fOpts); +end; + +destructor TCETermWidget.destroy; +begin + fOpts.saveToFile(getCoeditDocPath + optFname); + EntitiesConnector.removeObserver(fOpts); + inherited; +end; + +procedure TCETermWidget.FormShow(Sender: TObject); +begin + fOpts.applyChanges; +end; + +procedure TCETermWidget.docNew(document: TCESynMemo); +begin +end; + +procedure TCETermWidget.docFocused(document: TCESynMemo); +begin + if fOpts.followEditors and document.fileName.fileExists then + fTerm.Command('cd ' + document.fileName.extractFileDir); +end; + +procedure TCETermWidget.docChanged(document: TCESynMemo); +begin +end; + +procedure TCETermWidget.docClosing(document: TCESynMemo); +begin +end; + +procedure TCETermWidget.projNew(project: ICECommonProject); +begin +end; + +procedure TCETermWidget.projChanged(project: ICECommonProject); +begin +end; + +procedure TCETermWidget.projClosing(project: ICECommonProject); +begin +end; + +procedure TCETermWidget.projFocused(project: ICECommonProject); +begin + if fOpts.followProjects and project.fileName.fileExists then + fTerm.Command('cd ' + project.fileName.extractFileDir); +end; + +procedure TCETermWidget.projCompiling(project: ICECommonProject); +begin +end; + +procedure TCETermWidget.projCompiled(project: ICECommonProject; success: boolean); +begin +end; + +end. +