@janelia-flyem/neuroglancer
Advanced tools
Comparing version 2.34.3 to 2.35.0
@@ -60,2 +60,3 @@ import _Map from 'babel-runtime/core-js/map'; | ||
import { setClipboard } from './util/clipboard'; | ||
import { registerSegmentSelectTools } from './ui/segment_select_tools'; | ||
const SELECTED_ALPHA_JSON_KEY = 'selectedAlpha'; | ||
@@ -746,2 +747,3 @@ const NOT_SELECTED_ALPHA_JSON_KEY = 'notSelectedAlpha'; | ||
registerSegmentSplitMergeTools(); | ||
registerSegmentSelectTools(); | ||
//# sourceMappingURL=segmentation_user_layer.js.map |
@@ -36,3 +36,3 @@ /** | ||
const uppercase = String.fromCharCode(65 + i); | ||
map.set(`shift+key${lowercase}`, `tool-${uppercase}`); | ||
map.set(`alt?+control?+shift+key${lowercase}`, `tool-${uppercase}`); | ||
} | ||
@@ -39,0 +39,0 @@ map.set('keyn', 'add-layer'); |
@@ -44,2 +44,3 @@ import _Object$assign from 'babel-runtime/core-js/object/assign'; | ||
import { ANNOTATE_MERGE_SEGMENTS_TOOL_ID, ANNOTATE_SPLIT_SEGMENTS_TOOL_ID } from './segment_split_merge_tools'; | ||
import { SELECT_SEGMENTS_TOOLS_ID } from './segment_select_tools'; | ||
const tempUint64 = new Uint64(); | ||
@@ -703,2 +704,10 @@ class SegmentListSource extends RefCounted { | ||
})).element); | ||
const toolbox = document.createElement('div'); | ||
toolbox.className = 'neuroglancer-segmentation-toolbox'; | ||
toolbox.appendChild(makeToolButton(this, layer, { | ||
toolJson: SELECT_SEGMENTS_TOOLS_ID, | ||
label: 'Select', | ||
title: 'Select/Deselect segments' | ||
})); | ||
element.appendChild(toolbox); | ||
const queryElement = document.createElement('input'); | ||
@@ -705,0 +714,0 @@ queryElement.classList.add('neuroglancer-segment-list-query'); |
@@ -35,2 +35,3 @@ | ||
'at:shift?+mousedown0': { action: 'split-segments' }, | ||
'at:shift?+alt+mousedown0': { action: 'split-and-select-segments' }, | ||
'at:shift?+mousedown2': { action: 'set-anchor' } | ||
@@ -342,26 +343,34 @@ }); | ||
activation.registerDisposer(this.layer.anchorSegment.changed.add(debouncedUpdateStatus)); | ||
activation.bindAction('split-segments', event => { | ||
event.stopPropagation(); | ||
(async () => { | ||
const graph = segmentationGroupState.graph.value; | ||
const splitSegments = async select => { | ||
const graph = segmentationGroupState.graph.value; | ||
if (graph === undefined) return; | ||
if (graph === undefined) return; | ||
var _getSplitRequest2 = getSplitRequest(); | ||
var _getSplitRequest2 = getSplitRequest(); | ||
const anchorSegment = _getSplitRequest2.anchorSegment, | ||
otherSegment = _getSplitRequest2.otherSegment, | ||
error = _getSplitRequest2.error; | ||
const anchorSegment = _getSplitRequest2.anchorSegment, | ||
otherSegment = _getSplitRequest2.otherSegment, | ||
error = _getSplitRequest2.error; | ||
if (anchorSegment === undefined || otherSegment === undefined || error !== undefined) { | ||
return; | ||
if (anchorSegment === undefined || otherSegment === undefined || error !== undefined) { | ||
return; | ||
} | ||
try { | ||
await graph.split(anchorSegment, otherSegment); | ||
if (select) { | ||
segmentationGroupState.visibleSegments.add(segmentationGroupState.segmentEquivalences.get(otherSegment)); | ||
} | ||
try { | ||
await graph.split(anchorSegment, otherSegment); | ||
StatusMessage.showTemporaryMessage(`Split performed`); | ||
} catch (e) { | ||
StatusMessage.showTemporaryMessage(`Split failed: ${e}`); | ||
} | ||
})(); | ||
StatusMessage.showTemporaryMessage(`Split performed`); | ||
} catch (e) { | ||
StatusMessage.showTemporaryMessage(`Split failed: ${e}`); | ||
} | ||
}; | ||
activation.bindAction('split-segments', event => { | ||
event.stopPropagation(); | ||
splitSegments( /*select=*/false); | ||
}); | ||
activation.bindAction('split-and-select-segments', event => { | ||
event.stopPropagation(); | ||
splitSegments( /*select=*/true); | ||
}); | ||
activation.bindAction('set-anchor', event => { | ||
@@ -368,0 +377,0 @@ event.stopPropagation(); |
@@ -44,7 +44,13 @@ import _Object$entries from 'babel-runtime/core-js/object/entries'; | ||
} | ||
cancel() { | ||
if (this == this.tool.layer.manager.root.toolBinder.activeTool_) { | ||
this.tool.layer.manager.root.toolBinder.deactivate_(); | ||
} | ||
} | ||
} | ||
export class Tool extends RefCounted { | ||
constructor(layer) { | ||
constructor(layer, toggle = false) { | ||
super(); | ||
this.layer = layer; | ||
this.toggle = toggle; | ||
this.changed = new Signal(); | ||
@@ -179,7 +185,9 @@ this.keyBinding = undefined; | ||
export class ToolBinder extends RefCounted { | ||
constructor() { | ||
super(...arguments); | ||
constructor(inputEventMapBinder) { | ||
super(); | ||
this.inputEventMapBinder = inputEventMapBinder; | ||
this.bindings = new _Map(); | ||
this.changed = new Signal(); | ||
this.debounceDeactivate = this.registerCancellable(debounce(() => this.deactivate(), 1)); | ||
this.debounceDeactivate = this.registerCancellable(debounce(() => this.deactivate_(), 100)); | ||
this.debounceReactivate = this.registerCancellable(debounce(() => this.reactivateQueuedTool(), 100)); | ||
} | ||
@@ -222,43 +230,68 @@ get(key) { | ||
} | ||
activate(key, inputEventMapBinder) { | ||
var _a; | ||
activate(key) { | ||
const tool = this.get(key); | ||
if (tool === undefined) { | ||
this.deactivate(); | ||
this.deactivate_(); | ||
return; | ||
} | ||
this.debounceDeactivate.cancel(); | ||
if (tool === ((_a = this.activeTool) === null || _a === void 0 ? void 0 : _a.tool)) { | ||
this.debounceReactivate.cancel(); | ||
const activeTool = this.activeTool_; | ||
if (tool === (activeTool === null || activeTool === void 0 ? void 0 : activeTool.tool)) { | ||
if (tool.toggle) { | ||
this.deactivate_(); | ||
} | ||
return; | ||
} else if (activeTool !== undefined) { | ||
if (activeTool.tool.toggle && !tool.toggle) { | ||
this.queuedTool = activeTool.tool; | ||
} | ||
this.deactivate_(); | ||
} | ||
const activation = new ToolActivation(tool, inputEventMapBinder); | ||
this.activeTool = activation; | ||
const expectedCode = `Key${key}`; | ||
activation.registerEventListener(window, 'keyup', event => { | ||
if (event.code === expectedCode) { | ||
const activation = new ToolActivation(tool, this.inputEventMapBinder); | ||
this.activeTool_ = activation; | ||
if (!tool.toggle) { | ||
const expectedCode = `Key${key}`; | ||
activation.registerEventListener(window, 'keyup', event => { | ||
if (event.code === expectedCode) { | ||
this.debounceDeactivate(); | ||
this.debounceReactivate(); | ||
} | ||
}); | ||
activation.registerEventListener(window, 'blur', () => { | ||
this.debounceDeactivate(); | ||
} | ||
}); | ||
activation.registerEventListener(window, 'blur', () => { | ||
this.debounceDeactivate(); | ||
}); | ||
this.debounceReactivate(); | ||
}); | ||
} | ||
tool.activate(activation); | ||
return tool; | ||
} | ||
reactivateQueuedTool() { | ||
if (this.queuedTool) { | ||
const activation = new ToolActivation(this.queuedTool, this.inputEventMapBinder); | ||
this.activeTool_ = activation; | ||
this.queuedTool.activate(activation); | ||
this.queuedTool = undefined; | ||
} | ||
} | ||
destroyTool(tool) { | ||
var _a; | ||
if (((_a = this.activeTool) === null || _a === void 0 ? void 0 : _a.tool) === tool) { | ||
this.deactivate(); | ||
if (this.queuedTool === tool) { | ||
this.queuedTool = undefined; | ||
} | ||
if (((_a = this.activeTool_) === null || _a === void 0 ? void 0 : _a.tool) === tool) { | ||
this.deactivate_(); | ||
} | ||
tool.dispose(); | ||
} | ||
disposed() { | ||
this.deactivate(); | ||
this.deactivate_(); | ||
super.disposed(); | ||
} | ||
deactivate() { | ||
deactivate_() { | ||
// For internal use only- should only be called by ToolBinder and ToolActivation.cancel() | ||
this.debounceDeactivate.cancel(); | ||
const activation = this.activeTool; | ||
const activation = this.activeTool_; | ||
if (activation === undefined) return; | ||
this.activeTool = undefined; | ||
this.activeTool_ = undefined; | ||
activation.dispose(); | ||
@@ -265,0 +298,0 @@ } |
@@ -21,4 +21,12 @@ import _Set from 'babel-runtime/core-js/set'; | ||
// This is based on goog/ui/keyboardshortcuthandler.js in the Google Closure library. | ||
import { WatchableValue } from '../trackable_value'; | ||
import { RefCounted } from './disposable'; | ||
import { dispatchEventWithModifiers, EventActionMap, registerActionListener } from './event_action_map'; | ||
import { dispatchEventWithModifiers, EventActionMap, registerActionListener, getEventModifierMask } from './event_action_map'; | ||
export const globalModifiers = new WatchableValue(0); | ||
window.addEventListener('keydown', event => { | ||
globalModifiers.value = getEventModifierMask(event); | ||
}); | ||
window.addEventListener('keyup', event => { | ||
globalModifiers.value = getEventModifierMask(event); | ||
}); | ||
const globalKeys = new _Set(['f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12', 'escape', 'pause']); | ||
@@ -25,0 +33,0 @@ const DEFAULT_TEXT_INPUTS = new _Set(['color', 'date', 'datetime', 'datetime-local', 'email', 'month', 'number', 'password', 'search', 'tel', 'text', 'time', 'url', 'week']); |
@@ -225,3 +225,2 @@ import _Object$assign from 'babel-runtime/core-js/object/assign'; | ||
this.layerListPanelState = new LayerListPanelState(); | ||
this.toolBinder = this.registerDisposer(new ToolBinder()); | ||
this.resetInitiated = new NullarySignal(); | ||
@@ -244,2 +243,3 @@ this.makeUrlFromState = state => { | ||
}; | ||
this.toolBinder = this.registerDisposer(new ToolBinder(this.toolInputEventMapBinder)); | ||
var _options$dataContext = options.dataContext; | ||
@@ -630,3 +630,3 @@ const dataContext = _options$dataContext === undefined ? new DataManagementContext(display.gl, display, options.bundleRoot) : _options$dataContext; | ||
activateTool(uppercase) { | ||
this.toolBinder.activate(uppercase, this.toolInputEventMapBinder); | ||
this.toolBinder.activate(uppercase); | ||
} | ||
@@ -633,0 +633,0 @@ editJsonState() { |
@@ -5,3 +5,3 @@ { | ||
"license": "Apache-2.0", | ||
"version": "2.34.3", | ||
"version": "2.35.0", | ||
"main": "dist/module/main_module.js", | ||
@@ -8,0 +8,0 @@ "repository": { |
@@ -62,3 +62,4 @@ /** | ||
import {registerLayerShaderControlsTool} from 'neuroglancer/widget/shader_controls'; | ||
import { setClipboard } from './util/clipboard'; | ||
import { setClipboard } from 'neuroglancer/util/clipboard'; | ||
import {registerSegmentSelectTools} from 'neuroglancer/ui/segment_select_tools'; | ||
@@ -980,1 +981,2 @@ const SELECTED_ALPHA_JSON_KEY = 'selectedAlpha'; | ||
registerSegmentSplitMergeTools(); | ||
registerSegmentSelectTools(); |
@@ -42,3 +42,3 @@ /** | ||
const uppercase = String.fromCharCode(65 + i); | ||
map.set(`shift+key${lowercase}`, `tool-${uppercase}`); | ||
map.set(`alt?+control?+shift+key${lowercase}`, `tool-${uppercase}`); | ||
} | ||
@@ -45,0 +45,0 @@ |
@@ -44,2 +44,3 @@ /** | ||
import {ANNOTATE_MERGE_SEGMENTS_TOOL_ID, ANNOTATE_SPLIT_SEGMENTS_TOOL_ID} from 'neuroglancer/ui/segment_split_merge_tools'; | ||
import { SELECT_SEGMENTS_TOOLS_ID } from 'neuroglancer/ui/segment_select_tools'; | ||
@@ -802,2 +803,13 @@ const tempUint64 = new Uint64(); | ||
.element); | ||
const toolbox = document.createElement('div'); | ||
toolbox.className ='neuroglancer-segmentation-toolbox'; | ||
toolbox.appendChild(makeToolButton(this, layer, { | ||
toolJson: SELECT_SEGMENTS_TOOLS_ID, | ||
label: 'Select', | ||
title: 'Select/Deselect segments' | ||
})); | ||
element.appendChild(toolbox); | ||
const queryElement = document.createElement('input'); | ||
@@ -804,0 +816,0 @@ queryElement.classList.add('neuroglancer-segment-list-query'); |
@@ -40,2 +40,3 @@ /** | ||
'at:shift?+mousedown0': {action: 'split-segments'}, | ||
'at:shift?+alt+mousedown0': {action: 'split-and-select-segments'}, | ||
'at:shift?+mousedown2': {action: 'set-anchor'}, | ||
@@ -342,19 +343,29 @@ }); | ||
const splitSegments = async (select: boolean) => { | ||
const {graph: {value: graph}} = segmentationGroupState; | ||
if (graph === undefined) return; | ||
const {anchorSegment, otherSegment, error} = getSplitRequest(); | ||
if (anchorSegment === undefined || otherSegment === undefined || error !== undefined) { | ||
return; | ||
} | ||
try { | ||
await graph.split(anchorSegment, otherSegment); | ||
if (select) { | ||
segmentationGroupState.visibleSegments.add( | ||
segmentationGroupState.segmentEquivalences.get(otherSegment)); | ||
} | ||
StatusMessage.showTemporaryMessage(`Split performed`); | ||
} catch (e) { | ||
StatusMessage.showTemporaryMessage(`Split failed: ${e}`); | ||
} | ||
}; | ||
activation.bindAction('split-segments', event => { | ||
event.stopPropagation(); | ||
(async () => { | ||
const {graph: {value: graph}} = segmentationGroupState; | ||
if (graph === undefined) return; | ||
const {anchorSegment, otherSegment, error} = getSplitRequest(); | ||
if (anchorSegment === undefined || otherSegment === undefined || error !== undefined) { | ||
return; | ||
} | ||
try { | ||
await graph.split(anchorSegment, otherSegment); | ||
StatusMessage.showTemporaryMessage(`Split performed`); | ||
} catch (e) { | ||
StatusMessage.showTemporaryMessage(`Split failed: ${e}`); | ||
} | ||
})(); | ||
splitSegments(/*select=*/false); | ||
}); | ||
activation.bindAction('split-and-select-segments', event => { | ||
event.stopPropagation(); | ||
splitSegments(/*select=*/true); | ||
}); | ||
activation.bindAction('set-anchor', event => { | ||
@@ -361,0 +372,0 @@ event.stopPropagation(); |
@@ -48,2 +48,7 @@ /** | ||
} | ||
cancel() { | ||
if (this == this.tool.layer.manager.root.toolBinder.activeTool_) { | ||
this.tool.layer.manager.root.toolBinder.deactivate_(); | ||
} | ||
} | ||
} | ||
@@ -54,3 +59,3 @@ | ||
keyBinding: string|undefined = undefined; | ||
constructor(public layer: LayerType) { | ||
constructor(public layer: LayerType, public toggle: boolean = false) { | ||
super(); | ||
@@ -214,5 +219,11 @@ } | ||
changed = new Signal(); | ||
private activeTool: Owned<ToolActivation>|undefined; | ||
private debounceDeactivate = this.registerCancellable(debounce(() => this.deactivate(), 1)); | ||
activeTool_: Owned<ToolActivation>|undefined; // For internal use only- should only be called by ToolBinder and ToolActivation.cancel() | ||
private queuedTool: Tool|undefined; | ||
private debounceDeactivate = this.registerCancellable(debounce(() => this.deactivate_(), 100)); | ||
private debounceReactivate = this.registerCancellable(debounce(() => this.reactivateQueuedTool(), 100)); | ||
constructor(private inputEventMapBinder: InputEventMapBinder) { | ||
super(); | ||
} | ||
get(key: string): Borrowed<Tool>|undefined { | ||
@@ -255,23 +266,38 @@ return this.bindings.get(key); | ||
activate(key: string, inputEventMapBinder: InputEventMapBinder): Borrowed<Tool>|undefined { | ||
activate(key: string): Borrowed<Tool>|undefined { | ||
const tool = this.get(key); | ||
if (tool === undefined) { | ||
this.deactivate(); | ||
this.deactivate_(); | ||
return; | ||
} | ||
this.debounceDeactivate.cancel(); | ||
if (tool === this.activeTool?.tool) { | ||
this.debounceReactivate.cancel(); | ||
const activeTool = this.activeTool_; | ||
if (tool === activeTool?.tool) { | ||
if (tool.toggle) { | ||
this.deactivate_(); | ||
} | ||
return; | ||
} | ||
const activation = new ToolActivation(tool, inputEventMapBinder); | ||
this.activeTool = activation; | ||
const expectedCode = `Key${key}`; | ||
activation.registerEventListener(window, 'keyup', (event: KeyboardEvent) => { | ||
if (event.code === expectedCode) { | ||
else if (activeTool !== undefined) { | ||
if (activeTool.tool.toggle && !tool.toggle) { | ||
this.queuedTool = activeTool.tool; | ||
} | ||
this.deactivate_(); | ||
} | ||
const activation = new ToolActivation(tool, this.inputEventMapBinder); | ||
this.activeTool_ = activation; | ||
if (!tool.toggle) { | ||
const expectedCode = `Key${key}`; | ||
activation.registerEventListener(window, 'keyup', (event: KeyboardEvent) => { | ||
if (event.code === expectedCode) { | ||
this.debounceDeactivate(); | ||
this.debounceReactivate(); | ||
} | ||
}); | ||
activation.registerEventListener(window, 'blur', () => { | ||
this.debounceDeactivate(); | ||
} | ||
}); | ||
activation.registerEventListener(window, 'blur', () => { | ||
this.debounceDeactivate(); | ||
}); | ||
this.debounceReactivate(); | ||
}); | ||
} | ||
tool.activate(activation); | ||
@@ -281,6 +307,18 @@ return tool; | ||
private reactivateQueuedTool() { | ||
if (this.queuedTool) { | ||
const activation = new ToolActivation(this.queuedTool, this.inputEventMapBinder); | ||
this.activeTool_ = activation; | ||
this.queuedTool.activate(activation); | ||
this.queuedTool = undefined; | ||
} | ||
} | ||
destroyTool(tool: Owned<Tool>) { | ||
if (this.activeTool?.tool === tool) { | ||
this.deactivate(); | ||
if (this.queuedTool === tool) { | ||
this.queuedTool = undefined; | ||
} | ||
if (this.activeTool_?.tool === tool) { | ||
this.deactivate_(); | ||
} | ||
tool.dispose(); | ||
@@ -290,11 +328,12 @@ } | ||
disposed() { | ||
this.deactivate(); | ||
this.deactivate_(); | ||
super.disposed(); | ||
} | ||
private deactivate() { | ||
deactivate_() { | ||
// For internal use only- should only be called by ToolBinder and ToolActivation.cancel() | ||
this.debounceDeactivate.cancel(); | ||
const activation = this.activeTool; | ||
const activation = this.activeTool_; | ||
if (activation === undefined) return; | ||
this.activeTool = undefined; | ||
this.activeTool_ = undefined; | ||
activation.dispose(); | ||
@@ -301,0 +340,0 @@ } |
@@ -23,5 +23,10 @@ /** | ||
import {WatchableValue} from 'neuroglancer/trackable_value'; | ||
import {RefCounted} from 'neuroglancer/util/disposable'; | ||
import {ActionEvent, dispatchEventWithModifiers, EventActionMap, EventActionMapInterface, registerActionListener} from 'neuroglancer/util/event_action_map'; | ||
import {ActionEvent, dispatchEventWithModifiers, EventActionMap, EventActionMapInterface, registerActionListener, getEventModifierMask} from 'neuroglancer/util/event_action_map'; | ||
export const globalModifiers = new WatchableValue<number>(0); | ||
window.addEventListener('keydown', event => { globalModifiers.value = getEventModifierMask(event); }); | ||
window.addEventListener('keyup', event => { globalModifiers.value = getEventModifierMask(event); }); | ||
const globalKeys = new Set( | ||
@@ -28,0 +33,0 @@ ['f1', 'f2', 'f3', 'f4', 'f5', 'f6', 'f7', 'f8', 'f9', 'f10', 'f11', 'f12', 'escape', 'pause']); |
@@ -312,3 +312,2 @@ /** | ||
layerListPanelState = new LayerListPanelState(); | ||
toolBinder = this.registerDisposer(new ToolBinder()); | ||
@@ -839,5 +838,7 @@ resetInitiated = new NullarySignal(); | ||
}; | ||
private toolBinder = this.registerDisposer(new ToolBinder(this.toolInputEventMapBinder)); | ||
activateTool(uppercase: string) { | ||
this.toolBinder.activate(uppercase, this.toolInputEventMapBinder); | ||
this.toolBinder.activate(uppercase); | ||
} | ||
@@ -844,0 +845,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
9348020
1085
201694