feat: improve MTK input boxes, right-click context menus

This commit is contained in:
2026-05-06 08:03:14 +02:00
parent f19e97966d
commit 8997164203
15 changed files with 1337 additions and 256 deletions
@@ -183,6 +183,7 @@ void filemanager_open_ctx_menu(FileManagerState* fm, int local_x, int local_y, i
void filemanager_close_ctx_menu(FileManagerState* fm) {
fm->ctx_open = false;
fm->ctx_hover = -1;
}
} // namespace filemanager
@@ -25,50 +25,35 @@ void filemanager_on_mouse(Window* win, MouseEvent& ev) {
// ---- Context menu interaction ----
if (fm->ctx_open) {
int cmx = fm->ctx_x;
int cmy = fm->ctx_y;
int cmh = fm->ctx_item_count * CTX_ITEM_H + 8;
if (cmx + CTX_MENU_W > cw) cmx = cw - CTX_MENU_W;
if (cmy + cmh > win->content_h) cmy = win->content_h - cmh;
if (cmx < 0) cmx = 0;
if (cmy < 0) cmy = 0;
mtk::ContextMenuState state = filemanager_context_state(fm);
mtk::ContextMenuItem items[8];
filemanager_build_context_items(fm, items, 8);
int action = mtk::context_menu_handle_mouse(state, items,
fm->ctx_item_count,
local_x, local_y,
ev.buttons, ev.prev_buttons,
cw, win->content_h);
filemanager_store_context_state(fm, state);
// Update hover
if (local_x >= cmx && local_x < cmx + CTX_MENU_W &&
local_y >= cmy + 4 && local_y < cmy + 4 + fm->ctx_item_count * CTX_ITEM_H) {
fm->ctx_hover = (local_y - cmy - 4) / CTX_ITEM_H;
} else {
fm->ctx_hover = -1;
}
if (action >= 0) {
int target = fm->ctx_target_idx;
if (ev.left_pressed()) {
if (fm->ctx_hover >= 0 && fm->ctx_hover < fm->ctx_item_count) {
int action = fm->ctx_items[fm->ctx_hover];
int target = fm->ctx_target_idx;
filemanager_close_ctx_menu(fm);
// Select target if needed
if (target >= 0 && target < fm->entry_count)
fm->selected = target;
// Select target if needed
if (target >= 0 && target < fm->entry_count)
fm->selected = target;
switch (action) {
case CTX_OPEN: filemanager_open_entry(fm, target); break;
case CTX_COPY: filemanager_do_copy(fm); break;
case CTX_CUT: filemanager_do_cut(fm); break;
case CTX_PASTE: filemanager_do_paste(fm); break;
case CTX_RENAME: filemanager_start_rename(fm); break;
case CTX_DELETE: filemanager_delete_selected(fm); break;
case CTX_NEW_FOLDER: filemanager_new_folder(fm); break;
}
} else {
filemanager_close_ctx_menu(fm);
switch (action) {
case CTX_OPEN: filemanager_open_entry(fm, target); break;
case CTX_COPY: filemanager_do_copy(fm); break;
case CTX_CUT: filemanager_do_cut(fm); break;
case CTX_PASTE: filemanager_do_paste(fm); break;
case CTX_RENAME: filemanager_start_rename(fm); break;
case CTX_DELETE: filemanager_delete_selected(fm); break;
case CTX_NEW_FOLDER: filemanager_new_folder(fm); break;
}
return;
}
if (ev.right_pressed()) {
filemanager_close_ctx_menu(fm);
return;
}
if (action == mtk::CONTEXT_MENU_DISMISSED) return;
return;
}
@@ -7,6 +7,7 @@
#pragma once
#include "../apps_common.hpp"
#include <gui/mtk/widgets.hpp>
namespace filemanager {
@@ -131,9 +132,6 @@ inline constexpr int CTX_RENAME = 4;
inline constexpr int CTX_DELETE = 5;
inline constexpr int CTX_NEW_FOLDER = 6;
inline constexpr int CTX_MENU_W = 140;
inline constexpr int CTX_ITEM_H = 24;
inline bool filemanager_is_virtual_view(const FileManagerState* fm) {
return fm && fm->virtual_view != FM_VIRTUAL_VIEW_NONE;
}
@@ -153,6 +151,29 @@ inline const char* filemanager_virtual_view_label(FileManagerVirtualViewKind vie
int special_folder_index(const char* name);
const char* ctx_label(int action);
inline mtk::ContextMenuState filemanager_context_state(const FileManagerState* fm) {
if (!fm) return {};
return {fm->ctx_open, fm->ctx_x, fm->ctx_y, fm->ctx_hover};
}
inline void filemanager_store_context_state(FileManagerState* fm,
const mtk::ContextMenuState& state) {
if (!fm) return;
fm->ctx_open = state.open;
fm->ctx_x = state.x;
fm->ctx_y = state.y;
fm->ctx_hover = state.hover;
}
inline void filemanager_build_context_items(const FileManagerState* fm,
mtk::ContextMenuItem* items,
int max_items) {
if (!fm || !items || max_items <= 0) return;
int count = fm->ctx_item_count < max_items ? fm->ctx_item_count : max_items;
for (int i = 0; i < count; i++)
items[i] = {ctx_label(fm->ctx_items[i]), fm->ctx_items[i], true};
}
bool str_ends_with(const char* s, const char* suffix);
bool is_image_file(const char* name);
bool is_font_file(const char* name);
@@ -576,33 +576,14 @@ void filemanager_on_draw(Window* win, Framebuffer& fb) {
// ---- Context menu overlay ----
if (fm->ctx_open && fm->ctx_item_count > 0) {
int cmx = fm->ctx_x;
int cmy = fm->ctx_y;
int cmh = fm->ctx_item_count * CTX_ITEM_H + 8;
mtk::Theme theme = mtk::make_theme(colors::ACCENT);
theme.border = colors::BORDER;
theme.text = colors::TEXT_COLOR;
// Clamp to window bounds
if (cmx + CTX_MENU_W > c.w) cmx = c.w - CTX_MENU_W;
if (cmy + cmh > c.h) cmy = c.h - cmh;
if (cmx < 0) cmx = 0;
if (cmy < 0) cmy = 0;
// Shadow
c.fill_rect(cmx + 2, cmy + 2, CTX_MENU_W, cmh, Color::from_rgb(0x80, 0x80, 0x80));
// Background
c.fill_rounded_rect(cmx, cmy, CTX_MENU_W, cmh, 4, colors::WHITE);
c.rect(cmx, cmy, CTX_MENU_W, cmh, colors::BORDER);
for (int i = 0; i < fm->ctx_item_count; i++) {
int iy = cmy + 4 + i * CTX_ITEM_H;
// Hover highlight
if (i == fm->ctx_hover)
c.fill_rect(cmx + 2, iy, CTX_MENU_W - 4, CTX_ITEM_H, colors::MENU_HOVER);
int fh = system_font_height();
int ty = iy + (CTX_ITEM_H - fh) / 2;
c.text(cmx + 12, ty, ctx_label(fm->ctx_items[i]), colors::TEXT_COLOR);
}
mtk::ContextMenuItem items[8];
filemanager_build_context_items(fm, items, 8);
mtk::draw_context_menu(c, filemanager_context_state(fm), items,
fm->ctx_item_count, theme);
}
}