blob: dfdee425f3963ae79a79ab344b2a8b98f21093a9 [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
Georg Brandl33cece02008-05-20 06:58:21 +000069 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
Serhiy Storchakaadad50c2014-06-01 11:21:34 +030081 if self.name not in root.tk.splitlist(
82 root.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:
86 root.tk.call("font", "configure", self.name, *font)
87 else:
88 # create new font (raises TclError if the font exists)
89 root.tk.call("font", "create", self.name, *font)
90 self.delete_font = True
91 # backlinks!
92 self._root = root
93 self._split = root.tk.splitlist
94 self._call = root.tk.call
95
96 def __str__(self):
97 return self.name
98
99 def __eq__(self, other):
Serhiy Storchaka186f6652014-07-24 17:48:28 +0300100 return isinstance(other, Font) and self.name == other.name
Georg Brandl33cece02008-05-20 06:58:21 +0000101
102 def __getitem__(self, key):
103 return self.cget(key)
104
105 def __setitem__(self, key, value):
106 self.configure(**{key: value})
107
108 def __del__(self):
109 try:
110 if self.delete_font:
111 self._call("font", "delete", self.name)
112 except (KeyboardInterrupt, SystemExit):
113 raise
114 except Exception:
115 pass
116
117 def copy(self):
118 "Return a distinct copy of the current font"
119 return Font(self._root, **self.actual())
120
121 def actual(self, option=None):
122 "Return actual font attributes"
123 if option:
124 return self._call("font", "actual", self.name, "-"+option)
125 else:
126 return self._mkdict(
127 self._split(self._call("font", "actual", self.name))
128 )
129
130 def cget(self, option):
131 "Get font attribute"
132 return self._call("font", "config", self.name, "-"+option)
133
134 def config(self, **options):
135 "Modify font attributes"
136 if options:
137 self._call("font", "config", self.name,
138 *self._set(options))
139 else:
140 return self._mkdict(
141 self._split(self._call("font", "config", self.name))
142 )
143
144 configure = config
145
146 def measure(self, text):
147 "Return text width"
148 return int(self._call("font", "measure", self.name, text))
149
150 def metrics(self, *options):
151 """Return font metrics.
152
153 For best performance, create a dummy widget
154 using this font before calling this method."""
155
156 if options:
157 return int(
158 self._call("font", "metrics", self.name, self._get(options))
159 )
160 else:
161 res = self._split(self._call("font", "metrics", self.name))
162 options = {}
163 for i in range(0, len(res), 2):
164 options[res[i][1:]] = int(res[i+1])
165 return options
166
167def families(root=None):
168 "Get font families (as a tuple)"
169 if not root:
Georg Brandl6634bf22008-05-20 07:13:37 +0000170 root = Tkinter._default_root
Georg Brandl33cece02008-05-20 06:58:21 +0000171 return root.tk.splitlist(root.tk.call("font", "families"))
172
173def names(root=None):
174 "Get names of defined fonts (as a tuple)"
175 if not root:
Georg Brandl6634bf22008-05-20 07:13:37 +0000176 root = Tkinter._default_root
Georg Brandl33cece02008-05-20 06:58:21 +0000177 return root.tk.splitlist(root.tk.call("font", "names"))
178
179# --------------------------------------------------------------------
180# test stuff
181
182if __name__ == "__main__":
183
Georg Brandl6634bf22008-05-20 07:13:37 +0000184 root = Tkinter.Tk()
Georg Brandl33cece02008-05-20 06:58:21 +0000185
186 # create a font
187 f = Font(family="times", size=30, weight=NORMAL)
188
189 print f.actual()
190 print f.actual("family")
191 print f.actual("weight")
192
193 print f.config()
194 print f.cget("family")
195 print f.cget("weight")
196
197 print names()
198
199 print f.measure("hello"), f.metrics("linespace")
200
201 print f.metrics()
202
203 f = Font(font=("Courier", 20, "bold"))
204 print f.measure("hello"), f.metrics("linespace")
205
Georg Brandl6634bf22008-05-20 07:13:37 +0000206 w = Tkinter.Label(root, text="Hello, world", font=f)
Georg Brandl33cece02008-05-20 06:58:21 +0000207 w.pack()
208
Georg Brandl6634bf22008-05-20 07:13:37 +0000209 w = Tkinter.Button(root, text="Quit!", command=root.destroy)
Georg Brandl33cece02008-05-20 06:58:21 +0000210 w.pack()
211
212 fb = Font(font=w["font"]).copy()
213 fb.config(weight=BOLD)
214
215 w.config(font=fb)
216
Georg Brandl6634bf22008-05-20 07:13:37 +0000217 Tkinter.mainloop()