1
2 /******************************************************************************
3 * MODULE : boxes.cpp
4 * DESCRIPTION: Important routines for all boxes
5 * COPYRIGHT : (C) 1999 Joris van der Hoeven
6 *******************************************************************************
7 * This software falls under the GNU general public license version 3 or later.
8 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
9 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
10 ******************************************************************************/
11
12 #include "boxes.hpp"
13 #include "formatter.hpp"
14 #include "point.hpp"
15 #include "printer.hpp"
16 #include "file.hpp"
17 #include "merge_sort.hpp"
18
19 /******************************************************************************
20 * Default settings for virtual routines
21 ******************************************************************************/
22
subnr()23 int box_rep::subnr () { return 0; }
subbox(int i)24 box box_rep::subbox (int i) { (void) i; return box (); }
operator [](path p)25 box box::operator [] (path p) {
26 if (is_nil (p)) return *this; else return rep->subbox(p->item)[p->next]; }
left_slope()27 double box_rep::left_slope () { return 0.0; }
right_slope()28 double box_rep::right_slope () { return 0.0; }
left_correction()29 SI box_rep::left_correction () { return (SI) (-min (0, y1) * left_slope ()); }
right_correction()30 SI box_rep::right_correction () { return (SI) (max (0, y2) * right_slope ()); }
lsub_correction()31 SI box_rep::lsub_correction () { return 0; }
lsup_correction()32 SI box_rep::lsup_correction () { return 0; }
rsub_correction()33 SI box_rep::rsub_correction () { return 0; }
rsup_correction()34 SI box_rep::rsup_correction () { return 0; }
sub_lo_base(int level)35 SI box_rep::sub_lo_base (int level) { (void) level; return y1; }
sub_hi_lim(int level)36 SI box_rep::sub_hi_lim (int level) { (void) level; return y1 + ((y2-y1)/3); }
sup_lo_lim(int level)37 SI box_rep::sup_lo_lim (int level) { (void) level; return (y1 + y2) >> 1; }
sup_lo_base(int level)38 SI box_rep::sup_lo_base (int level) { (void) level; return y2 - ((y2-y1)/3); }
sup_hi_lim(int level)39 SI box_rep::sup_hi_lim (int level) { (void) level; return y2; }
get_bracket_extents(SI & lo,SI & hi)40 void box_rep::get_bracket_extents (SI& lo, SI& hi) { lo= y1; hi= y2; }
41
42 /******************************************************************************
43 * Positioning routines
44 ******************************************************************************/
45
46 bool
outside(SI x,SI delta,SI x1,SI x2)47 outside (SI x, SI delta, SI x1, SI x2) {
48 return
49 (x<x1) || ((x==x1) && (delta<0)) ||
50 (x>x2) || ((x==x2) && (delta>=0));
51 }
52
53 SI
get_delta(SI x,SI x1,SI x2)54 get_delta (SI x, SI x1, SI x2) {
55 if (x1==x2) return 0;
56 if (x==x1) return -1;
57 if (x==x2) return 1;
58 return 0;
59 }
60
61 SI
distance(int i,SI x,SI y,SI delta)62 box_rep::distance (int i, SI x, SI y, SI delta) {
63 box b= subbox (i);
64 x -= sx(i);
65 y -= sy(i);
66 int dx, dy;
67 if (x <= b->x1) dx = b->x1- x- (delta<0? 1:0);
68 else if (x >= b->x2) dx = x- b->x2+ (delta<0? 0:1);
69 else dx = 0;
70 if (y < b->y1) dy = b->y1- y;
71 else if (y >= b->y2) dy = y- b->y2;
72 else dy = 0;
73 return dx+dy;
74 }
75
76 bool
in_rectangle(SI X1,SI Y1,SI X2,SI Y2)77 box_rep::in_rectangle (SI X1, SI Y1, SI X2, SI Y2) {
78 return x1>=X1 && y1>=Y1 && x2<=X2 && y2<=Y2;
79 }
80
81 bool
contains_rectangle(SI X1,SI Y1,SI X2,SI Y2)82 box_rep::contains_rectangle (SI X1, SI Y1, SI X2, SI Y2) {
83 return x1<=X1 && y1<=Y1 && x2>=X2 && y2>=Y2;
84 }
85
86 box
adjust_kerning(int mode,double factor)87 box_rep::adjust_kerning (int mode, double factor) {
88 return this;
89 }
90
91 void
get_cell_extents(SI & l,SI & r)92 box_rep::get_cell_extents (SI& l, SI& r) {
93 (void) l; (void) r;
94 FAILED ("cell box expected");
95 }
96
97 box
adjust_cell_geometry(SI dx,SI dl,SI dr)98 box_rep::adjust_cell_geometry (SI dx, SI dl, SI dr) {
99 (void) dx; (void) dl; (void) dr;
100 FAILED ("cell box expected");
101 return this;
102 }
103
104 /******************************************************************************
105 * Cursor routines
106 ******************************************************************************/
107
108 path
find_box_path(SI x,SI y,SI delta,bool force,bool & found)109 box_rep::find_box_path (SI x, SI y, SI delta, bool force, bool& found) {
110 (void) y;
111 (void) force;
112 found= true;
113 SI m= (x1+x2)>>1;
114 return path (((x<m) || ((x==m) && (delta<0)))? 0: 1);
115 }
116
117 path
find_lip()118 box_rep::find_lip () {
119 return descend (ip, 0);
120 }
121
122 path
find_rip()123 box_rep::find_rip () {
124 return descend (ip, 1);
125 }
126
127 path
find_left_box_path()128 box_rep::find_left_box_path () {
129 return path (0);
130 }
131
132 path
find_right_box_path()133 box_rep::find_right_box_path () {
134 return path (1);
135 }
136
137 path
find_box_path(path p,bool & found)138 box_rep::find_box_path (path p, bool& found) {
139 // cout << "Find box path " << box (this) << ", " << p
140 // << "; " << reverse (ip)
141 // << ", " << reverse (find_lip ())
142 // << " -- " << reverse (find_rip ()) << "\n";
143 found= (!is_nil(p)) && is_accessible (ip);
144 if (last_item (p) == 0) return path (0);
145 else return path (1);
146 }
147
148 path
find_tree_path(path bp)149 box_rep::find_tree_path (path bp) {
150 if (bp == path (0)) return reverse (descend_decode (ip, 0));
151 else return reverse (descend_decode (ip, 1));
152 }
153
154 cursor
find_cursor(path bp)155 box_rep::find_cursor (path bp) {
156 bool flag= bp == path (0);
157 double slope= flag? left_slope (): right_slope ();
158 cursor cu (flag? x1: x2, 0);
159 cu->y1= y1; cu->y2= y2;
160 cu->slope= slope;
161 return cu;
162 }
163
164 selection
find_selection(path lbp,path rbp)165 box_rep::find_selection (path lbp, path rbp) {
166 if (lbp == rbp)
167 return selection (rectangles (),
168 find_tree_path (lbp), find_tree_path (rbp));
169 else
170 return selection (rectangle (x1, y1, x2, y2),
171 find_tree_path (path (0)), find_tree_path (path (1)));
172 }
173
174 path
find_tree_path(SI x,SI y,SI delta)175 box_rep::find_tree_path (SI x, SI y, SI delta) {
176 bool found;
177 path bp= find_box_path (x, y, delta, false, found);
178 //cout << "Find " << x << ", " << y << "; " << delta;
179 //cout << " -> " << bp << "\n";
180 return find_tree_path (bp);
181 }
182
183 cursor
find_check_cursor(path p)184 box_rep::find_check_cursor (path p) {
185 bool found;
186 path bp= find_box_path (p, found);
187 cursor cu= find_cursor (bp);
188 cu->valid= found;
189 return cu;
190 }
191
192 selection
find_check_selection(path lp,path rp)193 box_rep::find_check_selection (path lp, path rp) {
194 bool lfound= false, rfound= false;
195 path lbp= find_box_path (lp, lfound);
196 path rbp= find_box_path (rp, rfound);
197 selection sel= find_selection (lbp, rbp);
198 sel->valid= lfound && rfound;
199 return sel;
200 }
201
202 void
relocate(path new_ip,bool force)203 box_rep::relocate (path new_ip, bool force) {
204 if (!force)
205 if (is_nil (ip) || (ip->item >= 0) || (ip == new_ip)) return;
206 ip= new_ip;
207 int i, n= subnr ();
208 for (i=0; i<n; i++) subbox (i)->relocate (ip, force);
209 }
210
211 box
transform(frame fr)212 box_rep::transform (frame fr) {
213 (void) fr;
214 return box ();
215 }
216
217 /******************************************************************************
218 * Modified cursor routines in presence of scrolled boxes
219 ******************************************************************************/
220
221 path
find_innermost_scroll(box b,path p)222 find_innermost_scroll (box b, path p) {
223 // Given a box b and a logical path p, this routine returns
224 // the longest box path sp such that b[sp] is a scroll node
225 path bp;
226 while (true) {
227 bool found= false;
228 bp= b->find_box_path (p, found);
229 if (found) break;
230 p= path_up (p);
231 if (is_nil (p)) return path ();
232 }
233 bp= path_up (bp);
234 path cp, sp;
235 while (!is_nil (bp)) {
236 if (b->get_type () == SCROLL_BOX) sp= reverse (cp);
237 b = b[bp->item];
238 cp= path (bp->item, cp);
239 bp= bp->next;
240 }
241 if (is_nil (sp)) return sp;
242 else return sp * 0;
243 }
244
245 path
find_scrolled_box_path(box b,path sp,SI x,SI y,SI delta)246 find_scrolled_box_path (box b, path sp, SI x, SI y, SI delta) {
247 if (is_nil (sp)) {
248 bool found;
249 return b->find_box_path (x, y, delta, false, found);
250 }
251 else {
252 int m= sp->item;
253 SI xx= x - b->sx (m), yy= y - b->sy (m);
254 SI dd= delta + get_delta (xx, b[m]->x1, b[m]->x2);
255 return path (m, find_scrolled_box_path (b[m], sp->next, xx, yy, dd));
256 }
257 }
258
259 /*
260 void
261 debug (box b, path bp) {
262 tree t= (tree) b;
263 if (is_tuple (t) && N(t) > 0) cout << t[0];
264 else cout << t;
265 cout << ", " << bp << "\n";
266 if (!is_nil (bp))
267 debug (b[bp->item], bp->next);
268 }
269 */
270
271 path
find_scrolled_tree_path(box b,path sp,SI x,SI y,SI delta)272 find_scrolled_tree_path (box b, path sp, SI x, SI y, SI delta) {
273 path bp= find_scrolled_box_path (b, sp, x, y, delta);
274 //cout << "Find " << x << ", " << y << "; " << delta;
275 //cout << " -> " << bp << "\n";
276 return b->find_tree_path (bp);
277 }
278
279 void
find_canvas_info(box b,path sp,SI & x,SI & y,SI & sx,SI & sy,rectangle & outer,rectangle & inner)280 find_canvas_info (box b, path sp, SI& x, SI& y, SI& sx, SI& sy,
281 rectangle& outer, rectangle& inner)
282 {
283 if (is_nil (sp)) {
284 x= y= sx= sy= 0;
285 outer= inner= rectangle (0, 0, 0, 0);
286 }
287 else if (is_atom (sp)) {
288 x = 0;
289 y = 0;
290 sx = b->sx (0);
291 sy = b->sy (0);
292 outer= rectangle (b->x1, b->y1, b->x2, b->y2);
293 inner= rectangle (b[0]->x1, b[0]->y1, b[0]->x2, b[0]->y2);
294 }
295 else {
296 find_canvas_info (b[sp->item], sp->next, x, y, sx, sy, outer, inner);
297 x += b->sx (sp->item);
298 y += b->sy (sp->item);
299 }
300 }
301
302 /******************************************************************************
303 * For graphical boxes
304 ******************************************************************************/
305
306 frame
get_frame()307 box_rep::get_frame () {
308 return frame ();
309 }
310
311 grid
get_grid()312 box_rep::get_grid () {
313 return grid ();
314 }
315
316 void
get_limits(point & lim1,point & lim2)317 box_rep::get_limits (point& lim1, point& lim2) {
318 lim1= point (); lim2= point ();
319 }
320
321 frame
find_frame(path bp,bool last)322 box_rep::find_frame (path bp, bool last) {
323 SI x= 0;
324 SI y= 0;
325 box b= this;
326 frame f= get_frame ();
327 while (!is_nil (bp)) {
328 x += b->sx (bp->item);
329 y += b->sy (bp->item);
330 b = b->subbox (bp->item);
331 bp = bp->next;
332 frame g= b->get_frame ();
333 if (!is_nil (g)) {
334 if (last)
335 f= g;
336 else
337 f= scaling (1.0, point (x, y)) * g;
338 }
339 }
340 return f;
341 }
342
343 grid
find_grid(path bp)344 box_rep::find_grid (path bp) {
345 box b= this;
346 grid g= get_grid ();
347 while (!is_nil (bp)) {
348 b = b->subbox (bp->item);
349 bp = bp->next;
350 grid g2= b->get_grid ();
351 if (!is_nil (g2)) g= g2;
352 }
353 return g;
354 }
355
356 void
find_limits(path bp,point & lim1,point & lim2)357 box_rep::find_limits (path bp, point& lim1, point& lim2) {
358 box b= this;
359 get_limits (lim1, lim2);
360 while (!is_nil (bp)) {
361 point slim1, slim2;
362 b = b->subbox (bp->item);
363 bp = bp->next;
364 b->get_limits (slim1, slim2);
365 if (slim1 != point ()) {
366 lim1= slim1;
367 lim2= slim2;
368 }
369 }
370 }
371
372 SI
graphical_distance(SI x,SI y)373 box_rep::graphical_distance (SI x, SI y) {
374 SI dx, dy;
375 if (x <= x1) dx= x1 - x;
376 else if (x >= x2) dx= x - x2;
377 else dx= 0;
378 if (y < y1) dy= y1 - y;
379 else if (y >= y2) dy= y - y2;
380 else dy= 0;
381 return (SI) norm (point (dx, dy));
382 }
383
384 gr_selections
graphical_select(SI x,SI y,SI dist)385 box_rep::graphical_select (SI x, SI y, SI dist) {
386 gr_selections res;
387 if (graphical_distance (x, y) <= dist) {
388 gr_selection gs;
389 gs->type= "box";
390 gs->dist= graphical_distance (x, y);
391 gs->cp << find_tree_path (x, y, dist);
392 // FIXME: check whether this is correct: I do not remember whether
393 // find_tree_path returns an absolute or a relative path
394 gs->c= curve ();
395 res << gs;
396 }
397 return res;
398 }
399
400 gr_selections
graphical_select(SI x1,SI y1,SI x2,SI y2)401 box_rep::graphical_select (SI x1, SI y1, SI x2, SI y2) {
402 gr_selections res;
403 if (in_rectangle (x1, y1, x2, y2)) {
404 gr_selection gs;
405 gs->type= "box";
406 gs->dist= graphical_distance (x1, y1);
407 SI dist= (SI)norm (point (x2-x1, y2-y1));
408 gs->cp << find_tree_path (x1, y1, dist);
409 // FIXME: as above, check whether this is correct or not
410 gs->pts= array<point> (0);
411 gs->c= curve ();
412 res << gs;
413 }
414 return res;
415 }
416
417 /******************************************************************************
418 * Getting information from boxes
419 ******************************************************************************/
420
421 int
get_type()422 box_rep::get_type () {
423 return STD_BOX;
424 }
425
426 tree
get_info(tree in)427 box_rep::get_info (tree in) {
428 (void) in;
429 return "";
430 }
431
432 int
get_leaf_left_pos()433 box_rep::get_leaf_left_pos () {
434 failed_error << "The box is " << box (this) << "\n";
435 FAILED ("this box is not textual");
436 return 0;
437 }
438
439 int
get_leaf_right_pos()440 box_rep::get_leaf_right_pos () {
441 failed_error << "The box is " << box (this) << "\n";
442 FAILED ("this box is not textual");
443 return 0;
444 }
445
446 string
get_leaf_string()447 box_rep::get_leaf_string () {
448 failed_error << "The box is " << box (this) << "\n";
449 FAILED ("this box is not textual");
450 return "";
451 }
452
453 font
get_leaf_font()454 box_rep::get_leaf_font () {
455 failed_error << "The box is " << box (this) << "\n";
456 FAILED ("this box is not textual");
457 return font ();
458 }
459
460 pencil
get_leaf_pencil()461 box_rep::get_leaf_pencil () {
462 failed_error << "The box is " << box (this) << "\n";
463 FAILED ("this box is not textual");
464 return pencil (false);
465 }
466
467 language
get_leaf_language()468 box_rep::get_leaf_language () {
469 failed_error << "The box is " << box (this) << "\n";
470 FAILED ("this box is not textual");
471 return language ();
472 }
473
474 tree
get_leaf_tree()475 box_rep::get_leaf_tree () {
476 failed_error << "The box is " << box (this) << "\n";
477 FAILED ("no tree attached to this box");
478 return "";
479 }
480
481 box
get_leaf_box()482 box_rep::get_leaf_box () {
483 failed_error << "The box is " << box (this) << "\n";
484 FAILED ("no box attached to this box");
485 return box ();
486 }
487
488 lazy
get_leaf_lazy()489 box_rep::get_leaf_lazy () {
490 failed_error << "The box is " << box (this) << "\n";
491 FAILED ("no lazy attached to this box");
492 return lazy ();
493 }
494
495 SI
get_leaf_offset(string search)496 box_rep::get_leaf_offset (string search) {
497 (void) search;
498 return w();
499 }
500
501 /******************************************************************************
502 * Redrawing boxes
503 ******************************************************************************/
504
505 int nr_painted= 0;
506
507 void
clear_pattern_rectangles(renderer ren,rectangles l)508 clear_pattern_rectangles (renderer ren, rectangles l) {
509 while (!is_nil (l)) {
510 rectangle r (l->item);
511 ren->clear_pattern (r->x1- ren->ox, r->y1- ren->oy,
512 r->x2- ren->ox, r->y2- ren->oy);
513 l= l->next;
514 }
515 }
516
517 int
reindex(int i,int item,int n)518 box_rep::reindex (int i, int item, int n) {
519 if (item<0) item=0;
520 if (item>n) item=n;
521 if (i==0) return item;
522 if ((i <= (item<<1)) && (i <= ((n-item)<<1))) {
523 int d=(i+1)>>1;
524 if (((i+1)&1)==0) return item-d;
525 else return item+d;
526 }
527 if (i > (item<<1)) return i;
528 return n-i;
529 }
530
531 void
redraw(renderer ren,path p,rectangles & l)532 box_rep::redraw (renderer ren, path p, rectangles& l) {
533 if ((nr_painted&15) == 15 && ren->is_screen && gui_interrupted (true)) return;
534 ren->move_origin (x0, y0);
535 SI delta= ren->pixel; // adjust visibility to compensate truncation
536 if (ren->is_visible (x3- delta, y3- delta, x4+ delta, y4+ delta)) {
537 rectangles ll;
538 l= rectangles();
539 pre_display (ren);
540
541 int i, item=-1, n=subnr (), i1= n, i2= -1;
542 if (!is_nil(p)) i1= i2= item= p->item;
543 for (i=0; i<n; i++) {
544 int k= reindex (i, item, n-1);
545 if (is_nil(p)) subbox (k)->redraw (ren, path (), ll);
546 else if (i!=0) {
547 if (k > item) subbox(k)->redraw (ren, path (0), ll);
548 else subbox(k)->redraw (ren, path (subbox(k)->subnr()-1), ll);
549 }
550 else subbox(k)->redraw (ren, p->next, ll);
551 if (!is_nil(ll)) {
552 i1= min (i1, k);
553 i2= max (i2, k);
554 l = ll * l;
555 ll= rectangles ();
556 }
557 }
558
559 if ((nr_painted&15) == 15 && ren->is_screen && gui_interrupted ()) {
560 l= translate (l, -ren->ox, -ren->oy);
561 clear_incomplete (l, ren->pixel, item, i1, i2);
562 l= translate (l, ren->ox, ren->oy);
563 }
564 else {
565 l= rectangle (x3+ ren->ox, y3+ ren->oy, x4+ ren->ox, y4+ ren->oy);
566 display (ren);
567 if (nr_painted < 15) ren->apply_shadow (x1, y1, x2, y2);
568 nr_painted++;
569 }
570
571 post_display (ren);
572 }
573 ren->move_origin (-x0, -y0);
574 }
575
576 void
redraw(renderer ren,path p,rectangles & l,SI x,SI y)577 box_rep::redraw (renderer ren, path p, rectangles& l, SI x, SI y) {
578 ren->move_origin (x, y);
579 redraw (ren, p, l);
580 ren->move_origin (-x, -y);
581 }
582
583 void
clear_incomplete(rectangles & rs,SI pixel,int i,int i1,int i2)584 box_rep::clear_incomplete (rectangles& rs, SI pixel, int i, int i1, int i2) {
585 (void) rs; (void) pixel; (void) i; (void) i1; (void) i2;
586 }
587
588 void
pre_display(renderer & ren)589 box_rep::pre_display (renderer &ren) {
590 (void) ren;
591 }
592
593 void
post_display(renderer & ren)594 box_rep::post_display (renderer &ren) {
595 (void) ren;
596 }
597
598 /******************************************************************************
599 * The cursor class
600 ******************************************************************************/
601
cursor(SI x,SI y,SI delta,SI y1,SI y2,double slope,bool valid)602 cursor::cursor (SI x, SI y, SI delta, SI y1, SI y2, double slope, bool valid):
603 rep (tm_new<cursor_rep> ())
604 {
605 rep->ox= x ; rep->oy= y ; rep->delta= delta;
606 rep->y1= y1; rep->y2= y2; rep->slope= slope;
607 rep->valid= valid;
608 }
609
610 cursor
copy(cursor cu)611 copy (cursor cu) {
612 return cursor (cu->ox, cu->oy, cu->delta, cu->y1, cu->y2,
613 cu->slope, cu->valid);
614 }
615
616 bool
operator ==(cursor cu1,cursor cu2)617 operator == (cursor cu1, cursor cu2) {
618 return
619 (cu1->ox == cu2->ox) && (cu1->oy == cu2->oy) &&
620 // (cu1->delta == cu2->delta) &&
621 (cu1->y1 == cu2->y1) && (cu1->y2 == cu2->y2) &&
622 (cu1->slope == cu2->slope);
623 }
624
625 bool
operator !=(cursor cu1,cursor cu2)626 operator != (cursor cu1, cursor cu2) {
627 return ! (cu1 == cu2);
628 }
629
630 tm_ostream&
operator <<(tm_ostream & out,cursor cu)631 operator << (tm_ostream& out, cursor cu) {
632 out << "cursor (" << (cu->ox>>8) << ", " << (cu->oy>>8) << ": "
633 << cu->delta << ": "
634 << (cu->y1>>8) << ", " << (cu->y2>>8) << ": "
635 << cu->slope << ")";
636 return out;
637 }
638
639 /******************************************************************************
640 * Selections
641 ******************************************************************************/
642
selection(rectangles rs,path start,path end,bool valid)643 selection::selection (rectangles rs, path start, path end, bool valid):
644 rep (tm_new<selection_rep> ())
645 {
646 rep->rs = rs;
647 rep->start= start;
648 rep->end = end;
649 rep->valid= valid;
650 }
651
652 bool
operator ==(selection sel1,selection sel2)653 operator == (selection sel1, selection sel2) {
654 return
655 (sel1->start == sel2->start) &&
656 (sel1->end == sel2->end);
657 }
658
659 bool
operator !=(selection sel1,selection sel2)660 operator != (selection sel1, selection sel2) {
661 return !(sel1 == sel2);
662 }
663
664 tm_ostream&
operator <<(tm_ostream & out,selection sel)665 operator << (tm_ostream& out, selection sel) {
666 return out << "selection (" << sel->start << ", " << sel->end << ")";
667 }
668
669 /******************************************************************************
670 * Graphical selections
671 ******************************************************************************/
672
gr_selection(array<path> cp,SI dist)673 gr_selection::gr_selection (array<path> cp, SI dist):
674 rep (tm_new<gr_selection_rep> ())
675 {
676 rep->cp = cp;
677 rep->dist= dist;
678 }
679
680 tm_ostream&
operator <<(tm_ostream & out,gr_selection sel)681 operator << (tm_ostream& out, gr_selection sel) {
682 return out << "gr_selection (" << sel->type << ", "
683 << sel->dist << ", " << sel->cp << ")";
684 }
685
686 struct less_eq_gr_selection {
leqless_eq_gr_selection687 static inline bool leq (gr_selection& a, gr_selection& b) {
688 return a->dist <= b->dist; }
689 };
690
691 void
sort(gr_selections & sels)692 sort (gr_selections& sels) {
693 merge_sort_leq <gr_selection, less_eq_gr_selection> (sels);
694 }
695
696 tree
as_tree(gr_selections sels)697 as_tree (gr_selections sels) {
698 sort (sels);
699 int i, n= N(sels);
700 array<array<path> > res (n);
701 for (i=0; i<n; i++)
702 res[i]= sels[i]->cp;
703 return (tree) res;
704 }
705
706
707 /******************************************************************************
708 * Animations
709 ******************************************************************************/
710
711 int
anim_length()712 box_rep::anim_length () {
713 int i, n= subnr (), len=0;
714 for (i=0; i<n; i++) {
715 int slen= subbox (i)->anim_length ();
716 if (slen == -1) return -1;
717 if (slen > len) len= slen;
718 }
719 return len;
720 }
721
722 bool
anim_started()723 box_rep::anim_started () {
724 int i, n= subnr ();
725 for (i=0; i<n; i++)
726 if (!subbox (i)->anim_started ()) return false;
727 return true;
728 }
729
730 bool
anim_finished()731 box_rep::anim_finished () {
732 int i, n= subnr ();
733 for (i=0; i<n; i++)
734 if (!subbox (i)->anim_finished ()) return false;
735 return true;
736 }
737
738 void
anim_start_at(time_t at)739 box_rep::anim_start_at (time_t at) {
740 int i, n= subnr ();
741 for (i=0; i<n; i++)
742 subbox (i)->anim_start_at (at);
743 }
744
745 void
anim_finish_now()746 box_rep::anim_finish_now () {
747 int i, n= subnr ();
748 for (i=0; i<n; i++)
749 subbox (i)->anim_finish_now ();
750 }
751
752 time_t
anim_next_update()753 box_rep::anim_next_update () {
754 FAILED ("invalid situation");
755 return texmacs_time ();
756 }
757
758 void
anim_check_invalid(bool & flag,time_t & at,rectangles & rs)759 box_rep::anim_check_invalid (bool& flag, time_t& at, rectangles& rs) {
760 time_t now= texmacs_time ();
761 time_t finish_at= anim_next_update ();
762 if (finish_at - now < 0) finish_at= now;
763 if (flag && at - now < 0) at= now;
764 if (!flag || finish_at - (at - 3) < 0) {
765 flag= true;
766 at = finish_at;
767 rs = rectangle (x1, y1, x2, y2);
768 }
769 else if (finish_at - (at + 3) <= 0) {
770 rs << rectangle (x1, y1, x2, y2);
771 if (finish_at - at < 0)
772 at= finish_at;
773 }
774 }
775
776 void
anim_get_invalid(bool & flag,time_t & at,rectangles & rs)777 box_rep::anim_get_invalid (bool& flag, time_t& at, rectangles& rs) {
778 int i, n= subnr ();
779 for (i=0; i<n; i++) {
780 bool flag2= false;
781 time_t at2= at;
782 rectangles rs2;
783 subbox (i)->anim_get_invalid (flag2, at2, rs2);
784 if (flag2) {
785 rs2= translate (rs2, sx (i), sy (i));
786 if (at2 - (at-3) < 0) rs= rs2;
787 else rs << rs2;
788 flag= true;
789 if (at2 - at < 0) at= at2;
790 }
791 }
792 }
793
794 /******************************************************************************
795 * Miscellaneous routines
796 ******************************************************************************/
797
798 tree
action(tree t,SI x,SI y,SI delta)799 box_rep::action (tree t, SI x, SI y, SI delta) {
800 (void) x; (void) y; (void) delta; (void) t;
801 return "";
802 }
803
804 void
loci(SI x,SI y,SI delta,list<string> & ids,rectangles & rs)805 box_rep::loci (SI x, SI y, SI delta, list<string>& ids, rectangles& rs) {
806 (void) x; (void) y; (void) delta;
807 ids= list<string> ();
808 rs = rectangles ();
809 }
810
811 void
position_at(SI x,SI y,rectangles & change_log)812 box_rep::position_at (SI x, SI y, rectangles& change_log) {
813 int i, n= subnr ();
814 x += x0; y += y0;
815 for (i=0; i<n; i++) subbox (i)->position_at (x, y, change_log);
816 }
817
818 void
collect_page_numbers(hashmap<string,tree> & h,tree page)819 box_rep::collect_page_numbers (hashmap<string,tree>& h, tree page) {
820 (void) h; (void) page;
821 }
822
823 path
find_tag(string name)824 box_rep::find_tag (string name) {
825 (void) name;
826 return path ();
827 }
828
operator ==(box b2)829 bool box::operator == (box b2) { return rep==b2.rep; }
operator !=(box b2)830 bool box::operator != (box b2) { return rep!=b2.rep; }
831
operator tree()832 box::operator tree () { return tree (*rep); }
operator <<(tm_ostream & out,box b)833 tm_ostream& operator << (tm_ostream& out, box b) { return out << ((tree) b); }
834
835 path
descend_decode(path ip,int side)836 descend_decode (path ip, int side) {
837 if (is_nil (ip)) return descend (ip, side);
838 else switch (ip->item) {
839 case DECORATION : return ip->next;
840 case DECORATION_LEFT : return descend (ip->next, 0);
841 case DECORATION_MIDDLE: return descend (ip->next, side);
842 case DECORATION_RIGHT : return descend (ip->next, 1);
843 default : return descend (ip, side);
844 }
845 }
846
847 tree
attach_dip(tree ref,path dip)848 attach_dip (tree ref, path dip) {
849 path old_ip= obtain_ip (ref);
850 if (old_ip != path (DETACHED)) return ref;
851 if (is_atomic (ref)) {
852 tree r (ref->label);
853 r->obs= list_observer (ip_observer (dip), r->obs);
854 return r;
855 }
856 else {
857 int i, n= N(ref);
858 tree r (ref, n);
859 for (i=0; i<n; i++)
860 r[i]= attach_dip (ref[i], descend (dip, i));
861 r->obs= list_observer (ip_observer (dip), r->obs);
862 return r;
863 }
864 }
865
866 /******************************************************************************
867 * Convert to postscript
868 ******************************************************************************/
869
870 void
make_eps(url name,box b,int dpi=600)871 make_eps (url name, box b, int dpi=600) {
872 double inch= ((double) dpi * PIXEL);
873 double cm = inch / 2.54;
874 SI w= b->x4 - b->x3;
875 SI h= b->y4 - b->y3;
876 b->x0= -b->x3;
877 b->y0= -b->y4;
878 renderer ren= printer (name, dpi, 1, "user", false, w/cm, h/cm);
879 ren->set_background (white);
880 ren->set_pencil (black);
881 rectangles rs;
882 b->redraw (ren, path (0), rs);
883 tm_delete (ren);
884 }
885