void textshow(Text *t, uint q0, uint q1, int doselect) { int qe; int nl; uint q; if(t->what != Body){ if(doselect) textsetselect(t, q0, q1); return; } if(t->w!=nil && t->maxlines==0) colgrow(t->col, t->w, 1); if(doselect) textsetselect(t, q0, q1); qe = t->org+t->nchars; if(t->org<=q0 && (q0<qe || (q0==qe && qe==t->file->nc+t->ncache))) textscrdraw(t); else{ if(t->w->nopen[QWevent] > 0) nl = 3*t->maxlines/4; else nl = t->maxlines/4; q = textbacknl(t, q0, nl); /* avoid going backwards if trying to go forwards - long lines! */ if(!(q0>t->org && q<t->org)) textsetorigin(t, q, TRUE); while(q0 > t->org+t->nchars) textsetorigin(t, t->org+1, FALSE); } }
/* * Heuristic city. */ Window* makenewwindow(Text *t) { Column *c; Window *w, *bigw, *emptyw; Text *emptyb; int i, y, el; if(activecol) c = activecol; else if(seltext && seltext->col) c = seltext->col; else if(t && t->col) c = t->col; else{ if(row.ncol==0 && rowadd(&row, nil, -1)==nil) error("can't make column"); c = row.col[row.ncol-1]; } activecol = c; if(t==nil || t->w==nil || c->nw==0) return coladd(c, nil, nil, -1); /* find biggest window and biggest blank spot */ emptyw = c->w[0]; bigw = emptyw; for(i=1; i<c->nw; i++){ w = c->w[i]; /* use >= to choose one near bottom of screen */ if(w->body.maxlines >= bigw->body.maxlines) bigw = w; if(w->body.maxlines-w->body.nlines >= emptyw->body.maxlines-emptyw->body.nlines) emptyw = w; } emptyb = &emptyw->body; el = emptyb->maxlines-emptyb->nlines; /* if empty space is big, use it */ if(el>15 || (el>3 && el>(bigw->body.maxlines-1)/2)) y = emptyb->r.min.y+emptyb->nlines*font->height; else{ /* if this window is in column and isn't much smaller, split it */ if(t->col==c && Dy(t->w->r)>2*Dy(bigw->r)/3) bigw = t->w; y = (bigw->r.min.y + bigw->r.max.y)/2; } w = coladd(c, nil, nil, y); if(w->body.maxlines < 2) colgrow(w->col, w, 1); return w; }
void colclose(Column *c, Window *w, int dofree) { Rectangle r; int i, didmouse, up; /* w is locked */ if(!c->safe) colgrow(c, w, 1); for(i=0; i<c->nw; i++) if(c->w[i] == w) goto Found; error("can't find window"); Found: r = w->r; w->tag.col = nil; w->body.col = nil; w->col = nil; didmouse = restoremouse(w); if(dofree){ windelete(w); winclose(w); } c->nw--; memmove(c->w+i, c->w+i+1, (c->nw-i)*sizeof(Window*)); c->w = realloc(c->w, c->nw*sizeof(Window*)); if(c->nw == 0){ draw(screen, r, display->white, nil, ZP); return; } up = 0; if(i == c->nw){ /* extend last window down */ w = c->w[i-1]; r.min.y = w->r.min.y; r.max.y = c->r.max.y; }else{ /* extend next window up */ up = 1; w = c->w[i]; r.max.y = w->r.max.y; } draw(screen, r, textcols[BACK], nil, ZP); if(c->safe) { if(!didmouse && up) w->showdel = TRUE; winresize(w, r, FALSE, TRUE); if(!didmouse && up) movetodel(w); } }
/* * Heuristic city. */ Window* makenewwindow(Page *p) { Column *c; Window *w, *bigw, *emptyw; Page *emptyp; int i, y, el; if(activecol) c = activecol; else if(selpage && selpage->col) c = selpage->col; else if(p && p->col) c = p->col; else { if(row.ncol==0 && rowadd(&row, nil, -1)==nil) error("can't make column"); c = row.col[row.ncol-1]; } activecol = c; if(p==nil || p->w==nil || c->nw==0) return coladd(c, nil, nil, -1); /* find biggest window and biggest blank spot */ emptyw = c->w[0]; bigw = emptyw; for(i=1; i<c->nw; i++) { w = c->w[i]; /* use >= to choose one near bottom of screen */ if(Dy(w->page.all) >= Dy(bigw->page.all)) bigw = w; if(w->page.lay==nil && Dy(w->page.all) >= Dy(emptyw->page.all)) emptyw = w; } emptyp = &emptyw->page; el = Dy(emptyp->all); /* if empty space is big, use it */ if(el>15 || (el>3 && el>(Dy(bigw->page.all)-1)/2)) y = emptyp->all.max.y; else { /* if this window is in column and isn't much smaller, split it */ if(p->col==c && Dy(p->w->r)>2*Dy(bigw->r)/3) bigw = p->w; y = (bigw->r.min.y + bigw->r.max.y)/2; } w = coladd(c, nil, nil, y); colgrow(w->col, w, 1); return w; }
void textshow(Text *t, uint q0, uint q1, int doselect) { int qe; int nl; int tsd; int nc; uint q; if(t->what != Body){ if(doselect) textsetselect(t, q0, q1); return; } if(t->w!=nil && t->fr.maxlines==0) colgrow(t->col, t->w, 1); if(doselect) textsetselect(t, q0, q1); qe = t->org+t->fr.nchars; tsd = FALSE; /* do we call textscrdraw? */ nc = t->file->b.nc+t->ncache; if(t->org <= q0){ if(nc==0 || q0<qe) tsd = TRUE; else if(q0==qe && qe==nc){ if(textreadc(t, nc-1) == '\n'){ if(t->fr.nlines<t->fr.maxlines) tsd = TRUE; }else tsd = TRUE; } } if(tsd) textscrdraw(t); else{ if(t->w->nopen[QWevent] > 0) nl = 3*t->fr.maxlines/4; else nl = t->fr.maxlines/4; q = textbacknl(t, q0, nl); /* avoid going backwards if trying to go forwards - long lines! */ if(!(q0>t->org && q<t->org)) textsetorigin(t, q, TRUE); while(q0 > t->org+t->fr.nchars) textsetorigin(t, t->org+1, FALSE); } }
Window* coladd(Column *c, Window *w, Window *clone, int y) { Rectangle r, r1; Window *v; int i, t; v = nil; r = c->r; r.min.y = c->tag.r.max.y+Border; if(y<r.min.y && c->nw>0){ /* steal half of last window by default */ v = c->w[c->nw-1]; y = v->body.r.min.y+Dy(v->body.r)/2; } /* look for window we'll land on */ for(i=0; i<c->nw; i++){ v = c->w[i]; if(y < v->r.max.y) break; } if(c->nw > 0){ if(i < c->nw) i++; /* new window will go after v */ /* * if v's too small, grow it first. */ if(!c->safe || v->body.maxlines<=3){ colgrow(c, v, 1); y = v->body.r.min.y+Dy(v->body.r)/2; } r = v->r; if(i == c->nw) t = c->r.max.y; else t = c->w[i]->r.min.y-Border; r.max.y = t; draw(screen, r, textcols[BACK], nil, ZP); r1 = r; y = min(y, t-(v->tag.font->height+v->body.font->height+Border+1)); r1.max.y = min(y, v->body.r.min.y+v->body.nlines*v->body.font->height); r1.min.y = winresize(v, r1, FALSE); r1.max.y = r1.min.y+Border; draw(screen, r1, display->black, nil, ZP); r.min.y = r1.max.y; } if(w == nil){ w = emalloc(sizeof(Window)); w->col = c; draw(screen, r, textcols[BACK], nil, ZP); wininit(w, clone, r); }else{ w->col = c; winresize(w, r, FALSE); } w->tag.col = c; w->tag.row = c->row; w->body.col = c; w->body.row = c->row; c->w = realloc(c->w, (c->nw+1)*sizeof(Window*)); memmove(c->w+i+1, c->w+i, (c->nw-i)*sizeof(Window*)); c->nw++; c->w[i] = w; savemouse(w); /* near but not on the button */ moveto(mousectl, addpt(w->tag.scrollr.max, Pt(3, 3))); barttext = &w->body; c->safe = TRUE; return w; }
void coldragwin(Column *c, Window *w, int but) { Rectangle r; int i, b; Point p, op; Window *v; Column *nc; clearmouse(); setcursor(mousectl, &boxcursor); b = mouse->buttons; op = mouse->xy; while(mouse->buttons == b) readmouse(mousectl); setcursor(mousectl, nil); if(mouse->buttons){ while(mouse->buttons) readmouse(mousectl); return; } for(i=0; i<c->nw; i++) if(c->w[i] == w) goto Found; error("can't find window"); Found: p = mouse->xy; if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){ colgrow(c, w, but); winmousebut(w); return; } /* is it a flick to the right? */ if(abs(p.y-op.y)<10 && p.x>op.x+30 && rowwhichcol(c->row, p)==c) p.x = op.x+Dx(w->r); /* yes: toss to next column */ nc = rowwhichcol(c->row, p); if(nc!=nil && nc!=c){ colclose(c, w, FALSE); coladd(nc, w, nil, p.y); winmousebut(w); return; } if(i==0 && c->nw==1) return; /* can't do it */ if((i>0 && p.y<c->w[i-1]->r.min.y) || (i<c->nw-1 && p.y>w->r.max.y) || (i==0 && p.y>w->r.max.y)){ /* shuffle */ colclose(c, w, FALSE); coladd(c, w, nil, p.y); winmousebut(w); return; } if(i == 0) return; v = c->w[i-1]; if(p.y < v->tag.all.max.y) p.y = v->tag.all.max.y; if(p.y > w->r.max.y-Dy(w->tag.all)-Border) p.y = w->r.max.y-Dy(w->tag.all)-Border; r = v->r; r.max.y = p.y; if(r.max.y > v->body.r.min.y){ r.max.y -= (r.max.y-v->body.r.min.y)%v->body.font->height; if(v->body.r.min.y == v->body.r.max.y) r.max.y++; } if(!eqrect(v->r, r)){ draw(screen, r, textcols[BACK], nil, ZP); winresize(v, r, c->safe); } r.min.y = v->r.max.y; r.max.y = r.min.y+Border; draw(screen, r, display->black, nil, ZP); r.min.y = r.max.y; if(i == c->nw-1) r.max.y = c->r.max.y; else r.max.y = c->w[i+1]->r.min.y-Border; if(!eqrect(w->r, r)){ draw(screen, r, textcols[BACK], nil, ZP); winresize(w, r, c->safe); } c->safe = TRUE; winmousebut(w); }
Window* coladd(Column *c, Window *w, Window *clone, int y) { Rectangle r, r1; Window *v; int i, j, minht, ymax, buggered; v = nil; r = c->r; r.min.y = c->tag.fr.r.max.y+Border; if(y<r.min.y && c->nw>0){ /* steal half of last window by default */ v = c->w[c->nw-1]; y = v->body.fr.r.min.y+Dy(v->body.fr.r)/2; } /* look for window we'll land on */ for(i=0; i<c->nw; i++){ v = c->w[i]; if(y < v->r.max.y) break; } buggered = 0; if(c->nw > 0){ if(i < c->nw) i++; /* new window will go after v */ /* * if landing window (v) is too small, grow it first. */ minht = v->tag.fr.font->height+Border+1; j = 0; while(!c->safe || v->body.fr.maxlines<=3 || Dy(v->body.all) <= minht){ if(++j > 10){ buggered = 1; /* too many windows in column */ break; } colgrow(c, v, 1); } /* * figure out where to split v to make room for w */ /* new window stops where next window begins */ if(i < c->nw) ymax = c->w[i]->r.min.y-Border; else ymax = c->r.max.y; /* new window must start after v's tag ends */ y = max(y, v->tagtop.max.y+Border); /* new window must start early enough to end before ymax */ y = min(y, ymax - minht); /* if y is too small, too many windows in column */ if(y < v->tagtop.max.y+Border) buggered = 1; /* * resize & redraw v */ r = v->r; r.max.y = ymax; draw(screen, r, textcols[BACK], nil, ZP); r1 = r; y = min(y, ymax-(v->tag.fr.font->height*v->taglines+v->body.fr.font->height+Border+1)); r1.max.y = min(y, v->body.fr.r.min.y+v->body.fr.nlines*v->body.fr.font->height); r1.min.y = winresize(v, r1, FALSE, FALSE); r1.max.y = r1.min.y+Border; draw(screen, r1, display->black, nil, ZP); /* * leave r with w's coordinates */ r.min.y = r1.max.y; } if(w == nil){ w = emalloc(sizeof(Window)); w->col = c; draw(screen, r, textcols[BACK], nil, ZP); wininit(w, clone, r); }else{ w->col = c; winresize(w, r, FALSE, TRUE); } w->tag.col = c; w->tag.row = c->row; w->body.col = c; w->body.row = c->row; c->w = realloc(c->w, (c->nw+1)*sizeof(Window*)); memmove(c->w+i+1, c->w+i, (c->nw-i)*sizeof(Window*)); c->nw++; c->w[i] = w; c->safe = TRUE; /* if there were too many windows, redraw the whole column */ if(buggered) colresize(c, c->r); savemouse(w); /* near the button, but in the body */ moveto(mousectl, addpt(w->tag.scrollr.max, Pt(3, 3))); barttext = &w->body; return w; }
Window* openfile(Text *t, Expand *e) { Range r; Window *w, *ow; int eval, i, n; Rune *rp; Runestr rs; uint dummy; r.q0 = 0; r.q1 = 0; if(e->nname == 0){ w = t->w; if(w == nil) return nil; }else{ w = lookfile(e->name, e->nname); if(w == nil && e->name[0] != '/'){ /* * Unrooted path in new window. * This can happen if we type a pwd-relative path * in the topmost tag or the column tags. * Most of the time plumber takes care of these, * but plumber might not be running or might not * be configured to accept plumbed directories. * Make the name a full path, just like we would if * opening via the plumber. */ n = utflen(wdir)+1+e->nname+1; rp = runemalloc(n); runesnprint(rp, n, "%s/%.*S", wdir, e->nname, e->name); rs = cleanrname(runestr(rp, n-1)); free(e->name); e->name = rs.r; e->nname = rs.nr; w = lookfile(e->name, e->nname); } } if(w){ t = &w->body; if(!t->col->safe && t->fr.maxlines==0) /* window is obscured by full-column window */ colgrow(t->col, t->col->w[0], 1); }else{ ow = nil; if(t) ow = t->w; w = makenewwindow(t); t = &w->body; winsetname(w, e->name, e->nname); if(textload(t, 0, e->bname, 1) >= 0) t->file->unread = FALSE; t->file->mod = FALSE; t->w->dirty = FALSE; winsettag(t->w); textsetselect(&t->w->tag, t->w->tag.file->b.nc, t->w->tag.file->b.nc); if(ow != nil){ for(i=ow->nincl; --i>=0; ){ n = runestrlen(ow->incl[i]); rp = runemalloc(n); runemove(rp, ow->incl[i], n); winaddincl(w, rp, n); } w->autoindent = ow->autoindent; }else w->autoindent = globalautoindent; xfidlog(w, "new"); } if(e->a1 == e->a0) eval = FALSE; else{ eval = TRUE; r = address(TRUE, t, range(-1,-1), range(t->q0, t->q1), e->u.at, e->a0, e->a1, e->agetc, &eval, &dummy); if(r.q0 > r.q1) { eval = FALSE; warning(nil, "addresses out of order\n"); } if(eval == FALSE) e->jump = FALSE; /* don't jump if invalid address */ } if(eval == FALSE){ r.q0 = t->q0; r.q1 = t->q1; } textshow(t, r.q0, r.q1, 1); winsettag(t->w); seltext = t; if(e->jump) moveto(mousectl, addpt(frptofchar(&t->fr, t->fr.p0), Pt(4, font->height-4))); return w; }