Back to index

texmacs  1.0.7.15
concater.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : concater.cpp
00004 * DESCRIPTION: First pass for typesetting paragraphs;
00005 *              an array of line_items is created of the right types.
00006 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00007 *******************************************************************************
00008 * This software falls under the GNU general public license version 3 or later.
00009 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00010 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00011 ******************************************************************************/
00012 
00013 #include "concater.hpp"
00014 #include "analyze.hpp"
00015 #include "file.hpp"
00016 
00017 /******************************************************************************
00018 * Printing items
00019 ******************************************************************************/
00020 
00021 SI italic_correction (box left, box right);
00022 
00023 void
00024 concater_rep::print (box b) {
00025   a << line_item (STD_ITEM, env->mode_op, b, HYPH_INVALID);
00026 }
00027 
00028 void
00029 concater_rep::print (int type, int op_type, box b) {
00030   a << line_item (type, op_type, b, HYPH_INVALID);
00031 }
00032 
00033 void
00034 concater_rep::control (tree t, path ip) {
00035   box b= empty_box (ip, 0, 0, 0, env->fn->yx);
00036   a << line_item (CONTROL_ITEM, OP_SKIP, b, HYPH_INVALID, t);
00037 }
00038 
00039 void
00040 concater_rep::marker (path ip) {
00041   if (is_decoration (ip)) ip= path (0, ip);
00042   string fn_name= "cmr";
00043   int sz= script (env->fn_size, env->index_level);
00044   font gfn (tex_font (fn_name, sz, (int) (env->magn*env->dpi)));
00045   box b= text_box (ip->next, ip->item, "", gfn, blue);
00046   a << line_item (MARKER_ITEM, OP_SKIP, b, HYPH_INVALID);
00047 }
00048 
00049 void
00050 concater_rep::ghost (string s, path ip) {
00051   ghost (s, ip, blue);
00052 }
00053 
00054 void
00055 concater_rep::ghost (string s, path ip, color col) {
00056   if ((N(s)>2) && (s[0]=='<') && (s[N(s)-1]=='>')) {
00057     ghost ("<", ip, col);
00058     ghost (s (1,N(s)-1), ip, col);
00059     ghost (">", ip, col);
00060     return;
00061   }
00062   
00063   string fn_name= "cmr";
00064   if (N(s)==1) {
00065     if (s[0] == '<') { fn_name= "cmsy"; s= "h"; }
00066     else if (s[0] == '>') { fn_name= "cmsy"; s= "i"; }
00067     else if (s[0] == '|') { fn_name= "cmsy"; s= "j"; }
00068     else if (s[0] == '\\') { fn_name= "cmsy"; s= "n"; }
00069     else if (s[0] == '{') { fn_name= "cmsy"; s= "f"; }
00070     else if (s[0] == '}') { fn_name= "cmsy"; s= "g"; }
00071   }
00072   int sz= script (env->fn_size, env->index_level);
00073   font gfn (tex_font (fn_name, sz, (int) (env->magn*env->dpi)));
00074   box b= text_box (decorate (ip), 0, s, gfn, col);
00075   array<box> bs (1);
00076   bs[0]= b;
00077   a << line_item (STD_ITEM, OP_SKIP,
00078                   composite_box (decorate (ip), bs), HYPH_INVALID);
00079 }
00080 
00081 void
00082 concater_rep::flag_ok (string s, path ip, color col) {
00083   path dip = decorate_right (ip);
00084   SI h= 4*env->fn->wfn/5;
00085   int r, g, b, a;
00086   get_rgb_color (col, r, g, b, a);
00087   r= 255- (255 - r)/6;
00088   g= 255- (255 - g)/6;
00089   b= 255- (255 - b)/6;
00090   color light= rgb_color (r, g, b, a);
00091   int info= env->info_level;
00092   if (info == INFO_MINIMAL || info == INFO_SHORT) {
00093     box infob= info_box (dip, h, env->fn->wline, col, light);
00094     box specb= specific_box (ip, infob, false, env->fn);
00095     print (specb);
00096   }
00097   else if (info == INFO_DETAILED || info == INFO_PAPER) {
00098     int sz= script (env->fn_size, env->index_level+2);
00099     font gfn (tex_font ("ecrm", sz, (int) (env->magn*env->dpi)));
00100     box textb= text_box (decorate (ip), 0, s, gfn, col);
00101     box flagb= flag_box (dip, textb, h, env->fn->wline, col, light);
00102     if (info == INFO_DETAILED) {
00103       box specb= specific_box (ip, flagb, false, env->fn);
00104       print (specb);
00105     }
00106     else {
00107       box b= resize_box (ip, flagb, 0, 0, 0, env->fn->yx);
00108       print (b);
00109     }
00110   }
00111 }
00112 
00113 void
00114 concater_rep::flag (string s, path ip, color col) {
00115   if (is_accessible (ip) && (!env->read_only))
00116     flag_ok (s, ip, col);
00117 }
00118 
00119 /******************************************************************************
00120 * Printing spaces, setting penalties and limits
00121 ******************************************************************************/
00122 
00123 void
00124 concater_rep::print (space spc) {
00125   int n= N(a);
00126   if (n==0) return;
00127   a[n-1]->spc= max (spc, a[n-1]->spc);
00128 }
00129 
00130 void
00131 concater_rep::penalty_min (int p) {
00132   if (N(a)>0) a[N(a)-1]->penalty = min (a[N(a)-1]->penalty, p);
00133 }
00134 
00135 void
00136 concater_rep::penalty_max (int p) {
00137   if (N(a)>0) a[N(a)-1]->penalty = max (a[N(a)-1]->penalty, p);
00138 }
00139 
00140 void
00141 concater_rep::with_limits (int status) {
00142   if (env->display_style || (status == LIMITS_ALWAYS))
00143     if (N(a)>0)
00144       a[N(a)-1]->limits = true;
00145 }
00146 
00147 /******************************************************************************
00148 * Typesetting generic objects
00149 ******************************************************************************/
00150 
00151 void
00152 concater_rep::typeset (tree t, path ip) {
00153   // cout << "Typeset " << t << "\n";
00154   // cout << "Typeset " << t << ", " << ip << ", " << obtain_ip (t) << "\n";
00155 
00156   /*
00157   if (obtain_ip (t) != ip)
00158     cout << "TeXmacs] Wrong ip: " << t << "\n"
00159         << "       ] " << obtain_ip (t) << " -> " << ip << "\n";
00160   */
00161 
00162   if (!is_accessible (ip)) {
00163     path ip2= obtain_ip (t);
00164     if (ip2 != path (DETACHED))
00165       ip= ip2;
00166   }
00167 
00168   if (env->hl_lan != 0)
00169     env->lan->highlight (t);
00170 
00171   if (is_atomic (t)) {
00172     if      (env->mode == 1) typeset_text_string (t, ip, 0, N(t->label));
00173     else if (env->mode == 2) typeset_math_string (t, ip, 0, N(t->label));
00174     else if (env->mode == 3) typeset_prog_string (t, ip, 0, N(t->label));
00175     else                     typeset_text_string (t, ip, 0, N(t->label));
00176     return;
00177   }
00178 
00179   switch (L (t)) {
00180   case UNINIT:
00181   case ERROR:
00182     typeset_error (t, ip);
00183     break;
00184   case RAW_DATA:
00185     typeset_inactive (t, ip);
00186     break;
00187   case DOCUMENT:
00188     typeset_document (t, ip);
00189     break;
00190   case PARA:
00191     typeset_paragraph (t, ip);
00192     break;
00193   case SURROUND:
00194     typeset_surround (t, ip);
00195     break;
00196   case CONCAT:
00197     typeset_concat (t, ip);
00198     break;
00199   case RIGID:
00200     typeset_rigid (t, ip);
00201     break;
00202   case HIDDEN:
00203     //(void) env->exec (t);
00204     if (N(t) != 1) typeset_error (t, ip);
00205     else (void) typeset_as_concat (env, t[0], descend (ip, 0));
00206     break;
00207   case FREEZE:
00208     if (N(t) != 1) typeset_error (t, ip);
00209     else typeset (attach_middle (t[0], ip));
00210     //typeset (freeze (t[0]), decorate_middle (ip));
00211     break;
00212   case UNFREEZE:
00213     if (N(t) != 1) typeset_error (t, ip);
00214     else typeset (t[0], descend (ip, 0));
00215     break;
00216   case HSPACE:
00217     t= env->exec (t);
00218     typeset_hspace (t, ip);
00219     break;
00220   case VAR_VSPACE:
00221     flag (env->drd->get_name (L(t)), ip, brown);
00222     t= tree (VAR_VSPACE, env->exec (tree (TMLEN, A(t))));
00223     control (t, ip);
00224     break;
00225   case VSPACE:
00226     flag (env->drd->get_name (L(t)), ip, brown);
00227     t= tree (VSPACE, env->exec (tree (TMLEN, A(t))));
00228     control (t, ip);
00229     break;
00230   case SPACE:
00231     t= env->exec (t);
00232     typeset_space (attach_here (t, ip));
00233     break;
00234   case HTAB:
00235     if (N(t) != 1 && N(t) != 2) { typeset_error (t, ip); break; }
00236     if (N(a)==0) print (empty_box (ip, 0, 0, 0, env->fn->yx));
00237     print (space (env->as_length (t[0])));
00238     control (t, ip);
00239     break;
00240   case MOVE:
00241     typeset_move (t, ip);
00242     break;
00243   case SHIFT:
00244     typeset_shift (t, ip);
00245     break;
00246   case RESIZE:
00247     typeset_resize (t, ip);
00248     break;
00249   case CLIPPED:
00250     typeset_clipped (t, ip);
00251     break;
00252   case REPEAT:
00253     typeset_repeat (t, ip);
00254     break;
00255   case _FLOAT:
00256     typeset_float (t, ip);
00257     break;
00258   case DATOMS:
00259     typeset_formatting (t, ip, ATOM_DECORATIONS);
00260     break;
00261   case DLINES:
00262     typeset_formatting (t, ip, LINE_DECORATIONS);
00263     break;
00264   case DPAGES:
00265     typeset_formatting (t, ip, PAGE_DECORATIONS);
00266     break;
00267   case DBOX:
00268     typeset_decorated_box (t, ip);
00269     break;
00270 
00271   case WITH_LIMITS:
00272     with_limits (LIMITS_DISPLAY);
00273     flag ("with-limits", ip, brown);
00274     control (t, ip);
00275     break;
00276   case LINE_BREAK:
00277     if (N(a)>0) a[N(a)-1]->penalty = 0;   
00278     flag ("line-break", ip, brown);
00279     control (t, ip);
00280     break;
00281   case NEW_LINE:
00282   case NEXT_LINE:
00283     {
00284       string name= env->drd->get_name (L(t));
00285       flag (name, ip, brown);
00286       control (t, ip);
00287       break;
00288     }
00289   case NO_BREAK:
00290     if (N(a)>0) a[N(a)-1]->penalty = HYPH_INVALID;
00291     if ((N(a)>1) &&
00292        (a[N(a)-1]->type == STRING_ITEM) &&
00293        (a[N(a)-1]->b->get_leaf_string () == ""))
00294       a[N(a)-2]->penalty = HYPH_INVALID;  
00295     flag ("no line break", ip, brown);
00296     control (t, ip);
00297     break;
00298   case YES_INDENT:
00299     flag ("yes-first-indent", ip, brown);
00300     control (tuple ("env_par", PAR_FIRST, env->read (PAR_FIRST)), ip);
00301     break;
00302   case NO_INDENT:
00303     flag ("no-first-indent", ip, brown);
00304     control (tuple ("env_par", PAR_FIRST, "0cm"), ip);
00305     break;
00306   case VAR_YES_INDENT:
00307     flag ("yes-first-indent-after", ip, brown);
00308     control (tuple ("env_par", PAR_NO_FIRST, "false"), ip);
00309     break;
00310   case VAR_NO_INDENT:
00311     flag ("no-first-indent-after", ip, brown);
00312     control (tuple ("env_par", PAR_NO_FIRST, "true"), ip);
00313     break;
00314   case VAR_PAGE_BREAK:
00315   case PAGE_BREAK:
00316   case VAR_NO_PAGE_BREAK:
00317   case NO_PAGE_BREAK:
00318   case VAR_NEW_PAGE:
00319   case NEW_PAGE:
00320   case VAR_NEW_DPAGE:
00321   case NEW_DPAGE:
00322     {
00323       string name= env->drd->get_name (L(t));
00324       flag (name, ip, brown);
00325       control (t, ip);
00326       break;
00327     }
00328 
00329   case AROUND:
00330   case VAR_AROUND:
00331   case BIG_AROUND:
00332     typeset_around (t, ip, env->get_string (MATH_NESTING_MODE) != "off");
00333     break;
00334   case LEFT:
00335     typeset_large (t, ip, LEFT_BRACKET_ITEM, OP_OPENING_BRACKET, "<left-");
00336     break;
00337   case MID:
00338     typeset_large (t, ip, MIDDLE_BRACKET_ITEM, OP_MIDDLE_BRACKET, "<mid-");
00339     break;
00340   case RIGHT:
00341     typeset_large (t, ip, RIGHT_BRACKET_ITEM, OP_CLOSING_BRACKET, "<right-");
00342     break;
00343   case BIG:
00344     typeset_bigop (t, ip);
00345     break;
00346   case LONG_ARROW:
00347     typeset_long_arrow (t, ip);
00348     break;
00349   case LPRIME:
00350     typeset_lprime (t, ip);
00351     break;
00352   case RPRIME:
00353     typeset_rprime (t, ip);
00354     break;
00355   case BELOW:
00356     typeset_below (t, ip);
00357     break;
00358   case ABOVE:
00359     typeset_above (t, ip);
00360     break;
00361   case LSUB:
00362   case LSUP:
00363     typeset_script (t, ip, false);
00364     break;
00365   case RSUB:
00366   case RSUP:
00367     typeset_script (t, ip, true);
00368     break;
00369   case FRAC:
00370     typeset_frac (t, ip);
00371     break;
00372   case SQRT:
00373     typeset_sqrt (t, ip);
00374     break;
00375   case WIDE:
00376     typeset_wide (t, ip, true);
00377     break;
00378   case VAR_WIDE:
00379     typeset_wide (t, ip, false);
00380     break;
00381   case NEG:
00382     typeset_neg (t, ip);
00383     break;
00384   case TREE:
00385     typeset_tree (t, ip);
00386     break;
00387   case SYNTAX:
00388     typeset_syntax (t, ip);
00389     break;
00390 
00391   case TFORMAT:
00392     if ((N(t)>0) && is_table (t[N(t)-1])) typeset_table (t, ip);
00393     else typeset_formatting (t, ip, CELL_FORMAT);
00394     break;
00395   case TWITH:
00396   case CWITH:
00397   case TMARKER:
00398     typeset_inactive (t, ip);
00399     break;
00400   case TABLE:
00401     typeset_table (t, ip);
00402     break;
00403   case ROW:
00404   case CELL:
00405   case SUBTABLE:
00406     break;
00407 
00408   case ASSIGN:
00409     typeset_assign (t, ip);
00410     break;
00411   case WITH:
00412     typeset_with (t, ip);
00413     break;
00414   case PROVIDES:
00415     typeset_executable (t, ip);
00416     break;
00417   case QUOTE_VALUE:
00418     typeset_inactive (t, ip);
00419     break;
00420   case VALUE:
00421     typeset_value (t, ip);
00422     break;
00423   case MACRO:
00424     typeset_inactive (t, ip);
00425     break;
00426   case DRD_PROPS:
00427     typeset_drd_props (t, ip);
00428     break;
00429   case ARG:
00430     typeset_argument (t, ip);
00431     break;
00432   case QUOTE_ARG:
00433     typeset_inactive (t, ip);
00434     break;
00435   case COMPOUND:
00436     typeset_compound (t, ip);
00437     break;
00438   case XMACRO:
00439     typeset_inactive (t, ip);
00440     break;
00441   case GET_LABEL:
00442     typeset_executable (t, ip);
00443     break;
00444   case GET_ARITY:
00445     typeset_executable (t, ip);
00446     break;
00447   case MAP_ARGS:
00448     typeset_rewrite (t, ip);
00449     break;
00450   case EVAL_ARGS:
00451     typeset_eval_args (t, ip);
00452     break;
00453   case MARK:
00454     typeset_mark (t, ip);
00455     break;
00456   case EXPAND_AS:
00457     typeset_expand_as (t, ip);
00458     break;
00459   case EVAL:
00460     typeset_eval (t, ip);
00461     break;
00462   case QUOTE:
00463     typeset_inactive (t, ip);
00464     break;
00465   case QUASI:
00466     typeset_eval (tree (EVAL, tree (QUASIQUOTE, t[0])), ip);
00467     break;
00468   case QUASIQUOTE:
00469   case UNQUOTE:
00470   case VAR_UNQUOTE:
00471   case COPY:
00472     typeset_executable (t, ip);
00473     break;
00474   case IF:
00475     typeset_if (t, ip);
00476     break;
00477   case VAR_IF:
00478     typeset_var_if (t, ip);
00479     break;
00480   case CASE:
00481     typeset_case (t, ip);
00482     break;
00483   case WHILE:
00484   case FOR_EACH:
00485     typeset_executable (t, ip);
00486     break;
00487   case EXTERN:
00488     typeset_rewrite (t, ip);
00489     break;
00490   case INCLUDE:
00491     typeset_include (t, ip);
00492     break;
00493   case USE_PACKAGE:
00494   case USE_MODULE:
00495     typeset_executable (t, ip);
00496     break;
00497 
00498   case OR:
00499   case XOR:
00500   case AND:
00501   case NOT:
00502   case PLUS:
00503   case MINUS:
00504   case TIMES:
00505   case OVER:
00506   case DIV:
00507   case MOD:
00508   case MINIMUM:
00509   case MAXIMUM:
00510   case MATH_SQRT:
00511   case EXP:
00512   case LOG:
00513   case POW:
00514   case COS:
00515   case SIN:
00516   case TAN:
00517   case MERGE:
00518   case LENGTH:
00519     typeset_executable (t, ip);
00520     break;
00521   case RANGE:
00522     typeset_range (t, ip);
00523     break;
00524   case NUMBER:
00525   case _DATE:
00526   case TRANSLATE:
00527   case CHANGE_CASE:
00528   case FIND_FILE:
00529   case IS_TUPLE:
00530   case LOOK_UP:
00531   case EQUAL:
00532   case UNEQUAL:
00533   case LESS:
00534   case LESSEQ:
00535   case GREATER:
00536   case GREATEREQ:
00537   case BOX_INFO:
00538   case FRAME_DIRECT:
00539   case FRAME_INVERSE:
00540     typeset_executable (t, ip);
00541     break;
00542 
00543   case CM_LENGTH:
00544   case MM_LENGTH:
00545   case IN_LENGTH:
00546   case PT_LENGTH:
00547   case BP_LENGTH:
00548   case DD_LENGTH:
00549   case PC_LENGTH:
00550   case CC_LENGTH:
00551   case FS_LENGTH:
00552   case FBS_LENGTH:
00553   case EM_LENGTH:
00554   case LN_LENGTH:
00555   case SEP_LENGTH:
00556   case YFRAC_LENGTH:
00557   case EX_LENGTH:
00558   case FN_LENGTH:
00559   case FNS_LENGTH:
00560   case BLS_LENGTH:
00561   case SPC_LENGTH:
00562   case XSPC_LENGTH:
00563   case PAR_LENGTH:
00564   case PAG_LENGTH:
00565   case GW_LENGTH:
00566   case GH_LENGTH:
00567   case TMPT_LENGTH:
00568   case PX_LENGTH:
00569     typeset_executable (t, ip);
00570     break;
00571 
00572   case STYLE_ONLY:
00573   case VAR_STYLE_ONLY:
00574   case ACTIVE:
00575   case VAR_ACTIVE:
00576   case INACTIVE:
00577   case VAR_INACTIVE:
00578     typeset_compound (t, ip);
00579     break;
00580   case REWRITE_INACTIVE:
00581     typeset_rewrite (t, ip);
00582     break;
00583   case INLINE_TAG:
00584   case OPEN_TAG:
00585   case MIDDLE_TAG:
00586   case CLOSE_TAG:
00587     typeset_src_tag (t, ip);
00588     break;
00589   case SYMBOL:
00590   case LATEX:
00591   case HYBRID:
00592     typeset_inactive (t, ip);
00593     break;
00594 
00595   case LOCUS:
00596     typeset_locus (t, ip);
00597     break;
00598   case ID:
00599     typeset_inactive (t, ip);
00600     break;
00601   case HARD_ID:
00602     typeset_executable (t, ip);
00603     break;
00604   case LINK:
00605   case URL:
00606   case SCRIPT:
00607     typeset_inactive (t, ip);
00608     break;
00609   case HLINK:
00610   case ACTION:
00611     typeset_compound (t, ip);
00612     break;
00613   case SET_BINDING:
00614     typeset_set_binding (t, ip);
00615     break;
00616   case GET_BINDING:
00617     typeset_executable (t, ip);
00618     break;
00619   case LABEL:
00620   case REFERENCE:
00621   case PAGEREF:
00622     typeset_compound (t, ip);
00623     break;
00624   case WRITE:
00625     typeset_write (t, ip);
00626     break;
00627 
00628   case TUPLE:
00629   case ATTR:
00630   case TMLEN:
00631   case COLLECTION:
00632   case ASSOCIATE:
00633   case BACKUP:
00634     typeset_inactive (t, ip);
00635     break;
00636   case PATTERN:
00637   case GRADIENT:
00638     marker (descend (ip, 0));
00639     typeset_inactive (env->exec (t), decorate (ip));
00640     marker (descend (ip, 1));
00641     break;
00642   case SPECIFIC:
00643     typeset_specific (t, ip);
00644     break;
00645   case FLAG:
00646     typeset_flag (t, ip);
00647     break;
00648 
00649   case ANIM_COMPOSE:
00650     typeset_anim_compose (t, ip);
00651     break;
00652   case ANIM_REPEAT:
00653     typeset_anim_repeat (t, ip);
00654     break;
00655   case ANIM_CONSTANT:
00656     typeset_anim_constant (t, ip);
00657     break;
00658   case ANIM_TRANSLATE:
00659     typeset_anim_translate (t, ip);
00660     break;
00661   case ANIM_PROGRESSIVE:
00662     typeset_anim_progressive (t, ip);
00663     break;
00664   case VIDEO:
00665     typeset_video (t, ip);
00666     break;
00667   case SOUND:
00668     typeset_sound (t, ip);
00669     break;
00670 
00671   case GRAPHICS:
00672     typeset_graphics (t, ip);
00673     break;
00674   case SUPERPOSE:
00675     typeset_superpose (t, ip);
00676     break;
00677   case GR_GROUP:
00678     typeset_gr_group (t, ip);
00679     break;
00680   case GR_LINEAR_TRANSFORM:
00681     typeset_gr_linear_transform (t, ip);
00682     break;
00683   case TEXT_AT:
00684     typeset_text_at (t, ip);
00685     break;
00686   case MATH_AT:
00687     typeset_math_at (t, ip);
00688     break;
00689   case _POINT:
00690     typeset_point (t, ip);
00691     break;
00692   case LINE:
00693     typeset_line (t, ip, false);
00694     break;
00695   case CLINE:
00696     typeset_line (t, ip, true);
00697     break;
00698   case ARC:
00699     typeset_arc (t, ip, false);
00700     break;
00701   case CARC:
00702     typeset_arc (t, ip, true);
00703     break;
00704   case SPLINE:
00705     typeset_spline (t, ip, false);
00706     break;
00707   case VAR_SPLINE:
00708     typeset_var_spline (t, ip);
00709     break;
00710   case CSPLINE:
00711     typeset_cspline (t, ip);
00712     break;
00713   case FILL:
00714     typeset_fill (t, ip);
00715     break;
00716   case IMAGE:
00717     typeset_image (t, ip);
00718     break;
00719 
00720   case CANVAS:
00721     typeset_canvas (t, ip);
00722     break;
00723   case ORNAMENT:
00724     typeset_ornament (t, ip);
00725     break;
00726 
00727   default:
00728     if (L(t) < START_EXTENSIONS) print (test_box (ip));
00729     else typeset_compound (t, ip);
00730     break;
00731   }
00732 }
00733 
00734 /******************************************************************************
00735 * User interface
00736 ******************************************************************************/
00737 
00738 concater_rep::concater_rep (edit_env env2, bool rigid2):
00739   env (env2), rigid (rigid2) {}
00740 
00741 array<line_item>
00742 typeset_concat (edit_env env, tree t, path ip) {
00743   concater ccc= tm_new<concater_rep> (env);
00744   ccc->typeset (t, ip);
00745   ccc->finish ();
00746   array<line_item> a= ccc->a;
00747   tm_delete (ccc);
00748   return a;
00749 }
00750 
00751 array<line_item>
00752 typeset_marker (edit_env env, path ip) {
00753   concater ccc= tm_new<concater_rep> (env);
00754   ccc->marker (ip);
00755   array<line_item> a= ccc->a;
00756   tm_delete (ccc);
00757   return a;
00758 }
00759 
00760 box
00761 typeset_as_concat (edit_env env, tree t, path ip) {
00762   concater ccc= tm_new<concater_rep> (env, true);
00763   ccc->typeset (t, ip);
00764   ccc->finish ();
00765   array<line_item> a= ccc->a;
00766 
00767   int i, n=N(a);
00768   if (n == 0) return empty_box (ip); // FIXME: n=0 should never happen
00769   array<box> items (n);
00770   array<SI>  spc (n);
00771   if (n>0) {
00772     spc[0]=0;
00773     for (i=0; i<n-1; i++) {
00774       items[i]  = a[i]->b;
00775       spc  [i+1]= a[i]->spc->def;
00776     }
00777     items[i]= a[i]->b;
00778   }
00779   box b= concat_box (ip, items, spc);
00780 
00781   tm_delete (ccc);
00782   return b;
00783 }
00784 
00785 box
00786 typeset_as_box (edit_env env, tree t, path ip) {
00787   box b= typeset_as_concat (env, t, ip);
00788 
00789   SI ox= 0;
00790   int i, n=N(b);
00791   for (i=0; i<n; i++)
00792     if (b[i]->w() != 0)
00793       ox= b[i]->x1;
00794 
00795   array<box> bs (1);
00796   array<SI>  xs (1);
00797   array<SI>  ys (1);
00798   bs[0]= b;
00799   xs[0]= ox;
00800   ys[0]= 0;
00801   return composite_box (ip, bs, xs, ys);
00802 }
00803 
00804 bool build_locus (edit_env env, tree t, list<string>& ids, string& col, string &ref, string &anchor);
00805 bool build_locus (edit_env env, tree t, list<string>& ids, string& col);
00806 
00807 box
00808 typeset_as_atomic (edit_env env, tree t, path ip) {
00809   if (is_func (t, WITH)) {
00810     int i, n= N(t), k= (n-1)>>1; // is k=0 allowed ?
00811     if ((n&1) != 1) return empty_box (ip);
00812 
00813     STACK_NEW_ARRAY(vars,string,k);
00814     STACK_NEW_ARRAY(oldv,tree,k);
00815     STACK_NEW_ARRAY(newv,tree,k);
00816     for (i=0; i<k; i++) {
00817       tree var_t= env->exec (t[i<<1]);
00818       if (is_atomic (var_t)) {
00819        string var= var_t->label;
00820        vars[i]= var;
00821        oldv[i]= env->read (var);
00822        newv[i]= env->exec (t[(i<<1)+1]);
00823       }
00824       else {
00825        STACK_DELETE_ARRAY(vars);
00826        STACK_DELETE_ARRAY(oldv);
00827        STACK_DELETE_ARRAY(newv);
00828        return empty_box (ip);
00829       }
00830     }
00831 
00832     // for (i=0; i<k; i++) env->monitored_write_update (vars[i], newv[i]);
00833     for (i=0; i<k; i++) env->write_update (vars[i], newv[i]);
00834     box b= typeset_as_atomic (env, t[n-1], descend (ip, n-1));
00835     for (i=k-1; i>=0; i--) env->write_update (vars[i], oldv[i]);
00836     STACK_DELETE_ARRAY(vars);
00837     STACK_DELETE_ARRAY(oldv);
00838     STACK_DELETE_ARRAY(newv);
00839     return b;
00840   }
00841   else if (is_func (t, LOCUS) && N(t) != 0) {
00842     string ref;
00843     string anchor;
00844     int last= N(t)-1;
00845     list<string> ids;
00846     string col;
00847     (void) build_locus (env, t, ids, col, ref, anchor);
00848     tree old= env->local_begin (COLOR, col);
00849     box b= typeset_as_atomic (env, t[last], descend (ip, last));
00850     env->local_end (COLOR, old);
00851     return b;
00852   }
00853   else {
00854     array<line_item> a= typeset_concat (env, t, ip);
00855     if (N(a) == 1) return a[0]->b;
00856 
00857     int i, n=N(a);
00858     if (n == 0) return empty_box (ip); // FIXME: n=0 should never happen
00859     array<box> items (n);
00860     array<SI>  spc (n);
00861     if (n>0) {
00862       spc[0]=0;
00863       for (i=0; i<n-1; i++) {
00864        items[i]  = a[i]->b;
00865        spc  [i+1]= a[i]->spc->def;
00866       }
00867       items[i]= a[i]->b;
00868     }
00869     return concat_box (ip, items, spc);
00870   }
00871 }
00872 
00873 tree
00874 box_info (edit_env env, tree t, string what) {
00875   box b= typeset_as_atomic (env, attach_here (t, decorate ()));
00876 
00877   tree r= tuple();
00878   for (int i=0; i<N(what); i++) {
00879     switch (what[i]) {
00880     case 'l': r << as_string (b->x1); break;
00881     case 'b': r << as_string (b->y1); break;
00882     case 'r': r << as_string (b->x2); break;
00883     case 't': r << as_string (b->y2); break;
00884     case 'w': r << as_string (b->x2 - b->x1); break;
00885     case 'h': r << as_string (b->y2 - b->y1); break;
00886     case 'L': r << as_string (b->x3); break;
00887     case 'B': r << as_string (b->y3); break;
00888     case 'R': r << as_string (b->x4); break;
00889     case 'T': r << as_string (b->y4); break;
00890     case 'W': r << as_string (b->x4 - b->x3); break;
00891     case 'H': r << as_string (b->y4 - b->y3); break;
00892     case '.':
00893       if (N(r)==1) return as_string (r[0]) * "tmpt";
00894       else if (N(r)==0) return tree (ERROR, "No query for box-info");
00895       else return tree (ERROR, "More than one query for box-info");
00896     }
00897   }
00898   return r;
00899 }