Implement a simple scroll progress indicator

Shows a simple bar on the right edge of the window that moves up as you
scroll further back. There are apparently a lot of people that dont use
a pager for browsing large scrollbacks. I will never understand this,
but, what the hell I was in that code area anyway for other reasons.

TODO: Maybe make it a rounded rectangle
This commit is contained in:
Kovid Goyal 2024-03-28 20:33:35 +05:30
parent c9f8596357
commit 700b57bc18
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
7 changed files with 59 additions and 2 deletions

View file

@ -54,6 +54,8 @@ Detailed list of changes
using the panel kitten for all compositors that support the requisite Wayland
protocol which is practically speaking all of them but GNOME (:pull:`2590`)
- A new option :opt:`scrollback_indicator_opacity` to show a small indicator on the right hand side of the screen of how much you have scrolled
- Wayland: Support fractional scales so that there is no wasted drawing at larger scale followed by resizing in the compositor
- Wayland: Support preferred integer scales

View file

@ -374,6 +374,14 @@ is changed it will only affect newly created windows, not existing ones.
'''
)
opt('scrollback_indicator_opacity', '0.0',
option_type='unit_float', ctype='float', long_text='''
The opacity of the scrollback indicator which is a small colored rectangle that moves
along the right hand side of the window as you scroll, indicating what fraction you
have scrolled. The default is zero which means fully transparent, aka invisible.
Set to a value between zero and one to see the indicator.''')
opt('scrollback_pager', 'less --chop-long-lines --RAW-CONTROL-CHARS +INPUT_LINE_NUMBER',
option_type='to_cmdline',
long_text='''

View file

@ -1172,6 +1172,9 @@ class Parser:
def scrollback_fill_enlarged_window(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['scrollback_fill_enlarged_window'] = to_bool(val)
def scrollback_indicator_opacity(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['scrollback_indicator_opacity'] = unit_float(val)
def scrollback_lines(self, val: str, ans: typing.Dict[str, typing.Any]) -> None:
ans['scrollback_lines'] = scrollback_lines(val)

View file

@ -135,6 +135,19 @@ convert_from_opts_cursor_stop_blinking_after(PyObject *py_opts, Options *opts) {
Py_DECREF(ret);
}
static void
convert_from_python_scrollback_indicator_opacity(PyObject *val, Options *opts) {
opts->scrollback_indicator_opacity = PyFloat_AsFloat(val);
}
static void
convert_from_opts_scrollback_indicator_opacity(PyObject *py_opts, Options *opts) {
PyObject *ret = PyObject_GetAttrString(py_opts, "scrollback_indicator_opacity");
if (ret == NULL) return;
convert_from_python_scrollback_indicator_opacity(ret, opts);
Py_DECREF(ret);
}
static void
convert_from_python_scrollback_pager_history_size(PyObject *val, Options *opts) {
opts->scrollback_pager_history_size = PyLong_AsUnsignedLong(val);
@ -1132,6 +1145,8 @@ convert_opts_from_python_opts(PyObject *py_opts, Options *opts) {
if (PyErr_Occurred()) return false;
convert_from_opts_cursor_stop_blinking_after(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_scrollback_indicator_opacity(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_scrollback_pager_history_size(py_opts, opts);
if (PyErr_Occurred()) return false;
convert_from_opts_scrollback_fill_enlarged_window(py_opts, opts);

View file

@ -402,6 +402,7 @@ option_names = ( # {{{
'resize_debounce_time',
'resize_in_steps',
'scrollback_fill_enlarged_window',
'scrollback_indicator_opacity',
'scrollback_lines',
'scrollback_pager',
'scrollback_pager_history_size',
@ -562,6 +563,7 @@ class Options:
resize_debounce_time: typing.Tuple[float, float] = (0.1, 0.5)
resize_in_steps: bool = False
scrollback_fill_enlarged_window: bool = False
scrollback_indicator_opacity: float = 0
scrollback_lines: int = 2000
scrollback_pager: typing.List[str] = ['less', '--chop-long-lines', '--RAW-CONTROL-CHARS', '+INPUT_LINE_NUMBER']
scrollback_pager_history_size: int = 0

View file

@ -594,6 +594,31 @@ draw_tint(bool premult, Screen *screen, const CellRenderData *crd) {
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
static bool
draw_scroll_indicator(bool premult, Screen *screen, const CellRenderData *crd) {
if (OPT(scrollback_indicator_opacity) <= 0 || screen->linebuf != screen->main_linebuf || !screen->scrolled_by) return false;
glEnable(GL_BLEND);
if (premult) { BLEND_PREMULT } else { BLEND_ONTO_OPAQUE }
bind_program(TINT_PROGRAM);
const color_type bar_color = colorprofile_to_color(screen->color_profile, screen->color_profile->overridden.highlight_bg, screen->color_profile->configured.highlight_bg).rgb;
GLfloat alpha = 0.8f;
float frac = (float)screen->scrolled_by / (float)screen->historybuf->count;
const GLfloat bar_height = crd->gl.dy;
GLfloat bottom = (crd->gl.ystart - crd->gl.height);
bottom += MAX(0, crd->gl.height - bar_height) * frac;
#define C(shift) srgb_color((bar_color >> shift) & 0xFF) * premult_factor
GLfloat premult_factor = premult ? alpha : 1.0f;
glUniform4f(tint_program_layout.uniforms.tint_color, C(16), C(8), C(0), alpha);
#undef C
GLfloat width = 0.5f * crd->gl.dx;
GLfloat left = (GLfloat)(crd->gl.xstart + (screen->columns * crd->gl.dx - width));
glUniform4f(tint_program_layout.uniforms.edges, left, bottom, left + width, bottom + bar_height);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisable(GL_BLEND);
return true;
}
static float prev_inactive_text_alpha = -1;
static void
@ -972,14 +997,16 @@ draw_cells(ssize_t vao_idx, const WindowRenderData *srd, OSWindow *os_window, bo
scale_rendered_graphic(grman->render_data.item + i, srd->xstart, srd->ystart, crd.x_ratio, crd.y_ratio);
}
}
bool use_premult = false;
has_underlying_image |= grman->num_of_below_refs > 0 || grman->num_of_negative_refs > 0;
if (os_window->is_semi_transparent) {
if (has_underlying_image) draw_cells_interleaved_premult(vao_idx, screen, os_window, &crd, wl);
if (has_underlying_image) { draw_cells_interleaved_premult(vao_idx, screen, os_window, &crd, wl); use_premult = true; }
else draw_cells_simple(vao_idx, screen, &crd, os_window->is_semi_transparent);
} else {
if (has_underlying_image) draw_cells_interleaved(vao_idx, screen, os_window, &crd, wl);
else draw_cells_simple(vao_idx, screen, &crd, os_window->is_semi_transparent);
}
draw_scroll_indicator(use_premult, screen, &crd);
if (screen->start_visual_bell_at) {
GLfloat intensity = get_visual_bell_intensity(screen);

View file

@ -53,7 +53,7 @@ typedef struct {
float macos_thicken_font;
WindowTitleIn macos_show_window_title_in;
char *bell_path, *bell_theme;
float background_opacity, dim_opacity;
float background_opacity, dim_opacity, scrollback_indicator_opacity;
float text_contrast, text_gamma_adjustment;
bool text_old_gamma;