root/hacks/trunk/automatic_text.py

Revision 106, 8.9 kB (checked in by verbosus, 14 months ago)

Automatic Text: replaced list of string digits with neat list comprehension

  • Property svn:eol-style set to native
  • Property svn:executable set to *
  • Property svn:keywords set to Id
Line 
1#FLM: Automatic Text
2# -*- coding: utf-8 -*-
3
4"""Automatic Text
5
6A FontLab Studio port of a long forgotten but very helpful Letraset
7FontStudio feature. Automatic Text generates mixed sequences of
8glyphs, useful when checking for sanity your font metrics/kerning.
9
10It should work with any copy of FontLab Studio 5, nothing else is
11required.
12
13To install, put this file in your FontLab Macros folder (on OS X it is
14in ~/Library/Application Support/FontLab 5/Macros), then restart
15FontLab. You’ll find Automatic Text in the Macro toolbar, which can be
16toggled with the menu item View → Toolbars → Macro.
17
18You can then launch Automatic Text by clicking the Run button next to
19the macro name in the Macro toolbar, and it will popup its dialog
20box. If you select one glyph in the font window it will be selected as
21the glyph to generate. If you select several glyphs Automatic Text
22will default to the selection mode (which wasn’t there in FontStudio)
23using the selected glyphs as a base to generate the glyph sequence.
24
25Thanks to Claudio Piccinini <http://www.tht.it/> for showing me his
26(working!) copy of FontStudio with this neat feature.
27"""
28
29import string
30
31from FL import *
32
33__author__ = "Antonio Cavedoni <http://cavedoni.com/>"
34__version__ = "0.2"
35__svnid__ = "$Id$"
36__license__ = "Python"
37__contributors__ = [
38    "Claudio Piccinini <http://www.tht.it/>",
39    "Karsten Luecke <http://www.kltf.de/>"
40    ]
41
42UPPERCASE = [x for x in string.uppercase]
43LOWERCASE = [x for x in string.lowercase]
44DIGITS = "zero one two three four five six seven eight nine".split()
45
46class AutomaticTextDialog:
47    def __init__(self):
48        self.d = Dialog(self)
49        self.d.size = Point(320, 280)
50        self.d.Center()
51        self.d.title = 'Automatic Text...'
52        self.d.AddControl(CHECKBOXCONTROL, Rect(15, 10, 255, 40), 
53                          'generateall', STYLE_CHECKBOX, 
54                          'Generate all characters')
55        self.d.AddControl(CHECKBOXCONTROL, Rect(15, 60, 100, 80), 
56                          'generatebeside', STYLE_CHECKBOX, 'Generate')
57        self.d.AddControl(EDITCONTROL, Rect(100, 58, 170, 84), 
58                          'letter', STYLE_EDIT, '')
59        self.d.AddControl(STATICCONTROL, Rect(180, 62, 280, 86), 
60                          'label0', STYLE_LABEL, 'beside:')
61        self.d.AddControl(CHECKBOXCONTROL, Rect(50, 90, 160, 120), 
62                          'lowercase', STYLE_CHECKBOX, 
63                          'a through z')
64        self.d.AddControl(CHECKBOXCONTROL, Rect(180, 90, 310, 120), 
65                          'all_characters', STYLE_CHECKBOX, 'All characters')
66        self.d.AddControl(CHECKBOXCONTROL, Rect(50, 120, 160, 150), 
67                          'uppercase', STYLE_CHECKBOX, 'A through Z')
68        self.d.AddControl(CHECKBOXCONTROL, Rect(180, 120, 310, 150), 
69                          'numbers', STYLE_CHECKBOX, '0 through 9')
70        self.d.AddControl(CHECKBOXCONTROL, Rect(50, 150, 80, 180), 
71                          'other', STYLE_CHECKBOX, '')
72        self.d.AddControl(EDITCONTROL, Rect(70, 152, 140, 178), 
73                          'other_from', STYLE_EDIT, '')
74        self.d.AddControl(STATICCONTROL, Rect(150, 158, 210, 178), 
75                          'label1', STYLE_LABEL, 'through')
76        self.d.AddControl(EDITCONTROL, Rect(210, 152, 285, 178), 
77                          'other_to', STYLE_EDIT, '')
78        self.d.AddControl(CHECKBOXCONTROL, Rect(50, 185, 285, 210), 
79                          'selection', STYLE_CHECKBOX, 
80                          'Selected glyphs in font window')
81
82        self.generateall = 0
83        self.generatebeside = 1
84        self.letter = ''
85        self.lowercase = 1
86        self.all_characters = 0
87        self.uppercase = 0
88        self.numbers = 0
89        self.other = 0
90        self.other_from = ''
91        self.other_to = ''
92        self.selection = 0
93
94        if fl.count_selected == 1:
95            try:
96                self.letter = "/" + fl.glyph.name
97            except AttributeError:
98                pass
99        elif fl.count_selected > 1:
100            self.lowercase = 0
101            self.other = 0
102            self.selection = 1
103
104        self.generates = ['generateall', 'generatebeside']
105        self.besides = ['all_characters', 'lowercase', 'uppercase', 
106                        'numbers', 'other', 'selection']
107
108    def check_control_in_list(self, control, controls):
109        for c in controls:
110            if c == control:
111                setattr(self, c, 1)
112            else:
113                setattr(self, c, 0)
114            self.d.PutValue(c)
115        return control
116
117    def on_generateall(self, code):
118        self.d.GetValue('generateall')
119        self.check_control_in_list('generateall', self.generates + self.besides)
120
121    def on_generatebeside(self, code):
122        self.d.GetValue('generatebeside')
123        self.check_control_in_list('generatebeside', self.generates)
124
125    def on_letter(self, code):
126        self.d.GetValue('letter')
127
128    def on_other_from(self, code):
129        self.d.GetValue('other_from')
130
131    def on_other_to(self, code):
132        self.d.GetValue('other_to')
133
134    def on_selection(self, code):
135        self.d.GetValue('selection')
136        self.check_control_in_list('generatebeside', self.generates)
137        self.check_control_in_list('selection', self.besides)
138
139    def on_all_characters(self, code):
140        self.d.GetValue('all_characters')
141        self.check_control_in_list('generatebeside', self.generates)
142        self.check_control_in_list('all_characters', self.besides)
143
144    def on_numbers(self, code):
145        self.d.GetValue('numbers')
146        self.check_control_in_list('generatebeside', self.generates)
147        self.check_control_in_list('numbers', self.besides)
148
149    def on_uppercase(self, code):
150        self.d.GetValue('uppercase')
151        self.check_control_in_list('generatebeside', self.generates)
152        self.check_control_in_list('uppercase', self.besides)
153
154    def on_lowercase(self, code):
155        self.d.GetValue('lowercase')
156        self.check_control_in_list('generatebeside', self.generates)
157        self.check_control_in_list('lowercase', self.besides)
158
159    def on_other(self, code):
160        self.d.GetValue('other')
161        self.check_control_in_list('generatebeside', self.generates)
162        self.check_control_in_list('other', self.besides)
163
164    def on_ok(self, code):
165        return 1
166
167    def Run(self):
168        return self.d.Run()
169
170def get_all_glyphs():
171    # generate a temp font so we can sort its glyphs
172    # by Unicode name without damaging the original
173    tempfont = Font(fl.font)
174    fl.Add(tempfont)
175    tempfontid = fl.ifont
176    fl.CallCommand(fl_cmd.FontSortByUnicode)
177
178    # build a string with all the characters
179    glyphs = []
180    for i in range(len(tempfont)):
181        n = fl.font[i].name
182        if n not in ['.notdef', '.null', 'CR']:
183            glyphs.append(get_glyph_name(fl.font[i].name))
184
185    # close the temp font
186    tempfont.modified = 0
187    fl.Close(tempfontid)
188
189    return glyphs
190
191def map_digit_to_name(digit):
192    if digit in [str(x) for x in string.digits]:
193        return DIGITS[int(digit)]
194    else:
195        return digit
196   
197def get_glyph_name(glyph):
198    glyph = map_digit_to_name(glyph)
199    if not glyph.startswith('/'):
200        return '/%s' % glyph
201    else:
202        return glyph
203
204def get_selection():
205    selected = []
206    for i in range(len(fl.font)):
207        if fl.Selected(fl.font[i].index):
208            try:
209                selected.append(get_glyph_name(fl.font[i].name))
210            except AttributeError:
211                pass
212    return selected
213
214def generate(glyph_set, glyph_name=None):
215    # open metrics window
216    fl.CallCommand(fl_cmd.WindowNewMetrics)
217
218    # normalise the glyph names
219    glyph_set = [get_glyph_name(x) for x in glyph_set]
220
221    # write to the metrics preview text
222    if not glyph_name:
223        fl.metricspreview = "".join(glyph_set)
224    else:
225        fl.metricspreview = \
226            glyph_name + glyph_name.join(glyph_set) + glyph_name
227
228def generate_beside_two(glyph_name, glyph_from, glyph_to):
229    glyphset = []
230    in_sequence = False
231    for i in range(len(fl.font)):
232        if not in_sequence:
233            if fl.font[i].name == map_digit_to_name(glyph_from):
234                glyphset.append(get_glyph_name(fl.font[i].name))
235                in_sequence = True
236        else:
237            glyphset.append(get_glyph_name(fl.font[i].name))
238            if fl.font[i].name == map_digit_to_name(glyph_to):
239                break
240    generate(glyphset, get_glyph_name(glyph_name))
241
242d = AutomaticTextDialog()
243
244if d.Run() == 1:
245    if d.generateall:
246        generate(get_all_glyphs())
247
248    elif d.generatebeside:
249        char = get_glyph_name(d.letter)
250
251        if d.all_characters:
252            generate(get_all_glyphs(), char)
253        elif d.uppercase:
254            generate(UPPERCASE, char)
255        elif d.lowercase:
256            generate(LOWERCASE, char)
257        elif d.numbers:
258            generate(DIGITS, char)
259        elif d.other:
260            generate_beside_two(d.letter, d.other_from, d.other_to)
261        elif d.selection:
262            generate(get_selection(), char)
Note: See TracBrowser for help on using the browser.