From 3952212870d2ad12c76c23f22917fd9d03cfb35a Mon Sep 17 00:00:00 2001 From: solvedDev Date: Sun, 1 May 2022 14:37:00 +0200 Subject: [PATCH 01/12] feat: inital working tab --- src/components/Editors/Jigsaw/Tab.ts | 141 ++++++++++++++++++ src/components/Editors/Jigsaw/Tab.vue | 136 +++++++++++++++++ src/components/TabSystem/TabProvider.ts | 2 + .../Windows/Settings/setupSettings.ts | 1 + 4 files changed, 280 insertions(+) create mode 100644 src/components/Editors/Jigsaw/Tab.ts create mode 100644 src/components/Editors/Jigsaw/Tab.vue diff --git a/src/components/Editors/Jigsaw/Tab.ts b/src/components/Editors/Jigsaw/Tab.ts new file mode 100644 index 000000000..9acabe676 --- /dev/null +++ b/src/components/Editors/Jigsaw/Tab.ts @@ -0,0 +1,141 @@ +import { FileTab } from '/@/components/TabSystem/FileTab' +import JigsawTabComponent from './Tab.vue' +import { App } from '/@/App' +import { TabSystem } from '/@/components/TabSystem/TabSystem' +import json5 from 'json5' +import { settingsState } from '/@/components/Windows/Settings/SettingsState' +import { debounce } from 'lodash-es' +import { InformationWindow } from '../../Windows/Common/Information/InformationWindow' +import { AnyFileHandle } from '../../FileSystem/Types' + +const throttledCacheUpdate = debounce<(tab: JigsawTab) => Promise | void>( + async (tab) => { + const fileContent = JSON.stringify({ + // TODO: Get JSON from jigsaw tab + }) + const app = await App.getApp() + + app.project.fileChange.dispatch(tab.getPath(), await tab.getFile()) + + await app.project.packIndexer.updateFile( + tab.getPath(), + fileContent, + tab.isForeignFile, + true + ) + await app.project.jsonDefaults.updateDynamicSchemas(tab.getPath()) + }, + 600 +) + +export class JigsawTab extends FileTab { + component = JigsawTabComponent + + constructor( + parent: TabSystem, + fileHandle: AnyFileHandle, + isReadOnly = false + ) { + super(parent, fileHandle, isReadOnly) + + this.fired.then(async () => { + const app = await App.getApp() + await app.projectManager.projectReady.fired + + app.project.tabActionProvider.addTabActions(this) + }) + } + + get app() { + return this.parent.app + } + get project() { + return this.parent.project + } + + static is(fileHandle: AnyFileHandle) { + return ( + settingsState?.editor?.jsonEditor === 'jigsawEditor' && + fileHandle.name.endsWith('.json') + ) + } + async setup() { + let json: unknown + try { + const fileStr = await this.fileHandle + .getFile() + .then((file) => file.text()) + + if (fileStr === '') json = {} + else json = json5.parse(fileStr) + } catch { + new InformationWindow({ + name: 'windows.invalidJson.title', + description: 'windows.invalidJson.description', + }) + this.close() + return + } + + await super.setup() + } + async getFile() { + return new File( + [ + JSON.stringify({ + // TODO: Get JSON from jigsaw tab + }), + ], + this.name + ) + } + + updateCache() { + throttledCacheUpdate(this) + } + + async onActivate() {} + onDeactivate() {} + + loadEditor() {} + setReadOnly(val: boolean) { + this.isReadOnly = val + } + + async save() { + this.isTemporary = false + + const app = await App.getApp() + const fileContent = JSON.stringify( + { + // TODO: Stringify jigsaw editor here + }, + null, + '\t' + ) + + await app.fileSystem.write(this.fileHandle, fileContent) + } + + async paste() {} + + async copy() {} + + async cut() {} + + async close() { + const didClose = await super.close() + + // We need to clear the lightning cache store from temporary data if the user doesn't save changes + if (!this.isForeignFile && didClose && this.isUnsaved) { + const file = await this.fileHandle.getFile() + const fileContent = await file.text() + await this.project.packIndexer.updateFile( + this.getPath(), + fileContent + ) + } + + return didClose + } +} diff --git a/src/components/Editors/Jigsaw/Tab.vue b/src/components/Editors/Jigsaw/Tab.vue new file mode 100644 index 000000000..d2a8b7e99 --- /dev/null +++ b/src/components/Editors/Jigsaw/Tab.vue @@ -0,0 +1,136 @@ + + + + + diff --git a/src/components/TabSystem/TabProvider.ts b/src/components/TabSystem/TabProvider.ts index 8931fd4f8..70369f698 100644 --- a/src/components/TabSystem/TabProvider.ts +++ b/src/components/TabSystem/TabProvider.ts @@ -1,5 +1,6 @@ import { ImageTab } from '../Editors/Image/ImageTab' import { TargaTab } from '../Editors/Image/TargaTab' +import { JigsawTab } from '../Editors/Jigsaw/Tab' import { TextTab } from '../Editors/Text/TextTab' import { TreeTab } from '../Editors/TreeEditor/Tab' import { FileTab } from './FileTab' @@ -7,6 +8,7 @@ import { FileTab } from './FileTab' export class TabProvider { protected static _tabs = new Set([ TextTab, + JigsawTab, TreeTab, ImageTab, TargaTab, diff --git a/src/components/Windows/Settings/setupSettings.ts b/src/components/Windows/Settings/setupSettings.ts index b4f247887..c31949798 100644 --- a/src/components/Windows/Settings/setupSettings.ts +++ b/src/components/Windows/Settings/setupSettings.ts @@ -345,6 +345,7 @@ export async function setupSettings(settings: SettingsWindow) { options: [ { text: 'Tree Editor', value: 'treeEditor' }, { text: 'Raw Text', value: 'rawText' }, + { text: 'Jigsaw Editor', value: 'jigsawEditor' }, ], default: 'rawText', }) From ba0740e1bd5e15820707f5d84bdf3a8adc67ddca Mon Sep 17 00:00:00 2001 From: solvedDev Date: Sun, 1 May 2022 14:40:35 +0200 Subject: [PATCH 02/12] fix: store current grid position on tab instance --- src/components/Editors/Jigsaw/Tab.ts | 4 ++++ src/components/Editors/Jigsaw/Tab.vue | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/components/Editors/Jigsaw/Tab.ts b/src/components/Editors/Jigsaw/Tab.ts index 9acabe676..722b6da40 100644 --- a/src/components/Editors/Jigsaw/Tab.ts +++ b/src/components/Editors/Jigsaw/Tab.ts @@ -30,6 +30,10 @@ const throttledCacheUpdate = debounce<(tab: JigsawTab) => Promise | void>( export class JigsawTab extends FileTab { component = JigsawTabComponent + position = { + x: 0, + y: 0, + } constructor( parent: TabSystem, diff --git a/src/components/Editors/Jigsaw/Tab.vue b/src/components/Editors/Jigsaw/Tab.vue index d2a8b7e99..f4e0f7f9c 100644 --- a/src/components/Editors/Jigsaw/Tab.vue +++ b/src/components/Editors/Jigsaw/Tab.vue @@ -40,8 +40,6 @@ export default { height: Number, }, data: () => ({ - currentX: 0, - currentY: 0, cursorStyle: 'grab', startPosData: null, }), @@ -98,6 +96,22 @@ export default { ? `${this.settingsState.appearance.font} !important` : 'Roboto !important' }, + currentX: { + get() { + return this.tab.position.x + }, + set(val) { + this.tab.position.x = val + }, + }, + currentY: { + get() { + return this.tab.position.y + }, + set(val) { + this.tab.position.y = val + }, + }, }, watch: { 'tab.uuid'() { From a0902e9bb7a79864f191a7851882c0f54f643f0e Mon Sep 17 00:00:00 2001 From: solvedDev Date: Sun, 1 May 2022 17:48:15 +0200 Subject: [PATCH 03/12] upd: basic UI concept --- src/components/Editors/Jigsaw/EventLine.vue | 43 +++++++ src/components/Editors/Jigsaw/JigsawNode.vue | 63 +++++++++++ src/components/Editors/Jigsaw/Tab.vue | 112 ++++++++++++++++++- 3 files changed, 214 insertions(+), 4 deletions(-) create mode 100644 src/components/Editors/Jigsaw/EventLine.vue create mode 100644 src/components/Editors/Jigsaw/JigsawNode.vue diff --git a/src/components/Editors/Jigsaw/EventLine.vue b/src/components/Editors/Jigsaw/EventLine.vue new file mode 100644 index 000000000..9c0f19128 --- /dev/null +++ b/src/components/Editors/Jigsaw/EventLine.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/src/components/Editors/Jigsaw/JigsawNode.vue b/src/components/Editors/Jigsaw/JigsawNode.vue new file mode 100644 index 000000000..03cbd0fe5 --- /dev/null +++ b/src/components/Editors/Jigsaw/JigsawNode.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/src/components/Editors/Jigsaw/Tab.vue b/src/components/Editors/Jigsaw/Tab.vue index f4e0f7f9c..db08385fd 100644 --- a/src/components/Editors/Jigsaw/Tab.vue +++ b/src/components/Editors/Jigsaw/Tab.vue @@ -11,7 +11,7 @@ tabindex="-1" >
+ /> + + + + + + + + + + + + + + + + + + @@ -31,12 +131,15 @@ + + diff --git a/src/components/Editors/Jigsaw/EventLine.vue b/src/components/Editors/Jigsaw/EventLine.vue index 9c0f19128..1c96cbd55 100644 --- a/src/components/Editors/Jigsaw/EventLine.vue +++ b/src/components/Editors/Jigsaw/EventLine.vue @@ -1,24 +1,28 @@ diff --git a/src/components/Editors/Jigsaw/FlowArea/Grid.vue b/src/components/Editors/Jigsaw/FlowArea/Grid.vue new file mode 100644 index 000000000..28f3c48fa --- /dev/null +++ b/src/components/Editors/Jigsaw/FlowArea/Grid.vue @@ -0,0 +1,41 @@ + + + + + diff --git a/src/components/Editors/Jigsaw/FlowArea/GridElement.vue b/src/components/Editors/Jigsaw/FlowArea/GridElement.vue new file mode 100644 index 000000000..31c4f27a0 --- /dev/null +++ b/src/components/Editors/Jigsaw/FlowArea/GridElement.vue @@ -0,0 +1,32 @@ + + + diff --git a/src/components/Editors/Jigsaw/JigsawNode.vue b/src/components/Editors/Jigsaw/JigsawNode.vue index 03cbd0fe5..d0cbead14 100644 --- a/src/components/Editors/Jigsaw/JigsawNode.vue +++ b/src/components/Editors/Jigsaw/JigsawNode.vue @@ -1,26 +1,26 @@ - - diff --git a/src/components/Editors/Jigsaw/JigsawNode.vue b/src/components/Editors/Jigsaw/JigsawNode.vue index d0cbead14..bffa54eb4 100644 --- a/src/components/Editors/Jigsaw/JigsawNode.vue +++ b/src/components/Editors/Jigsaw/JigsawNode.vue @@ -8,6 +8,11 @@ :containerX="containerX" :containerY="containerY" > +
{{ icon }} @@ -35,6 +40,7 @@ export default { default: 'component', validate: (val) => ['component', 'event'].includes(val), }, + connection: String, }, data: () => ({}), computed: { @@ -60,4 +66,9 @@ export default { width: 37px; cursor: pointer; } +.connection { + position: absolute; + transform: rotate(45deg) scale(0.5); + left: 12px; +} diff --git a/src/components/Editors/Jigsaw/Tab.vue b/src/components/Editors/Jigsaw/Tab.vue index cf448bea6..69e82b237 100644 --- a/src/components/Editors/Jigsaw/Tab.vue +++ b/src/components/Editors/Jigsaw/Tab.vue @@ -45,6 +45,7 @@ From 038ad85bb90a0b7c6bff050a67b886ceb93312c5 Mon Sep 17 00:00:00 2001 From: solvedDev Date: Mon, 2 May 2022 10:31:45 +0200 Subject: [PATCH 06/12] upd: move to .flow files --- src/components/Editors/Jigsaw/Tab.ts | 5 +---- src/components/Windows/Settings/setupSettings.ts | 1 - 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/components/Editors/Jigsaw/Tab.ts b/src/components/Editors/Jigsaw/Tab.ts index 722b6da40..381d4045e 100644 --- a/src/components/Editors/Jigsaw/Tab.ts +++ b/src/components/Editors/Jigsaw/Tab.ts @@ -58,10 +58,7 @@ export class JigsawTab extends FileTab { } static is(fileHandle: AnyFileHandle) { - return ( - settingsState?.editor?.jsonEditor === 'jigsawEditor' && - fileHandle.name.endsWith('.json') - ) + return fileHandle.name.endsWith('.flow') } async setup() { let json: unknown diff --git a/src/components/Windows/Settings/setupSettings.ts b/src/components/Windows/Settings/setupSettings.ts index c31949798..b4f247887 100644 --- a/src/components/Windows/Settings/setupSettings.ts +++ b/src/components/Windows/Settings/setupSettings.ts @@ -345,7 +345,6 @@ export async function setupSettings(settings: SettingsWindow) { options: [ { text: 'Tree Editor', value: 'treeEditor' }, { text: 'Raw Text', value: 'rawText' }, - { text: 'Jigsaw Editor', value: 'jigsawEditor' }, ], default: 'rawText', }) From 5e11778ad489a8ed0d6fbaf6ec9ffbc7b523fb32 Mon Sep 17 00:00:00 2001 From: solvedDev Date: Mon, 2 May 2022 10:39:13 +0200 Subject: [PATCH 07/12] feat: allow nodes to connect into all directions --- src/components/Editors/Jigsaw/JigsawNode.vue | 27 +++++++++++++++----- src/components/Editors/Jigsaw/Tab.vue | 4 +-- 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/components/Editors/Jigsaw/JigsawNode.vue b/src/components/Editors/Jigsaw/JigsawNode.vue index bffa54eb4..fe213cb18 100644 --- a/src/components/Editors/Jigsaw/JigsawNode.vue +++ b/src/components/Editors/Jigsaw/JigsawNode.vue @@ -9,10 +9,15 @@ :containerY="containerY" >
+ v-for="dir in connectTo" + :key="dir" + class="component rounded-lg connect" + :style="{ + background: `var(--v-${color}-base)`, + left: `${dir === 'left' ? 12 : dir === 'right' ? -12 : 0}px`, + top: `${dir === 'up' ? -12 : dir === 'down' ? 12 : 0}px`, + }" + /> {{ icon }} @@ -40,7 +45,11 @@ export default { default: 'component', validate: (val) => ['component', 'event'].includes(val), }, - connection: String, + connect: { + type: [Array, String], + validate: (val) => + val.every((v) => ['left', 'right', 'up', 'down'].includes(v)), + }, }, data: () => ({}), computed: { @@ -54,6 +63,11 @@ export default { return '0' } }, + connectTo() { + return typeof this.connect === 'string' + ? [this.connect] + : this.connect + }, }, } @@ -66,9 +80,8 @@ export default { width: 37px; cursor: pointer; } -.connection { +.connect { position: absolute; transform: rotate(45deg) scale(0.5); - left: 12px; } diff --git a/src/components/Editors/Jigsaw/Tab.vue b/src/components/Editors/Jigsaw/Tab.vue index 69e82b237..907986619 100644 --- a/src/components/Editors/Jigsaw/Tab.vue +++ b/src/components/Editors/Jigsaw/Tab.vue @@ -45,7 +45,7 @@ Date: Mon, 2 May 2022 13:22:20 +0200 Subject: [PATCH 08/12] upd: improved grid dragging --- src/components/Editors/Jigsaw/Tab.vue | 11 +++++++++-- src/utils/disposableListener.ts | 11 +++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 src/utils/disposableListener.ts diff --git a/src/components/Editors/Jigsaw/Tab.vue b/src/components/Editors/Jigsaw/Tab.vue index 907986619..475690372 100644 --- a/src/components/Editors/Jigsaw/Tab.vue +++ b/src/components/Editors/Jigsaw/Tab.vue @@ -15,8 +15,6 @@
({ cursorStyle: 'grab', startPosData: null, + disposables: null, }), mounted() { // this.treeEditor.receiveContainer(this.$refs.editorContainer) @@ -165,6 +165,10 @@ export default { y: event.clientY, } this.cursorStyle = 'grabbing' + this.disposables = [ + addListener('mousemove', this.onMouseMove), + addListener('mouseup', this.onMouseUp), + ] }, onMouseMove(event) { if (!this.startPosData) return @@ -179,6 +183,9 @@ export default { onMouseUp(event) { this.startPosData = null this.cursorStyle = 'grab' + if (this.disposables) + this.disposables.forEach((disposable) => disposable.dispose()) + this.disposables = null }, }, computed: { diff --git a/src/utils/disposableListener.ts b/src/utils/disposableListener.ts new file mode 100644 index 000000000..709a8d386 --- /dev/null +++ b/src/utils/disposableListener.ts @@ -0,0 +1,11 @@ +export function addListener( + type: K, + listener: (this: Document, ev: DocumentEventMap[K]) => any, + options?: boolean | AddEventListenerOptions +) { + document.addEventListener(type, listener, options) + + return { + dispose: () => document.removeEventListener(type, listener), + } +} From 8ab15288a59ed621a20811759655cfdc1bcdecb7 Mon Sep 17 00:00:00 2001 From: solvedDev Date: Mon, 2 May 2022 14:40:11 +0200 Subject: [PATCH 09/12] feat: support dragging of nodes --- .../Editors/Jigsaw/FlowArea/GridElement.vue | 2 + src/components/Editors/Jigsaw/JigsawNode.vue | 121 +++++++++++++++++- 2 files changed, 118 insertions(+), 5 deletions(-) diff --git a/src/components/Editors/Jigsaw/FlowArea/GridElement.vue b/src/components/Editors/Jigsaw/FlowArea/GridElement.vue index 31c4f27a0..a52c1015f 100644 --- a/src/components/Editors/Jigsaw/FlowArea/GridElement.vue +++ b/src/components/Editors/Jigsaw/FlowArea/GridElement.vue @@ -5,6 +5,7 @@ top: `${containerY + this.y * 42 + 3 + yOffset}px`, left: `${containerX + this.x * 42 + 3}px`, background, + cursor, }" > @@ -27,6 +28,7 @@ export default { containerX: Number, containerY: Number, background: String, + cursor: String, }, } diff --git a/src/components/Editors/Jigsaw/JigsawNode.vue b/src/components/Editors/Jigsaw/JigsawNode.vue index fe213cb18..3f6e249a6 100644 --- a/src/components/Editors/Jigsaw/JigsawNode.vue +++ b/src/components/Editors/Jigsaw/JigsawNode.vue @@ -1,12 +1,17 @@