@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,31 @@
|
|
|
1
|
+
/** Precomputed lookup table mapping byte values 0-255 to two-char hex strings. */
|
|
2
|
+
export declare const HEX_LUT: string[];
|
|
3
|
+
/**
|
|
4
|
+
* Convert RGB [0,1] to HSV. Returns a reused tuple (not allocation-safe).
|
|
5
|
+
* RGB to HSV per A.R. Smith, "Color Gamut Transform Pairs" (1978)
|
|
6
|
+
*/
|
|
7
|
+
export declare function rgbToHsv(r: number, g: number, b: number): [number, number, number];
|
|
8
|
+
/**
|
|
9
|
+
* Convert HSV (h in [0,360], s and v in [0,1]) to RGB [0,1].
|
|
10
|
+
* Returns a reused tuple (not allocation-safe).
|
|
11
|
+
* HSV to RGB per A.R. Smith, "Color Gamut Transform Pairs" (1978)
|
|
12
|
+
*/
|
|
13
|
+
export declare function hsvToRgb(h: number, s: number, v: number): [number, number, number];
|
|
14
|
+
/** Pack float RGBA [0,1] into a single uint32 (RGBA byte order). */
|
|
15
|
+
export declare function packRGBA(r: number, g: number, b: number, a?: number): number;
|
|
16
|
+
/** Pack 8-bit integer RGBA [0,255] into a single uint32 (RGBA byte order). */
|
|
17
|
+
export declare function packRGBA8(r: number, g: number, b: number, a?: number): number;
|
|
18
|
+
/** Unpack a uint32 into float RGBA [0,1]. Returns a reused tuple. */
|
|
19
|
+
export declare function unpackRGBA(color: number): [number, number, number, number];
|
|
20
|
+
/** Convert a float {r, g, b} object to a packed uint32 with alpha=1. */
|
|
21
|
+
export declare function rgbObjToPacked(obj: {
|
|
22
|
+
r: number;
|
|
23
|
+
g: number;
|
|
24
|
+
b: number;
|
|
25
|
+
}): number;
|
|
26
|
+
/** Unpack a uint32 color to a float {r, g, b} object. Returns a reused object. */
|
|
27
|
+
export declare function packedToRgbObj(color: number): {
|
|
28
|
+
r: number;
|
|
29
|
+
g: number;
|
|
30
|
+
b: number;
|
|
31
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const t=[0,0,0],n=[0,0,0],r=Array.from({length:256},(t,n)=>n.toString(16).padStart(2,"0"));function o(n,r,o){const a=Math.max(n,r,o),e=a-Math.min(n,r,o);let c=0;return e>0&&(c=a===n?(r-o)/e%6:a===r?(o-n)/e+2:(n-r)/e+4,c*=60,c<0&&(c+=360)),t[0]=c,t[1]=0===a?0:e/a,t[2]=a,t}function a(t,r,o){const a=o*r,e=a*(1-Math.abs(t/60%2-1)),c=o-a;let u=0,i=0,f=0;return t<60?(u=a,i=e,f=0):t<120?(u=e,i=a,f=0):t<180?(u=0,i=a,f=e):t<240?(u=0,i=e,f=a):t<300?(u=e,i=0,f=a):(u=a,i=0,f=e),n[0]=u+c,n[1]=i+c,n[2]=f+c,n}function e(t,n,r,o=1){return(255*t+.5<<24|255*n+.5<<16|255*r+.5<<8|255*o+.5)>>>0}export{r as HEX_LUT,a as hsvToRgb,e as packRGBA,o as rgbToHsv};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { setGuiActive, getGuiActive } from './activity';
|
|
2
|
+
export { exportStateAsJSON, importStateFromJSON, saveConfig, loadConfig, clearConfig, copyConfigToClipboard, getVisibilityFromStorage, setVisibilityToStorage } from './persistence';
|
|
3
|
+
export { rgbToHsv, hsvToRgb, packRGBA, packRGBA8, unpackRGBA, rgbObjToPacked, packedToRgbObj, HEX_LUT } from './color-convert';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t="inspect-visible";exports.clearConfig=function(t){try{localStorage.removeItem(t)}catch{}},exports.copyConfigToClipboard=async function(t){const e=["{"],o=t,n=Object.keys(o);for(let t=0;t<n.length;t++){const r=n[t],c=o[r],a=t<n.length-1?",":"";"number"==typeof c?e.push(` ${r}: ${Number(c.toFixed(6))}${a}`):"string"==typeof c?e.push(` ${r}: "${c}"${a}`):"boolean"==typeof c?e.push(` ${r}: ${c}${a}`):e.push(` ${r}: ${JSON.stringify(c)}${a}`)}e.push("}");const r=e.join("\n");try{await navigator.clipboard.writeText(r)}catch{}return r},exports.exportStateAsJSON=function(t,e){const o=JSON.stringify(t,null,2),n=new Blob([o],{type:"application/json"}),r=URL.createObjectURL(n),c=document.createElement("a");c.download=e||`inspect-settings-${function(){const t=new Date;return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}_${String(t.getHours()).padStart(2,"0")}-${String(t.getMinutes()).padStart(2,"0")}-${String(t.getSeconds()).padStart(2,"0")}`}()}.json`,c.href=r,c.click(),URL.revokeObjectURL(r)},exports.getVisibilityFromStorage=function(e=t){try{const t=localStorage.getItem(e);return"true"===t||"false"!==t&&null}catch{return null}},exports.importStateFromJSON=function(t){const e=document.createElement("input");e.type="file",e.accept=".json",e.addEventListener("change",e=>{const o=e.target.files?.[0];if(o){const e=new FileReader;e.onload=e=>{try{const o=JSON.parse(e.target?.result);t(o)}catch(t){}},e.readAsText(o)}}),e.click()},exports.loadConfig=function(t,e){try{const o=localStorage.getItem(t);if(!o)return{...e};const n=JSON.parse(o),r={...e},c=e;for(const t of Object.keys(c))t in n&&typeof n[t]==typeof c[t]&&(r[t]=n[t]);return r}catch{return{...e}}},exports.saveConfig=function(t,e){try{localStorage.setItem(t,JSON.stringify(e))}catch{}},exports.setVisibilityToStorage=function(e,o=t){try{localStorage.setItem(o,e?"true":"false")}catch{}};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** read persisted visibility from localStorage; null when unset, not a stored boolean, or unreadable. */
|
|
2
|
+
export declare function getVisibilityFromStorage(storageKey?: string): boolean | null;
|
|
3
|
+
/** persist panel visibility to localStorage. */
|
|
4
|
+
export declare function setVisibilityToStorage(visible: boolean, storageKey?: string): void;
|
|
5
|
+
/** trigger a browser download of the given state serialized as JSON. */
|
|
6
|
+
export declare function exportStateAsJSON(state: unknown, filename?: string): void;
|
|
7
|
+
/** open a file picker for a JSON file and pass the parsed result to the callback. */
|
|
8
|
+
export declare function importStateFromJSON(callback: (state: unknown) => void): void;
|
|
9
|
+
/** serialize a config object to localStorage under the given key. */
|
|
10
|
+
export declare function saveConfig<T extends object>(storageKey: string, config: T): void;
|
|
11
|
+
/** load a config from localStorage, merging stored values into defaults by matching key/type. */
|
|
12
|
+
export declare function loadConfig<T extends object>(storageKey: string, defaults: T): T;
|
|
13
|
+
/** remove a config entry from localStorage. */
|
|
14
|
+
export declare function clearConfig(storageKey: string): void;
|
|
15
|
+
/** format a config as readable text and copy it to the clipboard. returns the text. */
|
|
16
|
+
export declare function copyConfigToClipboard<T extends object>(config: T): Promise<string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const t="inspect-visible";function e(e=t){try{const t=localStorage.getItem(e);return"true"===t||"false"!==t&&null}catch{return null}}function n(e,n=t){try{localStorage.setItem(n,e?"true":"false")}catch{}}function r(t,e){const n=JSON.stringify(t,null,2),r=new Blob([n],{type:"application/json"}),c=URL.createObjectURL(r),o=document.createElement("a");o.download=e||`inspect-settings-${function(){const t=/* @__PURE__ */new Date;return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,"0")}-${String(t.getDate()).padStart(2,"0")}_${String(t.getHours()).padStart(2,"0")}-${String(t.getMinutes()).padStart(2,"0")}-${String(t.getSeconds()).padStart(2,"0")}`}()}.json`,o.href=c,o.click(),URL.revokeObjectURL(c)}function c(t){const e=document.createElement("input");e.type="file",e.accept=".json",e.addEventListener("change",e=>{const n=e.target.files?.[0];if(n){const e=new FileReader;e.onload=e=>{try{const n=JSON.parse(e.target?.result);t(n)}catch(t){}},e.readAsText(n)}}),e.click()}function o(t,e){try{localStorage.setItem(t,JSON.stringify(e))}catch{}}function a(t,e){try{const n=localStorage.getItem(t);if(!n)return{...e};const r=JSON.parse(n),c={...e},o=e;for(const t of Object.keys(o))t in r&&typeof r[t]==typeof o[t]&&(c[t]=r[t]);return c}catch{return{...e}}}function s(t){try{localStorage.removeItem(t)}catch{}}async function i(t){const e=["{"],n=t,r=Object.keys(n);for(let t=0;t<r.length;t++){const c=r[t],o=n[c],a=t<r.length-1?",":"";"number"==typeof o?e.push(` ${c}: ${Number(o.toFixed(6))}${a}`):"string"==typeof o?e.push(` ${c}: "${o}"${a}`):"boolean"==typeof o?e.push(` ${c}: ${o}${a}`):e.push(` ${c}: ${JSON.stringify(o)}${a}`)}e.push("}");const c=e.join("\n");try{await navigator.clipboard.writeText(c)}catch{}return c}export{s as clearConfig,i as copyConfigToClipboard,r as exportStateAsJSON,e as getVisibilityFromStorage,c as importStateFromJSON,a as loadConfig,o as saveConfig,n as setVisibilityToStorage};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("../core/widget.cjs");class r extends o.Widget{bgColor=0;borderColor=0;borderWidth=0;borderRadius=0;borderTopColor=0;borderBottomColor=0;borderLeftColor=0;borderRightColor=0;drawSelf(o,r){const t=this.width,e=this.height,i=this.borderRadius;this.bgColor&&(i>0?o.fillRoundedRect(0,0,t,e,i,this.bgColor):o.fillRect(0,0,t,e,this.bgColor)),this.borderColor&&this.borderWidth>0&&(i>0?o.strokeRoundedRect(0,0,t,e,i,this.borderColor,this.borderWidth):o.strokeRect(0,0,t,e,this.borderColor,this.borderWidth)),this.borderTopColor&&o.fillRect(0,0,t,1,this.borderTopColor),this.borderBottomColor&&o.fillRect(0,e-1,t,1,this.borderBottomColor),this.borderLeftColor&&o.fillRect(0,0,1,e,this.borderLeftColor),this.borderRightColor&&o.fillRect(t-1,0,1,e,this.borderRightColor)}}exports.Box=r;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Widget } from '../core/widget';
|
|
2
|
+
import { Renderer } from '../core/renderer';
|
|
3
|
+
import { Theme } from '../core/theme';
|
|
4
|
+
/** Generic container widget with optional background fill, border, and per-edge border colors. */
|
|
5
|
+
export declare class Box extends Widget {
|
|
6
|
+
/** background fill color; zero for no fill. */
|
|
7
|
+
bgColor: number;
|
|
8
|
+
/** full-perimeter border color; zero disables the border. */
|
|
9
|
+
borderColor: number;
|
|
10
|
+
/** border stroke width in pixels. */
|
|
11
|
+
borderWidth: number;
|
|
12
|
+
/** corner radius applied to the background and full border. */
|
|
13
|
+
borderRadius: number;
|
|
14
|
+
/** color of a 1px top edge line; zero disables it. */
|
|
15
|
+
borderTopColor: number;
|
|
16
|
+
/** color of a 1px bottom edge line; zero disables it. */
|
|
17
|
+
borderBottomColor: number;
|
|
18
|
+
/** color of a 1px left edge line; zero disables it. */
|
|
19
|
+
borderLeftColor: number;
|
|
20
|
+
/** color of a 1px right edge line; zero disables it. */
|
|
21
|
+
borderRightColor: number;
|
|
22
|
+
/** paints the background, the full border, then any single-edge border lines. */
|
|
23
|
+
protected drawSelf(renderer: Renderer, _theme: Theme): void;
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Widget as o}from"../core/widget.mjs";class r extends o{bgColor=0;borderColor=0;borderWidth=0;borderRadius=0;borderTopColor=0;borderBottomColor=0;borderLeftColor=0;borderRightColor=0;drawSelf(o,r){const t=this.width,e=this.height,i=this.borderRadius;this.bgColor&&(i>0?o.fillRoundedRect(0,0,t,e,i,this.bgColor):o.fillRect(0,0,t,e,this.bgColor)),this.borderColor&&this.borderWidth>0&&(i>0?o.strokeRoundedRect(0,0,t,e,i,this.borderColor,this.borderWidth):o.strokeRect(0,0,t,e,this.borderColor,this.borderWidth)),this.borderTopColor&&o.fillRect(0,0,t,1,this.borderTopColor),this.borderBottomColor&&o.fillRect(0,e-1,t,1,this.borderBottomColor),this.borderLeftColor&&o.fillRect(0,0,1,e,this.borderLeftColor),this.borderRightColor&&o.fillRect(t-1,0,1,e,this.borderRightColor)}}export{r as Box};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("../core/widget.cjs"),e=require("../defaults.cjs");class r extends t.Widget{text="";textColor=t.THEME_DEFAULT;bgColor=t.THEME_DEFAULT;hoverColor=t.THEME_DEFAULT;activeColor=t.THEME_DEFAULT;borderColor=0;borderWidth=0;borderRadius=0;disabledAlpha=e.DEFAULTS.buttonDisabledAlpha;onClick=null;hovered=!1;pressed=!1;constructor(){super(),this.focusable=!0}get isHovered(){return this.hovered}get isPressed(){return this.pressed}getContentWidth(){if(this.children.length>0||!this.text)return 0;const t=this.resolveFont();return t?this.text.length*t.charWidth:0}getContentHeight(){if(this.children.length>0||!this.text)return 0;const t=this.resolveFont();return t?t.lineHeight:0}drawSelf(e,r){const o=this.width,i=this.height;this.enabled||e.pushAlpha(this.disabledAlpha);const s=this.bgColor===t.THEME_DEFAULT?r.bgButton:this.bgColor,h=this.hoverColor===t.THEME_DEFAULT?r.bgButtonHover:this.hoverColor,n=this.activeColor===t.THEME_DEFAULT?r.bgButtonActive:this.activeColor;let d=s;this.pressed?d=n:this.hovered&&(d=h);const l=this.borderRadius;if(l>0?e.fillRoundedRect(0,0,o,i,l,d):e.fillRect(0,0,o,i,d),this.borderColor&&this.borderWidth>0&&(l>0?e.strokeRoundedRect(0,0,o,i,l,this.borderColor,this.borderWidth):e.strokeRect(0,0,o,i,this.borderColor,this.borderWidth)),0===this.children.length&&this.text){const s=r.fontAtlas;if(s){const h=this.autoFitScale?this.computedScale:1,n=s.charWidth*h|0,d=s.lineHeight*h|0,l=this.text.length*n,a=Math.round((o-l)/2),c=Math.round((i-d)/2),u=this.textColor===t.THEME_DEFAULT?r.textPrimary:this.textColor;e.drawText(s,this.text,a,c,u,1!==h?h:void 0)}}this.enabled||e.popAlpha()}onPointerDown(t,e,r,o){return!!this.enabled&&(this.pressed=!0,this.markDirty(),super.onPointerDown(t,e,r,o)||!0)}onPointerUp(t,e,r,o){this.pressed&&this.enabled&&this.onClick&&this.onClick(),this.pressed=!1,this.markDirty(),super.onPointerUp(t,e,r,o)}onPointerEnter(){this.hovered=!0,this.markDirty()}onPointerLeave(){this.hovered=!1,this.pressed=!1,this.markDirty()}onKeyDown(t,e,r,o,i){return("Enter"===e||"Space"===e)&&this.enabled&&this.onClick?(this.onClick(),!0):super.onKeyDown(t,e,r,o,i)}}exports.Button=r;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Widget } from '../core/widget';
|
|
2
|
+
import { Renderer } from '../core/renderer';
|
|
3
|
+
import { Theme } from '../core/theme';
|
|
4
|
+
/** clickable button widget with hover and active states. */
|
|
5
|
+
export declare class Button extends Widget {
|
|
6
|
+
/** text displayed centered within the button. */
|
|
7
|
+
text: string;
|
|
8
|
+
/** text color override; uses theme default when set to THEME_DEFAULT. */
|
|
9
|
+
textColor: number;
|
|
10
|
+
/** background color override. */
|
|
11
|
+
bgColor: number;
|
|
12
|
+
/** background color when hovered. */
|
|
13
|
+
hoverColor: number;
|
|
14
|
+
/** background color when pressed. */
|
|
15
|
+
activeColor: number;
|
|
16
|
+
/** border stroke color; zero disables the border. */
|
|
17
|
+
borderColor: number;
|
|
18
|
+
/** border stroke width in pixels. */
|
|
19
|
+
borderWidth: number;
|
|
20
|
+
/** corner radius for rounded button shape. */
|
|
21
|
+
borderRadius: number;
|
|
22
|
+
/** alpha multiplier applied when the button is disabled. */
|
|
23
|
+
disabledAlpha: number;
|
|
24
|
+
/** callback invoked on click or keyboard activation. */
|
|
25
|
+
onClick: (() => void) | null;
|
|
26
|
+
private hovered;
|
|
27
|
+
private pressed;
|
|
28
|
+
/** marks the button focusable so it can be activated by keyboard. */
|
|
29
|
+
constructor();
|
|
30
|
+
/** whether the pointer is currently hovering over this button. */
|
|
31
|
+
get isHovered(): boolean;
|
|
32
|
+
/** whether the button is currently being pressed. */
|
|
33
|
+
get isPressed(): boolean;
|
|
34
|
+
/** intrinsic label width in pixels; zero when the button has children or no text. */
|
|
35
|
+
getContentWidth(): number;
|
|
36
|
+
/** intrinsic label height in pixels; zero when the button has children or no text. */
|
|
37
|
+
getContentHeight(): number;
|
|
38
|
+
/** paints the background for the hover/press state, the optional border, and centered text; dims when disabled. */
|
|
39
|
+
protected drawSelf(renderer: Renderer, theme: Theme): void;
|
|
40
|
+
/** enters the pressed state and claims the pointer, unless disabled. */
|
|
41
|
+
onPointerDown(pointerId: number, x: number, y: number, button: number): boolean;
|
|
42
|
+
/** fires onClick when released while still pressed and enabled, then clears the pressed state. */
|
|
43
|
+
onPointerUp(pointerId: number, x: number, y: number, button: number): void;
|
|
44
|
+
/** enters the hover state. */
|
|
45
|
+
onPointerEnter(): void;
|
|
46
|
+
/** clears hover and any pressed state when the pointer leaves. */
|
|
47
|
+
onPointerLeave(): void;
|
|
48
|
+
/** activates the button on Enter or Space when enabled. */
|
|
49
|
+
onKeyDown(key: string, code: string, ctrl: boolean, shift: boolean, alt: boolean): boolean;
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Widget as t,THEME_DEFAULT as e}from"../core/widget.mjs";import{DEFAULTS as r}from"../defaults.mjs";class o extends t{text="";textColor=e;bgColor=e;hoverColor=e;activeColor=e;borderColor=0;borderWidth=0;borderRadius=0;disabledAlpha=r.buttonDisabledAlpha;onClick=null;hovered=!1;pressed=!1;constructor(){super(),this.focusable=!0}get isHovered(){return this.hovered}get isPressed(){return this.pressed}getContentWidth(){if(this.children.length>0||!this.text)return 0;const t=this.resolveFont();return t?this.text.length*t.charWidth:0}getContentHeight(){if(this.children.length>0||!this.text)return 0;const t=this.resolveFont();return t?t.lineHeight:0}drawSelf(t,r){const o=this.width,i=this.height;this.enabled||t.pushAlpha(this.disabledAlpha);const s=this.bgColor===e?r.bgButton:this.bgColor,h=this.hoverColor===e?r.bgButtonHover:this.hoverColor,n=this.activeColor===e?r.bgButtonActive:this.activeColor;let d=s;this.pressed?d=n:this.hovered&&(d=h);const l=this.borderRadius;if(l>0?t.fillRoundedRect(0,0,o,i,l,d):t.fillRect(0,0,o,i,d),this.borderColor&&this.borderWidth>0&&(l>0?t.strokeRoundedRect(0,0,o,i,l,this.borderColor,this.borderWidth):t.strokeRect(0,0,o,i,this.borderColor,this.borderWidth)),0===this.children.length&&this.text){const s=r.fontAtlas;if(s){const h=this.autoFitScale?this.computedScale:1,n=s.charWidth*h|0,d=s.lineHeight*h|0,l=this.text.length*n,a=Math.round((o-l)/2),c=Math.round((i-d)/2),u=this.textColor===e?r.textPrimary:this.textColor;t.drawText(s,this.text,a,c,u,1!==h?h:void 0)}}this.enabled||t.popAlpha()}onPointerDown(t,e,r,o){return!!this.enabled&&(this.pressed=!0,this.markDirty(),super.onPointerDown(t,e,r,o)||!0)}onPointerUp(t,e,r,o){this.pressed&&this.enabled&&this.onClick&&this.onClick(),this.pressed=!1,this.markDirty(),super.onPointerUp(t,e,r,o)}onPointerEnter(){this.hovered=!0,this.markDirty()}onPointerLeave(){this.hovered=!1,this.pressed=!1,this.markDirty()}onKeyDown(t,e,r,o,i){return("Enter"===e||"Space"===e)&&this.enabled&&this.onClick?(this.onClick(),!0):super.onKeyDown(t,e,r,o,i)}}export{o as Button};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("../core/widget.cjs");class t extends e.Widget{onDraw=null;drawSelf(e,t){this.onDraw&&this.onDraw(e,t,this.width,this.height)}}exports.CanvasWidget=t;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Widget } from '../core/widget';
|
|
2
|
+
import { Renderer } from '../core/renderer';
|
|
3
|
+
import { Theme } from '../core/theme';
|
|
4
|
+
/** callback signature for custom draw logic within a CanvasWidget. */
|
|
5
|
+
export type CustomDrawFn = (renderer: Renderer, theme: Theme, width: number, height: number) => void;
|
|
6
|
+
/** widget that delegates its rendering to a user-supplied draw callback. */
|
|
7
|
+
export declare class CanvasWidget extends Widget {
|
|
8
|
+
/** draw callback invoked each frame; receives renderer, theme, and widget dimensions. */
|
|
9
|
+
onDraw: CustomDrawFn | null;
|
|
10
|
+
/** invokes the user draw callback, if set, with the renderer, theme, and current size. */
|
|
11
|
+
protected drawSelf(renderer: Renderer, theme: Theme): void;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Widget as t}from"../core/widget.mjs";class i extends t{onDraw=null;drawSelf(t,i){this.onDraw&&this.onDraw(t,i,this.width,this.height)}}export{i as CanvasWidget};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("../core/widget.cjs");class i extends t.Widget{text="";color=t.THEME_DEFAULT;hAlign="left";vAlign="middle";customFont=null;overflow="clip";scale=1;textOffsetY=0;_cachedText="";_cachedLines=[];_cachedEllipsisText="";_cachedEllipsisSource="";_cachedEllipsisMaxChars=-1;_isMultiline=!1;getLines(){return this._cachedText!==this.text&&(this._cachedText=this.text,-1===this.text.indexOf("\n")?(this._cachedLines[0]=this.text,this._cachedLines.length=1,this._isMultiline=!1):(this._cachedLines=this.text.split("\n"),this._isMultiline=!0)),this._cachedLines}getEllipsisText(t,i){return t===this._cachedEllipsisSource&&i===this._cachedEllipsisMaxChars||(this._cachedEllipsisSource=t,this._cachedEllipsisMaxChars=i,this._cachedEllipsisText=i>0?t.slice(0,i)+"~":""),this._cachedEllipsisText}getContentWidth(){const t=this.customFont??this.resolveFont();if(!t||!this.text)return 0;const i=this.autoFitScale?this.maxScale:this.scale,e=t.charWidth*i|0,s=this.getLines();if(!this._isMultiline)return this.text.length*e;let h=0;for(let t=0;t<s.length;t++){const i=s[t].length*e;i>h&&(h=i)}return h}getContentHeight(){const t=this.customFont??this.resolveFont();if(!t)return 0;const i=this.autoFitScale?this.maxScale:this.scale,e=t.lineHeight*i|0;return this.getLines(),this._isMultiline?this._cachedLines.length*e:e}drawSelf(i,e){if(!this.text)return;const s=this.customFont??e.fontAtlas;if(!s)return;const h=this.innerWidth,l=this.innerHeight,n=this.innerX,c=this.innerY,o=this.color===t.THEME_DEFAULT?e.textPrimary:this.color,r=this.autoFitScale?this.computedScale:this.scale;if(this.getLines(),!this._isMultiline)return void this.drawSingleLine(i,s,this.text,n,c,h,l,o,r);const a=s.lineHeight*r|0,d=s.charWidth*r|0,g=this.getLines(),u=g.length*a;let x=c;"middle"===this.vAlign?x=Math.round(c+(l-u)/2):"bottom"===this.vAlign&&(x=c+l-u),x+=this.textOffsetY;for(let t=0;t<g.length;t++){const e=g[t];if(!e){x+=a;continue}const l=e.length*d;let c=n;"center"===this.hAlign?c=Math.round(n+(h-l)/2):"right"===this.hAlign&&(c=n+h-l),i.drawText(s,e,c,x,o,1!==r?r:void 0),x+=a}}drawSingleLine(t,i,e,s,h,l,n,c,o){const r=i.charWidth*o|0,a=i.lineHeight*o|0;let d=e;if(e.length*r>l&&"ellipsis"===this.overflow&&r>0){const t=Math.max(0,Math.floor(l/r)-1);d=this.getEllipsisText(e,t)}const g=d.length*r;let u=s;"center"===this.hAlign?u=Math.round(s+(l-g)/2):"right"===this.hAlign&&(u=s+l-g);let x=h;"middle"===this.vAlign?x=Math.round(h+(n-a)/2):"bottom"===this.vAlign&&(x=h+n-a),x+=this.textOffsetY,t.drawText(i,d,u,x,c,1!==o?o:void 0)}}exports.Label=i;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Widget, HAlign, VAlign } from '../core/widget';
|
|
2
|
+
import { FontAtlas } from '../core/atlas';
|
|
3
|
+
import { Renderer } from '../core/renderer';
|
|
4
|
+
import { Theme } from '../core/theme';
|
|
5
|
+
/** text label widget supporting multiline, alignment, ellipsis overflow, and custom fonts. */
|
|
6
|
+
export declare class Label extends Widget {
|
|
7
|
+
/** text content; supports newlines for multiline rendering. */
|
|
8
|
+
text: string;
|
|
9
|
+
/** text color override; uses theme default when set to THEME_DEFAULT. */
|
|
10
|
+
color: number;
|
|
11
|
+
/** horizontal text alignment. */
|
|
12
|
+
hAlign: HAlign;
|
|
13
|
+
/** vertical text alignment. */
|
|
14
|
+
vAlign: VAlign;
|
|
15
|
+
/** optional font atlas override; falls back to theme font when null. */
|
|
16
|
+
customFont: FontAtlas | null;
|
|
17
|
+
/** overflow mode: "clip" truncates silently, "ellipsis" appends a tilde. */
|
|
18
|
+
overflow: "clip" | "ellipsis";
|
|
19
|
+
/** text scale factor applied during rendering. */
|
|
20
|
+
scale: number;
|
|
21
|
+
/** vertical pixel offset applied after alignment calculation. */
|
|
22
|
+
textOffsetY: number;
|
|
23
|
+
private _cachedText;
|
|
24
|
+
private _cachedLines;
|
|
25
|
+
private _cachedEllipsisText;
|
|
26
|
+
private _cachedEllipsisSource;
|
|
27
|
+
private _cachedEllipsisMaxChars;
|
|
28
|
+
private _isMultiline;
|
|
29
|
+
/** splits text into lines, caching the result and the single-versus-multiline flag until text changes. */
|
|
30
|
+
private getLines;
|
|
31
|
+
/** truncates text to maxChars and appends a tilde, caching the result for the same text and limit. */
|
|
32
|
+
private getEllipsisText;
|
|
33
|
+
/** returns the widest line width in pixels at the effective scale. */
|
|
34
|
+
getContentWidth(): number;
|
|
35
|
+
/** returns the total text height in pixels at the effective scale. */
|
|
36
|
+
getContentHeight(): number;
|
|
37
|
+
/** draws text within the content box: single-line, or multi-line layout with vertical/horizontal alignment. */
|
|
38
|
+
protected drawSelf(renderer: Renderer, theme: Theme): void;
|
|
39
|
+
/** draws one line, applying ellipsis truncation on overflow and aligning it within the content box. */
|
|
40
|
+
private drawSingleLine;
|
|
41
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Widget as t,THEME_DEFAULT as i}from"../core/widget.mjs";class e extends t{text="";color=i;hAlign="left";vAlign="middle";customFont=null;overflow="clip";scale=1;textOffsetY=0;_cachedText="";_cachedLines=[];_cachedEllipsisText="";_cachedEllipsisSource="";_cachedEllipsisMaxChars=-1;_isMultiline=!1;getLines(){return this._cachedText!==this.text&&(this._cachedText=this.text,-1===this.text.indexOf("\n")?(this._cachedLines[0]=this.text,this._cachedLines.length=1,this._isMultiline=!1):(this._cachedLines=this.text.split("\n"),this._isMultiline=!0)),this._cachedLines}getEllipsisText(t,i){return t===this._cachedEllipsisSource&&i===this._cachedEllipsisMaxChars||(this._cachedEllipsisSource=t,this._cachedEllipsisMaxChars=i,this._cachedEllipsisText=i>0?t.slice(0,i)+"~":""),this._cachedEllipsisText}getContentWidth(){const t=this.customFont??this.resolveFont();if(!t||!this.text)return 0;const i=this.autoFitScale?this.maxScale:this.scale,e=t.charWidth*i|0,s=this.getLines();if(!this._isMultiline)return this.text.length*e;let h=0;for(let t=0;t<s.length;t++){const i=s[t].length*e;i>h&&(h=i)}return h}getContentHeight(){const t=this.customFont??this.resolveFont();if(!t)return 0;const i=this.autoFitScale?this.maxScale:this.scale,e=t.lineHeight*i|0;return this.getLines(),this._isMultiline?this._cachedLines.length*e:e}drawSelf(t,e){if(!this.text)return;const s=this.customFont??e.fontAtlas;if(!s)return;const h=this.innerWidth,l=this.innerHeight,n=this.innerX,c=this.innerY,o=this.color===i?e.textPrimary:this.color,r=this.autoFitScale?this.computedScale:this.scale;if(this.getLines(),!this._isMultiline)return void this.drawSingleLine(t,s,this.text,n,c,h,l,o,r);const a=s.lineHeight*r|0,d=s.charWidth*r|0,g=this.getLines(),u=g.length*a;let x=c;"middle"===this.vAlign?x=Math.round(c+(l-u)/2):"bottom"===this.vAlign&&(x=c+l-u),x+=this.textOffsetY;for(let i=0;i<g.length;i++){const e=g[i];if(!e){x+=a;continue}const l=e.length*d;let c=n;"center"===this.hAlign?c=Math.round(n+(h-l)/2):"right"===this.hAlign&&(c=n+h-l),t.drawText(s,e,c,x,o,1!==r?r:void 0),x+=a}}drawSingleLine(t,i,e,s,h,l,n,c,o){const r=i.charWidth*o|0,a=i.lineHeight*o|0;let d=e;if(e.length*r>l&&"ellipsis"===this.overflow&&r>0){const t=Math.max(0,Math.floor(l/r)-1);d=this.getEllipsisText(e,t)}const g=d.length*r;let u=s;"center"===this.hAlign?u=Math.round(s+(l-g)/2):"right"===this.hAlign&&(u=s+l-g);let x=h;"middle"===this.vAlign?x=Math.round(h+(n-a)/2):"bottom"===this.vAlign&&(x=h+n-a),x+=this.textOffsetY,t.drawText(i,d,u,x,c,1!==o?o:void 0)}}export{e as Label};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("../core/widget.cjs"),i=require("../defaults.cjs"),e=i.DEFAULTS.scrubHitWidth,s=i.DEFAULTS.scrubLineWidth,n=i.DEFAULTS.scrubLineInset,r=i.DEFAULTS.scrubLineLeft;class h extends t.Widget{numValue=0;min=0;max=1;step=1;decimals=0;onChange=null;onCommit=null;bgColor=t.THEME_DEFAULT;textColor=t.THEME_DEFAULT;borderRadius=i.DEFAULTS.sliderValueBgRadius;paddingRight=i.DEFAULTS.sliderValuePaddingRight;scrubHovered=!1;scrubDragging=!1;scrubPointerId=-1;scrubOriginValue=0;scrubOriginX=0;pointerScale=.1;editing=!1;editInput=null;editCleanup=null;cachedText="";cachedValue=NaN;updatePointerScale(){const t=Math.abs(this.step);this.pointerScale=0===t?.1:Math.pow(10,Math.floor(Math.log10(t))-1)}formatValue(){return this.numValue!==this.cachedValue&&(this.cachedValue=this.numValue,this.cachedText=0===this.decimals?String(Math.round(this.numValue)):this.numValue.toFixed(this.decimals)),this.cachedText}drawSelf(e,h){const o=this.width,a=this.height,u=h,l=this.bgColor===t.THEME_DEFAULT?h.bgInput:this.bgColor;e.fillRoundedRect(0,0,o,a,this.borderRadius,l);const d=this.scrubHovered||this.scrubDragging?i.DEFAULTS.scrubLineHoverColor:i.DEFAULTS.scrubLineNormalColor,c=a-2*n,g=n;if(e.fillRoundedRect(r,g,s,c,1,d),!this.editing){const i=u.fontAtlas;if(i){const s=this.formatValue(),n=s.length*i.charWidth,r=o-this.paddingRight-n,l=(a-i.lineHeight)/2|0,d=this.textColor===t.THEME_DEFAULT?h.textValue:this.textColor;e.drawText(i,s,r,l+(u.textOffsetY??0),d)}}}onPointerLeave(){this.scrubHovered&&(this.scrubHovered=!1,this.markDirty())}onPointerMove(t,i,s){if(this.scrubDragging&&t===this.scrubPointerId){const t=i-this.scrubOriginX,e=this.scrubOriginValue+t*this.pointerScale,s=this.snap(e),n=Math.max(this.min,Math.min(this.max,s));return void(n!==this.numValue&&(this.numValue=n,this.onChange&&this.onChange(n),this.markDirty()))}const n=i>=0&&i<e;n!==this.scrubHovered&&(this.scrubHovered=n,this.markDirty())}onPointerDown(t,i,s,n){return!(0!==n||!this.enabled||(i<e?(this.scrubDragging=!0,this.scrubPointerId=t,this.scrubOriginValue=this.numValue,this.scrubOriginX=i,this.scrubHovered=!0,this.markDirty(),0):(this.startEditing(),0)))}onPointerUp(t,i,e,s){this.scrubDragging&&t===this.scrubPointerId&&(this.scrubDragging=!1,this.scrubPointerId=-1,this.onCommit&&this.onCommit(this.numValue),this.markDirty())}snap(t){return this.step<=0?t:Math.round(t/this.step)*this.step}startEditing(){if(this.editing||!this.surface)return;this.editing=!0,this.markDirty();const t=this.surface.canvas,e=t.getBoundingClientRect(),s=e.width/t.width,n=e.height/t.height,r=e.left+this.absoluteX*s,h=e.top+this.absoluteY*n,o=this.width*s,a=this.height*n,u=document.createElement("input");u.type="text",u.value=this.formatValue(),u.style.position="fixed",u.style.left=`${r}px`,u.style.top=`${h}px`,u.style.width=`${o}px`,u.style.height=`${a}px`,u.style.boxSizing="border-box",u.style.padding=`0 ${this.paddingRight}px`,u.style.margin="0",u.style.border="none",u.style.outline="none",u.style.borderRadius=`${this.borderRadius}px`,u.style.backgroundColor=i.DEFAULTS.editInputBg,u.style.color=i.DEFAULTS.editInputColor,u.style.fontFamily=i.DEFAULTS.panelDefaultFontFamily,u.style.fontSize=`${i.DEFAULTS.panelDefaultFontSize}px`,u.style.textAlign="right",u.style.zIndex=i.DEFAULTS.editInputZIndex,u.style.caretColor=i.DEFAULTS.editInputCaretColor,document.body.appendChild(u),this.editInput=u,requestAnimationFrame(()=>{u.focus(),u.select()});const l=()=>{const t=parseFloat(u.value);if(!isNaN(t)){const i=this.snap(t),e=Math.max(this.min,Math.min(this.max,i));this.numValue=e,this.onChange&&this.onChange(e),this.onCommit&&this.onCommit(e)}this.stopEditing()},d=t=>{"Enter"===t.key?(t.preventDefault(),l()):"Escape"===t.key&&(t.preventDefault(),this.stopEditing()),t.stopPropagation()},c=()=>{l()};u.addEventListener("keydown",d),u.addEventListener("blur",c),this.editCleanup=()=>{u.removeEventListener("keydown",d),u.removeEventListener("blur",c)}}stopEditing(){this.editing&&(this.editing=!1,this.editCleanup&&(this.editCleanup(),this.editCleanup=null),this.editInput&&(this.editInput.remove(),this.editInput=null),this.cachedValue=NaN,this.markDirty())}dispose(){this.stopEditing()}}exports.NumberInput=h;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { Widget } from '../core/widget';
|
|
2
|
+
import { Renderer } from '../core/renderer';
|
|
3
|
+
import { Theme } from '../core/theme';
|
|
4
|
+
/** numeric input widget with pointer-scrub and inline text editing. */
|
|
5
|
+
export declare class NumberInput extends Widget {
|
|
6
|
+
/** current numeric value. */
|
|
7
|
+
numValue: number;
|
|
8
|
+
/** minimum allowed value. */
|
|
9
|
+
min: number;
|
|
10
|
+
/** maximum allowed value. */
|
|
11
|
+
max: number;
|
|
12
|
+
/** step size for snapping. */
|
|
13
|
+
step: number;
|
|
14
|
+
/** number of decimal places in the formatted display. */
|
|
15
|
+
decimals: number;
|
|
16
|
+
/** called on every value change during scrubbing or editing. */
|
|
17
|
+
onChange: ((value: number) => void) | null;
|
|
18
|
+
/** called once when a scrub or edit session ends. */
|
|
19
|
+
onCommit: ((value: number) => void) | null;
|
|
20
|
+
/** background color override. */
|
|
21
|
+
bgColor: number;
|
|
22
|
+
/** text color override. */
|
|
23
|
+
textColor: number;
|
|
24
|
+
/** corner radius of the background rectangle. */
|
|
25
|
+
borderRadius: number;
|
|
26
|
+
/** right padding for the displayed number text. */
|
|
27
|
+
paddingRight: number;
|
|
28
|
+
private scrubHovered;
|
|
29
|
+
private scrubDragging;
|
|
30
|
+
private scrubPointerId;
|
|
31
|
+
private scrubOriginValue;
|
|
32
|
+
private scrubOriginX;
|
|
33
|
+
private pointerScale;
|
|
34
|
+
private editing;
|
|
35
|
+
private editInput;
|
|
36
|
+
private editCleanup;
|
|
37
|
+
private cachedText;
|
|
38
|
+
private cachedValue;
|
|
39
|
+
/** recalculates pointer scrub sensitivity based on step magnitude. */
|
|
40
|
+
updatePointerScale(): void;
|
|
41
|
+
/** formats the value to the configured decimal places, caching the string until the value changes. */
|
|
42
|
+
private formatValue;
|
|
43
|
+
/** paints the background, scrub handle line (lit while hovered/dragging), and value text unless editing. */
|
|
44
|
+
protected drawSelf(renderer: Renderer, theme: Theme): void;
|
|
45
|
+
/** clears the scrub-zone hover highlight when the pointer leaves. */
|
|
46
|
+
onPointerLeave(): void;
|
|
47
|
+
/** while dragging, maps horizontal movement to a snapped, clamped value change; otherwise tracks scrub-zone hover. */
|
|
48
|
+
onPointerMove(pointerId: number, x: number, _y: number): void;
|
|
49
|
+
/** starts a scrub drag when the press lands in the left handle zone, otherwise opens the inline text editor. */
|
|
50
|
+
onPointerDown(pointerId: number, x: number, _y: number, button: number): boolean;
|
|
51
|
+
/** ends a scrub drag and fires the commit callback with the final value. */
|
|
52
|
+
onPointerUp(pointerId: number, _x: number, _y: number, _button: number): void;
|
|
53
|
+
/** rounds a value to the nearest multiple of step, or returns it unchanged when step is not positive. */
|
|
54
|
+
private snap;
|
|
55
|
+
/**
|
|
56
|
+
* Opens a native text input overlaid on the widget's on-screen rect for
|
|
57
|
+
* direct editing. The rect is mapped from widget-absolute coordinates to page
|
|
58
|
+
* coordinates, and the input commits on Enter or blur and cancels on Escape.
|
|
59
|
+
*/
|
|
60
|
+
private startEditing;
|
|
61
|
+
/** closes the inline editor, removing its element and listeners and forcing a value reformat. */
|
|
62
|
+
private stopEditing;
|
|
63
|
+
/** tears down any active inline edit input element. */
|
|
64
|
+
dispose(): void;
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Widget as t,THEME_DEFAULT as i}from"../core/widget.mjs";import{DEFAULTS as e}from"../defaults.mjs";const s=e.scrubHitWidth,n=e.scrubLineWidth,r=e.scrubLineInset,h=e.scrubLineLeft;class o extends t{numValue=0;min=0;max=1;step=1;decimals=0;onChange=null;onCommit=null;bgColor=i;textColor=i;borderRadius=e.sliderValueBgRadius;paddingRight=e.sliderValuePaddingRight;scrubHovered=!1;scrubDragging=!1;scrubPointerId=-1;scrubOriginValue=0;scrubOriginX=0;pointerScale=.1;editing=!1;editInput=null;editCleanup=null;cachedText="";cachedValue=NaN;updatePointerScale(){const t=Math.abs(this.step);this.pointerScale=0===t?.1:Math.pow(10,Math.floor(Math.log10(t))-1)}formatValue(){return this.numValue!==this.cachedValue&&(this.cachedValue=this.numValue,this.cachedText=0===this.decimals?String(Math.round(this.numValue)):this.numValue.toFixed(this.decimals)),this.cachedText}drawSelf(t,s){const o=this.width,a=this.height,u=s,l=this.bgColor===i?s.bgInput:this.bgColor;t.fillRoundedRect(0,0,o,a,this.borderRadius,l);const d=this.scrubHovered||this.scrubDragging?e.scrubLineHoverColor:e.scrubLineNormalColor,c=a-2*r,g=r;if(t.fillRoundedRect(h,g,n,c,1,d),!this.editing){const e=u.fontAtlas;if(e){const n=this.formatValue(),r=n.length*e.charWidth,h=o-this.paddingRight-r,l=(a-e.lineHeight)/2|0,d=this.textColor===i?s.textValue:this.textColor;t.drawText(e,n,h,l+(u.textOffsetY??0),d)}}}onPointerLeave(){this.scrubHovered&&(this.scrubHovered=!1,this.markDirty())}onPointerMove(t,i,e){if(this.scrubDragging&&t===this.scrubPointerId){const t=i-this.scrubOriginX,e=this.scrubOriginValue+t*this.pointerScale,s=this.snap(e),n=Math.max(this.min,Math.min(this.max,s));return void(n!==this.numValue&&(this.numValue=n,this.onChange&&this.onChange(n),this.markDirty()))}const n=i>=0&&i<s;n!==this.scrubHovered&&(this.scrubHovered=n,this.markDirty())}onPointerDown(t,i,e,n){return!(0!==n||!this.enabled||(i<s?(this.scrubDragging=!0,this.scrubPointerId=t,this.scrubOriginValue=this.numValue,this.scrubOriginX=i,this.scrubHovered=!0,this.markDirty(),0):(this.startEditing(),0)))}onPointerUp(t,i,e,s){this.scrubDragging&&t===this.scrubPointerId&&(this.scrubDragging=!1,this.scrubPointerId=-1,this.onCommit&&this.onCommit(this.numValue),this.markDirty())}snap(t){return this.step<=0?t:Math.round(t/this.step)*this.step}startEditing(){if(this.editing||!this.surface)return;this.editing=!0,this.markDirty();const t=this.surface.canvas,i=t.getBoundingClientRect(),s=i.width/t.width,n=i.height/t.height,r=i.left+this.absoluteX*s,h=i.top+this.absoluteY*n,o=this.width*s,a=this.height*n,u=document.createElement("input");u.type="text",u.value=this.formatValue(),u.style.position="fixed",u.style.left=`${r}px`,u.style.top=`${h}px`,u.style.width=`${o}px`,u.style.height=`${a}px`,u.style.boxSizing="border-box",u.style.padding=`0 ${this.paddingRight}px`,u.style.margin="0",u.style.border="none",u.style.outline="none",u.style.borderRadius=`${this.borderRadius}px`,u.style.backgroundColor=e.editInputBg,u.style.color=e.editInputColor,u.style.fontFamily=e.panelDefaultFontFamily,u.style.fontSize=`${e.panelDefaultFontSize}px`,u.style.textAlign="right",u.style.zIndex=e.editInputZIndex,u.style.caretColor=e.editInputCaretColor,document.body.appendChild(u),this.editInput=u,requestAnimationFrame(()=>{u.focus(),u.select()});const l=()=>{const t=parseFloat(u.value);if(!isNaN(t)){const i=this.snap(t),e=Math.max(this.min,Math.min(this.max,i));this.numValue=e,this.onChange&&this.onChange(e),this.onCommit&&this.onCommit(e)}this.stopEditing()},d=t=>{"Enter"===t.key?(t.preventDefault(),l()):"Escape"===t.key&&(t.preventDefault(),this.stopEditing()),t.stopPropagation()},c=()=>{l()};u.addEventListener("keydown",d),u.addEventListener("blur",c),this.editCleanup=()=>{u.removeEventListener("keydown",d),u.removeEventListener("blur",c)}}stopEditing(){this.editing&&(this.editing=!1,this.editCleanup&&(this.editCleanup(),this.editCleanup=null),this.editInput&&(this.editInput.remove(),this.editInput=null),this.cachedValue=NaN,this.markDirty())}dispose(){this.stopEditing()}}export{o as NumberInput};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Widget } from '../core/widget';
|
|
2
|
+
import { Renderer } from '../core/renderer';
|
|
3
|
+
import { Theme } from '../core/theme';
|
|
4
|
+
/** full-size overlay widget with optional backdrop and dismiss-on-click behavior. */
|
|
5
|
+
export declare class Overlay extends Widget {
|
|
6
|
+
/** backdrop fill color; zero for transparent. */
|
|
7
|
+
backdropColor: number;
|
|
8
|
+
/** when true, clicking outside children triggers dismissal. */
|
|
9
|
+
dismissOnBackdrop: boolean;
|
|
10
|
+
/** callback invoked when the overlay is dismissed via backdrop click. */
|
|
11
|
+
onDismiss: (() => void) | null;
|
|
12
|
+
/** fills the backdrop across the whole overlay when a backdrop color is set. */
|
|
13
|
+
protected drawSelf(renderer: Renderer, _theme: Theme): void;
|
|
14
|
+
/** dismisses the overlay when the press lands on the backdrop rather than any child, consuming the event. */
|
|
15
|
+
onPointerDown(_pointerId: number, x: number, y: number, _button: number): boolean;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("../core/widget.cjs"),i=require("../defaults.cjs");class h extends t.Widget{scrollY=0;contentHeight=0;showScrollbar=!0;scrollbarWidth=i.DEFAULTS.scrollDefaultWidth;scrollbarColor=t.THEME_DEFAULT;thumbColor=t.THEME_DEFAULT;bgColor=0;anchorMode="top";anchorRow=0;rowHeight=0;manualScrollOffset=0;thumbDragging=!1;thumbDragStartY=0;thumbDragStartScroll=0;thumbPointerId=-1;_visibleStartRow=0;_visibleEndRow=0;get visibleStartRow(){return this._visibleStartRow}get visibleEndRow(){return this._visibleEndRow}computeVisibleRange(){const t=this.height;if(this.rowHeight<=0||t<=0)return this._visibleStartRow=0,void(this._visibleEndRow=0);const i=this.rowHeight>0?Math.ceil(this.contentHeight/this.rowHeight):0;if("center"===this.anchorMode){const h=(t/2+Math.abs(this.manualScrollOffset))/this.rowHeight|0;this._visibleStartRow=Math.max(0,this.anchorRow-h-1),this._visibleEndRow=Math.min(i,this.anchorRow+h+2)}else this._visibleStartRow=Math.max(0,this.scrollY/this.rowHeight|0),this._visibleEndRow=Math.min(i,this._visibleStartRow+Math.ceil(t/this.rowHeight)+1)}getRowY(t){return"center"===this.anchorMode?(this.height/2|0)+this.manualScrollOffset+(t-this.anchorRow)*this.rowHeight-this.rowHeight/2|0:t*this.rowHeight-this.scrollY|0}getEffectiveScroll(){return"center"===this.anchorMode?Math.max(0,this.anchorRow*this.rowHeight-this.height/2):this.scrollY}reserveScrollbarSpace(){this.showScrollbar&&(this.geometry[t.SLOT_PADDING_RIGHT]+=this.scrollbarWidth)}computeLayout(){const i=this.needsLayout;if(super.computeLayout(),i){let i=0;for(let h=this.children.length-1;h>=0;h--)if(this.children[h].visible){const e=this.children[h].geometry[t.SLOT_Y]+this.children[h].geometry[t.SLOT_HEIGHT];e>i&&(i=e)}this.contentHeight=i}"center"!==this.anchorMode&&0!==this.scrollY&&this.offsetChildrenAbsoluteY(this,-this.scrollY)}static _offsetStack=[];offsetChildrenAbsoluteY(t,i){const e=h._offsetStack;let s=0;for(e[s++]=t;s>0;){const t=e[--s].children;for(let h=t.length-1;h>=0;h--){const r=t[h];r.absoluteY=r.absoluteY+i|0,r.children.length>0&&(e[s++]=r)}}}drawSelf(h,e){const s=this.width,r=this.height;if(this.bgColor&&h.fillRect(0,0,s,r,this.bgColor),!this.showScrollbar||this.contentHeight<=r)return;const o=s-this.scrollbarWidth,l=r/this.contentHeight,n=Math.max(i.DEFAULTS.scrollThumbMinHeight,l*r|0),c=this.contentHeight-r,a=r-n,g=this.getEffectiveScroll(),S=c>0?g/c*a|0:0,b=this.scrollbarColor===t.THEME_DEFAULT?e.bgScrollTrack:this.scrollbarColor,u=this.thumbColor===t.THEME_DEFAULT?e.bgScrollThumb:this.thumbColor;h.fillRect(o,0,this.scrollbarWidth,r,b),h.fillRoundedRect(o,S,this.scrollbarWidth,n,i.DEFAULTS.scrollThumbBorderRadius,u)}drawChildren(i,h){const e=this.geometry[t.SLOT_PADDING_LEFT],s=this.geometry[t.SLOT_PADDING_TOP],r=this.innerWidth,o=this.innerHeight;if(i.pushTranslateClip(e,s,0,0,r,o),"center"===this.anchorMode)for(let e=0;e<this.children.length;e++){const s=this.children[e];if(!s.visible)continue;const r=s.geometry;r[t.SLOT_Y]+r[t.SLOT_HEIGHT]<0||r[t.SLOT_Y]>o||(i.pushTranslateClip(r[t.SLOT_X],r[t.SLOT_Y],0,0,r[t.SLOT_WIDTH],r[t.SLOT_HEIGHT]),s.draw(i,h),i.popTranslateClip())}else{const e=this.scrollY;i.pushTranslate(0,-e);for(let s=0;s<this.children.length;s++){const r=this.children[s];if(!r.visible)continue;const l=r.geometry,n=l[t.SLOT_Y]-e;n+l[t.SLOT_HEIGHT]<0||n>o||(i.pushTranslateClip(l[t.SLOT_X],l[t.SLOT_Y],0,0,l[t.SLOT_WIDTH],l[t.SLOT_HEIGHT]),r.draw(i,h),i.popTranslateClip())}i.popTranslate()}i.popTranslateClip()}onWheel(t,h){return!(this.contentHeight<=this.height||("center"===this.anchorMode?(this.manualScrollOffset+=h<0?i.DEFAULTS.scrollSpeed:-40,this.markDirty(),0):(this.scrollBy(h>0?i.DEFAULTS.scrollSpeed:-40),0)))}onPointerDown(t,i,h,e){if(0!==e)return!1;const s=this.width,r=this.height;return!(!this.showScrollbar||this.contentHeight<=r||i<s-this.scrollbarWidth||(this.thumbDragging=!0,this.thumbPointerId=t,this.thumbDragStartY=h,this.thumbDragStartScroll=this.scrollY,0))}onPointerMove(t,h,e){if(!this.thumbDragging||t!==this.thumbPointerId)return;const s=this.height,r=s/this.contentHeight,o=s-Math.max(i.DEFAULTS.scrollThumbMinHeight,r*s|0),l=this.contentHeight-s;if(o<=0)return;const n=(e-this.thumbDragStartY)/o*l;this.setScroll(this.thumbDragStartScroll+n)}onPointerUp(t,i,h,e){t===this.thumbPointerId&&(this.thumbDragging=!1,this.thumbPointerId=-1)}scrollBy(t){this.setScroll(this.scrollY+t)}setScroll(t){const i=Math.max(0,this.contentHeight-this.innerHeight),h=Math.max(0,Math.min(i,t));h!==this.scrollY&&(this.scrollY=h,this.markDirty())}hitTest(i,h){if(!this.visible)return null;const e=this.width,s=this.height;if(this.showScrollbar&&this.contentHeight>s&&i>=e-this.scrollbarWidth)return this;const r=i-this.geometry[t.SLOT_PADDING_LEFT],o=h-this.geometry[t.SLOT_PADDING_TOP],l="center"===this.anchorMode?0:this.scrollY;for(let i=this.children.length-1;i>=0;i--){const h=this.children[i];if(!h.visible)continue;const e=h.geometry,s=r-e[t.SLOT_X],n=o+l-e[t.SLOT_Y];if(s>=0&&s<e[t.SLOT_WIDTH]&&n>=0&&n<e[t.SLOT_HEIGHT]){const t=h.hitTest(s,n);if(t)return t}}return this}}exports.ScrollArea=h;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { Widget } from '../core/widget';
|
|
2
|
+
import { Renderer } from '../core/renderer';
|
|
3
|
+
import { Theme } from '../core/theme';
|
|
4
|
+
/** determines how scroll position is calculated relative to content. */
|
|
5
|
+
export type ScrollAnchorMode = "top" | "center";
|
|
6
|
+
/** scrollable container widget with virtual scrolling, scrollbar, and anchor modes. */
|
|
7
|
+
export declare class ScrollArea extends Widget {
|
|
8
|
+
/** current vertical scroll offset in pixels. */
|
|
9
|
+
scrollY: number;
|
|
10
|
+
/** total height of scrollable content in pixels. */
|
|
11
|
+
contentHeight: number;
|
|
12
|
+
/** whether the scrollbar track and thumb are drawn. */
|
|
13
|
+
showScrollbar: boolean;
|
|
14
|
+
/** scrollbar track width in pixels. */
|
|
15
|
+
scrollbarWidth: number;
|
|
16
|
+
/** scrollbar track color override. */
|
|
17
|
+
scrollbarColor: number;
|
|
18
|
+
/** scrollbar thumb color override. */
|
|
19
|
+
thumbColor: number;
|
|
20
|
+
/** background fill color; zero for transparent. */
|
|
21
|
+
bgColor: number;
|
|
22
|
+
/** scroll positioning strategy: "top" uses scrollY, "center" anchors around anchorRow. */
|
|
23
|
+
anchorMode: ScrollAnchorMode;
|
|
24
|
+
/** row index used as the center anchor when anchorMode is "center". */
|
|
25
|
+
anchorRow: number;
|
|
26
|
+
/** height of each row in pixels; used for virtual scrolling calculations. */
|
|
27
|
+
rowHeight: number;
|
|
28
|
+
/** additional user scroll offset applied in "center" anchor mode. */
|
|
29
|
+
manualScrollOffset: number;
|
|
30
|
+
private thumbDragging;
|
|
31
|
+
private thumbDragStartY;
|
|
32
|
+
private thumbDragStartScroll;
|
|
33
|
+
private thumbPointerId;
|
|
34
|
+
private _visibleStartRow;
|
|
35
|
+
private _visibleEndRow;
|
|
36
|
+
/** first visible row index (inclusive) based on current scroll state. */
|
|
37
|
+
get visibleStartRow(): number;
|
|
38
|
+
/** last visible row index (exclusive) based on current scroll state. */
|
|
39
|
+
get visibleEndRow(): number;
|
|
40
|
+
/** recalculates visible row range from current scroll position and viewport height. */
|
|
41
|
+
computeVisibleRange(): void;
|
|
42
|
+
/** returns the y-coordinate of a row relative to the scroll area top. */
|
|
43
|
+
getRowY(row: number): number;
|
|
44
|
+
/** returns the logical scroll offset accounting for anchor mode. */
|
|
45
|
+
getEffectiveScroll(): number;
|
|
46
|
+
/** adds scrollbar width to right padding so content does not overlap the track. */
|
|
47
|
+
reserveScrollbarSpace(): void;
|
|
48
|
+
/** runs base layout, measures content height, and applies the scroll offset to children. */
|
|
49
|
+
computeLayout(): void;
|
|
50
|
+
/** scratch traversal stack shared across instances, reused to avoid per-call allocation. */
|
|
51
|
+
private static _offsetStack;
|
|
52
|
+
/**
|
|
53
|
+
* Shifts the absolute y of every descendant by offset. It walks the subtree
|
|
54
|
+
* iteratively with a reused static stack rather than recursing, since this
|
|
55
|
+
* runs during layout for every scrolled frame.
|
|
56
|
+
*/
|
|
57
|
+
private offsetChildrenAbsoluteY;
|
|
58
|
+
/** paints the background and, when content overflows, the scrollbar track and a thumb sized to the scroll ratio. */
|
|
59
|
+
protected drawSelf(renderer: Renderer, theme: Theme): void;
|
|
60
|
+
/**
|
|
61
|
+
* Paints children clipped to the content box, culling those scrolled out of
|
|
62
|
+
* view. In "center" mode children keep their positions, otherwise the content
|
|
63
|
+
* is translated up by the scroll offset before drawing.
|
|
64
|
+
*/
|
|
65
|
+
protected drawChildren(renderer: Renderer, theme: Theme): void;
|
|
66
|
+
/** scrolls on wheel input; returns false when content fits without scrolling. */
|
|
67
|
+
onWheel(_deltaX: number, deltaY: number): boolean;
|
|
68
|
+
/** begins thumb drag when the left button is pressed over the scrollbar track. */
|
|
69
|
+
onPointerDown(pointerId: number, x: number, y: number, button: number): boolean;
|
|
70
|
+
/** updates scroll position while dragging the scrollbar thumb. */
|
|
71
|
+
onPointerMove(pointerId: number, _x: number, y: number): void;
|
|
72
|
+
/** ends any active thumb drag for the given pointer. */
|
|
73
|
+
onPointerUp(pointerId: number, _x: number, _y: number, _button: number): void;
|
|
74
|
+
/** scrolls by a relative delta, clamped to valid range. */
|
|
75
|
+
scrollBy(delta: number): void;
|
|
76
|
+
/** sets the absolute scroll position, clamped between 0 and max scroll. */
|
|
77
|
+
setScroll(value: number): void;
|
|
78
|
+
/** returns the scrollbar, a child, or this widget at the given local point. */
|
|
79
|
+
hitTest(x: number, y: number): Widget | null;
|
|
80
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Widget as t,THEME_DEFAULT as i,SLOT_PADDING_RIGHT as h,SLOT_Y as s,SLOT_HEIGHT as e,SLOT_PADDING_LEFT as r,SLOT_PADDING_TOP as o,SLOT_X as l,SLOT_WIDTH as n}from"../core/widget.mjs";import{DEFAULTS as c}from"../defaults.mjs";class a extends t{scrollY=0;contentHeight=0;showScrollbar=!0;scrollbarWidth=c.scrollDefaultWidth;scrollbarColor=i;thumbColor=i;bgColor=0;anchorMode="top";anchorRow=0;rowHeight=0;manualScrollOffset=0;thumbDragging=!1;thumbDragStartY=0;thumbDragStartScroll=0;thumbPointerId=-1;_visibleStartRow=0;_visibleEndRow=0;get visibleStartRow(){return this._visibleStartRow}get visibleEndRow(){return this._visibleEndRow}computeVisibleRange(){const t=this.height;if(this.rowHeight<=0||t<=0)return this._visibleStartRow=0,void(this._visibleEndRow=0);const i=this.rowHeight>0?Math.ceil(this.contentHeight/this.rowHeight):0;if("center"===this.anchorMode){const h=(t/2+Math.abs(this.manualScrollOffset))/this.rowHeight|0;this._visibleStartRow=Math.max(0,this.anchorRow-h-1),this._visibleEndRow=Math.min(i,this.anchorRow+h+2)}else this._visibleStartRow=Math.max(0,this.scrollY/this.rowHeight|0),this._visibleEndRow=Math.min(i,this._visibleStartRow+Math.ceil(t/this.rowHeight)+1)}getRowY(t){return"center"===this.anchorMode?(this.height/2|0)+this.manualScrollOffset+(t-this.anchorRow)*this.rowHeight-this.rowHeight/2|0:t*this.rowHeight-this.scrollY|0}getEffectiveScroll(){return"center"===this.anchorMode?Math.max(0,this.anchorRow*this.rowHeight-this.height/2):this.scrollY}reserveScrollbarSpace(){this.showScrollbar&&(this.geometry[h]+=this.scrollbarWidth)}computeLayout(){const t=this.needsLayout;if(super.computeLayout(),t){let t=0;for(let i=this.children.length-1;i>=0;i--)if(this.children[i].visible){const h=this.children[i].geometry[s]+this.children[i].geometry[e];h>t&&(t=h)}this.contentHeight=t}"center"!==this.anchorMode&&0!==this.scrollY&&this.offsetChildrenAbsoluteY(this,-this.scrollY)}static _offsetStack=[];offsetChildrenAbsoluteY(t,i){const h=a._offsetStack;let s=0;for(h[s++]=t;s>0;){const t=h[--s].children;for(let e=t.length-1;e>=0;e--){const r=t[e];r.absoluteY=r.absoluteY+i|0,r.children.length>0&&(h[s++]=r)}}}drawSelf(t,h){const s=this.width,e=this.height;if(this.bgColor&&t.fillRect(0,0,s,e,this.bgColor),!this.showScrollbar||this.contentHeight<=e)return;const r=s-this.scrollbarWidth,o=e/this.contentHeight,l=Math.max(c.scrollThumbMinHeight,o*e|0),n=this.contentHeight-e,a=e-l,g=this.getEffectiveScroll(),b=n>0?g/n*a|0:0,u=this.scrollbarColor===i?h.bgScrollTrack:this.scrollbarColor,d=this.thumbColor===i?h.bgScrollThumb:this.thumbColor;t.fillRect(r,0,this.scrollbarWidth,e,u),t.fillRoundedRect(r,b,this.scrollbarWidth,l,c.scrollThumbBorderRadius,d)}drawChildren(t,i){const h=this.geometry[r],c=this.geometry[o],a=this.innerWidth,g=this.innerHeight;if(t.pushTranslateClip(h,c,0,0,a,g),"center"===this.anchorMode)for(let h=0;h<this.children.length;h++){const r=this.children[h];if(!r.visible)continue;const o=r.geometry;o[s]+o[e]<0||o[s]>g||(t.pushTranslateClip(o[l],o[s],0,0,o[n],o[e]),r.draw(t,i),t.popTranslateClip())}else{const h=this.scrollY;t.pushTranslate(0,-h);for(let r=0;r<this.children.length;r++){const o=this.children[r];if(!o.visible)continue;const c=o.geometry,a=c[s]-h;a+c[e]<0||a>g||(t.pushTranslateClip(c[l],c[s],0,0,c[n],c[e]),o.draw(t,i),t.popTranslateClip())}t.popTranslate()}t.popTranslateClip()}onWheel(t,i){return!(this.contentHeight<=this.height||("center"===this.anchorMode?(this.manualScrollOffset+=i<0?c.scrollSpeed:-40,this.markDirty(),0):(this.scrollBy(i>0?c.scrollSpeed:-40),0)))}onPointerDown(t,i,h,s){if(0!==s)return!1;const e=this.width,r=this.height;return!(!this.showScrollbar||this.contentHeight<=r||i<e-this.scrollbarWidth||(this.thumbDragging=!0,this.thumbPointerId=t,this.thumbDragStartY=h,this.thumbDragStartScroll=this.scrollY,0))}onPointerMove(t,i,h){if(!this.thumbDragging||t!==this.thumbPointerId)return;const s=this.height,e=s/this.contentHeight,r=s-Math.max(c.scrollThumbMinHeight,e*s|0),o=this.contentHeight-s;if(r<=0)return;const l=(h-this.thumbDragStartY)/r*o;this.setScroll(this.thumbDragStartScroll+l)}onPointerUp(t,i,h,s){t===this.thumbPointerId&&(this.thumbDragging=!1,this.thumbPointerId=-1)}scrollBy(t){this.setScroll(this.scrollY+t)}setScroll(t){const i=Math.max(0,this.contentHeight-this.innerHeight),h=Math.max(0,Math.min(i,t));h!==this.scrollY&&(this.scrollY=h,this.markDirty())}hitTest(t,i){if(!this.visible)return null;const h=this.width,c=this.height;if(this.showScrollbar&&this.contentHeight>c&&t>=h-this.scrollbarWidth)return this;const a=t-this.geometry[r],g=i-this.geometry[o],b="center"===this.anchorMode?0:this.scrollY;for(let t=this.children.length-1;t>=0;t--){const i=this.children[t];if(!i.visible)continue;const h=i.geometry,r=a-h[l],o=g+b-h[s];if(r>=0&&r<h[n]&&o>=0&&o<h[e]){const t=i.hitTest(r,o);if(t)return t}}return this}}export{a as ScrollArea};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("../core/widget.cjs"),e=require("../defaults.cjs");class s extends t.Widget{direction="horizontal";color=e.DEFAULTS.separatorDefaultColor;thickness=e.DEFAULTS.separatorDefaultThickness;drawSelf(t,e){if("horizontal"===this.direction){const e=(this.height-this.thickness)/2|0;t.fillRect(0,e,this.width,this.thickness,this.color)}else{const e=(this.width-this.thickness)/2|0;t.fillRect(e,0,this.thickness,this.height,this.color)}}}exports.Separator=s;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Widget } from '../core/widget';
|
|
2
|
+
import { Renderer } from '../core/renderer';
|
|
3
|
+
import { Theme } from '../core/theme';
|
|
4
|
+
/** orientation for a visual divider line. */
|
|
5
|
+
export type SeparatorDirection = "horizontal" | "vertical";
|
|
6
|
+
/** thin line widget used as a visual divider between sections. */
|
|
7
|
+
export declare class Separator extends Widget {
|
|
8
|
+
/** orientation of the separator line. */
|
|
9
|
+
direction: SeparatorDirection;
|
|
10
|
+
/** fill color of the separator line. */
|
|
11
|
+
color: number;
|
|
12
|
+
/** line thickness in pixels. */
|
|
13
|
+
thickness: number;
|
|
14
|
+
/** draws the line centered along its cross axis, spanning the full length. */
|
|
15
|
+
protected drawSelf(renderer: Renderer, _theme: Theme): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Widget as t}from"../core/widget.mjs";import{DEFAULTS as s}from"../defaults.mjs";class i extends t{direction="horizontal";color=s.separatorDefaultColor;thickness=s.separatorDefaultThickness;drawSelf(t,s){if("horizontal"===this.direction){const s=(this.height-this.thickness)/2|0;t.fillRect(0,s,this.width,this.thickness,this.color)}else{const s=(this.width-this.thickness)/2|0;t.fillRect(s,0,this.thickness,this.height,this.color)}}}export{i as Separator};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const i=require("../core/widget.cjs"),t=require("../defaults.cjs"),e=t.DEFAULTS.sliderKnobShadowColor;class o extends i.Widget{value=0;min=0;max=1;trackColor=i.THEME_DEFAULT;fillColor=i.THEME_DEFAULT;thumbColor=i.THEME_DEFAULT;trackRadius=t.DEFAULTS.sliderTrackRadius;onChange=null;onRelease=null;dragging=!1;dragPointerId=-1;drawSelf(o,s){const r=this.width,l=this.height,a=this.max-this.min,n=a>0?(this.value-this.min)/a:0,h=this.trackColor===i.THEME_DEFAULT?s.bgInput:this.trackColor,d=this.thumbColor===i.THEME_DEFAULT?t.DEFAULTS.sliderDefaultThumbColor:this.thumbColor,u=this.fillColor===i.THEME_DEFAULT?s.bgSelected:this.fillColor,g=t.DEFAULTS.sliderTrackHeight,c=(l-g)/2|0,E=this.trackRadius;o.fillRoundedRect(0,c,r,g,E,h);const T=n*r|0;T>0&&o.fillRoundedRect(0,c,T,g,E,u);const m=Math.min(l,t.DEFAULTS.sliderThumbMaxDiameter)/2|0,C=n*(r-2*m)+m|0,D=l/2|0;o.fillCircle(C,D+t.DEFAULTS.sliderKnobShadowOffsetY,m,e),o.fillCircle(C,D,m,d)}onPointerDown(i,t,e,o){return!(0!==o||!this.enabled||(this.dragging=!0,this.dragPointerId=i,this.updateValueFromPosition(t),0))}onPointerMove(i,t,e){this.dragging&&i===this.dragPointerId&&this.updateValueFromPosition(t)}onPointerUp(i,t,e,o){i===this.dragPointerId&&(this.dragging=!1,this.dragPointerId=-1,this.onRelease&&this.onRelease())}updateValueFromPosition(i){const t=this.width;if(t<=0)return;const e=Math.max(0,Math.min(1,i/t)),o=this.min+e*(this.max-this.min);o!==this.value&&(this.value=o,this.onChange&&this.onChange(this.value),this.markDirty())}}exports.Slider=o;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Widget } from '../core/widget';
|
|
2
|
+
import { Renderer } from '../core/renderer';
|
|
3
|
+
import { Theme } from '../core/theme';
|
|
4
|
+
/** horizontal slider widget with track fill and circular thumb. */
|
|
5
|
+
export declare class Slider extends Widget {
|
|
6
|
+
/** current slider value between min and max. */
|
|
7
|
+
value: number;
|
|
8
|
+
/** minimum value at the left edge. */
|
|
9
|
+
min: number;
|
|
10
|
+
/** maximum value at the right edge. */
|
|
11
|
+
max: number;
|
|
12
|
+
/** track background color override. */
|
|
13
|
+
trackColor: number;
|
|
14
|
+
/** filled portion color override. */
|
|
15
|
+
fillColor: number;
|
|
16
|
+
/** thumb circle color override. */
|
|
17
|
+
thumbColor: number;
|
|
18
|
+
/** corner radius of the track rectangle. */
|
|
19
|
+
trackRadius: number;
|
|
20
|
+
/** called on every value change during drag. */
|
|
21
|
+
onChange: ((value: number) => void) | null;
|
|
22
|
+
/** called once when the drag ends. */
|
|
23
|
+
onRelease: (() => void) | null;
|
|
24
|
+
private dragging;
|
|
25
|
+
private dragPointerId;
|
|
26
|
+
/** draws the track, the filled portion up to the current value, and the thumb with its drop shadow. */
|
|
27
|
+
protected drawSelf(renderer: Renderer, theme: Theme): void;
|
|
28
|
+
/** begins a drag on primary-button press and sets the value from the pointer position. */
|
|
29
|
+
onPointerDown(pointerId: number, x: number, _y: number, button: number): boolean;
|
|
30
|
+
/** tracks the captured pointer during a drag and updates the value from its position. */
|
|
31
|
+
onPointerMove(pointerId: number, x: number, _y: number): void;
|
|
32
|
+
/** ends the drag and fires onRelease when the captured pointer lifts. */
|
|
33
|
+
onPointerUp(pointerId: number, _x: number, _y: number, _button: number): void;
|
|
34
|
+
/** maps an x coordinate to a value in the min..max range, firing onChange and repainting on change. */
|
|
35
|
+
private updateValueFromPosition;
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Widget as i,THEME_DEFAULT as t}from"../core/widget.mjs";import{DEFAULTS as o}from"../defaults.mjs";const e=o.sliderKnobShadowColor;class s extends i{value=0;min=0;max=1;trackColor=t;fillColor=t;thumbColor=t;trackRadius=o.sliderTrackRadius;onChange=null;onRelease=null;dragging=!1;dragPointerId=-1;drawSelf(i,s){const r=this.width,l=this.height,a=this.max-this.min,h=a>0?(this.value-this.min)/a:0,n=this.trackColor===t?s.bgInput:this.trackColor,d=this.thumbColor===t?o.sliderDefaultThumbColor:this.thumbColor,u=this.fillColor===t?s.bgSelected:this.fillColor,m=o.sliderTrackHeight,g=(l-m)/2|0,c=this.trackRadius;i.fillRoundedRect(0,g,r,m,c,n);const C=h*r|0;C>0&&i.fillRoundedRect(0,g,C,m,c,u);const f=Math.min(l,o.sliderThumbMaxDiameter)/2|0,P=h*(r-2*f)+f|0,b=l/2|0;i.fillCircle(P,b+o.sliderKnobShadowOffsetY,f,e),i.fillCircle(P,b,f,d)}onPointerDown(i,t,o,e){return!(0!==e||!this.enabled||(this.dragging=!0,this.dragPointerId=i,this.updateValueFromPosition(t),0))}onPointerMove(i,t,o){this.dragging&&i===this.dragPointerId&&this.updateValueFromPosition(t)}onPointerUp(i,t,o,e){i===this.dragPointerId&&(this.dragging=!1,this.dragPointerId=-1,this.onRelease&&this.onRelease())}updateValueFromPosition(i){const t=this.width;if(t<=0)return;const o=Math.max(0,Math.min(1,i/t)),e=this.min+o*(this.max-this.min);e!==this.value&&(this.value=e,this.onChange&&this.onChange(this.value),this.markDirty())}}export{s as Slider};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("../core/widget.cjs"),i=require("../defaults.cjs"),s=i.DEFAULTS.tabArrowWidth,h=i.DEFAULTS.tabArrowHalf,e=i.DEFAULTS.tabStripPaddingTop,o=i.DEFAULTS.tabStripPaddingSide,a=i.DEFAULTS.tabRadius,r=i.DEFAULTS.tabSeparatorHeight,l=i.DEFAULTS.tabSeparatorColor,n=i.DEFAULTS.tabHoverColor;class b extends t.Widget{tabs=[];value="";bgColor=t.THEME_DEFAULT;activeColor=t.THEME_DEFAULT;textColor=t.THEME_DEFAULT;activeTextColor=t.THEME_DEFAULT;tabSizing="content";tabPadding=16;onChange=null;reservedEdge=0;tabPositions=new Float32Array(i.DEFAULTS.tabInitialCapacity);tabWidths=new Float32Array(i.DEFAULTS.tabInitialCapacity);scrollOffset=0;totalTabWidth=0;showLeftArrow=!1;showRightArrow=!1;_tabsDirty=!0;_lastTabCount=0;_lastWidth=0;_lastCharWidth=0;_hoverIndex=-1;drawSelf(i,b){const d=this.width,c=this.height,f=this.tabs.length;if(0===f)return;const T=this.bgColor===t.THEME_DEFAULT?b.bgPanel:this.bgColor;i.fillRect(0,0,d,c,T);const u=b.fontAtlas,w=this.textColor===t.THEME_DEFAULT?b.textMuted:this.textColor,A=this.activeTextColor===t.THEME_DEFAULT?b.textPrimary:this.activeTextColor,v=this.activeColor===t.THEME_DEFAULT?b.bgPanelRaised:this.activeColor,E=this.textColor===t.THEME_DEFAULT?b.textMuted:this.textColor,g=u?.charWidth??8;this.computeTabPositions(d,g);const p=c-e,C=(this.showLeftArrow?s:0)+o,W=d-this.reservedEdge-(this.showRightArrow?s:0)-o-C;i.pushClip(C,0,W,c),i.pushTranslate(-this.scrollOffset+C,e);for(let t=0;t<f;t++){const s=this.tabs[t],h=this.tabPositions[t],e=this.tabWidths[t],o=s.value===this.value;if(o&&v?(i.fillRoundedRect(h,0,e,p+a,a,v),i.pushClip(h,p,e,a),i.fillRect(h,p,e,a,v),i.popClip()):t===this._hoverIndex&&(i.fillRoundedRect(h,0,e,p+a,a,n),i.pushClip(h,p,e,a),i.fillRect(h,p,e,a,n),i.popClip()),u){const a=s.label.length*g,r=Math.round(h+(e-a)/2),l=Math.round((p-u.lineHeight)/2),n=o||t===this._hoverIndex?A:w;i.drawText(u,s.label,r,l,n)}if(!o&&t<f-1&&!(t+1<f&&this.tabs[t+1].value===this.value)){const t=h+e,s=Math.round((p-r)/2);i.fillRect(t,s,1,r,l)}}if(i.popTranslate(),i.popClip(),this.showLeftArrow){i.fillRect(0,0,s+o,c,T);const t=s/2+5|0,e=2+(c/2|0);i.beginPath(),i.moveTo(t+h,e-h),i.lineTo(t-h,e),i.lineTo(t+h,e+h),i.fillPath(E)}if(this.showRightArrow){const t=d-this.reservedEdge-s-o;i.fillRect(t,0,s+o,c,T);const e=t+s/2+5|0,a=2+(c/2|0);i.beginPath(),i.moveTo(e-h,a-h),i.lineTo(e+h,a),i.lineTo(e-h,a+h),i.fillPath(E)}}onPointerDown(t,i,h,e){if(0!==e||!this.enabled)return!1;const a=this.tabs.length;if(0===a)return!1;if(this.showLeftArrow&&i<s+o)return this.scroll(.6*-this.width),!0;const r=this.width-this.reservedEdge-s-o;if(this.showRightArrow&&i>=r)return this.scroll(.6*this.width),!0;const l=i-((this.showLeftArrow?s:0)+o)+this.scrollOffset;for(let t=0;t<a;t++)if(l>=this.tabPositions[t]&&l<this.tabPositions[t]+this.tabWidths[t]){const i=this.tabs[t].value;return i!==this.value&&(this.value=i,this.scrollActiveTabIntoView(),this.onChange&&this.onChange(i),this.markDirty()),!0}return!0}onWheel(t,i){if(!this.overflows())return!1;const s=Math.abs(t)>=Math.abs(i)?t:i;return 0!==s&&(this.scroll(s),!0)}onPointerMove(t,i,h){const e=i-((this.showLeftArrow?s:0)+o)+this.scrollOffset;let a=-1;for(let t=0;t<this.tabs.length;t++)if(e>=this.tabPositions[t]&&e<this.tabPositions[t]+this.tabWidths[t]){this.tabs[t].value!==this.value&&(a=t);break}a!==this._hoverIndex&&(this._hoverIndex=a,this.markDirty())}onPointerLeave(){-1!==this._hoverIndex&&(this._hoverIndex=-1,this.markDirty())}scrollAvailableWidth(){return this.width-this.reservedEdge-2*o-s}scroll(t){const i=Math.max(0,this.totalTabWidth-this.scrollAvailableWidth());this.scrollOffset=Math.max(0,Math.min(i,this.scrollOffset+t)),this.updateArrowVisibility(),this.markDirty()}scrollActiveTabIntoView(){const t=this.tabs.length,i=this.scrollAvailableWidth();for(let s=0;s<t;s++)if(this.tabs[s].value===this.value){const t=this.tabPositions[s],h=t+this.tabWidths[s],e=this.scrollOffset,o=this.scrollOffset+i;if(t<e)this.scrollOffset=Math.max(0,t-8);else if(h>o){const t=Math.max(0,this.totalTabWidth-i);this.scrollOffset=Math.min(t,h-i+8)}this.updateArrowVisibility();break}}overflows(){const t=this.width-this.reservedEdge-2*o;return this.totalTabWidth>t}updateArrowVisibility(){const t=Math.max(0,this.totalTabWidth-this.scrollAvailableWidth()),i=t>1;this.showLeftArrow=i&&this.scrollOffset>1,this.showRightArrow=i&&this.scrollOffset<t-1}invalidateTabs(){this._tabsDirty=!0}computeTabPositions(t,i){const s=this.tabs.length;if(this._tabsDirty||s!==this._lastTabCount||t!==this._lastWidth||i!==this._lastCharWidth){if(this._tabsDirty=!1,this._lastTabCount=s,this._lastWidth=t,this._lastCharWidth=i,s>this.tabPositions.length&&(this.tabPositions=new Float32Array(s),this.tabWidths=new Float32Array(s)),"content"===this.tabSizing){let t=0;for(let h=0;h<s;h++){const s=this.tabs[h].label.length*i+2*this.tabPadding;this.tabPositions[h]=t,this.tabWidths[h]=s,t+=s}this.totalTabWidth=t}else{const i=(t-this.reservedEdge-2*o)/s|0;for(let t=0;t<s;t++)this.tabPositions[t]=t*i,this.tabWidths[t]=i;this.totalTabWidth=i*s}this.updateArrowVisibility()}}}exports.TabBar=b;
|