diff --git a/.vscode/launch.json b/.vscode/launch.json index eb5a47c..3fd353d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,15 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + { + "name": "Attach", + "port": 9229, + "request": "attach", + "skipFiles": [ + "/**" + ], + "type": "node" + }, { "request": "launch", "name": "Launch Program", diff --git a/deno.json b/deno.json index fd4aabb..03b0d04 100644 --- a/deno.json +++ b/deno.json @@ -3,7 +3,7 @@ "tasks": { "dev": "deno -A --watch instance/src/index.ts", "start": "deno -A instance/src/index.ts", - "dev-debug": "deno -A --inspect instance/src/index.ts", + "dev-debug": "deno -A --inspect-brk instance/src/index.ts", "build-web": "deno --cwd instance/src/web build", "uikit": "deno --cwd uikit-solid dev", "preinstall": "git pull --recurse-submodules" diff --git a/deno.lock b/deno.lock index e27e5a6..dc8b943 100644 --- a/deno.lock +++ b/deno.lock @@ -16,6 +16,7 @@ "npm:@material-symbols/svg-700@~0.42.3": "0.42.3", "npm:@material/material-color-utilities@0.3": "0.3.0", "npm:@mediapipe/tasks-vision@~0.10.32": "0.10.35", + "npm:@opentui/core@~0.4.1": "0.4.1_web-tree-sitter@0.25.10_typescript@6.0.3", "npm:@simplewebauthn/browser@^13.3.0": "13.3.0", "npm:@simplewebauthn/server@^13.3.0": "13.3.1", "npm:@solid-primitives/media@^2.3.3": "2.3.5_solid-js@1.9.13", @@ -985,6 +986,67 @@ "@nothing-but/utils@0.17.0": { "integrity": "sha512-TuCHcHLOqDL0SnaAxACfuRHBNRgNJcNn9X0GiH5H3YSDBVquCr3qEIG3FOQAuMyZCbu9w8nk2CHhOsn7IvhIwQ==" }, + "@opentui/core-darwin-arm64@0.4.1": { + "integrity": "sha512-ocs73hj9n0zLArOTpUWIXCWU6ERThG+3wQzO78EvfaR4hb5FRrDHGKWTzXpr6ukSKsUtKdztK5XYTPsJ5e3vww==", + "os": ["darwin"], + "cpu": ["arm64"] + }, + "@opentui/core-darwin-x64@0.4.1": { + "integrity": "sha512-YogRtDBfxGeOkcSHDMsGkKFBIt3cWPMPGNu2AmEN6a5KKjDYwAZCudwbDJaUbZDCJjfAUHz9iXjhJVXJBXs9vQ==", + "os": ["darwin"], + "cpu": ["x64"] + }, + "@opentui/core-linux-arm64-musl@0.4.1": { + "integrity": "sha512-Eps9qB+vQ/Lel4ZYqMH87Um9oiU17Vu4oWzvRi40Yf+69vA1a3R4D7KUCeY3OxKWnRnwAHkMU9TxNnjKngPH/w==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@opentui/core-linux-arm64@0.4.1": { + "integrity": "sha512-sBZTS1eEGeVSQ8fAmDALKQcT7FckrhK64oHfEO7W0lJ+lXapfJuOKtTM33na54V56GAM9guk4RD4cbPeTXEh4g==", + "os": ["linux"], + "cpu": ["arm64"] + }, + "@opentui/core-linux-x64-musl@0.4.1": { + "integrity": "sha512-UYcp8XGX4DZXN+VYUVuCrJkbFMJ0L+VUVu0t5KqqaeJ74fI4NZ+DmwNqPPg1+C+EIzoW4QChlEUdhlZRdiEQiA==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@opentui/core-linux-x64@0.4.1": { + "integrity": "sha512-9/xjYGzX5RdUl0qmGQY0OCayjJ4VffDhsBmApQdseUkMT6LGL3RumI4zPK3Y9vo1fuy6ffLnriLFOktOgutXDg==", + "os": ["linux"], + "cpu": ["x64"] + }, + "@opentui/core-win32-arm64@0.4.1": { + "integrity": "sha512-hkIbpUJcKd4iLetTygPlFS45teOBTto49aXuxNeafYQUNd3ehiSwJENNBlAGULLfq+KP3dMJoWUiOcbuPVOQRA==", + "os": ["win32"], + "cpu": ["arm64"] + }, + "@opentui/core-win32-x64@0.4.1": { + "integrity": "sha512-s1kGBcloy4ksl3wFCMqqOUFtXWlTTpzxe6pkLFhFhzgqKsMXHE9pwebiS3pzJkkFUxah5MYG+kbcn2Dw2Gdncg==", + "os": ["win32"], + "cpu": ["x64"] + }, + "@opentui/core@0.4.1_web-tree-sitter@0.25.10_typescript@6.0.3": { + "integrity": "sha512-ejlunoFCGLcghYGdfamI/DlWHsgCTLbuoL2JeOmFuLsN+DM5phje3CQbGR4tpl24cadCgHJQFomjoQ9Htvin+Q==", + "dependencies": [ + "bun-ffi-structs", + "diff", + "marked", + "string-width@7.2.0", + "strip-ansi@7.1.2", + "web-tree-sitter" + ], + "optionalDependencies": [ + "@opentui/core-darwin-arm64", + "@opentui/core-darwin-x64", + "@opentui/core-linux-arm64", + "@opentui/core-linux-arm64-musl", + "@opentui/core-linux-x64", + "@opentui/core-linux-x64-musl", + "@opentui/core-win32-arm64", + "@opentui/core-win32-x64" + ] + }, "@oxc-project/types@0.133.0": { "integrity": "sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==" }, @@ -1866,6 +1928,9 @@ "ansi-regex@5.0.1": { "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, + "ansi-regex@6.2.2": { + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==" + }, "ansi-styles@2.2.1": { "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==" }, @@ -2045,6 +2110,12 @@ "buildcheck@0.0.7": { "integrity": "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==" }, + "bun-ffi-structs@0.2.3_typescript@6.0.3": { + "integrity": "sha512-pgJiXP+hEgFo9qG51J6ItfY4ocs3vniwNzJ9WhoakB3QB2GdzQxX2EXssentPYlB2hOfJrTjO6iIQkWYzUodpg==", + "dependencies": [ + "typescript@6.0.3" + ] + }, "bun-types@1.3.14": { "integrity": "sha512-4N0ig0fEomHt5R0KCFWjovxow98rIoRwKolrYdCcknNwMekCXRnWEUvgu5soYV8QXtVsrUD8B95MBOZGPvr6KQ==", "dependencies": [ @@ -2369,6 +2440,9 @@ "detect-libc@2.1.2": { "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==" }, + "diff@9.0.0": { + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==" + }, "dijkstrajs@1.0.3": { "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==" }, @@ -2429,6 +2503,9 @@ "electron-to-chromium@1.5.372": { "integrity": "sha512-M3yhbAlilnwqC8D21t28UCDGHyitShTmmLRU/H+b74P6Ski16Nb9HONYEaVpMj/pwC7BEo5B95FpjODLCWbtfA==" }, + "emoji-regex@10.6.0": { + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==" + }, "emoji-regex@8.0.0": { "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, @@ -2707,6 +2784,9 @@ "get-caller-file@2.0.5": { "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, + "get-east-asian-width@1.6.0": { + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==" + }, "get-intrinsic@1.3.0": { "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dependencies": [ @@ -3176,6 +3256,10 @@ "pify@3.0.0" ] }, + "marked@17.0.1": { + "integrity": "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==", + "bin": true + }, "math-intrinsics@1.1.0": { "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==" }, @@ -4120,11 +4204,19 @@ "string-width@4.2.3": { "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dependencies": [ - "emoji-regex", + "emoji-regex@8.0.0", "is-fullwidth-code-point@3.0.0", "strip-ansi@6.0.1" ] }, + "string-width@7.2.0": { + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dependencies": [ + "emoji-regex@10.6.0", + "get-east-asian-width", + "strip-ansi@7.1.2" + ] + }, "string_decoder@1.1.1": { "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dependencies": [ @@ -4143,6 +4235,12 @@ "ansi-regex@5.0.1" ] }, + "strip-ansi@7.1.2": { + "integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==", + "dependencies": [ + "ansi-regex@6.2.2" + ] + }, "strip-dirs@2.1.0": { "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", "dependencies": [ @@ -4528,6 +4626,9 @@ "xml-name-validator" ] }, + "web-tree-sitter@0.25.10": { + "integrity": "sha512-Y09sF44/13XvgVKgO2cNDw5rGk6s26MgoZPXLESvMXeefBf7i6/73eFurre0IsTW6E14Y0ArIzhUMmjoc7xyzA==" + }, "webidl-conversions@8.0.1": { "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==" }, @@ -4960,7 +5061,8 @@ "dependencies": [ "jsr:@std/fs@^1.0.24", "jsr:@std/http@^1.1.1", - "jsr:@std/path@^1.1.5" + "jsr:@std/path@^1.1.5", + "npm:@opentui/core@~0.4.1" ], "packageJson": { "dependencies": [ diff --git a/instance/deno.json b/instance/deno.json index c4376c9..8b55534 100644 --- a/instance/deno.json +++ b/instance/deno.json @@ -2,7 +2,8 @@ "imports": { "@std/fs": "jsr:@std/fs@^1.0.24", "@std/http": "jsr:@std/http@^1.1.1", - "@std/path": "jsr:@std/path@^1.1.5" + "@std/path": "jsr:@std/path@^1.1.5", + "@opentui/core": "npm:@opentui/core@^0.4.1" }, "permissions": { "default": { diff --git a/instance/src/systems/terminalUI.ts b/instance/src/systems/terminalUI.ts index e983b7f..2494b1c 100644 --- a/instance/src/systems/terminalUI.ts +++ b/instance/src/systems/terminalUI.ts @@ -1,50 +1,33 @@ -import type { Instance } from "../index.ts"; -import System from "../system.ts"; -import Terminal from "./terminalUI/terminal.ts"; -import TerminalBorderView from "./terminalUI/views/borderView.ts"; -import TerminalContainerView from "./terminalUI/views/container.ts"; -import TerminalCrossView from "./terminalUI/views/crossView.ts"; -import TerminalTextInputView from "./terminalUI/views/textInput.ts"; - -export default class TerminalUISystem extends System { - constructor(instance: Instance) { - super("terminal_ui", instance); - } - - override async startup(): Promise { - if (!process.stdout) return false; - - await super.startup(); - - const terminal = new Terminal(); - - // biome-ignore format: TUI description - terminal.screen.childView.addChild( - TerminalContainerView, v => v.setFlowDirection("y") - .addChild( - TerminalBorderView, v => v - .addChild(TerminalContainerView, v => v.setFlowDirection("y") - .addChild( - TerminalTextInputView, v => v - .setPlaceholder("Placeholder Text") - ) - .addChild( - TerminalContainerView, v => v.setFlowDirection("x") - .addChild(TerminalCrossView) - .addChild(TerminalCrossView) - ) - ) - ) - // .addChild( - // TerminalBorderView, v=>v - // .setDimensions({width: { unit: "%", value: 100 }, height: { unit: "px", value: 5 } }) - // ) - ); - - setInterval(async () => { - await terminal.draw(); - }, 100); - - return true; - } -} +import type { Instance } from "../index.ts"; +import System from "../system.ts"; +import { createCliRenderer, Text } from "@opentui/core"; +import ffi from "node:ffi"; + +export default class TerminalUISystem extends System { + constructor(instance: Instance) { + super("terminal_ui", instance); + } + + override async startup(): Promise { + if (!process.stdout) return false; + + await super.startup(); + + try { + const renderer = await createCliRenderer({ + exitOnCtrlC: true, + }); + + renderer.root.add( + Text({ + content: "Hello, OpenTUI!", + fg: "#00FF00", + }), + ); + } catch (err) { + console.error(err); + } + + return true; + } +} diff --git a/instance/src/systems/terminalUI/effect.ts b/instance/src/systems/terminalUI/effect.ts deleted file mode 100644 index fb73d1b..0000000 --- a/instance/src/systems/terminalUI/effect.ts +++ /dev/null @@ -1,194 +0,0 @@ -export enum TerminalColor { - Black = 1, - Red, - Green, - Yellow, - Blue, - Magenta, - Cyan, - White, - BrightBlack, - BrightRed, - BrightGreen, - BrightYellow, - BrightBlue, - BrightMagenta, - BrightCyan, - BrightWhite, -} - -export default class TerminalEffect { - private foregroundColor?: TerminalColor; - private backgroundColor?: TerminalColor; - private bold?: boolean; - private underline?: boolean; - - setBold() { - this.bold = true; - - return this; - } - - setUnderline() { - this.underline = true; - - return this; - } - - setColor(color: TerminalColor) { - this.foregroundColor = color; - - return this; - } - - setBackgroundColor(color: TerminalColor) { - this.backgroundColor = color; - - return this; - } - - async _internal_apply(): Promise { - let outputString = ""; - - if (this.bold) outputString += "\x1b[1m"; - if (this.underline) outputString += "\x1b[4m"; - if (this.foregroundColor) { - switch (this.foregroundColor) { - case TerminalColor.Black: { - outputString += "\x1b[30m"; - break; - } - case TerminalColor.Red: { - outputString += "\x1b[31m"; - break; - } - case TerminalColor.Green: { - outputString += "\x1b[32m"; - break; - } - case TerminalColor.Yellow: { - outputString += "\x1b[33m"; - break; - } - case TerminalColor.Blue: { - outputString += "\x1b[34m"; - break; - } - case TerminalColor.Magenta: { - outputString += "\x1b[35m"; - break; - } - case TerminalColor.Cyan: { - outputString += "\x1b[36m"; - break; - } - case TerminalColor.White: { - outputString += "\x1b[37m"; - break; - } - case TerminalColor.BrightBlack: { - outputString += "\x1b[90m"; - break; - } - case TerminalColor.BrightRed: { - outputString += "\x1b[91m"; - break; - } - case TerminalColor.BrightGreen: { - outputString += "\x1b[92m"; - break; - } - case TerminalColor.BrightYellow: { - outputString += "\x1b[93m"; - break; - } - case TerminalColor.BrightBlue: { - outputString += "\x1b[94m"; - break; - } - case TerminalColor.BrightMagenta: { - outputString += "\x1b[95m"; - break; - } - case TerminalColor.BrightCyan: { - outputString += "\x1b[96m"; - break; - } - case TerminalColor.BrightWhite: { - outputString += "\x1b[97m"; - break; - } - } - } - if (this.backgroundColor) { - switch (this.backgroundColor) { - case TerminalColor.Black: { - outputString += "\x1b[40m"; - break; - } - case TerminalColor.Red: { - outputString += "\x1b[41m"; - break; - } - case TerminalColor.Green: { - outputString += "\x1b[42m"; - break; - } - case TerminalColor.Yellow: { - outputString += "\x1b[43m"; - break; - } - case TerminalColor.Blue: { - outputString += "\x1b[44m"; - break; - } - case TerminalColor.Magenta: { - outputString += "\x1b[45m"; - break; - } - case TerminalColor.Cyan: { - outputString += "\x1b[46m"; - break; - } - case TerminalColor.White: { - outputString += "\x1b[47m"; - break; - } - case TerminalColor.BrightBlack: { - outputString += "\x1b[100m"; - break; - } - case TerminalColor.BrightRed: { - outputString += "\x1b[101m"; - break; - } - case TerminalColor.BrightGreen: { - outputString += "\x1b[102m"; - break; - } - case TerminalColor.BrightYellow: { - outputString += "\x1b[103m"; - break; - } - case TerminalColor.BrightBlue: { - outputString += "\x1b[104m"; - break; - } - case TerminalColor.BrightMagenta: { - outputString += "\x1b[105m"; - break; - } - case TerminalColor.BrightCyan: { - outputString += "\x1b[106m"; - break; - } - case TerminalColor.BrightWhite: { - outputString += "\x1b[107m"; - break; - } - } - } - - return outputString; - } -} diff --git a/instance/src/systems/terminalUI/events/keyPressEvent.ts b/instance/src/systems/terminalUI/events/keyPressEvent.ts deleted file mode 100644 index 8384967..0000000 --- a/instance/src/systems/terminalUI/events/keyPressEvent.ts +++ /dev/null @@ -1,12 +0,0 @@ -import TerminalEvent, { TerminalEventType } from "../terminalEvent.ts"; - -export default class KeyPressEvent extends TerminalEvent { - type: TerminalEventType = TerminalEventType.KeyPress as const; - key: string; - - constructor(key: string) { - super(); - - this.key = key; - } -} diff --git a/instance/src/systems/terminalUI/events/mouseClickEvent.ts b/instance/src/systems/terminalUI/events/mouseClickEvent.ts deleted file mode 100644 index f591992..0000000 --- a/instance/src/systems/terminalUI/events/mouseClickEvent.ts +++ /dev/null @@ -1,12 +0,0 @@ -import TerminalEvent, { TerminalEventType } from "../terminalEvent.ts"; - -export default class MouseClickEvent extends TerminalEvent { - type: TerminalEventType = TerminalEventType.MouseClick as const; - position: { x: number; y: number }; - - constructor(position: MouseClickEvent["position"]) { - super(); - - this.position = position; - } -} diff --git a/instance/src/systems/terminalUI/events/resizeScreenEvent.ts b/instance/src/systems/terminalUI/events/resizeScreenEvent.ts deleted file mode 100644 index c457602..0000000 --- a/instance/src/systems/terminalUI/events/resizeScreenEvent.ts +++ /dev/null @@ -1,12 +0,0 @@ -import TerminalEvent, { TerminalEventType } from "../terminalEvent.ts"; - -export default class ResizeScreenEvent extends TerminalEvent { - type: TerminalEventType = TerminalEventType.ResizeScreen as const; - dimensions: { width: number; height: number }; - - constructor(dimensions: ResizeScreenEvent["dimensions"]) { - super(); - - this.dimensions = dimensions; - } -} diff --git a/instance/src/systems/terminalUI/events/scrollDownEvent.ts b/instance/src/systems/terminalUI/events/scrollDownEvent.ts deleted file mode 100644 index 6744128..0000000 --- a/instance/src/systems/terminalUI/events/scrollDownEvent.ts +++ /dev/null @@ -1,12 +0,0 @@ -import TerminalEvent, { TerminalEventType } from "../terminalEvent.ts"; - -export default class ScrollDownEvent extends TerminalEvent { - type: TerminalEventType = TerminalEventType.ScrollDown as const; - yVector: number; - - constructor(yVector: ScrollDownEvent["yVector"]) { - super(); - - this.yVector = yVector * -1; - } -} diff --git a/instance/src/systems/terminalUI/events/scrollUpEvent.ts b/instance/src/systems/terminalUI/events/scrollUpEvent.ts deleted file mode 100644 index 02425f1..0000000 --- a/instance/src/systems/terminalUI/events/scrollUpEvent.ts +++ /dev/null @@ -1,12 +0,0 @@ -import TerminalEvent, { TerminalEventType } from "../terminalEvent.ts"; - -export default class ScrollUpEvent extends TerminalEvent { - type: TerminalEventType = TerminalEventType.ScrollUp as const; - yVector: number; - - constructor(yVector: ScrollUpEvent["yVector"]) { - super(); - - this.yVector = yVector; - } -} diff --git a/instance/src/systems/terminalUI/notes.md b/instance/src/systems/terminalUI/notes.md deleted file mode 100644 index e39cba1..0000000 --- a/instance/src/systems/terminalUI/notes.md +++ /dev/null @@ -1,33 +0,0 @@ -# View Struct - -- viewProperties - - width : TerminalScalarValue - - height : TerminalScalarValue - - contentWidth : TerminalScalarValue - - contentHeight : TerminalScalarValue - - contentOffsetX : TerminalScalarValue - - contentOffsetY : TerminalScalarValue - - _absolute // Autogenerated (DO NOT EDIT) - - drawOriginX: number // Calculated by the parent's calculateAbsoluteProperties(); - - drawOriginY: number // Calculated by the parent's calculateAbsoluteProperties(); - - width : number - - height : number - - contentWidth : number - - contentHeight : number - - contentOffsetX : number - - contentOffsetY : number -- viewContext - - screen - - drawIdx - - parentView -- calculateAbsoluteProperties() -- draw() - -# View Size Calculation Steps - -- get available space -- get all absolute widths and heights for children with px values (include min px values if the normal val uses non px values) -- get remaining space for x & y -- calculate all total % dimensions for children -- calculate the value of a width & height percent using the remaining space -- get all absolute widths and heights for children with % values diff --git a/instance/src/systems/terminalUI/renderError.ts b/instance/src/systems/terminalUI/renderError.ts deleted file mode 100644 index ba85239..0000000 --- a/instance/src/systems/terminalUI/renderError.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type TerminalScreen from "./screen.ts"; - -export default class RenderError { - private errorMessage: string; - private flash: number; - - constructor(errorMessage: string) { - this.errorMessage = errorMessage; - this.flash = 0; - } - - async draw(screen: TerminalScreen) { - const errorMessage = `RenderError! ${this.errorMessage}`; - const xOrigin = Math.floor(screen.width / 2) - Math.floor(errorMessage.length / 2); - - this.flash += 0.25; - - await screen._rawCursorTo(xOrigin, 0); - await screen._rawWrite(`${this.flash % 2 === 0 ? "\x1b[90;41m" : "\x1b[91;40m"}\x1b[1m ${" ".repeat(errorMessage.length)} `); - await screen._rawCursorTo(xOrigin, 1); - await screen._rawWrite(`${this.flash % 2 === 0 ? "\x1b[90;41m" : "\x1b[91;40m"}\x1b[1m ${errorMessage} `); - await screen._rawCursorTo(xOrigin, 2); - await screen._rawWrite(`${this.flash % 2 === 0 ? "\x1b[90;41m" : "\x1b[91;40m"}\x1b[1m ${" ".repeat(errorMessage.length)} `); - } -} diff --git a/instance/src/systems/terminalUI/scalarValue.ts b/instance/src/systems/terminalUI/scalarValue.ts deleted file mode 100644 index f9eb65b..0000000 --- a/instance/src/systems/terminalUI/scalarValue.ts +++ /dev/null @@ -1,140 +0,0 @@ -import type TerminalView from "./view.ts"; - -enum TerminalScalarValueOperation { - Set, - Add, - Subtract, - Multiply, - Divide, - Floor, - Ceil, -} - -export enum TerminalScalarValueUnit { - Cell, - Percentage, -} - -export default class TerminalScalarValue { - operationChain: [TerminalScalarValueOperation, number?, TerminalScalarValueUnit?][]; - - constructor(); - constructor(value: number, unit: TerminalScalarValueUnit); - constructor(value?: number, unit?: TerminalScalarValueUnit) { - this.operationChain = []; - - if (value !== undefined && unit !== undefined) { - this.set(value, unit); - } - } - - set(value: number, unit: TerminalScalarValueUnit) { - this.operationChain.push([TerminalScalarValueOperation.Set, value, unit]); - return this; - } - - add(value: number, unit: TerminalScalarValueUnit) { - this.operationChain.push([TerminalScalarValueOperation.Add, value, unit]); - return this; - } - - subtract(value: number, unit: TerminalScalarValueUnit) { - this.operationChain.push([TerminalScalarValueOperation.Subtract, value, unit]); - return this; - } - - multiply(value: number) { - this.operationChain.push([TerminalScalarValueOperation.Multiply, value]); - return this; - } - - divide(value: number) { - this.operationChain.push([TerminalScalarValueOperation.Divide, value]); - return this; - } - - floor() { - this.operationChain.push([TerminalScalarValueOperation.Floor]); - return this; - } - - ceil() { - this.operationChain.push([TerminalScalarValueOperation.Ceil]); - return this; - } - - _internal_calculateFromView(view: TerminalView, valueType: "width" | "height"): number { - let maxSize = 0; - - if (valueType === "height") { - maxSize = view.viewProperties._absolute.contentHeight; - } - if (valueType === "width") { - maxSize = view.viewProperties._absolute.contentWidth; - } - - let val = 0; - - for (const operation of this.operationChain) { - switch (operation[0]) { - case TerminalScalarValueOperation.Set: { - switch (operation[2]) { - case TerminalScalarValueUnit.Cell: { - val = operation[1]!; - break; - } - case TerminalScalarValueUnit.Percentage: { - val = (maxSize / 100) * operation[1]!; - break; - } - } - break; - } - case TerminalScalarValueOperation.Add: { - switch (operation[2]) { - case TerminalScalarValueUnit.Cell: { - val += operation[1]!; - break; - } - case TerminalScalarValueUnit.Percentage: { - val += (maxSize / 100) * operation[1]!; - break; - } - } - break; - } - case TerminalScalarValueOperation.Subtract: { - switch (operation[2]) { - case TerminalScalarValueUnit.Cell: { - val -= operation[1]!; - break; - } - case TerminalScalarValueUnit.Percentage: { - val -= (maxSize / 100) * operation[1]!; - break; - } - } - break; - } - case TerminalScalarValueOperation.Multiply: { - val *= operation[1]!; - break; - } - case TerminalScalarValueOperation.Divide: { - val /= operation[1]!; - break; - } - case TerminalScalarValueOperation.Floor: { - val = Math.floor(val); - break; - } - case TerminalScalarValueOperation.Ceil: { - val = Math.ceil(val); - break; - } - } - } - - return val; - } -} diff --git a/instance/src/systems/terminalUI/screen.ts b/instance/src/systems/terminalUI/screen.ts deleted file mode 100644 index e48c9b1..0000000 --- a/instance/src/systems/terminalUI/screen.ts +++ /dev/null @@ -1,167 +0,0 @@ -import { timeStamp } from "node:console"; -import type TerminalEffect from "./effect.ts"; -import type Terminal from "./terminal.ts"; -import type TerminalView from "./view.ts"; -import TerminalContainerView from "./views/container.ts"; - -export default class TerminalScreen { - parentTerminal: Terminal; - private previousDrawBuffer: [string, string?][][]; - contentBuffer: [string, TerminalEffect?][]; - private cursorPosition: number; - visualCursorStopPosition: [number, number]; - _internal_isDrawingFrame: boolean; - width: number; - height: number; - childView: TerminalView; - - constructor(terminal: Terminal) { - this.parentTerminal = terminal; - this.previousDrawBuffer = []; - this.contentBuffer = []; - this.cursorPosition = 0; - this.visualCursorStopPosition = [0, 0]; - this._internal_isDrawingFrame = false; - this.width = process.stdout.columns; - this.height = process.stdout.rows; - this.childView = new TerminalContainerView({ screen: this, parentView: undefined }); - } - - cursorTo(x: number, y?: number) { - this.cursorPosition = x + (y !== undefined ? y * this.width : 0); - } - - write(text: string, effect?: TerminalEffect) { - const strArray = text.split(""); - - for (let idx = 0; idx < strArray.length; idx++) { - this.contentBuffer[this.cursorPosition] = [strArray[idx], effect]; - this.cursorPosition++; - } - } - - clearScreenDown() { - const originalCursorPosition = this.cursorPosition; - - while (true) { - if (!this.contentBuffer[this.cursorPosition]) break; - - this.contentBuffer[this.cursorPosition] = [" "]; - this.cursorPosition++; - } - - this.cursorPosition = originalCursorPosition; - } - - _rawCursorTo(x: number, y?: number) { - return new Promise((resolve) => process.stdout.cursorTo(x, y, () => resolve())); - } - - _rawWrite(text: string) { - const encoder = new TextEncoder(); - return Deno.stdout.write(encoder.encode(text)); - } - - _rawClearScreenDown() { - return new Promise((resolve) => process.stdout.clearScreenDown(() => resolve())); - } - - async onResize() { - this.width = process.stdout.columns; - this.height = process.stdout.rows; - - await this._rawWrite(`\u001b[?47h\u001b[?7l\u001b[3J`); - - this.contentBuffer = []; - this.previousDrawBuffer = []; - - const entries = this.width * this.height; - - for (let i = 0; i < entries; i++) { - this.contentBuffer.push([" "]); - } - } - - async draw() { - if (this._internal_isDrawingFrame) return; - this._internal_isDrawingFrame = true; - - this.childView.calculateAbsoluteProperties(); - await this.childView.draw({ - drawOriginX: 0, - drawOriginY: 0, - width: this.width, - height: this.height, - contentWidth: this.width, - contentHeight: this.height, - contentOffsetX: 0, - contentOffsetY: 0, - }); - - let remBuf = this.contentBuffer; - - let i = 0; - - while (remBuf.length !== 0) { - const curBuf = remBuf.slice(0, this.width); - remBuf = remBuf.slice(this.width); - - // let lastChar: TerminalScreen["contentBuffer"][0] | undefined; - // for (const char of curBuf) { - // if (char[1] !== lastChar?.[1]) { - // await this._rawWrite(await char[1]!._internal_apply()); - // } - - // await this._rawWrite(char[0]); - - // lastChar = char; - // } - - const drawBuffer: [string, string?][] = []; - - for (const char of curBuf) { - if (drawBuffer[drawBuffer.length - 1]) { - if (drawBuffer[drawBuffer.length - 1]?.[1] === char?.[1]) { - drawBuffer[drawBuffer.length - 1][0] += char?.[0]; - } else { - drawBuffer.push([char?.[0], await char?.[1]?._internal_apply()]); - } - } else { - drawBuffer.push([char?.[0], await char?.[1]?._internal_apply()]); - } - } - - if ( - !this.previousDrawBuffer[i]?.every((element, idx) => { - const target = drawBuffer[idx]; - if (!element || !target) return false; - - return element[0] === target[0] && element[1] === target[1]; - }) - ) { - let toDraw = ""; - - for (const group of drawBuffer) { - if (group[1]) { - toDraw += `${group[1] + group[0]}\u001b[0m`; - } else { - toDraw += group[0]; - } - } - - await this._rawWrite(`\u001b[${i + 1};1f${toDraw}`); - } - - if (this.previousDrawBuffer[i]) { - this.previousDrawBuffer[i] = drawBuffer; - } else { - this.previousDrawBuffer.push(drawBuffer); - } - - i++; - } - - await this._rawCursorTo(this.visualCursorStopPosition[0], this.visualCursorStopPosition[1]); - this._internal_isDrawingFrame = false; - } -} diff --git a/instance/src/systems/terminalUI/terminal.ts b/instance/src/systems/terminalUI/terminal.ts deleted file mode 100644 index 68e204b..0000000 --- a/instance/src/systems/terminalUI/terminal.ts +++ /dev/null @@ -1,32 +0,0 @@ -import type RenderError from "./renderError.ts"; -import TerminalScreen from "./screen.ts"; - -export default class Terminal { - screen: TerminalScreen; - renderError?: RenderError; - - constructor() { - this.screen = new TerminalScreen(this); - this.screen.onResize(); - - process.stdout.on("resize", async () => { - await this.screen.onResize(); - }); - - // process.stdin.setRawMode(true); - - globalThis.addEventListener("unload", () => { - this.end(); - }); - } - - async draw() { - await this.screen.draw(); - await this.renderError?.draw(this.screen); - } - - end() { - this.screen._rawWrite(`\x1b[?47l`); - // process.stdin.setRawMode(false); - } -} diff --git a/instance/src/systems/terminalUI/terminalEvent.ts b/instance/src/systems/terminalUI/terminalEvent.ts deleted file mode 100644 index 363548e..0000000 --- a/instance/src/systems/terminalUI/terminalEvent.ts +++ /dev/null @@ -1,27 +0,0 @@ -import type KeyPressEvent from "./events/keyPressEvent.ts"; -import type MouseClickEvent from "./events/mouseClickEvent.ts"; -import type ResizeScreenEvent from "./events/resizeScreenEvent.ts"; -import type ScrollDownEvent from "./events/scrollDownEvent.ts"; -import type ScrollUpEvent from "./events/scrollUpEvent.ts"; - -export enum TerminalEventType { - MouseClick, - ScrollUp, - ScrollDown, - KeyPress, - ResizeScreen, -} - -export default abstract class TerminalEvent { - abstract type: TerminalEventType; -} - -type TerminalEventMap = { - [TerminalEventType.MouseClick]: MouseClickEvent; - [TerminalEventType.ScrollUp]: ScrollUpEvent; - [TerminalEventType.ScrollDown]: ScrollDownEvent; - [TerminalEventType.KeyPress]: KeyPressEvent; - [TerminalEventType.ResizeScreen]: ResizeScreenEvent; -}; - -export type TerminalEventListener = { type: Ty; cb: (event: TerminalEventMap[Ty]) => void }; diff --git a/instance/src/systems/terminalUI/view.ts b/instance/src/systems/terminalUI/view.ts deleted file mode 100644 index cbd6e11..0000000 --- a/instance/src/systems/terminalUI/view.ts +++ /dev/null @@ -1,194 +0,0 @@ -import RenderError from "./renderError.ts"; -import TerminalScalarValue, { TerminalScalarValueUnit } from "./scalarValue.ts"; -import type TerminalScreen from "./screen.ts"; -import type { TerminalEventListener, TerminalEventType } from "./terminalEvent.ts"; - -export type TerminalViewContext = TerminalView["viewContext"]; - -export default abstract class TerminalView { - viewContext!: { screen: TerminalScreen; parentView?: TerminalView }; - - viewProperties: { - width: TerminalScalarValue; - height: TerminalScalarValue; - contentHeight: TerminalScalarValue; - contentWidth: TerminalScalarValue; - contentOffsetX: TerminalScalarValue; - contentOffsetY: TerminalScalarValue; - // managed by calculateAbsoluteProperties (DO NOT EDIT) - _absolute: { - drawOriginX: number; - drawOriginY: number; - width: number; - height: number; - contentWidth: number; - contentHeight: number; - contentOffsetX: number; - contentOffsetY: number; - }; - } = { - width: new TerminalScalarValue().set(0, TerminalScalarValueUnit.Cell), - height: new TerminalScalarValue().set(0, TerminalScalarValueUnit.Cell), - contentHeight: new TerminalScalarValue().set(0, TerminalScalarValueUnit.Cell), - contentWidth: new TerminalScalarValue().set(0, TerminalScalarValueUnit.Cell), - contentOffsetX: new TerminalScalarValue().set(0, TerminalScalarValueUnit.Cell), - contentOffsetY: new TerminalScalarValue().set(0, TerminalScalarValueUnit.Cell), - // managed by calculateAbsoluteProperties (DO NOT EDIT) - _absolute: { - drawOriginX: 0, - drawOriginY: 0, - width: 0, - height: 0, - contentWidth: 0, - contentHeight: 0, - contentOffsetX: 0, - contentOffsetY: 0, - }, - }; - - eventListeners: TerminalEventListener[]; - childViews: TerminalView[]; - childViewFlowDirection: "x" | "y" = "x"; - - constructor(viewContext: TerminalViewContext) { - this.viewContext = viewContext; - - if (!this.viewContext.screen) throw new Error(`This TerminalView -> ${this.constructor.name} was not initialized correctly!`); - - this.childViews = []; - this.eventListeners = []; - } - - calculateAbsoluteProperties() { - /* // Dimensions - // px - if (this.viewProperties.dimensions.width.unit === "px") { - this._absoluteDimensions.width = this.viewProperties.dimensions.width.value; - } - if (this.viewProperties.dimensions.height.unit === "px") { - this._absoluteDimensions.height = this.viewProperties.dimensions.height.value; - } - - // % - if (this.viewProperties.dimensions.width.unit === "%") { - this._absoluteDimensions.width = Math.floor((this.viewProperties.dimensions.width.value / 100) * parentContentAbsoluteDimensions.width); - } - if (this.viewProperties.dimensions.height.unit === "%") { - this._absoluteDimensions.height = Math.floor((this.viewProperties.dimensions.height.value / 100) * parentContentAbsoluteDimensions.height); - } - - if (this._absoluteDimensions.width > parentContentAbsoluteDimensions.width) { - this._absoluteDimensions.width = availableSpace.width; - } - - if (this._absoluteDimensions.height > parentContentAbsoluteDimensions.height) { - this._absoluteDimensions.height = availableSpace.height; - } - - // Content Offset - // px - if (this._contentOffset.width.unit === "px") { - this._contentAbsoluteOffset.width = this._contentOffset.width.value; - } - if (this._contentOffset.height.unit === "px") { - this._contentAbsoluteOffset.height = this._contentOffset.height.value; - } - - // % - if (this._contentOffset.width.unit === "%") { - this._contentAbsoluteOffset.width = Math.floor((this._contentOffset.width.value / 100) * parentContentAbsoluteDimensions.width); - } - if (this._contentOffset.height.unit === "%") { - this._contentAbsoluteOffset.height = Math.floor((this._contentOffset.height.value / 100) * parentContentAbsoluteDimensions.height); - } - - // Content Dimensions - // px - if (this._contentDimensions.width.unit === "px") { - this._contentAbsoluteDimensions.width = this._contentDimensions.width.value; - } - if (this._contentDimensions.height.unit === "px") { - this._contentAbsoluteDimensions.height = this._contentDimensions.height.value; - } - - // % - if (this._contentDimensions.width.unit === "%") { - this._contentAbsoluteDimensions.width = Math.floor((this._contentDimensions.width.value / 100) * this._absoluteDimensions.width); - } - if (this._contentDimensions.height.unit === "%") { - this._contentAbsoluteDimensions.height = Math.floor((this._contentDimensions.height.value / 100) * this._absoluteDimensions.height); - } - - // Shrink the absolute content dimensions by the offset doubled - this._contentAbsoluteDimensions.width -= this._contentAbsoluteOffset.width * 2; - this._contentAbsoluteDimensions.height -= this._contentAbsoluteOffset.height * 2; - - const remainingContentAbsoluteDimensions = { ...this._contentAbsoluteDimensions }; - - let totalChildrenPercentageWidth = 0; - let totalChildrenPercentageHeight = 0; - - for (const childView of this.childViews) { - if (this.childViewFlowDirection === "x") { - if (childView._dimensions.width.unit === "%") { - totalChildrenPercentageWidth += childView._dimensions.width.value; - childView._dimensions.width.value = (childView._dimensions.width.value / totalChildrenPercentageWidth) * 100; - } - } - - if (this.childViewFlowDirection === "y") { - if (childView._dimensions.height.unit === "%") { - totalChildrenPercentageHeight += childView._dimensions.height.value; - childView._dimensions.height.value = (childView._dimensions.height.value / totalChildrenPercentageHeight) * 100; - } - } - - childView._calculateSize(this._contentAbsoluteDimensions, remainingContentAbsoluteDimensions); - if (this.childViewFlowDirection === "x") remainingContentAbsoluteDimensions.width -= childView._absoluteDimensions.width; - if (this.childViewFlowDirection === "y") remainingContentAbsoluteDimensions.height -= childView._absoluteDimensions.height; - } - - const currentContentTotalChildSize: { width: number; height: number } = { width: 0, height: 0 }; - - for (const childView of this.childViews) { - if (this.childViewFlowDirection === "x") currentContentTotalChildSize.width += childView.absoluteDimensions.width; - if (this.childViewFlowDirection === "y") currentContentTotalChildSize.height += childView.absoluteDimensions.height; - - if (currentContentTotalChildSize.width > this.contentAbsoluteDimensions.width) { - this.viewContext.screen.parentTerminal.renderError = new RenderError( - `Content Width Exceeds Remaining Space, ${currentContentTotalChildSize.width} > ${this.contentAbsoluteDimensions.width}`, - ); - break; - } - - if (currentContentTotalChildSize.height > this.contentAbsoluteDimensions.height) { - this.viewContext.screen.parentTerminal.renderError = new RenderError( - `Content Height Exceeds Remaining Space, ${currentContentTotalChildSize.height} > ${this.contentAbsoluteDimensions.height}`, - ); - break; - } - } */ - - if (this.childViewFlowDirection === "x") { - let xWidthPercentageTotal = 0; - for (const childView of this.childViews) { - } - } - } - - addChild(view: new (viewContext: TerminalViewContext) => TV, cb?: (view: TV) => void) { - const av = new view({ ...this.viewContext, parentView: this }); - - this.childViews.push(av); - - cb?.(av); - - return this; - } - - async draw(drawProperties: TerminalView["viewProperties"]["_absolute"]) { - for (const childView of this.childViews) { - await childView.draw(drawProperties); - } - } -} diff --git a/instance/src/systems/terminalUI/views/borderView.ts b/instance/src/systems/terminalUI/views/borderView.ts deleted file mode 100644 index 34de2e3..0000000 --- a/instance/src/systems/terminalUI/views/borderView.ts +++ /dev/null @@ -1,34 +0,0 @@ -import TerminalEffect, { TerminalColor } from "../effect.ts"; -import TerminalScalarValue, { TerminalScalarValueUnit } from "../scalarValue.ts"; -import TerminalView, { type TerminalViewContext } from "../view.ts"; - -export default class TerminalBorderView extends TerminalView { - constructor(viewContext: TerminalViewContext) { - super(viewContext); - - this.viewProperties.width = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.height = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.contentWidth = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.contentHeight = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.contentOffsetX = new TerminalScalarValue(1, TerminalScalarValueUnit.Cell); - this.viewProperties.contentOffsetY = new TerminalScalarValue(1, TerminalScalarValueUnit.Cell); - } - - override async draw(drawProperties: TerminalView["viewProperties"]["_absolute"]) { - const screen = this.viewContext.screen; - - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY); - screen.write(`┌${"─".repeat(drawProperties.width - 2)}┐`, new TerminalEffect().setColor(TerminalColor.BrightBlack)); - - for (let i = 1; i < drawProperties.height - 1; i++) { - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY + i); - screen.write(`│${" ".repeat(drawProperties.width - 2)}│`, new TerminalEffect().setColor(TerminalColor.BrightBlack)); - } - screen.cursorTo(drawProperties.drawOriginX, drawProperties.height); - screen.write(`└${"─".repeat(drawProperties.width - 2)}┘`, new TerminalEffect().setColor(TerminalColor.BrightBlack)); - - // screen.write(JSON.stringify({ x: drawOrigin.x + this.contentAbsoluteOffset.width, y: drawOrigin.y + this.contentAbsoluteOffset.height })); - - await super.draw(drawProperties); - } -} diff --git a/instance/src/systems/terminalUI/views/container.ts b/instance/src/systems/terminalUI/views/container.ts deleted file mode 100644 index 5337121..0000000 --- a/instance/src/systems/terminalUI/views/container.ts +++ /dev/null @@ -1,25 +0,0 @@ -import TerminalScalarValue, { TerminalScalarValueUnit } from "../scalarValue.ts"; -import TerminalView, { type TerminalViewContext } from "../view.ts"; - -export default class TerminalContainerView extends TerminalView { - constructor(viewContext: TerminalViewContext) { - super(viewContext); - - this.viewProperties.width = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.height = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.contentWidth = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.contentHeight = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.contentOffsetX = new TerminalScalarValue(0, TerminalScalarValueUnit.Cell); - this.viewProperties.contentOffsetY = new TerminalScalarValue(0, TerminalScalarValueUnit.Cell); - } - - setFlowDirection(flowDirection: "x" | "y") { - this.childViewFlowDirection = flowDirection; - - return this; - } - - override async draw(drawProperties: TerminalView["viewProperties"]["_absolute"]): Promise { - await super.draw(drawProperties); - } -} diff --git a/instance/src/systems/terminalUI/views/crossView.ts b/instance/src/systems/terminalUI/views/crossView.ts deleted file mode 100644 index 0575219..0000000 --- a/instance/src/systems/terminalUI/views/crossView.ts +++ /dev/null @@ -1,116 +0,0 @@ -import TerminalEffect, { TerminalColor } from "../effect.ts"; -import TerminalScalarValue, { TerminalScalarValueUnit } from "../scalarValue.ts"; -import type TerminalScreen from "../screen.ts"; -import TerminalView, { type TerminalViewContext } from "../view.ts"; - -export default class TerminalCrossView extends TerminalView { - constructor(viewContext: TerminalViewContext) { - super(viewContext); - - this.viewProperties.width = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.height = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.contentWidth = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.contentHeight = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.contentOffsetX = new TerminalScalarValue(0, TerminalScalarValueUnit.Cell); - this.viewProperties.contentOffsetY = new TerminalScalarValue(0, TerminalScalarValueUnit.Cell); - } - - override async draw(drawProperties: TerminalView["viewProperties"]["_absolute"]): Promise { - const screen = this.viewContext.screen; - - if (drawProperties.width < 31 || drawProperties.height < 3) { - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY); - screen.write("Too Small to display CrossView"); - return; - } - - enum VerticalAlignment { - Even, - Odd, - } - enum HorizontalAlignment { - Even, - Odd, - } - - let horizontalAlignment: HorizontalAlignment; - let verticalAlignment: VerticalAlignment; - - if (drawProperties.width % 2 === 0) { - horizontalAlignment = HorizontalAlignment.Even; - } else { - horizontalAlignment = HorizontalAlignment.Odd; - } - - if (drawProperties.height % 2 === 0) { - verticalAlignment = VerticalAlignment.Even; - } else { - verticalAlignment = VerticalAlignment.Odd; - } - - const labelText = `${drawProperties.width}x${drawProperties.height}`; - let labelTextOffsetX = 0; - let labelTextOffsetY = 0; - - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY); - - if (horizontalAlignment === HorizontalAlignment.Odd) { - screen.write(`${" ".repeat((drawProperties.width - 1) / 2)}▲${" ".repeat((drawProperties.width - 1) / 2)}`); - - for (let i = 1; i < drawProperties.height - 1; i++) { - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY + i); - screen.write(`${" ".repeat((drawProperties.width - 1) / 2)}│${" ".repeat((drawProperties.width - 1) / 2)}`); - - labelTextOffsetX = - drawProperties.drawOriginX + (drawProperties.width - 1) / 2 - (labelText.length % 2 === 0 ? labelText.length / 2 : (labelText.length - 1) / 2); - } - - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY + (drawProperties.height - 1)); - screen.write(`${" ".repeat((drawProperties.width - 1) / 2)}▼${" ".repeat((drawProperties.width - 1) / 2)}`); - } else { - screen.write(`${" ".repeat(drawProperties.width / 2 - 1)}▲${" ".repeat(drawProperties.width / 2)}`); - - for (let i = 1; i < drawProperties.height - 1; i++) { - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY + i); - screen.write(`${" ".repeat(drawProperties.width / 2 - 1)}│${" ".repeat(drawProperties.width / 2)}`); - - labelTextOffsetX = - drawProperties.drawOriginX + drawProperties.width / 2 - 1 - (labelText.length % 2 === 0 ? labelText.length / 2 : (labelText.length - 1) / 2); - } - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY + drawProperties.height - 1); - screen.write(`${" ".repeat(drawProperties.width / 2 - 1)}▼${" ".repeat(drawProperties.width / 2)}`); - } - - if (verticalAlignment === VerticalAlignment.Odd) { - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY + (drawProperties.height - 1) / 2); - screen.write(`◀${"─".repeat(drawProperties.width - 2)}▶`); - - labelTextOffsetY = drawProperties.drawOriginY + (drawProperties.height - 1) / 2; - } else { - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY + drawProperties.height / 2 - 1); - screen.write(`◀${"─".repeat(drawProperties.width - 2)}▶`); - labelTextOffsetY = drawProperties.drawOriginY + drawProperties.height / 2 - 1; - } - - screen.cursorTo(labelTextOffsetX, labelTextOffsetY); - screen.write(labelText.split("x")[0], new TerminalEffect().setColor(TerminalColor.BrightWhite).setBold()); - screen.write("x", new TerminalEffect().setColor(TerminalColor.White)); - screen.write(labelText.split("x")[1], new TerminalEffect().setColor(TerminalColor.BrightWhite).setBold()); - - // screen.write(`${" ".repeat(Math.floor((drawProperties.width - 1) / 2))} ▲${" ".repeat(Math.floor((drawProperties.width - 1) / 2))}`); - - // for (let i = 1; i < drawProperties.height; i++) { - // screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY + i); - // if (i === Math.floor(drawProperties.height / 2) - 1) { - // const dashLen = Math.floor((drawProperties.width - dimensionText.length) / 2) - 2; - // screen.write(`◀${"─".repeat(dashLen)}${dimensionText}${"─".repeat(dashLen)}▶`); - // } else { - // screen.write(`${" ".repeat(Math.floor((drawProperties.width - 1) / 2))} │${" ".repeat(Math.floor((drawProperties.width - 1) / 2))}`); - // } - // } - // screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY + drawProperties.height); - // screen.write(`${" ".repeat(Math.floor((drawProperties.width - 1) / 2))} ▼${" ".repeat(Math.floor((drawProperties.width - 1) / 2))}`); - - await super.draw(drawProperties); - } -} diff --git a/instance/src/systems/terminalUI/views/textInput.ts b/instance/src/systems/terminalUI/views/textInput.ts deleted file mode 100644 index d921de2..0000000 --- a/instance/src/systems/terminalUI/views/textInput.ts +++ /dev/null @@ -1,40 +0,0 @@ -import TerminalEffect from "../effect.ts"; -import TerminalScalarValue, { TerminalScalarValueUnit } from "../scalarValue.ts"; -import type TerminalScreen from "../screen.ts"; -import TerminalView, { type TerminalViewContext } from "../view.ts"; - -export default class TerminalTextInputView extends TerminalView { - value: string; - private placeholder: string | undefined; - - constructor(viewContext: TerminalViewContext) { - super(viewContext); - - this.viewProperties.width = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.height = new TerminalScalarValue(1, TerminalScalarValueUnit.Cell); - this.viewProperties.contentWidth = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.contentHeight = new TerminalScalarValue(100, TerminalScalarValueUnit.Percentage); - this.viewProperties.contentOffsetX = new TerminalScalarValue(0, TerminalScalarValueUnit.Cell); - this.viewProperties.contentOffsetY = new TerminalScalarValue(0, TerminalScalarValueUnit.Cell); - - this.value = ""; - this.placeholder = undefined; - } - - setPlaceholder(placeholderText: string | undefined) { - this.placeholder = placeholderText; - - return this; - } - - override async draw(drawProperties: TerminalView["viewProperties"]["_absolute"]): Promise { - const screen = this.viewContext.screen; - - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY); - screen.write(`${" ".repeat(drawProperties.width)}`, new TerminalEffect().setUnderline()); - screen.cursorTo(drawProperties.drawOriginX, drawProperties.drawOriginY); - if (this.value === "" && this.placeholder !== undefined) screen.write(`${this.placeholder}`, new TerminalEffect().setUnderline()); - - await super.draw(drawProperties); - } -}