123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- /*
- * This file is part of the UCB release of Plan 9. It is subject to the license
- * terms in the LICENSE file found in the top-level directory of this
- * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
- * part of the UCB release of Plan 9, including this file, may be copied,
- * modified, propagated, or distributed except according to the terms contained
- * in the LICENSE file.
- */
- #include <u.h>
- #include <libc.h>
- #include <draw.h>
- #include <thread.h>
- #include <mouse.h>
- #include <keyboard.h>
- #include <control.h>
- static int debug = 0;
- typedef struct Text Text;
- struct Text
- {
- Control;
- int border;
- int topline;
- int scroll;
- int nvis;
- int lastbut;
- CFont *font;
- CImage *image;
- CImage *textcolor;
- CImage *bordercolor;
- CImage *selectcolor;
- CImage *selectingcolor;
- Rune **line;
- int selectmode; // Selsingle, Selmulti
- int selectstyle; // Seldown, Selup (use Selup only with Selsingle)
- uint8_t *selected;
- int nline;
- int warp;
- int align;
- int sel; // line nr of selection made by last button down
- int but; // last button down (still being hold)
- int offsel; // we are on selection
- };
- enum
- {
- Selsingle,
- Selmulti,
- Seldown,
- Selup,
- };
- enum{
- EAccumulate,
- EAdd,
- EAlign,
- EBorder,
- EBordercolor,
- EClear,
- EDelete,
- EFocus,
- EFont,
- EHide,
- EImage,
- ERect,
- EReplace,
- EReveal,
- EScroll,
- ESelect,
- ESelectcolor,
- ESelectingcolor,
- ESelectmode,
- ESelectstyle,
- EShow,
- ESize,
- ETextcolor,
- ETopline,
- EValue,
- EWarp,
- };
- static char *cmds[] = {
- [EAccumulate] = "accumulate",
- [EAdd] = "add",
- [EAlign] = "align",
- [EBorder] = "border",
- [EBordercolor] = "bordercolor",
- [EClear] = "clear",
- [EDelete] = "delete",
- [EFocus] = "focus",
- [EFont] = "font",
- [EHide] = "hide",
- [EImage] = "image",
- [ERect] = "rect",
- [EReplace] = "replace",
- [EReveal] = "reveal",
- [EScroll] = "scroll",
- [ESelect] = "select",
- [ESelectcolor] = "selectcolor",
- [ESelectingcolor] = "selectingcolor",
- [ESelectmode] = "selectmode",
- [ESelectstyle] = "selectstyle",
- [EShow] = "show",
- [ESize] = "size",
- [ETextcolor] = "textcolor",
- [ETopline] = "topline",
- [EValue] = "value",
- [EWarp] = "warp",
- nil
- };
- static void textshow(Text*);
- static void texttogglei(Text*, int);
- static int textline(Text*, Point);
- static int texttoggle(Text*, Point);
- static void
- textmouse(Control *c, Mouse *m)
- {
- Text *t;
- int sel;
- t = (Text*)c;
- if (debug) fprint(2, "textmouse %s t->lastbut %d; m->buttons %d\n", t->name, t->lastbut, m->buttons);
- if (t->warp >= 0)
- return;
- if ((t->selectstyle == Selup) && (m->buttons&7)) {
- sel = textline(t, m->xy);
- if (t->sel >= 0) {
- // if (debug) fprint(2, "textmouse Selup %q sel=%d t->sel=%d t->but=%d\n",
- // t->name, sel, t->sel, t->but);
- t->offsel = (sel == t->sel) ? 0 : 1;
- if ((sel == t->sel &&
- ((t->selected[t->sel] && !t->but) ||
- ((!t->selected[t->sel]) && t->but))) ||
- (sel != t->sel &&
- ((t->selected[t->sel] && t->but) ||
- ((!t->selected[t->sel]) && (!t->but))))) {
- texttogglei(t, t->sel);
- }
- }
- }
- if(t->lastbut != (m->buttons&7)){
- if(m->buttons & 7){
- sel = texttoggle(t, m->xy);
- if(sel >= 0) {
- if (t->selectstyle == Seldown) {
- chanprint(t->event, "%q: select %d %d",
- t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
- if (debug) fprint(2, "textmouse Seldown event %q: select %d %d\n",
- t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
- } else {
- if (debug) fprint(2, "textmouse Selup no event yet %q: select %d %d\n",
- t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
- t->sel = sel;
- t->but = t->selected[sel] ? (m->buttons & 7) : 0;
- }
- }
- } else if (t->selectstyle == Selup) {
- sel = textline(t, m->xy);
- t->offsel = 0;
- if ((sel >= 0) && (sel == t->sel)) {
- chanprint(t->event, "%q: select %d %d",
- t->name, sel, t->but);
- if (debug) fprint(2, "textmouse Selup event %q: select %d %d\n",
- t->name, sel, t->but);
- } else if (sel != t->sel) {
- if ((t->selected[t->sel] && t->but) ||
- ((!t->selected[t->sel]) && (!t->but))) {
- texttogglei(t, t->sel);
- } else {
- textshow(t);
- }
- if (debug) fprint(2, "textmouse Selup cancel %q: select %d %d\n",
- t->name, sel, t->but);
- }
- t->sel = -1;
- t->but = 0;
- }
- t->lastbut = m->buttons & 7;
- }
- }
- static void
- textfree(Control *c)
- {
- int i;
- Text *t;
- t = (Text*)c;
- _putctlfont(t->font);
- _putctlimage(t->image);
- _putctlimage(t->textcolor);
- _putctlimage(t->bordercolor);
- _putctlimage(t->selectcolor);
- _putctlimage(t->selectingcolor);
- for(i=0; i<t->nline; i++)
- free(t->line[i]);
- free(t->line);
- free(t->selected);
- }
- static void
- textshow(Text *t)
- {
- Rectangle r, tr;
- Point p;
- int i, ntext;
- Font *f;
- Rune *text;
- if (t->hidden)
- return;
- r = t->rect;
- f = t->font->font;
- draw(t->screen, r, t->image->image, nil, t->image->image->r.min);
- if(t->border > 0){
- border(t->screen, r, t->border, t->bordercolor->image, t->bordercolor->image->r.min);
- r = insetrect(r, t->border);
- }
- tr = r;
- t->nvis = Dy(r)/f->height;
- for(i=t->topline; i<t->nline && i<t->topline+t->nvis; i++){
- text = t->line[i];
- ntext = runestrlen(text);
- r.max.y = r.min.y+f->height;
- if(t->sel == i && t->offsel)
- draw(t->screen, r, t->selectingcolor->image, nil, ZP);
- else if(t->selected[i])
- draw(t->screen, r, t->selectcolor->image, nil, ZP);
- p = _ctlalignpoint(r,
- runestringnwidth(f, text, ntext),
- f->height, t->align);
- if(t->warp == i) {
- Point p2;
- p2.x = p.x + 0.5*runestringnwidth(f, text, ntext);
- p2.y = p.y + 0.5*f->height;
- moveto(t->controlset->mousectl, p2);
- t->warp = -1;
- }
- _string(t->screen, p, t->textcolor->image,
- ZP, f, nil, text, ntext, tr,
- nil, ZP, SoverD);
- r.min.y += f->height;
- }
- flushimage(display, 1);
- }
- static void
- textctl(Control *c, CParse *cp)
- {
- int cmd, i, n;
- Rectangle r;
- Text *t;
- Rune *rp;
- t = (Text*)c;
- cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
- switch(cmd){
- default:
- ctlerror("%q: unrecognized message '%s'", t->name, cp->str);
- break;
- case EAlign:
- _ctlargcount(t, cp, 2);
- t->align = _ctlalignment(cp->args[1]);
- break;
- case EBorder:
- _ctlargcount(t, cp, 2);
- if(cp->iargs[1] < 0)
- ctlerror("%q: bad border: %c", t->name, cp->str);
- t->border = cp->iargs[1];
- break;
- case EBordercolor:
- _ctlargcount(t, cp, 2);
- _setctlimage(t, &t->bordercolor, cp->args[1]);
- break;
- case EClear:
- _ctlargcount(t, cp, 1);
- for(i=0; i<t->nline; i++)
- free(t->line[i]);
- free(t->line);
- free(t->selected);
- t->line = ctlmalloc(sizeof(Rune*));
- t->selected = ctlmalloc(1);
- t->nline = 0;
- textshow(t);
- break;
- case EDelete:
- _ctlargcount(t, cp, 2);
- i = cp->iargs[1];
- if(i<0 || i>=t->nline)
- ctlerror("%q: line number out of range: %s", t->name, cp->str);
- free(t->line[i]);
- memmove(t->line+i, t->line+i+1, (t->nline-(i+1))*sizeof(Rune*));
- memmove(t->selected+i, t->selected+i+1, t->nline-(i+1));
- t->nline--;
- textshow(t);
- break;
- case EFocus:
- break;
- case EFont:
- _ctlargcount(t, cp, 2);
- _setctlfont(t, &t->font, cp->args[1]);
- break;
- case EHide:
- _ctlargcount(t, cp, 1);
- t->hidden = 1;
- break;
- case EImage:
- _ctlargcount(t, cp, 2);
- _setctlimage(t, &t->image, cp->args[1]);
- break;
- case ERect:
- _ctlargcount(t, cp, 5);
- r.min.x = cp->iargs[1];
- r.min.y = cp->iargs[2];
- r.max.x = cp->iargs[3];
- r.max.y = cp->iargs[4];
- if(Dx(r)<=0 || Dy(r)<=0)
- ctlerror("%q: bad rectangle: %s", t->name, cp->str);
- t->rect = r;
- t->nvis = (Dy(r)-2*t->border)/t->font->font->height;
- break;
- case EReplace:
- _ctlargcount(t, cp, 3);
- i = cp->iargs[1];
- if(i<0 || i>=t->nline)
- ctlerror("%q: line number out of range: %s", t->name, cp->str);
- free(t->line[i]);
- t->line[i] = _ctlrunestr(cp->args[2]);
- textshow(t);
- break;
- case EReveal:
- _ctlargcount(t, cp, 1);
- t->hidden = 0;
- textshow(t);
- break;
- case EScroll:
- _ctlargcount(t, cp, 2);
- t->scroll = cp->iargs[1];
- break;
- case ESelect:
- if(cp->nargs!=2 && cp->nargs!=3)
- badselect:
- ctlerror("%q: bad select message: %s", t->name, cp->str);
- if(cp->nargs == 2){
- if(strcmp(cp->args[1], "all") == 0){
- memset(t->selected, 1, t->nline);
- break;
- }
- if(strcmp(cp->args[1], "none") == 0){
- memset(t->selected, 0, t->nline);
- break;
- }
- if(cp->args[1][0]<'0' && '9'<cp->args[1][0])
- goto badselect;
- texttogglei(t, cp->iargs[1]);
- break;
- }
- if(cp->iargs[1]<0 || cp->iargs[1]>=t->nline)
- ctlerror("%q: selection index out of range (nline %d): %s", t->name, t->nline, cp->str);
- if(t->selected[cp->iargs[1]] != (cp->iargs[2]!=0))
- texttogglei(t, cp->iargs[1]);
- break;
- case ESelectcolor:
- _ctlargcount(t, cp, 2);
- _setctlimage(t, &t->selectcolor, cp->args[1]);
- break;
- case ESelectmode:
- _ctlargcount(t, cp, 2);
- if(strcmp(cp->args[1], "single") == 0)
- t->selectmode = Selsingle;
- else if(strncmp(cp->args[1], "multi", 5) == 0)
- t->selectmode = Selmulti;
- break;
- case ESelectstyle:
- _ctlargcount(t, cp, 2);
- if(strcmp(cp->args[1], "down") == 0)
- t->selectstyle = Seldown;
- else if(strcmp(cp->args[1], "up") == 0)
- t->selectstyle = Selup;
- break;
- case EShow:
- _ctlargcount(t, cp, 1);
- textshow(t);
- break;
- case ESize:
- if (cp->nargs == 3)
- r.max = Pt(10000, 10000);
- else{
- _ctlargcount(t, cp, 5);
- r.max.x = cp->iargs[3];
- r.max.y = cp->iargs[4];
- }
- r.min.x = cp->iargs[1];
- r.min.y = cp->iargs[2];
- if(r.min.x<=0 || r.min.y<=0 || r.max.x<=0 || r.max.y<=0 || r.max.x < r.min.x || r.max.y < r.min.y)
- ctlerror("%q: bad sizes: %s", t->name, cp->str);
- t->size.min = r.min;
- t->size.max = r.max;
- break;
- case ETextcolor:
- _ctlargcount(t, cp, 2);
- _setctlimage(t, &t->textcolor, cp->args[1]);
- break;
- case ETopline:
- _ctlargcount(t, cp, 2);
- i = cp->iargs[1];
- if(i < 0)
- i = 0;
- if(i > t->nline)
- i = t->nline;
- if(t->topline != i){
- t->topline = i;
- textshow(t);
- }
- break;
- case EValue:
- /* set contents to single line */
- /* free existing text and fall through to add */
- for(i=0; i<t->nline; i++){
- free(t->line[i]);
- t->line[i] = nil;
- }
- t->nline = 0;
- t->topline = 0;
- /* fall through */
- case EAccumulate:
- case EAdd:
- switch (cp->nargs) {
- default:
- ctlerror("%q: wrong argument count in '%s'", t->name, cp->str);
- case 2:
- n = t->nline;
- break;
- case 3:
- n = cp->iargs[1];
- if(n<0 || n>t->nline)
- ctlerror("%q: line number out of range: %s", t->name, cp->str);
- break;
- }
- rp = _ctlrunestr(cp->args[cp->nargs-1]);
- t->line = ctlrealloc(t->line, (t->nline+1)*sizeof(Rune*));
- memmove(t->line+n+1, t->line+n, (t->nline-n)*sizeof(Rune*));
- t->line[n] = rp;
- t->selected = ctlrealloc(t->selected, t->nline+1);
- memmove(t->selected+n+1, t->selected+n, t->nline-n);
- t->selected[n] = (t->selectmode==Selmulti && cmd!=EAccumulate);
- t->nline++;
- if(t->scroll) {
- if(n > t->topline + (t->nvis - 1)){
- t->topline = n - (t->nvis - 1);
- if(t->topline < 0)
- t->topline = 0;
- }
- if(n < t->topline)
- t->topline = n;
- }
- if(cmd != EAccumulate)
- if(t->scroll || t->nline<=t->topline+t->nvis)
- textshow(t);
- break;
- case EWarp:
- _ctlargcount(t, cp, 2);
- i = cp->iargs[1];
- if(i <0 || i>=t->nline)
- ctlerror("%q: selection index out of range (nline %d): %s", t->name, t->nline, cp->str);
- if(i < t->topline || i >= t->topline+t->nvis){
- t->topline = i;
- }
- t->warp = cp->iargs[1];
- textshow(t);
- t->warp = -1;
- break;
- }
- }
- static void
- texttogglei(Text *t, int i)
- {
- int prev;
- if(t->selectmode == Selsingle){
- /* clear the others */
- prev = t->selected[i];
- memset(t->selected, 0, t->nline);
- t->selected[i] = prev;
- }
- t->selected[i] ^= 1;
- textshow(t);
- }
- static int
- textline(Text *t, Point p)
- {
- Rectangle r;
- int i;
- r = t->rect;
- if(t->border > 0)
- r = insetrect(r, t->border);
- if(!ptinrect(p, r))
- return -1;
- i = (p.y-r.min.y)/t->font->font->height;
- i += t->topline;
- if(i >= t->nline)
- return -1;
- return i;
- }
- static int
- texttoggle(Text *t, Point p)
- {
- int i;
- i = textline(t, p);
- if (i >= 0)
- texttogglei(t, i);
- return i;
- }
- Control*
- createtext(Controlset *cs, char *name)
- {
- Text *t;
- t = (Text*)_createctl(cs, "text", sizeof(Text), name);
- t->line = ctlmalloc(sizeof(Rune*));
- t->selected = ctlmalloc(1);
- t->nline = 0;
- t->image = _getctlimage("white");
- t->textcolor = _getctlimage("black");
- t->bordercolor = _getctlimage("black");
- t->selectcolor = _getctlimage("yellow");
- t->selectingcolor = _getctlimage("paleyellow");
- t->font = _getctlfont("font");
- t->selectmode = Selsingle;
- t->selectstyle = Selup; // Seldown;
- t->lastbut = 0;
- t->mouse = textmouse;
- t->ctl = textctl;
- t->exit = textfree;
- t->warp = -1;
- t->sel = -1;
- t->offsel = 0;
- t->but = 0;
- return (Control *)t;
- }
|