1
1
<template >
2
2
<div class =" tool-options" >
3
- <template v-for =" (option , index ) in toolOptions [activeTool ] || [] " :key =" index " >
3
+ <template v-for =" (option , index ) in toolOptionsWidgets [activeTool ] || [] " :key =" index " >
4
4
<!-- TODO: Use `<component :is="" v-bind="attributesObject"></component>` to avoid all the separate components with `v-if` -->
5
5
<IconButton v-if =" option.kind === 'IconButton'" :action =" () => handleIconButtonAction(option)" :title =" option.tooltip" v-bind =" option.props" />
6
6
<PopoverButton v-if =" option.kind === 'PopoverButton'" :title =" option.tooltip" :action =" option.callback" v-bind =" option.props" >
7
7
<h3 >{{ option.popover.title }}</h3 >
8
8
<p >{{ option.popover.text }}</p >
9
9
</PopoverButton >
10
- <NumberInput v-if =" option.kind === 'NumberInput'" v-model:value =" option.props.value" @update:value =" option.callback" :title =" option.tooltip" v-bind =" option.props" />
10
+ <NumberInput
11
+ v-if =" option.kind === 'NumberInput'"
12
+ @update:value =" (value) => updateToolOptions(option.optionPath, value)"
13
+ :title =" option.tooltip"
14
+ :value =" getToolOption(option.optionPath)"
15
+ v-bind =" option.props"
16
+ />
11
17
<Separator v-if =" option.kind === 'Separator'" v-bind =" option.props" />
12
18
</template >
13
19
</div >
23
29
</style >
24
30
25
31
<script lang="ts">
26
- import { defineComponent } from " vue" ;
32
+ import { defineComponent , PropType } from " vue" ;
27
33
28
34
import { comingSoon } from " @/utilities/errors" ;
29
35
import { WidgetRow , SeparatorType , IconButtonWidget } from " @/components/widgets/widgets" ;
@@ -38,28 +44,36 @@ const wasm = import("@/../wasm/pkg");
38
44
export default defineComponent ({
39
45
props: {
40
46
activeTool: { type: String },
47
+ activeToolOptions: { type: Object as PropType <Record <string , object >> },
41
48
},
42
- computed: {},
43
49
methods: {
44
- async setShapeOptions(newValue : number ) {
45
- // TODO: Each value-input widget (i.e. not a button) should map to a field in an options struct,
46
- // and updating a widget should send the whole updated struct to the backend.
47
- // Later, it could send a single-field update to the backend.
48
-
49
- // This is a placeholder call, using the Shape tool as an example
50
- // eslint-disable-next-line camelcase
51
- (await wasm ).set_tool_options (this .$props .activeTool || " " , { Shape: { shape_type: { Polygon: { vertices: newValue } } } });
50
+ async updateToolOptions(path : string [], newValue : number ) {
51
+ this .setToolOption (path , newValue );
52
+ (await wasm ).set_tool_options (this .activeTool || " " , this .activeToolOptions );
52
53
},
53
- async setLineOptions(newValue : number ) {
54
- // eslint-disable-next-line camelcase
55
- (await wasm ).set_tool_options (this .$props .activeTool || " " , { Line: { weight: newValue } });
54
+ async sendToolMessage(message : string | object ) {
55
+ (await wasm ).send_tool_message (this .activeTool || " " , message );
56
56
},
57
- async setPenOptions(newValue : number ) {
58
- // eslint-disable-next-line camelcase
59
- (await wasm ).set_tool_options (this .$props .activeTool || " " , { Pen: { weight: newValue } });
57
+ // Traverses the given path and returns the direct parent of the option
58
+ getRecordContainingOption(optionPath : string []): Record <string , number > {
59
+ const allButLast = optionPath .slice (0 , - 1 );
60
+ let currentRecord = this .activeToolOptions as Record <string , object | number >;
61
+ [this .activeTool || " " , ... allButLast ].forEach ((attr ) => {
62
+ currentRecord = currentRecord [attr ] as Record <string , object | number >;
63
+ });
64
+ return currentRecord as Record <string , number >;
60
65
},
61
- async sendToolMessage(message : string | object ) {
62
- (await wasm ).send_tool_message (this .$props .activeTool || " " , message );
66
+ // Traverses the given path into the active tool's option struct, and sets the value at the path tail
67
+ setToolOption(optionPath : string [], newValue : number ) {
68
+ const last = optionPath .slice (- 1 )[0 ];
69
+ const recordContainingOption = this .getRecordContainingOption (optionPath );
70
+ recordContainingOption [last ] = newValue ;
71
+ },
72
+ // Traverses the given path into the active tool's option struct, and returns the value at the path tail
73
+ getToolOption(optionPath : string []): number {
74
+ const last = optionPath .slice (- 1 )[0 ];
75
+ const recordContainingOption = this .getRecordContainingOption (optionPath );
76
+ return recordContainingOption [last ];
63
77
},
64
78
handleIconButtonAction(option : IconButtonWidget ) {
65
79
if (option .message ) {
@@ -76,7 +90,7 @@ export default defineComponent({
76
90
},
77
91
},
78
92
data() {
79
- const toolOptions : Record <string , WidgetRow > = {
93
+ const toolOptionsWidgets : Record <string , WidgetRow > = {
80
94
Select: [
81
95
{ kind: " IconButton" , message: { Align: [" X" , " Min" ] }, tooltip: " Align Left" , props: { icon: " AlignLeft" , size: 24 } },
82
96
{ kind: " IconButton" , message: { Align: [" X" , " Center" ] }, tooltip: " Align Horizontal Center" , props: { icon: " AlignHorizontalCenter" , size: 24 } },
@@ -134,13 +148,13 @@ export default defineComponent({
134
148
props: {},
135
149
},
136
150
],
137
- Shape: [{ kind: " NumberInput" , callback: this . setShapeOptions , props: { value: 6 , min: 3 , isInteger: true , label: " Sides" } }],
138
- Line: [{ kind: " NumberInput" , callback: this . setLineOptions , props: { value: 5 , min: 1 , isInteger: true , unit: " px" , label: " Weight" } }],
139
- Pen: [{ kind: " NumberInput" , callback: this . setPenOptions , props: { value: 5 , min: 1 , isInteger: true , unit: " px" , label: " Weight" } }],
151
+ Shape: [{ kind: " NumberInput" , optionPath: [ " shape_type " , " Polygon " , " vertices " ], props: { min: 3 , isInteger: true , label: " Sides" } }],
152
+ Line: [{ kind: " NumberInput" , optionPath: [ " weight " ] , props: { min: 1 , isInteger: true , unit: " px" , label: " Weight" } }],
153
+ Pen: [{ kind: " NumberInput" , optionPath: [ " weight " ] , props: { min: 1 , isInteger: true , unit: " px" , label: " Weight" } }],
140
154
};
141
155
142
156
return {
143
- toolOptions ,
157
+ toolOptionsWidgets ,
144
158
SeparatorType ,
145
159
comingSoon ,
146
160
};
0 commit comments