awv3
Version:
⚡ AWV3 embedded CAD
164 lines (149 loc) • 6.5 kB
JavaScript
import * as THREE from 'three';
import Lifecycle from './lifecycle.js';
import { halt } from '../core/error';
import { actions } from './store/plugins';
import { actions as elementActions } from './store/elements';
import { actions as globalActions } from './store/globals';
import { actions as connectionActions, base as connectionBase } from './store/connections';
import { base as pluginBase } from './store/plugins';
import { createObserver } from './helpers';
import Element from './element';
import { Group, Button, Spacer, Divider } from './elements';
export default class Plugin extends Lifecycle() {
static persistent = false;
static measurable = false;
constructor(session = halt('plugin must be initialized with a session'), { feature, connection, pool, ...props }) {
super(session, actions, state => state.plugins[this.id], {
type: '',
name: '',
title: '',
resources: {},
icon: undefined,
enabled: false,
active: false,
collapsed: true,
closeable: true,
parent: undefined,
elements: [],
feature: feature ? feature.id : false,
connection: connection ? connection.id : undefined,
managed: true,
...props,
});
// If a parent exists (which mean this is a linked plugin, invoked by a parent plugin)
if (this.parent) {
let parentPlugin = pluginBase.references[this.parent];
// And if the parent is a feature, it gets to store its own pool under the parent, while
// it is allowed to pose as a feature plugin itself
if (parentPlugin.feature) {
feature = parentPlugin;
connection = parentPlugin.connection;
this.pool = new THREE.Group();
this.pool.updateParentMaterials = false;
this.pool.measurable = false;
this.pool.name = `plugin.linked_pool.${this.type}${this.name ? '+' + this.name : ''}`;
feature.pool.add(this.pool);
}
}
if (feature) {
Object.defineProperty(this, 'feature', { get: () => feature.id });
Object.defineProperty(this, 'connection', { get: () => connection });
if (!this.parent) {
this.pool = pool;
this.reset = new Button(this, { name: 'Reset', color: 'black', flex: 0 });
this.apply = new Button(this, { name: 'Apply', color: 'blue', flex: 0 });
this.addElement(
new Group(this, {
index: 10000000,
children: [
new Divider(this),
new Spacer(this),
new Group(this, {
format: Group.Format.Rows,
flexDirection: 'row-reverse',
children: [this.apply, new Spacer(this), this.reset],
}),
],
}),
);
}
} else {
Object.defineProperty(this, 'connection', {
get: () => connectionBase.references[this.session.globals.activeConnection],
});
this.pool = new THREE.Group();
this.pool.updateParentMaterials = false;
this.pool.measurable = false;
this.pool.name = `plugin.pool.${this.type}${this.name ? '+' + this.name : ''}`;
this.session.pool.temporary.add(this.pool);
}
// this.tree refers to the connections tree
Object.defineProperty(this, 'tree', { get: () => this.connection.tree });
Object.defineProperty(this, 'root', { get: () => this.tree[this.tree.root] });
Object.defineProperty(this, 'view', { get: () => this.pool.view });
// Internal observer for enabled state, gets cleared after destroy
// The enabled flag has to be kept locally as the destroyed event can be dispatched
// without calling destroy() directly, leaving the linked state empty
this.__enabled = this.enabled;
this.__enabledUnsubscribe = this.observe(
// selector
state => state.enabled,
// onChanged
(enabled, prev) => {
this.__enabled = enabled;
if (enabled !== prev) {
if (enabled) {
this.onEnabled();
} else {
this.onDisabled();
}
}
!enabled && this.removeSubscriptions();
},
// options
{ manager: undefined },
);
}
addElement(...elements) {
elements.forEach(element =>
this.store.dispatch(actions.addElement(this.id, element instanceof Element ? element.id : element)),
);
}
removeElement(element) {
this.store.dispatch(actions.removeElement(this.id, element instanceof Element ? element.id : element));
}
destroyElements() {
this.store.dispatch(
elementActions.unregister(
Object.keys(this.session.elements).filter(id => this.session.elements[id].plugin === this.id),
),
);
}
resetElements() {
this.store.dispatch(
elementActions.merge(this.dependencies.reduce((prev, obj) => ({ ...prev, [obj.id]: obj.props }), {})),
);
}
createToolbar(keys, cb, columns = 7) {
let children = [];
for (let count = 0; count < keys.length / columns; count++) {
children.push(
new Group(this, {
format: Group.Format.Buttons,
margin: count == keys.length / columns - 1,
children: cb(keys.slice(count * columns, Math.min(count * columns + columns, keys.length))),
}),
);
}
return new Group(this, { children });
}
onEnabled() {}
onDisabled() {}
__onDestroyed() {
this.store.dispatch(globalActions.unlinkPlugins(this.id));
if (this.connection) this.store.dispatch(connectionActions.unlinkPlugins(this.connection.id, this.id));
this.__enabledUnsubscribe();
this.__enabled && this.onDisabled();
this.pool && this.pool.destroy();
}
}