Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | # |
2 | # Tkinter | |
3 | # $Id: tkFont.py,v 1.9 2004/08/20 06:19:23 loewis Exp $ | |
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) | |
11 | # | |
12 | # Copyright (c) Secret Labs AB 1998. | |
13 | # | |
14 | # info@pythonware.com | |
15 | # http://www.pythonware.com | |
16 | # | |
17 | ||
18 | __version__ = "0.9" | |
19 | ||
20 | import Tkinter | |
21 | ||
22 | # weight/slant | |
23 | NORMAL = "normal" | |
24 | ROMAN = "roman" | |
25 | BOLD = "bold" | |
26 | ITALIC = "italic" | |
27 | ||
28 | def nametofont(name): | |
29 | """Given the name of a tk named font, returns a Font representation. | |
30 | """ | |
31 | return Font(name=name, exists=True) | |
32 | ||
33 | class 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) | |
40 | 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. | |
44 | ||
45 | the following are ignored if font is specified: | |
46 | ||
47 | family -- font 'family', e.g. Courier, Times, Helvetica | |
48 | size -- font size in points | |
49 | weight -- font thickness: NORMAL, BOLD | |
50 | slant -- font slant: ROMAN, ITALIC | |
51 | underline -- font underlining: false (0), true (1) | |
52 | overstrike -- font strikeout: false (0), true (1) | |
53 | ||
54 | """ | |
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): | |
64 | options = [] | |
65 | for k in args: | |
66 | options.append("-"+k) | |
67 | return tuple(options) | |
68 | ||
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 | ||
75 | def __init__(self, root=None, font=None, name=None, exists=False, **options): | |
76 | 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 | |
86 | ||
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: | |
94 | root.tk.call("font", "configure", self.name, *font) | |
95 | else: | |
96 | # create new font (raises TclError if the font exists) | |
97 | root.tk.call("font", "create", self.name, *font) | |
98 | self.delete_font = True | |
99 | # 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 | ||
107 | 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 | ||
116 | def __del__(self): | |
117 | try: | |
118 | if self.delete_font: | |
119 | self._call("font", "delete", self.name) | |
120 | except (AttributeError, Tkinter.TclError): | |
121 | pass | |
122 | ||
123 | def copy(self): | |
124 | "Return a distinct copy of the current font" | |
125 | return Font(self._root, **self.actual()) | |
126 | ||
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: | |
143 | self._call("font", "config", self.name, | |
144 | *self._set(options)) | |
145 | else: | |
146 | return self._mkdict( | |
147 | self._split(self._call("font", "config", self.name)) | |
148 | ) | |
149 | ||
150 | configure = config | |
151 | ||
152 | def measure(self, text): | |
153 | "Return text width" | |
154 | return int(self._call("font", "measure", self.name, text)) | |
155 | ||
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: | |
163 | return int( | |
164 | 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): | |
170 | options[res[i][1:]] = int(res[i+1]) | |
171 | return options | |
172 | ||
173 | def families(root=None): | |
174 | "Get font families (as a tuple)" | |
175 | if not root: | |
176 | root = Tkinter._default_root | |
177 | return root.tk.splitlist(root.tk.call("font", "families")) | |
178 | ||
179 | def 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 | |
187 | ||
188 | if __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) | |
220 | ||
221 | w.config(font=fb) | |
222 | ||
223 | Tkinter.mainloop() |