Skip to content

Commit

Permalink
Updated Reg. editor rename dialog (#24)
Browse files Browse the repository at this point in the history
* updated rename node dialog

* added keyboard control to float menu
  • Loading branch information
ivicic-petr authored Dec 8, 2023
1 parent e970bb4 commit 6d0dc4c
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 104 deletions.
2 changes: 1 addition & 1 deletion src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ edition = "2021"
tauri-build = { version = "1.4", features = [] }

[dependencies]
tauri = { version = "1.4", features = [ "window-close", "window-create", "dialog-ask", "shell-open"] }
tauri = { version = "1.4", features = [ "window-set-focus", "window-set-size", "window-close", "window-create", "dialog-ask", "shell-open"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

Expand Down
13 changes: 3 additions & 10 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
},
"window": {
"create": true,
"close": true
"close": true,
"setSize": true,
"setFocus": true
}
},
"bundle": {
Expand All @@ -41,15 +43,6 @@
"csp": null
},
"windows": [
{
"label": "signpost",
"fullscreen": false,
"resizable": true,
"title": "aeon-signpost",
"width": 800,
"height": 600,
"url": "src/html/signpost.html"
},
{
"label": "editor",
"fullscreen": false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
@import "uikit/src/less/uikit.theme.less";

.menu-icon {
max-height: 1em;
width: 100%;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { css, html, LitElement, type TemplateResult, unsafeCSS } from 'lit'
import { customElement, property, state } from 'lit/decorators.js'
import style_less from './node-menu.less?inline'
import style_less from './float-menu.less?inline'
import { findIconDefinition, icon, library } from '@fortawesome/fontawesome-svg-core'
import {
faArrowTrendDown,
Expand All @@ -15,46 +15,68 @@ import {
} from '@fortawesome/free-solid-svg-icons'
import { type Position } from 'cytoscape'
import { map } from 'lit/directives/map.js'
import { ElementType, Monotonicity } from './element-type'
import { ElementType, Monotonicity } from '../element-type'

library.add(faRightLeft, faArrowTrendUp, faArrowTrendDown, faCalculator, faEye, faEyeSlash, faPen, faTrash, faPlus)

@customElement('node-menu')
class NodeMenu extends LitElement {
@customElement('float-menu')
class FloatMenu extends LitElement {
static styles = css`${unsafeCSS(style_less)}`
@property() type = ElementType.NONE
@property() position: Position = { x: 0, y: 0 }
@property() zoom = 1.0
@property() data: { id: string, observable: boolean, monotonicity: Monotonicity, name: string } | undefined
@state() selectedButton: IButton | undefined = undefined

connectedCallback (): void {
super.connectedCallback()
document.addEventListener('keydown', this._handleKeyDown.bind(this))
}

private _handleKeyDown (event: KeyboardEvent): void {
switch (this.type) {
case ElementType.NODE:
switch (event.key.toUpperCase()) {
case 'E':
this.renameNode()
break
case 'A':
this.addEdge()
break
case 'F':
break
case 'DELETE':
case 'BACKSPACE':
this.removeElement()
break
}
break
case ElementType.EDGE:
switch (event.key.toUpperCase()) {
case 'O':
this.toggleObservability()
break
case 'M':
this.toggleMonotonicity()
break
case 'DELETE':
case 'BACKSPACE':
this.removeElement()
break
}
}
}

nodeButtons: IButton[] = [
{
icon: () => icon(faPen).node[0],
label: () => 'Edit name (E)',
click: () => {
this.dispatchEvent(new CustomEvent('rename-node', {
detail: {
id: this.data?.id,
name: this.data?.name
},
bubbles: true,
composed: true
}))
}
click: this.renameNode
},
{
icon: () => icon(faPlus).node[0],
label: () => 'Add Edge (A)',
click: () => {
this.dispatchEvent(new CustomEvent('add-edge', {
detail: {
id: this.data?.id
},
bubbles: true,
composed: true
}))
}
click: this.addEdge
},
{
icon: () => icon(faCalculator).node[0],
Expand All @@ -75,18 +97,7 @@ class NodeMenu extends LitElement {
this.data === null || this.data?.observable === null
? 'Toggle observability (O)'
: ((this.data?.observable) === true) ? 'Observability off (O)' : 'Observability on (O)',
click: () => {
this.dispatchEvent(new CustomEvent('update-edge', {
detail: {
edgeId: this.data?.id,
observable: !(this.data?.observable ?? false),
monotonicity: this.data?.monotonicity
},
bubbles: true,
composed: true
}))
if (this.data !== undefined) this.data = { ...this.data, observable: !(this.data?.observable ?? false) }
}
click: this.toggleObservability
},
{
icon: () => icon(findIconDefinition(
Expand All @@ -108,30 +119,7 @@ class NodeMenu extends LitElement {
return 'Toggle monotonicity (M)'
}
},
click: () => {
let monotonicity
switch (this.data?.monotonicity) {
case Monotonicity.ACTIVATION:
monotonicity = Monotonicity.INHIBITION
break
case Monotonicity.INHIBITION:
monotonicity = Monotonicity.OFF
break
default:
monotonicity = Monotonicity.ACTIVATION
break
}
if (this.data !== undefined) this.data = { ...this.data, monotonicity }
this.dispatchEvent(new CustomEvent('update-edge', {
detail: {
edgeId: this.data?.id,
observable: (this.data?.observable ?? true),
monotonicity
},
bubbles: true,
composed: true
}))
}
click: this.toggleMonotonicity
},
{
icon: () => icon(faTrash).node[0],
Expand All @@ -150,6 +138,65 @@ class NodeMenu extends LitElement {
}))
}

private toggleObservability (): void {
this.dispatchEvent(new CustomEvent('update-edge', {
detail: {
edgeId: this.data?.id,
observable: !(this.data?.observable ?? false),
monotonicity: this.data?.monotonicity
},
bubbles: true,
composed: true
}))
if (this.data !== undefined) this.data = { ...this.data, observable: !(this.data?.observable ?? false) }
}

private toggleMonotonicity (): void {
let monotonicity
switch (this.data?.monotonicity) {
case Monotonicity.ACTIVATION:
monotonicity = Monotonicity.INHIBITION
break
case Monotonicity.INHIBITION:
monotonicity = Monotonicity.OFF
break
default:
monotonicity = Monotonicity.ACTIVATION
break
}
if (this.data !== undefined) this.data = { ...this.data, monotonicity }
this.dispatchEvent(new CustomEvent('update-edge', {
detail: {
edgeId: this.data?.id,
observable: (this.data?.observable ?? true),
monotonicity
},
bubbles: true,
composed: true
}))
}

private renameNode (): void {
this.dispatchEvent(new CustomEvent('rename-node', {
detail: {
id: this.data?.id,
name: this.data?.name
},
bubbles: true,
composed: true
}))
}

private addEdge (): void {
this.dispatchEvent(new CustomEvent('add-edge', {
detail: {
id: this.data?.id
},
bubbles: true,
composed: true
}))
}

render (): TemplateResult {
let buttons: IButton[]
let yOffset = 0
Expand Down
48 changes: 29 additions & 19 deletions src/html/component/regulations-editor/regulations-editor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import cytoscape, { type Core, type EdgeSingular, type NodeSingular, type Positi
import dagre from 'cytoscape-dagre'
import edgeHandles, { type EdgeHandlesInstance } from 'cytoscape-edgehandles'
import dblclick from 'cytoscape-dblclick'
import './node-menu'
import './float-menu/float-menu'
import { edgeOptions, initOptions } from './regulations-editor.config'
import { ElementType, Monotonicity } from './element-type'
import { dialog } from '@tauri-apps/api'
Expand All @@ -19,8 +19,9 @@ const SAVE_EDGES = 'edges'
@customElement('regulations-editor')
class RegulationsEditor extends LitElement {
static styles = css`${unsafeCSS(style_less)}`
dialogs: Record<string, WebviewWindow | undefined> = {}

@query('#node-menu')
@query('#float-menu')
nodeMenu!: HTMLElement

@query('#edge-menu')
Expand All @@ -47,8 +48,8 @@ class RegulationsEditor extends LitElement {
this.addEventListener('adjust-graph', this.adjustPan)
this.addEventListener('add-edge', this.addEdge)
this.addEventListener('mousemove', this.hoverFix)
this.addEventListener('remove-element', (e) => { void (async () => { await this.removeElement(e) })() })
this.addEventListener('rename-node', (e) => { void (async () => { await this.renameNode(e) })() })
this.addEventListener('remove-element', (e) => { void this.removeElement(e) })
this.addEventListener('rename-node', (e) => { void this.renameNode(e) })

this.editorElement = document.createElement('div')
this.editorElement.id = 'cytoscape-editor'
Expand All @@ -58,7 +59,7 @@ class RegulationsEditor extends LitElement {
return html`
<button @click=${this.loadDummyData} class="uk-button uk-button-danger uk-button-small uk-margin-large-left uk-position-absolute uk-position-z-index-high">reset (debug)</button>
${this.editorElement}
<node-menu .type=${this.menuType} .position=${this.menuPosition} .zoom=${this.menuZoom} .data=${this.menuData}></node-menu>
<float-menu .type=${this.menuType} .position=${this.menuPosition} .zoom=${this.menuZoom} .data=${this.menuData}></float-menu>
`
}

Expand All @@ -72,7 +73,7 @@ class RegulationsEditor extends LitElement {
const nodeID = (event as CustomEvent).detail.id

// start attribute wrongly typed - added weird typecast to avoid tslint error
this.edgeHandles?.start((this.cy?.nodes(`#${nodeID}`) as unknown as string))
this.edgeHandles?.start((this.cy?.$id(nodeID) as unknown as string))
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
this.cy.renderer().hoverData.capture = true
Expand Down Expand Up @@ -184,27 +185,32 @@ class RegulationsEditor extends LitElement {
const nodeName = (event as CustomEvent).detail.name
const pos = await appWindow.outerPosition()
const size = await appWindow.outerSize()
const webview = new WebviewWindow('renameDialog', {
if (this.dialogs[nodeId] !== undefined) {
await this.dialogs[nodeId]?.setFocus()
return
}
const renameDialog = new WebviewWindow(`renameDialog${Math.floor(Math.random() * 1000000)}`, {
url: 'src/html/component/rename-dialog/rename-dialog.html',
title: 'Edit node',
title: `Edit node (${nodeId} / ${nodeName})`,
alwaysOnTop: true,
maximizable: false,
minimizable: false,
skipTaskbar: true,
height: 200,
resizable: false,
height: 100,
width: 400,
x: pos.x + size.width / 2 - 200,
y: pos.y + size.height / 2 - 100
x: pos.x + (size.width / 2) - 200,
y: pos.y + size.height / 4
})
await webview.once('window_loaded', () => {
void (async () => {
await webview.emit('edit_node_update', {
id: nodeId,
name: nodeName
})
this.dialogs[nodeId] = renameDialog
void renameDialog.once('loaded', () => {
void renameDialog.emit('edit_node_update', {
id: nodeId,
name: nodeName
})
})
await webview.once('edit_node_dialog', (event: TauriEvent<{ id: string, name: string }>) => {
void renameDialog.once('edit_node_dialog', (event: TauriEvent<{ id: string, name: string }>) => {
this.dialogs[nodeId] = undefined
// avoid overwriting existing nodes
if (nodeId !== event.payload.id && (this.cy?.$id(event.payload.id) !== undefined && this.cy?.$id(event.payload.id).length > 0)) {
UIkit.notification(`Node with id '${event.payload.id}' already exists!`)
Expand All @@ -224,6 +230,7 @@ class RegulationsEditor extends LitElement {
}
})
})
void renameDialog.onCloseRequested(() => { this.dialogs[nodeId] = undefined })
}

adjustPan (event: Event): void {
Expand Down Expand Up @@ -267,6 +274,7 @@ class RegulationsEditor extends LitElement {

toggleMenu (type: ElementType, position: Position | undefined = undefined, zoom = 1.0, data = undefined): void {
this.menuType = type
if (this.menuType === ElementType.NONE) this.cy?.nodes().deselect()
this.menuPosition = position ?? { x: 0, y: 0 }
this.menuZoom = zoom
this.menuData = data
Expand Down Expand Up @@ -313,7 +321,9 @@ class RegulationsEditor extends LitElement {
cancelLabel: 'Keep',
title: 'Delete'
})) return
this.cy?.$id((event as CustomEvent).detail.id).remove()
const nodeId = (event as CustomEvent).detail.id
void this.dialogs[nodeId]?.close()
this.cy?.$id(nodeId).remove()
this.toggleMenu(ElementType.NONE)
}

Expand Down
Loading

0 comments on commit 6d0dc4c

Please sign in to comment.