From c0c7f50dc97e5a75c06d0c4e7184553a3095557e Mon Sep 17 00:00:00 2001 From: akshay1992kalbhor Date: Thu, 27 May 2021 18:19:55 +0530 Subject: [PATCH 01/10] Change arg to IconButton component --- client/web/src/components/panels/LayerTree.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/web/src/components/panels/LayerTree.vue b/client/web/src/components/panels/LayerTree.vue index 40b6120120..0b60a5be0f 100644 --- a/client/web/src/components/panels/LayerTree.vue +++ b/client/web/src/components/panels/LayerTree.vue @@ -20,7 +20,7 @@
-
+
@@ -118,6 +118,9 @@ export default defineComponent({ const { toggle_layer_visibility } = await wasm; toggle_layer_visibility(path); }, + async handleClick(path: BigUint64Array) { + console.log(`A layer was clicked: ${path}`); + }, }, mounted() { registerResponseHandler(ResponseType.ExpandFolder, (responseData: Response) => { From 44db6d39aae27da86c7ffbdc412b3073f05625bf Mon Sep 17 00:00:00 2001 From: akshay1992kalbhor Date: Tue, 1 Jun 2021 15:28:19 +0530 Subject: [PATCH 02/10] Add basic layer selection mechanism --- client/web/.DS_Store | Bin 0 -> 6148 bytes .../web/src/components/panels/LayerTree.vue | 80 +++++++++++++++++- client/web/src/response-handler.ts | 2 + 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 client/web/.DS_Store diff --git a/client/web/.DS_Store b/client/web/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..edbbab67b94eeacde31c0391909a11917cd2ede9 GIT binary patch literal 6148 zcmeHK%}T>S5Z-O8ZYp9Af<5lVTMzwH@gRg)58i}`9#qUNM1wV$S3f1 zoY~zLO7-AH#Lk4-Z+3QOm;DlUvWzkAjJq|)N{lf9ikP#Y`9g3UbxCr@gUHn!35)$n zJoE>VzZ6Z5zsLZ-yLINV7@i(me1Gr$a1g{vwfezx`NG=zh7d(j+$!F>{b=GQUNVjy zZ*+~lb1&)p#=eN6!QA%z%b+)Dmv&B~F!6%0H&V$#w+A6NS3%f~CQdXCyRn+b)dNCU z!fKbw)9HS*UXhLFVOo*Xqk6R>n~j4swZ!gT?f9&7|M)b0PG4R%vm8D`CEEsP@CL@h zCLi2UIEcbK@XvB)v4q3`F+dEg00ZXe6PqirSK1;mKn(nh0X!chD57mJ)2NOPXz=$D z#|wxkVB=i^Q5v)jW*T7xgzHp5oyyG>gX?tgOA}`s%rxqB#?{I&k6D?U8wyvegI}s} z#%+z%5(C7*A_IBdEn)pX{r>*Hm_$8dfEf5!4DdqBZ8@+dQ(KodhqYFMc0f@uF4H(q j0YjByh{aM|22}!ni3Xr;Fw+Pg5c&~NG*Ckf{3-*Vd@WL) literal 0 HcmV?d00001 diff --git a/client/web/src/components/panels/LayerTree.vue b/client/web/src/components/panels/LayerTree.vue index 0b60a5be0f..8ce6ff6f5c 100644 --- a/client/web/src/components/panels/LayerTree.vue +++ b/client/web/src/components/panels/LayerTree.vue @@ -20,7 +20,7 @@
-
+
@@ -68,6 +68,10 @@ margin-left: 4px; padding-left: 16px; } + + .selected { + background: #ff0000; + } & + .layer-row { margin-top: 2px; @@ -118,8 +122,78 @@ export default defineComponent({ const { toggle_layer_visibility } = await wasm; toggle_layer_visibility(path); }, + async handleAnotherClick(path: BigUint64Array) { + // Keep everything else the same, toggle path + // Change mainPath + let i = 0; + this.reset = false; + for (const layer of this.layers) { + if (layer.path === path) { + layer.selected = !layer.selected; + if (layer.selected) { + this.mainPath = path; + } else { + if (layer !== this.layers[this.layers.length-1]) { + this.mainPath = this.layers[i+1].path; + } else { + // last layer + this.mainPath = i > 0 ? this.layers[i-1].path : new BigUint64Array([]); + } + } + } + i += 1; + } + console.log("Ctrl + Click"); + }, + async handleClickRange(path: BigUint64Array) { + //this.reset = false; + if (this.mainPath.length === 0) { + console.log("MainPath is []"); + for (const layer of this.layers) { + if (layer.path < path) { + layer.selected = !layer.selected; + } else if (layer.path === path) { + layer.selected = true + } + } + this.mainPath = path; + } else { + if (path <= this.mainPath) { + // UP + for (const layer of this.layers) { + if ((layer.path >= path && layer.path <= this.mainPath) || (layer.path <= path && layer.path >= this.mainPath)) { + layer.selected = true; + } else { + layer.selected = false; + } + } + } else { + // DOWN + for (const layer of this.layers) { + if ((layer.path >= path && layer.path <= this.mainPath) || (layer.path <= path && layer.path >= this.mainPath)) { + layer.selected = true; + } else { + if (this.reset) { + layer.selected = false; + } + } + } + } + } + console.log("Shift + Click"); + }, async handleClick(path: BigUint64Array) { - console.log(`A layer was clicked: ${path}`); + const { select_layer } = await wasm; + this.mainPath = path; + this.reset = true; + for (const layer of this.layers) { + if (layer.path === path) { + layer.selected = true; + } else { + layer.selected = false; + } + } + //console.log(`A layer was clicked: ${path}`); }, }, mounted() { @@ -143,6 +217,8 @@ export default defineComponent({ MenuDirection, SeparatorType, layers: [] as Array, + mainPath: new BigUint64Array([]), + reset: true, }; }, components: { diff --git a/client/web/src/response-handler.ts b/client/web/src/response-handler.ts index ea78365ead..d74da4bd0f 100644 --- a/client/web/src/response-handler.ts +++ b/client/web/src/response-handler.ts @@ -120,6 +120,7 @@ export interface LayerPanelEntry { layer_type: LayerType; collapsed: boolean; path: BigUint64Array; + selected: boolean; } function newLayerPanelEntry(input: any): LayerPanelEntry { return { @@ -128,6 +129,7 @@ function newLayerPanelEntry(input: any): LayerPanelEntry { layer_type: newLayerType(input.layer_type), collapsed: input.collapsed, path: new BigUint64Array(input.path.map((n: number) => BigInt(n))), + selected: false, }; } From a90da2139711a62970bf4cda31353d81d014bf84 Mon Sep 17 00:00:00 2001 From: akshay1992kalbhor Date: Tue, 1 Jun 2021 23:54:22 +0530 Subject: [PATCH 03/10] Almost good version --- .../web/src/components/panels/LayerTree.vue | 118 +++++++++++------- 1 file changed, 74 insertions(+), 44 deletions(-) diff --git a/client/web/src/components/panels/LayerTree.vue b/client/web/src/components/panels/LayerTree.vue index 8ce6ff6f5c..5b2921c69d 100644 --- a/client/web/src/components/panels/LayerTree.vue +++ b/client/web/src/components/panels/LayerTree.vue @@ -20,7 +20,7 @@
-
+
@@ -120,80 +120,110 @@ export default defineComponent({ methods: { async toggleLayerVisibility(path: BigUint64Array) { const { toggle_layer_visibility } = await wasm; + //console.log(`PPP: ${path.length}`); toggle_layer_visibility(path); }, - async handleAnotherClick(path: BigUint64Array) { + async handleControlClick(path: BigUint64Array) { // Keep everything else the same, toggle path // Change mainPath let i = 0; - this.reset = false; + this.endPath = new BigUint64Array([]); for (const layer of this.layers) { if (layer.path === path) { layer.selected = !layer.selected; if (layer.selected) { - this.mainPath = path; + this.startPath = path; } else { - if (layer !== this.layers[this.layers.length-1]) { - this.mainPath = this.layers[i+1].path; - } else { - // last layer - this.mainPath = i > 0 ? this.layers[i-1].path : new BigUint64Array([]); + console.log("HEROE"); + let j = i+1; + while (j < this.layers.length) { + if (this.layers[j].selected) { + console.log("BELOW"); + this.startPath = this.layers[j].path; + break; + } + j += 1; + } + if(j >= this.layers.length) { + // Look above + j = i-1; + while (j >= 0) { + if (this.layers[j].selected) { + console.log("ABOVE"); + this.startPath = this.layers[j].path; + break; + } + j -= 1; + } + } + if (j < 0) { + // RESET + console.log("RESEET"); + this.startPath = new BigUint64Array([]); } } } i += 1; } - console.log("Ctrl + Click"); + //console.log("Ctrl + Click"); }, - async handleClickRange(path: BigUint64Array) { - //this.reset = false; - if (this.mainPath.length === 0) { - console.log("MainPath is []"); + async handleShiftClick(path: BigUint64Array) { + // The two paths of the range are stored in startPath and endPath + // So for a new Shift+Click, unselect all paths between startPath and endPath(stored in prev Sft+C) + // Then select all paths between startPath and path(new endPath) and assign path to endPath + + if (this.startPath.length === 0) { + // If nothing was selected before, usually at the start of the app + // Also if the user manually deselects all the layers for (const layer of this.layers) { - if (layer.path < path) { + if (layer.path[0] < path[0]) { layer.selected = !layer.selected; - } else if (layer.path === path) { + } else if (layer.path[0] === path[0]) { layer.selected = true } } - this.mainPath = path; + this.startPath = path; + this.endPath = this.layers[0].path; } else { - if (path <= this.mainPath) { - // UP + + if (this.endPath.length !== 0) { for (const layer of this.layers) { - if ((layer.path >= path && layer.path <= this.mainPath) || (layer.path <= path && layer.path >= this.mainPath)) { - layer.selected = true; - } else { + if ((layer.path[0] >= this.endPath[0] && layer.path[0] < this.startPath[0]) || (layer.path[0] <= this.endPath[0] && layer.path[0] > this.startPath[0])) { layer.selected = false; } } - } else { - // DOWN - for (const layer of this.layers) { - if ((layer.path >= path && layer.path <= this.mainPath) || (layer.path <= path && layer.path >= this.mainPath)) { - layer.selected = true; - } else { - if (this.reset) { - layer.selected = false; - } - } + } + + this.endPath = path; + for (const layer of this.layers) { + if ((layer.path[0] >= path[0] && layer.path[0] <= this.startPath[0]) || (layer.path[0] <= path[0] && layer.path[0] >= this.startPath[0])) { + layer.selected = true; + console.log(`THIS: ${layer.path} in ${this.startPath} from ${this.endPath}`); } } } - console.log("Shift + Click"); }, + + async handleClick(path: BigUint64Array) { - const { select_layer } = await wasm; - this.mainPath = path; - this.reset = true; + //const { select_layer } = await wasm; + console.log(`mainPath: ${this.startPath}`); + this.startPath = path; + this.endPath = new BigUint64Array([]); + //this.endPath = path; + + console.log(`PATH: ${path}, ${path[0]}, ${path[1]}`); + /* + console.log(`PATH: ${this.mainPath}`); + console.log(`WHATPATH: ${typeof path}`); + console.log(`WHATPATH: ${Object.keys(path)}`); + console.log(`NAME: ${path.keys()}`); + */ for (const layer of this.layers) { - if (layer.path === path) { - layer.selected = true; - } else { - layer.selected = false; - } + // Can we directly index into `layers`? Is the path `i` at the `i`th index in layers? + // Delete layer op may affect the order of layers and the paths. + layer.selected = layer.path === path; } - //console.log(`A layer was clicked: ${path}`); }, }, mounted() { @@ -217,8 +247,8 @@ export default defineComponent({ MenuDirection, SeparatorType, layers: [] as Array, - mainPath: new BigUint64Array([]), - reset: true, + startPath: new BigUint64Array([]), + endPath: new BigUint64Array([]), }; }, components: { From adb67795005064c216e667d23a236508050343b0 Mon Sep 17 00:00:00 2001 From: akshay1992kalbhor Date: Wed, 2 Jun 2021 19:31:35 +0530 Subject: [PATCH 04/10] Clean up print statements and add some comments --- .../web/src/components/panels/LayerTree.vue | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/client/web/src/components/panels/LayerTree.vue b/client/web/src/components/panels/LayerTree.vue index 5b2921c69d..e3e3b4e370 100644 --- a/client/web/src/components/panels/LayerTree.vue +++ b/client/web/src/components/panels/LayerTree.vue @@ -120,12 +120,9 @@ export default defineComponent({ methods: { async toggleLayerVisibility(path: BigUint64Array) { const { toggle_layer_visibility } = await wasm; - //console.log(`PPP: ${path.length}`); toggle_layer_visibility(path); }, async handleControlClick(path: BigUint64Array) { - // Keep everything else the same, toggle path - // Change mainPath let i = 0; this.endPath = new BigUint64Array([]); for (const layer of this.layers) { @@ -134,11 +131,10 @@ export default defineComponent({ if (layer.selected) { this.startPath = path; } else { - console.log("HEROE"); let j = i+1; while (j < this.layers.length) { + // Look for a selected layer below to assign to startPath if (this.layers[j].selected) { - console.log("BELOW"); this.startPath = this.layers[j].path; break; } @@ -158,14 +154,12 @@ export default defineComponent({ } if (j < 0) { // RESET - console.log("RESEET"); this.startPath = new BigUint64Array([]); } } } i += 1; } - //console.log("Ctrl + Click"); }, async handleShiftClick(path: BigUint64Array) { // The two paths of the range are stored in startPath and endPath @@ -198,7 +192,6 @@ export default defineComponent({ for (const layer of this.layers) { if ((layer.path[0] >= path[0] && layer.path[0] <= this.startPath[0]) || (layer.path[0] <= path[0] && layer.path[0] >= this.startPath[0])) { layer.selected = true; - console.log(`THIS: ${layer.path} in ${this.startPath} from ${this.endPath}`); } } } @@ -206,19 +199,9 @@ export default defineComponent({ async handleClick(path: BigUint64Array) { - //const { select_layer } = await wasm; - console.log(`mainPath: ${this.startPath}`); this.startPath = path; this.endPath = new BigUint64Array([]); - //this.endPath = path; - console.log(`PATH: ${path}, ${path[0]}, ${path[1]}`); - /* - console.log(`PATH: ${this.mainPath}`); - console.log(`WHATPATH: ${typeof path}`); - console.log(`WHATPATH: ${Object.keys(path)}`); - console.log(`NAME: ${path.keys()}`); - */ for (const layer of this.layers) { // Can we directly index into `layers`? Is the path `i` at the `i`th index in layers? // Delete layer op may affect the order of layers and the paths. From cabae199d556fb105c88b23455c3a30900a37de3 Mon Sep 17 00:00:00 2001 From: akshay1992kalbhor Date: Mon, 7 Jun 2021 10:50:04 +0530 Subject: [PATCH 05/10] Simplified the layer selection mechanism --- client/web/.eslintrc.js | 1 + .../web/src/components/panels/LayerTree.vue | 123 ++++++++---------- 2 files changed, 57 insertions(+), 67 deletions(-) diff --git a/client/web/.eslintrc.js b/client/web/.eslintrc.js index 181a3892b9..8e2cedafd5 100644 --- a/client/web/.eslintrc.js +++ b/client/web/.eslintrc.js @@ -30,6 +30,7 @@ module.exports = { "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", "no-param-reassign": ["error", { props: false }], "max-len": ["error", { code: 200, tabWidth: 4 }], + "no-param-reassign": [2, { "props": false }], "@typescript-eslint/camelcase": "off", "@typescript-eslint/no-use-before-define": "off", "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], diff --git a/client/web/src/components/panels/LayerTree.vue b/client/web/src/components/panels/LayerTree.vue index e3e3b4e370..4e8cb53823 100644 --- a/client/web/src/components/panels/LayerTree.vue +++ b/client/web/src/components/panels/LayerTree.vue @@ -20,7 +20,13 @@
-
+
@@ -68,7 +74,6 @@ margin-left: 4px; padding-left: 16px; } - .selected { background: #ff0000; } @@ -124,89 +129,73 @@ export default defineComponent({ }, async handleControlClick(path: BigUint64Array) { let i = 0; - this.endPath = new BigUint64Array([]); - for (const layer of this.layers) { - if (layer.path === path) { - layer.selected = !layer.selected; - if (layer.selected) { - this.startPath = path; - } else { - let j = i+1; - while (j < this.layers.length) { - // Look for a selected layer below to assign to startPath + this.endPath = -1n; + this.layers.forEach((layer, idx, layers) => { + if (layer.path === path) { + layers[idx].selected = !layer.selected; + if (layer.selected) { + [this.startPath] = path; + } else { + let j = i + 1; + while (j < this.layers.length) { + // Look for a selected layer below to assign to startPath + if (this.layers[j].selected) { + [this.startPath] = this.layers[j].path; + break; + } + j += 1; + } + if (j >= this.layers.length) { + // Look above + j = i - 1; + while (j >= 0) { if (this.layers[j].selected) { - this.startPath = this.layers[j].path; + console.log("ABOVE"); + [this.startPath] = this.layers[j].path; break; } - j += 1; - } - if(j >= this.layers.length) { - // Look above - j = i-1; - while (j >= 0) { - if (this.layers[j].selected) { - console.log("ABOVE"); - this.startPath = this.layers[j].path; - break; - } - j -= 1; - } - } - if (j < 0) { - // RESET - this.startPath = new BigUint64Array([]); + j -= 1; } } + if (j < 0) { + // RESET + this.startPath = -1n; + } } - i += 1; - } + } + i += 1; + }); }, async handleShiftClick(path: BigUint64Array) { // The two paths of the range are stored in startPath and endPath - // So for a new Shift+Click, unselect all paths between startPath and endPath(stored in prev Sft+C) + // So for a new Shift+Click, unselect all paths between startPath and endPath(stored in prev Sft+C) // Then select all paths between startPath and path(new endPath) and assign path to endPath - - if (this.startPath.length === 0) { + if (this.startPath === -1n) { // If nothing was selected before, usually at the start of the app // Also if the user manually deselects all the layers - for (const layer of this.layers) { - if (layer.path[0] < path[0]) { - layer.selected = !layer.selected; - } else if (layer.path[0] === path[0]) { - layer.selected = true + this.layers.forEach((layer) => { + if (layer.path[0] <= path[0]) { + layer.selected = true; } - } - this.startPath = path; - this.endPath = this.layers[0].path; + }); } else { - - if (this.endPath.length !== 0) { - for (const layer of this.layers) { - if ((layer.path[0] >= this.endPath[0] && layer.path[0] < this.startPath[0]) || (layer.path[0] <= this.endPath[0] && layer.path[0] > this.startPath[0])) { - layer.selected = false; - } - } - } - - this.endPath = path; - for (const layer of this.layers) { - if ((layer.path[0] >= path[0] && layer.path[0] <= this.startPath[0]) || (layer.path[0] <= path[0] && layer.path[0] >= this.startPath[0])) { + [this.endPath] = path; + this.layers.forEach((layer) => { + if ((layer.path[0] >= path[0] && layer.path[0] <= this.startPath) || (layer.path[0] <= path[0] && layer.path[0] >= this.startPath)) { layer.selected = true; } - } + }); } }, - async handleClick(path: BigUint64Array) { - this.startPath = path; - this.endPath = new BigUint64Array([]); - - for (const layer of this.layers) { - // Can we directly index into `layers`? Is the path `i` at the `i`th index in layers? - // Delete layer op may affect the order of layers and the paths. - layer.selected = layer.path === path; - } + [this.startPath] = path; + [this.endPath] = path; + this.layers.forEach((layer) => { + // Can we directly index into `layers`? Is the path `i` at the `i`th index in layers? + // Delete layer op may affect the order of layers and the paths. + layer.selected = layer.path === path; + }); }, }, mounted() { @@ -230,8 +219,8 @@ export default defineComponent({ MenuDirection, SeparatorType, layers: [] as Array, - startPath: new BigUint64Array([]), - endPath: new BigUint64Array([]), + startPath: -1n, + endPath: -1n, }; }, components: { From 8de051714e7a6ac033e8f3b4f7ce0ead78a0930c Mon Sep 17 00:00:00 2001 From: akshay1992kalbhor Date: Mon, 7 Jun 2021 11:00:18 +0530 Subject: [PATCH 06/10] Remove redundant rule for 'no-param-reassign' --- client/web/.eslintrc.js | 1 - 1 file changed, 1 deletion(-) diff --git a/client/web/.eslintrc.js b/client/web/.eslintrc.js index 8e2cedafd5..181a3892b9 100644 --- a/client/web/.eslintrc.js +++ b/client/web/.eslintrc.js @@ -30,7 +30,6 @@ module.exports = { "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off", "no-param-reassign": ["error", { props: false }], "max-len": ["error", { code: 200, tabWidth: 4 }], - "no-param-reassign": [2, { "props": false }], "@typescript-eslint/camelcase": "off", "@typescript-eslint/no-use-before-define": "off", "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], From 3c0c0853401902ebfbb7771e8502db47b2386ba3 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Wed, 9 Jun 2021 16:23:10 +0200 Subject: [PATCH 07/10] Clean up frontend and and plumb selection flow to backend --- client/web/.DS_Store | Bin 6148 -> 0 bytes .../web/src/components/panels/LayerTree.vue | 131 ++++++++---------- client/web/src/response-handler.ts | 17 ++- 3 files changed, 73 insertions(+), 75 deletions(-) delete mode 100644 client/web/.DS_Store diff --git a/client/web/.DS_Store b/client/web/.DS_Store deleted file mode 100644 index edbbab67b94eeacde31c0391909a11917cd2ede9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHK%}T>S5Z-O8ZYp9Af<5lVTMzwH@gRg)58i}`9#qUNM1wV$S3f1 zoY~zLO7-AH#Lk4-Z+3QOm;DlUvWzkAjJq|)N{lf9ikP#Y`9g3UbxCr@gUHn!35)$n zJoE>VzZ6Z5zsLZ-yLINV7@i(me1Gr$a1g{vwfezx`NG=zh7d(j+$!F>{b=GQUNVjy zZ*+~lb1&)p#=eN6!QA%z%b+)Dmv&B~F!6%0H&V$#w+A6NS3%f~CQdXCyRn+b)dNCU z!fKbw)9HS*UXhLFVOo*Xqk6R>n~j4swZ!gT?f9&7|M)b0PG4R%vm8D`CEEsP@CL@h zCLi2UIEcbK@XvB)v4q3`F+dEg00ZXe6PqirSK1;mKn(nh0X!chD57mJ)2NOPXz=$D z#|wxkVB=i^Q5v)jW*T7xgzHp5oyyG>gX?tgOA}`s%rxqB#?{I&k6D?U8wyvegI}s} z#%+z%5(C7*A_IBdEn)pX{r>*Hm_$8dfEf5!4DdqBZ8@+dQ(KodhqYFMc0f@uF4H(q j0YjByh{aM|22}!ni3Xr;Fw+Pg5c&~NG*Ckf{3-*Vd@WL) diff --git a/client/web/src/components/panels/LayerTree.vue b/client/web/src/components/panels/LayerTree.vue index 4e8cb53823..3c553fa1ba 100644 --- a/client/web/src/components/panels/LayerTree.vue +++ b/client/web/src/components/panels/LayerTree.vue @@ -22,10 +22,10 @@
@@ -75,7 +75,7 @@ padding-left: 16px; } .selected { - background: #ff0000; + background: var(--color-accent); } & + .layer-row { @@ -127,75 +127,64 @@ export default defineComponent({ const { toggle_layer_visibility } = await wasm; toggle_layer_visibility(path); }, - async handleControlClick(path: BigUint64Array) { - let i = 0; - this.endPath = -1n; - this.layers.forEach((layer, idx, layers) => { - if (layer.path === path) { - layers[idx].selected = !layer.selected; - if (layer.selected) { - [this.startPath] = path; - } else { - let j = i + 1; - while (j < this.layers.length) { - // Look for a selected layer below to assign to startPath - if (this.layers[j].selected) { - [this.startPath] = this.layers[j].path; - break; - } - j += 1; - } - if (j >= this.layers.length) { - // Look above - j = i - 1; - while (j >= 0) { - if (this.layers[j].selected) { - console.log("ABOVE"); - [this.startPath] = this.layers[j].path; - break; - } - j -= 1; - } - } - if (j < 0) { - // RESET - this.startPath = -1n; - } - } - } - i += 1; - }); + async handleControlClick(clickedLayer: LayerPanelEntry) { + const index = this.layers.indexOf(clickedLayer); + clickedLayer.layer_data.selected = !clickedLayer.layer_data.selected; + this.selectionRangeEndLayer = undefined; + this.selectionRangeStartLayer = + this.layers.slice(index).filter((layer) => layer.layer_data.selected)[0] || + this.layers + .slice(0, index) + .reverse() + .filter((layer) => layer.layer_data.selected)[0]; + this.updateSelection(); }, - async handleShiftClick(path: BigUint64Array) { - // The two paths of the range are stored in startPath and endPath - // So for a new Shift+Click, unselect all paths between startPath and endPath(stored in prev Sft+C) - // Then select all paths between startPath and path(new endPath) and assign path to endPath - if (this.startPath === -1n) { - // If nothing was selected before, usually at the start of the app - // Also if the user manually deselects all the layers - this.layers.forEach((layer) => { - if (layer.path[0] <= path[0]) { - layer.selected = true; - } - }); - } else { - [this.endPath] = path; - this.layers.forEach((layer) => { - if ((layer.path[0] >= path[0] && layer.path[0] <= this.startPath) || (layer.path[0] <= path[0] && layer.path[0] >= this.startPath)) { - layer.selected = true; - } - }); - } + async handleShiftClick(clickedLayer: LayerPanelEntry) { + // The two paths of the range are stored in selectionRangeStartLayer and selectionRangeEndLayer + // So for a new Shift+Click, select all layers between selectionRangeStartLayer and selectionRangeEndLayer(stored in prev Sft+C) + this.selectionRangeEndLayer = clickedLayer; + this.selectionRangeStartLayer = (this.selectionRangeStartLayer as LayerPanelEntry) || clickedLayer; + this.clearSelection(); + this.fillSelectionRange(this.selectionRangeStartLayer, this.selectionRangeEndLayer, true); + this.updateSelection(); }, - async handleClick(path: BigUint64Array) { - [this.startPath] = path; - [this.endPath] = path; + async handleClick(clickedLayer: LayerPanelEntry) { + this.selectionRangeStartLayer = clickedLayer; + this.selectionRangeEndLayer = clickedLayer; + this.clearSelection(); + clickedLayer.layer_data.selected = true; + this.updateSelection(); + }, + async fillSelectionRange(start: LayerPanelEntry, end: LayerPanelEntry, selected = true) { + const startIndex = this.layers.indexOf(start); + const endIndex = this.layers.indexOf(end); + const [min, max] = [startIndex, endIndex].sort(); + for (let i = min; i <= max; i += 1) { + this.layers[i].layer_data.selected = selected; + } + }, + async clearSelection() { this.layers.forEach((layer) => { - // Can we directly index into `layers`? Is the path `i` at the `i`th index in layers? - // Delete layer op may affect the order of layers and the paths. - layer.selected = layer.path === path; + layer.layer_data.selected = false; + }); + }, + async updateSelection() { + const paths = this.layers.filter((layer) => layer.layer_data.selected).map((layer) => layer.path); + const length = paths.reduce((acc, cur) => acc + cur.length, 0) + paths.length - 1; + const output = new BigUint64Array(length); + let i = 0; + paths.forEach((path, index) => { + output.set(path, i); + i += path.length; + if (index < paths.length) { + // eslint-disable-next-line no-bitwise + output[i] = (1n << 64n) - 1n; + } + i += 1; }); + const { select_layers } = await wasm; + select_layers(output); }, }, mounted() { @@ -219,8 +208,8 @@ export default defineComponent({ MenuDirection, SeparatorType, layers: [] as Array, - startPath: -1n, - endPath: -1n, + selectionRangeStartLayer: undefined as LayerPanelEntry | undefined, + selectionRangeEndLayer: undefined as LayerPanelEntry | undefined, }; }, components: { diff --git a/client/web/src/response-handler.ts b/client/web/src/response-handler.ts index d74da4bd0f..528d7730ec 100644 --- a/client/web/src/response-handler.ts +++ b/client/web/src/response-handler.ts @@ -118,18 +118,27 @@ export interface LayerPanelEntry { name: string; visible: boolean; layer_type: LayerType; - collapsed: boolean; path: BigUint64Array; - selected: boolean; + layer_data: LayerData; } function newLayerPanelEntry(input: any): LayerPanelEntry { return { name: input.name, visible: input.visible, layer_type: newLayerType(input.layer_type), - collapsed: input.collapsed, + layer_data: newLayerData(input.layer_data), path: new BigUint64Array(input.path.map((n: number) => BigInt(n))), - selected: false, + }; +} + +export interface LayerData { + expanded: boolean; + selected: boolean; +} +function newLayerData(input: any): LayerData { + return { + expanded: input.expanded, + selected: input.selected, }; } From 5abc7d9df4ca4256dada1402fb50330aada94aa2 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Wed, 9 Jun 2021 19:56:29 +0200 Subject: [PATCH 08/10] Change Alt -> Ctrl and add color to css --- client/web/src/components/panels/LayerTree.vue | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/web/src/components/panels/LayerTree.vue b/client/web/src/components/panels/LayerTree.vue index 3c553fa1ba..7470186fa3 100644 --- a/client/web/src/components/panels/LayerTree.vue +++ b/client/web/src/components/panels/LayerTree.vue @@ -24,7 +24,7 @@ class="layer" :class="{ selected: layer.layer_data.selected }" @click.shift.exact="handleShiftClick(layer)" - @click.alt.exact="handleControlClick(layer)" + @click.ctrl.exact="handleControlClick(layer)" @click.exact="handleClick(layer)" >
@@ -76,6 +76,7 @@ } .selected { background: var(--color-accent); + color: var(--color-f-white); } & + .layer-row { From cf5a0defce70b91fa980d2d89e8363f77650eb52 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Wed, 9 Jun 2021 20:13:43 +0200 Subject: [PATCH 09/10] Add both alt and ctrl as select mod keys --- client/web/src/components/panels/LayerTree.vue | 1 + 1 file changed, 1 insertion(+) diff --git a/client/web/src/components/panels/LayerTree.vue b/client/web/src/components/panels/LayerTree.vue index 7470186fa3..7641f3586c 100644 --- a/client/web/src/components/panels/LayerTree.vue +++ b/client/web/src/components/panels/LayerTree.vue @@ -25,6 +25,7 @@ :class="{ selected: layer.layer_data.selected }" @click.shift.exact="handleShiftClick(layer)" @click.ctrl.exact="handleControlClick(layer)" + @click.alt.exact="handleControlClick(layer)" @click.exact="handleClick(layer)" >
From 17ce7d8aa3e309dd469fe9ec768f70fecb2221e4 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Wed, 9 Jun 2021 20:30:04 +0200 Subject: [PATCH 10/10] Update eslintrc --- client/web/.eslintrc.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/web/.eslintrc.js b/client/web/.eslintrc.js index 181a3892b9..e4eb13e196 100644 --- a/client/web/.eslintrc.js +++ b/client/web/.eslintrc.js @@ -1,7 +1,9 @@ module.exports = { root: true, env: { + browser: true, node: true, + es2020: true, }, extends: ["plugin:vue/vue3-essential", "@vue/airbnb", "@vue/typescript/recommended", "plugin:prettier-vue/recommended", "prettier"], parserOptions: {