fix: standardize scrollbars, fix scrollbar in TextEditor

This commit is contained in:
2026-05-26 07:59:40 +02:00
parent dc03f610fc
commit dfd618da89
2 changed files with 70 additions and 29 deletions
+9 -28
View File
@@ -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) {
+61 -1
View File
@@ -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) {