feat: desktop - use MTK buttons for power dialogs
This commit is contained in:
@@ -12,4 +12,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MONTAUK_BUILD_NUMBER 87
|
||||
#define MONTAUK_BUILD_NUMBER 88
|
||||
|
||||
+128
-203
@@ -5,6 +5,94 @@
|
||||
*/
|
||||
|
||||
#include "desktop_internal.hpp"
|
||||
#include <gui/mtk.hpp>
|
||||
|
||||
// ============================================================================
|
||||
// Shared Layout
|
||||
// ============================================================================
|
||||
//
|
||||
// All three power dialogs are the same shape: one centered question with a
|
||||
// confirm/Cancel pair pinned to the bottom. Draw and hit-test both derive the
|
||||
// button rects from these helpers, so neither has to cache a layout.
|
||||
|
||||
static constexpr int POWER_DIALOG_W = 300;
|
||||
static constexpr int POWER_DIALOG_H = 150;
|
||||
static constexpr int POWER_BTN_W = 100;
|
||||
static constexpr int POWER_BTN_GAP = 20;
|
||||
static constexpr int POWER_BTN_MARGIN = 20;
|
||||
|
||||
static Rect power_confirm_rect(int cw, int ch, const gui::mtk::Theme& theme) {
|
||||
int total = POWER_BTN_W * 2 + POWER_BTN_GAP;
|
||||
return {(cw - total) / 2, ch - theme.control_h - POWER_BTN_MARGIN,
|
||||
POWER_BTN_W, theme.control_h};
|
||||
}
|
||||
|
||||
static Rect power_cancel_rect(int cw, int ch, const gui::mtk::Theme& theme) {
|
||||
Rect r = power_confirm_rect(cw, ch, theme);
|
||||
r.x += POWER_BTN_W + POWER_BTN_GAP;
|
||||
return r;
|
||||
}
|
||||
|
||||
static gui::mtk::Theme power_dialog_theme(const DesktopState* ds) {
|
||||
return gui::mtk::make_theme(ds->settings.accent_color);
|
||||
}
|
||||
|
||||
static void power_dialog_draw(Window* win,
|
||||
const gui::mtk::Theme& theme,
|
||||
const char* message,
|
||||
const char* confirm_label,
|
||||
gui::mtk::ButtonVariant confirm_variant,
|
||||
bool hover_confirm,
|
||||
bool hover_cancel) {
|
||||
Canvas c(win);
|
||||
c.fill(theme.window_bg);
|
||||
|
||||
int tw = text_width(message);
|
||||
c.text((c.w - tw) / 2, 30, message, theme.text);
|
||||
|
||||
gui::mtk::draw_modal_actions(
|
||||
c,
|
||||
power_confirm_rect(c.w, c.h, theme), confirm_label, confirm_variant,
|
||||
gui::mtk::widget_state(false, hover_confirm),
|
||||
power_cancel_rect(c.w, c.h, theme), "Cancel",
|
||||
gui::mtk::widget_state(false, hover_cancel),
|
||||
theme);
|
||||
}
|
||||
|
||||
// Updates the hover flags from a mouse event and reports where the pointer is.
|
||||
static void power_dialog_hover(Window* win,
|
||||
const MouseEvent& ev,
|
||||
const gui::mtk::Theme& theme,
|
||||
bool* hover_confirm,
|
||||
bool* hover_cancel) {
|
||||
gui::mtk::DesktopHost host(win);
|
||||
int mx = 0;
|
||||
int my = 0;
|
||||
if (!host.map_mouse(ev, &mx, &my)) return;
|
||||
|
||||
int cw = win->content_w;
|
||||
int ch = win->content_h;
|
||||
*hover_confirm = power_confirm_rect(cw, ch, theme).contains(mx, my);
|
||||
*hover_cancel = power_cancel_rect(cw, ch, theme).contains(mx, my);
|
||||
}
|
||||
|
||||
// The dialogs own themselves through win->app_data, so closing means finding
|
||||
// the window that carries this state.
|
||||
static void power_dialog_close(DesktopState* ds, void* state) {
|
||||
for (int i = 0; i < ds->window_count; i++) {
|
||||
if (ds->windows[i].app_data == state) {
|
||||
desktop_close_window(ds, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void power_dialog_on_close(Window* win) {
|
||||
if (win->app_data) {
|
||||
montauk::mfree(win->app_data);
|
||||
win->app_data = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Reboot Dialog
|
||||
@@ -12,72 +100,29 @@
|
||||
|
||||
struct RebootDialogState {
|
||||
DesktopState* ds;
|
||||
// Button layout (pixel-buffer-relative coordinates)
|
||||
int btn_w, btn_h, btn_y, reboot_x, cancel_x;
|
||||
bool hover_reboot, hover_cancel;
|
||||
};
|
||||
|
||||
static void reboot_dialog_on_draw(Window* win, Framebuffer& fb) {
|
||||
(void)fb;
|
||||
RebootDialogState* rs = (RebootDialogState*)win->app_data;
|
||||
if (!rs) return;
|
||||
|
||||
Canvas c(win);
|
||||
c.fill(colors::WINDOW_BG);
|
||||
|
||||
// "Reboot the system?" centered
|
||||
const char* msg = "Reboot the system?";
|
||||
int tw = text_width(msg);
|
||||
c.text((c.w - tw) / 2, 30, msg, colors::TEXT_COLOR);
|
||||
|
||||
// Compute button layout
|
||||
int btn_w = 100;
|
||||
int btn_h = 32;
|
||||
int btn_y = c.h - btn_h - 20;
|
||||
int gap = 20;
|
||||
int total_w = btn_w * 2 + gap;
|
||||
int bx = (c.w - total_w) / 2;
|
||||
rs->btn_w = btn_w;
|
||||
rs->btn_h = btn_h;
|
||||
rs->btn_y = btn_y;
|
||||
rs->reboot_x = bx;
|
||||
rs->cancel_x = bx + btn_w + gap;
|
||||
|
||||
// Draw Reboot button
|
||||
Color reboot_bg = rs->hover_reboot
|
||||
? Color::from_rgb(0xDD, 0x44, 0x44)
|
||||
: Color::from_rgb(0xCC, 0x33, 0x33);
|
||||
c.button(rs->reboot_x, btn_y, btn_w, btn_h, "Reboot", reboot_bg, colors::WHITE, 4);
|
||||
|
||||
// Draw Cancel button
|
||||
Color cancel_bg = rs->hover_cancel
|
||||
? Color::from_rgb(0x99, 0x99, 0x99)
|
||||
: Color::from_rgb(0x88, 0x88, 0x88);
|
||||
c.button(rs->cancel_x, btn_y, btn_w, btn_h, "Cancel", cancel_bg, colors::WHITE, 4);
|
||||
power_dialog_draw(win, power_dialog_theme(rs->ds), "Reboot the system?",
|
||||
"Reboot", gui::mtk::BUTTON_DANGER,
|
||||
rs->hover_reboot, rs->hover_cancel);
|
||||
}
|
||||
|
||||
static void reboot_dialog_on_mouse(Window* win, MouseEvent& ev) {
|
||||
RebootDialogState* rs = (RebootDialogState*)win->app_data;
|
||||
if (!rs) return;
|
||||
|
||||
Rect cr = win->content_rect();
|
||||
int lx = ev.x - cr.x;
|
||||
int ly = ev.y - cr.y;
|
||||
|
||||
Rect rb = {rs->reboot_x, rs->btn_y, rs->btn_w, rs->btn_h};
|
||||
Rect cb = {rs->cancel_x, rs->btn_y, rs->btn_w, rs->btn_h};
|
||||
rs->hover_reboot = rb.contains(lx, ly);
|
||||
rs->hover_cancel = cb.contains(lx, ly);
|
||||
power_dialog_hover(win, ev, power_dialog_theme(rs->ds),
|
||||
&rs->hover_reboot, &rs->hover_cancel);
|
||||
|
||||
if (ev.left_pressed()) {
|
||||
if (rs->hover_reboot) desktop_request_power(montauk::abi::POWER_REQ_REBOOT);
|
||||
if (rs->hover_cancel) {
|
||||
for (int i = 0; i < rs->ds->window_count; i++) {
|
||||
if (rs->ds->windows[i].app_data == rs) {
|
||||
desktop_close_window(rs->ds, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rs->hover_cancel) power_dialog_close(rs->ds, rs);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,26 +134,14 @@ static void reboot_dialog_on_key(Window* win, const montauk::abi::KeyEvent& key)
|
||||
desktop_request_power(montauk::abi::POWER_REQ_REBOOT);
|
||||
}
|
||||
if (key.scancode == 0x01) { // Escape
|
||||
for (int i = 0; i < rs->ds->window_count; i++) {
|
||||
if (rs->ds->windows[i].app_data == rs) {
|
||||
desktop_close_window(rs->ds, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void reboot_dialog_on_close(Window* win) {
|
||||
if (win->app_data) {
|
||||
montauk::mfree(win->app_data);
|
||||
win->app_data = nullptr;
|
||||
power_dialog_close(rs->ds, rs);
|
||||
}
|
||||
}
|
||||
|
||||
void open_reboot_dialog(DesktopState* ds) {
|
||||
int wx = (ds->screen_w - 300) / 2;
|
||||
int wy = (ds->screen_h - 150) / 2;
|
||||
int idx = desktop_create_window(ds, "Reboot", wx, wy, 300, 150);
|
||||
int wx = (ds->screen_w - POWER_DIALOG_W) / 2;
|
||||
int wy = (ds->screen_h - POWER_DIALOG_H) / 2;
|
||||
int idx = desktop_create_window(ds, "Reboot", wx, wy, POWER_DIALOG_W, POWER_DIALOG_H);
|
||||
if (idx < 0) return;
|
||||
|
||||
Window* win = &ds->windows[idx];
|
||||
@@ -120,7 +153,7 @@ void open_reboot_dialog(DesktopState* ds) {
|
||||
win->on_draw = reboot_dialog_on_draw;
|
||||
win->on_mouse = reboot_dialog_on_mouse;
|
||||
win->on_key = reboot_dialog_on_key;
|
||||
win->on_close = reboot_dialog_on_close;
|
||||
win->on_close = power_dialog_on_close;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -129,67 +162,29 @@ void open_reboot_dialog(DesktopState* ds) {
|
||||
|
||||
struct ShutdownDialogState {
|
||||
DesktopState* ds;
|
||||
int btn_w, btn_h, btn_y, shutdown_x, cancel_x;
|
||||
bool hover_shutdown, hover_cancel;
|
||||
};
|
||||
|
||||
static void shutdown_dialog_on_draw(Window* win, Framebuffer& fb) {
|
||||
(void)fb;
|
||||
ShutdownDialogState* ss = (ShutdownDialogState*)win->app_data;
|
||||
if (!ss) return;
|
||||
|
||||
Canvas c(win);
|
||||
c.fill(colors::WINDOW_BG);
|
||||
|
||||
const char* msg = "Shut down the system?";
|
||||
int tw = text_width(msg);
|
||||
c.text((c.w - tw) / 2, 30, msg, colors::TEXT_COLOR);
|
||||
|
||||
int btn_w = 100;
|
||||
int btn_h = 32;
|
||||
int btn_y = c.h - btn_h - 20;
|
||||
int gap = 20;
|
||||
int total_w = btn_w * 2 + gap;
|
||||
int bx = (c.w - total_w) / 2;
|
||||
ss->btn_w = btn_w;
|
||||
ss->btn_h = btn_h;
|
||||
ss->btn_y = btn_y;
|
||||
ss->shutdown_x = bx;
|
||||
ss->cancel_x = bx + btn_w + gap;
|
||||
|
||||
Color shutdown_bg = ss->hover_shutdown
|
||||
? Color::from_rgb(0xDD, 0x44, 0x44)
|
||||
: Color::from_rgb(0xCC, 0x33, 0x33);
|
||||
c.button(ss->shutdown_x, btn_y, btn_w, btn_h, "Shut Down", shutdown_bg, colors::WHITE, 4);
|
||||
|
||||
Color cancel_bg = ss->hover_cancel
|
||||
? Color::from_rgb(0x99, 0x99, 0x99)
|
||||
: Color::from_rgb(0x88, 0x88, 0x88);
|
||||
c.button(ss->cancel_x, btn_y, btn_w, btn_h, "Cancel", cancel_bg, colors::WHITE, 4);
|
||||
power_dialog_draw(win, power_dialog_theme(ss->ds), "Shut down the system?",
|
||||
"Shut Down", gui::mtk::BUTTON_DANGER,
|
||||
ss->hover_shutdown, ss->hover_cancel);
|
||||
}
|
||||
|
||||
static void shutdown_dialog_on_mouse(Window* win, MouseEvent& ev) {
|
||||
ShutdownDialogState* ss = (ShutdownDialogState*)win->app_data;
|
||||
if (!ss) return;
|
||||
|
||||
Rect cr = win->content_rect();
|
||||
int lx = ev.x - cr.x;
|
||||
int ly = ev.y - cr.y;
|
||||
|
||||
Rect sb = {ss->shutdown_x, ss->btn_y, ss->btn_w, ss->btn_h};
|
||||
Rect cb = {ss->cancel_x, ss->btn_y, ss->btn_w, ss->btn_h};
|
||||
ss->hover_shutdown = sb.contains(lx, ly);
|
||||
ss->hover_cancel = cb.contains(lx, ly);
|
||||
power_dialog_hover(win, ev, power_dialog_theme(ss->ds),
|
||||
&ss->hover_shutdown, &ss->hover_cancel);
|
||||
|
||||
if (ev.left_pressed()) {
|
||||
if (ss->hover_shutdown) desktop_request_power(montauk::abi::POWER_REQ_SHUTDOWN);
|
||||
if (ss->hover_cancel) {
|
||||
for (int i = 0; i < ss->ds->window_count; i++) {
|
||||
if (ss->ds->windows[i].app_data == ss) {
|
||||
desktop_close_window(ss->ds, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ss->hover_cancel) power_dialog_close(ss->ds, ss);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,26 +196,14 @@ static void shutdown_dialog_on_key(Window* win, const montauk::abi::KeyEvent& ke
|
||||
desktop_request_power(montauk::abi::POWER_REQ_SHUTDOWN);
|
||||
}
|
||||
if (key.scancode == 0x01) { // Escape
|
||||
for (int i = 0; i < ss->ds->window_count; i++) {
|
||||
if (ss->ds->windows[i].app_data == ss) {
|
||||
desktop_close_window(ss->ds, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void shutdown_dialog_on_close(Window* win) {
|
||||
if (win->app_data) {
|
||||
montauk::mfree(win->app_data);
|
||||
win->app_data = nullptr;
|
||||
power_dialog_close(ss->ds, ss);
|
||||
}
|
||||
}
|
||||
|
||||
void open_shutdown_dialog(DesktopState* ds) {
|
||||
int wx = (ds->screen_w - 300) / 2;
|
||||
int wy = (ds->screen_h - 150) / 2;
|
||||
int idx = desktop_create_window(ds, "Shut Down", wx, wy, 300, 150);
|
||||
int wx = (ds->screen_w - POWER_DIALOG_W) / 2;
|
||||
int wy = (ds->screen_h - POWER_DIALOG_H) / 2;
|
||||
int idx = desktop_create_window(ds, "Shut Down", wx, wy, POWER_DIALOG_W, POWER_DIALOG_H);
|
||||
if (idx < 0) return;
|
||||
|
||||
Window* win = &ds->windows[idx];
|
||||
@@ -232,7 +215,7 @@ void open_shutdown_dialog(DesktopState* ds) {
|
||||
win->on_draw = shutdown_dialog_on_draw;
|
||||
win->on_mouse = shutdown_dialog_on_mouse;
|
||||
win->on_key = shutdown_dialog_on_key;
|
||||
win->on_close = shutdown_dialog_on_close;
|
||||
win->on_close = power_dialog_on_close;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
@@ -241,76 +224,34 @@ void open_shutdown_dialog(DesktopState* ds) {
|
||||
|
||||
struct SleepDialogState {
|
||||
DesktopState* ds;
|
||||
int btn_w, btn_h, btn_y, sleep_x, cancel_x;
|
||||
bool hover_sleep, hover_cancel;
|
||||
};
|
||||
|
||||
static void sleep_dialog_on_draw(Window* win, Framebuffer& fb) {
|
||||
(void)fb;
|
||||
SleepDialogState* ss = (SleepDialogState*)win->app_data;
|
||||
if (!ss) return;
|
||||
|
||||
Canvas c(win);
|
||||
c.fill(colors::WINDOW_BG);
|
||||
|
||||
const char* msg = "Suspend the system?";
|
||||
int tw = text_width(msg);
|
||||
c.text((c.w - tw) / 2, 30, msg, colors::TEXT_COLOR);
|
||||
|
||||
int btn_w = 100;
|
||||
int btn_h = 32;
|
||||
int btn_y = c.h - btn_h - 20;
|
||||
int gap = 20;
|
||||
int total_w = btn_w * 2 + gap;
|
||||
int bx = (c.w - total_w) / 2;
|
||||
ss->btn_w = btn_w;
|
||||
ss->btn_h = btn_h;
|
||||
ss->btn_y = btn_y;
|
||||
ss->sleep_x = bx;
|
||||
ss->cancel_x = bx + btn_w + gap;
|
||||
|
||||
Color sleep_bg = ss->hover_sleep
|
||||
? Color::from_rgb(0x44, 0x77, 0xDD)
|
||||
: Color::from_rgb(0x33, 0x66, 0xCC);
|
||||
c.button(ss->sleep_x, btn_y, btn_w, btn_h, "Sleep", sleep_bg, colors::WHITE, 4);
|
||||
|
||||
Color cancel_bg = ss->hover_cancel
|
||||
? Color::from_rgb(0x99, 0x99, 0x99)
|
||||
: Color::from_rgb(0x88, 0x88, 0x88);
|
||||
c.button(ss->cancel_x, btn_y, btn_w, btn_h, "Cancel", cancel_bg, colors::WHITE, 4);
|
||||
power_dialog_draw(win, power_dialog_theme(ss->ds), "Suspend the system?",
|
||||
"Sleep", gui::mtk::BUTTON_PRIMARY,
|
||||
ss->hover_sleep, ss->hover_cancel);
|
||||
}
|
||||
|
||||
static void sleep_dialog_on_mouse(Window* win, MouseEvent& ev) {
|
||||
SleepDialogState* ss = (SleepDialogState*)win->app_data;
|
||||
if (!ss) return;
|
||||
|
||||
Rect cr = win->content_rect();
|
||||
int lx = ev.x - cr.x;
|
||||
int ly = ev.y - cr.y;
|
||||
|
||||
Rect sb = {ss->sleep_x, ss->btn_y, ss->btn_w, ss->btn_h};
|
||||
Rect cb = {ss->cancel_x, ss->btn_y, ss->btn_w, ss->btn_h};
|
||||
ss->hover_sleep = sb.contains(lx, ly);
|
||||
ss->hover_cancel = cb.contains(lx, ly);
|
||||
power_dialog_hover(win, ev, power_dialog_theme(ss->ds),
|
||||
&ss->hover_sleep, &ss->hover_cancel);
|
||||
|
||||
if (ev.left_pressed()) {
|
||||
if (ss->hover_sleep) {
|
||||
montauk::suspend();
|
||||
// If suspend returns (resume from S3), close the dialog
|
||||
for (int i = 0; i < ss->ds->window_count; i++) {
|
||||
if (ss->ds->windows[i].app_data == ss) {
|
||||
desktop_close_window(ss->ds, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ss->hover_cancel) {
|
||||
for (int i = 0; i < ss->ds->window_count; i++) {
|
||||
if (ss->ds->windows[i].app_data == ss) {
|
||||
desktop_close_window(ss->ds, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
power_dialog_close(ss->ds, ss);
|
||||
return;
|
||||
}
|
||||
if (ss->hover_cancel) power_dialog_close(ss->ds, ss);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,34 +262,18 @@ static void sleep_dialog_on_key(Window* win, const montauk::abi::KeyEvent& key)
|
||||
if (key.ascii == '\n' || key.ascii == '\r') {
|
||||
montauk::suspend();
|
||||
// If suspend returns, close the dialog
|
||||
for (int i = 0; i < ss->ds->window_count; i++) {
|
||||
if (ss->ds->windows[i].app_data == ss) {
|
||||
desktop_close_window(ss->ds, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
power_dialog_close(ss->ds, ss);
|
||||
return;
|
||||
}
|
||||
if (key.scancode == 0x01) { // Escape
|
||||
for (int i = 0; i < ss->ds->window_count; i++) {
|
||||
if (ss->ds->windows[i].app_data == ss) {
|
||||
desktop_close_window(ss->ds, i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sleep_dialog_on_close(Window* win) {
|
||||
if (win->app_data) {
|
||||
montauk::mfree(win->app_data);
|
||||
win->app_data = nullptr;
|
||||
power_dialog_close(ss->ds, ss);
|
||||
}
|
||||
}
|
||||
|
||||
void open_sleep_dialog(DesktopState* ds) {
|
||||
int wx = (ds->screen_w - 300) / 2;
|
||||
int wy = (ds->screen_h - 150) / 2;
|
||||
int idx = desktop_create_window(ds, "Sleep", wx, wy, 300, 150);
|
||||
int wx = (ds->screen_w - POWER_DIALOG_W) / 2;
|
||||
int wy = (ds->screen_h - POWER_DIALOG_H) / 2;
|
||||
int idx = desktop_create_window(ds, "Sleep", wx, wy, POWER_DIALOG_W, POWER_DIALOG_H);
|
||||
if (idx < 0) return;
|
||||
|
||||
Window* win = &ds->windows[idx];
|
||||
@@ -360,5 +285,5 @@ void open_sleep_dialog(DesktopState* ds) {
|
||||
win->on_draw = sleep_dialog_on_draw;
|
||||
win->on_mouse = sleep_dialog_on_mouse;
|
||||
win->on_key = sleep_dialog_on_key;
|
||||
win->on_close = sleep_dialog_on_close;
|
||||
win->on_close = power_dialog_on_close;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user