|
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | 16 |
|
| 17 | +import type { UserLayer, UserLayerConstructor } from "#src/layer/index.js"; |
| 18 | +import { layerTypes } from "#src/layer/index.js"; |
17 | 19 | import { StatusMessage } from "#src/status.js"; |
18 | 20 | import { |
19 | 21 | bindDefaultCopyHandler, |
20 | 22 | bindDefaultPasteHandler, |
21 | 23 | } from "#src/ui/default_clipboard_handling.js"; |
22 | 24 | import { setDefaultInputEventBindings } from "#src/ui/default_input_event_bindings.js"; |
23 | 25 | import { makeDefaultViewer } from "#src/ui/default_viewer.js"; |
24 | | -import type { MinimalViewerOptions } from "#src/ui/minimal_viewer.js"; |
25 | 26 | import { bindTitle } from "#src/ui/title.js"; |
| 27 | +import type { Tool } from "#src/ui/tool.js"; |
| 28 | +import { restoreTool } from "#src/ui/tool.js"; |
26 | 29 | import { UrlHashBinding } from "#src/ui/url_hash_binding.js"; |
| 30 | +import { |
| 31 | + verifyObject, |
| 32 | + verifyObjectProperty, |
| 33 | + verifyString, |
| 34 | +} from "#src/util/json.js"; |
27 | 35 |
|
28 | 36 | declare let NEUROGLANCER_DEFAULT_STATE_FRAGMENT: string | undefined; |
29 | 37 |
|
| 38 | +type CustomToolBinding = { |
| 39 | + layer: string; |
| 40 | + tool: unknown; |
| 41 | + provider?: string; |
| 42 | +}; |
| 43 | + |
| 44 | +type CustomBindings = { |
| 45 | + [key: string]: CustomToolBinding | string | boolean; |
| 46 | +}; |
| 47 | + |
| 48 | +declare const CUSTOM_BINDINGS: CustomBindings | undefined; |
| 49 | +export const hasCustomBindings = |
| 50 | + typeof CUSTOM_BINDINGS !== "undefined" && |
| 51 | + Object.keys(CUSTOM_BINDINGS).length > 0; |
| 52 | + |
30 | 53 | /** |
31 | 54 | * Sets up the default neuroglancer viewer. |
32 | 55 | */ |
33 | | -export function setupDefaultViewer(options?: Partial<MinimalViewerOptions>) { |
34 | | - const viewer = ((<any>window).viewer = makeDefaultViewer(options)); |
| 56 | +export function setupDefaultViewer() { |
| 57 | + const viewer = ((<any>window).viewer = makeDefaultViewer()); |
35 | 58 | setDefaultInputEventBindings(viewer.inputEventBindings); |
36 | 59 |
|
| 60 | + const bindNonLayerSpecificTool = ( |
| 61 | + obj: unknown, |
| 62 | + toolKey: string, |
| 63 | + desiredLayerType: UserLayerConstructor, |
| 64 | + desiredProvider?: string, |
| 65 | + ) => { |
| 66 | + let previousTool: Tool<object> | undefined; |
| 67 | + let previousLayer: UserLayer | undefined; |
| 68 | + if (typeof obj === "string") { |
| 69 | + obj = { type: obj }; |
| 70 | + } |
| 71 | + verifyObject(obj); |
| 72 | + const type = verifyObjectProperty(obj, "type", verifyString); |
| 73 | + viewer.bindAction(`tool-${type}`, () => { |
| 74 | + const acceptableLayers = viewer.layerManager.managedLayers.filter( |
| 75 | + (managedLayer) => { |
| 76 | + const correctLayerType = |
| 77 | + managedLayer.layer instanceof desiredLayerType; |
| 78 | + if (desiredProvider && correctLayerType) { |
| 79 | + for (const dataSource of managedLayer.layer?.dataSources || []) { |
| 80 | + const protocol = viewer.dataSourceProvider.getProvider( |
| 81 | + dataSource.spec.url, |
| 82 | + )[2]; |
| 83 | + if (protocol === desiredProvider) { |
| 84 | + return true; |
| 85 | + } |
| 86 | + } |
| 87 | + return false; |
| 88 | + } else { |
| 89 | + return correctLayerType; |
| 90 | + } |
| 91 | + }, |
| 92 | + ); |
| 93 | + if (acceptableLayers.length > 0) { |
| 94 | + const firstLayer = acceptableLayers[0].layer; |
| 95 | + if (firstLayer) { |
| 96 | + if (firstLayer !== previousLayer) { |
| 97 | + previousTool = restoreTool(firstLayer, obj); |
| 98 | + previousLayer = firstLayer; |
| 99 | + } |
| 100 | + if (previousTool) { |
| 101 | + viewer.activateTool(toolKey, previousTool); |
| 102 | + } |
| 103 | + } |
| 104 | + } |
| 105 | + }); |
| 106 | + }; |
| 107 | + |
| 108 | + if (hasCustomBindings) { |
| 109 | + for (const [key, val] of Object.entries(CUSTOM_BINDINGS!)) { |
| 110 | + if (typeof val === "string") { |
| 111 | + viewer.inputEventBindings.global.set(key, val); |
| 112 | + } else if (typeof val === "boolean") { |
| 113 | + if (!val) { |
| 114 | + viewer.inputEventBindings.global.delete(key); |
| 115 | + viewer.inputEventBindings.global.parents.map((parent) => |
| 116 | + parent.delete(key), |
| 117 | + ); |
| 118 | + } |
| 119 | + } else { |
| 120 | + viewer.inputEventBindings.global.set(key, `tool-${val.tool}`); |
| 121 | + const layerConstructor = layerTypes.get(val.layer); |
| 122 | + if (layerConstructor) { |
| 123 | + const toolKey = key.charAt(key.length - 1).toUpperCase(); |
| 124 | + bindNonLayerSpecificTool( |
| 125 | + val.tool, |
| 126 | + toolKey, |
| 127 | + layerConstructor, |
| 128 | + val.provider, |
| 129 | + ); |
| 130 | + } |
| 131 | + } |
| 132 | + } |
| 133 | + } |
| 134 | + |
37 | 135 | const hashBinding = viewer.registerDisposer( |
38 | 136 | new UrlHashBinding( |
39 | 137 | viewer.state, |
|
0 commit comments