TLatex.cxx

Go to the documentation of this file.
00001 // @(#)root/graf:$Id: TLatex.cxx 35703 2010-09-24 09:22:02Z couet $
00002 // Author: Nicolas Brun, Olivier Couet, Oleksandr Grebenyuk
00003 
00004 /*************************************************************************
00005  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
00006  * All rights reserved.                                                  *
00007  *                                                                       *
00008  * For the licensing terms see $ROOTSYS/LICENSE.                         *
00009  * For the list of contributors see $ROOTSYS/README/CREDITS.             *
00010  *************************************************************************/
00011 
00012 #include "Riostream.h"
00013 #include "TROOT.h"
00014 #include "TClass.h"
00015 #include "TLatex.h"
00016 #include "TMath.h"
00017 #include "TVirtualPad.h"
00018 #include "TVirtualPS.h"
00019 
00020 #ifdef R__SUNCCBUG
00021 const Double_t kPI = 3.14159265358979323846;
00022 #else
00023 const Double_t kPI = TMath::Pi();
00024 #endif
00025 const Int_t kLatex      = BIT(10);
00026 const Int_t kPrintingPS = BIT(11); //set in TPad.h
00027 
00028 ClassImp(TLatex)
00029 
00030 
00031 //______________________________________________________________________________
00032 /* Begin_Html
00033 <center><h2>TLatex : to draw Mathematical Formula</h2></center>
00034 
00035 TLatex's purpose is to write mathematical equations.
00036 The syntax is very similar to Latex's.
00037 It provides several functionalities:
00038 <ul>
00039 <li><a href="#L1">  Subscripts and Superscripts</a></li>
00040 <li><a href="#L2">  Fractions</a></li>
00041 <li><a href="#L3">  Splitting Lines</a></li>
00042 <li><a href="#L4">  Roots</a></li>
00043 <li><a href="#L5">  Mathematical Symbols</a></li>
00044 <li><a href="#L6">  Delimiters</a></li>
00045 <li><a href="#L7">  Greek Letters</a></li>
00046 <li><a href="#L8">  Accents</a></li>
00047 <li><a href="#L9">  Changing Style</a></li>
00048 <li><a href="#L10"> Alignment Rules</a></li>
00049 <li><a href="#L11"> Character Adjustement</a></li>
00050 <li><a href="#L12"> Italic and Boldface</a></li>
00051 <li><a href="#L13"> Examples</a></li>
00052 </ul>
00053 
00054 When the font precision (see <tt>TAttText</tt>) is low (0 or 1), TLatex is
00055 painted as a normal TText, the control characters are not interpreted.
00056 
00057 <a name="L1"></a><h3>Subscripts and Superscripts</h3>
00058 Subscripts and superscripts are made with the <tt>_</tt> and <tt>^</tt>
00059 commands. These commands can be combined to make complicated subscript and
00060 superscript expressions. You may adjust the display of subscripts and
00061 superscripts by using the two functions <tt>SetIndiceSize(Double_t)</tt>,
00062 which set relative size of subscripts and superscripts, and
00063 <tt>SetLimitIndiceSize(Int_t)</tt>, which set limits for text resizing of
00064 subscipts and superscripts.
00065 <p>Examples:
00066 End_Html
00067    x^{2y} :    Begin_Latex x^{2y}    End_Latex x_{2y} :    Begin_Latex x^{2y}    End_Latex
00068    x^{y^{2}} : Begin_Latex x^{y^{2}} End_Latex x^{y_{1}} : Begin_Latex x^{y_{1}} End_Latex
00069    x^{y}_{1} : Begin_Latex x^{y}_{1} End_Latex x_{1}^{y} : Begin_Latex x_{1}^{y} End_Latex
00070 
00071 Begin_Html
00072 The subscripts and superscripts operators apply not only on one character but
00073 on all the "normal text" preceding them. In the following example the second
00074 <tt>E</tt> is lower than the first one because the operator <tt>_</tt> is
00075 applied on <tt>/f</tt> which has a descending part, and not only on <tt>f</tt>
00076 which as no descending part.
00077 End_Html
00078    f_{E}/f_{E} : Begin_Latex f_{E}/f_{E} End_Latex
00079 
00080 Begin_Html
00081    To make sure the second operator <tt>_</tt> applies only on <tt>f</tt>
00082    a dummy operator <tt>^{}</tt> should be introduced to separate the <tt>f</tt>
00083    from the <tt>/</tt>.
00084 End_Html
00085    f_{E}/^{}f_{E} : Begin_Latex f_{E}/^{}f_{E} End_Latex
00086 
00087 Begin_Html
00088 <a name="L2"></a><h3>Fractions</h3>
00089 Fractions denoted by the <tt>/</tt> symbol are made in the obvious way.
00090 The <tt>#frac</tt> command is used for large fractions in displayed formula;
00091 it has two arguments: the numerator and the denominator.
00092 <p>Examples:
00093 End_Html
00094    x = #frac{y+z/2}{y^{2}+1} : Begin_Latex x = #frac{y+z/2}{y^{2}+1} End_Latex
00095 
00096 Begin_Html
00097 <a name="L3"></a><h3>Splitting Lines</h3>
00098 Text can be split in two lines via the command <tt>#splitline</tt>.
00099 <p>Examples:
00100 End_Html
00101    #splitline{21 April 2003}{14:02:30} : Begin_Latex #splitline{21 April 2003}{14:02:30} End_Latex
00102 
00103 Begin_Html
00104 <a name="L4"></a><h3>Roots</h3>
00105 The <tt>#sqrt</tt> command produces the square root of its argument; it has
00106 an optional first argument for other roots.
00107 <p>Examples:
00108 End_Html
00109    #sqrt{10} : Begin_Latex #sqrt{10} End_Latex #sqrt[3]{10} : Begin_Latex #sqrt[3]{10} End_Latex
00110 
00111 Begin_Html
00112 <a name="L5"></a><h3>Mathematical Symbols</h3>
00113 TLatex can display dozens of special mathematical symbols. A few of them, such
00114 as <tt>+</tt> and <tt>></tt> , are produced by typing the corresponding
00115 keyboard character. Others are obtained with the commands in the following
00116 table:
00117 End_Html
00118 Begin_Macro(source)
00119 mathsymbols.C
00120 End_Macro
00121 
00122 Begin_Html
00123 <a name="L6"></a><h3>Delimiters</h3>
00124 TLatex provides 4 kinds of proportional delimiters:
00125 <pre>
00126    #[]{....} or "a la" Latex #left[.....#right] : big square brackets
00127    #{}{....} or              #left{.....#right} : big curly brackets
00128    #||{....} or              #left|.....#right| : big absolute value symbols
00129    #(){....} or              #left(.....#right) : big parentheses
00130 </pre>
00131 
00132 <a name="L7"></a><h3>Greek Letters</h3>
00133 The command to produce a lowercase Greek letter is obtained by adding a
00134 <tt>#</tt> to the name of the letter. For an uppercase Greek letter, just
00135 capitalize the first letter of the command name. Some letters have two
00136 representations. The name of the second one (the "variation") starts with "var".
00137 The following table gives the complete list:
00138 End_Html
00139 Begin_Macro(source)
00140 greekletters.C
00141 End_Macro
00142 
00143 Begin_Html
00144 <a name="L8"></a><h3>Accents</h3>
00145 Several kind of accents are available:
00146 End_Html
00147    #hat    = Begin_Latex #hat{a} End_Latex
00148    #check  = Begin_Latex #check{a} End_Latex
00149    #acute  = Begin_Latex #acute{a} End_Latex
00150    #grave  = Begin_Latex #grave{a} End_Latex
00151    #dot    = Begin_Latex #dot{a} End_Latex
00152    #ddot   = Begin_Latex #ddot{a} End_Latex
00153    #tilde  = Begin_Latex #tilde{a} End_Latex
00154 
00155 Begin_Html
00156 The special sign: <tt>#slash</tt> draws a slash on top of the text between brackets:
00157 End_Html
00158    #slash{E}_{T} : Begin_Latex #slash{E}_{T} End_Latex
00159 
00160 Begin_Html
00161 Bar and vectors sign are done the following way:
00162 End_Html
00163    #bar{a}: Begin_Latex #bar{a} End_Latex
00164    #vec{a}: Begin_Latex #vec{a} End_Latex
00165 
00166 Begin_Html
00167 <a name="L9"></a><h3>Changing Style</h3>
00168 One can change the font, the text color, or the text size at any time using :
00169 <tt>#font[font-number]{...}</tt>, <tt>#color[color-number]{...}</tt>
00170 and <tt>#scale[scale-factor]{...}</tt>
00171 <p>Examples:
00172 End_Html
00173    #font[12]{Times Italic} and #font[22]{Times bold} : Begin_Latex #font[12]{Times Italic} and #font[22]{Times bold} End_Latex
00174    #color[2]{Red} and #color[4]{Blue} : Begin_Latex #color[2]{Red} and #color[4]{Blue} End_Latex
00175    #scale[1.2]{Bigger} and #scale[0.8]{Smaller} : Begin_Latex #scale[1.2]{Bigger} and #scale[0.8]{Smaller} End_Latex
00176 
00177 Begin_Html
00178 <a name="L10"></a><h3>Alignment Rules</h3>
00179 The <tt>TText</tt> alignment rules apply to the <tt>TLatex</tt> objects with one exception
00180 concerning the vertical alignment:
00181 <ul>
00182 <li> if the vertical alignment = 1 , subscripts are not taken into account </li>
00183 <li> if the vertical alignment = 0 , the text is aligned to the box surrounding
00184                                      the full text with sub and superscripts</li>
00185 </ul>
00186 This is illustrated by the following example:
00187 End_Html
00188 Begin_Macro(source)
00189 {
00190    TCanvas Tlva("Tlva","Tlva",500,500);
00191    Tlva.SetGrid();
00192    Tlva.DrawFrame(0,0,1,1);
00193    const char *longstring = "K_{S}... K^{*0}... #frac{2s}{#pi#alpha^{2}}
00194    #frac{d#sigma}{dcos#theta} (e^{+}e^{-} #rightarrow f#bar{f} ) =
00195    #left| #frac{1}{1 - #Delta#alpha} #right|^{2} (1+cos^{2}#theta)";
00196 
00197    TLatex latex;
00198    latex.SetTextSize(0.025);
00199    latex.SetTextAlign(13);  //align at top
00200    latex.DrawLatex(.2,.9,"K_{S}");
00201    latex.DrawLatex(.3,.9,"K^{*0}");
00202    latex.DrawLatex(.2,.8,longstring);
00203 
00204    latex.SetTextAlign(12);  //centered
00205    latex.DrawLatex(.2,.6,"K_{S}");
00206    latex.DrawLatex(.3,.6,"K^{*0}");
00207    latex.DrawLatex(.2,.5,longstring);
00208 
00209    latex.SetTextAlign(11);  //default bottom alignment
00210    latex.DrawLatex(.2,.4,"K_{S}");
00211    latex.DrawLatex(.3,.4,"K^{*0}");
00212    latex.DrawLatex(.2,.3,longstring);
00213 
00214    latex.SetTextAlign(10);  //special bottom alignment
00215    latex.DrawLatex(.2,.2,"K_{S}");
00216    latex.DrawLatex(.3,.2,"K^{*0}");
00217    latex.DrawLatex(.2,.1,longstring);
00218 
00219    latex.SetTextAlign(12);
00220    latex->SetTextFont(72);
00221    latex->DrawLatex(.1,.80,"13");
00222    latex->DrawLatex(.1,.55,"12");
00223    latex->DrawLatex(.1,.35,"11");
00224    latex->DrawLatex(.1,.18,"10");
00225    return Tlva;
00226 }
00227 End_Macro
00228 
00229 Begin_Html
00230 <a name="L11"></a><h3>Character Adjustement</h3>
00231 The two commands <tt>#kern</tt> and <tt>#lower</tt> enable a better control
00232 over character placement. The command <tt>#kern[(Float_t)dx]{text}</tt> moves
00233 the output string horizontally by the fraction <tt>dx</tt> of its length.
00234 Similarly, <tt>#lower[(Float_t)dy]{text}</tt> shifts the text up or down by
00235 the fraction <tt>dy</tt> of its height.
00236 <p>Examples:
00237 End_Html
00238 Positive k#kern[0.3]{e}#kern[0.3]{r}#kern[0.3]{n}#kern[0.3]{i}#kern[0.3]{n}#kern[0.3]{g}:
00239 Begin_Latex Positive k#kern[0.3]{e}#kern[0.3]{r}#kern[0.3]{n}#kern[0.3]{i}#kern[0.3]{n}#kern[0.3]{g} End_Latex
00240 
00241 Negative k#kern[-0.3]{e}#kern[-0.3]{r}#kern[-0.3]{n}#kern[-0.3]{i}#kern[-0.3]{n}#kern[-0.3]{g}:
00242 Begin_Latex Negative k#kern[-0.3]{e}#kern[-0.3]{r}#kern[-0.3]{n}#kern[-0.3]{i}#kern[-0.3]{n}#kern[-0.3]{g} End_Latex
00243 
00244 Vertical a#lower[0.2]{d}#lower[0.4]{j}#lower[0.1]{u}#lower[-0.1]{s}#lower[-0.3]{t}#lower[-0.4]{m}#lower[-0.2]{e}#lower[0.1]{n}t:
00245 Begin_Latex Vertical a#lower[0.2]{d}#lower[0.4]{j}#lower[0.1]{u}#lower[-0.1]{s}#lower[-0.3]{t}#lower[-0.4]{m}#lower[-0.2]{e}#lower[0.1]{n}t End_Latex
00246 
00247 Begin_Html
00248 <a name="L12"></a><h3>Italic and Boldface</h3>
00249 Text can be turned italic or boldface using the commands
00250 <tt>#it</tt> and <tt>#bf</tt>.
00251 <p>Examples:
00252 End_Html
00253 #bf{bold}, #it{italic}, #bf{#it{bold italic}}, #bf{#bf{unbold}}}:
00254 Begin_Latex #bf{bold}, #it{italic}, #bf{#it{bold italic}}, #bf{#bf{unbold}} End_Latex
00255 
00256 abc#alpha#beta#gamma, #it{abc#alpha#beta#gamma}:
00257 Begin_Latex abc#alpha#beta#gamma, #it{abc#alpha#beta#gamma} End_Latex
00258 
00259 Begin_Html
00260 <a name="L13"></a><h3>Examples</h3>
00261 End_Html
00262 Begin_Macro(source)
00263 {
00264    TCanvas ex1("ex1","Latex",500,600);
00265    TLatex Tl;
00266    Tl.SetTextAlign(12);
00267    Tl.SetTextSize(0.04);
00268    Tl.DrawLatex(0.1,0.8,"1)   C(x) = d #sqrt{#frac{2}{#lambdaD}}  #int^{x}_{0}cos(#frac{#pi}{2}t^{2})dt");
00269    Tl.DrawLatex(0.1,0.6,"2)   C(x) = d #sqrt{#frac{2}{#lambdaD}}  #int^{x}cos(#frac{#pi}{2}t^{2})dt");
00270    Tl.DrawLatex(0.1,0.4,"3)   R = |A|^{2} = #frac{1}{2}(#[]{#frac{1}{2}+C(V)}^{2}+#[]{#frac{1}{2}+S(V)}^{2})");
00271    Tl.DrawLatex(0.1,0.2,"4)   F(t) = #sum_{i=-#infty}^{#infty}A(i)cos#[]{#frac{i}{t+i}}");
00272    return ex1;
00273 }
00274 End_Macro
00275 Begin_Macro(source)
00276 {
00277    TCanvas ex2("ex2","Latex",500,300);
00278    TLatex Tl;
00279    Tl.SetTextAlign(23);
00280    Tl.SetTextSize(0.08);
00281    Tl.DrawLatex(0.5,0.95,"e^{+}e^{-}#rightarrowZ^{0}#rightarrowI#bar{I}, q#bar{q}");
00282    Tl.DrawLatex(0.5,0.75,"|#vec{a}#bullet#vec{b}|=#Sigmaa^{i}_{jk}+b^{bj}_{i}");
00283    Tl.DrawLatex(0.5,0.5,"i(#partial_{#mu}#bar{#psi}#gamma^{#mu}+m#bar{#psi}=0#Leftrightarrow(#Box+m^{2})#psi=0");
00284    Tl.DrawLatex(0.5,0.3,"L_{em}=eJ^{#mu}_{em}A_{#mu} , J^{#mu}_{em}=#bar{I}#gamma_{#mu}I , M^{j}_{i}=#SigmaA_{#alpha}#tau^{#alphaj}_{i}");
00285    return ex2;
00286 }
00287 End_Macro
00288 Begin_Macro(source)
00289 {
00290    TCanvas ex3("ex3","Latex",500,300);
00291    TPaveText pt(.1,.1,.9,.9);
00292    pt.AddText("#frac{2s}{#pi#alpha^{2}}  #frac{d#sigma}{dcos#theta} (e^{+}e^{-} #rightarrow f#bar{f} ) = ");
00293    pt.AddText("#left| #frac{1}{1 - #Delta#alpha} #right|^{2} (1+cos^{2}#theta");
00294    pt.AddText("+ 4 Re #left{ #frac{2}{1 - #Delta#alpha} #chi(s) #[]{#hat{g}_{#nu}^{e}#hat{g}_{#nu}^{f}
00295    (1 + cos^{2}#theta) + 2 #hat{g}_{a}^{e}#hat{g}_{a}^{f} cos#theta) } #right}");
00296    pt.SetLabel("Born equation");
00297    pt.Draw();
00298    return ex3;
00299 }
00300 End_Macro
00301 */
00302 
00303 
00304 //______________________________________________________________________________
00305 TLatex::TLatex()
00306 {
00307    // Default constructor.
00308 
00309    fFactorSize  = 1.5;
00310    fFactorPos   = 0.6;
00311    fLimitFactorSize = 3;
00312    fError       = 0;
00313    fShow        = kFALSE;
00314    fPos=fTabMax = 0;
00315    fOriginSize  = 0.04;
00316    fTabSize     = 0;
00317    fItalic      = kFALSE;
00318    SetLineWidth(2);
00319 }
00320 
00321 
00322 //______________________________________________________________________________
00323 TLatex::TLatex(Double_t x, Double_t y, const char *text)
00324        :TText(x,y,text)
00325 {
00326    // Normal constructor.
00327 
00328    fFactorSize  = 1.5;
00329    fFactorPos   = 0.6;
00330    fError       = 0;
00331    fShow        = kFALSE;
00332    fPos         = 0;
00333    fTabMax      = 0;
00334    fOriginSize  = 0.04;
00335    fTabSize     = 0;
00336    fItalic      = kFALSE;
00337    fLimitFactorSize = 3;
00338    SetLineWidth(2);
00339 }
00340 
00341 
00342 //______________________________________________________________________________
00343 TLatex::~TLatex()
00344 {
00345    // Destructor.
00346 }
00347 
00348 
00349 //______________________________________________________________________________
00350 TLatex::TLatex(const TLatex &text) : TText(text), TAttLine(text)
00351 {
00352    // Copy constructor.
00353 
00354    fFactorSize  = 1.5;
00355    fFactorPos   = 0.6;
00356    fShow        = kFALSE;
00357    fPos         = 0;
00358    fTabMax      = 0;
00359    fOriginSize  = 0.04;
00360    fItalic      = kFALSE;
00361    fLimitFactorSize = 3;
00362    ((TLatex&)text).Copy(*this);
00363 }
00364 
00365 //______________________________________________________________________________
00366 TLatex& TLatex::operator=(const TLatex& lt)
00367 {
00368    //assignment operator
00369    if(this!=&lt) {
00370       TText::operator=(lt);
00371       TAttLine::operator=(lt);
00372       fFactorSize=lt.fFactorSize;
00373       fFactorPos=lt.fFactorPos;
00374       fLimitFactorSize=lt.fLimitFactorSize;
00375       fError=lt.fError;
00376       fShow=lt.fShow;
00377       fTabSize=lt.fTabSize;
00378       fOriginSize=lt.fOriginSize;
00379       fTabSize=lt.fTabSize;
00380       fTabSize=lt.fTabSize;
00381       fItalic=lt.fItalic;
00382    }
00383    return *this;
00384 }
00385 
00386 //______________________________________________________________________________
00387 void TLatex::Copy(TObject &obj) const
00388 {
00389    // Copy this TLatex object to another TLatex.
00390 
00391    ((TLatex&)obj).fFactorSize  = fFactorSize;
00392    ((TLatex&)obj).fFactorPos   = fFactorPos;
00393    ((TLatex&)obj).fLimitFactorSize  = fLimitFactorSize;
00394    ((TLatex&)obj).fError       = fError;
00395    ((TLatex&)obj).fShow        = fShow;
00396    ((TLatex&)obj).fTabSize     = 0;
00397    ((TLatex&)obj).fOriginSize  = fOriginSize;
00398    ((TLatex&)obj).fTabMax      = fTabMax;
00399    ((TLatex&)obj).fPos         = fPos;
00400    ((TLatex&)obj).fItalic      = fItalic;
00401    TText::Copy(obj);
00402    TAttLine::Copy(((TAttLine&)obj));
00403 }
00404 
00405 
00406 //______________________________________________________________________________
00407 TLatexFormSize TLatex::Anal1(TextSpec_t spec, const Char_t* t, Int_t length)
00408 {
00409    // Analyse function.
00410 
00411    return Analyse(0,0,spec,t,length);
00412 }
00413 
00414 
00415 //______________________________________________________________________________
00416 TLatexFormSize TLatex::Analyse(Double_t x, Double_t y, TextSpec_t spec, const Char_t* t, Int_t length)
00417 {
00418    //  Analyse and paint the TLatex formula
00419    //
00420    //  It is called twice : first for calculating the size of
00421    //  each portion of the formula, then to paint the formula.
00422    //  When analyse finds an operator or separator, it calls
00423    //  itself recursively to analyse the arguments of the operator.
00424    //  when the argument is an atom (normal text), it calculates
00425    //  the size of it and return it as the result.
00426    //  for example : if the operator #frac{arg1}{arg2} is found :
00427    //  Analyse(arg1) return the size of arg1 (width, up, down)
00428    //  Analyse(arg2) return the size of arg2
00429    //  now, we know the size of #frac{arg1}{arg2}  :
00430    //  width = max(width_arg1, width_arg2)
00431    //  up = up_arg1 + down_arg1
00432    //  down = up_arg2 + down_arg2
00433    //  so, when the user wants to paint a fraction at position (x,y),
00434    //  the rect used for the formula is : (x,y-up,x+width,y+down)
00435    //
00436    // return size of zone occupied by the text/formula
00437    // t : chain to be analyzed
00438    // length : number of chars in t.
00439 
00440    const char *tab[] = { "alpha","beta","chi","delta","varepsilon","phi","gamma","eta","iota","varphi","kappa","lambda",
00441                 "mu","nu","omicron","pi","theta","rho","sigma","tau","upsilon","varomega","omega","xi","psi","zeta",
00442                 "Alpha","Beta","Chi","Delta","Epsilon","Phi","Gamma","Eta","Iota","vartheta",
00443                 "Kappa","Lambda","Mu","Nu","Omicron","Pi","Theta","Rho","Sigma","Tau",
00444                 "Upsilon","varsigma","Omega","Xi","Psi","Zeta","varUpsilon","epsilon"};
00445 
00446    const char *tab2[] = { "leq","/","infty","voidb","club","diamond","heart",
00447                  "spade","leftrightarrow","leftarrow","uparrow","rightarrow",
00448                  "downarrow","circ","pm","doublequote","geq","times","propto",
00449                  "partial","bullet","divide","neq","equiv","approx","3dots",
00450                  "cbar","topbar","downleftarrow","aleph","Jgothic","Rgothic","voidn",
00451                  "otimes","oplus","oslash","cap","cup","supset","supseteq",
00452                  "notsubset","subset","subseteq","in","notin","angle","nabla",
00453                  "oright","ocopyright","trademark","prod","surd","upoint","corner","wedge",
00454                  "vee","Leftrightarrow","Leftarrow","Uparrow","Rightarrow",
00455                  "Downarrow","diamond","LT","void1","copyright","void3","sum",
00456                  "arctop","lbar","arcbottom","topbar","void8", "bottombar","arcbar",
00457                  "ltbar","AA","aa","void06","GT","int","forall","exists" };
00458 
00459    const char *tab3[] = { "bar","vec","dot","hat","ddot","acute","grave","check","tilde","slash"};
00460 
00461    if (fError != 0) return TLatexFormSize(0,0,0);
00462 
00463    Int_t nBlancDeb=0,nBlancFin=0,l_nBlancDeb=0,l_nBlancFin=0;
00464    Int_t i,k;
00465    Int_t min=0, max=0;
00466    Bool_t cont = kTRUE;
00467    while(cont) {
00468       // count leading blanks
00469       //while(nBlancDeb+nBlancFin<length && t[nBlancDeb]==' ') nBlancDeb++;
00470 
00471       if (nBlancDeb==length) return TLatexFormSize(0,0,0); // empty string
00472 
00473       // count trailing blanks
00474       //while(nBlancDeb+nBlancFin<length && t[length-nBlancFin-1]==' ') nBlancFin++;
00475 
00476       if (nBlancDeb==l_nBlancDeb && nBlancFin==l_nBlancFin) cont = kFALSE;
00477 
00478       // remove characters { }
00479       if (t[nBlancDeb]=='{' && t[length-nBlancFin-1]=='}') {
00480          Int_t nBrackets = 0;
00481          Bool_t sameBrackets = kTRUE;
00482          for(i=nBlancDeb;i<length-nBlancFin;i++) {
00483             if (t[i] == '{' && !(i>0 && t[i-1] == '@')) nBrackets++;
00484             if (t[i] == '}' && t[i-1]!= '@') nBrackets--;
00485             if (nBrackets==0 && i<length-nBlancFin-2) {
00486                sameBrackets=kFALSE;
00487                break;
00488             }
00489          }
00490 
00491          if (sameBrackets) {
00492             // begin and end brackets match
00493             nBlancDeb++;
00494             nBlancFin++;
00495             if (nBlancDeb+nBlancFin==length) return TLatexFormSize(0,0,0); // empty string
00496             cont = kTRUE;
00497          }
00498 
00499       }
00500 
00501       l_nBlancDeb = nBlancDeb;
00502       l_nBlancFin = nBlancFin;
00503    }
00504 
00505    // make a copy of the current processed chain of characters
00506    // removing leading and trailing blanks
00507    length -= nBlancFin+nBlancDeb; // length of string without blanks
00508    Char_t* text = new Char_t[length+1];
00509    strncpy(text,t+nBlancDeb,length);
00510    text[length] = 0;
00511 
00512    // compute size of subscripts and superscripts
00513    Double_t indiceSize = spec.fSize/fFactorSize;
00514    if(indiceSize<fOriginSize/TMath::Exp(fLimitFactorSize*TMath::Log(fFactorSize))-0.001f)
00515       indiceSize = spec.fSize;
00516    // substract 0.001 because of rounding errors
00517    TextSpec_t specNewSize = spec;
00518    specNewSize.fSize       = indiceSize;
00519 
00520    // recherche des operateurs
00521    Int_t opPower         = -1;   // Position of first ^ (power)
00522    Int_t opUnder         = -1;   // Position of first _ (indice)
00523    Int_t opFrac          = -1;   // Position of first \frac
00524    Int_t opSqrt          = -1;   // Position of first \sqrt
00525    Int_t nBrackets       = 0;    // Nesting level in { }
00526    Int_t nCroch          = 0;    // Nesting level in [ ]
00527    Int_t opCurlyCurly    = -1;   // Position of first }{
00528    Int_t opSquareCurly   = -1;   // Position of first ]{
00529    Int_t opCloseCurly    = -2;   // Position of first }
00530    Int_t opColor         = -1;   // Position of first \color
00531    Int_t opFont          = -1;   // Position of first \font
00532    Int_t opScale         = -1;   // Position of first \scale
00533    Int_t opGreek         = -1;   // Position of a Greek letter
00534    Int_t opSpec          = -1;   // position of a special character
00535    Int_t opAbove         = -1;   // position of a vector/overline
00536    Int_t opSquareBracket = 0 ;   // position of a "[]{" operator (#[]{arg})
00537    Int_t opBigCurly      = 0 ;   // position of a "{}{" operator (big curly bracket #{}{arg})
00538    Int_t opAbs           = 0 ;   // position of a "||{" operator (absolute value) (#||{arg})
00539    Int_t opParen         = 0 ;   // position of a "(){" operator (big parenthesis #(){arg})
00540    Int_t abovePlace      = 0 ;   // true if subscripts must be written above and not after
00541    Int_t opBox           = 0 ;   // position of #Box
00542    Int_t opPerp          = 0;    // position of #perp
00543    Int_t opOdot          = 0;    // position of #odot
00544    Int_t opHbar          = 0;    // position of #hbar
00545    Int_t opParallel      = 0;    // position of #parallel
00546    Int_t opSplitLine     = -1;   // Position of first \splitline
00547    Int_t opKern          = -1;   // Position of first #kern
00548    Int_t opLower         = -1;   // Position of first #lower
00549    Int_t opBf            = -1;   // Position of first #bf
00550    Int_t opIt            = -1;   // Position of first #it
00551    Bool_t opFound = kFALSE;
00552    Bool_t quote1 = kFALSE, quote2 = kFALSE ;
00553 
00554    for(i=0;i<length;i++) {
00555       switch (text[i]) {
00556          case '\'' : quote1 = !quote1 ; break ;
00557          case '"'  : quote2  = !quote2 ; break ;
00558       }
00559       //if (quote1 || quote2) continue ;
00560       switch (text[i]) {
00561          case '{':
00562             if (nCroch==0) {
00563                if (!(i>0 && text[i-1] == '@')) nBrackets++;
00564             }
00565             break;
00566          case '}':
00567             if (nCroch==0) {
00568                if (!(i>0 && text[i-1] == '@')) nBrackets--;
00569                if (nBrackets==0) {
00570                   if (i<length-1) if (text[i+1]=='{' && opCurlyCurly==-1) opCurlyCurly=i;
00571                   if (i<length-2) {
00572                      if (text[i+1]!='{' && !(text[i+2]=='{' && (text[i+1]=='^' || text[i+1]=='_'))
00573                      && opCloseCurly==-2) opCloseCurly=i;
00574                   }
00575                   else if (i<length-1) {
00576                      if (text[i+1]!='{' && opCloseCurly==-2) opCloseCurly=i;
00577                   }
00578                   else if (opCloseCurly==-2) opCloseCurly=i;
00579                }
00580             }
00581             break;
00582          case '[':
00583             if (nBrackets==0) {
00584                if (!(i>0 && text[i-1] == '@')) nCroch++;
00585             }
00586             break;
00587          case ']':
00588             if (nBrackets==0) {
00589                if (!(i>0 && text[i-1] == '@')) nCroch--;
00590                if (nCroch<0) {
00591                   // more "]" than "["
00592                   fError = "Missing \"[\"";
00593                   delete [] text;
00594                   return TLatexFormSize(0,0,0);
00595                }
00596             }
00597             break;
00598       }
00599       if (length>i+1) {
00600          Char_t buf[3];
00601          strncpy(buf,&text[i],2);
00602          if (strncmp(buf,"^{",2)==0) {
00603             if (opPower==-1 && nBrackets==0 && nCroch==0) opPower=i;
00604             if (i>3) {
00605                Char_t buf1[5];
00606                strncpy(buf1,&text[i-4],4);
00607                if (strncmp(buf1,"#int",4)==0) {
00608                   abovePlace = 1;
00609                   if (i>4 && opCloseCurly==-2) opCloseCurly=i-5;
00610                }
00611                if (strncmp(buf1,"#sum",4)==0) {
00612                   abovePlace = 2;
00613                   if (i>4 && opCloseCurly==-2) opCloseCurly=i-5;
00614                }
00615             }
00616          }
00617          if (strncmp(buf,"_{",2)==0) {
00618             if (opUnder==-1 && nBrackets==0 && nCroch==0) opUnder=i;
00619             if (i>3) {
00620                Char_t buf2[5];
00621                strncpy(buf2,&text[i-4],4);
00622                if (strncmp(buf2,"#int",4)==0) {
00623                   abovePlace = 1;
00624                   if (i>4 && opCloseCurly==-2) opCloseCurly=i-5;
00625                }
00626                if (strncmp(buf2,"#sum",4)==0) {
00627                   abovePlace = 2;
00628                   if (i>4 && opCloseCurly==-2) opCloseCurly=i-5;
00629                }
00630             }
00631          }
00632          if (strncmp(buf,"]{",2)==0)
00633             if (opSquareCurly==-1 && nBrackets==0 && nCroch==0) opSquareCurly=i;
00634       }
00635       // detect other operators
00636       if (text[i]=='\\' || (text[i]=='#' && !opFound && nBrackets==0 && nCroch==0)) {
00637 
00638          if (length>i+10 ) {
00639             Char_t buf[11];
00640             strncpy(buf,&text[i+1],10);
00641             if (strncmp(buf,"splitline{",10)==0) {
00642                opSplitLine=i; opFound = kTRUE;
00643                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00644                continue;
00645             }
00646          }
00647          if (length>i+8 ) {
00648             Char_t buf[9];
00649             strncpy(buf,&text[i+1],8);
00650             if (!opParallel && strncmp(buf,"parallel",8)==0) {
00651                opParallel=1; opFound = kTRUE;
00652                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00653                continue;
00654             }
00655          }
00656          if (length>i+6) {
00657             Char_t buf[7];
00658             strncpy(buf,&text[i+1],6);
00659             if (strncmp(buf,"lower[",6)==0 || strncmp(buf,"lower{",6)==0) {
00660                opLower=i; opFound = kTRUE;
00661                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00662                continue ;
00663             }
00664             if (strncmp(buf,"scale[",6)==0 || strncmp(buf,"scale{",6)==0) {
00665                opScale=i; opFound = kTRUE;
00666                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00667                continue ;
00668             }
00669             if (strncmp(buf,"color[",6)==0 || strncmp(buf,"color{",6)==0) {
00670                opColor=i; opFound = kTRUE;
00671                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00672                continue ;
00673             }
00674          }
00675          if (length>i+5 ) {
00676             Char_t buf[6];
00677             strncpy(buf,&text[i+1],5);
00678             if (strncmp(buf,"frac{",5)==0) {
00679                opFrac=i; opFound = kTRUE;
00680                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00681                continue;
00682             }
00683             if (strncmp(buf,"sqrt{",5)==0 || strncmp(buf,"sqrt[",5)==0) {
00684                opSqrt=i; opFound = kTRUE;
00685                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00686                continue;
00687             }
00688             if (strncmp(buf,"font{",5)==0 || strncmp(buf,"font[",5)==0) {
00689                opFont=i; opFound = kTRUE;
00690                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00691                continue;
00692             }
00693             if (strncmp(buf,"kern[",5)==0 || strncmp(buf,"kern{",5)==0) {
00694                opKern=i; opFound = kTRUE;
00695                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00696                continue ;
00697             }
00698          }
00699          if (length>i+4 ) {
00700             Char_t buf[5];
00701             strncpy(buf,&text[i+1],4);
00702             if (!opOdot && strncmp(buf,"odot",4)==0) {
00703                opOdot=1; opFound = kTRUE;
00704                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00705                continue;
00706             }
00707             if (!opHbar && strncmp(buf,"hbar",4)==0) {
00708                opHbar=1; opFound = kTRUE;
00709                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00710                continue;
00711             }
00712             if (!opPerp && strncmp(buf,"perp",4)==0) {
00713                opPerp=1; opFound = kTRUE;
00714                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00715                continue;
00716             }
00717          }
00718          if (length>i+3) {
00719             Char_t buf[4];
00720             strncpy(buf,&text[i+1],3);
00721             buf[3] = 0;
00722             if (strncmp(buf,"[]{",3)==0) {
00723                opSquareBracket=1; opFound = kTRUE;
00724                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00725                continue;
00726             }
00727             if (strncmp(buf,"{}{",3)==0 ) {
00728                opBigCurly=1; opFound = kTRUE;
00729                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00730                continue;
00731             }
00732             if (strncmp(buf,"||{",3)==0) {
00733                opAbs=1; opFound = kTRUE;
00734                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00735                continue;
00736             }
00737             if (strncmp(buf,"(){",3)==0) {
00738                opParen=1; opFound = kTRUE;
00739                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00740                continue;
00741             }
00742             if (!opBox && strncmp(buf,"Box",3)==0) {
00743                opBox=1; opFound = kTRUE;
00744                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00745                continue;
00746             }
00747             if (strncmp(buf,"bf[",3)==0 || strncmp(buf,"bf{",3)==0) {
00748                opBf=i; opFound = kTRUE;
00749                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00750                continue ;
00751             }
00752             if (strncmp(buf,"it[",3)==0 || strncmp(buf,"it{",3)==0) {
00753                opIt=i; opFound = kTRUE;
00754                if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00755                continue ;
00756             }
00757          }
00758          for(k=0;k<54;k++) {
00759             if (!opFound && UInt_t(length)>i+strlen(tab[k])) {
00760                if (strncmp(&text[i+1],tab[k],strlen(tab[k]))==0) {
00761                   opGreek=k;
00762                   opFound = kTRUE;
00763                   if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00764                }
00765             }
00766          }
00767          for(k=0;k<10;k++) {
00768             if (!opFound && UInt_t(length)>i+strlen(tab3[k])) {
00769                if (strncmp(&text[i+1],tab3[k],strlen(tab3[k]))==0) {
00770                   opAbove=k;
00771                   opFound = kTRUE;
00772                   if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00773                }
00774             }
00775          }
00776          UInt_t lastsize = 0;
00777          if (!opFound)
00778          for(k=0;k<82;k++) {
00779             if ((opSpec==-1 || strlen(tab2[k])>lastsize) && UInt_t(length)>i+strlen(tab2[k])) {
00780                if (strncmp(&text[i+1],tab2[k],strlen(tab2[k]))==0) {
00781                   lastsize = strlen(tab2[k]);
00782                   opSpec=k;
00783                   opFound = kTRUE;
00784                   if (i>0 && opCloseCurly==-2) opCloseCurly=i-1;
00785                }
00786             }
00787          }
00788       }
00789    }
00790 
00791    TLatexFormSize fs1;
00792    TLatexFormSize fs2;
00793    TLatexFormSize fs3;
00794    TLatexFormSize result;
00795 
00796    // analysis of operators found
00797    if (opCloseCurly>-1 && opCloseCurly<length-1) { // separator } found
00798       if(!fShow) {
00799          fs1 = Anal1(spec,text,opCloseCurly+1);
00800          fs2 = Anal1(spec,text+opCloseCurly+1,length-opCloseCurly-1);
00801          Savefs(&fs1);
00802       } else {
00803          fs1 = Readfs();
00804          Analyse(x+fs1.Width(),y,spec,text+opCloseCurly+1,length-opCloseCurly-1);
00805          Analyse(x,y,spec,text,opCloseCurly+1);
00806       }
00807       result = fs1+fs2;
00808    }
00809 
00810    else if (opPower>-1 && opUnder>-1) { // ^ and _ found
00811       min = TMath::Min(opPower,opUnder);
00812       max = TMath::Max(opPower,opUnder);
00813       Double_t xfpos = 0. ; //GetHeight()*spec.fSize/5.;
00814       Double_t prop=1, propU=1; // scale factor for #sum & #int
00815       switch (abovePlace) {
00816          case 1 :
00817             prop = .8 ; propU = 1.75 ; // Int
00818             break;
00819          case 2:
00820             prop = .9 ; propU = 1.75 ; // Sum
00821             break;
00822       }
00823      // propU acts on upper number
00824      // when increasing propU value, the upper indice position is higher
00825      // when increasing prop values, the lower indice position is lower
00826 
00827       if (!fShow) {
00828          Int_t ltext = min ;
00829          if (min >= 2 && strncmp(&text[min-2],"{}",2)==0) {
00830             // upper and lower indice before the character
00831             // like with chemical element
00832             snprintf(&text[ltext-2],length-(ltext-2),"I ") ;
00833             ltext-- ;
00834          }
00835          fs1 = Anal1(spec,text,ltext);
00836          fs2 = Anal1(specNewSize,text+min+1,max-min-1);
00837          fs3 = Anal1(specNewSize,text+max+1,length-max-1);
00838          Savefs(&fs1);
00839          Savefs(&fs2);
00840          Savefs(&fs3);
00841       } else {
00842          fs3 = Readfs();
00843          fs2 = Readfs();
00844          fs1 = Readfs();
00845          Double_t pos = 0;
00846          if (!abovePlace) {
00847             Double_t addW = fs1.Width()+xfpos, addH1, addH2;
00848             if (opPower<opUnder) {
00849                addH1 = -fs1.Over()*(fFactorPos)-fs2.Under();
00850                addH2 = fs1.Under()+fs3.Over()*(fFactorPos);
00851             } else {
00852                addH1 = fs1.Under()+fs2.Over()*(fFactorPos);
00853                addH2 = -fs1.Over()*(fFactorPos)-fs3.Under();
00854             }
00855             Analyse(x+addW,y+addH2,specNewSize,text+max+1,length-max-1);
00856             Analyse(x+addW,y+addH1,specNewSize,text+min+1,max-min-1);
00857          } else {
00858             Double_t addW1, addW2, addH1, addH2;
00859             Double_t m = TMath::Max(fs1.Width(),TMath::Max(fs2.Width(),fs3.Width()));
00860             pos = (m-fs1.Width())/2;
00861             if (opPower<opUnder) {
00862                addH1 = -fs1.Over()*propU-fs2.Under();
00863                addW1 = (m-fs2.Width())/2;
00864                addH2 = fs1.Under()*prop+fs3.Over();
00865                addW2 = (m-fs3.Width())/2;
00866             } else {
00867                addH1 = fs1.Under()*prop+fs2.Over();
00868                addW1 = (m-fs2.Width())/2;
00869                addH2 = -fs1.Over()*propU-fs3.Under();
00870                addW2 = (m-fs3.Width())/2;
00871             }
00872 
00873             Analyse(x+addW2,y+addH2,specNewSize,text+max+1,length-max-1);
00874             Analyse(x+addW1,y+addH1,specNewSize,text+min+1,max-min-1);
00875          }
00876 
00877          if (min >= 2 && strncmp(&text[min-2],"{}",2)==0) {
00878             snprintf(&text[min-2],length-(min-2),"  ") ;
00879             Analyse(x+pos,y,spec,text,min-1);
00880          } else {
00881             Analyse(x+pos,y,spec,text,min);
00882          }
00883       }
00884 
00885       if (!abovePlace) {
00886          if (opPower<opUnder) {
00887             result.Set(fs1.Width()+xfpos+TMath::Max(fs2.Width(),fs3.Width()),
00888                        fs1.Over()*fFactorPos+fs2.Height(),
00889                        fs1.Under()+fs3.Height()-fs3.Over()*(1-fFactorPos));
00890          } else {
00891             result.Set(fs1.Width()+xfpos+TMath::Max(fs2.Width(),fs3.Width()),
00892                        fs1.Over()*fFactorPos+fs3.Height(),
00893                        fs1.Under()+fs2.Height()-fs2.Over()*(1-fFactorPos));
00894          }
00895       } else {
00896          if (opPower<opUnder) {
00897             result.Set(TMath::Max(fs1.Width(),TMath::Max(fs2.Width(),fs3.Width())),
00898                        fs1.Over()*propU+fs2.Height(),fs1.Under()*prop+fs3.Height());
00899          } else {
00900             result.Set(TMath::Max(fs1.Width(),TMath::Max(fs2.Width(),fs3.Width())),
00901                        fs1.Over()*propU+fs3.Height(),fs1.Under()*prop+fs2.Height());
00902          }
00903       }
00904    }
00905    else if (opPower>-1) { // ^ found
00906       Double_t prop=1;
00907       Double_t xfpos = 0. ; //GetHeight()*spec.fSize/5. ;
00908       switch (abovePlace) {
00909          case 1 : //int
00910             prop = 1.75 ; break ;
00911          case 2 : // sum
00912             prop = 1.75;  break ;
00913       }
00914       // When increasing prop, the upper indice position is higher
00915       if (!fShow) {
00916          Int_t ltext = opPower ;
00917          if (ltext >= 2 && strncmp(&text[ltext-2],"{}",2)==0) {
00918             // upper and lower indice before the character
00919             // like with chemical element
00920             snprintf(&text[ltext-2],length-(ltext-2),"I ") ;
00921             ltext-- ;
00922          }
00923          fs1 = Anal1(spec,text,ltext);
00924          fs2 = Anal1(specNewSize,text+opPower+1,length-opPower-1);
00925          Savefs(&fs1);
00926          Savefs(&fs2);
00927       } else {
00928          fs2 = Readfs();
00929          fs1 = Readfs();
00930          Int_t pos = 0;
00931          if (!abovePlace){
00932             Double_t over = fs1.Over();
00933             if (over <= 0) over = 1.5*fs2.Over();
00934             Analyse(x+fs1.Width()+xfpos,y-over*fFactorPos-fs2.Under(),specNewSize,text+opPower+1,length-opPower-1);
00935          } else {
00936             Int_t pos2=0;
00937             if (fs2.Width()>fs1.Width())
00938                pos=Int_t((fs2.Width()-fs1.Width())/2);
00939             else
00940                pos2=Int_t((fs1.Width()-fs2.Width())/2);
00941 
00942             Analyse(x+pos2,y-fs1.Over()*prop-fs2.Under(),specNewSize,text+opPower+1,length-opPower-1);
00943          }
00944          if (opPower >= 2 && strncmp(&text[opPower-2],"{}",2)==0) {
00945             snprintf(&text[opPower-2],length-(opPower-2),"  ") ;
00946             Analyse(x+pos,y,spec,text,opPower-1);
00947          } else {
00948             Analyse(x+pos,y,spec,text,opPower);
00949          }
00950       }
00951 
00952       if (!abovePlace)
00953          result.Set(fs1.Width()+xfpos+fs2.Width(),
00954                     fs1.Over()*fFactorPos+fs2.Over(),fs1.Under());
00955       else
00956          result.Set(TMath::Max(fs1.Width(),fs2.Width()),fs1.Over()*prop+fs2.Height(),fs1.Under());
00957 
00958    }
00959    else if (opUnder>-1) { // _ found
00960       Double_t prop = .9; // scale factor for #sum & #frac
00961       Double_t xfpos = 0.;//GetHeight()*spec.fSize/5. ;
00962       Double_t fpos = fFactorPos ;
00963       // When increasing prop, the lower indice position is lower
00964       if(!fShow) {
00965          Int_t ltext = opUnder ;
00966          if (ltext >= 2 && strncmp(&text[ltext-2],"{}",2)==0) {
00967             // upper and lower indice before the character
00968             // like with chemical element
00969             snprintf(&text[ltext-2],length-(ltext-2),"I ") ;
00970             ltext-- ;
00971          }
00972          fs1 = Anal1(spec,text,ltext);
00973          fs2 = Anal1(specNewSize,text+opUnder+1,length-opUnder-1);
00974          Savefs(&fs1);
00975          Savefs(&fs2);
00976       } else {
00977          fs2 = Readfs();
00978          fs1 = Readfs();
00979          Int_t pos = 0;
00980          if (!abovePlace)
00981             Analyse(x+fs1.Width()+xfpos,y+fs1.Under()+fs2.Over()*fpos,specNewSize,text+opUnder+1,length-opUnder-1);
00982          else {
00983             Int_t pos2=0;
00984             if (fs2.Width()>fs1.Width())
00985                pos=Int_t((fs2.Width()-fs1.Width())/2);
00986             else
00987                pos2=Int_t((fs1.Width()-fs2.Width())/2);
00988 
00989             Analyse(x+pos2,y+fs1.Under()*prop+fs2.Over(),specNewSize,text+opUnder+1,length-opUnder-1);
00990          }
00991          if (opUnder >= 2 && strncmp(&text[opUnder-2],"{}",2)==0) {
00992             snprintf(&text[opUnder-2],length-(opUnder-2),"  ") ;
00993             Analyse(x+pos,y,spec,text,opUnder-1);
00994          } else {
00995             Analyse(x+pos,y,spec,text,opUnder);
00996          }
00997       }
00998       if (!abovePlace)
00999          result.Set(fs1.Width()+xfpos+fs2.Width(),fs1.Over(),
01000                     fs1.Under()+fs2.Under()+fs2.Over()*fpos);
01001       else
01002          result.Set(TMath::Max(fs1.Width(),fs2.Width()),fs1.Over(),fs1.Under()*prop+fs2.Height());
01003    }
01004    else if (opBox) {
01005       Double_t square = GetHeight()*spec.fSize/2;
01006       if (!fShow) {
01007          fs1 = Anal1(spec,text+4,length-4);
01008       } else {
01009          fs1 = Analyse(x+square,y,spec,text+4,length-4);
01010          Double_t adjust = GetHeight()*spec.fSize/20;
01011          Double_t x1 = x+adjust ;
01012          Double_t x2 = x-adjust+square ;
01013          Double_t y1 = y;
01014          Double_t y2 = y-square+adjust;
01015          DrawLine(x1,y1,x2,y1,spec);
01016          DrawLine(x2,y1,x2,y2,spec);
01017          DrawLine(x2,y2,x1,y2,spec);
01018          DrawLine(x1,y2,x1,y1,spec);
01019       }
01020       result = fs1 + TLatexFormSize(square,square,0);
01021    }
01022    else if (opOdot) {
01023       Double_t square = GetHeight()*spec.fSize/2;
01024       if (!fShow) {
01025          fs1 = Anal1(spec,text+5,length-5);
01026       } else {
01027          fs1 = Analyse(x+1.3*square,y,spec,text+5,length-5);
01028          Double_t adjust = GetHeight()*spec.fSize/20;
01029          Double_t r1 = 0.62*square;
01030          Double_t y1 = y-0.3*square-adjust;
01031          DrawCircle(x+0.6*square,y1,r1,spec) ;
01032          DrawCircle(x+0.6*square,y1,r1/100,spec) ;
01033       }
01034       result = fs1 + TLatexFormSize(square,square,0);
01035    }
01036    else if (opHbar) {
01037       Double_t square = GetHeight()*spec.fSize/2;
01038       if (!fShow) {
01039          fs1 = Anal1(spec,text+5,length-5);
01040       } else {
01041          fs1 = Analyse(x+square,y,spec,text+5,length-5);
01042          TText hbar;
01043          hbar.SetTextFont(12);
01044          hbar.SetTextColor(fTextColor);
01045          hbar.SetTextSize(spec.fSize);
01046          hbar.SetTextAngle(fTextAngle);
01047          Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
01048          Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
01049          Double_t angle   = kPI*spec.fAngle/180.;
01050          Double_t xx = gPad->AbsPixeltoX(Int_t((x-xOrigin)*TMath::Cos(angle)+(y-yOrigin)*TMath::Sin(angle)+xOrigin));
01051          Double_t yy = gPad->AbsPixeltoY(Int_t((x-xOrigin)*TMath::Sin(-angle)+(y-yOrigin)*TMath::Cos(angle)+yOrigin));
01052          hbar.PaintText(xx,yy,"h");
01053          DrawLine(x,y-0.8*square,x+0.75*square,y-square,spec);
01054       }
01055       result = fs1 + TLatexFormSize(square,square,0);
01056    }
01057    else if (opPerp) {
01058       Double_t square = GetHeight()*spec.fSize/1.4;
01059       if (!fShow) {
01060          fs1 = Anal1(spec,text+5,length-5);
01061       } else {
01062          fs1 = Analyse(x+0.5*square,y,spec,text+5,length-5);
01063          Double_t x0 = x  + 0.50*square;
01064          Double_t x1 = x0 - 0.48*square;
01065          Double_t x2 = x0 + 0.48*square;
01066          Double_t y1 = y  + 0.6*square;
01067          Double_t y2 = y1 - 1.3*square;
01068          DrawLine(x1,y1,x2,y1,spec);
01069          DrawLine(x0,y1,x0,y2,spec);
01070       }
01071       result = fs1;
01072    }
01073    else if (opParallel) {
01074       Double_t square = GetHeight()*spec.fSize/1.4;
01075       if (!fShow) {
01076          fs1 = Anal1(spec,text+9,length-9);
01077       } else {
01078          fs1 = Analyse(x+0.5*square,y,spec,text+9,length-9);
01079          Double_t x1 = x + 0.15*square;
01080          Double_t x2 = x + 0.45*square;
01081          Double_t y1 = y + 0.3*square;
01082          Double_t y2 = y1- 1.3*square;
01083          DrawLine(x1,y1,x1,y2,spec);
01084          DrawLine(x2,y1,x2,y2,spec);
01085       }
01086       result = fs1 + TLatexFormSize(square,square,0);
01087    }
01088    else if (opGreek>-1) {
01089       TextSpec_t newSpec = spec;
01090       newSpec.fFont = fItalic ? 152 : 122;
01091       char letter = 97 + opGreek;
01092       Double_t yoffset = 0.; // Greek letter too low
01093       if (opGreek>25) letter -= 58;
01094       if (opGreek == 52) letter = '\241'; //varUpsilon
01095       if (opGreek == 53) letter = '\316'; //epsilon
01096       if (!fShow) {
01097          fs1 = Anal1(newSpec,&letter,1);
01098          fs2 = Anal1(spec,text+strlen(tab[opGreek])+1,length-strlen(tab[opGreek])-1);
01099          Savefs(&fs1);
01100       } else {
01101          fs1 = Readfs();
01102          Analyse(x+fs1.Width(),y,spec,text+strlen(tab[opGreek])+1,length-strlen(tab[opGreek])-1);
01103          Analyse(x,y-yoffset,newSpec,&letter,1);
01104       }
01105       fs1.AddOver(TLatexFormSize(0,yoffset,0)) ;
01106       result = fs1+fs2;
01107    }
01108 
01109    else if (opSpec>-1) {
01110       TextSpec_t newSpec = spec;
01111       newSpec.fFont = fItalic ? 152 : 122;
01112       char letter = '\243' + opSpec;
01113       if(opSpec == 75 || opSpec == 76) {
01114          newSpec.fFont = GetTextFont();
01115          if (opSpec == 75) letter = '\305'; // AA Angstroem
01116          if (opSpec == 76) letter = '\345'; // aa Angstroem
01117       }
01118       if(opSpec == 80 || opSpec == 81) {
01119          if (opSpec == 80) letter = '\042'; // #forall
01120          if (opSpec == 81) letter = '\044'; // #exists
01121       }
01122       Double_t props, propi;
01123       props = 1.8 ; // scale factor for #sum(66)
01124       propi = 2.3 ; // scale factor for  #int(79)
01125 
01126       if (opSpec==66 ) {
01127          newSpec.fSize = spec.fSize*props;
01128       } else if (opSpec==79) {
01129          newSpec.fSize = spec.fSize*propi;
01130       }
01131       if (!fShow) {
01132          fs1 = Anal1(newSpec,&letter,1);
01133          if (opSpec == 79 || opSpec == 66)
01134             fs1.Set(fs1.Width(),fs1.Over()*0.45,fs1.Over()*0.45);
01135 
01136          fs2 = Anal1(spec,text+strlen(tab2[opSpec])+1,length-strlen(tab2[opSpec])-1);
01137          Savefs(&fs1);
01138       } else {
01139          fs1 = Readfs();
01140          Analyse(x+fs1.Width(),y,spec,text+strlen(tab2[opSpec])+1,length-strlen(tab2[opSpec])-1);
01141          if (opSpec!=66 && opSpec!=79)
01142             Analyse(x,y,newSpec,&letter,1);
01143          else {
01144                Analyse(x,y+fs1.Under()/2.,newSpec,&letter,1);
01145          }
01146       }
01147       result = fs1+fs2;
01148    }
01149    else if (opAbove>-1) {
01150       if (!fShow) {
01151          fs1 = Anal1(spec,text+strlen(tab3[opAbove])+1,length-strlen(tab3[opAbove])-1);
01152          Savefs(&fs1);
01153       } else {
01154          fs1 = Readfs();
01155          Analyse(x,y,spec,text+strlen(tab3[opAbove])+1,length-strlen(tab3[opAbove])-1);
01156          Double_t sub = GetHeight()*spec.fSize/14;
01157          Double_t x1 , y1 , x2, y2, x3, x4;
01158          switch(opAbove) {
01159          case 0: // bar
01160             Double_t ypos  ;
01161             ypos = y-fs1.Over()-sub ;//-GetHeight()*spec.fSize/4. ;
01162             DrawLine(x,ypos,x+fs1.Width(),ypos,spec);
01163             break;
01164          case 1: // vec
01165             Double_t y0 ;
01166             y0 = y-sub-fs1.Over() ;
01167             y1 = y0-GetHeight()*spec.fSize/8 ;
01168             x1 = x+fs1.Width() ;
01169             DrawLine(x,y1,x1,y1,spec);
01170             DrawLine(x1,y1,x1-GetHeight()*spec.fSize/4,y0-GetHeight()*spec.fSize/4,spec);
01171             DrawLine(x1,y1,x1-GetHeight()*spec.fSize/4,y0,spec);
01172             break;
01173          case 2: // dot
01174             x1 = x+fs1.Width()/2-3*sub/4 ;
01175             x2 = x+fs1.Width()/2+3*sub/4 ;
01176             y1 = y-sub-fs1.Over() ;
01177             DrawLine(x1,y1,x2,y1,spec);
01178             break;
01179          case 3: // hat
01180             x2 = x+fs1.Width()/2 ;
01181             y1 = y -9*sub;
01182             y2 = y1-2*sub;
01183             x1 = x2-fs1.Width()/3 ;
01184             x3 = x2+fs1.Width()/3 ;
01185             DrawLine(x1,y1,x2,y2,spec);
01186             DrawLine(x2,y2,x3,y1,spec);
01187             break;
01188          case 4: // ddot
01189             x1 = x+fs1.Width()/2-9*sub/4 ;
01190             x2 = x+fs1.Width()/2-3*sub/4 ;
01191             x3 = x+fs1.Width()/2+9*sub/4 ;
01192             x4 = x+fs1.Width()/2+3*sub/4 ;
01193             y1 = y-sub-fs1.Over() ;
01194             DrawLine(x1,y1,x2,y1,spec);
01195             DrawLine(x3,y1,x4,y1,spec);
01196             break;
01197          case 5: // acute
01198             x1 = x+fs1.Width()/2;
01199             y1 = y +sub -fs1.Over() ;
01200             x2 = x1 +3*sub;
01201             y2 = y1 -2.5*sub;
01202             DrawLine(x1,y1,x2,y2,spec);
01203             break;
01204          case 6: // grave
01205             x1 = x+fs1.Width()/2-sub;
01206             y1 = y-sub-fs1.Over() ;
01207             x2 = x1 +2*sub;
01208             y2 = y1 +2*sub;
01209             DrawLine(x1,y1,x2,y2,spec);
01210             break;
01211          case 7: // check
01212             x1 = x+fs1.Width()/2 ;
01213             x2 = x1 -2*sub ;
01214             x3 = x1 +2*sub ;
01215             y1 = y-sub-fs1.Over() ;
01216             DrawLine(x2,y-3*sub-fs1.Over(),x1,y1,spec);
01217             DrawLine(x3,y-3*sub-fs1.Over(),x1,y1,spec);
01218             break;
01219          case 8: // tilde
01220             x2 = x+fs1.Width()/2 ;
01221             y2 = y -fs1.Over() ;
01222             {
01223                // tilde must be drawn separately on screen and on PostScript
01224                // because an adjustment is required along Y for PostScript.
01225                TVirtualPS *saveps = gVirtualPS;
01226                if (gVirtualPS) gVirtualPS = 0;
01227                Double_t sinang  = TMath::Sin(spec.fAngle/180*kPI);
01228                Double_t cosang  = TMath::Cos(spec.fAngle/180*kPI);
01229                Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
01230                Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
01231                Double_t xx  = gPad->AbsPixeltoX(Int_t((x2-xOrigin)*cosang+(y2-yOrigin)*sinang+xOrigin));
01232                Double_t yy  = gPad->AbsPixeltoY(Int_t((x2-xOrigin)*-sinang+(y2-yOrigin)*cosang+yOrigin));
01233                TText tilde;
01234                tilde.SetTextFont(fTextFont);
01235                tilde.SetTextColor(fTextColor);
01236                tilde.SetTextSize(0.9*spec.fSize);
01237                tilde.SetTextAlign(22);
01238                tilde.SetTextAngle(fTextAngle);
01239                tilde.PaintText(xx,yy,"~");
01240                if (saveps) {
01241                   y2 -= 4*sub;
01242                   xx  = gPad->AbsPixeltoX(Int_t((x2-xOrigin)*cosang+(y2-yOrigin)*sinang+xOrigin));
01243                   yy  = gPad->AbsPixeltoY(Int_t((x2-xOrigin)*-sinang+(y2-yOrigin)*cosang+yOrigin));
01244                   gVirtualPS = saveps;
01245                   gVirtualPS->SetTextAlign(22);
01246                   gVirtualPS->Text(xx, yy, "~");
01247                }
01248             }
01249             break;
01250          case 9: // slash
01251             x1 = x + 0.8*fs1.Width();
01252             y1 = y -fs1.Over() ;
01253             x2 = x + 0.3*fs1.Width();
01254             y2 = y1 + 1.2*fs1.Height();
01255             DrawLine(x1,y1,x2,y2,spec);
01256             break;
01257          }
01258       }
01259       Double_t div = 3;
01260       if (opAbove==1) div=4;
01261       result.Set(fs1.Width(),fs1.Over()+GetHeight()*spec.fSize/div,fs1.Under());
01262    }
01263    else if (opSquareBracket) { // operator #[]{arg}
01264       Double_t l = GetHeight()*spec.fSize/4;
01265       Double_t l2 = l/2 ;
01266       if (!fShow) {
01267          fs1 = Anal1(spec,text+3,length-3);
01268          Savefs(&fs1);
01269       } else {
01270          fs1 = Readfs();
01271          Analyse(x+l2+l,y,spec,text+3,length-3);
01272          DrawLine(x+l2,y-fs1.Over(),x+l2,y+fs1.Under(),spec);
01273          DrawLine(x+l2,y-fs1.Over(),x+l2+l,y-fs1.Over(),spec);
01274          DrawLine(x+l2,y+fs1.Under(),x+l2+l,y+fs1.Under(),spec);
01275          DrawLine(x+l2+fs1.Width()+2*l,y-fs1.Over(),x+l2+fs1.Width()+2*l,y+fs1.Under(),spec);
01276          DrawLine(x+l2+fs1.Width()+2*l,y-fs1.Over(),x+l2+fs1.Width()+l,y-fs1.Over(),spec);
01277          DrawLine(x+l2+fs1.Width()+2*l,y+fs1.Under(),x+l2+fs1.Width()+l,y+fs1.Under(),spec);
01278       }
01279       result.Set(fs1.Width()+3*l,fs1.Over(),fs1.Under());
01280    }
01281    else if (opParen) {  // operator #(){arg}
01282       Double_t l = GetHeight()*spec.fSize/4;
01283       Double_t radius2,radius1 , dw, l2 = l/2 ;
01284       Double_t angle = 35 ;
01285       if (!fShow) {
01286          fs1 = Anal1(spec,text+3,length-3);
01287          Savefs(&fs1);
01288          radius2 = fs1.Height() ;
01289          radius1 = radius2  * 2 / 3;
01290          dw = radius1*(1 - TMath::Cos(kPI*angle/180)) ;
01291       } else {
01292          fs1 = Readfs();
01293          radius2 = fs1.Height();
01294          radius1 = radius2  * 2 / 3;
01295          dw = radius1*(1 - TMath::Cos(kPI*angle/180)) ;
01296          Double_t x1 = x+l2+radius1 ;
01297          Double_t x2 = x+5*l2+2*dw+fs1.Width()-radius1 ;
01298          Double_t y1 = y - (fs1.Over() - fs1.Under())/2. ;
01299          DrawParenthesis(x1,y1,radius1,radius2,180-angle,180+angle,spec) ;
01300          DrawParenthesis(x2,y1,radius1,radius2,360-angle,360+angle,spec) ;
01301          Analyse(x+3*l2+dw,y,spec,text+3,length-3);
01302       }
01303      // result = TLatexFormSize(fs1.Width()+3*l,fs1.Over(),fs1.Under());
01304       result.Set(fs1.Width()+3*l+2*dw,fs1.Over(),fs1.Under());
01305    }
01306    else if (opAbs) {  // operator #||{arg}
01307       Double_t l = GetHeight()*spec.fSize/4;
01308       Double_t l2 = l/2 ;
01309       if (!fShow) {
01310          fs1 = Anal1(spec,text+3,length-3);
01311          Savefs(&fs1);
01312       } else {
01313          fs1 = Readfs();
01314          Analyse(x+l2+l,y,spec,text+3,length-3);
01315          DrawLine(x+l2,y-fs1.Over(),x+l2,y+fs1.Under(),spec);
01316          DrawLine(x+l2+fs1.Width()+2*l,y-fs1.Over(),x+l2+fs1.Width()+2*l,y+fs1.Under(),spec);
01317       }
01318       result.Set(fs1.Width()+3*l,fs1.Over(),fs1.Under());
01319    }
01320    else if (opBigCurly) { // big curly bracket  #{}{arg}
01321       Double_t l = GetHeight()*spec.fSize/4;
01322       Double_t l2 = l/2 ;
01323       Double_t l8 , ltip;
01324 
01325       if (!fShow) {
01326          fs1 = Anal1(spec,text+3,length-3);
01327          l8 = fs1.Height()/8 ;
01328          ltip = TMath::Min(l8,l) ;
01329          l = ltip ;
01330          Savefs(&fs1);
01331       } else {
01332          fs1 = Readfs();
01333          Double_t y2 = y + (fs1.Under()-fs1.Over())/2 ;
01334          l8 = fs1.Height()/8 ;
01335          ltip = TMath::Min(l8,l) ;
01336          l = ltip ;
01337          Analyse(x+l+ltip+l2,y,spec,text+3,length-3);
01338          // Draw open curly bracket
01339          // Vertical lines
01340          DrawLine(x+l2+ltip,y-fs1.Over(),x+l2+ltip,y2-ltip,spec);
01341          DrawLine(x+l2+ltip,y2+ltip,x+l2+ltip,y+fs1.Under(),spec);
01342          // top and bottom lines
01343          DrawLine(x+l2+ltip,y-fs1.Over(),x+l2+ltip+l,y-fs1.Over(),spec);
01344          DrawLine(x+l2+ltip,y+fs1.Under(),x+l2+ltip+l,y+fs1.Under(),spec);
01345          // < sign
01346          DrawLine(x+l2,y2,x+l2+ltip,y2-ltip,spec);
01347          DrawLine(x+l2,y2,x+l2+ltip,y2+ltip,spec);
01348 
01349          // Draw close curly bracket
01350          // vertical lines
01351          DrawLine(x+l2+ltip+fs1.Width()+2*l,y-fs1.Over(),x+l2+ltip+fs1.Width()+2*l,y2-ltip,spec);
01352          DrawLine(x+l2+ltip+fs1.Width()+2*l,y2+ltip,x+l2+ltip+fs1.Width()+2*l,y+fs1.Under(),spec);
01353          // Top and bottom lines
01354          DrawLine(x+l2+fs1.Width()+l+ltip,y-fs1.Over(),x+l2+ltip+fs1.Width()+2*l,y-fs1.Over(),spec);
01355          DrawLine(x+l2+fs1.Width()+l+ltip,y+fs1.Under(),x+l2+ltip+fs1.Width()+2*l,y+fs1.Under(),spec);
01356          // > sign
01357          DrawLine(x+l2+ltip+2*l+fs1.Width(),y2-ltip,x+l2+2*l+2*ltip+fs1.Width(),y2,spec);
01358          DrawLine(x+l2+ltip+2*l+fs1.Width(),y2+ltip,x+l2+2*l+2*ltip+fs1.Width(),y2,spec);
01359       }
01360       result.Set(fs1.Width()+3*l+2*ltip,fs1.Over(),fs1.Under()) ;;
01361    }
01362    else if (opFrac>-1) { // \frac found
01363       if (opCurlyCurly==-1) { // }{ not found
01364          // arguments missing for \frac
01365          fError = "Missing denominator for #frac";
01366          return TLatexFormSize(0,0,0);
01367       }
01368       Double_t height = GetHeight()*spec.fSize/8;
01369       if (!fShow) {
01370          fs1 = Anal1(spec,text+opFrac+6,opCurlyCurly-opFrac-6);
01371          fs2 = Anal1(spec,text+opCurlyCurly+2,length-opCurlyCurly-3);
01372          Savefs(&fs1);
01373          Savefs(&fs2);
01374       } else {
01375          fs2 = Readfs();
01376          fs1 = Readfs();
01377          Double_t addW1,addW2;
01378          if (fs1.Width()<fs2.Width()) {
01379             addW1 = (fs2.Width()-fs1.Width())/2;
01380             addW2 = 0;
01381          } else {
01382             addW1 = 0;
01383             addW2 = (fs1.Width()-fs2.Width())/2;
01384          }
01385          Analyse(x+addW2,y+fs2.Over()-height,spec,text+opCurlyCurly+2,length-opCurlyCurly-3);  // denominator
01386          Analyse(x+addW1,y-fs1.Under()-3*height,spec,text+opFrac+6,opCurlyCurly-opFrac-6); //numerator
01387 
01388          DrawLine(x,y-2*height,x+TMath::Max(fs1.Width(),fs2.Width()),y-2*height,spec);
01389       }
01390 
01391       result.Set(TMath::Max(fs1.Width(),fs2.Width()),fs1.Height()+3*height,fs2.Height()-height);
01392 
01393    }
01394    else if (opSplitLine>-1) { // \splitline found
01395       if (opCurlyCurly==-1) { // }{ not found
01396          // arguments missing for \splitline
01397          fError = "Missing second line for #splitline";
01398          return TLatexFormSize(0,0,0);
01399       }
01400       Double_t height = GetHeight()*spec.fSize/8;
01401       if (!fShow) {
01402          fs1 = Anal1(spec,text+opSplitLine+11,opCurlyCurly-opSplitLine-11);
01403          fs2 = Anal1(spec,text+opCurlyCurly+2,length-opCurlyCurly-3);
01404          Savefs(&fs1);
01405          Savefs(&fs2);
01406       } else {
01407          fs2 = Readfs();
01408          fs1 = Readfs();
01409          Analyse(x,y+fs2.Over()-height,spec,text+opCurlyCurly+2,length-opCurlyCurly-3);  // second line
01410          Analyse(x,y-fs1.Under()-3*height,spec,text+opSplitLine+11,opCurlyCurly-opSplitLine-11); //first line
01411       }
01412 
01413       result.Set(TMath::Max(fs1.Width(),fs2.Width()),fs1.Height()+3*height,fs2.Height()-height);
01414 
01415    }
01416    else if (opSqrt>-1) { // \sqrt found
01417       if (!fShow) {
01418          if (opSquareCurly>-1) {
01419             // power nth  #sqrt[n]{arg}
01420             fs1 = Anal1(specNewSize,text+opSqrt+6,opSquareCurly-opSqrt-6);
01421             fs2 = Anal1(spec,text+opSquareCurly+1,length-opSquareCurly-1);
01422             Savefs(&fs1);
01423             Savefs(&fs2);
01424             result.Set(fs2.Width()+ GetHeight()*spec.fSize/10+TMath::Max(GetHeight()*spec.fSize/2,(Double_t)fs1.Width()),
01425                        fs2.Over()+fs1.Height()+GetHeight()*spec.fSize/4,fs2.Under());
01426          } else {
01427             fs1 = Anal1(spec,text+opSqrt+5,length-opSqrt-5);
01428             Savefs(&fs1);
01429             result.Set(fs1.Width()+GetHeight()*spec.fSize/2,fs1.Over()+GetHeight()*spec.fSize/4,fs1.Under());
01430          }
01431       } else {
01432          if (opSquareCurly>-1) { // ]{
01433             fs2 = Readfs();
01434             fs1 = Readfs();
01435             Double_t pas = TMath::Max(GetHeight()*spec.fSize/2,(Double_t)fs1.Width());
01436             Double_t pas2 = pas + GetHeight()*spec.fSize/10;
01437             Double_t y1 = y-fs2.Over() ;
01438             Double_t y2 = y+fs2.Under() ;
01439             Double_t y3 = y1-GetHeight()*spec.fSize/4;
01440             Analyse(x+pas2,y,spec,text+opSquareCurly+1,length-opSquareCurly-1);
01441             Analyse(x,y-fs2.Over()-fs1.Under(),specNewSize,text+opSqrt+6,opSquareCurly-opSqrt-6); // indice
01442             DrawLine(x,y1,x+pas,y2,spec);
01443             DrawLine(x+pas,y2,x+pas,y3,spec);
01444             DrawLine(x+pas,y3,x+pas2+fs2.Width(),y3,spec);
01445          } else {
01446             fs1 = Readfs();
01447             Double_t x1 = x+GetHeight()*spec.fSize*2/5 ;
01448             Double_t x2 = x+GetHeight()*spec.fSize/2+fs1.Width() ;
01449             Double_t y1 = y-fs1.Over() ;
01450             Double_t y2 = y+fs1.Under() ;
01451             Double_t y3 = y1-GetHeight()*spec.fSize/4;
01452 
01453             Analyse(x+GetHeight()*spec.fSize/2,y,spec,text+opSqrt+6,length-opSqrt-7);
01454 
01455             Short_t lineW = GetLineWidth();
01456             Double_t dx = (y2-y3)/8;
01457             SetLineWidth(TMath::Max(2,(Int_t)(dx/2)));
01458             DrawLine(x-dx,y1,x1-dx,y2,spec);
01459             SetLineWidth((Int_t)(dx/4));
01460             DrawLine(x1-dx,y2,x1,y3,spec);
01461             DrawLine(x1,y3,x2,y3,spec);
01462             SetLineWidth(lineW);
01463          }
01464       }
01465    }
01466    else if (opColor>-1) { // \color found
01467       if (opSquareCurly==-1) {
01468          // color number is not specified
01469          fError = "Missing color number. Syntax is #color[(Int_t)nb]{ ... }";
01470          return TLatexFormSize(0,0,0);
01471       }
01472       TextSpec_t newSpec = spec;
01473       Char_t *nb = new Char_t[opSquareCurly-opColor-6];
01474       strncpy(nb,text+opColor+7,opSquareCurly-opColor-7);
01475       nb[opSquareCurly-opColor-7] = 0;
01476       if (sscanf(nb,"%d",&newSpec.fColor) < 1) {
01477          delete[] nb;
01478          // color number is invalid
01479          fError = "Invalid color number. Syntax is #color[(Int_t)nb]{ ... }";
01480          return TLatexFormSize(0,0,0);
01481       }
01482       delete[] nb;
01483       if (!fShow) {
01484          result = Anal1(newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
01485       } else {
01486          Analyse(x,y,newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
01487       }
01488    }
01489    else if (opFont>-1) { // \font found
01490       if (opSquareCurly==-1) {
01491          // font number is not specified
01492          fError = "Missing font number. Syntax is #font[nb]{ ... }";
01493          return TLatexFormSize(0,0,0);
01494       }
01495       TextSpec_t newSpec = spec;
01496       Char_t *nb = new Char_t[opSquareCurly-opFont-5];
01497       strncpy(nb,text+opFont+6,opSquareCurly-opFont-6);
01498       nb[opSquareCurly-opFont-6] = 0;
01499       if (sscanf(nb,"%d",&newSpec.fFont) < 1) {
01500          delete[] nb;
01501          // font number is invalid
01502          fError = "Invalid font number. Syntax is #font[(Int_t)nb]{ ... }";
01503          return TLatexFormSize(0,0,0);
01504       }
01505       delete[] nb;
01506       if (!fShow) {
01507          result = Anal1(newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
01508       } else {
01509          Analyse(x,y,newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
01510       }
01511    }
01512    else if (opKern>-1) { // #kern found
01513       if (opSquareCurly==-1) {
01514          // horizontal shift is not specified
01515          fError = "Missing horizontal shift number. Syntax is #kern[dx]{ ... }";
01516          return TLatexFormSize(0,0,0);
01517       }
01518       Char_t *dxc = new Char_t[opSquareCurly-opKern-5];
01519       strncpy(dxc,text+opKern+6,opSquareCurly-opKern-6);
01520       dxc[opSquareCurly-opKern-6] = 0;
01521       Float_t dx = 0;
01522       if (sscanf(dxc,"%f",&dx) < 1) {
01523          delete[] dxc;
01524          // horizontal shift number is invalid
01525          fError = "Invalid horizontal shift number. Syntax is #kern[(Float_t)dx]{ ... }";
01526          return TLatexFormSize(0,0,0);
01527       }
01528       delete[] dxc;
01529       if (!fShow) {
01530          fs1 = Anal1(spec,text+opSquareCurly+1,length-opSquareCurly-1);
01531          Savefs(&fs1);
01532          Double_t ddx = dx * fs1.Width();
01533          result = TLatexFormSize(fs1.Width() + ddx, fs1.Over(), fs1.Under());
01534       } else {
01535          fs1 = Readfs();
01536          Double_t ddx = dx * fs1.Width();
01537          Analyse(x + ddx,y,spec,text+opSquareCurly+1,length-opSquareCurly-1);
01538       }
01539    }
01540    else if (opLower>-1) { // #lower found
01541       if (opSquareCurly==-1) {
01542          // vertical shift is not specified
01543          fError = "Missing vertical shift number. Syntax is #lower[dy]{ ... }";
01544          return TLatexFormSize(0,0,0);
01545       }
01546       Char_t *dyc = new Char_t[opSquareCurly-opLower-6];
01547       strncpy(dyc,text+opLower+7,opSquareCurly-opLower-7);
01548       dyc[opSquareCurly-opLower-7] = 0;
01549       Float_t dy = 0;
01550       if (sscanf(dyc,"%f",&dy) < 1) {
01551          delete[] dyc;
01552          // vertical shift number is invalid
01553          fError = "Invalid vertical shift number. Syntax is #lower[(Float_t)dy]{ ... }";
01554          return TLatexFormSize(0,0,0);
01555       }
01556       delete[] dyc;
01557       if (!fShow) {
01558          fs1 = Anal1(spec,text+opSquareCurly+1,length-opSquareCurly-1);
01559          Savefs(&fs1);
01560          Double_t ddy = dy * (fs1.Over() + fs1.Under());
01561          result = TLatexFormSize(fs1.Width(), fs1.Over() + ddy, fs1.Under() + ddy);
01562       } else {
01563          fs1 = Readfs();
01564          Double_t ddy = dy * (fs1.Over() + fs1.Under());
01565          Analyse(x,y + ddy,spec,text+opSquareCurly+1,length-opSquareCurly-1);
01566       }
01567    }
01568    else if (opScale>-1) { // \scale found
01569       if (opSquareCurly==-1) {
01570          // scale factor is not specified
01571          fError = "Missing scale factor. Syntax is #scale[(Double_t)nb]{ ... }";
01572          return TLatexFormSize(0,0,0);
01573       }
01574       TextSpec_t newSpec = spec;
01575       Char_t *nb = new Char_t[opSquareCurly-opScale-6];
01576       strncpy(nb,text+opScale+7,opSquareCurly-opScale-7);
01577       nb[opSquareCurly-opScale-7] = 0;
01578       if (sscanf(nb,"%lf",&newSpec.fSize) < 1) {
01579          delete[] nb;
01580          // scale factor is invalid
01581          fError = "Invalid scale factor. Syntax is #factor[(Double_t)nb]{ ... }";
01582          return TLatexFormSize(0,0,0);
01583       }
01584       newSpec.fSize *= spec.fSize;
01585       delete[] nb;
01586       if (!fShow) {
01587          result = Anal1(newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
01588       } else {
01589          Analyse(x,y,newSpec,text+opSquareCurly+1,length-opSquareCurly-1);
01590       }
01591    }
01592    else if (opBf>-1) { // operator #bf{arg}
01593       TextSpec_t newSpec = spec;
01594       Int_t lut[] = {3, 13, 1, 6, 7, 4, 5, 10, 11, 8, 9, 12, 2, 14, 15};
01595       Int_t fontId = (newSpec.fFont/10);
01596       if ((fontId >= 1) && (fontId <= (Int_t)(sizeof(lut)/sizeof(lut[0])))) fontId = lut[fontId-1];
01597       newSpec.fFont = fontId*10 + newSpec.fFont%10;
01598       if (!fShow) {
01599          fs1 = Anal1(newSpec,text+3,length-3);
01600          Savefs(&fs1);
01601       } else {
01602          fs1 = Readfs();
01603          Analyse(x,y,newSpec,text+3,length-3);
01604       }
01605       result = fs1;
01606    }
01607    else if (opIt>-1) { // operator #it{arg}
01608       TextSpec_t newSpec = spec;
01609       Int_t lut[] = {13, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 15, 1, 14, 12};
01610       Int_t fontId = (newSpec.fFont/10);
01611       if ((fontId >= 1) && (fontId <= (Int_t)(sizeof(lut)/sizeof(lut[0])))) fontId = lut[fontId-1];
01612       newSpec.fFont = fontId*10 + newSpec.fFont%10;
01613       fItalic = !fItalic;
01614       if (!fShow) {
01615          fs1 = Anal1(newSpec,text+3,length-3);
01616          Savefs(&fs1);
01617       } else {
01618          fs1 = Readfs();
01619          Analyse(x,y,newSpec,text+3,length-3);
01620       }
01621       fItalic = !fItalic;
01622       result = fs1;
01623    }
01624    else { // no operators found, it is a character string
01625       SetTextSize(spec.fSize);
01626       SetTextAngle(spec.fAngle);
01627       SetTextColor(spec.fColor);
01628       SetTextFont(spec.fFont);
01629       SetTextAlign(11);
01630       TAttText::Modify();
01631       UInt_t w=0,h=0;
01632 
01633       Int_t leng = strlen(text) ;
01634 
01635       quote1 = quote2 = kFALSE ;
01636       Char_t *p ;
01637       for (i=0 ; i<leng ; i++) {
01638          switch (text[i]) {
01639             case '\'' : quote1 = !quote1 ; break ; // single quote symbol not correctly interpreted when PostScript
01640             case '"'  : quote2 = !quote2 ;  break ;
01641          }
01642          //if (quote1 || quote2) continue ;
01643          if (text[i] == '@') {  // @ symbol not correctly interpreted when PostScript
01644             p = &text[i] ;
01645             if ( *(p+1) == '{' || *(p+1) == '}' || *(p+1) == '[' || *(p+1) == ']') {
01646                while (*p != 0) {
01647                   *p = *(p+1) ; p++ ;
01648                }
01649                leng-- ;
01650             }
01651          }
01652       }
01653       text[leng] = 0 ;
01654 
01655       if (fShow) {
01656          // paint the Latex sub-expression per sub-expression
01657          Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
01658          Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
01659          Double_t angle   = kPI*spec.fAngle/180.;
01660          Double_t xx = gPad->AbsPixeltoX(Int_t((x-xOrigin)*TMath::Cos(angle)+(y-yOrigin)*TMath::Sin(angle)+xOrigin));
01661          Double_t yy = gPad->AbsPixeltoY(Int_t((x-xOrigin)*TMath::Sin(-angle)+(y-yOrigin)*TMath::Cos(angle)+yOrigin));
01662          gPad->PaintText(xx,yy,text);
01663       } else {
01664          GetTextExtent(w,h,text);
01665          Double_t width = w;
01666          UInt_t a,d;
01667          GetTextAscentDescent(a, d, text);
01668          fs1.Set(width,a,d);
01669       }
01670 
01671       result = fs1;
01672    }
01673 
01674    delete[] text;
01675 
01676    return result;
01677 }
01678 
01679 
01680 //______________________________________________________________________________
01681 TLatex *TLatex::DrawLatex(Double_t x, Double_t y, const char *text)
01682 {
01683    // Make a copy of this object with the new parameters
01684    // And copy object attributes
01685 
01686    TLatex *newtext = new TLatex(x, y, text);
01687    TAttText::Copy(*newtext);
01688    newtext->SetBit(kCanDelete);
01689    if (TestBit(kTextNDC)) newtext->SetNDC();
01690    newtext->AppendPad();
01691    return newtext;
01692 }
01693 
01694 
01695 //______________________________________________________________________________
01696 void TLatex::DrawLine(Double_t x1, Double_t y1, Double_t x2, Double_t y2, TextSpec_t spec)
01697 {
01698    // Draw a line in a Latex formula
01699 
01700    Double_t sinang  = TMath::Sin(spec.fAngle/180*kPI);
01701    Double_t cosang  = TMath::Cos(spec.fAngle/180*kPI);
01702    Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
01703    Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
01704    Double_t xx  = gPad->AbsPixeltoX(Int_t((x1-xOrigin)*cosang+(y1-yOrigin)*sinang+xOrigin));
01705    Double_t yy  = gPad->AbsPixeltoY(Int_t((x1-xOrigin)*-sinang+(y1-yOrigin)*cosang+yOrigin));
01706 
01707    Double_t xx2 = gPad->AbsPixeltoX(Int_t((x2-xOrigin)*cosang+(y2-yOrigin)*sinang+xOrigin));
01708    Double_t yy2 = gPad->AbsPixeltoY(Int_t((x2-xOrigin)*-sinang+(y2-yOrigin)*cosang+yOrigin));
01709 
01710    SetLineColor(spec.fColor);
01711    TAttLine::Modify();
01712    gPad->PaintLine(xx,yy,xx2,yy2);
01713 }
01714 
01715 
01716 //______________________________________________________________________________
01717 void TLatex::DrawCircle(Double_t x1, Double_t y1, Double_t r, TextSpec_t spec )
01718 {
01719    // Draw an arc of ellipse in a Latex formula (right or left parenthesis)
01720 
01721    if (r < 1) r = 1;
01722    Double_t sinang  = TMath::Sin(spec.fAngle/180*kPI);
01723    Double_t cosang  = TMath::Cos(spec.fAngle/180*kPI);
01724    Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
01725    Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
01726 
01727    const Int_t np = 40;
01728    Double_t dphi = 2*kPI/np;
01729    Double_t x[np+3], y[np+3];
01730    Double_t angle,dx,dy;
01731 
01732    SetLineColor(spec.fColor);
01733    TAttLine::Modify();  //Change line attributes only if necessary
01734 
01735    for (Int_t i=0;i<=np;i++) {
01736       angle = Double_t(i)*dphi;
01737       dx    = r*TMath::Cos(angle) +x1 -xOrigin;
01738       dy    = r*TMath::Sin(angle) +y1 -yOrigin;
01739       x[i]  = gPad->AbsPixeltoX(Int_t( dx*cosang+ dy*sinang +xOrigin));
01740       y[i]  = gPad->AbsPixeltoY(Int_t(-dx*sinang+ dy*cosang +yOrigin));
01741    }
01742    gPad->PaintPolyLine(np+1,x,y);
01743 }
01744 
01745 
01746 //______________________________________________________________________________
01747 void TLatex::DrawParenthesis(Double_t x1, Double_t y1, Double_t r1, Double_t r2,
01748                      Double_t  phimin, Double_t  phimax, TextSpec_t spec )
01749 {
01750    // Draw an arc of ellipse in a Latex formula (right or left parenthesis)
01751 
01752    if (r1 < 1) r1 = 1;
01753    if (r2 < 1) r2 = 1;
01754    Double_t sinang  = TMath::Sin(spec.fAngle/180*kPI);
01755    Double_t cosang  = TMath::Cos(spec.fAngle/180*kPI);
01756    Double_t xOrigin = (Double_t)gPad->XtoAbsPixel(fX);
01757    Double_t yOrigin = (Double_t)gPad->YtoAbsPixel(fY);
01758 
01759    const Int_t np = 40;
01760    Double_t dphi = (phimax-phimin)*kPI/(180*np);
01761    Double_t x[np+3], y[np+3];
01762    Double_t angle,dx,dy ;
01763 
01764    SetLineColor(spec.fColor);
01765    TAttLine::Modify();  //Change line attributes only if necessary
01766 
01767    for (Int_t i=0;i<=np;i++) {
01768       angle = phimin*kPI/180 + Double_t(i)*dphi;
01769       dx    = r1*TMath::Cos(angle) +x1 -xOrigin;
01770       dy    = r2*TMath::Sin(angle) +y1 -yOrigin;
01771       x[i]  = gPad->AbsPixeltoX(Int_t( dx*cosang+dy*sinang +xOrigin));
01772       y[i]  = gPad->AbsPixeltoY(Int_t(-dx*sinang+dy*cosang +yOrigin));
01773    }
01774    gPad->PaintPolyLine(np+1,x,y);
01775 }
01776 
01777 
01778 //______________________________________________________________________________
01779 void TLatex::Paint(Option_t *)
01780 {
01781    // Paint.
01782 
01783    Double_t xsave = fX;
01784    Double_t ysave = fY;
01785    if (TestBit(kTextNDC)) {
01786       fX = gPad->GetX1() + xsave*(gPad->GetX2() - gPad->GetX1());
01787       fY = gPad->GetY1() + ysave*(gPad->GetY2() - gPad->GetY1());
01788       PaintLatex(fX,fY,GetTextAngle(),GetTextSize(),GetTitle());
01789    } else {
01790       PaintLatex(gPad->XtoPad(fX),gPad->YtoPad(fY),GetTextAngle(),GetTextSize(),GetTitle());
01791    }
01792    fX = xsave;
01793    fY = ysave;
01794 }
01795 
01796 
01797 //______________________________________________________________________________
01798 void TLatex::PaintLatex(Double_t x, Double_t y, Double_t angle, Double_t size, const Char_t *text1)
01799 {
01800    // Main drawing function
01801    //
01802    // Warning: Unlike most others "XYZ::PaintXYZ" methods, PaintLatex modifies
01803    //          the TLatex data members.
01804 
01805    TAttText::Modify();  // Change text attributes only if necessary.
01806 
01807    // Do not use Latex if font is low precision.
01808    if (fTextFont%10 < 2) {
01809       if (gVirtualX) gVirtualX->SetTextAngle(angle);
01810       if (gVirtualPS) gVirtualPS->SetTextAngle(angle);
01811       gPad->PaintText(x,y,text1);
01812       return;
01813    }
01814 
01815    TString newText = text1;
01816    if( newText.Length() == 0) return;
01817 
01818    Double_t saveSize = size;
01819    Int_t saveFont = fTextFont;
01820    if (fTextFont%10 > 2) {
01821       UInt_t w = TMath::Abs(gPad->XtoAbsPixel(gPad->GetX2()) -
01822                             gPad->XtoAbsPixel(gPad->GetX1()));
01823       UInt_t h = TMath::Abs(gPad->YtoAbsPixel(gPad->GetY2()) -
01824                             gPad->YtoAbsPixel(gPad->GetY1()));
01825       if (w < h)
01826          size = size/w;
01827       else
01828          size = size/h;
01829       SetTextFont(10*(saveFont/10) + 2);
01830    }
01831    if (gVirtualPS) gVirtualPS->SetBit(kLatex);
01832 
01833    fError = 0 ;
01834    if (CheckLatexSyntax(newText)) {
01835       cout<<"\n*ERROR<TLatex>: "<<fError<<endl;
01836       cout<<"==> "<<text1<<endl;
01837       return ;
01838    }
01839    fError = 0 ;
01840 
01841    Int_t length = newText.Length() ;
01842    const Char_t *text = newText.Data() ;
01843 
01844    fX=x;
01845    fY=y;
01846    x = gPad->XtoAbsPixel(x);
01847    y = gPad->YtoAbsPixel(y);
01848    fShow = kFALSE ;
01849    TLatexFormSize fs = FirstParse(angle,size,text);
01850 
01851    fOriginSize = size;
01852 
01853    // Get current line attributes.
01854    Short_t lineW = GetLineWidth();
01855    Int_t lineC = GetLineColor();
01856 
01857    TextSpec_t spec;
01858    spec.fAngle = angle;
01859    spec.fSize  = size;
01860    spec.fColor = GetTextColor();
01861    spec.fFont  = GetTextFont();
01862    Short_t halign = fTextAlign/10;
01863    Short_t valign = fTextAlign - 10*halign;
01864    TextSpec_t newSpec = spec;
01865    if (fError != 0) {
01866       cout<<"*ERROR<TLatex>: "<<fError<<endl;
01867       cout<<"==> "<<text<<endl;
01868    } else {
01869       fShow = kTRUE;
01870       newSpec.fSize = size;
01871 
01872       switch (valign) {
01873          case 0: y -= fs.Under() ; break;
01874          case 1: break;
01875          case 2: y += fs.Height()*0.5-fs.Under(); y++; break;
01876          case 3: y += fs.Over() ; break;
01877       }
01878       switch (halign) {
01879          case 2: x -= fs.Width()/2  ; break;
01880          case 3: x -= fs.Width()    ; break;
01881       }
01882       Analyse(x,y,newSpec,text,length);
01883    }
01884 
01885    SetTextSize(saveSize);
01886    SetTextAngle(angle);
01887    SetTextFont(saveFont);
01888    SetTextColor(spec.fColor);
01889    SetTextAlign(valign+10*halign);
01890    SetLineWidth(lineW);
01891    SetLineColor(lineC);
01892    delete[] fTabSize;
01893 
01894    if (gVirtualPS) gVirtualPS->ResetBit(kLatex);
01895 }
01896 
01897 
01898 //______________________________________________________________________________
01899 Int_t TLatex::CheckLatexSyntax(TString &text)
01900 {
01901    // Check if the Latex syntax is correct
01902 
01903    const Char_t *kWord1[] = {"{}^{","{}_{","^{","_{","#scale{","#color{","#font{","#sqrt{","#[]{","#{}{","#||{",
01904                        "#bar{","#vec{","#dot{","#hat{","#ddot{","#acute{","#grave{","#check{","#tilde{","#slash{","#bf{","#it{",
01905                        "\\scale{","\\color{","\\font{","\\sqrt{","\\[]{","\\{}{","\\||{","#(){","\\(){",
01906                        "\\bar{","\\vec{","\\dot{","\\hat{","\\ddot{","\\acute{","\\grave{","\\check{","\\bf{","\\it{"}; // check for }
01907    const Char_t *kWord2[] = {"#scale[","#color[","#font[","#sqrt[","#kern[","#lower[","\\scale[","\\color[","\\font[","\\sqrt[","\\kern[","\\lower["}; // check for ]{ + }
01908    const Char_t *kWord3[] = {"#frac{","\\frac{","#splitline{","\\splitline{"}; // check for }{ then }
01909    const Char_t *kLeft1[] = {"#left[","\\left[","#left{","\\left{","#left|","\\left|","#left(","\\left("};
01910    const Char_t *kLeft2[] = {"#[]{","#[]{","#{}{","#{}{","#||{","#||{","#(){","#(){"};
01911    const Char_t *kRight[] = {"#right]","\\right]","#right}","\\right}","#right|","\\right|","#right)","\\right)"};
01912    const Int_t lkWord1[]  = {4,4,2,2,7,7,6,6,4,4,4,5,5,5,5,6,7,7,7,7,7,4,4,7,7,6,6,4,4,4,4,4,5,5,5,5,6,7,7,7,4,4};
01913    const Int_t lkWord2[]  = {7,7,6,6,6,7,7,7,6,6,6,7} ;
01914    const Int_t lkWord3[]  = {6,6,11,11} ;
01915    Int_t nkWord1 = 42, nkWord2 = 12, nkWord3 = 4;
01916    Int_t i,k ;
01917    Int_t nLeft1 , nRight , nOfLeft, nOfRight;
01918    Int_t lLeft1 = 6 ;
01919    Int_t lLeft2 = 4 ;
01920    Int_t lRight = 7 ;
01921    nLeft1  = nRight   = 8 ;
01922    nOfLeft = nOfRight = 0 ;
01923 
01924    Char_t buf[11] ; for (i=0;i<11;i++) buf[i]=0;
01925    Bool_t opFound ;
01926    Int_t  opFrac = 0;
01927    Int_t length = text.Length() ;
01928 
01929    Int_t nOfCurlyBracket, nOfKW1, nOfKW2, nOfKW3, nOfSquareCurly, nOfCurlyCurly ;
01930    Int_t nOfExtraCurly = 0 , nOfExtraSquare = 0;
01931    Int_t nOfSquareBracket = 0 ;
01932    Int_t error = 0  ;
01933    Bool_t quote1 = kFALSE , quote2 = kFALSE;
01934 
01935    // first find and replace all occurences of "kLeft1" keyword by "kLeft2" keyword,
01936    // and all occurences of "kRight" keyword by "}".
01937    i = 0 ;
01938    while (i < length) {
01939       // The string in 'buf' does not need to be null terminated,
01940       // we will only check with strncmp.
01941       strncpy(buf,&text[i],TMath::Min(7,length-i));
01942       opFound = kFALSE ;
01943       for (k = 0 ; k < nLeft1 ; k++) {
01944          if (strncmp(buf,kLeft1[k],lLeft1)==0) {
01945             nOfLeft++ ;
01946             i+=lLeft1 ;
01947             opFound = kTRUE ;
01948             break ;
01949          }
01950       }
01951       if (opFound) continue ;
01952 
01953       for(k=0;k<nRight;k++) {
01954          if (strncmp(buf,kRight[k],lRight)==0) {
01955             nOfRight++ ;
01956             i+=lRight ;
01957             opFound = kTRUE ;
01958             break ;
01959          }
01960       }
01961       if (!opFound) i++ ;
01962    }
01963    if (nOfLeft != nOfRight) {
01964       printf(" nOfLeft = %d, nOfRight = %d\n",nOfLeft,nOfRight) ;
01965       error = 1 ;
01966       fError = "Operators \"#left\" and \"#right\" don't match !" ;
01967       goto ERROR_END ;
01968    }
01969 
01970    for (k = 0 ; k < nLeft1 ; k++) {
01971       text.ReplaceAll(kLeft1[k],lLeft1,kLeft2[k],lLeft2) ;
01972    }
01973    for (k = 0 ; k < nRight ; k++) {
01974       text.ReplaceAll(kRight[k],lRight,"}",1) ;
01975    }
01976    length = text.Length() ;
01977 
01978    i = nOfCurlyBracket = nOfKW1 = nOfKW2 = nOfKW3 = nOfSquareCurly = nOfCurlyCurly =0 ;
01979    while (i< length){
01980          switch (text[i]) {
01981             case '"' : quote1 = !quote1 ; break ;
01982             case '\'': quote2 = !quote2 ; break ;
01983          }
01984          // The string in 'buf' does not need to be null terminated,
01985          // we will only check with strncmp
01986          strncpy(buf,&text[i],TMath::Min(11,length-i));
01987          opFound = kFALSE ;
01988 
01989          for(k=0;k<nkWord1;k++) {
01990             if (strncmp(buf,kWord1[k],lkWord1[k])==0) {
01991                nOfKW1++ ;
01992                i+=lkWord1[k] ;
01993                opFound = kTRUE ;
01994                nOfCurlyBracket++ ;
01995                break ;
01996             }
01997          }
01998          if (opFound) continue ;
01999 
02000          for(k=0;k<nkWord2;k++) {
02001             if (strncmp(buf,kWord2[k],lkWord2[k])==0) {
02002                nOfKW2++ ;
02003                i+=lkWord2[k] ;
02004                opFound = kTRUE ;
02005                nOfSquareBracket++;
02006                break ;
02007             }
02008          }
02009          if (opFound) continue ;
02010 
02011          for(k=0;k<nkWord3;k++) {
02012             if (strncmp(buf,kWord3[k],lkWord3[k])==0) {
02013                nOfKW3++ ;
02014                i+=lkWord3[k] ;
02015                opFound = kTRUE ;
02016                opFrac++ ;
02017                nOfCurlyBracket++ ;
02018                break ;
02019             }
02020          }
02021          if (opFound) continue ;
02022          if (strncmp(buf,"}{",2) == 0 && opFrac) {
02023                opFrac-- ;
02024                nOfCurlyCurly++ ;
02025                i+= 2;
02026          }
02027          else if (strncmp(buf,"]{",2) == 0 && nOfSquareBracket) {
02028                nOfSquareCurly++ ;
02029                i+= 2 ;
02030                nOfCurlyBracket++ ;
02031                nOfSquareBracket-- ;
02032          }
02033          else if (strncmp(buf,"@{",2) == 0 || strncmp(buf,"@}",2) == 0) {
02034                i+= 2 ;
02035          }
02036          else if (strncmp(buf,"@[",2) == 0 || strncmp(buf,"@]",2) == 0) {
02037                i+= 2 ;
02038          }
02039          else if (text[i] == ']' ) {  // not belonging to a key word, add @ in front
02040                text.Insert(i,"@") ;
02041                length++ ;
02042                i+=2 ;
02043                nOfExtraSquare-- ;
02044          }
02045          else if (text[i] == '[' ) {  // not belonging to a key word, add @ in front
02046                text.Insert(i,"@") ;
02047                length++ ;
02048                i+=2 ;
02049                nOfExtraSquare++ ;
02050          }
02051          else if (text[i] == '{' ) {  // not belonging to a key word, add @ in front
02052                text.Insert(i,"@") ;
02053                length++ ;
02054                i+=2 ;
02055                nOfExtraCurly++ ;
02056          }
02057          else if (text[i] == '}' ) {
02058             if ( nOfCurlyBracket) {
02059                nOfCurlyBracket-- ;
02060                i++ ;
02061             } else  { // extra }, add @ in front
02062                text.Insert(i,"@") ;
02063                length++ ;
02064                i+=2 ;
02065                nOfExtraCurly-- ;
02066             }
02067          } else {
02068             i++ ;
02069             buf[1] = 0 ;
02070          }
02071    }
02072 
02073    if (nOfKW2 != nOfSquareCurly) {
02074       error = 1 ;
02075       fError = "Invalid number of \"]{\"" ;
02076    }
02077    else if (nOfKW3 != nOfCurlyCurly) {
02078       error = 1 ;
02079       fError = "Error in syntax of  \"#frac\"" ;
02080    }
02081    else if (nOfCurlyBracket  < 0) {
02082       error = 1 ;
02083       fError = "Missing \"{\"" ;
02084    }
02085    else if (nOfCurlyBracket  > 0) {
02086       error = 1 ;
02087       fError = "Missing \"}\"" ;
02088    }
02089    else if (nOfSquareBracket  < 0) {
02090       error  = 1 ;
02091       fError = "Missing \"[\"" ;
02092    }
02093    else if (nOfSquareBracket  > 0) {
02094       error = 1 ;
02095       fError = "Missing \"]\"" ;
02096    }
02097 
02098    ERROR_END:
02099    return error ;
02100 }
02101 
02102 
02103 //______________________________________________________________________________
02104 TLatexFormSize TLatex::FirstParse(Double_t angle, Double_t size, const Char_t *text)
02105 {
02106    // First parsing of the analyse sequence
02107 
02108    fError   = 0;
02109    fTabMax  = 100;
02110    fTabSize = new FormSize_t[fTabMax];
02111    // we assume less than 100 parts in one formula
02112    // we will reallocate if necessary.
02113    fPos        = 0;
02114    fShow       = kFALSE;
02115    fOriginSize = size;
02116 
02117    //get current line attributes
02118    Short_t lineW = GetLineWidth();
02119    Int_t lineC = GetLineColor();
02120 
02121    TextSpec_t spec;
02122    spec.fAngle = angle;
02123    if (fTextFont%10 == 3) {
02124       Double_t hw = TMath::Max((Double_t)gPad->XtoPixel(gPad->GetX2()),
02125                                (Double_t)gPad->YtoPixel(gPad->GetY1()));
02126       spec.fSize = size/hw;
02127    } else {
02128       spec.fSize  = size;
02129    }
02130    spec.fColor = GetTextColor();
02131    spec.fFont  = GetTextFont();
02132    Short_t halign = fTextAlign/10;
02133    Short_t valign = fTextAlign - 10*halign;
02134 
02135    TLatexFormSize fs = Anal1(spec,text,strlen(text));
02136 
02137    SetTextSize(size);
02138    SetTextAngle(angle);
02139    SetTextFont(spec.fFont);
02140    SetTextColor(spec.fColor);
02141    SetTextAlign(valign+10*halign);
02142    SetLineWidth(lineW);
02143    SetLineColor(lineC);
02144    return fs;
02145 }
02146 
02147 
02148 //______________________________________________________________________________
02149 Double_t TLatex::GetHeight() const
02150 {
02151    // Return height of current pad in pixels
02152 
02153    Double_t w = gPad->GetAbsWNDC()*Double_t(gPad->GetWw());
02154    Double_t h = gPad->GetAbsHNDC()*Double_t(gPad->GetWh());
02155    if (w < h)
02156       return w;
02157    else
02158       return h;
02159 }
02160 
02161 
02162 //______________________________________________________________________________
02163 Double_t TLatex::GetXsize()
02164 {
02165    // Return size of the formula along X in pad coordinates
02166 
02167    if (!gPad) return 0;
02168    TString newText = GetTitle();
02169    if( newText.Length() == 0) return 0;
02170    fError = 0 ;
02171    if (CheckLatexSyntax(newText)) {
02172       cout<<"\n*ERROR<TLatex>: "<<fError<<endl;
02173       cout<<"==> "<<GetTitle()<<endl;
02174       return 0;
02175    }
02176    fError = 0 ;
02177 
02178    const Char_t *text = newText.Data() ;
02179    Double_t angle_old = GetTextAngle();
02180    TLatexFormSize fs = FirstParse(0,GetTextSize(),text);
02181    SetTextAngle(angle_old);
02182    delete[] fTabSize;
02183    return TMath::Abs(gPad->AbsPixeltoX(Int_t(fs.Width())) - gPad->AbsPixeltoX(0));
02184 }
02185 
02186 
02187 //______________________________________________________________________________
02188 void TLatex::GetBoundingBox(UInt_t &w, UInt_t &h, Bool_t angle)
02189 {
02190    // Return text size in pixels
02191 
02192    if (!gPad) return;
02193    TString newText = GetTitle();
02194    if( newText.Length() == 0) return;
02195    fError = 0 ;
02196    if (CheckLatexSyntax(newText)) {
02197       cout<<"\n*ERROR<TLatex>: "<<fError<<endl;
02198       cout<<"==> "<<GetTitle()<<endl;
02199       return;
02200    }
02201    fError = 0 ;
02202 
02203    if (angle) {
02204       Int_t cBoxX[4], cBoxY[4];
02205       Int_t ptx, pty;
02206       if (TestBit(kTextNDC)) {
02207          ptx = gPad->UtoPixel(fX);
02208          pty = gPad->VtoPixel(fY);
02209       } else {
02210          ptx = gPad->XtoAbsPixel(gPad->XtoPad(fX));
02211          pty = gPad->YtoAbsPixel(gPad->YtoPad(fY));
02212       }
02213       GetControlBox(ptx, pty, fTextAngle, cBoxX, cBoxY);
02214       Int_t x1 = cBoxX[0];
02215       Int_t x2 = cBoxX[0];
02216       Int_t y1 = cBoxY[0];
02217       Int_t y2 = cBoxY[0];
02218       for (Int_t i=1; i<4; i++) {
02219          if (cBoxX[i] < x1) x1 = cBoxX[i];
02220          if (cBoxX[i] > x2) x2 = cBoxX[i];
02221          if (cBoxY[i] < y1) y1 = cBoxY[i];
02222          if (cBoxY[i] > y2) y2 = cBoxY[i];
02223       }
02224       w = x2-x1;
02225       h = y2-y1;
02226    } else {
02227       const Char_t *text = newText.Data() ;
02228       TLatexFormSize fs = FirstParse(GetTextAngle(),GetTextSize(),text);
02229       delete[] fTabSize;
02230       w = (UInt_t)fs.Width();
02231       h = (UInt_t)fs.Height();
02232    }
02233 }
02234 
02235 
02236 //______________________________________________________________________________
02237 Double_t TLatex::GetYsize()
02238 {
02239    // Return size of the formula along Y in pad coordinates
02240 
02241    if (!gPad) return 0;
02242    TString newText = GetTitle();
02243    if( newText.Length() == 0) return 0;
02244    fError = 0 ;
02245    if (CheckLatexSyntax(newText)) {
02246       cout<<"\n*ERROR<TLatex>: "<<fError<<endl;
02247       cout<<"==> "<<GetTitle()<<endl;
02248       return 0;
02249    }
02250    fError = 0 ;
02251 
02252    const Char_t *text = newText.Data() ;
02253    TLatexFormSize fs = FirstParse(0,GetTextSize(),text);
02254    delete[] fTabSize;
02255    return TMath::Abs(gPad->AbsPixeltoY(Int_t(fs.Height())) - gPad->AbsPixeltoY(0));
02256 }
02257 
02258 
02259 //______________________________________________________________________________
02260 TLatexFormSize TLatex::Readfs()
02261 {
02262    // Read fs in fTabSize
02263 
02264    fPos--;
02265    TLatexFormSize result(fTabSize[fPos].fWidth,fTabSize[fPos].fOver,fTabSize[fPos].fUnder);
02266    return result;
02267 }
02268 
02269 
02270 //______________________________________________________________________________
02271 void TLatex::Savefs(TLatexFormSize *fs)
02272 {
02273    // Save fs values in array fTabSize
02274 
02275    fTabSize[fPos].fWidth  = fs->Width();
02276    fTabSize[fPos].fOver   = fs->Over();
02277    fTabSize[fPos].fUnder  = fs->Under();
02278    fPos++;
02279    if (fPos>=fTabMax) {
02280       // allocate more memory
02281       FormSize_t *temp = new FormSize_t[fTabMax+100];
02282       // copy array
02283       memcpy(temp,fTabSize,fTabMax*sizeof(FormSize_t));
02284       fTabMax += 100;
02285       // free previous array
02286       delete [] fTabSize;
02287       // swap pointers
02288       fTabSize = temp;
02289    }
02290 }
02291 
02292 
02293 //______________________________________________________________________________
02294 void TLatex::SavePrimitive(ostream &out, Option_t * /*= ""*/)
02295 {
02296    // Save primitive as a C++ statement(s) on output stream out
02297 
02298    char quote = '"';
02299    if (gROOT->ClassSaved(TLatex::Class())) {
02300       out<<"   ";
02301    } else {
02302       out<<"   TLatex *";
02303    }
02304    TString s = GetTitle();
02305    s.ReplaceAll("\"","\\\"");
02306    out<<"   tex = new TLatex("<<fX<<","<<fY<<","<<quote<<s.Data()<<quote<<");"<<endl;
02307    if (TestBit(kTextNDC)) out<<"tex->SetNDC();"<<endl;
02308 
02309    SaveTextAttributes(out,"tex",11,0,1,62,0.05);
02310    SaveLineAttributes(out,"tex",1,1,1);
02311 
02312    out<<"   tex->Draw();"<<endl;
02313 }
02314 
02315 
02316 //______________________________________________________________________________
02317 void TLatex::SetIndiceSize(Double_t factorSize)
02318 {
02319    // Set relative size of subscripts and superscripts
02320 
02321    fFactorSize = factorSize;
02322 }
02323 
02324 
02325 //______________________________________________________________________________
02326 void TLatex::SetLimitIndiceSize(Int_t limitFactorSize)
02327 {
02328    // Set limit for text resizing of subscipts and superscripts
02329 
02330    fLimitFactorSize = limitFactorSize;
02331 }

Generated on Tue Jul 5 14:14:28 2011 for ROOT_528-00b_version by  doxygen 1.5.1