Back to index

texmacs  1.0.7.15
concat_text.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : concat_text.cpp
00004 * DESCRIPTION: Typesetting textual markup
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 "concater.hpp"
00013 #include "formatter.hpp"
00014 #include "analyze.hpp"
00015 
00016 lazy make_lazy_vstream (edit_env env, tree t, path ip, tree channel);
00017 
00018 /******************************************************************************
00019 * Typesetting strings
00020 ******************************************************************************/
00021 
00022 void
00023 concater_rep::typeset_substring (string s, path ip, int pos) {
00024   box b= text_box (ip, pos, s, env->fn, env->col);
00025   a << line_item (STRING_ITEM, OP_TEXT, b, HYPH_INVALID, env->lan);
00026 }
00027 
00028 void
00029 concater_rep::typeset_math_substring (string s, path ip, int pos, int otype) {
00030   box b= text_box (ip, pos, s, env->fn, env->col);
00031   a << line_item (STRING_ITEM, otype, b, HYPH_INVALID, env->lan);
00032 }
00033 
00034 void
00035 concater_rep::typeset_colored_substring
00036   (string s, path ip, int pos, string col)
00037 {
00038   color c= (col == ""? env->col: named_color (col));
00039   if (env->alpha != 255) {
00040     int r, g, b, a;
00041     get_rgb_color (c, r, g, b, a);
00042     c= rgb_color (r, g, b, env->alpha);
00043   }
00044   box b= text_box (ip, pos, s, env->fn, c);
00045   a << line_item (STRING_ITEM, OP_TEXT, b, HYPH_INVALID, env->lan);
00046 }
00047 
00048 #define PRINT_SPACE(spc_type) \
00049   switch (spc_type) { \
00050   case SPC_NONE: \
00051     break; \
00052   case SPC_SPACE: \
00053     print (spc); \
00054     break; \
00055   case SPC_DSPACE: \
00056     print (space (spc->min << 1, spc->def << 1, spc->max << 1)); \
00057     break; \
00058   case SPC_PERIOD: \
00059     print (spc+ extra); \
00060     break; \
00061   case SPC_TINY: \
00062     print (space (spc->min>>2, spc->def>>2, spc->max>>2)); \
00063     break; \
00064   case SPC_HALF: \
00065     print (space (spc->min>>1, spc->def>>2, spc->max>>1)); \
00066     break; \
00067   case SPC_OPERATOR: \
00068     print (space (spc->min>>1, spc->def>>1, spc->max)); \
00069     break; \
00070   case SPC_BIGOP: \
00071     break; \
00072   }
00073 
00074 #define PRINT_CONDENSED_SPACE(spc_type) \
00075   switch (spc_type) { \
00076   case SPC_NONE: \
00077     break; \
00078   case SPC_SPACE: \
00079     print (spc); \
00080     break; \
00081   case SPC_PERIOD: \
00082     print (spc+ extra); \
00083     break; \
00084   case SPC_TINY: \
00085     print (space (spc->min>>4, spc->def>>4, spc->max>>4)); \
00086     break; \
00087   case SPC_HALF: \
00088     print (space (spc->min>>3, spc->def>>4, spc->max>>3)); \
00089     break; \
00090   case SPC_OPERATOR: \
00091     print (space (spc->min>>3, spc->def>>3, spc->max>>2)); \
00092     break; \
00093   case SPC_BIGOP: \
00094     print (space (spc->min>>2, spc->def>>2, spc->max>>2)); \
00095     break; \
00096   }
00097 
00098 void
00099 concater_rep::typeset_text_string (tree t, path ip, int pos, int end) {
00100   string s= t->label;
00101   int    start;
00102   space  spc= env->fn->spc;
00103   space  extra= env->fn->extra;
00104 
00105   do {
00106     start= pos;
00107     text_property tp= env->lan->advance (t, pos);
00108     if (pos > end) pos= end;
00109     if ((pos > start) && (s[start] == ' ')) { // spaces
00110       if (start == 0) typeset_substring ("", ip, 0);
00111       penalty_min (tp->pen_after);
00112       PRINT_SPACE (tp->spc_before);
00113       PRINT_SPACE (tp->spc_after);
00114       if ((pos==end) || (s[pos]==' '))
00115        typeset_substring ("", ip, pos);
00116     }
00117     else { // strings
00118       penalty_max (tp->pen_before);
00119       PRINT_SPACE (tp->spc_before)
00120       typeset_substring (s (start, pos), ip, start);
00121       penalty_min (tp->pen_after);
00122       PRINT_SPACE (tp->spc_after)
00123     }
00124   } while (pos<end);
00125 }
00126 
00127 void
00128 concater_rep::typeset_math_string (tree t, path ip, int pos, int end) {
00129   string s= t->label;
00130   int    start;
00131   space  spc= env->fn->spc;
00132   space  extra= env->fn->extra;
00133   bool   condensed= env->math_condensed;
00134 
00135   do {
00136     start= pos;
00137     text_property tp= env->lan->advance (t, pos);
00138     int k= N(a);
00139     while (k > 0 && a[k-1]->op_type == OP_SKIP) k--;
00140     int prev_op_type= (k == 0? OP_TEXT: a[k-1]->op_type);
00141     int succ_status= succession_status (prev_op_type, tp->op_type);
00142     //cout << "Succession [" << s (start, pos) << "] "
00143     //     << "(" << prev_op_type << ", " << tp->op_type << ")"
00144     //     << " -> " << succ_status << "\n";
00145     if ((succ_status & 1) != 0 && k > 0) a[k-1]->spc= space (0);
00146     bool spc_ok= (succ_status <= 1);
00147     if (pos > end) pos= end;
00148     if ((pos > start) && (s[start]==' ')) { // spaces
00149       if (start == 0) typeset_substring ("", ip, 0);
00150       penalty_max (HYPH_INVALID);
00151       //penalty_min (tp->pen_after);
00152       if (spc_ok) {
00153         PRINT_SPACE (tp->spc_before);
00154         PRINT_SPACE (tp->spc_after);
00155       }
00156       //if ((pos==end) || (s[pos]==' '))
00157       typeset_math_substring ("", ip, pos, OP_APPLY);
00158     }
00159     else { // strings
00160       penalty_max (tp->pen_before);
00161       if (spc_ok) {
00162         if (condensed) PRINT_CONDENSED_SPACE (tp->spc_before)
00163         else PRINT_SPACE (tp->spc_before)
00164       }
00165       if (pos > start && s[start] == '*' && env->info_level >= INFO_SHORT) {
00166         color c = rgb_color (160, 160, 255);
00167         box   tb= text_box (decorate (ip), 0, "<cdot>", env->fn, c);
00168         box   sb= specific_box (decorate (ip), tb, false, env->fn);
00169         box   mb= move_box (decorate (ip), sb, -tb->w()>>1, 0);
00170         box   rb= resize_box (decorate (ip), mb, 0, tb->y1, 0, tb->y2);
00171         a << line_item (STD_ITEM, OP_SKIP, rb, HYPH_INVALID);
00172       }
00173       typeset_math_substring (s (start, pos), ip, start, tp->op_type);
00174       penalty_min (tp->pen_after);
00175       if (tp->limits != LIMITS_NONE) with_limits (tp->limits);
00176       if (spc_ok) {
00177         if (condensed) PRINT_CONDENSED_SPACE (tp->spc_after)
00178         else PRINT_SPACE (tp->spc_after)
00179       }
00180     }
00181   } while (pos<end);
00182 }
00183 
00184 void
00185 concater_rep::typeset_prog_string (tree t, path ip, int pos, int end) {
00186   string s= t->label;
00187   int    start;
00188   space  spc= env->fn->spc;
00189   space  extra= env->fn->extra;
00190 
00191   do {
00192     start= pos;
00193     text_property tp= env->lan->advance (t, pos);
00194     if (pos > end) pos= end;
00195     if ((pos>start) && (s[start]==' ')) { // spaces
00196       if (start == 0) typeset_substring ("", ip, 0);
00197       penalty_min (tp->pen_after);
00198       PRINT_SPACE (tp->spc_before);
00199       PRINT_SPACE (tp->spc_after);
00200       if ((pos==end) || (s[pos]==' '))
00201        typeset_substring ("", ip, pos);
00202     }
00203     else { // strings
00204       penalty_max (tp->pen_before);
00205       PRINT_SPACE (tp->spc_before)
00206       typeset_colored_substring (s (start, pos), ip, start,
00207                              env->lan->get_color (t, start, pos));
00208       penalty_min (tp->pen_after);
00209       PRINT_SPACE (tp->spc_after)
00210     }
00211   } while (pos<end);
00212 }
00213 
00214 /******************************************************************************
00215 * Typesetting errors, documents and concatenations
00216 ******************************************************************************/
00217 
00218 void
00219 concater_rep::typeset_paragraph (tree t, path ip) {
00220   print (::typeset_as_paragraph (env, t[0], descend (ip, 0)));
00221 }
00222 
00223 void
00224 concater_rep::typeset_document (tree t, path ip) {
00225   print (::typeset_as_stack (env, t, ip));
00226 }
00227 
00228 void
00229 concater_rep::typeset_surround (tree t, path ip) {
00230   if (N(t) != 3) { typeset_error (t, ip); return; }
00231   marker (descend (ip, 0));
00232   typeset (t[0], descend (ip, 0));
00233   array<line_item> b= ::typeset_concat (env, t[1], descend (ip, 1));
00234   typeset (t[2], descend (ip, 2));
00235   a << b;
00236   marker (descend (ip, 1));
00237 }
00238 
00239 void
00240 concater_rep::typeset_concat (tree t, path ip) {
00241   int i, n= N(t);
00242   for (i=0; i<n; i++)
00243     typeset (t[i], descend (ip, i));
00244 }
00245 
00246 void
00247 concater_rep::typeset_rigid (tree t, path ip) {
00248   if (N(t) != 1) { typeset_error (t, ip); return; }
00249   box b= typeset_as_concat (env, t[0], descend (ip, 0));
00250   print (move_box (ip, b, 0, 0, true));
00251 }
00252 
00253 void
00254 concater_rep::typeset_syntax (tree t, path ip) {
00255   if (N(t) != 2) { typeset_error (t, ip); return; }
00256   box b= typeset_as_concat (env, t[0], descend (ip, 0));
00257   b= move_box (ip, b, 0, 0, true);
00258   if (is_atomic (t[1]) && tm_string_length (t[1]->label) == 1) {
00259     space  spc= env->fn->spc;
00260     space  extra= env->fn->extra;
00261     bool   condensed= env->math_condensed;
00262     int    pos= 0;
00263     string s= t[1]->label;
00264     text_property tp= env->lan->advance (s, pos);
00265     int k= N(a);
00266     while (k > 0 && a[k-1]->op_type == OP_SKIP) k--;
00267     int prev_op_type= (k == 0? OP_TEXT: a[k-1]->op_type);
00268     int succ_status= succession_status (prev_op_type, tp->op_type);
00269     if ((succ_status & 1) != 0 && k > 0) a[k-1]->spc= space (0);
00270     bool spc_ok= (succ_status <= 1);
00271     penalty_max (tp->pen_before);
00272     if (spc_ok) {
00273       if (condensed) PRINT_CONDENSED_SPACE (tp->spc_before)
00274       else PRINT_SPACE (tp->spc_before)
00275     }
00276     print (STD_ITEM, tp->op_type, b);
00277     penalty_min (tp->pen_after);
00278     if (tp->limits != LIMITS_NONE) with_limits (tp->limits);
00279     if (spc_ok) {
00280       if (condensed) PRINT_CONDENSED_SPACE (tp->spc_after)
00281       else PRINT_SPACE (tp->spc_after)
00282     }
00283   }
00284   else print (b);
00285 }
00286 
00287 /******************************************************************************
00288 * Typesetting space
00289 ******************************************************************************/
00290 
00291 void
00292 concater_rep::typeset_hspace (tree t, path ip) {
00293   if (N(t) != 1 && N(t) != 3) { typeset_error (t, ip); return; }
00294   if (N(a)==0) print (empty_box (ip, 0, 0, 0, env->fn->yx));
00295   if (N(t)==1) print (env->as_hspace (t[0]));
00296   else print (space (env->as_length (t[0]),
00297                      env->as_length (t[1]),
00298                      env->as_length (t[2])));
00299   control (t, ip);
00300 }
00301 
00302 void
00303 concater_rep::typeset_space (tree t, path ip) {
00304   if (N(t) != 1 && N(t) != 3) { typeset_error (t, ip); return; }
00305   SI w = env->as_length (t[0]);
00306   SI y1= 0;
00307   SI y2= env->fn->yx;
00308   if (N(t)==3) {
00309     y1= env->as_length (t[1]);
00310     y2= env->as_length (t[2]);
00311   }
00312   print (empty_box (ip, 0, y1, w, y2));
00313 }
00314 
00315 /******************************************************************************
00316 * Moving and resizing
00317 ******************************************************************************/
00318 
00319 void
00320 concater_rep::typeset_move (tree t, path ip) {
00321   if (N(t) != 3) { typeset_error (t, ip); return; }
00322   box  b  = typeset_as_concat (env, t[0], descend (ip, 0));
00323   tree old= env->local_begin_extents (b);
00324   SI   x  = (t[1] == ""? 0: env->as_length (env->exec (t[1]), "w"));
00325   SI   y  = (t[2] == ""? 0: env->as_length (env->exec (t[2]), "h"));
00326   env->local_end_extents (old);
00327   print (move_box (ip, b, x, y, true));
00328 }
00329 
00330 void
00331 concater_rep::typeset_shift (tree t, path ip) {
00332   if (N(t) != 3) { typeset_error (t, ip); return; }
00333   box  b  = typeset_as_concat (env, t[0], descend (ip, 0));
00334   tree old= env->local_begin_extents (b);
00335   SI   x  = (t[1] == ""? 0: env->as_length (env->exec (t[1]), "w"));
00336   SI   y  = (t[2] == ""? 0: env->as_length (env->exec (t[2]), "h"));
00337   env->local_end_extents (old);
00338   print (shift_box (ip, b, x, y, true));
00339 }
00340 
00341 void
00342 concater_rep::typeset_resize (tree t, path ip) {
00343   if (N(t) != 5) { typeset_error (t, ip); return; }
00344   box  b = typeset_as_concat (env, t[0], descend (ip, 0));
00345   tree old= env->local_begin_extents (b);
00346   SI   x1 = (t[1] == ""? b->x1: env->as_length (env->exec (t[1]), "w"));
00347   SI   y1 = (t[2] == ""? b->y1: env->as_length (env->exec (t[2]), "h"));
00348   SI   x2 = (t[3] == ""? b->x2: env->as_length (env->exec (t[3]), "w"));
00349   SI   y2 = (t[4] == ""? b->y2: env->as_length (env->exec (t[4]), "h"));
00350   env->local_end_extents (old);
00351   print (resize_box (ip, b, x1, y1, x2, y2, true, true));
00352 }
00353 
00354 void
00355 concater_rep::typeset_clipped (tree t, path ip) {
00356   if (N(t) != 5) { typeset_error (t, ip); return; }
00357   box  b = typeset_as_concat (env, t[0], descend (ip, 0));
00358   tree old= env->local_begin_extents (b);
00359   SI   x1 = (t[1] == ""? b->x1: env->as_length (env->exec (t[1]), "w"));
00360   SI   y1 = (t[2] == ""? b->y1: env->as_length (env->exec (t[2]), "h"));
00361   SI   x2 = (t[3] == ""? b->x2: env->as_length (env->exec (t[3]), "w"));
00362   SI   y2 = (t[4] == ""? b->y2: env->as_length (env->exec (t[4]), "h"));
00363   env->local_end_extents (old);
00364   print (clip_box (ip, b, x1, y1, x2, y2));
00365 }
00366 
00367 /******************************************************************************
00368 * Floating objects
00369 ******************************************************************************/
00370 
00371 void
00372 concater_rep::typeset_float (tree t, path ip) {
00373   if (N(t) != 3) { typeset_error (t, ip); return; }
00374   tree t1= env->exec (t[0]);
00375   tree t2= env->exec (t[1]);
00376   tree ch= tuple (t1, t2);
00377   lazy lz= make_lazy_vstream (env, t[2], descend (ip, 2), ch);
00378   marker (descend (ip, 0));
00379   if (is_accessible (ip) && !env->read_only)
00380     flag_ok (as_string (t1), decorate_middle (ip), brown);
00381   print (FLOAT_ITEM, OP_SKIP, control_box (decorate_middle (ip), lz, env->fn));
00382   marker (descend (ip, 1));
00383 }
00384 
00385 /******************************************************************************
00386 * Repetition of boxes inside other boxes
00387 ******************************************************************************/
00388 
00389 void
00390 concater_rep::typeset_repeat (tree t, path ip) {
00391   if (N(t) != 2) { typeset_error (t, ip); return; }
00392   box b1  = typeset_as_concat (env, t[0], descend (ip, 0));
00393   box b2  = typeset_as_concat (env, t[1], descend (ip, 1));
00394   SI  xoff= env->get_length (XOFF_DECORATIONS);
00395   print (repeat_box (ip, b1, b2, xoff));
00396 }
00397 
00398 /******************************************************************************
00399 * Formatting information and decorations
00400 ******************************************************************************/
00401 
00402 void
00403 concater_rep::typeset_formatting (tree t, path ip, string v) {
00404   if (N(t) == 0) { typeset_error (t, ip); return; }
00405   if (rigid && v == ATOM_DECORATIONS) {
00406     int k, n=N(t);
00407     box b= typeset_as_concat (env, t[n-1], descend (ip, n-1));
00408     tree e (DBOX);
00409     for (k=n-2; k>=0; k--)
00410       if (is_func (t[k], MACRO, 2))
00411         e= tree (COMPOUND, t[k], e);
00412     if (e != tree (DBOX)) {
00413       env->decorated_boxes << b;
00414       box bb= typeset_as_concat (env, attach_middle (e, ip));
00415       env->decorated_boxes->resize (N (env->decorated_boxes) - 1);
00416       b= bb;
00417     }
00418     marker (descend (ip, 0));
00419     print (b);
00420     marker (descend (ip, 1));
00421   }
00422   else {
00423     int n= N(t);
00424     tree new_format= env->read (v) * t (0, n-1);
00425     tree old_format= env->local_begin (v, new_format);
00426     if (v != CELL_FORMAT) {
00427       marker (descend (ip, 0));
00428       control (t (0, N(t)-1), decorate (ip));
00429     }
00430     typeset (t[n-1], descend (ip, n-1));
00431     if (v != CELL_FORMAT) {
00432       control (tree (L(t)), decorate (ip));
00433       marker (descend (ip, 1));
00434     }
00435     env->local_end (v, old_format);
00436   }
00437 }
00438 
00439 void
00440 concater_rep::typeset_decorated_box (tree t, path ip) {
00441   (void) t; (void) ip;
00442   int n= N (env->decorated_boxes);
00443   if ((n > 0) && (!is_nil (env->decorated_boxes [n-1]))) {
00444     print (env->decorated_boxes [n-1]);
00445     env->decorated_boxes [n-1]= box ();
00446   }
00447 }