Introduction
Introduction Statistics Contact Development Disclaimer Help
tMake selecting and scrolling work somewhat better - ledit - Text editor (WIP)
git clone git://lumidify.org/ledit.git (fast, but not encrypted)
git clone https://lumidify.org/git/ledit.git (encrypted, but very slow)
Log
Files
Refs
README
LICENSE
---
commit b3a32dd52672a8a385308afb73198d129294c7c3
parent 91a730677ac95f922d6e5bca531f9cf0811e0fd6
Author: lumidify <[email protected]>
Date: Thu, 11 Nov 2021 13:41:07 +0100
Make selecting and scrolling work somewhat better
Diffstat:
M Makefile | 1 +
M buffer.c | 41 +++++++++++++++++++++++------…
A config.h | 5 +++++
M ledit.c | 70 +++++++++++++++++++++++++++--…
M theme_config.h | 2 +-
M window.c | 16 +++++-----------
M window.h | 2 +-
7 files changed, 106 insertions(+), 31 deletions(-)
---
diff --git a/Makefile b/Makefile
t@@ -47,6 +47,7 @@ LDFLAGS_LEDIT = ${LDFLAGS} `pkg-config --libs x11 xkbfile pa…
all: ${BIN}
+ledit.o : config.h
theme.o : theme_config.h
keys_basic.o : keys_basic_config.h
keys_command.o : keys_command_config.h
diff --git a/buffer.c b/buffer.c
t@@ -1976,18 +1976,22 @@ ledit_buffer_set_selection(ledit_buffer *buffer, int l…
byte1 == buffer->sel.byte1 && byte2 == buffer->sel.byte2) {
return;
}
- if (buffer->sel.line1 >= 0) {
+ /* FIXME: maybe check both lines and bytes? */
+ if (buffer->sel.line1 >= 0 || line1 >= 0) {
int l1_new = line1, l2_new = line2;
int b1_new = byte1, b2_new = byte2;
- ledit_buffer_sort_selection(&buffer->sel.line1, &buffer->sel.b…
ledit_buffer_sort_selection(&l1_new, &b1_new, &l2_new, &b2_new…
+ ledit_buffer_sort_selection(&buffer->sel.line1, &buffer->sel.b…
+ /* FIXME: make this a bit nicer and optimize it */
if (buffer->sel.line1 > l2_new || buffer->sel.line2 < l1_new) {
for (int i = buffer->sel.line1; i <= buffer->sel.line2…
- ledit_buffer_wipe_line_cursor_attrs(buffer, i);
+ if (i >= 0)
+ ledit_buffer_wipe_line_cursor_attrs(bu…
}
} else {
for (int i = buffer->sel.line1; i < l1_new; i++) {
- ledit_buffer_wipe_line_cursor_attrs(buffer, i);
+ if (i >= 0)
+ ledit_buffer_wipe_line_cursor_attrs(bu…
}
for (int i = buffer->sel.line2; i > l2_new; i--) {
ledit_buffer_wipe_line_cursor_attrs(buffer, i);
t@@ -2029,12 +2033,20 @@ ledit_buffer_button_handler(void *data, XEvent *event)…
ledit_buffer *buffer = (ledit_buffer *)data;
int x = event->xbutton.x;
int y = event->xbutton.y;
+ int snap;
switch (event->type) {
case ButtonPress:
- ledit_xy_to_line_byte(buffer, x, y, 0, &l, &b);
+ snap = buffer->common->mode == NORMAL ? 0 : 1;
+ ledit_xy_to_line_byte(buffer, x, y, snap, &l, &b);
buffer->selecting = 1;
+ if (buffer->common->mode == NORMAL)
+ ledit_buffer_wipe_line_cursor_attrs(buffer, buffer->cu…
buffer->cur_line = l;
buffer->cur_index = b;
+ /* don't set selection yet because the mouse may not be
+ dragged, so we don't want to switch to visual (this
+ allows setting just the cursor position in normal mode
+ without always switching to visual) */
ledit_buffer_set_selection(buffer, -1, -1, -1, -1);
if (buffer->common->mode == NORMAL)
ledit_buffer_set_line_cursor_attrs(buffer, l, b);
t@@ -2046,17 +2058,26 @@ ledit_buffer_button_handler(void *data, XEvent *event)…
if (buffer->selecting) {
y = y >= 0 ? y : 0;
ledit_xy_to_line_byte(buffer, x, y, 1, &l, &b);
- if (buffer->sel.line1 < 0 || buffer->sel.byte1 < 0) {
- ledit_buffer_set_selection(buffer, l, b, l, b);
- } else {
- ledit_buffer_set_selection(buffer, buffer->sel…
- }
if (buffer->common->mode == NORMAL) {
ledit_buffer_wipe_line_cursor_attrs(buffer, bu…
/* FIXME: return to old mode afterwards? */
/* should change_mode_group even be called her…
ledit_buffer_set_mode(buffer, VISUAL);
}
+ if (buffer->sel.line1 < 0 || buffer->sel.byte1 < 0) {
+ /* the selection has just started, so the curr…
+ position is already set to the beginning of…
+ selection (see case ButtonPress above) */
+ ledit_buffer_set_selection(
+ buffer,
+ buffer->cur_line, buffer->cur_index, l, b
+ );
+ } else {
+ ledit_buffer_set_selection(
+ buffer,
+ buffer->sel.line1, buffer->sel.byte1, l, b
+ );
+ }
buffer->cur_line = l;
buffer->cur_index = b;
}
diff --git a/config.h b/config.h
t@@ -0,0 +1,5 @@
+/* minimum time between redraws (nanoseconds) */
+#define TICK (long long)20000000
+/* minimum time between processing of mouse events -
+ events inbetween are discarded (nanoseconds) */
+#define MOUSE_TICK (long long)100000000
diff --git a/ledit.c b/ledit.c
t@@ -1,3 +1,4 @@
+/* FIXME: Make scrolling more smooth */
/* FIXME: Document that everything is assumed to be utf8 */
/* FIXME: Only redraw part of screen if needed */
/* FIXME: overflow in repeated commands */
t@@ -9,6 +10,7 @@
/* FIXME: sort out types for indices (currently just int, but that might overf…
/* TODO: allow extending selection with shift+mouse like in e.g. gtk */
#include <math.h>
+#include <time.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
t@@ -29,6 +31,7 @@
#include <X11/extensions/XKBrules.h>
#include <X11/extensions/Xdbe.h>
+#include "config.h"
#include "memory.h"
#include "common.h"
#include "txtbuf.h"
t@@ -48,7 +51,7 @@ static void mainloop(void);
static void setup(int argc, char *argv[]);
static void cleanup(void);
static void redraw(void);
-static int button_press(XEvent *event);
+static int button_press(XEvent *event, int scroll_num);
static int button_release(XEvent *event);
static int drag_motion(XEvent *event);
t@@ -91,9 +94,19 @@ mainloop(void) {
int need_redraw = 0;
redraw();
-
+ /* store last time that a mouse event was processed in order to
+ avoid sending too many mouse events to be processed */
+ /* also store last draw time so framerate can be limited */
+ struct timespec now, elapsed, last, last_scroll, last_motion, sleep_ti…
+ clock_gettime(CLOCK_MONOTONIC, &last);
+ last_scroll = last_motion = last;
+ sleep_time.tv_sec = 0;
+ XEvent last_scroll_event, last_motion_event;
+ int last_scroll_valid = 0, last_motion_valid = 0;
+ int scroll_num = 0;
+ int scroll_delta = 0;
while (running) {
- do {
+ while (XPending(common.dpy)) {
XNextEvent(common.dpy, &event);
if (event.type == xkb_event_type) {
change_kbd = 1;
t@@ -115,13 +128,28 @@ mainloop(void) {
need_redraw = 1;
break;
case ButtonPress:
- need_redraw |= button_press(&event);
+ /* FIXME: this is all a bit hacky */
+ if (event.xbutton.button == Button4 ||
+ event.xbutton.button == Button5) {
+ scroll_delta = event.xbutton.button ==…
+ if (last_scroll_valid) {
+ scroll_num += scroll_delta;
+ } else {
+ last_scroll_event = event;
+ last_scroll_valid = 1;
+ scroll_num = scroll_delta;
+ }
+ } else {
+ need_redraw |= button_press(&event, 0);
+ }
break;
case ButtonRelease:
need_redraw |= button_release(&event);
break;
case MotionNotify:
- need_redraw |= drag_motion(&event);
+ /* FIXME: is it legal to just copy event like …
+ last_motion_event = event;
+ last_motion_valid = 1;
break;
case KeyPress:
need_redraw = 1;
t@@ -143,7 +171,25 @@ mainloop(void) {
default:
break;
}
- } while (XPending(common.dpy));
+ };
+ if (last_motion_valid) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ timespecsub(&now, &last_motion, &elapsed);
+ if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= MOUSE_TIC…
+ need_redraw |= drag_motion(&last_motion_event);
+ last_motion = now;
+ last_motion_valid = 0;
+ }
+ }
+ if (last_scroll_valid) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ timespecsub(&now, &last_scroll, &elapsed);
+ if (elapsed.tv_sec > 0 || elapsed.tv_nsec >= MOUSE_TIC…
+ need_redraw |= button_press(&last_scroll_event…
+ last_scroll = now;
+ last_scroll_valid = 0;
+ }
+ }
if (change_kbd) {
change_kbd = 0;
t@@ -163,6 +209,14 @@ mainloop(void) {
redraw();
need_redraw = 0;
}
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ timespecsub(&now, &last, &elapsed);
+ if (elapsed.tv_sec == 0 && elapsed.tv_nsec < TICK) {
+ sleep_time.tv_nsec = TICK - elapsed.tv_nsec;
+ nanosleep(&sleep_time, NULL);
+ }
+ last = now;
}
}
t@@ -251,8 +305,8 @@ redraw(void) {
}
static int
-button_press(XEvent *event) {
- return ledit_window_button_press(window, event);
+button_press(XEvent *event, int scroll_num) {
+ return ledit_window_button_press(window, event, scroll_num);
}
static int
diff --git a/theme_config.h b/theme_config.h
t@@ -4,6 +4,6 @@ static const char *TEXT_BG = "#FFFFFF";
/* FIXME: give in units other than pixels */
static const int SCROLLBAR_WIDTH = 10;
-static const int SCROLLBAR_STEP = 10;
+static const int SCROLLBAR_STEP = 20;
static const char *SCROLLBAR_BG = "#CCCCCC";
static const char *SCROLLBAR_FG = "#000000";
diff --git a/window.c b/window.c
t@@ -700,7 +700,7 @@ clipboard_selrequest(ledit_window *window, XEvent *e)
/* FIXME: improve set_scroll_pos; make it a bit clearer */
int
-ledit_window_button_press(ledit_window *window, XEvent *event) {
+ledit_window_button_press(ledit_window *window, XEvent *event, int scroll_num)…
int x, y;
double scroll_h, scroll_y;
switch (event->xbutton.button) {
t@@ -723,18 +723,12 @@ ledit_window_button_press(ledit_window *window, XEvent *…
}
break;
case Button4:
- window->scroll_offset -= window->theme->scrollbar_step;
+ case Button5:
+ window->scroll_offset += scroll_num * window->theme->s…
if (window->scroll_offset < 0)
window->scroll_offset = 0;
- if (window->scroll_callback)
- window->scroll_callback(window->scroll_cb_data…
- return 1;
- case Button5:
- if (window->scroll_offset + window->text_h < window->s…
- window->scroll_offset += window->theme->scroll…
- if (window->scroll_offset + window->text_h > w…
- window->scroll_offset = window->scroll…
- }
+ if (window->scroll_offset + window->text_h > window->s…
+ window->scroll_offset = window->scroll_max - w…
}
if (window->scroll_callback)
window->scroll_callback(window->scroll_cb_data…
diff --git a/window.h b/window.h
t@@ -74,7 +74,7 @@ void clipboard_paste_clipboard(ledit_window *window);
void clipboard_paste_primary(ledit_window *window);
txtbuf *ledit_window_get_primary_clipboard_buffer(void);
-int ledit_window_button_press(ledit_window *window, XEvent *event);
+int ledit_window_button_press(ledit_window *window, XEvent *event, int scroll_…
int ledit_window_button_release(ledit_window *window, XEvent *event);
int ledit_window_drag_motion(ledit_window *window, XEvent *event);
int ledit_window_clipboard_event(ledit_window *window, XEvent *event);
You are viewing proxied material from lumidify.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.