feat: new Window Server helpers and app migrations
This commit is contained in:
+14
-18
@@ -147,27 +147,23 @@ Events are delivered via `win_poll()` into a `WinEvent` struct:
|
||||
|
||||
### Drawing Helpers
|
||||
|
||||
Standalone apps typically define local pixel-drawing helpers since they work with raw `uint32_t*` buffers:
|
||||
For new standalone apps, prefer the shared helpers in `#include <gui/standalone.hpp>`. It provides:
|
||||
|
||||
- `gui::WsWindow` for `win_create()` / `win_poll()` / `win_resize()` / `win_present()`
|
||||
- `gui::Canvas` for drawing into the window buffer
|
||||
- immediate-mode helpers like `draw_text()`, `draw_button()`, and `fill_circle()`
|
||||
|
||||
Older apps in the tree still define local `px_*` helpers, but new code should not need to.
|
||||
|
||||
```cpp
|
||||
static void px_fill(uint32_t* px, int bw, int bh,
|
||||
int x, int y, int w, int h, uint32_t color) {
|
||||
for (int row = y; row < y + h && row < bh; row++)
|
||||
for (int col = x; col < x + w && col < bw; col++)
|
||||
px[row * bw + col] = color;
|
||||
}
|
||||
gui::WsWindow win;
|
||||
win.create("My App", 400, 300);
|
||||
|
||||
static void px_hline(uint32_t* px, int bw, int bh,
|
||||
int x, int y, int w, uint32_t color) {
|
||||
for (int col = x; col < x + w && col < bw; col++)
|
||||
if (y >= 0 && y < bh) px[y * bw + col] = color;
|
||||
}
|
||||
|
||||
static void px_text(uint32_t* px, int bw, int bh,
|
||||
int x, int y, const char* text, Color c, int size) {
|
||||
if (g_font)
|
||||
g_font->draw_to_buffer(px, bw, bh, x, y, text, c, size);
|
||||
}
|
||||
gui::Canvas c = win.canvas();
|
||||
c.fill(gui::colors::WHITE);
|
||||
draw_text(c, g_font, 20, 30, "Hello", gui::colors::TEXT_COLOR, 18);
|
||||
draw_button(c, g_font, 20, 60, 96, 28, "OK",
|
||||
gui::colors::ACCENT, gui::colors::WHITE, 6, 16);
|
||||
```
|
||||
|
||||
### Rounded Rectangles
|
||||
|
||||
@@ -207,11 +207,12 @@ struct WinCreateResult {
|
||||
**`WinEvent` struct:**
|
||||
```cpp
|
||||
struct WinEvent {
|
||||
int type; // 0=Key, 1=Mouse, 2=Resize, 3=Close
|
||||
int type; // 0=Key, 1=Mouse, 2=Resize, 3=Close, 4=Scale
|
||||
union {
|
||||
struct { uint8_t scancode; char ascii; bool pressed, shift, ctrl, alt; } key;
|
||||
struct { int x, y; uint8_t buttons, prev_buttons; int32_t scroll; } mouse;
|
||||
struct { int w, h; } resize;
|
||||
struct { int scale; } scale;
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* standalone.hpp
|
||||
* MontaukOS helpers for standalone Window Server apps
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <montauk/syscall.h>
|
||||
#include "gui/canvas.hpp"
|
||||
#include "gui/svg.hpp"
|
||||
#include "gui/truetype.hpp"
|
||||
|
||||
namespace gui {
|
||||
|
||||
struct WsWindow {
|
||||
int id;
|
||||
uint32_t* pixels;
|
||||
int width;
|
||||
int height;
|
||||
int scale_factor;
|
||||
bool closed;
|
||||
|
||||
WsWindow()
|
||||
: id(-1), pixels(nullptr), width(0), height(0), scale_factor(1), closed(false) {}
|
||||
|
||||
bool create(const char* title, int w, int h) {
|
||||
Montauk::WinCreateResult wres;
|
||||
if (montauk::win_create(title, w, h, &wres) < 0 || wres.id < 0)
|
||||
return false;
|
||||
|
||||
id = wres.id;
|
||||
pixels = (uint32_t*)(uintptr_t)wres.pixelVa;
|
||||
width = w;
|
||||
height = h;
|
||||
scale_factor = montauk::win_getscale();
|
||||
closed = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
int poll(Montauk::WinEvent* ev) {
|
||||
if (id < 0 || closed) return -1;
|
||||
|
||||
int r = montauk::win_poll(id, ev);
|
||||
if (r <= 0) return r;
|
||||
|
||||
if (ev->type == 2) {
|
||||
width = ev->resize.w;
|
||||
height = ev->resize.h;
|
||||
pixels = (uint32_t*)(uintptr_t)montauk::win_resize(id, width, height);
|
||||
} else if (ev->type == 3) {
|
||||
closed = true;
|
||||
} else if (ev->type == 4) {
|
||||
scale_factor = ev->scale.scale;
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
Canvas canvas() const {
|
||||
return Canvas(pixels, width, height);
|
||||
}
|
||||
|
||||
void present() const {
|
||||
if (id >= 0)
|
||||
montauk::win_present(id);
|
||||
}
|
||||
|
||||
void set_cursor(int cursor) const {
|
||||
if (id >= 0)
|
||||
montauk::win_setcursor(id, cursor);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
if (id >= 0)
|
||||
montauk::win_destroy(id);
|
||||
id = -1;
|
||||
pixels = nullptr;
|
||||
width = 0;
|
||||
height = 0;
|
||||
closed = true;
|
||||
}
|
||||
};
|
||||
|
||||
inline int text_width(TrueTypeFont* font, const char* text, int size) {
|
||||
if (font && font->valid)
|
||||
return font->measure_text(text, size);
|
||||
int len = 0;
|
||||
while (text && text[len]) len++;
|
||||
return len * FONT_WIDTH;
|
||||
}
|
||||
|
||||
inline int text_height(TrueTypeFont* font, int size) {
|
||||
if (font && font->valid) {
|
||||
GlyphCache* cache = font->get_cache(size);
|
||||
if (cache)
|
||||
return cache->ascent - cache->descent;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
inline void draw_text(Canvas& c, TrueTypeFont* font, int x, int y,
|
||||
const char* text, Color color, int size) {
|
||||
if (!text || !text[0]) return;
|
||||
if (font && font->valid)
|
||||
font->draw_to_buffer(c.pixels, c.w, c.h, x, y, text, color, size);
|
||||
}
|
||||
|
||||
inline void fill_circle(Canvas& c, int cx, int cy, int r, Color color) {
|
||||
if (r <= 0) return;
|
||||
for (int dy = -r; dy <= r; dy++) {
|
||||
for (int dx = -r; dx <= r; dx++) {
|
||||
if (dx * dx + dy * dy <= r * r)
|
||||
c.put_pixel(cx + dx, cy + dy, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void draw_button(Canvas& c, TrueTypeFont* font, int x, int y, int w, int h,
|
||||
const char* label, Color bg, Color fg, int radius,
|
||||
int size = 16) {
|
||||
c.fill_rounded_rect(x, y, w, h, radius, bg);
|
||||
int tw = text_width(font, label, size);
|
||||
int th = text_height(font, size);
|
||||
draw_text(c, font, x + (w - tw) / 2, y + (h - th) / 2, label, fg, size);
|
||||
}
|
||||
|
||||
inline void draw_icon(Canvas& c, int x, int y, const SvgIcon& icon) {
|
||||
c.icon(x, y, icon);
|
||||
}
|
||||
|
||||
} // namespace gui
|
||||
Reference in New Issue
Block a user