365 lines
11 KiB
C++
365 lines
11 KiB
C++
/*
|
|
* dialogs.cpp
|
|
* Reboot, shutdown, and sleep confirmation dialogs
|
|
* Copyright (c) 2026 Daniel Hammer
|
|
*/
|
|
|
|
#include "desktop_internal.hpp"
|
|
|
|
// ============================================================================
|
|
// Reboot Dialog
|
|
// ============================================================================
|
|
|
|
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) {
|
|
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);
|
|
}
|
|
|
|
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);
|
|
|
|
if (ev.left_pressed()) {
|
|
if (rs->hover_reboot) montauk::reset();
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void reboot_dialog_on_key(Window* win, const Montauk::KeyEvent& key) {
|
|
RebootDialogState* rs = (RebootDialogState*)win->app_data;
|
|
if (!rs || !key.pressed) return;
|
|
|
|
if (key.ascii == '\n' || key.ascii == '\r') {
|
|
montauk::reset();
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
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);
|
|
if (idx < 0) return;
|
|
|
|
Window* win = &ds->windows[idx];
|
|
RebootDialogState* rs = (RebootDialogState*)montauk::malloc(sizeof(RebootDialogState));
|
|
montauk::memset(rs, 0, sizeof(RebootDialogState));
|
|
rs->ds = ds;
|
|
|
|
win->app_data = rs;
|
|
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;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Shutdown Dialog
|
|
// ============================================================================
|
|
|
|
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) {
|
|
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);
|
|
}
|
|
|
|
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);
|
|
|
|
if (ev.left_pressed()) {
|
|
if (ss->hover_shutdown) montauk::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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void shutdown_dialog_on_key(Window* win, const Montauk::KeyEvent& key) {
|
|
ShutdownDialogState* ss = (ShutdownDialogState*)win->app_data;
|
|
if (!ss || !key.pressed) return;
|
|
|
|
if (key.ascii == '\n' || key.ascii == '\r') {
|
|
montauk::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;
|
|
}
|
|
}
|
|
|
|
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);
|
|
if (idx < 0) return;
|
|
|
|
Window* win = &ds->windows[idx];
|
|
ShutdownDialogState* ss = (ShutdownDialogState*)montauk::malloc(sizeof(ShutdownDialogState));
|
|
montauk::memset(ss, 0, sizeof(ShutdownDialogState));
|
|
ss->ds = ds;
|
|
|
|
win->app_data = ss;
|
|
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;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Sleep (S3 Suspend) Dialog
|
|
// ============================================================================
|
|
|
|
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) {
|
|
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);
|
|
}
|
|
|
|
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);
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void sleep_dialog_on_key(Window* win, const Montauk::KeyEvent& key) {
|
|
SleepDialogState* ss = (SleepDialogState*)win->app_data;
|
|
if (!ss || !key.pressed) return;
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
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);
|
|
if (idx < 0) return;
|
|
|
|
Window* win = &ds->windows[idx];
|
|
SleepDialogState* ss = (SleepDialogState*)montauk::malloc(sizeof(SleepDialogState));
|
|
montauk::memset(ss, 0, sizeof(SleepDialogState));
|
|
ss->ds = ds;
|
|
|
|
win->app_data = ss;
|
|
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;
|
|
}
|