xbintsc 0.3.18 → 0.3.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -0
- package/dist/src/cli/main.js +124 -30
- package/dist/src/cli/main.js.map +1 -1
- package/dist/src/codegen/generator/calls/access.js +8 -1
- package/dist/src/codegen/generator/calls/access.js.map +1 -1
- package/dist/src/codegen/generator/state.js +20 -0
- package/dist/src/codegen/generator/state.js.map +1 -1
- package/dist/src/codegen/generator/tables.d.ts +6 -0
- package/dist/src/codegen/generator/tables.js +38 -0
- package/dist/src/codegen/generator/tables.js.map +1 -1
- package/dist/src/driver/bundler/commonjs.d.ts +52 -0
- package/dist/src/driver/bundler/commonjs.js +493 -0
- package/dist/src/driver/bundler/commonjs.js.map +1 -0
- package/dist/src/driver/bundler/graph.d.ts +2 -1
- package/dist/src/driver/bundler/graph.js +32 -3
- package/dist/src/driver/bundler/graph.js.map +1 -1
- package/dist/src/driver/bundler/merge.d.ts +2 -1
- package/dist/src/driver/bundler/merge.js +16 -2
- package/dist/src/driver/bundler/merge.js.map +1 -1
- package/dist/src/driver/bundler/types.d.ts +8 -0
- package/dist/src/driver/compiler.d.ts +8 -1
- package/dist/src/driver/compiler.js +75 -7
- package/dist/src/driver/compiler.js.map +1 -1
- package/dist/src/driver/config.d.ts +53 -0
- package/dist/src/driver/config.js +141 -0
- package/dist/src/driver/config.js.map +1 -0
- package/dist/src/driver/icon.d.ts +62 -0
- package/dist/src/driver/icon.js +151 -0
- package/dist/src/driver/icon.js.map +1 -0
- package/dist/src/driver/index.d.ts +4 -0
- package/dist/src/driver/index.js +4 -0
- package/dist/src/driver/index.js.map +1 -1
- package/dist/src/driver/mac-bundle.d.ts +41 -0
- package/dist/src/driver/mac-bundle.js +123 -0
- package/dist/src/driver/mac-bundle.js.map +1 -0
- package/dist/src/driver/win-icon.d.ts +27 -0
- package/dist/src/driver/win-icon.js +80 -0
- package/dist/src/driver/win-icon.js.map +1 -0
- package/dist/src/extensions/gui/html.d.ts +25 -0
- package/dist/src/extensions/gui/html.js +203 -0
- package/dist/src/extensions/gui/html.js.map +1 -0
- package/dist/src/extensions/gui/index.js +11 -0
- package/dist/src/extensions/gui/index.js.map +1 -1
- package/dist/src/extensions/registry.d.ts +29 -0
- package/dist/src/extensions/registry.js +14 -0
- package/dist/src/extensions/registry.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/lexer/scanner/identifiers.js +4 -12
- package/dist/src/lexer/scanner/identifiers.js.map +1 -1
- package/dist/src/parser/statements.js +17 -4
- package/dist/src/parser/statements.js.map +1 -1
- package/dist/tests/cli/main.test.js +46 -1
- package/dist/tests/cli/main.test.js.map +1 -1
- package/dist/tests/driver/bundler-resolve.test.d.ts +1 -0
- package/dist/tests/driver/bundler-resolve.test.js +230 -0
- package/dist/tests/driver/bundler-resolve.test.js.map +1 -0
- package/dist/tests/driver/config.test.d.ts +1 -0
- package/dist/tests/driver/config.test.js +124 -0
- package/dist/tests/driver/config.test.js.map +1 -0
- package/dist/tests/driver/icon.test.d.ts +1 -0
- package/dist/tests/driver/icon.test.js +421 -0
- package/dist/tests/driver/icon.test.js.map +1 -0
- package/dist/tests/driver/modules.test.js +177 -0
- package/dist/tests/driver/modules.test.js.map +1 -1
- package/dist/tests/e2e/fetch.test.d.ts +12 -0
- package/dist/tests/e2e/fetch.test.js +272 -0
- package/dist/tests/e2e/fetch.test.js.map +1 -0
- package/dist/tests/e2e/gui-dom.test.d.ts +5 -0
- package/dist/tests/e2e/gui-dom.test.js +102 -0
- package/dist/tests/e2e/gui-dom.test.js.map +1 -0
- package/dist/tests/e2e/gui-events.test.d.ts +5 -0
- package/dist/tests/e2e/gui-events.test.js +60 -0
- package/dist/tests/e2e/gui-events.test.js.map +1 -0
- package/dist/tests/e2e/gui-helpers.d.ts +31 -0
- package/dist/tests/e2e/gui-helpers.js +74 -0
- package/dist/tests/e2e/gui-helpers.js.map +1 -0
- package/dist/tests/e2e/gui-layout.test.d.ts +4 -0
- package/dist/tests/e2e/gui-layout.test.js +88 -0
- package/dist/tests/e2e/gui-layout.test.js.map +1 -0
- package/dist/tests/e2e/gui-lifecycle.test.d.ts +5 -0
- package/dist/tests/e2e/gui-lifecycle.test.js +58 -0
- package/dist/tests/e2e/gui-lifecycle.test.js.map +1 -0
- package/dist/tests/e2e/gui-paint.test.d.ts +5 -0
- package/dist/tests/e2e/gui-paint.test.js +111 -0
- package/dist/tests/e2e/gui-paint.test.js.map +1 -0
- package/dist/tests/e2e/gui-script.test.d.ts +5 -0
- package/dist/tests/e2e/gui-script.test.js +78 -0
- package/dist/tests/e2e/gui-script.test.js.map +1 -0
- package/dist/tests/e2e/gui-style.test.d.ts +5 -0
- package/dist/tests/e2e/gui-style.test.js +175 -0
- package/dist/tests/e2e/gui-style.test.js.map +1 -0
- package/dist/tests/e2e/icon.test.d.ts +7 -0
- package/dist/tests/e2e/icon.test.js +80 -0
- package/dist/tests/e2e/icon.test.js.map +1 -0
- package/dist/tests/e2e/npm-modules.test.d.ts +4 -1
- package/dist/tests/e2e/npm-modules.test.js +47 -1
- package/dist/tests/e2e/npm-modules.test.js.map +1 -1
- package/dist/tests/e2e/runtime-coverage-typed-array.test.d.ts +9 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js +140 -0
- package/dist/tests/e2e/runtime-coverage-typed-array.test.js.map +1 -0
- package/dist/tests/extensions/gui-index.test.d.ts +1 -0
- package/dist/tests/extensions/gui-index.test.js +49 -0
- package/dist/tests/extensions/gui-index.test.js.map +1 -0
- package/dist/tests/extensions/gui.test.d.ts +1 -0
- package/dist/tests/extensions/gui.test.js +177 -0
- package/dist/tests/extensions/gui.test.js.map +1 -0
- package/dist/tests/extensions/registry.test.js +36 -0
- package/dist/tests/extensions/registry.test.js.map +1 -1
- package/dist/tests/parser/statements.test.js +11 -0
- package/dist/tests/parser/statements.test.js.map +1 -1
- package/dist/tests/public-api.test.d.ts +1 -0
- package/dist/tests/public-api.test.js +31 -0
- package/dist/tests/public-api.test.js.map +1 -0
- package/package.json +1 -1
- package/runtime/ext_gui/css.cpp +4 -517
- package/runtime/ext_gui/css_internal.h +27 -0
- package/runtime/ext_gui/css_match.cpp +195 -0
- package/runtime/ext_gui/css_selector.cpp +207 -0
- package/runtime/ext_gui/css_sheet.cpp +129 -0
- package/runtime/ext_gui/document.cpp +90 -0
- package/runtime/ext_gui/document.h +23 -0
- package/runtime/ext_gui/dom.cpp +43 -403
- package/runtime/ext_gui/dom.h +7 -0
- package/runtime/ext_gui/dom_api.cpp +164 -0
- package/runtime/ext_gui/dom_api.h +12 -0
- package/runtime/ext_gui/dom_api_document.cpp +96 -0
- package/runtime/ext_gui/dom_api_events.cpp +123 -0
- package/runtime/ext_gui/dom_api_internal.h +135 -0
- package/runtime/ext_gui/dom_api_node.cpp +329 -0
- package/runtime/ext_gui/dom_api_node_read.cpp +294 -0
- package/runtime/ext_gui/dom_api_proto.cpp +130 -0
- package/runtime/ext_gui/dom_api_style.cpp +192 -0
- package/runtime/ext_gui/dom_internal.h +39 -0
- package/runtime/ext_gui/dom_parse.cpp +348 -0
- package/runtime/ext_gui/dom_serialize.cpp +54 -0
- package/runtime/ext_gui/gui.cpp +61 -245
- package/runtime/ext_gui/gui_engine.h +54 -0
- package/runtime/ext_gui/gui_events.cpp +294 -0
- package/runtime/ext_gui/gui_internal.h +29 -0
- package/runtime/ext_gui/layout.cpp +6 -597
- package/runtime/ext_gui/layout_flex.cpp +200 -0
- package/runtime/ext_gui/layout_flow.cpp +191 -0
- package/runtime/ext_gui/layout_flow_internal.h +149 -0
- package/runtime/ext_gui/layout_inline.cpp +181 -0
- package/runtime/ext_gui/layout_internal.h +20 -0
- package/runtime/ext_gui/renderer.cpp +15 -679
- package/runtime/ext_gui/renderer_image.cpp +233 -0
- package/runtime/ext_gui/renderer_internal.h +112 -0
- package/runtime/ext_gui/renderer_shaders.h +108 -0
- package/runtime/ext_gui/renderer_text.cpp +342 -0
- package/runtime/ext_gui/script.cpp +63 -0
- package/runtime/ext_gui/style.cpp +12 -660
- package/runtime/ext_gui/style_internal.h +33 -0
- package/runtime/ext_gui/style_print.cpp +113 -0
- package/runtime/ext_gui/style_ua.cpp +98 -0
- package/runtime/ext_gui/style_values.cpp +468 -0
- package/runtime/ext_gui/window.cpp +60 -0
- package/runtime/rt.h +6 -0
- package/runtime/rt_internal.h +4 -0
- package/runtime/xt_builtins.c +1 -0
- package/runtime/xt_containers/access.inc +32 -1
- package/runtime/xt_fetch/buffer.inc +64 -0
- package/runtime/xt_fetch/headers.inc +312 -0
- package/runtime/xt_fetch/request.inc +386 -0
- package/runtime/xt_fetch/response.inc +107 -0
- package/runtime/xt_fetch/socket.inc +72 -0
- package/runtime/xt_fetch/url.inc +108 -0
- package/runtime/xt_fetch.c +39 -0
- package/runtime/xt_stdlib2/set.inc +1 -1
- package/runtime/xt_typed_array.c +614 -0
- package/src/cli/main.ts +137 -29
- package/src/codegen/generator/calls/access.ts +9 -1
- package/src/codegen/generator/state.ts +20 -0
- package/src/codegen/generator/tables.ts +40 -0
- package/src/driver/bundler/commonjs.ts +553 -0
- package/src/driver/bundler/graph.ts +35 -2
- package/src/driver/bundler/merge.ts +18 -1
- package/src/driver/bundler/types.ts +8 -0
- package/src/driver/compiler.ts +85 -7
- package/src/driver/config.ts +173 -0
- package/src/driver/icon.ts +184 -0
- package/src/driver/index.ts +30 -0
- package/src/driver/mac-bundle.ts +156 -0
- package/src/driver/win-icon.ts +96 -0
- package/src/extensions/gui/html.ts +236 -0
- package/src/extensions/gui/index.ts +11 -0
- package/src/extensions/registry.ts +39 -0
- package/src/index.ts +1 -1
- package/src/lexer/scanner/identifiers.ts +4 -11
- package/src/parser/statements.ts +17 -4
- package/dist/tests/e2e/gui.test.d.ts +0 -12
- package/dist/tests/e2e/gui.test.js +0 -493
- package/dist/tests/e2e/gui.test.js.map +0 -1
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — input dispatch (pointer/wheel/key), pointer hover
|
|
3
|
+
* tracking and the per-frame rendering of every open window.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
#include "gui_internal.h"
|
|
7
|
+
|
|
8
|
+
#include "paint.h"
|
|
9
|
+
|
|
10
|
+
#include <stdio.h>
|
|
11
|
+
#include <string.h>
|
|
12
|
+
|
|
13
|
+
#include <string>
|
|
14
|
+
|
|
15
|
+
using namespace guidev;
|
|
16
|
+
|
|
17
|
+
/* -- window events -------------------------------------------------------- */
|
|
18
|
+
|
|
19
|
+
void xt_gui_emit(XtGuiWindow *win, const char *event) {
|
|
20
|
+
xt_gui_emit_payload(win, event, XT_UNDEFINED);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
void xt_gui_emit_payload(XtGuiWindow *win, const char *event, xt_value payload) {
|
|
24
|
+
if (win == NULL || !XT_IS_OBJECT(win->object)) return;
|
|
25
|
+
xt_value listeners = xt_object_get_cstr(win->object, "__xt_gui_events");
|
|
26
|
+
if (!XT_IS_OBJECT(listeners)) return;
|
|
27
|
+
xt_value array = xt_object_get(listeners, xt_string_from_cstr(event));
|
|
28
|
+
if (!XT_IS_ARRAY(array)) return;
|
|
29
|
+
xt_value args[1];
|
|
30
|
+
int32_t count = 0;
|
|
31
|
+
if (!XT_IS_UNDEFINED(payload)) {
|
|
32
|
+
args[0] = payload;
|
|
33
|
+
count = 1;
|
|
34
|
+
}
|
|
35
|
+
int32_t listener_count = (int32_t)xt_to_number(xt_array_length(array));
|
|
36
|
+
for (int32_t i = 0; i < listener_count; i++) {
|
|
37
|
+
xt_value fn = xt_array_get(array, xt_number((double)i));
|
|
38
|
+
if (XT_IS_FUNCTION(fn)) xt_call_with_this(fn, win->object, count, args);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
void xt_gui_flush_dom(XtGuiWindow *win) {
|
|
43
|
+
if (win == NULL || win->document == nullptr) return;
|
|
44
|
+
bool mutated = win->struct_dirty != 0;
|
|
45
|
+
win->struct_dirty = 0;
|
|
46
|
+
if (win->document->takeDirty()) mutated = true;
|
|
47
|
+
if (!mutated) return;
|
|
48
|
+
float width = 0;
|
|
49
|
+
float height = 0;
|
|
50
|
+
xt_gui_window_viewport(win, &width, &height);
|
|
51
|
+
win->document->restyle(width, height);
|
|
52
|
+
win->geometry.dirty = 1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static XtGuiWindow *xt_gui_find_by_window_id(SDL_WindowID id) {
|
|
56
|
+
SDL_Window *window = SDL_GetWindowFromID(id);
|
|
57
|
+
if (window == NULL) return NULL;
|
|
58
|
+
for (int i = 0; i < g_window_count; i++) {
|
|
59
|
+
if (g_windows[i].window == window) return &g_windows[i];
|
|
60
|
+
}
|
|
61
|
+
return NULL;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* -- input events --------------------------------------------------------- */
|
|
65
|
+
|
|
66
|
+
/** Deepest element under (x, y), or NULL. */
|
|
67
|
+
static const xtgui::Node *xt_gui_hit_node(XtGuiWindow *win, float x, float y) {
|
|
68
|
+
if (win->document == nullptr) return nullptr;
|
|
69
|
+
const xtgui::LayoutBox *box = win->document->layout().hitTest(x, y);
|
|
70
|
+
const xtgui::Node *node = box != nullptr ? box->node : nullptr;
|
|
71
|
+
while (node != nullptr && !node->isElement()) node = node->parent;
|
|
72
|
+
return node;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** Deepest element under (x, y) as a CSS-like descriptor, or an empty string. */
|
|
76
|
+
std::string xt_gui_hit_test(XtGuiWindow *win, float x, float y) {
|
|
77
|
+
const xtgui::Node *node = xt_gui_hit_node(win, x, y);
|
|
78
|
+
return node == nullptr ? std::string() : xtgui::xt_dom_describe(node);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Update the hovered element from the pointer position; marks paint dirty. */
|
|
82
|
+
static void xt_gui_update_hover(XtGuiWindow *win, float x, float y) {
|
|
83
|
+
if (win->document == nullptr) return;
|
|
84
|
+
if (win->document->setHover(xt_gui_hit_node(win, x, y))) win->geometry.dirty = 1;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
static xt_value xt_gui_pointer_payload(const char *type, XtGuiWindow *win, float x, float y,
|
|
88
|
+
int button, int clicks) {
|
|
89
|
+
xt_value payload = xt_object_new();
|
|
90
|
+
xt_object_set(payload, xt_string_from_cstr("type"), xt_string_from_cstr(type));
|
|
91
|
+
xt_object_set(payload, xt_string_from_cstr("x"), xt_number(x));
|
|
92
|
+
xt_object_set(payload, xt_string_from_cstr("y"), xt_number(y));
|
|
93
|
+
xt_object_set(payload, xt_string_from_cstr("clientX"), xt_number(x));
|
|
94
|
+
xt_object_set(payload, xt_string_from_cstr("clientY"), xt_number(y));
|
|
95
|
+
xt_object_set(payload, xt_string_from_cstr("button"), xt_number(button));
|
|
96
|
+
xt_object_set(payload, xt_string_from_cstr("clicks"), xt_number(clicks));
|
|
97
|
+
std::string target = xt_gui_hit_test(win, x, y);
|
|
98
|
+
if (!target.empty()) {
|
|
99
|
+
xt_object_set(payload, xt_string_from_cstr("target"), xt_string_from_cstr(target.c_str()));
|
|
100
|
+
}
|
|
101
|
+
return payload;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
void xt_gui_dispatch_pointer(XtGuiWindow *win, const char *type, float x, float y, int button,
|
|
105
|
+
int clicks) {
|
|
106
|
+
if (win == NULL || !win->open) return;
|
|
107
|
+
xt_gui_update_hover(win, x, y);
|
|
108
|
+
const xtgui::Node *node = xt_gui_hit_node(win, x, y);
|
|
109
|
+
if (strcmp(type, "mousedown") == 0 && win->document != nullptr) {
|
|
110
|
+
if (win->document->setFocus(node)) win->geometry.dirty = 1;
|
|
111
|
+
}
|
|
112
|
+
xt_value payload = xt_gui_pointer_payload(type, win, x, y, button, clicks);
|
|
113
|
+
if (node != nullptr) xt_gui_emit_dom_event(win, type, node, payload);
|
|
114
|
+
xt_gui_emit_payload(win, type, payload);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
void xt_gui_dispatch_wheel(XtGuiWindow *win, float x, float y, float delta_x, float delta_y) {
|
|
118
|
+
if (win == NULL || !win->open) return;
|
|
119
|
+
xt_value payload = xt_gui_pointer_payload("wheel", win, x, y, -1, 0);
|
|
120
|
+
xt_object_set(payload, xt_string_from_cstr("deltaX"), xt_number(delta_x));
|
|
121
|
+
xt_object_set(payload, xt_string_from_cstr("deltaY"), xt_number(delta_y));
|
|
122
|
+
const xtgui::Node *node = xt_gui_hit_node(win, x, y);
|
|
123
|
+
if (node != nullptr) xt_gui_emit_dom_event(win, "wheel", node, payload);
|
|
124
|
+
xt_gui_emit_payload(win, "wheel", payload);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static xt_value xt_gui_key_payload(const char *type, const char *key, const char *code, bool repeat,
|
|
128
|
+
bool ctrl, bool shift, bool alt, bool meta) {
|
|
129
|
+
xt_value payload = xt_object_new();
|
|
130
|
+
xt_object_set(payload, xt_string_from_cstr("type"), xt_string_from_cstr(type));
|
|
131
|
+
xt_object_set(payload, xt_string_from_cstr("key"), xt_string_from_cstr(key));
|
|
132
|
+
xt_object_set(payload, xt_string_from_cstr("code"), xt_string_from_cstr(code));
|
|
133
|
+
xt_object_set(payload, xt_string_from_cstr("repeat"), repeat ? XT_TRUE : XT_FALSE);
|
|
134
|
+
xt_object_set(payload, xt_string_from_cstr("ctrl"), ctrl ? XT_TRUE : XT_FALSE);
|
|
135
|
+
xt_object_set(payload, xt_string_from_cstr("shift"), shift ? XT_TRUE : XT_FALSE);
|
|
136
|
+
xt_object_set(payload, xt_string_from_cstr("alt"), alt ? XT_TRUE : XT_FALSE);
|
|
137
|
+
xt_object_set(payload, xt_string_from_cstr("meta"), meta ? XT_TRUE : XT_FALSE);
|
|
138
|
+
return payload;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
void xt_gui_dispatch_key(XtGuiWindow *win, const char *type, const char *key, const char *code) {
|
|
142
|
+
if (win == NULL || !win->open) return;
|
|
143
|
+
xt_value payload = xt_gui_key_payload(type, key, code, false, false, false, false, false);
|
|
144
|
+
const xtgui::Node *node = win->document != nullptr ? win->document->focus() : nullptr;
|
|
145
|
+
if (node != nullptr) xt_gui_emit_dom_event(win, type, node, payload);
|
|
146
|
+
xt_gui_emit_payload(win, type, payload);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
namespace guidev {
|
|
150
|
+
|
|
151
|
+
void handle_event(const SDL_Event *event) {
|
|
152
|
+
if (event->type == SDL_EVENT_QUIT) {
|
|
153
|
+
g_quit = 1;
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (event->type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) {
|
|
157
|
+
XtGuiWindow *win = xt_gui_find_by_window_id(event->window.windowID);
|
|
158
|
+
if (win != NULL && win->open) xt_gui_quit_window(win);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
if (event->type == SDL_EVENT_WINDOW_RESIZED) {
|
|
162
|
+
XtGuiWindow *win = xt_gui_find_by_window_id(event->window.windowID);
|
|
163
|
+
if (win == NULL || !win->open) return;
|
|
164
|
+
win->width = event->window.data1;
|
|
165
|
+
win->height = event->window.data2;
|
|
166
|
+
if (win->document != NULL) win->document->restyle((float)win->width, (float)win->height);
|
|
167
|
+
win->geometry.dirty = 1;
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (event->type == SDL_EVENT_MOUSE_MOTION) {
|
|
172
|
+
XtGuiWindow *win = xt_gui_find_by_window_id(event->motion.windowID);
|
|
173
|
+
xt_gui_dispatch_pointer(win, "mousemove", event->motion.x, event->motion.y, -1, 0);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
|
|
177
|
+
XtGuiWindow *win = xt_gui_find_by_window_id(event->button.windowID);
|
|
178
|
+
/* SDL numbers buttons 1/2/3 (left/middle/right); DOM uses 0/1/2. */
|
|
179
|
+
xt_gui_dispatch_pointer(win, "mousedown", event->button.x, event->button.y,
|
|
180
|
+
(int)event->button.button - 1, event->button.clicks);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (event->type == SDL_EVENT_MOUSE_BUTTON_UP) {
|
|
184
|
+
XtGuiWindow *win = xt_gui_find_by_window_id(event->button.windowID);
|
|
185
|
+
if (win == NULL || !win->open) return;
|
|
186
|
+
int button = (int)event->button.button - 1;
|
|
187
|
+
xt_gui_dispatch_pointer(win, "mouseup", event->button.x, event->button.y, button,
|
|
188
|
+
event->button.clicks);
|
|
189
|
+
if (button == 0) {
|
|
190
|
+
xt_gui_dispatch_pointer(win, "click", event->button.x, event->button.y, button,
|
|
191
|
+
event->button.clicks);
|
|
192
|
+
}
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (event->type == SDL_EVENT_MOUSE_WHEEL) {
|
|
196
|
+
XtGuiWindow *win = xt_gui_find_by_window_id(event->wheel.windowID);
|
|
197
|
+
/* DOM `deltaY` grows downwards; SDL's grows away from the user. */
|
|
198
|
+
xt_gui_dispatch_wheel(win, event->wheel.mouse_x, event->wheel.mouse_y, event->wheel.x,
|
|
199
|
+
-event->wheel.y);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (event->type == SDL_EVENT_KEY_DOWN || event->type == SDL_EVENT_KEY_UP) {
|
|
203
|
+
XtGuiWindow *win = xt_gui_find_by_window_id(event->key.windowID);
|
|
204
|
+
if (win == NULL || !win->open) return;
|
|
205
|
+
const char *type = event->type == SDL_EVENT_KEY_DOWN ? "keydown" : "keyup";
|
|
206
|
+
xt_gui_emit_payload(win, type,
|
|
207
|
+
xt_gui_key_payload(type, SDL_GetKeyName(event->key.key),
|
|
208
|
+
SDL_GetScancodeName(event->key.scancode),
|
|
209
|
+
event->key.repeat, (event->key.mod & SDL_KMOD_CTRL) != 0,
|
|
210
|
+
(event->key.mod & SDL_KMOD_SHIFT) != 0,
|
|
211
|
+
(event->key.mod & SDL_KMOD_ALT) != 0,
|
|
212
|
+
(event->key.mod & SDL_KMOD_GUI) != 0));
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
} // namespace guidev
|
|
218
|
+
|
|
219
|
+
/* -- rendering ------------------------------------------------------------ */
|
|
220
|
+
|
|
221
|
+
void xt_gui_run_animation_frames(XtGuiWindow *win, double timestamp_ms) {
|
|
222
|
+
if (win == NULL || win->animation_frames.empty()) return;
|
|
223
|
+
/* Swap the queue out first: a callback that calls requestAnimationFrame
|
|
224
|
+
* again schedules for the *next* frame, not this one. */
|
|
225
|
+
std::vector<XtGuiAnimationFrame> frames;
|
|
226
|
+
frames.swap(win->animation_frames);
|
|
227
|
+
for (const XtGuiAnimationFrame &frame : frames) {
|
|
228
|
+
if (!win->open) break;
|
|
229
|
+
xt_value arg = xt_number(timestamp_ms);
|
|
230
|
+
xt_call_with_this(frame.fn, win->object, 1, &arg);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
void xt_gui_render_window(XtGuiWindow *win) {
|
|
235
|
+
if (win == NULL || !win->open || win->window == NULL || g_device == NULL) return;
|
|
236
|
+
float viewport_width = 0;
|
|
237
|
+
float viewport_height = 0;
|
|
238
|
+
xt_gui_window_viewport(win, &viewport_width, &viewport_height);
|
|
239
|
+
|
|
240
|
+
/* Drive CSS transitions. */
|
|
241
|
+
double now = (double)SDL_GetTicks();
|
|
242
|
+
double delta = win->last_frame_ms > 0.0 ? now - win->last_frame_ms : 0.0;
|
|
243
|
+
win->last_frame_ms = now;
|
|
244
|
+
/* Animation-frame callbacks run before layout, so any DOM mutation they make
|
|
245
|
+
* is picked up by this same frame. */
|
|
246
|
+
xt_gui_run_animation_frames(win, now);
|
|
247
|
+
if (win->document != nullptr && win->document->advance(delta)) win->geometry.dirty = 1;
|
|
248
|
+
|
|
249
|
+
/* A DOM mutation from a handler invalidates the tree: restyle/relayout
|
|
250
|
+
* before (re)building the geometry. */
|
|
251
|
+
xt_gui_flush_dom(win);
|
|
252
|
+
|
|
253
|
+
/* Rebuild the geometry only when the document or viewport changed. */
|
|
254
|
+
bool can_paint = xt_gui_renderer_ensure(g_device, win->window);
|
|
255
|
+
if (can_paint && win->geometry.dirty && win->document != nullptr) {
|
|
256
|
+
xtgui::DisplayList list;
|
|
257
|
+
xtgui::xt_paint_build(win->document->layout().root(), list);
|
|
258
|
+
xt_gui_geometry_upload(g_device, &win->geometry, list);
|
|
259
|
+
float density = SDL_GetWindowPixelDensity(win->window);
|
|
260
|
+
xt_gui_text_upload(g_device, &win->text_geometry, list, density > 0.0f ? density : 1.0f);
|
|
261
|
+
xt_gui_image_upload(g_device, &win->image_geometry, list);
|
|
262
|
+
win->geometry.dirty = 0;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
SDL_GPUCommandBuffer *cmd = SDL_AcquireGPUCommandBuffer(g_device);
|
|
266
|
+
if (cmd == NULL) return;
|
|
267
|
+
SDL_GPUTexture *swapchain = NULL;
|
|
268
|
+
SDL_AcquireGPUSwapchainTexture(cmd, win->window, &swapchain, NULL, NULL);
|
|
269
|
+
bool firstFrame = false;
|
|
270
|
+
if (swapchain != NULL) {
|
|
271
|
+
SDL_GPUColorTargetInfo target;
|
|
272
|
+
memset(&target, 0, sizeof(target));
|
|
273
|
+
target.texture = swapchain;
|
|
274
|
+
target.clear_color.r = win->background[0];
|
|
275
|
+
target.clear_color.g = win->background[1];
|
|
276
|
+
target.clear_color.b = win->background[2];
|
|
277
|
+
target.clear_color.a = win->background[3];
|
|
278
|
+
target.load_op = SDL_GPU_LOADOP_CLEAR;
|
|
279
|
+
target.store_op = SDL_GPU_STOREOP_STORE;
|
|
280
|
+
SDL_GPURenderPass *pass = SDL_BeginGPURenderPass(cmd, &target, 1, NULL);
|
|
281
|
+
if (can_paint) {
|
|
282
|
+
xt_gui_renderer_draw(cmd, pass, &win->geometry, viewport_width, viewport_height);
|
|
283
|
+
xt_gui_text_draw(cmd, pass, &win->text_geometry, viewport_width, viewport_height);
|
|
284
|
+
xt_gui_image_draw(cmd, pass, &win->image_geometry, viewport_width, viewport_height);
|
|
285
|
+
}
|
|
286
|
+
SDL_EndGPURenderPass(pass);
|
|
287
|
+
firstFrame = !win->ready;
|
|
288
|
+
win->ready = 1;
|
|
289
|
+
}
|
|
290
|
+
SDL_SubmitGPUCommandBuffer(cmd);
|
|
291
|
+
/* The first presented frame marks the window ready. Emitting after the
|
|
292
|
+
* submit lets a `ready` handler safely close/destroy the window. */
|
|
293
|
+
if (firstFrame) xt_gui_emit(win, "ready");
|
|
294
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* xbintsc GUI engine — process-level state shared by `gui.cpp` (lifecycle and
|
|
3
|
+
* the main loop) and `gui_events.cpp` (input dispatch and rendering).
|
|
4
|
+
*
|
|
5
|
+
* One SDL_GPU device is shared by every window. The state used to be a set of
|
|
6
|
+
* file-statics in `gui.cpp`; it now has external linkage inside `guidev` so the
|
|
7
|
+
* event/render unit can reach it.
|
|
8
|
+
*/
|
|
9
|
+
#ifndef XT_GUI_INTERNAL_H
|
|
10
|
+
#define XT_GUI_INTERNAL_H
|
|
11
|
+
|
|
12
|
+
#include "gui_engine.h"
|
|
13
|
+
|
|
14
|
+
#define XT_GUI_MAX_WINDOWS 64
|
|
15
|
+
|
|
16
|
+
namespace guidev {
|
|
17
|
+
|
|
18
|
+
extern SDL_GPUDevice *g_device;
|
|
19
|
+
extern int g_sdl_initialized;
|
|
20
|
+
extern int g_quit;
|
|
21
|
+
extern XtGuiWindow g_windows[XT_GUI_MAX_WINDOWS];
|
|
22
|
+
extern int g_window_count;
|
|
23
|
+
|
|
24
|
+
/** Translate one SDL event into engine callbacks (defined in gui_events.cpp). */
|
|
25
|
+
void handle_event(const SDL_Event *event);
|
|
26
|
+
|
|
27
|
+
} // namespace guidev
|
|
28
|
+
|
|
29
|
+
#endif /* XT_GUI_INTERNAL_H */
|