blob: afbc18917dbc6445ed316c0cc66e31ee7792ebdd [file] [log] [blame]
Guido van Rossum3d16d3e1998-08-11 19:07:58 +00001#
2# Tkinter
3# $Id$
4#
5# font wrapper
6#
7# written by Fredrik Lundh <fredrik@pythonware.com>, February 1998
8#
9# FIXME: should add 'displayof' option where relevant (actual, families,
10# measure, and metrics)
Fred Draked038ca82000-10-23 18:31:14 +000011#
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000012# Copyright (c) Secret Labs AB 1998.
13#
14# info@pythonware.com
15# http://www.pythonware.com
16#
17
18__version__ = "0.9"
19
20import Tkinter
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000021
22# weight/slant
23NORMAL = "normal"
Martin v. Löwis1ef23652003-06-14 21:40:04 +000024ROMAN = "roman"
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000025BOLD = "bold"
26ITALIC = "italic"
27
Martin v. Löwisfe84d172004-08-18 11:06:45 +000028def nametofont(name):
29 """Given the name of a tk named font, returns a Font representation.
30 """
31 return Font(name=name, exists=True)
Tim Petersa45cacf2004-08-20 03:47:14 +000032
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000033class Font:
34
35 """Represents a named font.
36
37 Constructor options are:
38
39 font -- font specifier (name, system font, or (family, size, style)-tuple)
Martin v. Löwisfe84d172004-08-18 11:06:45 +000040 name -- name to use for this font configuration (defaults to a unique name)
41 exists -- does a named font by this name already exist?
42 Creates a new named font if False, points to the existing font if True.
43 Raises _tkinter.TclError if the assertion is false.
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000044
Martin v. Löwisfe84d172004-08-18 11:06:45 +000045 the following are ignored if font is specified:
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000046
47 family -- font 'family', e.g. Courier, Times, Helvetica
48 size -- font size in points
49 weight -- font thickness: NORMAL, BOLD
Martin v. Löwis1ef23652003-06-14 21:40:04 +000050 slant -- font slant: ROMAN, ITALIC
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000051 underline -- font underlining: false (0), true (1)
52 overstrike -- font strikeout: false (0), true (1)
Tim Petersa45cacf2004-08-20 03:47:14 +000053
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000054 """
55
56 def _set(self, kw):
57 options = []
58 for k, v in kw.items():
59 options.append("-"+k)
60 options.append(str(v))
61 return tuple(options)
62
63 def _get(self, args):
Fred Draked038ca82000-10-23 18:31:14 +000064 options = []
65 for k in args:
66 options.append("-"+k)
67 return tuple(options)
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000068
69 def _mkdict(self, args):
70 options = {}
71 for i in range(0, len(args), 2):
72 options[args[i][1:]] = args[i+1]
73 return options
74
Martin v. Löwisfe84d172004-08-18 11:06:45 +000075 def __init__(self, root=None, font=None, name=None, exists=False, **options):
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000076 if not root:
77 root = Tkinter._default_root
78 if font:
79 # get actual settings corresponding to the given font
80 font = root.tk.splitlist(root.tk.call("font", "actual", font))
81 else:
82 font = self._set(options)
83 if not name:
84 name = "font" + str(id(self))
85 self.name = name
Martin v. Löwisfe84d172004-08-18 11:06:45 +000086
87 if exists:
88 self.delete_font = False
89 # confirm font exists
90 if self.name not in root.tk.call("font", "names"):
91 raise Tkinter._tkinter.TclError, "named font %s does not already exist" % (self.name,)
92 # if font config info supplied, apply it
93 if font:
Martin v. Löwisfe84d172004-08-18 11:06:45 +000094 root.tk.call("font", "configure", self.name, *font)
95 else:
96 # create new font (raises TclError if the font exists)
Tim Petersa45cacf2004-08-20 03:47:14 +000097 root.tk.call("font", "create", self.name, *font)
Martin v. Löwisfe84d172004-08-18 11:06:45 +000098 self.delete_font = True
Guido van Rossum3d16d3e1998-08-11 19:07:58 +000099 # backlinks!
100 self._root = root
101 self._split = root.tk.splitlist
102 self._call = root.tk.call
103
104 def __str__(self):
105 return self.name
106
Martin v. Löwisfe84d172004-08-18 11:06:45 +0000107 def __eq__(self, other):
108 return self.name == other.name and isinstance(other, Font)
109
110 def __getitem__(self, key):
111 return self.cget(key)
112
113 def __setitem__(self, key, value):
114 self.configure(**{key: value})
115
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000116 def __del__(self):
117 try:
Martin v. Löwisfe84d172004-08-18 11:06:45 +0000118 if self.delete_font:
119 self._call("font", "delete", self.name)
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000120 except (AttributeError, Tkinter.TclError):
121 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(
147 self._split(self._call("font", "config", self.name))
148 )
149
150 configure = config
Fred Draked038ca82000-10-23 18:31:14 +0000151
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000152 def measure(self, text):
153 "Return text width"
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000154 return int(self._call("font", "measure", self.name, text))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000155
156 def metrics(self, *options):
157 """Return font metrics.
158
159 For best performance, create a dummy widget
160 using this font before calling this method."""
161
162 if options:
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000163 return int(
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000164 self._call("font", "metrics", self.name, self._get(options))
165 )
166 else:
167 res = self._split(self._call("font", "metrics", self.name))
168 options = {}
169 for i in range(0, len(res), 2):
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000170 options[res[i][1:]] = int(res[i+1])
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000171 return options
172
173def families(root=None):
174 "Get font families (as a tuple)"
175 if not root:
176 root = Tkinter._default_root
Fred Draked038ca82000-10-23 18:31:14 +0000177 return root.tk.splitlist(root.tk.call("font", "families"))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000178
179def names(root=None):
180 "Get names of defined fonts (as a tuple)"
181 if not root:
182 root = Tkinter._default_root
183 return root.tk.splitlist(root.tk.call("font", "names"))
184
185# --------------------------------------------------------------------
186# test stuff
Fred Draked038ca82000-10-23 18:31:14 +0000187
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000188if __name__ == "__main__":
189
190 root = Tkinter.Tk()
191
192 # create a font
193 f = Font(family="times", size=30, weight=NORMAL)
194
195 print f.actual()
196 print f.actual("family")
197 print f.actual("weight")
198
199 print f.config()
200 print f.cget("family")
201 print f.cget("weight")
202
203 print names()
204
205 print f.measure("hello"), f.metrics("linespace")
206
207 print f.metrics()
208
209 f = Font(font=("Courier", 20, "bold"))
210 print f.measure("hello"), f.metrics("linespace")
211
212 w = Tkinter.Label(root, text="Hello, world", font=f)
213 w.pack()
214
215 w = Tkinter.Button(root, text="Quit!", command=root.destroy)
216 w.pack()
217
218 fb = Font(font=w["font"]).copy()
219 fb.config(weight=BOLD)
Fred Draked038ca82000-10-23 18:31:14 +0000220
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000221 w.config(font=fb)
222
223 Tkinter.mainloop()