From 149a5d1824df252f84b81d5cd8db139588a6690b Mon Sep 17 00:00:00 2001 From: Russell Standish Date: Tue, 26 May 2026 16:17:47 +1000 Subject: [PATCH 1/2] feat: Add open/close all Godley tables menu items. For feature #173. --- .../app/managers/ApplicationMenuManager.ts | 8 ++ .../src/app/managers/CommandsManager.ts | 119 ++++++++++-------- .../src/app/managers/ContextMenuManager.ts | 14 ++- gui-js/libs/shared/src/lib/backend/minsky.ts | 1 + model/minsky.cc | 25 ++++ model/minsky.h | 5 +- 6 files changed, 121 insertions(+), 51 deletions(-) diff --git a/gui-js/apps/minsky-electron/src/app/managers/ApplicationMenuManager.ts b/gui-js/apps/minsky-electron/src/app/managers/ApplicationMenuManager.ts index 1413e4bf8..8404aef13 100644 --- a/gui-js/apps/minsky-electron/src/app/managers/ApplicationMenuManager.ts +++ b/gui-js/apps/minsky-electron/src/app/managers/ApplicationMenuManager.ts @@ -448,6 +448,14 @@ export class ApplicationMenuManager { label: 'Random Layout', async click() {minsky.randomLayout();} }, + { + label: 'Open All Godley Tables', + click() {CommandsManager.openAllGodleyTables();}, + }, + { + label: 'Close All Godley Tables', + click() {CommandsManager.closeAllGodleyTables();}, + }, ], }; } diff --git a/gui-js/apps/minsky-electron/src/app/managers/CommandsManager.ts b/gui-js/apps/minsky-electron/src/app/managers/CommandsManager.ts index 1d5ce0794..f0161fad9 100644 --- a/gui-js/apps/minsky-electron/src/app/managers/CommandsManager.ts +++ b/gui-js/apps/minsky-electron/src/app/managers/CommandsManager.ts @@ -831,82 +831,103 @@ export class CommandsManager { if (itemInfo?.classType) { switch (itemInfo?.classType) { - case ClassType.GodleyIcon: - await CommandsManager.openGodleyTable(itemInfo); - break; + case ClassType.GodleyIcon: { + const id=await minsky.canvas.item.id(); + if (id) { + await minsky.nameCurrentItem(id); + CommandsManager.openGodleyTable(id); + } + break; + } - case ClassType.PlotWidget: - await CommandsManager.expandPlot(itemInfo); + case ClassType.PlotWidget: + await CommandsManager.expandPlot(itemInfo); break; - case ClassType.Ravel: - await CommandsManager.openRavelPopup(itemInfo); - break; - - case ClassType.Variable: - case ClassType.VarConstant: - await CommandsManager.editVar(); - break; - - case ClassType.Operation: - await CommandsManager.editItem(ClassType.Operation); - - break; - - case ClassType.IntOp: - case ClassType.DataOp: - await CommandsManager.editItem(ClassType.IntOp); - - break; - - case ClassType.UserFunction: - await CommandsManager.editItem(ClassType.UserFunction); - - break; + case ClassType.Ravel: + await CommandsManager.openRavelPopup(itemInfo); + break; + case ClassType.Variable: + case ClassType.VarConstant: + await CommandsManager.editVar(); + break; + + case ClassType.Operation: + await CommandsManager.editItem(ClassType.Operation); + + break; + + case ClassType.IntOp: + case ClassType.DataOp: + await CommandsManager.editItem(ClassType.IntOp); + + break; + + case ClassType.UserFunction: + await CommandsManager.editItem(ClassType.UserFunction); + + break; + case ClassType.Group: if (await CommandsManager.selectVar(mouseX,mouseY)) await CommandsManager.editVar(); else await CommandsManager.editItem(ClassType.Group); break; - - case ClassType.Item: - await CommandsManager.postNote('item'); - break; - + + case ClassType.Item: + await CommandsManager.postNote('item'); + break; + case ClassType.Lock: new Lock(minsky.canvas.item).toggleLocked(); minsky.canvas.requestRedraw(); break; - default: - break; + default: + break; } } } - static async openGodleyTable(itemInfo: CanvasItem) { - if (!WindowManager.focusIfWindowIsPresent(itemInfo.id)) { - CommandsManager.addItemToNamedItems(itemInfo); - let godley=new GodleyIcon(minsky.namedItems.elem(itemInfo.id)); + static async openAllGodleyTables() { + for (const id of await minsky.allGodleyTables()) + this.openGodleyTable(id); + } + + static async closeAllGodleyTables() { + for (const id of await minsky.allGodleyTables()) + WindowManager.closeWindowByUid(id); + } + + static async openGodleyTable(id: string) { + if (!WindowManager.focusIfWindowIsPresent(id)) { + await minsky.itemFromNamedItem(id); // ensure named items is populated + let godley=new GodleyIcon(minsky.namedItems.elem(id)); var title=await godley.table.title(); - - const window = await this.initializePopupWindow({ - customTitle: `Godley Table : ${title}`, - itemInfo, - url: `#/headless/godley-widget-view?systemWindowId=0&itemId=${itemInfo.id}`, + const itemInfo={classType: ClassType.GodleyIcon, displayContents: false, id}; // TODO - is this stuff useful? + + const window = await WindowManager.createPopupWindowWithRouting({ + title: `Godley Table : ${title}`, + height: 600, + width: 800, + url: `#/headless/godley-widget-view?systemWindowId=0&itemId=${id}`, + uid: id, modal: false, + }, + () => { + this.onPopupWindowClose(itemInfo.id); }); - + Object.defineProperty(window,'dontCloseOnEscape',{value: true,writable:false}); godley.adjustPopupWidgets(); - let systemWindowId = WindowManager.getWindowByUid(itemInfo.id).systemWindowId; + let systemWindowId = WindowManager.getWindowByUid(id).systemWindowId; window.loadURL( WindowManager.getWindowUrl( - `#/headless/godley-widget-view?systemWindowId=${systemWindowId}&itemId=${itemInfo.id}` + `#/headless/godley-widget-view?systemWindowId=${systemWindowId}&itemId=${id}` ) ); @@ -915,7 +936,7 @@ export class CommandsManager { itemInfo, }); - this.activeGodleyWindowItems.set(itemInfo.id, itemInfo); + this.activeGodleyWindowItems.set(id, itemInfo); } } diff --git a/gui-js/apps/minsky-electron/src/app/managers/ContextMenuManager.ts b/gui-js/apps/minsky-electron/src/app/managers/ContextMenuManager.ts index 7c3c9459f..2ada60049 100644 --- a/gui-js/apps/minsky-electron/src/app/managers/ContextMenuManager.ts +++ b/gui-js/apps/minsky-electron/src/app/managers/ContextMenuManager.ts @@ -646,7 +646,19 @@ export class ContextMenuManager { const menuItems = [ new MenuItem({ label: 'Open Godley Table', - click: () => CommandsManager.openGodleyTable(itemInfo) + click: async () => { + const id=await minsky.canvas.item.id(); + if (id) + CommandsManager.openGodleyTable(id); + } + }), + new MenuItem({ + label: 'Open All Godley Tables', + click: () => {CommandsManager.openAllGodleyTables();} + }), + new MenuItem({ + label: 'Close All Godley Tables', + click() {CommandsManager.closeAllGodleyTables();}, }), new MenuItem({ label: 'Title', diff --git a/gui-js/libs/shared/src/lib/backend/minsky.ts b/gui-js/libs/shared/src/lib/backend/minsky.ts index dbbd20a86..3eb3d7e06 100644 --- a/gui-js/libs/shared/src/lib/backend/minsky.ts +++ b/gui-js/libs/shared/src/lib/backend/minsky.ts @@ -1335,6 +1335,7 @@ export class Minsky extends CppClass { async addIntegral(): Promise {return this.$callMethod('addIntegral');} async addNewPublicationTab(a1: string): Promise {return this.$callMethod('addNewPublicationTab',a1);} async allGodleyFlowVars(): Promise {return this.$callMethod('allGodleyFlowVars');} + async allGodleyTables(): Promise {return this.$callMethod('allGodleyTables');} async assetClasses(): Promise {return this.$callMethod('assetClasses');} async author(...args: string[]): Promise {return this.$callMethod('author',...args);} async autoLayout(): Promise {return this.$callMethod('autoLayout');} diff --git a/model/minsky.cc b/model/minsky.cc index e025d26d6..76afc2e3b 100644 --- a/model/minsky.cc +++ b/model/minsky.cc @@ -1658,6 +1658,22 @@ namespace minsky variableInstanceList.reset(); } + void Minsky::itemFromNamedItem(const std::string& name) + { + canvas.item=namedItems[name].lock(); + if (!canvas.item) + { + // name all items by id + model->recursiveDo(&GroupItems::items, + [this](const Items&,const Items::const_iterator& x){ + namedItems[(*x)->id()]=*x; + return false; + }); + canvas.item=namedItems[name].lock(); + } + } + + void Minsky::removeItems(Wire& wire) { if (wire.from()->wires().size()==1) @@ -1736,6 +1752,15 @@ namespace minsky }); } + vector Minsky::allGodleyTables() const + { + vector r; + for (auto& i: canvas.model->items) + if (i->godleyIconCast()) + r.push_back(i->id()); + return r; + } + size_t Minsky::physicalMem() { #if defined(__linux__) diff --git a/model/minsky.h b/model/minsky.h index 89aaea4c9..aa584595c 100644 --- a/model/minsky.h +++ b/model/minsky.h @@ -436,6 +436,9 @@ namespace minsky /// request all Godley table windows to redraw void redrawAllGodleyTables(); + /// returns list of ids of all Godley table in the current top level canvas + std::vector allGodleyTables() const; + /// set/clear busy cursor in GUI virtual void setBusyCursor() {} virtual void clearBusyCursor() {} @@ -524,7 +527,7 @@ namespace minsky std::map> namedItems; void nameCurrentItem(const std::string& name) {namedItems[name]=canvas.item;} - void itemFromNamedItem(const std::string& name) {canvas.item=namedItems[name].lock();} + void itemFromNamedItem(const std::string& name); VariablePane variablePane; From 04d2bda372fdd78e8119004633d7537dc327f3b4 Mon Sep 17 00:00:00 2001 From: Russell Standish Date: Wed, 27 May 2026 09:26:31 +1000 Subject: [PATCH 2/2] chore: address code review comments. --- .../minsky-electron/src/app/managers/CommandsManager.ts | 9 ++------- .../src/app/managers/ContextMenuManager.ts | 6 ++---- model/minsky.h | 2 +- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/gui-js/apps/minsky-electron/src/app/managers/CommandsManager.ts b/gui-js/apps/minsky-electron/src/app/managers/CommandsManager.ts index f0161fad9..fb2044549 100644 --- a/gui-js/apps/minsky-electron/src/app/managers/CommandsManager.ts +++ b/gui-js/apps/minsky-electron/src/app/managers/CommandsManager.ts @@ -831,14 +831,9 @@ export class CommandsManager { if (itemInfo?.classType) { switch (itemInfo?.classType) { - case ClassType.GodleyIcon: { - const id=await minsky.canvas.item.id(); - if (id) { - await minsky.nameCurrentItem(id); - CommandsManager.openGodleyTable(id); - } + case ClassType.GodleyIcon: + CommandsManager.openGodleyTable(itemInfo.id); break; - } case ClassType.PlotWidget: await CommandsManager.expandPlot(itemInfo); diff --git a/gui-js/apps/minsky-electron/src/app/managers/ContextMenuManager.ts b/gui-js/apps/minsky-electron/src/app/managers/ContextMenuManager.ts index 2ada60049..1444cc0df 100644 --- a/gui-js/apps/minsky-electron/src/app/managers/ContextMenuManager.ts +++ b/gui-js/apps/minsky-electron/src/app/managers/ContextMenuManager.ts @@ -646,10 +646,8 @@ export class ContextMenuManager { const menuItems = [ new MenuItem({ label: 'Open Godley Table', - click: async () => { - const id=await minsky.canvas.item.id(); - if (id) - CommandsManager.openGodleyTable(id); + click: () => { + CommandsManager.openGodleyTable(itemInfo.id); } }), new MenuItem({ diff --git a/model/minsky.h b/model/minsky.h index aa584595c..af2bb0f01 100644 --- a/model/minsky.h +++ b/model/minsky.h @@ -436,7 +436,7 @@ namespace minsky /// request all Godley table windows to redraw void redrawAllGodleyTables(); - /// returns list of ids of all Godley table in the current top level canvas + /// returns list of ids of all Godley tables in the current top level canvas std::vector allGodleyTables() const; /// set/clear busy cursor in GUI