flayer.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. /*
  2. * This file is part of the UCB release of Plan 9. It is subject to the license
  3. * terms in the LICENSE file found in the top-level directory of this
  4. * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
  5. * part of the UCB release of Plan 9, including this file, may be copied,
  6. * modified, propagated, or distributed except according to the terms contained
  7. * in the LICENSE file.
  8. */
  9. #include <u.h>
  10. #include <libc.h>
  11. #include <draw.h>
  12. #include <thread.h>
  13. #include <mouse.h>
  14. #include <keyboard.h>
  15. #include <frame.h>
  16. #include "flayer.h"
  17. #include "samterm.h"
  18. #define DELTA 10
  19. static Flayer **llist; /* front to back */
  20. static int nllist;
  21. static int nlalloc;
  22. static Rectangle lDrect;
  23. Vis visibility(Flayer *);
  24. void newvisibilities(int);
  25. void llinsert(Flayer*);
  26. void lldelete(Flayer*);
  27. Image *maincols[NCOL];
  28. Image *cmdcols[NCOL];
  29. void
  30. flstart(Rectangle r)
  31. {
  32. lDrect = r;
  33. /* Main text is yellowish */
  34. maincols[BACK] = allocimagemix(display, DPaleyellow, DWhite);
  35. maincols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DDarkyellow);
  36. maincols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, DYellowgreen);
  37. maincols[TEXT] = display->black;
  38. maincols[HTEXT] = display->black;
  39. /* Command text is blueish */
  40. cmdcols[BACK] = allocimagemix(display, DPalebluegreen, DWhite);
  41. cmdcols[HIGH] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPalegreygreen);
  42. cmdcols[BORD] = allocimage(display, Rect(0,0,2,2), screen->chan, 1, DPurpleblue);
  43. cmdcols[TEXT] = display->black;
  44. cmdcols[HTEXT] = display->black;
  45. }
  46. void
  47. flnew(Flayer *l, Rune *(*fn)(Flayer*, long, ulong*), int u0, void *u1)
  48. {
  49. if(nllist == nlalloc){
  50. nlalloc += DELTA;
  51. llist = realloc(llist, nlalloc*sizeof(Flayer**));
  52. if(llist == 0)
  53. panic("flnew");
  54. }
  55. l->textfn = fn;
  56. l->user0 = u0;
  57. l->user1 = u1;
  58. l->lastsr = ZR;
  59. llinsert(l);
  60. }
  61. Rectangle
  62. flrect(Flayer *l, Rectangle r)
  63. {
  64. rectclip(&r, lDrect);
  65. l->entire = r;
  66. l->scroll = insetrect(r, FLMARGIN);
  67. r.min.x =
  68. l->scroll.max.x = r.min.x+FLMARGIN+FLSCROLLWID+(FLGAP-FLMARGIN);
  69. return r;
  70. }
  71. static void
  72. fontbuggered(char *name)
  73. {
  74. fprint(2, "samterm: font %s has zero-width \"0\" character\n", name);
  75. threadexits("font zero-width");
  76. }
  77. void
  78. flinit(Flayer *l, Rectangle r, Font *ft, Image **cols)
  79. {
  80. lldelete(l);
  81. llinsert(l);
  82. l->visible = All;
  83. l->origin = l->p0 = l->p1 = 0;
  84. frinit(&l->f, insetrect(flrect(l, r), FLMARGIN), ft, screen, cols);
  85. l->f.maxtab = maxtab*stringwidth(ft, "0");
  86. if(l->f.maxtab == 0)
  87. fontbuggered(ft->name);
  88. newvisibilities(1);
  89. draw(screen, l->entire, l->f.cols[BACK], nil, ZP);
  90. scrdraw(l, 0L);
  91. flborder(l, 0);
  92. }
  93. void
  94. flclose(Flayer *l)
  95. {
  96. if(l->visible == All)
  97. draw(screen, l->entire, display->white, nil, ZP);
  98. else if(l->visible == Some){
  99. if(l->f.b == 0)
  100. l->f.b = allocimage(display, l->entire, screen->chan, 0, DNofill);
  101. if(l->f.b){
  102. draw(l->f.b, l->entire, display->white, nil, ZP);
  103. flrefresh(l, l->entire, 0);
  104. }
  105. }
  106. frclear(&l->f, 1);
  107. lldelete(l);
  108. if(l->f.b && l->visible!=All)
  109. freeimage(l->f.b);
  110. l->textfn = 0;
  111. newvisibilities(1);
  112. }
  113. void
  114. flborder(Flayer *l, int wide)
  115. {
  116. if(flprepare(l)){
  117. border(l->f.b, l->entire, FLMARGIN, l->f.cols[BACK], ZP);
  118. border(l->f.b, l->entire, wide? FLMARGIN : 1, l->f.cols[BORD], ZP);
  119. if(l->visible==Some)
  120. flrefresh(l, l->entire, 0);
  121. }
  122. }
  123. Flayer *
  124. flwhich(Point p)
  125. {
  126. int i;
  127. if(p.x==0 && p.y==0)
  128. return nllist? llist[0] : 0;
  129. for(i=0; i<nllist; i++)
  130. if(ptinrect(p, llist[i]->entire))
  131. return llist[i];
  132. return 0;
  133. }
  134. void
  135. flupfront(Flayer *l)
  136. {
  137. int v = l->visible;
  138. lldelete(l);
  139. llinsert(l);
  140. if(v!=All)
  141. newvisibilities(0);
  142. }
  143. void
  144. newvisibilities(int redraw)
  145. /* if redraw false, we know it's a flupfront, and needn't
  146. * redraw anyone becoming partially covered */
  147. {
  148. int i;
  149. Vis ov;
  150. Flayer *l;
  151. for(i = 0; i<nllist; i++){
  152. l = llist[i];
  153. l->lastsr = ZR; /* make sure scroll bar gets redrawn */
  154. ov = l->visible;
  155. l->visible = visibility(l);
  156. #define V(a, b) (((a)<<2)|((b)))
  157. switch(V(ov, l->visible)){
  158. case V(Some, None):
  159. if(l->f.b)
  160. freeimage(l->f.b);
  161. case V(All, None):
  162. case V(All, Some):
  163. l->f.b = 0;
  164. frclear(&l->f, 0);
  165. break;
  166. case V(Some, Some):
  167. if(l->f.b==0 && redraw)
  168. case V(None, Some):
  169. flprepare(l);
  170. if(l->f.b && redraw){
  171. flrefresh(l, l->entire, 0);
  172. freeimage(l->f.b);
  173. l->f.b = 0;
  174. frclear(&l->f, 0);
  175. }
  176. case V(None, None):
  177. case V(All, All):
  178. break;
  179. case V(Some, All):
  180. if(l->f.b){
  181. draw(screen, l->entire, l->f.b, nil, l->entire.min);
  182. freeimage(l->f.b);
  183. l->f.b = screen;
  184. break;
  185. }
  186. case V(None, All):
  187. flprepare(l);
  188. break;
  189. }
  190. if(ov==None && l->visible!=None)
  191. flnewlyvisible(l);
  192. }
  193. }
  194. void
  195. llinsert(Flayer *l)
  196. {
  197. int i;
  198. for(i=nllist; i>0; --i)
  199. llist[i]=llist[i-1];
  200. llist[0]=l;
  201. nllist++;
  202. }
  203. void
  204. lldelete(Flayer *l)
  205. {
  206. int i;
  207. for(i=0; i<nllist; i++)
  208. if(llist[i]==l){
  209. --nllist;
  210. for(; i<nllist; i++)
  211. llist[i] = llist[i+1];
  212. return;
  213. }
  214. panic("lldelete");
  215. }
  216. void
  217. flinsert(Flayer *l, Rune *sp, Rune *ep, long p0)
  218. {
  219. if(flprepare(l)){
  220. frinsert(&l->f, sp, ep, p0-l->origin);
  221. scrdraw(l, scrtotal(l));
  222. if(l->visible==Some)
  223. flrefresh(l, l->entire, 0);
  224. }
  225. }
  226. void
  227. fldelete(Flayer *l, long p0, long p1)
  228. {
  229. if(flprepare(l)){
  230. p0 -= l->origin;
  231. if(p0 < 0)
  232. p0 = 0;
  233. p1 -= l->origin;
  234. if(p1<0)
  235. p1 = 0;
  236. frdelete(&l->f, p0, p1);
  237. scrdraw(l, scrtotal(l));
  238. if(l->visible==Some)
  239. flrefresh(l, l->entire, 0);
  240. }
  241. }
  242. int
  243. flselect(Flayer *l)
  244. {
  245. int ret;
  246. if(l->visible!=All)
  247. flupfront(l);
  248. frselect(&l->f, mousectl);
  249. ret = 0;
  250. if(l->f.p0==l->f.p1){
  251. if(mousep->msec-l->click<Clicktime && l->f.p0+l->origin==l->p0){
  252. ret = 1;
  253. l->click = 0;
  254. }else
  255. l->click = mousep->msec;
  256. }else
  257. l->click = 0;
  258. l->p0 = l->f.p0+l->origin, l->p1 = l->f.p1+l->origin;
  259. return ret;
  260. }
  261. void
  262. flsetselect(Flayer *l, long p0, long p1)
  263. {
  264. ulong fp0, fp1;
  265. l->click = 0;
  266. if(l->visible==None || !flprepare(l)){
  267. l->p0 = p0, l->p1 = p1;
  268. return;
  269. }
  270. l->p0 = p0, l->p1 = p1;
  271. flfp0p1(l, &fp0, &fp1);
  272. if(fp0==l->f.p0 && fp1==l->f.p1)
  273. return;
  274. if(fp1<=l->f.p0 || fp0>=l->f.p1 || l->f.p0==l->f.p1 || fp0==fp1){
  275. /* no overlap or trivial repainting */
  276. frdrawsel(&l->f, frptofchar(&l->f, l->f.p0), l->f.p0, l->f.p1, 0);
  277. frdrawsel(&l->f, frptofchar(&l->f, fp0), fp0, fp1, 1);
  278. goto Refresh;
  279. }
  280. /* the current selection and the desired selection overlap and are both non-empty */
  281. if(fp0 < l->f.p0){
  282. /* extend selection backwards */
  283. frdrawsel(&l->f, frptofchar(&l->f, fp0), fp0, l->f.p0, 1);
  284. }else if(fp0 > l->f.p0){
  285. /* trim first part of selection */
  286. frdrawsel(&l->f, frptofchar(&l->f, l->f.p0), l->f.p0, fp0, 0);
  287. }
  288. if(fp1 > l->f.p1){
  289. /* extend selection forwards */
  290. frdrawsel(&l->f, frptofchar(&l->f, l->f.p1), l->f.p1, fp1, 1);
  291. }else if(fp1 < l->f.p1){
  292. /* trim last part of selection */
  293. frdrawsel(&l->f, frptofchar(&l->f, fp1), fp1, l->f.p1, 0);
  294. }
  295. Refresh:
  296. l->f.p0 = fp0;
  297. l->f.p1 = fp1;
  298. if(l->visible==Some)
  299. flrefresh(l, l->entire, 0);
  300. }
  301. void
  302. flfp0p1(Flayer *l, ulong *pp0, ulong *pp1)
  303. {
  304. long p0 = l->p0-l->origin, p1 = l->p1-l->origin;
  305. if(p0 < 0)
  306. p0 = 0;
  307. if(p1 < 0)
  308. p1 = 0;
  309. if(p0 > l->f.nchars)
  310. p0 = l->f.nchars;
  311. if(p1 > l->f.nchars)
  312. p1 = l->f.nchars;
  313. *pp0 = p0;
  314. *pp1 = p1;
  315. }
  316. Rectangle
  317. rscale(Rectangle r, Point old, Point new)
  318. {
  319. r.min.x = r.min.x*new.x/old.x;
  320. r.min.y = r.min.y*new.y/old.y;
  321. r.max.x = r.max.x*new.x/old.x;
  322. r.max.y = r.max.y*new.y/old.y;
  323. return r;
  324. }
  325. void
  326. flresize(Rectangle dr)
  327. {
  328. int i;
  329. Flayer *l;
  330. Frame *f;
  331. Rectangle r, olDrect;
  332. int move;
  333. olDrect = lDrect;
  334. lDrect = dr;
  335. move = 0;
  336. /* no moving on rio; must repaint */
  337. if(0 && Dx(dr)==Dx(olDrect) && Dy(dr)==Dy(olDrect))
  338. move = 1;
  339. else
  340. draw(screen, lDrect, display->white, nil, ZP);
  341. for(i=0; i<nllist; i++){
  342. l = llist[i];
  343. l->lastsr = ZR;
  344. f = &l->f;
  345. if(move)
  346. r = rectaddpt(rectsubpt(l->entire, olDrect.min), dr.min);
  347. else{
  348. r = rectaddpt(rscale(rectsubpt(l->entire, olDrect.min),
  349. subpt(olDrect.max, olDrect.min),
  350. subpt(dr.max, dr.min)), dr.min);
  351. if(l->visible==Some && f->b){
  352. freeimage(f->b);
  353. frclear(f, 0);
  354. }
  355. f->b = 0;
  356. if(l->visible!=None)
  357. frclear(f, 0);
  358. }
  359. if(!rectclip(&r, dr))
  360. panic("flresize");
  361. if(r.max.x-r.min.x<100)
  362. r.min.x = dr.min.x;
  363. if(r.max.x-r.min.x<100)
  364. r.max.x = dr.max.x;
  365. if(r.max.y-r.min.y<2*FLMARGIN+f->font->height)
  366. r.min.y = dr.min.y;
  367. if(r.max.y-r.min.y<2*FLMARGIN+f->font->height)
  368. r.max.y = dr.max.y;
  369. if(!move)
  370. l->visible = None;
  371. frsetrects(f, insetrect(flrect(l, r), FLMARGIN), f->b);
  372. if(!move && f->b)
  373. scrdraw(l, scrtotal(l));
  374. }
  375. newvisibilities(1);
  376. }
  377. int
  378. flprepare(Flayer *l)
  379. {
  380. Frame *f;
  381. ulong n;
  382. Rune *r;
  383. if(l->visible == None)
  384. return 0;
  385. f = &l->f;
  386. if(f->b == 0){
  387. if(l->visible == All)
  388. f->b = screen;
  389. else if((f->b = allocimage(display, l->entire, screen->chan, 0, 0))==0)
  390. return 0;
  391. draw(f->b, l->entire, f->cols[BACK], nil, ZP);
  392. border(f->b, l->entire, l==llist[0]? FLMARGIN : 1, f->cols[BORD], ZP);
  393. n = f->nchars;
  394. frinit(f, f->entire, f->font, f->b, 0);
  395. f->maxtab = maxtab*stringwidth(f->font, "0");
  396. if(f->maxtab == 0)
  397. fontbuggered(f->font->name);
  398. r = (*l->textfn)(l, n, &n);
  399. frinsert(f, r, r+n, (ulong)0);
  400. frdrawsel(f, frptofchar(f, f->p0), f->p0, f->p1, 0);
  401. flfp0p1(l, &f->p0, &f->p1);
  402. frdrawsel(f, frptofchar(f, f->p0), f->p0, f->p1, 1);
  403. l->lastsr = ZR;
  404. scrdraw(l, scrtotal(l));
  405. }
  406. return 1;
  407. }
  408. static int somevis, someinvis, justvis;
  409. Vis
  410. visibility(Flayer *l)
  411. {
  412. somevis = someinvis = 0;
  413. justvis = 1;
  414. flrefresh(l, l->entire, 0);
  415. justvis = 0;
  416. if(somevis==0)
  417. return None;
  418. if(someinvis==0)
  419. return All;
  420. return Some;
  421. }
  422. void
  423. flrefresh(Flayer *l, Rectangle r, int i)
  424. {
  425. Flayer *t;
  426. Rectangle s;
  427. Top:
  428. if((t=llist[i++]) == l){
  429. if(!justvis)
  430. draw(screen, r, l->f.b, nil, r.min);
  431. somevis = 1;
  432. }else{
  433. if(!rectXrect(t->entire, r))
  434. goto Top; /* avoid stacking unnecessarily */
  435. if(t->entire.min.x>r.min.x){
  436. s = r;
  437. s.max.x = t->entire.min.x;
  438. flrefresh(l, s, i);
  439. r.min.x = t->entire.min.x;
  440. }
  441. if(t->entire.min.y>r.min.y){
  442. s = r;
  443. s.max.y = t->entire.min.y;
  444. flrefresh(l, s, i);
  445. r.min.y = t->entire.min.y;
  446. }
  447. if(t->entire.max.x<r.max.x){
  448. s = r;
  449. s.min.x = t->entire.max.x;
  450. flrefresh(l, s, i);
  451. r.max.x = t->entire.max.x;
  452. }
  453. if(t->entire.max.y<r.max.y){
  454. s = r;
  455. s.min.y = t->entire.max.y;
  456. flrefresh(l, s, i);
  457. r.max.y = t->entire.max.y;
  458. }
  459. /* remaining piece of r is blocked by t; forget about it */
  460. someinvis = 1;
  461. }
  462. }