@mgz-dev/inspect 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +78 -0
- package/dist/Inspect.cjs +1 -0
- package/dist/Inspect.d.ts +68 -0
- package/dist/Inspect.mjs +1 -0
- package/dist/InspectRegistry.cjs +1 -0
- package/dist/InspectRegistry.d.ts +52 -0
- package/dist/InspectRegistry.mjs +1 -0
- package/dist/assets/default-atlas.cjs +1 -0
- package/dist/assets/default-atlas.d.ts +6 -0
- package/dist/assets/default-atlas.mjs +1 -0
- package/dist/core/atlas.cjs +1 -0
- package/dist/core/atlas.d.ts +29 -0
- package/dist/core/atlas.mjs +1 -0
- package/dist/core/canvas2d-renderer.cjs +1 -0
- package/dist/core/canvas2d-renderer.d.ts +94 -0
- package/dist/core/canvas2d-renderer.mjs +1 -0
- package/dist/core/font-generator.cjs +1 -0
- package/dist/core/font-generator.d.ts +20 -0
- package/dist/core/font-generator.mjs +1 -0
- package/dist/core/glyph-rasterizer.cjs +1 -0
- package/dist/core/glyph-rasterizer.d.ts +10 -0
- package/dist/core/glyph-rasterizer.mjs +1 -0
- package/dist/core/input.cjs +1 -0
- package/dist/core/input.d.ts +89 -0
- package/dist/core/input.mjs +1 -0
- package/dist/core/layout.d.ts +10 -0
- package/dist/core/layouts/stack-layout.cjs +1 -0
- package/dist/core/layouts/stack-layout.d.ts +69 -0
- package/dist/core/layouts/stack-layout.mjs +1 -0
- package/dist/core/renderer.d.ts +65 -0
- package/dist/core/surface.cjs +1 -0
- package/dist/core/surface.d.ts +81 -0
- package/dist/core/surface.mjs +1 -0
- package/dist/core/theme.d.ts +33 -0
- package/dist/core/ttf-parser.cjs +1 -0
- package/dist/core/ttf-parser.d.ts +29 -0
- package/dist/core/ttf-parser.mjs +1 -0
- package/dist/core/widget.cjs +1 -0
- package/dist/core/widget.d.ts +213 -0
- package/dist/core/widget.mjs +1 -0
- package/dist/defaults.cjs +1 -0
- package/dist/defaults.d.ts +113 -0
- package/dist/defaults.mjs +1 -0
- package/dist/gui/gui-button-row.cjs +1 -0
- package/dist/gui/gui-button-row.d.ts +21 -0
- package/dist/gui/gui-button-row.mjs +1 -0
- package/dist/gui/gui-button.cjs +1 -0
- package/dist/gui/gui-button.d.ts +9 -0
- package/dist/gui/gui-button.mjs +1 -0
- package/dist/gui/gui-color.cjs +1 -0
- package/dist/gui/gui-color.d.ts +105 -0
- package/dist/gui/gui-color.mjs +1 -0
- package/dist/gui/gui-folder.cjs +1 -0
- package/dist/gui/gui-folder.d.ts +49 -0
- package/dist/gui/gui-folder.mjs +1 -0
- package/dist/gui/gui-monitor.cjs +1 -0
- package/dist/gui/gui-monitor.d.ts +53 -0
- package/dist/gui/gui-monitor.mjs +1 -0
- package/dist/gui/gui-point2d.d.ts +43 -0
- package/dist/gui/gui-point3d.d.ts +48 -0
- package/dist/gui/gui-reorder-list.cjs +1 -0
- package/dist/gui/gui-reorder-list.d.ts +42 -0
- package/dist/gui/gui-reorder-list.mjs +1 -0
- package/dist/gui/gui-select.cjs +1 -0
- package/dist/gui/gui-select.d.ts +40 -0
- package/dist/gui/gui-select.mjs +1 -0
- package/dist/gui/gui-separator.cjs +1 -0
- package/dist/gui/gui-separator.d.ts +10 -0
- package/dist/gui/gui-separator.mjs +1 -0
- package/dist/gui/gui-slider.cjs +1 -0
- package/dist/gui/gui-slider.d.ts +34 -0
- package/dist/gui/gui-slider.mjs +1 -0
- package/dist/gui/gui-tab-container.d.ts +26 -0
- package/dist/gui/gui-text-log.cjs +1 -0
- package/dist/gui/gui-text-log.d.ts +24 -0
- package/dist/gui/gui-text-log.mjs +1 -0
- package/dist/gui/gui-text.cjs +1 -0
- package/dist/gui/gui-text.d.ts +22 -0
- package/dist/gui/gui-text.mjs +1 -0
- package/dist/gui/gui-toggle.cjs +1 -0
- package/dist/gui/gui-toggle.d.ts +19 -0
- package/dist/gui/gui-toggle.mjs +1 -0
- package/dist/gui/labeled-control.cjs +1 -0
- package/dist/gui/labeled-control.d.ts +21 -0
- package/dist/gui/labeled-control.mjs +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.mjs +1 -0
- package/dist/panel/inspect-debugger.cjs +1 -0
- package/dist/panel/inspect-debugger.d.ts +30 -0
- package/dist/panel/inspect-debugger.mjs +1 -0
- package/dist/panel/inspect-panel.cjs +1 -0
- package/dist/panel/inspect-panel.d.ts +66 -0
- package/dist/panel/inspect-panel.mjs +1 -0
- package/dist/panel/state-manager.cjs +1 -0
- package/dist/panel/state-manager.d.ts +8 -0
- package/dist/panel/state-manager.mjs +1 -0
- package/dist/panel/widget-builder.cjs +1 -0
- package/dist/panel/widget-builder.d.ts +80 -0
- package/dist/panel/widget-builder.mjs +1 -0
- package/dist/themes/dark.cjs +1 -0
- package/dist/themes/dark.d.ts +4 -0
- package/dist/themes/dark.mjs +1 -0
- package/dist/themes/inspect-theme.d.ts +20 -0
- package/dist/types.cjs +1 -0
- package/dist/types.d.ts +354 -0
- package/dist/types.mjs +1 -0
- package/dist/utils/activity.cjs +1 -0
- package/dist/utils/activity.d.ts +4 -0
- package/dist/utils/activity.mjs +1 -0
- package/dist/utils/color-convert.cjs +1 -0
- package/dist/utils/color-convert.d.ts +31 -0
- package/dist/utils/color-convert.mjs +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/persistence.cjs +1 -0
- package/dist/utils/persistence.d.ts +16 -0
- package/dist/utils/persistence.mjs +1 -0
- package/dist/widgets/box.cjs +1 -0
- package/dist/widgets/box.d.ts +24 -0
- package/dist/widgets/box.mjs +1 -0
- package/dist/widgets/button.cjs +1 -0
- package/dist/widgets/button.d.ts +50 -0
- package/dist/widgets/button.mjs +1 -0
- package/dist/widgets/canvas-widget.cjs +1 -0
- package/dist/widgets/canvas-widget.d.ts +12 -0
- package/dist/widgets/canvas-widget.mjs +1 -0
- package/dist/widgets/label.cjs +1 -0
- package/dist/widgets/label.d.ts +41 -0
- package/dist/widgets/label.mjs +1 -0
- package/dist/widgets/number-input.cjs +1 -0
- package/dist/widgets/number-input.d.ts +65 -0
- package/dist/widgets/number-input.mjs +1 -0
- package/dist/widgets/overlay.d.ts +16 -0
- package/dist/widgets/scroll-area.cjs +1 -0
- package/dist/widgets/scroll-area.d.ts +80 -0
- package/dist/widgets/scroll-area.mjs +1 -0
- package/dist/widgets/separator.cjs +1 -0
- package/dist/widgets/separator.d.ts +16 -0
- package/dist/widgets/separator.mjs +1 -0
- package/dist/widgets/slider.cjs +1 -0
- package/dist/widgets/slider.d.ts +36 -0
- package/dist/widgets/slider.mjs +1 -0
- package/dist/widgets/tab-bar.cjs +1 -0
- package/dist/widgets/tab-bar.d.ts +72 -0
- package/dist/widgets/tab-bar.mjs +1 -0
- package/dist/widgets/text-input.cjs +1 -0
- package/dist/widgets/text-input.d.ts +54 -0
- package/dist/widgets/text-input.mjs +1 -0
- package/dist/widgets/toggle-button.d.ts +18 -0
- package/dist/widgets/toggle-icon.cjs +1 -0
- package/dist/widgets/toggle-icon.d.ts +38 -0
- package/dist/widgets/toggle-icon.mjs +1 -0
- package/package.json +95 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Surface } from './surface';
|
|
2
|
+
import { Widget } from './widget';
|
|
3
|
+
/**
|
|
4
|
+
* Routes pointer, wheel, and keyboard events from a canvas to the widget tree.
|
|
5
|
+
* Manages pointer capture, focus, and hover chain diffing.
|
|
6
|
+
*/
|
|
7
|
+
export declare class InputDispatcher {
|
|
8
|
+
private surface;
|
|
9
|
+
private focusedWidget;
|
|
10
|
+
private activePointers;
|
|
11
|
+
private activePointerCount;
|
|
12
|
+
private cachedRect;
|
|
13
|
+
private rectFrameId;
|
|
14
|
+
private _localX;
|
|
15
|
+
private _localY;
|
|
16
|
+
private oldHoverChain;
|
|
17
|
+
private newHoverChain;
|
|
18
|
+
private oldHoverLength;
|
|
19
|
+
private newHoverLength;
|
|
20
|
+
private onPointerDownBound;
|
|
21
|
+
private onPointerUpBound;
|
|
22
|
+
private onPointerMoveBound;
|
|
23
|
+
private onPointerCancelBound;
|
|
24
|
+
private onPointerLeaveBound;
|
|
25
|
+
private onWheelBound;
|
|
26
|
+
private onKeyDownBound;
|
|
27
|
+
private onKeyUpBound;
|
|
28
|
+
/** binds and attaches the canvas pointer, wheel, and keyboard listeners, and makes the canvas focusable. */
|
|
29
|
+
constructor(surface: Surface);
|
|
30
|
+
/** Transfers keyboard focus to the given widget, firing blur/focus callbacks. */
|
|
31
|
+
setFocus(widget: Widget | null): void;
|
|
32
|
+
/** Returns the number of currently captured pointers (active drags). */
|
|
33
|
+
getActivePointerCount(): number;
|
|
34
|
+
/** Removes all event listeners and clears hover/pointer state. */
|
|
35
|
+
dispose(): void;
|
|
36
|
+
/**
|
|
37
|
+
* Returns the canvas's screen rect for client-to-local coordinate mapping.
|
|
38
|
+
*
|
|
39
|
+
* The rect is cached to keep the high-frequency pointermove and wheel path
|
|
40
|
+
* off `getBoundingClientRect`, which can force a synchronous layout. The
|
|
41
|
+
* canvas's on-screen position can change with no content repaint (the panel
|
|
42
|
+
* is `position: fixed` and slides via a CSS transition, the page scrolls, the
|
|
43
|
+
* browser zooms), so a cache keyed only to `frameId` (which advances only on a
|
|
44
|
+
* repaint) goes stale and every hit test misses until something repaints. To
|
|
45
|
+
* stay correct, each interaction forces a fresh read at pointerdown via
|
|
46
|
+
* `forceRefresh`; the cache still serves drags and hover, and refreshes
|
|
47
|
+
* whenever a repaint advances `frameId`.
|
|
48
|
+
*/
|
|
49
|
+
private getRect;
|
|
50
|
+
/** maps a pointer event's client coordinates into canvas-local coordinates, stored in _localX/_localY. */
|
|
51
|
+
private computeLocalCoords;
|
|
52
|
+
/** index of the active pointer with the given id, or -1 when it is not captured. */
|
|
53
|
+
private findActivePointer;
|
|
54
|
+
/** fills chain with the ancestor path from the root down to widget and returns its depth. */
|
|
55
|
+
private buildChain;
|
|
56
|
+
/**
|
|
57
|
+
* Diffs the previous hover chain against the chain for the newly hit widget:
|
|
58
|
+
* everything below the shared prefix in the old chain gets a pointer-leave,
|
|
59
|
+
* and everything below it in the new chain gets a pointer-enter. The chains
|
|
60
|
+
* are then swapped so the new one becomes current.
|
|
61
|
+
*/
|
|
62
|
+
private updateHover;
|
|
63
|
+
/** fires pointer-leave up the current hover chain and empties it, used on pointerleave and dispose. */
|
|
64
|
+
private clearHoverChain;
|
|
65
|
+
/**
|
|
66
|
+
* Hit tests the press point, then walks up from the hit widget offering the
|
|
67
|
+
* event to each ancestor until one claims it. The claimer captures the
|
|
68
|
+
* pointer, is recorded as active, and receives focus when focusable.
|
|
69
|
+
*/
|
|
70
|
+
private handlePointerDown;
|
|
71
|
+
/** delivers pointer-up to the capturing widget, then releases the capture and frees the active-pointer slot. */
|
|
72
|
+
private handlePointerUp;
|
|
73
|
+
/** routes a move to the capturing widget during a drag, else updates hover and forwards it to the hit widget. */
|
|
74
|
+
private handlePointerMove;
|
|
75
|
+
/** drops a cancelled pointer's active slot without dispatching an up event. */
|
|
76
|
+
private handlePointerCancel;
|
|
77
|
+
/** walks up from the widget under the pointer offering the wheel delta; the first to consume it stops page scroll. */
|
|
78
|
+
private handleWheel;
|
|
79
|
+
/** offers key-down to the focused widget and its ancestors; first to consume prevents default (ctrl covers meta). */
|
|
80
|
+
private handleKeyDown;
|
|
81
|
+
/** forwards key-up to the focused widget only. */
|
|
82
|
+
private handleKeyUp;
|
|
83
|
+
/** deepest widget under the given canvas-local point, or null when there is no root. */
|
|
84
|
+
private findHit;
|
|
85
|
+
/** absolute x of a widget, used to convert canvas-local coordinates into widget-local ones. */
|
|
86
|
+
private widgetGlobalX;
|
|
87
|
+
/** absolute y of a widget, used to convert canvas-local coordinates into widget-local ones. */
|
|
88
|
+
private widgetGlobalY;
|
|
89
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
class e{surface;focusedWidget=null;activePointers=Array.from({length:10},()=>({id:0,widget:null}));activePointerCount=0;cachedRect=null;rectFrameId=-1;_localX=0;_localY=0;oldHoverChain=new Array(64).fill(null);newHoverChain=new Array(64).fill(null);oldHoverLength=0;newHoverLength=0;onPointerDownBound;onPointerUpBound;onPointerMoveBound;onPointerCancelBound;onPointerLeaveBound;onWheelBound;onKeyDownBound;onKeyUpBound;constructor(e){this.surface=e,this.onPointerDownBound=this.handlePointerDown.bind(this),this.onPointerUpBound=this.handlePointerUp.bind(this),this.onPointerMoveBound=this.handlePointerMove.bind(this),this.onPointerCancelBound=this.handlePointerCancel.bind(this),this.onPointerLeaveBound=this.clearHoverChain.bind(this),this.onWheelBound=this.handleWheel.bind(this),this.onKeyDownBound=this.handleKeyDown.bind(this),this.onKeyUpBound=this.handleKeyUp.bind(this);const t=e.canvas;t.style.touchAction="none",t.addEventListener("pointerdown",this.onPointerDownBound),t.addEventListener("pointerup",this.onPointerUpBound),t.addEventListener("pointermove",this.onPointerMoveBound),t.addEventListener("pointercancel",this.onPointerCancelBound),t.addEventListener("pointerleave",this.onPointerLeaveBound),t.addEventListener("wheel",this.onWheelBound,{passive:!1}),t.addEventListener("keydown",this.onKeyDownBound),t.addEventListener("keyup",this.onKeyUpBound),t.tabIndex=0}setFocus(e){this.focusedWidget!==e&&(this.focusedWidget&&(this.focusedWidget.focused=!1,this.focusedWidget.onBlur()),this.focusedWidget=e,e&&(e.focused=!0,e.onFocus()))}getActivePointerCount(){return this.activePointerCount}dispose(){const e=this.surface.canvas;e.removeEventListener("pointerdown",this.onPointerDownBound),e.removeEventListener("pointerup",this.onPointerUpBound),e.removeEventListener("pointermove",this.onPointerMoveBound),e.removeEventListener("pointercancel",this.onPointerCancelBound),e.removeEventListener("pointerleave",this.onPointerLeaveBound),e.removeEventListener("wheel",this.onWheelBound),e.removeEventListener("keydown",this.onKeyDownBound),e.removeEventListener("keyup",this.onKeyUpBound),this.activePointerCount=0,this.clearHoverChain()}getRect(e=!1){const t=this.surface.frameId;return!e&&this.cachedRect&&this.rectFrameId===t||(this.cachedRect=this.surface.canvas.getBoundingClientRect(),this.rectFrameId=t),this.cachedRect}computeLocalCoords(e,t=!1){const n=this.getRect(t);this._localX=e.clientX-n.left,this._localY=e.clientY-n.top}findActivePointer(e){for(let t=0;t<this.activePointerCount;t++)if(this.activePointers[t].id===e)return t;return-1}buildChain(e,t){let n=0,i=e;for(;i&&n<64;)t[n++]=i,i=i.parent;for(let e=0,i=n-1;e<i;e++,i--){const n=t[e];t[e]=t[i],t[i]=n}return n}updateHover(e){this.newHoverLength=this.buildChain(e,this.newHoverChain);const t=Math.min(this.oldHoverLength,this.newHoverLength);let n=0;for(;n<t&&this.oldHoverChain[n]===this.newHoverChain[n];)n++;for(let e=this.oldHoverLength-1;e>=n;e--){const t=this.oldHoverChain[e];t&&t.onPointerLeave()}for(let e=n;e<this.newHoverLength;e++){const t=this.newHoverChain[e];t&&t.onPointerEnter()}const i=this.oldHoverChain;this.oldHoverChain=this.newHoverChain,this.newHoverChain=i,this.oldHoverLength=this.newHoverLength;for(let e=0;e<this.newHoverLength;e++)this.newHoverChain[e]=null}clearHoverChain(){for(let e=this.oldHoverLength-1;e>=0;e--){const t=this.oldHoverChain[e];t&&t.onPointerLeave(),this.oldHoverChain[e]=null}this.oldHoverLength=0}handlePointerDown(e){if(this.activePointerCount>=10)return;this.computeLocalCoords(e,!0);const t=this._localX,n=this._localY,i=this.findHit(t,n);if(!i)return;let o=i;for(;o;){const i=t-this.widgetGlobalX(o),s=n-this.widgetGlobalY(o);if(o.onPointerDown(e.pointerId,i,s,e.button)){this.surface.canvas.setPointerCapture(e.pointerId);const t=this.activePointers[this.activePointerCount];return t.id=e.pointerId,t.widget=o,this.activePointerCount++,void(o.focusable&&this.setFocus(o))}o=o.parent}}handlePointerUp(e){const t=this.findActivePointer(e.pointerId);if(-1===t)return;const n=this.activePointers[t];this.computeLocalCoords(e);const i=this._localX,o=this._localY,s=n.widget;if(s.onPointerUp(e.pointerId,i-this.widgetGlobalX(s),o-this.widgetGlobalY(s),e.button),this.activePointerCount--,t<this.activePointerCount){const e=this.activePointers[this.activePointerCount];this.activePointers[t].id=e.id,this.activePointers[t].widget=e.widget}this.activePointers[this.activePointerCount].widget=null,this.surface.canvas.releasePointerCapture(e.pointerId)}handlePointerMove(e){this.computeLocalCoords(e);const t=this._localX,n=this._localY,i=this.findActivePointer(e.pointerId);if(-1!==i){const o=this.activePointers[i];return void o.widget.onPointerMove(e.pointerId,t-this.widgetGlobalX(o.widget),n-this.widgetGlobalY(o.widget))}const o=this.findHit(t,n);this.updateHover(o),o&&o.onPointerMove(e.pointerId,t-this.widgetGlobalX(o),n-this.widgetGlobalY(o))}handlePointerCancel(e){const t=this.findActivePointer(e.pointerId);if(-1!==t){if(this.activePointerCount--,t<this.activePointerCount){const e=this.activePointers[this.activePointerCount];this.activePointers[t].id=e.id,this.activePointers[t].widget=e.widget}this.activePointers[this.activePointerCount].widget=null}}handleWheel(e){const t=this.getRect(),n=e.clientX-t.left,i=e.clientY-t.top;let o=this.findHit(n,i);for(;o;){if(o.onWheel(e.deltaX,e.deltaY))return void e.preventDefault();o=o.parent}}handleKeyDown(e){let t=this.focusedWidget;for(;t;){if(t.onKeyDown(e.key,e.code,e.ctrlKey||e.metaKey,e.shiftKey,e.altKey))return void e.preventDefault();t=t.parent}}handleKeyUp(e){this.focusedWidget&&this.focusedWidget.onKeyUp(e.key,e.code)}findHit(e,t){return this.surface.getRoot()?.hitTest(e,t)??null}widgetGlobalX(e){return e.absoluteX}widgetGlobalY(e){return e.absoluteY}}export{e as InputDispatcher};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Widget } from './widget';
|
|
2
|
+
/** Strategy for computing child positions and sizes within a container widget. */
|
|
3
|
+
export interface Layout {
|
|
4
|
+
/** Assigns x, y, width, height to all flow children of the container. */
|
|
5
|
+
compute(container: Widget): void;
|
|
6
|
+
/** Returns the intrinsic width the layout would prefer, given current children. */
|
|
7
|
+
measureWidth(container: Widget): number;
|
|
8
|
+
/** Returns the intrinsic height the layout would prefer, given current children. */
|
|
9
|
+
measureHeight(container: Widget): number;
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("../widget.cjs");exports.StackLayout=class{direction;gap;justify;align;wrap;runGap;_flowChildren=[];_sizes=new Float64Array(32);_wrapLines=[];_wrapLineSizes=[];constructor(t,e=0,i="start",s="stretch",n=!1,r=0){this.direction=t,this.gap=e,this.justify=i,this.align=s,this.wrap=n,this.runGap=r}measureWidth(t){const e=t.children,i="horizontal"===this.direction;let s=0,n=0;for(let t=0;t<e.length;t++){const r=e[t];r.visible&&!r.absolute&&(n++,s+=i?r.measureIntrinsicWidth():r.measureIntrinsicHeight())}if(i)return s+Math.max(0,n-1)*this.gap;let r=0;for(let t=0;t<e.length;t++){if(!e[t].visible||e[t].absolute)continue;const i=e[t].measureIntrinsicWidth();i>r&&(r=i)}return r}measureHeight(t){const e=t.children,i="horizontal"===this.direction;let s=0,n=0;for(let t=0;t<e.length;t++){const i=e[t];i.visible&&!i.absolute&&(n++,s+=i.measureIntrinsicHeight())}if(!i)return s+Math.max(0,n-1)*this.gap;let r=0;for(let t=0;t<e.length;t++){if(!e[t].visible||e[t].absolute)continue;const i=e[t].measureIntrinsicHeight();i>r&&(r=i)}return r}compute(e){const i=e.children,s=e.geometry,n="horizontal"===this.direction,r=s[t.SLOT_WIDTH]-s[t.SLOT_PADDING_LEFT]-s[t.SLOT_PADDING_RIGHT],o=s[t.SLOT_HEIGHT]-s[t.SLOT_PADDING_TOP]-s[t.SLOT_PADDING_BOTTOM],a=n?r:o,_=n?o:r;let l=0;for(let t=0;t<i.length;t++)i[t].visible&&!i[t].absolute&&(this._flowChildren[l++]=i[t]);const h=this._flowChildren;this.wrap?this.computeWrapped(h,l,a,_,n):this.computeSingleLine(h,l,a,_,n)}computeSingleLine(e,i,s,n,r){const o=Math.max(0,i-1)*this.gap;i>this._sizes.length&&(this._sizes=new Float64Array(i));const a=this._sizes;a.fill(0,0,i);let _=0;for(let t=0;t<i;t++){const i=e[t];if("percent"===(r?i.sizingX:i.sizingY)){const e=(s-o)*(r?i.percentWidth:i.percentHeight);a[t]=e,_+=e}}let l=0,h=0;for(let s=0;s<i;s++){const i=e[s],n=i.geometry,o=r?i.sizingX:i.sizingY;if("percent"!==o)if("grow"===o)h+=n[t.SLOT_FLEX_GROW]>0?n[t.SLOT_FLEX_GROW]:1;else if(n[t.SLOT_FLEX_GROW]>0){h+=n[t.SLOT_FLEX_GROW];const e=r?i.measureIntrinsicWidth():i.measureIntrinsicHeight();a[s]=e,l+=e}else if("fixed"===o){const e=r?n[t.SLOT_PREFERRED_WIDTH]:n[t.SLOT_PREFERRED_HEIGHT];a[s]=e,l+=e}else{const t=r?i.measureIntrinsicWidth():i.measureIntrinsicHeight();a[s]=t,l+=t}}const c=Math.max(0,s-l-_-o);if(h>0)for(let s=0;s<i;s++){const i=e[s],n=i.geometry;if("grow"===(r?i.sizingX:i.sizingY)||n[t.SLOT_FLEX_GROW]>0){const e=n[t.SLOT_FLEX_GROW]>0?n[t.SLOT_FLEX_GROW]:1;a[s]+=e/h*c}}for(let s=0;s<i;s++){const i=e[s].geometry,n=r?i[t.SLOT_MIN_WIDTH]:i[t.SLOT_MIN_HEIGHT],o=r?i[t.SLOT_MAX_WIDTH]:i[t.SLOT_MAX_HEIGHT];a[s]=Math.max(n,Math.min(o,a[s]))}let T=o;for(let t=0;t<i;t++)T+=a[t];const L=T-s;L>0&&this.compressChildren(e,i,a,L,r),T=o;for(let t=0;t<i;t++)T+=a[t];let O=0;"center"===this.justify?O=Math.round((s-T)/2):"end"===this.justify&&(O=s-T);for(let t=0;t<i;t++)this.positionChild(e[t],a[t],O,n,r),O+=a[t]+this.gap}computeWrapped(e,i,s,n,r){const o=this._wrapLines;let a=0,_=0,l=0,h=0;for(let t=0;t<i;t++){const i=e[t],n=r?i.measureIntrinsicWidth():i.measureIntrinsicHeight(),c=h>0?this.gap:0;if(h>0&&l+c+n>s){a>=o.length&&o.push({startIndex:0,endIndex:0,mainUsed:0,crossExtent:0});const e=o[a];e.startIndex=_,e.endIndex=t,e.mainUsed=l,e.crossExtent=0,a++,_=t,l=n,h=1}else l+=c+n,h++}if(h>0){a>=o.length&&o.push({startIndex:0,endIndex:0,mainUsed:0,crossExtent:0});const t=o[a];t.startIndex=_,t.endIndex=i,t.mainUsed=l,t.crossExtent=0,a++}const c=this._wrapLineSizes;for(let i=0;i<a;i++){const n=o[i],a=n.startIndex,_=n.endIndex-a,l=Math.max(0,_-1)*this.gap;let h;i<c.length?(h=c[i],h.length<_&&(h=new Float64Array(_),c[i]=h)):(h=new Float64Array(Math.max(_,16)),c.push(h)),h.fill(0,0,_);let T=0,L=0;for(let i=0;i<_;i++){const n=e[a+i],o=n.geometry,_=r?n.sizingX:n.sizingY;if("grow"===_)L+=o[t.SLOT_FLEX_GROW]>0?o[t.SLOT_FLEX_GROW]:1;else if(o[t.SLOT_FLEX_GROW]>0){L+=o[t.SLOT_FLEX_GROW];const e=r?n.measureIntrinsicWidth():n.measureIntrinsicHeight();h[i]=e,T+=e}else if("fixed"===_){const e=r?o[t.SLOT_PREFERRED_WIDTH]:o[t.SLOT_PREFERRED_HEIGHT];h[i]=e,T+=e}else if("percent"===_){const t=(s-l)*(r?n.percentWidth:n.percentHeight);h[i]=t,T+=t}else{const t=r?n.measureIntrinsicWidth():n.measureIntrinsicHeight();h[i]=t,T+=t}}const O=Math.max(0,s-T-l);if(L>0)for(let i=0;i<_;i++){const s=e[a+i],n=s.geometry;if("grow"===(r?s.sizingX:s.sizingY)||n[t.SLOT_FLEX_GROW]>0){const e=n[t.SLOT_FLEX_GROW]>0?n[t.SLOT_FLEX_GROW]:1;h[i]+=e/L*O}}let I=0;for(let i=0;i<_;i++){const s=e[a+i].geometry,n=r?s[t.SLOT_MIN_WIDTH]:s[t.SLOT_MIN_HEIGHT],o=r?s[t.SLOT_MAX_WIDTH]:s[t.SLOT_MAX_HEIGHT];h[i]=Math.max(n,Math.min(o,h[i]));const _=r?e[a+i].measureIntrinsicHeight():e[a+i].measureIntrinsicWidth(),l=r?s[t.SLOT_PREFERRED_HEIGHT]:s[t.SLOT_PREFERRED_WIDTH],c=l>0?l:_;c>I&&(I=c)}n.crossExtent=I}let T=0;for(let i=0;i<a;i++){const n=o[i],a=n.startIndex,_=n.endIndex-a,l=c[i],h=n.crossExtent;let L=Math.max(0,_-1)*this.gap;for(let t=0;t<_;t++)L+=l[t];let O=0;"center"===this.justify?O=Math.round((s-L)/2):"end"===this.justify&&(O=s-L);for(let i=0;i<_;i++){const s=e[a+i],n=s.geometry,o=l[i],_=s.alignSelf??this.align,c=r?n[t.SLOT_PREFERRED_HEIGHT]:n[t.SLOT_PREFERRED_WIDTH];let L=h,I=0;"stretch"!==_&&c>0&&(L=Math.min(c,h)),"center"===_?I=Math.round((h-L)/2):"end"===_&&(I=h-L),r?(n[t.SLOT_X]=0|O,n[t.SLOT_Y]=T+I|0,n[t.SLOT_WIDTH]=0|o,n[t.SLOT_HEIGHT]=0|L):(n[t.SLOT_X]=T+I|0,n[t.SLOT_Y]=0|O,n[t.SLOT_WIDTH]=0|L,n[t.SLOT_HEIGHT]=0|o),s.needsLayout=!0,O+=o+this.gap}T+=h+this.runGap}}compressChildren(e,i,s,n,r){let o=n,a=0;for(let n=0;n<i;n++){const i=e[n].geometry[t.SLOT_FLEX_SHRINK];i>0&&(a+=i*s[n])}if(a<=0)return;let _=a;for(let n=0;n<i;n++){const i=e[n].geometry,a=i[t.SLOT_FLEX_SHRINK];if(a<=0)continue;const l=a*s[n],h=o*(l/_),c=r?i[t.SLOT_MIN_WIDTH]:i[t.SLOT_MIN_HEIGHT],T=Math.max(c,s[n]-h),L=s[n]-T;s[n]=T,o-=L,_-=l}}positionChild(e,i,s,n,r){const o=e.geometry,a=e.alignSelf??this.align,_=r?o[t.SLOT_PREFERRED_HEIGHT]:o[t.SLOT_PREFERRED_WIDTH];let l=n,h=0;"stretch"!==a&&_>0&&(l=Math.min(_,n)),"center"===a?h=Math.round((n-l)/2):"end"===a&&(h=n-l),r?(o[t.SLOT_X]=0|s,o[t.SLOT_Y]=0|h,o[t.SLOT_WIDTH]=0|i,o[t.SLOT_HEIGHT]=0|l):(o[t.SLOT_X]=0|h,o[t.SLOT_Y]=0|s,o[t.SLOT_WIDTH]=0|l,o[t.SLOT_HEIGHT]=0|i),e.needsLayout=!0}};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { Layout } from '../layout';
|
|
2
|
+
import { Widget } from '../widget';
|
|
3
|
+
/** Main-axis direction for stacking children. */
|
|
4
|
+
export type StackDirection = "horizontal" | "vertical";
|
|
5
|
+
/** Main-axis distribution of remaining space. */
|
|
6
|
+
export type StackJustify = "start" | "center" | "end";
|
|
7
|
+
/** Cross-axis alignment for children. */
|
|
8
|
+
export type StackAlign = "start" | "center" | "end" | "stretch";
|
|
9
|
+
/**
|
|
10
|
+
* Flexbox-style layout that stacks children along a single axis with optional
|
|
11
|
+
* wrapping, grow/shrink factors, percent sizing, and cross-axis alignment.
|
|
12
|
+
*/
|
|
13
|
+
export declare class StackLayout implements Layout {
|
|
14
|
+
readonly direction: StackDirection;
|
|
15
|
+
readonly gap: number;
|
|
16
|
+
readonly justify: StackJustify;
|
|
17
|
+
readonly align: StackAlign;
|
|
18
|
+
readonly wrap: boolean;
|
|
19
|
+
readonly runGap: number;
|
|
20
|
+
private _flowChildren;
|
|
21
|
+
private _sizes;
|
|
22
|
+
private _wrapLines;
|
|
23
|
+
private _wrapLineSizes;
|
|
24
|
+
/**
|
|
25
|
+
* @param direction main axis to stack along
|
|
26
|
+
* @param gap space between adjacent children on the main axis
|
|
27
|
+
* @param justify distribution of leftover main-axis space
|
|
28
|
+
* @param align default cross-axis alignment for children
|
|
29
|
+
* @param wrap whether children flow onto multiple lines when they overflow
|
|
30
|
+
* @param runGap space between wrapped lines on the cross axis
|
|
31
|
+
*/
|
|
32
|
+
constructor(direction: StackDirection, gap?: number, justify?: StackJustify, align?: StackAlign, wrap?: boolean, runGap?: number);
|
|
33
|
+
/** returns the intrinsic width of the container's children for this layout. */
|
|
34
|
+
measureWidth(container: Widget): number;
|
|
35
|
+
/** returns the intrinsic height of the container's children for this layout. */
|
|
36
|
+
measureHeight(container: Widget): number;
|
|
37
|
+
/** positions and sizes the container's children along the main axis. */
|
|
38
|
+
compute(container: Widget): void;
|
|
39
|
+
/**
|
|
40
|
+
* Lays out all children on a single line. Percent children take a fraction of
|
|
41
|
+
* the main size, fixed and fit children take their preferred or intrinsic
|
|
42
|
+
* size, and grow children share the leftover space by flex weight. Sizes are
|
|
43
|
+
* clamped to each child's min/max, and any remaining overflow is resolved by
|
|
44
|
+
* compressChildren before positioning them per the justify setting.
|
|
45
|
+
*/
|
|
46
|
+
private computeSingleLine;
|
|
47
|
+
/**
|
|
48
|
+
* Lays out children across multiple lines. Children are first packed into
|
|
49
|
+
* lines that fit within mainSize, then each line resolves its own grow and
|
|
50
|
+
* min/max sizing and its tallest cross extent. Lines are stacked on the cross
|
|
51
|
+
* axis separated by runGap, with per-child cross alignment applied within each
|
|
52
|
+
* line. Cached per-line buffers are grown as needed to avoid re-allocation.
|
|
53
|
+
*/
|
|
54
|
+
private computeWrapped;
|
|
55
|
+
/**
|
|
56
|
+
* Shrinks children to absorb a main-axis overflow. Each child's share is
|
|
57
|
+
* weighted by its flex-shrink factor times its current size, so larger and
|
|
58
|
+
* more shrinkable children give up more, and no child shrinks below its
|
|
59
|
+
* minimum. Children with a zero shrink factor are left untouched.
|
|
60
|
+
*/
|
|
61
|
+
private compressChildren;
|
|
62
|
+
/**
|
|
63
|
+
* Writes one child's geometry: its main-axis size and position come from the
|
|
64
|
+
* caller, while its cross-axis extent and offset come from alignSelf (falling
|
|
65
|
+
* back to the layout's align). Non-stretch children keep their preferred cross
|
|
66
|
+
* size, then are centered or end-aligned within the available cross space.
|
|
67
|
+
*/
|
|
68
|
+
private positionChild;
|
|
69
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{SLOT_WIDTH as t,SLOT_PADDING_LEFT as e,SLOT_PADDING_RIGHT as i,SLOT_HEIGHT as s,SLOT_PADDING_TOP as n,SLOT_PADDING_BOTTOM as r,SLOT_FLEX_GROW as o,SLOT_PREFERRED_WIDTH as a,SLOT_PREFERRED_HEIGHT as h,SLOT_MIN_WIDTH as l,SLOT_MIN_HEIGHT as c,SLOT_MAX_WIDTH as g,SLOT_MAX_HEIGHT as d,SLOT_X as f,SLOT_Y as m,SLOT_FLEX_SHRINK as u}from"../widget.mjs";class p{direction;gap;justify;align;wrap;runGap;_flowChildren=[];_sizes=new Float64Array(32);_wrapLines=[];_wrapLineSizes=[];constructor(t,e=0,i="start",s="stretch",n=!1,r=0){this.direction=t,this.gap=e,this.justify=i,this.align=s,this.wrap=n,this.runGap=r}measureWidth(t){const e=t.children,i="horizontal"===this.direction;let s=0,n=0;for(let t=0;t<e.length;t++){const r=e[t];r.visible&&!r.absolute&&(n++,s+=i?r.measureIntrinsicWidth():r.measureIntrinsicHeight())}if(i)return s+Math.max(0,n-1)*this.gap;let r=0;for(let t=0;t<e.length;t++){if(!e[t].visible||e[t].absolute)continue;const i=e[t].measureIntrinsicWidth();i>r&&(r=i)}return r}measureHeight(t){const e=t.children,i="horizontal"===this.direction;let s=0,n=0;for(let t=0;t<e.length;t++){const i=e[t];i.visible&&!i.absolute&&(n++,s+=i.measureIntrinsicHeight())}if(!i)return s+Math.max(0,n-1)*this.gap;let r=0;for(let t=0;t<e.length;t++){if(!e[t].visible||e[t].absolute)continue;const i=e[t].measureIntrinsicHeight();i>r&&(r=i)}return r}compute(o){const a=o.children,h=o.geometry,l="horizontal"===this.direction,c=h[t]-h[e]-h[i],g=h[s]-h[n]-h[r],d=l?c:g,f=l?g:c;let m=0;for(let t=0;t<a.length;t++)a[t].visible&&!a[t].absolute&&(this._flowChildren[m++]=a[t]);const u=this._flowChildren;this.wrap?this.computeWrapped(u,m,d,f,l):this.computeSingleLine(u,m,d,f,l)}computeSingleLine(t,e,i,s,n){const r=Math.max(0,e-1)*this.gap;e>this._sizes.length&&(this._sizes=new Float64Array(e));const f=this._sizes;f.fill(0,0,e);let m=0;for(let s=0;s<e;s++){const e=t[s];if("percent"===(n?e.sizingX:e.sizingY)){const t=(i-r)*(n?e.percentWidth:e.percentHeight);f[s]=t,m+=t}}let u=0,p=0;for(let i=0;i<e;i++){const e=t[i],s=e.geometry,r=n?e.sizingX:e.sizingY;if("percent"!==r)if("grow"===r)p+=s[o]>0?s[o]:1;else if(s[o]>0){p+=s[o];const t=n?e.measureIntrinsicWidth():e.measureIntrinsicHeight();f[i]=t,u+=t}else if("fixed"===r){const t=n?s[a]:s[h];f[i]=t,u+=t}else{const t=n?e.measureIntrinsicWidth():e.measureIntrinsicHeight();f[i]=t,u+=t}}const x=Math.max(0,i-u-m-r);if(p>0)for(let i=0;i<e;i++){const e=t[i],s=e.geometry;if("grow"===(n?e.sizingX:e.sizingY)||s[o]>0){const t=s[o]>0?s[o]:1;f[i]+=t/p*x}}for(let i=0;i<e;i++){const e=t[i].geometry,s=n?e[l]:e[c],r=n?e[g]:e[d];f[i]=Math.max(s,Math.min(r,f[i]))}let I=r;for(let t=0;t<e;t++)I+=f[t];const y=I-i;y>0&&this.compressChildren(t,e,f,y,n),I=r;for(let t=0;t<e;t++)I+=f[t];let w=0;"center"===this.justify?w=Math.round((i-I)/2):"end"===this.justify&&(w=i-I);for(let i=0;i<e;i++)this.positionChild(t[i],f[i],w,s,n),w+=f[i]+this.gap}computeWrapped(e,i,n,r,u){const p=this._wrapLines;let x=0,I=0,y=0,w=0;for(let t=0;t<i;t++){const i=e[t],s=u?i.measureIntrinsicWidth():i.measureIntrinsicHeight(),r=w>0?this.gap:0;if(w>0&&y+r+s>n){x>=p.length&&p.push({startIndex:0,endIndex:0,mainUsed:0,crossExtent:0});const e=p[x];e.startIndex=I,e.endIndex=t,e.mainUsed=y,e.crossExtent=0,x++,I=t,y=s,w=1}else y+=r+s,w++}if(w>0){x>=p.length&&p.push({startIndex:0,endIndex:0,mainUsed:0,crossExtent:0});const t=p[x];t.startIndex=I,t.endIndex=i,t.mainUsed=y,t.crossExtent=0,x++}const z=this._wrapLineSizes;for(let t=0;t<x;t++){const i=p[t],s=i.startIndex,r=i.endIndex-s,f=Math.max(0,r-1)*this.gap;let m;t<z.length?(m=z[t],m.length<r&&(m=new Float64Array(r),z[t]=m)):(m=new Float64Array(Math.max(r,16)),z.push(m)),m.fill(0,0,r);let x=0,I=0;for(let t=0;t<r;t++){const i=e[s+t],r=i.geometry,l=u?i.sizingX:i.sizingY;if("grow"===l)I+=r[o]>0?r[o]:1;else if(r[o]>0){I+=r[o];const e=u?i.measureIntrinsicWidth():i.measureIntrinsicHeight();m[t]=e,x+=e}else if("fixed"===l){const e=u?r[a]:r[h];m[t]=e,x+=e}else if("percent"===l){const e=(n-f)*(u?i.percentWidth:i.percentHeight);m[t]=e,x+=e}else{const e=u?i.measureIntrinsicWidth():i.measureIntrinsicHeight();m[t]=e,x+=e}}const y=Math.max(0,n-x-f);if(I>0)for(let t=0;t<r;t++){const i=e[s+t],n=i.geometry;if("grow"===(u?i.sizingX:i.sizingY)||n[o]>0){const e=n[o]>0?n[o]:1;m[t]+=e/I*y}}let w=0;for(let t=0;t<r;t++){const i=e[s+t].geometry,n=u?i[l]:i[c],r=u?i[g]:i[d];m[t]=Math.max(n,Math.min(r,m[t]));const o=u?e[s+t].measureIntrinsicHeight():e[s+t].measureIntrinsicWidth(),f=u?i[h]:i[a],p=f>0?f:o;p>w&&(w=p)}i.crossExtent=w}let M=0;for(let i=0;i<x;i++){const r=p[i],o=r.startIndex,l=r.endIndex-o,c=z[i],g=r.crossExtent;let d=Math.max(0,l-1)*this.gap;for(let t=0;t<l;t++)d+=c[t];let x=0;"center"===this.justify?x=Math.round((n-d)/2):"end"===this.justify&&(x=n-d);for(let i=0;i<l;i++){const n=e[o+i],r=n.geometry,l=c[i],d=n.alignSelf??this.align,p=u?r[h]:r[a];let I=g,y=0;"stretch"!==d&&p>0&&(I=Math.min(p,g)),"center"===d?y=Math.round((g-I)/2):"end"===d&&(y=g-I),u?(r[f]=0|x,r[m]=M+y|0,r[t]=0|l,r[s]=0|I):(r[f]=M+y|0,r[m]=0|x,r[t]=0|I,r[s]=0|l),n.needsLayout=!0,x+=l+this.gap}M+=g+this.runGap}}compressChildren(t,e,i,s,n){let r=s,o=0;for(let s=0;s<e;s++){const e=t[s].geometry[u];e>0&&(o+=e*i[s])}if(o<=0)return;let a=o;for(let s=0;s<e;s++){const e=t[s].geometry,o=e[u];if(o<=0)continue;const h=o*i[s],g=r*(h/a),d=n?e[l]:e[c],f=Math.max(d,i[s]-g),m=i[s]-f;i[s]=f,r-=m,a-=h}}positionChild(e,i,n,r,o){const l=e.geometry,c=e.alignSelf??this.align,g=o?l[h]:l[a];let d=r,u=0;"stretch"!==c&&g>0&&(d=Math.min(g,r)),"center"===c?u=Math.round((r-d)/2):"end"===c&&(u=r-d),o?(l[f]=0|n,l[m]=0|u,l[t]=0|i,l[s]=0|d):(l[f]=0|u,l[m]=0|n,l[t]=0|d,l[s]=0|i),e.needsLayout=!0}}export{p as StackLayout};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { FontAtlas, TextureAtlas } from './atlas';
|
|
2
|
+
/**
|
|
3
|
+
* Abstract drawing backend for the widget system.
|
|
4
|
+
* Supports filled/stroked primitives, text, clipping, alpha, and transforms.
|
|
5
|
+
*/
|
|
6
|
+
export interface Renderer {
|
|
7
|
+
/** starts a full-frame pass, clearing the whole target to transparent. */
|
|
8
|
+
begin(width: number, height: number): void;
|
|
9
|
+
/** starts a partial pass clipped to the given rect, clearing only that region. */
|
|
10
|
+
beginPartial(x: number, y: number, width: number, height: number): void;
|
|
11
|
+
/** ends the current pass, restoring any state saved by beginPartial. */
|
|
12
|
+
end(): void;
|
|
13
|
+
/** fills an axis-aligned rectangle with a packed RGBA color (0xRRGGBBAA). */
|
|
14
|
+
fillRect(x: number, y: number, width: number, height: number, color: number): void;
|
|
15
|
+
/** strokes a rectangle outline centered on its edges with the given line width. */
|
|
16
|
+
strokeRect(x: number, y: number, width: number, height: number, color: number, lineWidth: number): void;
|
|
17
|
+
/** fills a rectangle with corners rounded to radius (clamped to half the smaller side). */
|
|
18
|
+
fillRoundedRect(x: number, y: number, width: number, height: number, radius: number, color: number): void;
|
|
19
|
+
/** strokes a rounded-rectangle outline. */
|
|
20
|
+
strokeRoundedRect(x: number, y: number, width: number, height: number, radius: number, color: number, lineWidth: number): void;
|
|
21
|
+
/** blits a source sub-region of an atlas image into a destination rectangle. */
|
|
22
|
+
drawImage(atlas: TextureAtlas, srcX: number, srcY: number, srcWidth: number, srcHeight: number, dstX: number, dstY: number, dstWidth: number, dstHeight: number): void;
|
|
23
|
+
/** draws monospace text with top-left at (x, y), recolored, with optional scale and letter spacing. */
|
|
24
|
+
drawText(atlas: FontAtlas, text: string, x: number, y: number, color: number, scale?: number, letterSpacing?: number): void;
|
|
25
|
+
/** strokes a straight line between two points. */
|
|
26
|
+
drawLine(x1: number, y1: number, x2: number, y2: number, color: number, lineWidth: number): void;
|
|
27
|
+
/** fills a circle at (cx, cy). */
|
|
28
|
+
fillCircle(cx: number, cy: number, radius: number, color: number): void;
|
|
29
|
+
/** strokes a circle outline at (cx, cy). */
|
|
30
|
+
strokeCircle(cx: number, cy: number, radius: number, color: number, lineWidth: number): void;
|
|
31
|
+
/** strokes a circular arc from startAngle to endAngle (radians), with an optional line cap. */
|
|
32
|
+
strokeArc(cx: number, cy: number, radius: number, startAngle: number, endAngle: number, color: number, lineWidth: number, lineCap?: "butt" | "round" | "square"): void;
|
|
33
|
+
/** starts a new path for the moveTo/lineTo/strokePath/fillPath primitives. */
|
|
34
|
+
beginPath(): void;
|
|
35
|
+
/** starts a new subpath at the given point. */
|
|
36
|
+
moveTo(x: number, y: number): void;
|
|
37
|
+
/** adds a straight segment from the current point to the given point. */
|
|
38
|
+
lineTo(x: number, y: number): void;
|
|
39
|
+
/** strokes the current path. */
|
|
40
|
+
strokePath(color: number, lineWidth: number): void;
|
|
41
|
+
/** fills the current path. */
|
|
42
|
+
fillPath(color: number): void;
|
|
43
|
+
/** pushes a rectangular clip region onto the clip stack. */
|
|
44
|
+
pushClip(x: number, y: number, width: number, height: number): void;
|
|
45
|
+
/** pops the most recently pushed clip region. */
|
|
46
|
+
popClip(): void;
|
|
47
|
+
/** pushes a translation and a clip rect (in the translated space) as one stack entry. */
|
|
48
|
+
pushTranslateClip(tx: number, ty: number, cx: number, cy: number, cw: number, ch: number): void;
|
|
49
|
+
/** pops a pushTranslateClip entry. */
|
|
50
|
+
popTranslateClip(): void;
|
|
51
|
+
/** multiplies the current alpha by the given factor and pushes the previous value. */
|
|
52
|
+
pushAlpha(alpha: number): void;
|
|
53
|
+
/** restores the alpha saved by the matching pushAlpha. */
|
|
54
|
+
popAlpha(): void;
|
|
55
|
+
/** pushes a translation onto the transform stack. */
|
|
56
|
+
pushTranslate(x: number, y: number): void;
|
|
57
|
+
/** pops the most recent translation. */
|
|
58
|
+
popTranslate(): void;
|
|
59
|
+
/** pushes a scale onto the transform stack. */
|
|
60
|
+
pushScale(scaleX: number, scaleY: number): void;
|
|
61
|
+
/** pops the most recent scale. */
|
|
62
|
+
popScale(): void;
|
|
63
|
+
/** releases cached resources held by the backend. */
|
|
64
|
+
dispose(): void;
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";function t(t,e,i,h,s,r,n,a){return!(t>s+n||t+i<s||e>r+a||e+h<r)}function e(t,e){const i=Math.min(t.x,e.x),h=Math.min(t.y,e.y),s=Math.max(t.x+t.width,e.x+e.width),r=Math.max(t.y+t.height,e.y+e.height);t.x=i,t.y=h,t.width=s-i,t.height=r-h}Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"}),exports.Surface=class{canvas;renderer;onAfterFlush=null;root=null;resizeObserver;_width=0;_height=0;theme;_frameId=0;animationFrameId=0;animationFrameScheduled=!1;_boundFlush=()=>{this.animationFrameScheduled=!1,this.flush()};dirtyRectsA=[];dirtyRectsB=[];dirtyRects=this.dirtyRectsA;dirtyRectCount=0;fullRepaint=!0;frameDirtyRects=this.dirtyRectsB;frameDirtyRectCount=0;frameIsFullRepaint=!0;dirtyRectPool=Array.from({length:32},()=>({x:0,y:0,width:0,height:0}));scratchRect={x:0,y:0,width:0,height:0};_flushInfo={isFullRepaint:!1,dirtyRects:[],dirtyRectCount:0,canvasWidth:0,canvasHeight:0,flushTimeMs:0};constructor(t,e,i){this.canvas=t,this.renderer=e,this.theme=i,this.resizeObserver=new ResizeObserver(t=>{const e=t[0].contentRect;this._width=0|e.width,this._height=0|e.height,this.fullRepaint=!0,this.scheduleFrame()}),this.resizeObserver.observe(this.canvas)}get width(){return this._width}get height(){return this._height}get frameId(){return this._frameId}getTheme(){return this.theme}getRoot(){return this.root}isRectInDirtyArea(t,e,i,h){if(this.frameIsFullRepaint)return!0;for(let s=0;s<this.frameDirtyRectCount;s++){const r=this.frameDirtyRects[s];if(!(t>=r.x+r.width||t+i<=r.x||e>=r.y+r.height||e+h<=r.y))return!0}return!1}setRoot(t){this.root&&this.root.setSurface(null),this.root=t,t.setSurface(this),t.needsLayout=!0,this.fullRepaint=!0,this.scheduleFrame()}setTheme(t){this.theme=t,this.fullRepaint=!0,this.scheduleFrame()}markDirty(){this.fullRepaint=!0,this.scheduleFrame()}markDirtyRect(i,h,s,r){if(this.fullRepaint)this.scheduleFrame();else if(!(i+s<=0||h+r<=0||i>=this._width||h>=this._height)){this.scratchRect.x=i,this.scratchRect.y=h,this.scratchRect.width=s,this.scratchRect.height=r;for(let n=0;n<this.dirtyRectCount;n++){const a=this.dirtyRects[n];if(t(i,h,s,r,a.x,a.y,a.width,a.height))return e(a,this.scratchRect),this.mergeOverlapping(n),void this.scheduleFrame()}if(this.dirtyRectCount>=32)this.fullRepaint=!0;else{const t=this.dirtyRectPool[this.dirtyRectCount];t.x=i,t.y=h,t.width=s,t.height=r,this.dirtyRects[this.dirtyRectCount]=t,this.dirtyRectCount++}this.scheduleFrame()}}mergeOverlapping(i){let h=!0;for(;h;){h=!1;const s=this.dirtyRects[i];for(let r=this.dirtyRectCount-1;r>=0;r--){if(r===i)continue;const n=this.dirtyRects[r];t(s.x,s.y,s.width,s.height,n.x,n.y,n.width,n.height)&&(e(s,n),this.dirtyRectCount--,r<this.dirtyRectCount&&(this.dirtyRects[r]=this.dirtyRects[this.dirtyRectCount]),r<i&&i--,h=!0)}}}dispose(){this.resizeObserver.disconnect(),this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=0),this.animationFrameScheduled=!1,this.root&&this.root.setSurface(null),this.renderer.dispose()}scheduleFrame(){this.animationFrameScheduled||(this.animationFrameScheduled=!0,this.animationFrameId=requestAnimationFrame(this._boundFlush))}flush(){if(!this.fullRepaint&&0===this.dirtyRectCount)return;if(!this.root)return;const t=this._width,e=this._height;if(0===t||0===e)return void this.scheduleFrame();this.canvas.width===t&&this.canvas.height===e||(this.canvas.width=t,this.canvas.height=e,this.fullRepaint=!0),this.root.width===t&&this.root.height===e||(this.root.width=t,this.root.height=e,this.root.needsLayout=!0),this.root.computeLayout(),this.frameIsFullRepaint=this.fullRepaint;const i=this.frameDirtyRects;this.frameDirtyRects=this.dirtyRects,this.frameDirtyRectCount=this.dirtyRectCount,this.dirtyRects=i,this.dirtyRectCount=0,this.fullRepaint=!1;const h=this.onAfterFlush?performance.now():0;if(this.frameIsFullRepaint)this.renderer.begin(t,e),this.root.draw(this.renderer,this.theme),this.renderer.end();else for(let i=0;i<this.frameDirtyRectCount;i++){const h=this.frameDirtyRects[i],s=Math.max(0,0|h.x),r=Math.max(0,0|h.y),n=Math.min(t-s,0|h.width),a=Math.min(e-r,0|h.height);n>0&&a>0&&(this.renderer.beginPartial(s,r,n,a),this.root.draw(this.renderer,this.theme),this.renderer.end())}this.onAfterFlush&&(this._flushInfo.isFullRepaint=this.frameIsFullRepaint,this._flushInfo.dirtyRects=this.frameDirtyRects,this._flushInfo.dirtyRectCount=this.frameDirtyRectCount,this._flushInfo.canvasWidth=t,this._flushInfo.canvasHeight=e,this._flushInfo.flushTimeMs=performance.now()-h,this.onAfterFlush(this._flushInfo)),this._frameId++}};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Renderer } from './renderer';
|
|
2
|
+
import { Theme } from './theme';
|
|
3
|
+
import { Widget } from './widget';
|
|
4
|
+
/** Diagnostic information emitted after each frame flush. */
|
|
5
|
+
export interface FlushInfo {
|
|
6
|
+
isFullRepaint: boolean;
|
|
7
|
+
dirtyRects: ReadonlyArray<{
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
}>;
|
|
13
|
+
dirtyRectCount: number;
|
|
14
|
+
canvasWidth: number;
|
|
15
|
+
canvasHeight: number;
|
|
16
|
+
flushTimeMs: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Manages a canvas element, dirty-rect tracking, resize observation, and
|
|
20
|
+
* per-frame rendering of the widget tree via requestAnimationFrame.
|
|
21
|
+
*/
|
|
22
|
+
export declare class Surface {
|
|
23
|
+
readonly canvas: HTMLCanvasElement;
|
|
24
|
+
readonly renderer: Renderer;
|
|
25
|
+
onAfterFlush: ((info: FlushInfo) => void) | null;
|
|
26
|
+
private root;
|
|
27
|
+
private resizeObserver;
|
|
28
|
+
private _width;
|
|
29
|
+
private _height;
|
|
30
|
+
private theme;
|
|
31
|
+
private _frameId;
|
|
32
|
+
private animationFrameId;
|
|
33
|
+
private animationFrameScheduled;
|
|
34
|
+
private readonly _boundFlush;
|
|
35
|
+
private dirtyRectsA;
|
|
36
|
+
private dirtyRectsB;
|
|
37
|
+
private dirtyRects;
|
|
38
|
+
private dirtyRectCount;
|
|
39
|
+
private fullRepaint;
|
|
40
|
+
private frameDirtyRects;
|
|
41
|
+
private frameDirtyRectCount;
|
|
42
|
+
private frameIsFullRepaint;
|
|
43
|
+
private dirtyRectPool;
|
|
44
|
+
private scratchRect;
|
|
45
|
+
private _flushInfo;
|
|
46
|
+
/** wires up the canvas, renderer, and theme, and observes the canvas for size changes that force a full repaint. */
|
|
47
|
+
constructor(canvas: HTMLCanvasElement, renderer: Renderer, theme: Theme);
|
|
48
|
+
/** current canvas width in pixels, as reported by the resize observer. */
|
|
49
|
+
get width(): number;
|
|
50
|
+
/** current canvas height in pixels, as reported by the resize observer. */
|
|
51
|
+
get height(): number;
|
|
52
|
+
/** monotonically increasing counter, bumped once per completed flush. */
|
|
53
|
+
get frameId(): number;
|
|
54
|
+
/** returns the active theme. */
|
|
55
|
+
getTheme(): Theme;
|
|
56
|
+
/** returns the root widget, or null if none is set. */
|
|
57
|
+
getRoot(): Widget | null;
|
|
58
|
+
/** Returns true if the given rect overlaps any dirty region in the current frame. */
|
|
59
|
+
isRectInDirtyArea(x: number, y: number, width: number, height: number): boolean;
|
|
60
|
+
/** replaces the root widget, detaching the previous one, and schedules a full repaint. */
|
|
61
|
+
setRoot(widget: Widget): void;
|
|
62
|
+
/** swaps the active theme and schedules a full repaint. */
|
|
63
|
+
setTheme(theme: Theme): void;
|
|
64
|
+
/** flags the whole surface for repaint on the next frame. */
|
|
65
|
+
markDirty(): void;
|
|
66
|
+
/** Marks a rectangular region for partial repaint; merges with overlapping rects. */
|
|
67
|
+
markDirtyRect(x: number, y: number, width: number, height: number): void;
|
|
68
|
+
/**
|
|
69
|
+
* After a rect at changedIndex grows, folds any other tracked rects it now
|
|
70
|
+
* overlaps into it, repeating until no more merges apply. Removed entries are
|
|
71
|
+
* filled from the end of the list, so the changed index is adjusted when the
|
|
72
|
+
* moved entry sat before it.
|
|
73
|
+
*/
|
|
74
|
+
private mergeOverlapping;
|
|
75
|
+
/** stops observation, cancels any pending frame, and disposes the renderer. */
|
|
76
|
+
dispose(): void;
|
|
77
|
+
/** requests a single animation frame to run flush, coalescing repeated calls within a frame. */
|
|
78
|
+
private scheduleFrame;
|
|
79
|
+
/** Performs layout and rendering for all accumulated dirty regions, then resets state. */
|
|
80
|
+
flush(): void;
|
|
81
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function t(t,i,e,h,s,r,n,a){return!(t>s+n||t+e<s||i>r+a||i+h<r)}function i(t,i){const e=Math.min(t.x,i.x),h=Math.min(t.y,i.y),s=Math.max(t.x+t.width,i.x+i.width),r=Math.max(t.y+t.height,i.y+i.height);t.x=e,t.y=h,t.width=s-e,t.height=r-h}class e{canvas;renderer;onAfterFlush=null;root=null;resizeObserver;_width=0;_height=0;theme;_frameId=0;animationFrameId=0;animationFrameScheduled=!1;_boundFlush=()=>{this.animationFrameScheduled=!1,this.flush()};dirtyRectsA=[];dirtyRectsB=[];dirtyRects=this.dirtyRectsA;dirtyRectCount=0;fullRepaint=!0;frameDirtyRects=this.dirtyRectsB;frameDirtyRectCount=0;frameIsFullRepaint=!0;dirtyRectPool=Array.from({length:32},()=>({x:0,y:0,width:0,height:0}));scratchRect={x:0,y:0,width:0,height:0};_flushInfo={isFullRepaint:!1,dirtyRects:[],dirtyRectCount:0,canvasWidth:0,canvasHeight:0,flushTimeMs:0};constructor(t,i,e){this.canvas=t,this.renderer=i,this.theme=e,this.resizeObserver=new ResizeObserver(t=>{const i=t[0].contentRect;this._width=0|i.width,this._height=0|i.height,this.fullRepaint=!0,this.scheduleFrame()}),this.resizeObserver.observe(this.canvas)}get width(){return this._width}get height(){return this._height}get frameId(){return this._frameId}getTheme(){return this.theme}getRoot(){return this.root}isRectInDirtyArea(t,i,e,h){if(this.frameIsFullRepaint)return!0;for(let s=0;s<this.frameDirtyRectCount;s++){const r=this.frameDirtyRects[s];if(!(t>=r.x+r.width||t+e<=r.x||i>=r.y+r.height||i+h<=r.y))return!0}return!1}setRoot(t){this.root&&this.root.setSurface(null),this.root=t,t.setSurface(this),t.needsLayout=!0,this.fullRepaint=!0,this.scheduleFrame()}setTheme(t){this.theme=t,this.fullRepaint=!0,this.scheduleFrame()}markDirty(){this.fullRepaint=!0,this.scheduleFrame()}markDirtyRect(e,h,s,r){if(this.fullRepaint)this.scheduleFrame();else if(!(e+s<=0||h+r<=0||e>=this._width||h>=this._height)){this.scratchRect.x=e,this.scratchRect.y=h,this.scratchRect.width=s,this.scratchRect.height=r;for(let n=0;n<this.dirtyRectCount;n++){const a=this.dirtyRects[n];if(t(e,h,s,r,a.x,a.y,a.width,a.height))return i(a,this.scratchRect),this.mergeOverlapping(n),void this.scheduleFrame()}if(this.dirtyRectCount>=32)this.fullRepaint=!0;else{const t=this.dirtyRectPool[this.dirtyRectCount];t.x=e,t.y=h,t.width=s,t.height=r,this.dirtyRects[this.dirtyRectCount]=t,this.dirtyRectCount++}this.scheduleFrame()}}mergeOverlapping(e){let h=!0;for(;h;){h=!1;const s=this.dirtyRects[e];for(let r=this.dirtyRectCount-1;r>=0;r--){if(r===e)continue;const n=this.dirtyRects[r];t(s.x,s.y,s.width,s.height,n.x,n.y,n.width,n.height)&&(i(s,n),this.dirtyRectCount--,r<this.dirtyRectCount&&(this.dirtyRects[r]=this.dirtyRects[this.dirtyRectCount]),r<e&&e--,h=!0)}}}dispose(){this.resizeObserver.disconnect(),this.animationFrameId&&(cancelAnimationFrame(this.animationFrameId),this.animationFrameId=0),this.animationFrameScheduled=!1,this.root&&this.root.setSurface(null),this.renderer.dispose()}scheduleFrame(){this.animationFrameScheduled||(this.animationFrameScheduled=!0,this.animationFrameId=requestAnimationFrame(this._boundFlush))}flush(){if(!this.fullRepaint&&0===this.dirtyRectCount)return;if(!this.root)return;const t=this._width,i=this._height;if(0===t||0===i)return void this.scheduleFrame();this.canvas.width===t&&this.canvas.height===i||(this.canvas.width=t,this.canvas.height=i,this.fullRepaint=!0),this.root.width===t&&this.root.height===i||(this.root.width=t,this.root.height=i,this.root.needsLayout=!0),this.root.computeLayout(),this.frameIsFullRepaint=this.fullRepaint;const e=this.frameDirtyRects;this.frameDirtyRects=this.dirtyRects,this.frameDirtyRectCount=this.dirtyRectCount,this.dirtyRects=e,this.dirtyRectCount=0,this.fullRepaint=!1;const h=this.onAfterFlush?performance.now():0;if(this.frameIsFullRepaint)this.renderer.begin(t,i),this.root.draw(this.renderer,this.theme),this.renderer.end();else for(let e=0;e<this.frameDirtyRectCount;e++){const h=this.frameDirtyRects[e],s=Math.max(0,0|h.x),r=Math.max(0,0|h.y),n=Math.min(t-s,0|h.width),a=Math.min(i-r,0|h.height);n>0&&a>0&&(this.renderer.beginPartial(s,r,n,a),this.root.draw(this.renderer,this.theme),this.renderer.end())}this.onAfterFlush&&(this._flushInfo.isFullRepaint=this.frameIsFullRepaint,this._flushInfo.dirtyRects=this.frameDirtyRects,this._flushInfo.dirtyRectCount=this.frameDirtyRectCount,this._flushInfo.canvasWidth=t,this._flushInfo.canvasHeight=i,this._flushInfo.flushTimeMs=performance.now()-h,this.onAfterFlush(this._flushInfo)),this._frameId++}}export{e as Surface};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { FontAtlas } from './atlas';
|
|
2
|
+
/** Base theme tokens shared by all inspect panel variants. Colors are packed RGBA uint32. */
|
|
3
|
+
export interface Theme {
|
|
4
|
+
bgApp: number;
|
|
5
|
+
bgPanel: number;
|
|
6
|
+
bgPanelInset: number;
|
|
7
|
+
bgPanelRaised: number;
|
|
8
|
+
bgButton: number;
|
|
9
|
+
bgButtonHover: number;
|
|
10
|
+
bgButtonActive: number;
|
|
11
|
+
bgInput: number;
|
|
12
|
+
bgSelected: number;
|
|
13
|
+
bgScrollTrack: number;
|
|
14
|
+
bgScrollThumb: number;
|
|
15
|
+
borderPanel: number;
|
|
16
|
+
borderInset: number;
|
|
17
|
+
borderRaised: number;
|
|
18
|
+
textPrimary: number;
|
|
19
|
+
textSecondary: number;
|
|
20
|
+
textMuted: number;
|
|
21
|
+
textValue: number;
|
|
22
|
+
textTitle: number;
|
|
23
|
+
textHighlight: number;
|
|
24
|
+
fontAtlas: FontAtlas;
|
|
25
|
+
spacingXS: number;
|
|
26
|
+
spacingSM: number;
|
|
27
|
+
spacingMD: number;
|
|
28
|
+
spacingLG: number;
|
|
29
|
+
borderRadius: number;
|
|
30
|
+
buttonHeight: number;
|
|
31
|
+
labelHeight: number;
|
|
32
|
+
separatorThickness: number;
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";function t(n,e,o,i){const s=n.getInt16(e),r=n.getInt16(e+2),f=n.getInt16(e+4),g=n.getInt16(e+6),c=n.getInt16(e+8);if(s<0)return function(n,e,o,i,s,r,f,g){const c=[];let l=!0;for(;l;){const s=n.getUint16(e);e+=2;const r=n.getUint16(e);e+=2;let f=0,g=0;if(1&s?(f=n.getInt16(e),e+=2,g=n.getInt16(e),e+=2):(f=n.getInt8(e),e+=1,g=n.getInt8(e),e+=1),8&s?e+=2:64&s?e+=4:128&s&&(e+=8),r<i.length-1){const e=i[r];if(e!==i[r+1]){const s=t(n,o+e,o,i);if(s)for(const t of s.contours){const n={points:t.points.map(t=>({x:t.x+f,y:t.y+g,onCurve:t.onCurve}))};c.push(n)}}}l=!!(32&s)}return c.length>0?{contours:c,xMin:s,yMin:r,xMax:f,yMax:g}:null}(n,e+10,o,i,r,f,g,c);if(0===s)return null;let l=e+10;const a=[];for(let t=0;t<s;t++)a.push(n.getUint16(l)),l+=2;l+=2+n.getUint16(l);const u=a[a.length-1]+1,U=[];for(let t=0;t<u;){const e=n.getUint8(l++);if(U.push(e),t++,8&e){const o=n.getUint8(l++);for(let n=0;n<o;n++)U.push(e),t++}}const h=[];let p=0;for(let t=0;t<u;t++){const e=U[t];if(2&e){const t=n.getUint8(l++);p+=16&e?t:-t}else 16&e||(p+=n.getInt16(l),l+=2);h.push(p)}const y=[];let x=0;for(let t=0;t<u;t++){const e=U[t];if(4&e){const t=n.getUint8(l++);x+=32&e?t:-t}else 32&e||(x+=n.getInt16(l),l+=2);y.push(x)}const M=[];let w=0;for(let t=0;t<s;t++){const n=a[t],e=[];for(let t=w;t<=n;t++)e.push({x:h[t],y:y[t],onCurve:!!(1&U[t])});M.push({points:e}),w=n+1}return{contours:M,xMin:r,yMin:f,xMax:g,yMax:c}}Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"}),exports.parseTTF=async function(n){let e;if("string"==typeof n){const t=await fetch(n);e=await t.arrayBuffer()}else e=n;const o=new DataView(e),i=o.getUint16(4),s={};for(let t=0;t<i;t++){const n=12+16*t;s[String.fromCharCode(o.getUint8(n))+String.fromCharCode(o.getUint8(n+1))+String.fromCharCode(o.getUint8(n+2))+String.fromCharCode(o.getUint8(n+3))]={offset:o.getUint32(n+8),length:o.getUint32(n+12)}}const r=s.head;if(!r)throw new Error("Missing head table");const f=o.getUint16(r.offset+18),g=o.getInt16(r.offset+50),c=s.cmap;if(!c)throw new Error("Missing cmap table");const l=function(t,n){const e=t.getUint16(n+2),o=new Map;let i=-1;for(let o=0;o<e;o++){const e=n+4+8*o,s=t.getUint16(e),r=t.getUint16(e+2),f=n+t.getUint32(e+4);if(3===s&&1===r){i=f;break}0===s&&(i=f)}if(-1===i)return o;const s=t.getUint16(i);return 4===s?function(t,n,e){const o=t.getUint16(n+6)/2,i=n+14,s=i+2*o+2,r=s+2*o,f=r+2*o;for(let n=0;n<o;n++){const o=t.getUint16(i+2*n),g=t.getUint16(s+2*n),c=t.getInt16(r+2*n),l=t.getUint16(f+2*n);if(65535===g)break;for(let i=g;i<=o;i++){let o;if(0===l)o=i+c&65535;else{const e=f+2*n+l+2*(i-g);o=t.getUint16(e),0!==o&&(o=o+c&65535)}0!==o&&e.set(i,o)}}}(t,i,o):12===s&&function(t,n,e){const o=t.getUint32(n+12);for(let i=0;i<o;i++){const o=n+16+12*i,s=t.getUint32(o),r=t.getUint32(o+4),f=t.getUint32(o+8);for(let t=s;t<=r;t++)e.set(t,f+(t-s))}}(t,i,o),o}(o,c.offset),a=s.loca,u=s.glyf;if(!a||!u)throw new Error("Missing loca/glyf tables");const U=s.maxp,h=U?o.getUint16(U.offset+4):0,p=function(t,n,e,o){const i=new Uint32Array(e+1);if(0===o)for(let o=0;o<=e;o++)i[o]=2*t.getUint16(n+2*o);else for(let o=0;o<=e;o++)i[o]=t.getUint32(n+4*o);return i}(o,a.offset,h,g),y=s.hmtx,x=s.hhea;let M=f;y&&x&&o.getUint16(x.offset+34)>0&&(M=o.getUint16(y.offset));const w=new Map;for(const[n,e]of l){if(e>=p.length-1)continue;const i=p[e];if(i===p[e+1])continue;const s=t(o,u.offset+i,u.offset,p);s&&w.set(n,s)}return{unitsPerEm:f,advanceWidth:M,glyphs:w}};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** A parsed TrueType glyph with its outline contours and bounding box. */
|
|
2
|
+
export interface TTFGlyph {
|
|
3
|
+
contours: TTFContour[];
|
|
4
|
+
xMin: number;
|
|
5
|
+
yMin: number;
|
|
6
|
+
xMax: number;
|
|
7
|
+
yMax: number;
|
|
8
|
+
}
|
|
9
|
+
/** A single closed contour of a glyph outline. */
|
|
10
|
+
export interface TTFContour {
|
|
11
|
+
points: {
|
|
12
|
+
x: number;
|
|
13
|
+
y: number;
|
|
14
|
+
onCurve: boolean;
|
|
15
|
+
}[];
|
|
16
|
+
}
|
|
17
|
+
/** Minimal parsed TTF font data: metrics and glyph outlines keyed by character code. */
|
|
18
|
+
export interface TTFFont {
|
|
19
|
+
unitsPerEm: number;
|
|
20
|
+
advanceWidth: number;
|
|
21
|
+
glyphs: Map<number, TTFGlyph>;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Parses a TrueType/OpenType font file into glyph outlines.
|
|
25
|
+
* TrueType/OpenType parsing per Apple TrueType Reference (1990) and OpenType spec 1.9
|
|
26
|
+
*
|
|
27
|
+
* @param source - URL string to fetch, or raw ArrayBuffer of font data.
|
|
28
|
+
*/
|
|
29
|
+
export declare function parseTTF(source: string | ArrayBuffer): Promise<TTFFont>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
async function t(t){let e;if("string"==typeof t){const n=await fetch(t);e=await n.arrayBuffer()}else e=t;const o=new DataView(e),i=o.getUint16(4),s={};for(let t=0;t<i;t++){const n=12+16*t;s[String.fromCharCode(o.getUint8(n))+String.fromCharCode(o.getUint8(n+1))+String.fromCharCode(o.getUint8(n+2))+String.fromCharCode(o.getUint8(n+3))]={offset:o.getUint32(n+8),length:o.getUint32(n+12)}}const f=s.head;if(!f)throw new Error("Missing head table");const r=o.getUint16(f.offset+18),g=o.getInt16(f.offset+50),c=s.cmap;if(!c)throw new Error("Missing cmap table");const l=function(t,n){const e=t.getUint16(n+2),o=/* @__PURE__ */new Map;let i=-1;for(let o=0;o<e;o++){const e=n+4+8*o,s=t.getUint16(e),f=t.getUint16(e+2),r=n+t.getUint32(e+4);if(3===s&&1===f){i=r;break}0===s&&(i=r)}if(-1===i)return o;const s=t.getUint16(i);return 4===s?function(t,n,e){const o=t.getUint16(n+6)/2,i=n+14,s=i+2*o+2,f=s+2*o,r=f+2*o;for(let n=0;n<o;n++){const o=t.getUint16(i+2*n),g=t.getUint16(s+2*n),c=t.getInt16(f+2*n),l=t.getUint16(r+2*n);if(65535===g)break;for(let i=g;i<=o;i++){let o;if(0===l)o=i+c&65535;else{const e=r+2*n+l+2*(i-g);o=t.getUint16(e),0!==o&&(o=o+c&65535)}0!==o&&e.set(i,o)}}}(t,i,o):12===s&&function(t,n,e){const o=t.getUint32(n+12);for(let i=0;i<o;i++){const o=n+16+12*i,s=t.getUint32(o),f=t.getUint32(o+4),r=t.getUint32(o+8);for(let t=s;t<=f;t++)e.set(t,r+(t-s))}}(t,i,o),o}(o,c.offset),a=s.loca,U=s.glyf;if(!a||!U)throw new Error("Missing loca/glyf tables");const u=s.maxp,h=u?o.getUint16(u.offset+4):0,p=function(t,n,e,o){const i=new Uint32Array(e+1);if(0===o)for(let o=0;o<=e;o++)i[o]=2*t.getUint16(n+2*o);else for(let o=0;o<=e;o++)i[o]=t.getUint32(n+4*o);return i}(o,a.offset,h,g),x=s.hmtx,y=s.hhea;let w=r;x&&y&&o.getUint16(y.offset+34)>0&&(w=o.getUint16(x.offset));const I=/* @__PURE__ */new Map;for(const[t,e]of l){if(e>=p.length-1)continue;const i=p[e];if(i===p[e+1])continue;const s=n(o,U.offset+i,U.offset,p);s&&I.set(t,s)}return{unitsPerEm:r,advanceWidth:w,glyphs:I}}function n(t,e,o,i){const s=t.getInt16(e),f=t.getInt16(e+2),r=t.getInt16(e+4),g=t.getInt16(e+6),c=t.getInt16(e+8);if(s<0)return function(t,e,o,i,s,f,r,g){const c=[];let l=!0;for(;l;){const s=t.getUint16(e);e+=2;const f=t.getUint16(e);e+=2;let r=0,g=0;if(1&s?(r=t.getInt16(e),e+=2,g=t.getInt16(e),e+=2):(r=t.getInt8(e),e+=1,g=t.getInt8(e),e+=1),8&s?e+=2:64&s?e+=4:128&s&&(e+=8),f<i.length-1){const e=i[f];if(e!==i[f+1]){const s=n(t,o+e,o,i);if(s)for(const t of s.contours){const n={points:t.points.map(t=>({x:t.x+r,y:t.y+g,onCurve:t.onCurve}))};c.push(n)}}}l=!!(32&s)}return c.length>0?{contours:c,xMin:s,yMin:f,xMax:r,yMax:g}:null}(t,e+10,o,i,f,r,g,c);if(0===s)return null;let l=e+10;const a=[];for(let n=0;n<s;n++)a.push(t.getUint16(l)),l+=2;l+=2+t.getUint16(l);const U=a[a.length-1]+1,u=[];for(let n=0;n<U;){const e=t.getUint8(l++);if(u.push(e),n++,8&e){const o=t.getUint8(l++);for(let t=0;t<o;t++)u.push(e),n++}}const h=[];let p=0;for(let n=0;n<U;n++){const e=u[n];if(2&e){const n=t.getUint8(l++);p+=16&e?n:-n}else 16&e||(p+=t.getInt16(l),l+=2);h.push(p)}const x=[];let y=0;for(let n=0;n<U;n++){const e=u[n];if(4&e){const n=t.getUint8(l++);y+=32&e?n:-n}else 32&e||(y+=t.getInt16(l),l+=2);x.push(y)}const w=[];let I=0;for(let t=0;t<s;t++){const n=a[t],e=[];for(let t=I;t<=n;t++)e.push({x:h[t],y:x[t],onCurve:!!(1&u[t])});w.push({points:e}),I=n+1}return{contours:w,xMin:f,yMin:r,xMax:g,yMax:c}}export{t as parseTTF};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});exports.SLOT_COUNT=16,exports.SLOT_FLEX_GROW=10,exports.SLOT_FLEX_SHRINK=11,exports.SLOT_HEIGHT=3,exports.SLOT_MAX_HEIGHT=9,exports.SLOT_MAX_WIDTH=8,exports.SLOT_MIN_HEIGHT=7,exports.SLOT_MIN_WIDTH=6,exports.SLOT_PADDING_BOTTOM=14,exports.SLOT_PADDING_LEFT=15,exports.SLOT_PADDING_RIGHT=13,exports.SLOT_PADDING_TOP=12,exports.SLOT_PREFERRED_HEIGHT=5,exports.SLOT_PREFERRED_WIDTH=4,exports.SLOT_WIDTH=2,exports.SLOT_X=0,exports.SLOT_Y=1,exports.THEME_DEFAULT=-1,exports.Widget=class{parent=null;surface=null;children=[];geometry=new Float32Array(16);_visible=!0;_effectivelyVisible=!0;enabled=!0;focusable=!1;focused=!1;absolute=!1;_hasAbsoluteChildren=!1;anchorTop=NaN;anchorRight=NaN;anchorBottom=NaN;anchorLeft=NaN;absoluteX=0;absoluteY=0;sizingX="fit";sizingY="fit";percentWidth=0;percentHeight=0;alignSelf=null;autoFitScale=!1;fitReferenceWidth=0;fitReferenceHeight=0;minScale=1;maxScale=1;computedScale=1;designWidth=0;designHeight=0;designScaleSnap="none";designScaleStep=0;designScale=1;screenScale=1;designOffsetX=0;designOffsetY=0;virtualWidth=0;virtualHeight=0;layout=null;needsLayout=!0;constructor(){this.geometry[8]=1e7,this.geometry[9]=1e7}get visible(){return this._visible}set visible(e){this._visible!==e&&(this._visible=e,this.propagateEffectiveVisibility(this._visible&&(!this.parent||this.parent._effectivelyVisible)))}propagateEffectiveVisibility(e){const t=this._visible&&e;if(t!==this._effectivelyVisible){this._effectivelyVisible=t;for(let e=0;e<this.children.length;e++)this.children[e].propagateEffectiveVisibility(t)}}get x(){return this.geometry[0]}set x(e){this.geometry[0]=e}get y(){return this.geometry[1]}set y(e){this.geometry[1]=e}get width(){return this.geometry[2]}set width(e){this.geometry[2]=e}get height(){return this.geometry[3]}set height(e){this.geometry[3]=e}get preferredWidth(){return this.geometry[4]}set preferredWidth(e){this.geometry[4]=e}get preferredHeight(){return this.geometry[5]}set preferredHeight(e){this.geometry[5]=e}get minWidth(){return this.geometry[6]}set minWidth(e){this.geometry[6]=e}get minHeight(){return this.geometry[7]}set minHeight(e){this.geometry[7]=e}get maxWidth(){return this.geometry[8]}set maxWidth(e){this.geometry[8]=e}get maxHeight(){return this.geometry[9]}set maxHeight(e){this.geometry[9]=e}get flexGrow(){return this.geometry[10]}set flexGrow(e){this.geometry[10]=e}get flexShrink(){return this.geometry[11]}set flexShrink(e){this.geometry[11]=e}setPadding(e,t,i,s){this.geometry[12]=e,this.geometry[13]=t,this.geometry[14]=i,this.geometry[15]=s}setPaddingAll(e){this.setPadding(e,e,e,e)}get innerWidth(){return this.geometry[2]-this.geometry[15]-this.geometry[13]}get innerHeight(){return this.geometry[3]-this.geometry[12]-this.geometry[14]}get innerX(){return this.geometry[15]}get innerY(){return this.geometry[12]}resolveFont(){return this.surface?.getTheme()?.fontAtlas??null}getContentWidth(){return 0}getContentHeight(){return 0}measureIntrinsicWidth(){return"fixed"===this.sizingX?this.preferredWidth:"grow"===this.sizingX||"percent"===this.sizingX?this.geometry[6]:this.preferredWidth>0?this.preferredWidth:this.layout?this.layout.measureWidth(this)+this.geometry[15]+this.geometry[13]:this.getContentWidth()+this.geometry[15]+this.geometry[13]}measureIntrinsicHeight(){return"fixed"===this.sizingY?this.preferredHeight:"grow"===this.sizingY||"percent"===this.sizingY?this.geometry[7]:this.preferredHeight>0?this.preferredHeight:this.layout?this.layout.measureHeight(this)+this.geometry[12]+this.geometry[14]:this.getContentHeight()+this.geometry[12]+this.geometry[14]}addChild(e){e.parent=this,e.propagateEffectiveVisibility(this._effectivelyVisible),e.absolute&&(this._hasAbsoluteChildren=!0),this.surface&&e.setSurface(this.surface),this.children.push(e),this.needsLayout=!0,this.markDirty()}removeChild(e){const t=this.children.indexOf(e);-1!==t&&(this.children.splice(t,1),e.parent=null,e.setSurface(null),e.absolute&&this.recomputeHasAbsoluteChildren(),this.needsLayout=!0,this.markDirty())}removeAllChildren(){for(let e=this.children.length-1;e>=0;e--)this.children[e].parent=null,this.children[e].setSurface(null);this.children.length=0,this._hasAbsoluteChildren=!1,this.needsLayout=!0,this.markDirty()}recomputeHasAbsoluteChildren(){this._hasAbsoluteChildren=!1;for(let e=0;e<this.children.length;e++)if(this.children[e].absolute)return void(this._hasAbsoluteChildren=!0)}isEffectivelyVisible(){return this._effectivelyVisible}invalidateLayout(){this.needsLayout=!0;let e=this.visible,t=this.parent;for(;t;)t.needsLayout=!0,e&&!t.visible&&(e=!1),t=t.parent;e&&this.surface&&this.surface.markDirty()}markDirty(){if(this.surface){const e=this.screenScale,t=this.width*e|0,i=this.height*e|0;this.surface.markDirtyRect(this.absoluteX-1,this.absoluteY-1,t+2,i+2)}}setSurface(e){this.surface=e;for(let t=0;t<this.children.length;t++)this.children[t].setSurface(e)}computeLayout(){const e=this.designWidth>0||this.designHeight>0;let t=0,i=0;if(e){t=this.geometry[2],i=this.geometry[3],this.virtualWidth=this.designWidth>0?this.designWidth:t,this.virtualHeight=this.designHeight>0?this.designHeight:i,this.geometry[2]=this.virtualWidth,this.geometry[3]=this.virtualHeight;const e=this.designWidth>0?t/this.designWidth:1,s=this.designHeight>0?i/this.designHeight:1;this.designScale=this.snapScale(Math.min(e,s));const h=this.virtualWidth*this.designScale,r=this.virtualHeight*this.designScale;this.designOffsetX=(t-h)/2|0,this.designOffsetY=(i-r)/2|0}else this.designScale=1,this.designOffsetX=0,this.designOffsetY=0;this.layout&&this.needsLayout&&(this.layout.compute(this),this.needsLayout=!1),this._hasAbsoluteChildren&&this.resolveAbsoluteChildren(),e&&(this.geometry[2]=t,this.geometry[3]=i);const s=this.geometry[15],h=this.geometry[12],r=this.screenScale*this.designScale;for(let t=0;t<this.children.length;t++){const i=this.children[t];i.screenScale=r,e?(i.absoluteX=this.absoluteX+this.designOffsetX+(s+i.geometry[0])*this.designScale|0,i.absoluteY=this.absoluteY+this.designOffsetY+(h+i.geometry[1])*this.designScale|0):(i.absoluteX=this.absoluteX+s+i.geometry[0]|0,i.absoluteY=this.absoluteY+h+i.geometry[1]|0),i.computeLayout()}}snapScale(e){if(this.designScaleStep>0){const t=Math.floor(e/this.designScaleStep)*this.designScaleStep;return t>0?t:this.designScaleStep}return"none"===this.designScaleSnap?e:e>=1?"binary"===this.designScaleSnap?2**Math.floor(Math.log2(e)):Math.floor(e)||1:2**Math.floor(Math.log2(e))}resolveAbsoluteChildren(){const e=this.innerWidth,t=this.innerHeight;for(let i=0;i<this.children.length;i++){const s=this.children[i];if(!s.absolute)continue;const h=s.geometry,r=s.anchorLeft==s.anchorLeft,n=s.anchorRight==s.anchorRight,o=s.anchorTop==s.anchorTop,l=s.anchorBottom==s.anchorBottom;let a,g,d,c;a=r&&n?e-s.anchorLeft-s.anchorRight:h[4]>0?h[4]:s.measureIntrinsicWidth(),g=o&&l?t-s.anchorTop-s.anchorBottom:h[5]>0?h[5]:s.measureIntrinsicHeight(),d=r?s.anchorLeft:n?e-a-s.anchorRight:Math.round((e-a)/2),c=o?s.anchorTop:l?t-g-s.anchorBottom:Math.round((t-g)/2),h[0]=d,h[1]=c,h[2]=a>0?a:0,h[3]=g>0?g:0,s.needsLayout=!0}}draw(e,t){if(this.autoFitScale){let e=this.maxScale;this.fitReferenceWidth>0&&(e=Math.min(e,this.innerWidth/this.fitReferenceWidth)),this.fitReferenceHeight>0&&(e=Math.min(e,this.innerHeight/this.fitReferenceHeight)),this.computedScale=Math.max(this.minScale,Math.min(this.maxScale,e))}this.drawSelf(e,t),this.drawChildren(e,t)}drawSelf(e,t){}drawChildren(e,t){const i=this.designWidth>0||this.designHeight>0,s=this.geometry[15],h=this.geometry[13],r=this.geometry[12],n=this.geometry[14],o=r>0||h>0||n>0||s>0;i&&(e.pushTranslate(this.designOffsetX,this.designOffsetY),e.pushScale(this.designScale,this.designScale));const l=i&&this.designScale>0&&this.designScale<1?Math.round(1/this.designScale):1;if(o){const t=l>1?Math.round(s/l)*l:s,o=l>1?Math.round(r/l)*l:r;if(e.pushTranslate(t,o),i){const i=this.virtualWidth-t-(l>1?Math.round(h/l)*l:h),s=this.virtualHeight-o-(l>1?Math.round(n/l)*l:n);e.pushClip(0,0,i,s)}else e.pushClip(0,0,this.innerWidth,this.innerHeight)}for(let i=0;i<this.children.length;i++){const s=this.children[i];if(!s.visible)continue;if(this.surface&&!this.surface.isRectInDirtyArea(s.absoluteX,s.absoluteY,s.geometry[2],s.geometry[3]))continue;const h=s.geometry,r=l>1?Math.round(h[0]/l)*l:h[0],n=l>1?Math.round(h[1]/l)*l:h[1],o=l>1?Math.round(h[2]/l)*l:h[2],a=l>1?Math.round(h[3]/l)*l:h[3];e.pushTranslateClip(r,n,0,0,o,a),s.draw(e,t),e.popTranslateClip()}o&&(e.popClip(),e.popTranslate()),i&&(e.popScale(),e.popTranslate())}hitTest(e,t){if(!this.visible)return null;let i=e,s=t;(this.designWidth>0||this.designHeight>0)&&(i=(e-this.designOffsetX)/this.designScale,s=(t-this.designOffsetY)/this.designScale);const h=i-this.geometry[15],r=s-this.geometry[12];for(let e=this.children.length-1;e>=0;e--){const t=this.children[e];if(!t.visible)continue;const i=t.geometry,s=h-i[0],n=r-i[1];if(s>=0&&s<i[2]&&n>=0&&n<i[3]){const e=t.hitTest(s,n);if(e)return e}}return this}onPointerDown(e,t,i,s){return!1}onPointerUp(e,t,i,s){}onPointerMove(e,t,i){}onPointerEnter(){}onPointerLeave(){}onWheel(e,t){return!1}onKeyDown(e,t,i,s,h){return!1}onKeyUp(e,t){}onFocus(){}onBlur(){}};
|