Instantly share code, notes, and snippets.
Last active
March 5, 2025 18:07
-
Star
0
(0)
You must be signed in to star a gist -
Fork
0
(0)
You must be signed in to fork a gist
-
-
Save ryanbugden/567ed3530e5e8c0485e33720da106e75 to your computer and use it in GitHub Desktop.
A contextual menu for Font Overview. Rename glyphs (rename one, find and replace or add to many names)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # menuTitle : (Start-up) (FO) Rename Glyphs | |
| # author: Ryan Bugden | |
| import ezui | |
| from mojo.subscriber import Subscriber, registerFontOverviewSubscriber | |
| from mojo.extensions import getExtensionDefault, setExtensionDefault | |
| from mojo.UI import CurrentFontWindow, Message | |
| EXTENSION_KEY = "com.ryanbugden.glyphRenamerSettings" | |
| class GlyphRenamer(ezui.WindowController): | |
| def build(self, parent): | |
| window = parent.w | |
| self.f = RFont(parent._font) | |
| self.glyphs_to_rename = self.f.templateSelectedGlyphNames | |
| content = """ | |
| (X) Rename @operationRadios | |
| ( ) Find / Replace | |
| ( ) Add to Name | |
| ( ) Force New Suffix | |
| --- | |
| [_ _] @renameTextField | |
| * HorizontalStack @findReplaceStack | |
| > [_ _] @findTextField | |
| > → @arrowLabel | |
| > [_ _] @replaceTextField | |
| [_ _] @addToNameTextField | |
| . [_ _] @forceSuffixTextField | |
| [X] Overwrite Existing Glyphs @overwriteCheckbox | |
| ====================== | |
| (Cancel) @cancelButton | |
| (Apply) @applyButton | |
| """ | |
| entry_width = 160 | |
| button_width = (entry_width - 10) / 2 | |
| descriptionData = dict( | |
| renameTextField=dict( | |
| valueWidth=entry_width, | |
| ), | |
| findReplaceStack=dict( | |
| width=entry_width, | |
| ), | |
| findTextField=dict( | |
| width=(entry_width - 32) / 2, | |
| ), | |
| replaceTextField=dict( | |
| width="fill", | |
| ), | |
| overwriteCheckbox=dict( | |
| sizeStyle="small", | |
| ), | |
| cancelButton=dict( | |
| width=button_width, | |
| ), | |
| applyButton=dict( | |
| width=button_width, | |
| ) | |
| ) | |
| self.w = ezui.EZSheet( | |
| content=content, | |
| descriptionData=descriptionData, | |
| size="auto", | |
| parent=window, | |
| controller=self | |
| ) | |
| self.operation = self.w.getItem("operationRadios") | |
| self.rename_field = self.w.getItem("renameTextField") | |
| self.find_field = self.w.getItem("findTextField") | |
| self.replace_field = self.w.getItem("replaceTextField") | |
| self.add_to_field = self.w.getItem("addToNameTextField") | |
| self.force_suffix_field = self.w.getItem("forceSuffixTextField") | |
| self.find_replace_stack = self.w.getItem("findReplaceStack") | |
| self.overwrite = self.w.getItem("overwriteCheckbox") | |
| self.apply_button = self.w.getItem("applyButton") | |
| self.cancel_button = self.w.getItem("cancelButton") | |
| self.cancel_button.bind(chr(27), []) | |
| self.w.setDefaultButton(self.apply_button) | |
| if len(self.glyphs_to_rename) > 1: | |
| self.operation.set(1) | |
| prefs = getExtensionDefault(EXTENSION_KEY, fallback=self.overwrite.get()) | |
| try: self.overwrite.set(prefs) | |
| except KeyError: pass | |
| self.update_field_options() | |
| def started(self): | |
| if not self.glyphs_to_rename: | |
| return | |
| self.rename_field.set(self.glyphs_to_rename[0]) | |
| replace = self.glyphs_to_rename[0] | |
| for g_name in self.glyphs_to_rename: | |
| if "." in g_name: | |
| replace = "." + g_name.split(".")[-1] | |
| break | |
| self.find_field.set(replace) | |
| self.replace_field.set(replace) | |
| self.w.open() | |
| def destroy(self): | |
| setExtensionDefault(EXTENSION_KEY, self.overwrite.get()) | |
| def cancelButtonCallback(self, sender): | |
| self.w.close() | |
| def applyButtonCallback(self, sender): | |
| kwargs = dict(renameComponents=True, renameGroups=True, renameKerning=True, renameInLayers=True) | |
| rename_dict = dict() | |
| for g_name in self.glyphs_to_rename: | |
| from_name, to_name = g_name, g_name | |
| # Rename | |
| if self.operation.get() == 0: | |
| to_name = self.rename_field.get() | |
| # Replace | |
| elif self.operation.get() == 1: | |
| to_name = g_name.replace(self.find_field.get(), self.replace_field.get()) | |
| # Add to name | |
| elif self.operation.get() == 2: | |
| to_name = g_name + self.add_to_field.get() | |
| # Force suffix | |
| elif self.operation.get() == 3: | |
| to_name = ".".join([g_name.split(".")[0], self.force_suffix_field.get()]) | |
| if from_name == to_name: | |
| continue | |
| rename_dict.update({from_name: to_name}) | |
| renamed_something = False | |
| if rename_dict: | |
| for from_name, to_name in rename_dict.items(): | |
| if to_name not in self.f.templateGlyphOrder or self.overwrite.get(): | |
| self.f.renameGlyph(from_name, to_name, **kwargs) | |
| renamed_something = True | |
| self.w.close() | |
| if not renamed_something: | |
| Message("No Renaming Done", informativeText='None of your glyphs were renamed.') | |
| def operationRadiosCallback(self, sender): | |
| self.update_field_options() | |
| def update_field_options(self): | |
| self.rename_field.enable(True) | |
| if len(self.glyphs_to_rename) > 1: | |
| self.rename_field.enable(False) | |
| if self.operation.get() == 0: | |
| self.rename_field.show(True) | |
| self.find_replace_stack.show(False) | |
| self.add_to_field.show(False) | |
| self.force_suffix_field.show(False) | |
| elif self.operation.get() == 1: | |
| self.rename_field.show(False) | |
| self.find_replace_stack.show(True) | |
| self.add_to_field.show(False) | |
| self.force_suffix_field.show(False) | |
| elif self.operation.get() == 2: | |
| self.rename_field.show(False) | |
| self.find_replace_stack.show(False) | |
| self.add_to_field.show(True) | |
| self.force_suffix_field.show(False) | |
| elif self.operation.get() == 3: | |
| self.rename_field.show(False) | |
| self.find_replace_stack.show(False) | |
| self.add_to_field.show(False) | |
| self.force_suffix_field.show(True) | |
| class RenameGlyphs(Subscriber): | |
| def fontOverviewWantsContextualMenuItems(self, info): | |
| self.f = CurrentFont() | |
| self.fo = info['fontOverview'] | |
| if not self.f.templateSelectedGlyphNames: | |
| return | |
| if len(self.f.templateSelectedGlyphNames) > 1: | |
| message = "Rename Glyphs..." | |
| else: | |
| message = "Rename Glyph..." | |
| my_menu_items = [ | |
| (message, self.renameGlyphsCallback) | |
| ] | |
| info['itemDescriptions'].extend(my_menu_items) | |
| def renameGlyphsCallback(self, sender): | |
| parent = CurrentFontWindow() | |
| GlyphRenamer(parent) | |
| if __name__ == "__main__": | |
| registerFontOverviewSubscriber(RenameGlyphs) |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Note to self: add checkbox for auto-unicode (opt-out at first)