From 91d16ace618f1314382d77f047031401e1b727b0 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Fri, 24 Mar 2017 13:07:35 -0400 Subject: [PATCH] Generalized scrollbar behavior to hopefully apply to picker and editor with ease --- inc/win.h | 4 ++++ lib/view.c | 10 ++++++++++ lib/win.c | 28 ++++++++++++---------------- term.c | 4 ++++ xedit.c | 17 +++++++++++++++++ 5 files changed, 47 insertions(+), 16 deletions(-) diff --git a/inc/win.h b/inc/win.h index fa7b94b..4b59f67 100644 --- a/inc/win.h +++ b/inc/win.h @@ -44,8 +44,12 @@ Sel* win_sel(WinRegion id); bool win_btnpressed(MouseBtn btn); WinRegion win_getregion(void); void win_setregion(WinRegion id); +void win_setscroll(double offset, double visible); +/* These functions must be implemented by any appliation that wishes + to use this module */ void onupdate(void); +void onscroll(double percent); void onmouseleft(WinRegion id, size_t count, size_t row, size_t col); void onmousemiddle(WinRegion id, size_t count, size_t row, size_t col); void onmouseright(WinRegion id, size_t count, size_t row, size_t col); diff --git a/lib/view.c b/lib/view.c index a816b22..89b8906 100644 --- a/lib/view.c +++ b/lib/view.c @@ -148,6 +148,8 @@ static void sync_view(View* view, size_t csr) { first = scroll_up(view); while (csr > last && last < buf_end(&(view->buffer))) last = scroll_dn(view); + while (buf_end(&(view->buffer)) && last > buf_end(&(view->buffer))) + last = scroll_up(view); view->sync_needed = false; if (view->sync_center) { sync_center(view, csr); @@ -155,6 +157,14 @@ static void sync_view(View* view, size_t csr) { } } +void view_jumpto(View* view, size_t off) { + size_t csrx, csry; + if (!view->nrows) return; + view->rows[0]->off = off; + view_update(view, &csrx, &csry); + sync_view(view, off); +} + static size_t getoffset(View* view, size_t row, size_t col) { Row* scrrow = view_getrow(view, row); if (!scrrow) return SIZE_MAX; diff --git a/lib/win.c b/lib/win.c index b34f0a5..939bfa9 100644 --- a/lib/win.c +++ b/lib/win.c @@ -21,6 +21,8 @@ static void onshutdown(void); static void onwheelup(WinRegion id, size_t count, size_t row, size_t col); static void onwheeldn(WinRegion id, size_t count, size_t row, size_t col); +static double ScrollOffset = 0.0; +static double ScrollVisible = 1.0; static XFont Font; static XConfig Config = { .redraw = onredraw, @@ -101,6 +103,11 @@ Sel* win_sel(WinRegion id) { return &(Regions[id].view.selection); } +void win_setscroll(double offset, double visible) { + ScrollOffset = offset; + ScrollVisible = visible; +} + static void layout(int width, int height) { size_t fheight = x11_font_height(Font); size_t fwidth = x11_font_width(Font); @@ -164,17 +171,9 @@ static void onredraw(int width, int height) { } /* draw the scroll region */ - View* view = win_view(EDIT); - size_t bend = buf_end(win_buf(EDIT)); - if (bend == 0) bend = 1; - size_t vbeg = view->rows[0]->off; - size_t vend = view->rows[view->nrows-1]->off + view->rows[view->nrows-1]->rlen; - size_t vtot = ((vend - vbeg) * 100) / bend; - if (vend > bend) vtot += 1; - size_t voff = (vbeg * 100 / bend); size_t thumbreg = (Regions[SCROLL].height - Regions[SCROLL].y + 9); - size_t thumboff = (thumbreg * voff / 100) + (Regions[SCROLL].y - 2); - size_t thumbsz = (thumbreg * vtot / 100); + size_t thumboff = (size_t)((thumbreg * ScrollOffset) + (Regions[SCROLL].y - 2)); + size_t thumbsz = (size_t)(thumbreg * ScrollVisible); if (thumbsz < 5) thumbsz = 5; x11_draw_rect(CLR_BASE01, Regions[SCROLL].width, Regions[SCROLL].y - 2, 1, Regions[SCROLL].height); x11_draw_rect(CLR_BASE00, 0, Regions[SCROLL].y - 2, Regions[SCROLL].width, thumbreg); @@ -228,12 +227,9 @@ static void onclick(MouseAct act, MouseBtn btn, int x, int y) { case MOUSE_BTN_LEFT: view_scroll(win_view(EDIT), -row); break; - case MOUSE_BTN_MIDDLE: { - size_t bend = buf_end(win_buf(EDIT)); - size_t csrx, csry, chunksz = (bend > 0 ? bend : 1) / Regions[SCROLL].height; - win_view(EDIT)->rows[0]->off = buf_bol(win_buf(EDIT), (y - Regions[SCROLL].y) * chunksz); - view_update(win_view(EDIT), &csrx, &csry); - } + case MOUSE_BTN_MIDDLE: + onscroll((double)(y - Regions[SCROLL].y) / + (double)(Regions[SCROLL].height - Regions[SCROLL].y())); break; case MOUSE_BTN_RIGHT: view_scroll(win_view(EDIT), +row); diff --git a/term.c b/term.c index 73c58d2..cbe35db 100644 --- a/term.c +++ b/term.c @@ -27,6 +27,10 @@ void onmouseright(WinRegion id, size_t count, size_t row, size_t col) { // } //}; +void onscroll(double percent) { + +} + /* Keyboard Handling *****************************************************************************/ diff --git a/xedit.c b/xedit.c index cca5d1d..79831af 100644 --- a/xedit.c +++ b/xedit.c @@ -500,6 +500,12 @@ static KeyBinding Bindings[] = { { 0, 0, 0 } }; +void onscroll(double percent) { + size_t bend = buf_end(win_buf(EDIT)); + size_t off = (size_t)((double)bend * percent); + view_jumpto(win_view(EDIT), (off >= bend ? bend : off)); +} + void onupdate(void) { static char status_bytes[256]; memset(status_bytes, 0, sizeof(status_bytes)); @@ -516,6 +522,17 @@ void onupdate(void) { size_t remlen = sizeof(status_bytes) - strlen(status_bytes) - 1; strncat(status, path, remlen); win_settext(STATUS, status_bytes); + + /* calculate and update scroll region */ + View* view = win_view(EDIT); + size_t bend = buf_end(win_buf(EDIT)); + if (bend == 0) bend = 1; + if (!view->rows) return; + size_t vbeg = view->rows[0]->off; + size_t vend = view->rows[view->nrows-1]->off + view->rows[view->nrows-1]->rlen; + double scroll_vis = (double)(vend - vbeg) / (double)bend; + double scroll_off = ((double)vbeg / (double)bend); + win_setscroll(scroll_off, scroll_vis); } #ifndef TEST -- 2.51.0