feat: desktop - use MTK menu for desktop right-click menu
This commit is contained in:
@@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MONTAUK_BUILD_NUMBER 84
|
#define MONTAUK_BUILD_NUMBER 87
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "gui/svg.hpp"
|
#include "gui/svg.hpp"
|
||||||
#include "gui/window.hpp"
|
#include "gui/window.hpp"
|
||||||
#include "gui/widgets.hpp"
|
#include "gui/widgets.hpp"
|
||||||
|
#include "gui/mtk/widgets.hpp"
|
||||||
#include "gui/terminal.hpp"
|
#include "gui/terminal.hpp"
|
||||||
#include <Api/Syscall.hpp>
|
#include <Api/Syscall.hpp>
|
||||||
|
|
||||||
@@ -172,8 +173,8 @@ struct DesktopState {
|
|||||||
int desktop_item_count;
|
int desktop_item_count;
|
||||||
int desktop_item_capacity;
|
int desktop_item_capacity;
|
||||||
|
|
||||||
bool ctx_menu_open;
|
// Right-click menu on the desktop background (MTK context menu).
|
||||||
int ctx_menu_x, ctx_menu_y;
|
mtk::ContextMenuState ctx_menu;
|
||||||
|
|
||||||
bool net_popup_open;
|
bool net_popup_open;
|
||||||
montauk::abi::NetCfg cached_net_cfg;
|
montauk::abi::NetCfg cached_net_cfg;
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ inline void draw_context_menu(Canvas& c,
|
|||||||
|
|
||||||
Rect menu = context_menu_rect(state, item_count, c.w, c.h,
|
Rect menu = context_menu_rect(state, item_count, c.w, c.h,
|
||||||
menu_w, item_h);
|
menu_w, item_h);
|
||||||
c.fill_rect(menu.x + 2, menu.y + 2, menu.w, menu.h,
|
c.fill_rounded_rect(menu.x + 2, menu.y + 2, menu.w, menu.h, 4,
|
||||||
Color::from_rgb(0x80, 0x80, 0x80));
|
Color::from_rgb(0x80, 0x80, 0x80));
|
||||||
c.fill_rounded_rect(menu.x, menu.y, menu.w, menu.h, 4,
|
c.fill_rounded_rect(menu.x, menu.y, menu.w, menu.h, 4,
|
||||||
colors::MENU_BG);
|
colors::MENU_BG);
|
||||||
|
|||||||
@@ -274,55 +274,16 @@ void gui::desktop_compose(DesktopState* ds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw right-click context menu if open
|
// Draw right-click context menu if open
|
||||||
if (ds->ctx_menu_open) {
|
if (ds->ctx_menu.open) {
|
||||||
static constexpr int CTX_MENU_W = 180;
|
gui::mtk::ContextMenuItem ctx_items[DESKTOP_CTX_COUNT];
|
||||||
static constexpr int CTX_ITEM_H = 36;
|
desktop_ctx_menu_items(ctx_items);
|
||||||
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
|
// The compositor draws straight into the back buffer; wrap it in a
|
||||||
if (cmx + CTX_MENU_W > sw) cmx = sw - CTX_MENU_W;
|
// Canvas so the shared MTK widget can render it.
|
||||||
if (cmy + cmh > sh) cmy = sh - cmh;
|
Canvas c(fb.buffer(), fb.pitch() / 4, sh);
|
||||||
|
gui::mtk::Theme theme = gui::mtk::make_theme(ds->settings.accent_color);
|
||||||
ensure_filemanager_icons_loaded(ds);
|
gui::mtk::draw_context_menu(c, ds->ctx_menu, ctx_items, DESKTOP_CTX_COUNT,
|
||||||
|
theme, DESKTOP_CTX_MENU_W, DESKTOP_CTX_ITEM_H);
|
||||||
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 },
|
|
||||||
{ "Settings", &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, gui::mtk::accent_hover_tint(ds->settings.accent_color));
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
if (ds->launcher_open) {
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ void desktop_lock_screen(DesktopState* ds) {
|
|||||||
ds->lock_show_error = false;
|
ds->lock_show_error = false;
|
||||||
ds->app_menu_open = false;
|
ds->app_menu_open = false;
|
||||||
desktop_close_launcher(ds);
|
desktop_close_launcher(ds);
|
||||||
ds->ctx_menu_open = false;
|
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||||
ds->net_popup_open = false;
|
ds->net_popup_open = false;
|
||||||
ds->wifi_popup_open = false;
|
ds->wifi_popup_open = false;
|
||||||
ds->vol_popup_open = false;
|
ds->vol_popup_open = false;
|
||||||
|
|||||||
@@ -8,8 +8,35 @@
|
|||||||
|
|
||||||
#include "apps/apps_common.hpp"
|
#include "apps/apps_common.hpp"
|
||||||
#include "wallpaper.hpp"
|
#include "wallpaper.hpp"
|
||||||
|
#include <gui/mtk.hpp>
|
||||||
#include <montauk/toml.h>
|
#include <montauk/toml.h>
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// Desktop Background Context Menu
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
|
enum DesktopCtxItem : int {
|
||||||
|
DESKTOP_CTX_TERMINAL = 0,
|
||||||
|
DESKTOP_CTX_FILES,
|
||||||
|
DESKTOP_CTX_SETTINGS,
|
||||||
|
DESKTOP_CTX_SLEEP,
|
||||||
|
DESKTOP_CTX_REBOOT,
|
||||||
|
DESKTOP_CTX_SHUTDOWN,
|
||||||
|
DESKTOP_CTX_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr int DESKTOP_CTX_MENU_W = 160;
|
||||||
|
static constexpr int DESKTOP_CTX_ITEM_H = 28;
|
||||||
|
|
||||||
|
inline void desktop_ctx_menu_items(gui::mtk::ContextMenuItem items[DESKTOP_CTX_COUNT]) {
|
||||||
|
items[DESKTOP_CTX_TERMINAL] = {"Terminal", DESKTOP_CTX_TERMINAL, true};
|
||||||
|
items[DESKTOP_CTX_FILES] = {"Files", DESKTOP_CTX_FILES, true};
|
||||||
|
items[DESKTOP_CTX_SETTINGS] = {"Settings", DESKTOP_CTX_SETTINGS, true};
|
||||||
|
items[DESKTOP_CTX_SLEEP] = {"Sleep", DESKTOP_CTX_SLEEP, true};
|
||||||
|
items[DESKTOP_CTX_REBOOT] = {"Reboot", DESKTOP_CTX_REBOOT, true};
|
||||||
|
items[DESKTOP_CTX_SHUTDOWN] = {"Shutdown", DESKTOP_CTX_SHUTDOWN, true};
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// App Menu Data (dynamic — built at startup from embedded + external apps)
|
// App Menu Data (dynamic — built at startup from embedded + external apps)
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -163,7 +163,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
|||||||
|
|
||||||
if (route_fullscreen_external_mouse(ds, ev, mx, my, buttons, prev)) {
|
if (route_fullscreen_external_mouse(ds, ev, mx, my, buttons, prev)) {
|
||||||
ds->app_menu_open = false;
|
ds->app_menu_open = false;
|
||||||
ds->ctx_menu_open = false;
|
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||||
ds->vol_popup_open = false;
|
ds->vol_popup_open = false;
|
||||||
ds->net_popup_open = false;
|
ds->net_popup_open = false;
|
||||||
ds->wifi_popup_open = false;
|
ds->wifi_popup_open = false;
|
||||||
@@ -176,41 +176,33 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle context menu clicks
|
// Handle context menu clicks
|
||||||
if (ds->ctx_menu_open) {
|
if (ds->ctx_menu.open) {
|
||||||
if (left_pressed) {
|
gui::mtk::ContextMenuItem ctx_items[DESKTOP_CTX_COUNT];
|
||||||
static constexpr int CTX_MENU_W = 180;
|
desktop_ctx_menu_items(ctx_items);
|
||||||
static constexpr int CTX_ITEM_H = 36;
|
int action = gui::mtk::context_menu_handle_mouse(
|
||||||
static constexpr int CTX_ITEM_COUNT = 6;
|
ds->ctx_menu, ctx_items, DESKTOP_CTX_COUNT, mx, my, buttons, prev,
|
||||||
int cmx = ds->ctx_menu_x;
|
ds->screen_w, ds->screen_h, DESKTOP_CTX_MENU_W, DESKTOP_CTX_ITEM_H);
|
||||||
int cmy = ds->ctx_menu_y;
|
|
||||||
int cmh = CTX_ITEM_H * CTX_ITEM_COUNT + 8;
|
|
||||||
if (cmx + CTX_MENU_W > ds->screen_w) cmx = ds->screen_w - CTX_MENU_W;
|
|
||||||
if (cmy + cmh > ds->screen_h) cmy = ds->screen_h - cmh;
|
|
||||||
|
|
||||||
Rect ctx_rect = {cmx, cmy, CTX_MENU_W, cmh};
|
switch (action) {
|
||||||
if (ctx_rect.contains(mx, my)) {
|
case DESKTOP_CTX_TERMINAL: open_terminal(ds); return;
|
||||||
int rel_y = my - cmy - 4;
|
case DESKTOP_CTX_FILES: open_filemanager(ds); return;
|
||||||
int item_idx = rel_y / CTX_ITEM_H;
|
case DESKTOP_CTX_SETTINGS:
|
||||||
if (item_idx >= 0 && item_idx < CTX_ITEM_COUNT) {
|
desktop_launch_builtin(ds, DESKTOP_BUILTIN_SYSTEM_CONFIGURATION);
|
||||||
ds->ctx_menu_open = false;
|
|
||||||
switch (item_idx) {
|
|
||||||
case 0: open_terminal(ds); break;
|
|
||||||
case 1: open_filemanager(ds); break;
|
|
||||||
case 2: desktop_launch_builtin(ds, DESKTOP_BUILTIN_SYSTEM_CONFIGURATION); break;
|
|
||||||
case 3: desktop_launch_builtin(ds, DESKTOP_BUILTIN_SLEEP); break;
|
|
||||||
case 4: desktop_launch_builtin(ds, DESKTOP_BUILTIN_REBOOT); break;
|
|
||||||
case 5: desktop_launch_builtin(ds, DESKTOP_BUILTIN_SHUTDOWN); break;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
case DESKTOP_CTX_SLEEP:
|
||||||
}
|
desktop_launch_builtin(ds, DESKTOP_BUILTIN_SLEEP);
|
||||||
ds->ctx_menu_open = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
case DESKTOP_CTX_REBOOT:
|
||||||
if (right_pressed) {
|
desktop_launch_builtin(ds, DESKTOP_BUILTIN_REBOOT);
|
||||||
ds->ctx_menu_open = false;
|
|
||||||
return;
|
return;
|
||||||
|
case DESKTOP_CTX_SHUTDOWN:
|
||||||
|
desktop_launch_builtin(ds, DESKTOP_BUILTIN_SHUTDOWN);
|
||||||
|
return;
|
||||||
|
default: break;
|
||||||
}
|
}
|
||||||
|
// A click outside the menu just dismisses it; plain motion (CONSUMED)
|
||||||
|
// falls through so window hover and drags keep working.
|
||||||
|
if (action == gui::mtk::CONTEXT_MENU_DISMISSED) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for ongoing window drags first
|
// Check for ongoing window drags first
|
||||||
@@ -542,7 +534,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
|||||||
ds->net_popup_open = false;
|
ds->net_popup_open = false;
|
||||||
ds->wifi_popup_open = false;
|
ds->wifi_popup_open = false;
|
||||||
ds->vol_popup_open = false;
|
ds->vol_popup_open = false;
|
||||||
ds->ctx_menu_open = false;
|
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,7 +545,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
|||||||
ds->app_menu_open = false;
|
ds->app_menu_open = false;
|
||||||
ds->net_popup_open = false;
|
ds->net_popup_open = false;
|
||||||
ds->wifi_popup_open = false;
|
ds->wifi_popup_open = false;
|
||||||
ds->ctx_menu_open = false;
|
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -563,7 +555,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
|||||||
ds->app_menu_open = false;
|
ds->app_menu_open = false;
|
||||||
ds->vol_popup_open = false;
|
ds->vol_popup_open = false;
|
||||||
ds->wifi_popup_open = false;
|
ds->wifi_popup_open = false;
|
||||||
ds->ctx_menu_open = false;
|
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -573,7 +565,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
|||||||
ds->app_menu_open = false;
|
ds->app_menu_open = false;
|
||||||
ds->vol_popup_open = false;
|
ds->vol_popup_open = false;
|
||||||
ds->net_popup_open = false;
|
ds->net_popup_open = false;
|
||||||
ds->ctx_menu_open = false;
|
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Window indicator buttons
|
// Window indicator buttons
|
||||||
@@ -725,7 +717,7 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ds->app_menu_open = false;
|
ds->app_menu_open = false;
|
||||||
ds->ctx_menu_open = false;
|
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||||
ds->vol_popup_open = false;
|
ds->vol_popup_open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -792,9 +784,14 @@ void gui::desktop_handle_mouse(DesktopState* ds) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!on_window) {
|
if (!on_window) {
|
||||||
ds->ctx_menu_open = true;
|
gui::mtk::context_menu_open(ds->ctx_menu, mx, my);
|
||||||
ds->ctx_menu_x = mx;
|
// Pin the menu inside the screen up front so hit-testing and
|
||||||
ds->ctx_menu_y = my;
|
// drawing agree on where it landed.
|
||||||
|
Rect r = gui::mtk::context_menu_rect(ds->ctx_menu, DESKTOP_CTX_COUNT,
|
||||||
|
ds->screen_w, ds->screen_h,
|
||||||
|
DESKTOP_CTX_MENU_W, DESKTOP_CTX_ITEM_H);
|
||||||
|
ds->ctx_menu.x = r.x;
|
||||||
|
ds->ctx_menu.y = r.y;
|
||||||
ds->app_menu_open = false;
|
ds->app_menu_open = false;
|
||||||
ds->net_popup_open = false;
|
ds->net_popup_open = false;
|
||||||
ds->wifi_popup_open = false;
|
ds->wifi_popup_open = false;
|
||||||
@@ -823,7 +820,7 @@ void gui::desktop_handle_keyboard(DesktopState* ds, const montauk::abi::KeyEvent
|
|||||||
montauk::win_sendevent(win->ext_win_id, &ev);
|
montauk::win_sendevent(win->ext_win_id, &ev);
|
||||||
ds->launcher_open = false;
|
ds->launcher_open = false;
|
||||||
ds->app_menu_open = false;
|
ds->app_menu_open = false;
|
||||||
ds->ctx_menu_open = false;
|
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -404,7 +404,7 @@ void desktop_open_launcher(DesktopState* ds) {
|
|||||||
ds->launcher_selected = -1;
|
ds->launcher_selected = -1;
|
||||||
ds->launcher_scroll = 0;
|
ds->launcher_scroll = 0;
|
||||||
ds->app_menu_open = false;
|
ds->app_menu_open = false;
|
||||||
ds->ctx_menu_open = false;
|
gui::mtk::context_menu_close(ds->ctx_menu);
|
||||||
ds->net_popup_open = false;
|
ds->net_popup_open = false;
|
||||||
ds->wifi_popup_open = false;
|
ds->wifi_popup_open = false;
|
||||||
ds->vol_popup_open = false;
|
ds->vol_popup_open = false;
|
||||||
|
|||||||
@@ -384,9 +384,7 @@ void gui::desktop_init(DesktopState* ds) {
|
|||||||
|
|
||||||
montauk::win_setscale(ds->settings.ui_scale);
|
montauk::win_setscale(ds->settings.ui_scale);
|
||||||
|
|
||||||
ds->ctx_menu_open = false;
|
gui::mtk::context_menu_reset(ds->ctx_menu);
|
||||||
ds->ctx_menu_x = 0;
|
|
||||||
ds->ctx_menu_y = 0;
|
|
||||||
|
|
||||||
ds->net_popup_open = false;
|
ds->net_popup_open = false;
|
||||||
montauk::get_netcfg(&ds->cached_net_cfg);
|
montauk::get_netcfg(&ds->cached_net_cfg);
|
||||||
|
|||||||
Reference in New Issue
Block a user