From 2f2808005d2363db79ae17e9a6b05e5628fd7c6e Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Mon, 23 Feb 2015 06:17:39 +0100 Subject: [PATCH 1/7] widget can specify it want to be shown as modal form --- src/ce_widget.pas | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ce_widget.pas b/src/ce_widget.pas index 6e9a38dd..9c03deeb 100644 --- a/src/ce_widget.pas +++ b/src/ce_widget.pas @@ -36,6 +36,7 @@ type procedure optset_UpdaterDelay(aReader: TReader); protected fDockable: boolean; + fModal: boolean; fID: string; // a descendant overrides to implementi a periodic update. procedure UpdateByLoop; virtual; @@ -51,6 +52,8 @@ type procedure sesoptBeforeSave; virtual; procedure sesoptDeclareProperties(aFiler: TFiler); virtual; procedure sesoptAfterLoad; virtual; + // + function getIfModal: boolean; published property updaterByLoopInterval: Integer read fLoopInter write setLoopInt; property updaterByDelayDuration: Integer read fDelayDur write setDelayDur; @@ -77,6 +80,8 @@ type property updating: boolean read fUpdating; // true by default, allow a widget to be docked. property isDockable: boolean read fDockable; + // not if isDockable, otherwise a the widget is shown as modal form. + property isModal: boolean read getIfModal; end; (** @@ -138,6 +143,13 @@ begin EntitiesConnector.removeObserver(self); inherited; end; + +function TCEWidget.getIfModal: boolean; +begin + if isDockable then result := false + else result := fModal; +end; + {$ENDREGION} {$REGION ICESessionOptionsObserver ---------------------------------------------} From d60048619869adcdc229508e64d240827e6b1aee Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Mon, 23 Feb 2015 06:18:19 +0100 Subject: [PATCH 2/7] tools pass their shortcut when declared in main menu --- src/ce_tools.pas | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/src/ce_tools.pas b/src/ce_tools.pas index a2a87aa5..36b69786 100644 --- a/src/ce_tools.pas +++ b/src/ce_tools.pas @@ -204,15 +204,20 @@ procedure TCETools.menuDeclare(item: TMenuItem); var i: Integer; itm: TMenuItem; + colitm: TCEToolItem; begin if tools.Count = 0 then exit; // item.Caption := 'Custom tools'; item.Clear; - for i := 0 to tools.Count-1 do begin + for i := 0 to tools.Count-1 do + begin + colitm := tool[i]; + // itm := TMenuItem.Create(item); - itm.Caption := tool[i].toolAlias; - itm.tag := ptrInt(tool[i]); + itm.ShortCut:= colitm.shortcut; + itm.Caption := colitm.toolAlias; + itm.tag := ptrInt(colitm); itm.onClick := @executeToolFromMenu; item.add(itm); end; @@ -221,16 +226,23 @@ end; procedure TCETools.menuUpdate(item: TMenuItem); var i: Integer; + colitm: TCEToolItem; + mnuitm: TMenuItem; begin if item = nil then exit; if item.Count <> tools.Count then menuDeclare(item) else for i:= 0 to tools.Count-1 do begin - if ptrInt(tool[i]) <> item.Items[i].Tag then - item.Items[i].Tag := ptrInt(tool[i]); - if item.Items[i].Caption <> tool[i].toolAlias then - item.Items[i].Caption := tool[i].toolAlias; + colitm := tool[i]; + mnuitm := item.Items[i]; + // + if mnuitm.Tag <> ptrInt(colitm) then + mnuitm.Tag := ptrInt(colitm); + if mnuitm.Caption <> colitm.toolAlias then + mnuitm.Caption := colitm.toolAlias; + if mnuitm.shortcut <> colitm.shortcut then + mnuitm.shortcut := colitm.shortcut; end; end; {$ENDREGION} @@ -253,8 +265,16 @@ begin end; procedure TCETools.scedSendItem(const category, identifier: string; aShortcut: TShortcut); +var + i: Integer; begin - + if category <> 'Tools' then exit; + // + for i := 0 to tools.Count-1 do if tool[i].toolAlias = identifier then + begin + tool[i].shortcut := aShortcut; + break; + end; end; {$ENDREGION} From 42a8cc89245a1ed9eff6a8455f0f0051b2491212 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Mon, 23 Feb 2015 06:19:08 +0100 Subject: [PATCH 3/7] option editor is modal when editing a shortcut this prevent the shortcut to be handled --- src/ce_optionseditor.lfm | 2 +- src/ce_optionseditor.pas | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ce_optionseditor.lfm b/src/ce_optionseditor.lfm index 1c17a44d..a9cf09e9 100644 --- a/src/ce_optionseditor.lfm +++ b/src/ce_optionseditor.lfm @@ -7,7 +7,7 @@ inherited CEOptionEditorWidget: TCEOptionEditorWidget Caption = 'Options editor' ClientHeight = 493 ClientWidth = 559 - FormStyle = fsStayOnTop + FormStyle = fsSystemStayOnTop inherited Back: TPanel Height = 493 Width = 559 diff --git a/src/ce_optionseditor.pas b/src/ce_optionseditor.pas index 38810c0c..03cd26c6 100644 --- a/src/ce_optionseditor.pas +++ b/src/ce_optionseditor.pas @@ -57,6 +57,7 @@ var begin inherited; fDockable := false; + fModal:= true; fEdOptsSubj := TCEEditableOptionsSubject.create; // png := TPortableNetworkGraphic.Create; From 9ea1608f74fbbdf2fc8150093d4eabe2efc16234 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Mon, 23 Feb 2015 06:20:00 +0100 Subject: [PATCH 4/7] added interface ICEActionProvider maybe as an alternative to ICEMainMenuProvider --- src/ce_interfaces.pas | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/src/ce_interfaces.pas b/src/ce_interfaces.pas index 217c6677..c40ec101 100644 --- a/src/ce_interfaces.pas +++ b/src/ce_interfaces.pas @@ -98,7 +98,7 @@ type (** - * An implementer can add a mai nmenu entry. + * An implementer can add a main menu entry. *) ICEMainMenuProvider = interface ['ICEMainMenuProvider'] @@ -108,7 +108,7 @@ type procedure menuUpdate(item: TMenuItem); end; (** - * An implementer agregates its observers menus. + * An implementer collects and updates its observers menus. *) TCEMainMenuSubject = class(TCECustomSubject) protected @@ -117,6 +117,31 @@ type + (** + * An implementer declares some actions which have their own main menu entry and + * whose shortcuts are automatically handled + *) + ICEActionProvider = interface + ['ICEActionProvider'] + // the action handler will clear the references to the actions collected previously and start collecting if result. + function actHandlerWantRecollect: boolean; + // the action handler starts to collect the actions if result. + function actHandlerWantFirst: boolean; + // the handler continue collecting action if result. + function actHandlerWantNext(out category: string; out action: TCustomAction): boolean; + // the handler update the state of a particular action. + procedure actHandleUpdater(action: TCustomAction); + end; + (** + * An implementer handles its observers actions. + *) + TCEActionProviderSubject = class(TCECustomSubject) + protected + function acceptObserver(aObject: TObject): boolean; override; + end; + + + (** * An implementer can expose some customizable shortcuts to be edited in a dedicated widget. *) @@ -128,7 +153,6 @@ type function scedWantNext(out category, identifier: string; out aShortcut: TShortcut): boolean; // a TCEEditableShortCutSubject sends the possibly modified shortcut procedure scedSendItem(const category, identifier: string; aShortcut: TShortcut); - end; (** * An implementer manages its observers shortcuts. @@ -139,6 +163,7 @@ type end; + // the option editor uses this value as a hint to cast and display an option container. TOptionEditorKind = (oekGeneric, oekForm, oekControl); // event generated by the option editor and passed to an ICEEditableOptions. @@ -400,6 +425,11 @@ function TCEEditableOptionsSubject.acceptObserver(aObject: TObject): boolean; begin exit(aObject is ICEEditableOptions); end; + +function TCEActionProviderSubject.acceptObserver(aObject: TObject): boolean; +begin + exit(aObject is ICEActionProvider); +end; {$ENDREGION} {$REGION ICESingleService getters ----------------------------------------------} From 6df102dac40ab00c1c9f29cfc240b274ee7e9653 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Mon, 23 Feb 2015 06:20:33 +0100 Subject: [PATCH 5/7] shortcut editor pass the new shortcut value to the observers --- src/ce_shortcutseditor.pas | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/ce_shortcutseditor.pas b/src/ce_shortcutseditor.pas index 0b781e04..ae2bbf7c 100644 --- a/src/ce_shortcutseditor.pas +++ b/src/ce_shortcutseditor.pas @@ -15,6 +15,8 @@ type private fIdentifier: string; fData: TShortcut; + fDeclarator: ICEEditableShortCut; + property declarator: ICEEditableShortCut read fDeclarator write fDeclarator; published property identifier: string read fIdentifier write fIdentifier; property data: TShortcut read fData write fData; @@ -220,13 +222,23 @@ begin end; procedure TCEShortcutEditor.LabeledEdit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); +var + sh: TShortCut; begin if tree.Selected = nil then exit; if tree.Selected.Level = 0 then exit; if tree.Selected.Data = nil then exit; // - if Key = VK_RETURN then shortcutCatcher.Enabled := false - else TShortcutItem(tree.Selected.Data).data := Shortcut(Key, Shift); + if Key = VK_RETURN then + shortcutCatcher.Enabled := false + else + begin + sh := Shortcut(Key, Shift); + TShortcutItem(tree.Selected.Data).data := sh; + TShortcutItem(tree.Selected.Data).declarator.scedSendItem( + tree.Selected.Parent.Text, + tree.Selected.Text, sh ); + end; // updateEditCtrls; end; @@ -281,6 +293,7 @@ begin itm := TShortcutItem(fShortcuts.items.Add); itm.identifier := idt; itm.data:= sht; + itm.declarator := obs; tree.Items.AddChildObject(prt, idt, itm); cat := ''; idt := ''; From 10aa04e96a011166d4e63194bdf63bbaac293778 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Mon, 23 Feb 2015 06:20:53 +0100 Subject: [PATCH 6/7] added support for modal widget --- src/ce_main.pas | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/ce_main.pas b/src/ce_main.pas index 382c833f..9533b986 100644 --- a/src/ce_main.pas +++ b/src/ce_main.pas @@ -1403,13 +1403,18 @@ begin if widg = nil then exit; // if widg.isDockable then - win := DockMaster.GetAnchorSite(widg) - else - win := widg; - // - if win = nil then exit; - win.Show; - win.BringToFront; + begin + win := DockMaster.GetAnchorSite(widg); + win.Show; + win.BringToFront; + end + else begin + if widg.isModal then widg.ShowModal else + begin + widg.Show; + widg.BringToFront; + end; + end; end; procedure TCEMainForm.layoutLoadFromFile(const aFilename: string); From a1d0d600f220f277cdf15daa8a888cd97f5957b5 Mon Sep 17 00:00:00 2001 From: Basile Burg Date: Mon, 23 Feb 2015 06:21:26 +0100 Subject: [PATCH 7/7] added basic TCEActionProviderSubject implementation --- src/ce_main.pas | 70 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 2 deletions(-) diff --git a/src/ce_main.pas b/src/ce_main.pas index 9533b986..fa0655f8 100644 --- a/src/ce_main.pas +++ b/src/ce_main.pas @@ -178,6 +178,7 @@ type private fDoc: TCESynMemo; + fActionHandler: TCEActionProviderSubject; fMultidoc: ICEMultiDocHandler; fScCollectCount: Integer; fUpdateCount: NativeInt; @@ -209,6 +210,10 @@ type fMainMenuSubj: TCEMainMenuSubject; procedure updateMainMenuProviders; + // action provider handling; + procedure clearActProviderEntries; + procedure collectedActProviderEntries; + // ICEMultiDocObserver procedure docNew(aDoc: TCESynMemo); procedure docClosing(aDoc: TCESynMemo); @@ -300,7 +305,8 @@ uses constructor TCEMainForm.create(aOwner: TComponent); begin inherited create(aOwner); - fMainMenuSubj:= TCEMainMenuSubject.create; + fMainMenuSubj := TCEMainMenuSubject.create; + fActionHandler := TCEActionProviderSubject.create; // EntitiesConnector.addObserver(self); // @@ -648,6 +654,7 @@ begin FreeRunnableProc; // fMainMenuSubj.Free; + fActionHandler.Free; EntitiesConnector.removeObserver(self); inherited; end; @@ -696,6 +703,11 @@ begin {$ENDIF} if fUpdateCount > 0 then exit; Inc(fUpdateCount); + + + clearActProviderEntries; + collectedActProviderEntries; + try HasEd := fDoc <> nil; if hasEd then @@ -905,7 +917,7 @@ begin end; {$ENDREGION} -{$REGION ICEEditableShortCut} +{$REGION ICEEditableShortCut ---------------------------------------------------} function TCEMainForm.scedWantFirst: boolean; begin fScCollectCount := 0; @@ -931,6 +943,60 @@ begin end; {$ENDREGION} +{$REGION TCEActionProviderHandler ----------------------------------------------} +procedure TCEMainForm.clearActProviderEntries; +var + prov: ICEActionProvider; + act: TContainedAction; + i, j: Integer; +begin + for i:= 0 to fActionHandler.observersCount-1 do + begin + prov := fActionHandler[i] as ICEActionProvider; + if not prov.actHandlerWantRecollect then continue; + // + for j := Actions.ActionCount-1 downto 0 do + begin + act := Actions.Actions[j]; + if act.Owner = Self then continue; + if act.Tag <> PtrInt(prov) then continue; + // + act.ActionList := nil; + end; + end; +end; + +procedure TCEMainForm.collectedActProviderEntries; +var + prov: ICEActionProvider; + act: TCustomAction; + cat: string; + i: Integer; + procedure addAction; + begin + act.ActionList := Actions; + act.Tag := ptrInt(prov); + act.Category := cat; + // + act := nil; + cat := ''; + end; + +begin + for i:= 0 to fActionHandler.observersCount-1 do + begin + prov := fActionHandler[i] as ICEActionProvider; + if not prov.actHandlerWantFirst then continue; + // + act := nil; + cat := ''; + while prov.actHandlerWantNext(cat, act) do + addAction; + addAction; + end; +end; +{$ENDREGION} + {$REGION file ------------------------------------------------------------------} procedure TCEMainForm.actFileHtmlExportExecute(Sender: TObject); var