From bee70fda92647cafc3aa5cf9bde4d9a43d671db5 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Fri, 13 Apr 2018 21:57:48 -0400 Subject: [PATCH] refactored view handling. stripped down to the studs. Will rebuild with support for proportional fonts. --- inc/edit.h | 17 ++- lib/view.c | 310 ++++++++++------------------------------------------- lib/x11.c | 14 +-- 3 files changed, 74 insertions(+), 267 deletions(-) diff --git a/inc/edit.h b/inc/edit.h index 8b3b8f1..0e71be8 100644 --- a/inc/edit.h +++ b/inc/edit.h @@ -73,13 +73,13 @@ char* buf_fetch(Buf* buf, bool (*isword)(Rune), size_t off); /* Screen management functions *****************************************************************************/ typedef struct { - Rune rune; /* rune value for the cell */ + size_t width; /* width of the glyph on screen */ + Rune rune; /* rune value for the cell */ } UGlyph; typedef struct { size_t off; /* offset of the first rune in the row */ - size_t rlen; /* number of runes displayed in the row */ - size_t len; /* number of screen columns taken up by row */ + size_t len; /* number of runes displayed in the row */ UGlyph cols[]; /* row data */ } Row; @@ -88,9 +88,9 @@ typedef struct { CURSOR = (1 << 0), CENTER = (1 << 1), } sync_flags; - Buf buffer; /* the buffer used to populate the view */ - size_t nrows, ncols; /* number of rows and columns in the view */ - Row** rows; /* array of row data structures */ + Buf buffer; /* the buffer used to populate the view */ + size_t nrows; /* number of rows and columns in the view */ + Row** rows; /* array of row data structures */ } View; enum { @@ -102,9 +102,8 @@ enum { void view_init(View* view, char* file); void view_reload(View* view); -size_t view_limitrows(View* view, size_t maxrows, size_t ncols); -void view_resize(View* view, size_t nrows, size_t ncols); -void view_update(View* view, int clrnor, int clrsel, size_t* csrx, size_t* csry); +void view_resize(View* view, size_t width, size_t nrows); +void view_update(View* view, size_t* csrx, size_t* csry); Row* view_getrow(View* view, size_t row); void view_byrune(View* view, int move, bool extsel); void view_byword(View* view, int move, bool extsel); diff --git a/lib/view.c b/lib/view.c index a9ef06e..cc9d10d 100644 --- a/lib/view.c +++ b/lib/view.c @@ -8,18 +8,51 @@ typedef size_t (*movefn_t)(Buf* buf, size_t pos, int count); -static void move_selection(View* view, bool extsel, int move, movefn_t bything); -static void move_to(View* view, bool extsel, size_t off); -static bool selection_visible(View* view); -static void find_cursor(View* view, size_t* csrx, size_t* csry); -static void clearrow(View* view, size_t row); -static size_t setcell(View* view, size_t row, size_t col, Rune r); -static size_t fill_row(View* view, unsigned row, size_t pos); -static unsigned prev_screen_line(View* view, unsigned bol, unsigned off); -static unsigned scroll_up(View* view); -static unsigned scroll_dn(View* view); -static void sync_center(View* view, size_t csr); -static size_t getoffset(View* view, size_t row, size_t col); +static void move_selection(View* view, bool extsel, int move, movefn_t bything) { + view->sync_flags |= CURSOR; + if (buf_selsz(BUF) && !extsel) { + buf_selclr(BUF, move); + } else { + CSRPOS = bything(BUF, CSRPOS, move); + if (bything == buf_byline) + buf_setcol(BUF); + if (!extsel) + buf_selclr(BUF, RIGHT); + } + /* only update column if not moving vertically */ + if (bything != buf_byline) + buf_getcol(BUF); +} + +static void move_to(View* view, bool extsel, size_t off) { + Buf* buf = BUF; + CSRPOS = (off > buf_end(buf) ? buf_end(buf) : off); + if (!extsel) + buf_selclr(BUF, RIGHT); + buf_getcol(buf); + view->sync_flags |= CURSOR; +} + +static bool selection_visible(View* view) { + if (!view->nrows) return true; + size_t csr = CSRPOS; + size_t beg = view->rows[0]->off; + size_t end = view->rows[view->nrows-1]->off + + view->rows[view->nrows-1]->len; + return (beg <= csr && csr <= end); +} + +static void find_cursor(View* view, size_t* csrx, size_t* csry) { + size_t csr = CSRPOS; + for (size_t y = 0; y < view->nrows; y++) { + size_t start = view->rows[y]->off; + size_t end = view->rows[y]->off + view->rows[y]->len - 1; + if (start <= csr && csr <= end) { + size_t pos = start; + break; + } + } +} static Sel* getsel(View* view) { return &(view->buffer.selection); @@ -47,52 +80,13 @@ void view_reload(View* view) { } size_t view_limitrows(View* view, size_t maxrows, size_t ncols) { - size_t nrows = 1, pos = 0, col = 0; - while (nrows < maxrows && pos < buf_end(BUF)) { - Rune r = buf_getrat(BUF, pos++); - col += runewidth(col, r); - if (col >= ncols || r == '\n') - col = 0, nrows++; - } - return nrows; + return 1; } -void view_resize(View* view, size_t nrows, size_t ncols) { -#if 1 - size_t off = 0; - if (view->nrows == nrows && view->ncols == ncols) return; - /* free the old row data */ - if (view->nrows) { - off = view->rows[0]->off; - for (size_t i = 0; i < view->nrows; i++) - free(view->rows[i]); - free(view->rows); - } - /* create the new row data */ - view->rows = calloc(nrows, sizeof(Row*)); - for (unsigned i = 0; i < nrows; i++) - view->rows[i] = calloc(1, sizeof(Row) + (ncols * sizeof(UGlyph))); - /* update dimensions */ - view->rows[0]->off = off; - view->nrows = nrows; - view->ncols = ncols; -#endif -} - -void view_update(View* view, int clrnor, int clrsel, size_t* csrx, size_t* csry) { -#if 1 - if (!view->nrows) return; - size_t csr = CSRPOS; - /* scroll the view and reflow the screen lines */ - size_t pos = view->rows[0]->off; - /* fill the view and scroll if needed */ - for (size_t y = 0; y < view->nrows; y++) - pos = fill_row(view, y, pos); - if (view->sync_flags) - view_scrollto(view, csr); - /* locate the cursor if visible */ - find_cursor(view, csrx, csry); -#endif +void view_resize(View* view, size_t width, size_t nrows) { +} + +void view_update(View* view, size_t* csrx, size_t* csry) { } Row* view_getrow(View* view, size_t row) { @@ -112,9 +106,6 @@ void view_byline(View* view, int move, bool extsel) { } void view_setcursor(View* view, size_t row, size_t col, bool extsel) { - size_t off = getoffset(view, row, col); - if (off != SIZE_MAX) - view_jumpto(view, extsel, off); } void view_selword(View* view, size_t row, size_t col) { @@ -140,10 +131,10 @@ size_t view_selsize(View* view) { } char* view_fetch(View* view, size_t row, size_t col, bool (*isword)(Rune)) { - char* str = NULL; - size_t off = getoffset(view, row, col); - if (off != SIZE_MAX) - str = buf_fetch(BUF, isword, off); + char* str = NULL; +// size_t off = getoffset(view, row, col); +// if (off != SIZE_MAX) +// str = buf_fetch(BUF, isword, off); return str; } @@ -241,10 +232,10 @@ void view_scroll(View* view, int move) { int dir = (move < 0 ? -1 : 1); move *= dir; for (int i = 0; i < move; i++) { - if (dir < 0) - scroll_up(view); - else - scroll_dn(view); +// if (dir < 0) +// scroll_up(view); +// else +// scroll_dn(view); } } @@ -258,16 +249,6 @@ Rune view_getrune(View* view) { } void view_scrollto(View* view, size_t csr) { - if (!view->nrows) return; - unsigned first = view->rows[0]->off; - unsigned last = view->rows[view->nrows-1]->off + view->rows[view->nrows-1]->rlen - 1; - while (csr < first) - first = scroll_up(view); - while (csr > last && last < buf_end(BUF)) - last = scroll_dn(view); - if (view->sync_flags & CENTER) - sync_center(view, csr); - view->sync_flags = 0; } void view_selectall(View* view) { @@ -280,179 +261,4 @@ void view_selectobj(View* view, bool (*istype)(Rune)) { view->sync_flags |= CURSOR; } -static void move_selection(View* view, bool extsel, int move, movefn_t bything) { - view->sync_flags |= CURSOR; - if (buf_selsz(BUF) && !extsel) { - buf_selclr(BUF, move); - } else { - CSRPOS = bything(BUF, CSRPOS, move); - if (bything == buf_byline) - buf_setcol(BUF); - if (!extsel) - buf_selclr(BUF, RIGHT); - } - /* only update column if not moving vertically */ - if (bything != buf_byline) - buf_getcol(BUF); -} - -static void move_to(View* view, bool extsel, size_t off) { - Buf* buf = BUF; - CSRPOS = (off > buf_end(buf) ? buf_end(buf) : off); - if (!extsel) - buf_selclr(BUF, RIGHT); - buf_getcol(buf); - view->sync_flags |= CURSOR; -} - -static bool selection_visible(View* view) { - if (!view->nrows) return true; - size_t csr = CSRPOS; - size_t beg = view->rows[0]->off; - size_t end = view->rows[view->nrows-1]->off + - view->rows[view->nrows-1]->rlen; - return (beg <= csr && csr <= end); -} -static void find_cursor(View* view, size_t* csrx, size_t* csry) { - size_t csr = CSRPOS; - for (size_t y = 0; y < view->nrows; y++) { - size_t start = view->rows[y]->off; - size_t end = view->rows[y]->off + view->rows[y]->rlen - 1; - if (start <= csr && csr <= end) { - size_t pos = start; - for (size_t x = 0; x < view->ncols;) { - if (pos == csr) { - *csry = y, *csrx = x; - break; - } - x += runewidth(x, buf_getrat(BUF, pos++)); - } - break; - } - } -} - -static void clearrow(View* view, size_t row) { - Row* scrrow = view_getrow(view, row); - if (!scrrow) return; - for (size_t i = 0; i < view->ncols; i++) - scrrow->cols[i].rune = (Rune)' '; - scrrow->rlen = 0; - scrrow->len = 0; -} - -static size_t setcell(View* view, size_t row, size_t col, Rune r) { - if (row >= view->nrows || col >= view->ncols) return 0; - Row* scrrow = view_getrow(view, row); - int ncols = runewidth(col, r); - /* write the rune to the screen buf */ - if (r == '\t') - scrrow->cols[col].rune = ' '; - else - scrrow->cols[col].rune = r; - /* Update lengths */ - scrrow->rlen += 1; - for (int i = 1; i < ncols; i++) { - scrrow->cols[col+i].rune = '\0'; - } - if ((col + ncols) > scrrow->len) - scrrow->len = col + ncols; - return ncols; -} - -static size_t fill_row(View* view, unsigned row, size_t pos) { - view_getrow(view, row)->off = pos; - clearrow(view, row); - for (size_t x = 0; x < view->ncols;) { - Rune r = buf_getrat(BUF, pos++); - x += setcell(view, row, x, r); - if (buf_iseol(BUF, pos-1)) { - break; - } - } - return pos; -} - -static unsigned prev_screen_line(View* view, unsigned bol, unsigned off) { - unsigned pos = bol; - while (true) { - unsigned x; - for (x = 0; x < view->ncols && (pos + x) < off; x++) - x += runewidth(x, buf_getrat(BUF, pos+x)); - if ((pos + x) >= off) break; - pos += x; - } - return pos; -} - -static unsigned scroll_up(View* view) { - size_t first = view->rows[0]->off; - size_t bol = buf_bol(BUF, first); - size_t prevln = (first == bol ? buf_byline(BUF, bol, UP) : bol); - if (!first) return first; - prevln = prev_screen_line(view, prevln, first); - /* delete the last row and shift the others */ - free(view->rows[view->nrows - 1]); - memmove(&view->rows[1], &view->rows[0], sizeof(Row*) * (view->nrows-1)); - view->rows[0] = calloc(1, sizeof(Row) + (view->ncols * sizeof(UGlyph))); - view->rows[0]->off = prevln; - /* fill in row content */ - fill_row(view, 0, view->rows[0]->off); - return view->rows[0]->off; -} - -static unsigned scroll_dn(View* view) { - size_t last = view->rows[view->nrows-1]->off + view->rows[view->nrows-1]->rlen - 1; - if (last >= buf_end(BUF)) return last; - /* delete the first row and shift the others */ - if (view->nrows > 1) { - free(view->rows[0]); - memmove(&view->rows[0], &view->rows[1], sizeof(Row*) * (view->nrows-1)); - view->rows[view->nrows-1] = calloc(1, sizeof(Row) + (view->ncols * sizeof(UGlyph))); - view->rows[view->nrows-1]->off = (view->rows[view->nrows-2]->off + view->rows[view->nrows-2]->rlen); - /* fill in row content */ - fill_row(view, view->nrows-1, view->rows[view->nrows-1]->off); - } else { - view->rows[0]->off += view->rows[0]->rlen; - fill_row(view, 0, view->rows[0]->off); - } - return view->rows[view->nrows-1]->off + view->rows[view->nrows-1]->rlen - 1; -} - -static void sync_center(View* view, size_t csr) { - /* determine the screenline containing the cursor */ - size_t scrln = 0; - for (; scrln < view->nrows; scrln++) { - unsigned first = view->rows[scrln]->off; - unsigned last = first + view->rows[scrln]->rlen - 1; - if (csr >= first && csr <= last) - break; - } - /* find the middle row and scroll until the cursor is on that row */ - unsigned midrow = view->nrows / 2; - int move = (scrln - midrow); - unsigned count = (move < 0 ? -move : move); - for (; count > 0; count--) - (move < 0 ? scroll_up : scroll_dn)(view); -} - -static size_t getoffset(View* view, size_t row, size_t col) { - Row* scrrow = view_getrow(view, row); - if (!scrrow) return SIZE_MAX; - size_t pos = scrrow->off; - if (col >= scrrow->len) { - pos = (scrrow->off + scrrow->rlen - 1); - } else { - /* multi column runes are followed by \0 slots so if we clicked on a \0 - slot, slide backwards to the real rune. */ - for (; !scrrow->cols[col].rune && col > 0; col--); - /* now lets count the number of runes up to the one we clicked on */ - for (unsigned i = 0; i < col; i++) - if (scrrow->cols[i].rune) - pos++; - } - if (pos >= buf_end(BUF)) - return buf_end(BUF); - return pos; -} diff --git a/lib/x11.c b/lib/x11.c index 1b0a8c5..ddb03d1 100644 --- a/lib/x11.c +++ b/lib/x11.c @@ -315,7 +315,8 @@ static void place_glyphs(int fg, XGlyphSpec* specs, size_t nspecs, bool eol) { XftColorFree(X.display, X.visual, X.colormap, &fgc); } -static void draw_glyphs(size_t x, size_t y, UGlyph* glyphs, size_t rlen, size_t ncols) { +static void draw_glyphs(size_t x, size_t y, UGlyph* glyphs, size_t len) { +#if 0 XGlyphSpec specs[rlen]; size_t i = 0; bool eol = false; @@ -340,6 +341,7 @@ static void draw_glyphs(size_t x, size_t y, UGlyph* glyphs, size_t rlen, size_t place_glyphs(EditFg, specs, numspecs, eol); eol = false, rlen -= numspecs; } +#endif } static void draw_view(int i, size_t nrows, drawcsr* csr, int bg, int fg, int sel) { @@ -348,12 +350,12 @@ static void draw_view(int i, size_t nrows, drawcsr* csr, int bg, int fg, int sel size_t csrx = SIZE_MAX, csry = SIZE_MAX; /* draw the view to the window */ View* view = win_view(i); - view_resize(view, nrows, (csr->w - csr->x) / fwidth); - view_update(view, (bg << 8 | fg), (sel << 8 | fg), &csrx, &csry); + view_resize(view, (csr->w - csr->x), nrows); + view_update(view, &csrx, &csry); draw_rect(bg, csr->x, csr->y, csr->w, (nrows * fheight) + 9); for (size_t y = 0; y < view->nrows; y++) { Row* row = view_getrow(view, y); - draw_glyphs(csr->x + 2, csr->y + 2 + ((y+1) * fheight), row->cols, row->rlen, row->len); + draw_glyphs(csr->x + 2, csr->y + 2 + ((y+1) * fheight), row->cols, row->len); } /* place the cursor on screen */ if (!view_selsize(view) && csrx != SIZE_MAX && csry != SIZE_MAX) { @@ -379,7 +381,7 @@ static void draw_scroll(drawcsr* csr) { 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; + size_t vend = view->rows[view->nrows-1]->off + view->rows[view->nrows-1]->len; double scroll_vis = (double)(vend - vbeg) / (double)bend; double scroll_off = ((double)vbeg / (double)bend); size_t thumbreg = (csr->y - Divider) + 4; @@ -542,7 +544,7 @@ static void xupdate(Job* job) { drawcsr csr = { .w = X.width, .h = X.height }; size_t maxtagrows = ((X.height - 2) / 4) / fheight; size_t tagcols = csr.w / fwidth; - size_t tagrows = view_limitrows(win_view(TAGS), maxtagrows, tagcols); + size_t tagrows = 1; size_t editrows = ((X.height - 7) / fheight) - tagrows; /* draw the regions to the window */ draw_view(TAGS, tagrows, &csr, TagsBg, TagsFg, TagsSel); -- 2.49.0