Last active
March 16, 2020 10:55
-
-
Save cjdunn/f7d9ea2011a823853354f03bf7a1b036 to your computer and use it in GitHub Desktop.
MM2SpaceCenter_v4.9.py
This file contains 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
# MM2SpaceCenter by CJ Dunn, 2019, and licensed under the MIT license. Thanks to Tal Leming, Andy Clymer, David Jonathan Ross, Jackson Cavanaugh, Nina Stössinger for help and inspiration with this script | |
# #when pair changes: get pair and set to space center | |
#you must have a UFO open and have MetricsMachine open | |
import sys, os | |
import random | |
from mojo.UI import CurrentSpaceCenter, OpenSpaceCenter | |
import metricsMachine | |
from vanilla import FloatingWindow, Button, TextBox, List, Window | |
from defconAppKit.windows.baseWindow import BaseWindowController | |
from mojo.events import addObserver, removeObserver, postEvent | |
class KerningWords: | |
def activateModule(self): | |
# init for glyphChangeObserver | |
addObserver(self, "myObserver", "currentGlyphChanged") | |
addObserver(self, "MMPairChangedObserver", "MetricsMachine.currentPairChanged") | |
print ('KerningWords activated') | |
def deactivateModule(self, sender): | |
removeObserver(self, "currentGlyphChanged") | |
removeObserver(self, "MetricsMachine.currentPairChanged") | |
print ('KerningWords deactivated') | |
def __init__(self, wordlistPath): | |
self.font = metricsMachine.CurrentFont() | |
self.pair = metricsMachine.GetCurrentPair() | |
self.wordlistPath = wordlistPath | |
self.activateModule() | |
#self.w = FloatingWindow((170, 200), "Kerning Words") | |
self.w = Window((200, 50), "Kern-O-Mat") | |
#placeholder, inspired by Copy Names to Clipboard by Erik van Blokland | |
#self.sampleText = [u"👀🔡👀🔡👀🔡👀🔡", u"🔡👀🔡👀🔡👀🔡👀", u"👀🔡👀🔡👀🔡👀🔡", u"🔡👀🔡👀🔡👀🔡👀",u"👀🔡👀🔡👀🔡👀🔡", u"🔡👀🔡👀🔡👀🔡👀",u"👀🔡👀🔡👀🔡👀🔡", u"🔡👀🔡👀🔡👀🔡👀", ] | |
#self.sampleText = [u"🔠👀🚀"] | |
self.sampleText = [] | |
#self.sampleText = [u"👀🔡👀🔡👀🔡👀🔡",] | |
#self.w.l = List((0,0,0,-40), self.sampleText) | |
#self.w.l.setSelection([]) | |
self.w.myTextBox = TextBox((10, 10, -10, 17), "Kern-O-Mat activated 😎", sizeStyle="regular") | |
#print (dir(self.w.myTextBox)) | |
self.w.bind("close", self.deactivateModule) | |
self.w.open() | |
def myObserver(self, sender): | |
#add code here for when myObserver is triggered | |
print ('current glyph changed') | |
pass | |
def MMPairChangedObserver(self, sender): | |
#add code here for when myObserver is triggered | |
self.pair = metricsMachine.GetCurrentPair() | |
#print ('current MM pair changed', self.pair) | |
self.wordsForMMPair() | |
pass | |
def getMetricsMachineController(self): | |
# Iterate through ALL OBJECTS IN PYTHON! | |
import gc | |
for obj in gc.get_objects(): | |
if hasattr(obj, "__class__"): | |
# Does this one have a familiar name? Cool. Assume that we have what we are looking for. | |
if obj.__class__.__name__ == "MetricsMachineController": | |
return obj | |
def setSpaceCenter(self, font, text): | |
currentSC = CurrentSpaceCenter() | |
if currentSC is None: | |
print ('opening space center, click back into MM window') | |
OpenSpaceCenter(font, newWindow=False) | |
currentSC = CurrentSpaceCenter() | |
currentSC.setRaw(text) | |
def randomly(self, seq): | |
shuffled = list(seq) | |
random.shuffle(shuffled) | |
return iter(shuffled) | |
def gname2char(self, f, gname): | |
uni = f[gname].unicodes[0] | |
char = chr(uni) | |
return char | |
def checkPairForUnencodedGnames(self, font, pair): | |
#if either glyph is unencoded, use gname | |
left = self.pair[0] | |
right = self.pair[1] | |
if not font[left].unicodes: | |
left = '/'+left+' ' | |
else: | |
left = self.gname2char(font, left) | |
if not font[right].unicodes: | |
right = '/'+right+' ' | |
else: | |
right = self.gname2char(font, right) | |
pairstring = left+right | |
return pairstring | |
#convert char gnames to chars to find words in dict | |
def pair2char(self, pair): | |
debug = False | |
try: | |
#print ('pair =', pair) | |
left = self.gname2char(CurrentFont(), pair[0]) | |
right = self.gname2char(CurrentFont(), pair[1]) | |
pair_char = (left, right) | |
return pair_char | |
except: | |
if debug == True: | |
print ("couldn't convert pair to chars") | |
return pair | |
def lcString(self, pairstring): | |
string = 'non'+pairstring+'nono'+pairstring+'oo' | |
return string | |
def ucString(self, pairstring): | |
string = 'HOH'+pairstring+'HOHO'+pairstring+'OO' | |
return string | |
def wordsForMMPair(self, ): | |
#read wordlist file | |
import codecs | |
#need to figure out how to ignore header, temporarily just deleted it | |
fo = codecs.open(self.wordlistPath, mode="r", encoding="utf-8") | |
wordsAll = fo.read().splitlines() | |
contentLimit = '*****' | |
contentStart = wordsAll.index(contentLimit) + 1 | |
wordsAll = wordsAll[contentStart:] | |
fo.close() | |
#default values are hard coded for now | |
maxWordCount = 20 | |
#currently allows any word lenght, this could be customized later | |
text = '' | |
#convert MM tuple into search pair | |
pairstring = ''.join(self.pair2char(self.pair)) | |
#print (pairstring) | |
#default value | |
makeUpper = False | |
if pairstring.isupper(): | |
#print ('upper') | |
makeUpper = True | |
#make lower for searching | |
searchString = pairstring.lower() | |
else: | |
#print('not upper') | |
makeUpper = False | |
searchString = pairstring | |
pass | |
try: | |
currentSC = CurrentSpaceCenter() | |
previousText = currentSC.getRaw() | |
except: | |
previousText = '' | |
pass | |
count = 0 | |
for word in self.randomly(wordsAll): | |
if searchString in word: | |
#print (word) | |
text += word +' ' | |
count +=1 | |
#stop when you get enough results | |
if count > maxWordCount: | |
#print (text) | |
if makeUpper == True: | |
#make text upper again | |
text = text.upper() | |
#print (text) | |
break | |
# if no words are found, show spacing string and previous text | |
if len(text) == 0: | |
pairstring = self.checkPairForUnencodedGnames(font, self.pair) | |
previousText = '\\n no words for pair ' + pairstring | |
#print ('*😞* no words found for', pairstring, self.pair) | |
# #if either glyph is unencoded, use gname | |
# left = self.pair[0] | |
# right = self.pair[1] | |
# if not font[left].unicodes: | |
# left = '/'+left+' ' | |
# else: | |
# left = self.gname2char(font, left) | |
# if not font[right].unicodes: | |
# right = '/'+right+' ' | |
# else: | |
# right = self.gname2char(font, right) | |
# pairstring = left+right | |
if makeUpper == True: | |
#not sure if I still need space before pairstring, was originally there to deal with / but since using setRaw this isn't an issue | |
#self.setSpaceCenter(font, ' '+pairstring +' not found '+self.ucString(pairstring)+ previousText) | |
self.setSpaceCenter(font, ' '+pairstring +' '+self.ucString(pairstring)+ previousText) | |
else: | |
#self.setSpaceCenter(font, ' '+pairstring +' not found ' +self.lcString(pairstring)+ previousText) | |
self.setSpaceCenter(font, ' '+pairstring +' ' +self.lcString(pairstring)+ previousText) | |
else: | |
#set space center if words are found | |
#not sure why there's always a /slash in from of the first word, added ' '+ to avoid losing the first word | |
self.setSpaceCenter(font, text) | |
font = metricsMachine.CurrentFont() | |
## set path to word list | |
wordlistPath_rel = 'resources/ukacd.txt' | |
#wordlistPath_rel = 'resources/ukacd_temp.txt' | |
#wordlistPath_rel = 'resources/german.txt' | |
pathname = os.path.dirname(sys.argv[0]) | |
cwd = os.path.abspath(pathname) | |
wordlistPath_abs = os.path.join(cwd ,wordlistPath_rel) | |
p = KerningWords(wordlistPath= wordlistPath_abs) | |
# to do: | |
# make sure space center "show kerning" is set to on | |
# add ability to change word lenght and number of words ? | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment