Skip to content

Commit

Permalink
feat(annotation): added keybinds for iterating through active annotat…
Browse files Browse the repository at this point in the history
…ion list, also pins and jumps to each annotation
  • Loading branch information
chrisj committed Aug 22, 2024
1 parent 9695a36 commit fe7b96d
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 14 deletions.
23 changes: 22 additions & 1 deletion src/layer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ import {
} from "#src/util/json.js";
import { MessageList } from "#src/util/message_list.js";
import type { AnyConstructor } from "#src/util/mixin.js";
import { NullarySignal } from "#src/util/signal.js";
import { NullarySignal, Signal } from "#src/util/signal.js";
import type { SignalBindingUpdater } from "#src/util/signal_binding_updater.js";
import {
addSignalBinding,
Expand Down Expand Up @@ -192,6 +192,27 @@ export class UserLayer extends RefCounted {

messages = new MessageList();

layerEventListeners = new Map<string, Signal>();

dispatchLayerEvent(type: string) {
this.layerEventListeners.get(type)?.dispatch();
}

registerLayerEvent(type: string, handler: () => void) {
const { layerEventListeners } = this;
let existingSignal = layerEventListeners.get(type);
if (!existingSignal) {
existingSignal = new Signal();
layerEventListeners.set(type, existingSignal);
}
const unregister = existingSignal.add(handler);
return () => {
const res = unregister();
// TODO delete from map? currently handlers is private
return res;
};
}

initializeSelectionState(state: this["selectionState"]) {
state.generation = -1;
state.localPositionValid = false;
Expand Down
70 changes: 57 additions & 13 deletions src/ui/annotations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,26 @@ interface AnnotationLayerViewAttachedState {
listOffset: number;
}

const moveToAnnotation = (
layer: UserLayer,
annotation: Annotation,
state: AnnotationLayerState,
) => {
const chunkTransform = state.chunkTransform.value as ChunkTransformParameters;
const { layerRank } = chunkTransform;
const chunkPosition = new Float32Array(layerRank);
const layerPosition = new Float32Array(layerRank);
getCenterPosition(chunkPosition, annotation);
matrix.transformPoint(
layerPosition,
chunkTransform.chunkToLayerTransform,
layerRank + 1,
chunkPosition,
layerRank,
);
setLayerPosition(layer, chunkTransform, layerPosition);
};

export class AnnotationLayerView extends Tab {
private previousSelectedState:
| {
Expand Down Expand Up @@ -456,7 +476,31 @@ export class AnnotationLayerView extends Tab {
this.virtualList.element.addEventListener("mouseleave", () => {
this.displayState.hoverState.value = undefined;
});

const changeSelectedIndex = (offset: number) => {
const selectedIndex = this.getSelectedAnnotationIndex();
if (selectedIndex === undefined) return;
const nextAnnotation = this.listElements[selectedIndex + offset];
if (nextAnnotation) {
const { state, annotation } = nextAnnotation;
this.layer.selectAnnotation(state, annotation.id, true);
moveToAnnotation(this.layer, annotation, state);
}
};
this.registerDisposer(
this.layer.registerLayerEvent("select-previous", () => {
// if (this.layer.panels.panels[0].selectedTab.value === "annotations") {
if (this.element.checkVisibility()) {
changeSelectedIndex(-1);
}
}),
);
this.registerDisposer(
this.layer.registerLayerEvent("select-next", () => {
if (this.element.checkVisibility()) {
changeSelectedIndex(1);
}
}),
);
const bindings = getDefaultAnnotationListBindings();
this.registerDisposer(
new MouseEventBinder(this.virtualList.element, bindings),
Expand Down Expand Up @@ -487,6 +531,17 @@ export class AnnotationLayerView extends Tab {
this.updateSelectionView();
}

private getSelectedAnnotationIndex() {
const { previousSelectedState: state } = this;
if (state === undefined) return;
const { annotationLayerState, annotationId } = state;
const attached = this.attachedAnnotationStates.get(annotationLayerState);
if (attached === undefined) return;
const index = attached.idToIndex.get(annotationId);
if (index === undefined) return;
return attached.listOffset + index;
}

private getRenderedAnnotationListElement(
state: AnnotationLayerState,
id: AnnotationId,
Expand Down Expand Up @@ -2196,18 +2251,7 @@ export function makeAnnotationListElement(
element.addEventListener("action:move-to-annotation", (event) => {
event.stopPropagation();
event.preventDefault();
const { layerRank } = chunkTransform;
const chunkPosition = new Float32Array(layerRank);
const layerPosition = new Float32Array(layerRank);
getCenterPosition(chunkPosition, annotation);
matrix.transformPoint(
layerPosition,
chunkTransform.chunkToLayerTransform,
layerRank + 1,
chunkPosition,
layerRank,
);
setLayerPosition(layer, chunkTransform, layerPosition);
moveToAnnotation(layer, annotation, state);
});
return [element, columnWidths];
}
3 changes: 3 additions & 0 deletions src/ui/default_input_event_bindings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ export function getDefaultGlobalBindings() {
map.set("space", "toggle-layout");
map.set("shift+space", "toggle-layout-alternative");
map.set("backslash", "toggle-show-statistics");

map.set("alt+arrowup", "select-previous");
map.set("alt+arrowdown", "select-next");
defaultGlobalBindings = map;
}
return defaultGlobalBindings;
Expand Down
24 changes: 24 additions & 0 deletions src/viewer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1028,6 +1028,30 @@ export class Viewer extends RefCounted implements ViewerState {
});
}

const sendEventToSelectedLayerTab = (type: string) => {
const elements = document.querySelectorAll(
'[data-neuroglancer-layer-panel-pinned="false"] .neuroglancer-stack-view > .neuroglancer-tab-content:not([style*="display: none"]):not([style*="display: none"]) > *',
);
for (const element of elements) {
const event = new Event(type);
console.log("sending", type, "to", element);
element.dispatchEvent(event);
}

const selectedLayer = this.selectedLayer.layer?.layer;
if (selectedLayer) {
selectedLayer.dispatchLayerEvent(type);
}
};

this.bindAction("select-previous", () => {
sendEventToSelectedLayerTab("select-previous");
});

this.bindAction("select-next", () => {
sendEventToSelectedLayerTab("select-next");
});

for (const action of ["select", "star"]) {
this.bindAction(action, () => {
this.mouseState.updateUnconditionally();
Expand Down

0 comments on commit fe7b96d

Please sign in to comment.