From 094e5974168deea85488dd43d16d829113212e9f Mon Sep 17 00:00:00 2001 From: PwLDev <64767383+PwLDev@users.noreply.github.com> Date: Mon, 4 May 2026 11:18:20 -0700 Subject: [PATCH 1/4] update milsko upstream --- binding.gyp | 17 ++++++++++++++--- bun.lock | 8 ++++---- deps/milsko | 2 +- package.json | 8 ++------ tsconfig.json | 7 ++++++- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/binding.gyp b/binding.gyp index abf3038..a973bb3 100644 --- a/binding.gyp +++ b/binding.gyp @@ -2,7 +2,12 @@ "targets": [ { "target_name": "milsko", - "sources": ["src/milsko.cpp"], + "sources": [ + "src/milsko.cpp", + "src/widget.cpp", + "src/classes.cpp", + "src/pixmap.cpp", + ], "include_dirs": [ "= 18" - }, "devDependencies": { "@types/node": "^25.6.0", - "fast-xml-parser": "^5.6.0", + "fast-xml-parser": "^5.7.2", "node-gyp": "^12.2.0", "prebuildify": "^6.0.1", "prettier": "^3.8.2", diff --git a/tsconfig.json b/tsconfig.json index eb9671c..54669ff 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,5 +13,10 @@ "declaration": true, "isolatedModules": true }, - "exclude": ["scripts"] + "exclude": [ + "scripts", + "examples", + "node_modules", + "dist" + ] } From 20df39ee4e17a4b32711fe65c84fd12d58f3269b Mon Sep 17 00:00:00 2001 From: PwLDev <64767383+PwLDev@users.noreply.github.com> Date: Mon, 4 May 2026 11:38:01 -0700 Subject: [PATCH 2/4] new bindgen --- scripts/bindgen.js | 228 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 219 insertions(+), 9 deletions(-) diff --git a/scripts/bindgen.js b/scripts/bindgen.js index b45f444..ca901b5 100644 --- a/scripts/bindgen.js +++ b/scripts/bindgen.js @@ -1,6 +1,7 @@ import { XMLParser } from "fast-xml-parser"; -import { createWriteStream } from "node:fs"; +import { createWriteStream, existsSync, mkdirSync, statSync } from "node:fs"; import { createRequire } from "node:module"; +import { join } from "node:path"; const { upstream } = createRequire(import.meta.url)("../package.json"); const source = @@ -10,6 +11,7 @@ const source = const structsOut = createWriteStream("lib/structs.ts"); const enumsOut = createWriteStream("lib/enums.ts"); const constantsOut = createWriteStream("lib/constants.ts"); +const widgetOut = createWriteStream("lib/widget.ts"); function toCamelCase(input) { const split = input.split("_"); @@ -33,6 +35,8 @@ function typeToTypescript(type) { return "number"; case "string": return "string"; + case "pixmap": + return "Pixmap"; default: "any"; } @@ -42,7 +46,6 @@ function scanStructs(root) { const list = root["structs"]["struct"]; for (const struct of list) { - console.log(struct); const structName = struct["@_name"]; structsOut.write("export interface " + structName + " {\n"); @@ -51,8 +54,14 @@ function scanStructs(root) { if (!type.startsWith("@_") && Array.isArray(children)) { for (const child of children) { const attributeName = toCamelCase(child["@_name"]); + let attributeType = typeToTypescript(type); + + if (type == "struct") { + attributeType = child["@_defname"]; + } + structsOut.write( - attributeName + ": " + typeToTypescript(type) + ";\n" + attributeName + ": " + attributeType + ";\n" ); } } @@ -115,11 +124,207 @@ function scanConstants(root) { constantsOut.end(); } +function getPropertyInfo(root, query) { + const properties = root["properties"]; + + for (const [type, children] of Object.entries(properties)) { + const match = children.find((k) => k["@_name"] == query); + if (match) { + return { + boolean: match["@_boolean"] == "yes", + defName: match["@_defname"], + type, + }; + } + } +} + +function getPropertySignature(inputName, inputType) { + let prefix = null, + setter = null, + getter = null; + + switch (inputType) { + case "string": + prefix = "S"; + setter = "setString"; + getter = "getString"; + break; + case "integer": + prefix = "I"; + setter = "setInteger"; + getter = "getInteger"; + break; + case "handler": + prefix = "C"; + setter = "addUserHandler"; + break; + default: + prefix = "V"; + setter = "setVoid"; + getter = "getVoid"; + break; + } + + return { prefix, setter, getter }; +} + +function createPropertyMethods(name, type, isBoolean, defName = "unknown") { + const output = []; + + // fluent setter + const { prefix, setter, getter } = getPropertySignature(name, type); + const methodName = toCamelCase( + "set" + name.charAt(0).toUpperCase() + name.slice(1)); + const propertyId = prefix + name; + + let finalType = isBoolean ? "boolean" : typeToTypescript(type); + const finalValue = isBoolean ? "+value" : "value"; + if (type == "struct") finalType = defName; + + output.push( + // signature + "public " + methodName + "(value: " + finalType + "): this {\n" + + + // call internal method + "return this." + setter + "(\"" + propertyId + "\"," + + finalValue + ");\n}\n\n" + ); + + // property setter and getter + const getterName = toCamelCase(name); + let cast = type == "pixmap" ? " as Pixmap" : ""; + + if (isBoolean) cast = " != 0" + else if (type == "struct") cast = "as " + defName + + output.push( + // getter + "get " + getterName + "(): " + finalType + " {\n" + + "return this." + getter + "(\"" + propertyId + + "\")" + cast + ";\n}\n\n" + + + // setter + "set " + getterName + "(value: " + finalType + ") {\n" + + "this." + setter + "(\"" + propertyId + "\", " + finalValue + ");\n}\n\n" + ); + + return output.join(""); +} + +function scanProperties(root) { + const properties = root["properties"]; + + widgetOut.write( + "import { BaseWidget } from \"./milsko\"\n" + + "import { Pixmap } from \"./types\"\n\n" + + "export class Widget extends BaseWidget {\n" + ); + + for (const [type, children] of Object.entries(properties)) { + for (const prop of children) { + if (prop["@_common"] != "yes") continue; + + const name = prop["@_name"]; + const isBoolean = prop["@_boolean"] == "yes"; + + widgetOut.write(createPropertyMethods(name, type, isBoolean)); + } + } + + widgetOut.write("\n}"); + widgetOut.close(); +} + +function scanWidgets(root) { + const widgets = root["widgets"]["widget"]; + const unsupported = ["OpenGL", "Vulkan"]; + + // first loop through widgets to detect for imports and print lines + for (const widget of widgets) { + const widgetName = widget["@_name"]; + if (unsupported.includes(widgetName)) continue; + + const typeImports = ["WidgetOptions"]; + const structImports = []; + const lines = []; + + const widgetFile = createWriteStream( + join("lib/widgets/", toCamelCase(widgetName) + ".ts") + ); + + // scan properties + if (widget["properties"]) { + const widgetProperties = widget["properties"]["property"]; + + for (const prop of widgetProperties) { + const name = prop["@_name"]; + let { boolean, defName, type } = getPropertyInfo(root, name); + + if (type == "struct") { + if (!structImports.includes(defName)) + structImports.push(defName); + } + + if (type == "pixmap") { + if (!typeImports.includes("Pixmap")) + typeImports.push("Pixmap"); + } + + // create methods + lines.push(createPropertyMethods(name, type, boolean, defName)) + } + } + + lines.push("}\n"); + + // after looping write the contents in the correct order + widgetFile.write( + "import { NativeClasses } from \"../milsko\"\n" + + "import { Widget } from \"../widget\"\n" + ); + + if (structImports.length) { + widgetFile.write( + "import { " + structImports.join(", ") + + " } from \"../structs\"\n" + ); + } + + widgetFile.write( + "import { " + typeImports.join(", ") + + " } from \"../types\"\n" + ); + + // init class + widgetFile.write("\nexport class " + widgetName + " extends Widget {\n"); + + // constructor + widgetFile.write( + "constructor(options: WidgetOptions) {\n" + + "super(NativeClasses." + widgetName + ", options);" + + "}\n\n" + ); + + for (const line of lines) { + widgetFile.write(line); + } + + widgetFile.close(); + } +} + +function isArray(tagName) { + if (tagName == "property" || tagName == "struct") + return true; +} + async function bindgen() { const parser = new XMLParser({ attributeNamePrefix: "@_", ignoreAttributes: false, - parseAttributeValue: true + parseAttributeValue: true, + isArray }); const response = await fetch(source); @@ -135,14 +340,17 @@ async function bindgen() { const match = tags.find((k) => k.name == upstream); if (!match) { - throw new Error( - "Could not find a tag that matches the upstream version " + upstream + console.warn( + "Could not find a tag that matches the upstream version " + upstream + + ", using as commit hash instead." ); } - const commitHash = match["id"] - const specURL = "https://forgejo.nishi.boats/pyrite-dev/milsko/raw/commit/" + - commitHash + "/milsko.xml"; + const commitHash = match ? match["id"] : upstream; + const specURL = + "https://forgejo.nishi.boats/pyrite-dev/milsko/raw/commit/" + + commitHash + + "/milsko.xml"; const spac = await fetch(specURL); if (!spac.ok) { @@ -158,6 +366,8 @@ async function bindgen() { scanStructs(root); scanEnumerations(root); scanConstants(root); + scanProperties(root); + scanWidgets(root); } bindgen(); From 9a3a1b084a5f8fc35f5b01c4c9fccbbe80b382d3 Mon Sep 17 00:00:00 2001 From: PwLDev <64767383+PwLDev@users.noreply.github.com> Date: Mon, 4 May 2026 11:38:58 -0700 Subject: [PATCH 3/4] new types and classes --- lib/index.ts | 7 + lib/milsko.ts | 14 ++ lib/structs.ts | 4 +- lib/types.ts | 208 ++++++++++++++++++++++++++++ lib/widget.ts | 268 +++++++++++++++++++++++++++++++++++++ lib/widgets/box.ts | 69 ++++++++++ lib/widgets/button.ts | 69 ++++++++++ lib/widgets/checkbox.ts | 21 +++ lib/widgets/combobox.ts | 33 +++++ lib/widgets/entry.ts | 33 +++++ lib/widgets/frame.ts | 33 +++++ lib/widgets/image.ts | 57 ++++++++ lib/widgets/index.ts | 19 +++ lib/widgets/label.ts | 81 +++++++++++ lib/widgets/listbox.ts | 45 +++++++ lib/widgets/menu.ts | 9 ++ lib/widgets/numberentry.ts | 21 +++ lib/widgets/progressbar.ts | 45 +++++++ lib/widgets/radiobox.ts | 21 +++ lib/widgets/scrollbar.ts | 81 +++++++++++ lib/widgets/submenu.ts | 21 +++ lib/widgets/subwindow.ts | 33 +++++ lib/widgets/treeview.ts | 33 +++++ lib/widgets/viewport.ts | 9 ++ lib/widgets/window.ts | 82 ++++++++++++ scripts/bindgen.js | 10 +- 26 files changed, 1324 insertions(+), 2 deletions(-) create mode 100644 lib/milsko.ts create mode 100644 lib/types.ts create mode 100644 lib/widget.ts create mode 100644 lib/widgets/box.ts create mode 100644 lib/widgets/button.ts create mode 100644 lib/widgets/checkbox.ts create mode 100644 lib/widgets/combobox.ts create mode 100644 lib/widgets/entry.ts create mode 100644 lib/widgets/frame.ts create mode 100644 lib/widgets/image.ts create mode 100644 lib/widgets/index.ts create mode 100644 lib/widgets/label.ts create mode 100644 lib/widgets/listbox.ts create mode 100644 lib/widgets/menu.ts create mode 100644 lib/widgets/numberentry.ts create mode 100644 lib/widgets/progressbar.ts create mode 100644 lib/widgets/radiobox.ts create mode 100644 lib/widgets/scrollbar.ts create mode 100644 lib/widgets/submenu.ts create mode 100644 lib/widgets/subwindow.ts create mode 100644 lib/widgets/treeview.ts create mode 100644 lib/widgets/viewport.ts create mode 100644 lib/widgets/window.ts diff --git a/lib/index.ts b/lib/index.ts index e69de29..198a472 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -0,0 +1,7 @@ +export * from "./constants"; +export * from "./enums"; +export * from "./structs"; +export * from "./types"; +export * from "./widgets"; + +export { BaseWidget, NativeClasses, Pixmap } from "./milsko"; diff --git a/lib/milsko.ts b/lib/milsko.ts new file mode 100644 index 0000000..a56b6f4 --- /dev/null +++ b/lib/milsko.ts @@ -0,0 +1,14 @@ +// @ts-ignore +import binding from "node-gyp-build"; +import { join } from "node:path"; +import { + BaseWidgetConstructor, + MwNativeClasses, + PixmapConstructor +} from "./types"; + +export const BaseWidget: BaseWidgetConstructor = binding.BaseWidget; +export const NativeClasses: MwNativeClasses = binding.Classes; +export const Pixmap: PixmapConstructor = binding.Pixmap; + +export default binding(join(__dirname, "..")); diff --git a/lib/structs.ts b/lib/structs.ts index 5affa0a..2cb09ea 100644 --- a/lib/structs.ts +++ b/lib/structs.ts @@ -23,7 +23,9 @@ export interface MwRGB { blue: number; } -export interface MwMouse {} +export interface MwMouse { + point: MwPoint; +} export interface MwVulkanConfig { apiVersion: number; diff --git a/lib/types.ts b/lib/types.ts new file mode 100644 index 0000000..1b84dd9 --- /dev/null +++ b/lib/types.ts @@ -0,0 +1,208 @@ +import { MwCLIPBOARD, MwCOORDINATE } from "./enums"; +import { MwPoint, MwRect } from "./structs"; + +export type MwClass = object & { __brand: "MwClass" }; + +/** + * `BaseWidget` represents the lowest level form of widgets before the native layer. + * This class contains the fundamental native methods shared by all widgets. + */ +export interface BaseWidget { + area: MwRect; + isPending: boolean; + parent: BaseWidget; + children: BaseWidget[]; + name: string; + cursorCoord: MwPoint; + screenSize: MwRect; + coordinateType: MwCOORDINATE; + nativeClass: MwClass; + + /** + * Sets new position and size to this widget + * @param area New rect + */ + setArea(area: MwRect): this; + + /** + * Moves this widget to an absolute position + * @param x X position + * @param y Y position + */ + move(x: number, y: number): this; + + /** + * Changes the size dimension of this widget + * @param width New width + * @param height New height + */ + resize(width: number, height: number): this; + + /** + * Runs a single step through the event loop + * @returns Wether the step was successful + */ + step(): boolean; + + /** + * Start the main loop on this widget + */ + loop(): this; + + /** + * Show/hide this widget + * @param toggle Wether the widget is shown + */ + show(toggle: boolean): this; + + /** + * Hides the cursor when being hovered over this widget + */ + hideCursor(): this; + + /** + * Grabs the pointer and pins it to the center of this widget + * @param toggle Wether the pointer is grabbed + */ + grabPointer(toggle: boolean): this; + + /** + * Focus this widget + */ + focus(): this; + + /** + * Adds this widget to the tick handler list + */ + addTickList(): this; + + /** + * Forces this widget to render + */ + forceRender(): this; + + /** + * Reparents this widget to a new parent + * @param widget New parent + */ + reparent(widget: BaseWidget): this; + + /** + * Adds another widget as child of this one + * @param widgets Widgets to add + */ + addChild(...widgets: BaseWidget[]): this; + + /** + * Destroys this widget + */ + destroy(): null; + + /** + * Queues this widget to get clipboard content. + * This is ignored in backends that aren't or X11/Wayland. + * @param type Clipboard type to get, if you are unsure just use `MwCLIPBOARD_MAIN` + */ + getClipboard(type: MwCLIPBOARD): undefined; + + /** + * Sets a value to an integer property by its key + * @param key Prefixed property key + * @param value Value to assign to property + */ + setInteger(key: string, value: number): this; + + /** + * Sets a value to a string property by its key + * @param key Prefixed property key + * @param value Value to assign to property + */ + setString(key: string, value: string): this; + + /** + * Sets the value of a void* property by its key. + * You most likely shouldn't use this unless you are extending BaseWidget + * @param key Prefixed property key + */ + setVoid(key: string, value: unknown): this; + + /** + * Gets the value of an integer property by its key + * @param key Prefixed property key + */ + getInteger(key: string): number; + + /** + * Gets the value of a string property by its key + * @param key Prefixed property key + */ + getString(key: string): string; + + /** + * Gets the value of a void* property by its key. + * You most likely shouldn't use this unless you are extending BaseWidget + * @param key Prefixed property key + */ + getVoid(key: string): unknown; +} + +export interface BaseWidgetConstructor { + new (cls: MwClass | null, options: WidgetOptions): BaseWidget; +} + +export interface MwNativeClasses { + Box: MwClass; + Button: MwClass; + CheckBox: MwClass; + Entry: MwClass; + Frame: MwClass; + Image: MwClass; + Label: MwClass; + ListBox: MwClass; + Menu: MwClass; + NumberEntry: MwClass; + ScrollBar: MwClass; + SubMenu: MwClass; + SubWindow: MwClass; + Viewport: MwClass; + Window: MwClass; + ProgressBar: MwClass; + RadioBox: MwClass; + ComboBox: MwClass; + TreeView: MwClass; +} + +export interface Pixmap { + size: MwRect; + + /** + * Get the raw data of this pixmap + */ + getRaw(): Buffer; + + /** + * Updates this pixmap using raw data + * @param data Image data to update + */ + reloadRaw(data: Buffer | ArrayBuffer): void; +} + +export interface PixmapOptions { + data?: Buffer; + width?: number; + height?: number; +} + +export interface PixmapConstructor { + new (cls: BaseWidget, options?: PixmapOptions): Pixmap; +} + +export interface WidgetOptions { + name?: string; + parent?: BaseWidget; + children?: BaseWidget[]; + x?: number; + y?: number; + width?: number; + height?: number; +} diff --git a/lib/widget.ts b/lib/widget.ts new file mode 100644 index 0000000..0257ec9 --- /dev/null +++ b/lib/widget.ts @@ -0,0 +1,268 @@ +import { BaseWidget } from "./milsko"; +import { Pixmap } from "./types"; + +export class Widget extends BaseWidget { + public setX(value: number): this { + return this.setInteger("Ix", value); + } + + get x(): number { + return this.getInteger("Ix"); + } + + set x(value: number) { + this.setInteger("Ix", value); + } + + public setY(value: number): this { + return this.setInteger("Iy", value); + } + + get y(): number { + return this.getInteger("Iy"); + } + + set y(value: number) { + this.setInteger("Iy", value); + } + + public setWidth(value: number): this { + return this.setInteger("Iwidth", value); + } + + get width(): number { + return this.getInteger("Iwidth"); + } + + set width(value: number) { + this.setInteger("Iwidth", value); + } + + public setHeight(value: number): this { + return this.setInteger("Iheight", value); + } + + get height(): number { + return this.getInteger("Iheight"); + } + + set height(value: number) { + this.setInteger("Iheight", value); + } + + public setModernLook(value: boolean): this { + return this.setInteger("ImodernLook", +value); + } + + get modernLook(): boolean { + return this.getInteger("ImodernLook") != 0; + } + + set modernLook(value: boolean) { + this.setInteger("ImodernLook", +value); + } + + public setBorderWidth(value: number): this { + return this.setInteger("IborderWidth", value); + } + + get borderWidth(): number { + return this.getInteger("IborderWidth"); + } + + set borderWidth(value: number) { + this.setInteger("IborderWidth", value); + } + + public setRatio(value: number): this { + return this.setInteger("Iratio", value); + } + + get ratio(): number { + return this.getInteger("Iratio"); + } + + set ratio(value: number) { + this.setInteger("Iratio", value); + } + + public setFixedSize(value: number): this { + return this.setInteger("IfixedSize", value); + } + + get fixedSize(): number { + return this.getInteger("IfixedSize"); + } + + set fixedSize(value: number) { + this.setInteger("IfixedSize", value); + } + + public setBitmapFont(value: boolean): this { + return this.setInteger("IbitmapFont", +value); + } + + get bitmapFont(): boolean { + return this.getInteger("IbitmapFont") != 0; + } + + set bitmapFont(value: boolean) { + this.setInteger("IbitmapFont", +value); + } + + public setForceInverted(value: boolean): this { + return this.setInteger("IforceInverted", +value); + } + + get forceInverted(): boolean { + return this.getInteger("IforceInverted") != 0; + } + + set forceInverted(value: boolean) { + this.setInteger("IforceInverted", +value); + } + + public setIsRounded(value: boolean): this { + return this.setInteger("IisRounded", +value); + } + + get isRounded(): boolean { + return this.getInteger("IisRounded") != 0; + } + + set isRounded(value: boolean) { + this.setInteger("IisRounded", +value); + } + + public setDarkTheme(value: boolean): this { + return this.setInteger("IdarkTheme", +value); + } + + get darkTheme(): boolean { + return this.getInteger("IdarkTheme") != 0; + } + + set darkTheme(value: boolean) { + this.setInteger("IdarkTheme", +value); + } + + public setUseMonospace(value: boolean): this { + return this.setInteger("IuseMonospace", +value); + } + + get useMonospace(): boolean { + return this.getInteger("IuseMonospace") != 0; + } + + set useMonospace(value: boolean) { + this.setInteger("IuseMonospace", +value); + } + + public setDarkThemeAutomatic(value: boolean): this { + return this.setInteger("IdarkThemeAutomatic", +value); + } + + get darkThemeAutomatic(): boolean { + return this.getInteger("IdarkThemeAutomatic") != 0; + } + + set darkThemeAutomatic(value: boolean) { + this.setInteger("IdarkThemeAutomatic", +value); + } + + public setWaitMS(value: number): this { + return this.setInteger("IwaitMS", value); + } + + get waitMS(): number { + return this.getInteger("IwaitMS"); + } + + set waitMS(value: number) { + this.setInteger("IwaitMS", value); + } + + public setBackground(value: string): this { + return this.setString("Sbackground", value); + } + + get background(): string { + return this.getString("Sbackground"); + } + + set background(value: string) { + this.setString("Sbackground", value); + } + + public setSubBackground(value: string): this { + return this.setString("SsubBackground", value); + } + + get subBackground(): string { + return this.getString("SsubBackground"); + } + + set subBackground(value: string) { + this.setString("SsubBackground", value); + } + + public setTitleBackground(value: string): this { + return this.setString("StitleBackground", value); + } + + get titleBackground(): string { + return this.getString("StitleBackground"); + } + + set titleBackground(value: string) { + this.setString("StitleBackground", value); + } + + public setForeground(value: string): this { + return this.setString("Sforeground", value); + } + + get foreground(): string { + return this.getString("Sforeground"); + } + + set foreground(value: string) { + this.setString("Sforeground", value); + } + + public setSubForeground(value: string): this { + return this.setString("SsubForeground", value); + } + + get subForeground(): string { + return this.getString("SsubForeground"); + } + + set subForeground(value: string) { + this.setString("SsubForeground", value); + } + + public setTitleForeground(value: string): this { + return this.setString("StitleForeground", value); + } + + get titleForeground(): string { + return this.getString("StitleForeground"); + } + + set titleForeground(value: string) { + this.setString("StitleForeground", value); + } + + public setBackgroundPixmap(value: Pixmap): this { + return this.setVoid("VbackgroundPixmap", value); + } + + get backgroundPixmap(): Pixmap { + return this.getVoid("VbackgroundPixmap") as Pixmap; + } + + set backgroundPixmap(value: Pixmap) { + this.setVoid("VbackgroundPixmap", value); + } +} diff --git a/lib/widgets/box.ts b/lib/widgets/box.ts new file mode 100644 index 0000000..f5afa67 --- /dev/null +++ b/lib/widgets/box.ts @@ -0,0 +1,69 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class Box extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.Box, options); + } + + public setOrientation(value: number): this { + return this.setInteger("Iorientation", value); + } + + get orientation(): number { + return this.getInteger("Iorientation"); + } + + set orientation(value: number) { + this.setInteger("Iorientation", value); + } + + public setMargin(value: number): this { + return this.setInteger("Imargin", value); + } + + get margin(): number { + return this.getInteger("Imargin"); + } + + set margin(value: number) { + this.setInteger("Imargin", value); + } + + public setPadding(value: number): this { + return this.setInteger("Ipadding", value); + } + + get padding(): number { + return this.getInteger("Ipadding"); + } + + set padding(value: number) { + this.setInteger("Ipadding", value); + } + + public setHasBorder(value: boolean): this { + return this.setInteger("IhasBorder", +value); + } + + get hasBorder(): boolean { + return this.getInteger("IhasBorder") != 0; + } + + set hasBorder(value: boolean) { + this.setInteger("IhasBorder", +value); + } + + public setInverted(value: boolean): this { + return this.setInteger("Iinverted", +value); + } + + get inverted(): boolean { + return this.getInteger("Iinverted") != 0; + } + + set inverted(value: boolean) { + this.setInteger("Iinverted", +value); + } +} diff --git a/lib/widgets/button.ts b/lib/widgets/button.ts new file mode 100644 index 0000000..8fbe2f6 --- /dev/null +++ b/lib/widgets/button.ts @@ -0,0 +1,69 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions, Pixmap } from "../types"; + +export class Button extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.Button, options); + } + + public setPixmap(value: Pixmap): this { + return this.setVoid("Vpixmap", value); + } + + get pixmap(): Pixmap { + return this.getVoid("Vpixmap") as Pixmap; + } + + set pixmap(value: Pixmap) { + this.setVoid("Vpixmap", value); + } + + public setText(value: string): this { + return this.setString("Stext", value); + } + + get text(): string { + return this.getString("Stext"); + } + + set text(value: string) { + this.setString("Stext", value); + } + + public setFlat(value: boolean): this { + return this.setInteger("Iflat", +value); + } + + get flat(): boolean { + return this.getInteger("Iflat") != 0; + } + + set flat(value: boolean) { + this.setInteger("Iflat", +value); + } + + public setPadding(value: number): this { + return this.setInteger("Ipadding", value); + } + + get padding(): number { + return this.getInteger("Ipadding"); + } + + set padding(value: number) { + this.setInteger("Ipadding", value); + } + + public setFillArea(value: number): this { + return this.setInteger("IfillArea", value); + } + + get fillArea(): number { + return this.getInteger("IfillArea"); + } + + set fillArea(value: number) { + this.setInteger("IfillArea", value); + } +} diff --git a/lib/widgets/checkbox.ts b/lib/widgets/checkbox.ts new file mode 100644 index 0000000..fc61f43 --- /dev/null +++ b/lib/widgets/checkbox.ts @@ -0,0 +1,21 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class CheckBox extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.CheckBox, options); + } + + public setChecked(value: boolean): this { + return this.setInteger("Ichecked", +value); + } + + get checked(): boolean { + return this.getInteger("Ichecked") != 0; + } + + set checked(value: boolean) { + this.setInteger("Ichecked", +value); + } +} diff --git a/lib/widgets/combobox.ts b/lib/widgets/combobox.ts new file mode 100644 index 0000000..754cc5d --- /dev/null +++ b/lib/widgets/combobox.ts @@ -0,0 +1,33 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class ComboBox extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.ComboBox, options); + } + + public setAreaShown(value: number): this { + return this.setInteger("IareaShown", value); + } + + get areaShown(): number { + return this.getInteger("IareaShown"); + } + + set areaShown(value: number) { + this.setInteger("IareaShown", value); + } + + public setValue(value: number): this { + return this.setInteger("Ivalue", value); + } + + get value(): number { + return this.getInteger("Ivalue"); + } + + set value(value: number) { + this.setInteger("Ivalue", value); + } +} diff --git a/lib/widgets/entry.ts b/lib/widgets/entry.ts new file mode 100644 index 0000000..099883b --- /dev/null +++ b/lib/widgets/entry.ts @@ -0,0 +1,33 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class Entry extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.Entry, options); + } + + public setText(value: string): this { + return this.setString("Stext", value); + } + + get text(): string { + return this.getString("Stext"); + } + + set text(value: string) { + this.setString("Stext", value); + } + + public setHideInput(value: boolean): this { + return this.setInteger("IhideInput", +value); + } + + get hideInput(): boolean { + return this.getInteger("IhideInput") != 0; + } + + set hideInput(value: boolean) { + this.setInteger("IhideInput", +value); + } +} diff --git a/lib/widgets/frame.ts b/lib/widgets/frame.ts new file mode 100644 index 0000000..18baa67 --- /dev/null +++ b/lib/widgets/frame.ts @@ -0,0 +1,33 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class Frame extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.Frame, options); + } + + public setHasBorder(value: boolean): this { + return this.setInteger("IhasBorder", +value); + } + + get hasBorder(): boolean { + return this.getInteger("IhasBorder") != 0; + } + + set hasBorder(value: boolean) { + this.setInteger("IhasBorder", +value); + } + + public setInverted(value: boolean): this { + return this.setInteger("Iinverted", +value); + } + + get inverted(): boolean { + return this.getInteger("Iinverted") != 0; + } + + set inverted(value: boolean) { + this.setInteger("Iinverted", +value); + } +} diff --git a/lib/widgets/image.ts b/lib/widgets/image.ts new file mode 100644 index 0000000..fb8ad31 --- /dev/null +++ b/lib/widgets/image.ts @@ -0,0 +1,57 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions, Pixmap } from "../types"; + +export class Image extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.Image, options); + } + + public setPixmap(value: Pixmap): this { + return this.setVoid("Vpixmap", value); + } + + get pixmap(): Pixmap { + return this.getVoid("Vpixmap") as Pixmap; + } + + set pixmap(value: Pixmap) { + this.setVoid("Vpixmap", value); + } + + public setHasBorder(value: boolean): this { + return this.setInteger("IhasBorder", +value); + } + + get hasBorder(): boolean { + return this.getInteger("IhasBorder") != 0; + } + + set hasBorder(value: boolean) { + this.setInteger("IhasBorder", +value); + } + + public setInverted(value: boolean): this { + return this.setInteger("Iinverted", +value); + } + + get inverted(): boolean { + return this.getInteger("Iinverted") != 0; + } + + set inverted(value: boolean) { + this.setInteger("Iinverted", +value); + } + + public setFillArea(value: number): this { + return this.setInteger("IfillArea", value); + } + + get fillArea(): number { + return this.getInteger("IfillArea"); + } + + set fillArea(value: number) { + this.setInteger("IfillArea", value); + } +} diff --git a/lib/widgets/index.ts b/lib/widgets/index.ts new file mode 100644 index 0000000..e844d7e --- /dev/null +++ b/lib/widgets/index.ts @@ -0,0 +1,19 @@ +export { Box } from "./box"; +export { Button } from "./button"; +export { CheckBox } from "./checkbox"; +export { Entry } from "./entry"; +export { Frame } from "./frame"; +export { Image } from "./image"; +export { Label } from "./label"; +export { ListBox } from "./listbox"; +export { Menu } from "./menu"; +export { NumberEntry } from "./numberentry"; +export { ScrollBar } from "./scrollbar"; +export { SubMenu } from "./submenu"; +export { Viewport } from "./viewport"; +export { Window } from "./window"; +export { ProgressBar } from "./progressbar"; +export { RadioBox } from "./radiobox"; +export { ComboBox } from "./combobox"; +export { TreeView } from "./treeview"; +export { SubWindow } from "./subwindow"; diff --git a/lib/widgets/label.ts b/lib/widgets/label.ts new file mode 100644 index 0000000..b5c423e --- /dev/null +++ b/lib/widgets/label.ts @@ -0,0 +1,81 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class Label extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.Label, options); + } + + public setText(value: string): this { + return this.setString("Stext", value); + } + + get text(): string { + return this.getString("Stext"); + } + + set text(value: string) { + this.setString("Stext", value); + } + + public setAlignment(value: number): this { + return this.setInteger("Ialignment", value); + } + + get alignment(): number { + return this.getInteger("Ialignment"); + } + + set alignment(value: number) { + this.setInteger("Ialignment", value); + } + + public setBold(value: boolean): this { + return this.setInteger("Ibold", +value); + } + + get bold(): boolean { + return this.getInteger("Ibold") != 0; + } + + set bold(value: boolean) { + this.setInteger("Ibold", +value); + } + + public setSevenSegment(value: boolean): this { + return this.setInteger("IsevenSegment", +value); + } + + get sevenSegment(): boolean { + return this.getInteger("IsevenSegment") != 0; + } + + set sevenSegment(value: boolean) { + this.setInteger("IsevenSegment", +value); + } + + public setLength(value: number): this { + return this.setInteger("Ilength", value); + } + + get length(): number { + return this.getInteger("Ilength"); + } + + set length(value: number) { + this.setInteger("Ilength", value); + } + + public setLeftPadding(value: number): this { + return this.setInteger("IleftPadding", value); + } + + get leftPadding(): number { + return this.getInteger("IleftPadding"); + } + + set leftPadding(value: number) { + this.setInteger("IleftPadding", value); + } +} diff --git a/lib/widgets/listbox.ts b/lib/widgets/listbox.ts new file mode 100644 index 0000000..f629b0f --- /dev/null +++ b/lib/widgets/listbox.ts @@ -0,0 +1,45 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class ListBox extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.ListBox, options); + } + + public setLeftPadding(value: number): this { + return this.setInteger("IleftPadding", value); + } + + get leftPadding(): number { + return this.getInteger("IleftPadding"); + } + + set leftPadding(value: number) { + this.setInteger("IleftPadding", value); + } + + public setHasHeading(value: boolean): this { + return this.setInteger("IhasHeading", +value); + } + + get hasHeading(): boolean { + return this.getInteger("IhasHeading") != 0; + } + + set hasHeading(value: boolean) { + this.setInteger("IhasHeading", +value); + } + + public setSingleClickSelectable(value: boolean): this { + return this.setInteger("IsingleClickSelectable", +value); + } + + get singleClickSelectable(): boolean { + return this.getInteger("IsingleClickSelectable") != 0; + } + + set singleClickSelectable(value: boolean) { + this.setInteger("IsingleClickSelectable", +value); + } +} diff --git a/lib/widgets/menu.ts b/lib/widgets/menu.ts new file mode 100644 index 0000000..20c58f8 --- /dev/null +++ b/lib/widgets/menu.ts @@ -0,0 +1,9 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class Menu extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.Menu, options); + } +} diff --git a/lib/widgets/numberentry.ts b/lib/widgets/numberentry.ts new file mode 100644 index 0000000..d268de9 --- /dev/null +++ b/lib/widgets/numberentry.ts @@ -0,0 +1,21 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class NumberEntry extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.NumberEntry, options); + } + + public setText(value: string): this { + return this.setString("Stext", value); + } + + get text(): string { + return this.getString("Stext"); + } + + set text(value: string) { + this.setString("Stext", value); + } +} diff --git a/lib/widgets/progressbar.ts b/lib/widgets/progressbar.ts new file mode 100644 index 0000000..f99ea4e --- /dev/null +++ b/lib/widgets/progressbar.ts @@ -0,0 +1,45 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class ProgressBar extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.ProgressBar, options); + } + + public setMinValue(value: number): this { + return this.setInteger("IminValue", value); + } + + get minValue(): number { + return this.getInteger("IminValue"); + } + + set minValue(value: number) { + this.setInteger("IminValue", value); + } + + public setMaxValue(value: number): this { + return this.setInteger("ImaxValue", value); + } + + get maxValue(): number { + return this.getInteger("ImaxValue"); + } + + set maxValue(value: number) { + this.setInteger("ImaxValue", value); + } + + public setValue(value: number): this { + return this.setInteger("Ivalue", value); + } + + get value(): number { + return this.getInteger("Ivalue"); + } + + set value(value: number) { + this.setInteger("Ivalue", value); + } +} diff --git a/lib/widgets/radiobox.ts b/lib/widgets/radiobox.ts new file mode 100644 index 0000000..be75a2d --- /dev/null +++ b/lib/widgets/radiobox.ts @@ -0,0 +1,21 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class RadioBox extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.RadioBox, options); + } + + public setChecked(value: boolean): this { + return this.setInteger("Ichecked", +value); + } + + get checked(): boolean { + return this.getInteger("Ichecked") != 0; + } + + set checked(value: boolean) { + this.setInteger("Ichecked", +value); + } +} diff --git a/lib/widgets/scrollbar.ts b/lib/widgets/scrollbar.ts new file mode 100644 index 0000000..94bc34b --- /dev/null +++ b/lib/widgets/scrollbar.ts @@ -0,0 +1,81 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class ScrollBar extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.ScrollBar, options); + } + + public setShowArrows(value: boolean): this { + return this.setInteger("IshowArrows", +value); + } + + get showArrows(): boolean { + return this.getInteger("IshowArrows") != 0; + } + + set showArrows(value: boolean) { + this.setInteger("IshowArrows", +value); + } + + public setAreaShown(value: number): this { + return this.setInteger("IareaShown", value); + } + + get areaShown(): number { + return this.getInteger("IareaShown"); + } + + set areaShown(value: number) { + this.setInteger("IareaShown", value); + } + + public setValue(value: number): this { + return this.setInteger("Ivalue", value); + } + + get value(): number { + return this.getInteger("Ivalue"); + } + + set value(value: number) { + this.setInteger("Ivalue", value); + } + + public setMinValue(value: number): this { + return this.setInteger("IminValue", value); + } + + get minValue(): number { + return this.getInteger("IminValue"); + } + + set minValue(value: number) { + this.setInteger("IminValue", value); + } + + public setMaxValue(value: number): this { + return this.setInteger("ImaxValue", value); + } + + get maxValue(): number { + return this.getInteger("ImaxValue"); + } + + set maxValue(value: number) { + this.setInteger("ImaxValue", value); + } + + public setOrientation(value: number): this { + return this.setInteger("Iorientation", value); + } + + get orientation(): number { + return this.getInteger("Iorientation"); + } + + set orientation(value: number) { + this.setInteger("Iorientation", value); + } +} diff --git a/lib/widgets/submenu.ts b/lib/widgets/submenu.ts new file mode 100644 index 0000000..ce8c796 --- /dev/null +++ b/lib/widgets/submenu.ts @@ -0,0 +1,21 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class SubMenu extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.SubMenu, options); + } + + public setLeftPadding(value: number): this { + return this.setInteger("IleftPadding", value); + } + + get leftPadding(): number { + return this.getInteger("IleftPadding"); + } + + set leftPadding(value: number) { + this.setInteger("IleftPadding", value); + } +} diff --git a/lib/widgets/subwindow.ts b/lib/widgets/subwindow.ts new file mode 100644 index 0000000..412d1f7 --- /dev/null +++ b/lib/widgets/subwindow.ts @@ -0,0 +1,33 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions, Pixmap } from "../types"; + +export class SubWindow extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.SubWindow, options); + } + + public setIconPixmap(value: Pixmap): this { + return this.setVoid("ViconPixmap", value); + } + + get iconPixmap(): Pixmap { + return this.getVoid("ViconPixmap") as Pixmap; + } + + set iconPixmap(value: Pixmap) { + this.setVoid("ViconPixmap", value); + } + + public setTitle(value: string): this { + return this.setString("Stitle", value); + } + + get title(): string { + return this.getString("Stitle"); + } + + set title(value: string) { + this.setString("Stitle", value); + } +} diff --git a/lib/widgets/treeview.ts b/lib/widgets/treeview.ts new file mode 100644 index 0000000..9a4ce57 --- /dev/null +++ b/lib/widgets/treeview.ts @@ -0,0 +1,33 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class TreeView extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.TreeView, options); + } + + public setLeftPadding(value: number): this { + return this.setInteger("IleftPadding", value); + } + + get leftPadding(): number { + return this.getInteger("IleftPadding"); + } + + set leftPadding(value: number) { + this.setInteger("IleftPadding", value); + } + + public setSingleClickSelectable(value: boolean): this { + return this.setInteger("IsingleClickSelectable", +value); + } + + get singleClickSelectable(): boolean { + return this.getInteger("IsingleClickSelectable") != 0; + } + + set singleClickSelectable(value: boolean) { + this.setInteger("IsingleClickSelectable", +value); + } +} diff --git a/lib/widgets/viewport.ts b/lib/widgets/viewport.ts new file mode 100644 index 0000000..214edf4 --- /dev/null +++ b/lib/widgets/viewport.ts @@ -0,0 +1,9 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { WidgetOptions } from "../types"; + +export class Viewport extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.Viewport, options); + } +} diff --git a/lib/widgets/window.ts b/lib/widgets/window.ts new file mode 100644 index 0000000..6da7f00 --- /dev/null +++ b/lib/widgets/window.ts @@ -0,0 +1,82 @@ +import { NativeClasses } from "../milsko"; +import { Widget } from "../widget"; +import { MwSizeHints } from "../structs"; +import { WidgetOptions, Pixmap } from "../types"; + +export class Window extends Widget { + constructor(options: WidgetOptions) { + super(NativeClasses.Window, options); + } + + public setTitle(value: string): this { + return this.setString("Stitle", value); + } + + get title(): string { + return this.getString("Stitle"); + } + + set title(value: string) { + this.setString("Stitle", value); + } + + public setMain(value: boolean): this { + return this.setInteger("Imain", +value); + } + + get main(): boolean { + return this.getInteger("Imain") != 0; + } + + set main(value: boolean) { + this.setInteger("Imain", +value); + } + + public setIconPixmap(value: Pixmap): this { + return this.setVoid("ViconPixmap", value); + } + + get iconPixmap(): Pixmap { + return this.getVoid("ViconPixmap") as Pixmap; + } + + set iconPixmap(value: Pixmap) { + this.setVoid("ViconPixmap", value); + } + + public setSizeHints(value: MwSizeHints): this { + return this.setVoid("VsizeHints", value); + } + + get sizeHints(): MwSizeHints { + return this.getVoid("VsizeHints") as MwSizeHints; + } + + set sizeHints(value: MwSizeHints) { + this.setVoid("VsizeHints", value); + } + + public setHasBorder(value: boolean): this { + return this.setInteger("IhasBorder", +value); + } + + get hasBorder(): boolean { + return this.getInteger("IhasBorder") != 0; + } + + set hasBorder(value: boolean) { + this.setInteger("IhasBorder", +value); + } + + public setInverted(value: boolean): this { + return this.setInteger("Iinverted", +value); + } + + get inverted(): boolean { + return this.getInteger("Iinverted") != 0; + } + + set inverted(value: boolean) { + this.setInteger("Iinverted", +value); + } +} diff --git a/scripts/bindgen.js b/scripts/bindgen.js index ca901b5..af0f391 100644 --- a/scripts/bindgen.js +++ b/scripts/bindgen.js @@ -12,6 +12,7 @@ const structsOut = createWriteStream("lib/structs.ts"); const enumsOut = createWriteStream("lib/enums.ts"); const constantsOut = createWriteStream("lib/constants.ts"); const widgetOut = createWriteStream("lib/widget.ts"); +const widgetsIndexOut = createWriteStream("lib/widgets/index.ts"); function toCamelCase(input) { const split = input.split("_"); @@ -250,7 +251,7 @@ function scanWidgets(root) { const lines = []; const widgetFile = createWriteStream( - join("lib/widgets/", toCamelCase(widgetName) + ".ts") + join("lib/widgets/", widgetName.toLowerCase() + ".ts") ); // scan properties @@ -310,8 +311,15 @@ function scanWidgets(root) { widgetFile.write(line); } + widgetsIndexOut.write( + "export { " + widgetName + " } from \"./" + + widgetName.toLowerCase() + "\"\n" + ); + widgetFile.close(); } + + widgetsIndexOut.close(); } function isArray(tagName) { From c4a3c14caf40ac6ddd01b69719974e2cfaf1b7b3 Mon Sep 17 00:00:00 2001 From: PwLDev <64767383+PwLDev@users.noreply.github.com> Date: Mon, 4 May 2026 11:39:15 -0700 Subject: [PATCH 4/4] new bindings --- src/classes.cpp | 32 ++++++ src/milsko.cpp | 10 +- src/pixmap.cpp | 153 ++++++++++++++++++++++++ src/pixmap.hpp | 19 +++ src/utils.hpp | 2 + src/widget.cpp | 300 ++++++++++++++++++++++++++++++++++++------------ src/widget.hpp | 71 +++++++----- 7 files changed, 481 insertions(+), 106 deletions(-) create mode 100644 src/pixmap.cpp create mode 100644 src/pixmap.hpp create mode 100644 src/utils.hpp diff --git a/src/classes.cpp b/src/classes.cpp index e69de29..9553c4e 100644 --- a/src/classes.cpp +++ b/src/classes.cpp @@ -0,0 +1,32 @@ +#include "classes.hpp" +#include + +#define NAPI_MWCLASS(env, cls) \ + Napi::External<_MwClass>::New(env, cls) + +Napi::Object ClassesInit(Napi::Env env, Napi::Object exports) { + Napi::Object classes = Napi::Object::New(env); + + classes.Set("Box", NAPI_MWCLASS(env, MwBoxClass)); + classes.Set("Button", NAPI_MWCLASS(env, MwButtonClass)); + classes.Set("CheckBox", NAPI_MWCLASS(env, MwCheckBoxClass)); + classes.Set("Entry", NAPI_MWCLASS(env, MwEntryClass)); + classes.Set("Frame", NAPI_MWCLASS(env, MwFrameClass)); + classes.Set("Image", NAPI_MWCLASS(env, MwImageClass)); + classes.Set("Label", NAPI_MWCLASS(env, MwLabelClass)); + classes.Set("ListBox", NAPI_MWCLASS(env, MwListBoxClass)); + classes.Set("Menu", NAPI_MWCLASS(env, MwMenuClass)); + classes.Set("NumberEntry", NAPI_MWCLASS(env, MwNumberEntryClass)); + classes.Set("ScrollBar", NAPI_MWCLASS(env, MwScrollBarClass)); + classes.Set("SubMenu", NAPI_MWCLASS(env, MwSubMenuClass)); + classes.Set("SubWindow", NAPI_MWCLASS(env, MwSubWindowClass)); + classes.Set("Viewport", NAPI_MWCLASS(env, MwViewportClass)); + classes.Set("Window", NAPI_MWCLASS(env, MwWindowClass)); + classes.Set("ProgressBar", NAPI_MWCLASS(env, MwProgressBarClass)); + classes.Set("RadioBox", NAPI_MWCLASS(env, MwRadioBoxClass)); + classes.Set("ComboBox", NAPI_MWCLASS(env, MwComboBoxClass)); + classes.Set("TreeView", NAPI_MWCLASS(env, MwTreeViewClass)); + + exports.Set("NativeClasses", classes); + return exports; +}; diff --git a/src/milsko.cpp b/src/milsko.cpp index 59b2577..3910ea5 100644 --- a/src/milsko.cpp +++ b/src/milsko.cpp @@ -1,13 +1,17 @@ +#include "classes.hpp" +#include "pixmap.hpp" #include "widget.hpp" #include #include Napi::Object Init(Napi::Env env, Napi::Object exports) { - MwLibraryInit(); + MwLibraryInit(); - MwBaseWidget::Init(env, exports); + MwBaseWidget::Init(env, exports); + MwPixmap::Init(env, exports); + ClassesInit(env, exports); - return exports; + return exports; } NODE_API_MODULE(milsko, Init); \ No newline at end of file diff --git a/src/pixmap.cpp b/src/pixmap.cpp new file mode 100644 index 0000000..261b5c4 --- /dev/null +++ b/src/pixmap.cpp @@ -0,0 +1,153 @@ +#include "classes.hpp" +#include "widget.hpp" +#include + +Napi::FunctionReference MwPixmap::constructor; + +Napi::Object MwPixmap::Init(Napi::Env env, Napi::Object exports) { + Napi::Function func = DefineClass(env, "Pixmap", + { + InstanceMethod("getRaw", &MwPixmap::GetRaw), + InstanceMethod("reloadRaw", &MwPixmap::ReloadRaw), + InstanceAccessor("size", &MwPixmap::GetSize, nullptr), + }); + + constructor = Napi::Persistent(func); + constructor.SuppressDestruct(); + + exports.Set("Pixmap", func); + return exports; +} + +MwPixmap::MwPixmap(const Napi::CallbackInfo &info): Napi::ObjectWrap(info) { + Napi::Env env = info.Env(); + Napi::HandleScope scope(env); + + if (info.Length() < 1 || !info[0].IsObject()) { + Napi::TypeError::New(env, "Expected an instance of widget as first argument") + .ThrowAsJavaScriptException(); + return; + } + + Napi::Object obj = info[0].As(); + MwBaseWidget *widget = MwBaseWidget::Unwrap(obj); + unsigned char *data = 0; + int width = 0; + int height = 0; + + if (!widget) { + Napi::TypeError::New(env, "First argument is not an instance of a widget") + .ThrowAsJavaScriptException(); + return; + } + + if (info.Length() > 1 && info[1].IsObject()) { + Napi::Object params = info[1].As(); + + if (params.Has("data")) { + Napi::Value dataParam = params.Get("data"); + + if (dataParam.IsBuffer()) { + data = dataParam.As>().Data(); + } else if (dataParam.IsArrayBuffer()) { + data = reinterpret_cast( + dataParam.As().Data() + ); + } else { + Napi::TypeError::New(env, "The data parameter must be of type Buffer or ArrayBuffer") + .ThrowAsJavaScriptException(); + return; + } + } + + if (params.Has("width")) { + Napi::Value widthParam = params.Get("width"); + + if (widthParam.IsNumber()) { + width = widthParam.As().Int32Value(); + } else { + Napi::TypeError::New(env, "The width parameter must be a number") + .ThrowAsJavaScriptException(); + return; + } + } + + if (params.Has("height")) { + Napi::Value heightParam = params.Get("height"); + + if (heightParam.IsNumber()) { + height = heightParam.As().Int32Value(); + } else { + Napi::TypeError::New(env, "The height parameter must be a number") + .ThrowAsJavaScriptException(); + return; + } + } + } + + handle = MwLoadRaw( + widget->handle, + data, + width, + height + ); +}; + +MwPixmap::~MwPixmap() { + if (handle) + MwLLDestroyPixmap(handle); +} + +Napi::Value MwPixmap::GetRaw(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + + unsigned char *data = MwPixmapGetRaw(handle); + Napi::Buffer buffer = Napi::Buffer::New( + env, + data, + sizeof(data), + [](Napi::Env env, unsigned char* finalized) { + free(finalized); + } + ); + + return buffer; +} + +Napi::Value MwPixmap::GetSize(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + Napi::Object size = Napi::Object::New(env); + MwRect rect; + + MwPixmapGetSize(handle, &rect); + + size.Set("x", Napi::Number::New(env, rect.x)); + size.Set("y", Napi::Number::New(env, rect.y)); + size.Set("width", Napi::Number::New(env, rect.width)); + size.Set("height", Napi::Number::New(env, rect.height)); + + return size; +} + +Napi::Value MwPixmap::ReloadRaw(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + + if (info.Length() < 1 || !info[0].IsBuffer() || !info[0].IsArrayBuffer()) { + Napi::TypeError::New(env, "Expected a buffer or array buffer as argument") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + unsigned char *data = 0; + + if (info[0].IsBuffer()) { + data = info[0].As>().Data(); + } else if (info[0].IsArrayBuffer()) { + data = reinterpret_cast( + info[0].As().Data() + ); + } + + MwPixmapReloadRaw(handle, data); + return env.Undefined(); +} diff --git a/src/pixmap.hpp b/src/pixmap.hpp new file mode 100644 index 0000000..4ba0e78 --- /dev/null +++ b/src/pixmap.hpp @@ -0,0 +1,19 @@ +#pragma once +#include +#include + +class MwPixmap : public Napi::ObjectWrap { +public: + static Napi::FunctionReference constructor; + static Napi::Object Init(Napi::Env env, Napi::Object exports); + static Napi::Object From(Napi::Env env, MwLLPixmap &pixmap); + MwPixmap(const Napi::CallbackInfo &info); + ~MwPixmap(); + + MwLLPixmap handle; + +protected: + Napi::Value GetRaw(const Napi::CallbackInfo &info); + Napi::Value GetSize(const Napi::CallbackInfo &info); + Napi::Value ReloadRaw(const Napi::CallbackInfo &info); +}; \ No newline at end of file diff --git a/src/utils.hpp b/src/utils.hpp new file mode 100644 index 0000000..ab35dff --- /dev/null +++ b/src/utils.hpp @@ -0,0 +1,2 @@ +#include + diff --git a/src/widget.cpp b/src/widget.cpp index e802c30..e11d807 100644 --- a/src/widget.cpp +++ b/src/widget.cpp @@ -4,36 +4,46 @@ Napi::FunctionReference MwBaseWidget::constructor; Napi::Object MwBaseWidget::Init(Napi::Env env, Napi::Object exports) { Napi::HandleScope scope(env); - Napi::Function func = DefineClass(env, "MwBaseWidget", + Napi::Function func = DefineClass(env, "BaseWidget", { - InstanceMethod("setArea", &SetArea), - InstanceMethod("move", &Move), - InstanceMethod("resize", &Resize), - InstanceMethod("step", &Step), - InstanceMethod("loop", &Loop), - InstanceMethod("show", &Show), - InstanceMethod("hideCursor", &HideCursor), - InstanceMethod("grabPointer", &GrabPointer), - InstanceMethod("getClipboard", &GetClipboard), - InstanceMethod("addTickList", &AddTickList), - InstanceMethod("forceRender", &ForceRender), - InstanceMethod("reparent", &Reparent), - InstanceMethod("add", &Add), - InstanceMethod("remove", &Remove), - InstanceAccessor("area", &GetArea, nullptr), - InstanceAccessor("isPending", &IsPending, nullptr), - InstanceAccessor("parent", &GetParent, nullptr), - InstanceAccessor("children", &GetChildren, nullptr), - InstanceAccessor("name", &GetName, nullptr), - InstanceAccessor("cursorCoord", &GetCursorCoord, nullptr), - InstanceAccessor("screenSize", &GetScreenSize, nullptr), - InstanceAccessor("coordinateType", &GetCoordinateType, nullptr), + InstanceMethod("setArea", &MwBaseWidget::GetArea), + InstanceMethod("move", &MwBaseWidget::Move), + InstanceMethod("resize", &MwBaseWidget::Resize), + InstanceMethod("step", &MwBaseWidget::Step), + InstanceMethod("loop", &MwBaseWidget::Loop), + InstanceMethod("show", &MwBaseWidget::Show), + InstanceMethod("hideCursor", &MwBaseWidget::HideCursor), + InstanceMethod("grabPointer", &MwBaseWidget::GrabPointer), + InstanceMethod("focus", &MwBaseWidget::Focus), + InstanceMethod("addTickList", &MwBaseWidget::AddTickList), + InstanceMethod("forceRender", &MwBaseWidget::ForceRender), + InstanceMethod("reparent", &MwBaseWidget::Reparent), + InstanceMethod("add", &MwBaseWidget::AddChild), + InstanceMethod("destroy", &MwBaseWidget::Destroy), + InstanceMethod("getClipboard", &MwBaseWidget::GetClipboard), + + InstanceMethod("setInteger", &MwBaseWidget::SetInteger), + InstanceMethod("setString", &MwBaseWidget::SetText), + InstanceMethod("setVoid", &MwBaseWidget::SetVoid), + InstanceMethod("getInteger", &MwBaseWidget::GetInteger), + InstanceMethod("getText", &MwBaseWidget::GetText), + InstanceMethod("getVoid", &MwBaseWidget::GetVoid), + + InstanceAccessor("area", &MwBaseWidget::GetArea, nullptr), + InstanceAccessor("isPending", &MwBaseWidget::IsPending, nullptr), + InstanceAccessor("parent", &MwBaseWidget::GetParent, nullptr), + InstanceAccessor("children", &MwBaseWidget::GetChildren, nullptr), + InstanceAccessor("name", &MwBaseWidget::GetName, nullptr), + InstanceAccessor("cursorCoord", &MwBaseWidget::GetCursorCoord, nullptr), + InstanceAccessor("screenSize", &MwBaseWidget::GetScreenSize, nullptr), + InstanceAccessor("coordinateType", &MwBaseWidget::GetCoordinateType, nullptr), + InstanceAccessor("nativeClass", &MwBaseWidget::GetNativeClass, nullptr), }); constructor = Napi::Persistent(func); constructor.SuppressDestruct(); - exports.Set("MwBaseWidget", func); + exports.Set("BaseWidget", func); return exports; }; @@ -107,7 +117,7 @@ Napi::Value MwBaseWidget::Move(const Napi::CallbackInfo &info) { .ThrowAsJavaScriptException(); } - return Napi::Value(); + return info.This(); } Napi::Value MwBaseWidget::Resize(const Napi::CallbackInfo &info) { @@ -127,7 +137,7 @@ Napi::Value MwBaseWidget::Resize(const Napi::CallbackInfo &info) { .ThrowAsJavaScriptException(); } - return Napi::Value(); + return info.This(); } Napi::Value MwBaseWidget::Step(const Napi::CallbackInfo &info) { @@ -146,11 +156,10 @@ Napi::Value MwBaseWidget::IsPending(const Napi::CallbackInfo &info) { Napi::Value MwBaseWidget::Loop(const Napi::CallbackInfo &info) { MwLoop(handle); - return Napi::Value(); + return info.This(); } Napi::Value MwBaseWidget::Show(const Napi::CallbackInfo &info) { - Napi::Env env = info.Env(); bool toggle = true; if (info.Length() > 0 && info[0].IsBoolean()) { @@ -158,16 +167,15 @@ Napi::Value MwBaseWidget::Show(const Napi::CallbackInfo &info) { } MwShow(handle, static_cast(toggle)); - return Napi::Value(); + return info.This(); } Napi::Value MwBaseWidget::HideCursor(const Napi::CallbackInfo &info) { MwHideCursor(handle); - return Napi::Value(); + return info.This(); } Napi::Value MwBaseWidget::GrabPointer(const Napi::CallbackInfo &info) { - Napi::Env env = info.Env(); bool toggle = true; if (info.Length() > 0 && info[0].IsBoolean()) { @@ -175,17 +183,22 @@ Napi::Value MwBaseWidget::GrabPointer(const Napi::CallbackInfo &info) { } MwGrabPointer(handle, static_cast(toggle)); - return Napi::Value(); + return info.This(); +} + +Napi::Value MwBaseWidget::Focus(const Napi::CallbackInfo &info) { + MwFocus(handle); + return info.This(); } Napi::Value MwBaseWidget::AddTickList(const Napi::CallbackInfo &info) { MwAddTickList(handle); - return Napi::Value(); + return info.This(); } Napi::Value MwBaseWidget::ForceRender(const Napi::CallbackInfo &info) { MwForceRender(handle); - return Napi::Value(); + return info.This(); } Napi::Value MwBaseWidget::Reparent(const Napi::CallbackInfo &info) { @@ -230,68 +243,76 @@ Napi::Value MwBaseWidget::Reparent(const Napi::CallbackInfo &info) { parent = newParent; newParent->children.push_back(this); - return Napi::Value(); + return info.This(); } -Napi::Value MwBaseWidget::Add(const Napi::CallbackInfo &info) { +Napi::Value MwBaseWidget::AddChild(const Napi::CallbackInfo &info) { Napi::Env env = info.Env(); - if (info.Length() < 1 || !info[0].IsObject()) { + if (info.Length() < 1 || !info[0].IsArray()) { Napi::TypeError::New(env, "Expected an instance of a widget class as argument") .ThrowAsJavaScriptException(); return env.Undefined(); } - Napi::Object wrapped = info[0].As(); - const bool isInstance = wrapped.InstanceOf(constructor.Value()); + Napi::Array widgets = info[0].As(); - if (isInstance) { - MwBaseWidget *child = MwBaseWidget::Unwrap(wrapped); + for (uint32_t i = 0; i < widgets.Length(); i++) { + const Napi::Value value = widgets.Get(i); - if (child == this) { - Napi::Error::New(env, "Cannot add widget as child of itself") + if (!value.IsObject()) { + Napi::TypeError::New(env, + "Expected argument " + std::to_string(i) + "to be instance of a widget" + ) .ThrowAsJavaScriptException(); return env.Null(); } - if (child->parent) { - // if the current parent has this widget as a child, disown :( - for (int i = 0; i < child->parent->children.size(); i++) { - if (child->parent->children[i] == this) { - child->parent->children.erase(child->parent->children.begin() + i); - break; + const Napi::Object wrapped = widgets.As(); + const bool isInstance = wrapped.InstanceOf(constructor.Value()); + + if (isInstance) { + MwBaseWidget *child = MwBaseWidget::Unwrap(wrapped); + + if (child == this) { + Napi::Error::New(env, "Cannot add widget as child of itself") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + if (child->parent) { + // if the current parent has this widget as a child, disown :( + for (size_t i = 0; i < child->parent->children.size(); i++) { + if (child->parent->children[i] == this) { + child->parent->children.erase(child->parent->children.begin() + i); + break; + } } } + + MwReparent( + child->handle, + handle + ); + + child->parent = this; + children.push_back(child); + } else { + Napi::TypeError::New(env,"Argument " + std::to_string(i) + "is not an instance of a widget") + .ThrowAsJavaScriptException(); + return env.Null(); } - - MwReparent( - child->handle, - handle - ); - - child->parent = this; - children.push_back(child); - } else { - Napi::TypeError::New(env, "Provided argument is not an instance of a widget") - .ThrowAsJavaScriptException(); - return env.Null(); } - return Napi::Value(); + return info.This(); } -Napi::Value MwBaseWidget::Remove(const Napi::CallbackInfo &info) { - if (parent) { - for (size_t i = 0; i < parent->children.size(); i++) { - if (parent->children[i] == this) { - parent->children.erase(parent->children.begin() + i); - break; - } - } - } +Napi::Value MwBaseWidget::Destroy(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + if (handle) + MwDestroyWidget(handle); - MwReparent(handle, nullptr); - return Napi::Value(); + return env.Null(); } Napi::Value MwBaseWidget::GetParent(const Napi::CallbackInfo &info) { @@ -366,3 +387,136 @@ Napi::Value MwBaseWidget::GetClipboard(const Napi::CallbackInfo &info) { return env.Undefined(); } + +Napi::Value MwBaseWidget::GetNativeClass(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + MwClass cls = MwGetClass(handle); + + return Napi::External<_MwClass>::New(env, cls); +} + +Napi::Value MwBaseWidget::SetInteger(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + + if (info.Length() < 2) { + Napi::TypeError::New(env, "Expected two arguments for key and value") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + if (!info[0].IsString() || !info[1].IsNumber()) { + Napi::TypeError::New(env, "Expected key to be a string and value to be a number") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + const std::string key = info[0].As().Utf8Value(); + const int value = info[1].As().Int32Value(); + + MwSetInteger(handle, key.c_str(), value); + return info.This(); +} + +Napi::Value MwBaseWidget::SetText(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + + if (info.Length() < 2) { + Napi::TypeError::New(env, "Expected two arguments for key and value") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + if (!info[0].IsString() || !info[1].IsString()) { + Napi::TypeError::New(env, "Expected key and value to be a string") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + const std::string key = info[0].As().Utf8Value(); + const std::string value = info[1].As().Utf8Value(); + + MwSetText(handle, key.c_str(), value.c_str()); + return info.This(); +} + +Napi::Value MwBaseWidget::SetVoid(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + + if (info.Length() < 2) { + Napi::TypeError::New(env, "Expected two arguments for key and value") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + if (!info[0].IsString() || !info[1].IsObject()) { + Napi::TypeError::New(env, "Expected key to be a string and value to be a native object") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + const std::string key = info[0].As().Utf8Value(); + const Napi::Object obj = info[1].As(); + + MwPixmap *pixmap = MwPixmap::Unwrap(obj); + + if (pixmap) { + MwSetVoid(handle, key.c_str(), pixmap->handle); + } else { + Napi::TypeError::New(env, "Expected second argument to be a valid native object") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + return info.This(); +} + +Napi::Value MwBaseWidget::GetInteger(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + + if (info.Length() < 1 || !info[0].IsString()) { + Napi::TypeError::New(env, "Expected key to be an argument of type string") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + const std::string key = info[0].As().Utf8Value(); + const int value = MwGetInteger(handle, key.c_str()); + + return Napi::Number::New(env, static_cast(value)); +} + +Napi::Value MwBaseWidget::GetText(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + + if (info.Length() < 1 || !info[0].IsString()) { + Napi::TypeError::New(env, "Expected key to be an argument of type string") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + const std::string key = info[0].As().Utf8Value(); + const char *value = MwGetText(handle, key.c_str()); + + return Napi::String::New(env, value); +} + +Napi::Value MwBaseWidget::GetVoid(const Napi::CallbackInfo &info) { + Napi::Env env = info.Env(); + + if (info.Length() < 1 || !info[0].IsString()) { + Napi::TypeError::New(env, "Expected key to be an argument of type string") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + if (!info[0].IsString() || !info[1].IsObject()) { + Napi::TypeError::New(env, "Expected key to be a string and value to be a native object") + .ThrowAsJavaScriptException(); + return env.Null(); + } + + const std::string key = info[0].As().Utf8Value(); + void *value = MwGetVoid(handle, key.c_str()); + + return Napi::External::New(env, value); +} diff --git a/src/widget.hpp b/src/widget.hpp index cc47ebf..2f83845 100644 --- a/src/widget.hpp +++ b/src/widget.hpp @@ -1,42 +1,53 @@ #pragma once +#include "pixmap.hpp" #include #include #include class MwBaseWidget : public Napi::ObjectWrap { public: - static Napi::Object Init(Napi::Env env, Napi::Object exports); - MwBaseWidget(const Napi::CallbackInfo &info); - ~MwBaseWidget(); + static Napi::Object Init(Napi::Env env, Napi::Object exports); + MwBaseWidget(const Napi::CallbackInfo &info); + ~MwBaseWidget(); protected: - static Napi::FunctionReference constructor; + static Napi::FunctionReference constructor; + friend class MwPixmap; - MwWidget handle; - MwBaseWidget *parent; - std::vector children; + MwWidget handle; + MwBaseWidget *parent; + std::vector children; - Napi::Value SetArea(const Napi::CallbackInfo &info); - Napi::Value Move(const Napi::CallbackInfo &info); - Napi::Value Resize(const Napi::CallbackInfo &info); - Napi::Value Step(const Napi::CallbackInfo &info); - Napi::Value Loop(const Napi::CallbackInfo &info); - Napi::Value Show(const Napi::CallbackInfo &info); - Napi::Value HideCursor(const Napi::CallbackInfo &info); - Napi::Value GrabPointer(const Napi::CallbackInfo &info); - Napi::Value AddTickList(const Napi::CallbackInfo &info); - Napi::Value ForceRender(const Napi::CallbackInfo &info); - Napi::Value Reparent(const Napi::CallbackInfo &info); - Napi::Value Add(const Napi::CallbackInfo &info); - Napi::Value Remove(const Napi::CallbackInfo &info); - Napi::Value GetClipboard(const Napi::CallbackInfo &info); + Napi::Value SetArea(const Napi::CallbackInfo &info); + Napi::Value Move(const Napi::CallbackInfo &info); + Napi::Value Resize(const Napi::CallbackInfo &info); + Napi::Value Step(const Napi::CallbackInfo &info); + Napi::Value Loop(const Napi::CallbackInfo &info); + Napi::Value Show(const Napi::CallbackInfo &info); + Napi::Value HideCursor(const Napi::CallbackInfo &info); + Napi::Value GrabPointer(const Napi::CallbackInfo &info); + Napi::Value Focus(const Napi::CallbackInfo &info); + Napi::Value AddTickList(const Napi::CallbackInfo &info); + Napi::Value ForceRender(const Napi::CallbackInfo &info); + Napi::Value Reparent(const Napi::CallbackInfo &info); + Napi::Value AddChild(const Napi::CallbackInfo &info); + Napi::Value Destroy(const Napi::CallbackInfo &info); + Napi::Value GetClipboard(const Napi::CallbackInfo &info); + + Napi::Value SetInteger(const Napi::CallbackInfo &info); + Napi::Value SetText(const Napi::CallbackInfo &info); + Napi::Value SetVoid(const Napi::CallbackInfo &info); + Napi::Value GetInteger(const Napi::CallbackInfo &info); + Napi::Value GetText(const Napi::CallbackInfo &info); + Napi::Value GetVoid(const Napi::CallbackInfo &info); - Napi::Value GetArea(const Napi::CallbackInfo &info); - Napi::Value IsPending(const Napi::CallbackInfo &info); - Napi::Value GetParent(const Napi::CallbackInfo &info); - Napi::Value GetChildren(const Napi::CallbackInfo &info); - Napi::Value GetName(const Napi::CallbackInfo &info); - Napi::Value GetCursorCoord(const Napi::CallbackInfo &info); - Napi::Value GetScreenSize(const Napi::CallbackInfo &info); - Napi::Value GetCoordinateType(const Napi::CallbackInfo &info); -}; \ No newline at end of file + Napi::Value GetArea(const Napi::CallbackInfo &info); + Napi::Value IsPending(const Napi::CallbackInfo &info); + Napi::Value GetParent(const Napi::CallbackInfo &info); + Napi::Value GetChildren(const Napi::CallbackInfo &info); + Napi::Value GetName(const Napi::CallbackInfo &info); + Napi::Value GetCursorCoord(const Napi::CallbackInfo &info); + Napi::Value GetScreenSize(const Napi::CallbackInfo &info); + Napi::Value GetCoordinateType(const Napi::CallbackInfo &info); + Napi::Value GetNativeClass(const Napi::CallbackInfo &info); +};