@nsshunt/stsui 1.11.24 → 1.11.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/stsui.mjs CHANGED
@@ -1,21 +1,9 @@
1
- var __defProp = Object.defineProperty;
2
- var __typeError = (msg) => {
3
- throw TypeError(msg);
4
- };
5
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
- var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
7
- var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
8
- var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
9
- var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
10
- var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
11
- var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
12
- var _cursor, _renderPanelFn, _cursorInfo, _CalcBoxPos, _UpdateUIBoxPos, _ReSize, _UpdatePanelPosition, _STSUIFrame_instances, SetupPanels_fn, UpdateUI_fn;
13
1
  import EventEmitter from "node:events";
14
2
  import blessed from "blessed";
15
3
  class MenuBar {
4
+ listb = null;
16
5
  // options := { screen: <blessed screen>, top: <bool>, menuitems: [ { text: <string>, key: <string>, cb: <call back func> } ] }
17
6
  constructor(screen, options) {
18
- __publicField(this, "listb", null);
19
7
  const compoptions = {
20
8
  parent: screen,
21
9
  left: 0,
@@ -62,6 +50,23 @@ class MenuBar {
62
50
  }
63
51
  }
64
52
  class STSUIFrame extends EventEmitter {
53
+ //export class STSUIFrame {
54
+ uiBoxes = {};
55
+ // { box: <<blessed box>>, boxHeader: <<blessed box>> }
56
+ screen = null;
57
+ #cursor = 0;
58
+ // panel index with the complete model data.
59
+ #renderPanelFn = null;
60
+ screenHeaderText = "...";
61
+ minRows = 1;
62
+ minCols = 1;
63
+ minWidth = 40;
64
+ minHeight = 7;
65
+ #cursorInfo = null;
66
+ sortInfo = null;
67
+ // Current sort mode UI box control
68
+ screenHeader = null;
69
+ uidata;
65
70
  /**
66
71
  *
67
72
  * @param {*} data The screen layout data. Schema: { title: <str>,
@@ -71,353 +76,254 @@ class STSUIFrame extends EventEmitter {
71
76
  */
72
77
  constructor(data, renderPanelFn = null) {
73
78
  super();
74
- __privateAdd(this, _STSUIFrame_instances);
75
- //export class STSUIFrame {
76
- __publicField(this, "uiBoxes", {});
77
- // { box: <<blessed box>>, boxHeader: <<blessed box>> }
78
- __publicField(this, "screen", null);
79
- __privateAdd(this, _cursor, 0);
80
- // panel index with the complete model data.
81
- __privateAdd(this, _renderPanelFn, null);
82
- __publicField(this, "screenHeaderText", "...");
83
- __publicField(this, "minRows", 1);
84
- __publicField(this, "minCols", 1);
85
- __publicField(this, "minWidth", 40);
86
- __publicField(this, "minHeight", 7);
87
- __privateAdd(this, _cursorInfo, null);
88
- __publicField(this, "sortInfo", null);
89
- // Current sort mode UI box control
90
- __publicField(this, "screenHeader", null);
91
- __publicField(this, "uidata");
92
- /**
93
- *
94
- * @param {number} position The index (0 based) for the panel item to be calculated
95
- * @returns object with top, left, width and height correctly set
96
- */
97
- __privateAdd(this, _CalcBoxPos, (panel) => {
98
- if (!this.screen) return null;
99
- if (!panel.pos) return null;
100
- let screenHeight = this.screen.height;
101
- if (this.uidata.menu !== null) {
102
- screenHeight -= this.uidata.menu.length;
103
- }
104
- const screenWidth = this.screen.width;
105
- const rows = this.uidata.grid.rows;
106
- const cols = this.uidata.grid.cols;
107
- const pos = panel.pos;
108
- const colWidth = Math.floor(screenWidth / cols);
109
- const rowHeight = Math.floor(screenHeight / rows);
110
- let topoffset = 0;
111
- if (this.uidata.menu !== null) {
112
- for (const [, value] of Object.entries(this.uidata.menu)) {
113
- if (value.top === true) {
114
- topoffset = 1;
115
- break;
116
- }
79
+ this.uidata = data;
80
+ this.#renderPanelFn = renderPanelFn;
81
+ this.SetupUI();
82
+ }
83
+ get blessed() {
84
+ return blessed;
85
+ }
86
+ /**
87
+ *
88
+ * @param {number} position The index (0 based) for the panel item to be calculated
89
+ * @returns object with top, left, width and height correctly set
90
+ */
91
+ #CalcBoxPos = (panel) => {
92
+ if (!this.screen) return null;
93
+ if (!panel.pos) return null;
94
+ let screenHeight = this.screen.height;
95
+ if (this.uidata.menu !== null) {
96
+ screenHeight -= this.uidata.menu.length;
97
+ }
98
+ const screenWidth = this.screen.width;
99
+ const rows = this.uidata.grid.rows;
100
+ const cols = this.uidata.grid.cols;
101
+ const pos = panel.pos;
102
+ const colWidth = Math.floor(screenWidth / cols);
103
+ const rowHeight = Math.floor(screenHeight / rows);
104
+ let topoffset = 0;
105
+ if (this.uidata.menu !== null) {
106
+ for (const [, value] of Object.entries(this.uidata.menu)) {
107
+ if (value.top === true) {
108
+ topoffset = 1;
109
+ break;
117
110
  }
118
111
  }
119
- const boxPos = {
120
- top: pos.row * rowHeight + topoffset,
121
- left: pos.col * colWidth,
122
- width: colWidth * pos.colSpan,
123
- height: rowHeight * pos.rowSpan
124
- };
125
- if (pos.col + pos.colSpan === cols) {
126
- boxPos.width = screenWidth - pos.col * colWidth;
127
- }
128
- if (pos.row + pos.rowSpan === rows) {
129
- boxPos.height = screenHeight - pos.row * rowHeight;
130
- }
131
- return boxPos;
132
- });
133
- __privateAdd(this, _UpdateUIBoxPos, (panel, uiBox) => {
134
- const pos = __privateGet(this, _CalcBoxPos).call(this, panel);
135
- if (!pos) {
136
- return;
137
- }
138
- uiBox.box.top = pos.top;
139
- uiBox.box.left = pos.left;
140
- uiBox.box.width = pos.width;
141
- uiBox.box.height = pos.height;
142
- uiBox.boxHeader.top = pos.top;
143
- uiBox.boxHeader.left = pos.left + 2;
144
- if (typeof panel.widgets !== "undefined" && panel.widgets !== null) {
145
- for (const [, value] of Object.entries(panel.widgets)) {
146
- if (value.widget === "log") {
147
- const widget = uiBox.box.get(value.widget);
148
- if (widget.position.top >= uiBox.box.height - 4) {
149
- widget.position.top = uiBox.box.height - 4;
150
- } else {
151
- if (value.options.top) {
152
- widget.position.top = value.options.top;
153
- }
112
+ }
113
+ const boxPos = {
114
+ top: pos.row * rowHeight + topoffset,
115
+ left: pos.col * colWidth,
116
+ width: colWidth * pos.colSpan,
117
+ height: rowHeight * pos.rowSpan
118
+ };
119
+ if (pos.col + pos.colSpan === cols) {
120
+ boxPos.width = screenWidth - pos.col * colWidth;
121
+ }
122
+ if (pos.row + pos.rowSpan === rows) {
123
+ boxPos.height = screenHeight - pos.row * rowHeight;
124
+ }
125
+ return boxPos;
126
+ };
127
+ #UpdateUIBoxPos = (panel, uiBox) => {
128
+ const pos = this.#CalcBoxPos(panel);
129
+ if (!pos) {
130
+ return;
131
+ }
132
+ uiBox.box.top = pos.top;
133
+ uiBox.box.left = pos.left;
134
+ uiBox.box.width = pos.width;
135
+ uiBox.box.height = pos.height;
136
+ uiBox.boxHeader.top = pos.top;
137
+ uiBox.boxHeader.left = pos.left + 2;
138
+ if (typeof panel.widgets !== "undefined" && panel.widgets !== null) {
139
+ for (const [, value] of Object.entries(panel.widgets)) {
140
+ if (value.widget === "log") {
141
+ const widget = uiBox.box.get(value.widget);
142
+ if (widget.position.top >= uiBox.box.height - 4) {
143
+ widget.position.top = uiBox.box.height - 4;
144
+ } else {
145
+ if (value.options.top) {
146
+ widget.position.top = value.options.top;
154
147
  }
155
148
  }
156
149
  }
157
150
  }
158
- });
159
- /**
160
- * ReSize the grid layout
161
- */
162
- __privateAdd(this, _ReSize, () => {
163
- for (const [, value] of Object.entries(this.uiBoxes)) {
164
- __privateGet(this, _UpdateUIBoxPos).call(this, value.box.get("panel"), value);
165
- }
166
- });
167
- __privateAdd(this, _UpdatePanelPosition, (panel, row, col, uiBox) => {
168
- panel.pos = { row, col, rowSpan: 1, colSpan: 1 };
169
- __privateGet(this, _UpdateUIBoxPos).call(this, panel, uiBox);
170
- uiBox.boxHeader.setContent(panel.panelHeader);
171
- });
172
- /*
173
- ClickEx(panel: any) {
174
- //@@ override in sub-class
175
151
  }
176
- */
177
- __publicField(this, "CreateWidget", (widgetName, widgetoptions) => {
178
- const widget = blessed[widgetName].call(this, widgetoptions);
179
- return widget;
180
- });
181
- __publicField(this, "SetupWidgets", (box, panel, parent, blessedWidgets) => {
182
- for (const [blessedWidgetKey, blessedWidgetDetails] of Object.entries(blessedWidgets)) {
183
- const widgetoptions = { ...blessedWidgetDetails.options };
184
- if (box) {
185
- if (widgetoptions.top && widgetoptions.top >= box.height - 3) {
186
- widgetoptions.top = box.height - 4;
187
- }
188
- }
189
- const widget = blessed[blessedWidgetDetails.widget].call(this, widgetoptions);
190
- widget.set("id", blessedWidgetDetails.id);
191
- parent.append(widget);
192
- parent.set(blessedWidgetDetails.widget, widget);
193
- parent.set(`__blessedWidgetKey__${blessedWidgetKey}`, widget);
194
- if (blessedWidgetDetails.events) {
195
- for (const [eventName, eventDetails] of Object.entries(blessedWidgetDetails.events)) {
196
- widget.on(eventName, () => {
197
- eventDetails.cb(panel, widget, parent);
198
- });
199
- }
200
- }
201
- this.emit("widgetsetup", box, panel, widget);
202
- if (blessedWidgetDetails.children) {
203
- this.SetupWidgets(null, panel, widget, blessedWidgetDetails.children);
204
- }
205
- }
206
- });
207
- /*
208
- ExitEx() {
209
- //@@ override in sub-class
210
- }
211
-
212
- EscapeEx() {
213
- //@@ override in sub-class
152
+ };
153
+ /**
154
+ * ReSize the grid layout
155
+ */
156
+ #ReSize = () => {
157
+ for (const [, value] of Object.entries(this.uiBoxes)) {
158
+ this.#UpdateUIBoxPos(value.box.get("panel"), value);
159
+ }
160
+ };
161
+ #UpdatePanelPosition = (panel, row, col, uiBox) => {
162
+ panel.pos = { row, col, rowSpan: 1, colSpan: 1 };
163
+ this.#UpdateUIBoxPos(panel, uiBox);
164
+ uiBox.boxHeader.setContent(panel.panelHeader);
165
+ };
166
+ /*
167
+ ClickEx(panel: any) {
168
+ //@@ override in sub-class
169
+ }
170
+ */
171
+ CreateWidget = (widgetName, widgetoptions) => {
172
+ const widget = blessed[widgetName].call(this, widgetoptions);
173
+ return widget;
174
+ };
175
+ CreateWidgetEx(widgetName, widgetoptions) {
176
+ const widget = blessed[widgetName].call(this, widgetoptions);
177
+ return widget;
178
+ }
179
+ SetupWidgets = (box, panel, parent, blessedWidgets) => {
180
+ for (const [blessedWidgetKey, blessedWidgetDetails] of Object.entries(blessedWidgets)) {
181
+ const widgetoptions = { ...blessedWidgetDetails.options };
182
+ if (box) {
183
+ if (widgetoptions.top && widgetoptions.top >= box.height - 3) {
184
+ widgetoptions.top = box.height - 4;
214
185
  }
215
- */
216
- // https://www.npmjs.com/package/blessed
217
- // data:= { title: <str>,
218
- // grid: { rows: <int>, cols: <int> },
219
- // menu: [ { top: <bool>, menuitems: [ { text: <string>, key: <string>, cb: <func> } ] } ]
220
- // panels: [ { id: <str>, pos: { row: <int>, col: <int>, rowSpan: <int>, colSpan: <int> }, template: <str> } ] }
221
- /**
222
- *
223
- * @param {*} data UI Data
224
- */
225
- __publicField(this, "SetupUI", () => {
226
- this.DestroyUI();
227
- if (this.screen === null) {
228
- this.screen = blessed.screen({
229
- smartCSR: true
230
- });
231
- }
232
- if (!this.screen) {
233
- return;
234
186
  }
235
- const data = this.uidata;
236
- this.screen.title = data.title;
237
- this.screen.on("resize", () => {
238
- __privateGet(this, _ReSize).call(this);
239
- this.Render();
240
- });
241
- if (data.menu !== null) {
242
- for (let i = 0; i < data.menu.length; i++) {
243
- new MenuBar(this.screen, data.menu[i]);
187
+ const widget = blessed[blessedWidgetDetails.widget].call(this, widgetoptions);
188
+ widget.set("id", blessedWidgetDetails.id);
189
+ parent.append(widget);
190
+ parent.set(blessedWidgetDetails.widget, widget);
191
+ parent.set(`__blessedWidgetKey__${blessedWidgetKey}`, widget);
192
+ if (blessedWidgetDetails.events) {
193
+ for (const [eventName, eventDetails] of Object.entries(blessedWidgetDetails.events)) {
194
+ widget.on(eventName, () => {
195
+ eventDetails.cb(panel, widget, parent);
196
+ });
244
197
  }
245
198
  }
246
- this.screen.key(["C-c"], () => {
247
- this.DestroyUI();
248
- this.emit("exit");
249
- });
250
- this.screen.key(["escape"], () => {
251
- this.emit("escape");
252
- });
253
- __privateMethod(this, _STSUIFrame_instances, SetupPanels_fn).call(this);
254
- __privateSet(this, _cursorInfo, blessed.box({
255
- parent: this.screen,
256
- bottom: 0,
257
- right: 0,
258
- width: "shrink",
259
- height: 1,
260
- style: {
261
- bg: "gray",
262
- fg: "white"
263
- },
264
- keys: false,
265
- // Do not allow default key handling for this box
266
- mouse: false,
267
- content: "",
268
- tags: true
269
- // Allow style in-line tags such as bolt, italics, etc.
270
- }));
271
- this.sortInfo = blessed.box({
272
- parent: this.screen,
273
- top: 0,
274
- right: 0,
275
- width: "shrink",
276
- height: 1,
277
- style: {
278
- bg: "gray",
279
- fg: "white"
280
- },
281
- keys: false,
282
- // Do not allow default key handling for this box
283
- mouse: false,
284
- content: "",
285
- tags: true
286
- // Allow style in-line tags such as bolt, italics, etc.
287
- });
288
- this.screenHeader = blessed.box({
289
- parent: this.screen,
290
- top: 0,
291
- left: "center",
292
- width: "shrink",
293
- height: 1,
294
- style: {
295
- bg: "gray",
296
- fg: "white"
297
- },
298
- keys: false,
299
- // Do not allow default key handling for this box
300
- mouse: false,
301
- content: `[ ... ]`,
302
- tags: true
303
- // Allow style in-line tags such as bolt, italics, etc.
304
- });
305
- this.UpdateCursorInfo();
306
- this.UpdateSortInfo("Default");
307
- this.UpdateScreenHeader(this.screenHeaderText);
308
- this.Render();
309
- });
310
- __publicField(this, "UpdateCursorInfo", () => {
311
- if (__privateGet(this, _cursorInfo)) {
312
- __privateGet(this, _cursorInfo).setContent(`Cursor: ${__privateGet(this, _cursor)} / ${this.TotalPanelNumber}`);
199
+ this.emit("widgetsetup", box, panel, widget);
200
+ if (blessedWidgetDetails.children) {
201
+ this.SetupWidgets(null, panel, widget, blessedWidgetDetails.children);
313
202
  }
314
- });
315
- __publicField(this, "UpdateSortInfo", (sortMode) => {
316
- if (this.sortInfo) {
317
- this.sortInfo.setContent(`Sort: ${sortMode}`);
318
- }
319
- });
320
- __publicField(this, "UpdateScreenHeader", (screenHeaderText) => {
321
- this.screenHeaderText = screenHeaderText;
322
- if (this.screenHeader) {
323
- this.screenHeader.setContent(`[ ${screenHeaderText} ]`);
324
- }
325
- });
326
- __publicField(this, "IncRows", () => {
327
- if (this.screen && this.screen.height / (this.uidata.grid.rows + 1) > this.minHeight) {
328
- this.uidata.grid.rows++;
329
- this.CheckCursor();
330
- __privateMethod(this, _STSUIFrame_instances, UpdateUI_fn).call(this);
331
- }
332
- });
333
- __publicField(this, "DecRows", () => {
334
- if (this.uidata.grid.rows > this.minRows) {
335
- this.uidata.grid.rows--;
336
- this.CheckCursor();
337
- __privateMethod(this, _STSUIFrame_instances, UpdateUI_fn).call(this);
338
- }
339
- });
340
- __publicField(this, "IncCols", () => {
341
- if (this.screen && this.screen.width / (this.uidata.grid.cols + 1) > this.minWidth) {
342
- this.uidata.grid.cols++;
343
- this.CheckCursor();
344
- __privateMethod(this, _STSUIFrame_instances, UpdateUI_fn).call(this);
345
- }
346
- });
347
- __publicField(this, "DecCols", () => {
348
- if (this.uidata.grid.cols > this.minCols) {
349
- this.uidata.grid.cols--;
350
- this.CheckCursor();
351
- __privateMethod(this, _STSUIFrame_instances, UpdateUI_fn).call(this);
352
- }
353
- });
354
- __publicField(this, "CheckCursor", () => {
355
- if (__privateGet(this, _cursor) > this.TotalPanelNumber - this.ScreenCells) {
356
- __privateSet(this, _cursor, this.TotalPanelNumber - this.ScreenCells);
357
- if (__privateGet(this, _cursor) < 0) {
358
- __privateSet(this, _cursor, 0);
203
+ }
204
+ };
205
+ /**
206
+ *
207
+ * Setup all panels
208
+ */
209
+ #SetupPanels() {
210
+ if (!this.screen) {
211
+ return;
212
+ }
213
+ const panelKeys = Object.keys(this.uidata.panels);
214
+ const uiBoxIds = Object.keys(this.uiBoxes);
215
+ for (let i = 0; i < uiBoxIds.length; i++) {
216
+ if (typeof this.uidata.panels[uiBoxIds[i]] === "undefined") {
217
+ let uiBox = this.uiBoxes[uiBoxIds[i]];
218
+ if (typeof uiBox !== "undefined") {
219
+ this.emit("preremovebox", uiBox.box, uiBox.box.get("panel"));
220
+ this.screen.remove(uiBox.boxHeader);
221
+ this.screen.remove(uiBox.box);
222
+ uiBox = null;
223
+ delete this.uiBoxes[uiBoxIds[i]];
359
224
  }
360
225
  }
361
- this.UpdateCursorInfo();
362
- });
363
- __publicField(this, "NextPage", () => {
364
- const endpos = this.TotalPanelNumber - this.ScreenCells;
365
- if (__privateGet(this, _cursor) < endpos) {
366
- __privateSet(this, _cursor, __privateGet(this, _cursor) + this.ScreenCells);
367
- if (__privateGet(this, _cursor) > endpos) {
368
- __privateSet(this, _cursor, endpos);
226
+ }
227
+ const touched = {};
228
+ for (let i = 0; i < this.uidata.grid.cols * this.uidata.grid.rows; i++) {
229
+ const gridPos = this.#cursor + i;
230
+ const col = i % this.uidata.grid.cols;
231
+ const row = Math.floor(i / this.uidata.grid.cols);
232
+ const panel = this.uidata.panels[panelKeys[gridPos]];
233
+ if (typeof panel !== "undefined") {
234
+ if (typeof this.uiBoxes[panel.id] === "undefined") {
235
+ panel.pos = { row, col, rowSpan: 1, colSpan: 1 };
236
+ const calculatedBoxPos = this.#CalcBoxPos(panel);
237
+ if (!calculatedBoxPos) {
238
+ return;
239
+ }
240
+ const { top, left, width, height } = this.#CalcBoxPos(panel);
241
+ const box = blessed.box({
242
+ parent: this.screen,
243
+ top,
244
+ left,
245
+ width,
246
+ height,
247
+ style: {
248
+ bg: "#101010",
249
+ fg: "white"
250
+ },
251
+ border: {
252
+ type: "line"
253
+ },
254
+ keys: false,
255
+ // Do not allow default key handling for this box
256
+ tags: true
257
+ // Allow style in-line tags such as bolt, italics, etc.
258
+ });
259
+ const boxHeader = blessed.box({
260
+ parent: this.screen,
261
+ top,
262
+ left: left + 2,
263
+ width: "shrink",
264
+ height: 1,
265
+ style: {
266
+ bg: "gray",
267
+ fg: "white"
268
+ },
269
+ keys: false,
270
+ // Do not allow default key handling for this box
271
+ mouse: false,
272
+ content: panel.panelHeader,
273
+ tags: true
274
+ // Allow style in-line tags such as bold, italics, etc.
275
+ });
276
+ this.uiBoxes[panel.id] = { box, boxHeader };
277
+ boxHeader.setIndex(-1);
278
+ box.on("click", () => {
279
+ this.emit("click", box.get("panel"));
280
+ });
281
+ box.on("destroy", () => {
282
+ this.emit("destroy", box, panel);
283
+ });
284
+ box.on("remove", () => {
285
+ this.emit("remove", box, panel);
286
+ });
287
+ box.on("detach", () => {
288
+ this.emit("detach", box, panel);
289
+ });
290
+ box.set("panel", panel);
291
+ this.uiBoxes[panel.id].box = box;
292
+ this.emit("boxsetup", box, panel);
293
+ if (typeof panel.widgets !== "undefined" && panel.widgets !== null) {
294
+ this.SetupWidgets(box, panel, box, panel.widgets);
295
+ this.emit("widgetsetupcomplete", box, panel, panel.widgets);
296
+ }
297
+ touched[panel.id] = true;
298
+ } else {
299
+ this.#UpdatePanelPosition(panel, row, col, this.uiBoxes[panel.id]);
300
+ touched[panel.id] = true;
369
301
  }
370
- __privateMethod(this, _STSUIFrame_instances, UpdateUI_fn).call(this);
371
- }
372
- });
373
- __publicField(this, "PrevPage", () => {
374
- if (__privateGet(this, _cursor) > 0) {
375
- __privateSet(this, _cursor, __privateGet(this, _cursor) - this.ScreenCells);
376
- if (__privateGet(this, _cursor) < 0) {
377
- __privateSet(this, _cursor, 0);
302
+ if (this.#renderPanelFn) {
303
+ this.#renderPanelFn(this.uiBoxes[panel.id].box, panel);
378
304
  }
379
- __privateMethod(this, _STSUIFrame_instances, UpdateUI_fn).call(this);
380
305
  }
381
- });
382
- __publicField(this, "Exit", () => {
383
- this.DestroyUI();
384
- this.emit("exit");
385
- });
386
- /**
387
- *
388
- */
389
- __publicField(this, "DestroyUI", () => {
390
- if (this.screen !== null) {
391
- this.uiBoxes = {};
392
- this.screen.destroy();
393
- this.screen = null;
394
- }
395
- });
396
- /**
397
- * Render the screen.
398
- */
399
- __publicField(this, "Render", () => {
400
- if (this.screen) {
401
- this.screen.render();
306
+ }
307
+ for (const [key] of Object.entries(this.uiBoxes)) {
308
+ const box = this.uiBoxes[key].box;
309
+ const panel = box.get("panel");
310
+ if (typeof touched[key] === "undefined") {
311
+ box.hide();
312
+ this.uiBoxes[key].boxHeader.hide();
313
+ this.emit("boxhide", this.uiBoxes[key].box, panel, panel.widgets);
314
+ } else {
315
+ box.show();
316
+ this.uiBoxes[key].boxHeader.show();
317
+ this.emit("boxshow", this.uiBoxes[key].box, panel, panel.widgets);
402
318
  }
403
- });
404
- this.uidata = data;
405
- __privateSet(this, _renderPanelFn, renderPanelFn);
406
- this.SetupUI();
407
- }
408
- get blessed() {
409
- return blessed;
410
- }
411
- CreateWidgetEx(widgetName, widgetoptions) {
412
- const widget = blessed[widgetName].call(this, widgetoptions);
413
- return widget;
319
+ }
414
320
  }
415
321
  get gridData() {
416
322
  return this.uidata;
417
323
  }
418
324
  set gridData(gridData) {
419
325
  this.uidata = gridData;
420
- __privateMethod(this, _STSUIFrame_instances, SetupPanels_fn).call(this);
326
+ this.#SetupPanels();
421
327
  this.UpdateCursorInfo();
422
328
  this.Render();
423
329
  }
@@ -426,153 +332,226 @@ class STSUIFrame extends EventEmitter {
426
332
  }
427
333
  set gridDataPanels(gridDataPanels) {
428
334
  this.uidata.panels = gridDataPanels;
429
- __privateMethod(this, _STSUIFrame_instances, SetupPanels_fn).call(this);
335
+ this.#SetupPanels();
430
336
  this.UpdateCursorInfo();
431
337
  this.Render();
432
338
  }
339
+ /*
340
+ ExitEx() {
341
+ //@@ override in sub-class
342
+ }
343
+
344
+ EscapeEx() {
345
+ //@@ override in sub-class
346
+ }
347
+ */
348
+ // https://www.npmjs.com/package/blessed
349
+ // data:= { title: <str>,
350
+ // grid: { rows: <int>, cols: <int> },
351
+ // menu: [ { top: <bool>, menuitems: [ { text: <string>, key: <string>, cb: <func> } ] } ]
352
+ // panels: [ { id: <str>, pos: { row: <int>, col: <int>, rowSpan: <int>, colSpan: <int> }, template: <str> } ] }
353
+ /**
354
+ *
355
+ * @param {*} data UI Data
356
+ */
357
+ SetupUI = () => {
358
+ this.DestroyUI();
359
+ if (this.screen === null) {
360
+ this.screen = blessed.screen({
361
+ smartCSR: true
362
+ });
363
+ }
364
+ if (!this.screen) {
365
+ return;
366
+ }
367
+ const data = this.uidata;
368
+ this.screen.title = data.title;
369
+ this.screen.on("resize", () => {
370
+ this.#ReSize();
371
+ this.Render();
372
+ });
373
+ if (data.menu !== null) {
374
+ for (let i = 0; i < data.menu.length; i++) {
375
+ new MenuBar(this.screen, data.menu[i]);
376
+ }
377
+ }
378
+ this.screen.key(["C-c"], () => {
379
+ this.DestroyUI();
380
+ this.emit("exit");
381
+ });
382
+ this.screen.key(["escape"], () => {
383
+ this.emit("escape");
384
+ });
385
+ this.#SetupPanels();
386
+ this.#cursorInfo = blessed.box({
387
+ parent: this.screen,
388
+ bottom: 0,
389
+ right: 0,
390
+ width: "shrink",
391
+ height: 1,
392
+ style: {
393
+ bg: "gray",
394
+ fg: "white"
395
+ },
396
+ keys: false,
397
+ // Do not allow default key handling for this box
398
+ mouse: false,
399
+ content: "",
400
+ tags: true
401
+ // Allow style in-line tags such as bolt, italics, etc.
402
+ });
403
+ this.sortInfo = blessed.box({
404
+ parent: this.screen,
405
+ top: 0,
406
+ right: 0,
407
+ width: "shrink",
408
+ height: 1,
409
+ style: {
410
+ bg: "gray",
411
+ fg: "white"
412
+ },
413
+ keys: false,
414
+ // Do not allow default key handling for this box
415
+ mouse: false,
416
+ content: "",
417
+ tags: true
418
+ // Allow style in-line tags such as bolt, italics, etc.
419
+ });
420
+ this.screenHeader = blessed.box({
421
+ parent: this.screen,
422
+ top: 0,
423
+ left: "center",
424
+ width: "shrink",
425
+ height: 1,
426
+ style: {
427
+ bg: "gray",
428
+ fg: "white"
429
+ },
430
+ keys: false,
431
+ // Do not allow default key handling for this box
432
+ mouse: false,
433
+ content: `[ ... ]`,
434
+ tags: true
435
+ // Allow style in-line tags such as bolt, italics, etc.
436
+ });
437
+ this.UpdateCursorInfo();
438
+ this.UpdateSortInfo("Default");
439
+ this.UpdateScreenHeader(this.screenHeaderText);
440
+ this.Render();
441
+ };
442
+ UpdateCursorInfo = () => {
443
+ if (this.#cursorInfo) {
444
+ this.#cursorInfo.setContent(`Cursor: ${this.#cursor} / ${this.TotalPanelNumber}`);
445
+ }
446
+ };
447
+ UpdateSortInfo = (sortMode) => {
448
+ if (this.sortInfo) {
449
+ this.sortInfo.setContent(`Sort: ${sortMode}`);
450
+ }
451
+ };
452
+ UpdateScreenHeader = (screenHeaderText) => {
453
+ this.screenHeaderText = screenHeaderText;
454
+ if (this.screenHeader) {
455
+ this.screenHeader.setContent(`[ ${screenHeaderText} ]`);
456
+ }
457
+ };
433
458
  get rows() {
434
459
  return this.uidata.grid.rows;
435
460
  }
436
461
  get cols() {
437
462
  return this.uidata.grid.cols;
438
463
  }
464
+ IncRows = () => {
465
+ if (this.screen && this.screen.height / (this.uidata.grid.rows + 1) > this.minHeight) {
466
+ this.uidata.grid.rows++;
467
+ this.CheckCursor();
468
+ this.#UpdateUI();
469
+ }
470
+ };
471
+ DecRows = () => {
472
+ if (this.uidata.grid.rows > this.minRows) {
473
+ this.uidata.grid.rows--;
474
+ this.CheckCursor();
475
+ this.#UpdateUI();
476
+ }
477
+ };
478
+ IncCols = () => {
479
+ if (this.screen && this.screen.width / (this.uidata.grid.cols + 1) > this.minWidth) {
480
+ this.uidata.grid.cols++;
481
+ this.CheckCursor();
482
+ this.#UpdateUI();
483
+ }
484
+ };
485
+ DecCols = () => {
486
+ if (this.uidata.grid.cols > this.minCols) {
487
+ this.uidata.grid.cols--;
488
+ this.CheckCursor();
489
+ this.#UpdateUI();
490
+ }
491
+ };
439
492
  get ScreenCells() {
440
493
  return this.uidata.grid.cols * this.uidata.grid.rows;
441
494
  }
442
495
  get TotalPanelNumber() {
443
496
  return Object.keys(this.uidata.panels).length;
444
497
  }
445
- get mainScreen() {
446
- return this.screen;
447
- }
448
- }
449
- _cursor = new WeakMap();
450
- _renderPanelFn = new WeakMap();
451
- _cursorInfo = new WeakMap();
452
- _CalcBoxPos = new WeakMap();
453
- _UpdateUIBoxPos = new WeakMap();
454
- _ReSize = new WeakMap();
455
- _UpdatePanelPosition = new WeakMap();
456
- _STSUIFrame_instances = new WeakSet();
457
- /**
458
- *
459
- * Setup all panels
460
- */
461
- SetupPanels_fn = function() {
462
- if (!this.screen) {
463
- return;
464
- }
465
- const panelKeys = Object.keys(this.uidata.panels);
466
- const uiBoxIds = Object.keys(this.uiBoxes);
467
- for (let i = 0; i < uiBoxIds.length; i++) {
468
- if (typeof this.uidata.panels[uiBoxIds[i]] === "undefined") {
469
- let uiBox = this.uiBoxes[uiBoxIds[i]];
470
- if (typeof uiBox !== "undefined") {
471
- this.emit("preremovebox", uiBox.box, uiBox.box.get("panel"));
472
- this.screen.remove(uiBox.boxHeader);
473
- this.screen.remove(uiBox.box);
474
- uiBox = null;
475
- delete this.uiBoxes[uiBoxIds[i]];
498
+ CheckCursor = () => {
499
+ if (this.#cursor > this.TotalPanelNumber - this.ScreenCells) {
500
+ this.#cursor = this.TotalPanelNumber - this.ScreenCells;
501
+ if (this.#cursor < 0) {
502
+ this.#cursor = 0;
476
503
  }
477
504
  }
478
- }
479
- const touched = {};
480
- for (let i = 0; i < this.uidata.grid.cols * this.uidata.grid.rows; i++) {
481
- const gridPos = __privateGet(this, _cursor) + i;
482
- const col = i % this.uidata.grid.cols;
483
- const row = Math.floor(i / this.uidata.grid.cols);
484
- const panel = this.uidata.panels[panelKeys[gridPos]];
485
- if (typeof panel !== "undefined") {
486
- if (typeof this.uiBoxes[panel.id] === "undefined") {
487
- panel.pos = { row, col, rowSpan: 1, colSpan: 1 };
488
- const calculatedBoxPos = __privateGet(this, _CalcBoxPos).call(this, panel);
489
- if (!calculatedBoxPos) {
490
- return;
491
- }
492
- const { top, left, width, height } = __privateGet(this, _CalcBoxPos).call(this, panel);
493
- const box = blessed.box({
494
- parent: this.screen,
495
- top,
496
- left,
497
- width,
498
- height,
499
- style: {
500
- bg: "#101010",
501
- fg: "white"
502
- },
503
- border: {
504
- type: "line"
505
- },
506
- keys: false,
507
- // Do not allow default key handling for this box
508
- tags: true
509
- // Allow style in-line tags such as bolt, italics, etc.
510
- });
511
- const boxHeader = blessed.box({
512
- parent: this.screen,
513
- top,
514
- left: left + 2,
515
- width: "shrink",
516
- height: 1,
517
- style: {
518
- bg: "gray",
519
- fg: "white"
520
- },
521
- keys: false,
522
- // Do not allow default key handling for this box
523
- mouse: false,
524
- content: panel.panelHeader,
525
- tags: true
526
- // Allow style in-line tags such as bold, italics, etc.
527
- });
528
- this.uiBoxes[panel.id] = { box, boxHeader };
529
- boxHeader.setIndex(-1);
530
- box.on("click", () => {
531
- this.emit("click", box.get("panel"));
532
- });
533
- box.on("destroy", () => {
534
- this.emit("destroy", box, panel);
535
- });
536
- box.on("remove", () => {
537
- this.emit("remove", box, panel);
538
- });
539
- box.on("detach", () => {
540
- this.emit("detach", box, panel);
541
- });
542
- box.set("panel", panel);
543
- this.uiBoxes[panel.id].box = box;
544
- this.emit("boxsetup", box, panel);
545
- if (typeof panel.widgets !== "undefined" && panel.widgets !== null) {
546
- this.SetupWidgets(box, panel, box, panel.widgets);
547
- this.emit("widgetsetupcomplete", box, panel, panel.widgets);
548
- }
549
- touched[panel.id] = true;
550
- } else {
551
- __privateGet(this, _UpdatePanelPosition).call(this, panel, row, col, this.uiBoxes[panel.id]);
552
- touched[panel.id] = true;
505
+ this.UpdateCursorInfo();
506
+ };
507
+ NextPage = () => {
508
+ const endpos = this.TotalPanelNumber - this.ScreenCells;
509
+ if (this.#cursor < endpos) {
510
+ this.#cursor += this.ScreenCells;
511
+ if (this.#cursor > endpos) {
512
+ this.#cursor = endpos;
553
513
  }
554
- if (__privateGet(this, _renderPanelFn)) {
555
- __privateGet(this, _renderPanelFn).call(this, this.uiBoxes[panel.id].box, panel);
514
+ this.#UpdateUI();
515
+ }
516
+ };
517
+ PrevPage = () => {
518
+ if (this.#cursor > 0) {
519
+ this.#cursor -= this.ScreenCells;
520
+ if (this.#cursor < 0) {
521
+ this.#cursor = 0;
556
522
  }
523
+ this.#UpdateUI();
557
524
  }
525
+ };
526
+ #UpdateUI() {
527
+ this.SetupUI();
558
528
  }
559
- for (const [key] of Object.entries(this.uiBoxes)) {
560
- const box = this.uiBoxes[key].box;
561
- const panel = box.get("panel");
562
- if (typeof touched[key] === "undefined") {
563
- box.hide();
564
- this.uiBoxes[key].boxHeader.hide();
565
- this.emit("boxhide", this.uiBoxes[key].box, panel, panel.widgets);
566
- } else {
567
- box.show();
568
- this.uiBoxes[key].boxHeader.show();
569
- this.emit("boxshow", this.uiBoxes[key].box, panel, panel.widgets);
529
+ Exit = () => {
530
+ this.DestroyUI();
531
+ this.emit("exit");
532
+ };
533
+ /**
534
+ *
535
+ */
536
+ DestroyUI = () => {
537
+ if (this.screen !== null) {
538
+ this.uiBoxes = {};
539
+ this.screen.destroy();
540
+ this.screen = null;
541
+ }
542
+ };
543
+ /**
544
+ * Render the screen.
545
+ */
546
+ Render = () => {
547
+ if (this.screen) {
548
+ this.screen.render();
570
549
  }
550
+ };
551
+ get mainScreen() {
552
+ return this.screen;
571
553
  }
572
- };
573
- UpdateUI_fn = function() {
574
- this.SetupUI();
575
- };
554
+ }
576
555
  export {
577
556
  MenuBar,
578
557
  STSUIFrame