Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

adds parent logic to scene graph, fixes #182 #183

Merged
merged 3 commits into from
Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion core/client/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default class MagicCircle {
this.stop = this.stop.bind(this);

this.arguments = { plugins, ipc };
this.layer = new Layer('base', true);
this.layer = new Layer('base', this);
this.isPlaying = false;
this.autoPlay = false;
this.isConnected = false;
Expand Down Expand Up @@ -209,10 +209,13 @@ export default class MagicCircle {
}

sync() {
if (!this.setupDone) return;

if (this.syncRequest) {
clearTimeout(this.syncRequest);
}

// debounce sync
this.syncRequest = setTimeout(() => {
this.flush();
}, 12);
Expand Down
24 changes: 24 additions & 0 deletions core/client/src/control.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default class Control<T, U extends options = options> {
blockHydrate?: boolean;
blockObjectMerge?: boolean;
watchChanges?: boolean;
parent?: Layer;

private updateHooks: Set<UpdateHook<T>>;

Expand Down Expand Up @@ -106,10 +107,22 @@ export default class Control<T, U extends options = options> {
}

addTo(layer: Layer) {
if (this.parent) {
this.removeFromParent();
}

this.parent = null;
layer.add(this);

return this;
}

sync() {
if (this.parent) {
this.parent.getMagicInstance()?.sync();
}
}

toJSON(basePath: string, paths: Paths) {
const path = this.getPath(basePath, paths);
return {
Expand All @@ -124,7 +137,18 @@ export default class Control<T, U extends options = options> {
};
}

removeFromParent() {
if (this.parent) {
this.parent.remove(this);
this.parent = null;
}
}

destroy() {
if (this.parent) {
this.removeFromParent();
}

this.reference = null;
this.updateHooks.clear();
}
Expand Down
2 changes: 1 addition & 1 deletion core/client/src/folder.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Layer from './layer';

export default class Folder extends Layer {
constructor(name: string, children?: Layer['children']) {
constructor(name: string, children?: Parameters<Layer['add']>[0]) {
super(name);
this.folder = true;
this.add(children || []);
Expand Down
76 changes: 73 additions & 3 deletions core/client/src/layer.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type MagicCircle from './client';
import type Control from './control';
import Paths from './paths';

Expand All @@ -6,16 +7,19 @@ export type Child = Layer | Control<any>;
export default class Layer {
name: string;
children: Child[];
parent?: Layer;
magicInstance?: MagicCircle;
folder: boolean;
collapsed: boolean;
isBaseLayer: boolean;

constructor(name: string, isBaseLayer = false) {
constructor(name: string, magicInstance?: MagicCircle) {
this.name = name;
this.children = [];
this.folder = false;
this.collapsed = false;
this.isBaseLayer = isBaseLayer;
this.isBaseLayer = !!magicInstance;
this.magicInstance = magicInstance;
}

forEach(fn: (child: Child) => void) {
Expand All @@ -25,6 +29,11 @@ export default class Layer {
}

forEachRecursive(fn: (child: Child, path: string) => void) {
console.warn('Deprecated: use .traverse');
this.traverse(fn);
}

traverse(fn: (child: Child, path: string) => void) {
const path = new Paths();

const recursive = (children: Child[], basePath: string) => {
Expand All @@ -41,22 +50,60 @@ export default class Layer {
recursive(this.children, this.isBaseLayer ? '' : this.name);
}

traverseAncestors(fn: (parent: Layer) => void) {
const recursive = (parent: Layer) => {
fn(parent);

// move upwards
if (parent.parent) {
recursive(parent.parent);
}
};

if (this.parent) {
recursive(this.parent);
}
}

getMagicInstance() {
let instance: MagicCircle | null = null;

this.traverseAncestors((layer) => {
if (layer.isBaseLayer) {
instance = layer.magicInstance;
}
});

return instance;
}

add(child: Child | Child[]) {
if (Array.isArray(child)) {
// Add one by one
child.forEach((c) => {
this.add(c);
this.children.push(c);
});
} else if (this.children.indexOf(child) === -1) {
// Make sure we're not duplicating
this.children.push(child);
}

// ensure we're syncing magic instance after
const mc = this.getMagicInstance();
if (mc) {
mc.sync();
}

return this;
}

addTo(layer: Layer) {
if (this.parent) {
this.removeFromParent();
}

layer.add(this);
this.parent = layer;

return this;
}
Expand All @@ -69,6 +116,29 @@ export default class Layer {
return this;
}

removeFromParent() {
if (this.parent) {
this.parent.remove(this);
this.parent = null;
}
}

destroy(removeChildren = false) {
if (this.parent) {
this.removeFromParent();
}

// remove all children if needed
if (removeChildren) {
this.traverse((child) => {
child.destroy();
});
}

this.children = [];
this.magicInstance = undefined;
}

collapse(collapsed = true) {
this.collapsed = collapsed;
return this;
Expand Down
4 changes: 2 additions & 2 deletions core/client/src/plugins/layers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default class PluginLayers extends Plugin {
const controls: typeof this.cache = {};
const watchers = {};

this.client.layer.forEachRecursive((child, path) => {
this.client.layer.traverse((child, path) => {
if ('value' in child) {
controls[path] = child;
}
Expand Down Expand Up @@ -108,7 +108,7 @@ export default class PluginLayers extends Plugin {
resetAll(sync = true) {
const { layer } = this.client;

layer.forEachRecursive((control) => {
layer.traverse((control) => {
if (control && 'value' in control && !control.blockHydrate) {
control.reset();
}
Expand Down
20 changes: 10 additions & 10 deletions core/client/test/layer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,62 +3,62 @@ import Layer from '../src/layer';
describe('core/client:layer', () => {
test('Layer should be able to get created', () => {
const layer = new Layer('layer1');

expect(layer.name).toBe('layer1');
});

test('Layer should be able to get added to a parent via addTo()', () => {
const parent = new Layer('parent');
const child = new Layer('child').addTo(parent);

expect(parent.children[0]).toBe(child);
expect(parent.children[0]).toBeDefined();
expect(parent.children[0] === child).toBe(true);
expect(child.parent).toBe(parent);
});

/*
test('Layer should be able to get added to a parent via add()', () => {
const parent = new Layer('parent');
const child = new Layer('child');
parent.add(child);

expect(parent.children[0]).toBe(child);
expect(child.parent).toBe(parent);
});

test('Multiple layers should be able to get added via add()', () => {
const parent = new Layer('parent');
const child1 = new Layer('child');
const child2 = new Layer('child');
parent.add([child1, child2]);

expect(parent.children.length).toBe(2);
expect(child1.parent).toBe(parent);
expect(child2.parent).toBe(parent);
});

test('Should not add duplicate layers via add()', () => {
const parent = new Layer('parent');
const child = new Layer('child');
parent.add([child, child, child]);

expect(parent.children.length).toBe(1);
});

test('Should be able to add and remove layer', () => {
const parent = new Layer('parent');
const child = new Layer('child');

parent.add(child);
expect(parent.children.length).toBe(1);

expect(child.parent).toBe(parent);
parent.remove(child);
expect(parent.children.length).toBe(0);
expect(child.parent).toBeNull();
});

test('Should be able to add and remove multiple layers', () => {
const parent = new Layer('parent');
const child1 = new Layer('child 1');
const child2 = new Layer('child 2');

parent.add([child1, child2]);
expect(parent.children.length).toBe(2);

parent.remove([child1, child2]);
expect(parent.children.length).toBe(0);
});
*/
});
Loading