Back to index

texmacs  1.0.7.15
concat_boxes.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : concat.cpp
00004 * DESCRIPTION: Concatenations of arrays of boxes
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "Boxes/composite.hpp"
00013 
00014 /******************************************************************************
00015 * The concat_box representation
00016 ******************************************************************************/
00017 
00018 struct concat_box_rep: public composite_box_rep {
00019   concat_box_rep (path ip, array<box> bs, array<SI> spc);
00020   operator tree ();
00021 
00022   void      finalize ();
00023   void      clear_incomplete (rectangles& rs, SI pixel, int i, int i1, int i2);
00024   bool      access_allowed ();
00025   void      position (array<SI> spc);
00026   int       count_left (int i);
00027   int       count_right (int i);
00028 
00029   int       get_first ();
00030   int       get_last ();
00031   double    left_slope ();
00032   double    right_slope ();
00033   SI        left_correction ();
00034   SI        right_correction ();
00035   SI        lsub_correction ();
00036   SI        lsup_correction ();
00037   SI        rsub_correction ();
00038   SI        rsup_correction ();
00039   SI        sub_lo_base (int level);
00040   SI        sub_hi_lim  (int level);
00041   SI        sup_lo_lim  (int level);
00042   SI        sup_lo_base (int level);
00043   SI        sup_hi_lim  (int level);
00044 
00045   int       find_any_child (SI x, SI y, SI delta, SI& delta_out);
00046   int       find_accessible_child (SI x, SI y, SI delta, SI& delta_out);
00047   int       find_child (SI x, SI y, SI delta, bool force);
00048   path      find_box_path (SI x, SI y, SI delta, bool force);
00049   path      find_tree_path (path bp);
00050   cursor    find_cursor (path bp);
00051   selection find_selection (path lbp, path rbp);
00052 
00053   tree      action (tree t, SI x, SI y, SI delta);
00054   void      loci (SI x, SI y, SI delta, list<string>& ids, rectangles& rs);
00055   SI        get_leaf_offset (string search);
00056 
00057   box       transform (frame fr);
00058   gr_selections graphical_select (SI x, SI y, SI dist);
00059   gr_selections graphical_select (SI x1, SI y1, SI x2, SI y2);
00060 };
00061 
00062 concat_box_rep::operator tree () {
00063   int i, n= N(bs);
00064   tree t (TUPLE, n+1);
00065   t[0]= "concat";
00066   for (i=0; i<n; i++) t[i+1]= (tree) bs[i];
00067   return t;
00068 }
00069 
00070 /******************************************************************************
00071 * Routines for concatenation boxes
00072 ******************************************************************************/
00073 
00074 void
00075 concat_box_rep::position (array<SI> spc) {
00076   int i;
00077   ASSERT (N(bs) != 0, "concat of zero boxes");
00078   x1 = bs[0]->x1;
00079   x2 = 0;
00080   for (i=0; i<N(bs); i++) {
00081     x2 += spc[i];
00082     sx(i)= x2;
00083     sy(i)= 0;
00084     x2 += bs[i]->x2;
00085   }
00086   composite_box_rep::position ();
00087 }
00088 
00089 concat_box_rep::concat_box_rep (path ip, array<box> bs2, array<SI> spc):
00090   composite_box_rep (ip)
00091 {
00092   bs = bs2;
00093   position (spc);
00094   finalize ();
00095 }
00096 
00097 void
00098 concat_box_rep::finalize () {
00099   path old_ip= ip;
00100   ip= decorate_middle (ip);
00101   composite_box_rep::finalize ();
00102   ip= old_ip;
00103 }
00104 
00105 bool
00106 concat_box_rep::access_allowed () {
00107   return false;
00108 }
00109 
00110 box
00111 concat_box_rep::transform (frame fr) {
00112   return composite_box_rep::transform (fr);
00113 }
00114 
00115 void
00116 concat_box_rep::clear_incomplete (
00117   rectangles& rs, SI pixel, int i, int i1, int i2)
00118 {
00119   (void) pixel; (void) i;
00120   if (i1 < i2) {
00121     // cout << "Concat " << i << " ( " << i1 << " - " << i2 << " )\n";
00122     // cout << "  in : " << rs << "\n";
00123 
00124     SI left = sx4 (i1);
00125     SI right= sx3 (i2);
00126     bool lbusy= (i+i) >= (i1+i2);
00127     bool rbusy= (i+i) <= (i1+i2);
00128     rectangles new_rs;
00129     rectangles mid_rs;
00130     rectangles count= rs;
00131     while (!is_nil (count)) {
00132       rectangle& r= count->item;
00133       if ((lbusy && (r->x1 < left)) || (rbusy && (r->x2 > right))) new_rs << r;
00134       else mid_rs << r;
00135       count= count->next;
00136     }
00137     rs= new_rs;
00138     if (!is_nil (mid_rs)) rs= rs * least_upper_bound (mid_rs);
00139 
00140     // cout << "  out: " << rs << "\n\n";
00141   }
00142 }
00143 
00144 /******************************************************************************
00145 * Layout routines
00146 ******************************************************************************/
00147 
00148 int
00149 concat_box_rep::get_first () {
00150   int i=0, n=N(bs);
00151   while ((i<n) && (sx2(i)<=x1)) i++;
00152   return i;
00153 }
00154 
00155 int
00156 concat_box_rep::get_last () {
00157   int n=N(bs), i=n-1;
00158   while ((i>=0) && (sx1(i)>=x2)) i--;
00159   return i;
00160 }
00161 
00162 double
00163 concat_box_rep::left_slope () {
00164   int i= get_first ();
00165   if (i<N(bs)) return bs[i]->left_slope ();
00166   return 0.0;
00167 }
00168 
00169 double
00170 concat_box_rep::right_slope () {
00171   int i= get_last ();
00172   if (i>=0) return bs[i]->right_slope ();
00173   return 0.0;
00174 }
00175 
00176 SI
00177 concat_box_rep::left_correction () {
00178   int i= get_first ();
00179   if (i<N(bs)) return bs[i]->left_correction ();
00180   return 0;
00181 }
00182 
00183 SI
00184 concat_box_rep::right_correction () {
00185   int i= get_last ();
00186   if (i>=0) return bs[i]->right_correction ();
00187   return 0;
00188 }
00189 
00190 SI
00191 concat_box_rep::lsub_correction () {
00192   int i= get_first ();
00193   if (i<N(bs)) return bs[i]->lsub_correction ();
00194   return 0;
00195 }
00196 
00197 SI
00198 concat_box_rep::lsup_correction () {
00199   int i= get_first ();
00200   if (i<N(bs)) return bs[i]->lsup_correction ();
00201   return 0;
00202 }
00203 
00204 SI
00205 concat_box_rep::rsub_correction () {
00206   int i= get_last ();
00207   if (i>=0) return bs[i]->rsub_correction ();
00208   return 0;
00209 }
00210 
00211 SI
00212 concat_box_rep::rsup_correction () {
00213   int i= get_last ();
00214   if (i>=0) return bs[i]->rsup_correction ();
00215   return 0;
00216 }
00217 
00218 SI
00219 concat_box_rep::sub_lo_base (int level) {
00220   int i=0, n=N(bs);
00221   SI  y=y1;
00222   for (i=0; i<n; i++)
00223     y= min (y, bs[i]->sub_lo_base (level));
00224   return y;
00225 }
00226 
00227 SI
00228 concat_box_rep::sub_hi_lim  (int level) {
00229   int i=0, n=N(bs);
00230   SI  y= y1 + (y2-y1)/4;
00231   for (i=0; i<n; i++)
00232     y= max (y, bs[i]->sub_hi_lim (level));
00233   return y;
00234 }
00235 
00236 SI
00237 concat_box_rep::sup_lo_lim  (int level) {
00238   int i=0, n=N(bs);
00239   SI  y=y2 - (y2-y1)/4;
00240   for (i=0; i<n; i++)
00241     y= min (y, bs[i]->sup_lo_lim (level));
00242   return y;
00243 }
00244 
00245 SI
00246 concat_box_rep::sup_lo_base (int level) {
00247   int i=0, n=N(bs);
00248   SI  y=y2 - (y2-y1)/4;
00249   for (i=0; i<n; i++)
00250     y= min (y, bs[i]->sup_lo_base (level));
00251   return y;
00252 }
00253 
00254 SI
00255 concat_box_rep::sup_hi_lim  (int level) {
00256   int i=0, n=N(bs);
00257   SI  y=y2;
00258   for (i=0; i<n; i++)
00259     y= max (y, bs[i]->sup_hi_lim (level));
00260   return y;
00261 }
00262 
00263 /******************************************************************************
00264 * Cursor routines
00265 ******************************************************************************/
00266 
00267 int
00268 concat_box_rep::count_left (int i) {
00269   int n;
00270   for (n=1; (i+n<N(bs)) && (i+n>0); n++)
00271     if (sx1(i+n) > sx1(i)) return n;
00272   return n;
00273 }
00274 
00275 int
00276 concat_box_rep::count_right (int i) {
00277   int n;
00278   for (n=1; (i-n<N(bs)) && (i-n>0); n++)
00279     if (sx2(i) > sx2(i-n)) return n;
00280   return n;
00281 }
00282 
00283 int
00284 concat_box_rep::find_any_child (SI x, SI y, SI delta, SI& delta_out) {
00285   (void) y;
00286   int i, n;
00287   bool flag;
00288   delta_out= delta;
00289 
00290   SI x_1= sx2(N(bs)-1);
00291   if (x >= x_1) {
00292     n= count_right (N(bs)-1);
00293     if ((delta >= 0) || (x > x_1)) i=N(bs)-1; else i=N(bs)+delta;
00294     if ((N(bs)-1)-i<n) {
00295       delta_out= ((i==N(bs)-1)? delta: 0);
00296       return i;
00297     }
00298     delta_out= delta+ (n-1);
00299     return N(bs)-n;
00300   }
00301 
00302   for (i=0; i<N(bs); i++) {
00303     SI x_i= sx1(i);
00304     if ((x < x_i) || ((x == x_i) && (delta < 0))) return i;
00305 
00306     n= count_left (i);
00307     if (x == sx1(i)) {
00308       // if ((i>0) && (sx2(i-1) < x))
00309       //   return i;
00310       if (delta<0) return i-1; // i can not be zero here
00311       if (delta<n) {
00312        delta_out= 0;
00313        return i + delta;
00314       }
00315       delta_out= delta- (n-1);
00316       return i + (n-1);
00317     }
00318 
00319     i += n-1;
00320     if (i+1 == N(bs)) flag=true;
00321     else {
00322       int ex1= x- sx2(i);
00323       int ex2= sx1(i+1)- x;
00324       flag= ((ex2>ex1+1) || ((ex2>=ex1) && (delta<0)));
00325     }
00326     if (flag) return i;
00327   }
00328 
00329   return -1;
00330 }
00331 
00332 int
00333 concat_box_rep::find_accessible_child (SI x, SI y, SI delta, SI& delta_out) {
00334   int i= find_any_child (x, y, delta, delta_out);
00335 
00336   if (bs[i]->decoration ()) {
00337     int j, k, n= N(bs);
00338     for (j=i-1; j>=0; j--)
00339       if (bs[j]->accessible ()) break;
00340     for (k=i+1; k< n; k++)
00341       if (bs[k]->accessible ()) break;
00342     if ((j< 0) && (k>=n)) return -1;
00343     if ((j>=0) && (k>=n)) return j;
00344     if ((j< 0) && (k< n)) return k;
00345     SI m= (sx2(j) + sx1(k)) >> 1;
00346     if (sx2(j) == m) return i <= ((j+k)>>1)? j: k;
00347     if ((x<m) || ((x==m) && (delta<0))) return j;
00348     return k;
00349   }
00350 
00351   return i;
00352 }
00353 
00354 int
00355 concat_box_rep::find_child (SI x, SI y, SI delta, bool force) {
00356   int delta_out;
00357   if (force) return find_any_child (x, y, delta, delta_out);
00358   else return find_accessible_child (x, y, delta, delta_out);
00359 }
00360 
00361 path
00362 concat_box_rep::find_box_path (SI x, SI y, SI delta, bool force) {
00363   int delta_out, m;
00364   if (force) m= find_any_child (x, y, delta, delta_out);
00365   else m= find_accessible_child (x, y, delta, delta_out);
00366   if (m==-1) return box_rep::find_box_path (x, y, delta, force);
00367   else {
00368     SI xx= x- sx(m), yy= y- sy(m);
00369     SI dd= delta_out + get_delta (xx, bs[m]->x1, bs[m]->x2);
00370     return path (m, bs[m]->find_box_path (xx, yy, dd, force));
00371   }
00372 }
00373 
00374 path
00375 concat_box_rep::find_tree_path (path bp) {
00376   if (is_atom (bp)) {
00377     if (bp->item == 0) {
00378       if (is_accessible (lip)) return reverse (lip);
00379       else return reverse (descend_decode (lip, 0));
00380     }
00381     else {
00382       if (is_accessible (rip)) return reverse (rip);
00383       else return reverse (descend_decode (rip, 1));
00384     }
00385   }
00386   else return composite_box_rep::find_tree_path (bp);
00387 }
00388 
00389 cursor
00390 concat_box_rep::find_cursor (path bp) {
00391   if (is_atom (bp)) return box_rep::find_cursor (bp);
00392   else {
00393     int i= bp->item, j, n;
00394     cursor cu= bs[i]->find_cursor (bp->next);
00395     cu->delta -= get_delta (cu->ox, bs[i]->x1, bs[i]->x2);
00396     cu->ox    += sx(i);
00397     cu->oy    += sy(i);
00398 
00399     SI x_1= sx2(N(bs)-1);
00400     if (cu->ox >= x_1) {
00401       n= count_right (N(bs)-1);
00402       if ((i==N(bs)-1) || (cu->ox > x_1));
00403       else if (i==N(bs)-n) cu->delta -= n-1;
00404       else cu->delta= i-N(bs);
00405       return cu;
00406     }
00407 
00408     if (cu->ox == sx1(i)) {
00409       // for (j=0; j<i; j++) if (sx1(j) >= sx1 (i)) break;
00410       for (j=i; j>0; j--) if (sx1(j) > sx1 (j-1)) break;
00411       n= count_left (j);
00412       if ((i==j) || (cu->ox != sx1(j)));
00413       else if (i==j+(n-1)) cu->delta += n-1;
00414       else cu->delta= i-j;
00415     }
00416 
00417     return cu;
00418   }
00419 }
00420 
00421 selection
00422 concat_box_rep::find_selection (path lbp, path rbp) {
00423   if ((N(bs) == 0) ||
00424       ((!is_atom (lbp)) && (!is_atom (rbp)) && (lbp->item == rbp->item)))
00425     return composite_box_rep::find_selection (lbp, rbp);
00426 
00427   int  i;
00428   int  i1  = is_atom (lbp)? 0      : lbp->item;
00429   int  i2  = is_atom (rbp)? N(bs)-1: rbp->item;
00430   path lbp1= is_atom (lbp)? path (i1, bs[i1]->find_left_box_path ()) : lbp;
00431   path rbp1= path (i1, bs[i1]->find_right_box_path ());
00432   path lbp2= path (i2, bs[i2]->find_left_box_path ());
00433   path rbp2= is_atom (rbp)? path (i2, bs[i2]->find_right_box_path ()): rbp;
00434 
00435   /*
00436   cout << "Find selection " << lbp << " --- " << rbp << "\n"
00437        << "     in concat " << box (this) << "\n";
00438   cout << "  i1  =" << i1 << "\n";
00439   cout << "  i2  =" << i2 << "\n";
00440   cout << "  lbp1=" << lbp1 << "\n";
00441   cout << "  rbp1=" << rbp1 << "\n";
00442   cout << "  lbp2=" << lbp2 << "\n";
00443   cout << "  rbp2=" << rbp2 << "\n";
00444   */
00445 
00446   if (i1 == i2) {
00447     path lp= find_tree_path (lbp);
00448     path rp= find_tree_path (rbp);
00449     return selection (find_selection (lbp1, rbp2)->rs, lp, rp);
00450   }
00451   else {
00452     selection sel1= find_selection (lbp1, rbp1);
00453     selection sel2= find_selection (lbp2, rbp2);
00454     path lp= sel1->start;
00455     path rp= sel2->end;
00456     rectangles rs; rs << sel1->rs << sel2->rs;
00457     for (i=i1+1; i<i2; i++) {
00458       path lbpi= path (i, bs[i]->find_left_box_path ());
00459       path rbpi= path (i, bs[i]->find_right_box_path ());
00460       rs << find_selection (lbpi, rbpi)->rs;
00461     }
00462     if (is_nil (rs)) return selection (rectangles (), lp, rp);
00463     rectangle r= least_upper_bound (rs);
00464     return selection (r, lp, rp);
00465   }
00466 }
00467 
00468 tree
00469 concat_box_rep::action (tree t, SI x, SI y, SI delta) {
00470   int delta_out, m= find_any_child (x, y, delta, delta_out);
00471   if (m == -1) return "";
00472   SI xx= x- sx(m), yy= y- sy(m);
00473   SI dd= delta_out + get_delta (xx, bs[m]->x1, bs[m]->x2);
00474   return bs[m]->action (t, xx, yy, dd);
00475 }
00476 
00477 void
00478 concat_box_rep::loci (SI x, SI y, SI delta,
00479                     list<string>& ids, rectangles& rs)
00480 {
00481   int delta_out, m= find_any_child (x, y, delta, delta_out);
00482   if (m == -1) box_rep::loci (x, y, delta, ids, rs);
00483   else {
00484     SI xx= x- sx(m), yy= y- sy(m);
00485     SI dd= delta_out + get_delta (xx, bs[m]->x1, bs[m]->x2);
00486     bs[m]->loci (xx, yy, dd, ids, rs);
00487     rs= translate (rs, sx(m), sy(m));
00488   }
00489 }
00490 
00491 SI
00492 concat_box_rep::get_leaf_offset (string search) {
00493   int i, n=N(bs);
00494   for (i=0; i<n; i++) {
00495     SI offset= bs[i]->get_leaf_offset (search);
00496     if (offset != bs[i]->w()) return sx1(i) + offset;
00497   }
00498   return w();
00499 }
00500 
00501 gr_selections
00502 concat_box_rep::graphical_select (SI x, SI y, SI dist) {
00503   gr_selections res;
00504   int i, n= subnr();
00505   for (i=n-1; i>=0; i--)
00506     res << bs[i]->graphical_select (x- sx(i), y- sy(i), dist);
00507   return res;
00508 }
00509 
00510 gr_selections
00511 concat_box_rep::graphical_select (SI x1, SI y1, SI x2, SI y2) {
00512   gr_selections res;
00513   int i, n= subnr();
00514   for (i=n-1; i>=0; i--)
00515     res << bs[i]->graphical_select (x1- sx(i), y1- sy(i),
00516                                     x2- sx(i), y2- sy(i));
00517   return res;
00518 }
00519 
00520 /******************************************************************************
00521 * Phrase boxes
00522 ******************************************************************************/
00523 
00524 class phrase_box_rep: public concat_box_rep {
00525 public:
00526   rectangles* logs_ptr;
00527   SI          ox, oy;
00528   phrase_box_rep (path ip, array<box> bs, array<SI> spc);
00529   ~phrase_box_rep ();
00530   void position_at (SI x, SI y, rectangles& change_log_ptr);
00531   void display (renderer ren);
00532 };
00533 
00534 phrase_box_rep::phrase_box_rep (path ip, array<box> bs, array<SI> spc):
00535   concat_box_rep (ip, bs, spc), logs_ptr (NULL) {}
00536 
00537 phrase_box_rep::~phrase_box_rep () {
00538   if (logs_ptr != NULL) {
00539     rectangles& logs= *logs_ptr;
00540     logs= rectangles (rectangle (ox+x3, oy+y3, ox+x4, oy+y4), logs);
00541     logs= rectangles (rectangle (0, 0, 0, 0), logs);
00542     // cout << "  8=X " << rectangle (ox+x3, oy+y3, ox+x4, oy+y4) << "\n";
00543   }
00544 }
00545 
00546 void
00547 phrase_box_rep::position_at (SI x, SI y, rectangles& logs) {
00548   x += x0; y += y0;
00549   if (logs_ptr == NULL) logs= rectangles (rectangle (0, 0, 0, 0), logs);
00550   else logs= rectangles (rectangle (ox+x3, oy+y3, ox+x4, oy+y4), logs);
00551   ox= x; oy= y;
00552   logs= rectangles (rectangle (ox+x3, oy+y3, ox+x4, oy+y4), logs);
00553   logs_ptr= &logs;
00554 }
00555 
00556 void
00557 phrase_box_rep::display (renderer ren) {
00558   ren->apply_shadow (x1, y1, x2, y2);
00559 }
00560 
00561 /******************************************************************************
00562 * box construction routines
00563 ******************************************************************************/
00564 
00565 box
00566 concat_box (path ip, array<box> bs, array<SI> spc) {
00567   return tm_new<concat_box_rep> (ip, bs, spc);
00568 }
00569 
00570 box
00571 phrase_box (path ip, array<box> bs, array<SI> spc) {
00572   return tm_new<phrase_box_rep> (ip, bs, spc);
00573 }