blob: 113c983b015990294e181909f930db78de6d5ebc [file] [log] [blame]
Georg Brandl33cece02008-05-20 06:58:21 +00001# 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
Georg Brandl6634bf22008-05-20 07:13:37 +000011import Tkinter
Georg Brandl33cece02008-05-20 06:58:21 +000012
13# weight/slant
14NORMAL = "normal"
15ROMAN = "roman"
16BOLD = "bold"
17ITALIC = "italic"
18
19def nametofont(name):
20 """Given the name of a tk named font, returns a Font representation.
21 """
22 return Font(name=name, exists=True)
23
24class 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.
Georg Brandl6634bf22008-05-20 07:13:37 +000034 Raises _Tkinter.TclError if the assertion is false.
Georg Brandl33cece02008-05-20 06:58:21 +000035
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:
Georg Brandl6634bf22008-05-20 07:13:37 +000068 root = Tkinter._default_root
Serhiy Storchaka44ae5132014-08-17 15:31:41 +030069 tk = getattr(root, 'tk', root)
Georg Brandl33cece02008-05-20 06:58:21 +000070 if font:
71 # get actual settings corresponding to the given font
Serhiy Storchaka44ae5132014-08-17 15:31:41 +030072 font = tk.splitlist(tk.call("font", "actual", font))
Georg Brandl33cece02008-05-20 06:58:21 +000073 else:
74 font = self._set(options)
75 if not name:
76 name = "font" + str(id(self))
77 self.name = name
78
79 if exists:
80 self.delete_font = False
81 # confirm font exists
Serhiy Storchaka44ae5132014-08-17 15:31:41 +030082 if self.name not in tk.splitlist(tk.call("font", "names")):
Georg Brandl6634bf22008-05-20 07:13:37 +000083 raise Tkinter._tkinter.TclError, "named font %s does not already exist" % (self.name,)
Georg Brandl33cece02008-05-20 06:58:21 +000084 # if font config info supplied, apply it
85 if font:
Serhiy Storchaka44ae5132014-08-17 15:31:41 +030086 tk.call("font", "configure", self.name, *font)
Georg Brandl33cece02008-05-20 06:58:21 +000087 else:
88 # create new font (raises TclError if the font exists)
Serhiy Storchaka44ae5132014-08-17 15:31:41 +030089 tk.call("font", "create", self.name, *font)
Georg Brandl33cece02008-05-20 06:58:21 +000090 self.delete_font = True
Serhiy Storchaka44ae5132014-08-17 15:31:41 +030091 self._tk = tk
92 self._split = tk.splitlist
93 self._call = tk.call
Georg Brandl33cece02008-05-20 06:58:21 +000094
95 def __str__(self):
96 return self.name
97
98 def __eq__(self, other):
Serhiy Storchaka186f6652014-07-24 17:48:28 +030099 return isinstance(other, Font) and self.name == other.name
Georg Brandl33cece02008-05-20 06:58:21 +0000100
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"
Serhiy Storchaka44ae5132014-08-17 15:31:41 +0300118 return Font(self._tk, **self.actual())
Georg Brandl33cece02008-05-20 06:58:21 +0000119
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
166def families(root=None):
167 "Get font families (as a tuple)"
168 if not root:
Georg Brandl6634bf22008-05-20 07:13:37 +0000169 root = Tkinter._default_root
Georg Brandl33cece02008-05-20 06:58:21 +0000170 return root.tk.splitlist(root.tk.call("font", "families"))
171
172def names(root=None):
173 "Get names of defined fonts (as a tuple)"
174 if not root:
Georg Brandl6634bf22008-05-20 07:13:37 +0000175 root = Tkinter._default_root
Georg Brandl33cece02008-05-20 06:58:21 +0000176 return root.tk.splitlist(root.tk.call("font", "names"))
177
178# --------------------------------------------------------------------
179# test stuff
180
181if __name__ == "__main__":
182
Georg Brandl6634bf22008-05-20 07:13:37 +0000183 root = Tkinter.Tk()
Georg Brandl33cece02008-05-20 06:58:21 +0000184
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
Georg Brandl6634bf22008-05-20 07:13:37 +0000205 w = Tkinter.Label(root, text="Hello, world", font=f)
Georg Brandl33cece02008-05-20 06:58:21 +0000206 w.pack()
207
Georg Brandl6634bf22008-05-20 07:13:37 +0000208 w = Tkinter.Button(root, text="Quit!", command=root.destroy)
Georg Brandl33cece02008-05-20 06:58:21 +0000209 w.pack()
210
211 fb = Font(font=w["font"]).copy()
212 fb.config(weight=BOLD)
213
214 w.config(font=fb)
215
Georg Brandl6634bf22008-05-20 07:13:37 +0000216 Tkinter.mainloop()