UNPKG

lazy-widgets

Version:

Typescript retained mode GUI for the HTML canvas API

156 lines 4.68 kB
import { PropagationModel } from '../events/WidgetEvent.js'; import { Parent } from './Parent.js'; /** * A {@link Parent} widget, similar to {@link PassthroughWidget}, which can * optionally have a single child, or no child at all, and can transfer the * child to other WidgetSlots. * * @category Widget */ export class WidgetSlot extends Parent { /** * @param child - The optional single child of this widget. Can be changed later via either {@link WidgetSlot#child}, {@link WidgetSlot#transferChildTo} or {@link WidgetSlot#swapChildWith}. */ constructor(child = null, properties) { super(properties); this._child = null; this.child = child; } /** The current child in this slot. May be null if the slot is empty. */ get child() { return this._child; } set child(child) { if (this._child === child) { return; } if (child && child.attached) { throw new Error('New child is already attached to another widget'); } const isAttached = this.attached; if (this._child && isAttached) { this._child.detach(); } this._child = child; if (child) { child.inheritedTheme = this.inheritedTheme; if (isAttached) { child.attach(this.root, this.viewport, this); } } this._layoutDirty = true; this.markWholeAsDirty(); } /** * Transfer this widget's child to a new WidgetSlot. Note that, if this * widget has no child, then the new slot will have its child removed. * * Does nothing if the new slot is this. */ transferChildTo(newSlot) { if (newSlot === this) { return; } const child = this._child; this.child = null; newSlot.child = child; } /** * Swap this widget's child with another WidgetSlot's child. Also works if * either (or both) slots have no child. * * Does nothing if the other slot is this. */ swapChildWith(otherSlot) { if (otherSlot === this) { return; } const thisChild = this._child; const otherChild = otherSlot.child; this.child = null; otherSlot.child = thisChild; this.child = otherChild; } handleEvent(event) { if (event.propagation !== PropagationModel.Trickling) { return super.handleEvent(event); } else if (this._child) { return this._child.dispatchEvent(event); } else { return null; } } handlePreLayoutUpdate() { if (!this._child) { return; } // Pre-layout update child this._child.preLayoutUpdate(); // If child's layout is dirty, set self's layout as dirty if (this._child && this._child.layoutDirty) { this._layoutDirty = true; } } handlePostLayoutUpdate() { // Post-layout update child if (this._child) { this._child.postLayoutUpdate(); } } handleResolveDimensions(minWidth, maxWidth, minHeight, maxHeight) { // Resolve child's dimensions and set own resolved dimensions to be // equal to the child's if (this._child) { this._child.resolveDimensions(minWidth, maxWidth, minHeight, maxHeight); [this.idealWidth, this.idealHeight] = this._child.idealDimensions; } else { this.idealWidth = 0; this.idealHeight = 0; } } resolvePosition(x, y) { super.resolvePosition(x, y); // Resolve child's position to be the same as this widget's position if (this._child) { this._child.resolvePosition(x, y); } } handlePainting(dirtyRects) { // Paint child if (this._child) { this._child.paint(dirtyRects); } } [Symbol.iterator]() { const child = this._child; let first = !!child; return { next() { if (first) { first = false; return { value: child, done: false }; } else { return { value: undefined, done: true }; } } }; } get childCount() { return this._child ? 1 : 0; } } WidgetSlot.autoXML = { name: 'widget-slot', inputConfig: [ { mode: 'widget', name: 'child', optional: true, } ] }; //# sourceMappingURL=WidgetSlot.js.map