diff --git a/.codex b/.codex new file mode 100644 index 0000000..e69de29 diff --git a/programs/src/printers/main.cpp b/programs/src/printers/main.cpp index 99c2219..64f912c 100644 --- a/programs/src/printers/main.cpp +++ b/programs/src/printers/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -32,7 +33,6 @@ static constexpr int TAB_BAR_H = 36; static constexpr int PAD_X = 16; static constexpr int PAD_Y = 20; static constexpr int BTN_H = 30; -static constexpr int ACTION_RADIUS = 4; static constexpr int FIELD_H = 32; static constexpr int PRINTER_ICON_SIZE = 24; @@ -79,6 +79,10 @@ struct AppState { char edit_uri[MAX_PATH_LEN]; int edit_len; char edit_error[128]; + int mouse_x; + int mouse_y; + int config_mouse_x; + int config_mouse_y; Color accent; }; @@ -94,6 +98,7 @@ struct Layout { }; struct ConfigLayout { + int input_label_y; Rect input; Rect save_btn; Rect cancel_btn; @@ -153,6 +158,13 @@ static void set_accent(Color accent) { g_app.accent = accent; } +static mtk::Theme printers_theme() { + mtk::Theme theme = mtk::make_theme(g_app.accent); + theme.disabled_bg = Color::from_rgb(0xE6, 0xE6, 0xE6); + theme.disabled_fg = Color::from_rgb(0x9A, 0x9A, 0x9A); + return theme; +} + static void load_accent() { set_accent(colors::ACCENT); @@ -255,95 +267,39 @@ static void text_fit(const char* src, char* out, int out_len, int max_w) { montauk::strncpy(out, ell, out_len - 1); } -static void draw_action_btn(Canvas& c, const Rect& r, const char* label, - bool enabled, bool primary) { - Color bg; - Color fg; - if (!enabled) { - bg = Color::from_rgb(0xE6, 0xE6, 0xE6); - fg = Color::from_rgb(0x9A, 0x9A, 0x9A); - } else if (primary) { - bg = g_app.accent; - fg = colors::WHITE; - } else { - bg = colors::WINDOW_BG; - fg = colors::TEXT_COLOR; - } - - c.fill_rounded_rect(r.x, r.y, r.w, r.h, ACTION_RADIUS, bg); - if (enabled && !primary) c.rect(r.x, r.y, r.w, r.h, colors::BORDER); - if (!enabled) c.rect(r.x, r.y, r.w, r.h, Color::from_rgb(0xD4, 0xD4, 0xD4)); - - int tw = text_width(label); - int fh = system_font_height(); - c.text(r.x + (r.w - tw) / 2, r.y + (r.h - fh) / 2, label, fg); +static bool main_mouse_in_rect(const Rect& rect) { + return rect.contains(g_app.mouse_x, g_app.mouse_y); } -static void draw_chip(Canvas& c, int x, int y, const char* label, Color bg, Color fg = colors::WHITE) { - int sfh = system_font_height(); - int chip_h = sfh + 8; - int chip_w = text_width(label) + 18; - c.fill_rounded_rect(x, y, chip_w, chip_h, chip_h / 2, bg); - c.text(x + 9, y + (chip_h - sfh) / 2, label, fg); +static bool config_mouse_in_rect(const Rect& rect) { + return rect.contains(g_app.config_mouse_x, g_app.config_mouse_y); } -static int chip_height() { - return system_font_height() + 8; +static mtk::WidgetState main_button_state(const Rect& rect, bool enabled, bool active = false) { + return mtk::widget_state(active, main_mouse_in_rect(rect), enabled); +} + +static mtk::WidgetState config_button_state(const Rect& rect, bool enabled, bool active = false) { + return mtk::widget_state(active, config_mouse_in_rect(rect), enabled); } static int control_row_text_y(int row_y) { - return row_y + 6; + return row_y + (BTN_H - system_font_height()) / 2; } -static int control_row_chip_y(int row_y) { - return row_y + 2; +static int control_row_badge_y(int row_y) { + return row_y + (BTN_H - mtk::badge_height()) / 2; } static void draw_overview_stat_row(Canvas& c, int x, int y, int w, - const char* label, int value) { + const char* label, int value, + const mtk::Theme& theme) { char value_buf[16]; snprintf(value_buf, sizeof(value_buf), "%d", value); - c.text(x, y, label, colors::TEXT_COLOR); + c.text(x, y, label, theme.text); int value_w = text_width(value_buf); - c.text(x + w - value_w, y, value_buf, colors::TEXT_COLOR); -} - -static void draw_tabs(Canvas& c) { - int sfh = system_font_height(); - c.fill_rect(0, 0, g_win.width, TAB_BAR_H, Color::from_rgb(0xF5, 0xF5, 0xF5)); - c.hline(0, TAB_BAR_H - 1, g_win.width, colors::BORDER); - - int tab_w = g_win.width / TAB_COUNT; - for (int i = 0; i < TAB_COUNT; i++) { - int tx = i * tab_w; - bool active = (i == g_app.active_tab); - if (active) { - c.fill_rect(tx, 0, tab_w, TAB_BAR_H, colors::WINDOW_BG); - c.fill_rect(tx + 4, TAB_BAR_H - 3, tab_w - 8, 3, g_app.accent); - } - - int tw = text_width(g_tab_labels[i]); - Color tc = active ? g_app.accent : Color::from_rgb(0x66, 0x66, 0x66); - c.text(tx + (tab_w - tw) / 2, (TAB_BAR_H - sfh) / 2, g_tab_labels[i], tc); - } -} - -static void draw_input_field(Canvas& c, int x, int y, int w, int h, - const char* label, const char* value, bool focused) { - int sfh = system_font_height(); - Color dim = Color::from_rgb(0x88, 0x88, 0x88); - - c.text(x, y, label, dim); - y += sfh + 2; - c.fill_rounded_rect(x, y, w, h, 3, Color::from_rgb(0xF5, 0xF5, 0xF5)); - c.rect(x, y, w, h, focused ? g_app.accent : colors::BORDER); - c.text(x + 8, y + (h - sfh) / 2, value, colors::TEXT_COLOR); - - if (focused) { - int tw = text_width(value); - c.fill_rect(x + 8 + tw, y + 6, 2, h - 12, g_app.accent); - } + c.text(x + w - value_w, y, value_buf, theme.text); } static void compute_layout(Layout* lo) { @@ -444,14 +400,19 @@ static void compute_layout(Layout* lo) { } +static Rect tab_bar_rect() { + return {0, 0, g_win.width, TAB_BAR_H}; +} + static void compute_config_layout(ConfigLayout* lo) { + mtk::Theme theme = printers_theme(); int pad = 16; int sfh = system_font_height(); int field_w = g_config.width - pad * 2; if (field_w < 120) field_w = 120; - int input_box_y = 16 + sfh + 6 + sfh + 10 + sfh + 2; - lo->input = {pad, input_box_y, field_w, FIELD_H}; + lo->input_label_y = 16 + sfh + 6 + sfh + 10; + lo->input = mtk::labeled_text_input_rect(pad, lo->input_label_y, field_w, theme, FIELD_H); lo->save_btn = {pad, g_config.height - BTN_H - 16, 80, BTN_H}; lo->cancel_btn = {pad + 88, g_config.height - BTN_H - 16, 80, BTN_H}; } @@ -509,6 +470,8 @@ static void open_config_popup() { g_app.edit_len = montauk::slen(g_app.edit_uri); g_app.edit_error[0] = '\0'; g_app.config_button_down = 0; + g_app.config_mouse_x = -1; + g_app.config_mouse_y = -1; if (!g_config.open) { Montauk::WinCreateResult wres; @@ -554,48 +517,55 @@ static void render_config_popup() { if (!g_app.config_open || !g_config.open || g_config.win_id < 0 || g_config.pixels == nullptr) return; Canvas c(g_config.pixels, g_config.width, g_config.height); - c.fill(colors::WINDOW_BG); + mtk::Theme theme = printers_theme(); + c.fill(theme.window_bg); ConfigLayout lo = {}; compute_config_layout(&lo); int sfh = system_font_height(); int x = 16; int y = 16; - c.text(x, y, "Default Printer", colors::TEXT_COLOR); + c.text(x, y, "Default Printer", theme.text); y += sfh + 6; - c.text(x, y, "Enter an IPP or IPPS destination URI.", Color::from_rgb(0x88, 0x88, 0x88)); - y += sfh + 10; + c.text(x, y, "Enter an IPP or IPPS destination URI.", theme.text_muted); - draw_input_field(c, lo.input.x, lo.input.y - (sfh + 2), - lo.input.w, lo.input.h, "Printer URI", - g_app.edit_uri, true); + mtk::draw_labeled_text_field(c, lo.input.x, lo.input_label_y, lo.input.w, + "Printer URI", g_app.edit_uri, g_app.edit_len, + true, false, theme, lo.input.h); y = lo.input.y + lo.input.h + 12; - c.text(x, y, "Example: ipp://printer.local/ipp/print", Color::from_rgb(0x88, 0x88, 0x88)); + c.text(x, y, "Example: ipp://printer.local/ipp/print", theme.text_muted); y += sfh + 10; if (g_app.edit_error[0]) - c.text(x, y, g_app.edit_error, Color::from_rgb(0xD0, 0x3E, 0x3E)); + c.text(x, y, g_app.edit_error, theme.danger); - draw_action_btn(c, lo.save_btn, "Save", true, true); - draw_action_btn(c, lo.cancel_btn, "Cancel", true, false); + mtk::draw_modal_actions(c, + lo.save_btn, "Save", + mtk::BUTTON_PRIMARY, + config_button_state(lo.save_btn, true, g_app.config_button_down == 1), + lo.cancel_btn, "Cancel", + config_button_state(lo.cancel_btn, true, g_app.config_button_down == 2), + theme); montauk::win_present(g_config.win_id); } static bool handle_config_mouse(int mx, int my, uint8_t buttons, uint8_t prev_buttons) { ConfigLayout lo = {}; compute_config_layout(&lo); + g_app.config_mouse_x = mx; + g_app.config_mouse_y = my; bool left_pressed = (buttons & 1) && !(prev_buttons & 1); bool left_released = !(buttons & 1) && (prev_buttons & 1); if (left_pressed) { + int button_down = 0; if (lo.save_btn.contains(mx, my)) - g_app.config_button_down = 1; + button_down = 1; else if (lo.cancel_btn.contains(mx, my)) - g_app.config_button_down = 2; - else - g_app.config_button_down = 0; + button_down = 2; + g_app.config_button_down = button_down; return false; } @@ -642,10 +612,10 @@ static bool handle_config_key(const Montauk::KeyEvent& key) { return false; } -static void render_overview(Canvas& c, const Layout& lo) { - Color dim = Color::from_rgb(0x88, 0x88, 0x88); +static void render_overview(Canvas& c, const Layout& lo, const mtk::Theme& theme) { + Color dim = theme.text_muted; Color success = Color::from_rgb(0x22, 0x88, 0x22); - Color danger = Color::from_rgb(0xCC, 0x33, 0x33); + Color danger = theme.danger; Color quiet_bg = Color::from_rgb(0xE6, 0xE6, 0xE6); int sfh = system_font_height(); int x = PAD_X; @@ -655,13 +625,13 @@ static void render_overview(Canvas& c, const Layout& lo) { char title[MAX_DEBUG_LEN]; if (status_visible()) { - c.text(x, y, g_app.status_msg, g_app.accent); + c.text(x, y, g_app.status_msg, theme.accent); y += sfh + 12; } const char* chip_label = "Not Set"; Color chip_bg = quiet_bg; - Color chip_fg = colors::TEXT_COLOR; + Color chip_fg = theme.text; if (g_app.printer_uri[0] && g_app.probe_ok) { chip_label = "Ready"; chip_bg = success; @@ -672,11 +642,11 @@ static void render_overview(Canvas& c, const Layout& lo) { chip_fg = colors::WHITE; } else if (g_app.printer_uri[0]) { chip_label = "Checking"; - chip_bg = Color::from_rgb(0xE3, 0xE8, 0xEF); - chip_fg = colors::TEXT_COLOR; + chip_bg = theme.accent_soft; + chip_fg = theme.text; } - int chip_w = text_width(chip_label) + 18; + int chip_w = mtk::badge_width(chip_label, theme); int chip_x = lo.configure_btn.x - chip_w - 12; if (chip_x < x + 74) chip_x = x + 74; @@ -696,10 +666,12 @@ static void render_overview(Canvas& c, const Layout& lo) { if (lo.printer_icon.w > 0 && g_printer_icon.pixels) c.icon(lo.printer_icon.x, lo.printer_icon.y, g_printer_icon); - c.text(title_x, control_row_text_y(y), title, colors::TEXT_COLOR); - draw_chip(c, chip_x, control_row_chip_y(y), chip_label, chip_bg, chip_fg); - draw_action_btn(c, lo.configure_btn, "Configure", true, true); - draw_action_btn(c, lo.clear_btn, "Clear", g_app.printer_uri[0] != '\0', false); + c.text(title_x, control_row_text_y(y), title, theme.text); + mtk::draw_badge(c, chip_x, control_row_badge_y(y), chip_label, chip_bg, chip_fg, theme); + mtk::draw_button(c, lo.configure_btn, "Configure", mtk::BUTTON_PRIMARY, + main_button_state(lo.configure_btn, true), theme); + mtk::draw_button(c, lo.clear_btn, "Clear", mtk::BUTTON_SECONDARY, + main_button_state(lo.clear_btn, g_app.printer_uri[0] != '\0'), theme); y += BTN_H + 8; char line[MAX_DEBUG_LEN]; @@ -709,7 +681,7 @@ static void render_overview(Canvas& c, const Layout& lo) { else safe_copy(line, sizeof(line), "No printer configured"); text_fit(line, line, sizeof(line), w); - c.text(x, y, line, colors::TEXT_COLOR); + c.text(x, y, line, theme.text); y += sfh + 4; } @@ -737,7 +709,7 @@ static void render_overview(Canvas& c, const Layout& lo) { c.text(x, y, "Waiting for the spooler to probe the configured printer.", dim); } y += sfh + 14; - c.hline(x, y, w, colors::BORDER); + mtk::draw_separator(c, x, y, w, theme); y += 16; if (!g_app.printer_uri[0]) { @@ -745,23 +717,23 @@ static void render_overview(Canvas& c, const Layout& lo) { return; } - c.text(x, y, "Queue", colors::TEXT_COLOR); + c.text(x, y, "Queue", theme.text); y += sfh + 8; int row_h = sfh + 10; - draw_overview_stat_row(c, x, y, w, "Waiting", g_app.queue_count); + draw_overview_stat_row(c, x, y, w, "Waiting", g_app.queue_count, theme); y += row_h; - c.hline(x, y - 5, w, Color::from_rgb(0xEB, 0xEB, 0xEB)); + mtk::draw_separator(c, x, y - 5, w, theme); - draw_overview_stat_row(c, x, y, w, "Printing", g_app.active_count); + draw_overview_stat_row(c, x, y, w, "Printing", g_app.active_count, theme); y += row_h; - c.hline(x, y - 5, w, Color::from_rgb(0xEB, 0xEB, 0xEB)); + mtk::draw_separator(c, x, y - 5, w, theme); - draw_overview_stat_row(c, x, y, w, "Completed", g_app.done_count); + draw_overview_stat_row(c, x, y, w, "Completed", g_app.done_count, theme); y += row_h; - c.hline(x, y - 5, w, Color::from_rgb(0xEB, 0xEB, 0xEB)); + mtk::draw_separator(c, x, y - 5, w, theme); - draw_overview_stat_row(c, x, y, w, "Failed", g_app.failed_count); + draw_overview_stat_row(c, x, y, w, "Failed", g_app.failed_count, theme); y += row_h; y += 2; @@ -791,21 +763,22 @@ static void render_overview(Canvas& c, const Layout& lo) { } y += 10; - c.hline(x, y, w, colors::BORDER); + mtk::draw_separator(c, x, y, w, theme); y += 16; - c.text(x, y + 6, "Test Page", colors::TEXT_COLOR); - draw_action_btn(c, lo.test_btn, "Print Test Page", true, true); + c.text(x, control_row_text_y(y), "Test Page", theme.text); + mtk::draw_button(c, lo.test_btn, "Print Test Page", mtk::BUTTON_PRIMARY, + main_button_state(lo.test_btn, true), theme); y += BTN_H + 8; c.text(x, y, "Queue a simple test page through the print spooler.", dim); y += sfh + 4; - c.text(x, y, "Uses the configured default printer.", colors::TEXT_COLOR); + c.text(x, y, "Uses the configured default printer.", theme.text); } -static void render_details(Canvas& c, const Layout& lo) { - Color dim = Color::from_rgb(0x88, 0x88, 0x88); +static void render_details(Canvas& c, const Layout& lo, const mtk::Theme& theme) { + Color dim = theme.text_muted; Color success = Color::from_rgb(0x22, 0x88, 0x22); - Color danger = Color::from_rgb(0xCC, 0x33, 0x33); + Color danger = theme.danger; int sfh = system_font_height(); int x = PAD_X; int y = TAB_BAR_H + PAD_Y; @@ -813,12 +786,13 @@ static void render_details(Canvas& c, const Layout& lo) { char line[MAX_DEBUG_LEN]; if (status_visible()) { - c.text(x, y, g_app.status_msg, g_app.accent); + c.text(x, y, g_app.status_msg, theme.accent); y += sfh + 12; } - c.text(x, y + 6, "Connection", colors::TEXT_COLOR); - draw_action_btn(c, lo.probe_btn, "Probe", g_app.printer_uri[0] != '\0', false); + c.text(x, control_row_text_y(y), "Connection", theme.text); + mtk::draw_button(c, lo.probe_btn, "Probe", mtk::BUTTON_SECONDARY, + main_button_state(lo.probe_btn, g_app.printer_uri[0] != '\0'), theme); y += BTN_H + 8; if (g_app.printer_uri[0]) { @@ -826,7 +800,7 @@ static void render_details(Canvas& c, const Layout& lo) { char err[128] = {}; if (normalize_ipp_uri(g_app.printer_uri, &normalized, err, sizeof(err))) { text_fit(g_app.printer_uri, line, sizeof(line), w); - c.text(x, y, line, colors::TEXT_COLOR); + c.text(x, y, line, theme.text); y += sfh + 4; snprintf(line, sizeof(line), "Host: %s", normalized.host); @@ -877,7 +851,7 @@ static void render_details(Canvas& c, const Layout& lo) { snprintf(line, sizeof(line), "Probe: %s", g_app.probe_message[0] ? g_app.probe_message : (g_app.probe_ok ? "ok" : "failed")); text_fit(line, line, sizeof(line), w); - c.text(x, y, line, g_app.probe_ok ? colors::TEXT_COLOR : danger); + c.text(x, y, line, g_app.probe_ok ? theme.text : danger); y += sfh + 4; if (g_app.probe_ok) { @@ -907,18 +881,22 @@ static void render_details(Canvas& c, const Layout& lo) { } y += 10; - c.hline(x, y, w, colors::BORDER); + mtk::draw_separator(c, x, y, w, theme); y += 16; - c.text(x, control_row_text_y(y), "Spooler", colors::TEXT_COLOR); - draw_action_btn(c, lo.start_btn, "Start Daemon", !g_app.daemon_running, false); - draw_action_btn(c, lo.refresh_btn, "Refresh", true, false); + c.text(x, control_row_text_y(y), "Spooler", theme.text); + mtk::draw_button(c, lo.start_btn, "Start Daemon", mtk::BUTTON_TONAL, + main_button_state(lo.start_btn, !g_app.daemon_running), theme); + mtk::draw_button(c, lo.refresh_btn, "Refresh", mtk::BUTTON_SECONDARY, + main_button_state(lo.refresh_btn, true), theme); const char* daemon_label = g_app.daemon_running ? "Running" : "Stopped"; - int chip_w = text_width(daemon_label) + 18; + int chip_w = mtk::badge_width(daemon_label, theme); int chip_x = lo.start_btn.x - chip_w - 12; if (chip_x < x + 70) chip_x = x + 70; - draw_chip(c, chip_x, control_row_chip_y(y), daemon_label, g_app.daemon_running ? success : danger); + mtk::draw_badge(c, chip_x, control_row_badge_y(y), daemon_label, + g_app.daemon_running ? success : danger, + colors::WHITE, theme); y += BTN_H + 8; if (g_app.daemon_running) @@ -929,10 +907,10 @@ static void render_details(Canvas& c, const Layout& lo) { y += sfh + 6; snprintf(line, sizeof(line), "Queued: %d Printing: %d", g_app.queue_count, g_app.active_count); - c.text(x, y, line, colors::TEXT_COLOR); + c.text(x, y, line, theme.text); y += sfh + 4; snprintf(line, sizeof(line), "Completed: %d Failed: %d", g_app.done_count, g_app.failed_count); - c.text(x, y, line, colors::TEXT_COLOR); + c.text(x, y, line, theme.text); y += sfh + 4; if (g_app.has_active) { @@ -967,22 +945,24 @@ static void render_details(Canvas& c, const Layout& lo) { static void render() { refresh_state(); - Canvas c = g_win.canvas(); - c.fill(colors::WINDOW_BG); + mtk::StandaloneHost host(&g_win); + Canvas c = host.canvas(); + mtk::Theme theme = printers_theme(); + c.fill(theme.window_bg); Layout lo = {}; compute_layout(&lo); - draw_tabs(c); + mtk::draw_tab_bar(c, tab_bar_rect(), g_tab_labels, TAB_COUNT, g_app.active_tab, theme); switch (g_app.active_tab) { case TAB_OVERVIEW: - render_overview(c, lo); + render_overview(c, lo, theme); break; case TAB_DETAILS: - render_details(c, lo); + render_details(c, lo, theme); break; } - g_win.present(); + host.present(); } static void handle_click(int mx, int my) { @@ -992,10 +972,9 @@ static void handle_click(int mx, int my) { if (g_app.config_open) return; - if (my >= 0 && my < TAB_BAR_H) { - int tab_w = g_win.width / TAB_COUNT; - int tab = mx / tab_w; - if (tab >= 0 && tab < TAB_COUNT) g_app.active_tab = tab; + int tab = mtk::hit_tab_bar(tab_bar_rect(), TAB_COUNT, mx, my); + if (tab >= 0) { + g_app.active_tab = tab; return; } @@ -1048,6 +1027,49 @@ static void handle_click(int mx, int my) { } } +static bool hover_changed(const Rect& rect, bool enabled, + int prev_x, int prev_y, int next_x, int next_y) { + if (!enabled) return false; + return rect.contains(prev_x, prev_y) != rect.contains(next_x, next_y); +} + +static bool handle_mouse(const Montauk::WinEvent& ev) { + if (g_app.config_open) + return false; + + Layout lo = {}; + compute_layout(&lo); + + int prev_x = g_app.mouse_x; + int prev_y = g_app.mouse_y; + g_app.mouse_x = ev.mouse.x; + g_app.mouse_y = ev.mouse.y; + + bool redraw = false; + if (g_app.active_tab == TAB_OVERVIEW) { + redraw |= hover_changed(lo.configure_btn, true, prev_x, prev_y, g_app.mouse_x, g_app.mouse_y); + redraw |= hover_changed(lo.clear_btn, g_app.printer_uri[0] != '\0', + prev_x, prev_y, g_app.mouse_x, g_app.mouse_y); + redraw |= hover_changed(lo.test_btn, g_app.printer_uri[0] != '\0', + prev_x, prev_y, g_app.mouse_x, g_app.mouse_y); + } else { + redraw |= hover_changed(lo.probe_btn, g_app.printer_uri[0] != '\0', + prev_x, prev_y, g_app.mouse_x, g_app.mouse_y); + redraw |= hover_changed(lo.start_btn, !g_app.daemon_running, + prev_x, prev_y, g_app.mouse_x, g_app.mouse_y); + redraw |= hover_changed(lo.refresh_btn, true, + prev_x, prev_y, g_app.mouse_x, g_app.mouse_y); + } + + bool clicked = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1); + if (clicked) { + handle_click(ev.mouse.x, ev.mouse.y); + return true; + } + + return redraw; +} + static void cycle_tab(int delta) { int next = g_app.active_tab + delta; while (next < 0) next += TAB_COUNT; @@ -1105,7 +1127,12 @@ extern "C" void _start() { if (!fonts::init()) montauk::exit(1); + montauk::memset(&g_app, 0, sizeof(g_app)); g_app.active_tab = TAB_OVERVIEW; + g_app.mouse_x = -1; + g_app.mouse_y = -1; + g_app.config_mouse_x = -1; + g_app.config_mouse_y = -1; load_accent(); load_icons(); refresh_state(true); @@ -1176,11 +1203,7 @@ extern "C" void _start() { handle_key(ev.key); redraw_main = true; } else if (ev.type == 1) { - bool clicked = (ev.mouse.buttons & 1) && !(ev.mouse.prev_buttons & 1); - if (clicked) { - handle_click(ev.mouse.x, ev.mouse.y); - redraw_main = true; - } + redraw_main |= handle_mouse(ev); } if (redraw_main) diff --git a/programs/src/wordprocessor/main.cpp b/programs/src/wordprocessor/main.cpp index aceaca6..be4ffd5 100644 --- a/programs/src/wordprocessor/main.cpp +++ b/programs/src/wordprocessor/main.cpp @@ -24,6 +24,7 @@ SvgIcon g_icon_list_bullet = {}; SvgIcon g_icon_list_number = {}; SvgIcon g_icon_indent_less = {}; SvgIcon g_icon_indent_more = {}; +SvgIcon g_icon_page_view = {}; TrueTypeFont* g_ui_font = nullptr; TrueTypeFont* g_ui_bold = nullptr; @@ -58,6 +59,8 @@ void wp_load_icons() { g_icon_indent_less = svg_load("0:/icons/format-indent-less-symbolic.svg", 16, 16, def_color); if (!g_icon_indent_more.pixels) g_icon_indent_more = svg_load("0:/icons/format-indent-more-symbolic.svg", 16, 16, def_color); + if (!g_icon_page_view.pixels) + g_icon_page_view = svg_load("0:/icons/view-paged-symbolic.svg", 16, 16, def_color); } void wp_cleanup_state() { @@ -75,6 +78,7 @@ void wp_cleanup_state() { if (g_icon_list_number.pixels) svg_free(g_icon_list_number); if (g_icon_indent_less.pixels) svg_free(g_icon_indent_less); if (g_icon_indent_more.pixels) svg_free(g_icon_indent_more); + if (g_icon_page_view.pixels) svg_free(g_icon_page_view); } extern "C" void _start() { diff --git a/programs/src/wordprocessor/render.cpp b/programs/src/wordprocessor/render.cpp index 683609e..a09b866 100644 --- a/programs/src/wordprocessor/render.cpp +++ b/programs/src/wordprocessor/render.cpp @@ -297,17 +297,8 @@ void wp_render() { Color pageview_bg = wp->page_view_mode ? btn_active : btn_bg; c.fill_rounded_rect(WP_BTN_PAGEVIEW_X, 6, 24, 24, 3, pageview_bg); - { - // Draw a small page icon: rectangle with lines - int px = WP_BTN_PAGEVIEW_X + 4; - int py = 9; - // Page outline - c.rect(px, py, 14, 18, colors::TEXT_COLOR); - // Lines inside page - c.hline(px + 2, py + 4, 10, colors::TEXT_COLOR); - c.hline(px + 2, py + 8, 10, colors::TEXT_COLOR); - c.hline(px + 2, py + 12, 6, colors::TEXT_COLOR); - } + wp_draw_ui_icon_button(c, WP_BTN_PAGEVIEW_X, 6, 24, 24, g_icon_page_view, "\xA7", + pageview_bg, colors::TEXT_COLOR); c.hline(0, WP_TOOLBAR_H - 1, c.w, colors::BORDER); diff --git a/programs/src/wordprocessor/wordprocessor.hpp b/programs/src/wordprocessor/wordprocessor.hpp index 6c54c8c..32313a9 100644 --- a/programs/src/wordprocessor/wordprocessor.hpp +++ b/programs/src/wordprocessor/wordprocessor.hpp @@ -396,6 +396,7 @@ extern SvgIcon g_icon_list_bullet; extern SvgIcon g_icon_list_number; extern SvgIcon g_icon_indent_less; extern SvgIcon g_icon_indent_more; +extern SvgIcon g_icon_page_view; extern TrueTypeFont* g_ui_font; extern TrueTypeFont* g_ui_bold; diff --git a/scripts/copy_icons.sh b/scripts/copy_icons.sh index e41f01c..dbed94e 100755 --- a/scripts/copy_icons.sh +++ b/scripts/copy_icons.sh @@ -127,6 +127,7 @@ ICONS=( "apps/scalable/sleep.svg" "apps/scalable/kolourpaint.svg" # paint app "panel/sensors-temperature-symbolic.svg" # temperature panel icon + "actions/symbolic/view-paged-symbolic.svg" # page view toggle (word processor) ) copied=0