static unsigned NumCols = 0;
static Row** Rows;
+#define ATTR_NORMAL (CLR_BASE03 << 8 | CLR_BASE0)
+#define ATTR_SELECTED (CLR_BASE0 << 8 | CLR_BASE03)
+
+static unsigned fill_row(Buf* buf, unsigned row, unsigned pos) {
+ screen_getrow(row)->off = pos;
+ screen_clearrow(row);
+ for (unsigned x = 0; x < NumCols;) {
+ uint32_t attr = (DotBeg <= pos && pos < DotEnd ? ATTR_SELECTED : ATTR_NORMAL);
+ Rune r = buf_get(buf, pos++);
+ x += screen_setcell(row, x, attr, r);
+ if (buf_iseol(buf, pos-1)) break;
+ }
+ return pos;
+}
+
static void screen_reflow(Buf* buf) {
unsigned pos = Rows[0]->off;
- for (unsigned y = 0; y < NumRows; y++) {
- screen_clearrow(y);
- screen_getrow(y)->off = pos;
- for (unsigned x = 0; x < NumCols;) {
- Rune r = buf_get(buf, pos++);
- x += screen_setcell(y,x,r);
- if (buf_iseol(buf, pos-1)) break;
- }
- }
+ for (unsigned y = 0; y < NumRows; y++)
+ pos = fill_row(buf, y, pos);
}
void screen_setsize(Buf* buf, unsigned nrows, unsigned ncols) {
scrrow->len = 0;
}
-unsigned screen_setcell(unsigned row, unsigned col, Rune r) {
+unsigned screen_setcell(unsigned row, unsigned col, uint32_t attr, Rune r) {
if (row >= NumRows || col >= NumCols) return 0;
Row* scrrow = screen_getrow(row);
int ncols = runewidth(col, r);
/* write the rune to the screen buf */
+ scrrow->cols[col].attr = attr;
if (r == '\t' || r == '\n' || r == RUNE_CRLF)
scrrow->cols[col].rune = ' ';
else
scrrow->cols[col].rune = r;
/* Update lengths */
scrrow->rlen += 1;
- for (int i = 1; i < ncols; i++)
+ for (int i = 1; i < ncols; i++) {
+ scrrow->cols[col].attr = attr;
scrrow->cols[col+i].rune = '\0';
+ }
if ((col + ncols) > scrrow->len)
scrrow->len = col + ncols;
return ncols;
return glyph;
}
-static void fill_row(Buf* buf, unsigned row, unsigned pos) {
- screen_clearrow(row);
- for (unsigned x = 0; x < NumCols;) {
- Rune r = buf_get(buf, pos++);
- x += screen_setcell(row, x, r);
- if (buf_iseol(buf, pos-1)) break;
- }
-}
-
static unsigned prev_screen_line(Buf* buf, unsigned bol, unsigned off) {
unsigned pos = bol;
while (true) {
void screen_update(Buf* buf, unsigned csr, unsigned* csrx, unsigned* csry) {
/* scroll the view and reflow the screen lines */
sync_view(buf, csr);
- if (buf->insert_mode)
- screen_reflow(buf);
+ screen_reflow(buf);
/* find the cursor on the new screen */
for (unsigned y = 0; y < NumRows; y++) {
unsigned start = Rows[y]->off;
}
int font_makespecs(XftGlyphFontSpec* specs, const UGlyph* glyphs, int len, int x, int y) {
- int winx = x * Fonts.base.width, winy = y * Fonts.base.height;
+ int winx = x * Fonts.base.width, winy = y * Fonts.base.ascent;
int numspecs = 0;
for (int i = 0, xp = winx, yp = winy + Fonts.base.ascent; i < len;) {
font_find(&(specs[numspecs]), glyphs[i].rune);
event.type = MouseMove;
event.button = MOUSE_NONE;
event.x = e->xmotion.x / Fonts.base.width;
- event.y = e->xmotion.y / (Fonts.base.ascent + Fonts.base.descent);
+ event.y = e->xmotion.y / Fonts.base.height;
} else {
event.type = (e->type = ButtonPress ? MouseDown : MouseUp);
/* set the button id */
default: event.button = MOUSE_NONE; break;
}
event.x = e->xbutton.x / Fonts.base.width;
- event.y = e->xbutton.y / (Fonts.base.ascent + Fonts.base.descent);
+ event.y = e->xbutton.y / Fonts.base.height;
}
return &event;
}
void draw_runes(unsigned x, unsigned y, XftColor* fg, XftColor* bg, UGlyph* glyphs, size_t rlen) {
(void)bg;
XftGlyphFontSpec specs[rlen];
- size_t nspecs = font_makespecs(specs, glyphs, rlen, x, y);
- XftDrawGlyphFontSpec(X.xft, fg, specs, nspecs);
+ while (rlen) {
+ size_t nspecs = font_makespecs(specs, glyphs, rlen, x, y);
+ XftDrawGlyphFontSpec(X.xft, fg, specs, nspecs);
+ rlen -= nspecs;
+ }
+}
+
+void draw_glyphs(unsigned x, unsigned y, UGlyph* glyphs, size_t rlen, size_t ncols) {
+ XftGlyphFontSpec specs[rlen];
+ int i = 0;
+ while (rlen) {
+ int numspecs = 0;
+ int attr = glyphs[i].attr;
+ while (i < ncols && glyphs[i].attr == attr) {
+ font_find(&(specs[numspecs]), glyphs[i].rune);
+ specs[numspecs].x = x;
+ specs[numspecs].y = y - Fonts.base.descent;
+ x += Fonts.base.width;
+ numspecs++;
+ i++;
+ /* skip over null chars which mark multi column runes */
+ for (; i < ncols && !glyphs[i].rune; i++)
+ x += Fonts.base.width;
+ }
+ /* Draw the glyphs with the proper colors */
+ uint8_t bg = attr >> 8;
+ uint8_t fg = attr & 0xFF;
+ if (bg != CLR_BASE03)
+ XftDrawRect(X.xft, clr(bg), specs[0].x, y-Fonts.base.height, x-specs[0].x, Fonts.base.height);
+ XftDrawGlyphFontSpec(X.xft, clr(fg), specs, numspecs);
+ rlen -= numspecs;
+ }
+}
+
+void draw_row(unsigned x, unsigned y, Row* row) {
+ draw_glyphs(x, y, row->cols, row->rlen, row->len);
}
static void draw_status(XftColor* fg, unsigned ncols) {
- UGlyph glyphs[ncols];
- UGlyph* status = glyphs;
+ UGlyph glyphs[ncols], *status = glyphs;
(status++)->rune = (Buffer.charset == BINARY ? 'B' : 'U');
(status++)->rune = (Buffer.crlf ? 'C' : 'N');
(status++)->rune = (Buffer.modified ? '*' : ' ');
draw_runes(0, 0, fg, NULL, glyphs, status - glyphs);
}
+static void draw_cursor(unsigned csrx, unsigned csry) {
+ unsigned rwidth;
+ UGlyph* csrrune = screen_getglyph(csry, csrx, &rwidth);
+ csrrune->attr = (CLR_BASE3 << 8 | CLR_BASE03);
+ if (Buffer.insert_mode) {
+ XftDrawRect(X.xft, CSRCLR, csrx * Fonts.base.width, (csry+1) * Fonts.base.height, 1, Fonts.base.height);
+ } else {
+ XftDrawRect(X.xft, CSRCLR, csrx * Fonts.base.width, (csry+1) * Fonts.base.height, rwidth * Fonts.base.width, Fonts.base.height);
+ draw_glyphs(csrx * Fonts.base.width, (csry+2) * Fonts.base.height, csrrune, 1, rwidth);
+ }
+}
+
static void redraw(void) {
+ uint32_t start = getmillis();
/* draw the background colors */
XftDrawRect(X.xft, BKGCLR, 0, 0, X.width, X.height);
XftDrawRect(X.xft, GTRCLR, 79 * Fonts.base.width, 0, Fonts.base.width, X.height);
- XftDrawRect(X.xft, TXTCLR, 0, 0, X.width, Fonts.base.height);
+ XftDrawRect(X.xft, clr(CLR_BASE02), 0, 0, X.width, Fonts.base.height);
+ XftDrawRect(X.xft, clr(CLR_BASE01), 0, Fonts.base.height, X.width, 1);
/* update the screen buffer and retrieve cursor coordinates */
unsigned csrx, csry;
/* flush the screen buffer */
unsigned nrows, ncols;
screen_getsize(&nrows, &ncols);
- draw_status(BKGCLR, ncols);
+ draw_status(clr(CLR_BASE2), ncols);
for (unsigned y = 0; y < nrows; y++) {
Row* row = screen_getrow(y);
- draw_runes(0, y+1, TXTCLR, NULL, row->cols, row->len);
+ draw_glyphs(0, (y+2) * Fonts.base.height, row->cols, row->rlen, row->len);
}
/* Place cursor on screen */
- unsigned rwidth;
- UGlyph* csrrune = screen_getglyph(csry, csrx, &rwidth);
- if (Buffer.insert_mode) {
- XftDrawRect(X.xft, CSRCLR, csrx * Fonts.base.width, (csry+1) * Fonts.base.height, 1, Fonts.base.height);
- } else {
- XftDrawRect(X.xft, CSRCLR, csrx * Fonts.base.width, (csry+1) * Fonts.base.height, rwidth * Fonts.base.width, Fonts.base.height);
- draw_runes(csrx, csry+1, BKGCLR, NULL, csrrune, 1);
- }
+ draw_cursor(csrx, csry);
/* flush pixels to the screen */
XCopyArea(X.display, X.pixmap, X.window, X.gc, 0, 0, X.width, X.height, 0, 0);
XFlush(X.display);
+ printf("refresh: %u\n", getmillis() - start);
}
int main(int argc, char** argv) {