scripts/path-controller/controller/controller_base.js
import {PropFlags, PropTypes} from '../toolsys/toolprop_abstract.js';
import {Quat, Vector2, Vector3, Vector4} from '../util/vectormath.js';
import * as toolprop_abstract from '../toolsys/toolprop_abstract.js';
import * as toolprop from '../toolsys/toolprop.js';
import {print_stack, cachering} from '../util/util.js';
export const DataFlags = {
READ_ONLY : 1,
USE_CUSTOM_GETSET : 2,
USE_FULL_UNDO : 4, //DataPathSetOp in controller_ops.js saves/loads entire file for undo/redo
USE_CUSTOM_PROP_GETTER: 8,
};
export const DataTypes = {
STRUCT : 0,
DYNAMIC_STRUCT: 1,
PROP : 2,
ARRAY : 3
};
let propCacheRings = {};
export function getTempProp(type) {
if (!(type in propCacheRings)) {
propCacheRings[type] = cachering.fromConstructor(ToolProperty.getClass(type), 32);
}
return propCacheRings[type].next();
}
export class DataPathError extends Error {
};
export function getVecClass(proptype) {
switch (proptype) {
case PropTypes.VEC2:
return Vector2;
case PropTypes.VEC3:
return Vector3;
case PropTypes.VEC4:
return Vector4;
case PropTypes.QUAT:
return Quat;
default:
throw new Error("bad prop type " + proptype);
}
}
export function isVecProperty(prop) {
if (!prop || typeof prop !== "object" || prop === null)
return false;
let ok = false;
ok = ok || prop instanceof toolprop_abstract.Vec2PropertyIF;
ok = ok || prop instanceof toolprop_abstract.Vec3PropertyIF;
ok = ok || prop instanceof toolprop_abstract.Vec4PropertyIF;
ok = ok || prop instanceof toolprop.Vec2Property;
ok = ok || prop instanceof toolprop.Vec3Property;
ok = ok || prop instanceof toolprop.Vec4Property;
ok = ok || prop.type === PropTypes.VEC2;
ok = ok || prop.type === PropTypes.VEC3;
ok = ok || prop.type === PropTypes.VEC4;
ok = ok || prop.type === PropTypes.QUAT;
return ok;
}
export class DataPath {
constructor(path, apiname, prop, type = DataTypes.PROP) {
this.type = type;
this.data = prop;
this.apiname = apiname;
this.path = path;
this.flag = 0;
this.struct = undefined;
}
copy() {
let ret = new DataPath();
ret.flag = this.flag;
ret.type = this.type;
ret.data = this.data;
ret.apiname = this.apiname;
ret.path = this.path;
ret.struct = this.struct;
return ret;
}
/** this property should not be treated as something
* that should be kept track off in the undo stack*/
noUndo() {
this.data.flag |= PropFlags.NO_UNDO;
return this;
}
setProp(prop) {
this.data = prop;
}
readOnly() {
this.flag |= DataFlags.READ_ONLY;
if (this.type === DataTypes.PROP) {
this.data.flag |= PropFlags.READ_ONLY;
}
return this;
}
read_only() {
console.warn("DataPath.read_only is deprecated; use readOnly");
return this.readOnly();
}
/** used to override tool property settings,
* e.g. ranges, units, etc; returns a
* base class instance of ToolProperty.
*
* The this context points to the original ToolProperty and contains
* a few useful references:
*
* this.dataref - an object instance of this struct type
* this.ctx - a context
*
* callback takes one argument, a new (freshly copied of original)
* tool property to modify
*
* */
customPropCallback(callback) {
this.flag |= DataFlags.USE_CUSTOM_PROP_GETTER;
this.data.flag |= PropFlags.USE_CUSTOM_PROP_GETTER;
this.propGetter = callback;
return this;
}
/**
*
* For the callbacks 'this' points to an internal ToolProperty;
* Referencing object lives in 'this.dataref'; calling context in 'this.ctx';
* and the datapath is 'this.datapath'
**/
customGetSet(get, set) {
this.flag |= DataFlags.USE_CUSTOM_GETSET;
if (this.type !== DataTypes.DYNAMIC_STRUCT && this.type !== DataTypes.STRUCT) {
this.data.flag |= PropFlags.USE_CUSTOM_GETSET;
this.data._getValue = this.data.getValue;
this.data._setValue = this.data.setValue;
if (get)
this.data.getValue = get;
if (set)
this.data.setValue = set;
} else {
this.getSet = {
get, set
};
this.getSet.dataref = undefined;
this.getSet.datapath = undefined;
this.getSet.ctx = undefined;
}
return this;
}
customSet(set) {
this.customGetSet(undefined, set);
return this;
}
customGet(get) {
this.customGetSet(get, undefined);
return this;
}
/**db will be executed with underlying data object
that contains this path in 'this.dataref'
main event is 'change'
*/
on(type, cb) {
if (this.type == DataTypes.PROP) {
this.data.on(type, cb);
} else {
throw new Error("invalid call to DataPath.on");
}
return this;
}
off(type, cb) {
if (this.type === DataTypes.PROP) {
this.data.off(type, cb);
}
}
simpleSlider() {
this.data.flag |= PropFlags.SIMPLE_SLIDER;
this.data.flag &= ~PropFlags.FORCE_ROLLER_SLIDER;
return this;
}
rollerSlider() {
this.data.flag &= ~PropFlags.SIMPLE_SLIDER;
this.data.flag |= PropFlags.FORCE_ROLLER_SLIDER;
return this;
}
noUnits() {
this.baseUnit("none");
this.displayUnit("none");
return this;
}
baseUnit(unit) {
this.data.setBaseUnit(unit);
return this;
}
displayUnit(unit) {
this.data.setDisplayUnit(unit);
return this;
}
unit(unit) {
return this.baseUnit(unit).displayUnit(unit);
}
editAsBaseUnit() {
this.data.flag |= PropFlags.EDIT_AS_BASE_UNIT;
return this;
}
range(min, max) {
this.data.setRange(min, max);
return this;
}
uiRange(min, max) {
this.data.setUIRange(min, max);
return this;
}
decimalPlaces(n) {
this.data.setDecimalPlaces(n);
return this;
}
/**
* like other callbacks (until I refactor it),
* func will be called with a mysterious object that stores
* the following properties:
*
* this.dataref : owning object reference
* this.datactx : ctx
* this.datapath : datapath
* */
uiNameGetter(func) {
this.ui_name_get = func;
return this;
}
expRate(exp) {
this.data.setExpRate(exp);
return this;
}
slideSpeed(speed) {
this.data.setSlideSpeed(speed);
return this;
}
/**adds a slider for moving vector component sliders simultaneously*/
uniformSlider(state = true) {
this.data.uniformSlider(state);
return this;
}
radix(r) {
this.data.setRadix(r);
return this;
}
relativeStep(s) {
this.data.setRelativeStep(s);
return this;
}
step(s) {
this.data.setStep(s);
return this;
}
/**
*
* Tell DataPathSetOp to save/load entire app state for undo/redo
*
* */
fullSaveUndo() {
this.flag |= DataFlags.USE_FULL_UNDO;
this.data.flag |= PropFlags.USE_BASE_UNDO;
return this;
}
icon(i) {
this.data.setIcon(i);
return this;
}
icon2(i) {
this.data.setIcon2(i);
return this;
}
icons(icons) { //for enum/flag properties
this.data.addIcons(icons);
return this;
}
/** secondary icons (e.g. disabled states) */
icons2(icons) {
this.data.addIcons2(icons);
return this;
}
descriptions(description_map) { //for enum/flag properties
this.data.addDescriptions(description_map);
return this;
}
uiNames(uinames) {
this.data.addUINames(uinames);
return this;
}
description(d) {
this.data.description = d;
return this;
}
}
export const StructFlags = {
NO_UNDO: 1 //struct and its child structs can't participate in undo
//via the DataPathToolOp
};
export class ListIface {
getStruct(api, list, key) {
}
get(api, list, key) {
}
getKey(api, list, obj) {
}
getActive(api, list) {
}
setActive(api, list, val) {
}
set(api, list, key, val) {
list[key] = val;
}
getIter() {
}
filter(api, list, filter) {
}
}
export class ToolOpIface {
constructor() {
}
static tooldef() {
return {
uiname : "!untitled tool",
icon : -1,
toolpath : "logical_module.tool", //logical_module need not match up to real module name
description: undefined,
is_modal : false,
inputs : {}, //tool properties
outputs : {} //tool properties
}
}
};
let DataAPIClass = undefined;
export function setImplementationClass(cls) {
DataAPIClass = cls;
}
export function registerTool(cls) {
if (DataAPIClass === undefined) {
throw new Error("data api not initialized properly; call setImplementationClass");
}
return DataAPIClass.registerTool(cls);
}