UGlyph cols[]; /* row data */
} Row;
-void screen_reflow(Buf* buf);
void screen_update(Buf* buf, unsigned crsr, unsigned* csrx, unsigned* csry);
unsigned screen_getoff(Buf* buf, unsigned pos, unsigned row, unsigned col);
void screen_setsize(Buf* buf, unsigned nrows, unsigned ncols);
void screen_getsize(unsigned* nrows, unsigned* ncols);
-void screen_clear(void);
Row* screen_getrow(unsigned row);
void screen_clearrow(unsigned row);
-void screen_setrowoff(unsigned row, unsigned off);
unsigned screen_setcell(unsigned row, unsigned col, Rune r);
-UGlyph* screen_getcell(unsigned row, unsigned col);
void screen_status(char* fmt, ...);
+UGlyph* screen_getglyph(unsigned row, unsigned col, unsigned* scrwidth);
/* Color Scheme Handling
*****************************************************************************/
#include "edit.h"
+#include <wchar.h>
static unsigned NumRows = 0;
static unsigned NumCols = 0;
static Row** Rows;
-void screen_reflow(Buf* buf) {
+static void screen_reflow(Buf* buf) {
unsigned pos = Rows[1]->off;
for (unsigned y = 1; y < NumRows; y++) {
screen_clearrow(y);
- screen_setrowoff(y, pos);
+ screen_getrow(y)->off = pos;
for (unsigned x = 0; x < NumCols;) {
Rune r = buf_get(buf, pos++);
x += screen_setcell(y,x,r);
if (col > scrrow->len) {
pos = (scrrow->off + scrrow->rlen - 1);
} else {
- for (unsigned x = 0; x < col;) {
- Rune r = buf_get(buf,pos++);
- if (r == '\n')
- break;
- else if (r == '\t')
- x += (TabWidth - (x % TabWidth));
- else
- x += 1;
- }
+ /* 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)-1;
*nrows = NumRows, *ncols = NumCols;
}
-void screen_clear(void) {
- for (unsigned i = 0; i < NumRows; i++)
- screen_clearrow(i);
-}
-
Row* screen_getrow(unsigned row) {
return (row < NumRows ? Rows[row] : NULL);
}
scrrow->len = 0;
}
-void screen_setrowoff(unsigned row, unsigned off) {
- screen_getrow(row)->off = off;
+static int runewidth(unsigned col, Rune r) {
+ if (r == '\t') return (TabWidth - (col % TabWidth));
+ int width = wcwidth(r);
+ if (width < 0) width = 1;
+ return width;
}
unsigned screen_setcell(unsigned row, unsigned col, 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 */
- unsigned ncols = 1;
- if (r == '\t') {
+ if (r == '\t' || r == '\n' || r == '\r')
scrrow->cols[col].rune = ' ';
- ncols = (TabWidth - (col % TabWidth));
- } else if (r != '\n') {
+ 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;
}
-UGlyph* screen_getcell(unsigned row, unsigned col) {
+UGlyph* screen_getglyph(unsigned row, unsigned col, unsigned* scrwidth) {
if (row >= NumRows || col >= NumCols) return 0;
Row* scrrow = screen_getrow(row);
- return &(scrrow->cols[col]);
+ UGlyph* glyph = &(scrrow->cols[col]);
+ *scrwidth = 1;
+ for (col++; !scrrow->cols[col].rune; col++)
+ *scrwidth += 1;
+ return glyph;
}
static void fill_row(Buf* buf, unsigned row, unsigned pos) {
static unsigned prev_screen_line(Buf* buf, unsigned bol, unsigned off) {
unsigned pos = bol;
while (true) {
- unsigned x = 0;
- for (; x < NumCols && (pos + x) < off; x++) {
- Rune r = buf_get(buf, pos+x);
- x += (r == '\t' ? (TabWidth - (x % TabWidth)) : 1);
- }
+ unsigned x;
+ for (x = 0; x < NumCols && (pos + x) < off; x++)
+ x += runewidth(x, buf_get(buf, pos+x));
if ((pos + x) >= off) break;
pos += x;
}
*csry = y, *csrx = x;
break;
}
- if (buf_get(buf,pos++) == '\t')
- x += (TabWidth - (x % TabWidth));
- else
- x += 1;
+ x += runewidth(x, buf_get(buf,pos++));
}
break;
}
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 numspecs = 0;
- for (int i = 0, xp = winx, yp = winy + Fonts.base.ascent; i < len; ++i) {
- if (!glyphs[i].rune) continue;
+ for (int i = 0, xp = winx, yp = winy + Fonts.base.ascent; i < len;) {
font_find(&(specs[numspecs]), glyphs[i].rune);
- int runewidth = wcwidth(glyphs[i].rune) * Fonts.base.width;
specs[numspecs].x = xp;
specs[numspecs].y = yp;
- xp += runewidth;
+ xp += Fonts.base.width;
numspecs++;
+ i++;
+ /* skip over null chars which mark multi column runes */
+ for (; i < len && !glyphs[i].rune; i++)
+ xp += Fonts.base.width;
}
return numspecs;
}
static XftColor xftcolor(enum ColorId cid) {
Color c = Palette[cid][ColorBase];
XftColor xc;
- xc.color.red = ((c & 0x00FF0000) >> 8);
- xc.color.green = ((c & 0x0000FF00));
- xc.color.blue = ((c & 0x000000FF) << 8);
+ xc.color.red = 0xFF | ((c & 0x00FF0000) >> 8);
+ xc.color.green = 0xFF | ((c & 0x0000FF00));
+ xc.color.blue = 0xFF | ((c & 0x000000FF) << 8);
xc.color.alpha = UINT16_MAX;
XftColorAllocValue(X.display, X.visual, X.colormap, &xc.color, &xc);
return xc;
}
/* Place cursor on screen */
- UGlyph* csrrune = screen_getcell(csry,csrx);
+ unsigned rwidth;
+ UGlyph* csrrune = screen_getglyph(csry, csrx, &rwidth);
if (Buffer.insert_mode) {
XftDrawRect(X.xft, &csrclr, csrx * Fonts.base.width, csry * Fonts.base.height, 2, Fonts.base.height);
} else {
- unsigned width = ('\t' == buf_get(&Buffer, CursorPos) ? (TabWidth - (csrx % TabWidth)) : 1);
- XftDrawRect(X.xft, &csrclr, csrx * Fonts.base.width, csry * Fonts.base.height, width * Fonts.base.width, Fonts.base.height);
+ XftDrawRect(X.xft, &csrclr, csrx * Fonts.base.width, csry * Fonts.base.height, rwidth * Fonts.base.width, Fonts.base.height);
draw_runes(csrx, csry, &bkgclr, NULL, csrrune, 1);
}