feat: screenshot app improvement, WIndow Server supports full-screen overlay, Disks app UI improvements
This commit is contained in:
@@ -240,93 +240,103 @@ void gui::desktop_compose(DesktopState* ds) {
|
||||
}
|
||||
}
|
||||
|
||||
// Draw panel on top
|
||||
desktop_draw_panel(ds);
|
||||
|
||||
// Draw app menu if open
|
||||
if (ds->app_menu_open) {
|
||||
desktop_draw_app_menu(ds);
|
||||
bool topFullscreen = false;
|
||||
for (int i = ds->window_count - 1; i >= 0; i--) {
|
||||
if (ds->windows[i].state == WIN_MINIMIZED || ds->windows[i].state == WIN_CLOSED)
|
||||
continue;
|
||||
topFullscreen = desktop_window_fullscreen(&ds->windows[i]);
|
||||
break;
|
||||
}
|
||||
|
||||
// Draw network popup if open
|
||||
if (ds->net_popup_open) {
|
||||
desktop_draw_net_popup(ds);
|
||||
}
|
||||
if (!topFullscreen) {
|
||||
// Draw panel on top
|
||||
desktop_draw_panel(ds);
|
||||
|
||||
// Draw volume popup if open
|
||||
if (ds->vol_popup_open) {
|
||||
desktop_draw_vol_popup(ds);
|
||||
}
|
||||
|
||||
// Draw right-click context menu if open
|
||||
if (ds->ctx_menu_open) {
|
||||
static constexpr int CTX_MENU_W = 180;
|
||||
static constexpr int CTX_ITEM_H = 36;
|
||||
static constexpr int CTX_ITEM_COUNT = 6;
|
||||
int cmx = ds->ctx_menu_x;
|
||||
int cmy = ds->ctx_menu_y;
|
||||
int cmh = CTX_ITEM_H * CTX_ITEM_COUNT + 8;
|
||||
|
||||
// Clamp to screen
|
||||
if (cmx + CTX_MENU_W > sw) cmx = sw - CTX_MENU_W;
|
||||
if (cmy + cmh > sh) cmy = sh - cmh;
|
||||
|
||||
ensure_filemanager_icons_loaded(ds);
|
||||
|
||||
draw_shadow(fb, cmx, cmy, CTX_MENU_W, cmh, 4, colors::SHADOW);
|
||||
fill_rounded_rect(fb, cmx, cmy, CTX_MENU_W, cmh, 8, colors::MENU_BG);
|
||||
draw_rect(fb, cmx, cmy, CTX_MENU_W, cmh, colors::BORDER);
|
||||
|
||||
struct CtxItem { const char* label; SvgIcon* icon; };
|
||||
CtxItem ctx_items[CTX_ITEM_COUNT] = {
|
||||
{ "Terminal", &ds->icon_terminal },
|
||||
{ "Files", &ds->icon_filemanager },
|
||||
{ "System Configuration", &ds->icon_system_configuration_menu },
|
||||
{ "Sleep", &ds->icon_sleep },
|
||||
{ "Reboot", &ds->icon_reboot },
|
||||
{ "Shutdown", &ds->icon_shutdown },
|
||||
};
|
||||
|
||||
int mmx = ds->mouse.x;
|
||||
int mmy = ds->mouse.y;
|
||||
|
||||
for (int i = 0; i < CTX_ITEM_COUNT; i++) {
|
||||
int iy = cmy + 4 + i * CTX_ITEM_H;
|
||||
Rect item_r = {cmx + 4, iy, CTX_MENU_W - 8, CTX_ITEM_H};
|
||||
|
||||
if (item_r.contains(mmx, mmy)) {
|
||||
fill_rounded_rect(fb, item_r.x, item_r.y, item_r.w, item_r.h, 4, colors::MENU_HOVER);
|
||||
}
|
||||
|
||||
int icon_x = item_r.x + 8;
|
||||
int icon_y = item_r.y + (CTX_ITEM_H - 20) / 2;
|
||||
if (ctx_items[i].icon && ctx_items[i].icon->pixels) {
|
||||
fb.blit_alpha(icon_x, icon_y, ctx_items[i].icon->width, ctx_items[i].icon->height, ctx_items[i].icon->pixels);
|
||||
}
|
||||
|
||||
int tx = icon_x + 28;
|
||||
int ty = item_r.y + (CTX_ITEM_H - system_font_height()) / 2;
|
||||
draw_text(fb, tx, ty, ctx_items[i].label, colors::TEXT_COLOR);
|
||||
// Draw app menu if open
|
||||
if (ds->app_menu_open) {
|
||||
desktop_draw_app_menu(ds);
|
||||
}
|
||||
}
|
||||
|
||||
if (ds->launcher_open) {
|
||||
desktop_draw_launcher(ds);
|
||||
}
|
||||
// Draw network popup if open
|
||||
if (ds->net_popup_open) {
|
||||
desktop_draw_net_popup(ds);
|
||||
}
|
||||
|
||||
// Draw snap preview overlay while dragging to screen edge
|
||||
for (int i = 0; i < ds->window_count; i++) {
|
||||
Window* win = &ds->windows[i];
|
||||
if (win->dragging) {
|
||||
int dmx = ds->mouse.x;
|
||||
if (dmx <= 0) {
|
||||
fb.fill_rect_alpha(0, PANEL_HEIGHT, sw / 2, sh - PANEL_HEIGHT,
|
||||
Color::from_rgba(0x33, 0x77, 0xCC, 0x30));
|
||||
} else if (dmx >= sw - 1) {
|
||||
fb.fill_rect_alpha(sw / 2, PANEL_HEIGHT, sw / 2, sh - PANEL_HEIGHT,
|
||||
Color::from_rgba(0x33, 0x77, 0xCC, 0x30));
|
||||
// Draw volume popup if open
|
||||
if (ds->vol_popup_open) {
|
||||
desktop_draw_vol_popup(ds);
|
||||
}
|
||||
|
||||
// Draw right-click context menu if open
|
||||
if (ds->ctx_menu_open) {
|
||||
static constexpr int CTX_MENU_W = 180;
|
||||
static constexpr int CTX_ITEM_H = 36;
|
||||
static constexpr int CTX_ITEM_COUNT = 6;
|
||||
int cmx = ds->ctx_menu_x;
|
||||
int cmy = ds->ctx_menu_y;
|
||||
int cmh = CTX_ITEM_H * CTX_ITEM_COUNT + 8;
|
||||
|
||||
// Clamp to screen
|
||||
if (cmx + CTX_MENU_W > sw) cmx = sw - CTX_MENU_W;
|
||||
if (cmy + cmh > sh) cmy = sh - cmh;
|
||||
|
||||
ensure_filemanager_icons_loaded(ds);
|
||||
|
||||
draw_shadow(fb, cmx, cmy, CTX_MENU_W, cmh, 4, colors::SHADOW);
|
||||
fill_rounded_rect(fb, cmx, cmy, CTX_MENU_W, cmh, 8, colors::MENU_BG);
|
||||
draw_rect(fb, cmx, cmy, CTX_MENU_W, cmh, colors::BORDER);
|
||||
|
||||
struct CtxItem { const char* label; SvgIcon* icon; };
|
||||
CtxItem ctx_items[CTX_ITEM_COUNT] = {
|
||||
{ "Terminal", &ds->icon_terminal },
|
||||
{ "Files", &ds->icon_filemanager },
|
||||
{ "System Configuration", &ds->icon_system_configuration_menu },
|
||||
{ "Sleep", &ds->icon_sleep },
|
||||
{ "Reboot", &ds->icon_reboot },
|
||||
{ "Shutdown", &ds->icon_shutdown },
|
||||
};
|
||||
|
||||
int mmx = ds->mouse.x;
|
||||
int mmy = ds->mouse.y;
|
||||
|
||||
for (int i = 0; i < CTX_ITEM_COUNT; i++) {
|
||||
int iy = cmy + 4 + i * CTX_ITEM_H;
|
||||
Rect item_r = {cmx + 4, iy, CTX_MENU_W - 8, CTX_ITEM_H};
|
||||
|
||||
if (item_r.contains(mmx, mmy)) {
|
||||
fill_rounded_rect(fb, item_r.x, item_r.y, item_r.w, item_r.h, 4, colors::MENU_HOVER);
|
||||
}
|
||||
|
||||
int icon_x = item_r.x + 8;
|
||||
int icon_y = item_r.y + (CTX_ITEM_H - 20) / 2;
|
||||
if (ctx_items[i].icon && ctx_items[i].icon->pixels) {
|
||||
fb.blit_alpha(icon_x, icon_y, ctx_items[i].icon->width, ctx_items[i].icon->height, ctx_items[i].icon->pixels);
|
||||
}
|
||||
|
||||
int tx = icon_x + 28;
|
||||
int ty = item_r.y + (CTX_ITEM_H - system_font_height()) / 2;
|
||||
draw_text(fb, tx, ty, ctx_items[i].label, colors::TEXT_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
if (ds->launcher_open) {
|
||||
desktop_draw_launcher(ds);
|
||||
}
|
||||
|
||||
// Draw snap preview overlay while dragging to screen edge
|
||||
for (int i = 0; i < ds->window_count; i++) {
|
||||
Window* win = &ds->windows[i];
|
||||
if (win->dragging) {
|
||||
int dmx = ds->mouse.x;
|
||||
if (dmx <= 0) {
|
||||
fb.fill_rect_alpha(0, PANEL_HEIGHT, sw / 2, sh - PANEL_HEIGHT,
|
||||
Color::from_rgba(0x33, 0x77, 0xCC, 0x30));
|
||||
} else if (dmx >= sw - 1) {
|
||||
fb.fill_rect_alpha(sw / 2, PANEL_HEIGHT, sw / 2, sh - PANEL_HEIGHT,
|
||||
Color::from_rgba(0x33, 0x77, 0xCC, 0x30));
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +349,8 @@ void gui::desktop_compose(DesktopState* ds) {
|
||||
cur_style = cursor_for_edge(win->resize_edge);
|
||||
break;
|
||||
}
|
||||
if (win->state == WIN_MINIMIZED || win->state == WIN_CLOSED || win->state == WIN_MAXIMIZED)
|
||||
if (win->state == WIN_MINIMIZED || win->state == WIN_CLOSED ||
|
||||
win->state == WIN_MAXIMIZED || desktop_window_fullscreen(win))
|
||||
continue;
|
||||
if (win->frame.contains(ds->mouse.x, ds->mouse.y)) {
|
||||
ResizeEdge edge = hit_test_resize_edge(win->frame, ds->mouse.x, ds->mouse.y);
|
||||
@@ -354,7 +365,7 @@ void gui::desktop_compose(DesktopState* ds) {
|
||||
if (cur_style == CURSOR_ARROW && ds->focused_window >= 0) {
|
||||
Window* fwin = &ds->windows[ds->focused_window];
|
||||
if (fwin->external && fwin->ext_cursor > 0) {
|
||||
Rect cr = fwin->content_rect();
|
||||
Rect cr = desktop_content_rect(fwin);
|
||||
if (cr.contains(ds->mouse.x, ds->mouse.y)) {
|
||||
if (fwin->ext_cursor == 1) cur_style = CURSOR_RESIZE_H;
|
||||
else if (fwin->ext_cursor == 2) cur_style = CURSOR_RESIZE_V;
|
||||
|
||||
@@ -112,6 +112,16 @@ inline int menu_add_external(const char* label, const char* binary, SvgIcon* ico
|
||||
// Forward Declarations (internal functions)
|
||||
// ============================================================================
|
||||
|
||||
inline bool desktop_window_fullscreen(const gui::Window* win) {
|
||||
return win && win->external && (win->ext_flags & Montauk::WIN_FLAG_FULLSCREEN);
|
||||
}
|
||||
|
||||
inline gui::Rect desktop_content_rect(const gui::Window* win) {
|
||||
return desktop_window_fullscreen(win)
|
||||
? win->frame
|
||||
: win->content_rect();
|
||||
}
|
||||
|
||||
// window.cpp
|
||||
gui::ResizeEdge hit_test_resize_edge(const gui::Rect& f, int mx, int my);
|
||||
gui::CursorStyle cursor_for_edge(gui::ResizeEdge edge);
|
||||
|
||||
+156
-87
@@ -94,6 +94,47 @@ static void handle_lock_keyboard(DesktopState* ds, const Montauk::KeyEvent& key)
|
||||
}
|
||||
}
|
||||
|
||||
static void forward_external_mouse(gui::Window* win,
|
||||
const gui::MouseEvent& ev,
|
||||
int mx,
|
||||
int my,
|
||||
uint8_t buttons,
|
||||
uint8_t prev) {
|
||||
gui::Rect cr = desktop_content_rect(win);
|
||||
Montauk::WinEvent wev;
|
||||
montauk::memset(&wev, 0, sizeof(wev));
|
||||
wev.type = 1; // mouse
|
||||
wev.mouse.x = mx - cr.x;
|
||||
wev.mouse.y = my - cr.y;
|
||||
wev.mouse.scroll = ev.scroll;
|
||||
wev.mouse.buttons = buttons;
|
||||
wev.mouse.prev_buttons = prev;
|
||||
montauk::win_sendevent(win->ext_win_id, &wev);
|
||||
}
|
||||
|
||||
static bool route_fullscreen_external_mouse(gui::DesktopState* ds,
|
||||
const gui::MouseEvent& ev,
|
||||
int mx,
|
||||
int my,
|
||||
uint8_t buttons,
|
||||
uint8_t prev) {
|
||||
for (int i = ds->window_count - 1; i >= 0; i--) {
|
||||
gui::Window* win = &ds->windows[i];
|
||||
if (win->state == gui::WIN_MINIMIZED || win->state == gui::WIN_CLOSED)
|
||||
continue;
|
||||
if (!desktop_window_fullscreen(win))
|
||||
return false;
|
||||
|
||||
if (i != ds->window_count - 1) {
|
||||
gui::desktop_raise_window(ds, i);
|
||||
win = &ds->windows[ds->window_count - 1];
|
||||
}
|
||||
forward_external_mouse(win, ev, mx, my, buttons, prev);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Desktop Mouse Handling
|
||||
// ============================================================================
|
||||
@@ -104,11 +145,6 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ds->launcher_open) {
|
||||
desktop_handle_launcher_mouse(ds);
|
||||
return;
|
||||
}
|
||||
|
||||
int mx = ds->mouse.x;
|
||||
int my = ds->mouse.y;
|
||||
uint8_t buttons = ds->mouse.buttons;
|
||||
@@ -125,6 +161,19 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
ev.prev_buttons = prev;
|
||||
ev.scroll = ds->mouse.scrollDelta;
|
||||
|
||||
if (route_fullscreen_external_mouse(ds, ev, mx, my, buttons, prev)) {
|
||||
ds->app_menu_open = false;
|
||||
ds->ctx_menu_open = false;
|
||||
ds->vol_popup_open = false;
|
||||
ds->net_popup_open = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ds->launcher_open) {
|
||||
desktop_handle_launcher_mouse(ds);
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle context menu clicks
|
||||
if (ds->ctx_menu_open) {
|
||||
if (left_pressed) {
|
||||
@@ -183,7 +232,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
win->frame = {0, PANEL_HEIGHT, ds->screen_w / 2, ds->screen_h - PANEL_HEIGHT};
|
||||
win->state = WIN_MAXIMIZED;
|
||||
if (!win->external) {
|
||||
Rect cr = win->content_rect();
|
||||
Rect cr = desktop_content_rect(win);
|
||||
if (cr.w != win->content_w || cr.h != win->content_h) {
|
||||
if (win->content) montauk::free(win->content);
|
||||
win->content_w = cr.w;
|
||||
@@ -192,7 +241,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
montauk::memset(win->content, 0xFF, cr.w * cr.h * 4);
|
||||
}
|
||||
} else {
|
||||
Rect cr = win->content_rect();
|
||||
Rect cr = desktop_content_rect(win);
|
||||
Montauk::WinEvent rev;
|
||||
montauk::memset(&rev, 0, sizeof(rev));
|
||||
rev.type = 2;
|
||||
@@ -205,7 +254,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
win->frame = {ds->screen_w / 2, PANEL_HEIGHT, ds->screen_w / 2, ds->screen_h - PANEL_HEIGHT};
|
||||
win->state = WIN_MAXIMIZED;
|
||||
if (!win->external) {
|
||||
Rect cr = win->content_rect();
|
||||
Rect cr = desktop_content_rect(win);
|
||||
if (cr.w != win->content_w || cr.h != win->content_h) {
|
||||
if (win->content) montauk::free(win->content);
|
||||
win->content_w = cr.w;
|
||||
@@ -214,7 +263,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
montauk::memset(win->content, 0xFF, cr.w * cr.h * 4);
|
||||
}
|
||||
} else {
|
||||
Rect cr = win->content_rect();
|
||||
Rect cr = desktop_content_rect(win);
|
||||
Montauk::WinEvent rev;
|
||||
montauk::memset(&rev, 0, sizeof(rev));
|
||||
rev.type = 2;
|
||||
@@ -271,7 +320,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
win->resizing = false;
|
||||
// Reallocate content buffer if dimensions changed (skip for external)
|
||||
if (!win->external) {
|
||||
Rect cr = win->content_rect();
|
||||
Rect cr = desktop_content_rect(win);
|
||||
if (cr.w != win->content_w || cr.h != win->content_h) {
|
||||
if (win->content) montauk::free(win->content);
|
||||
win->content_w = cr.w;
|
||||
@@ -281,7 +330,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
}
|
||||
win->dirty = true;
|
||||
} else {
|
||||
Rect cr = win->content_rect();
|
||||
Rect cr = desktop_content_rect(win);
|
||||
Montauk::WinEvent rev;
|
||||
montauk::memset(&rev, 0, sizeof(rev));
|
||||
rev.type = 2;
|
||||
@@ -505,92 +554,94 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
Window* win = &ds->windows[i];
|
||||
if (win->state == WIN_MINIMIZED || win->state == WIN_CLOSED) continue;
|
||||
|
||||
// Check close button
|
||||
Rect close_r = win->close_btn_rect();
|
||||
if (close_r.contains(mx, my)) {
|
||||
desktop_close_window(ds, i);
|
||||
return;
|
||||
}
|
||||
if (!desktop_window_fullscreen(win)) {
|
||||
// Check close button
|
||||
Rect close_r = win->close_btn_rect();
|
||||
if (close_r.contains(mx, my)) {
|
||||
desktop_close_window(ds, i);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check minimize button
|
||||
Rect min_r = win->min_btn_rect();
|
||||
if (min_r.contains(mx, my)) {
|
||||
win->state = WIN_MINIMIZED;
|
||||
if (ds->focused_window == i) {
|
||||
ds->focused_window = -1;
|
||||
for (int j = ds->window_count - 1; j >= 0; j--) {
|
||||
if (ds->windows[j].state == WIN_NORMAL || ds->windows[j].state == WIN_MAXIMIZED) {
|
||||
ds->focused_window = j;
|
||||
ds->windows[j].focused = true;
|
||||
break;
|
||||
// Check minimize button
|
||||
Rect min_r = win->min_btn_rect();
|
||||
if (min_r.contains(mx, my)) {
|
||||
win->state = WIN_MINIMIZED;
|
||||
if (ds->focused_window == i) {
|
||||
ds->focused_window = -1;
|
||||
for (int j = ds->window_count - 1; j >= 0; j--) {
|
||||
if (ds->windows[j].state == WIN_NORMAL || ds->windows[j].state == WIN_MAXIMIZED) {
|
||||
ds->focused_window = j;
|
||||
ds->windows[j].focused = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check maximize button
|
||||
Rect max_r = win->max_btn_rect();
|
||||
if (max_r.contains(mx, my)) {
|
||||
if (win->state == WIN_MAXIMIZED) {
|
||||
win->frame = win->saved_frame;
|
||||
win->state = WIN_NORMAL;
|
||||
} else {
|
||||
win->saved_frame = win->frame;
|
||||
win->frame = {0, PANEL_HEIGHT, ds->screen_w, ds->screen_h - PANEL_HEIGHT};
|
||||
win->state = WIN_MAXIMIZED;
|
||||
}
|
||||
// Reallocate content buffer for local windows only
|
||||
if (!win->external) {
|
||||
Rect cr = win->content_rect();
|
||||
if (cr.w != win->content_w || cr.h != win->content_h) {
|
||||
if (win->content) montauk::free(win->content);
|
||||
win->content_w = cr.w;
|
||||
win->content_h = cr.h;
|
||||
win->content = (uint32_t*)montauk::alloc(cr.w * cr.h * 4);
|
||||
montauk::memset(win->content, 0xFF, cr.w * cr.h * 4);
|
||||
// Check maximize button
|
||||
Rect max_r = win->max_btn_rect();
|
||||
if (max_r.contains(mx, my)) {
|
||||
if (win->state == WIN_MAXIMIZED) {
|
||||
win->frame = win->saved_frame;
|
||||
win->state = WIN_NORMAL;
|
||||
} else {
|
||||
win->saved_frame = win->frame;
|
||||
win->frame = {0, PANEL_HEIGHT, ds->screen_w, ds->screen_h - PANEL_HEIGHT};
|
||||
win->state = WIN_MAXIMIZED;
|
||||
}
|
||||
} else {
|
||||
Rect cr = win->content_rect();
|
||||
Montauk::WinEvent rev;
|
||||
montauk::memset(&rev, 0, sizeof(rev));
|
||||
rev.type = 2;
|
||||
rev.resize.w = cr.w;
|
||||
rev.resize.h = cr.h;
|
||||
montauk::win_sendevent(win->ext_win_id, &rev);
|
||||
// Reallocate content buffer for local windows only
|
||||
if (!win->external) {
|
||||
Rect cr = desktop_content_rect(win);
|
||||
if (cr.w != win->content_w || cr.h != win->content_h) {
|
||||
if (win->content) montauk::free(win->content);
|
||||
win->content_w = cr.w;
|
||||
win->content_h = cr.h;
|
||||
win->content = (uint32_t*)montauk::alloc(cr.w * cr.h * 4);
|
||||
montauk::memset(win->content, 0xFF, cr.w * cr.h * 4);
|
||||
}
|
||||
} else {
|
||||
Rect cr = desktop_content_rect(win);
|
||||
Montauk::WinEvent rev;
|
||||
montauk::memset(&rev, 0, sizeof(rev));
|
||||
rev.type = 2;
|
||||
rev.resize.w = cr.w;
|
||||
rev.resize.h = cr.h;
|
||||
montauk::win_sendevent(win->ext_win_id, &rev);
|
||||
}
|
||||
desktop_raise_window(ds, i);
|
||||
return;
|
||||
}
|
||||
desktop_raise_window(ds, i);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check resize edges (before titlebar drag, so corner grabs work)
|
||||
if (win->state != WIN_MAXIMIZED) {
|
||||
ResizeEdge edge = hit_test_resize_edge(win->frame, mx, my);
|
||||
if (edge != RESIZE_NONE) {
|
||||
// Check resize edges (before titlebar drag, so corner grabs work)
|
||||
if (win->state != WIN_MAXIMIZED) {
|
||||
ResizeEdge edge = hit_test_resize_edge(win->frame, mx, my);
|
||||
if (edge != RESIZE_NONE) {
|
||||
desktop_raise_window(ds, i);
|
||||
int new_idx = ds->window_count - 1;
|
||||
ds->windows[new_idx].resizing = true;
|
||||
ds->windows[new_idx].resize_edge = edge;
|
||||
ds->windows[new_idx].resize_start_frame = ds->windows[new_idx].frame;
|
||||
ds->windows[new_idx].resize_start_mx = mx;
|
||||
ds->windows[new_idx].resize_start_my = my;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check titlebar (start drag)
|
||||
Rect tb = win->titlebar_rect();
|
||||
if (tb.contains(mx, my)) {
|
||||
desktop_raise_window(ds, i);
|
||||
int new_idx = ds->window_count - 1;
|
||||
ds->windows[new_idx].resizing = true;
|
||||
ds->windows[new_idx].resize_edge = edge;
|
||||
ds->windows[new_idx].resize_start_frame = ds->windows[new_idx].frame;
|
||||
ds->windows[new_idx].resize_start_mx = mx;
|
||||
ds->windows[new_idx].resize_start_my = my;
|
||||
ds->windows[new_idx].dragging = true;
|
||||
ds->windows[new_idx].drag_offset_x = mx - ds->windows[new_idx].frame.x;
|
||||
ds->windows[new_idx].drag_offset_y = my - ds->windows[new_idx].frame.y;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Check titlebar (start drag)
|
||||
Rect tb = win->titlebar_rect();
|
||||
if (tb.contains(mx, my)) {
|
||||
desktop_raise_window(ds, i);
|
||||
int new_idx = ds->window_count - 1;
|
||||
ds->windows[new_idx].dragging = true;
|
||||
ds->windows[new_idx].drag_offset_x = mx - ds->windows[new_idx].frame.x;
|
||||
ds->windows[new_idx].drag_offset_y = my - ds->windows[new_idx].frame.y;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check content area
|
||||
Rect cr = win->content_rect();
|
||||
Rect cr = desktop_content_rect(win);
|
||||
if (cr.contains(mx, my)) {
|
||||
desktop_raise_window(ds, i);
|
||||
int new_idx = ds->window_count - 1;
|
||||
@@ -630,7 +681,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
if (!left_pressed && ds->focused_window >= 0) {
|
||||
Window* win = &ds->windows[ds->focused_window];
|
||||
if (win->state != WIN_MINIMIZED && win->state != WIN_CLOSED) {
|
||||
Rect cr = win->content_rect();
|
||||
Rect cr = desktop_content_rect(win);
|
||||
// Forward if mouse is over content (hover/move) or button is held/released (drag continuity)
|
||||
if (cr.contains(mx, my) || left_held || left_released) {
|
||||
if (win->external) {
|
||||
@@ -655,7 +706,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
// Handle scroll events on focused window
|
||||
if (ev.scroll != 0 && ds->focused_window >= 0) {
|
||||
Window* win = &ds->windows[ds->focused_window];
|
||||
Rect cr = win->content_rect();
|
||||
Rect cr = desktop_content_rect(win);
|
||||
if (cr.contains(mx, my)) {
|
||||
if (win->external) {
|
||||
Montauk::WinEvent wev;
|
||||
@@ -696,12 +747,30 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
||||
}
|
||||
|
||||
void gui::desktop_handle_keyboard(DesktopState* ds, const Montauk::KeyEvent& key) {
|
||||
if (desktop_handle_launcher_keyboard(ds, key)) {
|
||||
if (ds->screen_locked) {
|
||||
handle_lock_keyboard(ds, key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ds->screen_locked) {
|
||||
handle_lock_keyboard(ds, key);
|
||||
for (int i = ds->window_count - 1; i >= 0; i--) {
|
||||
Window* win = &ds->windows[i];
|
||||
if (win->state == WIN_MINIMIZED || win->state == WIN_CLOSED)
|
||||
continue;
|
||||
if (!desktop_window_fullscreen(win))
|
||||
break;
|
||||
|
||||
Montauk::WinEvent ev;
|
||||
montauk::memset(&ev, 0, sizeof(ev));
|
||||
ev.type = 0; // key
|
||||
ev.key = key;
|
||||
montauk::win_sendevent(win->ext_win_id, &ev);
|
||||
ds->launcher_open = false;
|
||||
ds->app_menu_open = false;
|
||||
ds->ctx_menu_open = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (desktop_handle_launcher_keyboard(ds, key)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -419,6 +419,7 @@ bool desktop_poll_external_windows(DesktopState* ds) {
|
||||
if (ds->windows[i].external && ds->windows[i].ext_win_id == extId) {
|
||||
found = true;
|
||||
bool remapRequested = false;
|
||||
bool wasFullscreen = desktop_window_fullscreen(&ds->windows[i]);
|
||||
uint64_t currentVa = (uint64_t)(uintptr_t)ds->windows[i].content;
|
||||
if (ds->windows[i].content_w != extWins[e].width ||
|
||||
ds->windows[i].content_h != extWins[e].height) {
|
||||
@@ -436,6 +437,26 @@ bool desktop_poll_external_windows(DesktopState* ds) {
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (ds->windows[i].ext_flags != extWins[e].flags) {
|
||||
ds->windows[i].ext_flags = extWins[e].flags;
|
||||
bool isFullscreen = desktop_window_fullscreen(&ds->windows[i]);
|
||||
if (isFullscreen) {
|
||||
if (!wasFullscreen) ds->windows[i].saved_frame = ds->windows[i].frame;
|
||||
ds->windows[i].frame = {0, 0, ds->screen_w, ds->screen_h};
|
||||
ds->windows[i].state = WIN_NORMAL;
|
||||
} else if (wasFullscreen) {
|
||||
ds->windows[i].frame = ds->windows[i].saved_frame;
|
||||
ds->windows[i].state = WIN_NORMAL;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
if (desktop_window_fullscreen(&ds->windows[i]) &&
|
||||
(ds->windows[i].frame.x != 0 || ds->windows[i].frame.y != 0 ||
|
||||
ds->windows[i].frame.w != ds->screen_w || ds->windows[i].frame.h != ds->screen_h)) {
|
||||
ds->windows[i].frame = {0, 0, ds->screen_w, ds->screen_h};
|
||||
ds->windows[i].state = WIN_NORMAL;
|
||||
changed = true;
|
||||
}
|
||||
// Update dirty flag and cursor
|
||||
if (extWins[e].dirty) {
|
||||
ds->windows[i].dirty = true;
|
||||
@@ -524,6 +545,12 @@ bool desktop_poll_external_windows(DesktopState* ds) {
|
||||
win->app_data = nullptr;
|
||||
win->external = true;
|
||||
win->ext_win_id = extId;
|
||||
win->ext_cursor = extWins[e].cursor;
|
||||
win->ext_flags = extWins[e].flags;
|
||||
if (desktop_window_fullscreen(win)) {
|
||||
win->frame = {0, 0, ds->screen_w, ds->screen_h};
|
||||
win->state = WIN_NORMAL;
|
||||
}
|
||||
|
||||
// Unfocus previous window
|
||||
if (ds->focused_window >= 0 && ds->focused_window < ds->window_count) {
|
||||
|
||||
@@ -39,6 +39,8 @@ int gui::desktop_create_window(DesktopState* ds, const char* title, int x, int y
|
||||
win->app_data = nullptr;
|
||||
win->external = false;
|
||||
win->ext_win_id = -1;
|
||||
win->ext_cursor = 0;
|
||||
win->ext_flags = 0;
|
||||
|
||||
// Unfocus previous window
|
||||
if (ds->focused_window >= 0 && ds->focused_window < ds->window_count) {
|
||||
@@ -131,50 +133,53 @@ void gui::desktop_draw_window(DesktopState* ds, int idx) {
|
||||
int y = win->frame.y;
|
||||
int w = win->frame.w;
|
||||
int h = win->frame.h;
|
||||
bool fullscreen = desktop_window_fullscreen(win);
|
||||
|
||||
// Draw shadow
|
||||
if (ds->settings.show_shadows)
|
||||
draw_shadow(fb, x, y, w, h, SHADOW_SIZE, colors::SHADOW);
|
||||
if (!fullscreen) {
|
||||
// Draw shadow
|
||||
if (ds->settings.show_shadows)
|
||||
draw_shadow(fb, x, y, w, h, SHADOW_SIZE, colors::SHADOW);
|
||||
|
||||
// Draw window body
|
||||
fb.fill_rect(x, y, w, h, colors::WINDOW_BG);
|
||||
// Draw window body
|
||||
fb.fill_rect(x, y, w, h, colors::WINDOW_BG);
|
||||
|
||||
// Draw titlebar
|
||||
Color tb_bg = win->focused ? colors::TITLEBAR_BG : Color::from_rgb(0xE8, 0xE8, 0xE8);
|
||||
fb.fill_rect(x, y, w, TITLEBAR_HEIGHT, tb_bg);
|
||||
// Draw titlebar
|
||||
Color tb_bg = win->focused ? colors::TITLEBAR_BG : Color::from_rgb(0xE8, 0xE8, 0xE8);
|
||||
fb.fill_rect(x, y, w, TITLEBAR_HEIGHT, tb_bg);
|
||||
|
||||
// Draw border
|
||||
draw_rect(fb, x, y, w, h, colors::BORDER);
|
||||
// Titlebar bottom separator
|
||||
draw_hline(fb, x, y + TITLEBAR_HEIGHT - 1, w, colors::BORDER);
|
||||
// Draw border
|
||||
draw_rect(fb, x, y, w, h, colors::BORDER);
|
||||
// Titlebar bottom separator
|
||||
draw_hline(fb, x, y + TITLEBAR_HEIGHT - 1, w, colors::BORDER);
|
||||
|
||||
// Draw window buttons (macOS style: close, minimize, maximize)
|
||||
Rect close_r = win->close_btn_rect();
|
||||
Rect min_r = win->min_btn_rect();
|
||||
Rect max_r = win->max_btn_rect();
|
||||
// Draw window buttons (macOS style: close, minimize, maximize)
|
||||
Rect close_r = win->close_btn_rect();
|
||||
Rect min_r = win->min_btn_rect();
|
||||
Rect max_r = win->max_btn_rect();
|
||||
|
||||
fill_circle(fb, close_r.x + BTN_RADIUS, close_r.y + BTN_RADIUS, BTN_RADIUS, colors::CLOSE_BTN);
|
||||
fill_circle(fb, min_r.x + BTN_RADIUS, min_r.y + BTN_RADIUS, BTN_RADIUS, colors::MIN_BTN);
|
||||
fill_circle(fb, max_r.x + BTN_RADIUS, max_r.y + BTN_RADIUS, BTN_RADIUS, colors::MAX_BTN);
|
||||
fill_circle(fb, close_r.x + BTN_RADIUS, close_r.y + BTN_RADIUS, BTN_RADIUS, colors::CLOSE_BTN);
|
||||
fill_circle(fb, min_r.x + BTN_RADIUS, min_r.y + BTN_RADIUS, BTN_RADIUS, colors::MIN_BTN);
|
||||
fill_circle(fb, max_r.x + BTN_RADIUS, max_r.y + BTN_RADIUS, BTN_RADIUS, colors::MAX_BTN);
|
||||
|
||||
// Draw title text centered in titlebar (after buttons)
|
||||
int title_x = x + 12 + 44 + BTN_RADIUS * 2 + 12; // after buttons
|
||||
int title_y = y + (TITLEBAR_HEIGHT - system_font_height()) / 2;
|
||||
int title_w = text_width(win->title);
|
||||
// Center in remaining space
|
||||
int remaining_w = w - (title_x - x) - 12;
|
||||
if (remaining_w > title_w) {
|
||||
title_x += (remaining_w - title_w) / 2;
|
||||
}
|
||||
draw_text(fb, title_x, title_y, win->title, colors::TEXT_COLOR);
|
||||
// Draw title text centered in titlebar (after buttons)
|
||||
int title_x = x + 12 + 44 + BTN_RADIUS * 2 + 12; // after buttons
|
||||
int title_y = y + (TITLEBAR_HEIGHT - system_font_height()) / 2;
|
||||
int title_w = text_width(win->title);
|
||||
// Center in remaining space
|
||||
int remaining_w = w - (title_x - x) - 12;
|
||||
if (remaining_w > title_w) {
|
||||
title_x += (remaining_w - title_w) / 2;
|
||||
}
|
||||
draw_text(fb, title_x, title_y, win->title, colors::TEXT_COLOR);
|
||||
|
||||
// Call app draw callback to render content (skip during resize — buffer is old size)
|
||||
if (win->on_draw && !win->resizing) {
|
||||
win->on_draw(win, fb);
|
||||
// Call app draw callback to render content (skip during resize — buffer is old size)
|
||||
if (win->on_draw && !win->resizing) {
|
||||
win->on_draw(win, fb);
|
||||
}
|
||||
}
|
||||
|
||||
// Blit content buffer to framebuffer (clip to actual buffer size during resize)
|
||||
Rect cr = win->content_rect();
|
||||
Rect cr = desktop_content_rect(win);
|
||||
if (win->content) {
|
||||
if (win->external && (cr.w != win->content_w || cr.h != win->content_h)) {
|
||||
// Nearest-neighbor scale for external windows (fixed-size shared buffer)
|
||||
|
||||
+15
-27
@@ -25,29 +25,17 @@ using namespace gui;
|
||||
|
||||
static constexpr int INIT_W = 640;
|
||||
static constexpr int INIT_H = 460;
|
||||
static constexpr int TOOLBAR_H = 40;
|
||||
static constexpr int HEADER_H = 26;
|
||||
static constexpr int TOOLBAR_H = 44;
|
||||
static constexpr int HEADER_H = 28;
|
||||
static constexpr int ITEM_H = 32;
|
||||
static constexpr int MAP_H = 48;
|
||||
static constexpr int MAP_PAD = 16;
|
||||
static constexpr int MAX_PARTS = 32;
|
||||
static constexpr int MAX_DISKS = 8;
|
||||
static constexpr int STATUS_H = 26;
|
||||
static constexpr int STATUS_H = 44;
|
||||
|
||||
static constexpr int TB_BTN_Y = 7;
|
||||
static constexpr int TB_BTN_H = 26;
|
||||
static constexpr int TB_BTN_RAD = 6;
|
||||
|
||||
static constexpr Color BG_COLOR = Color::from_rgb(0xFF, 0xFF, 0xFF);
|
||||
static constexpr Color TOOLBAR_BG = Color::from_rgb(0xF5, 0xF5, 0xF5);
|
||||
static constexpr Color HEADER_BG = Color::from_rgb(0xF0, 0xF0, 0xF0);
|
||||
static constexpr Color BORDER_COLOR = Color::from_rgb(0xCC, 0xCC, 0xCC);
|
||||
static constexpr Color TEXT_COLOR = Color::from_rgb(0x22, 0x22, 0x22);
|
||||
static constexpr Color DIM_TEXT = Color::from_rgb(0x66, 0x66, 0x66);
|
||||
static constexpr Color FAINT_TEXT = Color::from_rgb(0x88, 0x88, 0x88);
|
||||
static constexpr Color HOVER_BG = Color::from_rgb(0xE8, 0xF0, 0xF8);
|
||||
static constexpr Color STATUS_BG_COL = Color::from_rgb(0xF0, 0xF0, 0xF0);
|
||||
static constexpr Color WHITE = Color::from_rgb(0xFF, 0xFF, 0xFF);
|
||||
static constexpr int TB_BTN_H = 30;
|
||||
|
||||
static constexpr int NUM_PART_COLORS = 8;
|
||||
|
||||
@@ -119,6 +107,7 @@ struct DiskToolState {
|
||||
|
||||
extern int g_win_w, g_win_h;
|
||||
extern DiskToolState g_state;
|
||||
extern Color g_accent;
|
||||
|
||||
// ============================================================================
|
||||
// Partition colors
|
||||
@@ -133,33 +122,34 @@ extern const Color part_colors[NUM_PART_COLORS];
|
||||
inline int disk_button_width(int idx) {
|
||||
char label[8];
|
||||
snprintf(label, sizeof(label), "Disk %d", idx);
|
||||
return text_width(label) + 16;
|
||||
return text_width(label) + 20;
|
||||
}
|
||||
|
||||
inline Rect toolbar_disk_button_rect(int idx) {
|
||||
int bx = 8;
|
||||
for (int i = 0; i < idx; i++)
|
||||
bx += disk_button_width(i) + 6;
|
||||
bx += disk_button_width(i) + 8;
|
||||
return {bx, TB_BTN_Y, disk_button_width(idx), TB_BTN_H};
|
||||
}
|
||||
|
||||
inline Rect toolbar_refresh_button_rect() {
|
||||
return {g_win_w - 8 - 64, TB_BTN_Y, 64, TB_BTN_H};
|
||||
int y = g_win_h - STATUS_H + (STATUS_H - TB_BTN_H) / 2;
|
||||
return {g_win_w - 12 - 84, y, 84, TB_BTN_H};
|
||||
}
|
||||
|
||||
inline Rect toolbar_mount_button_rect() {
|
||||
Rect refresh = toolbar_refresh_button_rect();
|
||||
return {refresh.x - 6 - 60, TB_BTN_Y, 60, TB_BTN_H};
|
||||
return {refresh.x - 8 - 72, refresh.y, 72, TB_BTN_H};
|
||||
}
|
||||
|
||||
inline Rect toolbar_format_button_rect() {
|
||||
Rect mount = toolbar_mount_button_rect();
|
||||
return {mount.x - 6 - 64, TB_BTN_Y, 64, TB_BTN_H};
|
||||
return {mount.x - 8 - 72, mount.y, 72, TB_BTN_H};
|
||||
}
|
||||
|
||||
inline Rect toolbar_newpart_button_rect() {
|
||||
Rect format = toolbar_format_button_rect();
|
||||
return {format.x - 6 - 74, TB_BTN_Y, 74, TB_BTN_H};
|
||||
return {format.x - 8 - 96, format.y, 96, TB_BTN_H};
|
||||
}
|
||||
|
||||
inline int content_title_y() {
|
||||
@@ -188,15 +178,13 @@ inline Rect format_option_rect(int dialog_w, int index) {
|
||||
inline Rect dialog_primary_button_rect(int dialog_w, int dialog_h) {
|
||||
int btn_w = 90;
|
||||
int btn_h = 30;
|
||||
int gap = 16;
|
||||
int total_w = btn_w * 2 + gap;
|
||||
int bx = (dialog_w - total_w) / 2;
|
||||
return {bx, dialog_h - btn_h - 16, btn_w, btn_h};
|
||||
int bx = dialog_w - btn_w - 16;
|
||||
return {bx, dialog_h - btn_h - 12, btn_w, btn_h};
|
||||
}
|
||||
|
||||
inline Rect dialog_secondary_button_rect(int dialog_w, int dialog_h) {
|
||||
Rect primary = dialog_primary_button_rect(dialog_w, dialog_h);
|
||||
return {primary.x + primary.w + 16, primary.y, primary.w, primary.h};
|
||||
return {primary.x - 8 - primary.w, primary.y, primary.w, primary.h};
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
#include "disks.h"
|
||||
#include <gui/mtk/settings.hpp>
|
||||
#include <gui/standalone.hpp>
|
||||
|
||||
// ============================================================================
|
||||
@@ -15,6 +16,7 @@ int g_win_w = INIT_W;
|
||||
int g_win_h = INIT_H;
|
||||
|
||||
DiskToolState g_state;
|
||||
Color g_accent = colors::ACCENT;
|
||||
|
||||
const Color part_colors[NUM_PART_COLORS] = {
|
||||
Color::from_rgb(0x42, 0x7A, 0xB5),
|
||||
@@ -73,7 +75,6 @@ static bool handle_toolbar_click(int mx, int my) {
|
||||
|
||||
auto& dt = g_state;
|
||||
if (dt.disk_count == 0) return false;
|
||||
bool has_sel = dt.selected_part >= 0;
|
||||
|
||||
// Disk selector buttons
|
||||
for (int i = 0; i < dt.disk_count; i++) {
|
||||
@@ -85,7 +86,16 @@ static bool handle_toolbar_click(int mx, int my) {
|
||||
}
|
||||
}
|
||||
|
||||
// Right-side buttons (must match render layout)
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool handle_action_click(int mx, int my) {
|
||||
if (my < g_win_h - STATUS_H) return false;
|
||||
|
||||
auto& dt = g_state;
|
||||
if (dt.disk_count == 0) return false;
|
||||
bool has_sel = dt.selected_part >= 0;
|
||||
|
||||
if (toolbar_refresh_button_rect().contains(mx, my)) {
|
||||
disktool_refresh();
|
||||
set_status("Refreshed");
|
||||
@@ -285,7 +295,9 @@ static bool handle_mouse(const Montauk::WinEvent& ev) {
|
||||
|
||||
bool clicked = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1);
|
||||
if (clicked) {
|
||||
if (handle_toolbar_click(ev.mouse.x, ev.mouse.y) || handle_content_click(ev.mouse.x, ev.mouse.y))
|
||||
if (handle_toolbar_click(ev.mouse.x, ev.mouse.y) ||
|
||||
handle_action_click(ev.mouse.x, ev.mouse.y) ||
|
||||
handle_content_click(ev.mouse.x, ev.mouse.y))
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -365,6 +377,8 @@ extern "C" void _start() {
|
||||
if (!fonts::init())
|
||||
montauk::exit(1);
|
||||
|
||||
g_accent = mtk::load_system_accent();
|
||||
|
||||
disktool_refresh();
|
||||
|
||||
WsWindow win;
|
||||
|
||||
@@ -9,22 +9,20 @@
|
||||
#include <gui/mtk.hpp>
|
||||
|
||||
static mtk::Theme disks_theme() {
|
||||
mtk::Theme theme = mtk::make_theme();
|
||||
theme.window_bg = BG_COLOR;
|
||||
theme.surface = TOOLBAR_BG;
|
||||
theme.surface_alt = HEADER_BG;
|
||||
theme.surface_hover = HOVER_BG;
|
||||
theme.border = BORDER_COLOR;
|
||||
theme.text = TEXT_COLOR;
|
||||
theme.text_muted = FAINT_TEXT;
|
||||
theme.text_subtle = DIM_TEXT;
|
||||
theme.selection = HOVER_BG;
|
||||
theme.accent_soft = HOVER_BG;
|
||||
theme.disabled_bg = Color::from_rgb(0xF0, 0xF0, 0xF0);
|
||||
mtk::Theme theme = mtk::make_theme(g_accent);
|
||||
theme.selection = theme.accent_soft;
|
||||
theme.disabled_bg = Color::from_rgb(0xE4, 0xE4, 0xE4);
|
||||
theme.disabled_fg = Color::from_rgb(0x9A, 0x9A, 0x9A);
|
||||
return theme;
|
||||
}
|
||||
|
||||
static mtk::TableStyle partition_table_style(const mtk::Theme& theme) {
|
||||
mtk::TableStyle style = mtk::make_table_style(theme);
|
||||
style.row_selected_bg = theme.accent_soft;
|
||||
style.row_hover_bg = mtk::mix(theme.window_bg, theme.accent, 12);
|
||||
return style;
|
||||
}
|
||||
|
||||
static bool mouse_in_rect(const Rect& rect) {
|
||||
return rect.contains(g_state.mouse_x, g_state.mouse_y);
|
||||
}
|
||||
@@ -79,6 +77,13 @@ static void draw_centered_text(Canvas& c, int width, int y, const char* text, Co
|
||||
c.text((width - tw) / 2, y, text, color);
|
||||
}
|
||||
|
||||
static void draw_dialog_footer(Canvas& c, int dialog_w, int dialog_h, const mtk::Theme& theme) {
|
||||
constexpr int FOOTER_H = 54;
|
||||
int y = dialog_h - FOOTER_H;
|
||||
c.fill_rect(0, y, dialog_w, FOOTER_H, theme.surface);
|
||||
mtk::draw_separator(c, 0, y, dialog_w, theme);
|
||||
}
|
||||
|
||||
static void render_toolbar(Canvas& c, const mtk::Theme& theme) {
|
||||
auto& dt = g_state;
|
||||
int fh = system_font_height();
|
||||
@@ -98,21 +103,6 @@ static void render_toolbar(Canvas& c, const mtk::Theme& theme) {
|
||||
c.text(8, (TOOLBAR_H - fh) / 2, "No disks detected", theme.text);
|
||||
return;
|
||||
}
|
||||
|
||||
bool has_sel = dt.selected_part >= 0;
|
||||
Rect newpart = toolbar_newpart_button_rect();
|
||||
Rect format = toolbar_format_button_rect();
|
||||
Rect mount = toolbar_mount_button_rect();
|
||||
Rect refresh = toolbar_refresh_button_rect();
|
||||
|
||||
mtk::draw_button(c, newpart, "New Part", mtk::BUTTON_PRIMARY,
|
||||
toolbar_button_state(newpart, true), theme);
|
||||
mtk::draw_button(c, format, "Format", mtk::BUTTON_TONAL,
|
||||
toolbar_button_state(format, has_sel), theme);
|
||||
mtk::draw_button(c, mount, "Mount", mtk::BUTTON_TONAL,
|
||||
toolbar_button_state(mount, has_sel), theme);
|
||||
mtk::draw_button(c, refresh, "Refresh", mtk::BUTTON_SECONDARY,
|
||||
toolbar_button_state(refresh, true), theme);
|
||||
}
|
||||
|
||||
static void render_content(Canvas& c, const mtk::Theme& theme) {
|
||||
@@ -140,7 +130,7 @@ static void render_content(Canvas& c, const mtk::Theme& theme) {
|
||||
y = partition_map_y();
|
||||
|
||||
Rect map_rect = {MAP_PAD, y, g_win_w - MAP_PAD * 2, MAP_H};
|
||||
c.fill_rounded_rect(map_rect.x, map_rect.y, map_rect.w, map_rect.h, theme.radius_md, theme.surface_alt);
|
||||
mtk::draw_rounded_frame(c, map_rect, theme.radius_md, theme.surface_alt, theme.border);
|
||||
|
||||
int part_indices[MAX_PARTS];
|
||||
int nparts = get_disk_parts(part_indices, MAX_PARTS);
|
||||
@@ -155,45 +145,60 @@ static void render_content(Canvas& c, const mtk::Theme& theme) {
|
||||
if (part_x + part_w > map_rect.x + map_rect.w)
|
||||
part_w = map_rect.x + map_rect.w - part_x;
|
||||
|
||||
Color col = part_colors[pi % NUM_PART_COLORS];
|
||||
Rect segment = {part_x, map_rect.y + 3, part_w, MAP_H - 6};
|
||||
if (pi == dt.selected_part) {
|
||||
col = Color::from_rgb((col.r + 255) / 2,
|
||||
(col.g + 255) / 2,
|
||||
(col.b + 255) / 2);
|
||||
c.fill_rounded_rect(segment.x - 1, segment.y - 1,
|
||||
segment.w + 2, segment.h + 2,
|
||||
theme.radius_sm, theme.accent);
|
||||
}
|
||||
c.fill_rounded_rect(part_x, map_rect.y + 2, part_w, MAP_H - 4, theme.radius_sm, col);
|
||||
|
||||
Color col = part_colors[pi % NUM_PART_COLORS];
|
||||
c.fill_rounded_rect(segment.x, segment.y, segment.w, segment.h,
|
||||
theme.radius_sm, col);
|
||||
|
||||
char label[8];
|
||||
snprintf(label, sizeof(label), "%d", pi);
|
||||
int label_w = text_width(label);
|
||||
if (part_w > label_w + 4) {
|
||||
c.text(part_x + (part_w - label_w) / 2,
|
||||
c.text(segment.x + (segment.w - label_w) / 2,
|
||||
map_rect.y + (MAP_H - fh) / 2,
|
||||
label, WHITE);
|
||||
label, theme.text_inverse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
y = partition_header_y();
|
||||
c.fill_rect(0, y, g_win_w, HEADER_H, theme.surface_alt);
|
||||
mtk::draw_separator(c, 0, y + HEADER_H - 1, g_win_w, theme);
|
||||
int list_y = partition_list_y();
|
||||
int list_bottom = g_win_h - STATUS_H;
|
||||
int hovered_row = hovered_partition_row();
|
||||
mtk::TableStyle table_style = partition_table_style(theme);
|
||||
mtk::TableLayout table = {
|
||||
{0, y, g_win_w, HEADER_H},
|
||||
{0, list_y, g_win_w, list_bottom - list_y},
|
||||
ITEM_H
|
||||
};
|
||||
|
||||
int ty = y + (HEADER_H - fh) / 2;
|
||||
int col_idx = 12;
|
||||
int col_name = 40;
|
||||
int col_type = g_win_w / 2 - 20;
|
||||
int col_size = g_win_w - 160;
|
||||
int col_lba = g_win_w - 80;
|
||||
mtk::TableColumn cols[5] = {
|
||||
{"#", col_idx, col_name - col_idx - 8},
|
||||
{"Name", col_name, col_type - col_name - 10},
|
||||
{"Type", col_type, col_size - col_type - 10},
|
||||
{"Size", col_size, col_lba - col_size - 10},
|
||||
{"LBA", col_lba, g_win_w - col_lba - 12},
|
||||
};
|
||||
|
||||
c.text(col_idx, ty, "#", theme.text_subtle);
|
||||
c.text(col_name, ty, "Name", theme.text_subtle);
|
||||
c.text(col_type, ty, "Type", theme.text_subtle);
|
||||
c.text(col_size, ty, "Size", theme.text_subtle);
|
||||
c.text(col_lba, ty, "LBA", theme.text_subtle);
|
||||
c.fill_rect(table.header.x, table.header.y, table.header.w, table.header.h,
|
||||
table_style.header_bg);
|
||||
c.hline(table.header.x, table.header.y + table.header.h - 1,
|
||||
table.header.w, table_style.header_border);
|
||||
|
||||
int list_y = partition_list_y();
|
||||
int list_bottom = g_win_h - STATUS_H;
|
||||
int hovered_row = hovered_partition_row();
|
||||
int ty = table.header.y + (table.header.h - fh) / 2;
|
||||
for (int i = 0; i < 5; i++)
|
||||
c.text(table.header.x + cols[i].x, ty, cols[i].label, table_style.header_text);
|
||||
|
||||
for (int pi = 0; pi < nparts; pi++) {
|
||||
int row_y = list_y + pi * ITEM_H - dt.scroll_y;
|
||||
@@ -202,11 +207,11 @@ static void render_content(Canvas& c, const mtk::Theme& theme) {
|
||||
|
||||
Rect row_rect = {0, row_y, g_win_w, ITEM_H};
|
||||
if (pi == dt.selected_part) {
|
||||
mtk::draw_list_row(c, row_rect, true, false, theme);
|
||||
c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h,
|
||||
table_style.row_selected_bg);
|
||||
} else if (pi == hovered_row) {
|
||||
c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h, theme.surface_hover);
|
||||
} else {
|
||||
mtk::draw_list_row(c, row_rect, false, (pi & 1) != 0, theme);
|
||||
c.fill_rect(row_rect.x, row_rect.y, row_rect.w, row_rect.h,
|
||||
table_style.row_hover_bg);
|
||||
}
|
||||
|
||||
Montauk::PartInfo& p = dt.parts[part_indices[pi]];
|
||||
@@ -216,17 +221,17 @@ static void render_content(Canvas& c, const mtk::Theme& theme) {
|
||||
|
||||
int ry = row_y + (ITEM_H - fh) / 2;
|
||||
draw_text_fit(c, col_name, ry, p.name[0] ? p.name : "(unnamed)",
|
||||
col_type - col_name - 10, theme.text);
|
||||
cols[1].w, theme.text);
|
||||
draw_text_fit(c, col_type, ry, p.typeName,
|
||||
col_size - col_type - 10, theme.text_subtle);
|
||||
cols[2].w, theme.text_subtle);
|
||||
|
||||
char sz[24];
|
||||
format_disk_size(sz, sizeof(sz), p.sectorCount, disk.sectorSizeLog);
|
||||
c.text(col_size, ry, sz, theme.text);
|
||||
draw_text_fit(c, col_size, ry, sz, cols[3].w, theme.text);
|
||||
|
||||
char lba_str[24];
|
||||
snprintf(lba_str, sizeof(lba_str), "%lu", (unsigned)p.startLba);
|
||||
c.text(col_lba, ry, lba_str, theme.text_muted);
|
||||
draw_text_fit(c, col_lba, ry, lba_str, cols[4].w, theme.text_muted);
|
||||
}
|
||||
|
||||
if (nparts == 0)
|
||||
@@ -238,13 +243,34 @@ static void render_status(Canvas& c, const mtk::Theme& theme) {
|
||||
int fh = system_font_height();
|
||||
|
||||
int sy = g_win_h - STATUS_H;
|
||||
c.fill_rect(0, sy, g_win_w, STATUS_H, theme.surface_alt);
|
||||
c.fill_rect(0, sy, g_win_w, STATUS_H, theme.surface);
|
||||
mtk::draw_separator(c, 0, sy, g_win_w, theme);
|
||||
|
||||
bool has_disks = dt.disk_count > 0;
|
||||
bool has_sel = dt.selected_part >= 0;
|
||||
int text_right = g_win_w - 16;
|
||||
if (has_disks) {
|
||||
Rect newpart = toolbar_newpart_button_rect();
|
||||
Rect format = toolbar_format_button_rect();
|
||||
Rect mount = toolbar_mount_button_rect();
|
||||
Rect refresh = toolbar_refresh_button_rect();
|
||||
text_right = newpart.x - 12;
|
||||
|
||||
mtk::draw_button(c, newpart, "New Part", mtk::BUTTON_PRIMARY,
|
||||
toolbar_button_state(newpart, true), theme);
|
||||
mtk::draw_button(c, format, "Format", mtk::BUTTON_TONAL,
|
||||
toolbar_button_state(format, has_sel), theme);
|
||||
mtk::draw_button(c, mount, "Mount", mtk::BUTTON_TONAL,
|
||||
toolbar_button_state(mount, has_sel), theme);
|
||||
mtk::draw_button(c, refresh, "Refresh", mtk::BUTTON_SECONDARY,
|
||||
toolbar_button_state(refresh, true), theme);
|
||||
}
|
||||
|
||||
if (dt.status[0]) {
|
||||
uint64_t age = montauk::get_milliseconds() - dt.status_time;
|
||||
Color color = age < 5000 ? theme.text : theme.text_muted;
|
||||
c.text(8, sy + (STATUS_H - fh) / 2, dt.status, color);
|
||||
draw_text_fit(c, 16, sy + (STATUS_H - fh) / 2, dt.status,
|
||||
text_right - 16, color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,11 +291,14 @@ void render_format_window() {
|
||||
|
||||
for (int i = 0; i < NUM_FS_TYPES; i++) {
|
||||
Rect option = format_option_rect(FMT_DLG_W, i);
|
||||
if (i == dlg.selected_fs)
|
||||
c.fill_rounded_rect(option.x, option.y, option.w, option.h, theme.radius_md, theme.accent_soft);
|
||||
if (i == dlg.selected_fs) {
|
||||
mtk::draw_rounded_frame(c, option, theme.radius_md,
|
||||
theme.accent_soft, theme.accent_soft);
|
||||
}
|
||||
mtk::draw_radio(c, option, g_fsTypes[i].name, i == dlg.selected_fs, theme);
|
||||
}
|
||||
|
||||
draw_dialog_footer(c, FMT_DLG_W, FMT_DLG_H, theme);
|
||||
mtk::draw_modal_actions(c,
|
||||
dialog_primary_button_rect(FMT_DLG_W, FMT_DLG_H), "Format",
|
||||
mtk::BUTTON_DANGER,
|
||||
@@ -294,11 +323,15 @@ void render_newpart_window() {
|
||||
|
||||
Color warn_color = dlg.will_init_gpt ? theme.danger : theme.text;
|
||||
int warn_y = 12 + fh * 2 + 20;
|
||||
Rect warn_panel = {16, warn_y - 8, NP_DLG_W - 32, fh * 2 + 20};
|
||||
Color warn_bg = dlg.will_init_gpt ? theme.danger_soft : theme.surface_alt;
|
||||
mtk::draw_rounded_frame(c, warn_panel, theme.radius_md, warn_bg, warn_bg);
|
||||
draw_centered_text(c, NP_DLG_W, warn_y, dlg.warn_line1, warn_color);
|
||||
draw_centered_text(c, NP_DLG_W, warn_y + fh + 4, dlg.warn_line2, warn_color);
|
||||
|
||||
const char* confirm_label = dlg.will_init_gpt ? "Initialize" : "Create";
|
||||
mtk::ButtonVariant confirm_variant = dlg.will_init_gpt ? mtk::BUTTON_DANGER : mtk::BUTTON_PRIMARY;
|
||||
draw_dialog_footer(c, NP_DLG_W, NP_DLG_H, theme);
|
||||
mtk::draw_modal_actions(c,
|
||||
dialog_primary_button_rect(NP_DLG_W, NP_DLG_H), confirm_label,
|
||||
confirm_variant,
|
||||
|
||||
@@ -18,6 +18,7 @@ endif
|
||||
PROJECT_ROOT := $(shell cd ../../.. && pwd)
|
||||
PROGRAMS := $(PROJECT_ROOT)/programs
|
||||
JPEGWRITE_LIB := $(PROGRAMS)/lib/libjpegwrite
|
||||
LOADER_LIB := $(PROGRAMS)/lib/libloader
|
||||
LIBC_LIB := $(PROGRAMS)/lib/libc
|
||||
PROG_INC := $(PROGRAMS)/include
|
||||
LINK_LD := $(PROGRAMS)/link.ld
|
||||
@@ -66,11 +67,11 @@ LDFLAGS := \
|
||||
|
||||
# ---- Libraries ----
|
||||
|
||||
LIBS := $(JPEGWRITE_LIB)/libjpegwrite.a $(LIBC_LIB)/liblibc.a
|
||||
LIBS := $(JPEGWRITE_LIB)/libjpegwrite.a $(LOADER_LIB)/liblibloader.a $(LIBC_LIB)/liblibc.a
|
||||
|
||||
# ---- Source files ----
|
||||
|
||||
SRCS := main.cpp
|
||||
SRCS := main.cpp stb_truetype_impl.cpp
|
||||
OBJS := $(addprefix $(OBJDIR)/,$(SRCS:.cpp=.o))
|
||||
|
||||
# ---- Target ----
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* stb_truetype_impl.cpp
|
||||
* Single compilation unit for stb_truetype in MontaukOS freestanding environment
|
||||
* Copyright (c) 2026 Daniel Hammer
|
||||
*/
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <montauk/heap.h>
|
||||
#include <montauk/string.h>
|
||||
#include <gui/stb_math.h>
|
||||
|
||||
#define STBTT_ifloor(x) ((int) stb_floor(x))
|
||||
#define STBTT_iceil(x) ((int) stb_ceil(x))
|
||||
#define STBTT_sqrt(x) stb_sqrt(x)
|
||||
#define STBTT_pow(x,y) stb_pow(x,y)
|
||||
#define STBTT_fmod(x,y) stb_fmod(x,y)
|
||||
#define STBTT_cos(x) stb_cos(x)
|
||||
#define STBTT_acos(x) stb_acos(x)
|
||||
#define STBTT_fabs(x) stb_fabs(x)
|
||||
|
||||
#define STBTT_malloc(x,u) ((void)(u), montauk::malloc(x))
|
||||
#define STBTT_free(x,u) ((void)(u), montauk::mfree(x))
|
||||
|
||||
#define STBTT_memcpy(d,s,n) montauk::memcpy(d,s,n)
|
||||
#define STBTT_memset(d,v,n) montauk::memset(d,v,n)
|
||||
|
||||
#define STBTT_strlen(x) montauk::slen(x)
|
||||
|
||||
#define STBTT_assert(x) ((void)(x))
|
||||
|
||||
#define STB_TRUETYPE_IMPLEMENTATION
|
||||
#include <gui/stb_truetype.h>
|
||||
Reference in New Issue
Block a user