135135from sets import Set
136136from unicodedata import category
137137from warnings import warn
138+ import numpy
138139
139140from matplotlib import verbose
140141from matplotlib .pyparsing import Literal , Word , OneOrMore , ZeroOrMore , \
@@ -607,7 +608,11 @@ def _get_glyph(self, fontname, sym, fontsize):
607608 r'\backslash' : [('cal' , '\x6e ' ), ('ex' , '\xb2 ' ), ('ex' , '\x2f ' ),
608609 ('ex' , '\xc2 ' ), ('ex' , '\x2d ' )],
609610 r'/' : [('rm' , '/' ), ('ex' , '\xb1 ' ), ('ex' , '\x2e ' ),
610- ('ex' , '\xcb ' ), ('ex' , '\x2c ' )]
611+ ('ex' , '\xcb ' ), ('ex' , '\x2c ' )],
612+ r'\widehat' : [('rm' , '\x5e ' ), ('ex' , '\x62 ' ), ('ex' , '\x63 ' ),
613+ ('ex' , '\x64 ' )],
614+ r'\widetilde' : [('rm' , '\x7e ' ), ('ex' , '\x65 ' ), ('ex' , '\x66 ' ),
615+ ('ex' , '\x67 ' )]
611616 }
612617
613618 for alias , target in [('\leftparen' , '(' ),
@@ -1162,7 +1167,7 @@ def __init__(self, elements, h=0., m='additional'):
11621167 List .__init__ (self , elements )
11631168 self .vpack ()
11641169
1165- def vpack (self , h = 0. , m = 'additional' , l = float (' inf' )):
1170+ def vpack (self , h = 0. , m = 'additional' , l = float (numpy . inf )):
11661171 """The main duty of vpack is to compute the dimensions of the
11671172 resulting boxes, and to adjust the glue if one of those dimensions is
11681173 pre-specified.
@@ -1395,7 +1400,7 @@ def __init__(self):
13951400 self .super = None
13961401 Hlist .__init__ (self , [])
13971402
1398- class AutoSizedDelim (Hlist ):
1403+ class AutoHeightChar (Hlist ):
13991404 """A class that will create a character as close to the given height
14001405 and depth as possible. When using a font with multiple height versions
14011406 of some characters (such as the BaKoMa fonts), the correct glyph will
@@ -1425,6 +1430,34 @@ def __init__(self, c, height, depth, state, always=False):
14251430 shift = (depth - char .depth )
14261431 Hlist .__init__ (self , [char ])
14271432 self .shift_amount = shift
1433+
1434+ class AutoWidthChar (Hlist ):
1435+ """A class that will create a character as close to the given width
1436+ as possible. When using a font with multiple width versions
1437+ of some characters (such as the BaKoMa fonts), the correct glyph will
1438+ be selected, otherwise this will always just return a scaled version
1439+ of the glyph."""
1440+ def __init__ (self , c , width , state , always = False ):
1441+ alternatives = state .font_output .get_sized_alternatives_for_symbol (
1442+ state .font , c )
1443+
1444+ state = state .copy ()
1445+ big_enough = False
1446+ for fontname , sym in alternatives :
1447+ state .font = fontname
1448+ char = Char (sym , state )
1449+ if char .width > width :
1450+ big_enough = True
1451+ break
1452+
1453+ # If the largest option is still not big enough, just do
1454+ # simple scale on it.
1455+ if not big_enough :
1456+ factor = width / char .width
1457+ state .fontsize *= factor
1458+ char = Char (sym , state )
1459+
1460+ Hlist .__init__ (self , [char ])
14281461
14291462class Ship (object ):
14301463 """Once the boxes have been set up, this sends them to output.
@@ -1653,7 +1686,7 @@ def __init__(self):
16531686 bslash = Literal ('\\ ' )
16541687
16551688 accent = oneOf ("hat check dot breve acute ddot grave tilde bar "
1656- "vec \" ` ' ~ . ^" )
1689+ "vec \" ` ' ~ . ^ widehat widetilde " )
16571690
16581691 function = oneOf ("arccos csc ker min arcsin deg lg Pr arctan det "
16591692 "lim sec arg dim liminf sin cos exp limsup sinh "
@@ -1920,8 +1953,10 @@ def symbol(self, s, loc, toks):
19201953 r"\'" : r'\combiningacuteaccent' ,
19211954 r'\~' : r'\combiningtilde' ,
19221955 r'\.' : r'\combiningdotabove' ,
1923- r'\^' : r'\circumflexaccent' ,
1956+ r'\^' : r'\circumflexaccent'
19241957 }
1958+
1959+ _wide_accents = Set (r"\widehat \widetilde" .split ())
19251960
19261961 def accent (self , s , loc , toks ):
19271962 assert (len (toks )== 1 )
@@ -1931,7 +1966,10 @@ def accent(self, s, loc, toks):
19311966 if len (toks [0 ]) != 2 :
19321967 raise ParseFatalException ("Error parsing accent" )
19331968 accent , sym = toks [0 ]
1934- accent = Accent (self ._accent_map [accent ], self .get_state ())
1969+ if accent in self ._wide_accents :
1970+ accent = AutoWidthChar (accent , sym .width , state )
1971+ else :
1972+ accent = Accent (self ._accent_map [accent ], state )
19351973 centered = HCentered ([accent ])
19361974 centered .hpack (sym .width , 'exactly' )
19371975 centered .shift_amount = accent ._metrics .xmin
@@ -2154,7 +2192,7 @@ def sqrt(self, s, loc, toks):
21542192 # the height so it doesn't seem cramped
21552193 height = body .height - body .shift_amount + thickness * 5.0
21562194 depth = body .depth + body .shift_amount
2157- check = AutoSizedDelim (r'\sqrt' , height , depth , state , always = True )
2195+ check = AutoHeightChar (r'\sqrt' , height , depth , state , always = True )
21582196 height = check .height - check .shift_amount
21592197 depth = check .depth + check .shift_amount
21602198
@@ -2190,10 +2228,10 @@ def auto_sized_delimiter(self, s, loc, toks):
21902228 parts = []
21912229 # \left. and \right. aren't supposed to produce any symbols
21922230 if front != '.' :
2193- parts .append (AutoSizedDelim (front , height , depth , state ))
2231+ parts .append (AutoHeightChar (front , height , depth , state ))
21942232 parts .extend (middle .asList ())
21952233 if back != '.' :
2196- parts .append (AutoSizedDelim (back , height , depth , state ))
2234+ parts .append (AutoHeightChar (back , height , depth , state ))
21972235 hlist = Hlist (parts )
21982236 return hlist
21992237
0 commit comments