update bindings

This commit is contained in:
PwLDev 2026-05-07 09:40:35 -07:00
commit 382b9d65d9
28 changed files with 268 additions and 46 deletions

View file

@ -1,14 +1,14 @@
// @ts-ignore // @ts-ignore
import binding from "node-gyp-build"; import addon from "node-gyp-build";
import { join } from "node:path"; import { join } from "node:path";
import { import type {
BaseWidgetConstructor, BaseWidgetConstructor,
MwNativeClasses, MwNativeClasses,
PixmapConstructor PixmapConstructor
} from "./types"; } from "./types";
export const BaseWidget: BaseWidgetConstructor = binding.BaseWidget; const binding = addon(join(__dirname, ".."));
export const NativeClasses: MwNativeClasses = binding.Classes;
export const Pixmap: PixmapConstructor = binding.Pixmap;
export default binding(join(__dirname, "..")); export const BaseWidget: BaseWidgetConstructor = binding.BaseWidget;
export const NativeClasses: MwNativeClasses = binding.NativeClasses;
export const Pixmap: PixmapConstructor = binding.Pixmap;

View file

@ -5,7 +5,7 @@ export type MwClass = object & { __brand: "MwClass" };
/** /**
* `BaseWidget` represents the lowest level form of widgets before the native layer. * `BaseWidget` represents the lowest level form of widgets before the native layer.
* This class contains the fundamental native methods shared by all widgets. * This class contains the native methods shared by all widgets.
*/ */
export interface BaseWidget { export interface BaseWidget {
area: MwRect; area: MwRect;
@ -153,6 +153,7 @@ export interface BaseWidgetConstructor {
export interface MwNativeClasses { export interface MwNativeClasses {
Box: MwClass; Box: MwClass;
Button: MwClass; Button: MwClass;
Calendar: MwClass;
CheckBox: MwClass; CheckBox: MwClass;
Entry: MwClass; Entry: MwClass;
Frame: MwClass; Frame: MwClass;
@ -164,6 +165,7 @@ export interface MwNativeClasses {
ScrollBar: MwClass; ScrollBar: MwClass;
SubMenu: MwClass; SubMenu: MwClass;
SubWindow: MwClass; SubWindow: MwClass;
Tab: MwClass;
Viewport: MwClass; Viewport: MwClass;
Window: MwClass; Window: MwClass;
ProgressBar: MwClass; ProgressBar: MwClass;
@ -194,13 +196,12 @@ export interface PixmapOptions {
} }
export interface PixmapConstructor { export interface PixmapConstructor {
new (cls: BaseWidget, options?: PixmapOptions): Pixmap; new (widget: BaseWidget, options?: PixmapOptions): Pixmap;
} }
export interface WidgetOptions { export interface WidgetOptions {
name?: string; name?: string;
parent?: BaseWidget; parent?: BaseWidget;
children?: BaseWidget[];
x?: number; x?: number;
y?: number; y?: number;
width?: number; width?: number;

View file

@ -1,5 +1,5 @@
import { BaseWidget } from "./milsko"; import { BaseWidget } from "./milsko";
import { Pixmap } from "./types"; import type { Pixmap } from "./types";
export class Widget extends BaseWidget { export class Widget extends BaseWidget {
public setX(value: number): this { public setX(value: number): this {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class Box extends Widget { export class Box extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {
@ -66,4 +66,16 @@ export class Box extends Widget {
set inverted(value: boolean) { set inverted(value: boolean) {
this.setInteger("Iinverted", +value); this.setInteger("Iinverted", +value);
} }
public setWaitLayout(value: number): this {
return this.setInteger("IwaitLayout", value);
}
get waitLayout(): number {
return this.getInteger("IwaitLayout");
}
set waitLayout(value: number) {
this.setInteger("IwaitLayout", value);
}
} }

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions, Pixmap } from "../types"; import type { WidgetOptions, Pixmap } from "../types";
export class Button extends Widget { export class Button extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

69
lib/widgets/calendar.ts Normal file
View file

@ -0,0 +1,69 @@
import { NativeClasses } from "../milsko";
import { Widget } from "../widget";
import type { WidgetOptions } from "../types";
export class Calendar extends Widget {
constructor(options: WidgetOptions) {
super(NativeClasses.Calendar, options);
}
public setYear(value: number): this {
return this.setInteger("Iyear", value);
}
get year(): number {
return this.getInteger("Iyear");
}
set year(value: number) {
this.setInteger("Iyear", value);
}
public setMonth(value: number): this {
return this.setInteger("Imonth", value);
}
get month(): number {
return this.getInteger("Imonth");
}
set month(value: number) {
this.setInteger("Imonth", value);
}
public setDate(value: number): this {
return this.setInteger("Idate", value);
}
get date(): number {
return this.getInteger("Idate");
}
set date(value: number) {
this.setInteger("Idate", value);
}
public setDay(value: number): this {
return this.setInteger("Iday", value);
}
get day(): number {
return this.getInteger("Iday");
}
set day(value: number) {
this.setInteger("Iday", value);
}
public setScale(value: number): this {
return this.setInteger("Iscale", value);
}
get scale(): number {
return this.getInteger("Iscale");
}
set scale(value: number) {
this.setInteger("Iscale", value);
}
}

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class CheckBox extends Widget { export class CheckBox extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class ComboBox extends Widget { export class ComboBox extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class Entry extends Widget { export class Entry extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class Frame extends Widget { export class Frame extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions, Pixmap } from "../types"; import type { WidgetOptions, Pixmap } from "../types";
export class Image extends Widget { export class Image extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,5 +1,6 @@
export { Box } from "./box"; export { Box } from "./box";
export { Button } from "./button"; export { Button } from "./button";
export { Calendar } from "./calendar";
export { CheckBox } from "./checkbox"; export { CheckBox } from "./checkbox";
export { Entry } from "./entry"; export { Entry } from "./entry";
export { Frame } from "./frame"; export { Frame } from "./frame";
@ -17,3 +18,4 @@ export { RadioBox } from "./radiobox";
export { ComboBox } from "./combobox"; export { ComboBox } from "./combobox";
export { TreeView } from "./treeview"; export { TreeView } from "./treeview";
export { SubWindow } from "./subwindow"; export { SubWindow } from "./subwindow";
export { Tab } from "./tab";

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class Label extends Widget { export class Label extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class ListBox extends Widget { export class ListBox extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class Menu extends Widget { export class Menu extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class NumberEntry extends Widget { export class NumberEntry extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class ProgressBar extends Widget { export class ProgressBar extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class RadioBox extends Widget { export class RadioBox extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class ScrollBar extends Widget { export class ScrollBar extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class SubMenu extends Widget { export class SubMenu extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions, Pixmap } from "../types"; import type { WidgetOptions, Pixmap } from "../types";
export class SubWindow extends Widget { export class SubWindow extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

21
lib/widgets/tab.ts Normal file
View file

@ -0,0 +1,21 @@
import { NativeClasses } from "../milsko";
import { Widget } from "../widget";
import type { WidgetOptions } from "../types";
export class Tab extends Widget {
constructor(options: WidgetOptions) {
super(NativeClasses.Tab, options);
}
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);
}
}

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class TreeView extends Widget { export class TreeView extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,6 +1,6 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { WidgetOptions } from "../types"; import type { WidgetOptions } from "../types";
export class Viewport extends Widget { export class Viewport extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -1,7 +1,7 @@
import { NativeClasses } from "../milsko"; import { NativeClasses } from "../milsko";
import { Widget } from "../widget"; import { Widget } from "../widget";
import { MwSizeHints } from "../structs"; import type { MwSizeHints } from "../structs";
import { WidgetOptions, Pixmap } from "../types"; import type { WidgetOptions, Pixmap } from "../types";
export class Window extends Widget { export class Window extends Widget {
constructor(options: WidgetOptions) { constructor(options: WidgetOptions) {

View file

@ -218,7 +218,7 @@ function scanProperties(root) {
widgetOut.write( widgetOut.write(
"import { BaseWidget } from \"./milsko\"\n" + "import { BaseWidget } from \"./milsko\"\n" +
"import { Pixmap } from \"./types\"\n\n" + "import type { Pixmap } from \"./types\"\n\n" +
"export class Widget extends BaseWidget {\n" "export class Widget extends BaseWidget {\n"
); );
@ -287,13 +287,13 @@ function scanWidgets(root) {
if (structImports.length) { if (structImports.length) {
widgetFile.write( widgetFile.write(
"import { " + structImports.join(", ") + "import type { " + structImports.join(", ") +
" } from \"../structs\"\n" " } from \"../structs\"\n"
); );
} }
widgetFile.write( widgetFile.write(
"import { " + typeImports.join(", ") + "import type { " + typeImports.join(", ") +
" } from \"../types\"\n" " } from \"../types\"\n"
); );

View file

@ -1,2 +0,0 @@
#include <napi.h>

View file

@ -18,7 +18,7 @@ Napi::Object MwBaseWidget::Init(Napi::Env env, Napi::Object exports) {
InstanceMethod("addTickList", &MwBaseWidget::AddTickList), InstanceMethod("addTickList", &MwBaseWidget::AddTickList),
InstanceMethod("forceRender", &MwBaseWidget::ForceRender), InstanceMethod("forceRender", &MwBaseWidget::ForceRender),
InstanceMethod("reparent", &MwBaseWidget::Reparent), InstanceMethod("reparent", &MwBaseWidget::Reparent),
InstanceMethod("add", &MwBaseWidget::AddChild), InstanceMethod("addChild", &MwBaseWidget::AddChild),
InstanceMethod("destroy", &MwBaseWidget::Destroy), InstanceMethod("destroy", &MwBaseWidget::Destroy),
InstanceMethod("getClipboard", &MwBaseWidget::GetClipboard), InstanceMethod("getClipboard", &MwBaseWidget::GetClipboard),
@ -52,17 +52,138 @@ Napi::ObjectWrap<MwBaseWidget>(info) {
Napi::Env env = info.Env(); Napi::Env env = info.Env();
Napi::HandleScope scope(env); Napi::HandleScope scope(env);
handle = MwCreateWidget(MwWindowClass, "window", nullptr, 0, 0, 300, 300); if (info.Length() < 1 || !info[0].IsExternal()) {
Napi::TypeError::New(env, "Expected a MwClass as first argument")
.ThrowAsJavaScriptException();
return;
}
MwClass cls = info[0].As<Napi::External<_MwClass>>().Data();
std::string name = "widget"; // name is unused anyways
MwBaseWidget *parent = nullptr;
int xPos = 0;
int yPos = 0;
unsigned int width = 0;
unsigned int height = 0;
if (info.Length() > 1 && info[1].IsObject()) {
Napi::Object params = info[1].As<Napi::Object>();
if (params.Has("name")) {
Napi::Value nameParam = params.Get("name");
if (nameParam.IsString()) {
name = nameParam.As<Napi::String>().Utf8Value();
} else {
Napi::TypeError::New(env, "The name parameter must be a string")
.ThrowAsJavaScriptException();
return;
}
}
if (params.Has("parent")) {
Napi::Value parentParam = params.Get("parent");
if (parentParam.IsObject()) {
Napi::Object parentObj = parentParam.As<Napi::Object>();
bool isInstance = parentObj.InstanceOf(constructor.Value());
if (isInstance) {
parent = Unwrap(parentObj);
} else {
Napi::TypeError::New(env, "The parent parameter is not an instance of a widget")
.ThrowAsJavaScriptException();
return;
}
} else {
Napi::TypeError::New(env, "The parent parameter must be an instance of a widget")
.ThrowAsJavaScriptException();
return;
}
}
if (params.Has("x")) {
Napi::Value xParam = params.Get("x");
if (xParam.IsNumber()) {
xPos = xParam.As<Napi::Number>().Int32Value();
} else {
Napi::TypeError::New(env, "The x parameter must be a number")
.ThrowAsJavaScriptException();
return;
}
}
if (params.Has("y")) {
Napi::Value yParam = params.Get("y");
if (yParam.IsNumber()) {
yPos = yParam.As<Napi::Number>().Int32Value();
} else {
Napi::TypeError::New(env, "The y parameter must be a number")
.ThrowAsJavaScriptException();
return;
}
}
if (params.Has("width")) {
Napi::Value widthParam = params.Get("width");
if (widthParam.IsNumber()) {
width = widthParam.As<Napi::Number>().Uint32Value();
} 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<Napi::Number>().Uint32Value();
} else {
Napi::TypeError::New(env, "The height parameter must be a number")
.ThrowAsJavaScriptException();
return;
}
}
}
handle = MwCreateWidget(
cls,
name.c_str(),
parent ? parent->handle : nullptr,
xPos, yPos,
width, height
);
if (!handle) {
Napi::Error::New(env, "A native exception occured when creating the widget")
.ThrowAsJavaScriptException();
return;
}
if (parent) {
parent->children.push_back(this);
this->parent = parent;
}
}; };
MwBaseWidget::~MwBaseWidget() { MwBaseWidget::~MwBaseWidget() {
// call destructors for each children // call destructors for each children
if (children.size() > 0) { if (children.size() > 0) {
for (const auto &child : children) { for (size_t i = 0; i < children.size(); i++) {
delete child; delete children[i];
} }
} }
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;
}
}
}
if (handle) if (handle)
MwDestroyWidget(handle); MwDestroyWidget(handle);
}; };
@ -249,26 +370,24 @@ Napi::Value MwBaseWidget::Reparent(const Napi::CallbackInfo &info) {
Napi::Value MwBaseWidget::AddChild(const Napi::CallbackInfo &info) { Napi::Value MwBaseWidget::AddChild(const Napi::CallbackInfo &info) {
Napi::Env env = info.Env(); Napi::Env env = info.Env();
if (info.Length() < 1 || !info[0].IsArray()) { if (info.Length() < 1) {
Napi::TypeError::New(env, "Expected an instance of a widget class as argument") Napi::TypeError::New(env, "Expected at least one instance of a widget class as argument")
.ThrowAsJavaScriptException(); .ThrowAsJavaScriptException();
return env.Undefined(); return env.Undefined();
} }
Napi::Array widgets = info[0].As<Napi::Array>(); for (size_t i = 0; i < info.Length(); i++) {
const Napi::Value value = info[i];
for (uint32_t i = 0; i < widgets.Length(); i++) {
const Napi::Value value = widgets.Get(i);
if (!value.IsObject()) { if (!value.IsObject()) {
Napi::TypeError::New(env, Napi::TypeError::New(env,
"Expected argument " + std::to_string(i) + "to be instance of a widget" "Expected argument " + std::to_string(i) + "to be an instance of a widget"
) )
.ThrowAsJavaScriptException(); .ThrowAsJavaScriptException();
return env.Null(); return env.Null();
} }
const Napi::Object wrapped = widgets.As<Napi::Object>(); const Napi::Object wrapped = value.As<Napi::Object>();
const bool isInstance = wrapped.InstanceOf(constructor.Value()); const bool isInstance = wrapped.InstanceOf(constructor.Value());
if (isInstance) { if (isInstance) {