@elicdavis/node-flow 0.2.3 → 0.2.4

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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/render_scheduler.ts", "../../src/theme.ts", "../../src/styles/text.ts", "../../src/types/pool.ts", "../../src/types/vector2.ts", "../../src/types/box.ts", "../../src/types/list.ts", "../../src/contextMenu.ts", "../../src/input.ts", "../../src/elements/interfaces.ts", "../../src/elements/base.ts", "../../src/elements/container.ts", "../../src/elements/text.ts", "../../src/utils/string.ts", "../../src/types/text.ts", "../../src/utils/math.ts", "../../src/utils/color.ts", "../../src/port.ts", "../../src/styles/cursor.ts", "../../src/widgets/inplace.ts", "../../src/widgets/widget.ts", "../../src/widgets/hidden_ports.ts", "../../src/styles/stroke.ts", "../../src/styles/box.ts", "../../src/styles/bevel.ts", "../../src/widgets/field.ts", "../../src/widgets/value.ts", "../../src/widgets/number.ts", "../../src/widgets/button.ts", "../../src/widgets/color.ts", "../../src/widgets/slider.ts", "../../src/widgets/string.ts", "../../src/widgets/toggle.ts", "../../src/widgets/image.ts", "../../src/widgets/text.ts", "../../src/widgets/row.ts", "../../src/widgets/factory.ts", "../../src/connection.ts", "../../src/camera.ts", "../../src/organize.ts", "../../src/performance.ts", "../../src/nodes/publisher.ts", "../../src/nodes/factory.ts", "../../src/nodes/subsystem.ts", "../../src/popup.ts", "../../src/popups/string.ts", "../../src/popups/form.ts", "../../src/node.ts", "../../src/markdown/token.ts", "../../src/markdown/lexicalParser.ts", "../../src/markdown/entry.ts", "../../src/markdown/syntaxParser.ts", "../../src/markdown/markdown.ts", "../../src/notes/note.ts", "../../src/notes/subsystem.ts", "../../src/pass/subsystem.ts", "../../src/quickMenu.ts", "../../src/minimap.ts", "../../src/graph.ts"],
4
+ "sourcesContent": ["type Redraw = () => void;\n\nconst subscribers = new Set<Redraw>();\nlet frameQueued = false;\nlet continuous = 0;\n\nconst canSchedule = (): boolean =>\n typeof requestAnimationFrame === \"function\";\n\nexport function onRenderRequested(redraw: Redraw): () => void {\n subscribers.add(redraw);\n return () => {\n subscribers.delete(redraw);\n };\n}\n\n\nexport function requestRender(): void {\n if (frameQueued || !canSchedule()) {\n return;\n }\n\n frameQueued = true;\n requestAnimationFrame(() => {\n frameQueued = false;\n subscribers.forEach((redraw) => redraw());\n\n // Something asked to be redrawn every frame, so keep the loop\n // alive by asking again on its behalf.\n if (continuous > 0) {\n requestRender();\n }\n });\n}\n\n\nexport function renderContinuously(): () => void {\n continuous++;\n requestRender();\n\n let released = false;\n return () => {\n if (released) {\n return;\n }\n released = true;\n continuous--;\n };\n}\n", "import { requestRender } from \"./render_scheduler\";\r\n\r\nexport interface BevelColors {\r\n Light: string;\r\n Dark: string;\r\n}\r\n\r\nconst defaults = {\r\n FontFamily: \"Courier New\",\r\n Graph: {\r\n BackgroundColor: \"#07212a\",\r\n DotColor: \"rgb(41, 54, 57)\",\r\n },\r\n Node: {\r\n FontColor: \"#afb9bb\",\r\n BackgroundColor: \"#0c2b35\",\r\n Title: {\r\n Color: \"#154050\",\r\n FontColor: \"#afb9bb\",\r\n Padding: 5\r\n },\r\n BorderRadius: 15,\r\n Border: {\r\n Idle: \"#1c1c1c\",\r\n MouseOver: \"#8e8e8e\",\r\n Grabbed: \"white\",\r\n Selected: \"#6e6e6e\",\r\n Highlighted: \"#ffc95c\"\r\n },\r\n Bevel: null as BevelColors | null,\r\n Port: {\r\n FontColor: \"#afb9bb\"\r\n },\r\n Message: {\r\n InfoColor: \"#afb9bb\",\r\n WarnColor: \"#f1f663ff\",\r\n ErrorColor: \"#FF0000\"\r\n }\r\n },\r\n BoxSelect: {\r\n Color: \"white\",\r\n Size: 1,\r\n Radius: 2,\r\n LineDashLength: 5,\r\n },\r\n Widget: {\r\n FontColor: \"#afb9bb\",\r\n LabelColor: \"#7f9497\",\r\n FontSize: 14,\r\n Padding: 6,\r\n Gap: 4,\r\n BackgroundColor: \"#0f313c\",\r\n Border: {\r\n Color: \"#154050\",\r\n Size: 2,\r\n Radius: 2\r\n },\r\n Bevel: null as BevelColors | null,\r\n Hover: {\r\n BackgroundColor: \"#195366\"\r\n },\r\n Input: {\r\n BackgroundColor: \"#0f313c\",\r\n HoverBackgroundColor: \"#195366\",\r\n FontColor: \"#afb9bb\",\r\n },\r\n Slider: {\r\n FillColor: \"#07212A\",\r\n },\r\n Button: {\r\n Click: {\r\n BackgroundColor: \"#1f637a\"\r\n },\r\n }\r\n },\r\n ContextMenu: {\r\n BackgroundColor: \"#07212A\",\r\n HighlightColor: \"#205A6D\",\r\n HighlightFontColor: \"#afb9bb\",\r\n FontColor: \"#afb9bb\",\r\n DisabledFontColor: \"#4a585c\",\r\n BorderRadius: 5,\r\n },\r\n Minimap: {\r\n BackgroundColor: \"rgba(10, 16, 18, 0.85)\",\r\n BorderColor: \"#1c1c1c\",\r\n BorderRadius: 4,\r\n Padding: 6,\r\n NodeColor: \"#6b7f85\",\r\n ViewportColor: \"rgba(175, 185, 187, 0.25)\",\r\n },\r\n Popup: {\r\n BackgroundColor: \"#000000\",\r\n FontColor: \"#ffffff\",\r\n FontFamily: \"Verdana\",\r\n BorderRadius: 8,\r\n Backdrop: \"#00000070\",\r\n },\r\n Note: {\r\n FontColor: \"#afb9bb\",\r\n FontSize: 16,\r\n EntrySpacing: 20,\r\n LineSpacing: 5,\r\n DotSize: 3,\r\n HeaderLineWidth: 2,\r\n H1: {\r\n FontSize: 32,\r\n },\r\n H2: {\r\n FontSize: 16,\r\n },\r\n H3: {\r\n FontSize: 16,\r\n },\r\n CodeFontFamily: null as string | null,\r\n CodeBlock: {\r\n BackgroundColor: \"#0c2b35\",\r\n FontColor: \"#afb9bb\",\r\n Padding: 16,\r\n BorderRadius: 4,\r\n }\r\n }\r\n};\r\n\r\nexport type ThemeValues = typeof defaults;\r\n\r\ntype DeepPartial<T> = {\r\n [K in keyof T]?: T[K] extends BevelColors | null\r\n ? T[K]\r\n : T[K] extends object ? DeepPartial<T[K]> : T[K];\r\n};\r\n\r\nexport type ThemeConfig = DeepPartial<ThemeValues>;\r\n\r\nfunction clone<T>(value: T): T {\r\n return JSON.parse(JSON.stringify(value));\r\n}\r\n\r\nfunction merge(target: any, source: any): any {\r\n if (source === undefined) {\r\n return target;\r\n }\r\n if (source === null || typeof source !== \"object\" || target === null || typeof target !== \"object\") {\r\n return source;\r\n }\r\n for (const key of Object.keys(source)) {\r\n target[key] = merge(target[key], source[key]);\r\n }\r\n return target;\r\n}\r\n\r\nexport const DefaultTheme: Readonly<ThemeValues> = Object.freeze(clone(defaults));\r\n\r\nexport const Theme: ThemeValues = clone(defaults);\r\n\r\nlet version = 0;\r\n\r\nconst listeners = new Set<() => void>();\r\n\r\n/**\r\n * Replaces the theme: the defaults, with anything in config laid over them.\r\n * Everything already on screen picks the change up on its next draw.\r\n */\r\nexport function setTheme(config?: ThemeConfig): void {\r\n const next = merge(clone(defaults), config);\r\n for (const key of Object.keys(next) as Array<keyof ThemeValues>) {\r\n (Theme as any)[key] = next[key];\r\n }\r\n version++;\r\n listeners.forEach((listener) => listener());\r\n requestRender();\r\n}\r\n\r\nexport function themeVersion(): number {\r\n return version;\r\n}\r\n\r\nexport function onThemeChange(listener: () => void): () => void {\r\n listeners.add(listener);\r\n return () => listeners.delete(listener);\r\n}\r\n", "import { Theme } from \"../theme\";\r\nimport { Vector2 } from \"../types/vector2\";\r\n\r\nexport enum FontWeight {\r\n Normal = \"\",\r\n Bold = \"bold\"\r\n}\r\n\r\nexport enum FontStyle {\r\n Normal = \"\",\r\n Italic = \"italic\"\r\n}\r\n\r\nexport interface TextStyleConfig {\r\n size?: number;\r\n color?: string;\r\n font?: string;\r\n weight?: FontWeight;\r\n style?: FontStyle;\r\n}\r\n\r\nconst DefaultSize: number = 16;\r\nconst DefaultColor: string = \"black\";\r\n\r\nexport function TextStyleFallback(input?: TextStyleConfig, fallback?: TextStyleConfig): TextStyleConfig {\r\n return {\r\n color: input?.color === undefined ? fallback?.color : input?.color,\r\n size: input?.size === undefined ? fallback?.size : input?.size,\r\n font: input?.font === undefined ? fallback?.font : input?.font,\r\n style: input?.style === undefined ? fallback?.style : input?.style,\r\n weight: input?.weight === undefined ? fallback?.weight : input?.weight,\r\n };\r\n}\r\n\r\nexport class TextStyle {\r\n\r\n #size: number;\r\n\r\n #color: string;\r\n\r\n #font: string | undefined;\r\n\r\n #weight: FontWeight;\r\n\r\n #fontStyle: FontStyle;\r\n\r\n constructor(config: TextStyleConfig | undefined) {\r\n this.#size = config?.size === undefined ? DefaultSize : config.size;\r\n this.#color = config?.color === undefined ? DefaultColor : config.color;\r\n this.#font = config?.font;\r\n this.#weight = config?.weight === undefined ? FontWeight.Normal : config.weight;\r\n this.#fontStyle = config?.style === undefined ? FontStyle.Normal : config.style;\r\n }\r\n\r\n setupStyle(ctx: CanvasRenderingContext2D, scale: number): void {\r\n ctx.fillStyle = this.#color;\r\n ctx.font = this.#fontStyle + \" \" + this.#weight + \" \" + (this.#size * scale) + \"px \" + this.getFont();\r\n }\r\n\r\n getSize(): number {\r\n return this.#size;\r\n }\r\n\r\n getFont(): string {\r\n return this.#font ?? Theme.FontFamily;\r\n }\r\n\r\n getWeight(): FontWeight {\r\n return this.#weight;\r\n }\r\n\r\n getStyle(): FontStyle {\r\n return this.#fontStyle;\r\n }\r\n\r\n measure(ctx: CanvasRenderingContext2D, scale: number, text: string, out: Vector2): void {\r\n this.setupStyle(ctx, scale);\r\n const measurements = ctx.measureText(text)\r\n out.x = measurements.width;\r\n out.y = measurements.actualBoundingBoxAscent + measurements.actualBoundingBoxDescent;\r\n }\r\n\r\n setColor(color: string): void {\r\n this.#color = color;\r\n }\r\n\r\n getColor(): string {\r\n return this.#color ;\r\n }\r\n\r\n setSize(size: number): void {\r\n this.#size = size;\r\n }\r\n\r\n setWeight(weight: FontWeight): void {\r\n this.#weight = weight;\r\n }\r\n}", "import { Vector2 } from \"./vector2\";\r\n\r\n\r\n\r\nexport class Pool<Type> {\r\n\r\n #arr: Array<Type>;\r\n\r\n #count: number;\r\n\r\n #builder: () => Type;\r\n\r\n #reset: (v: Type) => void;\r\n\r\n #runningDepth: number;\r\n\r\n constructor(builder: () => Type, reset: (v: Type) => void) {\r\n this.#arr = new Array<Type>();\r\n this.#count = 0;\r\n this.#builder = builder;\r\n this.#reset = reset;\r\n this.#runningDepth = 0;\r\n }\r\n\r\n public runIf(condition: boolean, fn: () => void) {\r\n if (condition) {\r\n this.run(fn);\r\n }\r\n }\r\n\r\n #running(): boolean {\r\n return this.#runningDepth > 0;\r\n }\r\n\r\n public run(fn: () => void) {\r\n const start = this.#count;\r\n this.#runningDepth += 1;\r\n fn();\r\n this.#runningDepth -= 1;\r\n this.#count = start;\r\n // console.log(this.#arr.length);\r\n }\r\n\r\n get(): Type {\r\n if(!this.#running()) {\r\n throw new Error(\"can't use pool outside of running context\");\r\n }\r\n\r\n let value: Type;\r\n if (this.#arr.length === this.#count) {\r\n value = this.#builder();\r\n this.#arr.push(this.#builder());\r\n } else {\r\n value = this.#arr[this.#count];\r\n this.#reset(value);\r\n }\r\n this.#count++;\r\n return value;\r\n }\r\n\r\n}\r\n\r\nexport const VectorPool = new Pool<Vector2>(\r\n () => ({ x: 0, y: 0 }),\r\n (v) => { v.x = 0; v.y = 0; }\r\n)\r\n", "export interface Vector2 {\r\n x: number\r\n y: number\r\n}\r\n\r\nexport function CopyVector2(dst: Vector2, src: Vector2): void {\r\n dst.x = src.x;\r\n dst.y = src.y;\r\n}\r\n\r\nexport function SubVector2(dst: Vector2, a: Vector2, b: Vector2): void {\r\n dst.x = a.x - b.x;\r\n dst.y = a.y - b.y;\r\n}\r\n\r\nexport function AddVector2(dst: Vector2, a: Vector2, b: Vector2): void {\r\n dst.x = a.x + b.x;\r\n dst.y = a.y + b.y;\r\n}\r\n\r\nexport function ScaleVector(dst: Vector2, scale: number): void {\r\n dst.x *= scale;\r\n dst.y *= scale;\r\n}\r\n\r\nexport function Zero(): Vector2 {\r\n return { x: 0, y: 0 };\r\n}\r\n\r\nexport function Distance(a: Vector2, b: Vector2): number { \r\n const xd = b.x - a.x\r\n const yd = b.y - a.y\r\n return Math.sqrt((xd*xd)+(yd*yd))\r\n}\r\n", "import { VectorPool } from \"./pool\";\r\nimport { AddVector2, CopyVector2, SubVector2, Vector2, Zero } from \"./vector2\";\r\n\r\nexport interface Box {\r\n Position: Vector2\r\n Size: Vector2\r\n}\r\n\r\nexport function CopyBox(dst: Box, src: Box): void {\r\n dst.Position.x = src.Position.x;\r\n dst.Position.y = src.Position.y;\r\n dst.Size.x = src.Size.x;\r\n dst.Size.y = src.Size.y;\r\n}\r\n\r\nfunction normalizeMinMax(min: Vector2, max: Vector2) {\r\n if (min.x > max.x) {\r\n let temp = max.x;\r\n max.x = min.x;\r\n min.x = temp;\r\n }\r\n\r\n if (min.y > max.y) {\r\n let temp = max.y;\r\n max.y = min.y;\r\n min.y = temp;\r\n }\r\n}\r\n\r\nexport function BoxIntersection(a: Box, b: Box): boolean {\r\n let intersects = false;\r\n\r\n VectorPool.run(() => {\r\n const aMin = VectorPool.get();\r\n const aMax = VectorPool.get();\r\n CopyVector2(aMin, a.Position);\r\n AddVector2(aMax, aMin, a.Size);\r\n normalizeMinMax(aMin, aMax);\r\n\r\n const bMin = VectorPool.get();\r\n const bMax = VectorPool.get();\r\n CopyVector2(bMin, b.Position);\r\n AddVector2(bMax, bMin, b.Size);\r\n normalizeMinMax(bMin, bMax);\r\n\r\n intersects = (aMin.x <= bMax.x) && (aMax.x >= bMin.x) &&\r\n (aMin.y <= bMax.y) && (aMax.y >= bMin.y);\r\n })\r\n\r\n return intersects;\r\n}\r\n\r\n// TODO: This is probably incorrect. Needs more testing\r\n// export function ExpandBox(boxToExpand: Box, box: Box): void {\r\n// const newPos: Vector2 = Zero();\r\n// const newSize: Vector2 = Zero();\r\n\r\n// CopyVector2(newPos, boxToExpand.Position);\r\n// CopyVector2(newSize, boxToExpand.Size);\r\n\r\n\r\n// const positionOffset: Vector2 = Zero();\r\n\r\n// // Get Position Adjustment\r\n// SubVector2(positionOffset, box.Position, boxToExpand.Position);\r\n\r\n// // We only care about adjustments that make us bigger.\r\n// positionOffset.x = Math.min(positionOffset.x, 0);\r\n// positionOffset.y = Math.min(positionOffset.y, 0);\r\n\r\n// // Adjust our position \r\n// AddVector2(boxToExpand.Position, boxToExpand.Position, positionOffset);\r\n\r\n// // Increase our size to take into account new position\r\n// SubVector2(newSize, newSize, positionOffset);\r\n\r\n// const sizeIncrease: Vector2 = Zero();\r\n\r\n// const curEndPos: Vector2 = {\r\n// x: boxToExpand.Position.x + boxToExpand.Size.x,\r\n// y: boxToExpand.Position.y + boxToExpand.Size.y,\r\n// };\r\n\r\n// const boxEndPos: Vector2 = {\r\n// x: box.Position.x + box.Size.x,\r\n// y: box.Position.y + box.Size.y,\r\n// };\r\n\r\n// SubVector2(sizeIncrease, boxEndPos, curEndPos);\r\n\r\n// // We only care about increases to our size\r\n// sizeIncrease.x = Math.max(sizeIncrease.x, 0);\r\n// sizeIncrease.y = Math.max(sizeIncrease.y, 0);\r\n\r\n// // Increase our size to take into account new position\r\n// SubVector2(newSize, newSize, sizeIncrease)\r\n\r\n// // Finally, Set result\r\n// CopyVector2(boxToExpand.Position, newPos)\r\n// CopyVector2(boxToExpand.Size, newSize)\r\n// }\r\n\r\nexport function BoxCenter(box: Box, out: Vector2): Vector2 {\r\n out.x = box.Position.x + (box.Size.x / 2);\r\n out.y = box.Position.y + (box.Size.y / 2);\r\n return out\r\n}\r\n\r\nexport function InBox(box: Box, position: Vector2): boolean {\r\n const min = box.Position\r\n if (position.x < min.x) {\r\n return false\r\n }\r\n if (position.y < min.y) {\r\n return false\r\n }\r\n\r\n if (position.x > min.x + box.Size.x) {\r\n return false\r\n }\r\n if (position.y > min.y + box.Size.y) {\r\n return false\r\n }\r\n\r\n return true\r\n}", "export class List<Type> {\r\n\r\n #arr: Array<Type>;\r\n\r\n #count: number;\r\n\r\n constructor() {\r\n this.#arr = new Array<Type>();\r\n this.#count = 0;\r\n }\r\n\r\n public Count(): number {\r\n return this.#count;\r\n }\r\n\r\n public Clear(): void {\r\n this.#count = 0;\r\n }\r\n\r\n public At(index: number): Type {\r\n return this.#arr[index];\r\n }\r\n\r\n public Push(value: Type): void {\r\n if (this.#arr.length === this.#count) {\r\n this.#arr.push(value);\r\n } else {\r\n this.#arr[this.#count] = value;\r\n }\r\n this.#count++;\r\n }\r\n\r\n public ToArray(): Array<Type> {\r\n let arr = new Array<Type>(this.Count());\r\n for(let i = 0; i < this.#count; i ++) {\r\n arr[i] = this.#arr[i]\r\n }\r\n return arr;\r\n }\r\n\r\n}", "import { Theme } from './theme';\r\nimport { TextAlign } from './styles/canvasTextAlign';\r\nimport { TextStyle, TextStyleConfig, TextStyleFallback } from './styles/text';\r\nimport { Box, InBox } from './types/box';\r\nimport { List } from './types/list';\r\nimport { CopyVector2, Vector2, Zero } from './types/vector2';\r\n\r\nconst contextEntryHeight = 30;\r\nconst contextEntryWidth = 250;\r\n\r\nexport enum ContextMenuItemState {\r\n Enabled = 0,\r\n Disabled = 1,\r\n Hidden = 2,\r\n}\r\n\r\nexport interface ContextMenuItemConfig {\r\n name?: string;\r\n textStyle?: TextStyleConfig;\r\n group?: string;\r\n\r\n /**\r\n * Evaluated when the menu is opened. Defaults to Enabled when omitted.\r\n * Hidden items are omitted from the menu; Disabled items are shown muted\r\n * and are not clickable.\r\n */\r\n enabled?: () => ContextMenuItemState;\r\n\r\n callback?: () => void;\r\n}\r\n\r\nexport interface ContextMenuConfig {\r\n name?: string;\r\n textStyle?: TextStyleConfig;\r\n group?: string;\r\n\r\n subMenus?: Array<ContextMenuConfig>;\r\n items?: Array<ContextMenuItemConfig>;\r\n}\r\n\r\n\r\nexport class ContextMenuItem {\r\n #name: string;\r\n\r\n #callback?: () => void;\r\n\r\n #textStyle: TextStyle;\r\n\r\n #state: ContextMenuItemState;\r\n\r\n public group?: string;\r\n\r\n constructor(config?: ContextMenuItemConfig) {\r\n this.#name = config?.name === undefined ? \"item\" : config.name;\r\n this.#callback = config?.callback;\r\n this.#textStyle = new TextStyle(config?.textStyle);\r\n this.group = config?.group;\r\n this.#state = config?.enabled === undefined\r\n ? ContextMenuItemState.Enabled\r\n : config.enabled();\r\n }\r\n\r\n getName(): string {\r\n return this.#name;\r\n }\r\n\r\n state(): ContextMenuItemState {\r\n return this.#state;\r\n }\r\n\r\n execute(): void {\r\n if (this.#state !== ContextMenuItemState.Enabled || this.#callback === undefined) {\r\n return;\r\n }\r\n this.#callback();\r\n }\r\n}\r\n\r\nclass ContextGroup {\r\n\r\n #calculatedHeight: number;\r\n\r\n constructor(public entries: Array<ContextEntry>) {\r\n this.#calculatedHeight = entries.length * contextEntryHeight\r\n }\r\n\r\n height() {\r\n return this.#calculatedHeight;\r\n }\r\n\r\n}\r\n\r\nexport class ContextEntry {\r\n constructor(public text: string, public subMenu: ContextMenu | undefined, public item: ContextMenuItem | undefined) {\r\n }\r\n\r\n click(): void {\r\n this.item?.execute();\r\n }\r\n}\r\n\r\nexport function CombineContextMenus(...contextMenus: Array<ContextMenuConfig | undefined>): ContextMenuConfig {\r\n const finalConfig: ContextMenuConfig = {\r\n items: new Array<ContextMenuItemConfig>,\r\n subMenus: new Array<ContextMenuConfig>,\r\n }\r\n\r\n for (let i = 0; i < contextMenus.length; i++) {\r\n const config = contextMenus[i];\r\n if (config === undefined) {\r\n continue;\r\n }\r\n\r\n if (config.items !== undefined) {\r\n finalConfig.items = finalConfig.items?.concat(config.items);\r\n }\r\n\r\n if (config.subMenus !== undefined) {\r\n finalConfig.subMenus = finalConfig.subMenus?.concat(config.subMenus);\r\n }\r\n }\r\n\r\n return finalConfig;\r\n}\r\n\r\nexport class ContextMenu {\r\n\r\n #name: string;\r\n\r\n #items: Array<ContextMenuItem>;\r\n\r\n #subMenus: Array<ContextMenu>;\r\n\r\n #textStyle: TextStyle;\r\n\r\n #groups: List<ContextGroup>;\r\n\r\n #group?: string;\r\n\r\n #submenuPosition: Vector2;\r\n\r\n constructor(config?: ContextMenuConfig) {\r\n this.#submenuPosition = Zero();\r\n this.#groups = new List<ContextGroup>();\r\n this.#name = config?.name === undefined ? \"menu\" : config?.name;\r\n this.#items = new Array<ContextMenuItem>();\r\n this.#subMenus = new Array<ContextMenu>();\r\n this.#textStyle = new TextStyle(TextStyleFallback(config?.textStyle, {\r\n color: Theme.ContextMenu.FontColor\r\n }));\r\n this.#group = config?.group;\r\n\r\n if (config?.subMenus !== undefined) {\r\n for (let i = 0; i < config?.subMenus.length; i++) {\r\n this.#subMenus.push(new ContextMenu(config?.subMenus[i]));\r\n }\r\n }\r\n\r\n if (config?.items !== undefined) {\r\n for (let i = 0; i < config?.items.length; i++) {\r\n const item = new ContextMenuItem(config?.items[i]);\r\n if (item.state() === ContextMenuItemState.Hidden) {\r\n continue;\r\n }\r\n this.#items.push(item);\r\n }\r\n }\r\n\r\n this.#calculateEntries();\r\n }\r\n\r\n #calculateEntries(): void {\r\n\r\n const groupLUT = new Map<string, number>();\r\n const workingGroups = new Array<Array<ContextEntry>>();\r\n\r\n // Initialize first group for undefined entries\r\n workingGroups.push(new Array<ContextEntry>());\r\n\r\n for (let i = 0; i < this.#items.length; i++) {\r\n let group = 0; // index to undefined entries\r\n\r\n // Find collection that this entry belongs too\r\n const sub = this.#items[i]\r\n if (sub.group !== undefined) {\r\n const groupIndex = groupLUT.get(sub.group)\r\n if (groupIndex !== undefined) {\r\n group = groupIndex\r\n } else {\r\n group = workingGroups.length\r\n groupLUT.set(sub.group, group)\r\n workingGroups.push(new Array<ContextEntry>());\r\n }\r\n }\r\n\r\n workingGroups[group].push(new ContextEntry(\r\n this.#items[i].getName(),\r\n undefined,\r\n this.#items[i]\r\n ));\r\n }\r\n\r\n for (let i = 0; i < this.#subMenus.length; i++) {\r\n let group = 0; // index to undefined entries\r\n\r\n // Find collection that this entry belongs too\r\n const sub = this.#subMenus[i]\r\n if (sub.#group !== undefined) {\r\n const groupIndex = groupLUT.get(sub.#group)\r\n if (groupIndex !== undefined) {\r\n group = groupIndex\r\n } else {\r\n group = workingGroups.length\r\n groupLUT.set(sub.#group, group)\r\n workingGroups.push(new Array<ContextEntry>());\r\n }\r\n }\r\n\r\n workingGroups[group].push(new ContextEntry(\r\n this.#subMenus[i].getName(),\r\n this.#subMenus[i],\r\n undefined\r\n ));\r\n }\r\n\r\n this.#groups.Clear();\r\n for (let i = 0; i < workingGroups.length; i++) {\r\n const groupContent = workingGroups[i];\r\n if (groupContent.length === 0) {\r\n continue;\r\n }\r\n this.#groups.Push(new ContextGroup(groupContent));\r\n }\r\n }\r\n\r\n #calculatedWidth: number = 0;\r\n\r\n #getMaxWidthForText(ctx: CanvasRenderingContext2D, scale: number): number {\r\n if (this.#calculatedWidth > 0) {\r\n return this.#calculatedWidth;\r\n }\r\n\r\n const tempVec = Zero();\r\n for (let groupIndex = 0; groupIndex < this.#groups.Count(); groupIndex++) {\r\n const group = this.#groups.At(groupIndex);\r\n for (let entryIndex = 0; entryIndex < group.entries.length; entryIndex++) {\r\n this.#textStyle.measure(ctx, scale, group.entries[entryIndex].text, tempVec);\r\n this.#calculatedWidth = Math.max(tempVec.x, this.#calculatedWidth);\r\n }\r\n }\r\n return this.#calculatedWidth;\r\n }\r\n\r\n getName(): string {\r\n return this.#name;\r\n }\r\n\r\n #tempBox: Box = { Position: Zero(), Size: Zero() };\r\n\r\n #openSubMenu: ContextMenu | undefined;\r\n\r\n #bounds: Box | null = null;\r\n\r\n public contains(point: Vector2): boolean {\r\n if (this.#bounds !== null && InBox(this.#bounds, point)) {\r\n return true;\r\n }\r\n return this.#openSubMenu !== undefined && this.#openSubMenu.contains(point);\r\n }\r\n\r\n /**\r\n * A submenu is anchored to its parent's left edge and told the parent's\r\n * width, so it can open on whichever side has room.\r\n */\r\n public render(ctx: CanvasRenderingContext2D, anchor: Vector2, graphScale: number, mousePosition: Vector2 | undefined, openRight: boolean, parentWidth: number = 0): ContextEntry | null {\r\n const menuScale = 1.25;\r\n const scaledEntryHeight = menuScale * contextEntryHeight;\r\n const scaledEntryWidth = (menuScale * 40) + (this.#getMaxWidthForText(ctx, menuScale));\r\n\r\n let totalScaledHeight = 0\r\n for (let i = 0; i < this.#groups.Count(); i++) {\r\n totalScaledHeight += this.#groups.At(i).height();\r\n }\r\n totalScaledHeight *= menuScale;\r\n\r\n const canvasWidth = ctx.canvas.clientWidth;\r\n const position = { x: anchor.x, y: anchor.y };\r\n let opensRight = openRight;\r\n\r\n if (parentWidth === 0) {\r\n if (!openRight) {\r\n position.x -= scaledEntryWidth;\r\n }\r\n if (openRight && position.x + scaledEntryWidth > canvasWidth) {\r\n position.x = canvasWidth - scaledEntryWidth;\r\n opensRight = false;\r\n }\r\n } else {\r\n const rightOfParent = anchor.x + parentWidth;\r\n const leftOfParent = anchor.x - scaledEntryWidth;\r\n const fitsRight = rightOfParent + scaledEntryWidth <= canvasWidth;\r\n const fitsLeft = leftOfParent >= 0;\r\n opensRight = openRight ? (fitsRight || !fitsLeft) : (!fitsLeft && fitsRight);\r\n position.x = opensRight ? rightOfParent : leftOfParent;\r\n position.x = Math.max(0, Math.min(position.x, canvasWidth - scaledEntryWidth));\r\n }\r\n\r\n if (position.y + totalScaledHeight > ctx.canvas.clientHeight) {\r\n position.y = ctx.canvas.clientHeight - totalScaledHeight;\r\n }\r\n position.y = Math.max(0, position.y);\r\n\r\n this.#bounds = {\r\n Position: { x: position.x, y: position.y },\r\n Size: { x: scaledEntryWidth, y: totalScaledHeight },\r\n };\r\n\r\n const pointer = mousePosition !== undefined && this.#openSubMenu !== undefined && this.#openSubMenu.contains(mousePosition)\r\n ? undefined\r\n : mousePosition;\r\n\r\n this.#tempBox.Size.x = scaledEntryWidth;\r\n this.#tempBox.Size.y = scaledEntryHeight;\r\n CopyVector2(this.#tempBox.Position, position)\r\n\r\n\r\n\r\n ctx.textAlign = TextAlign.Left;\r\n ctx.fillStyle = Theme.ContextMenu.BackgroundColor;\r\n ctx.shadowColor = \"#000000\";\r\n ctx.shadowBlur = 5 * menuScale;\r\n ctx.beginPath();\r\n ctx.roundRect(\r\n position.x,\r\n this.#tempBox.Position.y,\r\n scaledEntryWidth,\r\n totalScaledHeight,\r\n Theme.ContextMenu.BorderRadius * menuScale\r\n );\r\n ctx.fill();\r\n ctx.shadowBlur = 0;\r\n\r\n let mouseIsOver: ContextEntry | null = null;\r\n if (pointer !== undefined) {\r\n let row = 0;\r\n for (let groupIndex = 0; groupIndex < this.#groups.Count(); groupIndex++) {\r\n for (const entry of this.#groups.At(groupIndex).entries) {\r\n this.#tempBox.Position.y = position.y + (scaledEntryHeight * row);\r\n if (InBox(this.#tempBox, pointer)) {\r\n mouseIsOver = entry;\r\n this.#openSubMenu = entry.subMenu;\r\n this.#submenuPosition.x = position.x;\r\n this.#submenuPosition.y = this.#tempBox.Position.y;\r\n }\r\n row++;\r\n }\r\n }\r\n }\r\n\r\n let optionsRendered = 0;\r\n for (let groupIndex = 0; groupIndex < this.#groups.Count(); groupIndex++) {\r\n const group = this.#groups.At(groupIndex);\r\n for (let entryIndex = 0; entryIndex < group.entries.length; entryIndex++) {\r\n const entry = group.entries[entryIndex];\r\n\r\n this.#tempBox.Position.y = position.y + (scaledEntryHeight * optionsRendered);\r\n\r\n const entryMousedOver = entry === mouseIsOver;\r\n\r\n const itemDisabled = entry.item !== undefined\r\n && entry.item.state() === ContextMenuItemState.Disabled;\r\n\r\n const highlighted = !itemDisabled && (entryMousedOver || (this.#openSubMenu !== undefined && entry.subMenu === this.#openSubMenu));\r\n if (highlighted) {\r\n ctx.fillStyle = Theme.ContextMenu.HighlightColor;\r\n ctx.beginPath();\r\n ctx.roundRect(\r\n position.x + (scaledEntryHeight / 10),\r\n this.#tempBox.Position.y + (scaledEntryHeight / 10),\r\n scaledEntryWidth - (scaledEntryHeight / 5),\r\n scaledEntryHeight - (scaledEntryHeight / 5),\r\n Theme.ContextMenu.BorderRadius * menuScale\r\n );\r\n ctx.fill();\r\n }\r\n\r\n this.#textStyle.setupStyle(ctx, menuScale);\r\n if (itemDisabled) {\r\n ctx.fillStyle = Theme.ContextMenu.DisabledFontColor;\r\n } else if (highlighted) {\r\n ctx.fillStyle = Theme.ContextMenu.HighlightFontColor;\r\n }\r\n ctx.fillText(entry.text, position.x + (scaledEntryHeight / 5), this.#tempBox.Position.y + (scaledEntryHeight / 2))\r\n\r\n // Render arrows\r\n if (entry.subMenu !== undefined) {\r\n ctx.beginPath()\r\n ctx.strokeStyle = highlighted ? Theme.ContextMenu.HighlightFontColor : Theme.ContextMenu.FontColor;\r\n ctx.lineWidth = 1 * menuScale;\r\n ctx.lineTo(position.x + scaledEntryWidth - (scaledEntryHeight / 2.5), this.#tempBox.Position.y + (scaledEntryHeight / 3))\r\n ctx.lineTo(position.x + scaledEntryWidth - (scaledEntryHeight / 4), this.#tempBox.Position.y + (scaledEntryHeight / 2))\r\n ctx.lineTo(position.x + scaledEntryWidth - (scaledEntryHeight / 2.5), this.#tempBox.Position.y + scaledEntryHeight - (scaledEntryHeight / 3))\r\n ctx.stroke();\r\n }\r\n\r\n optionsRendered++;\r\n }\r\n\r\n // Draw a line seperating the groups\r\n if (groupIndex !== this.#groups.Count() - 1) {\r\n ctx.strokeStyle = Theme.ContextMenu.FontColor;\r\n ctx.lineWidth = .5 * menuScale;\r\n ctx.beginPath();\r\n const startX = position.x + (scaledEntryHeight / 10);\r\n const y = this.#tempBox.Position.y + scaledEntryHeight\r\n ctx.lineTo(startX, y);\r\n ctx.lineTo(startX + scaledEntryWidth - (scaledEntryHeight / 5), y);\r\n ctx.stroke();\r\n }\r\n }\r\n\r\n if (this.#openSubMenu !== undefined) {\r\n const mouseOverSub = this.#openSubMenu.render(ctx, this.#submenuPosition, menuScale, mousePosition, opensRight, scaledEntryWidth)\r\n if (mouseOverSub !== null) {\r\n mouseIsOver = mouseOverSub;\r\n }\r\n }\r\n\r\n return mouseIsOver;\r\n }\r\n}", "import { requestRender } from \"./render_scheduler\";\r\nimport { CopyVector2, Distance, SubVector2, Vector2, Zero } from \"./types/vector2\";\r\n\r\nconst LONG_PRESS_MS = 500;\r\nconst LONG_PRESS_SLOP = 12;\r\nconst WHEEL_ZOOM_PER_PIXEL = 0.0005;\r\nconst SUPPRESS_MOUSE_MS = 600;\r\n\r\nexport class MouseObserver {\r\n\r\n #clicked: boolean;\r\n #lastTouch: Vector2;\r\n #ele: HTMLElement;\r\n #lastMousePosition: Vector2;\r\n\r\n #dragCallback: (delta: Vector2) => void;\r\n #moveCallback: (position: Vector2) => void;\r\n #clickStart: (position: Vector2, shiftOrCtrl: boolean) => void;\r\n #clickStop: () => void;\r\n #contextMenu: (position: Vector2) => void;\r\n #zoomCallback: (factor: number, anchor: Vector2) => void;\r\n #leaveCallback: (() => void) | undefined;\r\n #inside = false;\r\n\r\n #longPressTimer: ReturnType<typeof setTimeout> | null = null;\r\n #longPressOrigin: Vector2 = Zero();\r\n #longPressFired: boolean = false;\r\n #pinchDist: number = 0;\r\n #lastTouchAt: number = 0;\r\n\r\n constructor(\r\n ele: HTMLElement,\r\n dragCallback: (delta: Vector2) => void,\r\n moveCallback: (position: Vector2) => void,\r\n clickStart: (position: Vector2, shiftOrCtrl: boolean) => void,\r\n clickStop: () => void,\r\n contextMenu: (position: Vector2) => void,\r\n fileDrop: (file: File) => void,\r\n zoomCallback: (factor: number, anchor: Vector2) => void,\r\n leaveCallback?: () => void,\r\n ) {\r\n this.#ele = ele;\r\n this.#dragCallback = dragCallback;\r\n this.#moveCallback = moveCallback;\r\n this.#clickStart = clickStart;\r\n this.#clickStop = clickStop;\r\n this.#contextMenu = contextMenu;\r\n this.#zoomCallback = zoomCallback;\r\n this.#leaveCallback = leaveCallback;\r\n\r\n this.#clicked = false;\r\n this.#lastTouch = Zero();\r\n this.#lastMousePosition = Zero();\r\n\r\n ele.style.touchAction = \"none\";\r\n\r\n const redraws = <T extends Event>(handler: (event: T) => void) =>\r\n (event: T): void => {\r\n handler(event);\r\n requestRender();\r\n };\r\n\r\n ele.addEventListener(\"mousedown\", redraws(this.#down.bind(this)), false);\r\n ele.addEventListener(\"touchstart\", redraws(this.#touchStart.bind(this)), { passive: false });\r\n\r\n document.addEventListener(\"mouseup\", redraws(this.#up.bind(this)), false);\r\n document.addEventListener(\"touchend\", redraws(this.#touchEnd.bind(this)), false);\r\n document.addEventListener(\"touchcancel\", redraws(this.#touchEnd.bind(this)), false);\r\n\r\n ele.addEventListener(\"mousemove\", redraws(this.#move.bind(this)), false);\r\n ele.addEventListener(\"mouseleave\", redraws(() => {\r\n this.#inside = false;\r\n if (!this.#clicked) {\r\n this.#leaveCallback?.();\r\n }\r\n }), false);\r\n ele.addEventListener(\"touchmove\", redraws(this.#touchMove.bind(this)), { passive: false });\r\n\r\n ele.addEventListener(\"wheel\", redraws(this.#wheel.bind(this)), { passive: false });\r\n\r\n ele.addEventListener(\"drop\", redraws((ev: DragEvent) => {\r\n ev.preventDefault();\r\n if (ev.dataTransfer?.items) {\r\n [...ev.dataTransfer.items].forEach((item, i) => {\r\n if (item.kind === \"file\") {\r\n const file = item.getAsFile();\r\n if (file) {\r\n fileDrop(file);\r\n }\r\n }\r\n });\r\n }\r\n }));\r\n\r\n ele.addEventListener(\"dragover\", redraws((ev: DragEvent) => {\r\n ev.preventDefault();\r\n this.#moveCallback(this.#mousePos(ev));\r\n }));\r\n\r\n ele.addEventListener(\"contextmenu\", redraws((evt: MouseEvent) => {\r\n evt.preventDefault();\r\n // Touch uses long-press; ignore synthetic browser contextmenu after touch.\r\n if (Date.now() - this.#lastTouchAt < SUPPRESS_MOUSE_MS) {\r\n return;\r\n }\r\n this.#contextMenu(this.#mousePos(evt));\r\n }), false);\r\n }\r\n\r\n #mousePos(event: MouseEvent | DragEvent | WheelEvent): Vector2 {\r\n const rect = this.#ele.getBoundingClientRect();\r\n return {\r\n x: event.clientX - rect.left,\r\n y: event.clientY - rect.top,\r\n };\r\n }\r\n\r\n #touchPos(touch: Touch): Vector2 {\r\n const rect = this.#ele.getBoundingClientRect();\r\n return {\r\n x: touch.clientX - rect.left,\r\n y: touch.clientY - rect.top,\r\n };\r\n }\r\n\r\n #fromTouch(): boolean {\r\n return Date.now() - this.#lastTouchAt < SUPPRESS_MOUSE_MS;\r\n }\r\n\r\n #clearLongPress(): void {\r\n if (this.#longPressTimer !== null) {\r\n clearTimeout(this.#longPressTimer);\r\n this.#longPressTimer = null;\r\n }\r\n }\r\n\r\n #wheel(event: WheelEvent): void {\r\n event.preventDefault();\r\n let dy = event.deltaY;\r\n if (event.deltaMode === WheelEvent.DOM_DELTA_LINE) {\r\n dy *= 16;\r\n } else if (event.deltaMode === WheelEvent.DOM_DELTA_PAGE) {\r\n dy *= this.#ele.clientHeight;\r\n }\r\n if (dy === 0) {\r\n return;\r\n }\r\n const anchor = this.#mousePos(event);\r\n this.#moveCallback(anchor);\r\n this.#zoomCallback(Math.exp(-dy * WHEEL_ZOOM_PER_PIXEL), anchor);\r\n }\r\n\r\n #move(event: MouseEvent): void {\r\n if (this.#fromTouch()) {\r\n return;\r\n }\r\n this.#inside = true;\r\n const pos = this.#mousePos(event);\r\n if (this.#clicked) {\r\n const delta = Zero();\r\n SubVector2(delta, pos, this.#lastMousePosition);\r\n this.#dragCallback(delta);\r\n }\r\n this.#moveCallback(pos);\r\n CopyVector2(this.#lastMousePosition, pos);\r\n }\r\n\r\n #down(event: MouseEvent): void {\r\n if (event.button !== 0 || this.#fromTouch()) {\r\n return;\r\n }\r\n this.#inside = true;\r\n this.#clicked = true;\r\n this.#clickStart(this.#mousePos(event), event.ctrlKey || event.shiftKey);\r\n }\r\n\r\n #up(event: MouseEvent): void {\r\n if (event.button !== 0 || this.#fromTouch()) {\r\n return;\r\n }\r\n const wasClicked = this.#clicked;\r\n this.#clicked = false;\r\n this.#clickStop();\r\n if (wasClicked && !this.#inside) {\r\n this.#leaveCallback?.();\r\n }\r\n }\r\n\r\n #touchStart(event: TouchEvent): void {\r\n this.#lastTouchAt = Date.now();\r\n event.preventDefault();\r\n\r\n if (event.touches.length >= 2) {\r\n this.#clearLongPress();\r\n this.#clicked = false;\r\n this.#pinchDist = Distance(\r\n this.#touchPos(event.touches[0]),\r\n this.#touchPos(event.touches[1]),\r\n );\r\n return;\r\n }\r\n\r\n if (event.touches.length !== 1) {\r\n return;\r\n }\r\n\r\n const pos = this.#touchPos(event.touches[0]);\r\n CopyVector2(this.#longPressOrigin, pos);\r\n CopyVector2(this.#lastTouch, pos);\r\n this.#longPressFired = false;\r\n this.#pinchDist = 0;\r\n\r\n this.#clearLongPress();\r\n const x = pos.x;\r\n const y = pos.y;\r\n this.#longPressTimer = setTimeout(() => {\r\n this.#longPressTimer = null;\r\n this.#longPressFired = true;\r\n this.#clicked = false;\r\n this.#clickStop();\r\n this.#contextMenu({ x, y });\r\n requestRender();\r\n }, LONG_PRESS_MS);\r\n\r\n this.#clicked = true;\r\n this.#moveCallback(pos);\r\n this.#clickStart(pos, false);\r\n }\r\n\r\n #touchMove(event: TouchEvent): void {\r\n this.#lastTouchAt = Date.now();\r\n event.preventDefault();\r\n\r\n if (event.touches.length >= 2) {\r\n this.#clearLongPress();\r\n this.#clicked = false;\r\n const a = this.#touchPos(event.touches[0]);\r\n const b = this.#touchPos(event.touches[1]);\r\n const dist = Distance(a, b);\r\n const anchor = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };\r\n if (this.#pinchDist > 0) {\r\n this.#moveCallback(anchor);\r\n this.#zoomCallback(dist / this.#pinchDist, anchor);\r\n }\r\n this.#pinchDist = dist;\r\n return;\r\n }\r\n\r\n if (event.touches.length !== 1) {\r\n return;\r\n }\r\n\r\n const pos = this.#touchPos(event.touches[0]);\r\n if (this.#longPressTimer !== null && Distance(pos, this.#longPressOrigin) > LONG_PRESS_SLOP) {\r\n this.#clearLongPress();\r\n }\r\n\r\n this.#moveCallback(pos);\r\n if (this.#clicked && !this.#longPressFired) {\r\n this.#dragCallback({\r\n x: pos.x - this.#lastTouch.x,\r\n y: pos.y - this.#lastTouch.y,\r\n });\r\n }\r\n CopyVector2(this.#lastTouch, pos);\r\n }\r\n\r\n #touchEnd(event: TouchEvent): void {\r\n this.#lastTouchAt = Date.now();\r\n this.#clearLongPress();\r\n\r\n if (event.touches.length >= 1) {\r\n this.#pinchDist = 0;\r\n return;\r\n }\r\n\r\n this.#pinchDist = 0;\r\n this.#clicked = false;\r\n if (!this.#longPressFired) {\r\n this.#clickStop();\r\n }\r\n this.#longPressFired = false;\r\n }\r\n}\r\n", "import { Vector2 } from \"../types/vector2\"\r\n\r\n\r\nexport interface RenderElementSidesStyling {\r\n Left?: number\r\n Right?: number\r\n Top?: number\r\n Bottom?: number\r\n}\r\n\r\nexport interface RenderElementSides {\r\n Left: number\r\n Right: number\r\n Top: number\r\n Bottom: number\r\n}\r\n\r\nexport function InstantiateRenderElementSidesStyling(config?: RenderElementSidesStyling | number): RenderElementSides {\r\n if (typeof config === 'number') {\r\n return {\r\n Bottom: config,\r\n Right: config,\r\n Top: config,\r\n Left: config,\r\n }\r\n }\r\n return {\r\n Bottom: config?.Bottom === undefined ? 0 : config?.Bottom,\r\n Right: config?.Right === undefined ? 0 : config?.Right,\r\n Left: config?.Left === undefined ? 0 : config?.Left,\r\n Top: config?.Top === undefined ? 0 : config?.Top,\r\n }\r\n}\r\n\r\nexport interface IRenderElement {\r\n size(ctx: CanvasRenderingContext2D, out: Vector2): void;\r\n render(ctx: CanvasRenderingContext2D, position: Vector2, graphScale: number, scaledFillableSpace: Vector2): void;\r\n}\r\n\r\nexport interface Border {\r\n Color: string;\r\n Thickness: number;\r\n Radius: number;\r\n}\r\n\r\nexport interface BorderStyling {\r\n Color?: string;\r\n Thickness?: number;\r\n Radius?: number;\r\n}\r\n", "import { Vector2 } from \"../types/vector2\";\r\nimport { Border, BorderStyling, InstantiateRenderElementSidesStyling, IRenderElement, RenderElementSides, RenderElementSidesStyling } from \"./interfaces\";\r\n\r\nexport enum Display {\r\n Flex = \"flex\",\r\n None = \"none\"\r\n}\r\n\r\nexport interface RenderElementBaseStyling {\r\n Margin?: RenderElementSidesStyling | number;\r\n Padding?: RenderElementSidesStyling | number;\r\n Border?: BorderStyling;\r\n BackgroundColor?: string;\r\n MinWidth?: number;\r\n MaxWidth?: number;\r\n MaxHeight?: number;\r\n MinHeight?: number;\r\n Grow?: number;\r\n Display?: Display;\r\n}\r\n\r\nexport abstract class RenderElementBase implements IRenderElement {\r\n\r\n #margin: RenderElementSides;\r\n\r\n #padding: RenderElementSides;\r\n\r\n #border: Border;\r\n\r\n #backgroundColor?: string;\r\n\r\n #minWidth?: number;\r\n\r\n #maxWidth?: number;\r\n\r\n #minHeight?: number;\r\n\r\n #maxHeight?: number;\r\n\r\n #grow?: number;\r\n\r\n #display: Display;\r\n\r\n constructor(config?: RenderElementBaseStyling) {\r\n this.#margin = InstantiateRenderElementSidesStyling(config?.Margin);\r\n this.#padding = InstantiateRenderElementSidesStyling(config?.Padding);\r\n this.#backgroundColor = config?.BackgroundColor;\r\n this.#border = {\r\n Color: config?.Border?.Color ?? \"black\",\r\n Thickness: config?.Border?.Thickness ?? 0,\r\n Radius: config?.Border?.Radius ?? 0,\r\n }\r\n this.#minWidth = config?.MinWidth;\r\n this.#maxWidth = config?.MaxWidth;\r\n this.#minHeight = config?.MinHeight;\r\n this.#maxHeight = config?.MaxHeight;\r\n this.#grow = config?.Grow;\r\n this.#display = config?.Display ?? Display.Flex;\r\n }\r\n\r\n setBackgroundColor(newColor: string): void {\r\n this.#backgroundColor = newColor;\r\n }\r\n\r\n abstract doRender(ctx: CanvasRenderingContext2D, position: Vector2, graphScale: number, scaledFillableSpace: Vector2): void;\r\n\r\n render(ctx: CanvasRenderingContext2D, position: Vector2, graphScale: number, scaledFillableSpace: Vector2): void {\r\n if (this.#display === Display.None) {\r\n return;\r\n }\r\n\r\n const scaledSize = { x: 0, y: 0 };\r\n this.size(ctx, scaledSize);\r\n\r\n scaledSize.x = scaledSize.x * graphScale;\r\n scaledSize.y = scaledSize.y * graphScale;\r\n scaledSize.x = Math.max(scaledSize.x, scaledFillableSpace.x);\r\n scaledSize.y = Math.max(scaledSize.y, scaledFillableSpace.y);\r\n\r\n if (this.#backgroundColor) {\r\n ctx.fillStyle = this.#backgroundColor;\r\n ctx.beginPath();\r\n ctx.roundRect(\r\n position.x + (this.#margin.Left * graphScale),\r\n position.y + (this.#margin.Right * graphScale),\r\n scaledSize.x - ((this.#margin.Left + this.#margin.Right) * graphScale),\r\n scaledSize.y - ((this.#margin.Top + this.#margin.Bottom) * graphScale),\r\n this.#border.Radius * graphScale\r\n );\r\n ctx.fill();\r\n }\r\n\r\n if (this.#border.Thickness > 0) {\r\n ctx.lineWidth = this.#border.Thickness * graphScale;\r\n ctx.strokeStyle = this.#border.Color;\r\n ctx.stroke();\r\n }\r\n\r\n const offsetPosition = {\r\n x: position.x + (this.#totalLeftOffset() * graphScale),\r\n y: position.y + (this.#totalTopOffset() * graphScale),\r\n };\r\n const elementSize = {\r\n x: scaledSize.x - (this.#horizontalOffset() * graphScale),\r\n y: scaledSize.y - (this.#verticalOffset() * graphScale)\r\n }\r\n this.doRender(ctx, offsetPosition, graphScale, elementSize);\r\n }\r\n\r\n // todo: Remove limitations argument?\r\n abstract calcSize(ctx: CanvasRenderingContext2D, out: Vector2, limitations: Vector2): void;\r\n\r\n protected maxLimitations(out: Vector2): void {\r\n out.x = -1;\r\n out.y = -1;\r\n\r\n if (this.#maxWidth) {\r\n out.x = this.#maxWidth;\r\n }\r\n\r\n if (this.#maxHeight) {\r\n out.y = this.#maxHeight;\r\n }\r\n }\r\n\r\n setDisplay(display: Display): void {\r\n this.#display = display;\r\n }\r\n\r\n getDisplay(): Display {\r\n return this.#display;\r\n }\r\n\r\n size(ctx: CanvasRenderingContext2D, out: Vector2): void {\r\n out.x = 0;\r\n out.y = 0;\r\n if (this.#display === Display.None) {\r\n return;\r\n }\r\n\r\n const maxLimits = { x: -1, y: -1 }\r\n this.maxLimitations(maxLimits);\r\n\r\n this.calcSize(ctx, out, maxLimits);\r\n\r\n out.x += this.#horizontalOffset();\r\n out.y += this.#verticalOffset();\r\n\r\n if (this.#minWidth) {\r\n out.x = Math.max(out.x, this.#minWidth)\r\n }\r\n\r\n if (this.#maxWidth) {\r\n out.x = Math.min(this.#maxWidth, out.x);\r\n }\r\n\r\n if (this.#maxHeight) {\r\n out.y = Math.min(this.#maxHeight, out.y);\r\n }\r\n\r\n if (this.#minHeight) {\r\n out.y = Math.max(this.#minHeight, out.y);\r\n }\r\n }\r\n\r\n #horizontalOffset(): number {\r\n return (this.#border.Thickness) +\r\n this.#margin.Left +\r\n this.#margin.Right +\r\n this.#padding.Left +\r\n this.#padding.Right;\r\n }\r\n\r\n #verticalOffset(): number {\r\n return (this.#border.Thickness) +\r\n this.#margin.Top +\r\n this.#margin.Bottom +\r\n this.#padding.Top +\r\n this.#padding.Bottom;\r\n }\r\n\r\n #totalTopOffset(): number {\r\n return (this.#border.Thickness / 2) +\r\n this.#margin.Top +\r\n this.#padding.Top;\r\n }\r\n\r\n #totalLeftOffset(): number {\r\n return (this.#border.Thickness / 2) +\r\n this.#margin.Left +\r\n this.#padding.Left;\r\n }\r\n}\r\n", "import { ScaleVector, Vector2 } from '../types/vector2';\r\nimport { RenderElementBase, RenderElementBaseStyling } from \"./base\";\r\nimport { IRenderElement } from \"./interfaces\";\r\n\r\n\r\ninterface ContainerRenderElementConfig extends RenderElementBaseStyling {\r\n\r\n}\r\n\r\nexport enum LayoutDirection {\r\n Column = \"column\",\r\n Row = \"row\"\r\n}\r\n\r\nexport enum AlignItems {\r\n Stretch = \"stretch\",\r\n Start = \"start\",\r\n Center = \"center\",\r\n End = \"end\"\r\n}\r\n\r\nexport class ContainerRenderElement extends RenderElementBase {\r\n\r\n #elements: Array<IRenderElement>;\r\n\r\n #layout: LayoutDirection;\r\n\r\n #alignment: AlignItems;\r\n\r\n constructor(elements: Array<IRenderElement>, config?: ContainerRenderElementConfig) {\r\n super(config);\r\n this.#elements = elements;\r\n this.#layout = LayoutDirection.Column;\r\n this.#alignment = AlignItems.Stretch;\r\n }\r\n\r\n calcSize(ctx: CanvasRenderingContext2D, out: Vector2, limitations: Vector2): void {\r\n out.x = 0;\r\n out.y = 0;\r\n\r\n const eleSize = { x: 0, y: 0 };\r\n\r\n switch (this.#layout) {\r\n case LayoutDirection.Column:\r\n for (let i = 0; i < this.#elements.length; i++) {\r\n this.#elements[i].size(ctx, eleSize);\r\n out.x = Math.max(out.x, eleSize.x);\r\n out.y += eleSize.y;\r\n }\r\n break;\r\n\r\n case LayoutDirection.Row:\r\n for (let i = 0; i < this.#elements.length; i++) {\r\n this.#elements[i].size(ctx, eleSize);\r\n out.y = Math.max(out.y, eleSize.y);\r\n out.x += eleSize.x;\r\n }\r\n break;\r\n\r\n default:\r\n throw new Error(\"unknown layout: \" + this.#layout);\r\n }\r\n\r\n }\r\n\r\n doRender(ctx: CanvasRenderingContext2D, position: Vector2, graphScale: number, scaledFillableSpace: Vector2): void {\r\n // const size = { x: 0, y: 0 };\r\n // const limitations = { x: 0, y: 0 };\r\n // this.limitations(limitations)\r\n // this.calcSize(ctx, size, limitations);\r\n switch (this.#layout) {\r\n case LayoutDirection.Column:\r\n this.#renderColumn(ctx, position, graphScale, scaledFillableSpace);\r\n break;\r\n\r\n default:\r\n throw new Error(\"unimplemented layout direction: \" + this.#layout);\r\n }\r\n }\r\n\r\n #renderColumn(ctx: CanvasRenderingContext2D, position: Vector2, graphScale: number, scaledFillableSpace: Vector2): void {\r\n const currnetPos = { x: position.x, y: position.y };\r\n const scaledEleSize = { x: 0, y: 0 };\r\n for (let i = 0; i < this.#elements.length; i++) {\r\n const ele = this.#elements[i];\r\n\r\n ele.size(ctx, scaledEleSize);\r\n ScaleVector(scaledEleSize, graphScale);\r\n\r\n switch (this.#alignment) {\r\n\r\n case AlignItems.Stretch:\r\n currnetPos.x = position.x;\r\n scaledEleSize.x = scaledFillableSpace.x;\r\n break;\r\n\r\n // I'm not sure if this is even needed, I feel like this should\r\n // already be the case.\r\n case AlignItems.Start: //garney flarney <---- silly goose steenky feet\r\n currnetPos.x = position.x;\r\n break\r\n\r\n case AlignItems.End:\r\n currnetPos.x = scaledFillableSpace.x - scaledEleSize.x\r\n break;\r\n\r\n case AlignItems.Center:\r\n currnetPos.x = scaledFillableSpace.x - (scaledEleSize.x / 2)\r\n break;\r\n\r\n default:\r\n throw new Error(\"unimplmeneted alignment: \" + this.#alignment)\r\n }\r\n\r\n ele.render(ctx, currnetPos, graphScale, scaledEleSize);\r\n currnetPos.y += scaledEleSize.y;\r\n }\r\n }\r\n}", "import { Text } from \"../types/text\";\r\nimport { CopyVector2, ScaleVector, Vector2, Zero } from \"../types/vector2\";\r\nimport { RenderElementBase, RenderElementBaseStyling } from \"./base\";\r\n\r\nexport enum TextAlign {\r\n Left = \"left\",\r\n Right = \"right\",\r\n Center = \"center\",\r\n}\r\n\r\nexport enum VerticalAlign {\r\n Top = \"top\",\r\n Center = \"center\",\r\n Bottom = \"bottom\"\r\n}\r\n\r\nexport interface TextElementStyling extends RenderElementBaseStyling {\r\n Align?: TextAlign\r\n VerticalAlign?: VerticalAlign\r\n LineHeight?: number\r\n}\r\n\r\nexport class TextElement extends RenderElementBase {\r\n #text: Text;\r\n\r\n #align: TextAlign;\r\n\r\n #verticalAlign: VerticalAlign;\r\n\r\n #lineHeight: number;\r\n\r\n constructor(text: Text, styling?: TextElementStyling) {\r\n super(styling);\r\n this.#text = text;\r\n this.#align = styling?.Align ?? TextAlign.Left;\r\n this.#verticalAlign = styling?.VerticalAlign ?? VerticalAlign.Top;\r\n this.#lineHeight = styling?.LineHeight ?? 1;\r\n }\r\n\r\n doRender(ctx: CanvasRenderingContext2D, position: Vector2, graphScale: number, scaledFillableSpace: Vector2): void {\r\n const scale = Zero();\r\n this.calcSize(ctx, scale, scaledFillableSpace);\r\n ScaleVector(scale, graphScale);\r\n\r\n const justifiedPosition = Zero();\r\n CopyVector2(justifiedPosition, position)\r\n\r\n ctx.textAlign = \"left\";\r\n ctx.textBaseline = \"top\"\r\n\r\n switch (this.#align) {\r\n case TextAlign.Left:\r\n // Do nothing. This is default\r\n break;\r\n\r\n case TextAlign.Right:\r\n justifiedPosition.x += scaledFillableSpace.x - scale.x;\r\n break;\r\n\r\n case TextAlign.Center:\r\n justifiedPosition.x += (scaledFillableSpace.x - scale.x) / 2;\r\n break;\r\n\r\n default:\r\n throw new Error(\"unimplemented justification: \" + this.#align);\r\n }\r\n\r\n switch (this.#verticalAlign) {\r\n case VerticalAlign.Top:\r\n // Do nothing. This is default\r\n break;\r\n\r\n case VerticalAlign.Bottom:\r\n justifiedPosition.y += scaledFillableSpace.y - scale.y;\r\n break;\r\n\r\n case VerticalAlign.Center:\r\n justifiedPosition.y += (scaledFillableSpace.y - scale.y) / 2;\r\n break;\r\n\r\n default:\r\n throw new Error(\"unimplemented justification: \" + this.#align);\r\n }\r\n\r\n if (scaledFillableSpace.x <= 0) {\r\n this.#text.render(ctx, graphScale, justifiedPosition);\r\n } else {\r\n const eles = this.#text.breakIntoLines(ctx, scaledFillableSpace.x);\r\n\r\n const tempSize = { x: 0, y: 0 };\r\n for (let i = 0; i < eles.length; i++) {\r\n eles[i].render(ctx, graphScale, justifiedPosition);\r\n eles[i].size(ctx, 1, tempSize)\r\n justifiedPosition.y += this.#text.style().getSize() * this.#lineHeight\r\n }\r\n }\r\n }\r\n\r\n calcSize(ctx: CanvasRenderingContext2D, out: Vector2, limitations: Vector2): void {\r\n if (limitations.x <= 0) {\r\n this.#text.size(ctx, 1, out);\r\n return;\r\n }\r\n\r\n const eles = this.#text.breakIntoLines(ctx, limitations.x);\r\n const tempSize = { x: 0, y: 0 };\r\n out.x = 0;\r\n out.y = this.#text.style().getSize() * eles.length * this.#lineHeight;\r\n for (let i = 0; i < eles.length; i++) {\r\n eles[i].size(ctx, 1, tempSize)\r\n out.x = Math.max(tempSize.x, out.x);\r\n }\r\n }\r\n}\r\n", "interface BinarySearch {\r\n max: number;\r\n getValue: (guess: number) => number;\r\n match: number;\r\n}\r\n\r\nconst binarySearch = ({ max, getValue, match }: BinarySearch): number => {\r\n let min = 0;\r\n\r\n while (min <= max) {\r\n let guess = Math.floor((min + max) / 2);\r\n const compareVal = getValue(guess);\r\n\r\n if (compareVal === match) return guess;\r\n if (compareVal < match) min = guess + 1;\r\n else max = guess - 1;\r\n }\r\n\r\n return max;\r\n};\r\n\r\nexport function fitString(ctx: CanvasRenderingContext2D, str: string, maxWidth: number): string {\r\n let width = ctx.measureText(str).width;\r\n const ellipsis = '\u2026';\r\n const ellipsisWidth = ctx.measureText(ellipsis).width;\r\n if (width <= maxWidth || width <= ellipsisWidth) {\r\n return str;\r\n }\r\n\r\n const index = binarySearch({\r\n max: str.length,\r\n getValue: (guess: number) => ctx.measureText(str.substring(0, guess)).width,\r\n match: maxWidth - ellipsisWidth,\r\n });\r\n\r\n return str.substring(0, index) + ellipsis;\r\n};\r\n\r\nexport function splitString(ctx: CanvasRenderingContext2D, str: string, maxWidth: number): Array<string> {\r\n let width = ctx.measureText(str).width;\r\n if (width <= maxWidth) {\r\n return [str];\r\n }\r\n\r\n let index = binarySearch({\r\n max: str.length,\r\n getValue: (guess: number) => ctx.measureText(str.substring(0, guess)).width,\r\n match: maxWidth,\r\n });\r\n\r\n for (let backward = index - 1; backward >= 1; backward--) {\r\n if (str.charAt(backward) === \" \") {\r\n index = backward + 1;\r\n break;\r\n }\r\n }\r\n\r\n return [str.substring(0, index), str.substring(index)];\r\n};\r\n\r\n\r\nexport function splitStringIntoLines(ctx: CanvasRenderingContext2D, str: string, maxWidth: number): Array<string> {\r\n let width = ctx.measureText(str).width;\r\n if (width <= maxWidth) {\r\n return [str];\r\n }\r\n\r\n const strings = new Array<string>;\r\n let remaining = str;\r\n while (remaining !== \"\") {\r\n let index = binarySearch({\r\n max: remaining.length,\r\n getValue: (guess: number) => ctx.measureText(remaining.substring(0, guess)).width,\r\n match: maxWidth,\r\n });\r\n\r\n if (index === remaining.length) {\r\n strings.push(remaining.substring(0, index))\r\n break;\r\n }\r\n\r\n for (let backward = index - 1; backward >= 1; backward--) {\r\n if (remaining.charAt(backward) === \" \") {\r\n index = backward + 1;\r\n break;\r\n }\r\n }\r\n\r\n strings.push(remaining.substring(0, index))\r\n remaining = remaining.substring(index)\r\n }\r\n\r\n return strings;\r\n};\r\n\r\n// https://stackoverflow.com/a/18234317/4974261\r\nexport function Format(str: string, ...args: Array<string>): string {\r\n if (arguments.length) {\r\n for (let key in args) {\r\n str = str.replace(new RegExp(\"\\\\{\" + key + \"\\\\}\", \"gi\"), args[key]);\r\n }\r\n }\r\n return str;\r\n};", "import { requestRender } from \"../render_scheduler\";\r\nimport { themeVersion } from \"../theme\";\r\nimport { FontWeight, TextStyle, TextStyleConfig } from \"../styles/text\";\r\nimport { splitString, splitStringIntoLines } from \"../utils/string\";\r\nimport { CopyVector2, ScaleVector, Vector2, Zero } from \"./vector2\";\r\n\r\nexport interface MultilineTextConfig {\r\n MaxWidth?: number;\r\n LineSpacing?: number;\r\n}\r\n\r\nexport class Text {\r\n\r\n #measured: boolean\r\n\r\n #measuredForTheme = -1;\r\n\r\n #size: Vector2;\r\n\r\n #style: TextStyle;\r\n\r\n #value: string\r\n\r\n #maxWidth: number;\r\n\r\n #lineSpacing: number;\r\n\r\n #textToRender: Array<string>;\r\n\r\n constructor(value: string, style?: TextStyleConfig, config?: MultilineTextConfig) {\r\n this.#value = value;\r\n this.#measured = false;\r\n this.#size = Zero();\r\n this.#style = new TextStyle(style);\r\n this.#maxWidth = config?.MaxWidth ? config?.MaxWidth : -1;\r\n this.#lineSpacing = config?.LineSpacing ? config?.LineSpacing : 5;\r\n this.#textToRender = [value];\r\n\r\n if (typeof document !== \"undefined\" && document.fonts !== undefined) {\r\n if (!document.fonts.check(`16px \"${this.#style.getFont()}\"`)) {\r\n document.fonts.addEventListener(\"loadingdone\", () => {\r\n this.#measured = false;\r\n requestRender();\r\n });\r\n }\r\n }\r\n }\r\n\r\n set(newValue: string): void {\r\n this.#value = newValue;\r\n this.#measured = false;\r\n }\r\n\r\n get(): string {\r\n return this.#value;\r\n }\r\n\r\n breakIntoLines(ctx: CanvasRenderingContext2D, maxWidth: number): Array<Text> {\r\n const results = new Array<Text>();\r\n\r\n this.#style.setupStyle(ctx, 1);\r\n const entries = splitStringIntoLines(ctx, this.#value, maxWidth);\r\n if (entries.length === 1) {\r\n return [this];\r\n }\r\n for (let i = 0; i < entries.length; i++) {\r\n const text = new Text(entries[i])\r\n text.#style = this.#style;\r\n results.push(text)\r\n }\r\n\r\n return results;\r\n }\r\n\r\n split(char: string): Array<Text> {\r\n const entries = this.#value.split(char)\r\n const results = new Array<Text>();\r\n for (let i = 0; i < entries.length; i++) {\r\n const text = new Text(entries[i])\r\n text.#style = this.#style;\r\n results.push(text)\r\n }\r\n return results;\r\n }\r\n\r\n splitAtIndex(index: number): Array<Text> {\r\n const results = [\r\n new Text(this.#value.substring(0, index)),\r\n new Text(this.#value.substring(index, 0)),\r\n ];\r\n\r\n\r\n for (let i = 0; i < results.length; i++) {\r\n results[i].#style = this.#style;\r\n }\r\n return results;\r\n }\r\n\r\n splitAtWidth(ctx: CanvasRenderingContext2D, maxWidth: number): Array<Text> {\r\n this.#style.setupStyle(ctx, 1);\r\n const entries = splitString(ctx, this.#value, maxWidth);\r\n if (entries.length === 1) {\r\n return [this];\r\n }\r\n\r\n const results = new Array<Text>();\r\n for (let i = 0; i < entries.length; i++) {\r\n const text = new Text(entries[i])\r\n text.#style = this.#style;\r\n results.push(text)\r\n }\r\n return results;\r\n }\r\n\r\n #measure(ctx: CanvasRenderingContext2D): void {\r\n if (this.#measured && this.#measuredForTheme === themeVersion()) {\r\n return;\r\n }\r\n this.#measuredForTheme = themeVersion();\r\n\r\n\r\n this.#style.setupStyle(ctx, 1);\r\n\r\n if (this.#maxWidth == -1) {\r\n const measurements = ctx.measureText(this.#value);\r\n this.#size.x = measurements.width;\r\n this.#size.y = measurements.actualBoundingBoxAscent + measurements.actualBoundingBoxDescent;\r\n this.#textToRender = [this.#value];\r\n this.#measured = true;\r\n return;\r\n }\r\n\r\n this.#textToRender = splitStringIntoLines(ctx, this.#value, this.#maxWidth);\r\n\r\n this.#size.x = 0;\r\n this.#size.y = 0;\r\n for (let i = 0; i < this.#textToRender.length; i++) {\r\n const measurements = ctx.measureText(this.#textToRender[i]);\r\n this.#size.x = Math.max(this.#size.x, measurements.width);\r\n }\r\n\r\n this.#size.y += ((this.#textToRender.length - 1) * this.#lineSpacing) + (this.#style.getSize() * this.#textToRender.length);\r\n this.#measured = true;\r\n }\r\n\r\n size(ctx: CanvasRenderingContext2D, scale: number, out: Vector2): void {\r\n this.#measure(ctx);\r\n CopyVector2(out, this.#size);\r\n ScaleVector(out, scale);\r\n }\r\n\r\n height(ctx: CanvasRenderingContext2D): number {\r\n this.#measure(ctx);\r\n return this.#size.y;\r\n }\r\n\r\n setColor(color: string): void {\r\n this.#style.setColor(color);\r\n }\r\n\r\n getColor(): string {\r\n return this.#style.getColor();\r\n }\r\n\r\n setSize(size: number): void {\r\n this.#style.setSize(size);\r\n }\r\n\r\n setWeight(weight: FontWeight): void {\r\n this.#style.setWeight(weight);\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, scale: number, position: Vector2): void {\r\n this.#measure(ctx);\r\n this.#style.setupStyle(ctx, scale);\r\n let yOffset = 0;\r\n for (let i = 0; i < this.#textToRender.length; i++) {\r\n ctx.fillText(\r\n this.#textToRender[i],\r\n position.x,\r\n position.y + yOffset\r\n );\r\n yOffset += (this.#style.getSize() + this.#lineSpacing) * scale\r\n }\r\n }\r\n\r\n style(): TextStyle {\r\n return this.#style;\r\n }\r\n}", "export function Clamp(v: number, min: number, max: number): number {\r\n return Math.min(Math.max(v, min), max)\r\n}\r\n\r\nexport function Clamp01(v: number): number {\r\n return Clamp(v, 0, 1);\r\n}\r\n\r\n", "import { Clamp01 } from './math';\r\n\r\nexport interface Color {\r\n r: number, // 0 - 1\r\n g: number, // 0 - 1\r\n b: number, // 0 - 1\r\n}\r\n\r\nexport interface HSV {\r\n h: number, // angle in degrees\r\n s: number, // 0 - 1\r\n v: number, // 0 - 1\r\n}\r\n\r\nfunction componentToHex(c: number) {\r\n var hex = c.toString(16);\r\n return hex.length == 1 ? \"0\" + hex : hex;\r\n}\r\n\r\nexport function RgbToHex(c: Color): string {\r\n return \"#\" + componentToHex(Math.round(c.r * 255)) + componentToHex(Math.round(c.g * 255)) + componentToHex(Math.round(c.b * 255));\r\n}\r\n\r\nexport function HexToColor(hex: string): Color | null {\r\n var result = /^#?([a-f\\d]{2})([a-f\\d]{2})([a-f\\d]{2})(?:[a-f\\d]{2})?$/i.exec(hex);\r\n return result ? {\r\n r: parseInt(result[1], 16) / 255,\r\n g: parseInt(result[2], 16) / 255,\r\n b: parseInt(result[3], 16) / 255\r\n } : null;\r\n}\r\n\r\n\r\nexport function HSV2RGB(hsv: HSV, out: Color): void {\r\n if (hsv.s <= 0.0) { // < is bogus, just shuts up warnings\r\n out.r = hsv.v;\r\n out.g = hsv.v;\r\n out.b = hsv.v;\r\n return;\r\n }\r\n let hh = hsv.h;\r\n if (hh >= 360.0) {\r\n hh = 0.0;\r\n }\r\n hh /= 60.0;\r\n\r\n const i = Math.round(hh);\r\n const ff = hh - i;\r\n const p = hsv.v * (1.0 - hsv.s);\r\n const q = hsv.v * (1.0 - (hsv.s * ff));\r\n const t = hsv.v * (1.0 - (hsv.s * (1.0 - ff)));\r\n\r\n switch (i) {\r\n case 0:\r\n out.r = hsv.v;\r\n out.g = t;\r\n out.b = p;\r\n break;\r\n case 1:\r\n out.r = q;\r\n out.g = hsv.v;\r\n out.b = p;\r\n break;\r\n case 2:\r\n out.r = p;\r\n out.g = hsv.v;\r\n out.b = t;\r\n break;\r\n\r\n case 3:\r\n out.r = p;\r\n out.g = q;\r\n out.b = hsv.v;\r\n break;\r\n case 4:\r\n out.r = t;\r\n out.g = p;\r\n out.b = hsv.v;\r\n break;\r\n // case 5:\r\n default:\r\n out.r = hsv.v;\r\n out.g = p;\r\n out.b = q;\r\n break;\r\n }\r\n\r\n out.r = Clamp01(out.r)\r\n out.g = Clamp01(out.g)\r\n out.b = Clamp01(out.b)\r\n}\r\n\r\nexport function RGB2HSV(rgb: Color, out: HSV): void {\r\n out.h = 0;\r\n out.s = 0;\r\n out.v = 0;\r\n let min: number = 0;\r\n let max: number = 0;\r\n let delta: number = 0;\r\n\r\n min = rgb.r < rgb.g ? rgb.r : rgb.g;\r\n min = min < rgb.b ? min : rgb.b;\r\n\r\n max = rgb.r > rgb.g ? rgb.r : rgb.g;\r\n max = max > rgb.b ? max : rgb.b;\r\n\r\n out.v = max; // v\r\n delta = max - min;\r\n if (delta < 0.00001) {\r\n out.s = 0;\r\n out.h = 0; // undefined, maybe nan?\r\n return;\r\n }\r\n if (max > 0.0) { // NOTE: if Max is == 0, this divide would cause a crash\r\n out.s = (delta / max); // s\r\n } else {\r\n // if max is 0, then r = g = b = 0 \r\n // s = 0, h is undefined\r\n out.s = 0.0;\r\n out.h = NaN; // its now undefined\r\n return;\r\n }\r\n if (rgb.r >= max) // > is bogus, just keeps compilor happy\r\n out.h = (rgb.g - rgb.b) / delta; // between yellow & magenta\r\n else\r\n if (rgb.g >= max)\r\n out.h = 2.0 + (rgb.b - rgb.r) / delta; // between cyan & yellow\r\n else\r\n out.h = 4.0 + (rgb.r - rgb.g) / delta; // between magenta & cyan\r\n\r\n out.h *= 60.0; // degrees\r\n\r\n if (out.h < 0.0)\r\n out.h += 360.0;\r\n\r\n}\r\n", "import { Camera } from \"./camera\";\r\nimport { Connection } from './connection';\r\nimport { requestRender } from \"./render_scheduler\";\r\nimport { RenderElementBase } from \"./elements/base\";\r\nimport { ContainerRenderElement, AlignItems } from './elements/container';\r\nimport { TextAlign, TextElement } from \"./elements/text\";\r\nimport { FlowNode } from \"./node\";\r\nimport { PassSubsystem } from \"./pass/subsystem\";\r\nimport { FontStyle } from \"./styles/text\";\r\nimport { Box, InBox } from \"./types/box\";\r\nimport { Text } from \"./types/text\";\r\nimport { Vector2 } from \"./types/vector2\";\r\nimport { Color, HSV, HSV2RGB, RgbToHex } from './utils/color';\r\nimport type { Widget } from \"./widgets/widget\";\r\nimport type { WidgetConfig } from \"./widgets/factory\";\r\n\r\nexport enum PortType {\r\n Input = \"INPUT\",\r\n Output = \"OUTPUT\",\r\n InputArray = \"INPUTARRAY\",\r\n}\r\n\r\nexport interface PortStyle {\r\n size?: number;\r\n fillColor?: string;\r\n borderColor?: string;\r\n borderSize?: number;\r\n}\r\n\r\ntype ConnectionChangeCallback = (connection: Connection, connectionIndex: number, port: Port, portType: PortType, node: FlowNode) => void\r\n\r\nexport interface PortConfig {\r\n name?: string;\r\n type?: string;\r\n description?: string;\r\n array?: boolean;\r\n\r\n /**\r\n * Lets this port connect to a port of any type, instead of only to one\r\n * declaring the same `type` string. For a port whose type is decided by\r\n * whatever gets wired into it, where `type` is a placeholder shown to\r\n * the user rather than a promise about the values passing through.\r\n */\r\n anyType?: boolean;\r\n\r\n /**\r\n * Every type this port takes, when it takes more than one. For a port\r\n * that works on a single value or an array of them, where `type` is\r\n * only the one it happens to be showing.\r\n *\r\n * An empty or absent list means the port takes exactly its `type`,\r\n * unless `anyType` says otherwise.\r\n */\r\n acceptedTypes?: Array<string>;\r\n\r\n /**\r\n * Leaves the port off the node until something is connected to it.\r\n */\r\n hidden?: boolean;\r\n\r\n /**\r\n * A widget drawn on the port's own row while nothing is connected to\r\n * it, for a value the port holds on its own. Input ports only.\r\n */\r\n widget?: WidgetConfig;\r\n\r\n emptyStyle?: PortStyle;\r\n filledStyle?: PortStyle;\r\n onConnectionAdded?: ConnectionChangeCallback;\r\n onConnectionRemoved?: ConnectionChangeCallback;\r\n};\r\n\r\n/**\r\n * Whether two ports may be connected, going by their types alone. Each port\r\n * offers the set of types it takes - one entry for an ordinary port, several\r\n * for a port that takes more than one, and none at all for a port that takes\r\n * anything. They connect when those sets overlap.\r\n */\r\nexport function portsCompatible(a: Port | undefined | null, b: Port | undefined | null): boolean {\r\n if (!a || !b) {\r\n return false;\r\n }\r\n\r\n return typeSetsCompatible(a.acceptedTypes(), b.acceptedTypes());\r\n}\r\n\r\nexport function typeSetsCompatible(a: Array<string>, b: Array<string>): boolean {\r\n if (a.length === 0 || b.length === 0) {\r\n return true;\r\n }\r\n return a.some((type) => b.includes(type));\r\n}\r\n\r\n/**\r\n * Lets an output of type `from` feed an input of type `to`, and only that\r\n * way round.\r\n */\r\nexport interface Cast {\r\n from: string;\r\n to: string;\r\n}\r\n\r\n/**\r\n * Whether an output may feed an input: their types overlap, or a cast takes\r\n * one of the output's types to one of the input's.\r\n */\r\nexport function portsConnect(output: Port | undefined | null, input: Port | undefined | null, casts?: Array<Cast>): boolean {\r\n if (!output || !input) {\r\n return false;\r\n }\r\n\r\n return typeSetsConnect(output.acceptedTypes(), input.acceptedTypes(), casts);\r\n}\r\n\r\nexport function typeSetsConnect(output: Array<string>, input: Array<string>, casts?: Array<Cast>): boolean {\r\n if (typeSetsCompatible(output, input)) {\r\n return true;\r\n }\r\n return (casts ?? []).some((cast) => output.includes(cast.from) && input.includes(cast.to));\r\n}\r\n\r\nexport function portConfigTypes(config: PortConfig): Array<string> {\r\n if (config.anyType === true) {\r\n return [];\r\n }\r\n if (config.acceptedTypes !== undefined && config.acceptedTypes.length > 0) {\r\n return config.acceptedTypes;\r\n }\r\n return [config.type === undefined ? \"\" : config.type];\r\n}\r\n\r\nexport const ARRAY_SLOT_PITCH = 12;\r\n\r\n/**\r\n * Which gap between a port's wires a point is nearest: 0 is above the first,\r\n * `count` is below the last.\r\n */\r\nexport function arrayInsertIndex(box: Box, count: number, y: number): number {\r\n if (count === 0) {\r\n return 0;\r\n }\r\n const index = Math.round((y - box.Position.y) / (box.Size.y / count));\r\n return Math.min(count, Math.max(0, index));\r\n}\r\n\r\nexport function arraySlotCenter(box: Box, count: number, index: number): Vector2 {\r\n const slots = Math.max(1, count);\r\n return {\r\n x: box.Position.x + (box.Size.x / 2),\r\n y: box.Position.y + ((index + 0.5) * box.Size.y / slots),\r\n };\r\n}\r\n\r\n// Calculate a color hash for an arbirary type\r\nfunction fallbackColor(type: string, s: number): string {\r\n let value = 0;\r\n for (var i = 0; i < type.length; i++) {\r\n value += type.charCodeAt(i) * (i + 1);\r\n }\r\n\r\n const mod = 24;\r\n value = Math.round(value) % mod;\r\n\r\n const hsv: HSV = { h: (value / (mod - 1)) * 360, s: s, v: 1 };\r\n const color: Color = { r: 0, g: 0, b: 0 };\r\n HSV2RGB(hsv, color);\r\n return RgbToHex(color);\r\n}\r\n\r\nexport function portTypeColor(type: string): string {\r\n return fallbackColor(type, 1);\r\n}\r\n\r\nexport class Port {\r\n\r\n #node: FlowNode;\r\n\r\n #displayName: string;\r\n\r\n #emptyStyle: PortStyle;\r\n\r\n #filledStyle: PortStyle;\r\n\r\n #connections: Array<Connection>;\r\n\r\n #portType: PortType\r\n\r\n #dataType: string;\r\n\r\n #anyType: boolean;\r\n\r\n #acceptedTypes: Array<string>;\r\n\r\n #description: string;\r\n\r\n #array: boolean;\r\n\r\n #hidden: boolean;\r\n\r\n #configuredEmptyFill: string | undefined;\r\n\r\n #configuredFilledFill: string | undefined;\r\n\r\n #dataTypePopupElement: RenderElementBase;\r\n\r\n #onConnectionAdded: Array<ConnectionChangeCallback>;\r\n\r\n #onConnectionRemoved: Array<ConnectionChangeCallback>;\r\n\r\n #widget: Widget | null = null;\r\n\r\n constructor(node: FlowNode, portType: PortType, config?: PortConfig) {\r\n this.#node = node;\r\n this.#connections = new Array<Connection>();\r\n this.#portType = portType;\r\n this.#displayName = config?.name === undefined ? \"Port\" : config?.name;\r\n this.#dataType = config?.type === undefined ? \"\" : config?.type;\r\n this.#anyType = config?.anyType === true;\r\n this.#acceptedTypes = config?.acceptedTypes === undefined ? [] : config.acceptedTypes;\r\n this.#description = config?.description === undefined ? \"\" : config.description;\r\n this.#array = config?.array === true;\r\n this.#hidden = config?.hidden === true;\r\n this.#configuredEmptyFill = config?.emptyStyle?.fillColor;\r\n this.#configuredFilledFill = config?.filledStyle?.fillColor;\r\n\r\n this.#emptyStyle = {\r\n borderColor: config?.emptyStyle?.borderColor === undefined ? \"#1c1c1c\" : config.emptyStyle?.borderColor,\r\n fillColor: this.#configuredEmptyFill === undefined ? fallbackColor(this.#dataType, 0.3) : this.#configuredEmptyFill,\r\n borderSize: config?.emptyStyle?.borderSize === undefined ? 1 : config.emptyStyle?.borderSize,\r\n size: config?.emptyStyle?.size === undefined ? 4 : config.emptyStyle?.size\r\n }\r\n\r\n this.#filledStyle = {\r\n borderColor: config?.filledStyle?.borderColor === undefined ? \"#1c1c1c\" : config.filledStyle?.borderColor,\r\n fillColor: this.#configuredFilledFill === undefined ? fallbackColor(this.#dataType, 1) : this.#configuredFilledFill,\r\n borderSize: config?.filledStyle?.borderSize === undefined ? 1 : config.filledStyle?.borderSize,\r\n size: config?.filledStyle?.size === undefined ? 5 : config.filledStyle?.size\r\n }\r\n\r\n this.#onConnectionAdded = new Array<ConnectionChangeCallback>();\r\n if (config?.onConnectionAdded) {\r\n this.#onConnectionAdded.push(config?.onConnectionAdded);\r\n }\r\n\r\n this.#onConnectionRemoved = new Array<ConnectionChangeCallback>();\r\n if (config?.onConnectionRemoved) {\r\n this.#onConnectionRemoved.push(config?.onConnectionRemoved);\r\n }\r\n\r\n this.#dataTypePopupElement = this.#buildTooltip();\r\n }\r\n\r\n #buildTooltip(): RenderElementBase {\r\n const containerElements = new Array<RenderElementBase>();\r\n\r\n let dataTypeDisplay = this.#dataType;\r\n if (this.#acceptedTypes.length > 1) {\r\n dataTypeDisplay = this.#acceptedTypes.join(\" or \");\r\n }\r\n if (dataTypeDisplay === \"\" && this.#anyType) {\r\n dataTypeDisplay = \"any\";\r\n }\r\n if (this.#array) {\r\n dataTypeDisplay = \"Array<\" + dataTypeDisplay + \">\"\r\n }\r\n containerElements.push(new TextElement(\r\n new Text(dataTypeDisplay, {\r\n color: \"white\",\r\n }),\r\n {\r\n Align: TextAlign.Center,\r\n }\r\n ));\r\n\r\n if (this.#description !== \"\") {\r\n containerElements.push(new TextElement(\r\n new Text(this.#description, { color: \"white\", style: FontStyle.Italic }),\r\n {\r\n Align: TextAlign.Center,\r\n Padding: { Top: 16 },\r\n MaxWidth: 400,\r\n LineHeight: 1.5\r\n }\r\n ));\r\n }\r\n\r\n return new ContainerRenderElement(\r\n containerElements,\r\n {\r\n BackgroundColor: \"rgba(0, 0, 0, 0.85)\",\r\n Border: {\r\n Radius: 6,\r\n },\r\n Padding: 13,\r\n }\r\n );\r\n }\r\n\r\n #refreshDataType(): void {\r\n if (this.#configuredEmptyFill === undefined) {\r\n this.#emptyStyle.fillColor = fallbackColor(this.#dataType, 0.3);\r\n }\r\n if (this.#configuredFilledFill === undefined) {\r\n this.#filledStyle.fillColor = fallbackColor(this.#dataType, 1);\r\n }\r\n this.#dataTypePopupElement = this.#buildTooltip();\r\n requestRender();\r\n }\r\n\r\n setDataType(type: string): void {\r\n if (this.#dataType === type) {\r\n return;\r\n }\r\n this.#dataType = type;\r\n this.#refreshDataType();\r\n }\r\n\r\n setAnyType(anyType: boolean): void {\r\n if (this.#anyType === anyType) {\r\n return;\r\n }\r\n this.#anyType = anyType;\r\n this.#refreshDataType();\r\n }\r\n\r\n /**\r\n * Scope accepted types to singular type\r\n */\r\n settleOn(type: string): void {\r\n this.#acceptedTypes = [type];\r\n this.setDataType(type);\r\n this.#refreshDataType();\r\n }\r\n\r\n addConnection(connection: Connection, index?: number): void {\r\n const c = index === undefined\r\n ? this.#connections.length\r\n : Math.min(Math.max(index, 0), this.#connections.length);\r\n const was = this.hidden();\r\n this.#connections.splice(c, 0, connection);\r\n this.#visibilityMayHaveChanged(was);\r\n for (let i = 0; i < this.#onConnectionAdded.length; i++) {\r\n this.#onConnectionAdded[i](connection, c, this, this.#portType, this.#node);\r\n }\r\n }\r\n\r\n replaceConnection(connection: Connection, index: number): void {\r\n const c = this.#connections.length;\r\n this.#connections[index] = connection;\r\n for (let i = 0; i < this.#onConnectionAdded.length; i++) {\r\n this.#onConnectionAdded[i](connection, c, this, this.#portType, this.#node);\r\n }\r\n }\r\n\r\n addConnectionAddedListener(callback: ConnectionChangeCallback) {\r\n if (callback === undefined) {\r\n return;\r\n }\r\n this.#onConnectionAdded.push(callback);\r\n }\r\n\r\n connections(): Array<Connection> {\r\n return this.#connections;\r\n }\r\n\r\n /**\r\n * How many wires the port has room for: one per connection on an array\r\n * input, so each can be told apart and picked up on its own.\r\n */\r\n slots(): number {\r\n if (this.#portType !== PortType.InputArray) {\r\n return 1;\r\n }\r\n return Math.max(1, this.#connections.length);\r\n }\r\n\r\n setHidden(hidden: boolean): void {\r\n const was = this.hidden();\r\n this.#hidden = hidden;\r\n this.#visibilityMayHaveChanged(was);\r\n }\r\n\r\n #visibilityMayHaveChanged(was: boolean): void {\r\n if (was !== this.hidden() || this.#portType === PortType.InputArray || this.#widget !== null) {\r\n this.#node?.invalidateLayout();\r\n }\r\n }\r\n\r\n setWidget(widget: Widget | null): void {\r\n this.#widget = widget;\r\n this.#node?.invalidateLayout();\r\n }\r\n\r\n widget(): Widget | null {\r\n return this.#widget;\r\n }\r\n\r\n /**\r\n * The widget stands in for a wire, so it leaves once one is connected.\r\n */\r\n widgetShown(): boolean {\r\n return this.#widget !== null\r\n && this.#portType !== PortType.Output\r\n && this.#connections.length === 0\r\n && !this.hidden()\r\n && !(this.#widget.Hidden?.() ?? false);\r\n }\r\n\r\n /**\r\n * A port asked to hide still shows while anything is connected to it,\r\n * and while its node is showing its hidden ports.\r\n */\r\n hidden(): boolean {\r\n return this.tucked() && !(this.#node?.hiddenPortsShown() ?? false);\r\n }\r\n\r\n tucked(): boolean {\r\n return this.#hidden && this.#connections.length === 0;\r\n }\r\n\r\n addConnectionRemovedListener(callback: ConnectionChangeCallback) {\r\n if (callback === undefined) {\r\n return;\r\n }\r\n this.#onConnectionRemoved.push(callback);\r\n }\r\n\r\n clearConnection(connection: Connection): void {\r\n const index = this.#connections.indexOf(connection);\r\n if (index > -1) {\r\n const was = this.hidden();\r\n this.#connections.splice(index, 1);\r\n this.#visibilityMayHaveChanged(was);\r\n for (let i = 0; i < this.#onConnectionRemoved.length; i++) {\r\n this.#onConnectionRemoved[i](connection, index, this, this.#portType, this.#node);\r\n }\r\n } else {\r\n console.error(\"no connection found to remove\");\r\n }\r\n }\r\n\r\n getDataType(): string {\r\n return this.#dataType;\r\n }\r\n\r\n acceptsAnyType(): boolean {\r\n return this.#anyType;\r\n }\r\n\r\n /**\r\n * Every type this port takes. Empty means it takes anything.\r\n */\r\n acceptedTypes(): Array<string> {\r\n if (this.#anyType) {\r\n return [];\r\n }\r\n if (this.#acceptedTypes.length > 0) {\r\n return this.#acceptedTypes;\r\n }\r\n return [this.#dataType];\r\n }\r\n\r\n setAcceptedTypes(types: Array<string>): void {\r\n this.#acceptedTypes = types;\r\n }\r\n\r\n getPortType(): PortType {\r\n return this.#portType;\r\n }\r\n\r\n getDisplayName(): string {\r\n return this.#displayName;\r\n }\r\n\r\n filledStyleColor(): string {\r\n if (this.#filledStyle.fillColor === undefined) {\r\n console.error(\"There's no fill color!!!!!!!!!\")\r\n return \"black\";\r\n }\r\n return this.#filledStyle.fillColor;\r\n }\r\n\r\n #box: Box = { Position: { x: 0, y: 0 }, Size: { x: 0, y: 0 } };\r\n\r\n render(ctx: CanvasRenderingContext2D, position: Vector2, camera: Camera, mousePosition: Vector2 | undefined, postProcess: PassSubsystem): Box {\r\n let style = this.#emptyStyle;\r\n if (this.#connections.length > 0) {\r\n style = this.#filledStyle;\r\n }\r\n\r\n let scaledRadius = style.size as number * camera.zoom\r\n\r\n if (mousePosition && InBox(this.#box, mousePosition)) {\r\n scaledRadius *= 1.25;\r\n\r\n // Redeclare so lambda is ensured to use these values\r\n const xPos = position.x;\r\n const yPos = position.y;\r\n\r\n // TODO: Make it so we're not creating a new lambda each frame\r\n postProcess.queue(() => {\r\n const size = { x: 0, y: 0 }\r\n this.#dataTypePopupElement.calcSize(ctx, size, { x: -1, y: -1 });\r\n // size.x = Math.min(150, size.x)\r\n this.#dataTypePopupElement.render(ctx, { x: xPos - (size.x / 2), y: yPos }, 1, size)\r\n })\r\n }\r\n\r\n const slots = this.slots();\r\n const height = slots === 1 ? scaledRadius * 2 : slots * ARRAY_SLOT_PITCH * camera.zoom;\r\n this.#box.Position.x = position.x - scaledRadius;\r\n this.#box.Position.y = position.y - (height / 2);\r\n this.#box.Size.x = scaledRadius * 2;\r\n this.#box.Size.y = height;\r\n\r\n ctx.strokeStyle = style.borderColor as string;\r\n ctx.fillStyle = style.fillColor as string;\r\n\r\n ctx.beginPath();\r\n if (this.#portType === PortType.InputArray) {\r\n ctx.roundRect(this.#box.Position.x, this.#box.Position.y, this.#box.Size.x, this.#box.Size.y, slots === 1 ? 0 : scaledRadius);\r\n } else {\r\n ctx.arc(position.x, position.y, scaledRadius, 0, 2 * Math.PI);\r\n }\r\n ctx.fill();\r\n ctx.stroke();\r\n\r\n if (slots > 1) {\r\n ctx.fillStyle = style.borderColor as string;\r\n for (let i = 0; i < slots; i++) {\r\n const slot = arraySlotCenter(this.#box, slots, i);\r\n ctx.beginPath();\r\n ctx.arc(slot.x, slot.y, scaledRadius * 0.4, 0, 2 * Math.PI);\r\n ctx.fill();\r\n }\r\n }\r\n\r\n return this.#box;\r\n }\r\n}", "// https://developer.mozilla.org/en-US/docs/Web/CSS/cursor\r\nexport enum CursorStyle {\r\n Default = 'default',\r\n Pointer = 'pointer',\r\n Grab = 'grab',\r\n Grabbing = 'grabbing',\r\n Wait = 'wait',\r\n Help = 'help',\r\n Crosshair = 'crosshair',\r\n Cell = 'cell',\r\n Text = 'text',\r\n Move = 'move',\r\n NotAllowed = 'not-allowed',\r\n ZoomIn = 'zoom-in',\r\n ZoomOut = 'zoom-out',\r\n None = 'none',\r\n ContextMenu = 'context-menu',\r\n EWResize = 'ew-resize',\r\n}", "import { requestRender } from \"../render_scheduler\";\nimport { Theme } from \"../theme\";\nimport { Box } from \"../types/box\";\n\nexport interface InPlaceEditConfig {\n canvas: HTMLCanvasElement | null;\n\n /**\n * Where to sit, in canvas pixels.\n */\n box: Box;\n\n scale: number;\n\n value: string;\n\n onCommit: (text: string) => void;\n}\n\nexport interface InPlaceEdit {\n input: HTMLInputElement;\n\n /**\n * Moves the input over where the widget was just drawn, in canvas pixels.\n */\n place(box: Box, scale: number): void;\n}\n\ninterface OpenEdit {\n canvas: HTMLCanvasElement;\n input: HTMLInputElement;\n placed: boolean;\n}\n\nconst open = new Set<OpenEdit>();\n\nexport function placeEditsDuring(canvas: HTMLCanvasElement, draw: () => void): void {\n open.forEach((edit) => {\n if (edit.canvas === canvas) {\n edit.placed = false;\n }\n });\n draw();\n open.forEach((edit) => {\n if (edit.canvas === canvas && !edit.placed) {\n // Not visibility or display: hiding either way blurs the input, which ends the edit.\n edit.input.style.opacity = \"0\";\n edit.input.style.pointerEvents = \"none\";\n }\n });\n}\n\n/**\n * Lays a text input over a widget. Enter or clicking away keeps what was\n * typed; Escape throws it away.\n */\nexport function editInPlace(config: InPlaceEditConfig): InPlaceEdit | null {\n const canvas = config.canvas;\n if (canvas === null) {\n return null;\n }\n\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.value = config.value;\n const edit: OpenEdit = { canvas, input, placed: true };\n\n const place = (box: Box, scale: number) => {\n const rect = canvas.getBoundingClientRect();\n const sx = canvas.width > 0 ? rect.width / canvas.width : 1;\n const sy = canvas.height > 0 ? rect.height / canvas.height : 1;\n const left = rect.left + (box.Position.x * sx);\n const top = rect.top + (box.Position.y * sy);\n const width = box.Size.x * sx;\n const height = box.Size.y * sy;\n const clip = [\n Math.max(0, rect.top - top),\n Math.max(0, (left + width) - (rect.left + rect.width)),\n Math.max(0, (top + height) - (rect.top + rect.height)),\n Math.max(0, rect.left - left),\n ];\n\n edit.placed = true;\n input.style.cssText = [\n \"position: fixed\",\n `left: ${left}px`,\n `top: ${top}px`,\n `width: ${width}px`,\n `height: ${height}px`,\n `clip-path: inset(${clip.map((c) => `${c}px`).join(\" \")})`,\n \"box-sizing: border-box\",\n \"margin: 0\",\n `padding: 0 ${Theme.Widget.Padding * scale}px`,\n `font: ${Theme.Widget.FontSize * scale * sy}px ${Theme.FontFamily}`,\n `color: ${Theme.Widget.FontColor}`,\n `background: ${Theme.Widget.Hover.BackgroundColor}`,\n `border: ${Theme.Widget.Border.Size * scale}px solid ${Theme.Widget.Border.Color}`,\n `border-radius: ${Theme.Widget.Border.Radius * scale}px`,\n \"outline: none\",\n \"z-index: 1000\",\n ].join(\";\");\n };\n place(config.box, config.scale);\n\n let done = false;\n const finish = (keep: boolean) => {\n if (done) {\n return;\n }\n done = true;\n open.delete(edit);\n input.remove();\n if (keep) {\n config.onCommit(input.value);\n }\n requestRender();\n };\n\n input.addEventListener(\"keydown\", (event: KeyboardEvent) => {\n event.stopPropagation();\n if (event.key === \"Enter\") {\n event.preventDefault();\n finish(true);\n } else if (event.key === \"Escape\") {\n event.preventDefault();\n finish(false);\n }\n });\n input.addEventListener(\"blur\", () => finish(true));\n\n open.add(edit);\n document.body.appendChild(input);\n input.focus();\n input.select();\n return { input, place };\n}\n", "import { Box, InBox } from '../types/box';\r\nimport { Vector2 } from '../types/vector2';\r\nimport { CursorStyle } from '../styles/cursor';\r\nimport { requestRender } from '../render_scheduler';\r\nimport { editInPlace, InPlaceEdit } from './inplace';\r\n\r\nexport const width = 150;\r\nexport const height = 25;\r\n\r\n/**\r\n * Where the pointer is, in canvas pixels, and whether it is over the widget.\r\n * A press that starts on a widget keeps reporting to it until it is let go,\r\n * wherever the pointer wanders.\r\n */\r\nexport interface WidgetPointer {\r\n position: Vector2;\r\n inside: boolean;\r\n}\r\n\r\nexport interface Widget {\r\n /**\r\n * The smallest room the widget needs, in graph units. The node may hand\r\n * it a wider box.\r\n */\r\n Size(): Vector2;\r\n\r\n Draw(ctx: CanvasRenderingContext2D, box: Box, scale: number, mousePosition: Vector2 | undefined): void;\r\n\r\n PointerDown?(pointer: WidgetPointer): void;\r\n PointerMove?(pointer: WidgetPointer): void;\r\n PointerUp?(pointer: WidgetPointer): void;\r\n\r\n Cursor?(): CursorStyle;\r\n Hidden?(): boolean;\r\n Disabled?(): boolean;\r\n}\r\n\r\nexport abstract class WidgetBase implements Widget {\r\n\r\n #hidden = false;\r\n\r\n #disabled = false;\r\n\r\n #hovered = false;\r\n\r\n #pressed = false;\r\n\r\n #box: Box = { Position: { x: 0, y: 0 }, Size: { x: 0, y: 0 } };\r\n\r\n #canvas: HTMLCanvasElement | null = null;\r\n\r\n #scale = 1;\r\n\r\n #editing: InPlaceEdit | null = null;\r\n\r\n abstract Size(): Vector2;\r\n\r\n protected abstract render(ctx: CanvasRenderingContext2D, box: Box, scale: number): void;\r\n\r\n Draw(ctx: CanvasRenderingContext2D, box: Box, scale: number, mousePosition: Vector2 | undefined): void {\r\n this.#box = { Position: { x: box.Position.x, y: box.Position.y }, Size: { x: box.Size.x, y: box.Size.y } };\r\n this.#canvas = ctx.canvas ?? null;\r\n this.#scale = scale;\r\n this.#hovered = !this.#disabled && mousePosition !== undefined && InBox(box, mousePosition);\r\n\r\n if (this.#editing !== null) {\r\n if (this.#editing.input.isConnected) {\r\n this.#editing.place(this.#box, scale);\r\n } else {\r\n this.#editing = null;\r\n }\r\n }\r\n\r\n ctx.save();\r\n if (this.#disabled) {\r\n ctx.globalAlpha *= 0.4;\r\n }\r\n this.render(ctx, box, scale);\r\n ctx.restore();\r\n }\r\n\r\n PointerDown(pointer: WidgetPointer): void {\r\n if (this.#disabled) {\r\n return;\r\n }\r\n this.#pressed = true;\r\n this.onPointerDown(pointer);\r\n requestRender();\r\n }\r\n\r\n PointerMove(pointer: WidgetPointer): void {\r\n if (!this.#pressed) {\r\n return;\r\n }\r\n this.onPointerMove(pointer);\r\n requestRender();\r\n }\r\n\r\n PointerUp(pointer: WidgetPointer): void {\r\n if (!this.#pressed) {\r\n return;\r\n }\r\n this.#pressed = false;\r\n this.onPointerUp(pointer);\r\n if (pointer.inside) {\r\n this.onClick(pointer);\r\n }\r\n requestRender();\r\n }\r\n\r\n Cursor(): CursorStyle {\r\n return CursorStyle.Pointer;\r\n }\r\n\r\n Hidden(): boolean {\r\n return this.#hidden;\r\n }\r\n\r\n setHidden(hidden: boolean): void {\r\n this.#hidden = hidden;\r\n requestRender();\r\n }\r\n\r\n Disabled(): boolean {\r\n return this.#disabled;\r\n }\r\n\r\n setDisabled(disabled: boolean): void {\r\n this.#disabled = disabled;\r\n if (disabled) {\r\n this.#pressed = false;\r\n }\r\n requestRender();\r\n }\r\n\r\n protected hovered(): boolean {\r\n return this.#hovered;\r\n }\r\n\r\n protected pressed(): boolean {\r\n return this.#pressed;\r\n }\r\n\r\n /**\r\n * Where the widget was last drawn, in canvas pixels.\r\n */\r\n protected box(): Box {\r\n return this.#box;\r\n }\r\n\r\n protected canvas(): HTMLCanvasElement | null {\r\n return this.#canvas;\r\n }\r\n\r\n protected scale(): number {\r\n return this.#scale;\r\n }\r\n\r\n protected editText(value: string, onCommit: (text: string) => void): void {\r\n this.#editing = editInPlace({\r\n canvas: this.#canvas,\r\n box: this.#box,\r\n scale: this.#scale,\r\n value,\r\n onCommit,\r\n });\r\n }\r\n\r\n protected onPointerDown(pointer: WidgetPointer): void { }\r\n\r\n protected onPointerMove(pointer: WidgetPointer): void { }\r\n\r\n protected onPointerUp(pointer: WidgetPointer): void { }\r\n\r\n /**\r\n * A press and release that both landed on the widget.\r\n */\r\n protected onClick(pointer: WidgetPointer): void { }\r\n}\r\n\r\ninterface PropertyReader {\r\n getProperty(name: string): any;\r\n}\r\n\r\nexport function startingWidgetValue<T>(\r\n node: PropertyReader,\r\n property: string | undefined,\r\n configured: T | undefined,\r\n fallback: T,\r\n): T {\r\n if (configured !== undefined) {\r\n return configured;\r\n }\r\n if (property !== undefined && property !== null) {\r\n const existing = node.getProperty(property);\r\n if (existing !== undefined && existing !== null) {\r\n return existing as T;\r\n }\r\n }\r\n return fallback;\r\n}\r\n", "import { Theme } from \"../theme\";\nimport { Box } from \"../types/box\";\nimport { Vector2 } from \"../types/vector2\";\nimport { WidgetBase } from \"./widget\";\n\nexport interface HiddenPortsOwner {\n hiddenPortCount(): number;\n hiddenPortsShown(): boolean;\n setHiddenPortsShown(shown: boolean): void;\n}\n\nexport class HiddenPortsToggle extends WidgetBase {\n\n constructor(private readonly owner: HiddenPortsOwner) {\n super();\n }\n\n Size(): Vector2 {\n return { x: 150, y: 16 };\n }\n\n protected render(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\n const label = this.owner.hiddenPortsShown() ? \"\u25B4 less\" : `\u25BE ${this.owner.hiddenPortCount()} more`;\n\n const midY = box.Position.y + box.Size.y / 2;\n const centerX = box.Position.x + box.Size.x / 2;\n\n ctx.font = `${11 * scale}px ${Theme.FontFamily}`;\n const half = ctx.measureText(label).width / 2 + 6 * scale;\n\n ctx.globalAlpha = this.hovered() ? 1 : 0.5;\n ctx.strokeStyle = Theme.Widget.FontColor;\n ctx.fillStyle = Theme.Widget.FontColor;\n ctx.lineWidth = Math.max(1, scale);\n ctx.beginPath();\n ctx.moveTo(box.Position.x, midY);\n ctx.lineTo(centerX - half, midY);\n ctx.moveTo(centerX + half, midY);\n ctx.lineTo(box.Position.x + box.Size.x, midY);\n ctx.stroke();\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.fillText(label, centerX, midY);\n }\n\n protected onClick(): void {\n this.owner.setHiddenPortsShown(!this.owner.hiddenPortsShown());\n }\n}\n", "export interface StrokeStyleConfig {\r\n size?: number;\r\n color?: string;\r\n}\r\n\r\nexport function StrokeStyleWithFallback(input?: StrokeStyleConfig, fallback?: StrokeStyleConfig): StrokeStyleConfig {\r\n return {\r\n color: input?.color === undefined ? fallback?.color : input?.color,\r\n size: input?.size === undefined ? fallback?.size : input?.size,\r\n };\r\n}\r\n\r\nexport class StrokeStyle {\r\n #size: number;\r\n\r\n #color: string;\r\n\r\n constructor(config?: StrokeStyleConfig) {\r\n this.#size = config?.size === undefined ? 0.5 : config.size;\r\n this.#color = config?.color === undefined ? \"black\" : config.color;\r\n }\r\n\r\n setupStyle(ctx: CanvasRenderingContext2D, scale: number): void {\r\n ctx.strokeStyle = this.#color;\r\n ctx.lineWidth = scale * this.#size;\r\n }\r\n\r\n setColor(newColor: string): void {\r\n this.#color = newColor;\r\n }\r\n\r\n setSize(newSize: number): void {\r\n this.#size = newSize;\r\n }\r\n\r\n size(): number {\r\n return this.#size;\r\n }\r\n}", "import { Box } from \"../types/box\";\r\nimport { StrokeStyle, StrokeStyleConfig, StrokeStyleWithFallback } from \"./stroke\";\r\n\r\nexport interface BoxStyleConfig {\r\n border?: StrokeStyleConfig;\r\n color?: string;\r\n radius?: number;\r\n}\r\n\r\nexport function BoxStyleWithFallback(input?: BoxStyleConfig, fallback?: BoxStyleConfig): BoxStyleConfig {\r\n return {\r\n radius: input?.radius === undefined ? fallback?.radius : input?.radius,\r\n color: input?.color === undefined ? fallback?.color : input?.color,\r\n border: StrokeStyleWithFallback(input?.border, fallback?.border)\r\n };\r\n}\r\n\r\nexport class BoxStyle {\r\n #border: StrokeStyle | null;\r\n\r\n #color: string;\r\n\r\n #radius: number;\r\n\r\n constructor(config?: BoxStyleConfig) {\r\n this.#color = config?.color === undefined ? \"#CCCCCC\" : config.color;\r\n this.#border = config?.border === undefined ? null : new StrokeStyle(config.border);\r\n this.#radius = config?.radius === undefined ? 2 : config.radius;\r\n }\r\n\r\n #box(ctx: CanvasRenderingContext2D, box: Box, scale: number, radius: any): void {\r\n ctx.fillStyle = this.#color\r\n this.#border?.setupStyle(ctx, scale);\r\n ctx.beginPath();\r\n ctx.roundRect(\r\n box.Position.x,\r\n box.Position.y,\r\n box.Size.x,\r\n box.Size.y,\r\n radius\r\n );\r\n ctx.fill();\r\n }\r\n\r\n #draw(ctx: CanvasRenderingContext2D, box: Box, scale: number, radius: any): void {\r\n this.#box(ctx, box, scale, radius);\r\n ctx.stroke();\r\n }\r\n\r\n Outline(ctx: CanvasRenderingContext2D, box: Box, scale: number, radius: any): void {\r\n this.#border?.setupStyle(ctx, scale);\r\n ctx.beginPath();\r\n ctx.roundRect(\r\n box.Position.x,\r\n box.Position.y,\r\n box.Size.x,\r\n box.Size.y,\r\n radius\r\n );\r\n ctx.stroke();\r\n }\r\n\r\n Draw(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\r\n this.#draw(ctx, box, scale, this.#radius * scale)\r\n }\r\n\r\n DrawRoundedTopOnly(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\r\n this.#draw(ctx, box, scale, [this.#radius * scale * 2, this.#radius * scale * 2, 0, 0])\r\n }\r\n\r\n DrawUnderline(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\r\n this.#box(ctx, box, scale, [this.#radius * scale * 2, this.#radius * scale * 2, 0, 0]);\r\n ctx.beginPath();\r\n ctx.moveTo(box.Position.x, box.Position.y + box.Size.y)\r\n ctx.lineTo(box.Position.x + box.Size.x, box.Position.y + box.Size.y);\r\n ctx.stroke();\r\n }\r\n\r\n borderSize(): number {\r\n if (this.#border === null) {\r\n return 0;\r\n }\r\n return this.#border.size();\r\n }\r\n\r\n radius(): number {\r\n return this.#radius;\r\n }\r\n\r\n setColor(color: string): void {\r\n this.#color = color;\r\n }\r\n\r\n setBorderColor(color: string): void {\r\n if (this.#border === null) {\r\n this.#border = new StrokeStyle({\r\n color: color\r\n })\r\n } else {\r\n this.#border.setColor(color);\r\n }\r\n }\r\n\r\n}", "import { BevelColors } from \"../theme\";\nimport { Box } from \"../types/box\";\n\nexport function drawBevel(ctx: CanvasRenderingContext2D, box: Box, scale: number, colors: BevelColors, sunken: boolean): void {\n const width = Math.max(1, 2 * scale);\n const half = width / 2;\n const left = box.Position.x + half;\n const top = box.Position.y + half;\n const right = box.Position.x + box.Size.x - half;\n const bottom = box.Position.y + box.Size.y - half;\n\n ctx.save();\n ctx.lineWidth = width;\n ctx.lineCap = \"square\";\n\n ctx.strokeStyle = sunken ? colors.Dark : colors.Light;\n ctx.beginPath();\n ctx.moveTo(left, bottom);\n ctx.lineTo(left, top);\n ctx.lineTo(right, top);\n ctx.stroke();\n\n ctx.strokeStyle = sunken ? colors.Light : colors.Dark;\n ctx.beginPath();\n ctx.moveTo(right, top);\n ctx.lineTo(right, bottom);\n ctx.lineTo(left, bottom);\n ctx.stroke();\n\n ctx.restore();\n}\n", "import { Theme } from \"../theme\";\nimport { drawBevel } from \"../styles/bevel\";\nimport { Box } from \"../types/box\";\nimport { fitString } from \"../utils/string\";\n\nexport interface FieldLook {\n hovered: boolean;\n pressed?: boolean;\n\n /**\n * Something typed or dragged into, as opposed to something pressed.\n */\n input?: boolean;\n\n label?: string;\n value: string;\n background?: string;\n border?: string;\n textColor?: string;\n}\n\nexport function widgetFont(scale: number): string {\n return `${Theme.Widget.FontSize * scale}px ${Theme.FontFamily}`;\n}\n\nfunction fieldBackground(look: FieldLook): string {\n if (look.background !== undefined) {\n return look.background;\n }\n if (look.input) {\n return look.hovered ? Theme.Widget.Input.HoverBackgroundColor : Theme.Widget.Input.BackgroundColor;\n }\n if (look.pressed) {\n return Theme.Widget.Button.Click.BackgroundColor;\n }\n return look.hovered ? Theme.Widget.Hover.BackgroundColor : Theme.Widget.BackgroundColor;\n}\n\nexport function drawFieldBox(ctx: CanvasRenderingContext2D, box: Box, scale: number, look: FieldLook): void {\n ctx.fillStyle = fieldBackground(look);\n ctx.beginPath();\n ctx.roundRect(box.Position.x, box.Position.y, box.Size.x, box.Size.y, Theme.Widget.Border.Radius * scale);\n ctx.fill();\n\n if (Theme.Widget.Border.Size > 0) {\n ctx.strokeStyle = look.border ?? Theme.Widget.Border.Color;\n ctx.lineWidth = Theme.Widget.Border.Size * scale;\n ctx.stroke();\n }\n\n if (Theme.Widget.Bevel !== null) {\n drawBevel(ctx, box, scale, Theme.Widget.Bevel, look.input === true || look.pressed === true);\n }\n}\n\n/**\n * A boxed value with an optional label: the label on the left and the value\n * on the right, or the value alone in the middle.\n */\nexport function drawField(ctx: CanvasRenderingContext2D, box: Box, scale: number, look: FieldLook): void {\n drawFieldBox(ctx, box, scale, look);\n drawFieldText(ctx, box, scale, look);\n}\n\nexport function drawFieldText(ctx: CanvasRenderingContext2D, box: Box, scale: number, look: FieldLook): void {\n const padding = Theme.Widget.Padding * scale;\n const middle = box.Position.y + (box.Size.y / 2);\n const textColor = look.textColor ?? (look.input ? Theme.Widget.Input.FontColor : Theme.Widget.FontColor);\n\n ctx.font = widgetFont(scale);\n ctx.textBaseline = \"middle\";\n\n if (look.label === undefined || look.label === \"\") {\n ctx.textAlign = \"center\";\n ctx.fillStyle = textColor;\n ctx.fillText(\n fitString(ctx, look.value, box.Size.x - (padding * 2)),\n box.Position.x + (box.Size.x / 2),\n middle,\n );\n return;\n }\n\n const room = box.Size.x - (padding * 2);\n const label = fitString(ctx, look.label, room / 2);\n const labelWidth = ctx.measureText(label).width;\n\n ctx.textAlign = \"left\";\n ctx.fillStyle = look.textColor ?? Theme.Widget.LabelColor;\n ctx.fillText(label, box.Position.x + padding, middle);\n\n ctx.textAlign = \"right\";\n ctx.fillStyle = textColor;\n ctx.fillText(\n fitString(ctx, look.value, room - labelWidth - padding),\n box.Position.x + box.Size.x - padding,\n middle,\n );\n}\n", "import { FlowNode } from \"../node\";\nimport { requestRender } from \"../render_scheduler\";\nimport { Vector2 } from \"../types/vector2\";\nimport { height, startingWidgetValue, width, WidgetBase } from \"./widget\";\n\nexport interface ValueWidgetConfig<T> {\n /**\n * A node property the widget shows and edits. Setting the property from\n * code updates the widget without counting as an edit.\n */\n property?: string;\n\n value?: T;\n\n label?: string;\n\n /**\n * The narrowest the widget gets, in graph units.\n */\n width?: number;\n\n /**\n * A person finished changing the value.\n */\n callback?: (value: T) => void;\n\n /**\n * The value moved while a person is still changing it.\n */\n onInput?: (value: T) => void;\n}\n\nexport abstract class ValueWidget<T> extends WidgetBase {\n\n #node: FlowNode;\n\n #property: string | undefined;\n\n #value: T;\n\n #label: string;\n\n #width: number;\n\n #callback?: (value: T) => void;\n\n #onInput?: (value: T) => void;\n\n constructor(node: FlowNode, config: ValueWidgetConfig<T> | undefined, fallback: T) {\n super();\n this.#node = node;\n this.#property = config?.property;\n this.#label = config?.label ?? \"\";\n this.#width = config?.width ?? width;\n this.#value = startingWidgetValue(node, this.#property, config?.value, fallback);\n this.#callback = config?.callback;\n this.#onInput = config?.onInput;\n\n if (this.#property !== undefined) {\n node.setProperty(this.#property, this.#value);\n node.addPropertyChangeListener(this.#property, (_, next) => this.setValue(next));\n }\n }\n\n Size(): Vector2 {\n return { x: this.#width, y: height };\n }\n\n value(): T {\n return this.#value;\n }\n\n /**\n * Shows a new value without treating it as a person's edit: no callback\n * and no edit event.\n */\n setValue(value: T): void {\n if (this.equal(value, this.#value)) {\n return;\n }\n this.#value = value;\n this.valueChanged();\n if (this.#property !== undefined) {\n this.#node.setProperty(this.#property, value);\n }\n requestRender();\n }\n\n label(): string {\n return this.#label;\n }\n\n setLabel(label: string): void {\n this.#label = label;\n requestRender();\n }\n\n protected node(): FlowNode {\n return this.#node;\n }\n\n protected input(value: T): void {\n this.setValue(value);\n this.#onInput?.(value);\n }\n\n /**\n * Ends a person's edit. Nothing is reported when they ended where they\n * started.\n */\n protected commit(value: T, startedAt: T): void {\n this.setValue(value);\n if (this.equal(value, startedAt)) {\n return;\n }\n if (this.#property !== undefined) {\n this.#node.editProperty(this.#property, value);\n }\n this.#callback?.(value);\n }\n\n protected valueChanged(): void { }\n\n protected equal(a: T, b: T): boolean {\n return Object.is(a, b);\n }\n}\n", "import { FlowNode } from \"../node\";\nimport { CursorStyle } from \"../styles/cursor\";\nimport { Box } from \"../types/box\";\nimport { drawField } from \"./field\";\nimport { ValueWidget, ValueWidgetConfig } from \"./value\";\nimport { WidgetPointer } from \"./widget\";\n\nexport interface NumberWidgetConfig extends ValueWidgetConfig<number> {\n /**\n * How much the value moves per pixel dragged. Left out, it scales with\n * the value's size.\n */\n step?: number;\n\n integer?: boolean;\n\n min?: number;\n\n max?: number;\n}\n\nconst DRAG_THRESHOLD = 3;\n\nexport class NumberWidget extends ValueWidget<number> {\n\n #step: number | undefined;\n\n #integer: boolean;\n\n #min: number;\n\n #max: number;\n\n #startX = 0;\n\n #startValue = 0;\n\n #dragging = false;\n\n #dragged = false;\n\n constructor(node: FlowNode, config?: NumberWidgetConfig) {\n super(node, config, 0);\n this.#step = config?.step;\n this.#integer = config?.integer === true;\n this.#min = config?.min ?? -Infinity;\n this.#max = config?.max ?? Infinity;\n }\n\n Cursor(): CursorStyle {\n return CursorStyle.EWResize;\n }\n\n protected render(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\n drawField(ctx, box, scale, {\n input: true,\n hovered: this.hovered() || this.pressed(),\n label: this.label(),\n value: formatNumber(this.value()),\n });\n }\n\n protected onPointerDown(pointer: WidgetPointer): void {\n this.#startX = pointer.position.x;\n this.#startValue = this.value();\n this.#dragging = false;\n this.#dragged = false;\n }\n\n protected onPointerMove(pointer: WidgetPointer): void {\n const dx = pointer.position.x - this.#startX;\n if (!this.#dragging && Math.abs(dx) < DRAG_THRESHOLD) {\n return;\n }\n this.#dragging = true;\n this.input(this.#clean(this.#startValue + (dx * this.#stepFor(this.#startValue))));\n }\n\n protected onPointerUp(): void {\n this.#dragged = this.#dragging;\n if (this.#dragging) {\n this.#dragging = false;\n this.commit(this.value(), this.#startValue);\n }\n }\n\n protected onClick(): void {\n if (this.#dragged) {\n return;\n }\n const before = this.value();\n this.editText(String(before), (text) => {\n const parsed = Number.parseFloat(text);\n if (Number.isFinite(parsed)) {\n this.commit(this.#clean(parsed), before);\n }\n });\n }\n\n #stepFor(value: number): number {\n if (this.#step !== undefined) {\n return this.#step;\n }\n return Math.max(Math.abs(value) * 0.01, this.#integer ? 0.1 : 0.01);\n }\n\n #clean(value: number): number {\n const rounded = this.#integer ? Math.round(value) : value;\n return Math.min(this.#max, Math.max(this.#min, rounded));\n }\n}\n\nexport function formatNumber(value: number): string {\n return '' + parseFloat(value.toPrecision(6));\n}\n", "import { requestRender } from \"../render_scheduler\";\nimport { Box } from \"../types/box\";\nimport { Vector2 } from \"../types/vector2\";\nimport { drawField } from \"./field\";\nimport { height, width, WidgetBase } from \"./widget\";\n\nexport interface ButtonWidgetConfig {\n text?: string;\n callback?: () => void;\n width?: number;\n}\n\nexport class ButtonWidget extends WidgetBase {\n\n #text: string;\n\n #callback?: () => void;\n\n #width: number;\n\n constructor(config?: ButtonWidgetConfig) {\n super();\n this.#text = config?.text ?? \"Button\";\n this.#callback = config?.callback;\n this.#width = config?.width ?? width;\n }\n\n Size(): Vector2 {\n return { x: this.#width, y: height };\n }\n\n text(): string {\n return this.#text;\n }\n\n setText(text: string): void {\n this.#text = text;\n requestRender();\n }\n\n protected render(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\n drawField(ctx, box, scale, {\n hovered: this.hovered(),\n pressed: this.pressed(),\n value: this.#text,\n });\n }\n\n protected onClick(): void {\n this.#callback?.();\n }\n}\n", "import { HexToColor } from \"../utils/color\";\nimport { Box } from \"../types/box\";\nimport { drawField } from \"./field\";\nimport { FlowNode } from \"../node\";\nimport { ValueWidget, ValueWidgetConfig } from \"./value\";\n\nexport interface ColorWidgetConfig extends ValueWidgetConfig<string> { }\n\nfunction contrastColor(color: string): string {\n const c = HexToColor(color);\n if (c === null) {\n return \"black\";\n }\n\n if ((c.r + c.g + c.b) / 3 > 0.5) {\n return \"black\"\n }\n\n return \"white\";\n}\n\nlet picker: HTMLInputElement | null = null;\n\nfunction sharedPicker(): HTMLInputElement {\n if (picker === null || !picker.isConnected) {\n picker = document.createElement(\"input\");\n picker.type = \"color\";\n document.body.appendChild(picker);\n }\n return picker;\n}\n\nexport class ColorWidget extends ValueWidget<string> {\n\n #contrast: string;\n\n constructor(node: FlowNode, config?: ColorWidgetConfig) {\n super(node, config, \"#000000\");\n this.#contrast = contrastColor(this.value());\n }\n\n protected valueChanged(): void {\n this.#contrast = contrastColor(this.value());\n }\n\n protected render(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\n drawField(ctx, box, scale, {\n input: true,\n hovered: this.hovered(),\n label: this.label(),\n value: this.value(),\n background: this.value(),\n border: this.#contrast,\n textColor: this.#contrast,\n });\n }\n\n protected onClick(): void {\n const canvas = this.canvas();\n if (canvas === null) {\n return;\n }\n\n const before = this.value();\n // The browser's picker has no alpha, so the old alpha is carried over.\n const alpha = before.slice(7);\n const box = this.box();\n const rect = canvas.getBoundingClientRect();\n const sx = canvas.width > 0 ? rect.width / canvas.width : 1;\n const sy = canvas.height > 0 ? rect.height / canvas.height : 1;\n\n const input = sharedPicker();\n input.style.cssText = [\n \"position: fixed\",\n `left: ${rect.left + (box.Position.x * sx)}px`,\n `top: ${rect.top + (box.Position.y * sy)}px`,\n `width: ${box.Size.x * sx}px`,\n `height: ${box.Size.y * sy}px`,\n \"opacity: 0\",\n \"pointer-events: none\",\n \"border: 0\",\n \"padding: 0\",\n ].join(\";\");\n input.value = before.slice(0, 7);\n input.oninput = () => this.input(input.value + alpha);\n input.onchange = () => this.commit(input.value + alpha, before);\n // Reading the rect lays the input out first; the picker opens at its last laid-out spot.\n input.getBoundingClientRect();\n input.click();\n }\n}\n", "import { Theme } from \"../theme\";\nimport { Box } from \"../types/box\";\nimport { Clamp, Clamp01 } from \"../utils/math\";\nimport { FlowNode } from \"../node\";\nimport { CursorStyle } from \"../styles/cursor\";\nimport { drawFieldBox, drawFieldText } from \"./field\";\nimport { formatNumber } from \"./number\";\nimport { ValueWidget, ValueWidgetConfig } from \"./value\";\nimport { WidgetPointer } from \"./widget\";\n\nexport interface SliderWidgetConfig extends ValueWidgetConfig<number> {\n min?: number;\n\n max?: number;\n\n snapIncrement?: number;\n\n fillColor?: string;\n}\n\nexport class SliderWidget extends ValueWidget<number> {\n\n #min: number;\n\n #max: number;\n\n #snapIncrement?: number;\n\n #fillColor: string | undefined;\n\n #startValue = 0;\n\n constructor(node: FlowNode, config?: SliderWidgetConfig) {\n const min = config?.min ?? 0;\n const max = config?.max ?? 1;\n super(node, { ...config, value: config?.value === undefined ? undefined : Clamp(config.value, min, max) }, min);\n this.#min = min;\n this.#max = max;\n this.#snapIncrement = config?.snapIncrement;\n this.#fillColor = config?.fillColor;\n }\n\n Cursor(): CursorStyle {\n return CursorStyle.EWResize;\n }\n\n setValue(value: number): void {\n super.setValue(Clamp(value, this.#min, this.#max));\n }\n\n protected render(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\n drawFieldBox(ctx, box, scale, { input: true, hovered: this.hovered() || this.pressed(), value: \"\" });\n\n const border = Theme.Widget.Border.Size * scale;\n const fill = Clamp01((this.value() - this.#min) / (this.#max - this.#min));\n ctx.fillStyle = this.#fillColor ?? Theme.Widget.Slider.FillColor;\n ctx.beginPath();\n ctx.roundRect(\n box.Position.x + (border / 2),\n box.Position.y + (border / 2),\n Math.max(0, (box.Size.x * fill) - border),\n box.Size.y - border,\n Theme.Widget.Border.Radius * scale\n );\n ctx.fill();\n\n drawFieldText(ctx, box, scale, {\n input: true,\n hovered: false,\n label: this.label(),\n value: formatNumber(Number(this.value().toFixed(3))),\n });\n }\n\n protected onPointerDown(pointer: WidgetPointer): void {\n this.#startValue = this.value();\n this.input(this.#valueAt(pointer.position.x));\n }\n\n protected onPointerMove(pointer: WidgetPointer): void {\n this.input(this.#valueAt(pointer.position.x));\n }\n\n protected onPointerUp(): void {\n this.commit(this.value(), this.#startValue);\n }\n\n #valueAt(x: number): number {\n const box = this.box();\n const border = Theme.Widget.Border.Size * this.scale();\n const min = box.Position.x + (border / 2);\n const max = min + box.Size.x - border;\n const p = Clamp01((x - min) / (max - min));\n\n let value = (p * (this.#max - this.#min)) + this.#min;\n if (this.#snapIncrement !== undefined) {\n value = Math.round(value / this.#snapIncrement) * this.#snapIncrement;\n }\n return Clamp(value, this.#min, this.#max);\n }\n}\n", "import { FlowNode } from \"../node\";\nimport { CursorStyle } from \"../styles/cursor\";\nimport { Box } from \"../types/box\";\nimport { drawField } from \"./field\";\nimport { ValueWidget, ValueWidgetConfig } from \"./value\";\n\nexport interface StringWidgetConfig extends ValueWidgetConfig<string> { }\n\nexport class StringWidget extends ValueWidget<string> {\n\n constructor(node: FlowNode, config?: StringWidgetConfig) {\n super(node, config, \"\");\n }\n\n Cursor(): CursorStyle {\n return CursorStyle.Text;\n }\n\n protected render(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\n drawField(ctx, box, scale, {\n input: true,\n hovered: this.hovered(),\n label: this.label(),\n value: this.value(),\n });\n }\n\n protected onClick(): void {\n const before = this.value();\n this.editText(before, (text) => this.commit(text, before));\n }\n}\n", "import { Theme } from \"../theme\";\nimport { Box } from \"../types/box\";\nimport { FlowNode } from \"../node\";\nimport { drawFieldBox, widgetFont } from \"./field\";\nimport { ValueWidget, ValueWidgetConfig } from \"./value\";\nimport { fitString } from \"../utils/string\";\n\nexport interface ToggleWidgetConfig extends ValueWidgetConfig<boolean> {\n onColor?: string;\n offColor?: string;\n}\n\nexport class ToggleWidget extends ValueWidget<boolean> {\n\n #onColor: string;\n\n #offColor: string;\n\n constructor(node: FlowNode, config?: ToggleWidgetConfig) {\n super(node, { ...config, label: config?.label ?? \"Toggle\" }, false);\n this.#onColor = config?.onColor ?? \"#00FF00\";\n this.#offColor = config?.offColor ?? \"#004400\";\n }\n\n Toggle(): void {\n const before = this.value();\n this.commit(!before, before);\n }\n\n protected render(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\n drawFieldBox(ctx, box, scale, { hovered: this.hovered(), value: \"\" });\n\n const light = Math.min(box.Size.x, box.Size.y) * 0.6;\n const inset = (box.Size.y - light) / 2;\n const on = this.value();\n ctx.fillStyle = on ? this.#onColor : this.#offColor;\n ctx.beginPath();\n ctx.roundRect(box.Position.x + inset, box.Position.y + inset, light, light, Theme.Widget.Border.Radius * scale);\n if (on) {\n ctx.shadowBlur = 15 * scale;\n ctx.shadowColor = this.#onColor;\n }\n ctx.fill();\n ctx.shadowBlur = 0;\n\n const textLeft = box.Position.x + (inset * 2) + light;\n ctx.font = widgetFont(scale);\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"middle\";\n ctx.fillStyle = Theme.Widget.FontColor;\n const room = box.Position.x + box.Size.x - textLeft - inset;\n ctx.fillText(\n fitString(ctx, this.label(), room),\n textLeft + (room / 2),\n box.Position.y + (box.Size.y / 2),\n );\n }\n\n protected onClick(): void {\n this.Toggle();\n }\n}\n", "import { requestRender } from \"../render_scheduler\";\nimport { CursorStyle } from \"../styles/cursor\";\nimport { Box } from \"../types/box\";\nimport { Vector2 } from \"../types/vector2\";\nimport { WidgetBase } from \"./widget\";\n\nexport interface ImageWidgetConfig {\n image?: string;\n maxWidth?: number\n maxHeight?: number\n blob?: Blob;\n}\n\nexport class ImageWidget extends WidgetBase {\n\n #url: string | undefined;\n\n #ownedUrl: string | undefined;\n\n #image: HTMLImageElement | undefined;\n\n #maxWidth: number;\n\n #maxHeight: number;\n\n constructor(config?: ImageWidgetConfig) {\n super();\n this.#maxWidth = config?.maxWidth === undefined ? 150 : config?.maxWidth;\n this.#maxHeight = config?.maxHeight === undefined ? 150 : config?.maxHeight;\n if (config?.image) {\n this.SetUrl(config?.image);\n } else if (config?.blob) {\n this.SetBlob(config?.blob);\n }\n }\n\n SetBlob(blob: Blob) {\n const url = URL.createObjectURL(blob);\n this.SetUrl(url);\n this.#ownedUrl = url;\n }\n\n SetUrl(url: string) {\n if (this.#ownedUrl !== undefined) {\n URL.revokeObjectURL(this.#ownedUrl);\n this.#ownedUrl = undefined;\n }\n this.#image = undefined;\n this.#url = url;\n\n const img = document.createElement(\"img\");\n img.src = url;\n img.onload = () => {\n if (this.#url !== url) {\n return;\n }\n this.#image = img;\n requestRender();\n };\n img.onerror = (event) => {\n console.log(\"error loading image:\", url, event);\n }\n }\n\n Cursor(): CursorStyle {\n return CursorStyle.Default;\n }\n\n Size(): Vector2 {\n if (this.#image === undefined) {\n return { \"x\": 0, \"y\": 0 }\n }\n\n let adjust = 1;\n if (this.#image.width > this.#maxWidth) {\n adjust = this.#maxWidth / this.#image.width\n }\n\n if (this.#image.height > this.#maxHeight) {\n let heightAdjust = this.#maxHeight / this.#image.height\n if (heightAdjust < adjust) {\n adjust = heightAdjust;\n }\n }\n\n return {\n \"x\": adjust * this.#image.width,\n \"y\": adjust * this.#image.height\n }\n }\n\n protected render(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\n if (!this.#image) {\n return;\n }\n const size = this.Size();\n const w = size.x * scale;\n const h = size.y * scale;\n ctx.drawImage(\n this.#image,\n box.Position.x + ((box.Size.x - w) / 2),\n box.Position.y,\n w,\n h\n );\n }\n}\n", "import { Theme, themeVersion } from \"../theme\";\nimport { Box } from \"../types/box\";\nimport { Vector2, Zero } from \"../types/vector2\";\nimport { FlowNode } from '../node';\nimport { Text } from \"../types/text\";\nimport { TextStyleConfig, TextStyleFallback } from \"../styles/text\";\nimport { CursorStyle } from \"../styles/cursor\";\nimport { requestRender } from \"../render_scheduler\";\nimport { WidgetBase } from \"./widget\";\n\nexport interface TextWidgetConfig {\n property?: string;\n value?: string;\n textBoxStyle?: TextStyleConfig;\n}\n\nexport class TextWidget extends WidgetBase {\n\n #value: Text;\n\n #size: Vector2;\n\n #styleConfig: TextStyleConfig | undefined;\n\n #styledForTheme = -1;\n\n #followTheme(): void {\n if (this.#styledForTheme === themeVersion()) {\n return;\n }\n this.#styledForTheme = themeVersion();\n const style = this.#value.style();\n style.setColor(this.#styleConfig?.color ?? Theme.Widget.FontColor);\n style.setSize(this.#styleConfig?.size ?? Theme.Note.FontSize);\n }\n\n constructor(node: FlowNode, config?: TextWidgetConfig) {\n super();\n this.#size = Zero();\n this.#styleConfig = config?.textBoxStyle;\n this.#value = new Text(\"\", TextStyleFallback(config?.textBoxStyle, {}));\n this.#followTheme();\n this.setText(config?.value ?? \"\");\n\n const property = config?.property;\n if (property !== undefined) {\n const existing = node.getProperty(property);\n if (existing !== undefined && existing !== null) {\n this.setText(String(existing));\n }\n node.addPropertyChangeListener(property, (_, next) => this.setText(String(next)));\n }\n }\n\n Cursor(): CursorStyle {\n return CursorStyle.Default;\n }\n\n Size(): Vector2 {\n return this.#size;\n }\n\n text(): string {\n return this.#value.get();\n }\n\n setText(value: string): void {\n if (this.#value.get() === value) {\n return;\n }\n this.#value.set(value);\n requestRender();\n }\n\n protected render(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\n this.#followTheme();\n this.#value.size(ctx, 1, this.#size);\n ctx.textAlign = \"left\";\n this.#value.render(ctx, scale, box.Position);\n }\n}\n", "import { Theme } from \"../theme\";\nimport { CursorStyle } from \"../styles/cursor\";\nimport { Box, InBox } from \"../types/box\";\nimport { Vector2 } from \"../types/vector2\";\nimport { Widget, WidgetBase, WidgetPointer } from \"./widget\";\n\nexport interface RowWidgetConfig {\n /**\n * How the room beyond each child's own width is shared out. Left out,\n * every child grows the same; 0 keeps a child at its own width.\n */\n grow?: Array<number>;\n\n gap?: number;\n}\n\nexport class RowWidget extends WidgetBase {\n\n #children: Array<Widget>;\n\n #grow: Array<number>;\n\n #gap: number;\n\n #boxes: Array<Box | null> = [];\n\n #captured: Widget | null = null;\n\n #capturedBox: Box | null = null;\n\n #mouse: Vector2 | undefined;\n\n constructor(children: Array<Widget>, config?: RowWidgetConfig) {\n super();\n this.#children = children;\n this.#grow = config?.grow ?? children.map(() => 1);\n this.#gap = config?.gap ?? Theme.Widget.Gap;\n }\n\n children(): ReadonlyArray<Widget> {\n return this.#children;\n }\n\n Size(): Vector2 {\n const shown = this.#shown();\n let x = 0;\n let y = 0;\n for (const child of shown) {\n const size = child.Size();\n x += size.x;\n y = Math.max(y, size.y);\n }\n x += Math.max(0, shown.length - 1) * this.#gap;\n return { x, y };\n }\n\n Cursor(): CursorStyle {\n const over = this.#captured ?? this.#childAt(this.#mouse);\n return over?.Cursor?.() ?? CursorStyle.Default;\n }\n\n Draw(ctx: CanvasRenderingContext2D, box: Box, scale: number, mousePosition: Vector2 | undefined): void {\n this.#mouse = mousePosition;\n super.Draw(ctx, box, scale, mousePosition);\n }\n\n protected render(ctx: CanvasRenderingContext2D, box: Box, scale: number): void {\n const shown = this.#shown();\n const gap = this.#gap * scale;\n const natural = shown.reduce((sum, child) => sum + (child.Size().x * scale), 0);\n const extra = Math.max(0, box.Size.x - natural - (gap * Math.max(0, shown.length - 1)));\n const totalGrow = shown.reduce((sum, child) => sum + this.#growOf(child), 0);\n\n this.#boxes = this.#children.map(() => null);\n let x = box.Position.x;\n for (const child of shown) {\n const size = child.Size();\n const share = totalGrow > 0 ? extra * (this.#growOf(child) / totalGrow) : 0;\n const childBox: Box = {\n Position: { x, y: box.Position.y + ((box.Size.y - (size.y * scale)) / 2) },\n Size: { x: (size.x * scale) + share, y: size.y * scale },\n };\n this.#boxes[this.#children.indexOf(child)] = childBox;\n child.Draw(ctx, childBox, scale, this.#captured === null || this.#captured === child ? this.#mouse : undefined);\n x += childBox.Size.x + gap;\n }\n }\n\n protected onPointerDown(pointer: WidgetPointer): void {\n const child = this.#childAt(pointer.position);\n if (child === null || child.Disabled?.()) {\n return;\n }\n this.#captured = child;\n this.#capturedBox = this.#boxes[this.#children.indexOf(child)];\n child.PointerDown?.(this.#forChild(pointer));\n }\n\n protected onPointerMove(pointer: WidgetPointer): void {\n this.#captured?.PointerMove?.(this.#forChild(pointer));\n }\n\n protected onPointerUp(pointer: WidgetPointer): void {\n const child = this.#captured;\n const forChild = this.#forChild(pointer);\n this.#captured = null;\n this.#capturedBox = null;\n child?.PointerUp?.(forChild);\n }\n\n #forChild(pointer: WidgetPointer): WidgetPointer {\n return {\n position: pointer.position,\n inside: this.#capturedBox !== null && InBox(this.#capturedBox, pointer.position),\n };\n }\n\n #childAt(position: Vector2 | undefined): Widget | null {\n if (position === undefined) {\n return null;\n }\n for (let i = 0; i < this.#children.length; i++) {\n const box = this.#boxes[i];\n if (box && InBox(box, position)) {\n return this.#children[i];\n }\n }\n return null;\n }\n\n #shown(): Array<Widget> {\n return this.#children.filter((child) => !child.Hidden?.());\n }\n\n #growOf(child: Widget): number {\n return this.#grow[this.#children.indexOf(child)] ?? 1;\n }\n}\n", "import { Widget } from \"./widget\";\nimport { NumberWidget, NumberWidgetConfig } from './number';\nimport { ButtonWidget, ButtonWidgetConfig } from './button';\nimport { ColorWidget, ColorWidgetConfig } from './color';\nimport { SliderWidget, SliderWidgetConfig } from './slider';\nimport { StringWidget, StringWidgetConfig } from './string';\nimport { ToggleWidget, ToggleWidgetConfig } from './toggle';\nimport { FlowNode } from \"../node\";\nimport { ImageWidget, ImageWidgetConfig } from \"./image\";\nimport { TextWidget, TextWidgetConfig } from \"./text\";\nimport { RowWidget, RowWidgetConfig } from \"./row\";\n\nexport interface RowWidgetFactoryConfig extends RowWidgetConfig {\n widgets: Array<WidgetConfig>;\n}\n\nexport interface WidgetConfigs {\n button: ButtonWidgetConfig;\n number: NumberWidgetConfig;\n color: ColorWidgetConfig;\n slider: SliderWidgetConfig;\n string: StringWidgetConfig;\n toggle: ToggleWidgetConfig;\n image: ImageWidgetConfig;\n text: TextWidgetConfig;\n row: RowWidgetFactoryConfig;\n}\n\nexport interface WidgetTypes {\n button: ButtonWidget;\n number: NumberWidget;\n color: ColorWidget;\n slider: SliderWidget;\n string: StringWidget;\n toggle: ToggleWidget;\n image: ImageWidget;\n text: TextWidget;\n row: RowWidget;\n}\n\nexport type WidgetConfig = {\n [K in keyof WidgetConfigs]: { type: K; config?: WidgetConfigs[K] }\n}[keyof WidgetConfigs];\n\nexport type WidgetBuilder = (node: FlowNode, config?: any) => Widget;\n\nexport class WidgetFactory {\n\n #registeredWidgets: Map<string, WidgetBuilder>\n\n constructor() {\n this.#registeredWidgets = new Map<string, WidgetBuilder>();\n }\n\n register(widgetType: string, builder: WidgetBuilder): void {\n this.#registeredWidgets.set(widgetType, builder);\n }\n\n create<K extends keyof WidgetConfigs>(node: FlowNode, widgetType: K, config?: WidgetConfigs[K]): WidgetTypes[K];\n create(node: FlowNode, widgetType: string, config?: unknown): Widget;\n create(node: FlowNode, widgetType: string, config?: unknown): Widget {\n const builder = this.#registeredWidgets.get(widgetType)\n if (builder === undefined) {\n throw new Error(\"no builder registered for widget: \" + widgetType);\n }\n return builder(node, config);\n }\n\n createFromConfig(node: FlowNode, config: WidgetConfig): Widget {\n return this.create(node, config.type, config.config);\n }\n}\n\nconst GlobalWidgetFactory = new WidgetFactory();\n\nGlobalWidgetFactory.register(\"button\", (node: FlowNode, config?: ButtonWidgetConfig) => new ButtonWidget(config));\nGlobalWidgetFactory.register(\"number\", (node: FlowNode, config?: NumberWidgetConfig) => new NumberWidget(node, config));\nGlobalWidgetFactory.register(\"color\", (node: FlowNode, config?: ColorWidgetConfig) => new ColorWidget(node, config));\nGlobalWidgetFactory.register(\"slider\", (node: FlowNode, config?: SliderWidgetConfig) => new SliderWidget(node, config));\nGlobalWidgetFactory.register(\"string\", (node: FlowNode, config?: StringWidgetConfig) => new StringWidget(node, config));\nGlobalWidgetFactory.register(\"toggle\", (node: FlowNode, config?: ToggleWidgetConfig) => new ToggleWidget(node, config));\nGlobalWidgetFactory.register(\"image\", (node: FlowNode, config?: ImageWidgetConfig) => new ImageWidget(config));\nGlobalWidgetFactory.register(\"text\", (node: FlowNode, config?: TextWidgetConfig) => new TextWidget(node, config));\nGlobalWidgetFactory.register(\"row\", (node: FlowNode, config?: RowWidgetFactoryConfig) => new RowWidget(\n (config?.widgets ?? []).map((child) => GlobalWidgetFactory.createFromConfig(node, child)),\n config,\n));\n\nexport { GlobalWidgetFactory };\n", "import { FlowNode } from \"./node\";\r\nimport { Port } from \"./port\";\r\nimport { Box, BoxCenter, InBox } from \"./types/box\";\r\nimport { Vector2, Zero } from \"./types/vector2\";\r\nimport { Clamp01 } from \"./utils/math\";\r\n\r\nexport interface ConnectionRendererParams {\r\n ctx: CanvasRenderingContext2D;\r\n start: Vector2;\r\n end: Vector2;\r\n graphScale: number;\r\n mouseOver: boolean;\r\n\r\n inNode: FlowNode | null;\r\n inPort: Port | null;\r\n outNode: FlowNode | null;\r\n outPort: Port | null;\r\n}\r\n\r\nexport type ConnectionRenderer = (params: ConnectionRendererParams) => void\r\n\r\n/** Horizontal stub (screen px) at full strength on each port when output is right of input. */\r\nconst BACKWARD_PORT_STUB = 30;\r\n/** Screen px of output-over-input overlap over which stubs ramp from 0 to full. */\r\nconst BACKWARD_STUB_RAMP = 80;\r\n\r\nfunction smoothstep(t: number): number {\r\n const x = Clamp01(t);\r\n return x * x * (3 - 2 * x);\r\n}\r\n\r\nexport function DefaultConnectionRenderer(connectionSize: number, connectionColor: string | undefined, mouseOverSize: number, mouseOverColor: string | undefined): ConnectionRenderer {\r\n return (params: ConnectionRendererParams) => {\r\n\r\n let color = \"#00FF00\";\r\n if (params.outPort !== null) {\r\n color = params.outPort.filledStyleColor()\r\n } else if (params.inPort !== null) {\r\n color = params.inPort.filledStyleColor()\r\n }\r\n\r\n let lineSize = connectionSize * params.graphScale;\r\n if (connectionColor !== undefined) {\r\n color = connectionColor;\r\n }\r\n\r\n if (params.mouseOver || params.inNode?.selected() || params.outNode?.selected()) {\r\n lineSize = mouseOverSize * params.graphScale;\r\n params.ctx.shadowBlur = 25 * params.graphScale;\r\n\r\n if (mouseOverColor !== undefined) {\r\n color = mouseOverColor;\r\n }\r\n\r\n params.ctx.shadowColor = color;\r\n }\r\n\r\n params.ctx.strokeStyle = color;\r\n params.ctx.lineWidth = lineSize;\r\n\r\n // start = input port, end = output port\r\n const inX = params.start.x;\r\n const inY = params.start.y;\r\n const outX = params.end.x;\r\n const outY = params.end.y;\r\n\r\n const overlap = outX - inX;\r\n const fullStub = BACKWARD_PORT_STUB * params.graphScale;\r\n const ramp = BACKWARD_STUB_RAMP * params.graphScale;\r\n const stub = overlap <= 0 ? 0 : fullStub * smoothstep(overlap / ramp);\r\n const curveStartX = inX - stub;\r\n const curveEndX = outX + stub;\r\n\r\n params.ctx.beginPath();\r\n params.ctx.moveTo(inX, inY);\r\n if (stub > 0) {\r\n params.ctx.lineTo(curveStartX, inY);\r\n }\r\n const midX = (curveStartX + curveEndX) / 2;\r\n params.ctx.bezierCurveTo(midX, inY, midX, outY, curveEndX, outY);\r\n if (stub > 0) {\r\n params.ctx.lineTo(outX, outY);\r\n }\r\n params.ctx.stroke();\r\n params.ctx.shadowBlur = 0;\r\n }\r\n}\r\n\r\nexport class Connection {\r\n\r\n // Variables for holding temp data, preventing object allocations each\r\n // frame\r\n #inPos: Vector2;\r\n #outPos: Vector2;\r\n\r\n #inNode: FlowNode | null;\r\n #inNodePortIndex: number;\r\n #outNode: FlowNode | null;\r\n #outNodePortIndex: number;\r\n #renderer: ConnectionRenderer;\r\n\r\n constructor(\r\n inNode: FlowNode | null,\r\n inNodePortIndex: number,\r\n outNode: FlowNode | null,\r\n outNodePortIndex: number,\r\n renderer: ConnectionRenderer,\r\n ) {\r\n\r\n this.#inNode = inNode;\r\n this.#inNodePortIndex = inNodePortIndex;\r\n this.#outNode = outNode;\r\n this.#outNodePortIndex = outNodePortIndex;\r\n this.#renderer = renderer;\r\n \r\n this.#inPos = Zero();\r\n this.#outPos = Zero();\r\n\r\n if (inNode !== null) {\r\n inNode.inputPort(this.#inNodePortIndex).addConnection(this);\r\n }\r\n\r\n if (outNode !== null) {\r\n outNode.outputPort(this.#outNodePortIndex).addConnection(this);\r\n }\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, graphScale: number, mouseOver: boolean, mousePosition: Vector2 | undefined): void {\r\n\r\n // Not sure what to do here? Maybe we should throw an error in the \r\n // future?\r\n if (this.#inNode === null && this.#outNode === null) {\r\n return;\r\n }\r\n\r\n if (this.#inNode !== null) {\r\n const inPortBox = this.#inSlotBox();\r\n if (inPortBox === undefined) {\r\n return;\r\n }\r\n BoxCenter(inPortBox, this.#inPos);\r\n } else if (mousePosition !== undefined) {\r\n this.#inPos.x = mousePosition.x;\r\n this.#inPos.y = mousePosition.y;\r\n } else {\r\n return;\r\n }\r\n\r\n if (this.#outNode !== null) {\r\n const outPortBox = this.#outNode.outputPortPosition(this.#outNodePortIndex);\r\n if (outPortBox === undefined) {\r\n return;\r\n }\r\n BoxCenter(outPortBox, this.#outPos);\r\n } else if (mousePosition !== undefined) {\r\n this.#outPos.x = mousePosition.x;\r\n this.#outPos.y = mousePosition.y;\r\n } else {\r\n return;\r\n }\r\n\r\n this.#renderer({\r\n ctx: ctx,\r\n start: this.#inPos,\r\n end: this.#outPos,\r\n graphScale: graphScale,\r\n mouseOver: mouseOver,\r\n\r\n inPort: this.inPort(),\r\n inNode: this.#inNode,\r\n outPort: this.outPort(),\r\n outNode: this.#outNode,\r\n });\r\n }\r\n\r\n inNode(): FlowNode | null {\r\n return this.#inNode;\r\n }\r\n\r\n outNode(): FlowNode | null {\r\n return this.#outNode;\r\n }\r\n\r\n clearPort(mousePosition: Vector2): void {\r\n if (this.#inNode !== null) {\r\n const inPortBox = this.#inNode.inputPortPosition(this.#inNodePortIndex)\r\n if (inPortBox !== undefined && InBox(inPortBox, mousePosition)) {\r\n this.clearInput();\r\n }\r\n }\r\n\r\n if (this.#outNode !== null) {\r\n const outPortBox = this.#outNode.outputPortPosition(this.#outNodePortIndex);\r\n if (outPortBox !== undefined && InBox(outPortBox, mousePosition)) {\r\n this.clearOutput();\r\n }\r\n }\r\n }\r\n\r\n clearPorts(): void {\r\n this.clearInput();\r\n this.clearOutput();\r\n }\r\n\r\n setInput(node: FlowNode, portIndex: number, replace?: boolean, insertAt?: number): void {\r\n this.#inNode = node;\r\n this.#inNodePortIndex = portIndex;\r\n\r\n const port = this.#inNode.inputPort(portIndex);\r\n if(!!replace && port.connections().length > 0) {\r\n port.replaceConnection(this, 0);\r\n } else {\r\n port.addConnection(this, insertAt);\r\n }\r\n }\r\n\r\n setOutput(node: FlowNode, portIndex: number): void {\r\n this.#outNode = node;\r\n this.#outNodePortIndex = portIndex;\r\n this.#outNode.outputPort(portIndex).addConnection(this);\r\n }\r\n\r\n clearInput() {\r\n this.#inNode?.inputPort(this.#inNodePortIndex).clearConnection(this);\r\n this.#inNode = null;\r\n this.#inNodePortIndex = -1;\r\n }\r\n\r\n clearOutput() {\r\n this.#outNode?.outputPort(this.#outNodePortIndex).clearConnection(this);\r\n this.#outNode = null;\r\n this.#outNodePortIndex = -1;\r\n }\r\n\r\n /**\r\n * The part of the input port this wire lands on: the whole port, or its\r\n * own slot on a port holding several wires.\r\n */\r\n #inSlotBox(): Box | undefined {\r\n if (this.#inNode === null) {\r\n return undefined;\r\n }\r\n const box = this.#inNode.inputPortPosition(this.#inNodePortIndex);\r\n const port = this.#inNode.inputPort(this.#inNodePortIndex);\r\n const slots = port.slots();\r\n if (box === undefined || slots === 1) {\r\n return box;\r\n }\r\n const index = port.connections().indexOf(this);\r\n if (index === -1) {\r\n return box;\r\n }\r\n const height = box.Size.y / slots;\r\n return {\r\n Position: { x: box.Position.x, y: box.Position.y + (index * height) },\r\n Size: { x: box.Size.x, y: height },\r\n };\r\n }\r\n\r\n mouseOverPort(mousePosition: Vector2): Port | null {\r\n if (this.#inNode !== null) {\r\n const inPortBox = this.#inSlotBox();\r\n if (inPortBox !== undefined && InBox(inPortBox, mousePosition)) {\r\n return this.#inNode.inputPort(this.#inNodePortIndex)\r\n }\r\n }\r\n\r\n if (this.#outNode !== null) {\r\n const outPortBox = this.#outNode.outputPortPosition(this.#outNodePortIndex);\r\n if (outPortBox !== undefined && InBox(outPortBox, mousePosition)) {\r\n return this.#outNode.outputPort(this.#outNodePortIndex)\r\n }\r\n }\r\n\r\n return null;\r\n }\r\n\r\n outPort(): Port | null {\r\n if (this.#outNode === null) {\r\n return null;\r\n }\r\n return this.#outNode.outputPort(this.#outNodePortIndex);\r\n }\r\n\r\n inPort(): Port | null {\r\n if (this.#inNode === null) {\r\n return null;\r\n }\r\n return this.#inNode.inputPort(this.#inNodePortIndex);\r\n }\r\n\r\n referencesNode(node: FlowNode): boolean {\r\n if (this.#inNode === node) {\r\n return true;\r\n }\r\n\r\n if (this.#outNode === node) {\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n}", "import { Vector2, Zero } from \"./types/vector2\";\r\n\r\n/** Serializable camera orientation for save/restore. */\r\nexport interface CameraOrientation {\r\n position: Vector2;\r\n zoom: number;\r\n}\r\n\r\nexport class Camera {\r\n\r\n zoom: number;\r\n\r\n position: Vector2;\r\n\r\n constructor() {\r\n this.zoom = 1;\r\n this.position = Zero();\r\n }\r\n\r\n screenSpaceToGraphSpace(screenPosition: Vector2, out: Vector2): void {\r\n const scale = this.zoom;\r\n out.x = (screenPosition.x / scale) - (this.position.x / scale);\r\n out.y = (screenPosition.y / scale) - (this.position.y / scale);\r\n }\r\n\r\n graphSpaceToScreenSpace(graphPosition: Vector2, out: Vector2): void {\r\n out.x = this.position.x + (graphPosition.x * this.zoom);\r\n out.y = this.position.y + (graphPosition.y * this.zoom);\r\n }\r\n\r\n getOrientation(): CameraOrientation {\r\n return {\r\n position: {\r\n x: this.position.x,\r\n y: this.position.y,\r\n },\r\n zoom: this.zoom,\r\n };\r\n }\r\n\r\n setOrientation(orientation: CameraOrientation): void {\r\n this.position.x = orientation.position.x;\r\n this.position.y = orientation.position.y;\r\n this.zoom = orientation.zoom;\r\n }\r\n\r\n reset(): void {\r\n this.zoom = 1;\r\n this.position.x = 0;\r\n this.position.y = 0;\r\n }\r\n}\r\n", "import { Camera } from \"./camera\";\nimport { FlowNode } from \"./node\";\nimport { NodeSubsystem } from \"./nodes/subsystem\";\nimport { Vector2 } from \"./types/vector2\";\n\nconst widthSpacing = 100;\nconst heightSpacing = 50;\nconst laneSpacing = 25;\nconst pieceSpacing = 150;\nconst orderingSweeps = 8;\nconst placementSweeps = 8;\n\nexport interface Layout {\n /** Indices into the node array, one list per layer, left to right. */\n layers: Array<Array<number>>;\n /** Which layer each node landed in, by node index. */\n layerOf: Map<number, number>;\n}\n\ntype Edges = Map<number, Array<number>>;\n\nexport function topologicalOrder(sorting: Array<number>, upstream: Edges): Array<number> {\n const visited = new Set<number>();\n const order = new Array<number>();\n\n for (const root of sorting) {\n if (visited.has(root)) {\n continue;\n }\n\n const stack: Array<{ node: number, expanded: boolean }> = [{ node: root, expanded: false }];\n while (stack.length > 0) {\n const top = stack[stack.length - 1];\n\n if (top.expanded) {\n stack.pop();\n order.push(top.node);\n continue;\n }\n\n top.expanded = true;\n if (visited.has(top.node)) {\n stack.pop();\n continue;\n }\n visited.add(top.node);\n\n for (const feeder of upstream.get(top.node) ?? []) {\n if (!visited.has(feeder)) {\n stack.push({ node: feeder, expanded: false });\n }\n }\n }\n }\n\n return order;\n}\n\nfunction consumersOf(sorting: Array<number>, upstream: Edges): Edges {\n const downstream: Edges = new Map();\n for (const node of sorting) {\n downstream.set(node, []);\n }\n for (const node of sorting) {\n for (const feeder of upstream.get(node) ?? []) {\n const consumers = downstream.get(feeder);\n if (consumers !== undefined && !consumers.includes(node)) {\n consumers.push(node);\n }\n }\n }\n return downstream;\n}\n\n/**\n * Puts every node in the layer just left of its leftmost consumer, so an\n * input sits beside what it feeds rather than at the far left. Nodes nothing\n * consumes sit just right of their feeders.\n */\nexport function assignLayers(sorting: Array<number>, upstream: Edges): Layout {\n const downstream = consumersOf(sorting, upstream);\n const order = topologicalOrder(sorting, downstream);\n const placed = new Set<number>();\n const rank = new Map<number, number>();\n\n for (const node of order) {\n let r = 0;\n for (const consumer of downstream.get(node) ?? []) {\n if (placed.has(consumer)) {\n r = Math.max(r, (rank.get(consumer) as number) + 1);\n }\n }\n rank.set(node, r);\n placed.add(node);\n }\n\n let deepest = 0;\n for (const r of rank.values()) {\n deepest = Math.max(deepest, r);\n }\n\n const layerOf = new Map<number, number>();\n for (const node of sorting) {\n layerOf.set(node, deepest - (rank.get(node) as number));\n }\n\n for (const node of sorting) {\n const layer = layerOf.get(node) as number;\n if ((downstream.get(node) ?? []).some((c) => (layerOf.get(c) as number) > layer)) {\n continue;\n }\n let pulled = -1;\n for (const feeder of upstream.get(node) ?? []) {\n const feederLayer = layerOf.get(feeder);\n if (feederLayer !== undefined && feederLayer < layer) {\n pulled = Math.max(pulled, feederLayer + 1);\n }\n }\n if (pulled >= 0) {\n layerOf.set(node, pulled);\n }\n }\n\n const used = [...new Set(layerOf.values())].sort((a, b) => a - b);\n const compact = new Map<number, number>();\n used.forEach((layer, i) => compact.set(layer, i));\n\n const layers = used.map(() => new Array<number>());\n for (const node of sorting) {\n const layer = compact.get(layerOf.get(node) as number) as number;\n layerOf.set(node, layer);\n layers[layer].push(node);\n }\n\n return { layers, layerOf };\n}\n\nfunction crossingsOf(layout: Layout, downstream: Edges): number {\n const slotOf = new Map<number, number>();\n for (const layer of layout.layers) {\n layer.forEach((node, slot) => slotOf.set(node, slot));\n }\n\n let total = 0;\n for (let i = 0; i + 1 < layout.layers.length; i++) {\n const spans = new Array<[number, number]>();\n for (const node of layout.layers[i]) {\n for (const consumer of downstream.get(node) ?? []) {\n if (layout.layerOf.get(consumer) === i + 1) {\n spans.push([slotOf.get(node) as number, slotOf.get(consumer) as number]);\n }\n }\n }\n for (let a = 0; a < spans.length; a++) {\n for (let b = a + 1; b < spans.length; b++) {\n if ((spans[a][0] - spans[b][0]) * (spans[a][1] - spans[b][1]) < 0) {\n total++;\n }\n }\n }\n }\n return total;\n}\n\n/**\n * Reorders each layer so nodes sit across from the ones they connect to,\n * sweeping back and forth and keeping whichever order crossed the fewest\n * wires.\n */\nexport function orderWithinLayers(layout: Layout, upstream: Edges, downstream: Edges): void {\n const slotOf = new Map<number, number>();\n for (const layer of layout.layers) {\n for (let i = 0; i < layer.length; i++) {\n slotOf.set(layer[i], i);\n }\n }\n\n const meanSlot = (node: number, neighbours: Edges, layer: number): number => {\n let total = 0;\n let count = 0;\n for (const neighbour of neighbours.get(node) ?? []) {\n if (layout.layerOf.get(neighbour) !== layer) {\n continue;\n }\n total += slotOf.get(neighbour) as number;\n count++;\n }\n return count === 0 ? -1 : total / count;\n };\n\n const sweep = (neighbours: Edges, towards: number): void => {\n for (let i = 0; i < layout.layers.length; i++) {\n const index = towards > 0 ? i : layout.layers.length - 1 - i;\n const adjacent = index + towards;\n if (adjacent < 0 || adjacent >= layout.layers.length) {\n continue;\n }\n\n const layer = layout.layers[index];\n const keys = new Map<number, number>();\n for (const node of layer) {\n const mean = meanSlot(node, neighbours, adjacent);\n keys.set(node, mean === -1 ? (slotOf.get(node) as number) : mean);\n }\n\n layer.sort((a, b) => (keys.get(a) as number) - (keys.get(b) as number));\n for (let s = 0; s < layer.length; s++) {\n slotOf.set(layer[s], s);\n }\n }\n };\n\n let best = layout.layers.map((layer) => layer.slice());\n let fewest = crossingsOf(layout, downstream);\n for (let i = 0; i < orderingSweeps && fewest > 0; i++) {\n sweep(upstream, -1);\n sweep(downstream, 1);\n const crossings = crossingsOf(layout, downstream);\n if (crossings < fewest) {\n fewest = crossings;\n best = layout.layers.map((layer) => layer.slice());\n }\n }\n\n for (let i = 0; i < best.length; i++) {\n layout.layers[i] = best[i];\n }\n}\n\nexport function findPieces(sorting: Array<number>, upstream: Edges, downstream: Edges): Array<Array<number>> {\n const rankOf = new Map<number, number>();\n sorting.forEach((node, i) => rankOf.set(node, i));\n\n const seen = new Set<number>();\n const pieces = new Array<Array<number>>();\n for (const start of sorting) {\n if (seen.has(start)) {\n continue;\n }\n seen.add(start);\n const piece = new Array<number>();\n const stack = [start];\n while (stack.length > 0) {\n const node = stack.pop() as number;\n piece.push(node);\n for (const neighbour of [...(upstream.get(node) ?? []), ...(downstream.get(node) ?? [])]) {\n if (rankOf.has(neighbour) && !seen.has(neighbour)) {\n seen.add(neighbour);\n stack.push(neighbour);\n }\n }\n }\n piece.sort((a, b) => (rankOf.get(a) as number) - (rankOf.get(b) as number));\n pieces.push(piece);\n }\n return pieces;\n}\n\nfunction treeRoot(piece: Array<number>, downstream: Edges): number | undefined {\n let root: number | undefined;\n for (const node of piece) {\n const consumers = downstream.get(node) ?? [];\n if (consumers.length > 1) {\n return undefined;\n }\n if (consumers.length === 0) {\n if (root !== undefined) {\n return undefined;\n }\n root = node;\n }\n }\n return root;\n}\n\nfunction columnXs(widths: Array<number>): Array<number> {\n const xs = new Array<number>();\n let x = 0;\n for (const width of widths) {\n xs.push(x);\n x += width + widthSpacing;\n }\n return xs;\n}\n\nfunction layoutTree(root: number, upstream: Edges, sizes: Map<number, Vector2>): Map<number, Vector2> {\n const children = (node: number): Array<number> => [...new Set(upstream.get(node) ?? [])];\n\n const depthOf = new Map<number, number>([[root, 0]]);\n const preorder = new Array<number>();\n const stack = [root];\n let deepest = 0;\n while (stack.length > 0) {\n const node = stack.pop() as number;\n preorder.push(node);\n const kids = children(node);\n for (let i = kids.length - 1; i >= 0; i--) {\n const depth = (depthOf.get(node) as number) + 1;\n depthOf.set(kids[i], depth);\n deepest = Math.max(deepest, depth);\n stack.push(kids[i]);\n }\n }\n\n const widths = new Array<number>(deepest + 1).fill(0);\n for (const [node, depth] of depthOf) {\n widths[deepest - depth] = Math.max(widths[deepest - depth], (sizes.get(node) as Vector2).x);\n }\n const xs = columnXs(widths);\n\n const band = new Map<number, number>();\n const topInBand = new Map<number, number>();\n const childOffset = new Map<number, number>();\n for (let i = preorder.length - 1; i >= 0; i--) {\n const node = preorder[i];\n const height = (sizes.get(node) as Vector2).y;\n const kids = children(node);\n if (kids.length === 0) {\n band.set(node, height);\n topInBand.set(node, 0);\n continue;\n }\n\n let offset = 0;\n for (const kid of kids) {\n childOffset.set(kid, offset);\n offset += (band.get(kid) as number) + heightSpacing;\n }\n const centre = (kid: number) =>\n (childOffset.get(kid) as number) + (topInBand.get(kid) as number) + (sizes.get(kid) as Vector2).y / 2;\n let top = (centre(kids[0]) + centre(kids[kids.length - 1])) / 2 - height / 2;\n let shift = 0;\n if (top < 0) {\n shift = -top;\n top = 0;\n for (const kid of kids) {\n childOffset.set(kid, (childOffset.get(kid) as number) + shift);\n }\n }\n band.set(node, Math.max(offset - heightSpacing + shift, top + height));\n topInBand.set(node, top);\n }\n\n const positions = new Map<number, Vector2>();\n const bandTop = new Map<number, number>([[root, 0]]);\n for (const node of preorder) {\n const column = deepest - (depthOf.get(node) as number);\n const size = sizes.get(node) as Vector2;\n positions.set(node, {\n x: xs[column] + (widths[column] - size.x) / 2,\n y: (bandTop.get(node) as number) + (topInBand.get(node) as number),\n });\n for (const kid of children(node)) {\n bandTop.set(kid, (bandTop.get(node) as number) + (childOffset.get(kid) as number));\n }\n }\n return positions;\n}\n\nfunction isotonic(targets: Array<number>): Array<number> {\n const blocks = new Array<{ sum: number, count: number }>();\n for (const target of targets) {\n blocks.push({ sum: target, count: 1 });\n while (blocks.length > 1) {\n const last = blocks[blocks.length - 1];\n const before = blocks[blocks.length - 2];\n if (before.sum / before.count <= last.sum / last.count) {\n break;\n }\n before.sum += last.sum;\n before.count += last.count;\n blocks.pop();\n }\n }\n const result = new Array<number>();\n for (const block of blocks) {\n for (let i = 0; i < block.count; i++) {\n result.push(block.sum / block.count);\n }\n }\n return result;\n}\n\nfunction median(values: Array<number>): number {\n const sorted = values.slice().sort((a, b) => a - b);\n const middle = Math.floor(sorted.length / 2);\n return sorted.length % 2 === 1 ? sorted[middle] : (sorted[middle - 1] + sorted[middle]) / 2;\n}\n\nfunction layoutLayered(piece: Array<number>, upstream: Edges, downstream: Edges, sizes: Map<number, Vector2>): Map<number, Vector2> {\n const layout = assignLayers(piece, upstream);\n\n const up: Edges = new Map();\n const down: Edges = new Map();\n const heightOf = new Map<number, number>();\n for (const node of piece) {\n up.set(node, [...new Set(upstream.get(node) ?? [])]);\n down.set(node, [...new Set(downstream.get(node) ?? [])]);\n heightOf.set(node, (sizes.get(node) as Vector2).y);\n }\n\n let nextLane = -1;\n for (const from of piece) {\n const fromLayer = layout.layerOf.get(from) as number;\n const consumers = down.get(from) as Array<number>;\n for (let c = 0; c < consumers.length; c++) {\n const to = consumers[c];\n const toLayer = layout.layerOf.get(to) as number;\n if (toLayer - fromLayer < 2) {\n continue;\n }\n\n let previous = from;\n for (let layer = fromLayer + 1; layer < toLayer; layer++) {\n const lane = nextLane--;\n layout.layerOf.set(lane, layer);\n layout.layers[layer].push(lane);\n heightOf.set(lane, 0);\n up.set(lane, [previous]);\n down.set(lane, []);\n if (previous === from) {\n consumers[c] = lane;\n } else {\n (down.get(previous) as Array<number>).push(lane);\n }\n previous = lane;\n }\n (down.get(previous) as Array<number>).push(to);\n const feeders = up.get(to) as Array<number>;\n feeders[feeders.indexOf(from)] = previous;\n }\n }\n\n const sequence = new Map<number, number>();\n for (const sink of piece) {\n if ((down.get(sink) as Array<number>).length > 0) {\n continue;\n }\n const stack = [sink];\n while (stack.length > 0) {\n const node = stack.pop() as number;\n if (sequence.has(node)) {\n continue;\n }\n sequence.set(node, sequence.size);\n const feeders = up.get(node) ?? [];\n for (let i = feeders.length - 1; i >= 0; i--) {\n stack.push(feeders[i]);\n }\n }\n }\n for (const layer of layout.layers) {\n layer.sort((a, b) => (sequence.get(a) ?? Infinity) - (sequence.get(b) ?? Infinity));\n }\n\n orderWithinLayers(layout, up, down);\n\n const gapAfter = (above: number, below: number): number =>\n above < 0 || below < 0 ? laneSpacing : heightSpacing;\n\n const topOf = new Map<number, number>();\n for (const layer of layout.layers) {\n let y = 0;\n for (let i = 0; i < layer.length; i++) {\n topOf.set(layer[i], y);\n y += (heightOf.get(layer[i]) as number) + (i + 1 < layer.length ? gapAfter(layer[i], layer[i + 1]) : 0);\n }\n for (const node of layer) {\n topOf.set(node, (topOf.get(node) as number) - y / 2);\n }\n }\n\n const centreOf = (node: number) => (topOf.get(node) as number) + (heightOf.get(node) as number) / 2;\n\n const place = (layer: Array<number>, neighbours: Edges, adjacent: number): void => {\n const offsets = new Array<number>();\n const targets = new Array<number>();\n let offset = 0;\n for (let i = 0; i < layer.length; i++) {\n const node = layer[i];\n const centres = (neighbours.get(node) ?? [])\n .filter((n) => layout.layerOf.get(n) === adjacent)\n .map(centreOf);\n const desired = centres.length > 0\n ? median(centres) - (heightOf.get(node) as number) / 2\n : topOf.get(node) as number;\n offsets.push(offset);\n targets.push(desired - offset);\n if (i + 1 < layer.length) {\n offset += (heightOf.get(node) as number) + gapAfter(node, layer[i + 1]);\n }\n }\n const solved = isotonic(targets);\n for (let i = 0; i < layer.length; i++) {\n topOf.set(layer[i], solved[i] + offsets[i]);\n }\n };\n\n for (let s = 0; s < placementSweeps; s++) {\n if (s % 2 === 0) {\n for (let i = 1; i < layout.layers.length; i++) {\n place(layout.layers[i], up, i - 1);\n }\n } else {\n for (let i = layout.layers.length - 2; i >= 0; i--) {\n place(layout.layers[i], down, i + 1);\n }\n }\n }\n\n const widths = layout.layers.map((layer) =>\n layer.reduce((widest, node) => node < 0 ? widest : Math.max(widest, (sizes.get(node) as Vector2).x), 0));\n const xs = columnXs(widths);\n\n const positions = new Map<number, Vector2>();\n for (const node of piece) {\n const layer = layout.layerOf.get(node) as number;\n positions.set(node, {\n x: xs[layer] + (widths[layer] - (sizes.get(node) as Vector2).x) / 2,\n y: topOf.get(node) as number,\n });\n }\n return positions;\n}\n\nfunction layoutLoose(loose: Array<number>, sizes: Map<number, Vector2>): Map<number, Vector2> {\n const columns = Math.ceil(Math.sqrt(loose.length));\n const widths = new Array<number>(columns).fill(0);\n const heights = new Array<number>(Math.ceil(loose.length / columns)).fill(0);\n loose.forEach((node, i) => {\n const size = sizes.get(node) as Vector2;\n widths[i % columns] = Math.max(widths[i % columns], size.x);\n heights[Math.floor(i / columns)] = Math.max(heights[Math.floor(i / columns)], size.y);\n });\n\n const xs = new Array<number>();\n let x = 0;\n for (const width of widths) {\n xs.push(x);\n x += width + heightSpacing;\n }\n const ys = new Array<number>();\n let y = 0;\n for (const height of heights) {\n ys.push(y);\n y += height + heightSpacing;\n }\n\n const positions = new Map<number, Vector2>();\n loose.forEach((node, i) => positions.set(node, { x: xs[i % columns], y: ys[Math.floor(i / columns)] }));\n return positions;\n}\n\ninterface Block {\n positions: Map<number, Vector2>;\n size: Vector2;\n}\n\nfunction toBlock(positions: Map<number, Vector2>, sizes: Map<number, Vector2>): Block {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n for (const [node, position] of positions) {\n const size = sizes.get(node) as Vector2;\n minX = Math.min(minX, position.x);\n minY = Math.min(minY, position.y);\n maxX = Math.max(maxX, position.x + size.x);\n maxY = Math.max(maxY, position.y + size.y);\n }\n const shifted = new Map<number, Vector2>();\n for (const [node, position] of positions) {\n shifted.set(node, { x: position.x - minX, y: position.y - minY });\n }\n return { positions: shifted, size: { x: maxX - minX, y: maxY - minY } };\n}\n\n/**\n * Lays out each connected piece on its own and packs the pieces into rows,\n * tallest first, with every unconnected node gathered into one grid at the\n * end. Positions are top-left corners, with the whole layout starting at the\n * origin.\n */\nexport function layoutGraph(\n sorting: Array<number>,\n upstream: Edges,\n downstream: Edges,\n sizes: Map<number, Vector2>,\n): Map<number, Vector2> {\n const blocks = new Array<Block>();\n const loose = new Array<number>();\n for (const piece of findPieces(sorting, upstream, downstream)) {\n if (piece.length === 1) {\n loose.push(piece[0]);\n continue;\n }\n const root = treeRoot(piece, downstream);\n const positions = root !== undefined\n ? layoutTree(root, upstream, sizes)\n : layoutLayered(piece, upstream, downstream, sizes);\n blocks.push(toBlock(positions, sizes));\n }\n\n blocks.sort((a, b) => b.size.y - a.size.y || b.size.x - a.size.x);\n if (loose.length > 0) {\n blocks.push(toBlock(layoutLoose(loose, sizes), sizes));\n }\n\n let area = 0;\n let widest = 0;\n for (const block of blocks) {\n area += (block.size.x + pieceSpacing) * (block.size.y + pieceSpacing);\n widest = Math.max(widest, block.size.x);\n }\n const rowWidth = Math.max(widest, Math.sqrt(area));\n\n const positions = new Map<number, Vector2>();\n let x = 0;\n let y = 0;\n let rowHeight = 0;\n for (const block of blocks) {\n if (x > 0 && x + block.size.x > rowWidth) {\n x = 0;\n y += rowHeight + pieceSpacing;\n rowHeight = 0;\n }\n for (const [node, position] of block.positions) {\n positions.set(node, { x: position.x + x, y: position.y + y });\n }\n x += block.size.x + pieceSpacing;\n rowHeight = Math.max(rowHeight, block.size.y);\n }\n return positions;\n}\n\nexport function Organize(ctx: CanvasRenderingContext2D, graph: NodeSubsystem, nodesToSort?: Array<number>): void {\n const nodes = graph.getNodes();\n if (nodes.length === 0) {\n return;\n }\n\n const sorting = new Array<number>();\n if (nodesToSort) {\n for (const index of nodesToSort) {\n if (index >= 0 && index < nodes.length) {\n sorting.push(index);\n }\n }\n } else {\n for (let i = 0; i < nodes.length; i++) {\n sorting.push(i);\n }\n }\n if (sorting.length < 2) {\n return;\n }\n\n const inLayout = new Set<number>(sorting);\n const nodeLUT = new Map<FlowNode, number>();\n for (let i = 0; i < nodes.length; i++) {\n nodeLUT.set(nodes[i], i);\n }\n\n const camera = new Camera();\n const sizes = new Map<number, Vector2>();\n for (const index of sorting) {\n sizes.set(index, nodes[index].calculateBounds(ctx, camera).Size);\n }\n\n const upstream: Edges = new Map();\n for (const index of sorting) {\n const node = nodes[index];\n const feeders = new Array<number>();\n for (let i = 0; i < node.inputs(); i++) {\n for (const connection of node.inputPort(i).connections()) {\n const feeder = connection.outNode();\n const feederIndex = feeder === null ? undefined : nodeLUT.get(feeder);\n if (feederIndex !== undefined && inLayout.has(feederIndex) && feederIndex !== index && !feeders.includes(feederIndex)) {\n feeders.push(feederIndex);\n }\n }\n }\n upstream.set(index, feeders);\n }\n const downstream = consumersOf(sorting, upstream);\n\n const positions = layoutGraph(sorting, upstream, downstream, sizes);\n\n const anchor: Vector2 = { x: 0, y: 0 };\n for (const index of sorting) {\n const position = nodes[index].getPosition();\n anchor.x += position.x;\n anchor.y += position.y;\n }\n anchor.x /= sorting.length;\n anchor.y /= sorting.length;\n\n let right = 0;\n let bottom = 0;\n for (const [index, position] of positions) {\n right = Math.max(right, position.x + (sizes.get(index) as Vector2).x);\n bottom = Math.max(bottom, position.y + (sizes.get(index) as Vector2).y);\n }\n\n for (const [index, position] of positions) {\n nodes[index].setPosition({ x: anchor.x - right / 2 + position.x, y: anchor.y - bottom / 2 + position.y });\n }\n}\n", "export function TimeExecution(name: string, callback: Function) {\r\n const start = name + \"_Start\";\r\n const end = name + \"_End\";\r\n\r\n performance.mark(start);\r\n callback();\r\n performance.mark(end);\r\n performance.measure(name, start, end);\r\n}", "import { ContextMenuConfig, ContextMenuItemConfig } from \"../contextMenu\";\r\nimport { FlowNode, FlowNodeConfig } from '../node';\r\nimport { Cast, PortConfig, PortType, portConfigTypes, typeSetsConnect } from \"../port\";\r\nimport { Vector2 } from \"../types/vector2\";\r\nimport { NodeSubsystem } from \"./subsystem\";\r\n\r\n/**\r\n * Narrows a \"new node\" menu to the nodes that could actually be wired to a\r\n * particular port.\r\n */\r\nexport interface NodeMenuFilter {\r\n /** Which side the new node has to offer. */\r\n needs: PortType;\r\n\r\n /** Types that side has to accept. An empty list takes anything. */\r\n types: Array<string>;\r\n\r\n casts?: Array<Cast>;\r\n\r\n onCreated?: (node: FlowNode) => void;\r\n}\r\n\r\nfunction offersMatchingPort(config: FlowNodeConfig, filter: NodeMenuFilter): boolean {\r\n if (filter.needs === PortType.Input) {\r\n return (config.inputs ?? []).some((port) => typeSetsConnect(filter.types, portConfigTypes(port), filter.casts));\r\n }\r\n return (config.outputs ?? []).some((port) => typeSetsConnect(portConfigTypes(port), filter.types, filter.casts));\r\n}\r\n\r\ninterface PublisherNodes {\r\n [name: string]: FlowNodeConfig\r\n}\r\n\r\nexport interface PublisherConfig {\r\n name?: string;\r\n description?: string;\r\n version?: string;\r\n nodes?: PublisherNodes\r\n}\r\n\r\nexport class Publisher {\r\n\r\n #name: string;\r\n\r\n #description: string;\r\n\r\n #version: string;\r\n\r\n #registeredNodes: Map<string, FlowNodeConfig>\r\n\r\n constructor(config?: PublisherConfig) {\r\n this.#name = config?.name === undefined ? \"Unknown\" : config.name;\r\n this.#description = config?.description === undefined ? \"\" : config.description;\r\n this.#version = config?.version === undefined ? \"v0.0.0\" : config.version;\r\n\r\n this.#registeredNodes = new Map<string, FlowNodeConfig>();\r\n\r\n if (config?.nodes !== undefined) {\r\n for (const nodeKey in config.nodes) {\r\n this.register(nodeKey, config.nodes[nodeKey]);\r\n }\r\n }\r\n }\r\n\r\n nodes(): Map<string, FlowNodeConfig> {\r\n return this.#registeredNodes;\r\n }\r\n\r\n register(nodeType: string, config: FlowNodeConfig): void {\r\n this.#registeredNodes.set(nodeType, config);\r\n }\r\n\r\n unregister(nodeType: string): boolean {\r\n return this.#registeredNodes.delete(nodeType);\r\n }\r\n\r\n #recurseBuildMenu(graph: NodeSubsystem, name: string, subMenu: Map<string, FlowNodeConfig>, position: Vector2, filter?: NodeMenuFilter): ContextMenuConfig {\r\n const items: Array<ContextMenuItemConfig> = [];\r\n const subMenus = new Map<string, Map<string, FlowNodeConfig>>();\r\n\r\n for (let [key, nodeConfig] of subMenu) {\r\n const slashIndex = key.indexOf(\"/\")\r\n const bracketIndex = key.indexOf(\"[\")\r\n\r\n if (slashIndex === -1 || (bracketIndex !== -1 && bracketIndex < slashIndex)) {\r\n if (filter !== undefined && !offersMatchingPort(nodeConfig, filter)) {\r\n continue;\r\n }\r\n\r\n items.push({\r\n name: key,\r\n callback: () => {\r\n const node = new FlowNode(nodeConfig);\r\n node.setPosition(position);\r\n graph.addNode(node);\r\n filter?.onCreated?.(node);\r\n },\r\n });\r\n } else {\r\n const elements = key.split(\"/\");\r\n if (!subMenus.has(elements[0])) {\r\n subMenus.set(elements[0], new Map<string, FlowNodeConfig>());\r\n }\r\n\r\n const menu = subMenus.get(elements[0]);\r\n elements.shift();\r\n menu?.set(elements.join(\"/\"), nodeConfig)\r\n }\r\n }\r\n\r\n const menus: Array<ContextMenuConfig> = [];\r\n for (let [key, nodes] of subMenus) {\r\n const built = this.#recurseBuildMenu(graph, key, nodes, position, filter);\r\n if (filter !== undefined && built.items?.length === 0 && built.subMenus?.length === 0) {\r\n continue;\r\n }\r\n menus.push(built);\r\n }\r\n\r\n return {\r\n name: name,\r\n items: items,\r\n subMenus: menus\r\n }\r\n }\r\n\r\n contextMenu(graph: NodeSubsystem, position: Vector2, filter?: NodeMenuFilter): ContextMenuConfig {\r\n return this.#recurseBuildMenu(graph, this.#name, this.#registeredNodes, position, filter);\r\n }\r\n\r\n create(nodeType: string): FlowNode {\r\n const config = this.#registeredNodes.get(nodeType)\r\n if (config === undefined) {\r\n throw new Error(\"no builder registered for node: \" + nodeType);\r\n }\r\n return new FlowNode(config);\r\n }\r\n}", "import { FlowNode } from \"../node\";\r\nimport { NodeMenuFilter, Publisher, PublisherConfig } from \"./publisher\";\r\nimport { ContextMenuConfig } from \"../contextMenu\";\r\nimport { Vector2 } from \"../types/vector2\";\r\nimport { nodeFlowGroup as nodeFlowContextMenuGroup, NodeSubsystem } from \"./subsystem\";\r\n\r\nexport type NodeCreatedCallback = (publisher: string, nodeType: string, node: FlowNode) => void;\r\n\r\ninterface NodeFactoryPublishers {\r\n [name: string]: PublisherConfig\r\n}\r\n\r\nexport interface NodeFactoryConfig {\r\n publishers?: NodeFactoryPublishers\r\n onNodeCreated?: NodeCreatedCallback;\r\n}\r\n\r\nexport class NodeFactory {\r\n #registeredPublishers: Map<string, Publisher>;\r\n\r\n #registeredCallbacks: Array<NodeCreatedCallback>;\r\n\r\n constructor(config?: NodeFactoryConfig) {\r\n this.#registeredPublishers = new Map<string, Publisher>();\r\n this.#registeredCallbacks = new Array<NodeCreatedCallback>();\r\n\r\n if (config?.onNodeCreated) {\r\n this.#registeredCallbacks.push(config?.onNodeCreated);\r\n }\r\n\r\n if (config?.publishers !== undefined) {\r\n for (let entry in config.publishers) {\r\n this.addPublisher(entry, new Publisher(config.publishers[entry]));\r\n }\r\n }\r\n }\r\n\r\n public addOnNodeCreatedListener(callback: NodeCreatedCallback): void {\r\n this.#registeredCallbacks.push(callback);\r\n }\r\n\r\n public addPublisher(identifier: string, publisher: Publisher): void {\r\n this.#registeredPublishers.set(identifier, publisher);\r\n }\r\n\r\n // I'm not even sure if I want this here? You can register on Publishers...\r\n // So why not just make people register with the publisher.\r\n // public register(publisher: string, nodeType: string, config: FlowNodeConfiguration): void {\r\n // const foundPublisher = this.#registeredPublishers.get(publisher);\r\n // if (foundPublisher === undefined) {\r\n // console.error(\"no publisher registered with identifier:\" + publisher);\r\n // return;\r\n // }\r\n\r\n // foundPublisher.register(nodeType, config);\r\n // }\r\n\r\n public create(publisher: string, nodeType: string): FlowNode {\r\n const publisherIdentifier = this.#registeredPublishers.get(publisher)\r\n if (publisherIdentifier === undefined) {\r\n throw new Error(\"no publisher registered with identifier: \" + publisher);\r\n }\r\n const node = publisherIdentifier.create(nodeType);\r\n\r\n for (let i = 0; i < this.#registeredCallbacks.length; i++) {\r\n const callback = this.#registeredCallbacks[i];\r\n callback(publisher, nodeType, node);\r\n }\r\n return node;\r\n }\r\n\r\n public newNodeSubmenus(graph: NodeSubsystem, position: Vector2, filter?: NodeMenuFilter): Array<ContextMenuConfig> {\r\n const menus: Array<ContextMenuConfig> = [];\r\n for (let [_, publisher] of this.#registeredPublishers) {\r\n const built = publisher.contextMenu(graph, position, filter);\r\n if (filter !== undefined && built.items?.length === 0 && built.subMenus?.length === 0) {\r\n continue;\r\n }\r\n menus.push(built);\r\n }\r\n return menus;\r\n }\r\n\r\n public openMenu(graph: NodeSubsystem, position: Vector2, filter?: NodeMenuFilter): ContextMenuConfig {\r\n return {\r\n name: \"New Node\",\r\n group: nodeFlowContextMenuGroup,\r\n subMenus: this.newNodeSubmenus(graph, position, filter),\r\n };\r\n }\r\n} \r\n", "import { Camera } from \"../camera\";\r\nimport { Connection, ConnectionRenderer, DefaultConnectionRenderer } from \"../connection\";\r\nimport { CombineContextMenus, ContextMenuConfig } from \"../contextMenu\";\r\nimport { RenderResults } from \"../graphSubsystem\";\r\nimport { FlowNode, NodeState } from \"../node\";\r\nimport { Organize } from \"../organize\";\r\nimport { PassSubsystem } from \"../pass/subsystem\";\r\nimport { TimeExecution } from \"../performance\";\r\nimport { arrayInsertIndex, Cast, Port, PortType, portsConnect } from \"../port\";\r\nimport { requestRender } from \"../render_scheduler\";\r\nimport { BoxStyle } from \"../styles/box\";\r\nimport { CursorStyle } from \"../styles/cursor\";\r\nimport { Theme } from \"../theme\";\r\nimport { Box, BoxIntersection, InBox } from \"../types/box\";\r\nimport { List } from \"../types/list\";\r\nimport { Pool, VectorPool } from \"../types/pool\";\r\nimport { AddVector2, CopyVector2, SubVector2, Vector2, Zero } from \"../types/vector2\";\r\nimport { Widget, WidgetPointer } from \"../widgets/widget\";\r\nimport { NodeCreatedCallback, NodeFactory, NodeFactoryConfig } from \"./factory\";\r\nimport { Publisher } from \"./publisher\";\r\n\r\nexport type NodeAddedCallback = (node: FlowNode) => void;\r\nexport type NodeRemovedCallback = (node: FlowNode) => void;\r\nexport type NodeHoverCallback = (node: FlowNode | null) => void;\r\n\r\nexport const nodeFlowGroup = \"node-flow-graph-node-menu\";\r\n\r\n/**\r\n * A connection between two nodes of a copied set, by their position in that\r\n * set rather than by node, so it can be rebuilt against the copies.\r\n */\r\nexport interface InternalConnection {\r\n fromNode: number;\r\n fromPort: number;\r\n toNode: number;\r\n toPort: number;\r\n}\r\n\r\n/**\r\n * A connection that was dragged out and dropped on empty canvas. Describes\r\n * what a node would have to offer to finish it, and joins the two up once\r\n * one has been made.\r\n */\r\nexport interface DanglingConnection {\r\n /** The side the new node has to offer. */\r\n needs: PortType;\r\n\r\n /** The types that side has to accept. Empty takes anything. */\r\n types: Array<string>;\r\n\r\n /** Wires the new node to the port the drag started from. */\r\n connectTo: (node: FlowNode) => void;\r\n}\r\n\r\nexport interface ConnectionRendererConfiguration {\r\n size?: number;\r\n color?: string;\r\n\r\n mouseOverSize?: number;\r\n mouseOverColor?: string;\r\n\r\n renderer?: ConnectionRenderer;\r\n}\r\n\r\nfunction BuildConnectionRenderer(config: ConnectionRendererConfiguration | undefined): ConnectionRenderer {\r\n if (config?.renderer !== undefined) {\r\n return config.renderer;\r\n }\r\n\r\n return DefaultConnectionRenderer(\r\n config?.size === undefined ? 2 : config.size,\r\n undefined, // config?.color === undefined ? \"#00FF00\" : config.color,\r\n config?.mouseOverSize === undefined ? 4 : config.mouseOverSize,\r\n undefined, // config?.mouseOverColor === undefined ? \"#00FF22\" : config.mouseOverColor\r\n );\r\n}\r\n\r\ninterface PortIntersection {\r\n Node: FlowNode;\r\n Port: Port;\r\n Index: number;\r\n InputPort: boolean;\r\n}\r\n\r\ninterface NodeSubsystemConfig {\r\n idleConnection?: ConnectionRendererConfiguration\r\n nodes?: NodeFactoryConfig\r\n casts?: Array<Cast>\r\n}\r\n\r\nexport class NodeSubsystem {\r\n\r\n #postProcessPass: PassSubsystem;\r\n\r\n #nodes: Array<FlowNode>;\r\n\r\n #connections: Array<Connection>;\r\n\r\n #nodeHovering: number;\r\n\r\n #nodesGrabbed: List<number>;\r\n\r\n #connectionSelected: Connection | null;\r\n\r\n #idleConnectionRenderer: ConnectionRenderer\r\n\r\n #portHovering: PortIntersection | null;\r\n\r\n #widgetHovering: Widget | null;\r\n\r\n #widgetCurrentlyClicking: Widget | null;\r\n\r\n #widgetHoveringBox: Box | null = null;\r\n\r\n #capturedWidgetBox: Box | null = null;\r\n\r\n #capturedPointer: Vector2 = Zero();\r\n\r\n #cursor: CursorStyle;\r\n\r\n #nodeFactory: NodeFactory;\r\n\r\n #boxSelect: boolean;\r\n\r\n #boxSelectStart_graphSpace: Vector2;\r\n\r\n #boxSelectEnd_graphSpace: Vector2;\r\n\r\n #boxSelectionNodes: List<number>;\r\n\r\n #casts: Array<Cast>;\r\n\r\n #lastCtx: CanvasRenderingContext2D | null;\r\n\r\n #lastMousePosition: Vector2 | undefined;\r\n\r\n // LISTENERS ==============================================================\r\n\r\n #nodeRemovedCallbacks: Array<NodeRemovedCallback>;\r\n\r\n #registeredNodeAddedCallbacks: Array<NodeAddedCallback>;\r\n\r\n #nodeHoverCallbacks = new Array<NodeHoverCallback>();\r\n\r\n #hoveredNode: FlowNode | null = null;\r\n\r\n // ========================================================================\r\n\r\n constructor(postProcessPass: PassSubsystem, config?: NodeSubsystemConfig) {\r\n this.#postProcessPass = postProcessPass;\r\n this.#nodes = [];\r\n this.#nodeHovering = -1;\r\n this.#nodesGrabbed = new List<number>();\r\n this.#connectionSelected = null;\r\n this.#portHovering = null;\r\n this.#widgetHovering = null;\r\n this.#widgetCurrentlyClicking = null;\r\n this.#connections = new Array<Connection>();\r\n this.#nodeFactory = new NodeFactory(config?.nodes);\r\n this.#idleConnectionRenderer = BuildConnectionRenderer(config?.idleConnection);\r\n this.#registeredNodeAddedCallbacks = new Array<NodeAddedCallback>();\r\n this.#nodeRemovedCallbacks = new Array<NodeRemovedCallback>();\r\n this.#cursor = CursorStyle.Default;\r\n\r\n this.#boxSelect = false;\r\n this.#boxSelectStart_graphSpace = Zero();\r\n this.#boxSelectEnd_graphSpace = Zero();\r\n this.#boxSelectionNodes = new List<number>();\r\n this.#lastCtx = null;\r\n this.#casts = config?.casts ?? [];\r\n }\r\n\r\n public setCasts(casts: Array<Cast>): void {\r\n this.#casts = casts;\r\n }\r\n\r\n public casts(): Array<Cast> {\r\n return this.#casts;\r\n }\r\n\r\n public addPublisher(identifier: string, publisher: Publisher): void {\r\n this.#nodeFactory.addPublisher(identifier, publisher);\r\n }\r\n\r\n public addOnNodeCreatedListener(callback: NodeCreatedCallback): void {\r\n this.#nodeFactory.addOnNodeCreatedListener(callback);\r\n }\r\n\r\n public nodeFactory(): NodeFactory {\r\n return this.#nodeFactory;\r\n }\r\n\r\n public addOnNodeAddedListener(callback: NodeAddedCallback): void {\r\n if (callback === null || callback === undefined) {\r\n return;\r\n }\r\n this.#registeredNodeAddedCallbacks.push(callback);\r\n }\r\n\r\n public addOnNodeRemovedListener(callback: NodeRemovedCallback): void {\r\n if (callback === null || callback === undefined) {\r\n return;\r\n }\r\n this.#nodeRemovedCallbacks.push(callback);\r\n }\r\n\r\n public addNodeHoverListener(callback: NodeHoverCallback): void {\r\n this.#nodeHoverCallbacks.push(callback);\r\n }\r\n\r\n #setHoveredNode(node: FlowNode | null): void {\r\n if (this.#hoveredNode === node) {\r\n return;\r\n }\r\n this.#hoveredNode = node;\r\n for (let i = 0; i < this.#nodeHoverCallbacks.length; i++) {\r\n this.#nodeHoverCallbacks[i](node);\r\n }\r\n }\r\n\r\n clickStart(mousePosition: Vector2, camera: Camera, ctrlKey: boolean): boolean {\r\n this.#boxSelect = false;\r\n this.#nodesGrabbed.Clear();\r\n\r\n // Touch has no continuous hover \u2014 hit-test at the click position.\r\n if (this.#lastCtx !== null) {\r\n this.#portHovering = null;\r\n this.#widgetHovering = null;\r\n this.#nodeHovering = -1;\r\n for (let i = 0; i < this.#nodes.length; i++) {\r\n const intersection = this.#nodes[i].inBounds(this.#lastCtx, camera, mousePosition);\r\n if (intersection.Node !== undefined && intersection.PortIndex === undefined && intersection.Widget === undefined) {\r\n this.#nodeHovering = i;\r\n }\r\n if (intersection.Widget !== undefined) {\r\n this.#widgetHovering = intersection.Widget;\r\n this.#widgetHoveringBox = intersection.WidgetBox ?? null;\r\n }\r\n if (intersection.Port !== undefined && intersection.Node !== undefined && intersection.PortIndex !== undefined && intersection.PortIsInput !== undefined) {\r\n this.#portHovering = {\r\n Index: intersection.PortIndex,\r\n Node: intersection.Node,\r\n Port: intersection.Port,\r\n InputPort: intersection.PortIsInput\r\n };\r\n }\r\n }\r\n }\r\n\r\n let hoveringSomething = false;\r\n if (this.#nodeHovering > -1) {\r\n this.#selectNodeByIndex(this.#nodeHovering, !ctrlKey);\r\n\r\n for (let i = 0; i < this.#nodes.length; i++) {\r\n if (this.#nodes[i].selected()) {\r\n this.#nodesGrabbed.Push(i);\r\n }\r\n }\r\n\r\n hoveringSomething = true;\r\n }\r\n\r\n if (this.#widgetHovering !== null) {\r\n if (!this.#widgetHovering.Disabled?.()) {\r\n this.#widgetCurrentlyClicking = this.#widgetHovering;\r\n this.#capturedWidgetBox = this.#widgetHoveringBox === null ? null : {\r\n Position: { x: this.#widgetHoveringBox.Position.x, y: this.#widgetHoveringBox.Position.y },\r\n Size: { x: this.#widgetHoveringBox.Size.x, y: this.#widgetHoveringBox.Size.y },\r\n };\r\n CopyVector2(this.#capturedPointer, mousePosition);\r\n this.#widgetCurrentlyClicking.PointerDown?.(this.#widgetPointer());\r\n }\r\n hoveringSomething = true;\r\n }\r\n\r\n if (this.#portHovering === null) {\r\n\r\n if (ctrlKey && !hoveringSomething) {\r\n camera.screenSpaceToGraphSpace(mousePosition, this.#boxSelectStart_graphSpace)\r\n CopyVector2(this.#boxSelectEnd_graphSpace, this.#boxSelectStart_graphSpace);\r\n this.#boxSelect = true;\r\n }\r\n\r\n if (!hoveringSomething && !ctrlKey) {\r\n this.unselectAllNodes();\r\n }\r\n\r\n return hoveringSomething || ctrlKey;\r\n }\r\n\r\n if (this.#portHovering.InputPort) {\r\n const port = this.#portHovering.Port;\r\n const wires = port.connections();\r\n const picked = wires.find((wire) => wire.mouseOverPort(mousePosition) === port) ?? wires[0];\r\n if (picked !== undefined) {\r\n picked.clearInput();\r\n this.#connectionSelected = picked;\r\n }\r\n } else {\r\n let inNode: FlowNode | null = this.#portHovering.Node\r\n let inNodeIndex = this.#portHovering.Index\r\n let outNode: FlowNode | null = this.#portHovering.Node\r\n let outNodeIndex = this.#portHovering.Index\r\n\r\n if (this.#portHovering.InputPort) {\r\n outNode = null;\r\n outNodeIndex = -1;\r\n } else {\r\n inNode = null;\r\n inNodeIndex = -1;\r\n }\r\n\r\n const connection = new Connection(inNode, inNodeIndex, outNode, outNodeIndex, this.#idleConnectionRenderer);\r\n this.#connectionSelected = connection;\r\n this.#connections.push(connection);\r\n }\r\n\r\n return true;\r\n }\r\n\r\n #widgetPointer(): WidgetPointer {\r\n return {\r\n position: { x: this.#capturedPointer.x, y: this.#capturedPointer.y },\r\n inside: this.#capturedWidgetBox !== null && InBox(this.#capturedWidgetBox, this.#capturedPointer),\r\n };\r\n }\r\n\r\n mouseDragEvent(delta: Vector2, scale: number): boolean {\r\n if (this.#widgetCurrentlyClicking !== null) {\r\n this.#capturedPointer.x += delta.x;\r\n this.#capturedPointer.y += delta.y;\r\n this.#widgetCurrentlyClicking.PointerMove?.(this.#widgetPointer());\r\n return true;\r\n }\r\n\r\n let nodeMoved = false;\r\n\r\n VectorPool.run(() => {\r\n const scaledDelta = VectorPool.get();\r\n scaledDelta.x = delta.x / scale;\r\n scaledDelta.y = delta.y / scale;\r\n AddVector2(this.#boxSelectEnd_graphSpace, this.#boxSelectEnd_graphSpace, scaledDelta);\r\n\r\n if (this.#interactingWithNode()) {\r\n for (let i = 0; i < this.#nodesGrabbed.Count(); i++) {\r\n const node = this.#nodes[this.#nodesGrabbed.At(i)];\r\n if (node.locked()) {\r\n continue;\r\n }\r\n node.translate(scaledDelta);\r\n nodeMoved = true;\r\n }\r\n }\r\n });\r\n\r\n if (nodeMoved) {\r\n return true;\r\n }\r\n return this.#interactingWithConnection() || this.#interactingWithWidget() || this.#boxSelect;\r\n }\r\n\r\n clearNodeInputConnection(node: FlowNode, index: number): void {\r\n const port = node.inputPort(index);\r\n for (let i = this.#connections.length - 1; i >= 0; i--) {\r\n if (this.#connections[i].inPort() === port) {\r\n this.#removeConnection(this.#connections[i], true);\r\n }\r\n }\r\n }\r\n\r\n public connectionsWithin(nodes: Array<FlowNode>): Array<InternalConnection> {\r\n const within: Array<InternalConnection> = [];\r\n\r\n for (const connection of this.#connections) {\r\n const outNode = connection.outNode();\r\n const inNode = connection.inNode();\r\n if (outNode === null || inNode === null) {\r\n continue;\r\n }\r\n\r\n const from = nodes.indexOf(outNode);\r\n const to = nodes.indexOf(inNode);\r\n if (from === -1 || to === -1) {\r\n continue;\r\n }\r\n\r\n const outPort = connection.outPort();\r\n const inPort = connection.inPort();\r\n if (outPort === null || inPort === null) {\r\n continue;\r\n }\r\n\r\n within.push({\r\n fromNode: from,\r\n fromPort: this.#outputPortIndex(outNode, outPort),\r\n toNode: to,\r\n toPort: this.#inputPortIndex(inNode, inPort),\r\n });\r\n }\r\n\r\n return within;\r\n }\r\n\r\n #onConnectionReleased: ((dangling: DanglingConnection) => void) | null = null;\r\n\r\n public setConnectionReleasedHandler(handler: (dangling: DanglingConnection) => void): void {\r\n this.#onConnectionReleased = handler;\r\n }\r\n\r\n #describeDanglingConnection(conn: Connection): DanglingConnection | null {\r\n const outNode = conn.outNode();\r\n const inNode = conn.inNode();\r\n\r\n // Dragged from an output, so the new node supplies the input.\r\n if (outNode !== null && inNode === null) {\r\n const from = conn.outPort();\r\n if (from === null) {\r\n return null;\r\n }\r\n const fromIndex = this.#outputPortIndex(outNode, from);\r\n return {\r\n needs: PortType.Input,\r\n types: from.acceptedTypes(),\r\n connectTo: (node) => {\r\n const to = this.#firstCompatiblePort(node, PortType.Input, from);\r\n if (to !== -1 && fromIndex !== -1) {\r\n this.connectNodes(outNode, fromIndex, node, to);\r\n }\r\n },\r\n };\r\n }\r\n\r\n // Dragged from an input, so the new node supplies the output.\r\n if (inNode !== null && outNode === null) {\r\n const to = conn.inPort();\r\n if (to === null) {\r\n return null;\r\n }\r\n const toIndex = this.#inputPortIndex(inNode, to);\r\n return {\r\n needs: PortType.Output,\r\n types: to.acceptedTypes(),\r\n connectTo: (node) => {\r\n const from = this.#firstCompatiblePort(node, PortType.Output, to);\r\n if (from !== -1 && toIndex !== -1) {\r\n this.connectNodes(node, from, inNode, toIndex);\r\n }\r\n },\r\n };\r\n }\r\n\r\n return null;\r\n }\r\n\r\n #outputPortIndex(node: FlowNode, port: Port): number {\r\n for (let i = 0; i < node.outputs(); i++) {\r\n if (node.outputPort(i) === port) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n }\r\n\r\n #inputPortIndex(node: FlowNode, port: Port): number {\r\n for (let i = 0; i < node.inputs(); i++) {\r\n if (node.inputPort(i) === port) {\r\n return i;\r\n }\r\n }\r\n return -1;\r\n }\r\n\r\n #firstCompatiblePort(node: FlowNode, side: PortType, against: Port): number {\r\n const count = side === PortType.Input ? node.inputs() : node.outputs();\r\n let firstHidden = -1;\r\n for (let i = 0; i < count; i++) {\r\n const port = side === PortType.Input ? node.inputPort(i) : node.outputPort(i);\r\n const compatible = side === PortType.Input\r\n ? portsConnect(against, port, this.#casts)\r\n : portsConnect(port, against, this.#casts);\r\n if (!compatible) {\r\n continue;\r\n }\r\n if (!port.hidden()) {\r\n return i;\r\n }\r\n if (firstHidden === -1) {\r\n firstHidden = i;\r\n }\r\n }\r\n return firstHidden;\r\n }\r\n\r\n clickEnd(): void {\r\n\r\n for (let i = 0; i < this.#nodesGrabbed.Count(); i++) {\r\n const node = this.#nodes[this.#nodesGrabbed.At(i)];\r\n node.raiseDragStoppedEvent();\r\n }\r\n this.#nodesGrabbed.Clear();\r\n\r\n if (this.#boxSelect) {\r\n for (let i = 0; i < this.#boxSelectionNodes.Count(); i++) {\r\n this.#selectNode(this.#nodes[this.#boxSelectionNodes.At(i)], false);\r\n }\r\n\r\n this.#boxSelectionNodes.Clear();\r\n this.#boxSelect = false;\r\n }\r\n\r\n if (this.#widgetCurrentlyClicking !== null) {\r\n const widget = this.#widgetCurrentlyClicking;\r\n const pointer = this.#widgetPointer();\r\n this.#widgetCurrentlyClicking = null;\r\n this.#capturedWidgetBox = null;\r\n widget.PointerUp?.(pointer);\r\n }\r\n\r\n if (this.#connectionSelected === null) {\r\n return;\r\n }\r\n\r\n if (this.#portHovering === null) {\r\n const dangling = this.#describeDanglingConnection(this.#connectionSelected);\r\n this.#clearCurrentlySelectedConnection();\r\n if (dangling !== null) {\r\n this.#onConnectionReleased?.(dangling);\r\n }\r\n return;\r\n }\r\n\r\n const port = this.#portHovering.Port;\r\n const conn = this.#connectionSelected;\r\n\r\n // If the port we're hovering is the one we started the connection \r\n // with...\r\n if (port === conn.inPort() || port === conn.outPort()) {\r\n this.#clearCurrentlySelectedConnection();\r\n return;\r\n }\r\n\r\n // If the port we're hoving is input, and also we started the \r\n // connection with an input, we can't do anything. We can't connect\r\n // input to input\r\n if (this.#portHovering.InputPort && conn.inPort() !== null) {\r\n this.#clearCurrentlySelectedConnection();\r\n return;\r\n }\r\n\r\n // Same with out. Can't connect output to output\r\n if (!this.#portHovering.InputPort && conn.outPort() !== null) {\r\n this.#clearCurrentlySelectedConnection();\r\n return;\r\n }\r\n\r\n // Different types, can't connect\r\n if (this.#portHovering.InputPort && !portsConnect(conn.outPort(), this.#portHovering.Port, this.#casts)) {\r\n this.#clearCurrentlySelectedConnection();\r\n return;\r\n }\r\n\r\n // Different types, can't connect\r\n if (!this.#portHovering.InputPort && !portsConnect(this.#portHovering.Port, conn.inPort(), this.#casts)) {\r\n this.#clearCurrentlySelectedConnection();\r\n return;\r\n }\r\n\r\n // Ight. Let's make the connection.\r\n if (this.#portHovering.InputPort) {\r\n let replace = false;\r\n const inputPort = this.#portHovering.Node.inputPort(this.#portHovering.Index);\r\n if (this.#portHovering.Port.getPortType() !== PortType.InputArray && inputPort.connections().length > 0) {\r\n replace = true;\r\n }\r\n\r\n if (replace) {\r\n // Remove input port's connection's output\r\n inputPort.connections()[0].clearOutput();\r\n\r\n // Remove connection from this subsystem\r\n this.#removeConnection(inputPort.connections()[0], false);\r\n }\r\n conn.setInput(this.#portHovering.Node, this.#portHovering.Index, replace, this.#insertIndex());\r\n\r\n } else {\r\n conn.setOutput(this.#portHovering.Node, this.#portHovering.Index);\r\n }\r\n\r\n this.#connectionSelected = null;\r\n }\r\n\r\n connectNodes(nodeOut: FlowNode, outPort: number, nodeIn: FlowNode, inPort: number): Connection | undefined {\r\n const from = nodeOut.outputPort(outPort);\r\n const to = nodeIn.inputPort(inPort);\r\n if (!portsConnect(from, to, this.#casts)) {\r\n console.error(\"can't connect nodes of different types\", from.getDataType(), to.getDataType());\r\n return;\r\n }\r\n\r\n // Check and make sure the nodes aren't already connected\r\n const existingInputConnections = nodeIn.inputPort(inPort).connections();\r\n for (let i = 0; i < existingInputConnections.length; i++) {\r\n const connection = existingInputConnections[i];\r\n\r\n\r\n if (connection.outNode() !== nodeOut) {\r\n continue;\r\n }\r\n\r\n if (connection.outPort() !== nodeOut.outputPort(outPort)) {\r\n continue;\r\n }\r\n\r\n // This kind of connection already *exists*. Let's not add a duplicate\r\n return;\r\n }\r\n\r\n const connection = new Connection(\r\n nodeIn, inPort,\r\n nodeOut, outPort,\r\n this.#idleConnectionRenderer,\r\n );\r\n this.#connections.push(connection);\r\n requestRender();\r\n return connection;\r\n }\r\n\r\n getNodes(): Array<FlowNode> {\r\n return this.#nodes;\r\n }\r\n\r\n /**\r\n * Returns currently selected nodes in stable graph order (same selection\r\n * state used by Ctrl+click and box-select styling via FlowNode.selected()).\r\n */\r\n getSelectedNodes(): Array<FlowNode> {\r\n const selected = new Array<FlowNode>();\r\n for (let i = 0; i < this.#nodes.length; i++) {\r\n if (this.#nodes[i].selected()) {\r\n selected.push(this.#nodes[i]);\r\n }\r\n }\r\n return selected;\r\n }\r\n\r\n /**\r\n * Returns all nodes who are connected to the inputs of the \r\n * node in question\r\n * \r\n * @param nodeIndex index of the node to examine inputs to\r\n */\r\n connectedInputsNodeReferencesByIndex(nodeIndex: number): Array<FlowNode> {\r\n return this.connectedInputsNodeReferences(this.#nodes[nodeIndex]);\r\n }\r\n\r\n connectedInputsNodeReferences(node: FlowNode): Array<FlowNode> {\r\n const connections = new Array<FlowNode>();\r\n for (let i = 0; i < this.#connections.length; i++) {\r\n const connection = this.#connections[i];\r\n if (node !== connection.inNode()) {\r\n continue;\r\n }\r\n\r\n const outNode = connection.outNode();\r\n if (outNode === null) {\r\n continue;\r\n }\r\n\r\n connections.push(outNode);\r\n }\r\n return connections;\r\n }\r\n\r\n connectedOutputsNodeReferences(nodeIndex: number): Array<FlowNode> {\r\n const node = this.#nodes[nodeIndex]\r\n const connections = new Array<FlowNode>();\r\n for (let i = 0; i < this.#connections.length; i++) {\r\n const connection = this.#connections[i];\r\n if (node !== connection.outNode()) {\r\n continue;\r\n }\r\n\r\n const inNode = connection.inNode();\r\n if (inNode === null) {\r\n continue;\r\n }\r\n\r\n connections.push(inNode);\r\n }\r\n return connections;\r\n }\r\n\r\n addNode(node: FlowNode): void {\r\n this.#nodes.push(node);\r\n requestRender();\r\n for (let i = 0; i < this.#registeredNodeAddedCallbacks.length; i++) {\r\n const callback = this.#registeredNodeAddedCallbacks[i];\r\n if (!callback) {\r\n continue;\r\n }\r\n callback(node);\r\n }\r\n }\r\n\r\n fileDrop(file: File): boolean {\r\n if (this.#nodeHovering === -1) {\r\n return false;\r\n }\r\n this.#nodes[this.#nodeHovering].dropFile(file);\r\n return true;\r\n }\r\n\r\n #removeNodeConnections(nodeIndex: number): void {\r\n if (nodeIndex >= this.#nodes.length || nodeIndex < 0) {\r\n console.error(\"invalid node connection\");\r\n return;\r\n }\r\n for (let i = this.#connections.length - 1; i >= 0; i--) {\r\n if (this.#connections[i].referencesNode(this.#nodes[nodeIndex])) {\r\n this.#removeConnectionByIndex(i, true);\r\n }\r\n }\r\n }\r\n\r\n #interactingWithNode(): boolean {\r\n return this.#nodesGrabbed.Count() > 0;\r\n }\r\n\r\n #interactingWithConnection(): boolean {\r\n return this.#connectionSelected !== null;\r\n }\r\n\r\n #interactingWithWidget(): boolean {\r\n return this.#widgetCurrentlyClicking !== null;\r\n }\r\n\r\n removeNode(node: FlowNode): void {\r\n for (let i = 0; i < this.#nodes.length; i++) {\r\n if (this.#nodes[i] === node) {\r\n this.#removeNodeByIndex(i);\r\n }\r\n }\r\n }\r\n\r\n #removeNodeByIndex(nodeIndex: number): void {\r\n this.#removeNodeConnections(nodeIndex);\r\n const node = this.#nodes[nodeIndex];\r\n this.#nodes.splice(nodeIndex, 1);\r\n\r\n // Hover is only recomputed on render, which is lazy, so it must follow the splice.\r\n if (this.#nodeHovering === nodeIndex) {\r\n this.#nodeHovering = -1;\r\n } else if (this.#nodeHovering > nodeIndex) {\r\n this.#nodeHovering--;\r\n }\r\n if (this.#portHovering?.Node === node) {\r\n this.#portHovering = null;\r\n }\r\n requestRender();\r\n for (let i = 0; i < this.#nodeRemovedCallbacks.length; i++) {\r\n this.#nodeRemovedCallbacks[i](node);\r\n }\r\n }\r\n\r\n #removeConnectionByIndex(index: number, clearPorts: boolean): void {\r\n if (clearPorts) {\r\n this.#connections[index].clearPorts();\r\n }\r\n this.#connections.splice(index, 1);\r\n requestRender();\r\n }\r\n\r\n #removeConnection(connection: Connection, clearPorts: boolean): void {\r\n const index = this.#connections.indexOf(connection);\r\n if (index > -1) {\r\n this.#removeConnectionByIndex(index, clearPorts);\r\n } else {\r\n console.error(\"no connection found to remove\");\r\n }\r\n }\r\n\r\n organize(ctx: CanvasRenderingContext2D): void {\r\n Organize(ctx, this);\r\n }\r\n\r\n #nodesSelected(): Array<number> {\r\n const selected = new Array<number>();\r\n for (let i = 0; i < this.#nodes.length; i++) {\r\n if (this.#nodes[i].selected()) {\r\n selected.push(i);\r\n }\r\n }\r\n return selected;\r\n }\r\n\r\n #organizeSelected(ctx: CanvasRenderingContext2D): void {\r\n Organize(ctx, this, this.#nodesSelected());\r\n }\r\n\r\n openContextMenu(ctx: CanvasRenderingContext2D, position: Vector2): ContextMenuConfig | null {\r\n\r\n const organizeNodesSubMenu: ContextMenuConfig = {\r\n name: \"Organize\",\r\n group: nodeFlowGroup,\r\n items: [\r\n {\r\n name: \"All Nodes\",\r\n group: nodeFlowGroup,\r\n callback: () => {\r\n this.organize(ctx);\r\n }\r\n }\r\n ]\r\n }\r\n\r\n let config: ContextMenuConfig = {\r\n items: [],\r\n subMenus: [\r\n organizeNodesSubMenu,\r\n this.#nodeFactory.openMenu(this, position)\r\n ]\r\n }\r\n\r\n const selectedCount = this.#nodesSelected().length;\r\n if (selectedCount > 0) {\r\n organizeNodesSubMenu.items?.push({\r\n name: \"Selected Nodes\",\r\n group: nodeFlowGroup,\r\n callback: () => {\r\n this.#organizeSelected(ctx)\r\n }\r\n })\r\n\r\n config.items?.push({\r\n name: selectedCount === 1 ? \"Delete Selected Node\" : `Delete ${selectedCount} Selected Nodes`,\r\n group: nodeFlowGroup,\r\n callback: () => {\r\n this.removeSelectedNodes();\r\n }\r\n })\r\n }\r\n\r\n if (this.#nodeHovering > -1) {\r\n const nodeToReview = this.#nodeHovering;\r\n const nodeToReviewNode = this.#nodes[nodeToReview];\r\n\r\n config.subMenus?.push({\r\n group: nodeFlowGroup,\r\n name: \"Select\",\r\n items: [\r\n {\r\n name: \"Direct Connected Nodes\",\r\n group: nodeFlowGroup,\r\n callback: () => {\r\n this.#selectConnectedNodes(nodeToReview);\r\n }\r\n },\r\n {\r\n name: \"Input Nodes + Descendents\",\r\n group: nodeFlowGroup,\r\n callback: () => {\r\n this.#selectInputNodesAndDescendents(nodeToReviewNode);\r\n }\r\n },\r\n ]\r\n })\r\n\r\n config.subMenus?.push({\r\n group: nodeFlowGroup,\r\n name: \"Delete\",\r\n items: [\r\n {\r\n name: \"Node\",\r\n group: nodeFlowGroup,\r\n callback: () => {\r\n this.#removeNodeByIndex(nodeToReview);\r\n }\r\n },\r\n {\r\n name: \"Connections\",\r\n group: nodeFlowGroup,\r\n callback: () => {\r\n this.#removeNodeConnections(nodeToReview);\r\n }\r\n }\r\n ]\r\n })\r\n config = CombineContextMenus(config, nodeToReviewNode.contextMenu());\r\n }\r\n return config;\r\n }\r\n\r\n #selectInputNodesAndDescendents(node: FlowNode): void {\r\n if (node === undefined) {\r\n return;\r\n }\r\n this.#selectNode(node, false);\r\n\r\n const inputs = this.connectedInputsNodeReferences(node);\r\n for (let i = 0; i < inputs.length; i++) {\r\n this.#selectInputNodesAndDescendents(inputs[i]);\r\n }\r\n }\r\n\r\n #selectConnectedNodes(nodeIndex: number): void {\r\n const node = this.#nodes[nodeIndex];\r\n if (node === undefined) {\r\n return;\r\n }\r\n this.#selectNode(node, false);\r\n\r\n const outputs = this.connectedOutputsNodeReferences(nodeIndex);\r\n for (let i = 0; i < outputs.length; i++) {\r\n this.#selectNode(outputs[i], false);\r\n }\r\n\r\n const inputs = this.connectedInputsNodeReferencesByIndex(nodeIndex);\r\n for (let i = 0; i < inputs.length; i++) {\r\n this.#selectNode(inputs[i], false);\r\n }\r\n }\r\n\r\n /** Drops the selection entirely. */\r\n public unselectAllNodes(): void {\r\n let changed = false;\r\n for (let i = 0; i < this.#nodes.length; i++) {\r\n if (this.#nodes[i].selected()) {\r\n this.#nodes[i].unselect();\r\n changed = true;\r\n }\r\n }\r\n\r\n if (changed) {\r\n requestRender();\r\n }\r\n }\r\n\r\n /**\r\n * Removes every selected node, and the connections that touched them.\r\n */\r\n public removeSelectedNodes(): Array<FlowNode> {\r\n const removed = this.getSelectedNodes();\r\n for (const node of removed) {\r\n this.removeNode(node);\r\n }\r\n return removed;\r\n }\r\n\r\n #selectNodeByIndex(nodeIndex: number, unselectOthers: boolean): void {\r\n this.#selectNode(this.#nodes[nodeIndex], unselectOthers);\r\n }\r\n\r\n #selectNode(node: FlowNode, unselectOthers: boolean): void {\r\n node.select();\r\n\r\n if (!unselectOthers) {\r\n return;\r\n }\r\n\r\n for (let i = 0; i < this.#nodes.length; i++) {\r\n if (node === this.#nodes[i]) {\r\n continue\r\n }\r\n this.#nodes[i].unselect();\r\n }\r\n }\r\n\r\n #clearCurrentlySelectedConnection(): void {\r\n if (this.#connectionSelected === null) {\r\n return;\r\n }\r\n this.#removeConnection(this.#connectionSelected, true);\r\n this.#connectionSelected = null;\r\n }\r\n\r\n #renderConnections(ctx: CanvasRenderingContext2D, camera: Camera, mousePosition: Vector2 | undefined): void {\r\n for (let i = 0; i < this.#connections.length; i++) {\r\n let portMousedOver = false;\r\n if (mousePosition !== undefined) {\r\n portMousedOver = this.#connections[i].mouseOverPort(mousePosition) !== null;\r\n }\r\n this.#connections[i].render(ctx, camera.zoom, portMousedOver, mousePosition);\r\n }\r\n }\r\n\r\n #renderNodes(ctx: CanvasRenderingContext2D, camera: Camera, mousePosition: Vector2 | undefined) {\r\n this.#portHovering = null;\r\n this.#widgetHovering = null;\r\n this.#nodeHovering = -1;\r\n this.#boxSelectionNodes.Clear();\r\n let hovered: FlowNode | null = null;\r\n\r\n const selectedBox_Screenspace = this.#boxSelectionScreenspaceBox(camera);\r\n\r\n // Nodes outside the canvas are not drawn, but their ports are still\r\n // placed, because wires to them stay on screen. \r\n const canvas: Box = {\r\n Position: { x: 0, y: 0 },\r\n Size: { x: ctx.canvas.width, y: ctx.canvas.height },\r\n };\r\n\r\n for (let i = 0; i < this.#nodes.length; i++) {\r\n let state = NodeState.Idle;\r\n\r\n const nodeBounds = this.#nodes[i].calculateBounds(ctx, camera);\r\n if (!BoxIntersection(nodeBounds, canvas)\r\n && this.#nodes[i].layoutPortsWithoutDrawing(nodeBounds, camera.zoom)) {\r\n continue;\r\n }\r\n\r\n if (mousePosition !== undefined && !this.#boxSelect) {\r\n const intersection = this.#nodes[i].inBounds(ctx, camera, mousePosition);\r\n if (intersection.Node !== undefined) {\r\n hovered = intersection.Node;\r\n }\r\n\r\n if (intersection.Node !== undefined && intersection.PortIndex === undefined && intersection.Widget === undefined) {\r\n state = NodeState.MouseOver;\r\n this.#nodeHovering = i;\r\n this.#cursor = CursorStyle.Grab;\r\n }\r\n\r\n if (intersection.Widget !== undefined) {\r\n this.#widgetHovering = intersection.Widget\r\n this.#widgetHoveringBox = intersection.WidgetBox ?? null;\r\n this.#cursor = intersection.Widget.Disabled?.()\r\n ? CursorStyle.Default\r\n : intersection.Widget.Cursor?.() ?? CursorStyle.Pointer;\r\n }\r\n\r\n if (intersection.Port !== undefined && intersection.Node !== undefined && intersection.PortIndex !== undefined && intersection.PortIsInput !== undefined) {\r\n this.#portHovering = {\r\n Index: intersection.PortIndex,\r\n Node: intersection.Node,\r\n Port: intersection.Port,\r\n InputPort: intersection.PortIsInput\r\n };\r\n }\r\n } else if (this.#boxSelect) {\r\n const nodeBounds = this.#nodes[i].calculateBounds(ctx, camera);\r\n\r\n if (BoxIntersection(selectedBox_Screenspace, nodeBounds)) {\r\n state = NodeState.MouseOver;\r\n this.#boxSelectionNodes.Push(i);\r\n }\r\n }\r\n\r\n // if (i === this.#nodeSelected) {\r\n // state = NodeState.Selected;\r\n // }\r\n\r\n if (this.#nodes[i].selected() && this.#nodesGrabbed.Count() > 0) {\r\n state = NodeState.Grabbed;\r\n this.#cursor = CursorStyle.Grabbing;\r\n }\r\n\r\n this.#nodes[i].render(ctx, camera, state, mousePosition, this.#postProcessPass);\r\n }\r\n this.#setHoveredNode(hovered);\r\n\r\n if (this.#widgetCurrentlyClicking !== null) {\r\n this.#cursor = this.#widgetCurrentlyClicking.Cursor?.() ?? CursorStyle.Pointer;\r\n }\r\n }\r\n\r\n #boxSelectionScreenspaceBox(camera: Camera): Box {\r\n const box = { Position: Zero(), Size: Zero() }\r\n\r\n camera.graphSpaceToScreenSpace(this.#boxSelectStart_graphSpace, box.Position);\r\n camera.graphSpaceToScreenSpace(this.#boxSelectEnd_graphSpace, box.Size);\r\n\r\n SubVector2(box.Size, box.Size, box.Position);\r\n\r\n return box;\r\n }\r\n\r\n /**\r\n * Where a wire being dropped on the hovered array input would go, or\r\n * undefined when it is not over one.\r\n */\r\n #insertIndex(): number | undefined {\r\n const hovering = this.#portHovering;\r\n if (hovering === null || !hovering.InputPort || this.#lastMousePosition === undefined\r\n || hovering.Port.getPortType() !== PortType.InputArray) {\r\n return undefined;\r\n }\r\n const box = hovering.Node.inputPortPosition(hovering.Index);\r\n return arrayInsertIndex(box, hovering.Port.connections().length, this.#lastMousePosition.y);\r\n }\r\n\r\n #renderInsertMarker(ctx: CanvasRenderingContext2D, camera: Camera): void {\r\n const hovering = this.#portHovering;\r\n if (this.#connectionSelected === null || this.#connectionSelected.inPort() !== null || hovering === null) {\r\n return;\r\n }\r\n const index = this.#insertIndex();\r\n const count = hovering.Port.connections().length;\r\n if (index === undefined || count === 0) {\r\n return;\r\n }\r\n const box = hovering.Node.inputPortPosition(hovering.Index);\r\n const y = box.Position.y + (index * box.Size.y / count);\r\n const overhang = 6 * camera.zoom;\r\n ctx.save();\r\n ctx.strokeStyle = \"#ffffff\";\r\n ctx.lineWidth = Math.max(1, 2 * camera.zoom);\r\n ctx.beginPath();\r\n ctx.moveTo(box.Position.x - overhang, y);\r\n ctx.lineTo(box.Position.x + box.Size.x + overhang, y);\r\n ctx.stroke();\r\n ctx.restore();\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, camera: Camera, mousePosition: Vector2 | undefined): RenderResults | undefined {\r\n this.#lastCtx = ctx;\r\n this.#lastMousePosition = mousePosition;\r\n this.#cursor = CursorStyle.Default;\r\n\r\n // Connections draw first but need port positions, which only exist\r\n // once a node has been drawn so a new node costs one extra frame.\r\n const awaitingLayout = this.#nodes.some((node) => !node.hasBeenLaidOut());\r\n\r\n for (const node of this.#nodes) {\r\n if (node.hasBeenLaidOut()) {\r\n node.placePorts(node.calculateBounds(ctx, camera), camera.zoom);\r\n }\r\n }\r\n\r\n TimeExecution(\"Render_Connections\", () => {\r\n this.#renderConnections(ctx, camera, mousePosition);\r\n })\r\n TimeExecution(\"Render_Nodes\", () => {\r\n this.#renderNodes(ctx, camera, mousePosition);\r\n })\r\n this.#renderInsertMarker(ctx, camera);\r\n\r\n if (awaitingLayout) {\r\n requestRender();\r\n }\r\n\r\n if (this.#boxSelect) {\r\n const box = this.#boxSelectionScreenspaceBox(camera);\r\n ctx.setLineDash([Theme.BoxSelect.LineDashLength]);\r\n new BoxStyle({\r\n border: { color: Theme.BoxSelect.Color, size: Theme.BoxSelect.Size },\r\n color: \"rgba(0,0,0,0)\",\r\n radius: Theme.BoxSelect.Radius,\r\n }).Draw(ctx, box, 1);\r\n ctx.setLineDash([]);\r\n }\r\n\r\n return { cursorStyle: this.#cursor }\r\n }\r\n\r\n}", "import { Theme } from \"./theme\";\r\n\r\nexport interface PopupConfig {\r\n title: string;\r\n options: Array<string>;\r\n\r\n onClose?: (button: string | null) => void;\r\n content?: () => Element;\r\n buttonCSS?: string;\r\n}\r\n\r\nexport class Popup {\r\n\r\n #title: string;\r\n\r\n #options: Array<string>;\r\n\r\n #content?: () => Element;\r\n\r\n #onClose?: (button: string | null) => void;\r\n\r\n // Styling ================================================================\r\n\r\n #buttonCSS: string;\r\n\r\n // Runtime ================================================================\r\n\r\n #popup: HTMLDivElement | null;\r\n\r\n #keyHandler: ((e: KeyboardEvent) => void) | null;\r\n\r\n constructor(config: PopupConfig) {\r\n this.#title = config.title;\r\n this.#options = config.options;\r\n this.#content = config.content;\r\n this.#onClose = config.onClose;\r\n this.#buttonCSS = config.buttonCSS === undefined ? \"flex-grow: 1; margin-right: 8px;\" : config.buttonCSS;\r\n this.#popup = null;\r\n this.#keyHandler = null;\r\n }\r\n\r\n Hide(): void {\r\n if (this.#popup === null) {\r\n return;\r\n }\r\n if (this.#keyHandler !== null) {\r\n document.removeEventListener(\"keydown\", this.#keyHandler, true);\r\n this.#keyHandler = null;\r\n }\r\n document.body.removeChild(this.#popup);\r\n this.#popup = null;\r\n }\r\n\r\n #close(option: string | null): void {\r\n this.Hide();\r\n if (this.#onClose !== undefined) {\r\n this.#onClose(option);\r\n }\r\n }\r\n\r\n Show(): void {\r\n this.#popup = document.createElement('div');\r\n this.#popup.style.cssText = `position:absolute;top:0;width:100%;display:flex;height:100%;justify-content:center;align-items:center;background-color:${Theme.Popup.Backdrop};`;\r\n document.body.appendChild(this.#popup);\r\n\r\n const container = document.createElement('div');\r\n container.style.cssText = `background-color:${Theme.Popup.BackgroundColor};color:${Theme.Popup.FontColor};font-family:${Theme.Popup.FontFamily};border-radius:${Theme.Popup.BorderRadius}px;padding:16px;`;\r\n this.#popup.appendChild(container);\r\n\r\n const title = document.createElement(\"h2\");\r\n title.textContent = this.#title;\r\n title.style.cssText = \"margin-top:0;margin-bottom:16px;\";\r\n container.appendChild(title)\r\n\r\n if (this.#content !== undefined) {\r\n container.appendChild(this.#content());\r\n }\r\n\r\n const buttonContainer = document.createElement(\"div\");\r\n buttonContainer.style.cssText = 'margin-top:16px;justify-content:space-around;align-items:center;flex-direction:row;display:flex;';\r\n container.appendChild(buttonContainer);\r\n\r\n for (let i = 0; i < this.#options.length; i++) {\r\n const button = document.createElement(\"button\");\r\n button.style.cssText = this.#buttonCSS;\r\n button.textContent = this.#options[i];\r\n button.onclick = () => this.#close(this.#options[i]);\r\n buttonContainer.appendChild(button);\r\n }\r\n\r\n this.#keyHandler = (e: KeyboardEvent): void => {\r\n if (e.key === \"Enter\") {\r\n e.preventDefault();\r\n this.#close(this.#options.length > 0 ? this.#options[0] : null);\r\n } else if (e.key === \"Escape\") {\r\n e.preventDefault();\r\n this.#close(null);\r\n }\r\n e.stopPropagation();\r\n };\r\n document.addEventListener(\"keydown\", this.#keyHandler, true);\r\n }\r\n\r\n} ", "import { Popup } from \"../popup\";\r\n\r\ninterface Config {\r\n title: string;\r\n startingValue: string;\r\n onUpdate: (newValue: string) => void;\r\n onCancel?: () => void;\r\n}\r\n\r\nexport function SetStringPopup(config: Config): Popup {\r\n let input: HTMLInputElement | null = null;\r\n\r\n return new Popup({\r\n title: config.title,\r\n options: [\"Set\", \"Cancel\"],\r\n content: () => {\r\n const container = document.createElement('div');\r\n input = document.createElement('input')\r\n input.value = config.startingValue;\r\n container.append(input);\r\n return container;\r\n },\r\n onClose: (button: string | null): void => {\r\n if (button !== \"Set\" || input === null) {\r\n if(config.onCancel) {\r\n config.onCancel();\r\n }\r\n return;\r\n }\r\n config.onUpdate(input.value);\r\n },\r\n });\r\n}", "import { Popup } from \"../popup\";\r\n\r\ninterface FormValue {\r\n name: string;\r\n\r\n // https://html.spec.whatwg.org/multipage/input.html#dom-input-type\r\n type: string;\r\n\r\n startingValue: any;\r\n}\r\n\r\ninterface Config {\r\n title: string;\r\n form: Array<FormValue>;\r\n onUpdate: (newValue: Array<any>) => void;\r\n onCancel?: () => void;\r\n}\r\n\r\nexport function FormPopup(config: Config): Popup {\r\n let input = new Array<HTMLInputElement | null>();\r\n\r\n const setOption = \"Set\";\r\n const cancelOption = \"Cancel\";\r\n\r\n return new Popup({\r\n title: config.title,\r\n options: [setOption, cancelOption],\r\n content: () => {\r\n const container = document.createElement('div');\r\n container.style.flexDirection = \"column\";\r\n container.style.display = \"flex\";\r\n\r\n for (let i = 0; i < config.form.length; i++) {\r\n const title = document.createElement(\"h4\");\r\n title.innerText = config.form[i].name;\r\n container.append(title);\r\n\r\n const ele = document.createElement('input');\r\n ele.value = config.form[i].startingValue;\r\n ele.type = config.form[i].type;\r\n container.append(ele);\r\n input.push(ele);\r\n container.append(document.createElement(\"br\"));\r\n }\r\n\r\n return container;\r\n },\r\n onClose: (button: string | null): void => {\r\n if (button !== setOption || input === null) {\r\n if (config.onCancel) {\r\n config.onCancel();\r\n }\r\n return;\r\n }\r\n\r\n const values = new Array<any>();\r\n for (let i = 0; i < config.form.length; i++) {\r\n values[i] = input[i]?.value;\r\n }\r\n config.onUpdate(values);\r\n },\r\n });\r\n}\r\n", "import { ARRAY_SLOT_PITCH, Port, PortConfig, PortType } from \"./port\";\r\nimport { requestRender } from \"./render_scheduler\";\r\nimport { FontWeight, TextStyle, TextStyleConfig, TextStyleFallback } from \"./styles/text\";\r\nimport { Box, InBox } from \"./types/box\";\r\nimport { CopyVector2, Distance, ScaleVector, Vector2, Zero } from \"./types/vector2\";\r\nimport { Widget } from './widgets/widget';\r\nimport { HiddenPortsToggle } from './widgets/hidden_ports';\r\nimport { List } from './types/list';\r\nimport { BoxStyle, BoxStyleConfig, BoxStyleWithFallback } from \"./styles/box\";\r\nimport { Text } from \"./types/text\";\r\nimport { GlobalWidgetFactory, WidgetConfig } from \"./widgets/factory\";\r\nimport { Theme, themeVersion } from \"./theme\";\r\nimport { drawBevel } from \"./styles/bevel\";\r\nimport { TextAlign } from \"./styles/canvasTextAlign\";\r\nimport { TextBaseline } from \"./styles/canvasTextBaseline\";\r\nimport { CombineContextMenus, ContextMenuConfig, ContextMenuItemConfig } from \"./contextMenu\";\r\nimport { nodeFlowGroup } from \"./nodes/subsystem\";\r\nimport { SetStringPopup } from \"./popups/string\";\r\nimport { ButtonWidget } from \"./widgets/button\";\r\nimport { FormPopup } from \"./popups/form\";\r\nimport { NumberWidget } from \"./widgets/number\";\r\nimport { StringWidget } from \"./widgets/string\";\r\nimport { ToggleWidget } from \"./widgets/toggle\";\r\nimport { ColorWidget } from \"./widgets/color\";\r\nimport { SliderWidget } from \"./widgets/slider\";\r\nimport { ImageWidget } from \"./widgets/image\";\r\nimport { VectorPool } from \"./types/pool\";\r\nimport { Camera } from \"./camera\";\r\nimport { PassSubsystem } from \"./pass/subsystem\";\r\nimport { splitString, splitStringIntoLines } from \"./utils/string\";\r\nimport { Metadata } from './metadata';\r\n\r\nconst MINIMUM_NODE_WIDTH = 150;\r\n\r\ntype AnyPropertyChangeCallback = (propertyName: string, oldValue: any, newValue: any) => void\r\ntype PropertyChangeCallback = (oldValue: any, newValue: any) => void\r\ntype PropertyEditCallback = (newValue: any) => void\r\ntype TitleChangeCallback = (node: FlowNode, oldTitle: string, newTitle: string) => void\r\ntype InfoChangeCallback = (node: FlowNode, oldInfo: string, newInfo: string) => void\r\n\r\n\r\nexport interface FlowNodeTitleConfig {\r\n textStyle?: TextStyleConfig;\r\n color?: string;\r\n padding?: number;\r\n}\r\n\r\nexport interface FlowNodeStyle {\r\n title?: FlowNodeTitleConfig;\r\n idle?: BoxStyleConfig;\r\n mouseOver?: BoxStyleConfig;\r\n grabbed?: BoxStyleConfig;\r\n selected?: BoxStyleConfig;\r\n portText?: TextStyleConfig;\r\n}\r\n\r\nexport enum MessageType {\r\n Info = \"info\",\r\n Warning = \"warning\",\r\n Error = \"error\"\r\n};\r\n\r\nfunction MessageTypeColor(messageType: MessageType): string {\r\n switch (messageType) {\r\n case MessageType.Info:\r\n return Theme.Node.Message.InfoColor;\r\n\r\n case MessageType.Warning:\r\n return Theme.Node.Message.WarnColor;\r\n\r\n case MessageType.Error:\r\n return Theme.Node.Message.ErrorColor;\r\n\r\n default:\r\n throw new Error(`unrecognized message type ${messageType}`)\r\n }\r\n}\r\n\r\nexport interface NodeMessageConfig {\r\n message: string;\r\n type?: MessageType;\r\n alwaysShow?: boolean;\r\n color?: string;\r\n}\r\n\r\nexport interface FlowNodeConfig {\r\n position?: Vector2;\r\n title?: string;\r\n subTitle?: string;\r\n info?: string;\r\n messages?: Array<NodeMessageConfig>\r\n locked?: boolean;\r\n data?: Metadata;\r\n contextMenu?: ContextMenuConfig;\r\n metadata?: any;\r\n\r\n canEditTitle?: boolean;\r\n canEditInfo?: boolean;\r\n canEditPorts?: boolean;\r\n\r\n // Ports\r\n inputs?: Array<PortConfig>;\r\n outputs?: Array<PortConfig>;\r\n\r\n // Callbacks\r\n onGrab?: () => void;\r\n onRelease?: () => void;\r\n onSelect?: () => void;\r\n onUnselect?: () => void;\r\n onDragStop?: (FlowNode: FlowNode) => void;\r\n onFileDrop?: (file: File) => void;\r\n onTitleChange?: TitleChangeCallback;\r\n onInfoChange?: InfoChangeCallback;\r\n\r\n // Widgets\r\n widgets?: Array<WidgetConfig>;\r\n\r\n // Styling\r\n style?: FlowNodeStyle;\r\n}\r\n\r\nexport enum NodeState {\r\n Idle,\r\n MouseOver,\r\n Grabbed\r\n}\r\n\r\nexport interface NodeIntersection {\r\n Node?: FlowNode\r\n\r\n // Port\r\n Port?: Port\r\n PortIndex?: number\r\n PortIsInput?: boolean\r\n\r\n // Widget\r\n Widget?: Widget\r\n WidgetIndex?: number\r\n WidgetBox?: Box\r\n\r\n}\r\n\r\nclass MessageRenderer {\r\n\r\n #text: Text;\r\n\r\n #alwaysShow: boolean;\r\n\r\n constructor(config: NodeMessageConfig) {\r\n this.#alwaysShow = config.alwaysShow ? config.alwaysShow : false;\r\n this.#text = new Text(config.message,\r\n {\r\n color: config.color ? config.color : MessageTypeColor(config.type ? config.type : MessageType.Info),\r\n },\r\n {\r\n LineSpacing: 2.5,\r\n MaxWidth: 200\r\n }\r\n );\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, scale: number, position: Vector2, hovering: boolean): number {\r\n if (!this.#alwaysShow && !hovering) {\r\n return 0;\r\n }\r\n ctx.textAlign = TextAlign.Center;\r\n this.#text.render(ctx, scale, position);\r\n return this.#text.height(ctx) * scale;\r\n }\r\n}\r\n\r\nexport class FlowNode {\r\n\r\n #position: Vector2;\r\n\r\n #title: Text;\r\n\r\n #subTitle: Text;\r\n\r\n #infoSymbol: Text;\r\n\r\n #infoText: string;\r\n\r\n #messages: Array<MessageRenderer>\r\n\r\n #input: Array<Port>;\r\n\r\n #output: Array<Port>;\r\n\r\n #widgets: Array<Widget>;\r\n\r\n #locked: boolean;\r\n\r\n #canEditTitle: boolean;\r\n\r\n #canEditInfo: boolean;\r\n\r\n #canEditPorts: boolean;\r\n\r\n #contextMenu: ContextMenuConfig | null;\r\n\r\n #metadata: any;\r\n\r\n // Callbacks\r\n\r\n #onSelect: Array<() => void>;\r\n\r\n #onUnselect: Array<() => void>;\r\n\r\n #onFiledrop: Array<(file: File) => void>;\r\n\r\n #onDragStop: Array<(node: FlowNode) => void>;\r\n\r\n #titleChangeCallback: Array<TitleChangeCallback>;\r\n\r\n #infoChangeCallback: Array<InfoChangeCallback>;\r\n\r\n // Styling ================================================================\r\n\r\n #styleConfig: FlowNodeStyle | undefined;\r\n\r\n #styledForTheme = -1;\r\n\r\n #titleColor!: string;\r\n\r\n #selectedStyle!: BoxStyle;\r\n\r\n #stateStyles = new Map<NodeState, BoxStyle>();\r\n\r\n #padding: number;\r\n\r\n #portTextStyle!: TextStyle;\r\n\r\n #elementSpacing: number;\r\n\r\n // Runtime ================================================================\r\n\r\n #selected: boolean;\r\n\r\n #highlighted = false;\r\n\r\n #inputPortPositions: List<Box>;\r\n\r\n #outputPortPositions: List<Box>;\r\n\r\n #widgetPositions: List<Box>;\r\n\r\n #portWidgetPositions: List<Box> = new List<Box>();\r\n\r\n #data: Metadata;\r\n\r\n #registeredAnyPropertyChangeCallbacks: Array<AnyPropertyChangeCallback>;\r\n\r\n #registeredPropertyChangeCallbacks: Map<string, Array<PropertyChangeCallback>>;\r\n\r\n #registeredPropertyEditCallbacks = new Map<string, Array<PropertyEditCallback>>();\r\n\r\n constructor(config?: FlowNodeConfig) {\r\n this.#input = new Array<Port>();\r\n this.#output = new Array<Port>();\r\n this.#widgets = new Array<Widget>();\r\n this.#inputPortPositions = new List<Box>();\r\n this.#outputPortPositions = new List<Box>();\r\n this.#widgetPositions = new List<Box>();\r\n this.#elementSpacing = 15;\r\n this.#locked = config?.locked === undefined ? false : config.locked;\r\n this.#data = config?.data === undefined ? {} : config?.data;\r\n this.#registeredPropertyChangeCallbacks = new Map<string, Array<PropertyChangeCallback>>();\r\n this.#registeredAnyPropertyChangeCallbacks = new Array<AnyPropertyChangeCallback>();\r\n this.#canEditPorts = config?.canEditPorts === undefined ? false : config.canEditPorts;\r\n this.#canEditTitle = config?.canEditTitle === undefined ? false : config.canEditTitle;\r\n this.#canEditInfo = config?.canEditInfo === undefined ? false : config.canEditInfo;\r\n this.#contextMenu = config?.contextMenu === undefined ? null : config.contextMenu;\r\n this.#metadata = config?.metadata;\r\n\r\n this.#messages = [];\r\n if (config?.messages) {\r\n for (let i = 0; i < config.messages.length; i++) {\r\n const message = config.messages[i];\r\n this.#messages.push(new MessageRenderer(message));\r\n }\r\n }\r\n\r\n this.#selected = false;\r\n this.#onSelect = new Array<() => void>();\r\n this.#onUnselect = new Array<() => void>();\r\n this.#onFiledrop = new Array<(file: File) => void>();\r\n this.#onDragStop = new Array<() => void>();\r\n this.#titleChangeCallback = new Array<TitleChangeCallback>();\r\n this.#infoChangeCallback = new Array<InfoChangeCallback>();\r\n\r\n if (config?.onSelect) {\r\n this.#onSelect.push(config?.onSelect);\r\n }\r\n\r\n if (config?.onUnselect) {\r\n this.#onUnselect.push(config?.onUnselect);\r\n }\r\n\r\n if (config?.onFileDrop) {\r\n this.#onFiledrop.push(config?.onFileDrop);\r\n }\r\n\r\n if (config?.onDragStop) {\r\n this.#onDragStop.push(config.onDragStop);\r\n }\r\n\r\n if (config?.onTitleChange) {\r\n this.#titleChangeCallback.push(config.onTitleChange);\r\n }\r\n\r\n if (config?.onInfoChange) {\r\n this.#infoChangeCallback.push(config.onInfoChange);\r\n }\r\n\r\n this.#position = config?.position === undefined ? { x: 0, y: 0 } : config.position;\r\n this.#title = new Text(\r\n config?.title === undefined ? \"\" : config.title,\r\n TextStyleFallback(config?.style?.title?.textStyle, { size: 16, weight: FontWeight.Bold })\r\n );\r\n\r\n this.#subTitle = new Text(\r\n config?.subTitle === undefined ? \"\" : config.subTitle,\r\n TextStyleFallback(config?.style?.title?.textStyle, { size: 10, weight: FontWeight.Bold })\r\n );\r\n\r\n this.#infoSymbol = new Text(\"i\", { size: 13, weight: FontWeight.Bold });\r\n this.#infoText = config?.info ? config?.info : \"\";\r\n\r\n this.#padding = config?.style?.title?.padding === undefined ? 15 : config?.style?.title?.padding;\r\n\r\n this.#styleConfig = config?.style;\r\n this.#applyStyle();\r\n\r\n if (config?.inputs !== undefined) {\r\n for (let i = 0; i < config.inputs.length; i++) {\r\n this.addInput(config.inputs[i]);\r\n }\r\n }\r\n\r\n if (config?.outputs !== undefined) {\r\n for (let i = 0; i < config.outputs.length; i++) {\r\n this.addOutput(config.outputs[i]);\r\n }\r\n }\r\n\r\n if (config?.widgets !== undefined) {\r\n for (const widget of config.widgets) {\r\n this.addWidget(GlobalWidgetFactory.createFromConfig(this, widget));\r\n }\r\n }\r\n }\r\n\r\n public metadata(): any {\r\n return this.#metadata;\r\n }\r\n\r\n public selected(): boolean {\r\n return this.#selected;\r\n }\r\n\r\n public select(): void {\r\n if (this.#selected) {\r\n return;\r\n }\r\n this.#selected = true;\r\n requestRender();\r\n for (let i = 0; i < this.#onSelect.length; i++) {\r\n this.#onSelect[i]();\r\n }\r\n }\r\n\r\n public highlighted(): boolean {\r\n return this.#highlighted;\r\n }\r\n\r\n public setHighlighted(highlighted: boolean): void {\r\n if (this.#highlighted === highlighted) {\r\n return;\r\n }\r\n this.#highlighted = highlighted;\r\n requestRender();\r\n }\r\n\r\n public raiseDragStoppedEvent() {\r\n for (let i = 0; i < this.#onDragStop.length; i++) {\r\n this.#onDragStop[i](this);\r\n }\r\n }\r\n\r\n public addTitleChangeListener(callback: TitleChangeCallback): void {\r\n if (callback === undefined || callback === null) {\r\n }\r\n this.#titleChangeCallback.push(callback);\r\n }\r\n\r\n public addInfoChangeListener(callback: InfoChangeCallback): void {\r\n if (callback === undefined || callback === null) {\r\n }\r\n this.#infoChangeCallback.push(callback);\r\n }\r\n\r\n\r\n public addDragStoppedListener(callback: (node: FlowNode) => void): void {\r\n if (callback === undefined || callback === null) {\r\n }\r\n this.#onDragStop.push(callback);\r\n }\r\n\r\n public addAnyPropertyChangeListener(callback: AnyPropertyChangeCallback): void {\r\n if (callback === undefined || callback === null) {\r\n }\r\n this.#registeredAnyPropertyChangeCallbacks.push(callback);\r\n }\r\n\r\n public addPropertyChangeListener(name: string, callback: PropertyChangeCallback): void {\r\n if (!this.#registeredPropertyChangeCallbacks.has(name)) {\r\n this.#registeredPropertyChangeCallbacks.set(name, []);\r\n }\r\n\r\n const callbacks = this.#registeredPropertyChangeCallbacks.get(name);\r\n if (callbacks === undefined) {\r\n return;\r\n }\r\n callbacks.push(callback);\r\n }\r\n\r\n public setProperty(name: string, value: any): void {\r\n const oldValue = this.#data[name];\r\n // Object.is, not ===: NaN never equals itsel.\r\n if (Object.is(oldValue, value)) {\r\n return;\r\n }\r\n\r\n this.#data[name] = value;\r\n requestRender();\r\n\r\n for (let i = 0; i < this.#registeredAnyPropertyChangeCallbacks.length; i++) {\r\n this.#registeredAnyPropertyChangeCallbacks[i](name, oldValue, value);\r\n }\r\n\r\n const callbacks = this.#registeredPropertyChangeCallbacks.get(name);\r\n if (callbacks === undefined) {\r\n return;\r\n }\r\n\r\n for (let i = 0; i < callbacks.length; i++) {\r\n callbacks[i](oldValue, value);\r\n }\r\n }\r\n\r\n /**\r\n * Listens for a person changing the property through a widget, but not\r\n * for the property being set from code.\r\n */\r\n public addPropertyEditListener(name: string, callback: PropertyEditCallback): void {\r\n let callbacks = this.#registeredPropertyEditCallbacks.get(name);\r\n if (callbacks === undefined) {\r\n callbacks = [];\r\n this.#registeredPropertyEditCallbacks.set(name, callbacks);\r\n }\r\n callbacks.push(callback);\r\n }\r\n\r\n /**\r\n * Sets the property as a person's finished edit, so edit listeners hear\r\n * it even when the value was already showing.\r\n */\r\n public editProperty(name: string, value: any): void {\r\n this.setProperty(name, value);\r\n const callbacks = this.#registeredPropertyEditCallbacks.get(name);\r\n if (callbacks === undefined) {\r\n return;\r\n }\r\n for (const callback of [...callbacks]) {\r\n callback(value);\r\n }\r\n }\r\n\r\n public getProperty(name: string): any {\r\n return this.#data[name];\r\n }\r\n\r\n #popupNodeTitleSelection(): void {\r\n SetStringPopup({\r\n title: \"Set Node Title\",\r\n startingValue: this.title(),\r\n onUpdate: (value: string): void => {\r\n this.setTitle(value);\r\n },\r\n }).Show();\r\n }\r\n\r\n #popupNodeInfoSelection(): void {\r\n SetStringPopup({\r\n title: \"Set Node Info\",\r\n startingValue: this.#infoText,\r\n onUpdate: (value: string): void => {\r\n this.setInfo(value);\r\n },\r\n }).Show();\r\n }\r\n\r\n #popupNewButtonWidget(): void {\r\n SetStringPopup({\r\n title: \"New Button Widget Text\",\r\n startingValue: \"My Button\",\r\n onUpdate: (value: string): void => {\r\n this.addWidget(new ButtonWidget({\r\n text: value\r\n }));\r\n },\r\n }).Show()\r\n }\r\n\r\n #widgetSubmenu(): ContextMenuConfig {\r\n return {\r\n name: \"Widget\",\r\n items: [\r\n {\r\n name: \"Button\",\r\n callback: this.#popupNewButtonWidget.bind(this),\r\n },\r\n {\r\n name: \"Number\",\r\n callback: () => {\r\n this.addWidget(new NumberWidget(this))\r\n }\r\n },\r\n {\r\n name: \"Color\",\r\n callback: () => {\r\n this.addWidget(new ColorWidget(this))\r\n }\r\n },\r\n {\r\n name: \"Slider\",\r\n callback: () => {\r\n FormPopup({\r\n title: \"New Slider\",\r\n form: [\r\n {\r\n name: \"min\",\r\n type: \"number\",\r\n startingValue: 0\r\n },\r\n {\r\n name: \"max\",\r\n type: \"number\",\r\n startingValue: 100\r\n }\r\n ],\r\n onUpdate: (data: Array<any>) => {\r\n this.addWidget(new SliderWidget(this, {\r\n min: data[0],\r\n max: data[1],\r\n }));\r\n }\r\n }).Show();\r\n }\r\n },\r\n {\r\n name: \"String\",\r\n callback: () => {\r\n this.addWidget(new StringWidget(this))\r\n }\r\n },\r\n {\r\n name: \"Toggle\",\r\n callback: () => {\r\n this.addWidget(new ToggleWidget(this))\r\n }\r\n },\r\n {\r\n name: \"Image\",\r\n callback: () => {\r\n FormPopup({\r\n title: \"New Image\",\r\n form: [\r\n {\r\n name: \"URL\",\r\n type: \"text\",\r\n startingValue: \"https://pbs.twimg.com/media/GYabtu6bsAA7m99?format=jpg&name=medium\"\r\n },\r\n {\r\n name: \"Max Width\",\r\n type: \"number\",\r\n startingValue: MINIMUM_NODE_WIDTH\r\n },\r\n {\r\n name: \"Max Height\",\r\n type: \"number\",\r\n startingValue: MINIMUM_NODE_WIDTH\r\n }\r\n ],\r\n onUpdate: (data: Array<any>) => {\r\n this.addWidget(new ImageWidget({\r\n image: data[0],\r\n maxWidth: data[1],\r\n maxHeight: data[2],\r\n }));\r\n }\r\n }).Show();\r\n }\r\n }\r\n ]\r\n };\r\n }\r\n\r\n public contextMenu(): ContextMenuConfig {\r\n let config: ContextMenuConfig = {\r\n group: nodeFlowGroup,\r\n items: [\r\n // {\r\n // name: \"Debug\",\r\n // callback: () => {\r\n // console.log(this);\r\n // }\r\n // }\r\n ],\r\n subMenus: [],\r\n }\r\n\r\n if (this.canEditPorts() || this.canEditTitle() || this.#canEditInfo) {\r\n\r\n const items = new Array<ContextMenuItemConfig>();\r\n if (this.canEditTitle()) {\r\n items.push({\r\n name: \"Title\",\r\n callback: () => {\r\n this.#popupNodeTitleSelection();\r\n }\r\n })\r\n }\r\n\r\n if (this.#canEditInfo) {\r\n items.push({\r\n name: \"Info\",\r\n callback: () => {\r\n this.#popupNodeInfoSelection();\r\n }\r\n })\r\n }\r\n\r\n const submenus = new Array<ContextMenuConfig>();\r\n if (this.canEditPorts()) {\r\n submenus.push({\r\n name: \"Add\",\r\n items: [\r\n {\r\n name: \"Input\",\r\n callback: () => {\r\n FormPopup({\r\n title: \"New Input\",\r\n form: [\r\n {\r\n name: \"name\",\r\n type: \"text\",\r\n startingValue: \"input\"\r\n },\r\n {\r\n name: \"type\",\r\n type: \"text\",\r\n startingValue: \"string\"\r\n }\r\n ],\r\n onUpdate: (data: Array<any>) => {\r\n this.addInput({\r\n name: data[0],\r\n type: data[1]\r\n })\r\n }\r\n }).Show();\r\n }\r\n },\r\n {\r\n name: \"Output\",\r\n callback: () => {\r\n FormPopup({\r\n title: \"New Output\",\r\n form: [\r\n {\r\n name: \"name\",\r\n type: \"text\",\r\n startingValue: \"output\"\r\n },\r\n {\r\n name: \"type\",\r\n type: \"text\",\r\n startingValue: \"string\"\r\n }\r\n ],\r\n onUpdate: (data: Array<any>) => {\r\n this.addOutput({\r\n name: data[0],\r\n type: data[1]\r\n })\r\n }\r\n }).Show();\r\n }\r\n },\r\n ],\r\n subMenus: [\r\n this.#widgetSubmenu(),\r\n ]\r\n });\r\n }\r\n\r\n config.subMenus?.push({\r\n group: nodeFlowGroup,\r\n name: \"Edit\",\r\n items: items,\r\n subMenus: submenus,\r\n })\r\n }\r\n\r\n if (this.locked()) {\r\n config.items?.push({\r\n name: \"Unlock Node Position\",\r\n group: nodeFlowGroup,\r\n callback: this.unlock.bind(this),\r\n });\r\n } else {\r\n config.items?.push({\r\n name: \"Lock Node Position\",\r\n group: nodeFlowGroup,\r\n callback: this.lock.bind(this),\r\n })\r\n }\r\n\r\n if (this.#contextMenu !== null) {\r\n config = CombineContextMenus(config, this.#contextMenu)\r\n }\r\n\r\n return config;\r\n }\r\n\r\n public unselect(): void {\r\n if (!this.#selected) {\r\n return;\r\n }\r\n this.#selected = false;\r\n requestRender();\r\n for (let i = 0; i < this.#onUnselect.length; i++) {\r\n this.#onUnselect[i]();\r\n }\r\n }\r\n\r\n public addUnselectListener(callback: () => void): void {\r\n this.#onUnselect.push(callback);\r\n }\r\n\r\n public addSelectListener(callback: () => void): void {\r\n this.#onSelect.push(callback);\r\n }\r\n\r\n public dropFile(file: File): void {\r\n for (let i = 0; i < this.#onFiledrop.length; i++) {\r\n this.#onFiledrop[i](file);\r\n }\r\n }\r\n\r\n public addFileDropListener(callback: (file: File) => void): void {\r\n this.#onFiledrop.push(callback);\r\n }\r\n\r\n public locked(): boolean {\r\n return this.#locked;\r\n }\r\n\r\n public lock(): void {\r\n this.#locked = true;\r\n }\r\n\r\n public unlock(): void {\r\n this.#locked = false;\r\n }\r\n\r\n public setPosition(position: Vector2): void {\r\n CopyVector2(this.#position, position);\r\n requestRender();\r\n }\r\n\r\n public getPosition(): Vector2 {\r\n return this.#position;\r\n }\r\n\r\n // #measureTitleText(ctx: CanvasRenderingContext2D, scale: number): Vector2 {\r\n // return this.#titleTextStyle.measure(ctx, scale, this.#title);\r\n // }\r\n\r\n public calculateBounds(ctx: CanvasRenderingContext2D, camera: Camera): Box {\r\n this.#followTheme();\r\n const tempMeasurement = Zero();\r\n\r\n const doublePadding = this.#padding * 2;\r\n\r\n const screenSpacePosition = Zero();\r\n camera.graphSpaceToScreenSpace(this.#position, screenSpacePosition);\r\n\r\n const size = Zero();\r\n this.#title.size(ctx, 1, size);\r\n\r\n const subtitleSize = Zero();\r\n this.#subTitle.size(ctx, 1, subtitleSize);\r\n size.x = Math.max(size.x, subtitleSize.x);\r\n\r\n if (this.#infoText !== \"\") {\r\n size.x += (size.y * 4);\r\n }\r\n\r\n size.x += doublePadding;\r\n size.y += doublePadding;\r\n\r\n for (const port of [...this.#input, ...this.#output]) {\r\n if (port.hidden()) {\r\n continue;\r\n }\r\n this.#portTextStyle.measure(ctx, 1, port.getDisplayName(), tempMeasurement);\r\n size.y += this.#portRowHeight(port, tempMeasurement.y) + this.#elementSpacing;\r\n size.x = Math.max(size.x, this.#portRowWidth(port, tempMeasurement.x) + doublePadding)\r\n }\r\n\r\n const widgets = this.#hasHiddenPortsToggle() ? [this.#hiddenPortsToggle, ...this.#widgets] : this.#widgets;\r\n for (const widget of widgets) {\r\n if (widget.Hidden?.()) {\r\n continue;\r\n }\r\n const eleSize = widget.Size();\r\n size.y += eleSize.y + this.#elementSpacing;\r\n size.x = Math.max(size.x, (eleSize.x) + doublePadding)\r\n }\r\n\r\n // Add some padding at the end!\r\n size.y += this.#elementSpacing\r\n\r\n size.x = Math.max(size.x, MINIMUM_NODE_WIDTH)\r\n ScaleVector(size, camera.zoom);\r\n\r\n return {\r\n Position: screenSpacePosition,\r\n Size: size,\r\n }\r\n }\r\n\r\n addInput(config: PortConfig): Port {\r\n const port = new Port(this, config.array ? PortType.InputArray : PortType.Input, config);\r\n if (config.widget !== undefined) {\r\n port.setWidget(GlobalWidgetFactory.createFromConfig(this, config.widget));\r\n }\r\n this.#input.push(port);\r\n return port;\r\n }\r\n\r\n addOutput(config: PortConfig): Port {\r\n const port = new Port(this, PortType.Output, config);\r\n this.#output.push(port);\r\n return port;\r\n }\r\n\r\n #hiddenPortsShown = false;\r\n\r\n #hiddenPortsToggle = new HiddenPortsToggle(this);\r\n\r\n #hiddenPortsTogglePosition: Box | null = null;\r\n\r\n hiddenPortsShown(): boolean {\r\n return this.#hiddenPortsShown;\r\n }\r\n\r\n setHiddenPortsShown(shown: boolean): void {\r\n if (shown === this.#hiddenPortsShown) {\r\n return;\r\n }\r\n this.#hiddenPortsShown = shown;\r\n this.invalidateLayout();\r\n }\r\n\r\n hiddenPortCount(): number {\r\n let count = 0;\r\n for (const port of [...this.#input, ...this.#output]) {\r\n if (port.tucked()) {\r\n count++;\r\n }\r\n }\r\n return count;\r\n }\r\n\r\n #hasHiddenPortsToggle(): boolean {\r\n return this.hiddenPortCount() > 0;\r\n }\r\n\r\n addWidget(widget: Widget): void {\r\n this.#widgets.push(widget);\r\n requestRender();\r\n }\r\n\r\n insertWidget(index: number, widget: Widget): void {\r\n const at = Math.max(0, Math.min(index, this.#widgets.length));\r\n this.#widgets.splice(at, 0, widget);\r\n requestRender();\r\n }\r\n\r\n removeWidget(widget: Widget): void {\r\n const index = this.#widgets.indexOf(widget, 0);\r\n if (index === -1) {\r\n throw new Error(\"node does not contain widget\");\r\n }\r\n this.#widgets.splice(index, 1);\r\n requestRender();\r\n }\r\n\r\n removeWidgetAt(index: number): Widget | undefined {\r\n if (index < 0 || index >= this.#widgets.length) {\r\n return undefined;\r\n }\r\n const removed = this.#widgets.splice(index, 1)[0];\r\n requestRender();\r\n return removed;\r\n }\r\n\r\n moveWidget(from: number, to: number): void {\r\n if (from < 0 || from >= this.#widgets.length) {\r\n return;\r\n }\r\n if (to < 0 || to >= this.#widgets.length || from === to) {\r\n return;\r\n }\r\n const [widget] = this.#widgets.splice(from, 1);\r\n this.#widgets.splice(to, 0, widget);\r\n requestRender();\r\n }\r\n\r\n clearWidgets(): void {\r\n this.#widgets.length = 0;\r\n requestRender();\r\n }\r\n\r\n getWidget(index: number): Widget {\r\n return this.#widgets[index];\r\n }\r\n\r\n widgets(): ReadonlyArray<Widget> {\r\n return this.#widgets;\r\n }\r\n\r\n indexOfWidget(widget: Widget): number {\r\n return this.#widgets.indexOf(widget, 0);\r\n }\r\n\r\n widgetCount(): number {\r\n return this.#widgets.length;\r\n }\r\n\r\n translate(delta: Vector2): void {\r\n this.#position.x += delta.x;\r\n this.#position.y += delta.y;\r\n }\r\n\r\n inBounds(ctx: CanvasRenderingContext2D, camera: Camera, position: Vector2): NodeIntersection {\r\n var intersection: NodeIntersection = {}\r\n\r\n const box = this.calculateBounds(ctx, camera);\r\n if (InBox(box, position)) {\r\n intersection.Node = this;\r\n }\r\n\r\n for (let i = 0; i < this.#inputPortPositions.Count(); i++) {\r\n if (!this.#input[i].hidden() && InBox(this.#inputPortPositions.At(i), position)) {\r\n intersection.Node = this;\r\n intersection.PortIndex = i;\r\n intersection.PortIsInput = true;\r\n intersection.Port = this.#input[i]\r\n }\r\n }\r\n\r\n for (let i = 0; i < this.#outputPortPositions.Count(); i++) {\r\n if (!this.#output[i].hidden() && InBox(this.#outputPortPositions.At(i), position)) {\r\n intersection.Node = this;\r\n intersection.PortIndex = i;\r\n intersection.PortIsInput = false;\r\n intersection.Port = this.#output[i];\r\n }\r\n }\r\n\r\n if (this.#hiddenPortsTogglePosition !== null && InBox(this.#hiddenPortsTogglePosition, position)) {\r\n intersection.Node = this;\r\n intersection.Widget = this.#hiddenPortsToggle;\r\n intersection.WidgetBox = this.#hiddenPortsTogglePosition;\r\n }\r\n\r\n for (let i = 0; i < this.#widgetPositions.Count(); i++) {\r\n const widget = this.#widgets[i];\r\n if (widget !== undefined && !widget.Hidden?.() && InBox(this.#widgetPositions.At(i), position)) {\r\n intersection.Node = this;\r\n intersection.WidgetIndex = i;\r\n intersection.Widget = widget;\r\n intersection.WidgetBox = this.#widgetPositions.At(i);\r\n }\r\n }\r\n\r\n for (let i = 0; i < this.#portWidgetPositions.Count(); i++) {\r\n const port = this.#input[i];\r\n if (port !== undefined && port.widgetShown() && InBox(this.#portWidgetPositions.At(i), position)) {\r\n intersection.Node = this;\r\n intersection.Widget = port.widget() as Widget;\r\n intersection.WidgetBox = this.#portWidgetPositions.At(i);\r\n intersection.Port = undefined;\r\n intersection.PortIndex = undefined;\r\n intersection.PortIsInput = undefined;\r\n }\r\n }\r\n\r\n return intersection;\r\n }\r\n\r\n canEditTitle(): boolean {\r\n return this.#canEditTitle;\r\n }\r\n\r\n canEditPorts(): boolean {\r\n return this.#canEditPorts;\r\n }\r\n\r\n title(): string {\r\n return this.#title.get();\r\n }\r\n\r\n setTitle(newTitle: string): void {\r\n let cleaned = newTitle;\r\n if (cleaned === null || cleaned === undefined) {\r\n cleaned = \"\";\r\n }\r\n\r\n const old = this.title();\r\n if (cleaned === old) {\r\n return;\r\n }\r\n\r\n this.#title.set(cleaned);\r\n requestRender();\r\n\r\n for (let i = 0; i < this.#titleChangeCallback.length; i++) {\r\n const callback = this.#titleChangeCallback[i];\r\n callback(this, old, cleaned);\r\n }\r\n }\r\n\r\n setInfo(newInfo: string): void {\r\n let cleaned = newInfo;\r\n if (cleaned === null || cleaned === undefined) {\r\n cleaned = \"\";\r\n }\r\n\r\n if (cleaned === this.#infoText) {\r\n return;\r\n }\r\n\r\n const old = this.#infoText;\r\n this.#infoText = cleaned;\r\n requestRender();\r\n\r\n for (let i = 0; i < this.#infoChangeCallback.length; i++) {\r\n const callback = this.#infoChangeCallback[i];\r\n callback(this, old, cleaned);\r\n }\r\n }\r\n\r\n inputPortPosition(index: number): Box {\r\n return this.#inputPortPositions.At(index);\r\n }\r\n\r\n widgetPosition(index: number): Box | undefined {\r\n if (index < 0 || index >= this.#widgetPositions.Count()) {\r\n return undefined;\r\n }\r\n return this.#widgetPositions.At(index);\r\n }\r\n\r\n inputPort(index: number): Port {\r\n return this.#input[index];\r\n }\r\n\r\n inputs(): number {\r\n return this.#input.length;\r\n }\r\n\r\n outputPortPosition(index: number): Box {\r\n return this.#outputPortPositions.At(index);\r\n }\r\n\r\n outputPort(index: number): Port {\r\n return this.#output[index];\r\n }\r\n\r\n outputs(): number {\r\n return this.#output.length;\r\n }\r\n\r\n #applyStyle(): void {\r\n const style = this.#styleConfig;\r\n const titleText = style?.title?.textStyle?.color ?? Theme.Node.Title.FontColor;\r\n this.#title.style().setColor(titleText);\r\n this.#subTitle.style().setColor(titleText);\r\n this.#infoSymbol.style().setColor(titleText);\r\n\r\n this.#titleColor = style?.title?.color ?? Theme.Node.Title.Color;\r\n\r\n const box = (config: BoxStyleConfig | undefined, border: string, size: number) =>\r\n new BoxStyle(BoxStyleWithFallback(config, {\r\n border: { color: border, size },\r\n radius: Theme.Node.BorderRadius,\r\n color: Theme.Node.BackgroundColor,\r\n }));\r\n this.#stateStyles.set(NodeState.Idle, box(style?.idle, Theme.Node.Border.Idle, 1));\r\n this.#stateStyles.set(NodeState.MouseOver, box(style?.mouseOver, Theme.Node.Border.MouseOver, 1.1));\r\n this.#stateStyles.set(NodeState.Grabbed, box(style?.grabbed, Theme.Node.Border.Grabbed, 2));\r\n this.#selectedStyle = box(style?.selected, Theme.Node.Border.Selected, 1);\r\n\r\n this.#portTextStyle = new TextStyle({\r\n size: style?.portText?.size ?? 14,\r\n color: style?.portText?.color ?? Theme.Node.Port.FontColor,\r\n font: style?.portText?.font,\r\n weight: style?.portText?.weight,\r\n });\r\n\r\n this.#styledForTheme = themeVersion();\r\n }\r\n\r\n #followTheme(): void {\r\n if (this.#styledForTheme !== themeVersion()) {\r\n this.#applyStyle();\r\n }\r\n }\r\n\r\n #calculateStyle(state: NodeState): BoxStyle {\r\n // Let the node being selected override the idle style\r\n if (this.#selected && state === NodeState.Idle) {\r\n return this.#selectedStyle;\r\n }\r\n\r\n let boxStyle = this.#stateStyles.get(state);\r\n if (boxStyle === undefined) {\r\n throw new Error(\"no registered border style for state: \" + state)\r\n }\r\n return boxStyle;\r\n }\r\n\r\n addMessage(message: NodeMessageConfig): void {\r\n this.#messages.push(new MessageRenderer(message));\r\n }\r\n\r\n clearMessages(): void {\r\n this.#messages = [];\r\n }\r\n\r\n #portRowHeight(port: Port, textHeight: number): number {\r\n const slots = port.slots();\r\n const widget = port.widgetShown() ? (port.widget() as Widget).Size().y : 0;\r\n return Math.max(slots > 1 ? slots * ARRAY_SLOT_PITCH : 0, textHeight, widget);\r\n }\r\n\r\n #portRowWidth(port: Port, textWidth: number): number {\r\n if (!port.widgetShown()) {\r\n return textWidth;\r\n }\r\n return textWidth + this.#elementSpacing + (port.widget() as Widget).Size().x;\r\n }\r\n\r\n public hasBeenLaidOut(): boolean {\r\n return this.#laidOut;\r\n }\r\n\r\n /**\r\n * Throws away where the ports were last placed, so wires wait for the\r\n * next draw instead of pointing at the old spots.\r\n */\r\n public invalidateLayout(): void {\r\n this.#laidOut = false;\r\n this.#portOffsets = { input: [], output: [] };\r\n requestRender();\r\n }\r\n\r\n #laidOut: boolean = false;\r\n\r\n render(ctx: CanvasRenderingContext2D, camera: Camera, state: NodeState, mousePosition: Vector2 | undefined, postProcess: PassSubsystem): void {\r\n this.#laidOut = true;\r\n\r\n VectorPool.run(() => {\r\n const tempMeasurement = VectorPool.get();\r\n\r\n this.#inputPortPositions.Clear();\r\n this.#outputPortPositions.Clear();\r\n this.#widgetPositions.Clear();\r\n this.#portWidgetPositions.Clear();\r\n const scaledPadding = this.#padding * camera.zoom;\r\n const scaledElementSpacing = this.#elementSpacing * camera.zoom;\r\n\r\n const nodeBounds = this.calculateBounds(ctx, camera);\r\n\r\n // Background\r\n const nodeStyle = this.#calculateStyle(state);\r\n nodeStyle.Draw(ctx, nodeBounds, camera.zoom);\r\n\r\n // Fixed screen width, so the node stays findable when zoomed far out.\r\n if (this.#highlighted) {\r\n const gap = 3;\r\n ctx.save();\r\n ctx.strokeStyle = Theme.Node.Border.Highlighted;\r\n ctx.lineWidth = 2;\r\n ctx.beginPath();\r\n ctx.roundRect(\r\n nodeBounds.Position.x - gap, nodeBounds.Position.y - gap,\r\n nodeBounds.Size.x + gap * 2, nodeBounds.Size.y + gap * 2,\r\n nodeStyle.radius() * camera.zoom + gap\r\n );\r\n ctx.stroke();\r\n ctx.restore();\r\n }\r\n\r\n // Title\r\n const borderSize = nodeStyle.borderSize();\r\n ctx.textAlign = TextAlign.Center;\r\n ctx.textBaseline = TextBaseline.Middle;\r\n\r\n const titleSize = VectorPool.get();\r\n this.#title.size(ctx, camera.zoom, titleSize);\r\n\r\n const subtitleSize = VectorPool.get();\r\n this.#subTitle.size(ctx, camera.zoom, subtitleSize);\r\n\r\n const titleBoxSize = VectorPool.get();\r\n titleBoxSize.x = nodeBounds.Size.x;\r\n titleBoxSize.y = titleSize.y + (scaledPadding * 2);\r\n\r\n ctx.fillStyle = this.#titleColor;\r\n ctx.beginPath();\r\n const titleX = nodeBounds.Position.x + (borderSize * camera.zoom * 0.5)\r\n const titleY = nodeBounds.Position.y + (borderSize * camera.zoom * 0.5)\r\n const titleWidth = titleBoxSize.x - (borderSize * camera.zoom);\r\n const titleHeight = titleBoxSize.y - (borderSize * camera.zoom * 0.5);\r\n ctx.roundRect(\r\n titleX, titleY, titleWidth, titleHeight,\r\n [nodeStyle.radius() * camera.zoom, nodeStyle.radius() * camera.zoom, 0, 0]\r\n );\r\n ctx.fill();\r\n\r\n if (Theme.Node.Bevel !== null) {\r\n drawBevel(ctx, nodeBounds, camera.zoom, Theme.Node.Bevel, false);\r\n }\r\n\r\n const titlePosition = VectorPool.get();\r\n titlePosition.x = nodeBounds.Position.x + (nodeBounds.Size.x / 2)\r\n titlePosition.y = nodeBounds.Position.y + scaledPadding + (titleSize.y / 2)\r\n\r\n if (this.#subTitle.get() !== \"\") {\r\n const subtitlePosition = VectorPool.get();\r\n CopyVector2(subtitlePosition, titlePosition);\r\n\r\n // TODO: I'm fudging a bunch of numbers ot make it fit nicely \r\n // together. \r\n // \r\n // Need to come up with like, proper logic about how we ensure \r\n // title and subtitle fit together\r\n subtitlePosition.y -= titleSize.y / 1.5;\r\n titlePosition.y += scaledPadding / 2\r\n\r\n this.#subTitle.render(ctx, camera.zoom, subtitlePosition);\r\n }\r\n\r\n this.#title.render(ctx, camera.zoom, titlePosition);\r\n\r\n // Info symbol\r\n if (this.#infoText !== \"\") {\r\n const infoRadius = titleHeight * .25;\r\n const centerX = titleX + titleWidth - (titleHeight * .25) - infoRadius;\r\n const centerY = titleY + (titleHeight * .25) + infoRadius;\r\n\r\n const infoPosition = VectorPool.get();\r\n infoPosition.x = centerX;\r\n infoPosition.y = centerY + (titleHeight * .025);\r\n\r\n let infoLineThickness = 1.5 * camera.zoom;\r\n\r\n if (mousePosition && Distance(infoPosition, mousePosition) <= infoRadius) {\r\n infoLineThickness *= 1.5;\r\n\r\n // This is a slightly expensive function if we're not \r\n // caching, but it only executes while we're mousing over \r\n // the info symbol, so I'm not particularly obligated to\r\n // optimize it. \r\n //\r\n // If you're just bored, def cache the split string method,\r\n // and figure out a system to recalculate as a node has its\r\n // title, port, or widgets change.\r\n //\r\n // Should probably break out the lambda into a proper \r\n // function as well. I think as it is, we're creating a new\r\n // lambda function per frame?\r\n postProcess.queue(() => {\r\n this.#infoSymbol.style().setupStyle(ctx, camera.zoom);\r\n ctx.textAlign = TextAlign.Center;\r\n\r\n const infoBoxWidth = titleWidth * 1.5;\r\n const textEntries = splitStringIntoLines(ctx, this.#infoText, infoBoxWidth);\r\n\r\n const lineHeight = (this.#infoSymbol.style().getSize() + 2);\r\n const infoBoxHeight = lineHeight * textEntries.length * camera.zoom;\r\n const scaledLineHeight = lineHeight * camera.zoom;\r\n const start = titleY - infoBoxHeight - (scaledLineHeight / 2);\r\n\r\n // Draw box\r\n ctx.fillStyle = this.#titleColor;\r\n ctx.beginPath();\r\n ctx.roundRect(\r\n centerX - (infoBoxWidth / 2) - (scaledLineHeight / 2),\r\n start - scaledLineHeight,\r\n infoBoxWidth + scaledLineHeight,\r\n infoBoxHeight + scaledLineHeight,\r\n nodeStyle.radius() * camera.zoom\r\n );\r\n ctx.fill();\r\n\r\n // Render Text\r\n this.#infoSymbol.style().setupStyle(ctx, camera.zoom);\r\n for (let i = 0; i < textEntries.length; i++) {\r\n const entry = textEntries[i];\r\n ctx.fillText(entry, centerX, start + (i * lineHeight * camera.zoom));\r\n }\r\n });\r\n }\r\n\r\n ctx.beginPath();\r\n ctx.arc(centerX, centerY, infoRadius, 0, 2 * Math.PI, false);\r\n ctx.lineWidth = infoLineThickness;\r\n ctx.strokeStyle = this.#infoSymbol.getColor();\r\n ctx.stroke();\r\n\r\n ctx.textAlign = TextAlign.Center;\r\n this.#infoSymbol.render(ctx, camera.zoom, infoPosition);\r\n }\r\n\r\n\r\n // Input Ports\r\n let startY = nodeBounds.Position.y + (scaledPadding * 2) + titleSize.y + scaledElementSpacing;\r\n const leftSide = nodeBounds.Position.x + scaledPadding;\r\n for (let i = 0; i < this.#input.length; i++) {\r\n ctx.textAlign = TextAlign.Left;\r\n const port = this.#input[i];\r\n if (port.hidden()) {\r\n this.#inputPortPositions.Push({ Position: { x: nodeBounds.Position.x, y: startY }, Size: { x: 0, y: 0 } });\r\n this.#portWidgetPositions.Push({ Position: { x: nodeBounds.Position.x, y: startY }, Size: { x: 0, y: 0 } });\r\n continue;\r\n }\r\n this.#portTextStyle.measure(ctx, 1, port.getDisplayName(), tempMeasurement);\r\n const portHeight = this.#portRowHeight(port, tempMeasurement.y) * camera.zoom;\r\n const position = VectorPool.get();\r\n\r\n position.x = nodeBounds.Position.x;\r\n position.y = startY + (portHeight / 2);\r\n\r\n // Text\r\n this.#portTextStyle.setupStyle(ctx, camera.zoom);\r\n ctx.fillText(port.getDisplayName(), leftSide, position.y);\r\n\r\n // Widget\r\n if (port.widgetShown()) {\r\n const widget = port.widget() as Widget;\r\n const widgetHeight = widget.Size().y * camera.zoom;\r\n const widgetLeft = leftSide + (tempMeasurement.x * camera.zoom) + scaledElementSpacing;\r\n const box: Box = {\r\n Position: { x: widgetLeft, y: startY + ((portHeight - widgetHeight) / 2) },\r\n Size: { x: nodeBounds.Position.x + nodeBounds.Size.x - scaledPadding - widgetLeft, y: widgetHeight },\r\n };\r\n widget.Draw(ctx, box, camera.zoom, mousePosition);\r\n this.#portWidgetPositions.Push(box);\r\n } else {\r\n this.#portWidgetPositions.Push({ Position: { x: nodeBounds.Position.x, y: startY }, Size: { x: 0, y: 0 } });\r\n }\r\n\r\n // Port\r\n this.#inputPortPositions.Push(port.render(ctx, position, camera, mousePosition, postProcess));\r\n\r\n startY += portHeight + scaledElementSpacing;\r\n }\r\n\r\n // Output Ports\r\n const rightSide = nodeBounds.Position.x + nodeBounds.Size.x;\r\n ctx.textAlign = TextAlign.Right;\r\n for (let i = 0; i < this.#output.length; i++) {\r\n const port = this.#output[i];\r\n if (port.hidden()) {\r\n this.#outputPortPositions.Push({ Position: { x: rightSide, y: startY }, Size: { x: 0, y: 0 } });\r\n continue;\r\n }\r\n this.#portTextStyle.measure(ctx, 1, port.getDisplayName(), tempMeasurement);\r\n const portHeight = tempMeasurement.y * camera.zoom;\r\n const position = VectorPool.get();\r\n position.x = rightSide;\r\n position.y = startY + (portHeight / 2);\r\n\r\n // Text\r\n this.#portTextStyle.setupStyle(ctx, camera.zoom);\r\n ctx.fillText(port.getDisplayName(), rightSide - scaledPadding, position.y);\r\n\r\n // Port\r\n this.#outputPortPositions.Push(port.render(ctx, position, camera, mousePosition, postProcess));\r\n\r\n startY += portHeight + scaledElementSpacing;\r\n }\r\n\r\n this.#hiddenPortsTogglePosition = null;\r\n if (this.#hasHiddenPortsToggle()) {\r\n const box: Box = {\r\n Position: { x: nodeBounds.Position.x + scaledPadding, y: startY },\r\n Size: { x: nodeBounds.Size.x - (scaledPadding * 2), y: this.#hiddenPortsToggle.Size().y * camera.zoom },\r\n };\r\n this.#hiddenPortsToggle.Draw(ctx, box, camera.zoom, mousePosition);\r\n this.#hiddenPortsTogglePosition = box;\r\n startY += box.Size.y + scaledElementSpacing;\r\n }\r\n\r\n // Widgets\r\n for (let i = 0; i < this.#widgets.length; i++) {\r\n const widget = this.#widgets[i];\r\n if (widget.Hidden?.()) {\r\n this.#widgetPositions.Push({ Position: { x: nodeBounds.Position.x, y: startY }, Size: { x: 0, y: 0 } });\r\n continue;\r\n }\r\n const widgetSize = widget.Size();\r\n const box: Box = {\r\n Position: { x: nodeBounds.Position.x + scaledPadding, y: startY },\r\n Size: { x: nodeBounds.Size.x - (scaledPadding * 2), y: widgetSize.y * camera.zoom },\r\n };\r\n widget.Draw(ctx, box, camera.zoom, mousePosition);\r\n this.#widgetPositions.Push(box);\r\n startY += box.Size.y + scaledElementSpacing;\r\n }\r\n\r\n // Messages\r\n const messageStart = VectorPool.get();\r\n messageStart.x = nodeBounds.Position.x + (nodeBounds.Size.x / 2);\r\n messageStart.y = nodeBounds.Position.y + nodeBounds.Size.y + (15 * camera.zoom);\r\n for (let i = 0; i < this.#messages.length; i++) {\r\n const message = this.#messages[i];\r\n messageStart.y += message.render(ctx, camera.zoom, messageStart, !(state === NodeState.Idle)) + (10 * camera.zoom);\r\n }\r\n\r\n this.#rememberPortOffsets(nodeBounds, camera.zoom);\r\n })\r\n }\r\n\r\n #portOffsets: { input: Array<Box>, output: Array<Box> } = { input: [], output: [] };\r\n\r\n #rememberPortOffsets(bounds: Box, zoom: number): void {\r\n if (zoom <= 0) {\r\n return;\r\n }\r\n\r\n const record = (positions: List<Box>, into: Array<Box>) => {\r\n into.length = 0;\r\n for (let i = 0; i < positions.Count(); i++) {\r\n const box = positions.At(i);\r\n into.push({\r\n Position: {\r\n x: (box.Position.x - bounds.Position.x) / zoom,\r\n y: (box.Position.y - bounds.Position.y) / zoom,\r\n },\r\n Size: {\r\n x: box.Size.x / zoom,\r\n y: box.Size.y / zoom,\r\n },\r\n });\r\n }\r\n };\r\n\r\n record(this.#inputPortPositions, this.#portOffsets.input);\r\n record(this.#outputPortPositions, this.#portOffsets.output);\r\n }\r\n\r\n public layoutPortsWithoutDrawing(bounds: Box, zoom: number): boolean {\r\n if (!this.placePorts(bounds, zoom)) {\r\n return false;\r\n }\r\n this.#widgetPositions.Clear();\r\n this.#portWidgetPositions.Clear();\r\n this.#hiddenPortsTogglePosition = null;\r\n return true;\r\n }\r\n\r\n public placePorts(bounds: Box, zoom: number): boolean {\r\n if (this.#portOffsets.input.length === 0 && this.#portOffsets.output.length === 0) {\r\n return false;\r\n }\r\n\r\n const project = (offsets: Array<Box>, into: List<Box>) => {\r\n into.Clear();\r\n for (let i = 0; i < offsets.length; i++) {\r\n const offset = offsets[i];\r\n into.Push({\r\n Position: {\r\n x: bounds.Position.x + (offset.Position.x * zoom),\r\n y: bounds.Position.y + (offset.Position.y * zoom),\r\n },\r\n Size: {\r\n x: offset.Size.x * zoom,\r\n y: offset.Size.y * zoom,\r\n },\r\n });\r\n }\r\n };\r\n\r\n project(this.#portOffsets.input, this.#inputPortPositions);\r\n project(this.#portOffsets.output, this.#outputPortPositions);\r\n\r\n return true;\r\n }\r\n}\r\n", "export enum MarkdownTokenType {\r\n Text = \"Text\",\r\n H1 = \"H1\",\r\n H2 = \"H2\",\r\n H3 = \"H3\",\r\n NewLine = \"New Line\",\r\n Star = \"Star\",\r\n Space = \"Space\",\r\n BackTick = \"`\"\r\n}\r\n\r\nexport class MarkdownToken {\r\n\r\n #type: MarkdownTokenType;\r\n\r\n #lexeme: string\r\n\r\n #tokenStart: number\r\n\r\n #tokenEnd: number\r\n\r\n constructor(type: MarkdownTokenType, lexeme: string, tokenStart: number, tokenEnd: number) {\r\n this.#type = type;\r\n this.#lexeme = lexeme;\r\n this.#tokenStart = tokenStart;\r\n this.#tokenEnd = tokenEnd;\r\n }\r\n\r\n type(): MarkdownTokenType {\r\n return this.#type;\r\n }\r\n\r\n lexeme(): string {\r\n return this.#lexeme;\r\n }\r\n\r\n tokenStart(): number {\r\n return this.#tokenStart;\r\n }\r\n tokenEnd(): number {\r\n return this.#tokenEnd;\r\n }\r\n}\r\n", "import { MarkdownToken, MarkdownTokenType } from \"./token\";\r\n\r\nexport class MarkdownLexicalParser {\r\n\r\n #body: string;\r\n\r\n #index: number\r\n\r\n #tokens: Array<MarkdownToken>;\r\n\r\n constructor(body: string) {\r\n this.#index = 0;\r\n this.#body = body;\r\n this.#tokens = new Array<MarkdownToken>();\r\n }\r\n\r\n tokens(): Array<MarkdownToken> {\r\n return this.#tokens;\r\n }\r\n\r\n #current(): string {\r\n if (this.#index > this.#body.length - 1) {\r\n return \"\"\r\n }\r\n return this.#body.charAt(this.#index);\r\n }\r\n\r\n #inc(): void {\r\n this.#index++\r\n }\r\n\r\n #next(): string {\r\n this.#index++\r\n if (this.#index > this.#body.length - 1) {\r\n return \"\"\r\n }\r\n return this.#body.charAt(this.#index);\r\n }\r\n\r\n #tokenStart = 0;\r\n\r\n #addToken(token: MarkdownTokenType, lexeme: string, start?: number): void {\r\n this.#tokens.push(new MarkdownToken(token, lexeme, start ?? this.#tokenStart, this.#index));\r\n }\r\n\r\n #header(): void {\r\n let count = 0;\r\n while (this.#current() === \"#\") {\r\n count++;\r\n this.#inc();\r\n }\r\n\r\n let type = MarkdownTokenType.H3;\r\n if (count === 1) {\r\n type = MarkdownTokenType.H1;\r\n } else if (count === 2) {\r\n type = MarkdownTokenType.H2;\r\n }\r\n\r\n this.#addToken(type, \"#\".repeat(count));\r\n }\r\n\r\n #whiteSpace(): void {\r\n let char = this.#current();\r\n\r\n while (char !== \"\") {\r\n if (char !== \" \" && char !== \"\\t\") {\r\n break;\r\n }\r\n char = this.#next();\r\n }\r\n\r\n this.#addToken(MarkdownTokenType.Space, \" \")\r\n }\r\n\r\n #text(): void {\r\n let char = this.#current();\r\n\r\n let started = -1;\r\n\r\n while (char !== \"\") {\r\n if (char === \" \" || char === \"\\t\") {\r\n\r\n // Eat white space if we haven't seen anything yet!\r\n if (started === -1) {\r\n this.#inc();\r\n continue;\r\n }\r\n }\r\n\r\n // End of the line!\r\n if (char === \"\\n\" || char === \"*\" || char === \"`\") {\r\n if (started != -1) {\r\n this.#addToken(MarkdownTokenType.Text, this.#body.substring(started, this.#index))\r\n }\r\n return;\r\n }\r\n\r\n\r\n if (started === -1) {\r\n started = this.#index;\r\n }\r\n\r\n char = this.#next();\r\n }\r\n\r\n if (started != -1) {\r\n this.#addToken(MarkdownTokenType.Text, this.#body.substring(started, this.#index), started)\r\n }\r\n }\r\n\r\n parse(): void {\r\n let char = this.#current();\r\n\r\n while (char !== \"\") {\r\n this.#tokenStart = this.#index;\r\n\r\n if (char === \" \" || char === \"\\t\") {\r\n this.#whiteSpace();\r\n } else if (char === \"#\") {\r\n this.#header();\r\n } else if (char === \"\\n\") {\r\n this.#inc();\r\n this.#addToken(MarkdownTokenType.NewLine, \"\\n\");\r\n } else if (char === \"*\") {\r\n this.#inc();\r\n this.#addToken(MarkdownTokenType.Star, \"*\");\r\n } else if (char === \"`\") {\r\n this.#inc();\r\n this.#addToken(MarkdownTokenType.BackTick, \"`\");\r\n } else {\r\n this.#text();\r\n }\r\n\r\n char = this.#current();\r\n }\r\n }\r\n}\r\n", "import { requestRender } from \"../render_scheduler\";\r\nimport { Theme } from \"../theme\";\r\nimport { List } from \"../types/list\";\r\nimport { Text } from \"../types/text\";\r\nimport { Vector2, Zero } from \"../types/vector2\";\r\n\r\nexport interface MarkdownEntry {\r\n render(ctx: CanvasRenderingContext2D, position: Vector2, scale: number, maxWidth: number): number\r\n}\r\n\r\nfunction onFontsLoaded(callback: () => void): void {\r\n if (typeof document === \"undefined\" || document.fonts === undefined) {\r\n return;\r\n }\r\n document.fonts.addEventListener(\"loadingdone\", () => {\r\n callback();\r\n requestRender();\r\n });\r\n}\r\n\r\nexport class CodeBlockEntry {\r\n\r\n #text: Text\r\n\r\n #calculatedPositions: List<Vector2>\r\n\r\n #calculatedEntries: List<Text>\r\n\r\n #calculatedForWidth: number;\r\n\r\n text(): Text {\r\n return this.#text;\r\n }\r\n\r\n constructor(text: Text) {\r\n this.#text = text;\r\n this.#calculatedForWidth = -1\r\n\r\n this.#calculatedEntries = new List<Text>();\r\n this.#calculatedPositions = new List<Vector2>();\r\n\r\n onFontsLoaded(() => {\r\n this.#calculatedForWidth = -1\r\n });\r\n }\r\n\r\n #calculateLayout(ctx: CanvasRenderingContext2D, maxWidth: number): void {\r\n if (this.#calculatedForWidth === maxWidth) {\r\n return;\r\n }\r\n\r\n let adjustedWith = maxWidth;\r\n adjustedWith -= Theme.Note.CodeBlock.Padding * 2;\r\n\r\n this.#calculatedEntries.Clear();\r\n this.#calculatedPositions.Clear();\r\n\r\n let curHeight = 0;\r\n const lineInc = this.#text.style().getSize() + Theme.Note.LineSpacing;\r\n\r\n let entries = this.#text.split(\"\\n\")\r\n\r\n for (let entryIndex = 0; entryIndex < entries.length; entryIndex++) {\r\n const entry = entries[entryIndex];\r\n\r\n let lines = entry.breakIntoLines(ctx, adjustedWith);\r\n for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {\r\n\r\n this.#calculatedEntries.Push(lines[lineIndex])\r\n this.#calculatedPositions.Push({\r\n x: 0,\r\n y: curHeight,\r\n })\r\n \r\n curHeight += lineInc;\r\n }\r\n }\r\n\r\n this.#calculatedForWidth = maxWidth;\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, position: Vector2, scale: number, maxWidth: number): number {\r\n this.#calculateLayout(ctx, maxWidth);\r\n\r\n const padding = Theme.Note.CodeBlock.Padding * scale;\r\n const lineCount = this.#calculatedEntries.Count();\r\n const lastTop = lineCount === 0 ? 0 : this.#calculatedPositions.At(lineCount - 1).y;\r\n const contentHeight = lineCount === 0 ? 0 : (lastTop + this.#text.style().getSize()) * scale;\r\n const height = contentHeight + (padding * 2);\r\n\r\n ctx.fillStyle = Theme.Note.CodeBlock.BackgroundColor;\r\n ctx.beginPath();\r\n ctx.roundRect(\r\n position.x,\r\n position.y,\r\n maxWidth * scale,\r\n height,\r\n Theme.Note.CodeBlock.BorderRadius * scale\r\n );\r\n ctx.fill();\r\n\r\n const baseline = ctx.textBaseline;\r\n ctx.textBaseline = \"top\";\r\n for (let i = 0; i < lineCount; i++) {\r\n const entry = this.#calculatedEntries.At(i);\r\n const pos = this.#calculatedPositions.At(i);\r\n\r\n entry.render(ctx, scale, {\r\n x: (pos.x * scale) + position.x + padding,\r\n y: (pos.y * scale) + position.y + padding\r\n });\r\n }\r\n ctx.textBaseline = baseline;\r\n\r\n return height;\r\n }\r\n}\r\n\r\nexport class UnorderedListMarkdownEntry {\r\n\r\n #entries: Array<BasicMarkdownEntry>;\r\n\r\n constructor(entries: Array<BasicMarkdownEntry>) {\r\n this.#entries = entries;\r\n }\r\n\r\n entries(): ReadonlyArray<BasicMarkdownEntry> {\r\n return this.#entries;\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, position: Vector2, scale: number, maxWidth: number): number {\r\n let offset = 0;\r\n let shift = 20;\r\n\r\n let pos = {\r\n x: position.x + (shift * scale),\r\n y: position.y\r\n }\r\n\r\n let dot = Theme.Note.DotSize * scale;\r\n\r\n for (let i = 0; i < this.#entries.length; i++) {\r\n\r\n ctx.beginPath();\r\n ctx.arc(position.x + dot, pos.y + (dot * 3), dot, 0, 2 * Math.PI);\r\n ctx.fill();\r\n\r\n offset += this.#entries[i].render(ctx, pos, scale, maxWidth - shift) + (scale * Theme.Note.LineSpacing * 2);\r\n pos.y = position.y + offset;\r\n }\r\n\r\n return offset;\r\n }\r\n}\r\n\r\nexport class BasicMarkdownEntry {\r\n\r\n #underline: boolean;\r\n\r\n #background: boolean;\r\n\r\n #entries: Array<Text>\r\n\r\n #calculatedPositions: List<Vector2>\r\n\r\n #calculatedEntries: List<Text>\r\n\r\n #calculatedForWidth: number;\r\n\r\n lines(): ReadonlyArray<Text> {\r\n return this.#entries;\r\n }\r\n\r\n constructor(lines: Array<Text>, underline: boolean, background: boolean) {\r\n this.#entries = lines;\r\n this.#underline = underline;\r\n this.#background = background;\r\n this.#calculatedForWidth = -1\r\n\r\n this.#calculatedEntries = new List<Text>();\r\n this.#calculatedPositions = new List<Vector2>();\r\n\r\n onFontsLoaded(() => {\r\n this.#calculatedForWidth = -1\r\n });\r\n }\r\n\r\n #calculateLayout(ctx: CanvasRenderingContext2D, maxWidth: number): void {\r\n if (this.#calculatedForWidth === maxWidth) {\r\n return;\r\n }\r\n\r\n let adjustedWith = maxWidth;\r\n if (this.#background) {\r\n adjustedWith -= Theme.Note.CodeBlock.Padding * 2;\r\n }\r\n\r\n this.#calculatedEntries.Clear();\r\n this.#calculatedPositions.Clear();\r\n\r\n const curPosition: Vector2 = Zero();\r\n const texSize: Vector2 = Zero();\r\n\r\n let currentLineHeight = 0;\r\n const currentLineText = new List<Text>();\r\n const currentLineWidths = new List<number>();\r\n\r\n for (let entryIndex = 0; entryIndex < this.#entries.length; entryIndex++) {\r\n const entry = this.#entries[entryIndex];\r\n\r\n let lines = entry.splitAtWidth(ctx, adjustedWith - curPosition.x);\r\n let i = 0;\r\n while (lines.length > 1 && i < 100) {\r\n i++\r\n\r\n // We can't collapse this thing any further. Break out of the \r\n // while loop before we have infinite loop on our hands\r\n // if (lines[0].get() === \"\" && lines[1].get().length === 1) {\r\n // lines[0] = lines[1];\r\n // break;\r\n // }\r\n\r\n // We can't collapse this thing any further. Break out of the \r\n // while loop before we have infinite loop on our hands\r\n if (lines[0].get() === \"\" && currentLineText.Count() === 0) {\r\n\r\n if (lines[1].get().length === 1) {\r\n lines[0] = lines[1];\r\n break;\r\n } else {\r\n lines = lines[1].splitAtIndex(1);\r\n }\r\n\r\n }\r\n\r\n // This effectiviely finishes off the line we're currenly working on.\r\n if (lines[0].get() !== \"\") {\r\n lines[0].size(ctx, 1, texSize);\r\n currentLineHeight = Math.max(currentLineHeight, texSize.y);\r\n\r\n currentLineText.Push(lines[0]);\r\n currentLineWidths.Push(curPosition.x);\r\n }\r\n\r\n curPosition.y += currentLineHeight;\r\n\r\n // Take everything we're working with and finalize it\r\n for (let i = 0; i < currentLineText.Count(); i++) {\r\n this.#calculatedEntries.Push(currentLineText.At(i));\r\n this.#calculatedPositions.Push({ x: currentLineWidths.At(i), y: curPosition.y })\r\n }\r\n\r\n currentLineText.Clear();\r\n currentLineWidths.Clear();\r\n\r\n curPosition.y += Theme.Note.LineSpacing;\r\n currentLineHeight = 0;\r\n curPosition.x = 0;\r\n\r\n lines = lines[1].splitAtWidth(ctx, adjustedWith);\r\n }\r\n if (i === 100) {\r\n console.log(lines)\r\n }\r\n\r\n lines[0].size(ctx, 1, texSize);\r\n currentLineHeight = Math.max(currentLineHeight, texSize.y)\r\n\r\n currentLineText.Push(lines[0]);\r\n currentLineWidths.Push(curPosition.x);\r\n\r\n curPosition.x += texSize.x;\r\n }\r\n\r\n curPosition.y += currentLineHeight;\r\n\r\n // Take everything we're working with and finalize it\r\n for (let i = 0; i < currentLineText.Count(); i++) {\r\n this.#calculatedEntries.Push(currentLineText.At(i));\r\n this.#calculatedPositions.Push({ x: currentLineWidths.At(i), y: curPosition.y })\r\n }\r\n\r\n this.#calculatedForWidth = maxWidth;\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, position: Vector2, scale: number, maxWidth: number): number {\r\n this.#calculateLayout(ctx, maxWidth);\r\n\r\n let padding = 0;\r\n if (this.#background) {\r\n padding += Theme.Note.CodeBlock.Padding * scale;\r\n }\r\n\r\n\r\n if (this.#background) {\r\n let max = 0;\r\n for (let i = 0; i < this.#calculatedEntries.Count(); i++) {\r\n const pos = this.#calculatedPositions.At(i);\r\n max = Math.max(max, pos.y * scale)\r\n }\r\n\r\n const y = position.y + max + (scale * 5)\r\n ctx.fillStyle = Theme.Note.CodeBlock.BackgroundColor;\r\n ctx.beginPath();\r\n ctx.roundRect(\r\n position.x,\r\n position.y,\r\n maxWidth * scale,\r\n max + (padding * 2),\r\n Theme.Note.CodeBlock.BorderRadius * scale\r\n );\r\n ctx.fill();\r\n }\r\n\r\n\r\n let max = 0;\r\n for (let i = 0; i < this.#calculatedEntries.Count(); i++) {\r\n const entry = this.#calculatedEntries.At(i);\r\n const pos = this.#calculatedPositions.At(i);\r\n\r\n entry.render(ctx, scale, {\r\n x: (pos.x * scale) + position.x + padding,\r\n y: (pos.y * scale) + position.y + padding\r\n });\r\n\r\n max = Math.max(max, pos.y * scale)\r\n }\r\n\r\n // Add underline \r\n if (this.#underline) {\r\n const y = position.y + max + (scale * 5)\r\n ctx.strokeStyle = Theme.Note.FontColor;\r\n ctx.lineWidth = Theme.Note.HeaderLineWidth * scale;\r\n ctx.beginPath();\r\n ctx.moveTo(position.x, y);\r\n ctx.lineTo(position.x + (maxWidth * scale), y);\r\n ctx.stroke();\r\n }\r\n\r\n return max + (padding * 2);\r\n }\r\n}\r\n", "import { FontStyle, FontWeight, TextStyleConfig } from \"../styles/text\";\r\nimport { Theme } from \"../theme\";\r\nimport { Text } from \"../types/text\";\r\nimport { BasicMarkdownEntry, CodeBlockEntry, MarkdownEntry, UnorderedListMarkdownEntry } from \"./entry\";\r\nimport { MarkdownToken, MarkdownTokenType } from \"./token\";\r\n\r\nexport class MarkdownSyntaxParser {\r\n\r\n #tokens: Array<MarkdownToken>;\r\n\r\n #index: number;\r\n\r\n #originalText: string;\r\n\r\n constructor(originalText: string, tokens: Array<MarkdownToken>) {\r\n this.#originalText = originalText;\r\n this.#index = 0;\r\n this.#tokens = tokens;\r\n }\r\n\r\n #current(): MarkdownToken | null {\r\n if (this.#index > this.#tokens.length - 1) {\r\n return null\r\n }\r\n return this.#tokens[this.#index];\r\n }\r\n\r\n #inc(): void {\r\n this.#index++\r\n }\r\n\r\n #next(): MarkdownToken | null {\r\n this.#index++\r\n if (this.#index >= this.#tokens.length) {\r\n return null\r\n }\r\n return this.#tokens[this.#index];\r\n }\r\n\r\n #peak(): MarkdownToken | null {\r\n return this.#peakInto(1);\r\n }\r\n\r\n #peakInto(amount: number): MarkdownToken | null {\r\n if (this.#index + amount >= this.#tokens.length) {\r\n return null\r\n }\r\n return this.#tokens[this.#index + amount];\r\n }\r\n\r\n #emphasis(): Array<Text> {\r\n\r\n // Count the stars either side of the content and match as many as\r\n // both ends can supply; the rest stay on the line as characters.\r\n //\r\n // *a* -> <i>a</i> **a* -> *<i>a</i>\r\n // **a** -> <b>a</b> *a** -> <i>a</i>*\r\n // **a f** -> <b>a f</b> *a -> *a\r\n // ** a ** -> ** a ** **a ** -> **a **\r\n\r\n // A star with a space after it opens nothing, so leave the space\r\n // where it is rather than consuming it - the caller still has to\r\n // read it as part of the line.\r\n if (this.#peak()?.type() === MarkdownTokenType.Space) {\r\n return [new Text(\"*\")];\r\n }\r\n\r\n const openers = this.#runOfStars();\r\n\r\n let content = \"\";\r\n let closers = 0;\r\n while (true) {\r\n const token = this.#current();\r\n if (token === null || token.type() === MarkdownTokenType.NewLine) {\r\n break;\r\n }\r\n if (token.type() === MarkdownTokenType.Star) {\r\n closers = this.#runOfStars();\r\n break;\r\n }\r\n content += token.lexeme();\r\n this.#inc();\r\n }\r\n\r\n // Leave the reader on the last token taken, since the caller steps\r\n // forward once more before looking at anything.\r\n this.#index--;\r\n\r\n // A run of stars only emphasises what it hugs. With a space against\r\n // the inside of either end, or nothing between them at all, the\r\n // stars are just stars.\r\n const hugsContent = content !== \"\"\r\n && content.trimStart() === content\r\n && content.trimEnd() === content;\r\n\r\n const matched = hugsContent ? Math.min(openers, closers) : 0;\r\n if (matched === 0) {\r\n return [new Text(\"*\".repeat(openers) + content + \"*\".repeat(closers))];\r\n }\r\n\r\n const style: TextStyleConfig = {};\r\n if (matched >= 2) {\r\n style.weight = FontWeight.Bold;\r\n } else {\r\n style.style = FontStyle.Italic;\r\n }\r\n\r\n // Stars past the pair that matched were never part of the emphasis,\r\n // so they stay on the line as the characters they are.\r\n const runs = new Array<Text>();\r\n if (openers > matched) {\r\n runs.push(new Text(\"*\".repeat(openers - matched)));\r\n }\r\n runs.push(new Text(content, style));\r\n if (closers > matched) {\r\n runs.push(new Text(\"*\".repeat(closers - matched)));\r\n }\r\n return runs;\r\n }\r\n\r\n /** Consumes a run of stars, leaving the reader on the token after it. */\r\n #runOfStars(): number {\r\n let count = 0;\r\n while (this.#current()?.type() === MarkdownTokenType.Star) {\r\n count++;\r\n this.#inc();\r\n }\r\n return count;\r\n }\r\n\r\n /**\r\n * Reads `code` up to the closing backtick on the same line. An opening\r\n * backtick with no partner is only a backtick.\r\n */\r\n #inlineCode(): Array<Text> {\r\n const opened = this.#index;\r\n\r\n this.#inc();\r\n let content = \"\";\r\n while (true) {\r\n const token = this.#current();\r\n if (token === null || token.type() === MarkdownTokenType.NewLine) {\r\n this.#index = opened;\r\n return [new Text(\"`\")];\r\n }\r\n if (token.type() === MarkdownTokenType.BackTick) {\r\n break;\r\n }\r\n content += token.lexeme();\r\n this.#inc();\r\n }\r\n\r\n return [new Text(content, { font: Theme.Note.CodeFontFamily ?? \"monospace\" })];\r\n }\r\n\r\n #text(): Array<Text> {\r\n let contents: Array<Text> = new Array<Text>();\r\n let textContent = \"\";\r\n\r\n let token = this.#current();\r\n\r\n // Read off all starting whitespace \r\n while (token !== null && token.type() === MarkdownTokenType.Space) {\r\n token = this.#next();\r\n }\r\n\r\n while (token !== null && token.type() !== MarkdownTokenType.NewLine) {\r\n switch (token.type()) {\r\n case MarkdownTokenType.Text:\r\n case MarkdownTokenType.H1:\r\n case MarkdownTokenType.H2:\r\n case MarkdownTokenType.H3:\r\n case MarkdownTokenType.Space:\r\n textContent += token.lexeme();\r\n break;\r\n\r\n case MarkdownTokenType.Star:\r\n case MarkdownTokenType.BackTick:\r\n if (textContent !== \"\") {\r\n contents.push(new Text(textContent))\r\n textContent = \"\";\r\n }\r\n const runs = token.type() === MarkdownTokenType.Star\r\n ? this.#emphasis()\r\n : this.#inlineCode();\r\n for (let i = 0; i < runs.length; i++) {\r\n contents.push(runs[i]);\r\n }\r\n break;\r\n }\r\n\r\n token = this.#next();\r\n }\r\n\r\n if (textContent !== \"\") {\r\n contents.push(new Text(textContent))\r\n }\r\n\r\n return contents;\r\n }\r\n\r\n #h1(): BasicMarkdownEntry {\r\n // Move off of the header token\r\n this.#inc();\r\n\r\n const text = this.#text();\r\n for (let i = 0; i < text.length; i++) {\r\n text[i].setColor(Theme.Note.FontColor);\r\n text[i].setSize(Theme.Note.H1.FontSize);\r\n text[i].setWeight(FontWeight.Bold);\r\n }\r\n\r\n return new BasicMarkdownEntry(text, true, false);\r\n }\r\n\r\n #h2(): BasicMarkdownEntry {\r\n // Move off of the header token\r\n this.#inc();\r\n\r\n const text = this.#text();\r\n for (let i = 0; i < text.length; i++) {\r\n text[i].setColor(Theme.Note.FontColor);\r\n text[i].setSize(Theme.Note.H2.FontSize);\r\n text[i].setWeight(FontWeight.Bold);\r\n }\r\n\r\n return new BasicMarkdownEntry(text, true, false);\r\n }\r\n\r\n #h3(): BasicMarkdownEntry {\r\n // Move off of the header token\r\n this.#inc();\r\n\r\n const text = this.#text();\r\n for (let i = 0; i < text.length; i++) {\r\n text[i].setColor(Theme.Note.FontColor);\r\n text[i].setSize(Theme.Note.H3.FontSize);\r\n text[i].setWeight(FontWeight.Bold);\r\n }\r\n\r\n return new BasicMarkdownEntry(text, false, false);\r\n }\r\n\r\n #starLineStart(): MarkdownEntry {\r\n if (this.#peak()?.type() !== MarkdownTokenType.Space) {\r\n const starEntries = this.#text();\r\n this.#assignStandardStyling(starEntries);\r\n return new BasicMarkdownEntry(starEntries, false, false);\r\n }\r\n\r\n // We've begun with a space, which means unordered list!\r\n\r\n const entries = new Array<BasicMarkdownEntry>();\r\n\r\n while (this.#current()?.type() === MarkdownTokenType.Star && this.#peak()?.type() === MarkdownTokenType.Space) {\r\n this.#inc();\r\n const starEntries = this.#text();\r\n this.#assignStandardStyling(starEntries);\r\n entries.push(new BasicMarkdownEntry(starEntries, false, false));\r\n\r\n // Text reads to the end of the line, which means we're at the new\r\n // line character. Move forward 1. \r\n this.#inc();\r\n }\r\n\r\n return new UnorderedListMarkdownEntry(entries);\r\n\r\n }\r\n\r\n #assignStandardStyling(textEntries: Array<Text>): void {\r\n for (let i = 0; i < textEntries.length; i++) {\r\n textEntries[i].setColor(Theme.Note.FontColor);\r\n textEntries[i].setSize(Theme.Note.FontSize);\r\n }\r\n }\r\n\r\n #backtickLineStart(): MarkdownEntry {\r\n\r\n // If we're not a ```, just treat as regular text\r\n if (this.#peak()?.type() !== MarkdownTokenType.BackTick || this.#peakInto(2)?.type() !== MarkdownTokenType.BackTick) {\r\n const starEntries = this.#text();\r\n this.#assignStandardStyling(starEntries);\r\n return new BasicMarkdownEntry(starEntries, false, false);\r\n }\r\n this.#inc();\r\n this.#inc();\r\n\r\n let token = this.#next();\r\n\r\n // Eat the first new line character\r\n if (token?.type() === MarkdownTokenType.NewLine) {\r\n token = this.#next();\r\n }\r\n\r\n let start = token?.tokenStart();\r\n let end = start;\r\n\r\n // Read until we hit another ``` \r\n while (token !== null) {\r\n\r\n if (\r\n token.type() === MarkdownTokenType.BackTick &&\r\n this.#peak()?.type() === MarkdownTokenType.BackTick &&\r\n this.#peakInto(2)?.type() === MarkdownTokenType.BackTick\r\n ) {\r\n end = token.tokenEnd() - 1;\r\n break;\r\n }\r\n\r\n token = this.#next();\r\n }\r\n\r\n this.#inc(); // puts us on the 2nd\r\n this.#inc(); // puts us on the 3rd\r\n this.#inc(); // puts us on the next token\r\n\r\n const codeBlockText = this.#originalText.substring(start as number, end).replace(/\\r?\\n$/, \"\");\r\n const entryText = new Text(codeBlockText, { font: Theme.Note.CodeFontFamily ?? undefined });\r\n this.#assignStandardStyling([entryText])\r\n entryText.setColor(Theme.Note.CodeBlock.FontColor);\r\n return new CodeBlockEntry(entryText)\r\n }\r\n\r\n parse(): Array<MarkdownEntry> {\r\n let token = this.#current();\r\n\r\n const entries = new Array<MarkdownEntry>();\r\n\r\n while (token !== null) {\r\n switch (token.type()) {\r\n case MarkdownTokenType.H1:\r\n entries.push(this.#h1());\r\n break;\r\n\r\n case MarkdownTokenType.H2:\r\n entries.push(this.#h2());\r\n break;\r\n\r\n case MarkdownTokenType.H3:\r\n entries.push(this.#h3());\r\n break;\r\n\r\n case MarkdownTokenType.Text:\r\n const textEntries = this.#text();\r\n this.#assignStandardStyling(textEntries);\r\n entries.push(new BasicMarkdownEntry(textEntries, false, false));\r\n break;\r\n\r\n case MarkdownTokenType.Star:\r\n entries.push(this.#starLineStart());\r\n break;\r\n\r\n case MarkdownTokenType.NewLine:\r\n this.#inc();\r\n break;\r\n\r\n case MarkdownTokenType.BackTick:\r\n entries.push(this.#backtickLineStart());\r\n break;\r\n\r\n default:\r\n this.#inc();\r\n }\r\n\r\n token = this.#current();\r\n }\r\n\r\n return entries;\r\n }\r\n}\r\n", "import { MarkdownEntry } from \"./entry\";\r\nimport { MarkdownLexicalParser } from \"./lexicalParser\";\r\nimport { MarkdownSyntaxParser } from \"./syntaxParser\";\r\n\r\nexport function BuildMarkdown(data: string): Array<MarkdownEntry> {\r\n const lexicalParser = new MarkdownLexicalParser(data);\r\n lexicalParser.parse();\r\n // console.log(lexicalParser.tokens());\r\n\r\n const syntaxParser = new MarkdownSyntaxParser(data, lexicalParser.tokens());\r\n const contents = syntaxParser.parse()\r\n // console.log(contents);\r\n return contents;\r\n}", "import { BuildMarkdown } from \"../markdown/markdown\";\r\nimport { MarkdownEntry } from \"../markdown/entry\";\r\nimport { Popup } from \"../popup\";\r\nimport { BoxStyle } from \"../styles/box\";\r\nimport { TextAlign } from \"../styles/canvasTextAlign\";\r\nimport { TextBaseline } from \"../styles/canvasTextBaseline\";\r\nimport { TextStyleConfig } from \"../styles/text\";\r\nimport { Theme, themeVersion } from \"../theme\";\r\nimport { Box } from \"../types/box\";\r\nimport { CopyVector2, Vector2, Zero } from \"../types/vector2\";\r\nimport { Camera } from \"../camera\";\r\nimport { Metadata } from \"../metadata\";\r\n\r\nexport type NoteContentChangeCallback = (node: FlowNote, newContents: string) => void\r\nexport type NoteWidthChangeCallback = (node: FlowNote, newWidth: number) => void\r\n\r\nexport interface FlowNoteConfig {\r\n text?: string;\r\n style?: TextStyleConfig;\r\n metadata?: Metadata;\r\n position?: Vector2;\r\n width?: number;\r\n locked?: boolean;\r\n onWidthChange?: NoteWidthChangeCallback;\r\n onContentChange?: NoteContentChangeCallback;\r\n}\r\n\r\nexport enum DragHandle {\r\n None,\r\n Left,\r\n Right\r\n};\r\n\r\nconst BOUNDS_SPACING = 20;\r\nconst BOX_SIZE = 10;\r\n\r\nexport class FlowNote {\r\n\r\n #originalText: string;\r\n\r\n #document: Array<MarkdownEntry>;\r\n\r\n #parsedForTheme = -1;\r\n\r\n #width: number;\r\n\r\n #edittingStyle: BoxStyle;\r\n\r\n // Runtime ================================================================\r\n\r\n #data: Metadata;\r\n\r\n #position: Vector2;\r\n\r\n #handleSelected: DragHandle;\r\n\r\n #edittingLayout: boolean;\r\n\r\n #lastRenderedBox: Box;\r\n\r\n #hovering: boolean;\r\n\r\n // Callbacks ==============================================================\r\n\r\n #widthChangeCallbacks: Array<NoteWidthChangeCallback>;\r\n\r\n #contentChangeCallbacks: Array<NoteContentChangeCallback>;\r\n\r\n // ========================================================================\r\n\r\n constructor(config?: FlowNoteConfig) {\r\n this.#widthChangeCallbacks = new Array<NoteWidthChangeCallback>();\r\n this.#contentChangeCallbacks = new Array<NoteContentChangeCallback>();\r\n this.#data = config?.metadata === undefined ? {} : config?.metadata;\r\n this.#document = [];\r\n this.#originalText = \"\";\r\n this.#hovering = false;\r\n this.#edittingLayout = config?.locked === undefined ? true : !config?.locked;\r\n this.#width = config?.width === undefined ? 500 : config.width;\r\n this.#position = config?.position === undefined ? { x: 0, y: 0 } : config.position;\r\n this.setText(config?.text === undefined ? \"\" : config?.text);\r\n this.#lastRenderedBox = { Position: { x: 0, y: 0 }, Size: { x: 0, y: 0 } };\r\n this.#handleSelected = DragHandle.None;\r\n\r\n this.#edittingStyle = new BoxStyle({\r\n border: {\r\n color: \"white\",\r\n size: 1\r\n },\r\n })\r\n\r\n if (config?.onWidthChange) {\r\n this.#widthChangeCallbacks.push(config.onWidthChange);\r\n }\r\n\r\n if (config?.onContentChange) {\r\n this.#contentChangeCallbacks.push(config.onContentChange);\r\n }\r\n }\r\n\r\n setText(text: string): void {\r\n this.#originalText = text;\r\n this.#document = BuildMarkdown(this.#originalText);\r\n this.#parsedForTheme = themeVersion();\r\n for (let i = 0; i < this.#contentChangeCallbacks.length; i++) {\r\n this.#contentChangeCallbacks[i](this, text);\r\n }\r\n }\r\n\r\n public setMetadataProperty(name: string, value: any): void {\r\n this.#data[name] = value;\r\n }\r\n\r\n public getMetadataProperty(name: string): any {\r\n return this.#data[name];\r\n }\r\n\r\n text(): string {\r\n return this.#originalText;\r\n }\r\n\r\n width(): number {\r\n return this.#width;\r\n }\r\n\r\n position(): Vector2 {\r\n return this.#position;\r\n }\r\n\r\n translate(delta: Vector2): void {\r\n this.#position.x += delta.x;\r\n this.#position.y += delta.y;\r\n }\r\n\r\n setPosition(position: Vector2): void {\r\n CopyVector2(this.#position, position);\r\n }\r\n\r\n handleSelected(): DragHandle {\r\n return this.#handleSelected;\r\n }\r\n\r\n selectHandle(handle: DragHandle): void {\r\n this.#handleSelected = handle;\r\n }\r\n\r\n #tempPosition: Vector2 = Zero();\r\n\r\n public setWidth(newWidth: number): void {\r\n if (newWidth === undefined) {\r\n console.error(\"Attempted to set note's width to undefined\");\r\n }\r\n this.#width = newWidth;\r\n for (let i = 0; i < this.#widthChangeCallbacks.length; i++) {\r\n this.#widthChangeCallbacks[i](this, newWidth);\r\n }\r\n }\r\n\r\n public addWidthChangeListener(callback: NoteWidthChangeCallback): void {\r\n if (callback === null || callback === undefined) {\r\n return;\r\n }\r\n this.#widthChangeCallbacks.push(callback);\r\n }\r\n\r\n public addContentChangeListener(callback: NoteContentChangeCallback): void {\r\n if (callback === null || callback === undefined) {\r\n return;\r\n }\r\n this.#contentChangeCallbacks.push(callback);\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, camera: Camera, mousePosition: Vector2 | undefined): void {\r\n if (this.#edittingLayout && (this.#hovering || this.#handleSelected !== DragHandle.None)) {\r\n\r\n if (mousePosition) {\r\n if (this.#handleSelected === DragHandle.Right) {\r\n\r\n const leftPosition = (this.#position.x * camera.zoom) + camera.position.x;\r\n this.setWidth(Math.max((mousePosition.x - leftPosition) / camera.zoom, 1));\r\n\r\n } else if (this.#handleSelected === DragHandle.Left) {\r\n\r\n const scaledWidth = this.#width * camera.zoom;\r\n const rightPosition = (this.#position.x * camera.zoom) + camera.position.x + scaledWidth;\r\n this.setWidth(Math.max((rightPosition - mousePosition.x) / camera.zoom, 1));\r\n this.#position.x = rightPosition - (this.#width * camera.zoom) - camera.position.x;\r\n this.#position.x /= camera.zoom;\r\n }\r\n }\r\n\r\n this.#edittingStyle.Outline(ctx, this.leftResizeHandleBox(), camera.zoom, 2);\r\n this.#edittingStyle.Outline(ctx, this.rightResizeHandleBox(), camera.zoom, 2);\r\n\r\n ctx.beginPath();\r\n const left = this.#lastRenderedBox.Position.x;\r\n const right = this.#lastRenderedBox.Position.x + this.#lastRenderedBox.Size.x;\r\n const bottom = this.#lastRenderedBox.Position.y;\r\n const top = this.#lastRenderedBox.Position.y + this.#lastRenderedBox.Size.y;\r\n ctx.moveTo(left, bottom + (this.#lastRenderedBox.Size.y / 2) - (BOX_SIZE));\r\n ctx.lineTo(left, bottom);\r\n ctx.lineTo(right, bottom);\r\n ctx.lineTo(right, bottom + (this.#lastRenderedBox.Size.y / 2) - (BOX_SIZE));\r\n\r\n ctx.moveTo(left, top - (this.#lastRenderedBox.Size.y / 2) + (BOX_SIZE));\r\n ctx.lineTo(left, top);\r\n ctx.lineTo(right, top);\r\n ctx.lineTo(right, top - (this.#lastRenderedBox.Size.y / 2) + (BOX_SIZE));\r\n ctx.stroke();\r\n // this.#edittingStyle.Outline(ctx, bigBox, camera.zoom, 2);\r\n }\r\n\r\n camera.graphSpaceToScreenSpace(this.#position, this.#tempPosition);\r\n CopyVector2(this.#lastRenderedBox.Position, this.#tempPosition)\r\n\r\n if (this.#parsedForTheme !== themeVersion()) {\r\n this.#document = BuildMarkdown(this.#originalText);\r\n this.#parsedForTheme = themeVersion();\r\n }\r\n\r\n const startY = this.#tempPosition.y;\r\n const lineSpacing = Theme.Note.EntrySpacing * camera.zoom;\r\n\r\n ctx.textAlign = TextAlign.Left;\r\n ctx.textBaseline = TextBaseline.Alphabetic;\r\n for (let i = 0; i < this.#document.length; i++) {\r\n const text = this.#document[i];\r\n this.#tempPosition.y += text.render(ctx, this.#tempPosition, camera.zoom, this.#width) + lineSpacing;\r\n }\r\n\r\n this.#lastRenderedBox.Position.x -= BOUNDS_SPACING\r\n this.#lastRenderedBox.Position.y -= BOUNDS_SPACING\r\n this.#lastRenderedBox.Size.x = camera.zoom * this.#width + (BOUNDS_SPACING * 2);\r\n this.#lastRenderedBox.Size.y = this.#tempPosition.y - startY + (BOUNDS_SPACING * 2);\r\n }\r\n\r\n leftResizeHandleBox(): Box {\r\n return {\r\n Position: {\r\n x: this.#lastRenderedBox.Position.x - (BOX_SIZE / 2),\r\n y: this.#lastRenderedBox.Position.y + (this.#lastRenderedBox.Size.y / 2) - (BOX_SIZE / 2),\r\n },\r\n Size: { x: BOX_SIZE, y: BOX_SIZE, }\r\n };\r\n }\r\n\r\n rightResizeHandleBox(): Box {\r\n return {\r\n Position: {\r\n x: this.#lastRenderedBox.Position.x - (BOX_SIZE / 2) + this.#lastRenderedBox.Size.x,\r\n y: this.#lastRenderedBox.Position.y + (this.#lastRenderedBox.Size.y / 2) - (BOX_SIZE / 2),\r\n },\r\n Size: { x: BOX_SIZE, y: BOX_SIZE, }\r\n };\r\n }\r\n\r\n edittingLayout(): boolean {\r\n return this.#edittingLayout;\r\n }\r\n\r\n setHovering(hovering: boolean): void {\r\n this.#hovering = hovering;\r\n }\r\n\r\n editContent(): void {\r\n let input: HTMLTextAreaElement | null = null;\r\n let saveText = \"Save\";\r\n\r\n const popup = new Popup({\r\n title: \"Edit Note\",\r\n options: [saveText, \"Cancel\"],\r\n content: () => {\r\n const container = document.createElement('div');\r\n input = document.createElement('textarea')\r\n input.rows = 8;\r\n input.cols = 50;\r\n input.value = this.#originalText;\r\n container.append(input);\r\n return container;\r\n },\r\n onClose: (button: string | null): void => {\r\n if (button !== saveText || input === null) {\r\n return;\r\n }\r\n this.setText(input.value);\r\n },\r\n });\r\n\r\n popup.Show();\r\n }\r\n\r\n lock(): void {\r\n this.#edittingLayout = false;\r\n }\r\n\r\n unlock(): void {\r\n this.#edittingLayout = true;\r\n }\r\n\r\n bounds(): Box {\r\n return this.#lastRenderedBox;\r\n }\r\n}", "import { Camera } from \"../camera\";\r\nimport { ContextMenuConfig } from \"../contextMenu\";\r\nimport { requestRender } from \"../render_scheduler\";\r\nimport { RenderResults } from \"../graphSubsystem\";\r\nimport { InBox } from \"../types/box\";\r\nimport { Vector2 } from \"../types/vector2\";\r\nimport { DragHandle, FlowNote, FlowNoteConfig } from './note';\r\n\r\n\r\nexport type NoteAddedCallback = (addedNote: FlowNote) => void\r\nexport type NoteRemovedCallback = (noteRemoved: FlowNote) => void\r\n\r\nexport type NoteDragStartCallback = (nodeDragged: FlowNote) => void\r\nexport type NoteDragStopCallback = (nodeDragged: FlowNote) => void\r\n\r\n\r\nexport interface NoteSubsystemConfig {\r\n onNoteAdded?: NoteAddedCallback;\r\n onNoteRemoved?: NoteRemovedCallback;\r\n onNoteDragStop?: NoteDragStopCallback\r\n onNoteDragStart?: NoteDragStartCallback\r\n notes?: Array<FlowNoteConfig>\r\n}\r\n\r\nexport class NoteSubsystem {\r\n\r\n #notes: Array<FlowNote>;\r\n\r\n #noteHovering: FlowNote | null;\r\n\r\n #noteSelected: FlowNote | null;\r\n\r\n #hoveringHandle: DragHandle;\r\n\r\n #onNoteAddedCallbacks: Array<NoteAddedCallback>;\r\n\r\n #onNoteRemovedCallbacks: Array<NoteRemovedCallback>;\r\n\r\n #onNoteDragStartCallbacks: Array<NoteDragStartCallback>;\r\n\r\n #onNoteDragStopCallbacks: Array<NoteDragStopCallback>;\r\n\r\n constructor(config?: NoteSubsystemConfig) {\r\n this.#hoveringHandle = DragHandle.None;\r\n this.#notes = [];\r\n this.#noteHovering = null;\r\n this.#noteSelected = null;\r\n\r\n // Callbacks\r\n this.#onNoteAddedCallbacks = new Array<NoteAddedCallback>();\r\n this.#onNoteRemovedCallbacks = new Array<NoteRemovedCallback>();\r\n this.#onNoteDragStartCallbacks = new Array<NoteDragStartCallback>();\r\n this.#onNoteDragStopCallbacks = new Array<NoteDragStopCallback>();\r\n\r\n if (config?.notes !== undefined) {\r\n for (let i = 0; i < config?.notes.length; i++) {\r\n this.addNote(new FlowNote(config?.notes[i]));\r\n }\r\n }\r\n\r\n // Add callback *after* we added all the initial notes\r\n if (config?.onNoteAdded !== undefined) {\r\n this.#onNoteAddedCallbacks.push(config?.onNoteAdded);\r\n }\r\n\r\n if (config?.onNoteDragStop !== undefined) {\r\n this.#onNoteDragStopCallbacks.push(config?.onNoteDragStop);\r\n }\r\n\r\n if (config?.onNoteDragStart !== undefined) {\r\n this.#onNoteDragStartCallbacks.push(config?.onNoteDragStart);\r\n }\r\n\r\n if (config?.onNoteRemoved !== undefined) {\r\n this.#onNoteRemovedCallbacks.push(config?.onNoteRemoved);\r\n }\r\n }\r\n\r\n addNote(note: FlowNote): void {\r\n if (note === null || note === undefined) {\r\n return;\r\n }\r\n\r\n this.#notes.push(note);\r\n requestRender();\r\n for (let i = 0; i < this.#onNoteAddedCallbacks.length; i++) {\r\n this.#onNoteAddedCallbacks[i](note);\r\n }\r\n }\r\n\r\n getNotes(): Array<FlowNote> {\r\n return this.#notes;\r\n }\r\n\r\n public addNoteAddedListener(callback: NoteAddedCallback): void {\r\n if (callback === null || callback === undefined) {\r\n return;\r\n }\r\n this.#onNoteAddedCallbacks.push(callback);\r\n }\r\n\r\n public addNoteRemovedListener(callback: NoteRemovedCallback): void {\r\n if (callback === null || callback === undefined) {\r\n return;\r\n }\r\n this.#onNoteRemovedCallbacks.push(callback);\r\n }\r\n\r\n public addNoteDragStartListener(callback: NoteDragStartCallback): void {\r\n if (callback === null || callback === undefined) {\r\n return;\r\n }\r\n this.#onNoteDragStartCallbacks.push(callback);\r\n }\r\n\r\n public addNoteDragStopListener(callback: NoteDragStopCallback): void {\r\n if (callback === null || callback === undefined) {\r\n return;\r\n }\r\n this.#onNoteDragStopCallbacks.push(callback);\r\n }\r\n\r\n openContextMenu(ctx: CanvasRenderingContext2D, position: Vector2): ContextMenuConfig | null {\r\n const group = \"node-flow-graph-note-menu\";\r\n\r\n const result: ContextMenuConfig = {\r\n items: [\r\n {\r\n name: \"New Note\",\r\n group: group,\r\n callback: () => {\r\n this.addNote(new FlowNote({\r\n text: \"#Note\\n\\nRight-click this note and select \\\"edit note\\\" to put what you want here.\",\r\n width: 300,\r\n position: position\r\n }))\r\n }\r\n }\r\n ],\r\n subMenus: [],\r\n }\r\n\r\n if (this.#noteHovering !== null) {\r\n const noteToReview = this.#noteHovering;\r\n result.items?.push(\r\n {\r\n name: \"Delete Note\",\r\n group: group,\r\n callback: () => {\r\n this.removeNote(noteToReview);\r\n }\r\n },\r\n {\r\n name: \"Edit Note\",\r\n group: group,\r\n callback: noteToReview.editContent.bind(noteToReview),\r\n },\r\n );\r\n\r\n if (!noteToReview.edittingLayout()) {\r\n result.items?.push({\r\n name: \"Unlock Note\",\r\n group: group,\r\n callback: noteToReview.unlock.bind(noteToReview),\r\n })\r\n } else {\r\n result.items?.push({\r\n name: \"Lock Note\",\r\n group: group,\r\n callback: noteToReview.lock.bind(noteToReview),\r\n })\r\n }\r\n }\r\n\r\n return result;\r\n }\r\n\r\n clickStart(mousePosition: Vector2, camera: Camera, ctrlKey: boolean): boolean {\r\n if (this.#noteHovering !== null && this.#noteHovering.edittingLayout()) {\r\n this.#noteSelected = this.#noteHovering;\r\n this.#noteSelected.selectHandle(this.#hoveringHandle);\r\n\r\n for (let i = 0; i < this.#onNoteDragStartCallbacks.length; i++) {\r\n this.#onNoteDragStartCallbacks[i](this.#noteSelected);\r\n }\r\n return true;\r\n }\r\n return false;\r\n }\r\n\r\n clickEnd(): void {\r\n if (this.#noteSelected !== null) {\r\n this.#noteSelected.selectHandle(DragHandle.None);\r\n for (let i = 0; i < this.#onNoteDragStopCallbacks.length; i++) {\r\n this.#onNoteDragStopCallbacks[i](this.#noteSelected);\r\n }\r\n }\r\n this.#noteSelected = null;\r\n }\r\n\r\n mouseDragEvent(delta: Vector2, scale: number): boolean {\r\n if (this.#noteSelected === null) {\r\n return false;\r\n }\r\n\r\n // Return early so we don't translate since we're moving a drag handle\r\n if (this.#noteSelected.handleSelected()) {\r\n return true;\r\n }\r\n\r\n this.#noteSelected.translate({\r\n x: delta.x * (1 / scale),\r\n y: delta.y * (1 / scale)\r\n });\r\n return true;\r\n }\r\n\r\n fileDrop(file: File): boolean {\r\n return false;\r\n }\r\n\r\n removeNote(note: FlowNote): void {\r\n const index = this.#notes.indexOf(note);\r\n if (index > -1) {\r\n const noteRemoved = this.#notes[index];\r\n this.#notes.splice(index, 1);\r\n requestRender();\r\n\r\n for (let i = 0; i < this.#onNoteRemovedCallbacks.length; i++) {\r\n this.#onNoteRemovedCallbacks[i](noteRemoved)\r\n }\r\n } else {\r\n console.error(\"no note found to remove\");\r\n }\r\n }\r\n\r\n removeAllNotes(): void {\r\n const notes = this.#notes;\r\n this.#notes = [];\r\n this.#noteHovering = null;\r\n this.#noteSelected = null;\r\n\r\n for (let i = 0; i < notes.length; i++) {\r\n for (let j = 0; j < this.#onNoteRemovedCallbacks.length; j++) {\r\n this.#onNoteRemovedCallbacks[j](notes[i]);\r\n }\r\n }\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, camera: Camera, mousePosition: Vector2 | undefined): RenderResults | undefined {\r\n this.#noteHovering = null;\r\n this.#hoveringHandle = DragHandle.None;\r\n\r\n // Set hovering to false on everything\r\n if (mousePosition) {\r\n for (let i = 0; i < this.#notes.length; i++) {\r\n this.#notes[i].setHovering(false);\r\n if (InBox(this.#notes[i].bounds(), mousePosition)) {\r\n this.#noteHovering = this.#notes[i];\r\n }\r\n }\r\n }\r\n\r\n // The note on top of everything is the one that get's to be in a \r\n // hover state\r\n if (this.#noteHovering != null) {\r\n this.#noteHovering.setHovering(true);\r\n if (mousePosition) {\r\n if (InBox(this.#noteHovering.leftResizeHandleBox(), mousePosition)) {\r\n this.#hoveringHandle = DragHandle.Left;\r\n } else if (InBox(this.#noteHovering.rightResizeHandleBox(), mousePosition)) {\r\n this.#hoveringHandle = DragHandle.Right;\r\n }\r\n }\r\n }\r\n\r\n for (let i = 0; i < this.#notes.length; i++) {\r\n this.#notes[i].render(ctx, camera, mousePosition);\r\n }\r\n return;\r\n }\r\n}", "import { Camera } from \"../camera\";\r\nimport { ContextMenuConfig } from \"../contextMenu\";\r\nimport { RenderResults } from \"../graphSubsystem\";\r\nimport { List } from \"../types/list\";\r\nimport { Vector2 } from \"../types/vector2\";\r\n\r\ntype RenderLambda = () => void\r\n\r\n\r\n/**\r\n * Generic subsystem meant for other sybsystems to pass whatever to to render \r\n * at a certain time.\r\n * \r\n * Initial inspriation is for a subsytem to submit something to render on top \r\n * of all other subsystems.\r\n */\r\nexport class PassSubsystem {\r\n\r\n #queue: List<RenderLambda>\r\n\r\n constructor() {\r\n this.#queue = new List<RenderLambda>();\r\n }\r\n\r\n queue(lambda: RenderLambda): void {\r\n if(!lambda) {\r\n return;\r\n }\r\n this.#queue.Push(lambda);\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, camera: Camera, mousePosition: Vector2 | undefined): RenderResults | undefined {\r\n for (let i = 0; i < this.#queue.Count(); i++) {\r\n this.#queue.At(i)();\r\n }\r\n this.#queue.Clear();\r\n return;\r\n }\r\n\r\n openContextMenu(ctx: CanvasRenderingContext2D, position: Vector2): ContextMenuConfig | null {\r\n // Left intentionally blank\r\n return null;\r\n }\r\n\r\n clickStart(mousePosition: Vector2, camera: Camera, ctrlKey: boolean): boolean {\r\n // Left intentionally blank\r\n return false;\r\n }\r\n\r\n mouseDragEvent(delta: Vector2, scale: number): boolean {\r\n // Left intentionally blank\r\n return false;\r\n }\r\n\r\n fileDrop(file: File): boolean {\r\n // Left intentionally blank\r\n return false;\r\n }\r\n\r\n clickEnd(): void {\r\n // Left intentionally blank\r\n }\r\n\r\n}", "import { ContextMenuConfig, ContextMenuItemConfig } from \"./contextMenu\";\r\nimport { ContainerRenderElement as ContainerElement } from \"./elements/container\";\r\nimport { IRenderElement } from \"./elements/interfaces\";\r\nimport { TextAlign, TextElement as TextElement, VerticalAlign } from \"./elements/text\";\r\nimport { FontWeight } from \"./styles/text\";\r\nimport { Theme } from \"./theme\";\r\nimport { Text } from './types/text';\r\nimport { ScaleVector, Vector2 } from './types/vector2';\r\nimport { Box, InBox } from './types/box';\r\nimport { Display } from './elements/base';\r\n\r\nclass QuickMenuGroup {\r\n\r\n #text: TextElement;\r\n\r\n public items: Array<QuickMenuItem>;\r\n\r\n constructor(text: TextElement, items: Array<QuickMenuItem>) {\r\n this.#text = text;\r\n this.items = items;\r\n }\r\n\r\n updateRendering(terms: Array<string>): void {\r\n let shouldRender = false;\r\n for (let i = 0; i < this.items.length; i++) {\r\n const kept = this.items[i].filter(terms);\r\n this.items[i].render(kept);\r\n if (kept) {\r\n shouldRender = true;\r\n }\r\n }\r\n\r\n this.#text.setDisplay(shouldRender ? Display.Flex : Display.None);\r\n }\r\n\r\n}\r\n\r\nclass QuickMenuItem {\r\n #searchText: string;\r\n #text: TextElement;\r\n #context: ContextMenuItemConfig\r\n\r\n constructor(searchText: string, text: TextElement, context: ContextMenuItemConfig) {\r\n this.#searchText = searchText.toLowerCase();\r\n this.#text = text;\r\n this.#context = context;\r\n }\r\n\r\n filter(terms: Array<string>): boolean {\r\n if (terms.length === 0) {\r\n return true;\r\n }\r\n for (let i = 0; i < terms.length; i++) {\r\n if (terms[i] === \"\") {\r\n continue;\r\n }\r\n\r\n if (this.#searchText.indexOf(terms[i]) === -1) {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n render(render: boolean): void {\r\n this.#text.setDisplay(render ? Display.Flex : Display.None);\r\n }\r\n\r\n rendering(): boolean {\r\n return this.#text.getDisplay() === Display.Flex;\r\n }\r\n\r\n highlight(highlight: boolean): void {\r\n this.#text.setBackgroundColor(highlight ? Theme.ContextMenu.HighlightColor : \"\");\r\n }\r\n\r\n select(): void {\r\n if (this.#context.callback) {\r\n this.#context.callback()\r\n }\r\n }\r\n}\r\n\r\nfunction RecurseBuildContainers(\r\n path: string,\r\n config: ContextMenuConfig,\r\n renderElements: Array<IRenderElement>,\r\n groups: Array<QuickMenuGroup>\r\n): void {\r\n\r\n let currentPath = config?.name ?? \"\";\r\n if (path !== \"\") {\r\n currentPath = path + \" / \" + currentPath;\r\n }\r\n\r\n if (config?.items && config.items.length > 0) {\r\n const titleText = new TextElement(\r\n new Text(\r\n currentPath,\r\n {\r\n color: Theme.ContextMenu.FontColor,\r\n weight: FontWeight.Bold,\r\n size: 12,\r\n }\r\n ),\r\n {\r\n Align: TextAlign.Center,\r\n VerticalAlign: VerticalAlign.Center,\r\n Padding: 16\r\n }\r\n );\r\n renderElements.push(titleText);\r\n\r\n const quickItems = new Array<QuickMenuItem>();\r\n\r\n for (let i = 0; i < config.items.length; i++) {\r\n const configItem = config.items[i];\r\n\r\n const itemText = new TextElement(\r\n new Text(\r\n configItem.name ?? \"Item\",\r\n {\r\n color: Theme.ContextMenu.FontColor,\r\n }\r\n ),\r\n {\r\n Padding: 8\r\n }\r\n );\r\n\r\n quickItems.push(new QuickMenuItem(\r\n currentPath + (configItem.name ?? \"\"),\r\n itemText,\r\n configItem\r\n ));\r\n\r\n renderElements.push(itemText);\r\n }\r\n\r\n groups.push(new QuickMenuGroup(titleText, quickItems));\r\n }\r\n\r\n if (config?.subMenus) {\r\n for (let i = 0; i < config?.subMenus.length; i++) {\r\n const configItem = config?.subMenus[i];\r\n RecurseBuildContainers(currentPath, configItem, renderElements, groups);\r\n }\r\n }\r\n}\r\n\r\nexport class QuickMenu {\r\n\r\n #menuGroups: Array<QuickMenuGroup>\r\n\r\n #container: ContainerElement\r\n\r\n #searchText: Text;\r\n\r\n #currentSelection: number;\r\n\r\n constructor(config?: ContextMenuConfig) {\r\n this.#menuGroups = [];\r\n this.#currentSelection = 0;\r\n\r\n this.#searchText = new Text(\r\n \"\",\r\n {\r\n color: Theme.ContextMenu.FontColor,\r\n }\r\n );\r\n\r\n const elements = [\r\n new TextElement(\r\n new Text(\r\n \"Search\",\r\n {\r\n color: Theme.ContextMenu.FontColor,\r\n }\r\n ),\r\n {\r\n Padding: {\r\n Bottom: 0,\r\n Left: 8,\r\n Right: 8,\r\n Top: 8\r\n },\r\n }\r\n ),\r\n\r\n // Search Box...\r\n new ContainerElement(\r\n [\r\n new TextElement(\r\n this.#searchText,\r\n undefined\r\n ),\r\n ],\r\n {\r\n Border: {\r\n Radius: 2,\r\n },\r\n BackgroundColor: \"#003847\",\r\n Padding: 8,\r\n Margin: 8,\r\n MinHeight: 46,\r\n }\r\n ),\r\n ]\r\n\r\n if (config) {\r\n RecurseBuildContainers(\"\", config, elements, this.#menuGroups);\r\n }\r\n\r\n this.#container = new ContainerElement(\r\n elements,\r\n {\r\n BackgroundColor: Theme.ContextMenu.BackgroundColor,\r\n Border: {\r\n Thickness: 1,\r\n Radius: 4\r\n }\r\n }\r\n )\r\n\r\n this.#updateHighlighting();\r\n }\r\n\r\n execute(): void {\r\n let selection = this.#currentSelection;\r\n\r\n for (let groupIndex = 0; groupIndex < this.#menuGroups.length; groupIndex++) {\r\n const group = this.#menuGroups[groupIndex];\r\n\r\n for (let itemIndex = 0; itemIndex < group.items.length; itemIndex++) {\r\n if (group.items[itemIndex].rendering()) {\r\n if (selection === 0) {\r\n group.items[itemIndex].select();\r\n return;\r\n }\r\n selection--;\r\n }\r\n }\r\n }\r\n }\r\n\r\n #updateHighlighting(): void {\r\n const searchText = this.#searchText\r\n .get()\r\n .trim()\r\n .toLowerCase();\r\n\r\n let terms = new Array<string>();\r\n if (searchText !== \"\") {\r\n var potentialTerms = searchText.split(\" \");\r\n for (let i = 0; i < potentialTerms.length; i++) {\r\n const cleaned = potentialTerms[i].trim();\r\n if (cleaned !== \"\") {\r\n terms.push(cleaned);\r\n }\r\n }\r\n }\r\n\r\n let selection = this.#currentSelection;\r\n\r\n for (let groupIndex = 0; groupIndex < this.#menuGroups.length; groupIndex++) {\r\n const group = this.#menuGroups[groupIndex];\r\n group.updateRendering(terms);\r\n\r\n for (let itemIndex = 0; itemIndex < group.items.length; itemIndex++) {\r\n if (group.items[itemIndex].rendering()) {\r\n group.items[itemIndex].highlight(selection === 0)\r\n selection--;\r\n }\r\n }\r\n }\r\n }\r\n\r\n keyboardEvent(event: KeyboardEvent): void {\r\n\r\n let intercepted = true;\r\n\r\n if (event.code === \"Backspace\") {\r\n this.#currentSelection = 0;\r\n const text = this.#searchText.get();\r\n this.#searchText.set(text.slice(0, text.length - 1));\r\n } else if (/^[a-zA-Z0-9]$/.test(event.key) || event.key === \" \") {\r\n this.#currentSelection = 0;\r\n this.#searchText.set(this.#searchText.get() + event.key);\r\n } else if (event.key === \"ArrowUp\") {\r\n this.#currentSelection = Math.max(0, this.#currentSelection - 1);\r\n } else if (event.key === \"ArrowDown\") {\r\n this.#currentSelection ++;\r\n } else {\r\n intercepted = false;\r\n }\r\n\r\n if (intercepted) {\r\n this.#updateHighlighting();\r\n event.preventDefault();\r\n }\r\n\r\n // console.log(event);\r\n }\r\n\r\n renderSize = { x: 0, y: 0 };\r\n\r\n public render(ctx: CanvasRenderingContext2D, pos: Vector2, graphScale: number, mousePosition: Vector2 | undefined): null {\r\n this.#container.calcSize(ctx, this.renderSize, { x: -1, y: -1 });\r\n // ScaleVector(this.renderSize, graphScale);\r\n\r\n // Clamp the position so it's not spilling off the canvas\r\n if (pos.y + Math.min(this.renderSize.y, 400) > ctx.canvas.clientHeight) {\r\n pos.y = ctx.canvas.clientHeight - Math.min(this.renderSize.y, 400);\r\n }\r\n\r\n if (pos.x + this.renderSize.x > ctx.canvas.clientWidth) {\r\n pos.x = ctx.canvas.clientWidth - this.renderSize.x;\r\n }\r\n\r\n if (pos.y < 0) {\r\n pos.y = 0;\r\n }\r\n\r\n if (pos.x < 0) {\r\n pos.x = 0;\r\n }\r\n\r\n this.#container.render(ctx, pos, 1, this.renderSize);\r\n this.#bounds = {\r\n Position: { x: pos.x, y: pos.y },\r\n Size: { x: this.renderSize.x, y: this.renderSize.y },\r\n };\r\n return null;\r\n }\r\n\r\n #bounds: Box | null = null;\r\n\r\n public contains(point: Vector2): boolean {\r\n return this.#bounds !== null && InBox(this.#bounds, point);\r\n }\r\n}\r\n", "import { Camera } from \"./camera\";\nimport { FlowNode } from \"./node\";\nimport { Theme } from \"./theme\";\nimport { Box, InBox } from \"./types/box\";\nimport { Vector2 } from \"./types/vector2\";\n\nexport interface MinimapConfig {\n enabled?: boolean;\n width?: number;\n height?: number;\n margin?: number;\n\n /** Overrides Theme.Minimap.BackgroundColor for this minimap alone. */\n backgroundColor?: string;\n\n /** Overrides Theme.Minimap.BorderColor for this minimap alone. */\n borderColor?: string;\n\n /** Overrides Theme.Minimap.NodeColor for this minimap alone. */\n nodeColor?: string;\n\n /** Overrides Theme.Minimap.ViewportColor for this minimap alone. */\n viewportColor?: string;\n}\n\nexport class Minimap {\n\n #enabled: boolean;\n\n #width: number;\n\n #height: number;\n\n #margin: number;\n\n #backgroundColor?: string;\n\n #borderColor?: string;\n\n #nodeColor?: string;\n\n #viewportColor?: string;\n\n #box: Box = { Position: { x: 0, y: 0 }, Size: { x: 0, y: 0 } };\n\n #scale: number = 1;\n\n #originX: number = 0;\n\n #originY: number = 0;\n\n // The padding the last frame was laid out with, so a click maps back\n // through the same geometry it was drawn with.\n #padding: number = Theme.Minimap.Padding;\n\n #drawn: boolean = false;\n\n constructor(config?: MinimapConfig) {\n this.#enabled = config?.enabled === true;\n this.#width = config?.width === undefined ? 200 : config.width;\n this.#height = config?.height === undefined ? 150 : config.height;\n this.#margin = config?.margin === undefined ? 16 : config.margin;\n this.#backgroundColor = config?.backgroundColor;\n this.#borderColor = config?.borderColor;\n this.#nodeColor = config?.nodeColor;\n this.#viewportColor = config?.viewportColor;\n }\n\n enabled(): boolean {\n return this.#enabled;\n }\n\n setEnabled(enabled: boolean): void {\n this.#enabled = enabled;\n this.#drawn = false;\n }\n\n contains(position: Vector2): boolean {\n return this.#enabled && this.#drawn && InBox(this.#box, position);\n }\n\n graphPositionOf(position: Vector2, out: Vector2): void {\n out.x = (position.x - this.#box.Position.x - this.#padding) / this.#scale + this.#originX;\n out.y = (position.y - this.#box.Position.y - this.#padding) / this.#scale + this.#originY;\n }\n\n render(ctx: CanvasRenderingContext2D, canvas: HTMLCanvasElement, camera: Camera, nodes: Array<FlowNode>): void {\n if (!this.#enabled) {\n this.#drawn = false;\n return;\n }\n\n // Bounds are taken with a fresh camera so they come back in graph\n // space rather than wherever the real camera happens to be looking.\n const flat = new Camera();\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n\n const boxes: Array<Box> = [];\n for (let i = 0; i < nodes.length; i++) {\n const bounds = nodes[i].calculateBounds(ctx, flat);\n boxes.push(bounds);\n minX = Math.min(minX, bounds.Position.x);\n minY = Math.min(minY, bounds.Position.y);\n maxX = Math.max(maxX, bounds.Position.x + bounds.Size.x);\n maxY = Math.max(maxY, bounds.Position.y + bounds.Size.y);\n }\n\n // What the camera can currently see, so the graph never scales out\n // from under the viewport box.\n const topLeft: Vector2 = { x: 0, y: 0 };\n const bottomRight: Vector2 = { x: 0, y: 0 };\n camera.screenSpaceToGraphSpace({ x: 0, y: 0 }, topLeft);\n camera.screenSpaceToGraphSpace({ x: canvas.width, y: canvas.height }, bottomRight);\n\n minX = Math.min(minX, topLeft.x);\n minY = Math.min(minY, topLeft.y);\n maxX = Math.max(maxX, bottomRight.x);\n maxY = Math.max(maxY, bottomRight.y);\n\n if (!isFinite(minX) || maxX <= minX || maxY <= minY) {\n this.#drawn = false;\n return;\n }\n\n this.#box.Size.x = this.#width;\n this.#box.Size.y = this.#height;\n this.#box.Position.x = canvas.width - this.#width - this.#margin;\n this.#box.Position.y = canvas.height - this.#height - this.#margin;\n\n this.#padding = Theme.Minimap.Padding;\n\n const usableWidth = this.#width - (this.#padding * 2);\n const usableHeight = this.#height - (this.#padding * 2);\n this.#scale = Math.min(usableWidth / (maxX - minX), usableHeight / (maxY - minY));\n this.#originX = minX;\n this.#originY = minY;\n\n const left = this.#box.Position.x + this.#padding;\n const top = this.#box.Position.y + this.#padding;\n const toMapX = (x: number) => left + ((x - minX) * this.#scale);\n const toMapY = (y: number) => top + ((y - minY) * this.#scale);\n\n ctx.fillStyle = this.#backgroundColor ?? Theme.Minimap.BackgroundColor;\n ctx.strokeStyle = this.#borderColor ?? Theme.Minimap.BorderColor;\n ctx.lineWidth = 1;\n ctx.beginPath();\n ctx.roundRect(\n this.#box.Position.x,\n this.#box.Position.y,\n this.#width,\n this.#height,\n Theme.Minimap.BorderRadius,\n );\n ctx.fill();\n ctx.stroke();\n\n ctx.fillStyle = this.#nodeColor ?? Theme.Minimap.NodeColor;\n for (let i = 0; i < boxes.length; i++) {\n const b = boxes[i];\n ctx.fillRect(\n toMapX(b.Position.x),\n toMapY(b.Position.y),\n Math.max(1, b.Size.x * this.#scale),\n Math.max(1, b.Size.y * this.#scale),\n );\n }\n\n ctx.fillStyle = this.#viewportColor ?? Theme.Minimap.ViewportColor;\n ctx.fillRect(\n toMapX(topLeft.x),\n toMapY(topLeft.y),\n Math.max(1, (bottomRight.x - topLeft.x) * this.#scale),\n Math.max(1, (bottomRight.y - topLeft.y) * this.#scale),\n );\n\n this.#drawn = true;\n }\n}\n", "import { CombineContextMenus, ContextEntry, ContextMenu, ContextMenuConfig } from './contextMenu';\r\nimport { Theme } from \"./theme\";\r\nimport { MouseObserver } from \"./input\";\r\nimport { FlowNode } from \"./node\";\r\nimport { NodeCreatedCallback, NodeFactoryConfig } from \"./nodes/factory\";\r\nimport { TimeExecution } from \"./performance\";\r\nimport { CursorStyle } from \"./styles/cursor\";\r\nimport { CopyVector2, Vector2, Zero } from './types/vector2';\r\nimport { Clamp01 } from \"./utils/math\";\r\nimport { GraphSubsystem, RenderResults } from './graphSubsystem';\r\nimport { FlowNote } from \"./notes/note\";\r\nimport { NoteAddedCallback, NoteDragStartCallback, NoteDragStopCallback, NoteRemovedCallback, NoteSubsystem, NoteSubsystemConfig } from \"./notes/subsystem\";\r\nimport { ConnectionRendererConfiguration, DanglingConnection, InternalConnection, NodeAddedCallback, NodeHoverCallback, NodeRemovedCallback, NodeSubsystem } from \"./nodes/subsystem\";\r\nimport { Connection } from './connection';\r\nimport { Publisher } from './nodes/publisher';\r\nimport { VectorPool } from './types/pool';\r\nimport { Camera, CameraOrientation } from './camera';\r\nexport { CameraOrientation };\r\nimport { PassSubsystem } from './pass/subsystem';\r\nimport { QuickMenu } from './quickMenu';\r\nimport { onRenderRequested, renderContinuously, requestRender } from './render_scheduler';\r\nimport { placeEditsDuring } from './widgets/inplace';\r\nimport { Minimap, MinimapConfig } from './minimap';\r\nimport { Cast } from './port';\r\n\r\nexport type GraphRenderer = (canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, position: Vector2, scale: number) => void;\r\n\r\nfunction BuildBackgroundRenderer(backgroundColor: string | undefined): GraphRenderer {\r\n return (canvas: HTMLCanvasElement, context: CanvasRenderingContext2D, position: Vector2, scale: number): void => {\r\n context.fillStyle = backgroundColor ?? Theme.Graph.BackgroundColor;\r\n context.fillRect(0, 0, canvas.width, canvas.height);\r\n\r\n const alpha = Clamp01(scale - 0.3);\r\n if (alpha <= 0) {\r\n return;\r\n }\r\n\r\n context.save();\r\n context.globalAlpha = alpha;\r\n context.fillStyle = Theme.Graph.DotColor;\r\n const spacing = 100;\r\n const pi2 = 2 * Math.PI\r\n const dotScale = 2 * scale;\r\n for (let x = -50; x < 50; x++) {\r\n const xPos = (x * spacing * scale) + position.x;\r\n for (let y = -50; y < 50; y++) {\r\n const yPos = (y * spacing * scale) + position.y;\r\n context.beginPath();\r\n context.arc(xPos, yPos, dotScale, 0, pi2);\r\n context.fill();\r\n }\r\n }\r\n context.restore();\r\n }\r\n}\r\n\r\nconst contextMenuGroup = \"graph-context-menu\";\r\n\r\nexport type CopyCallback = (nodes: Array<FlowNode>, connections: Array<InternalConnection>) => void;\r\n\r\nexport type PasteCallback = (position: Vector2) => void;\r\n\r\nexport interface FlowNodeGraphConfiguration {\r\n backgroundRenderer?: GraphRenderer;\r\n backgroundColor?: string;\r\n idleConnection?: ConnectionRendererConfiguration\r\n contextMenu?: ContextMenuConfig\r\n nodes?: NodeFactoryConfig\r\n casts?: Array<Cast>\r\n board?: NoteSubsystemConfig\r\n minimap?: MinimapConfig\r\n}\r\n\r\ninterface OpenContextMenu {\r\n Menu: ContextMenu\r\n Position: Vector2\r\n}\r\n\r\ninterface OpenQuickMenu {\r\n Menu: QuickMenu\r\n Position: Vector2\r\n}\r\n\r\nexport class GraphView {\r\n\r\n #subsystems: Array<GraphSubsystem>;\r\n\r\n constructor(subsystems: Array<GraphSubsystem>) {\r\n this.#subsystems = subsystems;\r\n }\r\n\r\n clickStart(mousePosition: Vector2, camera: Camera, ctrlKey: boolean) {\r\n // Since the graph is rendered from 0 => n, n is the last thing \r\n // rendererd and is always shown to the user. So if their clicking on\r\n // two things technically, we need to make sure it's whatever was most \r\n // recently rendered. So we traverse n => 0. \r\n for (let i = this.#subsystems.length - 1; i >= 0; i--) {\r\n // If the user sucesfully clicked on something in this layer, don't\r\n // check any more layers.\r\n if (this.#subsystems[i].clickStart(mousePosition, camera, ctrlKey)) {\r\n return;\r\n }\r\n }\r\n }\r\n\r\n fileDrop(file: File): boolean {\r\n for (let i = this.#subsystems.length - 1; i >= 0; i--) {\r\n if (this.#subsystems[i].fileDrop(file)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n openContextMenu(ctx: CanvasRenderingContext2D, position: Vector2): ContextMenuConfig {\r\n let finalConfig: ContextMenuConfig = {};\r\n\r\n for (let i = 0; i < this.#subsystems.length; i++) {\r\n const subSystemMenu = this.#subsystems[i].openContextMenu(ctx, position);\r\n if (subSystemMenu !== null) {\r\n finalConfig = CombineContextMenus(finalConfig, subSystemMenu);\r\n }\r\n }\r\n\r\n return finalConfig;\r\n }\r\n\r\n clickEnd(): void {\r\n for (let i = 0; i < this.#subsystems.length; i++) {\r\n this.#subsystems[i].clickEnd();\r\n }\r\n }\r\n\r\n mouseDragEvent(delta: Vector2, scale: number): boolean {\r\n for (let i = 0; i < this.#subsystems.length; i++) {\r\n if (this.#subsystems[i].mouseDragEvent(delta, scale)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n render(ctx: CanvasRenderingContext2D, camera: Camera, mousePosition: Vector2 | undefined): RenderResults {\r\n const results: RenderResults = {};\r\n for (let i = 0; i < this.#subsystems.length; i++) {\r\n TimeExecution(\"Render_Subsystem_\" + i, () => {\r\n const layer = this.#subsystems[i].render(ctx, camera, mousePosition);\r\n if (layer?.cursorStyle) {\r\n results.cursorStyle = layer.cursorStyle;\r\n }\r\n })\r\n }\r\n return results;\r\n }\r\n}\r\n\r\nexport class NodeFlowGraph {\r\n\r\n #ctx: CanvasRenderingContext2D;\r\n\r\n #canvas: HTMLCanvasElement;\r\n\r\n #backgroundRenderer: GraphRenderer\r\n\r\n #contextMenuConfig: ContextMenuConfig;\r\n\r\n #mousePosition: Vector2 | undefined;\r\n\r\n #mouseOverCanvas = false;\r\n\r\n #camera: Camera;\r\n\r\n #openedContextMenu: OpenContextMenu | null;\r\n\r\n #openQuickMenu: OpenQuickMenu | null;\r\n\r\n #contextMenuEntryHovering: ContextEntry | null;\r\n\r\n #views: Array<GraphView>;\r\n\r\n #currentView: number;\r\n\r\n #mainNodeSubsystem: NodeSubsystem;\r\n\r\n #mainNoteSubsystem: NoteSubsystem;\r\n\r\n constructor(canvas: HTMLCanvasElement, config?: FlowNodeGraphConfiguration) {\r\n const postProcessPass = new PassSubsystem();\r\n\r\n this.#mainNodeSubsystem = new NodeSubsystem(postProcessPass, {\r\n nodes: config?.nodes,\r\n idleConnection: config?.idleConnection,\r\n casts: config?.casts,\r\n });\r\n\r\n this.#lastFrameCursor = CursorStyle.Default;\r\n this.#cursor = CursorStyle.Default;\r\n\r\n this.#mainNoteSubsystem = new NoteSubsystem(config?.board);\r\n\r\n this.#views = [\r\n new GraphView([\r\n this.#mainNoteSubsystem,\r\n this.#mainNodeSubsystem,\r\n postProcessPass\r\n ])\r\n ];\r\n this.#currentView = 0;\r\n\r\n this.#camera = new Camera();\r\n\r\n this.#contextMenuConfig = CombineContextMenus({\r\n items: [\r\n {\r\n name: \"Center on Graph\",\r\n group: contextMenuGroup,\r\n callback: this.centerOnGraph.bind(this)\r\n },\r\n ],\r\n }, config?.contextMenu);\r\n\r\n this.#openedContextMenu = null;\r\n this.#openQuickMenu = null;\r\n this.#contextMenuEntryHovering = null;\r\n\r\n this.#canvas = canvas;\r\n const ctx = canvas.getContext(\"2d\")\r\n if (ctx === null) {\r\n throw new Error(\"could not create canvas context\")\r\n }\r\n this.#ctx = ctx;\r\n\r\n if (config?.backgroundRenderer !== undefined) {\r\n this.#backgroundRenderer = config?.backgroundRenderer\r\n } else {\r\n this.#backgroundRenderer = BuildBackgroundRenderer(config?.backgroundColor);\r\n }\r\n\r\n this.#minimap = new Minimap(config?.minimap);\r\n\r\n this.#mainNodeSubsystem.setConnectionReleasedHandler((dangling) => {\r\n this.#openScopedMenu(dangling);\r\n });\r\n\r\n this.#watchCanvasSize();\r\n this.#stopRendering = onRenderRequested(this.#render.bind(this));\r\n requestRender();\r\n\r\n new MouseObserver(this.#canvas,\r\n this.#mouseDragEvent.bind(this),\r\n (mousePosition) => {\r\n this.#mousePosition = mousePosition;\r\n this.#mouseOverCanvas = true;\r\n },\r\n this.#clickStart.bind(this),\r\n this.#clickEnd.bind(this),\r\n this.#openContextMenu.bind(this),\r\n this.#fileDrop.bind(this),\r\n (factor, anchor) => {\r\n this.#zoomBy(factor, anchor);\r\n },\r\n () => {\r\n this.#mouseOverCanvas = false;\r\n }\r\n );\r\n\r\n document.addEventListener(\r\n \"keydown\",\r\n (e) => {\r\n this.#keyDown(e);\r\n requestRender();\r\n }\r\n );\r\n }\r\n\r\n #copyCallbacks: Array<CopyCallback> = [];\r\n\r\n #pasteCallbacks: Array<PasteCallback> = [];\r\n\r\n public addCopyListener(callback: CopyCallback): void {\r\n this.#copyCallbacks.push(callback);\r\n }\r\n\r\n public addPasteListener(callback: PasteCallback): void {\r\n this.#pasteCallbacks.push(callback);\r\n }\r\n\r\n #raiseCopy(): void {\r\n const nodes = this.#mainNodeSubsystem.getSelectedNodes();\r\n if (nodes.length === 0) {\r\n return;\r\n }\r\n\r\n const connections = this.#mainNodeSubsystem.connectionsWithin(nodes);\r\n this.#copyCallbacks.forEach((callback) => callback(nodes, connections));\r\n }\r\n\r\n #raisePaste(): void {\r\n const position = this.#mousePosition === undefined\r\n ? { x: 0, y: 0 }\r\n : this.#sceenPositionToGraphPosition(this.#mousePosition);\r\n\r\n this.#pasteCallbacks.forEach((callback) => callback(position));\r\n }\r\n\r\n #deleteKey(e: KeyboardEvent): boolean {\r\n return e.code === \"Delete\" || e.key === \"Delete\";\r\n }\r\n\r\n #keyDown(e: KeyboardEvent): void {\r\n if (document.activeElement) {\r\n if ([\"INPUT\", \"TEXTAREA\"].includes(document.activeElement.tagName)) return;\r\n }\r\n\r\n // Open menus eat input \r\n if (this.#openQuickMenu) {\r\n if (e.code === \"Escape\") {\r\n this.#openQuickMenu = null;\r\n return;\r\n }\r\n\r\n if (e.code === \"Enter\") {\r\n this.#openQuickMenu.Menu.execute();\r\n this.#openQuickMenu = null;\r\n return;\r\n }\r\n\r\n this.#openQuickMenu.Menu.keyboardEvent(e);\r\n return\r\n }\r\n\r\n if (this.#deleteKey(e)) {\r\n if (this.#mainNodeSubsystem.getSelectedNodes().length > 0) {\r\n e.preventDefault();\r\n this.#mainNodeSubsystem.removeSelectedNodes();\r\n return;\r\n }\r\n }\r\n\r\n if (e.ctrlKey || e.metaKey) {\r\n const letter = e.code.startsWith(\"Key\")\r\n ? e.code.substring(3).toLowerCase()\r\n : (e.key ?? \"\").toLowerCase();\r\n\r\n switch (letter) {\r\n case \"c\":\r\n this.#raiseCopy();\r\n return;\r\n\r\n case \"v\":\r\n this.#raisePaste();\r\n return;\r\n\r\n // duplicate\r\n case \"d\":\r\n e.preventDefault();\r\n this.#raiseCopy();\r\n this.#raisePaste();\r\n return;\r\n }\r\n }\r\n\r\n const spacePressed = e.key == \" \" || e.code == \"Space\";\r\n if (!spacePressed) {\r\n return;\r\n }\r\n\r\n if (!this.#mousePosition) {\r\n return;\r\n }\r\n const contextMenuPosition = this.#sceenPositionToGraphPosition(this.#mousePosition);\r\n\r\n let items = this.#mainNodeSubsystem.nodeFactory().newNodeSubmenus(this.#mainNodeSubsystem, contextMenuPosition);\r\n this.#openQuickMenu = {\r\n Menu: new QuickMenu({\r\n subMenus: items,\r\n }),\r\n Position: contextMenuPosition\r\n }\r\n }\r\n\r\n #fileDrop(file: File): void {\r\n\r\n if (this.currentView().fileDrop(file)) {\r\n return;\r\n }\r\n\r\n const contents = file.name.split('.');\r\n const extension = contents[contents.length - 1];\r\n if (extension !== \"jpg\" && extension !== \"jpeg\" && extension !== \"png\") {\r\n return;\r\n }\r\n\r\n let pos = Zero();\r\n if (this.#mousePosition) {\r\n CopyVector2(pos, this.#sceenPositionToGraphPosition(this.#mousePosition));\r\n }\r\n\r\n this.#mainNodeSubsystem.addNode(new FlowNode({\r\n title: contents[0],\r\n position: pos,\r\n widgets: [{\r\n type: \"image\",\r\n config: {\r\n blob: file,\r\n }\r\n }]\r\n }));\r\n }\r\n\r\n public addNoteAddedListener(callback: NoteAddedCallback): void {\r\n this.#mainNoteSubsystem.addNoteAddedListener(callback);\r\n }\r\n\r\n public addNoteRemovedListener(callback: NoteRemovedCallback): void {\r\n this.#mainNoteSubsystem.addNoteRemovedListener(callback);\r\n }\r\n\r\n public addNoteDragStartListener(callback: NoteDragStartCallback): void {\r\n this.#mainNoteSubsystem.addNoteDragStartListener(callback);\r\n }\r\n\r\n public addNoteDragStopListener(callback: NoteDragStopCallback): void {\r\n this.#mainNoteSubsystem.addNoteDragStopListener(callback);\r\n }\r\n\r\n\r\n zoom(amount: number, anchor?: Vector2): void {\r\n this.#zoomBy(1 + amount * 0.05, anchor);\r\n }\r\n\r\n #zoomBy(factor: number, anchor?: Vector2): void {\r\n const anchorPos = anchor ?? this.#mousePosition;\r\n\r\n let oldPos: Vector2 | undefined = undefined;\r\n if (anchorPos !== undefined) {\r\n oldPos = this.#sceenPositionToGraphPosition(anchorPos);\r\n }\r\n\r\n this.#camera.zoom *= factor;\r\n\r\n if (!oldPos || anchorPos === undefined) {\r\n return;\r\n }\r\n\r\n if (anchor !== undefined) {\r\n this.#mousePosition = anchor;\r\n }\r\n\r\n const newPos = this.#sceenPositionToGraphPosition(anchorPos);\r\n this.#camera.position.x += (newPos.x - oldPos.x) * this.#camera.zoom;\r\n this.#camera.position.y += (newPos.y - oldPos.y) * this.#camera.zoom;\r\n }\r\n\r\n #clickStart(mousePosition: Vector2, ctrlKey: boolean): void {\r\n if (this.#contextMenuEntryHovering !== null) {\r\n this.#contextMenuEntryHovering.click();\r\n this.#openedContextMenu = null;\r\n this.#contextMenuEntryHovering = null;\r\n return;\r\n }\r\n this.#openedContextMenu = null;\r\n this.#openQuickMenu = null;\r\n this.#contextMenuEntryHovering = null;\r\n\r\n this.#mousePosition = mousePosition;\r\n this.#mouseOverCanvas = true;\r\n\r\n if (this.#minimap.contains(mousePosition)) {\r\n this.#lookAtFromMinimap(mousePosition);\r\n this.#draggingMinimap = true;\r\n return;\r\n }\r\n\r\n this.currentView().clickStart(mousePosition, this.#camera, ctrlKey);\r\n }\r\n\r\n #draggingMinimap: boolean = false;\r\n\r\n #lookAtFromMinimap(mousePosition: Vector2): void {\r\n const target: Vector2 = { x: 0, y: 0 };\r\n this.#minimap.graphPositionOf(mousePosition, target);\r\n\r\n // Centre the viewport on it rather than putting it in the corner.\r\n this.#camera.position.x = -(target.x * this.#camera.zoom) + (this.#canvas.width / 2);\r\n this.#camera.position.y = -(target.y * this.#camera.zoom) + (this.#canvas.height / 2);\r\n requestRender();\r\n }\r\n\r\n /** The minimap, so it can be turned on and sized by the host. */\r\n public minimap(): Minimap {\r\n return this.#minimap;\r\n }\r\n\r\n currentView(): GraphView {\r\n return this.#views[this.#currentView];\r\n }\r\n\r\n organize(): void {\r\n this.#mainNodeSubsystem.organize(this.#ctx);\r\n }\r\n\r\n addPublisher(identifier: string, publisher: Publisher): void {\r\n this.#mainNodeSubsystem.addPublisher(identifier, publisher);\r\n }\r\n\r\n setCasts(casts: Array<Cast>): void {\r\n this.#mainNodeSubsystem.setCasts(casts);\r\n }\r\n\r\n getNodes(): Array<FlowNode> {\r\n return this.#mainNodeSubsystem.getNodes();\r\n }\r\n\r\n /**\r\n * Returns currently selected nodes in stable graph order (same selection\r\n * state used by Ctrl+click and box-select styling via FlowNode.selected()).\r\n */\r\n getSelectedNodes(): Array<FlowNode> {\r\n return this.#mainNodeSubsystem.getSelectedNodes();\r\n }\r\n\r\n public unselectAllNodes(): void {\r\n this.#mainNodeSubsystem.unselectAllNodes();\r\n }\r\n\r\n public removeSelectedNodes(): Array<FlowNode> {\r\n return this.#mainNodeSubsystem.removeSelectedNodes();\r\n }\r\n\r\n /**\r\n * Returns a copy of the current camera orientation (screen-space pan + zoom).\r\n */\r\n getCamera(): CameraOrientation {\r\n return this.#camera.getOrientation();\r\n }\r\n\r\n /**\r\n * Restores a previously saved camera orientation.\r\n */\r\n setCamera(orientation: CameraOrientation): void {\r\n this.#camera.setOrientation(orientation);\r\n }\r\n\r\n /**\r\n * Resets the camera to the default orientation (origin, zoom 1).\r\n */\r\n resetCamera(): void {\r\n this.#camera.reset();\r\n }\r\n\r\n /**\r\n * Adjusts camera position and zoom so all nodes fit in view (~10% padding).\r\n * Falls back to camera.reset() when there are no nodes.\r\n */\r\n centerOnGraph(): void {\r\n const nodes = this.getNodes();\r\n if (nodes.length === 0) {\r\n this.#camera.reset();\r\n return;\r\n }\r\n\r\n // Identity camera so calculateBounds returns graph-space sizes.\r\n const measureCamera = new Camera();\r\n let minX = Infinity;\r\n let minY = Infinity;\r\n let maxX = -Infinity;\r\n let maxY = -Infinity;\r\n\r\n for (let i = 0; i < nodes.length; i++) {\r\n const bounds = nodes[i].calculateBounds(this.#ctx, measureCamera);\r\n minX = Math.min(minX, bounds.Position.x);\r\n minY = Math.min(minY, bounds.Position.y);\r\n maxX = Math.max(maxX, bounds.Position.x + bounds.Size.x);\r\n maxY = Math.max(maxY, bounds.Position.y + bounds.Size.y);\r\n }\r\n\r\n let width = maxX - minX;\r\n let height = maxY - minY;\r\n if (width <= 0 || height <= 0) {\r\n this.#camera.reset();\r\n return;\r\n }\r\n\r\n const padX = width * 0.05;\r\n const padY = height * 0.05;\r\n minX -= padX;\r\n minY -= padY;\r\n width += padX * 2;\r\n height += padY * 2;\r\n\r\n const canvasWidth = this.#canvas.clientWidth;\r\n const canvasHeight = this.#canvas.clientHeight;\r\n if (canvasWidth <= 0 || canvasHeight <= 0) {\r\n this.#camera.reset();\r\n return;\r\n }\r\n\r\n const zoom = Math.min(canvasWidth / width, canvasHeight / height);\r\n const centerX = minX + width / 2;\r\n const centerY = minY + height / 2;\r\n\r\n this.#camera.zoom = zoom;\r\n this.#camera.position.x = canvasWidth / 2 - centerX * zoom;\r\n this.#camera.position.y = canvasHeight / 2 - centerY * zoom;\r\n }\r\n\r\n connectedInputsNodeReferences(nodeIndex: number): Array<FlowNode> {\r\n return this.#mainNodeSubsystem.connectedInputsNodeReferencesByIndex(nodeIndex);\r\n }\r\n\r\n connectedOutputsNodeReferences(nodeIndex: number): Array<FlowNode> {\r\n return this.#mainNodeSubsystem.connectedOutputsNodeReferences(nodeIndex);\r\n }\r\n\r\n connectNodes(nodeOut: FlowNode, outPort: number, nodeIn: FlowNode, inPort: number): Connection | undefined {\r\n return this.#mainNodeSubsystem.connectNodes(nodeOut, outPort, nodeIn, inPort);\r\n }\r\n\r\n clearNodeInputConnection(node: FlowNode, index: number): void {\r\n this.#mainNodeSubsystem.clearNodeInputConnection(node, index);\r\n }\r\n\r\n addNode(node: FlowNode): void {\r\n this.#mainNodeSubsystem.addNode(node);\r\n }\r\n\r\n removeNode(node: FlowNode): void {\r\n this.#mainNodeSubsystem.removeNode(node);\r\n }\r\n\r\n addNote(note: FlowNote): void {\r\n this.#mainNoteSubsystem.addNote(note);\r\n }\r\n\r\n removeNote(note: FlowNote): void {\r\n this.#mainNoteSubsystem.removeNote(note);\r\n }\r\n\r\n removeAllNotes(): void {\r\n this.#mainNoteSubsystem.removeAllNotes();\r\n }\r\n\r\n getNotes(): Array<FlowNote> {\r\n return this.#mainNoteSubsystem.getNotes();\r\n }\r\n\r\n public addOnNodeCreatedListener(callback: NodeCreatedCallback): void {\r\n this.#mainNodeSubsystem.addOnNodeCreatedListener(callback);\r\n }\r\n\r\n public addOnNodeAddedListener(callback: NodeAddedCallback): void {\r\n this.#mainNodeSubsystem.addOnNodeAddedListener(callback);\r\n }\r\n\r\n public addOnNodeRemovedListener(callback: NodeRemovedCallback): void {\r\n this.#mainNodeSubsystem.addOnNodeRemovedListener(callback);\r\n }\r\n\r\n public addNodeHoverListener(callback: NodeHoverCallback): void {\r\n this.#mainNodeSubsystem.addNodeHoverListener(callback);\r\n }\r\n\r\n #sceenPositionToGraphPosition(screenPosition: Vector2): Vector2 {\r\n const out = Zero();\r\n this.#camera.screenSpaceToGraphSpace(screenPosition, out);\r\n return out;\r\n }\r\n\r\n #openContextMenu(position: Vector2): void {\r\n let finalConfig = this.#contextMenuConfig;\r\n\r\n const contextMenuPosition = this.#sceenPositionToGraphPosition(position);\r\n\r\n finalConfig = CombineContextMenus(finalConfig, this.currentView().openContextMenu(this.#ctx, contextMenuPosition));\r\n\r\n this.#openedContextMenu = {\r\n Menu: new ContextMenu(finalConfig),\r\n Position: contextMenuPosition,\r\n };\r\n }\r\n\r\n #openScopedMenu(dangling: DanglingConnection): void {\r\n if (this.#mousePosition === undefined) {\r\n return;\r\n }\r\n\r\n const position = this.#sceenPositionToGraphPosition(this.#mousePosition);\r\n const menu = this.#mainNodeSubsystem.nodeFactory().openMenu(\r\n this.#mainNodeSubsystem,\r\n position,\r\n {\r\n needs: dangling.needs,\r\n types: dangling.types,\r\n casts: this.#mainNodeSubsystem.casts(),\r\n onCreated: dangling.connectTo,\r\n },\r\n );\r\n\r\n this.#openedContextMenu = {\r\n Menu: new ContextMenu(menu),\r\n Position: position,\r\n };\r\n requestRender();\r\n }\r\n\r\n #clickEnd(): void {\r\n this.#draggingMinimap = false;\r\n this.currentView().clickEnd();\r\n }\r\n\r\n #mouseDragEvent(delta: Vector2): void {\r\n if (this.#draggingMinimap) {\r\n if (this.#mousePosition !== undefined) {\r\n this.#lookAtFromMinimap(this.#mousePosition);\r\n }\r\n return;\r\n }\r\n\r\n let draggingSomething = this.currentView().mouseDragEvent(delta, this.#camera.zoom);\r\n if (!draggingSomething) {\r\n this.#camera.position.x += delta.x;\r\n this.#camera.position.y += delta.y;\r\n }\r\n }\r\n\r\n #lastFrameCursor: CursorStyle;\r\n\r\n #cursor: CursorStyle;\r\n\r\n #minimap: Minimap;\r\n\r\n #stopRendering: () => void;\r\n\r\n #sizeObserver: ResizeObserver | undefined;\r\n\r\n #matchCanvasToParent(): void {\r\n const parent = this.#canvas.parentNode as HTMLElement | null;\r\n if (parent === null) {\r\n return;\r\n }\r\n\r\n const rect = parent.getBoundingClientRect();\r\n if (this.#canvas.width === rect.width && this.#canvas.height === rect.height) {\r\n return;\r\n }\r\n\r\n this.#canvas.width = rect.width;\r\n this.#canvas.height = rect.height;\r\n }\r\n\r\n #watchCanvasSize(): void {\r\n this.#matchCanvasToParent();\r\n\r\n const parent = this.#canvas.parentNode as HTMLElement | null;\r\n if (parent === null || typeof ResizeObserver === \"undefined\") {\r\n return;\r\n }\r\n\r\n this.#sizeObserver = new ResizeObserver(() => {\r\n this.#matchCanvasToParent();\r\n requestRender();\r\n });\r\n this.#sizeObserver.observe(parent);\r\n }\r\n\r\n public requestRender(): void {\r\n requestRender();\r\n }\r\n\r\n public renderContinuously(): () => void {\r\n return renderContinuously();\r\n }\r\n\r\n public dispose(): void {\r\n this.#stopRendering();\r\n this.#sizeObserver?.disconnect();\r\n }\r\n\r\n #render(): void {\r\n this.#matchCanvasToParent();\r\n\r\n this.#cursor = CursorStyle.Default;\r\n\r\n TimeExecution(\"Render_Background\", this.#renderBackground.bind(this));\r\n\r\n TimeExecution(\"Render_View_\" + this.#currentView, () => {\r\n placeEditsDuring(this.#canvas, () => {\r\n let results = this.currentView().render(this.#ctx, this.#camera, this.#pointerOnGraph());\r\n if (results?.cursorStyle) {\r\n this.#cursor = results?.cursorStyle;\r\n }\r\n });\r\n });\r\n\r\n TimeExecution(\"Render_Minimap\", () => {\r\n this.#minimap.render(this.#ctx, this.#canvas, this.#camera, this.#mainNodeSubsystem.getNodes());\r\n });\r\n\r\n TimeExecution(\"Render_Context\", this.#renderContextMenu.bind(this));\r\n\r\n TimeExecution(\"Render_QuickMenu\", this.#renderQuickMenu.bind(this))\r\n\r\n // Only update CSS style if things have changed\r\n // TODO: Does this actually have any measurable performance savings?\r\n if (this.#lastFrameCursor !== this.#cursor) {\r\n this.#canvas.style.cursor = this.#cursor;\r\n }\r\n this.#lastFrameCursor = this.#cursor;\r\n }\r\n\r\n #pointer(): Vector2 | undefined {\r\n return this.#mouseOverCanvas ? this.#mousePosition : undefined;\r\n }\r\n\r\n #pointerOnGraph(): Vector2 | undefined {\r\n const pointer = this.#pointer();\r\n if (pointer === undefined) {\r\n return undefined;\r\n }\r\n if (this.#openedContextMenu?.Menu.contains(pointer) || this.#openQuickMenu?.Menu.contains(pointer)) {\r\n return undefined;\r\n }\r\n return pointer;\r\n }\r\n\r\n #renderBackground(): void {\r\n this.#backgroundRenderer(this.#canvas, this.#ctx, this.#camera.position, this.#camera.zoom);\r\n }\r\n\r\n #renderContextMenu(): void {\r\n VectorPool.run(() => {\r\n if (this.#openedContextMenu !== null) {\r\n const pos = VectorPool.get();\r\n this.#camera.graphSpaceToScreenSpace(this.#openedContextMenu.Position, pos)\r\n this.#contextMenuEntryHovering = this.#openedContextMenu.Menu.render(this.#ctx, pos, this.#camera.zoom, this.#pointer(), true);\r\n\r\n if (this.#contextMenuEntryHovering !== null) {\r\n this.#cursor = CursorStyle.Pointer;\r\n }\r\n }\r\n });\r\n }\r\n\r\n #renderQuickMenu(): void {\r\n VectorPool.run(() => {\r\n if (this.#openQuickMenu !== null) {\r\n const pos = VectorPool.get();\r\n this.#camera.graphSpaceToScreenSpace(this.#openQuickMenu.Position, pos)\r\n this.#contextMenuEntryHovering = this.#openQuickMenu.Menu.render(this.#ctx, pos, this.#camera.zoom, this.#pointer());\r\n\r\n if (this.#contextMenuEntryHovering !== null) {\r\n this.#cursor = CursorStyle.Pointer;\r\n }\r\n }\r\n });\r\n }\r\n}"],
5
+ "mappings": "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",
6
+ "names": ["subscribers", "frameQueued", "continuous", "canSchedule", "onRenderRequested", "redraw", "requestRender", "renderContinuously", "released", "defaults", "clone", "value", "merge", "target", "source", "key", "DefaultTheme", "Theme", "version", "listeners", "setTheme", "config", "next", "listener", "requestRender", "themeVersion", "onThemeChange", "DefaultSize", "DefaultColor", "TextStyleFallback", "input", "fallback", "TextStyle", "#size", "#color", "#font", "#weight", "#fontStyle", "config", "ctx", "scale", "Theme", "text", "out", "measurements", "color", "size", "weight", "Pool", "#arr", "#count", "#builder", "#reset", "#runningDepth", "builder", "reset", "condition", "fn", "#running", "start", "value", "VectorPool", "v", "CopyVector2", "dst", "src", "SubVector2", "a", "b", "AddVector2", "ScaleVector", "scale", "Zero", "Distance", "xd", "yd", "normalizeMinMax", "min", "max", "temp", "BoxIntersection", "a", "b", "intersects", "VectorPool", "aMin", "aMax", "CopyVector2", "AddVector2", "bMin", "bMax", "BoxCenter", "box", "out", "InBox", "position", "List", "#arr", "#count", "index", "value", "arr", "i", "contextEntryHeight", "ContextMenuItemState", "ContextMenuItem", "#name", "#callback", "#textStyle", "#state", "config", "TextStyle", "ContextGroup", "entries", "#calculatedHeight", "contextEntryHeight", "ContextEntry", "text", "subMenu", "item", "CombineContextMenus", "contextMenus", "finalConfig", "i", "ContextMenu", "#items", "#subMenus", "#groups", "#group", "#submenuPosition", "Zero", "List", "TextStyleFallback", "Theme", "#calculateEntries", "groupLUT", "workingGroups", "group", "sub", "groupIndex", "groupContent", "#calculatedWidth", "#getMaxWidthForText", "ctx", "scale", "tempVec", "entryIndex", "#tempBox", "#openSubMenu", "#bounds", "point", "InBox", "anchor", "graphScale", "mousePosition", "openRight", "parentWidth", "scaledEntryHeight", "scaledEntryWidth", "totalScaledHeight", "canvasWidth", "position", "opensRight", "rightOfParent", "leftOfParent", "fitsRight", "fitsLeft", "pointer", "CopyVector2", "mouseIsOver", "row", "entry", "optionsRendered", "entryMousedOver", "itemDisabled", "highlighted", "startX", "y", "mouseOverSub", "LONG_PRESS_MS", "LONG_PRESS_SLOP", "WHEEL_ZOOM_PER_PIXEL", "SUPPRESS_MOUSE_MS", "MouseObserver", "#clicked", "#lastTouch", "#ele", "#lastMousePosition", "#dragCallback", "#moveCallback", "#clickStart", "#clickStop", "#contextMenu", "#zoomCallback", "#leaveCallback", "#inside", "#longPressTimer", "#longPressOrigin", "Zero", "#longPressFired", "#pinchDist", "#lastTouchAt", "ele", "dragCallback", "moveCallback", "clickStart", "clickStop", "contextMenu", "fileDrop", "zoomCallback", "leaveCallback", "redraws", "handler", "event", "requestRender", "#down", "#touchStart", "#up", "#touchEnd", "#move", "#touchMove", "#wheel", "ev", "item", "i", "file", "#mousePos", "evt", "rect", "#touchPos", "touch", "#fromTouch", "#clearLongPress", "dy", "anchor", "pos", "delta", "SubVector2", "CopyVector2", "wasClicked", "Distance", "x", "y", "a", "b", "dist", "InstantiateRenderElementSidesStyling", "config", "RenderElementBase", "#margin", "#padding", "#border", "#backgroundColor", "#minWidth", "#maxWidth", "#minHeight", "#maxHeight", "#grow", "#display", "config", "InstantiateRenderElementSidesStyling", "newColor", "ctx", "position", "graphScale", "scaledFillableSpace", "scaledSize", "offsetPosition", "#totalLeftOffset", "#totalTopOffset", "elementSize", "#horizontalOffset", "#verticalOffset", "out", "display", "maxLimits", "ContainerRenderElement", "RenderElementBase", "#elements", "#layout", "#alignment", "elements", "config", "ctx", "out", "limitations", "eleSize", "i", "position", "graphScale", "scaledFillableSpace", "#renderColumn", "currnetPos", "scaledEleSize", "ele", "ScaleVector", "TextElement", "RenderElementBase", "#text", "#align", "#verticalAlign", "#lineHeight", "text", "styling", "ctx", "position", "graphScale", "scaledFillableSpace", "scale", "Zero", "ScaleVector", "justifiedPosition", "CopyVector2", "eles", "tempSize", "i", "out", "limitations", "binarySearch", "max", "getValue", "match", "min", "guess", "compareVal", "fitString", "ctx", "str", "maxWidth", "width", "ellipsis", "ellipsisWidth", "index", "splitString", "backward", "splitStringIntoLines", "strings", "remaining", "Text", "#measured", "#measuredForTheme", "#size", "#style", "#value", "#maxWidth", "#lineSpacing", "#textToRender", "value", "style", "config", "Zero", "TextStyle", "requestRender", "newValue", "ctx", "maxWidth", "results", "entries", "splitStringIntoLines", "i", "text", "char", "index", "splitString", "#measure", "themeVersion", "measurements", "scale", "out", "CopyVector2", "ScaleVector", "color", "size", "weight", "position", "yOffset", "Clamp", "v", "min", "max", "Clamp01", "componentToHex", "c", "hex", "RgbToHex", "HexToColor", "result", "HSV2RGB", "hsv", "out", "hh", "i", "ff", "p", "q", "t", "Clamp01", "PortType", "portsCompatible", "a", "b", "typeSetsCompatible", "type", "portsConnect", "output", "input", "casts", "typeSetsConnect", "cast", "portConfigTypes", "config", "ARRAY_SLOT_PITCH", "arrayInsertIndex", "box", "count", "y", "index", "arraySlotCenter", "slots", "fallbackColor", "s", "value", "i", "mod", "hsv", "color", "HSV2RGB", "RgbToHex", "portTypeColor", "Port", "#node", "#displayName", "#emptyStyle", "#filledStyle", "#connections", "#portType", "#dataType", "#anyType", "#acceptedTypes", "#description", "#array", "#hidden", "#configuredEmptyFill", "#configuredFilledFill", "#dataTypePopupElement", "#onConnectionAdded", "#onConnectionRemoved", "#widget", "node", "portType", "#buildTooltip", "containerElements", "dataTypeDisplay", "TextElement", "Text", "ContainerRenderElement", "#refreshDataType", "requestRender", "anyType", "connection", "c", "was", "#visibilityMayHaveChanged", "callback", "hidden", "widget", "types", "#box", "ctx", "position", "camera", "mousePosition", "postProcess", "style", "scaledRadius", "InBox", "xPos", "yPos", "size", "height", "slot", "CursorStyle", "open", "placeEditsDuring", "canvas", "draw", "edit", "editInPlace", "config", "input", "place", "box", "scale", "rect", "sx", "sy", "left", "top", "width", "height", "clip", "c", "Theme", "done", "finish", "keep", "requestRender", "event", "width", "height", "WidgetBase", "#hidden", "#disabled", "#hovered", "#pressed", "#box", "#canvas", "#scale", "#editing", "ctx", "box", "scale", "mousePosition", "InBox", "pointer", "requestRender", "hidden", "disabled", "value", "onCommit", "editInPlace", "startingWidgetValue", "node", "property", "configured", "fallback", "existing", "HiddenPortsToggle", "WidgetBase", "owner", "ctx", "box", "scale", "label", "midY", "centerX", "Theme", "half", "StrokeStyleWithFallback", "input", "fallback", "StrokeStyle", "#size", "#color", "config", "ctx", "scale", "newColor", "newSize", "BoxStyleWithFallback", "input", "fallback", "StrokeStyleWithFallback", "BoxStyle", "#border", "#color", "#radius", "config", "StrokeStyle", "#box", "ctx", "box", "scale", "radius", "#draw", "color", "drawBevel", "ctx", "box", "scale", "colors", "sunken", "width", "half", "left", "top", "right", "bottom", "widgetFont", "scale", "Theme", "fieldBackground", "look", "drawFieldBox", "ctx", "box", "drawBevel", "drawField", "drawFieldText", "padding", "middle", "textColor", "fitString", "room", "label", "labelWidth", "ValueWidget", "WidgetBase", "#node", "#property", "#value", "#label", "#width", "#callback", "#onInput", "node", "config", "fallback", "width", "startingWidgetValue", "_", "next", "height", "value", "requestRender", "label", "startedAt", "a", "b", "DRAG_THRESHOLD", "NumberWidget", "ValueWidget", "#step", "#integer", "#min", "#max", "#startX", "#startValue", "#dragging", "#dragged", "node", "config", "ctx", "box", "scale", "drawField", "formatNumber", "pointer", "dx", "#clean", "#stepFor", "before", "text", "parsed", "value", "rounded", "ButtonWidget", "WidgetBase", "#text", "#callback", "#width", "config", "width", "height", "text", "requestRender", "ctx", "box", "scale", "drawField", "contrastColor", "color", "c", "HexToColor", "picker", "sharedPicker", "ColorWidget", "ValueWidget", "#contrast", "node", "config", "ctx", "box", "scale", "drawField", "canvas", "before", "alpha", "rect", "sx", "sy", "input", "SliderWidget", "ValueWidget", "#min", "#max", "#snapIncrement", "#fillColor", "#startValue", "node", "config", "min", "max", "Clamp", "value", "ctx", "box", "scale", "drawFieldBox", "border", "Theme", "fill", "Clamp01", "drawFieldText", "formatNumber", "pointer", "#valueAt", "x", "StringWidget", "ValueWidget", "node", "config", "ctx", "box", "scale", "drawField", "before", "text", "ToggleWidget", "ValueWidget", "#onColor", "#offColor", "node", "config", "before", "ctx", "box", "scale", "drawFieldBox", "light", "inset", "on", "Theme", "textLeft", "widgetFont", "room", "fitString", "ImageWidget", "WidgetBase", "#url", "#ownedUrl", "#image", "#maxWidth", "#maxHeight", "config", "blob", "url", "img", "requestRender", "event", "adjust", "heightAdjust", "ctx", "box", "scale", "size", "w", "h", "TextWidget", "WidgetBase", "#value", "#size", "#styleConfig", "#styledForTheme", "#followTheme", "themeVersion", "style", "Theme", "node", "config", "Zero", "Text", "TextStyleFallback", "property", "existing", "_", "next", "value", "requestRender", "ctx", "box", "scale", "RowWidget", "WidgetBase", "#children", "#grow", "#gap", "#boxes", "#captured", "#capturedBox", "#mouse", "children", "config", "Theme", "shown", "#shown", "x", "y", "child", "size", "#childAt", "ctx", "box", "scale", "mousePosition", "gap", "natural", "sum", "extra", "totalGrow", "#growOf", "share", "childBox", "pointer", "#forChild", "forChild", "InBox", "position", "i", "WidgetFactory", "#registeredWidgets", "widgetType", "builder", "node", "config", "GlobalWidgetFactory", "ButtonWidget", "NumberWidget", "ColorWidget", "SliderWidget", "StringWidget", "ToggleWidget", "ImageWidget", "TextWidget", "RowWidget", "child", "BACKWARD_PORT_STUB", "BACKWARD_STUB_RAMP", "smoothstep", "t", "x", "Clamp01", "DefaultConnectionRenderer", "connectionSize", "connectionColor", "mouseOverSize", "mouseOverColor", "params", "color", "lineSize", "inX", "inY", "outX", "outY", "overlap", "fullStub", "ramp", "stub", "curveStartX", "curveEndX", "midX", "Connection", "#inPos", "#outPos", "#inNode", "#inNodePortIndex", "#outNode", "#outNodePortIndex", "#renderer", "inNode", "inNodePortIndex", "outNode", "outNodePortIndex", "renderer", "Zero", "ctx", "graphScale", "mouseOver", "mousePosition", "inPortBox", "#inSlotBox", "BoxCenter", "outPortBox", "InBox", "node", "portIndex", "replace", "insertAt", "port", "box", "slots", "index", "height", "Camera", "Zero", "screenPosition", "out", "scale", "graphPosition", "orientation", "widthSpacing", "heightSpacing", "laneSpacing", "pieceSpacing", "orderingSweeps", "placementSweeps", "topologicalOrder", "sorting", "upstream", "visited", "order", "root", "stack", "top", "feeder", "consumersOf", "downstream", "node", "consumers", "assignLayers", "placed", "rank", "r", "consumer", "deepest", "layerOf", "layer", "c", "pulled", "feederLayer", "used", "a", "b", "compact", "i", "layers", "crossingsOf", "layout", "slotOf", "slot", "total", "spans", "orderWithinLayers", "meanSlot", "neighbours", "count", "neighbour", "sweep", "towards", "index", "adjacent", "keys", "mean", "s", "best", "fewest", "crossings", "findPieces", "rankOf", "seen", "pieces", "start", "piece", "treeRoot", "columnXs", "widths", "xs", "x", "width", "layoutTree", "sizes", "children", "depthOf", "preorder", "kids", "depth", "band", "topInBand", "childOffset", "height", "offset", "kid", "centre", "shift", "positions", "bandTop", "column", "size", "isotonic", "targets", "blocks", "target", "last", "before", "result", "block", "median", "values", "sorted", "middle", "layoutLayered", "up", "down", "heightOf", "nextLane", "from", "fromLayer", "to", "toLayer", "previous", "lane", "feeders", "sequence", "sink", "gapAfter", "above", "below", "topOf", "y", "centreOf", "place", "offsets", "centres", "n", "desired", "solved", "widest", "layoutLoose", "loose", "columns", "heights", "ys", "toBlock", "minX", "minY", "maxX", "maxY", "position", "shifted", "layoutGraph", "area", "rowWidth", "rowHeight", "Organize", "ctx", "graph", "nodesToSort", "nodes", "inLayout", "nodeLUT", "camera", "Camera", "connection", "feederIndex", "anchor", "right", "bottom", "TimeExecution", "name", "callback", "start", "end", "offersMatchingPort", "config", "filter", "port", "typeSetsConnect", "portConfigTypes", "Publisher", "#name", "#description", "#version", "#registeredNodes", "nodeKey", "nodeType", "#recurseBuildMenu", "graph", "name", "subMenu", "position", "items", "subMenus", "key", "nodeConfig", "slashIndex", "bracketIndex", "node", "FlowNode", "elements", "menu", "menus", "nodes", "built", "NodeFactory", "#registeredPublishers", "#registeredCallbacks", "config", "entry", "Publisher", "callback", "identifier", "publisher", "nodeType", "publisherIdentifier", "node", "i", "graph", "position", "filter", "menus", "_", "built", "nodeFlowGroup", "nodeFlowGroup", "BuildConnectionRenderer", "config", "DefaultConnectionRenderer", "NodeSubsystem", "#postProcessPass", "#nodes", "#connections", "#nodeHovering", "#nodesGrabbed", "#connectionSelected", "#idleConnectionRenderer", "#portHovering", "#widgetHovering", "#widgetCurrentlyClicking", "#widgetHoveringBox", "#capturedWidgetBox", "#capturedPointer", "Zero", "#cursor", "#nodeFactory", "#boxSelect", "#boxSelectStart_graphSpace", "#boxSelectEnd_graphSpace", "#boxSelectionNodes", "#casts", "#lastCtx", "#lastMousePosition", "#nodeRemovedCallbacks", "#registeredNodeAddedCallbacks", "#nodeHoverCallbacks", "#hoveredNode", "postProcessPass", "List", "NodeFactory", "casts", "identifier", "publisher", "callback", "#setHoveredNode", "node", "i", "mousePosition", "camera", "ctrlKey", "intersection", "hoveringSomething", "#selectNodeByIndex", "CopyVector2", "#widgetPointer", "port", "wires", "picked", "wire", "inNode", "inNodeIndex", "outNode", "outNodeIndex", "connection", "Connection", "InBox", "delta", "scale", "nodeMoved", "VectorPool", "scaledDelta", "AddVector2", "#interactingWithNode", "#interactingWithConnection", "#interactingWithWidget", "index", "#removeConnection", "nodes", "within", "from", "to", "outPort", "inPort", "#outputPortIndex", "#inputPortIndex", "#onConnectionReleased", "handler", "#describeDanglingConnection", "conn", "fromIndex", "#firstCompatiblePort", "toIndex", "side", "against", "count", "firstHidden", "portsConnect", "#selectNode", "widget", "pointer", "dangling", "#clearCurrentlySelectedConnection", "replace", "inputPort", "#insertIndex", "nodeOut", "nodeIn", "existingInputConnections", "requestRender", "selected", "nodeIndex", "connections", "file", "#removeNodeConnections", "#removeConnectionByIndex", "#removeNodeByIndex", "clearPorts", "ctx", "Organize", "#nodesSelected", "#organizeSelected", "position", "organizeNodesSubMenu", "selectedCount", "nodeToReview", "nodeToReviewNode", "#selectConnectedNodes", "#selectInputNodesAndDescendents", "CombineContextMenus", "inputs", "outputs", "changed", "removed", "unselectOthers", "#renderConnections", "portMousedOver", "#renderNodes", "hovered", "selectedBox_Screenspace", "#boxSelectionScreenspaceBox", "canvas", "state", "nodeBounds", "BoxIntersection", "box", "SubVector2", "hovering", "arrayInsertIndex", "#renderInsertMarker", "y", "overhang", "awaitingLayout", "TimeExecution", "Theme", "BoxStyle", "Popup", "#title", "#options", "#content", "#onClose", "#buttonCSS", "#popup", "#keyHandler", "config", "#close", "option", "Theme", "container", "title", "buttonContainer", "button", "e", "SetStringPopup", "config", "input", "Popup", "container", "button", "FormPopup", "config", "input", "setOption", "cancelOption", "Popup", "container", "i", "title", "ele", "button", "values", "MINIMUM_NODE_WIDTH", "MessageType", "MessageTypeColor", "messageType", "Theme", "NodeState", "MessageRenderer", "#text", "#alwaysShow", "config", "Text", "ctx", "scale", "position", "hovering", "FlowNode", "#position", "#title", "#subTitle", "#infoSymbol", "#infoText", "#messages", "#input", "#output", "#widgets", "#locked", "#canEditTitle", "#canEditInfo", "#canEditPorts", "#contextMenu", "#metadata", "#onSelect", "#onUnselect", "#onFiledrop", "#onDragStop", "#titleChangeCallback", "#infoChangeCallback", "#styleConfig", "#styledForTheme", "#titleColor", "#selectedStyle", "#stateStyles", "#padding", "#portTextStyle", "#elementSpacing", "#selected", "#highlighted", "#inputPortPositions", "#outputPortPositions", "#widgetPositions", "#portWidgetPositions", "List", "#data", "#registeredAnyPropertyChangeCallbacks", "#registeredPropertyChangeCallbacks", "#registeredPropertyEditCallbacks", "i", "message", "TextStyleFallback", "#applyStyle", "widget", "GlobalWidgetFactory", "requestRender", "highlighted", "callback", "name", "callbacks", "value", "oldValue", "#popupNodeTitleSelection", "SetStringPopup", "#popupNodeInfoSelection", "#popupNewButtonWidget", "ButtonWidget", "#widgetSubmenu", "NumberWidget", "ColorWidget", "FormPopup", "data", "SliderWidget", "StringWidget", "ToggleWidget", "ImageWidget", "nodeFlowGroup", "items", "submenus", "CombineContextMenus", "file", "CopyVector2", "camera", "#followTheme", "tempMeasurement", "Zero", "doublePadding", "screenSpacePosition", "size", "subtitleSize", "port", "#portRowHeight", "#portRowWidth", "widgets", "#hasHiddenPortsToggle", "#hiddenPortsToggle", "eleSize", "ScaleVector", "Port", "#hiddenPortsShown", "HiddenPortsToggle", "#hiddenPortsTogglePosition", "shown", "count", "index", "at", "removed", "from", "to", "delta", "intersection", "box", "InBox", "newTitle", "cleaned", "old", "newInfo", "style", "titleText", "border", "BoxStyle", "BoxStyleWithFallback", "TextStyle", "themeVersion", "#calculateStyle", "state", "boxStyle", "textHeight", "slots", "ARRAY_SLOT_PITCH", "textWidth", "#laidOut", "#portOffsets", "mousePosition", "postProcess", "VectorPool", "scaledPadding", "scaledElementSpacing", "nodeBounds", "nodeStyle", "borderSize", "titleSize", "titleBoxSize", "titleX", "titleY", "titleWidth", "titleHeight", "drawBevel", "titlePosition", "subtitlePosition", "infoRadius", "centerX", "centerY", "infoPosition", "infoLineThickness", "Distance", "infoBoxWidth", "textEntries", "splitStringIntoLines", "lineHeight", "infoBoxHeight", "scaledLineHeight", "start", "entry", "startY", "leftSide", "portHeight", "widgetHeight", "widgetLeft", "rightSide", "widgetSize", "messageStart", "#rememberPortOffsets", "bounds", "zoom", "record", "positions", "into", "project", "offsets", "offset", "MarkdownToken", "#type", "#lexeme", "#tokenStart", "#tokenEnd", "type", "lexeme", "tokenStart", "tokenEnd", "MarkdownLexicalParser", "#body", "#index", "#tokens", "body", "#current", "#inc", "#next", "#tokenStart", "#addToken", "token", "lexeme", "start", "MarkdownToken", "#header", "count", "type", "#whiteSpace", "char", "#text", "started", "onFontsLoaded", "callback", "requestRender", "CodeBlockEntry", "#text", "#calculatedPositions", "#calculatedEntries", "#calculatedForWidth", "text", "List", "#calculateLayout", "ctx", "maxWidth", "adjustedWith", "Theme", "curHeight", "lineInc", "entries", "entryIndex", "lines", "lineIndex", "position", "scale", "padding", "lineCount", "lastTop", "height", "baseline", "i", "entry", "pos", "UnorderedListMarkdownEntry", "#entries", "offset", "shift", "dot", "BasicMarkdownEntry", "#underline", "#background", "underline", "background", "curPosition", "Zero", "texSize", "currentLineHeight", "currentLineText", "currentLineWidths", "max", "y", "MarkdownSyntaxParser", "#tokens", "#index", "#originalText", "originalText", "tokens", "#current", "#inc", "#next", "#peak", "#peakInto", "amount", "#emphasis", "Text", "openers", "#runOfStars", "content", "closers", "token", "matched", "style", "runs", "count", "#inlineCode", "opened", "Theme", "#text", "contents", "textContent", "i", "#h1", "text", "BasicMarkdownEntry", "#h2", "#h3", "#starLineStart", "starEntries", "#assignStandardStyling", "entries", "UnorderedListMarkdownEntry", "textEntries", "#backtickLineStart", "start", "end", "codeBlockText", "entryText", "CodeBlockEntry", "BuildMarkdown", "data", "lexicalParser", "MarkdownLexicalParser", "MarkdownSyntaxParser", "BOUNDS_SPACING", "BOX_SIZE", "FlowNote", "#originalText", "#document", "#parsedForTheme", "#width", "#edittingStyle", "#data", "#position", "#handleSelected", "#edittingLayout", "#lastRenderedBox", "#hovering", "#widthChangeCallbacks", "#contentChangeCallbacks", "config", "BoxStyle", "text", "BuildMarkdown", "themeVersion", "i", "name", "value", "delta", "position", "CopyVector2", "handle", "#tempPosition", "Zero", "newWidth", "callback", "ctx", "camera", "mousePosition", "leftPosition", "scaledWidth", "rightPosition", "left", "right", "bottom", "top", "startY", "lineSpacing", "Theme", "hovering", "input", "saveText", "Popup", "container", "button", "NoteSubsystem", "#notes", "#noteHovering", "#noteSelected", "#hoveringHandle", "#onNoteAddedCallbacks", "#onNoteRemovedCallbacks", "#onNoteDragStartCallbacks", "#onNoteDragStopCallbacks", "config", "i", "FlowNote", "note", "requestRender", "callback", "ctx", "position", "group", "result", "noteToReview", "mousePosition", "camera", "ctrlKey", "delta", "scale", "file", "index", "noteRemoved", "notes", "j", "InBox", "PassSubsystem", "#queue", "List", "lambda", "ctx", "camera", "mousePosition", "position", "ctrlKey", "delta", "scale", "file", "QuickMenuGroup", "#text", "text", "items", "terms", "shouldRender", "i", "kept", "QuickMenuItem", "#searchText", "#context", "searchText", "context", "render", "highlight", "Theme", "RecurseBuildContainers", "path", "config", "renderElements", "groups", "currentPath", "titleText", "TextElement", "Text", "quickItems", "configItem", "itemText", "QuickMenu", "#menuGroups", "#container", "#currentSelection", "elements", "ContainerRenderElement", "#updateHighlighting", "selection", "groupIndex", "group", "itemIndex", "potentialTerms", "cleaned", "event", "intercepted", "ctx", "pos", "graphScale", "mousePosition", "#bounds", "point", "InBox", "Minimap", "#enabled", "#width", "#height", "#margin", "#backgroundColor", "#borderColor", "#nodeColor", "#viewportColor", "#box", "#scale", "#originX", "#originY", "#padding", "Theme", "#drawn", "config", "enabled", "position", "InBox", "out", "ctx", "canvas", "camera", "nodes", "flat", "Camera", "minX", "minY", "maxX", "maxY", "boxes", "i", "bounds", "topLeft", "bottomRight", "usableWidth", "usableHeight", "left", "top", "toMapX", "toMapY", "y", "b", "BuildBackgroundRenderer", "backgroundColor", "canvas", "context", "position", "scale", "Theme", "alpha", "Clamp01", "spacing", "pi2", "dotScale", "x", "xPos", "y", "yPos", "contextMenuGroup", "GraphView", "#subsystems", "subsystems", "mousePosition", "camera", "ctrlKey", "file", "i", "ctx", "finalConfig", "subSystemMenu", "CombineContextMenus", "delta", "results", "TimeExecution", "layer", "NodeFlowGraph", "#ctx", "#canvas", "#backgroundRenderer", "#contextMenuConfig", "#mousePosition", "#mouseOverCanvas", "#camera", "#openedContextMenu", "#openQuickMenu", "#contextMenuEntryHovering", "#views", "#currentView", "#mainNodeSubsystem", "#mainNoteSubsystem", "config", "postProcessPass", "PassSubsystem", "NodeSubsystem", "#lastFrameCursor", "#cursor", "NoteSubsystem", "Camera", "#minimap", "Minimap", "dangling", "#openScopedMenu", "#watchCanvasSize", "#stopRendering", "onRenderRequested", "#render", "requestRender", "MouseObserver", "#mouseDragEvent", "#clickStart", "#clickEnd", "#openContextMenu", "#fileDrop", "factor", "anchor", "#zoomBy", "e", "#keyDown", "#copyCallbacks", "#pasteCallbacks", "callback", "#raiseCopy", "nodes", "connections", "#raisePaste", "#sceenPositionToGraphPosition", "#deleteKey", "contextMenuPosition", "items", "QuickMenu", "contents", "extension", "pos", "Zero", "CopyVector2", "FlowNode", "amount", "anchorPos", "oldPos", "newPos", "#lookAtFromMinimap", "#draggingMinimap", "target", "identifier", "publisher", "casts", "orientation", "measureCamera", "minX", "minY", "maxX", "maxY", "bounds", "width", "height", "padX", "padY", "canvasWidth", "canvasHeight", "zoom", "centerX", "centerY", "nodeIndex", "nodeOut", "outPort", "nodeIn", "inPort", "node", "index", "note", "screenPosition", "out", "ContextMenu", "menu", "#sizeObserver", "#matchCanvasToParent", "parent", "rect", "renderContinuously", "#renderBackground", "placeEditsDuring", "#pointerOnGraph", "#renderContextMenu", "#renderQuickMenu", "#pointer", "pointer", "VectorPool"]
7
+ }