python (3.11.7)

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