cols.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <draw.h>
  4. #include <thread.h>
  5. #include <cursor.h>
  6. #include <mouse.h>
  7. #include <keyboard.h>
  8. #include <frame.h>
  9. #include <fcall.h>
  10. #include <plumb.h>
  11. #include "dat.h"
  12. #include "fns.h"
  13. void
  14. colinit(Column *c, Rectangle r)
  15. {
  16. Rectangle r1;
  17. Text *t;
  18. draw(screen, r, display->white, nil, ZP);
  19. c->r = r;
  20. c->w = nil;
  21. c->nw = 0;
  22. t = &c->tag;
  23. t->w = nil;
  24. t->col = c;
  25. r1 = r;
  26. r1.max.y = r1.min.y + font->height;
  27. textinit(t, fileaddtext(nil, t), r1, &reffont, tagcols);
  28. t->what = Columntag;
  29. r1.min.y = r1.max.y;
  30. r1.max.y += Border;
  31. draw(screen, r1, display->black, nil, ZP);
  32. textinsert(t, 0, L"New Cut Paste Snarf Sort Zerox Delcol ", 38, TRUE);
  33. textsetselect(t, t->file->nc, t->file->nc);
  34. draw(screen, t->scrollr, colbutton, nil, colbutton->r.min);
  35. c->safe = TRUE;
  36. }
  37. Window*
  38. coladd(Column *c, Window *w, Window *clone, int y)
  39. {
  40. Rectangle r, r1;
  41. Window *v;
  42. int i, t;
  43. v = nil;
  44. r = c->r;
  45. r.min.y = c->tag.r.max.y+Border;
  46. if(y<r.min.y && c->nw>0){ /* steal half of last window by default */
  47. v = c->w[c->nw-1];
  48. y = v->body.r.min.y+Dy(v->body.r)/2;
  49. }
  50. /* look for window we'll land on */
  51. for(i=0; i<c->nw; i++){
  52. v = c->w[i];
  53. if(y < v->r.max.y)
  54. break;
  55. }
  56. if(c->nw > 0){
  57. if(i < c->nw)
  58. i++; /* new window will go after v */
  59. /*
  60. * if v's too small, grow it first.
  61. */
  62. if(!c->safe || v->body.maxlines<=3){
  63. colgrow(c, v, 1);
  64. y = v->body.r.min.y+Dy(v->body.r)/2;
  65. }
  66. r = v->r;
  67. if(i == c->nw)
  68. t = c->r.max.y;
  69. else
  70. t = c->w[i]->r.min.y-Border;
  71. r.max.y = t;
  72. draw(screen, r, textcols[BACK], nil, ZP);
  73. r1 = r;
  74. y = min(y, t-(v->tag.font->height+v->body.font->height+Border+1));
  75. r1.max.y = min(y, v->body.r.min.y+v->body.nlines*v->body.font->height);
  76. r1.min.y = winresize(v, r1, FALSE);
  77. r1.max.y = r1.min.y+Border;
  78. draw(screen, r1, display->black, nil, ZP);
  79. r.min.y = r1.max.y;
  80. }
  81. if(w == nil){
  82. w = emalloc(sizeof(Window));
  83. w->col = c;
  84. draw(screen, r, textcols[BACK], nil, ZP);
  85. wininit(w, clone, r);
  86. }else{
  87. w->col = c;
  88. winresize(w, r, FALSE);
  89. }
  90. w->tag.col = c;
  91. w->tag.row = c->row;
  92. w->body.col = c;
  93. w->body.row = c->row;
  94. c->w = realloc(c->w, (c->nw+1)*sizeof(Window*));
  95. memmove(c->w+i+1, c->w+i, (c->nw-i)*sizeof(Window*));
  96. c->nw++;
  97. c->w[i] = w;
  98. savemouse(w);
  99. /* near but not on the button */
  100. moveto(mousectl, addpt(w->tag.scrollr.max, Pt(3, 3)));
  101. barttext = &w->body;
  102. c->safe = TRUE;
  103. return w;
  104. }
  105. void
  106. colclose(Column *c, Window *w, int dofree)
  107. {
  108. Rectangle r;
  109. int i;
  110. /* w is locked */
  111. if(!c->safe)
  112. colgrow(c, w, 1);
  113. for(i=0; i<c->nw; i++)
  114. if(c->w[i] == w)
  115. goto Found;
  116. error("can't find window");
  117. Found:
  118. r = w->r;
  119. w->tag.col = nil;
  120. w->body.col = nil;
  121. w->col = nil;
  122. restoremouse(w);
  123. if(dofree){
  124. windelete(w);
  125. winclose(w);
  126. }
  127. memmove(c->w+i, c->w+i+1, (c->nw-i)*sizeof(Window*));
  128. c->nw--;
  129. c->w = realloc(c->w, c->nw*sizeof(Window*));
  130. if(c->nw == 0){
  131. draw(screen, r, display->white, nil, ZP);
  132. return;
  133. }
  134. if(i == c->nw){ /* extend last window down */
  135. w = c->w[i-1];
  136. r.min.y = w->r.min.y;
  137. r.max.y = c->r.max.y;
  138. }else{ /* extend next window up */
  139. w = c->w[i];
  140. r.max.y = w->r.max.y;
  141. }
  142. draw(screen, r, textcols[BACK], nil, ZP);
  143. if(c->safe)
  144. winresize(w, r, FALSE);
  145. }
  146. void
  147. colcloseall(Column *c)
  148. {
  149. int i;
  150. Window *w;
  151. if(c == activecol)
  152. activecol = nil;
  153. textclose(&c->tag);
  154. for(i=0; i<c->nw; i++){
  155. w = c->w[i];
  156. winclose(w);
  157. }
  158. c->nw = 0;
  159. free(c->w);
  160. free(c);
  161. clearmouse();
  162. }
  163. void
  164. colmousebut(Column *c)
  165. {
  166. moveto(mousectl, divpt(addpt(c->tag.scrollr.min, c->tag.scrollr.max), 2));
  167. }
  168. void
  169. colresize(Column *c, Rectangle r)
  170. {
  171. int i;
  172. Rectangle r1, r2;
  173. Window *w;
  174. clearmouse();
  175. r1 = r;
  176. r1.max.y = r1.min.y + c->tag.font->height;
  177. textresize(&c->tag, r1);
  178. draw(screen, c->tag.scrollr, colbutton, nil, colbutton->r.min);
  179. r1.min.y = r1.max.y;
  180. r1.max.y += Border;
  181. draw(screen, r1, display->black, nil, ZP);
  182. r1.max.y = r.max.y;
  183. for(i=0; i<c->nw; i++){
  184. w = c->w[i];
  185. w->maxlines = 0;
  186. if(i == c->nw-1)
  187. r1.max.y = r.max.y;
  188. else
  189. r1.max.y = r1.min.y+(Dy(w->r)+Border)*Dy(r)/Dy(c->r);
  190. r2 = r1;
  191. r2.max.y = r2.min.y+Border;
  192. draw(screen, r2, display->black, nil, ZP);
  193. r1.min.y = r2.max.y;
  194. r1.min.y = winresize(w, r1, FALSE);
  195. }
  196. c->r = r;
  197. }
  198. static
  199. int
  200. colcmp(void *a, void *b)
  201. {
  202. Rune *r1, *r2;
  203. int i, nr1, nr2;
  204. r1 = (*(Window**)a)->body.file->name;
  205. nr1 = (*(Window**)a)->body.file->nname;
  206. r2 = (*(Window**)b)->body.file->name;
  207. nr2 = (*(Window**)b)->body.file->nname;
  208. for(i=0; i<nr1 && i<nr2; i++){
  209. if(*r1 != *r2)
  210. return *r1-*r2;
  211. r1++;
  212. r2++;
  213. }
  214. return nr1-nr2;
  215. }
  216. void
  217. colsort(Column *c)
  218. {
  219. int i, y;
  220. Rectangle r, r1, *rp;
  221. Window **wp, *w;
  222. if(c->nw == 0)
  223. return;
  224. clearmouse();
  225. rp = emalloc(c->nw*sizeof(Rectangle));
  226. wp = emalloc(c->nw*sizeof(Window*));
  227. memmove(wp, c->w, c->nw*sizeof(Window*));
  228. qsort(wp, c->nw, sizeof(Window*), colcmp);
  229. for(i=0; i<c->nw; i++)
  230. rp[i] = wp[i]->r;
  231. r = c->r;
  232. r.min.y = c->tag.r.max.y;
  233. draw(screen, r, textcols[BACK], nil, ZP);
  234. y = r.min.y;
  235. for(i=0; i<c->nw; i++){
  236. w = wp[i];
  237. r.min.y = y;
  238. if(i == c->nw-1)
  239. r.max.y = c->r.max.y;
  240. else
  241. r.max.y = r.min.y+Dy(w->r)+Border;
  242. r1 = r;
  243. r1.max.y = r1.min.y+Border;
  244. draw(screen, r1, display->black, nil, ZP);
  245. r.min.y = r1.max.y;
  246. y = winresize(w, r, FALSE);
  247. }
  248. free(rp);
  249. free(c->w);
  250. c->w = wp;
  251. }
  252. void
  253. colgrow(Column *c, Window *w, int but)
  254. {
  255. Rectangle r, cr;
  256. int i, j, k, l, y1, y2, *nl, *ny, tot, nnl, onl, dnl, h;
  257. Window *v;
  258. for(i=0; i<c->nw; i++)
  259. if(c->w[i] == w)
  260. goto Found;
  261. error("can't find window");
  262. Found:
  263. cr = c->r;
  264. if(but < 0){ /* make sure window fills its own space properly */
  265. r = w->r;
  266. if(i==c->nw-1 || c->safe==FALSE)
  267. r.max.y = cr.max.y;
  268. else
  269. r.max.y = c->w[i+1]->r.min.y;
  270. winresize(w, r, FALSE);
  271. return;
  272. }
  273. cr.min.y = c->w[0]->r.min.y;
  274. if(but == 3){ /* full size */
  275. if(i != 0){
  276. v = c->w[0];
  277. c->w[0] = w;
  278. c->w[i] = v;
  279. }
  280. draw(screen, cr, textcols[BACK], nil, ZP);
  281. winresize(w, cr, FALSE);
  282. for(i=1; i<c->nw; i++)
  283. c->w[i]->body.maxlines = 0;
  284. c->safe = FALSE;
  285. return;
  286. }
  287. /* store old #lines for each window */
  288. onl = w->body.maxlines;
  289. nl = emalloc(c->nw * sizeof(int));
  290. ny = emalloc(c->nw * sizeof(int));
  291. tot = 0;
  292. for(j=0; j<c->nw; j++){
  293. l = c->w[j]->body.maxlines;
  294. nl[j] = l;
  295. tot += l;
  296. }
  297. /* approximate new #lines for this window */
  298. if(but == 2){ /* as big as can be */
  299. memset(nl, 0, c->nw * sizeof(int));
  300. goto Pack;
  301. }
  302. nnl = min(onl + max(min(5, w->maxlines), onl/2), tot);
  303. if(nnl < w->maxlines)
  304. nnl = (w->maxlines+nnl)/2;
  305. if(nnl == 0)
  306. nnl = 2;
  307. dnl = nnl - onl;
  308. /* compute new #lines for each window */
  309. for(k=1; k<c->nw; k++){
  310. /* prune from later window */
  311. j = i+k;
  312. if(j<c->nw && nl[j]){
  313. l = min(dnl, max(1, nl[j]/2));
  314. nl[j] -= l;
  315. nl[i] += l;
  316. dnl -= l;
  317. }
  318. /* prune from earlier window */
  319. j = i-k;
  320. if(j>=0 && nl[j]){
  321. l = min(dnl, max(1, nl[j]/2));
  322. nl[j] -= l;
  323. nl[i] += l;
  324. dnl -= l;
  325. }
  326. }
  327. Pack:
  328. /* pack everyone above */
  329. y1 = cr.min.y;
  330. for(j=0; j<i; j++){
  331. v = c->w[j];
  332. r = v->r;
  333. r.min.y = y1;
  334. r.max.y = y1+Dy(v->tag.all);
  335. if(nl[j])
  336. r.max.y += 1 + nl[j]*v->body.font->height;
  337. if(!c->safe || !eqrect(v->r, r)){
  338. draw(screen, r, textcols[BACK], nil, ZP);
  339. winresize(v, r, c->safe);
  340. }
  341. r.min.y = v->r.max.y;
  342. r.max.y += Border;
  343. draw(screen, r, display->black, nil, ZP);
  344. y1 = r.max.y;
  345. }
  346. /* scan to see new size of everyone below */
  347. y2 = c->r.max.y;
  348. for(j=c->nw-1; j>i; j--){
  349. v = c->w[j];
  350. r = v->r;
  351. r.min.y = y2-Dy(v->tag.all);
  352. if(nl[j])
  353. r.min.y -= 1 + nl[j]*v->body.font->height;
  354. r.min.y -= Border;
  355. ny[j] = r.min.y;
  356. y2 = r.min.y;
  357. }
  358. /* compute new size of window */
  359. r = w->r;
  360. r.min.y = y1;
  361. r.max.y = r.min.y+Dy(w->tag.all);
  362. h = w->body.font->height;
  363. if(y2-r.max.y >= 1+h+Border){
  364. r.max.y += 1;
  365. r.max.y += h*((y2-r.max.y)/h);
  366. }
  367. /* draw window */
  368. if(!c->safe || !eqrect(w->r, r)){
  369. draw(screen, r, textcols[BACK], nil, ZP);
  370. winresize(w, r, c->safe);
  371. }
  372. if(i < c->nw-1){
  373. r.min.y = r.max.y;
  374. r.max.y += Border;
  375. draw(screen, r, display->black, nil, ZP);
  376. for(j=i+1; j<c->nw; j++)
  377. ny[j] -= (y2-r.max.y);
  378. }
  379. /* pack everyone below */
  380. y1 = r.max.y;
  381. for(j=i+1; j<c->nw; j++){
  382. v = c->w[j];
  383. r = v->r;
  384. r.min.y = y1;
  385. r.max.y = y1+Dy(v->tag.all);
  386. if(nl[j])
  387. r.max.y += 1 + nl[j]*v->body.font->height;
  388. if(!c->safe || !eqrect(v->r, r)){
  389. draw(screen, r, textcols[BACK], nil, ZP);
  390. winresize(v, r, c->safe);
  391. }
  392. if(j < c->nw-1){ /* no border on last window */
  393. r.min.y = v->r.max.y;
  394. r.max.y += Border;
  395. draw(screen, r, display->black, nil, ZP);
  396. }
  397. y1 = r.max.y;
  398. }
  399. r = w->r;
  400. r.min.y = y1;
  401. r.max.y = c->r.max.y;
  402. draw(screen, r, textcols[BACK], nil, ZP);
  403. free(nl);
  404. free(ny);
  405. c->safe = TRUE;
  406. winmousebut(w);
  407. }
  408. void
  409. coldragwin(Column *c, Window *w, int but)
  410. {
  411. Rectangle r;
  412. int i, b;
  413. Point p, op;
  414. Window *v;
  415. Column *nc;
  416. clearmouse();
  417. setcursor(mousectl, &boxcursor);
  418. b = mouse->buttons;
  419. op = mouse->xy;
  420. while(mouse->buttons == b)
  421. readmouse(mousectl);
  422. setcursor(mousectl, nil);
  423. if(mouse->buttons){
  424. while(mouse->buttons)
  425. readmouse(mousectl);
  426. return;
  427. }
  428. for(i=0; i<c->nw; i++)
  429. if(c->w[i] == w)
  430. goto Found;
  431. error("can't find window");
  432. Found:
  433. p = mouse->xy;
  434. if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){
  435. colgrow(c, w, but);
  436. winmousebut(w);
  437. return;
  438. }
  439. /* is it a flick to the right? */
  440. if(abs(p.y-op.y)<10 && p.x>op.x+30 && rowwhichcol(c->row, p)==c)
  441. p.x += Dx(w->r); /* yes: toss to next column */
  442. nc = rowwhichcol(c->row, p);
  443. if(nc!=nil && nc!=c){
  444. colclose(c, w, FALSE);
  445. coladd(nc, w, nil, p.y);
  446. winmousebut(w);
  447. return;
  448. }
  449. if(i==0 && c->nw==1)
  450. return; /* can't do it */
  451. if((i>0 && p.y<c->w[i-1]->r.min.y) || (i<c->nw-1 && p.y>w->r.max.y)
  452. || (i==0 && p.y>w->r.max.y)){
  453. /* shuffle */
  454. colclose(c, w, FALSE);
  455. coladd(c, w, nil, p.y);
  456. winmousebut(w);
  457. return;
  458. }
  459. if(i == 0)
  460. return;
  461. v = c->w[i-1];
  462. if(p.y < v->tag.all.max.y)
  463. p.y = v->tag.all.max.y;
  464. if(p.y > w->r.max.y-Dy(w->tag.all)-Border)
  465. p.y = w->r.max.y-Dy(w->tag.all)-Border;
  466. r = v->r;
  467. r.max.y = p.y;
  468. if(r.max.y > v->body.r.min.y){
  469. r.max.y -= (r.max.y-v->body.r.min.y)%v->body.font->height;
  470. if(v->body.r.min.y == v->body.r.max.y)
  471. r.max.y++;
  472. }
  473. if(!eqrect(v->r, r)){
  474. draw(screen, r, textcols[BACK], nil, ZP);
  475. winresize(v, r, c->safe);
  476. }
  477. r.min.y = v->r.max.y;
  478. r.max.y = r.min.y+Border;
  479. draw(screen, r, display->black, nil, ZP);
  480. r.min.y = r.max.y;
  481. if(i == c->nw-1)
  482. r.max.y = c->r.max.y;
  483. else
  484. r.max.y = c->w[i+1]->r.min.y-Border;
  485. if(!eqrect(w->r, r)){
  486. draw(screen, r, textcols[BACK], nil, ZP);
  487. winresize(w, r, c->safe);
  488. }
  489. c->safe = TRUE;
  490. winmousebut(w);
  491. }
  492. Text*
  493. colwhich(Column *c, Point p)
  494. {
  495. int i;
  496. Window *w;
  497. if(!ptinrect(p, c->r))
  498. return nil;
  499. if(ptinrect(p, c->tag.all))
  500. return &c->tag;
  501. for(i=0; i<c->nw; i++){
  502. w = c->w[i];
  503. if(ptinrect(p, w->r)){
  504. if(ptinrect(p, w->tag.all))
  505. return &w->tag;
  506. return &w->body;
  507. }
  508. }
  509. return nil;
  510. }
  511. int
  512. colclean(Column *c)
  513. {
  514. int i, clean;
  515. clean = TRUE;
  516. for(i=0; i<c->nw; i++)
  517. clean &= winclean(c->w[i], TRUE);
  518. return clean;
  519. }