richterm

"terminal emulator" with support for text fonts and images for plan9
git clone git://nsmpr.xyz/richterm.git
Log | Files | Refs | README

commit 5944cd9eec718dbaa0c48f56be9a0ffd4bf34a94
parent 03262c40695a4e1e7d29804f13f721bfec77fe71
Author: Pavel Renev <an2qzavok@gmail.com>
Date:   Sun,  8 Aug 2021 23:30:19 +0000

change color scheme, add selection (still buggy)

Diffstat:
Mrichterm.c | 210+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------
Mrichterm.h | 6++++--
2 files changed, 168 insertions(+), 48 deletions(-)

diff --git a/richterm.c b/richterm.c @@ -16,15 +16,23 @@ Channel *pidchan; Devfsctl *dctl; Fsctl *fsctl; Fonts fonts; -Image *Iscrollbar, *Ilink; +Image *Iscrollbar, *Ilink, *Inormbg, *Iselbg; Object *olast; +enum { + MM_NONE, + MM_SCROLLBAR, + MM_TEXT, + MM_SELECT, +}; + void resize(void); void shutdown(void); void send_interrupt(void); void runcmd(void *); void scroll(Point, Rich *); -int mouse(Mouse, int); +void mouse(Mouse, int *); +usize getsel(Point p); View * getview(Point p); void @@ -63,6 +71,9 @@ threadmain(int argc, char **argv) rich.page.scroll = ZP; rich.page.view = nil; + rich.page.selstart = 0; + rich.page.selend = 0; + qunlock(rich.l); if (initdraw(0, 0, "richterm") < 0) @@ -70,12 +81,19 @@ threadmain(int argc, char **argv) olast = newobject(&rich, nil); - mmode = 0; + mmode = MM_NONE; Iscrollbar = allocimage( - display, Rect(0,0,1,1), screen->chan, 1, 0x888888FF); + display, Rect(0,0,1,1), screen->chan, 1, 0x999999FF); + + Inormbg = allocimage( + display, Rect(0,0,1,1), screen->chan, 1, 0xDDDDDDFF); - Ilink = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DBlue); + Iselbg = allocimage( + display, Rect(0,0,1,1), screen->chan, 1, 0xBBBBBBFF); + + Ilink = allocimage( + display, Rect(0,0,1,1), screen->chan, 1, DBlue); resize(); redraw(1); @@ -103,7 +121,7 @@ threadmain(int argc, char **argv) for (;;) { switch(alt(alts)) { case MOUSE: - mmode = mouse(mv, mmode); + mouse(mv, &mmode); break; case RESIZE: if (getwindow(display, Refnone) < 0) @@ -143,13 +161,16 @@ threadmain(int argc, char **argv) break; } if (rich.obj != nil) { + int n; + n = runelen(kv); + qlock(rich.l); - olast->dtext->n+=runelen(kv); + olast->dtext->n+=n; olast->dtext->p = realloc( olast->dtext->p, olast->dtext->n + 1); - runetochar(olast->dtext->p + olast->dtext->n - 1, &kv); + runetochar(olast->dtext->p + olast->dtext->n - n, &kv); olast->dtext->p[olast->dtext->n] = '\0'; qunlock(rich.l); @@ -185,55 +206,71 @@ threadmain(int argc, char **argv) } } -int -mouse(Mouse mv, int mmode) +void +mouse(Mouse mv, int *mmode) { - if (mv.buttons == 0) mmode = 0; + View *v; + + if (mv.buttons == 0) { + *mmode = MM_NONE; + return; + } if (mv.buttons == 8) { scroll( subpt(rich.page.scroll, Pt(0, mv.xy.y - rich.page.r.min.y)), &rich); - return mmode; + return; } if (mv.buttons == 16) { scroll( addpt(rich.page.scroll, Pt(0, mv.xy.y - rich.page.r.min.y)), &rich); - return mmode; + return; + } + + if (*mmode == MM_NONE) { + if (ptinrect(mv.xy, rich.page.rs) != 0) + *mmode = MM_SCROLLBAR; + if (ptinrect(mv.xy, rich.page.r) != 0) + *mmode = MM_TEXT; } - if (ptinrect(mv.xy, rich.page.rs) != 0) { /* scrollbar */ + + switch (*mmode) { + case MM_SCROLLBAR: if (mv.buttons == 1) { scroll( subpt(rich.page.scroll, Pt(0, mv.xy.y - rich.page.r.min.y)), &rich); + } else if (mv.buttons == 2) { + scroll( + Pt(rich.page.scroll.x, + (mv.xy.y - rich.page.r.min.y) * + ((double)rich.page.max.y / Dy(rich.page.r))), + &rich); } else if (mv.buttons == 4) { scroll( addpt(rich.page.scroll, Pt(0, mv.xy.y - rich.page.r.min.y)), &rich); - } else if (mv.buttons == 2) { - mmode = 1; } - } - if (mmode == 1) { - int y; - - y = (mv.xy.y - rich.page.r.min.y) * - ((double)rich.page.max.y / Dy(rich.page.r)); - - scroll(Pt(rich.page.scroll.x, y), &rich); - } else { /* text area */ + break; + case MM_TEXT: if (mv.buttons == 1) { - View *view; + rich.page.selstart = getsel(mv.xy); + rich.page.selend = rich.page.selstart; + redraw(1); + *mmode = MM_SELECT; + } + if (mv.buttons == 4) { Object *obj; Data *dlink; - view = getview(mv.xy); + v = getview(mv.xy); obj = nil; dlink = nil; - if (view != nil) obj = view->obj; + if (v != nil) obj = v->obj; if (obj != nil) dlink = obj->dlink; if ((dlink != nil) && (dlink->n > 0)) { Data dv; @@ -242,19 +279,53 @@ mouse(Mouse mv, int mmode) memcpy(dv.p, dlink->p, dv.n); nbsend(dctl->rc, &dv); } + break; } + case MM_SELECT: + if (mv.buttons == (1|2)) { + /* cut */ + break; + } + if (mv.buttons == (1|4)) { + /* paste */ + break; + } + rich.page.selend = getsel(mv.xy); + redraw(1); } +} - return mmode; +usize +getsel(Point p) +{ + View *v; + long i; + usize cc; + cc = 0; + v = getview(p); + if (v == nil) return 0; + for (i = 0; i < rich.page.count ; i++) { + if (v == &rich.page.view[i]) break; + cc += rich.page.view[i].length; + } + for (i = 0; i < v->length; i++) { + if (stringnwidth(v->obj->font, v->dp, i) >= + p.x - v->r.min.x) + break; + } + return cc + i - 1; } View * getview(Point p) { int i; + if (p.x < rich.page.r.min.x) p.x = rich.page.r.min.x; + if (p.x > rich.page.r.max.x) p.x = rich.page.r.max.x; + for (i = 0; i < rich.page.count; i++) { if (ptinrect(p, rich.page.view[i].r) != 0) - return &(rich.page.view[i]); + return &rich.page.view[i]; } return nil; } @@ -273,48 +344,75 @@ drawpage(Image *dst, Page *p) void drawview(Image *dst, View *v) { + Image *bg; Rectangle r; r = rectsubpt(v->r, v->page->scroll); - draw(dst, r, display->white, nil, ZP); - stringn(dst, r.min, v->color, ZP, v->obj->font, v->dp, v->length); + if (v->image != nil) { + draw(dst, r, v->image, nil, ZP); + } else { + bg = (v->selected != 0) ? Iselbg : Inormbg; + draw(dst, r, bg, nil, ZP); + stringn(dst, r.min, v->color, ZP, + v->obj->font, v->dp, v->length); + } } void generatepage(Rich *rich) { - #define BSIZE 4096 - Rectangle r; char *sp; + usize cc; Object *obj; - int newline, tab, ymax, i; + int sel, ymax, i; + usize selmin, selmax; Point pt; Page *page; - View *v; - char *brkp; + + enum { + SEL_BEFORE, + SEL_IN, + SEL_AFTER + }; + + + sel = SEL_BEFORE; + cc = 0; qlock(rich->l); + + if (rich->obj == nil) { + qunlock(rich->l); + return; + } page = &rich->page; r = page->r; + if (page->selstart < page->selend) { + selmin = page->selstart; + selmax = page->selend; + } else { + selmin = page->selend; + selmax = page->selstart; + } + page->count = 0; - page->scroll = rich->page.scroll; pt = r.min; ymax = 0; - - if (rich->obj == nil) { - qunlock(rich->l); - return; - } obj = *rich->obj; sp = obj->dtext->p; i = 0; while (i < rich->count) { + int newline, tab; + View *v; + char *brkp; + newline = 0; tab = 0; + page->count++; page->view = realloc(page->view, sizeof(View) * (page->count)); v = &page->view[page->count - 1]; @@ -324,15 +422,31 @@ generatepage(Rich *rich) if (obj->dlink->n > 0) v->color = Ilink; v->page = &rich->page; + v->image = nil; + v->selected = (sel == SEL_IN); + v->dp = sp; /* TODO: next line is probably incorrect */ - v->length = obj->dtext->n; + v->length = obj->dtext->n; /* this how it should look in theory, but it doesn't work: * v->length = obj->dtext->p + obj->dtext->n - sp + 1; */ + if ((sel==SEL_BEFORE) && + (v->length > selmin - cc)) { + v->length = selmin - cc; + sp = v->dp + v->length; + sel = SEL_IN; + } + if ((sel==SEL_IN) && + (v->length > selmax - cc)) { + v->length = selmax - cc; + sp = v->dp + v->length; + sel = SEL_AFTER; + } + /* TODO: v->dp is not guaranteed to be null-terminated * so, rework following section without strpbrk */ @@ -374,9 +488,11 @@ generatepage(Rich *rich) break; } } + v->r.max.x = nx; pt.x = nx; } if (newline != 0) { + v->r.max.x = r.max.x; pt.x = r.min.x; pt.y = ymax; } @@ -388,6 +504,8 @@ generatepage(Rich *rich) sp = obj->dtext->p; } } + + cc += v->length; } rich->page.max.y = ymax - r.min.y; @@ -530,7 +648,7 @@ void redraw(int regen) { if (regen != 0) generatepage(&rich); - draw(screen, screen->r, display->white, nil, ZP); + draw(screen, screen->r, Inormbg, nil, ZP); drawpage(screen, &rich.page); drawscrollbar(); flushimage(display, 1); @@ -551,7 +669,7 @@ drawscrollbar(void) ), rich.page.rs.min); draw(screen, rich.page.rs, Iscrollbar, nil, ZP); - draw(screen, r, display->white, nil, ZP); + draw(screen, r, Inormbg, nil, ZP); } void diff --git a/richterm.h b/richterm.h @@ -52,7 +52,9 @@ struct View { char *dp; long length; Image *color; + Image *image; Rectangle r; + int selected; }; struct Page { @@ -62,6 +64,8 @@ struct Page { Point max; Rectangle r; Rectangle rs; + usize selstart; + usize selend; }; void drawview(Image *, View *); @@ -76,8 +80,6 @@ struct Rich { usize count; usize idcount; Page page; - usize selstart; - usize selend; }; extern Rich rich;