class GlyphnameDialog( object): def __init__( self ): x = 10 y = 10 height = 20 button_width = 30 glyphname_width = 180 gap = 6 self.w = Window( ( x + button_width + gap + glyphname_width + gap + button_width + x, y + height + y ), "insert glyph" ) self.w.center() self.w.glyphname = EditText( ( x, y, glyphname_width, height ), '') x += glyphname_width + gap self.w.alignleft = Button( ( x, y, button_width, height ), LEFT, callback = self.buttonCallback ) x += button_width + gap self.w.alignright = Button( ( x, y, button_width, height ), RIGHT, callback = self.buttonCallback ) self.w.setDefaultButton( self.w.alignleft ) self.w.alignright.bind( "\x1b", [] ) self.w.open() def buttonCallback( self, sender ): alignment = sender.getTitle() glyphname = self.w.glyphname.get() if not glyphname: self.w.close() return if len( glyphname ) == 1: uni = ord(glyphname) g = font.glyphForUnicode_("%.4X" % uni) if g: glyphname = g.name other_glyph = font.glyphs[ glyphname ] if not other_glyph: for glyph in font.glyphs: if glyph.name.startswith( glyphname ): other_glyph = glyph print 'Using', glyph.name break else: print 'No matching glyph found.' self.w.close() return selected_glyphs = set( [ layer.parent for layer in font.selectedLayers ] ) for glyph in selected_glyphs: glyph.beginUndo() for layer in glyph.layers: # find other layer for other_layer in other_glyph.layers: if other_layer.name == layer.name: insert_paths( layer, other_layer, alignment ) break else: if active_layerId == layer.layerId: insert_paths( layer, other_glyph.layers[layer.associatedMasterId], alignment ) glyph.endUndo() self.w.close()
class GlyphnameDialog(object): def __init__(self): x = 10 y = 10 height = 20 button_width = 30 glyphname_width = 180 gap = 6 self.w = Window( (x + button_width + gap + glyphname_width + gap + button_width + x, y + height + y), "insert glyph") self.w.center() self.w.glyphname = EditText((x, y, glyphname_width, height), '') x += glyphname_width + gap self.w.alignleft = Button((x, y, button_width, height), LEFT, callback=self.buttonCallback) x += button_width + gap self.w.alignright = Button((x, y, button_width, height), RIGHT, callback=self.buttonCallback) self.w.setDefaultButton(self.w.alignleft) self.w.alignright.bind("\x1b", []) self.w.open() def buttonCallback(self, sender): title = sender.getTitle() glyphname = self.w.glyphname.get() if not glyphname: self.w.close() return if len(glyphname) == 1: uni = ord(glyphname) g = font.glyphForUnicode_("%.4X" % uni) if g: glyphname = g.name other_glyph = font.glyphs[glyphname] if not other_glyph: for glyph in font.glyphs: if glyph.name.startswith(glyphname): other_glyph = glyph break else: self.w.close() return for layer in font.selectedLayers: glyph = layer.parent glyph.beginUndo() # deselect all for path in layer.paths: for node in path.nodes: layer.removeObjectFromSelection_(node) # find other layer for other_layer in other_glyph.layers: if other_layer.name == layer.name: # insert paths for path in other_layer.copyDecomposedLayer().paths: if title == RIGHT: shift = layer.width - other_layer.width for node in path.nodes: node.x = node.x + shift layer.paths.append(path) # select path layer.paths[-1].selected = True break glyph.endUndo() self.w.close()
class makeDisplay(object): def __init__(self): self.verboten = { 'right': ['napostrophe', 'Omegadasiavaria'], 'left': ['ldot', 'Ldot', 'ldot.sc', 'sigmafinal'], 'both': ['*.tf', '*.tosf', '.notdef', 'NULL', 'CR'] } self.category = None self.messages = [] self.interpolated_fonts = dict() self.use_real = True self.use_selection = False self.ignore_red = False self.current_glyph = None self.leftside_kerning_groups = None self.rightside_kerning_groups = None self.all_kern_categories = self.get_all_kern_categories() self.categories_leftside = self.get_categorised_glyphs('left') self.categories_rightside = self.get_categorised_glyphs('right') item_height = 24.0 w_width = 300.0 w_height = item_height * (7 + len(self.all_kern_categories)) margin = 10 next_y = margin col_1_width = w_width - (margin * 2) item_height = 24 radio_height = item_height * len(self.all_kern_categories) self.w = Window((w_width, w_height), "Make Kerning Strings") self.w.text_1 = TextBox((margin, next_y, w_width, item_height), "Kern with:", sizeStyle='regular') next_y += item_height self.w.radioCategories = RadioGroup((margin, next_y, col_1_width, radio_height), self.all_kern_categories, sizeStyle='regular') self.w.radioCategories.set(0) next_y += radio_height + margin self.w.use_real = CheckBox((margin, next_y, col_1_width, item_height), "Use real words", value=True, sizeStyle='regular') next_y += item_height self.w.use_selected = CheckBox((margin, next_y, col_1_width, item_height), "Use the selected glyphs verbatum", value=False, sizeStyle='regular') next_y += item_height self.w.ignore_red = CheckBox((margin, next_y, col_1_width, item_height), "Ignore red marked glyphs", value=False, sizeStyle='regular') next_y += item_height + margin self.w.gobutton = Button((margin + (col_1_width / 4), next_y, col_1_width / 2, item_height), 'Make Strings', callback=self.makeitso) self.w.setDefaultButton(self.w.gobutton) self.w.center() self.w.open() # self.makeitso(None) def sbuttonCallback(self, sender): self.s.close() @staticmethod def has_smallcaps(): for g in Glyphs.font.glyphs: if g.subCategory == 'Smallcaps': return True return False def get_all_kern_categories(self): kcats = [ 'Uppercase', 'Lowercase', ] if self.has_smallcaps: kcats.append('Smallcaps') kcats += [ 'Quotes', 'Number', 'Punctuation', 'Other', ] return kcats def get_canonincal_kerning_glyph(self, layer, pair_side): g = layer.parent if self.use_selection: return g if pair_side == 'left': g = Glyphs.font.glyphs[layer.parent.rightKerningGroup] or layer.parent if pair_side == 'right': g = Glyphs.font.glyphs[layer.parent.leftKerningGroup] or layer.parent if g is None: g = layer.parent return g @staticmethod def make_list_unique(this_list): unique_list = [] for x in this_list: if x in unique_list or x is None: continue unique_list.append(x) return unique_list def get_categorised_glyphs(self, side): # cats = defaultdict(lambda: defaultdict(list)) cats = dict((k, defaultdict(list)) for k in self.all_kern_categories) for g in [x for x in Glyphs.font.glyphs if self.is_elligable(x)]: l = cats.get(g.category, cats.get(g.subCategory, cats['Other'])) l[g.script].append(self.get_canonincal_kerning_glyph(g.layers[0], side)) for cat in cats.keys(): for script in cats[cat].keys(): cats[cat][script] = self.make_list_unique(cats[cat][script]) return cats def get_string(self, left_g, right_g): string = None if self.category == 'Quotes': cat = left_g.subCategory if left_g.subCategory != 'Other' else left_g.category pattern = _kerningStrings.patterns.get(left_g.script, _kerningStrings.patterns.get('latin')).get(cat + '-Quotes', '') strings = [pattern.format(right=right_g.name, left=left_g.name, qL=quote_pair[0], qR=quote_pair[1]).replace(' /', '/') for quote_pair in _kerningStrings.quotations] string = ' '.join(strings) if not string and self.use_real: base_name_left, _, suffix_left = left_g.name.partition('.') base_name_right, _, suffix_right = right_g.name.partition('.') potentials = [ base_name_left + base_name_right, base_name_left + '/' + base_name_right, '/' + base_name_left + ' ' + base_name_right, '/' + base_name_left + '/' + base_name_right, ] for s in potentials: string = _kerningStrings.strings.get(s) if string: break print(s) if not string: pattern = self.get_pattern(left_g, right_g) string = pattern.format(right=right_g.name, left=left_g.name).replace(' /', '/') if not string: string = '/' + left_g.name + '/' + right_g.name return string def get_category_for_glyph(self, glyph): if glyph.category in self.all_kern_categories: return glyph.category if glyph.subCategory in self.all_kern_categories: return glyph.subCategory if glyph.subCategory == 'Currancy': return 'Number' return 'Other' def get_pattern(self, main_glyph, other_glyph): scripts_patterns = _kerningStrings.patterns.get(main_glyph.script, {}) # print(self.get_category_for_glyph(main_glyph)) # print(self.get_category_for_glyph(main_glyph) + '-' + self.get_category_for_glyph(other_glyph), self.all_kern_categories) pattern = scripts_patterns.get(self.get_category_for_glyph(main_glyph) + '-' + self.get_category_for_glyph(other_glyph), '') if self.category == 'Number': suffix = ''.join(main_glyph.name.partition('.')[1:]) else: suffix = '' try: pattern = pattern.format( suffix=suffix, left='{left}', right='{right}', ) except KeyError: pass return pattern def is_elligable(self, glyph, side='both'): if self.ignore_red and glyph.color == 0: return False if not glyph.export: return False for vgn in self.verboten[side]: if re.match(vgn.replace('.', '\\.').replace('*', '.*'), glyph.name): return False return True def makeitso(self, sender): try: self.w.close() except AttributeError: pass self.category = self.all_kern_categories[self.w.radioCategories.get()] self.use_real = self.w.use_real.get() self.use_selection = self.w.use_selected.get() self.ignore_red = self.w.ignore_red.get() all_strings = [] if self.category == 'Quotes': left_of_string_glyphs = self.make_list_unique([self.get_canonincal_kerning_glyph(sl, 'right') for sl in Glyphs.font.selectedLayers if self.is_elligable(sl.parent, 'right')]) right_of_string_glyphs = self.make_list_unique([self.get_canonincal_kerning_glyph(sl, 'left') for sl in Glyphs.font.selectedLayers if self.is_elligable(sl.parent, 'left')]) pairs = zip_longest(left_of_string_glyphs, right_of_string_glyphs) for p in pairs: gl, gr = p if gl is None: gl = gr if gr in left_of_string_glyphs else left_of_string_glyphs[0] if gr is None: gr = gl if gl in left_of_string_glyphs else right_of_string_glyphs[0] kerning_string = self.get_string(gl, gr) if kerning_string not in all_strings: all_strings.append(kerning_string) else: # Holds kerning key glyphs that have been seen already, to avoid duplicates processed_main_glyphs_left = OrderedDict() processed_main_glyphs_right = OrderedDict() # print([(k, self.categories_rightside[k].keys()) for k in self.categories_rightside.keys()]) for sl in Glyphs.font.selectedLayers: # Process the selected glyph on the left side main_g_left = self.get_canonincal_kerning_glyph(sl, 'left') pair_strings_left = [] if self.is_elligable(main_g_left, 'left'): if main_g_left.name not in processed_main_glyphs_left.keys(): processed_main_glyphs_left[main_g_left.name] = [sl.parent.name] try: if sl.parent.script: other_glyphs_rightside = self.categories_rightside[self.category].get(sl.parent.script, self.categories_rightside[self.category].get(None)) else: other_glyphs_rightside = self.categories_rightside[self.category].get(None, self.categories_rightside[self.category].get('latin')) except KeyError: other_glyphs_rightside = [] # print(self.category, self.categories_rightside.keys()) print(sl.parent.script, self.category, self.categories_rightside[self.category].keys()) for g in other_glyphs_rightside: if not self.is_elligable(g, 'right'): continue other_g = self.get_canonincal_kerning_glyph(g.layers[sl.associatedMasterId], 'right') kerning_string_left = self.get_string(main_g_left, other_g) if kerning_string_left not in pair_strings_left: pair_strings_left.append(kerning_string_left) else: processed_main_glyphs_left[main_g_left.name].append(sl.parent.name) if pair_strings_left: pair_strings_left.insert(0, main_g_left.name) # Process the selected glyph on the right side main_g_right = self.get_canonincal_kerning_glyph(sl, 'right') pair_strings_right = [] if self.is_elligable(main_g_right, 'right'): if main_g_right.name not in processed_main_glyphs_right.keys(): processed_main_glyphs_right[main_g_right.name] = [sl.parent.name] if self.category == 'Quotes': other_glyphs_leftside = [main_g_right] main_g_right = self.get_canonincal_kerning_glyph(sl, 'left') else: if sl.parent.script: other_glyphs_leftside = self.categories_leftside[self.category].get(sl.parent.script, self.categories_leftside[self.category].get(None, [])) else: other_glyphs_leftside = self.categories_leftside[self.category].get(None, self.categories_leftside[self.category].get('latin', [])) for g in other_glyphs_leftside: if not self.is_elligable(g, 'left'): continue other_g = self.get_canonincal_kerning_glyph(g.layers[sl.associatedMasterId], 'left') kerning_string_right = self.get_string(other_g, main_g_right) if kerning_string_right not in pair_strings_right: pair_strings_right.append(kerning_string_right) else: processed_main_glyphs_right[main_g_right.name].append(sl.parent.name) if pair_strings_right: pair_strings_right.insert(0, main_g_right.name) left_string = ' '.join(self.make_list_unique(pair_strings_left)) right_string = ' '.join(self.make_list_unique(pair_strings_right)) if all([left_string, right_string]): pair_strings = '\n'.join([left_string, right_string]) else: pair_strings = left_string or right_string # print(':', pair_strings, ':') if pair_strings: all_strings.append(pair_strings) Glyphs.font.newTab('\n\n'.join(all_strings)) Glyphs.font.currentTab.previewInstances = 'live' Glyphs.font.currentTab.scale = 0.065 Glyphs.font.currentTab.textCursor = 3 Glyphs.font.tool = 'TextTool'
class replaceNamedComponent: def __init__(self): item_height = 24.0 margin = 10 w_width = 350.0 w_height = (item_height * 5) + margin next_y = margin col_1_width = w_width - (margin * 2) item_height = 24 self.get_prefs('SlantComponentPositions.pref') self.w = Window((w_width, w_height), "Slant Angle") self.w.slant_angle_text = TextBox( (margin, next_y + 2, col_1_width, item_height), "Slant Angle:", sizeStyle='regular') next_y += item_height self.w.slant_angle = EditText( (margin, next_y, col_1_width, item_height), self.prefs.get('slant_angle', '')) next_y += item_height + margin self.w.slant_all_layers = CheckBox( (margin, next_y, col_1_width, item_height), "Slant All Layers", value=int(self.prefs.get('slant_all_layers')), sizeStyle='regular') next_y += item_height + margin self.w.makeitso = Button( (w_width / 4.0, next_y, col_1_width / 2.0, item_height), 'Slant Components', callback=self.makeitso) self.w.setDefaultButton(self.w.makeitso) self.w.open() self.w.center() def get_prefs(self, filename): self.pref_folder = os.path.expanduser( '~/Library/Application Support/Glyphs/Prefs') self.pref_filepath = os.path.join(self.pref_folder, filename) self.prefs = {} if os.path.exists(self.pref_filepath): with open(self.pref_filepath) as f: preflines = f.readlines() self.prefs = dict( line.split('\t') for line in preflines if line[0] != '#' and line.strip()) def set_prefs(self, **kwargs): try: if not os.path.exists(self.pref_folder): os.makedirs(self.pref_folder) pref_string = '\n'.join( ['\t'.join(str(b) for b in a) for a in kwargs.items()]) with open(self.pref_filepath, 'w') as f: f.write(pref_string) except AttributeError: print('The Preference filename has not been set.') def get_reference_point(self, selection, layer=None): return self.get_center_of_selection(selection) # return NSPoint(self.get_obj_center(layer).x, Glyphs.font.selectedFontMaster.xHeight / 2) def get_obj_center(self, obj): return NSPoint(obj.bounds.origin.x + (obj.bounds.size.width / 2), obj.bounds.origin.y + (obj.bounds.size.height / 2)) def get_center_of_selection(self, selection): all_points = [] for obj in selection: try: all_points.append(self.get_obj_center(obj)) except AttributeError: all_points.append(obj.position) all_xs = [x.x for x in all_points] all_ys = [x.x for x in all_points] x_average = sum(all_xs) / len(all_xs) y_average = sum(all_ys) / len(all_ys) return NSPoint(int(x_average), int(y_average)) def makeitso(self, sender): self.w.close() slant_all_layers = self.w.slant_all_layers.get() # print(slant_all_layers, type(slant_all_layers)) try: slant_angle = float(self.w.slant_angle.get()) except TypeError: Glyphs.showNotification('Slant Component Positions', 'The slant angle was not a number!') return self.set_prefs(slant_angle=slant_angle, slant_all_layers=slant_all_layers) if not Glyphs.font.selectedLayers: return for sl in Glyphs.font.selectedLayers: if slant_all_layers: layers = [l for l in sl.parent.layers] else: layers = [sl] for l in layers: comps = [c for c in l.components if c.selected ] or [c for c in l.components] if not comps: Glyphs.showNotification( 'Slant Component Positions', 'You haven\'t selected any Components!') return reference_point = self.get_reference_point(comps, l) for c in comps: x_shift = math.tan(math.radians(slant_angle)) * ( self.get_obj_center(c).y - reference_point.y) c.position = NSPoint(c.position.x + x_shift, c.position.y)
class GlyphnameDialog( object): def __init__( self ): hori_margin = 10 verti_margin = hori_margin button_width = 30 glyphname_width = 180 line_height = 20 gap = 9 dialog_height = line_height + gap + line_height + gap + line_height dialog_width = button_width + gap + glyphname_width + gap + button_width self.w = Window( ( hori_margin + dialog_width + hori_margin, verti_margin + dialog_height + verti_margin ), "insert glyph" ) self.w.center() x = hori_margin y = verti_margin # glyph name self.w.glyphname = EditText( ( x, y, glyphname_width, line_height ), '') self.w.glyphname.getNSTextField().setToolTip_( u'Enter the name of the glyph to be inserted. It is sufficient to enter the beginning of the glyph name, e.g. “deg” for “degree”.' ) # buttons x += glyphname_width + gap self.w.alignleft = Button( ( x, y, button_width, line_height ), LEFT, callback = self.buttonCallback ) self.w.alignleft.getNSButton().setToolTip_( 'Insert the other glyph left-aligned, i.e. at its original same position. Keyboard shortcut: Enter' ) x += button_width + gap self.w.alignright = Button( ( x, y, button_width, line_height ), RIGHT, callback = self.buttonCallback ) self.w.alignright.getNSButton().setToolTip_( 'Insert the other glyph right-aligned with respect to the advance widths. Keyboard shortcut: Esc' ) self.w.setDefaultButton( self.w.alignleft ) self.w.alignright.bind( "\x1b", [] ) # insert as component as_component_is_checked = True if Glyphs.defaults["com.FMX.InsertGlyphToBackground.AsCompoment"] is not None: as_component_is_checked = Glyphs.defaults["com.FMX.InsertGlyphToBackground.AsCompoment"] y += line_height + gap x = hori_margin self.w.as_component = CheckBox( ( x, y, dialog_width, line_height ), 'Insert as component', callback=None, value=as_component_is_checked ) self.w.as_component.getNSButton().setToolTip_( 'If checked, the other glyph is inserted to the background as a component. Otherwise, it is inserted as paths (even if the other glyph is made of components).' ) # clear current contents y += line_height + gap clear_contents_is_checked = True if Glyphs.defaults["com.FMX.InsertGlyphToBackground.ClearContents"] is not None: clear_contents_is_checked = Glyphs.defaults["com.FMX.InsertGlyphToBackground.ClearContents"] self.w.clear_contents = CheckBox( ( x, y, dialog_width, line_height ), 'Clear current contents', callback=None, value=clear_contents_is_checked ) self.w.clear_contents.getNSButton().setToolTip_( 'Check this to clear the background before inserting the other glyph. Uncheck to keep the current contents of the background.' ) self.w.open() def buttonCallback( self, sender ): alignment = sender.getTitle() glyphname = self.w.glyphname.get() as_component_is_checked = self.w.as_component.get() clear_contents_is_checked = self.w.clear_contents.get() if not glyphname: self.w.close() return if len( glyphname ) == 1: uni = ord(glyphname) g = font.glyphForUnicode_("%.4X" % uni) if g: glyphname = g.name other_glyph = font.glyphs[ glyphname ] if not other_glyph: for glyph in font.glyphs: if glyph.name.startswith( glyphname ): other_glyph = glyph break else: self.w.close() return selected_glyphs = set( [ layer.parent for layer in font.selectedLayers ] ) for glyph in selected_glyphs: glyph.beginUndo() for layer in glyph.layers: # find other layer for other_layer in other_glyph.layers: if other_layer.name == layer.name: insert_paths( layer, other_layer, alignment, as_component_is_checked, clear_contents_is_checked ) break else: if layer.isBraceLayer: # the corresponding brace layer was not found in other_glyph. # let’s interpolate it on-the-fly: other_glyph_copy = other_glyph.copy() other_glyph_copy.parent = font # ^ Glyphs needs the font’s master coordinates for the re-interpolation interpolatedLayer = GSLayer() interpolatedLayer.name = layer.name # ^ necessary for the re-interpolation other_glyph_copy.layers.append( interpolatedLayer ) interpolatedLayer.reinterpolate() insert_paths( layer, interpolatedLayer, alignment, as_component = False, clear_contents = clear_contents_is_checked ) elif active_layerId == layer.layerId: insert_paths( layer, other_glyph.layers[layer.associatedMasterId], alignment, as_component_is_checked, clear_contents_is_checked ) glyph.endUndo() Glyphs.defaults["com.FMX.InsertGlyphToBackground.AsCompoment"] = as_component_is_checked Glyphs.defaults["com.FMX.InsertGlyphToBackground.ClearContents"] = clear_contents_is_checked self.w.close()
class copyKerning(object): # TODO: Add class to different class name copying. # TODO: Allow left or right or both selection. # TODO: Allow open font selection. # TODO: Allow from/to layer selection. def __init__(self): item_height = 24.0 margin = 10 next_y = margin w_width = 400.0 w_height = item_height * 7 + margin col_1_width = w_width - (margin * 2) self.this_font = Glyphs.font try: self.other_font = [f for f in Glyphs.fonts if f != self.this_font][0] except IndexError: Glyphs.showNotification('Copy kerning for Class from Other Font:', 'There is only 1 file open!') raise self.other_fonts_classes = self.get_other_fonts_classes() self.w = Window((w_width, w_height), "Copy kerning for Class from Other Font") self.w.text_1 = TextBox( (margin, next_y, w_width, item_height), "Copy the kerning for this class to this font:", sizeStyle='small') next_y += item_height self.w.class_to_copy = PopUpButton( (margin, next_y, w_width - (margin * 2), item_height), self.other_fonts_classes, sizeStyle='regular') next_y += item_height + item_height self.w.copy_for_all = RadioGroup( (margin, next_y, w_width, item_height * 2), [ ' Copy only for the current Master', ' Copy for All masters', ]) self.w.copy_for_all.set(0) next_y += (item_height * 2) + margin self.w.gobutton = Button( (margin + (col_1_width / 4), next_y, col_1_width / 2, item_height), 'Copy', callback=self.makeitso) self.w.setDefaultButton(self.w.gobutton) self.w.center() self.w.open() def get_other_fonts_classes(self): all_kern_groups = set() for g in self.other_font.glyphs: if g.leftKerningGroup is not None: all_kern_groups.add(g.leftKerningGroup) if g.rightKerningGroup is not None: all_kern_groups.add(g.rightKerningGroup) return sorted(all_kern_groups) def get_other_master(self, this_master): try: other_master = [ m for m in self.other_font.masters if m.name == this_master.name ][0] return other_master except IndexError: pass return self.other_font.selectedFontMaster @staticmethod def glyph_for_id(font, some_name): try: return font.glyphForId_(some_name).name except AttributeError: return some_name def get_this_glyphname(self, some_name): try: return Glyphs.font.glyphForId_(some_name).name except AttributeError: return some_name def copy_left_kerning(self, this_master, class_name): mmk_class_name = '@MMK_L_{}'.format(class_name) for right, val in self.other_font.kerning[self.get_other_master( this_master).id][mmk_class_name].items(): if right.startswith('@MMK'): right_name = right else: right_name = self.other_font.glyphForId_(right).name self.this_font.setKerningForPair(this_master.id, mmk_class_name, right_name, val) def copy_right_kerning(self, this_master, class_name): # TODO: This. Like, it's not done. print( 'No left-side kerning was copied because the function hasn\'t been written yet.' ) pass def makeitso(self, sender): self.w.close() class_name = self.w.class_to_copy.getItem() print(bool(self.w.copy_for_all.get())) chosen_masters = self.this_font.masters if self.w.copy_for_all.get( ) else [self.this_font.selectedFontMaster] for m in chosen_masters: self.copy_left_kerning(m, class_name) self.copy_right_kerning(m, class_name)
class GlyphnameDialog(object): def __init__(self): x = 10 y = 10 height = 20 button_width = 30 glyphname_width = 180 gap = 6 self.w = Window( (x + button_width + gap + glyphname_width + gap + button_width + x, y + height + y), "insert glyph") self.w.center() self.w.glyphname = EditText((x, y, glyphname_width, height), '') x += glyphname_width + gap self.w.alignleft = Button((x, y, button_width, height), LEFT, callback=self.buttonCallback) x += button_width + gap self.w.alignright = Button((x, y, button_width, height), RIGHT, callback=self.buttonCallback) self.w.setDefaultButton(self.w.alignleft) self.w.alignright.bind("\x1b", []) self.w.open() def buttonCallback(self, sender): alignment = sender.getTitle() glyphname = self.w.glyphname.get() if not glyphname: self.w.close() return if len(glyphname) == 1: uni = ord(glyphname) g = font.glyphForUnicode_("%.4X" % uni) if g: glyphname = g.name other_glyph = font.glyphs[glyphname] if not other_glyph: for glyph in font.glyphs: if glyph.name.startswith(glyphname): other_glyph = glyph print 'Using', glyph.name break else: print 'No matching glyph found.' self.w.close() return selected_glyphs = set([layer.parent for layer in font.selectedLayers]) for glyph in selected_glyphs: glyph.beginUndo() for layer in glyph.layers: # find other layer for other_layer in other_glyph.layers: if other_layer.name == layer.name: insert_paths(layer, other_layer, alignment) break else: if active_layerId == layer.layerId: insert_paths( layer, other_glyph.layers[layer.associatedMasterId], alignment) glyph.endUndo() self.w.close()
class GlyphnameDialog( object): def __init__( self ): x = 10 y = 10 height = 20 button_width = 30 glyphname_width = 180 gap = 6 self.w = Window( ( x + button_width + gap + glyphname_width + gap + button_width + x, y + height + y ), "insert glyph" ) self.w.center() self.w.glyphname = EditText( ( x, y, glyphname_width, height ), '') x += glyphname_width + gap self.w.alignleft = Button( ( x, y, button_width, height ), LEFT, callback = self.buttonCallback ) x += button_width + gap self.w.alignright = Button( ( x, y, button_width, height ), RIGHT, callback = self.buttonCallback ) self.w.setDefaultButton( self.w.alignleft ) self.w.alignright.bind( "\x1b", [] ) self.w.open() def buttonCallback( self, sender ): title = sender.getTitle() glyphname = self.w.glyphname.get() if not glyphname: self.w.close() return if len( glyphname ) == 1: uni = ord(glyphname) g = font.glyphForUnicode_("%.4X" % uni) if g: glyphname = g.name other_glyph = font.glyphs[ glyphname ] if not other_glyph: for glyph in font.glyphs: if glyph.name.startswith( glyphname ): other_glyph = glyph print 'Using', glyph.name break else: print 'No matching glyph found.' self.w.close() return for layer in font.selectedLayers: glyph = layer.parent glyph.beginUndo() # deselect all for path in layer.paths: for node in path.nodes: layer.removeObjectFromSelection_( node ) # find other layer for other_layer in other_glyph.layers: if other_layer.name == layer.name: # insert paths for path in other_layer.copyDecomposedLayer().paths: if title == RIGHT: shift = layer.width - other_layer.width for node in path.nodes: node.x = node.x + shift layer.paths.append( path ) # select path layer.paths[-1].selected = True break glyph.endUndo() self.w.close()
class renameKerning(object): def __init__(self): item_height = 24.0 w_width = 300.0 w_height = item_height * 8 margin = 10 next_y = margin col_1_width = w_width - (margin * 2) item_height = 24 self.messages = [] self.interpolated_fonts = dict() self.current_glyph = None self.all_kern_groups = self.get_all_kern_groups() self.w = Window((w_width, w_height), "Rename Kern Groups") self.w.text_1 = TextBox((margin, next_y, w_width, item_height), "Rename:", sizeStyle='small') next_y += item_height self.w.nameFind = PopUpButton( (margin, next_y, w_width - (margin * 2), item_height), self.all_kern_groups, sizeStyle='regular') next_y += item_height + item_height self.w.text_2 = TextBox((margin, next_y, w_width, item_height), "To:", sizeStyle='small') next_y += item_height self.w.nameReplace = EditText( (margin, next_y, w_width - (margin * 2), item_height), "", sizeStyle='regular') next_y += item_height + margin self.w.gobutton = Button( (margin + (col_1_width / 4), next_y, col_1_width / 2, item_height), 'Rename', callback=self.makeitso) self.w.setDefaultButton(self.w.gobutton) self.w.center() self.w.open() def sbuttonCallback(self, sender): self.s.close() def get_all_kern_groups(self): all_kern_groups = set() for g in Glyphs.font.glyphs: if g.leftKerningGroup is not None: all_kern_groups.add('{} - LEFT'.format(g.leftKerningGroup)) if '{} - RIGHT'.format(g.leftKerningGroup) in all_kern_groups: all_kern_groups.add('{} - BOTH'.format(g.leftKerningGroup)) if g.rightKerningGroup is not None: all_kern_groups.add('{} - RIGHT'.format(g.rightKerningGroup)) if '{} - LEFT'.format(g.rightKerningGroup) in all_kern_groups: all_kern_groups.add('{} - BOTH'.format( g.rightKerningGroup)) return sorted(all_kern_groups) def makeitso(self, sender): self.w.close() nameReplace = self.w.nameReplace.get() nameFind = self.w.nameFind.getItem() group_name, _, side = nameFind.partition(' - ') for g in Glyphs.font.glyphs: if side in ['LEFT', 'BOTH']: if g.leftKerningGroup == group_name: g.leftKerningGroup = nameReplace if side in ['RIGHT', 'BOTH']: if g.rightKerningGroup == group_name: g.rightKerningGroup = nameReplace if '{} - {}'.format(nameReplace, side) in self.all_kern_groups: Glyphs.showNotification( 'Kern Group Renaming Success!', 'Note: the kern group named "{}" already exists so it will keep its existing kerning values.' .format(nameReplace)) return for m_id in Glyphs.font.kerning: for left_group in Glyphs.font.kerning[m_id]: if side in ['RIGHT', 'BOTH']: group_prefix = self.is_group(left_group, group_name) if group_prefix: for right_group, val in Glyphs.font.kerning[m_id][ left_group].items(): Glyphs.font.setKerningForPair( m_id, group_prefix + nameReplace, self.glyph_for_id(right_group), val) Glyphs.font.removeKerningForPair( m_id, left_group, self.glyph_for_id(right_group)) left_group = group_prefix + nameReplace if side in ['LEFT', 'BOTH']: for right_group, val in Glyphs.font.kerning[m_id][ left_group].items(): group_prefix = self.is_group(right_group, group_name) if group_prefix: # print(m_id, left_group, right_group, self.glyph_for_id(left_group), group_prefix + nameReplace, val) # with open('/Users/benjones/Desktop/test.txt', 'a') as f: # f.write('{}\n'.format([m_id, left_group, right_group, self.glyph_for_id(left_group), group_prefix + nameReplace, val])) Glyphs.font.setKerningForPair( m_id, self.glyph_for_id(left_group), group_prefix + nameReplace, val) Glyphs.font.removeKerningForPair( m_id, self.glyph_for_id(left_group), right_group) @staticmethod def is_group(group, group_name): found_group = re.match('^(@MMK_._){}$'.format(group_name), group) if found_group is None: return False return found_group.group(1) @staticmethod def glyph_for_id(some_name): try: return Glyphs.font.glyphForId_(some_name).name except AttributeError: return some_name
class makeDisplay(object): def __init__(self): self.all_layer_combos = self.get_all_layer_combos() self.instance_values = self.get_instance_values() item_height = 24.0 w_width = 300.0 w_height = item_height * 10 margin = 10 next_y = margin col_1_width = w_width - (margin * 2) col_2_width = (w_width / 2) - (margin * 1.5) item_height = 24 radio_height = 20 * 2 self.get_prefs('addBraceLayers.pref') self.w = Window((w_width, w_height), "Add Layers") self.w.text_1 = TextBox((margin, next_y, col_1_width, item_height), "Layer Combinations:", sizeStyle='regular') next_y += item_height self.w.parent_layers = PopUpButton( (margin, next_y, col_1_width, item_height), self.all_layer_combos, sizeStyle='regular') self.set_all_layer_combos() next_y += item_height + margin self.w.brace_or_bracket = RadioGroup( (margin, next_y, col_1_width, radio_height), ['Bracket Layer [X]', 'Brace Layer {X}'], sizeStyle='regular') self.w.brace_or_bracket.set(int(self.prefs.get('brace_or_bracket', 0))) next_y += radio_height + margin self.w.text_2 = TextBox((margin, next_y, col_1_width, item_height), "Layer Value:", sizeStyle='regular') next_y += item_height self.w.layer_value = EditText( (margin, next_y, col_2_width, item_height), '', sizeStyle='small', placeholder='e.g. 700') self.w.instance_value_popup = PopUpButton( (margin + margin + col_2_width, next_y, col_2_width, item_height), self.instance_values, sizeStyle='regular', callback=self.changeinstance_value) next_y += item_height + margin if self.prefs.get('layer_value') is not None: self.w.layer_value.set(self.prefs.get('layer_value')) self.w.gobutton = Button( (margin + (col_1_width / 4), next_y, col_1_width / 2, item_height), 'Add Layers', callback=self.makeitso) self.w.setDefaultButton(self.w.gobutton) self.w.center() self.w.open() # self.makeitso(None) def get_prefs(self, filename): self.pref_folder = os.path.expanduser( '~/Library/Application Support/Glyphs/Prefs') self.pref_filepath = os.path.join(self.pref_folder, filename) self.prefs = {} if os.path.exists(self.pref_filepath): with open(self.pref_filepath) as f: preflines = f.readlines() self.prefs = dict( line.split('\t') for line in preflines if line[0] != '#' and line.strip()) def set_prefs(self, **kwargs): try: if not os.path.exists(self.pref_folder): os.makedirs(self.pref_folder) pref_string = '\n'.join( ['\t'.join(str(b) for b in a) for a in kwargs.items()]) with open(self.pref_filepath, 'w') as f: f.write(pref_string) except AttributeError: print('The Preference filename has not been set.') def get_all_layer_combos(self): master_combos = OrderedDict() for mi, m in enumerate(Glyphs.font.masters): try: next_m = Glyphs.font.masters[mi + 1] if not next_m: break combo_tup = (m, next_m) master_combos['{}-{}'.format( *[x.name for x in combo_tup])] = combo_tup except IndexError: break return master_combos def set_all_layer_combos(self): selection_index = Glyphs.font.masterIndex if selection_index >= len(self.all_layer_combos): selection_index = len(self.all_layer_combos) - 1 self.w.parent_layers.set(selection_index) def get_instance_values(self): return [''] + [ ', '.join([str(x) for x in list(i.axes)]) for i in Glyphs.font.instances ] def changeinstance_value(self, sender): self.w.layer_value.set(sender.getItem()) def makeitso(self, sender): try: self.w.close() except AttributeError: pass parent_layers = self.w.parent_layers.getItem() brace_or_bracket = self.w.brace_or_bracket.get() layer_value = float(self.w.layer_value.get().strip()) if int(layer_value) - layer_value == 0: layer_value = int(layer_value) self.set_prefs( parent_layers=parent_layers, brace_or_bracket=brace_or_bracket, layer_value=layer_value, ) layer_name_template = '{master_name} {{{layer_value}}}' if brace_or_bracket else '{master_name} [{layer_value}]' master_names = parent_layers.split('-') masters = [m for m in Glyphs.font.masters if m.name in master_names] for sl in Glyphs.font.selectedLayers: g = sl.parent for m in masters: newL = copy.copy(g.layers[m.id]) newL.layerId = None newL.associatedMasterId = m.id newL.name = layer_name_template.format( master_name=m.name, layer_value=layer_value, ) g.layers.append(newL)