flayer.c 9.6 KB

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