blob: 27e0cc849a85c7e8abdad7a4e30ae3320b63ec99 [file] [log] [blame]
Fredrik Lundhd4893982005-11-12 15:28:52 +00001# Tkinter font wrapper
Guido van Rossum3d16d3e1998-08-11 19:07:58 +00002#
Fredrik Lundhd4893982005-11-12 15:28:52 +00003# written by Fredrik Lundh, February 1998
Guido van Rossum3d16d3e1998-08-11 19:07:58 +00004#
5# FIXME: should add 'displayof' option where relevant (actual, families,
6# measure, and metrics)
Fred Draked038ca82000-10-23 18:31:14 +00007#
Guido van Rossum3d16d3e1998-08-11 19:07:58 +00008
9__version__ = "0.9"
10
Andrew Svetlov39f00372012-04-03 09:48:07 +030011import itertools
Georg Brandl14fc4272008-05-17 18:39:55 +000012import tkinter
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000013
Andrew Svetlov5af3e1a2012-04-03 09:39:47 +030014
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000015# weight/slant
16NORMAL = "normal"
Martin v. Löwis1ef23652003-06-14 21:40:04 +000017ROMAN = "roman"
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000018BOLD = "bold"
19ITALIC = "italic"
20
Andrew Svetlov5af3e1a2012-04-03 09:39:47 +030021
Martin v. Löwisfe84d172004-08-18 11:06:45 +000022def nametofont(name):
23 """Given the name of a tk named font, returns a Font representation.
24 """
25 return Font(name=name, exists=True)
Tim Petersa45cacf2004-08-20 03:47:14 +000026
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000027
Andrew Svetlov5af3e1a2012-04-03 09:39:47 +030028class Font:
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000029 """Represents a named font.
30
31 Constructor options are:
32
33 font -- font specifier (name, system font, or (family, size, style)-tuple)
Martin v. Löwisfe84d172004-08-18 11:06:45 +000034 name -- name to use for this font configuration (defaults to a unique name)
35 exists -- does a named font by this name already exist?
36 Creates a new named font if False, points to the existing font if True.
37 Raises _tkinter.TclError if the assertion is false.
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000038
Martin v. Löwisfe84d172004-08-18 11:06:45 +000039 the following are ignored if font is specified:
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000040
41 family -- font 'family', e.g. Courier, Times, Helvetica
42 size -- font size in points
43 weight -- font thickness: NORMAL, BOLD
Martin v. Löwis1ef23652003-06-14 21:40:04 +000044 slant -- font slant: ROMAN, ITALIC
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000045 underline -- font underlining: false (0), true (1)
46 overstrike -- font strikeout: false (0), true (1)
Tim Petersa45cacf2004-08-20 03:47:14 +000047
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000048 """
49
Andrew Svetlov39f00372012-04-03 09:48:07 +030050 counter = itertools.count(1)
51
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000052 def _set(self, kw):
53 options = []
54 for k, v in kw.items():
55 options.append("-"+k)
56 options.append(str(v))
57 return tuple(options)
58
59 def _get(self, args):
Fred Draked038ca82000-10-23 18:31:14 +000060 options = []
61 for k in args:
62 options.append("-"+k)
63 return tuple(options)
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000064
65 def _mkdict(self, args):
66 options = {}
67 for i in range(0, len(args), 2):
68 options[args[i][1:]] = args[i+1]
69 return options
70
Andrew Svetlov5af3e1a2012-04-03 09:39:47 +030071 def __init__(self, root=None, font=None, name=None, exists=False,
72 **options):
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000073 if not root:
Georg Brandl14fc4272008-05-17 18:39:55 +000074 root = tkinter._default_root
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000075 if font:
76 # get actual settings corresponding to the given font
77 font = root.tk.splitlist(root.tk.call("font", "actual", font))
78 else:
79 font = self._set(options)
80 if not name:
Andrew Svetlov39f00372012-04-03 09:48:07 +030081 name = "font" + str(next(self.counter))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000082 self.name = name
Martin v. Löwisfe84d172004-08-18 11:06:45 +000083
84 if exists:
85 self.delete_font = False
86 # confirm font exists
87 if self.name not in root.tk.call("font", "names"):
Georg Brandl14fc4272008-05-17 18:39:55 +000088 raise tkinter._tkinter.TclError(
89 "named font %s does not already exist" % (self.name,))
Martin v. Löwisfe84d172004-08-18 11:06:45 +000090 # if font config info supplied, apply it
91 if font:
Martin v. Löwisfe84d172004-08-18 11:06:45 +000092 root.tk.call("font", "configure", self.name, *font)
93 else:
94 # create new font (raises TclError if the font exists)
Tim Petersa45cacf2004-08-20 03:47:14 +000095 root.tk.call("font", "create", self.name, *font)
Martin v. Löwisfe84d172004-08-18 11:06:45 +000096 self.delete_font = True
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000097 # backlinks!
98 self._root = root
99 self._split = root.tk.splitlist
100 self._call = root.tk.call
101
102 def __str__(self):
103 return self.name
104
Martin v. Löwisfe84d172004-08-18 11:06:45 +0000105 def __eq__(self, other):
Amaury Forgeot d'Arcd61d0772010-09-17 23:27:09 +0000106 return isinstance(other, Font) and self.name == other.name
Martin v. Löwisfe84d172004-08-18 11:06:45 +0000107
108 def __getitem__(self, key):
109 return self.cget(key)
110
111 def __setitem__(self, key, value):
112 self.configure(**{key: value})
113
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000114 def __del__(self):
115 try:
Martin v. Löwisfe84d172004-08-18 11:06:45 +0000116 if self.delete_font:
117 self._call("font", "delete", self.name)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000118 except (KeyboardInterrupt, SystemExit):
119 raise
120 except Exception:
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000121 pass
Tim Petersa45cacf2004-08-20 03:47:14 +0000122
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000123 def copy(self):
124 "Return a distinct copy of the current font"
Raymond Hettingerff41c482003-04-06 09:01:11 +0000125 return Font(self._root, **self.actual())
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000126
127 def actual(self, option=None):
128 "Return actual font attributes"
129 if option:
130 return self._call("font", "actual", self.name, "-"+option)
131 else:
132 return self._mkdict(
133 self._split(self._call("font", "actual", self.name))
134 )
135
136 def cget(self, option):
137 "Get font attribute"
138 return self._call("font", "config", self.name, "-"+option)
139
140 def config(self, **options):
141 "Modify font attributes"
142 if options:
Raymond Hettingerff41c482003-04-06 09:01:11 +0000143 self._call("font", "config", self.name,
144 *self._set(options))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000145 else:
146 return self._mkdict(
Andrew Svetlov5af3e1a2012-04-03 09:39:47 +0300147 self._split(self._call("font", "config", self.name)))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000148
149 configure = config
Fred Draked038ca82000-10-23 18:31:14 +0000150
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000151 def measure(self, text):
152 "Return text width"
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000153 return int(self._call("font", "measure", self.name, text))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000154
155 def metrics(self, *options):
156 """Return font metrics.
157
158 For best performance, create a dummy widget
159 using this font before calling this method."""
160
161 if options:
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000162 return int(
Andrew Svetlov5af3e1a2012-04-03 09:39:47 +0300163 self._call("font", "metrics", self.name, self._get(options)))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000164 else:
165 res = self._split(self._call("font", "metrics", self.name))
166 options = {}
167 for i in range(0, len(res), 2):
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000168 options[res[i][1:]] = int(res[i+1])
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000169 return options
170
Andrew Svetlov5af3e1a2012-04-03 09:39:47 +0300171
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000172def families(root=None):
173 "Get font families (as a tuple)"
174 if not root:
Georg Brandl14fc4272008-05-17 18:39:55 +0000175 root = tkinter._default_root
Fred Draked038ca82000-10-23 18:31:14 +0000176 return root.tk.splitlist(root.tk.call("font", "families"))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000177
Andrew Svetlov5af3e1a2012-04-03 09:39:47 +0300178
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000179def names(root=None):
180 "Get names of defined fonts (as a tuple)"
181 if not root:
Georg Brandl14fc4272008-05-17 18:39:55 +0000182 root = tkinter._default_root
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000183 return root.tk.splitlist(root.tk.call("font", "names"))
184
Andrew Svetlov5af3e1a2012-04-03 09:39:47 +0300185
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000186# --------------------------------------------------------------------
187# test stuff
Fred Draked038ca82000-10-23 18:31:14 +0000188
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000189if __name__ == "__main__":
190
Georg Brandl14fc4272008-05-17 18:39:55 +0000191 root = tkinter.Tk()
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000192
193 # create a font
194 f = Font(family="times", size=30, weight=NORMAL)
195
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000196 print(f.actual())
197 print(f.actual("family"))
198 print(f.actual("weight"))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000199
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000200 print(f.config())
201 print(f.cget("family"))
202 print(f.cget("weight"))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000203
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000204 print(names())
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000205
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000206 print(f.measure("hello"), f.metrics("linespace"))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000207
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000208 print(f.metrics())
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000209
210 f = Font(font=("Courier", 20, "bold"))
Guido van Rossumbe19ed72007-02-09 05:37:30 +0000211 print(f.measure("hello"), f.metrics("linespace"))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000212
Georg Brandl14fc4272008-05-17 18:39:55 +0000213 w = tkinter.Label(root, text="Hello, world", font=f)
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000214 w.pack()
215
Georg Brandl14fc4272008-05-17 18:39:55 +0000216 w = tkinter.Button(root, text="Quit!", command=root.destroy)
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000217 w.pack()
218
219 fb = Font(font=w["font"]).copy()
220 fb.config(weight=BOLD)
Fred Draked038ca82000-10-23 18:31:14 +0000221
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000222 w.config(font=fb)
223
Georg Brandl14fc4272008-05-17 18:39:55 +0000224 tkinter.mainloop()