13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <thread.h>
57dd7cddfSDavid du Colombier #include <mouse.h>
63e12c5d1SDavid du Colombier #include <frame.h>
73e12c5d1SDavid du Colombier
83e12c5d1SDavid du Colombier #define DELTA 25
93e12c5d1SDavid du Colombier #define TMPSIZE 256
103e12c5d1SDavid du Colombier static Frame frame;
113e12c5d1SDavid du Colombier
123e12c5d1SDavid du Colombier static
133e12c5d1SDavid du Colombier Point
bxscan(Frame * f,Rune * sp,Rune * ep,Point * ppt)143e12c5d1SDavid du Colombier bxscan(Frame *f, Rune *sp, Rune *ep, Point *ppt)
153e12c5d1SDavid du Colombier {
163e12c5d1SDavid du Colombier int w, c, nb, delta, nl, nr, rw;
173e12c5d1SDavid du Colombier Frbox *b;
183e12c5d1SDavid du Colombier char *s, tmp[TMPSIZE+3]; /* +3 for rune overflow */
193e12c5d1SDavid du Colombier uchar *p;
203e12c5d1SDavid du Colombier
213e12c5d1SDavid du Colombier frame.r = f->r;
223e12c5d1SDavid du Colombier frame.b = f->b;
233e12c5d1SDavid du Colombier frame.font = f->font;
243e12c5d1SDavid du Colombier frame.maxtab = f->maxtab;
253e12c5d1SDavid du Colombier frame.nbox = 0;
263e12c5d1SDavid du Colombier frame.nchars = 0;
277dd7cddfSDavid du Colombier memmove(frame.cols, f->cols, sizeof frame.cols);
283e12c5d1SDavid du Colombier delta = DELTA;
293e12c5d1SDavid du Colombier nl = 0;
303e12c5d1SDavid du Colombier for(nb=0; sp<ep && nl<=f->maxlines; nb++,frame.nbox++){
313e12c5d1SDavid du Colombier if(nb == frame.nalloc){
323e12c5d1SDavid du Colombier _frgrowbox(&frame, delta);
333e12c5d1SDavid du Colombier if(delta < 10000)
343e12c5d1SDavid du Colombier delta *= 2;
353e12c5d1SDavid du Colombier }
363e12c5d1SDavid du Colombier b = &frame.box[nb];
373e12c5d1SDavid du Colombier c = *sp;
383e12c5d1SDavid du Colombier if(c=='\t' || c=='\n'){
393e12c5d1SDavid du Colombier b->bc = c;
403e12c5d1SDavid du Colombier b->wid = 5000;
417dd7cddfSDavid du Colombier b->minwid = (c=='\n')? 0 : stringwidth(frame.font, " ");
423e12c5d1SDavid du Colombier b->nrune = -1;
433e12c5d1SDavid du Colombier if(c=='\n')
443e12c5d1SDavid du Colombier nl++;
453e12c5d1SDavid du Colombier frame.nchars++;
463e12c5d1SDavid du Colombier sp++;
473e12c5d1SDavid du Colombier }else{
483e12c5d1SDavid du Colombier s = tmp;
493e12c5d1SDavid du Colombier nr = 0;
503e12c5d1SDavid du Colombier w = 0;
513e12c5d1SDavid du Colombier while(sp < ep){
52219b2ee8SDavid du Colombier c = *sp;
53219b2ee8SDavid du Colombier if(c=='\t' || c=='\n')
54219b2ee8SDavid du Colombier break;
553e12c5d1SDavid du Colombier rw = runetochar(s, sp);
563e12c5d1SDavid du Colombier if(s+rw >= tmp+TMPSIZE)
573e12c5d1SDavid du Colombier break;
587dd7cddfSDavid du Colombier w += runestringnwidth(frame.font, sp, 1);
593e12c5d1SDavid du Colombier sp++;
603e12c5d1SDavid du Colombier s += rw;
613e12c5d1SDavid du Colombier nr++;
623e12c5d1SDavid du Colombier }
633e12c5d1SDavid du Colombier *s++ = 0;
647dd7cddfSDavid du Colombier p = _frallocstr(f, s-tmp);
653e12c5d1SDavid du Colombier b = &frame.box[nb];
663e12c5d1SDavid du Colombier b->ptr = p;
673e12c5d1SDavid du Colombier memmove(p, tmp, s-tmp);
683e12c5d1SDavid du Colombier b->wid = w;
693e12c5d1SDavid du Colombier b->nrune = nr;
703e12c5d1SDavid du Colombier frame.nchars += nr;
713e12c5d1SDavid du Colombier }
723e12c5d1SDavid du Colombier }
733e12c5d1SDavid du Colombier _frcklinewrap0(f, ppt, &frame.box[0]);
743e12c5d1SDavid du Colombier return _frdraw(&frame, *ppt);
753e12c5d1SDavid du Colombier }
763e12c5d1SDavid du Colombier
773e12c5d1SDavid du Colombier static
783e12c5d1SDavid du Colombier void
chopframe(Frame * f,Point pt,ulong p,int bn)793e12c5d1SDavid du Colombier chopframe(Frame *f, Point pt, ulong p, int bn)
803e12c5d1SDavid du Colombier {
813e12c5d1SDavid du Colombier Frbox *b;
823e12c5d1SDavid du Colombier
833e12c5d1SDavid du Colombier for(b = &f->box[bn]; ; b++){
843e12c5d1SDavid du Colombier if(b >= &f->box[f->nbox])
857dd7cddfSDavid du Colombier drawerror(f->display, "endofframe");
863e12c5d1SDavid du Colombier _frcklinewrap(f, &pt, b);
873e12c5d1SDavid du Colombier if(pt.y >= f->r.max.y)
883e12c5d1SDavid du Colombier break;
893e12c5d1SDavid du Colombier p += NRUNE(b);
903e12c5d1SDavid du Colombier _fradvance(f, &pt, b);
913e12c5d1SDavid du Colombier }
923e12c5d1SDavid du Colombier f->nchars = p;
933e12c5d1SDavid du Colombier f->nlines = f->maxlines;
943e12c5d1SDavid du Colombier if(b<&f->box[f->nbox]) /* BUG */
953e12c5d1SDavid du Colombier _frdelbox(f, (int)(b-f->box), f->nbox-1);
963e12c5d1SDavid du Colombier }
973e12c5d1SDavid du Colombier
983e12c5d1SDavid du Colombier void
frinsert(Frame * f,Rune * sp,Rune * ep,ulong p0)993e12c5d1SDavid du Colombier frinsert(Frame *f, Rune *sp, Rune *ep, ulong p0)
1003e12c5d1SDavid du Colombier {
10180ee5cbfSDavid du Colombier Point pt0, pt1, opt0, ppt0, ppt1, pt;
1023e12c5d1SDavid du Colombier Frbox *b;
1033e12c5d1SDavid du Colombier int n, n0, nn0, y;
1047dd7cddfSDavid du Colombier ulong cn0;
1057dd7cddfSDavid du Colombier Image *col;
1063e12c5d1SDavid du Colombier Rectangle r;
1073e12c5d1SDavid du Colombier static struct{
1083e12c5d1SDavid du Colombier Point pt0, pt1;
1093e12c5d1SDavid du Colombier }*pts;
1103e12c5d1SDavid du Colombier static int nalloc=0;
1113e12c5d1SDavid du Colombier int npts;
1123e12c5d1SDavid du Colombier
1137dd7cddfSDavid du Colombier if(p0>f->nchars || sp==ep || f->b==nil)
1143e12c5d1SDavid du Colombier return;
1153e12c5d1SDavid du Colombier n0 = _frfindbox(f, 0, 0, p0);
1167dd7cddfSDavid du Colombier cn0 = p0;
1173e12c5d1SDavid du Colombier nn0 = n0;
1183e12c5d1SDavid du Colombier pt0 = _frptofcharnb(f, p0, n0);
1193e12c5d1SDavid du Colombier ppt0 = pt0;
12080ee5cbfSDavid du Colombier opt0 = pt0;
1213e12c5d1SDavid du Colombier pt1 = bxscan(f, sp, ep, &ppt0);
1223e12c5d1SDavid du Colombier ppt1 = pt1;
1233e12c5d1SDavid du Colombier if(n0 < f->nbox){
1247dd7cddfSDavid du Colombier _frcklinewrap(f, &pt0, b = &f->box[n0]); /* for frdrawsel() */
1253e12c5d1SDavid du Colombier _frcklinewrap0(f, &ppt1, b);
1263e12c5d1SDavid du Colombier }
1273e12c5d1SDavid du Colombier f->modified = 1;
1283e12c5d1SDavid du Colombier /*
1293e12c5d1SDavid du Colombier * ppt0 and ppt1 are start and end of insertion as they will appear when
1303e12c5d1SDavid du Colombier * insertion is complete. pt0 is current location of insertion position
1313e12c5d1SDavid du Colombier * (p0); pt1 is terminal point (without line wrap) of insertion.
1323e12c5d1SDavid du Colombier */
1337dd7cddfSDavid du Colombier if(f->p0 == f->p1)
1347dd7cddfSDavid du Colombier frtick(f, frptofchar(f, f->p0), 0);
1357dd7cddfSDavid du Colombier
1363e12c5d1SDavid du Colombier /*
1373e12c5d1SDavid du Colombier * Find point where old and new x's line up
1383e12c5d1SDavid du Colombier * Invariants:
1393e12c5d1SDavid du Colombier * pt0 is where the next box (b, n0) is now
1407dd7cddfSDavid du Colombier * pt1 is where it will be after the insertion
1413e12c5d1SDavid du Colombier * If pt1 goes off the rectangle, we can toss everything from there on
1423e12c5d1SDavid du Colombier */
1433e12c5d1SDavid du Colombier for(b = &f->box[n0],npts=0;
1443e12c5d1SDavid du Colombier pt1.x!=pt0.x && pt1.y!=f->r.max.y && n0<f->nbox; b++,n0++,npts++){
1453e12c5d1SDavid du Colombier _frcklinewrap(f, &pt0, b);
1463e12c5d1SDavid du Colombier _frcklinewrap0(f, &pt1, b);
1473e12c5d1SDavid du Colombier if(b->nrune > 0){
1483e12c5d1SDavid du Colombier n = _frcanfit(f, pt1, b);
1493e12c5d1SDavid du Colombier if(n == 0)
1507dd7cddfSDavid du Colombier drawerror(f->display, "_frcanfit==0");
1513e12c5d1SDavid du Colombier if(n != b->nrune){
1523e12c5d1SDavid du Colombier _frsplitbox(f, n0, n);
1533e12c5d1SDavid du Colombier b = &f->box[n0];
1543e12c5d1SDavid du Colombier }
1553e12c5d1SDavid du Colombier }
1563e12c5d1SDavid du Colombier if(npts == nalloc){
1573e12c5d1SDavid du Colombier pts = realloc(pts, (npts+DELTA)*sizeof(pts[0]));
1583e12c5d1SDavid du Colombier nalloc += DELTA;
1593e12c5d1SDavid du Colombier b = &f->box[n0];
1603e12c5d1SDavid du Colombier }
1613e12c5d1SDavid du Colombier pts[npts].pt0 = pt0;
1623e12c5d1SDavid du Colombier pts[npts].pt1 = pt1;
1633e12c5d1SDavid du Colombier /* has a text box overflowed off the frame? */
1643e12c5d1SDavid du Colombier if(pt1.y == f->r.max.y)
1653e12c5d1SDavid du Colombier break;
1663e12c5d1SDavid du Colombier _fradvance(f, &pt0, b);
1673e12c5d1SDavid du Colombier pt1.x += _frnewwid(f, pt1, b);
1687dd7cddfSDavid du Colombier cn0 += NRUNE(b);
1693e12c5d1SDavid du Colombier }
1703e12c5d1SDavid du Colombier if(pt1.y > f->r.max.y)
1717dd7cddfSDavid du Colombier drawerror(f->display, "frinsert pt1 too far");
1723e12c5d1SDavid du Colombier if(pt1.y==f->r.max.y && n0<f->nbox){
1733e12c5d1SDavid du Colombier f->nchars -= _frstrlen(f, n0);
1743e12c5d1SDavid du Colombier _frdelbox(f, n0, f->nbox-1);
1753e12c5d1SDavid du Colombier }
1763e12c5d1SDavid du Colombier if(n0 == f->nbox)
1777dd7cddfSDavid du Colombier f->nlines = (pt1.y-f->r.min.y)/f->font->height+(pt1.x>f->r.min.x);
1783e12c5d1SDavid du Colombier else if(pt1.y!=pt0.y){
1793e12c5d1SDavid du Colombier int q0, q1;
1803e12c5d1SDavid du Colombier
1813e12c5d1SDavid du Colombier y = f->r.max.y;
1823e12c5d1SDavid du Colombier q0 = pt0.y+f->font->height;
1833e12c5d1SDavid du Colombier q1 = pt1.y+f->font->height;
1843e12c5d1SDavid du Colombier f->nlines += (q1-q0)/f->font->height;
1853e12c5d1SDavid du Colombier if(f->nlines > f->maxlines)
1863e12c5d1SDavid du Colombier chopframe(f, ppt1, p0, nn0);
1873e12c5d1SDavid du Colombier if(pt1.y < y){
1883e12c5d1SDavid du Colombier r = f->r;
1897dd7cddfSDavid du Colombier r.min.y = q1;
1907dd7cddfSDavid du Colombier r.max.y = y;
1913e12c5d1SDavid du Colombier if(q1 < y)
1927dd7cddfSDavid du Colombier draw(f->b, r, f->b, nil, Pt(f->r.min.x, q0));
1937dd7cddfSDavid du Colombier r.min = pt1;
1947dd7cddfSDavid du Colombier r.max.x = pt1.x+(f->r.max.x-pt0.x);
1957dd7cddfSDavid du Colombier r.max.y = q1;
1967dd7cddfSDavid du Colombier draw(f->b, r, f->b, nil, pt0);
1973e12c5d1SDavid du Colombier }
1983e12c5d1SDavid du Colombier }
1993e12c5d1SDavid du Colombier /*
2003e12c5d1SDavid du Colombier * Move the old stuff down to make room. The loop will move the stuff
2013e12c5d1SDavid du Colombier * between the insertion and the point where the x's lined up.
2027dd7cddfSDavid du Colombier * The draw()s above moved everything down after the point they lined up.
2033e12c5d1SDavid du Colombier */
2043e12c5d1SDavid du Colombier for((y=pt1.y==f->r.max.y?pt1.y:0),b = &f->box[n0-1]; --npts>=0; --b){
2053e12c5d1SDavid du Colombier pt = pts[npts].pt1;
2063e12c5d1SDavid du Colombier if(b->nrune > 0){
2077dd7cddfSDavid du Colombier r.min = pt;
2083e12c5d1SDavid du Colombier r.max = r.min;
2093e12c5d1SDavid du Colombier r.max.x += b->wid;
2103e12c5d1SDavid du Colombier r.max.y += f->font->height;
2117dd7cddfSDavid du Colombier draw(f->b, r, f->b, nil, pts[npts].pt0);
21280ee5cbfSDavid du Colombier /* clear bit hanging off right */
21380ee5cbfSDavid du Colombier if(npts==0 && pt.y>pt0.y){
21480ee5cbfSDavid du Colombier /*
21580ee5cbfSDavid du Colombier * first new char is bigger than first char we're
21680ee5cbfSDavid du Colombier * displacing, causing line wrap. ugly special case.
21780ee5cbfSDavid du Colombier */
21880ee5cbfSDavid du Colombier r.min = opt0;
21980ee5cbfSDavid du Colombier r.max = opt0;
22080ee5cbfSDavid du Colombier r.max.x = f->r.max.x;
22180ee5cbfSDavid du Colombier r.max.y += f->font->height;
22280ee5cbfSDavid du Colombier if(f->p0<=cn0 && cn0<f->p1) /* b+1 is inside selection */
22380ee5cbfSDavid du Colombier col = f->cols[HIGH];
22480ee5cbfSDavid du Colombier else
22580ee5cbfSDavid du Colombier col = f->cols[BACK];
22680ee5cbfSDavid du Colombier draw(f->b, r, col, nil, r.min);
22780ee5cbfSDavid du Colombier }else if(pt.y < y){
2283e12c5d1SDavid du Colombier r.min = pt;
2293e12c5d1SDavid du Colombier r.max = pt;
2303e12c5d1SDavid du Colombier r.min.x += b->wid;
2313e12c5d1SDavid du Colombier r.max.x = f->r.max.x;
2323e12c5d1SDavid du Colombier r.max.y += f->font->height;
2337dd7cddfSDavid du Colombier if(f->p0<=cn0 && cn0<f->p1) /* b+1 is inside selection */
2347dd7cddfSDavid du Colombier col = f->cols[HIGH];
2357dd7cddfSDavid du Colombier else
2367dd7cddfSDavid du Colombier col = f->cols[BACK];
2377dd7cddfSDavid du Colombier draw(f->b, r, col, nil, r.min);
2383e12c5d1SDavid du Colombier }
2393e12c5d1SDavid du Colombier y = pt.y;
2407dd7cddfSDavid du Colombier cn0 -= b->nrune;
2413e12c5d1SDavid du Colombier }else{
2423e12c5d1SDavid du Colombier r.min = pt;
2433e12c5d1SDavid du Colombier r.max = pt;
2443e12c5d1SDavid du Colombier r.max.x += b->wid;
2453e12c5d1SDavid du Colombier r.max.y += f->font->height;
2463e12c5d1SDavid du Colombier if(r.max.x >= f->r.max.x)
2473e12c5d1SDavid du Colombier r.max.x = f->r.max.x;
2487dd7cddfSDavid du Colombier cn0--;
2497dd7cddfSDavid du Colombier if(f->p0<=cn0 && cn0<f->p1) /* b is inside selection */
2507dd7cddfSDavid du Colombier col = f->cols[HIGH];
2517dd7cddfSDavid du Colombier else
2527dd7cddfSDavid du Colombier col = f->cols[BACK];
2537dd7cddfSDavid du Colombier draw(f->b, r, col, nil, r.min);
2547dd7cddfSDavid du Colombier y = 0;
2557dd7cddfSDavid du Colombier if(pt.x == f->r.min.x)
2567dd7cddfSDavid du Colombier y = pt.y;
2573e12c5d1SDavid du Colombier }
2583e12c5d1SDavid du Colombier }
2597dd7cddfSDavid du Colombier /* insertion can extend the selection, so the condition here is different */
2607dd7cddfSDavid du Colombier if(f->p0<p0 && p0<=f->p1)
2617dd7cddfSDavid du Colombier col = f->cols[HIGH];
2627dd7cddfSDavid du Colombier else
2637dd7cddfSDavid du Colombier col = f->cols[BACK];
2647dd7cddfSDavid du Colombier frselectpaint(f, ppt0, ppt1, col);
265*8f5875f3SDavid du Colombier _frdrawtext(&frame, ppt0, f->cols[TEXT], col);
2663e12c5d1SDavid du Colombier _fraddbox(f, nn0, frame.nbox);
2673e12c5d1SDavid du Colombier for(n=0; n<frame.nbox; n++)
2683e12c5d1SDavid du Colombier f->box[nn0+n] = frame.box[n];
2697dd7cddfSDavid du Colombier if(nn0>0 && f->box[nn0-1].nrune>=0 && ppt0.x-f->box[nn0-1].wid>=f->r.min.x){
2703e12c5d1SDavid du Colombier --nn0;
2713e12c5d1SDavid du Colombier ppt0.x -= f->box[nn0].wid;
2723e12c5d1SDavid du Colombier }
2733e12c5d1SDavid du Colombier n0 += frame.nbox;
2743e12c5d1SDavid du Colombier _frclean(f, ppt0, nn0, n0<f->nbox-1? n0+1 : n0);
2753e12c5d1SDavid du Colombier f->nchars += frame.nchars;
2763e12c5d1SDavid du Colombier if(f->p0 >= p0)
2773e12c5d1SDavid du Colombier f->p0 += frame.nchars;
2783e12c5d1SDavid du Colombier if(f->p0 > f->nchars)
2793e12c5d1SDavid du Colombier f->p0 = f->nchars;
2803e12c5d1SDavid du Colombier if(f->p1 >= p0)
2813e12c5d1SDavid du Colombier f->p1 += frame.nchars;
2823e12c5d1SDavid du Colombier if(f->p1 > f->nchars)
2833e12c5d1SDavid du Colombier f->p1 = f->nchars;
2847dd7cddfSDavid du Colombier if(f->p0 == f->p1)
2857dd7cddfSDavid du Colombier frtick(f, frptofchar(f, f->p0), 1);
2863e12c5d1SDavid du Colombier }
287