From 975df8b241da1651e6e506e4ae2d8ca661109783 Mon Sep 17 00:00:00 2001 From: HugoJourdan <76793951+HugoJourdan@users.noreply.github.com> Date: Mon, 30 May 2022 18:26:54 +0200 Subject: [PATCH 1/9] Fix for Glyph3 --- plugin.py | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 plugin.py diff --git a/plugin.py b/plugin.py new file mode 100644 index 0000000..47b93b6 --- /dev/null +++ b/plugin.py @@ -0,0 +1,135 @@ +# encoding: utf-8 +from __future__ import division, print_function, unicode_literals + +########################################################################################################### +# +# +# Palette Plugin +# +# Read the docs: +# https://github.com/schriftgestalt/GlyphsSDK/tree/master/Python%20Templates/Palette +# +# +########################################################################################################### +from vanilla import * +import objc +import re +import os +import codecs +from GlyphsApp.plugins import * +from GlyphsApp.UI import * + +class labelKey(PalettePlugin): + + @objc.python_method + def settings(self): + self.name = 'Label Key' + self.width = 160 + self.elementHeight = 16 + keyQuantity = 12 + self.height = keyQuantity * self.elementHeight + self.paletteView = Window((self.width, self.height + 10)) + self.paletteView.frame = Group((0, 0, self.width, self.height + 5)) + + self.paletteView.frame.swatches = CanvasView((10, 0, -10, 0), self) + + self.dialog = self.paletteView.frame.getNSView() + + #colorsData = GSGlyphsInfo.labelColors() + colorKeys = ["red", + "orange", + "brown", + "yellow", + "lightGreen", + "darkGreen", + "lightBlue", + "darkBlue", + "purple", + "magenta", + "lightGray", + "charcoal"] + colours = [ + (0.85, 0.26, 0.06, 0.5), + (0.99, 0.62, 0.11, 0.5), + (0.65, 0.48, 0.20, 0.5), + (0.97, 0.90, 0.00, 0.5), + (0.67, 0.95, 0.38, 0.5), + (0.04, 0.57, 0.04, 0.5), + (0.06, 0.60, 0.98, 0.5), + (0.00, 0.20, 0.88, 0.5), + (0.50, 0.09, 0.79, 0.5), + (0.98, 0.36, 0.67, 0.5), + (0.75, 0.75, 0.75, 0.5), + (0.25, 0.25, 0.25, 0.5), + ] + # for colorData in colorsData: + # color = NSUnarchiver.unarchiveObjectWithData_(colorData) + # colours.append(color) + self.colours = dict(zip(colorKeys, colours)) + self.order = [] + + @objc.python_method + def update(self, sender): + if hasattr(self.paletteView.frame, 'labels'): + delattr(self.paletteView.frame, 'labels') + colourLabels, self.order = self.mapKeys(self.getKeyFile()) + self.paletteView.frame.labels = Group((27, 4, -10, 0)) + for num, i in enumerate(self.order): + setattr(self.paletteView.frame.labels, i, TextBox((0, num * self.elementHeight, 0, 22), colourLabels[i], sizeStyle="small")) + newHeight = self.elementHeight * len(self.order) + self.paletteView.frame.resize(self.width, newHeight + 10) + + @objc.python_method + def draw(self, view): + keyDiameter = 10 + height = view.bounds().size.height + for num, i in enumerate(self.order, 1): + print(num) + print(i) + if bool(re.search(r"\d", i)): + duplicateColour = re.match(r".*?(?=\d)", i).group(0) + self.colours[duplicateColour].set() + else: + NSColor.colorWithRed_green_blue_alpha_(*(self.colours[i])).set() + NSBezierPath.bezierPathWithOvalInRect_(((0, height - (num * self.elementHeight)), (keyDiameter, keyDiameter))).fill() + print("PRINT") + + @objc.python_method + def getKeyFile(self): + keyFile = None + try: + thisDirPath = os.path.dirname(self.windowController().document().font.filepath) + localKeyFile = thisDirPath + '/labelkey.txt' + if os.path.exists(localKeyFile): + keyFile = localKeyFile + except: + pass + if keyFile is None: + keyFile = os.path.expanduser('~/Library/Application Support/Glyphs/Info/labelkey.txt') + return keyFile + @objc.python_method + def mapKeys(self, keyFile): + order = [] + colourLabels = {} + if os.path.exists(keyFile): + with codecs.open(keyFile, "r", "utf-8") as file: + for line in file: + colour = re.match(r".*?(?=\=)", line).group(0) + label = re.search(r"(?<=\=).*", line).group(0) + colourLabels[colour] = label + order.append(colour) + #print "__colourLabels:", colourLabels, order + return colourLabels, order + + def setWindowController_(self, windowController): + try: + self._windowController = windowController + self.update(None) + except: + import traceback + self.logError(traceback.format_exc()) + + @objc.python_method + def __file__(self): + """Please leave this method unchanged""" + return __file__ From e737bb37509a65a632affde7d8ff4f639544ae1b Mon Sep 17 00:00:00 2001 From: HugoJourdan <76793951+HugoJourdan@users.noreply.github.com> Date: Mon, 30 May 2022 19:09:05 +0200 Subject: [PATCH 2/9] Add labelkey.txt if missing --- plugin.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/plugin.py b/plugin.py index 47b93b6..0e5008e 100644 --- a/plugin.py +++ b/plugin.py @@ -84,15 +84,12 @@ def draw(self, view): keyDiameter = 10 height = view.bounds().size.height for num, i in enumerate(self.order, 1): - print(num) - print(i) if bool(re.search(r"\d", i)): duplicateColour = re.match(r".*?(?=\d)", i).group(0) self.colours[duplicateColour].set() else: NSColor.colorWithRed_green_blue_alpha_(*(self.colours[i])).set() NSBezierPath.bezierPathWithOvalInRect_(((0, height - (num * self.elementHeight)), (keyDiameter, keyDiameter))).fill() - print("PRINT") @objc.python_method def getKeyFile(self): @@ -106,14 +103,24 @@ def getKeyFile(self): pass if keyFile is None: keyFile = os.path.expanduser('~/Library/Application Support/Glyphs/Info/labelkey.txt') + + if not os.path.exists(keyFile): + f = open(keyFile,"w+") + f.write("red=Red\norange=Orange\nbrown=Brown\nyellow=Yellow\nlightGreen=Light green\ndarkGreen=Dark green\nlightBlue=Light blue\ndarkBlue=Dark blue\npurple=Purple\nmagenta=Magenta\nlightGray=Light Gray\ncharcoal=Charcoal") + else: + pass return keyFile + + @objc.python_method def mapKeys(self, keyFile): + order = [] colourLabels = {} if os.path.exists(keyFile): with codecs.open(keyFile, "r", "utf-8") as file: for line in file: + colour = re.match(r".*?(?=\=)", line).group(0) label = re.search(r"(?<=\=).*", line).group(0) colourLabels[colour] = label From b2977bc55b51aeedc67e3a61ab05c2c12bcaa910 Mon Sep 17 00:00:00 2001 From: HugoJourdan <76793951+HugoJourdan@users.noreply.github.com> Date: Mon, 30 May 2022 23:29:32 +0200 Subject: [PATCH 3/9] Fix Label opacity --- plugin.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/plugin.py b/plugin.py index 0e5008e..eb8eb2b 100644 --- a/plugin.py +++ b/plugin.py @@ -49,18 +49,18 @@ def settings(self): "lightGray", "charcoal"] colours = [ - (0.85, 0.26, 0.06, 0.5), - (0.99, 0.62, 0.11, 0.5), - (0.65, 0.48, 0.20, 0.5), - (0.97, 0.90, 0.00, 0.5), - (0.67, 0.95, 0.38, 0.5), - (0.04, 0.57, 0.04, 0.5), - (0.06, 0.60, 0.98, 0.5), - (0.00, 0.20, 0.88, 0.5), - (0.50, 0.09, 0.79, 0.5), - (0.98, 0.36, 0.67, 0.5), - (0.75, 0.75, 0.75, 0.5), - (0.25, 0.25, 0.25, 0.5), + (0.85, 0.26, 0.06, 0.9), + (0.99, 0.62, 0.11, 0.9), + (0.65, 0.48, 0.20, 0.9), + (0.97, 0.90, 0.00, 0.9), + (0.67, 0.95, 0.38, 0.9), + (0.04, 0.57, 0.04, 0.9), + (0.06, 0.60, 0.98, 0.9), + (0.00, 0.20, 0.88, 0.9), + (0.50, 0.09, 0.79, 0.9), + (0.98, 0.36, 0.67, 0.9), + (0.75, 0.75, 0.75, 0.9), + (0.25, 0.25, 0.25, 0.9), ] # for colorData in colorsData: # color = NSUnarchiver.unarchiveObjectWithData_(colorData) From 6cebca5d292744290c8cb75f9392629234eff65b Mon Sep 17 00:00:00 2001 From: HugoJourdan <76793951+HugoJourdan@users.noreply.github.com> Date: Mon, 30 May 2022 23:30:04 +0200 Subject: [PATCH 4/9] Delete plugin.py --- plugin.py | 142 ------------------------------------------------------ 1 file changed, 142 deletions(-) delete mode 100644 plugin.py diff --git a/plugin.py b/plugin.py deleted file mode 100644 index eb8eb2b..0000000 --- a/plugin.py +++ /dev/null @@ -1,142 +0,0 @@ -# encoding: utf-8 -from __future__ import division, print_function, unicode_literals - -########################################################################################################### -# -# -# Palette Plugin -# -# Read the docs: -# https://github.com/schriftgestalt/GlyphsSDK/tree/master/Python%20Templates/Palette -# -# -########################################################################################################### -from vanilla import * -import objc -import re -import os -import codecs -from GlyphsApp.plugins import * -from GlyphsApp.UI import * - -class labelKey(PalettePlugin): - - @objc.python_method - def settings(self): - self.name = 'Label Key' - self.width = 160 - self.elementHeight = 16 - keyQuantity = 12 - self.height = keyQuantity * self.elementHeight - self.paletteView = Window((self.width, self.height + 10)) - self.paletteView.frame = Group((0, 0, self.width, self.height + 5)) - - self.paletteView.frame.swatches = CanvasView((10, 0, -10, 0), self) - - self.dialog = self.paletteView.frame.getNSView() - - #colorsData = GSGlyphsInfo.labelColors() - colorKeys = ["red", - "orange", - "brown", - "yellow", - "lightGreen", - "darkGreen", - "lightBlue", - "darkBlue", - "purple", - "magenta", - "lightGray", - "charcoal"] - colours = [ - (0.85, 0.26, 0.06, 0.9), - (0.99, 0.62, 0.11, 0.9), - (0.65, 0.48, 0.20, 0.9), - (0.97, 0.90, 0.00, 0.9), - (0.67, 0.95, 0.38, 0.9), - (0.04, 0.57, 0.04, 0.9), - (0.06, 0.60, 0.98, 0.9), - (0.00, 0.20, 0.88, 0.9), - (0.50, 0.09, 0.79, 0.9), - (0.98, 0.36, 0.67, 0.9), - (0.75, 0.75, 0.75, 0.9), - (0.25, 0.25, 0.25, 0.9), - ] - # for colorData in colorsData: - # color = NSUnarchiver.unarchiveObjectWithData_(colorData) - # colours.append(color) - self.colours = dict(zip(colorKeys, colours)) - self.order = [] - - @objc.python_method - def update(self, sender): - if hasattr(self.paletteView.frame, 'labels'): - delattr(self.paletteView.frame, 'labels') - colourLabels, self.order = self.mapKeys(self.getKeyFile()) - self.paletteView.frame.labels = Group((27, 4, -10, 0)) - for num, i in enumerate(self.order): - setattr(self.paletteView.frame.labels, i, TextBox((0, num * self.elementHeight, 0, 22), colourLabels[i], sizeStyle="small")) - newHeight = self.elementHeight * len(self.order) - self.paletteView.frame.resize(self.width, newHeight + 10) - - @objc.python_method - def draw(self, view): - keyDiameter = 10 - height = view.bounds().size.height - for num, i in enumerate(self.order, 1): - if bool(re.search(r"\d", i)): - duplicateColour = re.match(r".*?(?=\d)", i).group(0) - self.colours[duplicateColour].set() - else: - NSColor.colorWithRed_green_blue_alpha_(*(self.colours[i])).set() - NSBezierPath.bezierPathWithOvalInRect_(((0, height - (num * self.elementHeight)), (keyDiameter, keyDiameter))).fill() - - @objc.python_method - def getKeyFile(self): - keyFile = None - try: - thisDirPath = os.path.dirname(self.windowController().document().font.filepath) - localKeyFile = thisDirPath + '/labelkey.txt' - if os.path.exists(localKeyFile): - keyFile = localKeyFile - except: - pass - if keyFile is None: - keyFile = os.path.expanduser('~/Library/Application Support/Glyphs/Info/labelkey.txt') - - if not os.path.exists(keyFile): - f = open(keyFile,"w+") - f.write("red=Red\norange=Orange\nbrown=Brown\nyellow=Yellow\nlightGreen=Light green\ndarkGreen=Dark green\nlightBlue=Light blue\ndarkBlue=Dark blue\npurple=Purple\nmagenta=Magenta\nlightGray=Light Gray\ncharcoal=Charcoal") - else: - pass - return keyFile - - - @objc.python_method - def mapKeys(self, keyFile): - - order = [] - colourLabels = {} - if os.path.exists(keyFile): - with codecs.open(keyFile, "r", "utf-8") as file: - for line in file: - - colour = re.match(r".*?(?=\=)", line).group(0) - label = re.search(r"(?<=\=).*", line).group(0) - colourLabels[colour] = label - order.append(colour) - #print "__colourLabels:", colourLabels, order - return colourLabels, order - - def setWindowController_(self, windowController): - try: - self._windowController = windowController - self.update(None) - except: - import traceback - self.logError(traceback.format_exc()) - - @objc.python_method - def __file__(self): - """Please leave this method unchanged""" - return __file__ From 2fe54b57911b291479598a6a5470c233a077870f Mon Sep 17 00:00:00 2001 From: HugoJourdan <76793951+HugoJourdan@users.noreply.github.com> Date: Mon, 30 May 2022 23:30:24 +0200 Subject: [PATCH 5/9] Fix Label Opacity --- .../Contents/Resources/plugin.py | 52 +++++++++++++++---- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/LabelKey.glyphsPalette/Contents/Resources/plugin.py b/LabelKey.glyphsPalette/Contents/Resources/plugin.py index 0641f38..eb8eb2b 100644 --- a/LabelKey.glyphsPalette/Contents/Resources/plugin.py +++ b/LabelKey.glyphsPalette/Contents/Resources/plugin.py @@ -1,4 +1,5 @@ # encoding: utf-8 +from __future__ import division, print_function, unicode_literals ########################################################################################################### # @@ -11,6 +12,7 @@ # ########################################################################################################### from vanilla import * +import objc import re import os import codecs @@ -19,8 +21,8 @@ class labelKey(PalettePlugin): - - def settings( self ): + @objc.python_method + def settings(self): self.name = 'Label Key' self.width = 160 self.elementHeight = 16 @@ -33,7 +35,7 @@ def settings( self ): self.dialog = self.paletteView.frame.getNSView() - colorsData = Glyphs.defaults["LabelColors"] + #colorsData = GSGlyphsInfo.labelColors() colorKeys = ["red", "orange", "brown", @@ -46,12 +48,27 @@ def settings( self ): "magenta", "lightGray", "charcoal"] - colours = [] - for colorData in colorsData: - color = NSUnarchiver.unarchiveObjectWithData_(colorData) - colours.append(color) + colours = [ + (0.85, 0.26, 0.06, 0.9), + (0.99, 0.62, 0.11, 0.9), + (0.65, 0.48, 0.20, 0.9), + (0.97, 0.90, 0.00, 0.9), + (0.67, 0.95, 0.38, 0.9), + (0.04, 0.57, 0.04, 0.9), + (0.06, 0.60, 0.98, 0.9), + (0.00, 0.20, 0.88, 0.9), + (0.50, 0.09, 0.79, 0.9), + (0.98, 0.36, 0.67, 0.9), + (0.75, 0.75, 0.75, 0.9), + (0.25, 0.25, 0.25, 0.9), + ] + # for colorData in colorsData: + # color = NSUnarchiver.unarchiveObjectWithData_(colorData) + # colours.append(color) self.colours = dict(zip(colorKeys, colours)) + self.order = [] + @objc.python_method def update(self, sender): if hasattr(self.paletteView.frame, 'labels'): delattr(self.paletteView.frame, 'labels') @@ -62,7 +79,8 @@ def update(self, sender): newHeight = self.elementHeight * len(self.order) self.paletteView.frame.resize(self.width, newHeight + 10) - def draw( self, view ): + @objc.python_method + def draw(self, view): keyDiameter = 10 height = view.bounds().size.height for num, i in enumerate(self.order, 1): @@ -70,10 +88,11 @@ def draw( self, view ): duplicateColour = re.match(r".*?(?=\d)", i).group(0) self.colours[duplicateColour].set() else: - self.colours[i].set() + NSColor.colorWithRed_green_blue_alpha_(*(self.colours[i])).set() NSBezierPath.bezierPathWithOvalInRect_(((0, height - (num * self.elementHeight)), (keyDiameter, keyDiameter))).fill() - def getKeyFile( self ): + @objc.python_method + def getKeyFile(self): keyFile = None try: thisDirPath = os.path.dirname(self.windowController().document().font.filepath) @@ -84,14 +103,24 @@ def getKeyFile( self ): pass if keyFile is None: keyFile = os.path.expanduser('~/Library/Application Support/Glyphs/Info/labelkey.txt') + + if not os.path.exists(keyFile): + f = open(keyFile,"w+") + f.write("red=Red\norange=Orange\nbrown=Brown\nyellow=Yellow\nlightGreen=Light green\ndarkGreen=Dark green\nlightBlue=Light blue\ndarkBlue=Dark blue\npurple=Purple\nmagenta=Magenta\nlightGray=Light Gray\ncharcoal=Charcoal") + else: + pass return keyFile - def mapKeys( self, keyFile ): + + @objc.python_method + def mapKeys(self, keyFile): + order = [] colourLabels = {} if os.path.exists(keyFile): with codecs.open(keyFile, "r", "utf-8") as file: for line in file: + colour = re.match(r".*?(?=\=)", line).group(0) label = re.search(r"(?<=\=).*", line).group(0) colourLabels[colour] = label @@ -107,6 +136,7 @@ def setWindowController_(self, windowController): import traceback self.logError(traceback.format_exc()) + @objc.python_method def __file__(self): """Please leave this method unchanged""" return __file__ From 10742557981596975f0cd93a825f71b59610b2f2 Mon Sep 17 00:00:00 2001 From: schriftgestalt Date: Fri, 10 Jun 2022 17:00:59 +0200 Subject: [PATCH 6/9] update plugin binary --- LabelKey.glyphsPalette/Contents/Info.plist | 20 +++++------------- LabelKey.glyphsPalette/Contents/MacOS/main.py | 11 ---------- LabelKey.glyphsPalette/Contents/MacOS/plugin | Bin 56924 -> 120256 bytes LabelKey.glyphsPalette/Contents/PkgInfo | 1 - 4 files changed, 5 insertions(+), 27 deletions(-) delete mode 100644 LabelKey.glyphsPalette/Contents/MacOS/main.py mode change 100644 => 100755 LabelKey.glyphsPalette/Contents/MacOS/plugin delete mode 100644 LabelKey.glyphsPalette/Contents/PkgInfo diff --git a/LabelKey.glyphsPalette/Contents/Info.plist b/LabelKey.glyphsPalette/Contents/Info.plist index fd13dba..7e22376 100644 --- a/LabelKey.glyphsPalette/Contents/Info.plist +++ b/LabelKey.glyphsPalette/Contents/Info.plist @@ -1,11 +1,9 @@ - + CFBundleDevelopmentRegion - English - CFBundleDisplayName - Label Key + en CFBundleExecutable plugin CFBundleIdentifier @@ -14,25 +12,17 @@ 6.0 CFBundleName Label Key - CFBundlePackageType - BNDL - CFBundleVersion - 2.0 CFBundleShortVersionString 2.0 - UpdateFeedURL - https://github.com/RobertPratley/labelKey/LabelKey.glyphsPalette/Contents/Info.plist - productPageURL - https://github.com/RobertPratley/labelKey - productReleaseNotes - + CFBundleVersion + 3 NSHumanReadableCopyright Copyright, RobertPratley, 2017 NSPrincipalClass labelKey PyMainFileNames - ../MacOS/main.py + plugin.py diff --git a/LabelKey.glyphsPalette/Contents/MacOS/main.py b/LabelKey.glyphsPalette/Contents/MacOS/main.py deleted file mode 100644 index 98f307d..0000000 --- a/LabelKey.glyphsPalette/Contents/MacOS/main.py +++ /dev/null @@ -1,11 +0,0 @@ -def _run(*scripts): - global __file__ - import os, sys #, site - sys.frozen = 'macosx_plugin' - base = os.environ['RESOURCEPATH'] - for script in scripts: - path = os.path.join(base, script) - __file__ = path - execfile(path, globals(), globals()) - -_run('plugin.py') diff --git a/LabelKey.glyphsPalette/Contents/MacOS/plugin b/LabelKey.glyphsPalette/Contents/MacOS/plugin old mode 100644 new mode 100755 index b21f0e490123246868a0871f758ac53ed4c23d62..ce7d93c039eb62a72ccfd18b7c2e0b7dfbfa3246 GIT binary patch literal 120256 zcmeHw3wTu3+3uQ20x3#GA&A!MU`4S-E|w@p(V2va8J%331PT7No5{>hGBTMN=K@5F z1`#F3w9rze)@r=eLTX#uVvDynR)4`(D`=}&YX!76)YjsqNUS>N{nq;S%$^C+^Pm5m z^F06ato>x~wZ6;x*0J@`u@gwr9!ScFAFxDkAF9WI{+??{9~AR@#c z266c`#q^;O&G-C*VAU$QsV(ID{*lLKsG~ zx22hx_P}i?5NEmsQ95Z+0XhsLWv)o6xT5pzl}=N#=Z{jMMQ2kKi|%Y35yMEP(yhrX ztI)qc&sCxuS%YY~i~-Z7Y;O$H%AV0-M&f1yyh3{&k|!Fa>oe&g2_}O9BpTf zLVI61O9}2}2Q1n$m}eVI!$^Ouz2f;QWd$1`+FoAEt`!I~$Y=G!O84Wm6~YsMq&mAaL(O9g^x z^2a*J-V}>KXc&>e$N4wit(3QM8lvs?sDGWnG71c%Ge(sVP8n_KXmEsod)!LdDlgG? zd!JI`?A0)WZT5y&SRX@3PsfsC6%uW?r?|N*x4Up>pxvaVQfRNnt8^{@i2k^C!uFD8 zBw@B;I4HE&!1fNX3q;%fD^WvU)Je`2!+i{uOXENTPC6(#onOE?1Lx;(j&|(0Nr*2VM)(=;o@rEZh*?ct$&}eS z%O7q{1QK1dsuLKEm&X!Ile4N~!B}8so5h%QiJ3@-W6|U+j}jrhvbzLf)^6r+V^BKB z$JniorK4z+Fm*WNRkLz(wm;8qU%Uniey5X(S&?unopdLe>6sboLL5SQPG_Li zk>?W6LQiv3&Fa5*)b!4GO~wD1r{TYYHNEAhxDfPg&y>A%yb!*g{~S6Nzmyny5WiNc z>6`z(V-P<`@il{~Bf;1}j3P?eH~$ujzi1O)PmI@9N*RCHCQOs?NhMrG@jGn7I5F;1 z!Vuy$edSRE57IxihptupAn9CgOVmh=wZtnp6x?@7UMBy zTy8ObN{rt5za;Cu<G4wx}KPQW$&ZnYI-i)SkvF@1hLLs0_U;H$w6dB$={W z{GS{}NuLG`dZc6J`yhboQc~?3e;oqvoWVJRnX;**+gpAk$$Pw30ec=Bx(&Y=@b!@Y z%cLxe&jt9U2aw(fuD>Va?|Bp6&v_CUJdYnQcrwrXdL9RwNOwLoK*N(%N$r}~QoC?L z!XHBo+Ac_sy6$cK>;WiVMOpM-){TU~CR5f69pLm!*@idZ-~X~^>X36y-(}A{Q6%OZ ztm*q!Jd?@P^qg7K*SA8(<{(K;&!2~Wi6)ULdylfG#(5Bt8;jO@w_G=vIbeJzwzlUzC{;sA z$$dRf5dQep71bEmUACsFT~UKUQ$yqX?A&bI_y!V4B2c@KrB{%|!IR0F;9e~%xa0KRRRvbSN+-}6tvTr-(m+eZ#bP$?I*iBPrq7-Y)zvFEp|a+I2ft3GKBn5+#mJZp z_m=M>7y8ORZ|i^MD;4i7J8zZZRf6Z8^BOgjo=4{l!iK+RKS~F1wv)@~f24@&+eMe> zq)&fDbD&X%D)ng6>MMU~Jh9Md-p`cX4p#TdEnt^CP3*q;&r)#If#in z_jeK1JHMGU`pVY;)}g;rH|hCjrfmBpFjqg`@gJTqdoJ^Q#baFd7>XB=J+bU~YUt?I zvJDXbOT@QEne=Sn@eAVgmb($4wiVjvs?;AKBO8Q-P4D~{l)j6Co@^{eDB%1TpJgVfI=^&5k*e!3DrNaDV-m#8oI?4{

s6ZXE2k;VJu1!pWSj=8r<8_Qf>M47D6|Sv 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 literal 56924 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

7eMUO`~A7L)S-3ZSj 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 WKHh|^)uOdb{I@%FFuu7ThyM%ug;eJN diff --git a/LabelKey.glyphsPalette/Contents/PkgInfo b/LabelKey.glyphsPalette/Contents/PkgInfo deleted file mode 100644 index 19a9cf6..0000000 --- a/LabelKey.glyphsPalette/Contents/PkgInfo +++ /dev/null @@ -1 +0,0 @@ -BNDL???? \ No newline at end of file From 046ffb5a85b5a2eea6954d7ee70bde00c6ffec6d Mon Sep 17 00:00:00 2001 From: HugoJourd Date: Thu, 16 Feb 2023 15:30:53 +0100 Subject: [PATCH 7/9] Fix for Glyphs3 --- .../Contents/Resources/plugin.py | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/LabelKey.glyphsPalette/Contents/Resources/plugin.py b/LabelKey.glyphsPalette/Contents/Resources/plugin.py index eb8eb2b..985bc16 100644 --- a/LabelKey.glyphsPalette/Contents/Resources/plugin.py +++ b/LabelKey.glyphsPalette/Contents/Resources/plugin.py @@ -25,11 +25,11 @@ class labelKey(PalettePlugin): def settings(self): self.name = 'Label Key' self.width = 160 - self.elementHeight = 16 + self.elementHeight = 17 keyQuantity = 12 self.height = keyQuantity * self.elementHeight self.paletteView = Window((self.width, self.height + 10)) - self.paletteView.frame = Group((0, 0, self.width, self.height + 5)) + self.paletteView.frame = Group((0, 0, self.width, self.height + 10)) self.paletteView.frame.swatches = CanvasView((10, 0, -10, 0), self) @@ -66,16 +66,18 @@ def settings(self): # color = NSUnarchiver.unarchiveObjectWithData_(colorData) # colours.append(color) self.colours = dict(zip(colorKeys, colours)) - self.order = [] + self.order = self.mapKeys(self.getKeyFile()) @objc.python_method def update(self, sender): if hasattr(self.paletteView.frame, 'labels'): delattr(self.paletteView.frame, 'labels') colourLabels, self.order = self.mapKeys(self.getKeyFile()) - self.paletteView.frame.labels = Group((27, 4, -10, 0)) + self.paletteView.frame.labels = Group((0, 4, -10, 0)) for num, i in enumerate(self.order): - setattr(self.paletteView.frame.labels, i, TextBox((0, num * self.elementHeight, 0, 22), colourLabels[i], sizeStyle="small")) + setattr(self.paletteView.frame.labels, i, TextBox((24, num * self.elementHeight, 0, 22), colourLabels[i], sizeStyle="small")) + + newHeight = self.elementHeight * len(self.order) self.paletteView.frame.resize(self.width, newHeight + 10) @@ -85,33 +87,38 @@ def draw(self, view): height = view.bounds().size.height for num, i in enumerate(self.order, 1): if bool(re.search(r"\d", i)): + duplicateColour = re.match(r".*?(?=\d)", i).group(0) self.colours[duplicateColour].set() else: NSColor.colorWithRed_green_blue_alpha_(*(self.colours[i])).set() - NSBezierPath.bezierPathWithOvalInRect_(((0, height - (num * self.elementHeight)), (keyDiameter, keyDiameter))).fill() + + NSBezierPath.bezierPathWithOvalInRect_(((0, height - (num * self.elementHeight)), (keyDiameter, keyDiameter))).fill() @objc.python_method def getKeyFile(self): keyFile = None + + # Get colorNames.txt file next to Glyph file try: thisDirPath = os.path.dirname(self.windowController().document().font.filepath) - localKeyFile = thisDirPath + '/labelkey.txt' + localKeyFile = thisDirPath + '/colorNames.txt' if os.path.exists(localKeyFile): keyFile = localKeyFile except: pass if keyFile is None: - keyFile = os.path.expanduser('~/Library/Application Support/Glyphs/Info/labelkey.txt') - - if not os.path.exists(keyFile): + if Glyphs.versionString.startswith("3"): + keyFile = os.path.expanduser('~/Library/Application Support/Glyphs 3/info/colorNames.txt') + else: + keyFile = os.path.expanduser('~/Library/Application Support/Glyphs/info/colorNames.txt') + if not os.path.exists(keyFile): f = open(keyFile,"w+") - f.write("red=Red\norange=Orange\nbrown=Brown\nyellow=Yellow\nlightGreen=Light green\ndarkGreen=Dark green\nlightBlue=Light blue\ndarkBlue=Dark blue\npurple=Purple\nmagenta=Magenta\nlightGray=Light Gray\ncharcoal=Charcoal") + f.write("None=🫥 None\nred=🚨 Red\norange=🦊 Orange\nbrown=🪵 Brown\nyellow=🌼 Yellow\nlightGreen=🍀 Light green\ndarkGreen=🫑 Dark green\nlightBlue=💎 Light blue\ndarkBlue=🌀 Dark blue\npurple=🔮 Purple\nmagenta=🌺 Magenta\nlightGray=🏐 Light Gray\ncharcoal=🎱 Charcoal") else: pass return keyFile - @objc.python_method def mapKeys(self, keyFile): @@ -120,6 +127,7 @@ def mapKeys(self, keyFile): if os.path.exists(keyFile): with codecs.open(keyFile, "r", "utf-8") as file: for line in file: + if "None" in line: continue colour = re.match(r".*?(?=\=)", line).group(0) label = re.search(r"(?<=\=).*", line).group(0) From ce27d058b6c7208022722160d58fb4e320956b1b Mon Sep 17 00:00:00 2001 From: Hugo Jourdan <76793951+HugoJourdan@users.noreply.github.com> Date: Thu, 16 Feb 2023 15:31:45 +0100 Subject: [PATCH 8/9] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5c61660..1c282df 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ It adds a new palette to the sidebar displaying a user defined key for Glyphs' c ### How to use -The plugin requires a labelkey.txt file stored in either ~/Library/Application Support/Glyphs/info/ or the same directory as the current Glyphs source file. Preference is given to the latter allowing for the sharing of the labelkey.txt file with glyphs source files to retain labelling information between project contributors. +The plugin requires a `colorNames.txt` file stored in either ~/Library/Application Support/Glyphs/info/ or the same directory as the current Glyphs source file. Preference is given to the latter allowing for the sharing of the labelkey.txt file with glyphs source files to retain labelling information between project contributors. -The labelkey.txt file requires the formatting `colorName=meaning`, with each key on a newline and with no space surrounding the '='. The order of the key will follow the order specified in the text file. An example, with the defined colorNames is given below. +The `colorNames.txt` file requires the formatting `colorName=meaning`, with each key on a newline and with no space surrounding the '='. The order of the key will follow the order specified in the text file. An example, with the defined colorNames is given below. ``` red=Red From d898e2164f8e3e369566aec468e47692cf1d0528 Mon Sep 17 00:00:00 2001 From: schriftgestalt Date: Tue, 1 Aug 2023 11:35:50 +0200 Subject: [PATCH 9/9] improve file handling/writing default file --- .../Contents/Resources/plugin.py | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/LabelKey.glyphsPalette/Contents/Resources/plugin.py b/LabelKey.glyphsPalette/Contents/Resources/plugin.py index 985bc16..8899be3 100644 --- a/LabelKey.glyphsPalette/Contents/Resources/plugin.py +++ b/LabelKey.glyphsPalette/Contents/Resources/plugin.py @@ -97,27 +97,35 @@ def draw(self, view): @objc.python_method def getKeyFile(self): - keyFile = None - + keyFilePath = None + keyFileName = 'colorNames.txt' # Get colorNames.txt file next to Glyph file try: - thisDirPath = os.path.dirname(self.windowController().document().font.filepath) - localKeyFile = thisDirPath + '/colorNames.txt' - if os.path.exists(localKeyFile): - keyFile = localKeyFile + thisDirPath = os.path.dirname(self.windowController().document().fileURL().path()) + localKeyFilePath = os.path.join(thisDirPath, keyFileName) + if os.path.exists(localKeyFilePath): + keyFilePath = localKeyFilePath except: pass - if keyFile is None: - if Glyphs.versionString.startswith("3"): - keyFile = os.path.expanduser('~/Library/Application Support/Glyphs 3/info/colorNames.txt') + if keyFilePath is None: + + if Glyphs.versionNumber >= 3: + keyFolderPath = '~/Library/Application Support/Glyphs 3/Info' else: - keyFile = os.path.expanduser('~/Library/Application Support/Glyphs/info/colorNames.txt') - if not os.path.exists(keyFile): - f = open(keyFile,"w+") - f.write("None=🫥 None\nred=🚨 Red\norange=🦊 Orange\nbrown=🪵 Brown\nyellow=🌼 Yellow\nlightGreen=🍀 Light green\ndarkGreen=🫑 Dark green\nlightBlue=💎 Light blue\ndarkBlue=🌀 Dark blue\npurple=🔮 Purple\nmagenta=🌺 Magenta\nlightGray=🏐 Light Gray\ncharcoal=🎱 Charcoal") - else: - pass - return keyFile + keyFolderPath = '~/Library/Application Support/Glyphs/Info' + + keyFolderPath = os.path.expanduser(keyFolderPath) + + if not os.path.exists(keyFolderPath): + os.makedirs(keyFolderPath) + + keyFilePath = os.path.join(keyFolderPath, keyFileName) + if not os.path.exists(keyFilePath): + f = codecs.open(keyFilePath, mode="w", encoding="utf-8") + f.write("None=🫥 None\nred=🚨 Red\norange=🦊 Orange\nbrown=🪵 Brown\nyellow=🌼 Yellow\nlightGreen=🍀 Light green\ndarkGreen=🫑 Dark green\nlightBlue=💎 Light blue\ndarkBlue=🌀 Dark blue\npurple=🔮 Purple\nmagenta=🌺 Magenta\nlightGray=🏐 Light Gray\ncharcoal=🎱 Charcoal") + f.close() + + return keyFilePath @objc.python_method def mapKeys(self, keyFile):