Back to index

texmacs  1.0.7.15
stack_boxes.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : stack.cpp
00004 * DESCRIPTION: Boxes stacked one above another
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 stack_box representation
00016 ******************************************************************************/
00017 
00018 struct stack_box_rep: public composite_box_rep {
00019   stack_box_rep (path ip, array<box> bs, array<SI> spc); 
00020   int get_type () { return STACK_BOX; }
00021   operator tree () {
00022     int i, n= N(bs);
00023     tree t (TUPLE, "stack");
00024     for (i=0; i<n; i++) t << ((tree) bs[i]);
00025     return t;
00026   }
00027 
00028   void      position (array<SI> spc);
00029   void      finalize ();
00030   void      display (renderer ren);
00031   void      clear_incomplete (rectangles& rs, SI pixel, int i, int i1, int i2);
00032   bool      access_allowed ();
00033 
00034   int       find_child (SI x, SI y, SI delta, bool force);
00035   path      find_tree_path (path bp);
00036   cursor    find_cursor (path bp);
00037   selection find_selection (path lbp, path rbp);
00038   gr_selections graphical_select (SI x1, SI y1, SI x2, SI y2);
00039 };
00040 
00041 /******************************************************************************
00042 * Stack boxes
00043 ******************************************************************************/
00044 
00045 void
00046 stack_box_rep::position (array<SI> spc) {
00047   int i;
00048   y1 = y2 = 0;
00049   for (i=0; i<N(bs); i++) {
00050     sx(i)= 0;
00051     sy(i)= y1- bs[i]->y2;
00052     y1 -= (bs[i]->h()+ spc[i]);
00053   }
00054   composite_box_rep::position ();
00055 }
00056 
00057 stack_box_rep::stack_box_rep (path ip, array<box> bs2, array<SI> spc):
00058   composite_box_rep (ip)
00059 {
00060   bs= bs2;
00061   if (N(bs) != 0)
00062     position (spc);
00063   finalize ();
00064 }
00065 
00066 void
00067 stack_box_rep::finalize () {
00068   path old_ip= ip;
00069   ip= decorate_middle (ip);
00070   composite_box_rep::finalize ();
00071   ip= old_ip;
00072 }
00073 
00074 void
00075 stack_box_rep::display (renderer ren) {
00076   ren->apply_shadow (x1, y1, x2, y2);
00077 }
00078 
00079 bool
00080 stack_box_rep::access_allowed () {
00081   return false;
00082 }
00083 
00084 void
00085 stack_box_rep::clear_incomplete (
00086   rectangles& rs, SI pixel, int which, int i1, int i2)
00087 {
00088   if (N(bs) == 0) return;
00089   if ((i1 <= i2) && (!is_nil (rs))) {
00090     //cout << "Stack " << which << " ( " << i1 << " - " << i2 << " )" << LF;
00091     //cout << "  in: " << (rs/256) << LF;
00092     
00093     int i, n= N(bs);
00094     rectangle bound= least_upper_bound (rs);
00095     SI left = bound->x1, right= bound->x2;
00096     for (i=0; i<n; i++) {
00097       left = min (left , sx3 (i));
00098       right= max (right, sx4 (i));
00099     }
00100     if ((which >= 0) && (which < n)) {
00101       rectangle& r= access_last (rs);
00102       if (r->x2 >= sx4 (which)) r->x2= right;
00103     }
00104 
00105     /*
00106     SI Min_y= min_y, Max_y= max_y;
00107     if (i2+1<n) Min_y= sy4 (i2+1) + 2*pixel;
00108     if (i1  >0) Max_y= sy3 (i1-1) - 2*pixel;
00109     // cout << "  ys : " << Min_y/256 << ", " << min_y/256 << ", " << max_y/256 << ", " << Max_y/256 << "\n";
00110     */
00111 
00112     SI min_y= sy4 (i2) + 2*pixel, max_y= sy3 (i1) - 2*pixel;
00113     if ((min_y < max_y) && (bound->y1 < min_y) && (max_y < bound->y2)) {
00114       rectangles new_rs;
00115       rectangles count= rs;
00116       while (!is_nil (count)) {
00117        rectangle& r= count->item;
00118        if ((r->y1 <= min_y) || (r->y2 >= max_y))
00119          new_rs= rectangles (r, new_rs);
00120        count= count->next;
00121       }
00122       new_rs= rectangles (rectangle (left, min_y, right, max_y), new_rs);
00123       rs= reverse (new_rs);
00124     }
00125 
00126     // cout << "  out: " << (rs/256) << "\n\n";
00127   }
00128 }
00129 
00130 /******************************************************************************
00131 * Cursor routines
00132 ******************************************************************************/
00133 
00134 int
00135 stack_box_rep::find_child (SI x, SI y, SI delta, bool force) {
00136   int i, h, n=N(bs);
00137   if (n==0) return -1;
00138   else if (n<4) i=0;
00139   else {
00140     i= h= n>>1;
00141     while (h != 0) {
00142       SI yhi= sy1(i);
00143       SI ylo= sy2(i+1);
00144       if (h==1) h= 0;
00145       else h= (h+1) >> 1;
00146       if ((y < yhi) && (y < ylo)) i += h;
00147       else i -= max (h, 1);
00148       if (i < 0  ) i= 0;
00149       if (i > n-2) i= n-2;
00150     }
00151   }
00152 
00153   for (; i<n; i++) {
00154     if (i<n-1) {
00155       box sb1= bs[i];
00156       box sb2= bs[i+1];
00157       SI  yhi= sy1(i);
00158       SI  ylo= sy2(i+1);
00159       // cout << "Test [" << i << "] " << sb1 << ", " << sb2 << "\n";
00160       // cout << "  y  = " << y   << "\n";
00161       // cout << "  yhi= " << yhi << "\n";
00162       // cout << "  ylo= " << ylo << "\n";
00163       if ((y < yhi) && (y < ylo)) continue;
00164       if (ylo <= yhi) {
00165        if (y < ((ylo+yhi) >> 1)) continue;
00166       }
00167       else {
00168        int j;
00169        SI m= ylo, M= yhi;
00170        SI ox1= sx(i), ox2= sx(i+1);
00171        SI oy1= sy(i), oy2= sy(i+1);
00172        while ((N (sb1) == 1) && (N (sb2) == 1)) {
00173          ox1 += sb1->sx(0); ox2 += sb2->sx(0);
00174          oy1 += sb1->sy(0); oy2 += sb2->sy(0);
00175          sb1= sb1[0];
00176          sb2= sb2[0];
00177        }
00178        if ((N(sb1) > 0 && N(sb1[0]) == 0) ||
00179            (N(sb2) > 0 && N(sb2[0]) == 0))
00180          if (y < ((ylo+yhi) >> 1)) continue;
00181        for (j=0; j<N(sb1); j++)
00182          if (!outside (x- ox1- sb1->sx(j), delta, sb1[j]->x1, sb1[j]->x2))
00183            m= min (m, oy1+ sb1->sy1(j));
00184        for (j=0; j<N(sb2); j++)
00185          if (!outside (x- ox2- sb2->sx(j), delta, sb2[j]->x1, sb2[j]->x2))
00186            M= max (M, oy2+ sb2->sy2(j));
00187        if (y < ((m+M) >> 1)) continue;
00188       }
00189     }
00190     // cout << "Done [" << i << "]\n";
00191 
00192     if (bs[i]->decoration () && (!force)) {
00193       int j, k;
00194       for (j=i-1; j>=0; j--)
00195        if (bs[j]->accessible () || force) break;
00196       for (k=i+1; k< n; k++)
00197        if (bs[k]->accessible () || force) break;
00198       if ((j< 0) && (k>=n)) return -1;
00199       if ((j>=0) && (k>=n)) return j;
00200       if ((j< 0) && (k< n)) return k;
00201       if (y >= ((sy1(j) + sy2(k)) >> 1)) return j;
00202       return k;
00203     }
00204 
00205     return i;
00206   }
00207 
00208   return -1;
00209 }
00210 
00211 path
00212 stack_box_rep::find_tree_path (path bp) {
00213   if (is_atom (bp)) {
00214     if (bp->item == 0) {
00215       if (is_accessible (lip)) return reverse (lip);
00216       else return reverse (descend_decode (lip, 0));
00217     }
00218     else {
00219       if (is_accessible (rip)) return reverse (rip);
00220       else return reverse (descend_decode (rip, 1));
00221     }
00222   }
00223   else return composite_box_rep::find_tree_path (bp);
00224 }
00225 
00226 cursor
00227 stack_box_rep::find_cursor (path bp) {
00228   cursor cu= composite_box_rep::find_cursor (bp);
00229   int i= bp->item, j1, j2, n= N(bs);
00230   if (is_atom (bp)) i= (bp == 0? 0: N(bs)-1);
00231   if (bs[i]->h() != 0) return cu;
00232   for (j1= i-1; j1>=0; j1--)
00233     if (bs[j1]->h () != 0) break;
00234   for (j2= i+1; j2<n; j2++)
00235     if (bs[j2]->h () != 0) break;
00236   if (j2 < n) cu->oy += sy (j2) - sy (i);
00237   else if (j1 >= 0) cu->oy += sy (j1) - sy (i);
00238   return cu;
00239 }
00240 
00241 /******************************************************************************
00242 * Selections
00243 ******************************************************************************/
00244 
00245 static rectangles
00246 descend (rectangles l, SI y) {
00247   if (is_nil (l)) return l;
00248   rectangle& r= l->item;
00249   return rectangles (rectangle (r->x1, min (r->y1, y), r->x2, r->y2),
00250                    descend (l->next, y));
00251 }
00252 
00253 static rectangles
00254 ascend (rectangles l, SI y) {
00255   if (is_nil (l)) return l;
00256   rectangle& r= l->item;
00257   return rectangles (rectangle (r->x1, r->y1, r->x2, max (r->y2, y)),
00258                    ascend (l->next, y));
00259 }
00260 
00261 static rectangles
00262 extend_left (rectangles l, SI x) {
00263   if (is_nil (l)) return l;
00264   rectangle& r= l->item;
00265   return rectangles (rectangle (min (r->x1, x), r->y1, r->x2, r->y2),
00266                    extend_left (l->next, x));
00267 }
00268 
00269 static rectangles
00270 extend_right (rectangles l, SI x) {
00271   if (is_nil (l)) return l;
00272   rectangle& r= l->item;
00273   return rectangles (rectangle (r->x1, r->y1, max (r->x2, x), r->y2),
00274                    extend_right (l->next, x));
00275 }
00276 
00277 static rectangles
00278 truncate_top (rectangles l, SI y) {
00279   if (is_nil (l)) return l;
00280   rectangle& r= l->item;
00281   return rectangles (rectangle (r->x1, r->y1, r->x2, min (r->y2, y)),
00282                    truncate_top (l->next, y));
00283 }
00284 
00285 static rectangles
00286 truncate_bottom (rectangles l, SI y) {
00287   if (is_nil (l)) return l;
00288   rectangle& r= l->item;
00289   return rectangles (rectangle (r->x1, max (r->y1, y), r->x2, r->y2),
00290                    truncate_bottom (l->next, y));
00291 }
00292 
00293 selection
00294 stack_box_rep::find_selection (path lbp, path rbp) {
00295   if ((N(bs) == 0) ||
00296       ((!is_atom (lbp)) && (!is_atom (rbp)) && (lbp->item == rbp->item)))
00297     return composite_box_rep::find_selection (lbp, rbp);
00298 
00299   int  i1  = is_atom (lbp)? 0      : lbp->item;
00300   int  i2  = is_atom (rbp)? N(bs)-1: rbp->item;
00301   path lbp1= is_atom (lbp)? path (i1, bs[i1]->find_left_box_path ()) : lbp;
00302   path rbp1= path (i1, bs[i1]->find_right_box_path ());
00303   path lbp2= path (i2, bs[i2]->find_left_box_path ());
00304   path rbp2= is_atom (rbp)? path (i2, bs[i2]->find_right_box_path ()): rbp;
00305 
00306   if (i1 == i2) {
00307     path lp= find_tree_path (lbp);
00308     path rp= find_tree_path (rbp);
00309     return selection (find_selection (lbp1, rbp2)->rs, lp, rp);
00310   }
00311   else if (i1 < i2) {
00312     selection sel1= find_selection (lbp1, rbp1);
00313     selection sel2= find_selection (lbp2, rbp2);
00314     path lp= sel1->start;
00315     path rp= sel2->end;
00316     SI midy1= sy1(i2-1);
00317     SI midy2= sy2(i1+1);
00318     rectangles rs;
00319     if (i2 == i1+1) {
00320       rs << extend_right (sel1->rs, x2);
00321       rs << extend_left  (sel2->rs, x1);
00322       if ((!is_nil (sel1->rs)) && (!is_nil (sel2->rs))) {
00323        rectangle r1= least_upper_bound (sel1->rs);
00324        rectangle r2= least_upper_bound (sel2->rs);
00325        if ((r1->x1 < r2->x2) && (r2->y2 < r1->y1))
00326          rs << rectangle (r1->x1, r2->y2, r2->x2, r1->y1);
00327       }
00328     }
00329     else {
00330       rs << extend_right (descend (sel1->rs, midy2), x2);
00331       rs << extend_left  (ascend  (sel2->rs, midy1), x1);
00332       if (midy1 < midy2) rs << rectangle (x1, midy1, x2, midy2);
00333     }
00334 
00335     /* This hack produces nicer selections in case of a hidden top/bottom */
00336     int j1= i1, j2= i2;
00337     while (j1 < i2 && bs[j1]->h() == 0) j1++;
00338     while (j2 > j1 && bs[j2]->h() == 0) j2--;
00339     if (j1 != i1) rs= truncate_top    (rs, sy2 (j1));
00340     if (j2 != i2) rs= truncate_bottom (rs, sy1 (j2));
00341     /* End hack */
00342 
00343     return selection (rs, lp, rp);
00344   }
00345   else return box_rep::find_selection (lbp, rbp);
00346 }
00347 
00348 gr_selections
00349 stack_box_rep::graphical_select (SI x1, SI y1, SI x2, SI y2) {
00350   gr_selections res;
00351   int i, n= subnr();
00352   for (i=n-1; i>=0; i--)
00353     res << bs[i]->graphical_select (x1- sx(i), y1- sy(i),
00354                                 x2- sx(i), y2- sy(i));
00355   return res;
00356 }
00357 
00358 /******************************************************************************
00359 * box construction routines
00360 ******************************************************************************/
00361 
00362 box
00363 stack_box (path ip, array<box> bs, array<SI> spc) {
00364   return tm_new<stack_box_rep> (ip, bs, spc);
00365 }