feat: improve MTK input boxes, right-click context menus
This commit is contained in:
@@ -542,6 +542,7 @@ void wp_init_empty_document(WordProcessorState* wp) {
|
||||
wp->line_spacing_dropdown_open = false;
|
||||
wp->divider_flyout_open = false;
|
||||
wp->special_char_flyout_open = false;
|
||||
mtk::context_menu_reset(wp->context_menu);
|
||||
wp->page_view_mode = false;
|
||||
wp->pending_page_view_toggle = false;
|
||||
|
||||
|
||||
@@ -65,6 +65,59 @@ static bool wp_paste_from_clipboard(WordProcessorState* wp) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wp_context_item_enabled(WordProcessorState* wp, int item) {
|
||||
switch (item) {
|
||||
case WP_CTX_CUT:
|
||||
case WP_CTX_COPY:
|
||||
case WP_CTX_DELETE:
|
||||
return wp && wp->has_selection;
|
||||
case WP_CTX_PASTE:
|
||||
return gui::clipboard_has_text();
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void wp_build_context_items(WordProcessorState* wp,
|
||||
mtk::ContextMenuItem items[WP_CTX_COUNT]) {
|
||||
items[WP_CTX_CUT] = {"Cut", WP_CTX_CUT,
|
||||
wp_context_item_enabled(wp, WP_CTX_CUT)};
|
||||
items[WP_CTX_COPY] = {"Copy", WP_CTX_COPY,
|
||||
wp_context_item_enabled(wp, WP_CTX_COPY)};
|
||||
items[WP_CTX_PASTE] = {"Paste", WP_CTX_PASTE,
|
||||
wp_context_item_enabled(wp, WP_CTX_PASTE)};
|
||||
items[WP_CTX_DELETE] = {"Delete", WP_CTX_DELETE,
|
||||
wp_context_item_enabled(wp, WP_CTX_DELETE)};
|
||||
}
|
||||
|
||||
static bool wp_selection_contains_abs(WordProcessorState* wp, int abs) {
|
||||
if (!wp || !wp->has_selection) return false;
|
||||
int sel_s = 0;
|
||||
int sel_e = 0;
|
||||
wp_sel_range(wp, &sel_s, &sel_e);
|
||||
return abs >= sel_s && abs < sel_e;
|
||||
}
|
||||
|
||||
static bool wp_perform_context_action(WordProcessorState* wp, int item) {
|
||||
if (!wp_context_item_enabled(wp, item)) return false;
|
||||
|
||||
switch (item) {
|
||||
case WP_CTX_CUT:
|
||||
return wp_cut_selection_to_clipboard(wp);
|
||||
case WP_CTX_COPY:
|
||||
return wp_copy_selection_to_clipboard(wp);
|
||||
case WP_CTX_PASTE:
|
||||
return wp_paste_from_clipboard(wp);
|
||||
case WP_CTX_DELETE:
|
||||
wp_delete_selection(wp);
|
||||
wp_history_checkpoint(wp);
|
||||
wp_set_status(wp, "Deleted selection");
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void wp_open_pathbar_for_open(WordProcessorState* wp) {
|
||||
char path[256] = {};
|
||||
char msg[160] = {};
|
||||
@@ -255,6 +308,26 @@ void wp_handle_mouse(const Montauk::WinEvent& ev) {
|
||||
recompute_w = WP_A4_PAGE_W;
|
||||
}
|
||||
|
||||
if (wp->context_menu.open) {
|
||||
if (ev.mouse.scroll != 0) {
|
||||
mtk::context_menu_close(wp->context_menu);
|
||||
return;
|
||||
}
|
||||
|
||||
mtk::ContextMenuItem items[WP_CTX_COUNT];
|
||||
wp_build_context_items(wp, items);
|
||||
int action = mtk::context_menu_handle_mouse(wp->context_menu,
|
||||
items, WP_CTX_COUNT,
|
||||
local_x, local_y,
|
||||
ev.mouse.buttons,
|
||||
ev.mouse.prev_buttons,
|
||||
g_win_w, g_win_h);
|
||||
if (action >= 0)
|
||||
wp_perform_context_action(wp, action);
|
||||
if (action != mtk::CONTEXT_MENU_NONE)
|
||||
return;
|
||||
}
|
||||
|
||||
wp->scrollbar.handle_mouse(local_x, local_y, ev.mouse.buttons, ev.mouse.prev_buttons, ev.mouse.scroll);
|
||||
|
||||
if (wp->font_dropdown_open && wp_left_pressed(ev.mouse.buttons, ev.mouse.prev_buttons)) {
|
||||
@@ -464,6 +537,27 @@ void wp_handle_mouse(const Montauk::WinEvent& ev) {
|
||||
|
||||
wp_recompute_wrap(wp, recompute_w, WP_SCREEN_DPI);
|
||||
|
||||
bool right_pressed = wp_right_pressed(ev.mouse.buttons, ev.mouse.prev_buttons);
|
||||
bool in_text_area = local_y >= edit_y && local_y < edit_y + text_area_h &&
|
||||
local_x >= 0 && local_x < g_win_w - WP_SCROLLBAR_W;
|
||||
if (in_text_area && wp->page_view_mode) {
|
||||
in_text_area = local_x >= page_off_x && local_x < page_off_x + WP_A4_PAGE_W &&
|
||||
local_y >= page_off_y && local_y < page_off_y + WP_A4_PAGE_H;
|
||||
}
|
||||
|
||||
if (right_pressed && in_text_area) {
|
||||
wp_close_dropdowns(wp);
|
||||
|
||||
int abs = wp_hit_test_text(wp, local_x, local_y, edit_y, page_off_x, page_off_y);
|
||||
if (!wp_selection_contains_abs(wp, abs)) {
|
||||
wp_pos_to_run(wp, abs, &wp->cursor_run, &wp->cursor_offset);
|
||||
wp_clear_selection(wp);
|
||||
}
|
||||
wp->mouse_selecting = false;
|
||||
mtk::context_menu_open(wp->context_menu, local_x, local_y);
|
||||
return;
|
||||
}
|
||||
|
||||
if (wp_left_pressed(ev.mouse.buttons, ev.mouse.prev_buttons) &&
|
||||
local_y >= edit_y && local_y < edit_y + text_area_h) {
|
||||
wp_close_dropdowns(wp);
|
||||
@@ -502,6 +596,11 @@ void wp_handle_key(const Montauk::KeyEvent& key) {
|
||||
WordProcessorState* wp = &g_wp;
|
||||
if (!key.pressed) return;
|
||||
|
||||
if (wp->context_menu.open) {
|
||||
mtk::context_menu_close(wp->context_menu);
|
||||
if (key.scancode == 0x01) return;
|
||||
}
|
||||
|
||||
if (wp->show_pathbar) {
|
||||
if (key.ascii == '\n' || key.ascii == '\r') {
|
||||
wp_commit_pathbar(wp);
|
||||
|
||||
@@ -35,6 +35,21 @@ static void wp_draw_ui_icon_button(Canvas& c, int x, int y, int w, int h,
|
||||
wp_draw_ui_button(c, x, y, w, h, fallback, bg, fg, radius);
|
||||
}
|
||||
|
||||
static void wp_draw_context_menu(Canvas& c, WordProcessorState* wp) {
|
||||
if (!wp || !wp->context_menu.open) return;
|
||||
|
||||
mtk::Theme theme = mtk::make_theme(colors::ACCENT);
|
||||
theme.border = colors::BORDER;
|
||||
theme.text = colors::TEXT_COLOR;
|
||||
|
||||
mtk::ContextMenuItem items[WP_CTX_COUNT];
|
||||
wp_build_context_items(wp, items);
|
||||
mtk::draw_context_menu(c, wp->context_menu, items, WP_CTX_COUNT, theme,
|
||||
mtk::CONTEXT_MENU_DEFAULT_W,
|
||||
mtk::CONTEXT_MENU_ITEM_H,
|
||||
g_ui_font, fonts::UI_SIZE);
|
||||
}
|
||||
|
||||
static int wp_special_char_flyout_x() {
|
||||
int dx = WP_BTN_SECTION_X + 24 - WP_SPECIAL_CHAR_FLYOUT_W;
|
||||
if (dx + WP_SPECIAL_CHAR_FLYOUT_W > g_win_w) dx = g_win_w - WP_SPECIAL_CHAR_FLYOUT_W;
|
||||
@@ -666,4 +681,6 @@ void wp_render() {
|
||||
WP_SPECIAL_CHAR_OPTIONS[i].label, colors::TEXT_COLOR);
|
||||
}
|
||||
}
|
||||
|
||||
wp_draw_context_menu(c, wp);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <gui/standalone.hpp>
|
||||
#include <gui/truetype.hpp>
|
||||
#include <gui/svg.hpp>
|
||||
#include <gui/mtk/widgets.hpp>
|
||||
|
||||
extern "C" {
|
||||
#include <string.h>
|
||||
@@ -239,6 +240,18 @@ inline bool wp_left_released(uint8_t buttons, uint8_t prev_buttons) {
|
||||
return !(buttons & 0x01) && (prev_buttons & 0x01);
|
||||
}
|
||||
|
||||
inline bool wp_right_pressed(uint8_t buttons, uint8_t prev_buttons) {
|
||||
return (buttons & 0x02) && !(prev_buttons & 0x02);
|
||||
}
|
||||
|
||||
enum WpContextItem : int {
|
||||
WP_CTX_CUT = 0,
|
||||
WP_CTX_COPY,
|
||||
WP_CTX_PASTE,
|
||||
WP_CTX_DELETE,
|
||||
WP_CTX_COUNT,
|
||||
};
|
||||
|
||||
struct WpScrollbar {
|
||||
Rect bounds;
|
||||
int content_height;
|
||||
@@ -370,6 +383,7 @@ struct WordProcessorState {
|
||||
bool line_spacing_dropdown_open;
|
||||
bool divider_flyout_open;
|
||||
bool special_char_flyout_open;
|
||||
mtk::ContextMenuState context_menu;
|
||||
bool page_view_mode;
|
||||
bool pending_page_view_toggle;
|
||||
|
||||
@@ -462,6 +476,9 @@ bool wp_redo(WordProcessorState* wp);
|
||||
|
||||
bool wp_print_document(WordProcessorState* wp, char* out_status, int out_status_len);
|
||||
bool wp_export_pdf_document(WordProcessorState* wp, const char* path, char* out_status, int out_status_len);
|
||||
bool wp_context_item_enabled(WordProcessorState* wp, int item);
|
||||
void wp_build_context_items(WordProcessorState* wp,
|
||||
mtk::ContextMenuItem items[WP_CTX_COUNT]);
|
||||
|
||||
void wp_render();
|
||||
void wp_handle_mouse(const Montauk::WinEvent& ev);
|
||||
|
||||
Reference in New Issue
Block a user