Skip to content
Snippets Groups Projects
Commit d9a1a2d2 authored by David Sehnal's avatar David Sehnal
Browse files

mol-plugin: interactivity tweaks

parent 47055f4c
No related branches found
No related tags found
No related merge requests found
......@@ -14,7 +14,7 @@ export const FocusLociOnSelect = PluginBehavior.create<{ minRadius: number, extr
category: 'interaction',
ctor: class extends PluginBehavior.Handler<{ minRadius: number, extraRadius: number }> {
register(): void {
this.subscribeObservable(this.ctx.events.canvas3d.click, ({ current, buttons, modifiers }) => {
this.subscribeObservable(this.ctx.behaviors.canvas3d.click, ({ current, buttons, modifiers }) => {
if (!this.ctx.canvas3d || buttons !== ButtonsType.Flag.Primary || !ModifiersKeys.areEqual(modifiers, ModifiersKeys.None)) return;
const sphere = Loci.getBoundingSphere(current.loci);
......
......@@ -26,7 +26,7 @@ export const HighlightLoci = PluginBehavior.create({
let prev: Representation.Loci = { loci: EmptyLoci, repr: void 0 };
const sel = this.ctx.helpers.structureSelection;
this.subscribeObservable(this.ctx.events.canvas3d.highlight, ({ current, modifiers }) => {
this.subscribeObservable(this.ctx.behaviors.canvas3d.highlight, ({ current, modifiers }) => {
if (!this.ctx.canvas3d) return;
if (StructureElement.isLoci(current.loci)) {
......@@ -70,7 +70,7 @@ export const SelectLoci = PluginBehavior.create({
}
}
this.subscribeObservable(this.ctx.events.canvas3d.click, ({ current, buttons, modifiers }) => {
this.subscribeObservable(this.ctx.behaviors.canvas3d.click, ({ current, buttons, modifiers }) => {
if (!this.ctx.canvas3d) return;
if (current.loci.kind === 'empty-loci') {
......
......@@ -84,11 +84,30 @@ export class StructureRepresentationInteractionBehavior extends PluginBehavior.W
return { state, builder, refs };
}
private clear() {
const state = this.plugin.state.dataState;
const groups = state.select(StateSelection.Generators.root.subtree().filter(o => o.transform.props.tag === Tags.Group));
if (groups.length === 0) return;
const update = state.build();
for (const g of groups) update.delete(g.transform.ref);
PluginCommands.State.Update.dispatch(this.plugin, { state, tree: update, options: { doNotLogTiming: true, doNotUpdateCurrent: true } });
}
register(ref: string): void {
// this.ref = ref;
this.subscribeObservable(this.plugin.events.canvas3d.click, ({ current, buttons }) => {
this.subscribeObservable(this.plugin.behaviors.canvas3d.click, ({ current, buttons, modifiers }) => {
if (buttons !== ButtonsType.Flag.Secondary) return;
if (current.loci.kind === 'empty-loci') {
if (modifiers.control && buttons === ButtonsType.Flag.Secondary) {
this.clear();
return;
}
}
// TODO: support link loci as well?
if (!StructureElement.isLoci(current.loci)) return;
......
......@@ -21,6 +21,8 @@ import { urlCombine } from 'mol-util/url';
import { VolumeServerHeader, VolumeServerInfo } from './model';
import { CreateVolumeStreamingBehavior } from './transformers';
import { ButtonsType } from 'mol-util/input/input-observer';
import { PluginCommands } from 'mol-plugin/command';
import { StateSelection } from 'mol-state';
export class VolumeStreaming extends PluginStateObject.CreateBehavior<VolumeStreaming.Behavior>({ name: 'Volume Streaming' }) { }
......@@ -146,21 +148,12 @@ export namespace VolumeStreaming {
return ret;
}
register(ref: string): void {
// this.ref = ref;
this.subscribeObservable(this.plugin.events.canvas3d.click, ({ current, buttons }) => {
if (buttons !== ButtonsType.Flag.Secondary || this.params.view.name !== 'selection-box') return;
// TODO: support link loci as well?
// Perhaps structure loci too?
if (!StructureElement.isLoci(current.loci)) return;
// TODO: check if it's the related structure
const loci = StructureElement.Loci.extendToWholeResidues(current.loci);
private updateDynamicBox(ref: string, box: Box3D) {
if (this.params.view.name !== 'selection-box') return;
const eR = this.params.view.params.radius;
const box = StructureElement.Loci.getBoundary(loci).box;
const update = this.plugin.state.dataState.build().to(ref).update(CreateVolumeStreamingBehavior, old => ({
const state = this.plugin.state.dataState;
const update = state.build().to(ref).update(CreateVolumeStreamingBehavior, old => ({
...old,
view: {
name: 'selection-box' as 'selection-box',
......@@ -172,8 +165,38 @@ export namespace VolumeStreaming {
}
}));
// TODO: create/use command queue here and cancel any ongoing updates.
this.plugin.runTask(this.plugin.state.dataState.updateTree(update));
PluginCommands.State.Update.dispatch(this.plugin, { state, tree: update, options: { doNotUpdateCurrent: true } });
}
private getStructureRoot(ref: string) {
return this.plugin.state.dataState.select(StateSelection.Generators.byRef(ref).rootOfType([PluginStateObject.Molecule.Structure]))[0];
}
register(ref: string): void {
// this.ref = ref;
this.subscribeObservable(this.plugin.behaviors.canvas3d.click, ({ current, buttons, modifiers }) => {
if (buttons !== ButtonsType.Flag.Secondary || this.params.view.name !== 'selection-box') return;
if (current.loci.kind === 'empty-loci') {
if (modifiers.control && buttons === ButtonsType.Flag.Secondary) {
this.updateDynamicBox(ref, Box3D.empty());
return;
}
}
// TODO: support link loci as well?
// Perhaps structure loci too?
if (!StructureElement.isLoci(current.loci)) return;
const parent = this.plugin.helpers.substructureParent.get(current.loci.structure);
if (!parent) return;
const root = this.getStructureRoot(ref);
if (!root || !root.obj || root.obj !== parent.obj) return;
const loci = StructureElement.Loci.extendToWholeResidues(current.loci);
const box = StructureElement.Loci.getBoundary(loci).box;
this.updateDynamicBox(ref, box);
});
}
......
......@@ -52,7 +52,9 @@ export const InitVolumeStreaming = StateAction.build({
const infoObj = await state.updateTree(infoTree).runInContext(taskCtx);
const behTree = state.build().to(infoTree.ref).apply(CreateVolumeStreamingBehavior, PD.getDefaultValues(VolumeStreaming.createParams(infoObj.data)));
const behTree = state.build().to(infoTree.ref).apply(CreateVolumeStreamingBehavior,
PD.getDefaultValues(VolumeStreaming.createParams(infoObj.data)));
if (params.method === 'em') {
behTree.apply(VolumeStreamingVisual, { channel: 'em' }, { props: { isGhost: true } });
} else {
......@@ -96,7 +98,7 @@ const CreateVolumeStreamingInfo = PluginStateTransform.BuiltIn({
emDefaultContourLevel,
structure: a.data
};
return new VolumeServerInfo(data, { label: `Volume Streaming: ${dataId}` });
return new VolumeServerInfo(data, { label: `Volume Server: ${dataId}` });
})
});
......@@ -118,7 +120,7 @@ const CreateVolumeStreamingBehavior = PluginStateTransform.BuiltIn({
apply: ({ a, params }, plugin: PluginContext) => Task.create('Volume streaming', async _ => {
const behavior = new VolumeStreaming.Behavior(plugin, a.data);
await behavior.update(params);
return new VolumeStreaming(behavior, { label: 'Streaming Controls' });
return new VolumeStreaming(behavior, { label: 'Volume Streaming' });
}),
update({ b, newParams }) {
return Task.create('Update Volume Streaming', async _ => {
......
......@@ -105,16 +105,16 @@ export function Highlight(ctx: PluginContext) {
// const cell = state.select(ref)[0]
// const repr = cell && SO.isRepresentation3D(cell.obj) ? cell.obj.data : undefined
// if (cell && cell.obj && cell.obj.type === PluginStateObject.Molecule.Structure.type) {
// ctx.events.canvas3d.highlight.next({ current: { loci: Structure.Loci(cell.obj.data) } });
// ctx.behaviors.canvas3d.highlight.next({ current: { loci: Structure.Loci(cell.obj.data) } });
// } else if (repr) {
// ctx.events.canvas3d.highlight.next({ current: { loci: EveryLoci, repr } });
// ctx.behaviors.canvas3d.highlight.next({ current: { loci: EveryLoci, repr } });
// }
});
}
export function ClearHighlight(ctx: PluginContext) {
PluginCommands.State.ClearHighlight.subscribe(ctx, ({ state, ref }) => {
// ctx.events.canvas3d.highlight.next({ current: { loci: EmptyLoci } });
// ctx.behaviors.canvas3d.highlight.next({ current: { loci: EmptyLoci } });
});
}
......
......@@ -32,6 +32,8 @@ import { TaskManager } from './util/task-manager';
import { PLUGIN_VERSION, PLUGIN_VERSION_DATE } from './version';
import { StructureElementSelectionManager } from './util/structure-element-selection';
import { SubstructureParentHelper } from './util/substructure-parent-helper';
import { Representation } from 'mol-repr/representation';
import { ModifiersKeys } from 'mol-util/input/input-observer';
export class PluginContext {
private disposed = false;
......@@ -59,18 +61,15 @@ export class PluginContext {
log: this.ev<LogEntry>(),
task: this.tasks.events,
canvas3d: {
settingsUpdated: this.ev(),
highlight: this.ev<Canvas3D.HighlightEvent>(),
click: this.ev<Canvas3D.ClickEvent>()
settingsUpdated: this.ev()
}
};
readonly behaviors = {
// canvas: {
// highlightLoci: this.ev.behavior<{ loci: Loci, repr?: Representation.Any, modifiers?: ModifiersKeys }>({ loci: EmptyLoci }),
// selectLoci: this.ev.behavior<{ loci: Loci, repr?: Representation.Any, modifiers?: ModifiersKeys }>({ loci: EmptyLoci }),
// },
canvas3d: {
highlight: this.ev.behavior<Canvas3D.HighlightEvent>({ current: Representation.Loci.Empty, prev: Representation.Loci.Empty }),
click: this.ev.behavior<Canvas3D.ClickEvent>({ current: Representation.Loci.Empty, modifiers: ModifiersKeys.None, buttons: 0 })
},
labels: {
highlight: this.ev.behavior<{ entries: ReadonlyArray<LociLabelEntry> }>({ entries: [] })
},
......
......@@ -110,8 +110,8 @@ export class Viewport extends PluginUIComponent<{ }, ViewportState> {
const canvas3d = this.plugin.canvas3d;
this.subscribe(canvas3d.input.resize, this.handleResize);
this.subscribe(canvas3d.interaction.click, e => this.plugin.events.canvas3d.click.next(e));
this.subscribe(canvas3d.interaction.highlight, e => this.plugin.events.canvas3d.highlight.next(e));
this.subscribe(canvas3d.interaction.click, e => this.plugin.behaviors.canvas3d.click.next(e));
this.subscribe(canvas3d.interaction.highlight, e => this.plugin.behaviors.canvas3d.highlight.next(e));
this.subscribe(this.plugin.layout.events.updated, () => {
setTimeout(this.handleResize, 50);
});
......
......@@ -35,6 +35,6 @@ export class LociLabelManager {
}
constructor(public ctx: PluginContext) {
ctx.events.canvas3d.highlight.subscribe(ev => ctx.behaviors.labels.highlight.next({ entries: this.getInfo(ev.current) }));
ctx.behaviors.canvas3d.highlight.subscribe(ev => ctx.behaviors.labels.highlight.next({ entries: this.getInfo(ev.current) }));
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment