180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <draw.h>
480ee5cbfSDavid du Colombier #include <thread.h>
580ee5cbfSDavid du Colombier #include <mouse.h>
680ee5cbfSDavid du Colombier #include <keyboard.h>
780ee5cbfSDavid du Colombier #include <control.h>
880ee5cbfSDavid du Colombier
96f314b92SDavid du Colombier static int debug = 0;
106f314b92SDavid du Colombier
1180ee5cbfSDavid du Colombier typedef struct Text Text;
1280ee5cbfSDavid du Colombier
1380ee5cbfSDavid du Colombier struct Text
1480ee5cbfSDavid du Colombier {
1580ee5cbfSDavid du Colombier Control;
1680ee5cbfSDavid du Colombier int border;
1780ee5cbfSDavid du Colombier int topline;
1880ee5cbfSDavid du Colombier int scroll;
1980ee5cbfSDavid du Colombier int nvis;
209a747e4fSDavid du Colombier int lastbut;
2180ee5cbfSDavid du Colombier CFont *font;
2280ee5cbfSDavid du Colombier CImage *image;
2380ee5cbfSDavid du Colombier CImage *textcolor;
2480ee5cbfSDavid du Colombier CImage *bordercolor;
2580ee5cbfSDavid du Colombier CImage *selectcolor;
266f314b92SDavid du Colombier CImage *selectingcolor;
2780ee5cbfSDavid du Colombier Rune **line;
286f314b92SDavid du Colombier int selectmode; // Selsingle, Selmulti
296f314b92SDavid du Colombier int selectstyle; // Seldown, Selup (use Selup only with Selsingle)
3080ee5cbfSDavid du Colombier uchar *selected;
3180ee5cbfSDavid du Colombier int nline;
326f314b92SDavid du Colombier int warp;
3380ee5cbfSDavid du Colombier int align;
346f314b92SDavid du Colombier int sel; // line nr of selection made by last button down
356f314b92SDavid du Colombier int but; // last button down (still being hold)
366f314b92SDavid du Colombier int offsel; // we are on selection
3780ee5cbfSDavid du Colombier };
3880ee5cbfSDavid du Colombier
3980ee5cbfSDavid du Colombier enum
4080ee5cbfSDavid du Colombier {
4180ee5cbfSDavid du Colombier Selsingle,
4280ee5cbfSDavid du Colombier Selmulti,
436f314b92SDavid du Colombier Seldown,
446f314b92SDavid du Colombier Selup,
4580ee5cbfSDavid du Colombier };
4680ee5cbfSDavid du Colombier
4780ee5cbfSDavid du Colombier enum{
489a747e4fSDavid du Colombier EAccumulate,
4980ee5cbfSDavid du Colombier EAdd,
5080ee5cbfSDavid du Colombier EAlign,
5180ee5cbfSDavid du Colombier EBorder,
5280ee5cbfSDavid du Colombier EBordercolor,
5380ee5cbfSDavid du Colombier EClear,
5480ee5cbfSDavid du Colombier EDelete,
5580ee5cbfSDavid du Colombier EFocus,
5680ee5cbfSDavid du Colombier EFont,
579a747e4fSDavid du Colombier EHide,
5880ee5cbfSDavid du Colombier EImage,
5980ee5cbfSDavid du Colombier ERect,
6080ee5cbfSDavid du Colombier EReplace,
619a747e4fSDavid du Colombier EReveal,
6280ee5cbfSDavid du Colombier EScroll,
6380ee5cbfSDavid du Colombier ESelect,
6480ee5cbfSDavid du Colombier ESelectcolor,
656f314b92SDavid du Colombier ESelectingcolor,
6680ee5cbfSDavid du Colombier ESelectmode,
676f314b92SDavid du Colombier ESelectstyle,
6880ee5cbfSDavid du Colombier EShow,
699a747e4fSDavid du Colombier ESize,
7080ee5cbfSDavid du Colombier ETextcolor,
7180ee5cbfSDavid du Colombier ETopline,
7280ee5cbfSDavid du Colombier EValue,
736f314b92SDavid du Colombier EWarp,
7480ee5cbfSDavid du Colombier };
7580ee5cbfSDavid du Colombier
7680ee5cbfSDavid du Colombier static char *cmds[] = {
779a747e4fSDavid du Colombier [EAccumulate] = "accumulate",
7880ee5cbfSDavid du Colombier [EAdd] = "add",
7980ee5cbfSDavid du Colombier [EAlign] = "align",
8080ee5cbfSDavid du Colombier [EBorder] = "border",
8180ee5cbfSDavid du Colombier [EBordercolor] = "bordercolor",
8280ee5cbfSDavid du Colombier [EClear] = "clear",
8380ee5cbfSDavid du Colombier [EDelete] = "delete",
8480ee5cbfSDavid du Colombier [EFocus] = "focus",
8580ee5cbfSDavid du Colombier [EFont] = "font",
869a747e4fSDavid du Colombier [EHide] = "hide",
8780ee5cbfSDavid du Colombier [EImage] = "image",
8880ee5cbfSDavid du Colombier [ERect] = "rect",
8980ee5cbfSDavid du Colombier [EReplace] = "replace",
909a747e4fSDavid du Colombier [EReveal] = "reveal",
9180ee5cbfSDavid du Colombier [EScroll] = "scroll",
9280ee5cbfSDavid du Colombier [ESelect] = "select",
9380ee5cbfSDavid du Colombier [ESelectcolor] = "selectcolor",
946f314b92SDavid du Colombier [ESelectingcolor] = "selectingcolor",
9580ee5cbfSDavid du Colombier [ESelectmode] = "selectmode",
966f314b92SDavid du Colombier [ESelectstyle] = "selectstyle",
9780ee5cbfSDavid du Colombier [EShow] = "show",
989a747e4fSDavid du Colombier [ESize] = "size",
9980ee5cbfSDavid du Colombier [ETextcolor] = "textcolor",
10080ee5cbfSDavid du Colombier [ETopline] = "topline",
10180ee5cbfSDavid du Colombier [EValue] = "value",
1026f314b92SDavid du Colombier [EWarp] = "warp",
10380ee5cbfSDavid du Colombier nil
10480ee5cbfSDavid du Colombier };
10580ee5cbfSDavid du Colombier
10680ee5cbfSDavid du Colombier static void textshow(Text*);
10780ee5cbfSDavid du Colombier static void texttogglei(Text*, int);
1086f314b92SDavid du Colombier static int textline(Text*, Point);
10980ee5cbfSDavid du Colombier static int texttoggle(Text*, Point);
11080ee5cbfSDavid du Colombier
11180ee5cbfSDavid du Colombier static void
textmouse(Control * c,Mouse * m)1129a747e4fSDavid du Colombier textmouse(Control *c, Mouse *m)
11380ee5cbfSDavid du Colombier {
11480ee5cbfSDavid du Colombier Text *t;
1159a747e4fSDavid du Colombier int sel;
11680ee5cbfSDavid du Colombier
1179a747e4fSDavid du Colombier t = (Text*)c;
1186f314b92SDavid du Colombier if (debug) fprint(2, "textmouse %s t->lastbut %d; m->buttons %d\n", t->name, t->lastbut, m->buttons);
1196f314b92SDavid du Colombier if (t->warp >= 0)
1206f314b92SDavid du Colombier return;
1216f314b92SDavid du Colombier if ((t->selectstyle == Selup) && (m->buttons&7)) {
1226f314b92SDavid du Colombier sel = textline(t, m->xy);
1236f314b92SDavid du Colombier if (t->sel >= 0) {
1246f314b92SDavid du Colombier // if (debug) fprint(2, "textmouse Selup %q sel=%d t->sel=%d t->but=%d\n",
1256f314b92SDavid du Colombier // t->name, sel, t->sel, t->but);
1266f314b92SDavid du Colombier t->offsel = (sel == t->sel) ? 0 : 1;
1276f314b92SDavid du Colombier if ((sel == t->sel &&
1286f314b92SDavid du Colombier ((t->selected[t->sel] && !t->but) ||
1296f314b92SDavid du Colombier ((!t->selected[t->sel]) && t->but))) ||
1306f314b92SDavid du Colombier (sel != t->sel &&
1316f314b92SDavid du Colombier ((t->selected[t->sel] && t->but) ||
1326f314b92SDavid du Colombier ((!t->selected[t->sel]) && (!t->but))))) {
1336f314b92SDavid du Colombier texttogglei(t, t->sel);
1346f314b92SDavid du Colombier }
1356f314b92SDavid du Colombier }
1366f314b92SDavid du Colombier }
1379a747e4fSDavid du Colombier if(t->lastbut != (m->buttons&7)){
1389a747e4fSDavid du Colombier if(m->buttons & 7){
1399a747e4fSDavid du Colombier sel = texttoggle(t, m->xy);
1406f314b92SDavid du Colombier if(sel >= 0) {
1416f314b92SDavid du Colombier if (t->selectstyle == Seldown) {
1429a747e4fSDavid du Colombier chanprint(t->event, "%q: select %d %d",
1439a747e4fSDavid du Colombier t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
1446f314b92SDavid du Colombier if (debug) fprint(2, "textmouse Seldown event %q: select %d %d\n",
1456f314b92SDavid du Colombier t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
1466f314b92SDavid du Colombier } else {
1476f314b92SDavid du Colombier if (debug) fprint(2, "textmouse Selup no event yet %q: select %d %d\n",
1486f314b92SDavid du Colombier t->name, sel, t->selected[sel] ? (m->buttons & 7) : 0);
1496f314b92SDavid du Colombier t->sel = sel;
1506f314b92SDavid du Colombier t->but = t->selected[sel] ? (m->buttons & 7) : 0;
1516f314b92SDavid du Colombier }
1526f314b92SDavid du Colombier }
1536f314b92SDavid du Colombier } else if (t->selectstyle == Selup) {
1546f314b92SDavid du Colombier sel = textline(t, m->xy);
1556f314b92SDavid du Colombier t->offsel = 0;
1566f314b92SDavid du Colombier if ((sel >= 0) && (sel == t->sel)) {
1576f314b92SDavid du Colombier chanprint(t->event, "%q: select %d %d",
1586f314b92SDavid du Colombier t->name, sel, t->but);
1596f314b92SDavid du Colombier if (debug) fprint(2, "textmouse Selup event %q: select %d %d\n",
1606f314b92SDavid du Colombier t->name, sel, t->but);
1616f314b92SDavid du Colombier } else if (sel != t->sel) {
1626f314b92SDavid du Colombier if ((t->selected[t->sel] && t->but) ||
1636f314b92SDavid du Colombier ((!t->selected[t->sel]) && (!t->but))) {
1646f314b92SDavid du Colombier texttogglei(t, t->sel);
1656f314b92SDavid du Colombier } else {
1666f314b92SDavid du Colombier textshow(t);
1676f314b92SDavid du Colombier }
1686f314b92SDavid du Colombier if (debug) fprint(2, "textmouse Selup cancel %q: select %d %d\n",
1696f314b92SDavid du Colombier t->name, sel, t->but);
1706f314b92SDavid du Colombier }
1716f314b92SDavid du Colombier t->sel = -1;
1726f314b92SDavid du Colombier t->but = 0;
17380ee5cbfSDavid du Colombier }
1749a747e4fSDavid du Colombier t->lastbut = m->buttons & 7;
17580ee5cbfSDavid du Colombier }
17680ee5cbfSDavid du Colombier }
17780ee5cbfSDavid du Colombier
17880ee5cbfSDavid du Colombier static void
textfree(Control * c)1799a747e4fSDavid du Colombier textfree(Control *c)
18080ee5cbfSDavid du Colombier {
18180ee5cbfSDavid du Colombier int i;
1829a747e4fSDavid du Colombier Text *t;
18380ee5cbfSDavid du Colombier
1849a747e4fSDavid du Colombier t = (Text*)c;
18580ee5cbfSDavid du Colombier _putctlfont(t->font);
18680ee5cbfSDavid du Colombier _putctlimage(t->image);
18780ee5cbfSDavid du Colombier _putctlimage(t->textcolor);
18880ee5cbfSDavid du Colombier _putctlimage(t->bordercolor);
18980ee5cbfSDavid du Colombier _putctlimage(t->selectcolor);
1906f314b92SDavid du Colombier _putctlimage(t->selectingcolor);
19180ee5cbfSDavid du Colombier for(i=0; i<t->nline; i++)
19280ee5cbfSDavid du Colombier free(t->line[i]);
19380ee5cbfSDavid du Colombier free(t->line);
19480ee5cbfSDavid du Colombier free(t->selected);
19580ee5cbfSDavid du Colombier }
19680ee5cbfSDavid du Colombier
19780ee5cbfSDavid du Colombier static void
textshow(Text * t)19880ee5cbfSDavid du Colombier textshow(Text *t)
19980ee5cbfSDavid du Colombier {
20080ee5cbfSDavid du Colombier Rectangle r, tr;
20180ee5cbfSDavid du Colombier Point p;
20280ee5cbfSDavid du Colombier int i, ntext;
20380ee5cbfSDavid du Colombier Font *f;
20480ee5cbfSDavid du Colombier Rune *text;
20580ee5cbfSDavid du Colombier
2069a747e4fSDavid du Colombier if (t->hidden)
2079a747e4fSDavid du Colombier return;
20880ee5cbfSDavid du Colombier r = t->rect;
20980ee5cbfSDavid du Colombier f = t->font->font;
21080ee5cbfSDavid du Colombier draw(t->screen, r, t->image->image, nil, t->image->image->r.min);
21180ee5cbfSDavid du Colombier if(t->border > 0){
21280ee5cbfSDavid du Colombier border(t->screen, r, t->border, t->bordercolor->image, t->bordercolor->image->r.min);
21380ee5cbfSDavid du Colombier r = insetrect(r, t->border);
21480ee5cbfSDavid du Colombier }
21580ee5cbfSDavid du Colombier tr = r;
2169a747e4fSDavid du Colombier t->nvis = Dy(r)/f->height;
21780ee5cbfSDavid du Colombier for(i=t->topline; i<t->nline && i<t->topline+t->nvis; i++){
21880ee5cbfSDavid du Colombier text = t->line[i];
21980ee5cbfSDavid du Colombier ntext = runestrlen(text);
22080ee5cbfSDavid du Colombier r.max.y = r.min.y+f->height;
2216f314b92SDavid du Colombier if(t->sel == i && t->offsel)
2226f314b92SDavid du Colombier draw(t->screen, r, t->selectingcolor->image, nil, ZP);
2236f314b92SDavid du Colombier else if(t->selected[i])
22480ee5cbfSDavid du Colombier draw(t->screen, r, t->selectcolor->image, nil, ZP);
22580ee5cbfSDavid du Colombier p = _ctlalignpoint(r,
22680ee5cbfSDavid du Colombier runestringnwidth(f, text, ntext),
22780ee5cbfSDavid du Colombier f->height, t->align);
2286f314b92SDavid du Colombier if(t->warp == i) {
2296f314b92SDavid du Colombier Point p2;
2306f314b92SDavid du Colombier p2.x = p.x + 0.5*runestringnwidth(f, text, ntext);
2316f314b92SDavid du Colombier p2.y = p.y + 0.5*f->height;
2326f314b92SDavid du Colombier moveto(t->controlset->mousectl, p2);
2336f314b92SDavid du Colombier t->warp = -1;
2346f314b92SDavid du Colombier }
23580ee5cbfSDavid du Colombier _string(t->screen, p, t->textcolor->image,
23680ee5cbfSDavid du Colombier ZP, f, nil, text, ntext, tr,
237ac57dd0bSDavid du Colombier nil, ZP, SoverD);
23880ee5cbfSDavid du Colombier r.min.y += f->height;
23980ee5cbfSDavid du Colombier }
24080ee5cbfSDavid du Colombier flushimage(display, 1);
24180ee5cbfSDavid du Colombier }
24280ee5cbfSDavid du Colombier
24380ee5cbfSDavid du Colombier static void
textctl(Control * c,CParse * cp)2449a747e4fSDavid du Colombier textctl(Control *c, CParse *cp)
24580ee5cbfSDavid du Colombier {
24680ee5cbfSDavid du Colombier int cmd, i, n;
24780ee5cbfSDavid du Colombier Rectangle r;
24880ee5cbfSDavid du Colombier Text *t;
24980ee5cbfSDavid du Colombier Rune *rp;
25080ee5cbfSDavid du Colombier
25180ee5cbfSDavid du Colombier t = (Text*)c;
2529a747e4fSDavid du Colombier cmd = _ctllookup(cp->args[0], cmds, nelem(cmds));
25380ee5cbfSDavid du Colombier switch(cmd){
25480ee5cbfSDavid du Colombier default:
2559a747e4fSDavid du Colombier ctlerror("%q: unrecognized message '%s'", t->name, cp->str);
25680ee5cbfSDavid du Colombier break;
25780ee5cbfSDavid du Colombier case EAlign:
2589a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2599a747e4fSDavid du Colombier t->align = _ctlalignment(cp->args[1]);
26080ee5cbfSDavid du Colombier break;
26180ee5cbfSDavid du Colombier case EBorder:
2629a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2639a747e4fSDavid du Colombier if(cp->iargs[1] < 0)
2649a747e4fSDavid du Colombier ctlerror("%q: bad border: %c", t->name, cp->str);
2659a747e4fSDavid du Colombier t->border = cp->iargs[1];
26680ee5cbfSDavid du Colombier break;
26780ee5cbfSDavid du Colombier case EBordercolor:
2689a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2699a747e4fSDavid du Colombier _setctlimage(t, &t->bordercolor, cp->args[1]);
27080ee5cbfSDavid du Colombier break;
27180ee5cbfSDavid du Colombier case EClear:
2729a747e4fSDavid du Colombier _ctlargcount(t, cp, 1);
27380ee5cbfSDavid du Colombier for(i=0; i<t->nline; i++)
27480ee5cbfSDavid du Colombier free(t->line[i]);
27580ee5cbfSDavid du Colombier free(t->line);
27680ee5cbfSDavid du Colombier free(t->selected);
27780ee5cbfSDavid du Colombier t->line = ctlmalloc(sizeof(Rune*));
27880ee5cbfSDavid du Colombier t->selected = ctlmalloc(1);
27980ee5cbfSDavid du Colombier t->nline = 0;
28080ee5cbfSDavid du Colombier textshow(t);
28180ee5cbfSDavid du Colombier break;
28280ee5cbfSDavid du Colombier case EDelete:
2839a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2849a747e4fSDavid du Colombier i = cp->iargs[1];
28580ee5cbfSDavid du Colombier if(i<0 || i>=t->nline)
2869a747e4fSDavid du Colombier ctlerror("%q: line number out of range: %s", t->name, cp->str);
28780ee5cbfSDavid du Colombier free(t->line[i]);
28880ee5cbfSDavid du Colombier memmove(t->line+i, t->line+i+1, (t->nline-(i+1))*sizeof(Rune*));
28980ee5cbfSDavid du Colombier memmove(t->selected+i, t->selected+i+1, t->nline-(i+1));
29080ee5cbfSDavid du Colombier t->nline--;
29180ee5cbfSDavid du Colombier textshow(t);
29280ee5cbfSDavid du Colombier break;
29380ee5cbfSDavid du Colombier case EFocus:
29480ee5cbfSDavid du Colombier break;
29580ee5cbfSDavid du Colombier case EFont:
2969a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
2979a747e4fSDavid du Colombier _setctlfont(t, &t->font, cp->args[1]);
2989a747e4fSDavid du Colombier break;
2999a747e4fSDavid du Colombier case EHide:
3009a747e4fSDavid du Colombier _ctlargcount(t, cp, 1);
3019a747e4fSDavid du Colombier t->hidden = 1;
30280ee5cbfSDavid du Colombier break;
30380ee5cbfSDavid du Colombier case EImage:
3049a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
3059a747e4fSDavid du Colombier _setctlimage(t, &t->image, cp->args[1]);
30680ee5cbfSDavid du Colombier break;
30780ee5cbfSDavid du Colombier case ERect:
3089a747e4fSDavid du Colombier _ctlargcount(t, cp, 5);
3099a747e4fSDavid du Colombier r.min.x = cp->iargs[1];
3109a747e4fSDavid du Colombier r.min.y = cp->iargs[2];
3119a747e4fSDavid du Colombier r.max.x = cp->iargs[3];
3129a747e4fSDavid du Colombier r.max.y = cp->iargs[4];
31380ee5cbfSDavid du Colombier if(Dx(r)<=0 || Dy(r)<=0)
3149a747e4fSDavid du Colombier ctlerror("%q: bad rectangle: %s", t->name, cp->str);
31580ee5cbfSDavid du Colombier t->rect = r;
3169a747e4fSDavid du Colombier t->nvis = (Dy(r)-2*t->border)/t->font->font->height;
31780ee5cbfSDavid du Colombier break;
31880ee5cbfSDavid du Colombier case EReplace:
3199a747e4fSDavid du Colombier _ctlargcount(t, cp, 3);
3209a747e4fSDavid du Colombier i = cp->iargs[1];
32180ee5cbfSDavid du Colombier if(i<0 || i>=t->nline)
3229a747e4fSDavid du Colombier ctlerror("%q: line number out of range: %s", t->name, cp->str);
32380ee5cbfSDavid du Colombier free(t->line[i]);
3249a747e4fSDavid du Colombier t->line[i] = _ctlrunestr(cp->args[2]);
3259a747e4fSDavid du Colombier textshow(t);
3269a747e4fSDavid du Colombier break;
3279a747e4fSDavid du Colombier case EReveal:
3289a747e4fSDavid du Colombier _ctlargcount(t, cp, 1);
3299a747e4fSDavid du Colombier t->hidden = 0;
33080ee5cbfSDavid du Colombier textshow(t);
33180ee5cbfSDavid du Colombier break;
33280ee5cbfSDavid du Colombier case EScroll:
3339a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
3349a747e4fSDavid du Colombier t->scroll = cp->iargs[1];
33580ee5cbfSDavid du Colombier break;
33680ee5cbfSDavid du Colombier case ESelect:
3379a747e4fSDavid du Colombier if(cp->nargs!=2 && cp->nargs!=3)
33880ee5cbfSDavid du Colombier badselect:
3399a747e4fSDavid du Colombier ctlerror("%q: bad select message: %s", t->name, cp->str);
3409a747e4fSDavid du Colombier if(cp->nargs == 2){
3419a747e4fSDavid du Colombier if(strcmp(cp->args[1], "all") == 0){
34280ee5cbfSDavid du Colombier memset(t->selected, 1, t->nline);
34380ee5cbfSDavid du Colombier break;
34480ee5cbfSDavid du Colombier }
3459a747e4fSDavid du Colombier if(strcmp(cp->args[1], "none") == 0){
34680ee5cbfSDavid du Colombier memset(t->selected, 0, t->nline);
34780ee5cbfSDavid du Colombier break;
34880ee5cbfSDavid du Colombier }
3499a747e4fSDavid du Colombier if(cp->args[1][0]<'0' && '9'<cp->args[1][0])
35080ee5cbfSDavid du Colombier goto badselect;
3519a747e4fSDavid du Colombier texttogglei(t, cp->iargs[1]);
35280ee5cbfSDavid du Colombier break;
35380ee5cbfSDavid du Colombier }
3549a747e4fSDavid du Colombier if(cp->iargs[1]<0 || cp->iargs[1]>=t->nline)
3559a747e4fSDavid du Colombier ctlerror("%q: selection index out of range (nline %d): %s", t->name, t->nline, cp->str);
3569a747e4fSDavid du Colombier if(t->selected[cp->iargs[1]] != (cp->iargs[2]!=0))
3579a747e4fSDavid du Colombier texttogglei(t, cp->iargs[1]);
35880ee5cbfSDavid du Colombier break;
35980ee5cbfSDavid du Colombier case ESelectcolor:
3609a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
3619a747e4fSDavid du Colombier _setctlimage(t, &t->selectcolor, cp->args[1]);
36280ee5cbfSDavid du Colombier break;
36380ee5cbfSDavid du Colombier case ESelectmode:
3649a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
3659a747e4fSDavid du Colombier if(strcmp(cp->args[1], "single") == 0)
36680ee5cbfSDavid du Colombier t->selectmode = Selsingle;
3679a747e4fSDavid du Colombier else if(strncmp(cp->args[1], "multi", 5) == 0)
36880ee5cbfSDavid du Colombier t->selectmode = Selmulti;
36980ee5cbfSDavid du Colombier break;
3706f314b92SDavid du Colombier case ESelectstyle:
3716f314b92SDavid du Colombier _ctlargcount(t, cp, 2);
3726f314b92SDavid du Colombier if(strcmp(cp->args[1], "down") == 0)
3736f314b92SDavid du Colombier t->selectstyle = Seldown;
3746f314b92SDavid du Colombier else if(strcmp(cp->args[1], "up") == 0)
3756f314b92SDavid du Colombier t->selectstyle = Selup;
3766f314b92SDavid du Colombier break;
37780ee5cbfSDavid du Colombier case EShow:
3789a747e4fSDavid du Colombier _ctlargcount(t, cp, 1);
37980ee5cbfSDavid du Colombier textshow(t);
38080ee5cbfSDavid du Colombier break;
3819a747e4fSDavid du Colombier case ESize:
3829a747e4fSDavid du Colombier if (cp->nargs == 3)
3839a747e4fSDavid du Colombier r.max = Pt(10000, 10000);
3849a747e4fSDavid du Colombier else{
3859a747e4fSDavid du Colombier _ctlargcount(t, cp, 5);
3869a747e4fSDavid du Colombier r.max.x = cp->iargs[3];
3879a747e4fSDavid du Colombier r.max.y = cp->iargs[4];
3889a747e4fSDavid du Colombier }
3899a747e4fSDavid du Colombier r.min.x = cp->iargs[1];
3909a747e4fSDavid du Colombier r.min.y = cp->iargs[2];
3919a747e4fSDavid du Colombier 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)
3929a747e4fSDavid du Colombier ctlerror("%q: bad sizes: %s", t->name, cp->str);
3939a747e4fSDavid du Colombier t->size.min = r.min;
3949a747e4fSDavid du Colombier t->size.max = r.max;
39580ee5cbfSDavid du Colombier break;
3969a747e4fSDavid du Colombier case ETextcolor:
3979a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
3989a747e4fSDavid du Colombier _setctlimage(t, &t->textcolor, cp->args[1]);
39980ee5cbfSDavid du Colombier break;
40080ee5cbfSDavid du Colombier case ETopline:
4019a747e4fSDavid du Colombier _ctlargcount(t, cp, 2);
4029a747e4fSDavid du Colombier i = cp->iargs[1];
40380ee5cbfSDavid du Colombier if(i < 0)
40480ee5cbfSDavid du Colombier i = 0;
40580ee5cbfSDavid du Colombier if(i > t->nline)
40680ee5cbfSDavid du Colombier i = t->nline;
40780ee5cbfSDavid du Colombier if(t->topline != i){
40880ee5cbfSDavid du Colombier t->topline = i;
40980ee5cbfSDavid du Colombier textshow(t);
41080ee5cbfSDavid du Colombier }
41180ee5cbfSDavid du Colombier break;
41280ee5cbfSDavid du Colombier case EValue:
41380ee5cbfSDavid du Colombier /* set contents to single line */
41480ee5cbfSDavid du Colombier /* free existing text and fall through to add */
41580ee5cbfSDavid du Colombier for(i=0; i<t->nline; i++){
41680ee5cbfSDavid du Colombier free(t->line[i]);
41780ee5cbfSDavid du Colombier t->line[i] = nil;
41880ee5cbfSDavid du Colombier }
41980ee5cbfSDavid du Colombier t->nline = 0;
42080ee5cbfSDavid du Colombier t->topline = 0;
42180ee5cbfSDavid du Colombier /* fall through */
4229a747e4fSDavid du Colombier case EAccumulate:
42380ee5cbfSDavid du Colombier case EAdd:
4249a747e4fSDavid du Colombier switch (cp->nargs) {
42580ee5cbfSDavid du Colombier default:
4269a747e4fSDavid du Colombier ctlerror("%q: wrong argument count in '%s'", t->name, cp->str);
42780ee5cbfSDavid du Colombier case 2:
42880ee5cbfSDavid du Colombier n = t->nline;
42980ee5cbfSDavid du Colombier break;
43080ee5cbfSDavid du Colombier case 3:
4319a747e4fSDavid du Colombier n = cp->iargs[1];
43280ee5cbfSDavid du Colombier if(n<0 || n>t->nline)
4339a747e4fSDavid du Colombier ctlerror("%q: line number out of range: %s", t->name, cp->str);
43480ee5cbfSDavid du Colombier break;
43580ee5cbfSDavid du Colombier }
4369a747e4fSDavid du Colombier rp = _ctlrunestr(cp->args[cp->nargs-1]);
43780ee5cbfSDavid du Colombier t->line = ctlrealloc(t->line, (t->nline+1)*sizeof(Rune*));
43880ee5cbfSDavid du Colombier memmove(t->line+n+1, t->line+n, (t->nline-n)*sizeof(Rune*));
43980ee5cbfSDavid du Colombier t->line[n] = rp;
44080ee5cbfSDavid du Colombier t->selected = ctlrealloc(t->selected, t->nline+1);
44180ee5cbfSDavid du Colombier memmove(t->selected+n+1, t->selected+n, t->nline-n);
4429a747e4fSDavid du Colombier t->selected[n] = (t->selectmode==Selmulti && cmd!=EAccumulate);
44380ee5cbfSDavid du Colombier t->nline++;
44480ee5cbfSDavid du Colombier if(t->scroll) {
4459a747e4fSDavid du Colombier if(n > t->topline + (t->nvis - 1)){
4469a747e4fSDavid du Colombier t->topline = n - (t->nvis - 1);
4479a747e4fSDavid du Colombier if(t->topline < 0)
4489a747e4fSDavid du Colombier t->topline = 0;
4499a747e4fSDavid du Colombier }
45080ee5cbfSDavid du Colombier if(n < t->topline)
45180ee5cbfSDavid du Colombier t->topline = n;
45280ee5cbfSDavid du Colombier }
4539a747e4fSDavid du Colombier if(cmd != EAccumulate)
45480ee5cbfSDavid du Colombier if(t->scroll || t->nline<=t->topline+t->nvis)
45580ee5cbfSDavid du Colombier textshow(t);
45680ee5cbfSDavid du Colombier break;
4576f314b92SDavid du Colombier case EWarp:
4586f314b92SDavid du Colombier _ctlargcount(t, cp, 2);
459*da79363fSDavid du Colombier i = cp->iargs[1];
460*da79363fSDavid du Colombier if(i <0 || i>=t->nline)
4616f314b92SDavid du Colombier ctlerror("%q: selection index out of range (nline %d): %s", t->name, t->nline, cp->str);
462*da79363fSDavid du Colombier if(i < t->topline || i >= t->topline+t->nvis){
463*da79363fSDavid du Colombier t->topline = i;
464*da79363fSDavid du Colombier }
4656f314b92SDavid du Colombier t->warp = cp->iargs[1];
4666f314b92SDavid du Colombier textshow(t);
4676f314b92SDavid du Colombier t->warp = -1;
4686f314b92SDavid du Colombier break;
46980ee5cbfSDavid du Colombier }
47080ee5cbfSDavid du Colombier }
47180ee5cbfSDavid du Colombier
47280ee5cbfSDavid du Colombier static void
texttogglei(Text * t,int i)47380ee5cbfSDavid du Colombier texttogglei(Text *t, int i)
47480ee5cbfSDavid du Colombier {
47580ee5cbfSDavid du Colombier int prev;
47680ee5cbfSDavid du Colombier
47780ee5cbfSDavid du Colombier if(t->selectmode == Selsingle){
47880ee5cbfSDavid du Colombier /* clear the others */
47980ee5cbfSDavid du Colombier prev = t->selected[i];
48080ee5cbfSDavid du Colombier memset(t->selected, 0, t->nline);
48180ee5cbfSDavid du Colombier t->selected[i] = prev;
48280ee5cbfSDavid du Colombier }
48380ee5cbfSDavid du Colombier t->selected[i] ^= 1;
48480ee5cbfSDavid du Colombier textshow(t);
48580ee5cbfSDavid du Colombier }
48680ee5cbfSDavid du Colombier
48780ee5cbfSDavid du Colombier static int
textline(Text * t,Point p)4886f314b92SDavid du Colombier textline(Text *t, Point p)
48980ee5cbfSDavid du Colombier {
49080ee5cbfSDavid du Colombier Rectangle r;
49180ee5cbfSDavid du Colombier int i;
49280ee5cbfSDavid du Colombier
49380ee5cbfSDavid du Colombier r = t->rect;
49480ee5cbfSDavid du Colombier if(t->border > 0)
49580ee5cbfSDavid du Colombier r = insetrect(r, t->border);
49680ee5cbfSDavid du Colombier if(!ptinrect(p, r))
49780ee5cbfSDavid du Colombier return -1;
4989a747e4fSDavid du Colombier i = (p.y-r.min.y)/t->font->font->height;
49980ee5cbfSDavid du Colombier i += t->topline;
50080ee5cbfSDavid du Colombier if(i >= t->nline)
50180ee5cbfSDavid du Colombier return -1;
5026f314b92SDavid du Colombier return i;
5036f314b92SDavid du Colombier }
5046f314b92SDavid du Colombier
5056f314b92SDavid du Colombier static int
texttoggle(Text * t,Point p)5066f314b92SDavid du Colombier texttoggle(Text *t, Point p)
5076f314b92SDavid du Colombier {
5086f314b92SDavid du Colombier int i;
5096f314b92SDavid du Colombier
5106f314b92SDavid du Colombier i = textline(t, p);
5116f314b92SDavid du Colombier if (i >= 0)
51280ee5cbfSDavid du Colombier texttogglei(t, i);
51380ee5cbfSDavid du Colombier return i;
51480ee5cbfSDavid du Colombier }
5159a747e4fSDavid du Colombier
5169a747e4fSDavid du Colombier Control*
createtext(Controlset * cs,char * name)5179a747e4fSDavid du Colombier createtext(Controlset *cs, char *name)
5189a747e4fSDavid du Colombier {
5199a747e4fSDavid du Colombier Text *t;
5209a747e4fSDavid du Colombier
5219a747e4fSDavid du Colombier t = (Text*)_createctl(cs, "text", sizeof(Text), name);
5229a747e4fSDavid du Colombier t->line = ctlmalloc(sizeof(Rune*));
5239a747e4fSDavid du Colombier t->selected = ctlmalloc(1);
5249a747e4fSDavid du Colombier t->nline = 0;
5259a747e4fSDavid du Colombier t->image = _getctlimage("white");
5269a747e4fSDavid du Colombier t->textcolor = _getctlimage("black");
5279a747e4fSDavid du Colombier t->bordercolor = _getctlimage("black");
5289a747e4fSDavid du Colombier t->selectcolor = _getctlimage("yellow");
5296f314b92SDavid du Colombier t->selectingcolor = _getctlimage("paleyellow");
5309a747e4fSDavid du Colombier t->font = _getctlfont("font");
5319a747e4fSDavid du Colombier t->selectmode = Selsingle;
5326f314b92SDavid du Colombier t->selectstyle = Selup; // Seldown;
5339a747e4fSDavid du Colombier t->lastbut = 0;
5349a747e4fSDavid du Colombier t->mouse = textmouse;
5359a747e4fSDavid du Colombier t->ctl = textctl;
5369a747e4fSDavid du Colombier t->exit = textfree;
5376f314b92SDavid du Colombier t->warp = -1;
5386f314b92SDavid du Colombier t->sel = -1;
5396f314b92SDavid du Colombier t->offsel = 0;
5406f314b92SDavid du Colombier t->but = 0;
5419a747e4fSDavid du Colombier return (Control *)t;
5429a747e4fSDavid du Colombier }
543