Skip to content

Instantly share code, notes, and snippets.

@ryanbugden
Last active October 9, 2023 19:06
Show Gist options
  • Save ryanbugden/a7b946f786dce9cfd92853cdc827aeb1 to your computer and use it in GitHub Desktop.
Save ryanbugden/a7b946f786dce9cfd92853cdc827aeb1 to your computer and use it in GitHub Desktop.
Hit Command+L and type a glyph to throw it into the background layer very quickly.
# menuTitle : Throw Glyph in Background
# shortCut : command + l
from vanilla import Window, TextBox, ComboBox, Button, HorizontalLine
from mojo.UI import AskString, StatusInteractivePopUpWindow, CurrentGlyphWindow
from mojo.events import addObserver, removeObserver
from defconAppKit.windows.baseWindow import BaseWindowController
from AppKit import NSColor, NSObject
if __name__ == "__main__":
from lib.tools.debugTools import ClassNameIncrementer
else:
def ClassNameIncrementer(clsName, bases, dct):
return type(clsName, bases, dct)
f = CurrentFont()
g = CurrentGlyph()
throw_to_lname = 'background'
# def getGlyphEditorRectAndScreen(editorWindow):
# screen = editorWindow.w.getNSWindow().screen()
# nsWindow = editorWindow.w.getNSWindow()
# scrollView = editorWindow.getGlyphView().enclosingScrollView()
# rectInWindowCoords = scrollView.convertRect_toView_(scrollView.frame(), None)
# rectInScreenCoords = nsWindow.convertRectToScreen_(rectInWindowCoords)
# (screenX, screenY), (screenWidth, screenHeight) = screen.frame()
# (x, y), (w, h) = rectInScreenCoords
# y = -(y + h)
# return (x, y, w, h), screen
def sortedByLength(lst):
lst2 = sorted(lst, key=len)
return lst2
class GlyphThrower(BaseWindowController):
def __init__(self):
f = CurrentFont()
margin = 8
text_height = 20
text_width = 120
gutter = 2
button_width = text_width
button_height = text_height
window_height = margin * 2 + text_height * 2 + gutter * 3
window_width = margin * 2 + text_width
# editorWindow = CurrentGlyphWindow()
# (editorX, editorY, editorW, editorH), screen = getGlyphEditorRectAndScreen(editorWindow)
# x = editorX + ((editorW - window_width) / 2)
# y = editorY + ((editorH - window_height) / 2)
self.w = StatusInteractivePopUpWindow((window_width, window_height))
self.w.center()
self.w.text_box = TextBox(
(margin, margin, text_width, text_height),
text='Throw Glyph',
alignment='center',
selectable=False,
sizeStyle='small'
)
self.w.line = HorizontalLine((margin, margin + text_height + gutter/2, text_width, 1))
self.chosen_glyph = str(g.name)
self.w.glyph_input = ComboBox(
(margin, margin + text_height + gutter*3, text_width, text_height),
sortedByLength(f.glyphOrder), # redundant now?
completes=True,
# continuous=True,
callback=self.throwCallback,
)
g_i_NS = self.w.glyph_input.getNSComboBox()
g_i_NS.setAlignment_(0)
g_i_NS.setFocusRingType_(1)
# g_i_NS.setAutomaticTextCompletionEnabled_(True)
g_i_NS.becomeFirstResponder()
g_i_NS.setNumberOfVisibleItems_(10)
g_i_NS.setButtonBordered_(False)
# g_i_NS.setHasVerticalScroller_(False)
self._sourceGlyphNameComboBoxDataSource = comboBoxDataSource.alloc().init()
g_i_NS.setUsesDataSource_(True)
g_i_NS.setDataSource_(self._sourceGlyphNameComboBoxDataSource)
self._sourceGlyphNameComboBoxDataSource.setGlyphNames_(sortedByLength(f.glyphOrder))
self.w.glyph_input.set(self.chosen_glyph)
# invisible "close button"
self.w.close_button = Button((window_width + 20, window_height + 20, 1, 1), "", callback=self.closeCallback)
self.w.close_button.bind(chr(27), []) # make "escape" work
self.w.open()
def throwCallback(self, sender):
self.chosen_glyph = str(sender.get())
if not self.chosen_glyph in f:
for glyph_name in f.glyphOrder:
if self.chosen_glyph in glyph_name:
if glyph_name.split(self.chosen_glyph)[0] == '':
self.chosen_glyph = glyph_name
if g != None:
try:
cl = CurrentLayer()
fro = f.defaultLayer[self.chosen_glyph]
if self.chosen_glyph in cl.keys():
if cl[self.chosen_glyph].contours or cl[self.chosen_glyph].components:
fro = cl[self.chosen_glyph]
else:
fro = f.defaultLayer[self.chosen_glyph]
back = g.getLayer(throw_to_lname)
with back.undo(f'Throw glyph {g.name} in {throw_to_lname}'):
back.clear()
get_g = fro.copy()
fro.decompose()
back.appendGlyph(fro)
back.width = fro.width
fro.clear()
fro.appendGlyph(get_g)
back.changed()
# f.removeLayer('temp')
f.changed()
self.w.close()
except ValueError:
self.w.close()
else:
self.w.close()
f.getLayer(throw_to_lname).setDisplayOption({'Fill': True})
def closeCallback(self, sender):
self.w.close()
# code from Tal to improve auto-complete behavior
class comboBoxDataSource(NSObject, metaclass=ClassNameIncrementer):
def init(self):
self = super(comboBoxDataSource, self).init()
self._glyphNames = []
return self
def setGlyphNames_(self, names):
self._glyphNames = names
def comboBox_completedString_(self, comboBox, text):
if text in self._glyphNames:
return text
for name in self._glyphNames:
if name.startswith(text):
return name
return text
def comboBox_indexOfItemWithStringValue_(self, comboBox, text):
if text not in self._glyphNames:
return -1
return self._glyphNames.index(text)
def comboBox_objectValueForItemAtIndex_(self, comboBox, index):
return self._glyphNames[index]
def numberOfItemsInComboBox_(self, comboBox):
return len(self._glyphNames)
if __name__ == "__main__":
GlyphThrower()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment