From 074ca1521e81506767f4c9e211600b915dcfe8cd Mon Sep 17 00:00:00 2001 From: Ben Kiel Date: Thu, 6 Jul 2023 13:18:53 -0500 Subject: [PATCH 1/6] Update logic for public.openTypePostUnderlinePosition key --- .../lib/Underline StrikeThrough.py | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py b/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py index 1ccb5a8..b4aab09 100644 --- a/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py +++ b/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py @@ -6,6 +6,7 @@ from mojo.extensions import getExtensionDefault, setExtensionDefault from defconAppKit.tools.textSplitter import splitText from lib.tools.unicodeTools import GN2UV +from fontTools.misc import otRound def getKey(val, di): @@ -194,7 +195,7 @@ def build(self): self.w.getItem('testText').set(self.testString) self.underlineThickness = {} - self.underlinePosition = {} + self.underlinePosition = {} # The top of the underline self.strikeThickness = {} self.strikePosition = {} @@ -299,7 +300,6 @@ def updateFontList(self): # Update internal account of data when new font is opened/closed dictionaryToValue = [ (self.underlineThickness , font.info.postscriptUnderlineThickness), - (self.underlinePosition , font.info.postscriptUnderlinePosition), (self.strikeThickness , font.info.openTypeOS2StrikeoutSize), (self.strikePosition , font.info.openTypeOS2StrikeoutPosition) ] @@ -310,7 +310,19 @@ def updateFontList(self): dictionary.update({fontIdentifier: value}) else: dictionary.update({fontIdentifier: None}) - + # Deal with underline position + if 'public.openTypePostUnderlinePosition' in font.lib.keys(): + self.underlinePosition.update{fontIdentifier: font.lib['public.openTypePostUnderlinePosition'} + # If font doesn't have that lib key set, but is using fontmake, use fontmake behavior + elif font.lib["com.robofont.fontCompilerTool"] == 'fontmake': + self.underlinePosition.update{fontIdentifier: font.info.postscriptUnderlineThickness} + # If not that, do the math to get position + elif font.info.postscriptUnderlinePosition and font.info.postscriptUnderlineThickness: + ul = font.info.postscriptUnderlinePosition + font.info.postscriptUnderlineThickness / 2 + self.underlinePosition.update{fontIdentifier: ul} + # If no position or thickness, value is None + else: + self.underlinePosition.update{fontIdentifier: None} # Set the font list in the UI self.w.getItem("table").set(self.fontsList) @@ -396,7 +408,7 @@ def ulDescButtonCallback(self, sender): fontIdentifier = self.getFontIdentifier(font) value = None if self.underlineThickness[fontIdentifier]: - value = int(font.info.descender + self.underlineThickness[fontIdentifier] / 2) + value = int(font.info.descender + self.underlineThickness[fontIdentifier]) self.underlinePosition[fontIdentifier] = value self.updatePreview() self.updateTextFields() @@ -407,7 +419,7 @@ def ulBelowDescButtonCallback(self, sender): fontIdentifier = self.getFontIdentifier(font) value = None if self.underlineThickness[fontIdentifier]: - value = int(font.info.descender - self.underlineThickness[fontIdentifier] * 1.5) + value = int(font.info.descender - self.underlineThickness[fontIdentifier]) self.underlinePosition[fontIdentifier] = value self.updatePreview() self.updateTextFields() @@ -505,8 +517,8 @@ def updatePreview(self): if self.underlinePosition[fontIdentifier] and self.underlineThickness[fontIdentifier]: underlineLine = self.container.appendLineSublayer( - startPoint=(margin, baseline + self.underlinePosition[fontIdentifier]), - endPoint=(cursor, baseline + self.underlinePosition[fontIdentifier]), + startPoint=(margin, baseline + self.underlinePosition[fontIdentifier] - self.underlineThickness[fontIdentifier] / 2), + endPoint=(cursor, baseline + self.underlinePosition[fontIdentifier] - self.underlineThickness[fontIdentifier] / 2), strokeWidth=self.underlineThickness[fontIdentifier] * viewScale, strokeColor=self.localStrokeColor ) @@ -525,8 +537,8 @@ def roundInteger(self, value): '''Same as int(), but accepts None.''' if value == None: return None - return int(value) - + return otRound(value) + def setAllButtonCallback(self, sender): ''' Uses the tool’s dictionary we've been building, and writes those values into the UFO files themselves. @@ -539,7 +551,12 @@ def setAllButtonCallback(self, sender): for font in self.fonts: fontIdentifier = self.getFontIdentifier(font) font.info.postscriptUnderlineThickness = self.roundInteger(uT[fontIdentifier]) - font.info.postscriptUnderlinePosition = self.roundInteger(uP[fontIdentifier]) + # Math only works if there is a underline thickness + if uT[fontIdentifier]: + font.info.postscriptUnderlinePosition = self.roundInteger(uP[fontIdentifier] - uT[fontIdentifier] / 2) + else: + font.info.postscriptUnderlinePosition = None + font.lib['public.openTypePostUnderlinePosition'] = self.roundInteger(uP[fontIdentifier]) font.info.openTypeOS2StrikeoutSize = self.roundInteger(sT[fontIdentifier]) font.info.openTypeOS2StrikeoutPosition = self.roundInteger(sP[fontIdentifier]) self.w.getItem('setAllLabel').show(True) From 1c0e4abcd78b09a477f582ffd8bcb4e8c3a21efc Mon Sep 17 00:00:00 2001 From: Ben Kiel Date: Wed, 12 Jul 2023 14:27:25 -0500 Subject: [PATCH 2/6] Style fixups, missing parends for .update --- .../lib/Underline StrikeThrough.py | 193 +++++++++--------- 1 file changed, 98 insertions(+), 95 deletions(-) diff --git a/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py b/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py index b4aab09..75c4184 100644 --- a/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py +++ b/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py @@ -9,11 +9,12 @@ from fontTools.misc import otRound -def getKey(val, di): - for key, value in di.items(): - if val == value: +def getKey(val, di): + for key, value in di.items(): + if val == value: return key - + + extensionKey = 'com.typefounding.underlineStrikethrough' @@ -21,70 +22,70 @@ class UnderlineStrikethrough(Subscriber, ezui.WindowController): def build(self): content = """ - * HorizontalStack + * HorizontalStack > |-----| @table > | | > |-----| - + > --- - + > * VerticalStack - + >> * MerzView @merzView - + >> * HorizontalStack @textArea >>> [_ _] @testText >>> * ColorWell @colorWell - + >> --- - + >> * HorizontalStack - + >>> !!!!! Underline @ulLabel - + >>> * VerticalStack - + >>>> * TwoColumnForm @underlineForm - + >>>>> : Thickness: >>>>> * HorizontalStack >>>>>> [_ _] @ulThicknessText - >>>>>> (Sync) @syncThickULButton - - >>>>> --- - + >>>>>> (Sync) @syncThickULButton + + >>>>> --- + >>>>> : Position: >>>>> [_ _] @ulPosText >>>>> (Descender) @ulDescButton >>>>> (Below Descender) @ulBelowDescButton - + >>> --- - + >>> !!!!! Strikethrough @stLabel - + >>> * VerticalStack - + >>>> * TwoColumnForm @strikeForm - + >>>>> : Thickness: >>>>> * HorizontalStack >>>>>> [_ _] @stThicknessText - >>>>>> (Sync) @syncThickSTButton - - >>>>> --- - + >>>>>> (Sync) @syncThickSTButton + + >>>>> --- + >>>>> : Position: >>>>> [_ _] @stPosText >>>>> (Mid Cap-Height) @stMidCapButton >>>>> (Mid X-Height) @stMidXButton - + --- """ - footer=""" + footer = """ !- All values have been written into their respective UFOs. @setAllLabel (Set Values) @setAllButton """ - + tableWidth = 225 fieldWidth = 55 headerWidth = 120 @@ -92,8 +93,7 @@ def build(self): titleWidth = 70 itemWidth = buttonWidth syncWidth = fieldWidth - - + descriptionData = dict( table=dict( items=[], @@ -106,11 +106,11 @@ def build(self): ), testText=dict( width='fill', - height=24, + height=24, ), colorWell=dict( width=fieldWidth, - height=24, + height=24, ), ulThicknessText=dict( valueType='integer', @@ -121,7 +121,7 @@ def build(self): valueType='integer', valueWidth=fieldWidth, # valueIncrement=1 - ), + ), syncThickSTButton=dict( width = syncWidth, ), @@ -178,7 +178,7 @@ def build(self): footer=footer, # tabLoops=['ulThicknessText', 'stThicknessText', 'ulPosText', 'stPosText'], # Doesn't seem to work. ) - + # Set the position of the window to relate to the front-most font overview window. if CurrentFontWindow(): fw_x, fw_y, _, _ = CurrentFontWindow().w.getPosSize() @@ -186,32 +186,32 @@ def build(self): fw_x, fw_y = 300, 300 _, _, w_w, w_h = self.w.getPosSize() self.w.setPosSize((fw_x + 50, fw_y + 50, w_w, w_h)) - + self.merzView = self.w.getItem("merzView") - + self.w.getItem('setAllLabel').show(False) - + self.testString = getExtensionDefault(extensionKey + '.testString', fallback="Hloxtps") self.w.getItem('testText').set(self.testString) - + self.underlineThickness = {} self.underlinePosition = {} # The top of the underline self.strikeThickness = {} self.strikePosition = {} - + self.strokeColor = getExtensionDefault(extensionKey + '.strokeColor', fallback=(0,0,0,1)) self.w.getItem('colorWell').set(self.strokeColor) - + self.setPreviewColors() - + def acceptsFirstResponder(self, sender): return True - + # def magnifyWithEvent(self, sender, event): # print("magnifying...") # print(event) # # self.container.setContainerScale(scale) - + def started(self): self.w.open() @@ -220,51 +220,53 @@ def started(self): if AllFonts(): self.fonts = AllFonts() self.selectedFonts = [self.fonts[0]] - - self.updateFontList() + + self.updateFontList() self.updateTextFields() - self.updatePreview() - + self.updatePreview() + # Change the preview colors if the app switches to dark mode. def roboFontAppearanceChanged(self, info): self.setPreviewColors() self.updatePreview() - + def roboFontDidChangePreferences(self, info): self.setPreviewColors() self.updatePreview() - + def setPreviewColors(self): self.bgColor = getDefault("spaceCenterBackgroundColor") if NSApp().appearance() == NSAppearance.appearanceNamed_(NSAppearanceNameDarkAqua): self.bgColor = getDefault("spaceCenterBackgroundColor.dark") - + self.fgColor = getDefault("spaceCenterGlyphColor") if NSApp().appearance() == NSAppearance.appearanceNamed_(NSAppearanceNameDarkAqua): self.fgColor = getDefault("spaceCenterGlyphColor.dark") - + def destroy(self): self.selectedFonts = [] - + def clearInternalDictionary(self): self.underlineThickness = {} self.underlinePosition = {} self.strikeThickness = {} self.strikePosition = {} - + def fontDocumentDidOpen(self, info): self.updateFontList() - + def fontDocumentDidOpenNew(self, info): self.updateFontList() - - fontDocumentDidSaveDelay=1 # Doesn't seem to work as intended without a delay. + + # Doesn't seem to work as intended without a delay. + fontDocumentDidSaveDelay = 1 + def fontDocumentDidSave(self, info): self.updateFontList() - + def fontDocumentDidClose(self, info): self.updateFontList() - + def getFontIdentifier(self, font): # Try to keep track of the font using its path, but if it doesn't have a path (not saved yet)... if font.path: @@ -273,14 +275,14 @@ def getFontIdentifier(self, font): else: identifier = font.fontWindow().w.getNSWindow().title() return identifier - + def getFontDisplayName(self, font): if font.info.familyName and font.info.styleName: displayName = font.info.familyName + " - " + font.info.styleName else: displayName = font.fontWindow().w.getNSWindow().title() return displayName - + def updateFontList(self): ''' Updates the font list upon open and when new UFOs @@ -290,14 +292,14 @@ def updateFontList(self): self.fonts = AllFonts() self.fontsList = [] self.clearInternalDictionary() # Leave behind any old "identifiers" - + if self.fonts: for font in self.fonts: # Update the font list panel itself displayName = self.getFontDisplayName(font) - self.fontsList.append(displayName) - - # Update internal account of data when new font is opened/closed + self.fontsList.append(displayName) + + # Update internal account of data when new font is opened/closed dictionaryToValue = [ (self.underlineThickness , font.info.postscriptUnderlineThickness), (self.strikeThickness , font.info.openTypeOS2StrikeoutSize), @@ -305,27 +307,28 @@ def updateFontList(self): ] fontIdentifier = self.getFontIdentifier(font) for dictionary, value in dictionaryToValue: - if not fontIdentifier in dictionary.keys(): + if fontIdentifier not in dictionary.keys(): if value: dictionary.update({fontIdentifier: value}) else: dictionary.update({fontIdentifier: None}) # Deal with underline position - if 'public.openTypePostUnderlinePosition' in font.lib.keys(): - self.underlinePosition.update{fontIdentifier: font.lib['public.openTypePostUnderlinePosition'} + if 'public.openTypePostUnderlinePosition' in font.lib: + self.underlinePosition.update({fontIdentifier: font.lib['public.openTypePostUnderlinePosition']}) # If font doesn't have that lib key set, but is using fontmake, use fontmake behavior elif font.lib["com.robofont.fontCompilerTool"] == 'fontmake': - self.underlinePosition.update{fontIdentifier: font.info.postscriptUnderlineThickness} + self.underlinePosition.update({fontIdentifier: font.info.postscriptUnderlineThickness}) # If not that, do the math to get position elif font.info.postscriptUnderlinePosition and font.info.postscriptUnderlineThickness: ul = font.info.postscriptUnderlinePosition + font.info.postscriptUnderlineThickness / 2 - self.underlinePosition.update{fontIdentifier: ul} + self.underlinePosition.update({fontIdentifier: ul}) # If no position or thickness, value is None else: - self.underlinePosition.update{fontIdentifier: None} + self.underlinePosition.update({fontIdentifier: None}) + # Set the font list in the UI self.w.getItem("table").set(self.fontsList) - + # Select what was selected before fontIndexesToSelect = [] if len(self.fonts) == 1: # If there's only one font, select that one. @@ -337,10 +340,10 @@ def updateFontList(self): fontIndexesToSelect.append(i) self.selectedFonts = [self.fonts[index] for index in fontIndexesToSelect] self.w.getItem("table").setSelectedIndexes(fontIndexesToSelect) - + self.updateTextFields() self.updatePreview() - + def getValueIfConsistent(self, fonts, dictionary): ''' Check whether the fonts selected in list have the same value for any given attribute. @@ -356,7 +359,7 @@ def getValueIfConsistent(self, fonts, dictionary): return value else: return '' - + def updateTextFields(self): self.w.getItem('setAllLabel').show(False) self.w.getItem("ulThicknessText").set(self.getValueIfConsistent(self.selectedFonts, self.underlineThickness)) @@ -382,7 +385,7 @@ def ulThicknessTextCallback(self, sender): fontIdentifier = self.getFontIdentifier(font) self.underlineThickness[fontIdentifier] = value self.updatePreview() - + def syncThickULButtonCallback(self, sender): '''Matches strikethrough thickness value''' value = self.w.getItem('stThicknessText').get() @@ -401,7 +404,7 @@ def ulPosTextCallback(self, sender): fontIdentifier = self.getFontIdentifier(font) self.underlinePosition[fontIdentifier] = value self.updatePreview() - + def ulDescButtonCallback(self, sender): '''Snaps the underline value to bottom-align with the descender.''' for font in self.selectedFonts: @@ -412,7 +415,7 @@ def ulDescButtonCallback(self, sender): self.underlinePosition[fontIdentifier] = value self.updatePreview() self.updateTextFields() - + def ulBelowDescButtonCallback(self, sender): '''Snaps the underline value to an underline thickness distance below the descender.''' for font in self.selectedFonts: @@ -431,7 +434,7 @@ def stThicknessTextCallback(self, sender): fontIdentifier = self.getFontIdentifier(font) self.strikeThickness[fontIdentifier] = value self.updatePreview() - + def syncThickSTButtonCallback(self, sender): '''Matches underline thickness value''' value = self.w.getItem('ulThicknessText').get() @@ -450,7 +453,7 @@ def stPosTextCallback(self, sender): fontIdentifier = self.getFontIdentifier(font) self.strikePosition[fontIdentifier] = value self.updatePreview() - + def stMidCapButtonCallback(self, sender): '''Snaps the strikethrough value to the middle of the cap-height''' for font in self.selectedFonts: @@ -461,7 +464,7 @@ def stMidCapButtonCallback(self, sender): self.strikePosition[fontIdentifier] = value self.updatePreview() self.updateTextFields() - + def stMidXButtonCallback(self, sender): '''Snaps the strikethrough value to the middle of the x-height''' for font in self.selectedFonts: @@ -472,16 +475,16 @@ def stMidXButtonCallback(self, sender): self.strikePosition[fontIdentifier] = value self.updatePreview() self.updateTextFields() - + def colorWellCallback(self, sender): self.strokeColor = sender.get() setExtensionDefault(extensionKey + '.strokeColor', self.strokeColor) self.updatePreview() - + def updatePreview(self): '''Updates the Merz View which shows the test string with underline and strikethrough applied.''' self.w.getItem('setAllLabel').show(False) - + self.container = self.merzView.getMerzContainer() self.container.setBackgroundColor(self.bgColor) self.container.clearSublayers() @@ -493,7 +496,7 @@ def updatePreview(self): fontIdentifier = self.getFontIdentifier(viewFont) baseline = merzH / 2 - 200 viewScale = merzH / (viewFont.info.unitsPerEm + margin*2) * 0.75 - + self.localFGColor = self.fgColor self.localStrokeColor = self.strokeColor if viewFont != self.selectedFonts[0]: @@ -501,7 +504,7 @@ def updatePreview(self): self.localFGColor = r, g, b, 0.25 r, g, b, a = self.strokeColor self.localStrokeColor = r, g, b, 0.25 - + cursor = margin for char in self.testString: glyphLayer = self.container.appendPathSublayer( @@ -511,10 +514,10 @@ def updatePreview(self): gName = getKey(ord(char), GN2UV) glyph = viewFont[gName] glyphPath = glyph.getRepresentation("merz.CGPath") - + glyphLayer.setPath(glyphPath) cursor += glyph.width - + if self.underlinePosition[fontIdentifier] and self.underlineThickness[fontIdentifier]: underlineLine = self.container.appendLineSublayer( startPoint=(margin, baseline + self.underlinePosition[fontIdentifier] - self.underlineThickness[fontIdentifier] / 2), @@ -522,7 +525,7 @@ def updatePreview(self): strokeWidth=self.underlineThickness[fontIdentifier] * viewScale, strokeColor=self.localStrokeColor ) - + if self.strikePosition[fontIdentifier] and self.strikeThickness[fontIdentifier]: strikethroughLine = self.container.appendLineSublayer( startPoint=(margin, baseline + self.strikePosition[fontIdentifier] - self.strikeThickness[fontIdentifier] / 2), @@ -530,12 +533,12 @@ def updatePreview(self): strokeWidth=self.strikeThickness[fontIdentifier] * viewScale, strokeColor=self.localStrokeColor ) - + self.container.addSublayerScaleTransformation(viewScale, name='scale', center=(0, merzH/2)) - + def roundInteger(self, value): '''Same as int(), but accepts None.''' - if value == None: + if value is None: return None return otRound(value) @@ -562,4 +565,4 @@ def setAllButtonCallback(self, sender): self.w.getItem('setAllLabel').show(True) -registerRoboFontSubscriber(UnderlineStrikethrough) \ No newline at end of file +registerRoboFontSubscriber(UnderlineStrikethrough) From 3fa85eff808966f4292b599b445c72144c1db819 Mon Sep 17 00:00:00 2001 From: Ben Kiel Date: Wed, 12 Jul 2023 14:52:24 -0500 Subject: [PATCH 3/6] Fixes to logic --- .../lib/Underline StrikeThrough.py | 120 +++++++++--------- 1 file changed, 61 insertions(+), 59 deletions(-) diff --git a/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py b/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py index 75c4184..bc67017 100644 --- a/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py +++ b/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py @@ -4,7 +4,6 @@ from mojo.subscriber import Subscriber, registerRoboFontSubscriber from mojo.UI import getDefault, CurrentFontWindow from mojo.extensions import getExtensionDefault, setExtensionDefault -from defconAppKit.tools.textSplitter import splitText from lib.tools.unicodeTools import GN2UV from fontTools.misc import otRound @@ -15,7 +14,7 @@ def getKey(val, di): return key -extensionKey = 'com.typefounding.underlineStrikethrough' +extensionKey = "com.typefounding.underlineStrikethrough" class UnderlineStrikethrough(Subscriber, ezui.WindowController): @@ -105,7 +104,7 @@ def build(self): height=300 ), testText=dict( - width='fill', + width="fill", height=24, ), colorWell=dict( @@ -113,12 +112,12 @@ def build(self): height=24, ), ulThicknessText=dict( - valueType='integer', + valueType="integer", valueWidth=fieldWidth, # valueIncrement=1 ), ulPosText=dict( - valueType='integer', + valueType="integer", valueWidth=fieldWidth, # valueIncrement=1 ), @@ -137,12 +136,12 @@ def build(self): itemColumnWidth=itemWidth, ), stThicknessText=dict( - valueType='integer', + valueType="integer", valueWidth=fieldWidth, # valueIncrement=1 ), stPosText=dict( - valueType='integer', + valueType="integer", valueWidth=fieldWidth, # valueIncrement=1 ), @@ -166,17 +165,17 @@ def build(self): ), setAllButton=dict( width=tableWidth, - gravity='leading' + gravity="leading" ), ) self.w = ezui.EZWindow( content=content, - title='Underline Strikethrough', + title="Underline Strikethrough", descriptionData=descriptionData, controller=self, - size='auto', + size="auto", footer=footer, - # tabLoops=['ulThicknessText', 'stThicknessText', 'ulPosText', 'stPosText'], # Doesn't seem to work. + # tabLoops=["ulThicknessText", "stThicknessText", "ulPosText", "stPosText"], # Doesn"t seem to work. ) # Set the position of the window to relate to the front-most font overview window. @@ -189,18 +188,18 @@ def build(self): self.merzView = self.w.getItem("merzView") - self.w.getItem('setAllLabel').show(False) + self.w.getItem("setAllLabel").show(False) - self.testString = getExtensionDefault(extensionKey + '.testString', fallback="Hloxtps") - self.w.getItem('testText').set(self.testString) + self.testString = getExtensionDefault(extensionKey + ".testString", fallback="Hloxtps") + self.w.getItem("testText").set(self.testString) self.underlineThickness = {} self.underlinePosition = {} # The top of the underline self.strikeThickness = {} self.strikePosition = {} - self.strokeColor = getExtensionDefault(extensionKey + '.strokeColor', fallback=(0,0,0,1)) - self.w.getItem('colorWell').set(self.strokeColor) + self.strokeColor = getExtensionDefault(extensionKey + ".strokeColor", fallback=(0,0,0,1)) + self.w.getItem("colorWell").set(self.strokeColor) self.setPreviewColors() @@ -214,7 +213,7 @@ def acceptsFirstResponder(self, sender): def started(self): self.w.open() - + # Select the first font on open self.selectedFonts = [] if AllFonts(): @@ -258,7 +257,7 @@ def fontDocumentDidOpen(self, info): def fontDocumentDidOpenNew(self, info): self.updateFontList() - # Doesn't seem to work as intended without a delay. + # Doesn"t seem to work as intended without a delay. fontDocumentDidSaveDelay = 1 def fontDocumentDidSave(self, info): @@ -268,7 +267,7 @@ def fontDocumentDidClose(self, info): self.updateFontList() def getFontIdentifier(self, font): - # Try to keep track of the font using its path, but if it doesn't have a path (not saved yet)... + # Try to keep track of the font using its path, but if it doesn"t have a path (not saved yet)... if font.path: identifier = font.path # Use the title on its window. @@ -284,11 +283,11 @@ def getFontDisplayName(self, font): return displayName def updateFontList(self): - ''' + """ Updates the font list upon open and when new UFOs are opened/closed while the extension is open. - ''' - self.w.getItem('setAllLabel').show(False) + """ + self.w.getItem("setAllLabel").show(False) self.fonts = AllFonts() self.fontsList = [] self.clearInternalDictionary() # Leave behind any old "identifiers" @@ -313,15 +312,18 @@ def updateFontList(self): else: dictionary.update({fontIdentifier: None}) # Deal with underline position - if 'public.openTypePostUnderlinePosition' in font.lib: - self.underlinePosition.update({fontIdentifier: font.lib['public.openTypePostUnderlinePosition']}) - # If font doesn't have that lib key set, but is using fontmake, use fontmake behavior - elif font.lib["com.robofont.fontCompilerTool"] == 'fontmake': - self.underlinePosition.update({fontIdentifier: font.info.postscriptUnderlineThickness}) + if "public.openTypePostUnderlinePosition" in font.lib: + self.underlinePosition.update({fontIdentifier: font.lib["public.openTypePostUnderlinePosition"]}) + # If font doesn"t have that lib key set, but is using fontmake, use fontmake behavior + elif getDefault("fontCompilerTool") == "fontmake": + self.underlinePosition.update({fontIdentifier: font.info.postscriptUnderlinePosition}) # If not that, do the math to get position elif font.info.postscriptUnderlinePosition and font.info.postscriptUnderlineThickness: ul = font.info.postscriptUnderlinePosition + font.info.postscriptUnderlineThickness / 2 self.underlinePosition.update({fontIdentifier: ul}) + # If a position but no thickness, top is the position + elif font.info.postscriptUnderlinePosition: + self.underlinePosition.update({fontIdentifier: font.info.postscriptUnderlinePosition}) # If no position or thickness, value is None else: self.underlinePosition.update({fontIdentifier: None}) @@ -331,7 +333,7 @@ def updateFontList(self): # Select what was selected before fontIndexesToSelect = [] - if len(self.fonts) == 1: # If there's only one font, select that one. + if len(self.fonts) == 1: # If there"s only one font, select that one. fontIndexesToSelect = [0] else: for font in self.selectedFonts: @@ -345,23 +347,23 @@ def updateFontList(self): self.updatePreview() def getValueIfConsistent(self, fonts, dictionary): - ''' + """ Check whether the fonts selected in list have the same value for any given attribute. If so, returns that value. If not, return an empty string. - ''' + """ if fonts and dictionary: value = dictionary[self.getFontIdentifier(fonts[0])] for font in fonts: fontIdentifier = self.getFontIdentifier(font) checkValue = dictionary[fontIdentifier] if checkValue != value: - return '' + return "" return value else: - return '' + return "" def updateTextFields(self): - self.w.getItem('setAllLabel').show(False) + self.w.getItem("setAllLabel").show(False) self.w.getItem("ulThicknessText").set(self.getValueIfConsistent(self.selectedFonts, self.underlineThickness)) self.w.getItem("ulPosText").set(self.getValueIfConsistent(self.selectedFonts, self.underlinePosition)) self.w.getItem("stThicknessText").set(self.getValueIfConsistent(self.selectedFonts, self.strikeThickness)) @@ -369,7 +371,7 @@ def updateTextFields(self): def testTextCallback(self, sender): self.testString = sender.get() - setExtensionDefault(extensionKey + '.testString', self.testString) + setExtensionDefault(extensionKey + ".testString", self.testString) self.updatePreview() def tableSelectionCallback(self, sender): @@ -380,18 +382,18 @@ def tableSelectionCallback(self, sender): def ulThicknessTextCallback(self, sender): value = sender.get() - if value != '-': + if value != "-": for font in self.selectedFonts: fontIdentifier = self.getFontIdentifier(font) self.underlineThickness[fontIdentifier] = value self.updatePreview() def syncThickULButtonCallback(self, sender): - '''Matches strikethrough thickness value''' - value = self.w.getItem('stThicknessText').get() + """Matches strikethrough thickness value""" + value = self.w.getItem("stThicknessText").get() if value: value = int(value) - self.w.getItem('ulThicknessText').set(value) + self.w.getItem("ulThicknessText").set(value) for font in self.selectedFonts: fontIdentifier = self.getFontIdentifier(font) self.underlineThickness[fontIdentifier] = value @@ -399,14 +401,14 @@ def syncThickULButtonCallback(self, sender): def ulPosTextCallback(self, sender): value = sender.get() - if value != '-': + if value != "-": for font in self.selectedFonts: fontIdentifier = self.getFontIdentifier(font) self.underlinePosition[fontIdentifier] = value self.updatePreview() def ulDescButtonCallback(self, sender): - '''Snaps the underline value to bottom-align with the descender.''' + """Snaps the underline value to bottom-align with the descender.""" for font in self.selectedFonts: fontIdentifier = self.getFontIdentifier(font) value = None @@ -417,7 +419,7 @@ def ulDescButtonCallback(self, sender): self.updateTextFields() def ulBelowDescButtonCallback(self, sender): - '''Snaps the underline value to an underline thickness distance below the descender.''' + """Snaps the underline value to an underline thickness distance below the descender.""" for font in self.selectedFonts: fontIdentifier = self.getFontIdentifier(font) value = None @@ -429,18 +431,18 @@ def ulBelowDescButtonCallback(self, sender): def stThicknessTextCallback(self, sender): value = sender.get() - if value != '-': + if value != "-": for font in self.selectedFonts: fontIdentifier = self.getFontIdentifier(font) self.strikeThickness[fontIdentifier] = value self.updatePreview() def syncThickSTButtonCallback(self, sender): - '''Matches underline thickness value''' - value = self.w.getItem('ulThicknessText').get() + """Matches underline thickness value""" + value = self.w.getItem("ulThicknessText").get() if value: value = int(value) - self.w.getItem('stThicknessText').set(value) + self.w.getItem("stThicknessText").set(value) for font in self.selectedFonts: fontIdentifier = self.getFontIdentifier(font) self.strikeThickness[fontIdentifier] = value @@ -448,14 +450,14 @@ def syncThickSTButtonCallback(self, sender): def stPosTextCallback(self, sender): value = sender.get() - if value != '-': + if value != "-": for font in self.selectedFonts: fontIdentifier = self.getFontIdentifier(font) self.strikePosition[fontIdentifier] = value self.updatePreview() def stMidCapButtonCallback(self, sender): - '''Snaps the strikethrough value to the middle of the cap-height''' + """Snaps the strikethrough value to the middle of the cap-height""" for font in self.selectedFonts: fontIdentifier = self.getFontIdentifier(font) value = None @@ -466,7 +468,7 @@ def stMidCapButtonCallback(self, sender): self.updateTextFields() def stMidXButtonCallback(self, sender): - '''Snaps the strikethrough value to the middle of the x-height''' + """Snaps the strikethrough value to the middle of the x-height""" for font in self.selectedFonts: fontIdentifier = self.getFontIdentifier(font) value = None @@ -478,12 +480,12 @@ def stMidXButtonCallback(self, sender): def colorWellCallback(self, sender): self.strokeColor = sender.get() - setExtensionDefault(extensionKey + '.strokeColor', self.strokeColor) + setExtensionDefault(extensionKey + ".strokeColor", self.strokeColor) self.updatePreview() def updatePreview(self): - '''Updates the Merz View which shows the test string with underline and strikethrough applied.''' - self.w.getItem('setAllLabel').show(False) + """Updates the Merz View which shows the test string with underline and strikethrough applied.""" + self.w.getItem("setAllLabel").show(False) self.container = self.merzView.getMerzContainer() self.container.setBackgroundColor(self.bgColor) @@ -534,19 +536,19 @@ def updatePreview(self): strokeColor=self.localStrokeColor ) - self.container.addSublayerScaleTransformation(viewScale, name='scale', center=(0, merzH/2)) + self.container.addSublayerScaleTransformation(viewScale, name="scale", center=(0, merzH/2)) def roundInteger(self, value): - '''Same as int(), but accepts None.''' + """Same as int(), but accepts None.""" if value is None: return None return otRound(value) def setAllButtonCallback(self, sender): - ''' - Uses the tool’s dictionary we've been building, and writes those values into the UFO files themselves. + """ + Uses the tool’s dictionary we"ve been building, and writes those values into the UFO files themselves. Each UFO will have its own corresponding values. - ''' + """ uT = self.underlineThickness uP = self.underlinePosition sT = self.strikeThickness @@ -558,11 +560,11 @@ def setAllButtonCallback(self, sender): if uT[fontIdentifier]: font.info.postscriptUnderlinePosition = self.roundInteger(uP[fontIdentifier] - uT[fontIdentifier] / 2) else: - font.info.postscriptUnderlinePosition = None - font.lib['public.openTypePostUnderlinePosition'] = self.roundInteger(uP[fontIdentifier]) + font.info.postscriptUnderlinePosition = self.roundInteger(uP[fontIdentifier]) + font.lib["public.openTypePostUnderlinePosition"] = self.roundInteger(uP[fontIdentifier]) font.info.openTypeOS2StrikeoutSize = self.roundInteger(sT[fontIdentifier]) font.info.openTypeOS2StrikeoutPosition = self.roundInteger(sP[fontIdentifier]) - self.w.getItem('setAllLabel').show(True) + self.w.getItem("setAllLabel").show(True) registerRoboFontSubscriber(UnderlineStrikethrough) From c5d972818acbe1a0bbdb37eca8a1bd0f1f6d04d7 Mon Sep 17 00:00:00 2001 From: Ben Kiel Date: Wed, 12 Jul 2023 14:54:50 -0500 Subject: [PATCH 4/6] Grammer --- .../lib/Underline StrikeThrough.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py b/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py index bc67017..93af82b 100644 --- a/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py +++ b/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py @@ -175,7 +175,7 @@ def build(self): controller=self, size="auto", footer=footer, - # tabLoops=["ulThicknessText", "stThicknessText", "ulPosText", "stPosText"], # Doesn"t seem to work. + # tabLoops=["ulThicknessText", "stThicknessText", "ulPosText", "stPosText"], # Doesn't seem to work. ) # Set the position of the window to relate to the front-most font overview window. @@ -257,7 +257,7 @@ def fontDocumentDidOpen(self, info): def fontDocumentDidOpenNew(self, info): self.updateFontList() - # Doesn"t seem to work as intended without a delay. + # Doesn't seem to work as intended without a delay. fontDocumentDidSaveDelay = 1 def fontDocumentDidSave(self, info): @@ -267,7 +267,7 @@ def fontDocumentDidClose(self, info): self.updateFontList() def getFontIdentifier(self, font): - # Try to keep track of the font using its path, but if it doesn"t have a path (not saved yet)... + # Try to keep track of the font using its path, but if it doesn't have a path (not saved yet)... if font.path: identifier = font.path # Use the title on its window. @@ -314,7 +314,7 @@ def updateFontList(self): # Deal with underline position if "public.openTypePostUnderlinePosition" in font.lib: self.underlinePosition.update({fontIdentifier: font.lib["public.openTypePostUnderlinePosition"]}) - # If font doesn"t have that lib key set, but is using fontmake, use fontmake behavior + # If font doesn't have that lib key set, but is using fontmake, use fontmake behavior elif getDefault("fontCompilerTool") == "fontmake": self.underlinePosition.update({fontIdentifier: font.info.postscriptUnderlinePosition}) # If not that, do the math to get position From 69a0602fb88074c319fc030bd6262b3aec7a96e6 Mon Sep 17 00:00:00 2001 From: Ben Kiel Date: Wed, 12 Jul 2023 14:59:17 -0500 Subject: [PATCH 5/6] correct import --- .../lib/Underline StrikeThrough.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py b/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py index 93af82b..1e6d0ea 100644 --- a/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py +++ b/Underline Strikethrough.roboFontExt/lib/Underline StrikeThrough.py @@ -5,7 +5,7 @@ from mojo.UI import getDefault, CurrentFontWindow from mojo.extensions import getExtensionDefault, setExtensionDefault from lib.tools.unicodeTools import GN2UV -from fontTools.misc import otRound +from fontTools.misc.roundTools import otRound def getKey(val, di): From 13152613cbb7a2e76548278fad50787823d101ca Mon Sep 17 00:00:00 2001 From: Ben Kiel Date: Wed, 12 Jul 2023 15:11:19 -0500 Subject: [PATCH 6/6] Readme updates and bumping version number --- README.md | 4 +++- Underline Strikethrough.roboFontExt/info.plist | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 128d31d..bd25c11 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,12 @@ This lists all currently-open UFOs. This now auto-updates when fonts are opened ### Underline Settings - **Thickness:** The thickness of the underline. This corresponds to `font.info.postscriptUnderlineThickness`. Click "Sync" to set it to match the strikethrough thickness. -- **Position:** The position of the underline (the top of the line). This corresponds to `font.info.postscriptUnderlinePosition`. +- **Position:** The position of the underline (the top of the line). - **Snap to Descender:** This will snap the descender value of selected fonts to bottom-align with `font.info.descender`. *Note: this will not write the values into the font yet. This is just a quick operation for your convenience.* - **Snap to Below Descender:** This will snap the descender value of selected fonts to an underline-thickness-distance below `font.info.descender`. *Note: this will not write the values into the font yet. This is just a quick operation for your convenience.* +The underline position will be written into your UFOs using the `font.lib` key `public.openTypePostUnderlinePosition` (this is the value you set in **Position**) and to the `font.info.postscriptUnderlinePosition`. The extension calculates the value for `font.info.postscriptUnderlinePosition` (lowering the underline position by half of the underline thickness). + Read [here](https://learn.microsoft.com/en-us/typography/opentype/spec/post) for more guidance on setting these values. ### Strikethrough Settings diff --git a/Underline Strikethrough.roboFontExt/info.plist b/Underline Strikethrough.roboFontExt/info.plist index 06fb5e6..89aaeaf 100644 --- a/Underline Strikethrough.roboFontExt/info.plist +++ b/Underline Strikethrough.roboFontExt/info.plist @@ -28,7 +28,7 @@ timeStamp 1688077927 version - 2.1 + 2.2 com.robofontmechanic.Mechanic repositoryURL