diff --git a/src/app/components/console/input.ts b/src/app/components/console/input.ts index c4c21eac..fc5863ff 100644 --- a/src/app/components/console/input.ts +++ b/src/app/components/console/input.ts @@ -58,7 +58,7 @@ export namespace Input { return m(BooleanInput, attrs); case TypeIdentifier.Trigger: - attrs.onInput(null); + attrs.oninput(null); return; default: @@ -97,9 +97,9 @@ export namespace Input { label: subName, type: subType, initValue: this.values.get(subName), - onInput: (v: any) => { + oninput: (v: any) => { values.set(subName, v); - attrs.onInput(this.post(values)); + attrs.oninput(this.post(values)); }, }), )) @@ -160,16 +160,16 @@ export namespace Input { size: "small", onclick: () => { that.values[index] = undefined; - attrs.onInput(this.post(this.values)); + attrs.oninput(this.post(this.values)); }, }, m(Icon, {fas: "minus"})), m(ConsoleEntry, { size: "small", type: attrs.type, initValue: entry, - onInput: (v: any) => { + oninput: (v: any) => { that.values[index] = v; - attrs.onInput(this.post(this.values)); + attrs.oninput(this.post(this.values)); }, }), ]); diff --git a/src/app/components/operator-context-menu.ts b/src/app/components/operator-context-menu.ts index e2ade193..99b44458 100644 --- a/src/app/components/operator-context-menu.ts +++ b/src/app/components/operator-context-menu.ts @@ -9,7 +9,7 @@ export class ContextMenu { public static show(oprBox: OperatorBoxComponent, comp: m.Component) { this.contextMenu = oprBox .createComponent({x: 0, y: 0, align: "tl"}) - .attachTo(oprBox.getShape(), "tr") + .attachTo(oprBox, "tr") .mount(comp) } diff --git a/src/app/components/operator-control.ts b/src/app/components/operator-control.ts deleted file mode 100644 index 2b66c92e..00000000 --- a/src/app/components/operator-control.ts +++ /dev/null @@ -1,53 +0,0 @@ -import m, {ClassComponent, CVnode} from "mithril"; -import {IconButton} from "../../slang/ui/toolkit/buttons"; -interface OperatorControlAttrs { - ondelete?(): void; - onclone?(): void; - onopen?(): void; - onconfig?(): void; -} - -export class OperatorControl implements ClassComponent { - public view({attrs}: CVnode): any { - - return m(".sle-comp__opr-ctrl", - m(".buttons.are-normal", [ - attrs.ondelete - ? m(IconButton, { - color: "black", - fas: "trash-alt", - tooltip: "Remove operator", - onclick: attrs.ondelete - }) - : undefined, - - attrs.onclone - ? m(IconButton, { - color: "black", - fas: "clone", - tooltip: "Clone operator", - onclick: attrs.onclone - }) - : undefined, - - attrs.onopen - ? m(IconButton, { - color: "black", - fas: "project-diagram", - tooltip: "Open blueprint", - onclick: attrs.onopen - }) - : undefined, - - attrs.onconfig - ? m(IconButton, { - color: "black", - fas: "wrench", - tooltip: "Configure operator", - onclick: attrs.onconfig - }) - : undefined, - ]), - ); - } -} \ No newline at end of file diff --git a/src/app/components/operator-dashboard.ts b/src/app/components/operator-dashboard.ts index 9a17a63b..21920f0d 100644 --- a/src/app/components/operator-dashboard.ts +++ b/src/app/components/operator-dashboard.ts @@ -113,7 +113,7 @@ export class PropertyFormDashboardModule implements DashboardModule { size: "small", label: fieldName, initValue: !this.formData.has(fieldName) ? initValue : undefined, - onInput: (v: any) => { + oninput: (v: any) => { this.formData.set(fieldName, v); this.beforeFormSubmit(this.formData).forEach((value, propertyName) => { this.operator.getProperties().get(propertyName).assign(value); @@ -154,7 +154,7 @@ export class PortTypeDashboardModule implements DashboardModule { return m(TypeSelect, { label: genId, type: genType, - onInput: (nType: SlangType) => { + oninput: (nType: SlangType) => { this.operator.getGenerics().specify(genId, nType); }, }); diff --git a/src/app/views/edit-blueprint.ts b/src/app/views/edit-blueprint.ts index c40956dd..dc3498be 100644 --- a/src/app/views/edit-blueprint.ts +++ b/src/app/views/edit-blueprint.ts @@ -1,4 +1,4 @@ -import m, {ClassComponent, CVnode} from "mithril"; +import m, { ClassComponent, CVnode } from "mithril"; import { OperatorBoxComponent } from "../../slang/ui/components/blackbox"; import { BlueprintModel } from "../../slang/core/models"; import { ViewFrame } from "../../slang/ui/frame"; @@ -7,11 +7,11 @@ import { BlueprintControlBar } from "../components/blueprint-control-bar"; import { BlueprintMenu } from "../components/blueprint-menu"; import { AppState } from "../state"; import { OperatorDashboard } from "../components/operator-dashboard"; -import { OperatorControl } from "../components/operator-control"; import { ContextMenu } from "../components/operator-context-menu"; import { Box } from "../../slang/ui/toolkit"; import { UserEvent } from "../../slang/ui/views/user-events"; import { ConnectionComponent } from "../../slang/ui/components/connection"; +import { IconButton } from "../../slang/ui/toolkit/buttons"; class Editor { private static frame: ViewFrame; @@ -48,32 +48,61 @@ class Editor { const operatorBp = operator.blueprint; const view = blueprintView; ContextMenu.show(e.target, { - view: () => m(".sle-comp__opr-context-menu", - m(OperatorControl, { - ondelete: view.isEditable - ? () => { - ContextMenu.hide(); - blueprint.deleteOperator(operator) - } - : undefined, - - onclone: view.isEditable - ? () => { - ContextMenu.hide(); - blueprint.cloneOperator(operator); - } - : undefined, - - onopen: view.isDescendable && !operatorBp.isElementary() - ? () => { - ContextMenu.hide(); - m.route.set("/edit/:uuid", {uuid: operatorBp.uuid}) - } - : undefined, - }), - operatorBp.hasProperties() || operatorBp.hasGenerics() - ? m(OperatorDashboard, {operator, view}) - : undefined + view: () => + m(".sle-comp__opr-context-menu", + m(".sle-comp__opr-ctrl", + m(".buttons.are-normal", [ + view.isEditable + ? m(IconButton, { + color: "black", + fas: "trash-alt", + tooltip: "Remove operator", + onclick() { + ContextMenu.hide(); + blueprint.deleteOperator(operator) + } + }) + : undefined, + + view.isEditable + ? m(IconButton, { + color: "black", + fas: "clone", + tooltip: "Clone operator", + onclick() { + ContextMenu.hide(); + blueprint.cloneOperator(operator); + } + }) + : undefined, + + view.isDescendable && !operatorBp.isElementary() + ? m(IconButton, { + color: "black", + fas: "project-diagram", + tooltip: "Open blueprint", + onclick() { + ContextMenu.hide(); + m.route.set("/edit/:uuid", {uuid: operatorBp.uuid}) + } + }) + : undefined, + ]) + ), + /* + m(".sle-comp__opr-dashboard", { + onmousewheel: (e: WheelEvent) => { + e.stopPropagation(); + }, + }, + m(Box, [ + m(OperatorDetailsDashboardModule, {operator}), + m(PropertyFormDashboardModule, {operator}), + m(PortTypeDashboardModule, {operator}), + ]) + ) + */ + m(OperatorDashboard, {operator, view}) ) }); } diff --git a/src/slang/ui/components/base.ts b/src/slang/ui/components/base.ts index c1408327..9df40d80 100644 --- a/src/slang/ui/components/base.ts +++ b/src/slang/ui/components/base.ts @@ -6,6 +6,7 @@ import {XY} from "../../definitions/api"; import {cssattr, cssobj, CSSType, cssupdate} from "../utils"; import {PaperView} from "../views/paper-view"; import { UserEvent, UserEvents } from "../views/user-events"; +import { BlackBoxComponent } from "./blackbox"; import {Container} from "./toolkit"; @@ -195,15 +196,16 @@ export class AttachableComponent extends HtmlComponent { super(paperView, offset); } - public attachTo(elem: dia.Element, align?: Alignment) { - this.update(elem, align); - elem.on("change:position change:size", () => { - this.update(elem, align); + public attachTo(comp: BlackBoxComponent, align?: Alignment) { + this.update(comp, align); + comp.changed.subscribe(() => { + this.update(comp, align); }); return this; } - protected update(elem: dia.Element, align?: Alignment) { + protected update(comp: BlackBoxComponent, align?: Alignment) { + const elem = comp.getShape(); const bbox = elem.getBBox(); let originPos = bbox.center(); diff --git a/src/slang/ui/components/blackbox.ts b/src/slang/ui/components/blackbox.ts index d3f77a91..e159a39a 100644 --- a/src/slang/ui/components/blackbox.ts +++ b/src/slang/ui/components/blackbox.ts @@ -85,6 +85,7 @@ export abstract class BlackBoxComponent extends CellComponent { protected shape!: BlackBoxShape; protected portGroups!: PortGroupComponent[]; + public readonly changed = new SlangSubject("position-size-changed"); private portMouseEntered = new SlangSubject<{ port: PortModel, x: number, y: number }>("port-mouseentered"); private portMouseLeft = new SlangSubject<{ port: PortModel, x: number, y: number }>("port-mouseleft"); @@ -104,6 +105,10 @@ export abstract class BlackBoxComponent extends CellComponent { group.setParent(this.shape, this.createGhostPorts); }); + this.shape.on("change:position change:size", () => { + this.changed.next(null); + }); + this.render(); } diff --git a/src/slang/ui/toolkit/input.ts b/src/slang/ui/toolkit/input.ts index a8c61f20..5c1fc7a2 100644 --- a/src/slang/ui/toolkit/input.ts +++ b/src/slang/ui/toolkit/input.ts @@ -11,7 +11,7 @@ export interface BaseInputAttrs extends HasSizeAttrs { initValue?: T; readonly?: boolean; - onInput(value: T, e?: { redraw: boolean }): void; + oninput(value: T, e?: { redraw: boolean }): void; onchange?(file: File): void; @@ -66,7 +66,7 @@ export class StringInput implements BaseInput { } }, oninput: (e: MithrilEvent) => { - attrs.onInput(e.currentTarget.value, e); + attrs.oninput(e.currentTarget.value, e); }, onkeydown: attrs.onkeydown, onkeyup: attrs.onkeyup, @@ -89,7 +89,7 @@ export class NumberInput implements BaseInput { } }, oninput: (e: MithrilEvent) => { - attrs.onInput(Number(e.currentTarget.value), e); + attrs.oninput(Number(e.currentTarget.value), e); }, onkeydown: attrs.onkeydown, onkeyup: attrs.onkeyup, @@ -115,7 +115,7 @@ export class BooleanInput implements BaseInput { }, // @ts-ignore oninput: m.withAttr("checked", (v: boolean) => { - attrs.onInput(v); + attrs.oninput(v); }), onkeydown: attrs.onkeydown, onkeyup: attrs.onkeyup, @@ -148,7 +148,7 @@ export class FileInput implements BaseInput { }, // @ts-ignore oninput: m.withAttr("files", (files: File[]) => { - attrs.onInput(files[0]); + attrs.oninput(files[0]); }), onkeydown: attrs.onkeydown, onkeyup: attrs.onkeyup, @@ -189,7 +189,7 @@ export class SelectInput implements ClassComponent { } }, oninput: (e: MithrilEvent) => { - attrs.onInput(e.currentTarget.value, e); + attrs.oninput(e.currentTarget.value, e); }, onkeydown: attrs.onkeydown, onkeyup: attrs.onkeyup, diff --git a/src/slang/ui/toolkit/type.ts b/src/slang/ui/toolkit/type.ts index 67fe33b3..92fea8e9 100644 --- a/src/slang/ui/toolkit/type.ts +++ b/src/slang/ui/toolkit/type.ts @@ -45,7 +45,7 @@ class MapEntriesInput implements ClassComponent { label: "", size: "small", initValue: tname, - onInput(ntname: string) { + oninput(ntname: string) { attrs.oneditEntry(index, [ntname, type]); }, onkeydown: (e: MithrilKeyboardEvent) => { @@ -60,7 +60,7 @@ class MapEntriesInput implements ClassComponent { type, label: "", size: "small", - onInput: (ntype: SlangType) => { + oninput: (ntype: SlangType) => { attrs.oneditEntry(index, [tname, ntype]); }, }), @@ -100,17 +100,17 @@ export class MapTypeSelectInput implements ClassComponent { onremoveEntry(idx: number) { that.mapEntries.splice(idx, 1); - attrs.onInput(that.getMapSlangType(that.mapEntries)); + attrs.oninput(that.getMapSlangType(that.mapEntries)); }, onappendEntry(entry: [string, SlangType]) { that.mapEntries.push(entry); - attrs.onInput(that.getMapSlangType(that.mapEntries)); + attrs.oninput(that.getMapSlangType(that.mapEntries)); }, oneditEntry(idx: number, entry: [string, SlangType]) { that.mapEntries[idx] = entry; - attrs.onInput(that.getMapSlangType(that.mapEntries)); + attrs.oninput(that.getMapSlangType(that.mapEntries)); }, }); } @@ -128,8 +128,8 @@ export class StreamTypeSelectInput implements ClassComponent { const t = attrs.type; return m(TypeSelect, { type: t.getStreamSub(), - onInput: (ntype: SlangType) => { - attrs.onInput(that.getStreamSlangType(ntype)); + oninput: (ntype: SlangType) => { + attrs.oninput(that.getStreamSlangType(ntype)); }, }); } @@ -153,21 +153,21 @@ export class TypeSelect implements ClassComponent { switch (ti) { case TypeIdentifier.Map: return m(Block, - this.renderInput(t, attrs.onInput, attrs.label), + this.renderInput(t, attrs.oninput, attrs.label), m(MapTypeSelectInput, { type: t, - onInput: attrs.onInput, + oninput: attrs.oninput, })); case TypeIdentifier.Stream: return m(".is-flex.is-flex-direction-row", - this.renderInput(t, attrs.onInput, attrs.label), + this.renderInput(t, attrs.oninput, attrs.label), m(StreamTypeSelectInput, { type: t, - onInput: attrs.onInput, + oninput: attrs.oninput, })); default: - return this.renderInput(t, attrs.onInput, attrs.label); + return this.renderInput(t, attrs.oninput, attrs.label); } } @@ -181,7 +181,7 @@ export class TypeSelect implements ClassComponent { size: "small", selected: ti, options: (fixed) ? [ti] : this.portTypeOptions, - onInput: (fixed) ? () => null : + oninput: (fixed) ? () => null : (opt: string) => { if (this.portTypeOptions.indexOf(opt) < 0) { return;