UNPKG

lazy-widgets

Version:

Typescript retained mode GUI for the HTML canvas API

197 lines 7.98 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { Alignment } from '../theme/Alignment.js'; import { SingleParent } from './SingleParent.js'; import { resolveContainerDimensions } from '../helpers/resolveContainerDimensions.js'; import { resolveContainerPosition } from '../helpers/resolveContainerPosition.js'; import { safeRoundRect } from '../helpers/safeRoundRect.js'; import { accessorAlias, layoutArrayField, layoutField } from '../decorators/FlagFields.js'; import { SingleParentXMLInputConfig } from '../xml/SingleParentXMLInputConfig.js'; import { TooltipAxisBias } from '../core/TooltipAxisBias.js'; import { PropagationModel } from '../events/WidgetEvent.js'; const startAlignment = { horizontal: Alignment.Start, vertical: Alignment.Start }; /** * A container widget for a widget that will be shown when a {@link Tooltip} is * hovered. * * @category Widget */ export class TooltipContainer extends SingleParent { constructor(child, properties) { var _a, _b; super(child, properties); /** * The horizontal component of the position to place this tooltip around. * Automatically set by {@link Tooltip} widget. Used for positioning. */ this.anchorX = 0; /** * The vertical component of the position to place this tooltip around. * Automatically set by {@link Tooltip} widget. Used for positioning. */ this.anchorY = 0; /** * A rectangle representing the dimensions and position of the * {@link Tooltip} that binds this box. Used for positioning. */ this.tooltipRect = [0, 0, 0, 0]; this.idealTooltipWidth = 0; this.idealTooltipHeight = 0; this.horizontalBias = (_a = properties === null || properties === void 0 ? void 0 : properties.horizontalBias) !== null && _a !== void 0 ? _a : TooltipAxisBias.After; this.verticalBias = (_b = properties === null || properties === void 0 ? void 0 : properties.verticalBias) !== null && _b !== void 0 ? _b : TooltipAxisBias.Auto; } onThemeUpdated(property = null) { super.onThemeUpdated(property); if (property === null || property === 'tooltipPadding') { this._layoutDirty = true; this.markWholeAsDirty(); } else if (property === 'tooltipFill' || property === 'tooltipRadii') { this.markWholeAsDirty(); } } handleEvent(event) { if (event.propagation === PropagationModel.Trickling) { return this.child.dispatchEvent(event); } else { return super.handleEvent(event); } } handlePreLayoutUpdate() { // Pre-layout update child const child = this.child; child.preLayoutUpdate(); // If child's layout is dirty, set self's layout as dirty if (child.layoutDirty) { this._layoutDirty = true; } } handlePostLayoutUpdate() { // Post-layout update child this.child.postLayoutUpdate(); } handleResolveDimensions(_minWidth, maxWidth, _minHeight, maxHeight) { [this.idealTooltipWidth, this.idealTooltipHeight] = resolveContainerDimensions(0, maxWidth, 0, maxHeight, this.tooltipPadding, startAlignment, this.child); this.idealWidth = Math.min(maxWidth, this.idealTooltipWidth); this.idealHeight = Math.min(maxHeight, this.idealTooltipHeight); } resolvePosition(x, y) { // resolve best alignment that places the child under (or over) the // cursor // check if there is space above or below the wrapper widget let pX = 0; let pY = 0; let pW = Infinity; let pH = Infinity; const [wX, wY, wW, wH] = this.tooltipRect; if (this._parent) { [pX, pY, pW, pH] = this._parent.idealRect; } const spaceAbove = Math.max(wY - pY, 0); const pBot = pY + pH; const wBot = wY + wH; const spaceBelow = Math.max(pBot - wBot, 0); // decide whether to place tooltip above or below widget. fall back to // above the widget const fitsAbove = spaceAbove >= this.idealTooltipHeight; const fitsBelow = spaceBelow >= this.idealTooltipHeight; if (fitsAbove && fitsBelow) { const vBias = this.verticalBias; // XXX it doesn't make sense to have a centre-biased vertical axis, // so assume the user meant to use automatic bias if (vBias === TooltipAxisBias.Before || ((vBias === TooltipAxisBias.Center || vBias === TooltipAxisBias.Auto) && this.anchorY <= (wY + 0.5 * wH))) { // put above y = wY - this.idealTooltipHeight; } else { // put below y = wBot; } } else if (fitsAbove) { // put above y = wY - this.idealTooltipHeight; } else if (fitsBelow) { // put below y = wBot; } else { // put on cursor y = this.anchorY; } switch (this.horizontalBias) { case TooltipAxisBias.Before: x = this.anchorX - this.idealTooltipWidth; break; case TooltipAxisBias.Center: x = this.anchorX - this.idealTooltipWidth * 0.5; break; case TooltipAxisBias.After: x = this.anchorX; break; default: x = this.anchorX - ((this.anchorX <= (wX + 0.5 * wW)) ? 0 : this.idealTooltipWidth); } // clamp to bounds of parent const pRight = pX + pW; if (x + this.idealTooltipWidth > pRight) { x = pRight - this.idealTooltipWidth; } if (y + this.idealTooltipHeight > pBot) { y = pBot - this.idealTooltipHeight; } if (x < 0) { x = 0; } if (y < 0) { y = 0; } super.resolvePosition(x, y); resolveContainerPosition(x, y, this.idealWidth, this.idealHeight, this.tooltipPadding, startAlignment, this.child); } handlePainting(dirtyRects) { const ctx = this.viewport.context; ctx.save(); ctx.beginPath(); safeRoundRect(ctx, this.idealX, this.idealY, this.idealTooltipWidth, this.idealTooltipHeight, this.tooltipRadii); ctx.clip(); ctx.fillStyle = this.tooltipFill; ctx.fillRect(this.idealX, this.idealY, this.idealTooltipWidth, this.idealTooltipHeight); this.child.paint(dirtyRects); ctx.restore(); } } TooltipContainer.autoXML = { name: 'tooltip-container', inputConfig: SingleParentXMLInputConfig }; __decorate([ layoutField ], TooltipContainer.prototype, "anchorX", void 0); __decorate([ layoutField ], TooltipContainer.prototype, "anchorY", void 0); __decorate([ accessorAlias('anchorX') ], TooltipContainer.prototype, "cursorX", void 0); __decorate([ accessorAlias('anchorY') ], TooltipContainer.prototype, "cursorY", void 0); __decorate([ layoutField ], TooltipContainer.prototype, "horizontalBias", void 0); __decorate([ layoutField ], TooltipContainer.prototype, "verticalBias", void 0); __decorate([ layoutArrayField(false) ], TooltipContainer.prototype, "tooltipRect", void 0); //# sourceMappingURL=TooltipContainer.js.map