Skip to content

Commit 466ce63

Browse files
authored
Allow to switch to fill or pick segment tool when eraser is active (#8314)
* implement shift and ctrl-shift modifier for the eraser (switch to pick or fill tool) * tweak highlighted color in tree and segments tab for light theme * update changelog * prepare merge for import sorting pr
1 parent e007e41 commit 466ce63

File tree

6 files changed

+58
-23
lines changed

6 files changed

+58
-23
lines changed

CHANGELOG.unreleased.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ For upgrade instructions, please check the [migration guide](MIGRATIONS.released
1717
- Added the option for "Selective Segment Visibility" for segmentation layers. Select this option in the left sidebar to only show segments that are currently active or hovered. [#8281](https://github.com/scalableminds/webknossos/pull/8281)
1818
- A segment can be activated with doubleclick now. [#8281](https://github.com/scalableminds/webknossos/pull/8281)
1919
- It is now possible to select the magnification of the layers on which an AI model will be trained. [#8266](https://github.com/scalableminds/webknossos/pull/8266)
20+
- When the eraser tool is active, one can switch temporarily to the fill-segment tool by pressing shift and ctrl. Only pressing shift, switches to the pick-segment tool. [#8314](https://github.com/scalableminds/webknossos/pull/8314)
2021
- Enabled auto sorting of Typescript imports in Biome linter. [#8313](https://github.com/scalableminds/webknossos/pull/8313)
2122

22-
2323
### Changed
2424
- Renamed "resolution" to "magnification" in more places within the codebase, including local variables. [#8168](https://github.com/scalableminds/webknossos/pull/8168)
2525
- Layer names are now allowed to contain `$` as special characters. [#8241](https://github.com/scalableminds/webknossos/pull/8241)

frontend/javascripts/oxalis/controller/combinations/tool_controls.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -497,12 +497,26 @@ export class EraseTool {
497497
leftDownMove: (_delta: Point2, pos: Point2) => {
498498
VolumeHandlers.handleMoveForDrawOrErase(pos);
499499
},
500-
leftMouseDown: (pos: Point2, plane: OrthoView, _event: MouseEvent) => {
500+
leftMouseDown: (pos: Point2, plane: OrthoView, event: MouseEvent) => {
501+
if (event.shiftKey || event.ctrlKey || event.metaKey) {
502+
return;
503+
}
504+
501505
VolumeHandlers.handleEraseStart(pos, plane);
502506
},
503507
leftMouseUp: () => {
504508
VolumeHandlers.handleEndForDrawOrErase();
505509
},
510+
leftClick: (pos: Point2, plane: OrthoView, event: MouseEvent) => {
511+
const isControlOrMetaPressed = event.ctrlKey || event.metaKey;
512+
if (event.shiftKey) {
513+
if (isControlOrMetaPressed) {
514+
VolumeHandlers.handleFloodFill(pos, plane);
515+
} else {
516+
VolumeHandlers.handlePickCell(pos);
517+
}
518+
}
519+
},
506520
rightClick: (pos: Point2, plane: OrthoView, event: MouseEvent, isTouch: boolean) => {
507521
SkeletonHandlers.handleOpenContextMenu(planeView, pos, plane, isTouch, event);
508522
},

frontend/javascripts/oxalis/model/accessors/tool_accessor.ts

+25-16
Original file line numberDiff line numberDiff line change
@@ -350,47 +350,56 @@ export const getDisabledInfoForTools = reuseInstanceOnEquality(_getDisabledInfoF
350350
export function adaptActiveToolToShortcuts(
351351
activeTool: AnnotationTool,
352352
isShiftPressed: boolean,
353-
isControlPressed: boolean,
353+
isControlOrMetaPressed: boolean,
354354
isAltPressed: boolean,
355355
): AnnotationTool {
356-
if (!isShiftPressed && !isControlPressed && !isAltPressed) {
356+
if (!isShiftPressed && !isControlOrMetaPressed && !isAltPressed) {
357357
// No modifier is pressed
358358
return activeTool;
359359
}
360360

361361
if (
362362
activeTool === AnnotationToolEnum.MOVE ||
363-
activeTool === AnnotationToolEnum.ERASE_BRUSH ||
364-
activeTool === AnnotationToolEnum.ERASE_TRACE ||
365363
activeTool === AnnotationToolEnum.QUICK_SELECT ||
366364
activeTool === AnnotationToolEnum.PROOFREAD ||
367365
activeTool === AnnotationToolEnum.LINE_MEASUREMENT ||
368366
activeTool === AnnotationToolEnum.AREA_MEASUREMENT
369367
) {
370368
// These tools do not have any modifier-related behavior currently (except for ALT
371369
// which is already handled below)
370+
} else if (
371+
activeTool === AnnotationToolEnum.ERASE_BRUSH ||
372+
activeTool === AnnotationToolEnum.ERASE_TRACE
373+
) {
374+
if (isShiftPressed) {
375+
if (isControlOrMetaPressed) {
376+
return AnnotationToolEnum.FILL_CELL;
377+
} else {
378+
return AnnotationToolEnum.PICK_CELL;
379+
}
380+
}
372381
} else {
373382
if (activeTool === AnnotationToolEnum.SKELETON) {
374383
// The "skeleton" tool is not changed right now (since actions such as moving a node
375384
// don't have a dedicated tool). The only exception is "Alt" which switches to the move tool.
376-
if (isAltPressed && !isControlPressed && !isShiftPressed) {
385+
if (isAltPressed && !isControlOrMetaPressed && !isShiftPressed) {
377386
return AnnotationToolEnum.MOVE;
378387
}
379388

380389
return activeTool;
381390
}
382391

383-
if (isShiftPressed && !isControlPressed && !isAltPressed) {
384-
// Only shift is pressed. Switch to the picker
385-
return AnnotationToolEnum.PICK_CELL;
386-
}
387-
388-
if (isControlPressed && isShiftPressed && !isAltPressed) {
389-
// Control and shift switch to the eraser
390-
if (activeTool === AnnotationToolEnum.BRUSH) {
391-
return AnnotationToolEnum.ERASE_BRUSH;
392-
} else if (activeTool === AnnotationToolEnum.TRACE) {
393-
return AnnotationToolEnum.ERASE_TRACE;
392+
if (isShiftPressed && !isAltPressed) {
393+
if (!isControlOrMetaPressed) {
394+
// Only shift is pressed. Switch to the picker
395+
return AnnotationToolEnum.PICK_CELL;
396+
} else {
397+
// Control and shift switch to the eraser
398+
if (activeTool === AnnotationToolEnum.BRUSH) {
399+
return AnnotationToolEnum.ERASE_BRUSH;
400+
} else if (activeTool === AnnotationToolEnum.TRACE) {
401+
return AnnotationToolEnum.ERASE_TRACE;
402+
}
394403
}
395404
}
396405
}

frontend/javascripts/oxalis/model/sagas/volume/floodfill_saga.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@ import type {
1010
Vector2,
1111
Vector3,
1212
} from "oxalis/constants";
13-
import Constants, { FillModeEnum, Unicode } from "oxalis/constants";
13+
import Constants, { AnnotationToolEnum, FillModeEnum, Unicode } from "oxalis/constants";
1414

1515
import _ from "lodash";
1616
import { getDatasetBoundingBox, getMagInfo } from "oxalis/model/accessors/dataset_accessor";
1717
import { getActiveMagIndexForLayer } from "oxalis/model/accessors/flycam_accessor";
18+
import { getDisabledInfoForTools } from "oxalis/model/accessors/tool_accessor";
1819
import { enforceActiveVolumeTracing } from "oxalis/model/accessors/volumetracing_accessor";
1920
import { addUserBoundingBoxAction } from "oxalis/model/actions/annotation_actions";
2021
import { setBusyBlockingInfoAction } from "oxalis/model/actions/ui_actions";
@@ -117,8 +118,9 @@ function* getBoundingBoxForFloodFill(
117118

118119
function* handleFloodFill(floodFillAction: FloodFillAction): Saga<void> {
119120
const allowUpdate = yield* select((state) => state.tracing.restrictions.allowUpdate);
121+
const disabledInfosForTools = yield* select(getDisabledInfoForTools);
120122

121-
if (!allowUpdate) {
123+
if (!allowUpdate || disabledInfosForTools[AnnotationToolEnum.FILL_CELL].isDisabled) {
122124
return;
123125
}
124126

frontend/javascripts/oxalis/view/input_catcher.tsx

+7-2
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,20 @@ function InputCatcher({
140140
const activeTool = useSelector((state: OxalisState) => state.uiInformation.activeTool);
141141

142142
const isShiftPressed = useKeyPress("Shift");
143-
const isControlPressed = useKeyPress("ControlOrMeta");
143+
const isControlOrMetaPressed = useKeyPress("ControlOrMeta");
144144
const isAltPressed = useKeyPress("Alt");
145145

146146
const adaptedTool =
147147
viewportID === ArbitraryViews.arbitraryViewport
148148
? AnnotationToolEnum.SKELETON
149149
: viewportID === OrthoViews.TDView
150150
? AnnotationToolEnum.MOVE
151-
: adaptActiveToolToShortcuts(activeTool, isShiftPressed, isControlPressed, isAltPressed);
151+
: adaptActiveToolToShortcuts(
152+
activeTool,
153+
isShiftPressed,
154+
isControlOrMetaPressed,
155+
isAltPressed,
156+
);
152157

153158
return (
154159
<div

frontend/javascripts/theme.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ const globalDesignToken: Partial<AliasToken> = {
2828
'"Nunito", "Monospaced Number", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;',
2929
};
3030

31+
const lightGlobalToken = theme.getDesignToken({
32+
token: globalDesignToken,
33+
algorithm: theme.defaultAlgorithm,
34+
});
35+
3136
const darkGlobalToken = theme.getDesignToken({
3237
token: globalDesignToken,
3338
algorithm: theme.darkAlgorithm,
@@ -87,7 +92,7 @@ export function getAntdTheme(userTheme: Theme) {
8792
},
8893
Tree: {
8994
colorBgContainer: "transparent",
90-
directoryNodeSelectedBg: ColorWKBlue,
95+
nodeSelectedBg: lightGlobalToken.blue3,
9196
titleHeight: 20, // default is 24px,
9297
marginXXS: 2, // default is 4px; adjust to match checkboxes because of smaller titleHeight
9398
},

0 commit comments

Comments
 (0)