col.b 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. implement Columnm;
  2. include "common.m";
  3. sys : Sys;
  4. utils : Utils;
  5. drawm : Draw;
  6. acme : Acme;
  7. graph : Graph;
  8. gui : Gui;
  9. dat : Dat;
  10. textm : Textm;
  11. rowm : Rowm;
  12. filem : Filem;
  13. windowm : Windowm;
  14. FALSE, TRUE, XXX : import Dat;
  15. Border : import Dat;
  16. mouse, colbutton : import dat;
  17. Point, Rect, Image : import drawm;
  18. draw : import graph;
  19. min, max, abs, error, clearmouse : import utils;
  20. black, white, mainwin : import gui;
  21. Text : import textm;
  22. Row : import rowm;
  23. Window : import windowm;
  24. File : import filem;
  25. Columntag : import Textm;
  26. BACK : import Framem;
  27. tagcols, textcols : import acme;
  28. init(mods : ref Dat->Mods)
  29. {
  30. sys = mods.sys;
  31. dat = mods.dat;
  32. utils = mods.utils;
  33. drawm = mods.draw;
  34. acme = mods.acme;
  35. graph = mods.graph;
  36. gui = mods.gui;
  37. textm = mods.textm;
  38. rowm = mods.rowm;
  39. filem = mods.filem;
  40. windowm = mods.windowm;
  41. }
  42. Column.init(c : self ref Column, r : Rect)
  43. {
  44. r1 : Rect;
  45. t : ref Text;
  46. dummy : ref File = nil;
  47. draw(mainwin, r, white, nil, (0, 0));
  48. c.r = r;
  49. c.row = nil;
  50. c.w = nil;
  51. c.nw = 0;
  52. c.tag = textm->newtext();
  53. t = c.tag;
  54. t.w = nil;
  55. t.col = c;
  56. r1 = r;
  57. r1.max.y = r1.min.y + (graph->font).height;
  58. t.init(dummy.addtext(t), r1, dat->reffont, tagcols);
  59. t.what = Columntag;
  60. r1.min.y = r1.max.y;
  61. r1.max.y += Border;
  62. draw(mainwin, r1, black, nil, (0, 0));
  63. t.insert(0, "New Cut Paste Snarf Sort Zerox Delcol ", 38, TRUE, 0);
  64. t.setselect(t.file.buf.nc, t.file.buf.nc);
  65. draw(mainwin, t.scrollr, colbutton, nil, colbutton.r.min);
  66. c.safe = TRUE;
  67. }
  68. Column.add(c : self ref Column, w : ref Window, clone : ref Window, y : int) : ref Window
  69. {
  70. r, r1 : Rect;
  71. v : ref Window;
  72. i, t : int;
  73. v = nil;
  74. r = c.r;
  75. r.min.y = c.tag.frame.r.max.y+Border;
  76. if(y<r.min.y && c.nw>0){ # steal half of last window by default
  77. v = c.w[c.nw-1];
  78. y = v.body.frame.r.min.y+v.body.frame.r.dy()/2;
  79. }
  80. # look for window we'll land on
  81. for(i=0; i<c.nw; i++){
  82. v = c.w[i];
  83. if(y < v.r.max.y)
  84. break;
  85. }
  86. if(c.nw > 0){
  87. if(i < c.nw)
  88. i++; # new window will go after v
  89. #
  90. # if v's too small, grow it first.
  91. #
  92. if(!c.safe || v.body.frame.maxlines<=3){
  93. c.grow(v, 1, 1);
  94. y = v.body.frame.r.min.y+v.body.frame.r.dy()/2;
  95. }
  96. r = v.r;
  97. if(i == c.nw)
  98. t = c.r.max.y;
  99. else
  100. t = c.w[i].r.min.y-Border;
  101. r.max.y = t;
  102. draw(mainwin, r, textcols[BACK], nil, (0, 0));
  103. r1 = r;
  104. y = min(y, t-(v.tag.frame.font.height+v.body.frame.font.height+Border+1));
  105. r1.max.y = min(y, v.body.frame.r.min.y+v.body.frame.nlines*v.body.frame.font.height);
  106. r1.min.y = v.reshape(r1, FALSE);
  107. r1.max.y = r1.min.y+Border;
  108. draw(mainwin, r1, black, nil, (0, 0));
  109. r.min.y = r1.max.y;
  110. }
  111. if(w == nil){
  112. w = ref Window;
  113. draw(mainwin, r, textcols[BACK], nil, (0, 0));
  114. w.col = c;
  115. w.init(clone, r);
  116. }else{
  117. w.col = c;
  118. w.reshape(r, FALSE);
  119. }
  120. w.tag.col = c;
  121. w.tag.row = c.row;
  122. w.body.col = c;
  123. w.body.row = c.row;
  124. ocw := c.w;
  125. c.w = array[c.nw+1] of ref Window;
  126. c.w[0:] = ocw[0:i];
  127. c.w[i+1:] = ocw[i:c.nw];
  128. ocw = nil;
  129. c.nw++;
  130. c.w[i] = w;
  131. utils->savemouse(w);
  132. # near but not on the button
  133. graph->cursorset(w.tag.scrollr.max.add(Point(3, 3)));
  134. dat->barttext = w.body;
  135. c.safe = TRUE;
  136. return w;
  137. }
  138. Column.close(c : self ref Column, w : ref Window, dofree : int)
  139. {
  140. r : Rect;
  141. i : int;
  142. # w is locked
  143. if(!c.safe)
  144. c.grow(w, 1, 1);
  145. for(i=0; i<c.nw; i++)
  146. if(c.w[i] == w)
  147. break;
  148. if (i == c.nw)
  149. error("can't find window");
  150. r = w.r;
  151. w.tag.col = nil;
  152. w.body.col = nil;
  153. w.col = nil;
  154. utils->restoremouse(w);
  155. if(dofree){
  156. w.delete();
  157. w.close();
  158. }
  159. ocw := c.w;
  160. c.w = array[c.nw-1] of ref Window;
  161. c.w[0:] = ocw[0:i];
  162. c.w[i:] = ocw[i+1:c.nw];
  163. ocw = nil;
  164. c.nw--;
  165. if(c.nw == 0){
  166. draw(mainwin, r, white, nil, (0, 0));
  167. return;
  168. }
  169. if(i == c.nw){ # extend last window down
  170. w = c.w[i-1];
  171. r.min.y = w.r.min.y;
  172. r.max.y = c.r.max.y;
  173. }else{ # extend next window up
  174. w = c.w[i];
  175. r.max.y = w.r.max.y;
  176. }
  177. draw(mainwin, r, textcols[BACK], nil, (0, 0));
  178. if(c.safe)
  179. w.reshape(r, FALSE);
  180. }
  181. Column.closeall(c : self ref Column)
  182. {
  183. i : int;
  184. w : ref Window;
  185. if(c == dat->activecol)
  186. dat->activecol = nil;
  187. c.tag.close();
  188. for(i=0; i<c.nw; i++){
  189. w = c.w[i];
  190. w.close();
  191. }
  192. c.nw = 0;
  193. c.w = nil;
  194. c = nil;
  195. clearmouse();
  196. }
  197. Column.mousebut(c : self ref Column)
  198. {
  199. graph->cursorset(c.tag.scrollr.min.add(c.tag.scrollr.max).div(2));
  200. }
  201. Column.reshape(c : self ref Column, r : Rect)
  202. {
  203. i : int;
  204. r1, r2 : Rect;
  205. w : ref Window;
  206. clearmouse();
  207. r1 = r;
  208. r1.max.y = r1.min.y + c.tag.frame.font.height;
  209. c.tag.reshape(r1);
  210. draw(mainwin, c.tag.scrollr, colbutton, nil, colbutton.r.min);
  211. r1.min.y = r1.max.y;
  212. r1.max.y += Border;
  213. draw(mainwin, r1, black, nil, (0, 0));
  214. r1.max.y = r.max.y;
  215. for(i=0; i<c.nw; i++){
  216. w = c.w[i];
  217. w.maxlines = 0;
  218. if(i == c.nw-1)
  219. r1.max.y = r.max.y;
  220. else
  221. r1.max.y = r1.min.y+(w.r.dy()+Border)*r.dy()/c.r.dy();
  222. r2 = r1;
  223. r2.max.y = r2.min.y+Border;
  224. draw(mainwin, r2, black, nil, (0, 0));
  225. r1.min.y = r2.max.y;
  226. r1.min.y = w.reshape(r1, FALSE);
  227. }
  228. c.r = r;
  229. }
  230. colcmp(a : ref Window, b : ref Window) : int
  231. {
  232. r1, r2 : string;
  233. r1 = a.body.file.name;
  234. r2 = b.body.file.name;
  235. if (r1 < r2)
  236. return -1;
  237. if (r1 > r2)
  238. return 1;
  239. return 0;
  240. }
  241. qsort(a : array of ref Window, n : int)
  242. {
  243. i, j : int;
  244. t : ref Window;
  245. while(n > 1) {
  246. i = n>>1;
  247. t = a[0]; a[0] = a[i]; a[i] = t;
  248. i = 0;
  249. j = n;
  250. for(;;) {
  251. do
  252. i++;
  253. while(i < n && colcmp(a[i], a[0]) < 0);
  254. do
  255. j--;
  256. while(j > 0 && colcmp(a[j], a[0]) > 0);
  257. if(j < i)
  258. break;
  259. t = a[i]; a[i] = a[j]; a[j] = t;
  260. }
  261. t = a[0]; a[0] = a[j]; a[j] = t;
  262. n = n-j-1;
  263. if(j >= n) {
  264. qsort(a, j);
  265. a = a[j+1:];
  266. } else {
  267. qsort(a[j+1:], n);
  268. n = j;
  269. }
  270. }
  271. }
  272. Column.sort(c : self ref Column)
  273. {
  274. i, y : int;
  275. r, r1 : Rect;
  276. rp : array of Rect;
  277. w : ref Window;
  278. wp : array of ref Window;
  279. if(c.nw == 0)
  280. return;
  281. clearmouse();
  282. rp = array[c.nw] of Rect;
  283. wp = array[c.nw] of ref Window;
  284. wp[0:] = c.w[0:c.nw];
  285. qsort(wp, c.nw);
  286. for(i=0; i<c.nw; i++)
  287. rp[i] = wp[i].r;
  288. r = c.r;
  289. r.min.y = c.tag.frame.r.max.y;
  290. draw(mainwin, r, textcols[BACK], nil, (0, 0));
  291. y = r.min.y;
  292. for(i=0; i<c.nw; i++){
  293. w = wp[i];
  294. r.min.y = y;
  295. if(i == c.nw-1)
  296. r.max.y = c.r.max.y;
  297. else
  298. r.max.y = r.min.y+w.r.dy()+Border;
  299. r1 = r;
  300. r1.max.y = r1.min.y+Border;
  301. draw(mainwin, r1, black, nil, (0, 0));
  302. r.min.y = r1.max.y;
  303. y = w.reshape(r, FALSE);
  304. }
  305. rp = nil;
  306. c.w = wp;
  307. }
  308. Column.grow(c : self ref Column, w : ref Window, but : int, mv : int)
  309. {
  310. r, cr : Rect;
  311. i, j, k, l, y1, y2, tot, nnl, onl, dnl, h : int;
  312. nl, ny : array of int;
  313. v : ref Window;
  314. for(i=0; i<c.nw; i++)
  315. if(c.w[i] == w)
  316. break;
  317. if (i == c.nw)
  318. error("can't find window");
  319. cr = c.r;
  320. if(but < 0){ # make sure window fills its own space properly
  321. r = w.r;
  322. if(i == c.nw-1)
  323. r.max.y = cr.max.y;
  324. else
  325. r.max.y = c.w[i+1].r.min.y;
  326. w.reshape(r, FALSE);
  327. return;
  328. }
  329. cr.min.y = c.w[0].r.min.y;
  330. if(but == 3){ # full size
  331. if(i != 0){
  332. v = c.w[0];
  333. c.w[0] = w;
  334. c.w[i] = v;
  335. }
  336. draw(mainwin, cr, textcols[BACK], nil, (0, 0));
  337. w.reshape(cr, FALSE);
  338. for(i=1; i<c.nw; i++)
  339. c.w[i].body.frame.maxlines = 0;
  340. c.safe = FALSE;
  341. return;
  342. }
  343. # store old #lines for each window
  344. onl = w.body.frame.maxlines;
  345. nl = array[c.nw] of int;
  346. ny = array[c.nw] of int;
  347. tot = 0;
  348. for(j=0; j<c.nw; j++){
  349. l = c.w[j].body.frame.maxlines;
  350. nl[j] = l;
  351. tot += l;
  352. }
  353. # approximate new #lines for this window
  354. if(but == 2){ # as big as can be
  355. for (j = 0; j < c.nw; j++)
  356. nl[j] = 0;
  357. nl[i] = tot;
  358. }
  359. else {
  360. nnl = min(onl + max(min(5, w.maxlines), onl/2), tot);
  361. if(nnl < w.maxlines)
  362. nnl = (w.maxlines+nnl)/2;
  363. if(nnl == 0)
  364. nnl = 2;
  365. dnl = nnl - onl;
  366. # compute new #lines for each window
  367. for(k=1; k<c.nw; k++){
  368. # prune from later window
  369. j = i+k;
  370. if(j<c.nw && nl[j]){
  371. l = min(dnl, max(1, nl[j]/2));
  372. nl[j] -= l;
  373. nl[i] += l;
  374. dnl -= l;
  375. }
  376. # prune from earlier window
  377. j = i-k;
  378. if(j>=0 && nl[j]){
  379. l = min(dnl, max(1, nl[j]/2));
  380. nl[j] -= l;
  381. nl[i] += l;
  382. dnl -= l;
  383. }
  384. }
  385. }
  386. # pack everyone above
  387. y1 = cr.min.y;
  388. for(j=0; j<i; j++){
  389. v = c.w[j];
  390. r = v.r;
  391. r.min.y = y1;
  392. r.max.y = y1+v.tag.all.dy();
  393. if(nl[j])
  394. r.max.y += 1 + nl[j]*v.body.frame.font.height;
  395. if(!c.safe || !v.r.eq(r)){
  396. draw(mainwin, r, textcols[BACK], nil, (0, 0));
  397. v.reshape(r, c.safe);
  398. }
  399. r.min.y = v.r.max.y;
  400. r.max.y += Border;
  401. draw(mainwin, r, black, nil, (0, 0));
  402. y1 = r.max.y;
  403. }
  404. # scan to see new size of everyone below
  405. y2 = c.r.max.y;
  406. for(j=c.nw-1; j>i; j--){
  407. v = c.w[j];
  408. r = v.r;
  409. r.min.y = y2-v.tag.all.dy();
  410. if(nl[j])
  411. r.min.y -= 1 + nl[j]*v.body.frame.font.height;
  412. r.min.y -= Border;
  413. ny[j] = r.min.y;
  414. y2 = r.min.y;
  415. }
  416. # compute new size of window
  417. r = w.r;
  418. r.min.y = y1;
  419. r.max.y = r.min.y+w.tag.all.dy();
  420. h = w.body.frame.font.height;
  421. if(y2-r.max.y >= 1+h+Border){
  422. r.max.y += 1;
  423. r.max.y += h*((y2-r.max.y)/h);
  424. }
  425. # draw window
  426. if(!c.safe || !w.r.eq(r)){
  427. draw(mainwin, r, textcols[BACK], nil, (0, 0));
  428. w.reshape(r, c.safe);
  429. }
  430. if(i < c.nw-1){
  431. r.min.y = r.max.y;
  432. r.max.y += Border;
  433. draw(mainwin, r, black, nil, (0, 0));
  434. for(j=i+1; j<c.nw; j++)
  435. ny[j] -= (y2-r.max.y);
  436. }
  437. # pack everyone below
  438. y1 = r.max.y;
  439. for(j=i+1; j<c.nw; j++){
  440. v = c.w[j];
  441. r = v.r;
  442. r.min.y = y1;
  443. r.max.y = y1+v.tag.all.dy();
  444. if(nl[j])
  445. r.max.y += 1 + nl[j]*v.body.frame.font.height;
  446. if(!c.safe || !v.r.eq(r)){
  447. draw(mainwin, r, textcols[BACK], nil, (0, 0));
  448. v.reshape(r, c.safe);
  449. }
  450. if(j < c.nw-1){ # no border on last window
  451. r.min.y = v.r.max.y;
  452. r.max.y += Border;
  453. draw(mainwin, r, black, nil, (0, 0));
  454. }
  455. y1 = r.max.y;
  456. }
  457. r = w.r;
  458. r.min.y = y1;
  459. r.max.y = c.r.max.y;
  460. draw(mainwin, r, textcols[BACK], nil, (0, 0));
  461. nl = nil;
  462. ny = nil;
  463. c.safe = TRUE;
  464. if (mv)
  465. w.mousebut();
  466. }
  467. Column.dragwin(c : self ref Column, w : ref Window, but : int)
  468. {
  469. r : Rect;
  470. i, b : int;
  471. p, op : Point;
  472. v : ref Window;
  473. nc : ref Column;
  474. clearmouse();
  475. graph->cursorswitch(dat->boxcursor);
  476. b = mouse.buttons;
  477. op = mouse.xy;
  478. while(mouse.buttons == b)
  479. acme->frgetmouse();
  480. graph->cursorswitch(dat->arrowcursor);
  481. if(mouse.buttons){
  482. while(mouse.buttons)
  483. acme->frgetmouse();
  484. return;
  485. }
  486. for(i=0; i<c.nw; i++)
  487. if(c.w[i] == w)
  488. break;
  489. if (i == c.nw)
  490. error("can't find window");
  491. p = mouse.xy;
  492. if(abs(p.x-op.x)<5 && abs(p.y-op.y)<5){
  493. c.grow(w, but, 1);
  494. w.mousebut();
  495. return;
  496. }
  497. # is it a flick to the right?
  498. if(abs(p.y-op.y)<10 && p.x>op.x+30 && c.row.whichcol(p) == c)
  499. p.x += w.r.dx(); # yes: toss to next column
  500. nc = c.row.whichcol(p);
  501. if(nc!=nil && nc!=c){
  502. c.close(w, FALSE);
  503. nc.add(w, nil, p.y);
  504. w.mousebut();
  505. return;
  506. }
  507. if(i==0 && c.nw==1)
  508. return; # can't do it
  509. if((i>0 && p.y<c.w[i-1].r.min.y) || (i<c.nw-1 && p.y>w.r.max.y)
  510. || (i==0 && p.y>w.r.max.y)){
  511. # shuffle
  512. c.close(w, FALSE);
  513. c.add(w, nil, p.y);
  514. w.mousebut();
  515. return;
  516. }
  517. if(i == 0)
  518. return;
  519. v = c.w[i-1];
  520. if(p.y < v.tag.all.max.y)
  521. p.y = v.tag.all.max.y;
  522. if(p.y > w.r.max.y-w.tag.all.dy()-Border)
  523. p.y = w.r.max.y-w.tag.all.dy()-Border;
  524. r = v.r;
  525. r.max.y = p.y;
  526. if(r.max.y > v.body.frame.r.min.y){
  527. r.max.y -= (r.max.y-v.body.frame.r.min.y)%v.body.frame.font.height;
  528. if(v.body.frame.r.min.y == v.body.frame.r.max.y)
  529. r.max.y++;
  530. }
  531. if(!r.eq(v.r)){
  532. draw(mainwin, r, textcols[BACK], nil, (0, 0));
  533. v.reshape(r, c.safe);
  534. }
  535. r.min.y = v.r.max.y;
  536. r.max.y = r.min.y+Border;
  537. draw(mainwin, r, black, nil, (0, 0));
  538. r.min.y = r.max.y;
  539. if(i == c.nw-1)
  540. r.max.y = c.r.max.y;
  541. else
  542. r.max.y = c.w[i+1].r.min.y-Border;
  543. # r.max.y = w.r.max.y;
  544. if(!r.eq(w.r)){
  545. draw(mainwin, r, textcols[BACK], nil, (0, 0));
  546. w.reshape(r, c.safe);
  547. }
  548. c.safe = TRUE;
  549. w.mousebut();
  550. }
  551. Column.which(c : self ref Column, p : Point) : ref Text
  552. {
  553. i : int;
  554. w : ref Window;
  555. if(!p.in(c.r))
  556. return nil;
  557. if(p.in(c.tag.all))
  558. return c.tag;
  559. for(i=0; i<c.nw; i++){
  560. w = c.w[i];
  561. if(p.in(w.r)){
  562. if(p.in(w.tag.all))
  563. return w.tag;
  564. return w.body;
  565. }
  566. }
  567. return nil;
  568. }
  569. Column.clean(c : self ref Column, exiting : int) : int
  570. {
  571. clean : int;
  572. i : int;
  573. clean = TRUE;
  574. for(i=0; i<c.nw; i++)
  575. clean &= c.w[i].clean(TRUE, exiting);
  576. return clean;
  577. }