blob: 06e0c985c16ad00663079d71a880509550d9a817 [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)
32
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)
Martin v. Löwisfe84d172004-08-18 11:06:45 +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öwisbabc5ec2004-08-18 17:47:40 +000094 print "font=%r" % font
Martin v. Löwisfe84d172004-08-18 11:06:45 +000095 root.tk.call("font", "configure", self.name, *font)
96 else:
97 # create new font (raises TclError if the font exists)
98 root.tk.call("font", "create", self.name, *font)
99 self.delete_font = True
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000100 # backlinks!
101 self._root = root
102 self._split = root.tk.splitlist
103 self._call = root.tk.call
104
105 def __str__(self):
106 return self.name
107
Martin v. Löwisfe84d172004-08-18 11:06:45 +0000108 def __eq__(self, other):
109 return self.name == other.name and isinstance(other, Font)
110
111 def __getitem__(self, key):
112 return self.cget(key)
113
114 def __setitem__(self, key, value):
115 self.configure(**{key: value})
116
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000117 def __del__(self):
118 try:
Martin v. Löwisfe84d172004-08-18 11:06:45 +0000119 if self.delete_font:
120 self._call("font", "delete", self.name)
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000121 except (AttributeError, Tkinter.TclError):
122 pass
Martin v. Löwisfe84d172004-08-18 11:06:45 +0000123
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000124 def copy(self):
125 "Return a distinct copy of the current font"
Raymond Hettingerff41c482003-04-06 09:01:11 +0000126 return Font(self._root, **self.actual())
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000127
128 def actual(self, option=None):
129 "Return actual font attributes"
130 if option:
131 return self._call("font", "actual", self.name, "-"+option)
132 else:
133 return self._mkdict(
134 self._split(self._call("font", "actual", self.name))
135 )
136
137 def cget(self, option):
138 "Get font attribute"
139 return self._call("font", "config", self.name, "-"+option)
140
141 def config(self, **options):
142 "Modify font attributes"
143 if options:
Raymond Hettingerff41c482003-04-06 09:01:11 +0000144 self._call("font", "config", self.name,
145 *self._set(options))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000146 else:
147 return self._mkdict(
148 self._split(self._call("font", "config", self.name))
149 )
150
151 configure = config
Fred Draked038ca82000-10-23 18:31:14 +0000152
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000153 def measure(self, text):
154 "Return text width"
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000155 return int(self._call("font", "measure", self.name, text))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000156
157 def metrics(self, *options):
158 """Return font metrics.
159
160 For best performance, create a dummy widget
161 using this font before calling this method."""
162
163 if options:
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000164 return int(
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000165 self._call("font", "metrics", self.name, self._get(options))
166 )
167 else:
168 res = self._split(self._call("font", "metrics", self.name))
169 options = {}
170 for i in range(0, len(res), 2):
Eric S. Raymondfc170b12001-02-09 11:51:27 +0000171 options[res[i][1:]] = int(res[i+1])
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000172 return options
173
174def families(root=None):
175 "Get font families (as a tuple)"
176 if not root:
177 root = Tkinter._default_root
Fred Draked038ca82000-10-23 18:31:14 +0000178 return root.tk.splitlist(root.tk.call("font", "families"))
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000179
180def names(root=None):
181 "Get names of defined fonts (as a tuple)"
182 if not root:
183 root = Tkinter._default_root
184 return root.tk.splitlist(root.tk.call("font", "names"))
185
186# --------------------------------------------------------------------
187# test stuff
Fred Draked038ca82000-10-23 18:31:14 +0000188
Guido van Rossum3d16d3e1998-08-11 19:07:58 +0000189if __name__ == "__main__":
190
191 root = Tkinter.Tk()
192
193 # create a font
194 f = Font(family="times", size=30, weight=NORMAL)
195
196 print f.actual()
197 print f.actual("family")
198 print f.actual("weight")
199
200 print f.config()
201 print f.cget("family")
202 print f.cget("weight")
203
204 print names()
205
206 print f.measure("hello"), f.metrics("linespace")
207
208 print f.metrics()
209
210 f = Font(font=("Courier", 20, "bold"))
211 print f.measure("hello"), f.metrics("linespace")
212
213 w = Tkinter.Label(root, text="Hello, world", font=f)
214 w.pack()
215
216 w = Tkinter.Button(root, text="Quit!", command=root.destroy)
217 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
224 Tkinter.mainloop()