diff --git a/programs/include/gui/mtk/widgets.hpp b/programs/include/gui/mtk/widgets.hpp index 498f739..03328db 100644 --- a/programs/include/gui/mtk/widgets.hpp +++ b/programs/include/gui/mtk/widgets.hpp @@ -775,10 +775,10 @@ inline void draw_separator(Canvas& c, int x, int y, int w, const Theme& theme) { } static constexpr int SCROLLBAR_W = 12; -static constexpr int SCROLLBAR_OUTER_PAD = 4; -static constexpr int SCROLLBAR_TRACK_PAD = 8; -static constexpr int SCROLLBAR_THUMB_INSET = 2; -static constexpr int SCROLLBAR_MIN_THUMB = 24; +static constexpr int SCROLLBAR_OUTER_PAD = 0; +static constexpr int SCROLLBAR_TRACK_PAD = 0; +static constexpr int SCROLLBAR_THUMB_INSET = 1; +static constexpr int SCROLLBAR_MIN_THUMB = 20; inline bool scrollbar_needed(int content_extent, int view_extent) { return content_extent > view_extent && view_extent > 0; @@ -851,13 +851,11 @@ inline int scrollbar_offset_from_thumb_top(const Rect& track, return (int)(((int64_t)rel * max_offset + travel / 2) / travel); } -inline Color scrollbar_thumb_color(const Theme& theme, +inline Color scrollbar_thumb_color(const Theme& /*theme*/, bool hovered, bool dragging) { - Color base = mix(theme.border, theme.text_muted, 54); - if (dragging) return mix(base, theme.accent, 118); - if (hovered) return mix(base, theme.accent, 42); - return base; + if (hovered || dragging) return Color::from_rgb(0xA0, 0xA0, 0xA0); + return colors::SCROLLBAR_FG; } inline void draw_scrollbar(Canvas& c, @@ -868,26 +866,9 @@ inline void draw_scrollbar(Canvas& c, const Theme& theme) { if (track.empty() || thumb.empty()) return; - if (hovered || dragging) { - int rail_w = track.w > 6 ? track.w - 6 : track.w; - if (rail_w < 1) rail_w = 1; - Rect rail = { - track.x + (track.w - rail_w) / 2, - track.y, - rail_w, - track.h - }; - Color rail_fill = dragging - ? mix(theme.window_bg, theme.accent, 34) - : mix(theme.window_bg, theme.text_muted, 24); - c.fill_rounded_rect(rail.x, rail.y, rail.w, rail.h, - gui_max(theme.radius_sm, rail.w / 2), - rail_fill); - } - + c.fill_rect(track.x, track.y, track.w, track.h, colors::SCROLLBAR_BG); Color thumb_fill = scrollbar_thumb_color(theme, hovered, dragging); - int radius = gui_max(theme.radius_sm, thumb.w / 2); - c.fill_rounded_rect(thumb.x, thumb.y, thumb.w, thumb.h, radius, thumb_fill); + c.fill_rect(thumb.x, thumb.y, thumb.w, thumb.h, thumb_fill); } inline Rect tab_rect(const Rect& bar, int count, int index) { diff --git a/programs/src/texteditor/main.cpp b/programs/src/texteditor/main.cpp index 66fe195..fadd06c 100644 --- a/programs/src/texteditor/main.cpp +++ b/programs/src/texteditor/main.cpp @@ -97,6 +97,9 @@ int g_cursor_line = 0; int g_cursor_col = 0; int g_scroll_y = 0; // first visible line int g_scroll_x = 0; // horizontal scroll in pixels +bool g_scroll_dragging = false; +int g_scroll_drag_offset = 0; // mouse y - thumb_y at drag start +bool g_scroll_hovered = false; bool g_modified = false; bool g_cursor_moved = true; char g_status_msg[128] = {}; @@ -923,7 +926,10 @@ static void render(uint32_t* pixels) { if (thumb_h < 20) thumb_h = 20; int range = text_area_h - thumb_h; int thumb_y = editor_y + (g_scroll_y * range) / max_scr; - px_fill(pixels, W, H, sb_x + 1, thumb_y, SCROLLBAR_W - 2, thumb_h, Color::from_rgb(0xAA, 0xAA, 0xAA)); + Color thumb_c = (g_scroll_hovered || g_scroll_dragging) + ? Color::from_rgb(0xA0, 0xA0, 0xA0) + : Color::from_rgb(0xC0, 0xC0, 0xC0); + px_fill(pixels, W, H, sb_x + 1, thumb_y, SCROLLBAR_W - 2, thumb_h, thumb_c); } // ---- Status bar ---- @@ -1283,6 +1289,60 @@ static bool handle_mouse(Montauk::WinEvent& ev, int win_id) { return true; } + // ---- Scrollbar interaction ---- + int visible_lines = (cell_h > 0) ? text_area_h / cell_h : 0; + int content_h = g_line_count * cell_h; + bool sb_visible = content_h > text_area_h && visible_lines > 0; + int sb_x = g_win_w - SCROLLBAR_W; + int thumb_h = 0, thumb_y = 0, max_scr = 0, range = 0; + if (sb_visible) { + max_scr = g_line_count - visible_lines; + if (max_scr < 1) max_scr = 1; + thumb_h = (text_area_h * text_area_h) / content_h; + if (thumb_h < 20) thumb_h = 20; + range = text_area_h - thumb_h; + thumb_y = editor_y + (g_scroll_y * range) / max_scr; + } + + bool in_track = sb_visible && mx >= sb_x && mx < sb_x + SCROLLBAR_W + && my >= editor_y && my < editor_y + text_area_h; + bool in_thumb = in_track && my >= thumb_y && my < thumb_y + thumb_h; + g_scroll_hovered = in_thumb || g_scroll_dragging; + + if (g_scroll_dragging) { + if (held) { + if (range > 0) { + int new_thumb_y = my - g_scroll_drag_offset; + int rel = new_thumb_y - editor_y; + if (rel < 0) rel = 0; + if (rel > range) rel = range; + g_scroll_y = (rel * max_scr + range / 2) / range; + if (g_scroll_y < 0) g_scroll_y = 0; + if (g_scroll_y > max_scr) g_scroll_y = max_scr; + } + return true; + } + if (released) { + g_scroll_dragging = false; + return true; + } + } + + if (clicked && in_track) { + if (in_thumb) { + g_scroll_dragging = true; + g_scroll_drag_offset = my - thumb_y; + } else if (range > 0) { + // page jump: click above/below thumb scrolls by one page + int delta_lines = visible_lines > 1 ? visible_lines - 1 : 1; + if (my < thumb_y) g_scroll_y -= delta_lines; + else g_scroll_y += delta_lines; + if (g_scroll_y < 0) g_scroll_y = 0; + if (g_scroll_y > max_scr) g_scroll_y = max_scr; + } + return true; + } + // ---- Editor click ---- if (right_clicked && my >= editor_y && my < editor_y + text_area_h && mx > LINE_NUM_W && mx < g_win_w - SCROLLBAR_W) {