Home | History | Annotate | Download | only in lib-tk
      1 # Tkinter font wrapper
      2 #
      3 # written by Fredrik Lundh, February 1998
      4 #
      5 # FIXME: should add 'displayof' option where relevant (actual, families,
      6 #        measure, and metrics)
      7 #
      8 
      9 __version__ = "0.9"
     10 
     11 import Tkinter
     12 
     13 # weight/slant
     14 NORMAL = "normal"
     15 ROMAN = "roman"
     16 BOLD   = "bold"
     17 ITALIC = "italic"
     18 
     19 def nametofont(name):
     20     """Given the name of a tk named font, returns a Font representation.
     21     """
     22     return Font(name=name, exists=True)
     23 
     24 class Font:
     25 
     26     """Represents a named font.
     27 
     28     Constructor options are:
     29 
     30     font -- font specifier (name, system font, or (family, size, style)-tuple)
     31     name -- name to use for this font configuration (defaults to a unique name)
     32     exists -- does a named font by this name already exist?
     33        Creates a new named font if False, points to the existing font if True.
     34        Raises _Tkinter.TclError if the assertion is false.
     35 
     36        the following are ignored if font is specified:
     37 
     38     family -- font 'family', e.g. Courier, Times, Helvetica
     39     size -- font size in points
     40     weight -- font thickness: NORMAL, BOLD
     41     slant -- font slant: ROMAN, ITALIC
     42     underline -- font underlining: false (0), true (1)
     43     overstrike -- font strikeout: false (0), true (1)
     44 
     45     """
     46 
     47     def _set(self, kw):
     48         options = []
     49         for k, v in kw.items():
     50             options.append("-"+k)
     51             options.append(str(v))
     52         return tuple(options)
     53 
     54     def _get(self, args):
     55         options = []
     56         for k in args:
     57             options.append("-"+k)
     58         return tuple(options)
     59 
     60     def _mkdict(self, args):
     61         options = {}
     62         for i in range(0, len(args), 2):
     63             options[args[i][1:]] = args[i+1]
     64         return options
     65 
     66     def __init__(self, root=None, font=None, name=None, exists=False, **options):
     67         if not root:
     68             root = Tkinter._default_root
     69         if font:
     70             # get actual settings corresponding to the given font
     71             font = root.tk.splitlist(root.tk.call("font", "actual", font))
     72         else:
     73             font = self._set(options)
     74         if not name:
     75             name = "font" + str(id(self))
     76         self.name = name
     77 
     78         if exists:
     79             self.delete_font = False
     80             # confirm font exists
     81             if self.name not in root.tk.call("font", "names"):
     82                 raise Tkinter._tkinter.TclError, "named font %s does not already exist" % (self.name,)
     83             # if font config info supplied, apply it
     84             if font:
     85                 root.tk.call("font", "configure", self.name, *font)
     86         else:
     87             # create new font (raises TclError if the font exists)
     88             root.tk.call("font", "create", self.name, *font)
     89             self.delete_font = True
     90         # backlinks!
     91         self._root  = root
     92         self._split = root.tk.splitlist
     93         self._call  = root.tk.call
     94 
     95     def __str__(self):
     96         return self.name
     97 
     98     def __eq__(self, other):
     99         return self.name == other.name and isinstance(other, Font)
    100 
    101     def __getitem__(self, key):
    102         return self.cget(key)
    103 
    104     def __setitem__(self, key, value):
    105         self.configure(**{key: value})
    106 
    107     def __del__(self):
    108         try:
    109             if self.delete_font:
    110                 self._call("font", "delete", self.name)
    111         except (KeyboardInterrupt, SystemExit):
    112             raise
    113         except Exception:
    114             pass
    115 
    116     def copy(self):
    117         "Return a distinct copy of the current font"
    118         return Font(self._root, **self.actual())
    119 
    120     def actual(self, option=None):
    121         "Return actual font attributes"
    122         if option:
    123             return self._call("font", "actual", self.name, "-"+option)
    124         else:
    125             return self._mkdict(
    126                 self._split(self._call("font", "actual", self.name))
    127                 )
    128 
    129     def cget(self, option):
    130         "Get font attribute"
    131         return self._call("font", "config", self.name, "-"+option)
    132 
    133     def config(self, **options):
    134         "Modify font attributes"
    135         if options:
    136             self._call("font", "config", self.name,
    137                   *self._set(options))
    138         else:
    139             return self._mkdict(
    140                 self._split(self._call("font", "config", self.name))
    141                 )
    142 
    143     configure = config
    144 
    145     def measure(self, text):
    146         "Return text width"
    147         return int(self._call("font", "measure", self.name, text))
    148 
    149     def metrics(self, *options):
    150         """Return font metrics.
    151 
    152         For best performance, create a dummy widget
    153         using this font before calling this method."""
    154 
    155         if options:
    156             return int(
    157                 self._call("font", "metrics", self.name, self._get(options))
    158                 )
    159         else:
    160             res = self._split(self._call("font", "metrics", self.name))
    161             options = {}
    162             for i in range(0, len(res), 2):
    163                 options[res[i][1:]] = int(res[i+1])
    164             return options
    165 
    166 def families(root=None):
    167     "Get font families (as a tuple)"
    168     if not root:
    169         root = Tkinter._default_root
    170     return root.tk.splitlist(root.tk.call("font", "families"))
    171 
    172 def names(root=None):
    173     "Get names of defined fonts (as a tuple)"
    174     if not root:
    175         root = Tkinter._default_root
    176     return root.tk.splitlist(root.tk.call("font", "names"))
    177 
    178 # --------------------------------------------------------------------
    179 # test stuff
    180 
    181 if __name__ == "__main__":
    182 
    183     root = Tkinter.Tk()
    184 
    185     # create a font
    186     f = Font(family="times", size=30, weight=NORMAL)
    187 
    188     print f.actual()
    189     print f.actual("family")
    190     print f.actual("weight")
    191 
    192     print f.config()
    193     print f.cget("family")
    194     print f.cget("weight")
    195 
    196     print names()
    197 
    198     print f.measure("hello"), f.metrics("linespace")
    199 
    200     print f.metrics()
    201 
    202     f = Font(font=("Courier", 20, "bold"))
    203     print f.measure("hello"), f.metrics("linespace")
    204 
    205     w = Tkinter.Label(root, text="Hello, world", font=f)
    206     w.pack()
    207 
    208     w = Tkinter.Button(root, text="Quit!", command=root.destroy)
    209     w.pack()
    210 
    211     fb = Font(font=w["font"]).copy()
    212     fb.config(weight=BOLD)
    213 
    214     w.config(font=fb)
    215 
    216     Tkinter.mainloop()
    217