From c0aa770571d7a49e2edecbd393d75536d364c6a7 Mon Sep 17 00:00:00 2001 From: Martin Vladic Date: Sun, 29 Dec 2024 12:02:19 +0100 Subject: [PATCH] FocusWidget action for the Dashboard projects --- npm-module/package.json | 2 +- packages/home/main.tsx | 9 -- packages/home/tabs-store.tsx | 16 +++ .../flow/components/actions/file.tsx | 12 +- .../flow/components/actions/index.tsx | 107 ++++++++++++++++++ .../components/widgets/dashboard/index.tsx | 27 +++++ .../flow/runtime/wasm-runtime.tsx | 3 +- .../project-editor/ui-components/icons.tsx | 9 ++ 8 files changed, 170 insertions(+), 15 deletions(-) diff --git a/npm-module/package.json b/npm-module/package.json index fe8a5e4c..5509b992 100644 --- a/npm-module/package.json +++ b/npm-module/package.json @@ -3,7 +3,7 @@ "author": "Envox ", "description": "EEZ Studio for building standalone dashboard applications", "repository": "https://github.com/eez-open/studio", - "version": "0.0.54", + "version": "0.0.56", "revision": "1", "license": "GPL-3.0-only", "files": ["packages", "libs", "resources"] diff --git a/packages/home/main.tsx b/packages/home/main.tsx index b72cd056..67984c6b 100644 --- a/packages/home/main.tsx +++ b/packages/home/main.tsx @@ -24,7 +24,6 @@ import { LineMarkers } from "project-editor/flow/connection-line/ConnectionLineC import "home/settings"; import { extensionsCatalog } from "./extensions-manager/catalog"; -import { initProjectEditor } from "project-editor/project-editor-bootstrap"; import { buildProject } from "home/build-project"; import { layoutModels } from "eez-studio-ui/side-dock"; @@ -84,14 +83,6 @@ ipcRenderer.on( } ); -ipcRenderer.on("show-documentation-browser", async () => { - const { showDocumentationBrowser } = await import( - "home/documentation-browser" - ); - await initProjectEditor(tabs, ProjectEditorTab); - showDocumentationBrowser(); -}); - ipcRenderer.on("show-about-box", async () => { showAboutBox(); }); diff --git a/packages/home/tabs-store.tsx b/packages/home/tabs-store.tsx index d7427b4c..33bdfaee 100644 --- a/packages/home/tabs-store.tsx +++ b/packages/home/tabs-store.tsx @@ -1331,3 +1331,19 @@ export function openProject(filePath: string, runMode: boolean) { console.error(err); } } + +ipcRenderer.on("show-documentation-browser", async () => { + if ( + tabs.activeTab instanceof ProjectEditorTab && + tabs.activeTab.projectStore && + tabs.activeTab.projectStore.runtime + ) { + return; + } + + const { showDocumentationBrowser } = await import( + "home/documentation-browser" + ); + await initProjectEditor(tabs, ProjectEditorTab); + showDocumentationBrowser(); +}); diff --git a/packages/project-editor/flow/components/actions/file.tsx b/packages/project-editor/flow/components/actions/file.tsx index d3d26c79..f2736ae1 100644 --- a/packages/project-editor/flow/components/actions/file.tsx +++ b/packages/project-editor/flow/components/actions/file.tsx @@ -147,7 +147,7 @@ registerActionComponents("File", [ name: "encoding", type: "expression", valueType: "string", - formText: `"ascii", "base64", "hex", "ucs2", "ucs-2", "utf16le", "utf-16le", "utf8", "utf-8", "binary" or "latin1"` + formText: `"ascii", "base64", "hex", "ucs2", "ucs-2", "utf16le", "utf-16le", "utf8", "utf-8", "utf8-bom", "binary" or "latin1"` } ], execute: (context: IDashboardComponentContext) => { @@ -157,12 +157,14 @@ registerActionComponents("File", [ return; } - const encodingValue = context.evalProperty("encoding"); + let encodingValue = context.evalProperty("encoding"); if (typeof encodingValue != "string") { context.throwError("${encoding} is not a string"); return; } + let contentValue = context.evalProperty("content"); + const encodings = [ "ascii", "base64", @@ -176,6 +178,10 @@ registerActionComponents("File", [ "binary", "latin1" ]; + if (encodingValue == "utf8-bom") { + encodingValue = "utf8"; + contentValue = "\ufeff" + contentValue; + } if (encodings.indexOf(encodingValue) == -1) { context.throwError( `Unsupported encoding value ${encodingValue}, supported: ${encodings.join( @@ -185,8 +191,6 @@ registerActionComponents("File", [ return; } - const contentValue = context.evalProperty("content"); - context = context.startAsyncExecution(); (async function () { diff --git a/packages/project-editor/flow/components/actions/index.tsx b/packages/project-editor/flow/components/actions/index.tsx index cf91df0d..03202260 100644 --- a/packages/project-editor/flow/components/actions/index.tsx +++ b/packages/project-editor/flow/components/actions/index.tsx @@ -122,6 +122,7 @@ import { CALL_ACTION_ICON, CALL_NATIVE_ACTION_ICON, CLIPBOARD_WRITE_ICON, + FOCUS_WIDGET_ICON, LANGUAGE_ICON, LOG_ICON, PALETTE_ICON, @@ -4835,6 +4836,110 @@ export class PrintToPDFActionComponent extends ActionComponent { //////////////////////////////////////////////////////////////////////////////// +export class FocusWidgetActionComponent extends ActionComponent { + static classInfo = makeDerivedClassInfo(ActionComponent.classInfo, { + componentPaletteGroupName: "GUI", + properties: [ + makeExpressionProperty( + { + name: "widget", + type: PropertyType.MultilineText, + propertyGridGroup: specificGroup + }, + "widget" + ) + ], + defaultValue: {}, + icon: FOCUS_WIDGET_ICON, + componentHeaderColor: "#DEB887", + execute: (context: IDashboardComponentContext) => { + const widget = context.evalProperty("widget"); + if (widget == undefined) { + context.throwError(`Invalid Widget property`); + return; + } + + const widgetInfo = + context.WasmFlowRuntime.getWidgetHandleInfo(widget); + + if (!widgetInfo) { + context.throwError(`Invalid Widget handle`); + return; + } + + const widgetContext = new DashboardComponentContext( + context.WasmFlowRuntime, + widgetInfo.flowStateIndex, + widgetInfo.componentIndex + ); + + const executionState = + widgetContext.getComponentExecutionState(); + + if (!executionState) { + context.throwError(`Widget not initialized`); + return; + } + + if (!executionState.focus) { + context.throwError(`Widget doesn't support focus`); + return; + } + + executionState.focus(); + + context.propagateValueThroughSeqout(); + } + }); + + widget: string; + + override makeEditable() { + super.makeEditable(); + + makeObservable(this, { + widget: observable + }); + } + + getInputs() { + return [ + { + name: "@seqin", + type: "any" as ValueType, + isSequenceInput: true, + isOptionalInput: true + }, + ...super.getInputs() + ]; + } + + getOutputs() { + return [ + { + name: "@seqout", + type: "null" as ValueType, + isSequenceOutput: true, + isOptionalOutput: true + }, + ...super.getOutputs() + ]; + } + + getBody(flowContext: IFlowContext): React.ReactNode { + if (!this.widget) { + return null; + } + return ( +
+
{this.widget}
+
+ ); + } +} + +//////////////////////////////////////////////////////////////////////////////// + registerClass("StartActionComponent", StartActionComponent); registerClass("EndActionComponent", EndActionComponent); registerClass("InputActionComponent", InputActionComponent); @@ -4902,3 +5007,5 @@ registerClass("NoopActionComponent", NoopActionComponent); registerClass("CommentActionComponent", CommentActionComponent); registerClass("PrintToPDFActionComponent", PrintToPDFActionComponent); + +registerClass("FocusWidgetActionComponent", FocusWidgetActionComponent); diff --git a/packages/project-editor/flow/components/widgets/dashboard/index.tsx b/packages/project-editor/flow/components/widgets/dashboard/index.tsx index 1b985891..d8910eb0 100644 --- a/packages/project-editor/flow/components/widgets/dashboard/index.tsx +++ b/packages/project-editor/flow/components/widgets/dashboard/index.tsx @@ -612,6 +612,10 @@ registerClass("TextInputWidget", TextInputWidget); //////////////////////////////////////////////////////////////////////////////// +class NumberInputDashboardExecutionState { + focus?: () => void; +} + const NumberInputDashboardWidgetElement = observer( class NumberInputDashboardWidgetElement extends React.Component<{ className: string; @@ -636,6 +640,16 @@ const NumberInputDashboardWidgetElement = observer( if (this.props.flowContext.flowState && this.inputElement.current) { this.inputElement.current.focus(); } + + let executionState = + this.props.flowContext.flowState?.getComponentExecutionState( + this.props.component + ); + if (executionState) { + executionState.focus = () => { + this.inputElement.current?.focus(); + }; + } } dispose: IReactionDisposer; @@ -812,6 +826,18 @@ export class NumberInputDashboardWidget extends Widget { paramExpressionType: `struct:${SLIDER_CHANGE_EVENT_STRUCT_NAME}`, oldName: "action" } + }, + + execute: (context: IDashboardComponentContext) => { + Widget.classInfo.execute!(context); + + let executionState = + context.getComponentExecutionState(); + if (!executionState) { + context.setComponentExecutionState( + new NumberInputDashboardExecutionState() + ); + } } }); @@ -2605,3 +2631,4 @@ import "project-editor/flow/components/widgets/dashboard/embedded-dashboard"; import { assignProperty } from "project-editor/flow/runtime/worker-dashboard-component-context"; import { guid } from "eez-studio-shared/guid"; +import { IDashboardComponentContext } from "eez-studio-types"; diff --git a/packages/project-editor/flow/runtime/wasm-runtime.tsx b/packages/project-editor/flow/runtime/wasm-runtime.tsx index f42985d0..f80f6efe 100644 --- a/packages/project-editor/flow/runtime/wasm-runtime.tsx +++ b/packages/project-editor/flow/runtime/wasm-runtime.tsx @@ -79,7 +79,6 @@ import { getClassByName } from "project-editor/core/object"; import { FLOW_EVENT_KEYDOWN } from "project-editor/flow/runtime/flow-events"; import { preloadAllBitmaps } from "project-editor/features/bitmap/bitmap"; import { releaseRuntimeDashboardStates } from "project-editor/flow/runtime/component-execution-states"; -import { hasClass } from "eez-studio-shared/dom"; import { findBitmap } from "project-editor/project/assets"; interface IGlobalVariableBase { @@ -1186,6 +1185,7 @@ export class WasmRuntime extends RemoteRuntime { //key = e.key; } + /* if (e.target instanceof HTMLInputElement) { if ( (key != "Tab" && key != "ShiftTab") || @@ -1208,6 +1208,7 @@ export class WasmRuntime extends RemoteRuntime { e.preventDefault(); e.stopPropagation(); + */ let valuePtr = createWasmValue(this.worker.wasm, key); diff --git a/packages/project-editor/ui-components/icons.tsx b/packages/project-editor/ui-components/icons.tsx index 0c9ea774..612c00ff 100644 --- a/packages/project-editor/ui-components/icons.tsx +++ b/packages/project-editor/ui-components/icons.tsx @@ -3549,3 +3549,12 @@ export const CALL_NATIVE_ACTION_ICON: any = ( ); + +export const FOCUS_WIDGET_ICON: any = ( + + + +);