frinsert.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  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 <frame.h>
  15. #define DELTA 25
  16. #define TMPSIZE 256
  17. static Frame frame;
  18. static
  19. Point
  20. bxscan(Frame *f, Rune *sp, Rune *ep, Point *ppt)
  21. {
  22. int w, c, nb, delta, nl, nr, rw;
  23. Frbox *b;
  24. char *s, tmp[TMPSIZE+3]; /* +3 for rune overflow */
  25. uint8_t *p;
  26. frame.r = f->r;
  27. frame.b = f->b;
  28. frame.font = f->font;
  29. frame.maxtab = f->maxtab;
  30. frame.nbox = 0;
  31. frame.nchars = 0;
  32. memmove(frame.cols, f->cols, sizeof frame.cols);
  33. delta = DELTA;
  34. nl = 0;
  35. for(nb=0; sp<ep && nl<=f->maxlines; nb++,frame.nbox++){
  36. if(nb == frame.nalloc){
  37. _frgrowbox(&frame, delta);
  38. if(delta < 10000)
  39. delta *= 2;
  40. }
  41. b = &frame.box[nb];
  42. c = *sp;
  43. if(c=='\t' || c=='\n'){
  44. b->bc = c;
  45. b->wid = 5000;
  46. b->minwid = (c=='\n')? 0 : stringwidth(frame.font, " ");
  47. b->nrune = -1;
  48. if(c=='\n')
  49. nl++;
  50. frame.nchars++;
  51. sp++;
  52. }else{
  53. s = tmp;
  54. nr = 0;
  55. w = 0;
  56. while(sp < ep){
  57. c = *sp;
  58. if(c=='\t' || c=='\n')
  59. break;
  60. rw = runetochar(s, sp);
  61. if(s+rw >= tmp+TMPSIZE)
  62. break;
  63. w += runestringnwidth(frame.font, sp, 1);
  64. sp++;
  65. s += rw;
  66. nr++;
  67. }
  68. *s++ = 0;
  69. p = _frallocstr(f, s-tmp);
  70. b = &frame.box[nb];
  71. b->ptr = p;
  72. memmove(p, tmp, s-tmp);
  73. b->wid = w;
  74. b->nrune = nr;
  75. frame.nchars += nr;
  76. }
  77. }
  78. _frcklinewrap0(f, ppt, &frame.box[0]);
  79. return _frdraw(&frame, *ppt);
  80. }
  81. static
  82. void
  83. chopframe(Frame *f, Point pt, uint32_t p, int bn)
  84. {
  85. Frbox *b;
  86. for(b = &f->box[bn]; ; b++){
  87. if(b >= &f->box[f->nbox])
  88. drawerror(f->display, "endofframe");
  89. _frcklinewrap(f, &pt, b);
  90. if(pt.y >= f->r.max.y)
  91. break;
  92. p += NRUNE(b);
  93. _fradvance(f, &pt, b);
  94. }
  95. f->nchars = p;
  96. f->nlines = f->maxlines;
  97. if(b<&f->box[f->nbox]) /* BUG */
  98. _frdelbox(f, (int)(b-f->box), f->nbox-1);
  99. }
  100. void
  101. frinsert(Frame *f, Rune *sp, Rune *ep, uint32_t p0)
  102. {
  103. Point pt0, pt1, opt0, ppt0, ppt1, pt;
  104. Frbox *b;
  105. int n, n0, nn0, y;
  106. uint32_t cn0;
  107. Image *col;
  108. Rectangle r;
  109. static struct{
  110. Point pt0, pt1;
  111. }*pts;
  112. static int nalloc=0;
  113. int npts;
  114. if(p0>f->nchars || sp==ep || f->b==nil)
  115. return;
  116. n0 = _frfindbox(f, 0, 0, p0);
  117. cn0 = p0;
  118. nn0 = n0;
  119. pt0 = _frptofcharnb(f, p0, n0);
  120. ppt0 = pt0;
  121. opt0 = pt0;
  122. pt1 = bxscan(f, sp, ep, &ppt0);
  123. ppt1 = pt1;
  124. if(n0 < f->nbox){
  125. _frcklinewrap(f, &pt0, b = &f->box[n0]); /* for frdrawsel() */
  126. _frcklinewrap0(f, &ppt1, b);
  127. }
  128. f->modified = 1;
  129. /*
  130. * ppt0 and ppt1 are start and end of insertion as they will appear when
  131. * insertion is complete. pt0 is current location of insertion position
  132. * (p0); pt1 is terminal point (without line wrap) of insertion.
  133. */
  134. if(f->p0 == f->p1)
  135. frtick(f, frptofchar(f, f->p0), 0);
  136. /*
  137. * Find point where old and new x's line up
  138. * Invariants:
  139. * pt0 is where the next box (b, n0) is now
  140. * pt1 is where it will be after the insertion
  141. * If pt1 goes off the rectangle, we can toss everything from there on
  142. */
  143. for(b = &f->box[n0],npts=0;
  144. pt1.x!=pt0.x && pt1.y!=f->r.max.y && n0<f->nbox; b++,n0++,npts++){
  145. _frcklinewrap(f, &pt0, b);
  146. _frcklinewrap0(f, &pt1, b);
  147. if(b->nrune > 0){
  148. n = _frcanfit(f, pt1, b);
  149. if(n == 0)
  150. drawerror(f->display, "_frcanfit==0");
  151. if(n != b->nrune){
  152. _frsplitbox(f, n0, n);
  153. b = &f->box[n0];
  154. }
  155. }
  156. if(npts == nalloc){
  157. pts = realloc(pts, (npts+DELTA)*sizeof(pts[0]));
  158. nalloc += DELTA;
  159. b = &f->box[n0];
  160. }
  161. pts[npts].pt0 = pt0;
  162. pts[npts].pt1 = pt1;
  163. /* has a text box overflowed off the frame? */
  164. if(pt1.y == f->r.max.y)
  165. break;
  166. _fradvance(f, &pt0, b);
  167. pt1.x += _frnewwid(f, pt1, b);
  168. cn0 += NRUNE(b);
  169. }
  170. if(pt1.y > f->r.max.y)
  171. drawerror(f->display, "frinsert pt1 too far");
  172. if(pt1.y==f->r.max.y && n0<f->nbox){
  173. f->nchars -= _frstrlen(f, n0);
  174. _frdelbox(f, n0, f->nbox-1);
  175. }
  176. if(n0 == f->nbox)
  177. f->nlines = (pt1.y-f->r.min.y)/f->font->height+(pt1.x>f->r.min.x);
  178. else if(pt1.y!=pt0.y){
  179. int q0, q1;
  180. y = f->r.max.y;
  181. q0 = pt0.y+f->font->height;
  182. q1 = pt1.y+f->font->height;
  183. f->nlines += (q1-q0)/f->font->height;
  184. if(f->nlines > f->maxlines)
  185. chopframe(f, ppt1, p0, nn0);
  186. if(pt1.y < y){
  187. r = f->r;
  188. r.min.y = q1;
  189. r.max.y = y;
  190. if(q1 < y)
  191. draw(f->b, r, f->b, nil, Pt(f->r.min.x, q0));
  192. r.min = pt1;
  193. r.max.x = pt1.x+(f->r.max.x-pt0.x);
  194. r.max.y = q1;
  195. draw(f->b, r, f->b, nil, pt0);
  196. }
  197. }
  198. /*
  199. * Move the old stuff down to make room. The loop will move the stuff
  200. * between the insertion and the point where the x's lined up.
  201. * The draw()s above moved everything down after the point they lined up.
  202. */
  203. for((y=pt1.y==f->r.max.y?pt1.y:0),b = &f->box[n0-1]; --npts>=0; --b){
  204. pt = pts[npts].pt1;
  205. if(b->nrune > 0){
  206. r.min = pt;
  207. r.max = r.min;
  208. r.max.x += b->wid;
  209. r.max.y += f->font->height;
  210. draw(f->b, r, f->b, nil, pts[npts].pt0);
  211. /* clear bit hanging off right */
  212. if(npts==0 && pt.y>pt0.y){
  213. /*
  214. * first new char is bigger than first char we're
  215. * displacing, causing line wrap. ugly special case.
  216. */
  217. r.min = opt0;
  218. r.max = opt0;
  219. r.max.x = f->r.max.x;
  220. r.max.y += f->font->height;
  221. if(f->p0<=cn0 && cn0<f->p1) /* b+1 is inside selection */
  222. col = f->cols[HIGH];
  223. else
  224. col = f->cols[BACK];
  225. draw(f->b, r, col, nil, r.min);
  226. }else if(pt.y < y){
  227. r.min = pt;
  228. r.max = pt;
  229. r.min.x += b->wid;
  230. r.max.x = f->r.max.x;
  231. r.max.y += f->font->height;
  232. if(f->p0<=cn0 && cn0<f->p1) /* b+1 is inside selection */
  233. col = f->cols[HIGH];
  234. else
  235. col = f->cols[BACK];
  236. draw(f->b, r, col, nil, r.min);
  237. }
  238. y = pt.y;
  239. cn0 -= b->nrune;
  240. }else{
  241. r.min = pt;
  242. r.max = pt;
  243. r.max.x += b->wid;
  244. r.max.y += f->font->height;
  245. if(r.max.x >= f->r.max.x)
  246. r.max.x = f->r.max.x;
  247. cn0--;
  248. if(f->p0<=cn0 && cn0<f->p1) /* b is inside selection */
  249. col = f->cols[HIGH];
  250. else
  251. col = f->cols[BACK];
  252. draw(f->b, r, col, nil, r.min);
  253. y = 0;
  254. if(pt.x == f->r.min.x)
  255. y = pt.y;
  256. }
  257. }
  258. /* insertion can extend the selection, so the condition here is different */
  259. if(f->p0<p0 && p0<=f->p1)
  260. col = f->cols[HIGH];
  261. else
  262. col = f->cols[BACK];
  263. frselectpaint(f, ppt0, ppt1, col);
  264. _frdrawtext(&frame, ppt0, f->cols[TEXT], col);
  265. _fraddbox(f, nn0, frame.nbox);
  266. for(n=0; n<frame.nbox; n++)
  267. f->box[nn0+n] = frame.box[n];
  268. if(nn0>0 && f->box[nn0-1].nrune>=0 && ppt0.x-f->box[nn0-1].wid>=f->r.min.x){
  269. --nn0;
  270. ppt0.x -= f->box[nn0].wid;
  271. }
  272. n0 += frame.nbox;
  273. _frclean(f, ppt0, nn0, n0<f->nbox-1? n0+1 : n0);
  274. f->nchars += frame.nchars;
  275. if(f->p0 >= p0)
  276. f->p0 += frame.nchars;
  277. if(f->p0 > f->nchars)
  278. f->p0 = f->nchars;
  279. if(f->p1 >= p0)
  280. f->p1 += frame.nchars;
  281. if(f->p1 > f->nchars)
  282. f->p1 = f->nchars;
  283. if(f->p0 == f->p1)
  284. frtick(f, frptofchar(f, f->p0), 1);
  285. }