@@ -2,17 +2,19 @@ import { Color4 } from '@js-draw/math';
2
2
import { isRestylableComponent } from '../../components/RestylableComponent' ;
3
3
import Editor from '../../Editor' ;
4
4
import uniteCommands from '../../commands/uniteCommands' ;
5
- import SelectionTool from '../../tools/SelectionTool/SelectionTool' ;
5
+ import SelectionTool , { SelectionMode } from '../../tools/SelectionTool/SelectionTool' ;
6
6
import { EditorEventType } from '../../types' ;
7
7
import { KeyPressEvent } from '../../inputEvents' ;
8
8
import { ToolbarLocalization } from '../localization' ;
9
9
import makeColorInput from './components/makeColorInput' ;
10
- import ActionButtonWidget from './ActionButtonWidget' ;
11
10
import BaseToolWidget from './BaseToolWidget' ;
12
11
import { resizeImageToSelectionKeyboardShortcut } from './keybindings' ;
13
12
import makeSeparator from './components/makeSeparator' ;
14
13
import { toolbarCSSPrefix } from '../constants' ;
15
14
import HelpDisplay from '../utils/HelpDisplay' ;
15
+ import BaseWidget , { SavedToolbuttonState } from './BaseWidget' ;
16
+ import makeButtonGrid from './components/makeButtonGrid' ;
17
+ import { MutableReactiveValue } from '../../util/ReactiveValue' ;
16
18
17
19
const makeFormatMenu = (
18
20
editor : Editor ,
@@ -89,8 +91,55 @@ const makeFormatMenu = (
89
91
} ;
90
92
} ;
91
93
94
+ class LassoSelectToggle extends BaseWidget {
95
+ public constructor (
96
+ editor : Editor ,
97
+ protected tool : SelectionTool ,
98
+
99
+ localizationTable ?: ToolbarLocalization ,
100
+ ) {
101
+ super ( editor , 'selection-mode-toggle' , localizationTable ) ;
102
+
103
+ editor . notifier . on ( EditorEventType . ToolUpdated , ( toolEvt ) => {
104
+ if ( toolEvt . kind === EditorEventType . ToolUpdated && toolEvt . tool === tool ) {
105
+ this . setSelected ( tool . modeValue . get ( ) === SelectionMode . Lasso ) ;
106
+ }
107
+ } ) ;
108
+ this . setSelected ( false ) ;
109
+ }
110
+
111
+ protected override shouldAutoDisableInReadOnlyEditor ( ) : boolean {
112
+ return false ;
113
+ }
114
+
115
+ private setModeFlag ( enabled : boolean ) {
116
+ this . tool . modeValue . set ( enabled ? SelectionMode . Lasso : SelectionMode . Rectangle ) ;
117
+ }
118
+
119
+ protected handleClick ( ) {
120
+ this . setModeFlag ( ! this . isSelected ( ) ) ;
121
+ }
122
+
123
+ protected getTitle ( ) : string {
124
+ return this . localizationTable . selectionTool__lassoSelect ;
125
+ }
126
+
127
+ protected createIcon ( ) : Element {
128
+ return this . editor . icons . makeSelectionIcon ( SelectionMode . Lasso ) ;
129
+ }
130
+
131
+ protected override fillDropdown ( _dropdown : HTMLElement ) : boolean {
132
+ return false ;
133
+ }
134
+
135
+ protected override getHelpText ( ) {
136
+ return this . localizationTable . selectionTool__lassoSelect__help ;
137
+ }
138
+ }
139
+
92
140
export default class SelectionToolWidget extends BaseToolWidget {
93
141
private updateFormatMenu : ( ) => void = ( ) => { } ;
142
+ private hasSelectionValue : MutableReactiveValue < boolean > ;
94
143
95
144
public constructor (
96
145
editor : Editor ,
@@ -99,56 +148,13 @@ export default class SelectionToolWidget extends BaseToolWidget {
99
148
) {
100
149
super ( editor , tool , 'selection-tool-widget' , localization ) ;
101
150
102
- const resizeButton = new ActionButtonWidget (
103
- editor ,
104
- 'resize-btn' ,
105
- ( ) => editor . icons . makeResizeImageToSelectionIcon ( ) ,
106
- this . localizationTable . resizeImageToSelection ,
107
- ( ) => {
108
- this . resizeImageToSelection ( ) ;
109
- } ,
110
- localization ,
111
- ) ;
112
- resizeButton . setHelpText ( this . localizationTable . selectionDropdown__resizeToHelpText ) ;
113
-
114
- const deleteButton = new ActionButtonWidget (
115
- editor ,
116
- 'delete-btn' ,
117
- ( ) => editor . icons . makeDeleteSelectionIcon ( ) ,
118
- this . localizationTable . deleteSelection ,
119
- ( ) => {
120
- const selection = this . tool . getSelection ( ) ;
121
- this . editor . dispatch ( selection ! . deleteSelectedObjects ( ) ) ;
122
- this . tool . clearSelection ( ) ;
123
- } ,
124
- localization ,
125
- ) ;
126
- deleteButton . setHelpText ( this . localizationTable . selectionDropdown__deleteHelpText ) ;
127
-
128
- const duplicateButton = new ActionButtonWidget (
129
- editor ,
130
- 'duplicate-btn' ,
131
- ( ) => editor . icons . makeDuplicateSelectionIcon ( ) ,
132
- this . localizationTable . duplicateSelection ,
133
- async ( ) => {
134
- const selection = this . tool . getSelection ( ) ;
135
- this . editor . dispatch ( await selection ! . duplicateSelectedObjects ( ) ) ;
136
- this . setDropdownVisible ( false ) ;
137
- } ,
138
- localization ,
139
- ) ;
140
- duplicateButton . setHelpText ( this . localizationTable . selectionDropdown__duplicateHelpText ) ;
141
-
142
- this . addSubWidget ( resizeButton ) ;
143
- this . addSubWidget ( deleteButton ) ;
144
- this . addSubWidget ( duplicateButton ) ;
151
+ this . addSubWidget ( new LassoSelectToggle ( editor , tool , this . localizationTable ) ) ;
145
152
146
- const updateDisabled = ( disabled : boolean ) => {
147
- resizeButton . setDisabled ( disabled ) ;
148
- deleteButton . setDisabled ( disabled ) ;
149
- duplicateButton . setDisabled ( disabled ) ;
153
+ const hasSelection = ( ) => {
154
+ const selection = this . tool . getSelection ( ) ;
155
+ return ! ! selection && selection . getSelectedItemCount ( ) > 0 ;
150
156
} ;
151
- updateDisabled ( true ) ;
157
+ this . hasSelectionValue = MutableReactiveValue . fromInitialValue ( hasSelection ( ) ) ;
152
158
153
159
// Enable/disable actions based on whether items are selected
154
160
this . editor . notifier . on ( EditorEventType . ToolUpdated , ( toolEvt ) => {
@@ -157,13 +163,13 @@ export default class SelectionToolWidget extends BaseToolWidget {
157
163
}
158
164
159
165
if ( toolEvt . tool === this . tool ) {
160
- const selection = this . tool . getSelection ( ) ;
161
- const hasSelection = selection && selection . getSelectedItemCount ( ) > 0 ;
162
-
163
- updateDisabled ( ! hasSelection ) ;
166
+ this . hasSelectionValue . set ( hasSelection ( ) ) ;
164
167
this . updateFormatMenu ( ) ;
165
168
}
166
169
} ) ;
170
+ tool . modeValue . onUpdate ( ( ) => {
171
+ this . updateIcon ( ) ;
172
+ } ) ;
167
173
}
168
174
169
175
private resizeImageToSelection ( ) {
@@ -195,22 +201,86 @@ export default class SelectionToolWidget extends BaseToolWidget {
195
201
}
196
202
197
203
protected createIcon ( ) : Element {
198
- return this . editor . icons . makeSelectionIcon ( ) ;
204
+ return this . editor . icons . makeSelectionIcon ( this . tool . modeValue . get ( ) ) ;
199
205
}
200
206
201
207
protected override getHelpText ( ) : string {
202
208
return this . localizationTable . selectionDropdown__baseHelpText ;
203
209
}
204
210
211
+ protected createSelectionActions ( helpDisplay ?: HelpDisplay ) {
212
+ const icons = this . editor . icons ;
213
+ const grid = makeButtonGrid (
214
+ [
215
+ {
216
+ icon : ( ) => icons . makeDeleteSelectionIcon ( ) ,
217
+ label : this . localizationTable . deleteSelection ,
218
+ onCreated : ( button ) => {
219
+ helpDisplay ?. registerTextHelpForElement (
220
+ button ,
221
+ this . localizationTable . selectionDropdown__deleteHelpText ,
222
+ ) ;
223
+ } ,
224
+ onClick : ( ) => {
225
+ const selection = this . tool . getSelection ( ) ;
226
+ this . editor . dispatch ( selection ! . deleteSelectedObjects ( ) ) ;
227
+ this . tool . clearSelection ( ) ;
228
+ } ,
229
+ enabled : this . hasSelectionValue ,
230
+ } ,
231
+ {
232
+ icon : ( ) => icons . makeDuplicateSelectionIcon ( ) ,
233
+ label : this . localizationTable . duplicateSelection ,
234
+ onCreated : ( button ) => {
235
+ helpDisplay ?. registerTextHelpForElement (
236
+ button ,
237
+ this . localizationTable . selectionDropdown__duplicateHelpText ,
238
+ ) ;
239
+ } ,
240
+ onClick : async ( ) => {
241
+ const selection = this . tool . getSelection ( ) ;
242
+ const command = await selection ?. duplicateSelectedObjects ( ) ;
243
+ if ( command ) {
244
+ this . editor . dispatch ( command ) ;
245
+ }
246
+ } ,
247
+ enabled : this . hasSelectionValue ,
248
+ } ,
249
+ {
250
+ icon : ( ) => icons . makeResizeImageToSelectionIcon ( ) ,
251
+ label : this . localizationTable . resizeImageToSelection ,
252
+ onCreated : ( button ) => {
253
+ helpDisplay ?. registerTextHelpForElement (
254
+ button ,
255
+ this . localizationTable . selectionDropdown__resizeToHelpText ,
256
+ ) ;
257
+ } ,
258
+ onClick : ( ) => {
259
+ this . resizeImageToSelection ( ) ;
260
+ } ,
261
+ enabled : this . hasSelectionValue ,
262
+ } ,
263
+ ] ,
264
+ 3 ,
265
+ ) ;
266
+
267
+ return { container : grid . container } ;
268
+ }
269
+
205
270
protected override fillDropdown ( dropdown : HTMLElement , helpDisplay ?: HelpDisplay ) : boolean {
206
271
super . fillDropdown ( dropdown , helpDisplay ) ;
207
272
208
273
const controlsContainer = document . createElement ( 'div' ) ;
209
274
controlsContainer . classList . add ( `${ toolbarCSSPrefix } nonbutton-controls-main-list` ) ;
210
275
dropdown . appendChild ( controlsContainer ) ;
211
276
212
- makeSeparator ( this . localizationTable . reformatSelection ) . addTo ( controlsContainer ) ;
277
+ // Actions (duplicate, delete, etc.)
278
+ makeSeparator ( ) . addTo ( controlsContainer ) ;
279
+ const actions = this . createSelectionActions ( helpDisplay ) ;
280
+ controlsContainer . appendChild ( actions . container ) ;
213
281
282
+ // Formatting
283
+ makeSeparator ( this . localizationTable . reformatSelection ) . addTo ( controlsContainer ) ;
214
284
const formatMenu = makeFormatMenu ( this . editor , this . tool , this . localizationTable ) ;
215
285
formatMenu . addTo ( controlsContainer ) ;
216
286
this . updateFormatMenu = ( ) => formatMenu . update ( ) ;
@@ -223,4 +293,20 @@ export default class SelectionToolWidget extends BaseToolWidget {
223
293
224
294
return true ;
225
295
}
296
+
297
+ public override serializeState ( ) : SavedToolbuttonState {
298
+ return {
299
+ ...super . serializeState ( ) ,
300
+ selectionMode : this . tool . modeValue . get ( ) ,
301
+ } ;
302
+ }
303
+
304
+ public override deserializeFrom ( state : SavedToolbuttonState ) : void {
305
+ super . deserializeFrom ( state ) ;
306
+
307
+ const isValidSelectionMode = Object . values ( SelectionMode ) . includes ( state . selectionMode ) ;
308
+ if ( isValidSelectionMode ) {
309
+ this . tool . modeValue . set ( state . selectionMode ) ;
310
+ }
311
+ }
226
312
}
0 commit comments