commit 1619b579fa72a45217ceeab062cd5dc6c9961a37
parent bf406bf2c7ad5025890a061780823576b65a67d7
Author: lumidify <nobody@lumidify.org>
Date: Fri, 29 Oct 2021 21:03:27 +0200
Add Ctrl-f and Ctrl-b for scrolling whole screens at a time
Diffstat:
5 files changed, 107 insertions(+), 12 deletions(-)
diff --git a/buffer.c b/buffer.c
@@ -1363,16 +1363,25 @@ ledit_buffer_resize_textview(ledit_buffer *buffer) {
}
ledit_window_set_scroll_max(buffer->window, buffer->total_height);
if (buffer->display_offset > 0 &&
- buffer->display_offset + text_h >= buffer->total_height) {
- buffer->display_offset = buffer->total_height - text_h;
- if (buffer->display_offset < 0)
- buffer->display_offset = 0;
- ledit_window_set_scroll_pos(buffer->window, buffer->display_offset);
+ buffer->display_offset + text_h > buffer->total_height) {
+ ledit_buffer_scroll(buffer, buffer->total_height - text_h);
}
}
void
-ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int *line_ret, int *byte_ret) {
+ledit_buffer_scroll(ledit_buffer *buffer, long new_offset) {
+ int text_w, text_h;
+ ledit_window_get_textview_size(buffer->window, &text_w, &text_h);
+ if (new_offset + text_h > buffer->total_height)
+ new_offset = buffer->total_height - text_h;
+ if (new_offset < 0)
+ new_offset = 0;
+ buffer->display_offset = new_offset;
+ ledit_window_set_scroll_pos(buffer->window, buffer->display_offset);
+}
+
+void
+ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int snap_to_nearest, int *line_ret, int *byte_ret) {
/* FIXME: store current line offset to speed this up */
/* FIXME: use y_offset in lines */
long h = 0;
@@ -1386,9 +1395,11 @@ ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int *line_ret, int *by
x * PANGO_SCALE, (int)(pos - h) * PANGO_SCALE,
&index, &trailing
);
- while (trailing > 0) {
- trailing--;
- index = ledit_line_next_utf8(line, index);
+ if (snap_to_nearest) {
+ while (trailing > 0) {
+ trailing--;
+ index = ledit_line_next_utf8(line, index);
+ }
}
*line_ret = i;
*byte_ret = index;
@@ -1509,7 +1520,7 @@ ledit_buffer_button_handler(void *data, XEvent *event) {
int y = event->xbutton.y;
switch (event->type) {
case ButtonPress:
- ledit_xy_to_line_byte(buffer, x, y, &l, &b);
+ ledit_xy_to_line_byte(buffer, x, y, 1, &l, &b);
ledit_buffer_set_selection(buffer, l, b, l, b);
if (buffer->common->mode == NORMAL) {
ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
@@ -1528,7 +1539,7 @@ ledit_buffer_button_handler(void *data, XEvent *event) {
case MotionNotify:
if (buffer->selecting) {
y = y >= 0 ? y : 0;
- ledit_xy_to_line_byte(buffer, x, y, &l, &b);
+ ledit_xy_to_line_byte(buffer, x, y, 1, &l, &b);
ledit_buffer_set_selection(buffer, buffer->sel.line1, buffer->sel.byte1, l, b);
buffer->cur_line = l;
buffer->cur_index = b;
diff --git a/buffer.h b/buffer.h
@@ -128,7 +128,10 @@ void ledit_buffer_insert_text_from_line(
);
void ledit_buffer_resize_width(ledit_buffer *buffer, int width);
-void ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int *line_ret, int *byte_ret);
+/* x and y are in pixels, if snap_to_nearest is nonzero, the returned byte
+ is at the nearest grapheme boundary, if it is zero, the byte is always
+ the beginning of the grapheme under the position */
+void ledit_xy_to_line_byte(ledit_buffer *buffer, int x, int y, int snap_to_nearest, int *line_ret, int *byte_ret);
void ledit_buffer_ensure_cursor_shown(ledit_buffer *buffer);
void ledit_buffer_scroll_handler(void *buffer, long pos);
void ledit_buffer_button_handler(void *data, XEvent *event);
@@ -140,3 +143,4 @@ void ledit_buffer_set_mode(ledit_buffer *buffer, enum ledit_mode mode);
void ledit_buffer_paste_clipboard(ledit_buffer *buffer);
void ledit_buffer_paste_primary(ledit_buffer *buffer);
void ledit_buffer_resize_textview(ledit_buffer *buffer);
+void ledit_buffer_scroll(ledit_buffer *buffer, long new_offset);
diff --git a/keys_basic.c b/keys_basic.c
@@ -343,6 +343,79 @@ delete_selection(ledit_buffer *buffer) {
return 0;
}
+/* get the number of times a command should be repeated, or -1 if anything
+ invalid was on the stack - this is for commands that just take a repeat
+ count and nothin else (cursor movement keys are different because they
+ can use other elements on the key stack to, for instance, call a callback
+ as is done for deletion */
+static int
+get_key_repeat(void) {
+ int num = 1;
+ struct key_stack_elem *e = pop_key_stack();
+ if (e != NULL) {
+ if (e->key & KEY_NUMBER) {
+ /* FIXME: why did I do this? */
+ num = e->count > 0 ? e->count : 0;
+ e = pop_key_stack();
+ }
+ if (e != NULL) {
+ /* the key was not a number, or there was another
+ element under it on the stack -> error */
+ num = -1;
+ }
+ }
+ clear_key_stack();
+ return num;
+}
+
+/* movement is multiplied to the window height and added to the display offset
+ the cursor is moved to the top if movement is upwards, to the bottom otherwise */
+static void
+move_screen(ledit_buffer *buffer, int movement) {
+ int w, h;
+ ledit_window_get_textview_size(buffer->window, &w, &h);
+ long total = movement * (long)h;
+ ledit_buffer_scroll(buffer, buffer->display_offset + total);
+ ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cur_line);
+ /* try to keep current x position of cursor */
+ ledit_line *ll = ledit_buffer_get_line(buffer, buffer->cur_line);
+ int x, softline;
+ /* FIXME: properly document what uses PANGO_SCALE and what not */
+ ledit_pos_to_x_softline(ll, buffer->cur_index, &x, &softline);
+ /* if movement is up, move cursor to top, else to bottom of current screen */
+ ledit_xy_to_line_byte(
+ buffer, x / PANGO_SCALE, movement < 0 ? 0 : h, 0,
+ &buffer->cur_line, &buffer->cur_index
+ );
+ ledit_buffer_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_index);
+}
+
+static struct action
+screen_up(ledit_buffer *buffer, char *text, int len) {
+ (void)text;
+ (void)len;
+ int repeat = get_key_repeat();
+ if (repeat >= 0)
+ move_screen(buffer, -repeat);
+ else
+ ledit_window_show_message(buffer->window, "Invalid key", -1);
+ discard_repetition_stack();
+ return (struct action){ACTION_NONE, NULL};
+}
+
+static struct action
+screen_down(ledit_buffer *buffer, char *text, int len) {
+ (void)text;
+ (void)len;
+ int repeat = get_key_repeat();
+ if (repeat >= 0)
+ move_screen(buffer, repeat);
+ else
+ ledit_window_show_message(buffer->window, "Invalid key", -1);
+ discard_repetition_stack();
+ return (struct action){ACTION_NONE, NULL};
+}
+
static struct action
key_d(ledit_buffer *buffer, char *text, int len) {
(void)text;
@@ -665,6 +738,7 @@ return_key(ledit_buffer *buffer, char *text, int len) {
return (struct action){ACTION_NONE, NULL};
}
+/* FIXME: Is this illegal due to different licenses? */
/* FIXME: Check earliest version of other used functions to get minimum pango version
for ledit as a whole */
/* FIXME: This is just copied from the newer version of pango. It *seems* like
diff --git a/keys_basic_config.h b/keys_basic_config.h
@@ -57,6 +57,8 @@ static struct action undo(ledit_buffer *buffer, char *text, int len);
static struct action redo(ledit_buffer *buffer, char *text, int len);
static struct action insert_mode_insert_text(ledit_buffer *buffer, char *text, int len);
static struct action repeat_command(ledit_buffer *buffer, char *text, int len);
+static struct action screen_up(ledit_buffer *buffer, char *text, int len);
+static struct action screen_down(ledit_buffer *buffer, char *text, int len);
/* FIXME: maybe sort these and use binary search
-> but that would mess with the catch-all keys */
@@ -102,6 +104,8 @@ static struct key keys_en[] = {
{".", 0, 0, NORMAL, KEY_ANY, KEY_ANY, &repeat_command}, /* FIXME: only allow after finished key sequence */
{"z", ControlMask, 0, INSERT, KEY_ANY, KEY_ANY, &undo},
{"y", ControlMask, 0, INSERT, KEY_ANY, KEY_ANY, &redo},
+ {"b", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &screen_up},
+ {"f", ControlMask, 0, NORMAL, KEY_ANY, KEY_NUMBERALLOWED, &screen_down},
{"", 0, 0, INSERT, KEY_ANY, KEY_ANY, &insert_mode_insert_text}
};
diff --git a/window.c b/window.c
@@ -415,6 +415,8 @@ ledit_window_create(ledit_common *common, ledit_theme *theme) {
void
ledit_window_destroy(ledit_window *window) {
/* FIXME: cleanup everything else */
+ /* FIXME: This doesn't seem to be correct - g_object_unref sometimes
+ causes segfault */
pango_font_description_free(window->font);
g_object_unref(window->fontmap);
g_object_unref(window->context);