diff --git a/README.md b/README.md index bc051fa..6ab26a6 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ by Andy Clymer, [www.andyclymer.com](http://www.andyclymer.com) updated for RF4.4 by Connor Davenport [www.connordavenport.com](http://www.connordavenport.com) -![Blue Zone Editor Icon](/resources/icon.png?raw=true) +![Blue Zone Editor Icon](source/resources/icon.png?raw=true) Download it here, or find it in the Mechanic 2 extension diff --git a/info.yaml b/info.yaml index c899c71..3744d95 100644 --- a/info.yaml +++ b/info.yaml @@ -3,7 +3,7 @@ developer: Andy Clymer developerURL: http://www.andyclymer.com/ launchAtStartUp: true mainScript: Blues.py -version: '1.4' +version: '1.4.1' addToMenu: [] html: true requiresVersionMajor: '4' diff --git a/source/lib/Blues.py b/source/lib/Blues.py index 4caf829..c2edea7 100644 --- a/source/lib/Blues.py +++ b/source/lib/Blues.py @@ -1,9 +1,8 @@ -from mojo.events import EditingTool, BaseEventTool, installTool, addObserver, removeObserver, extractNSEvent +from mojo.events import BaseEventTool, installTool, extractNSEvent import mojo.drawingTools as dt -from mojo.UI import getGlyphViewDisplaySettings, setGlyphViewDisplaySettings, CurrentGlyphWindow +from mojo.UI import getGlyphViewDisplaySettings, setGlyphViewDisplaySettings from lib.tools.defaults import getDefaultColor, getDefault from mojo.extensions import ExtensionBundle -from mojo.subscriber import Subscriber, registerRoboFontSubscriber import AppKit from merz import MerzPen @@ -26,17 +25,18 @@ c = getDefaultColor("glyphViewOtherBluesColor") OTHERBLUESCOLOR = (c.redComponent(), c.greenComponent(), c.blueComponent(), c.alphaComponent()) -VIEWWIDTH = getDefault("glyphViewArtBoardHorizontalBorder") * 2 +VIEWWIDTH = getDefault("glyphViewHorizontalPadding", 3000) * 2 KEY = "com.andyclymer.blueZoneEditor" - + + class BlueZone(object): - + """ Manages a pair of blue zone locations as one solid zone Has helper functions for selecting zone edges and moving the selection """ - + def __init__(self, startPosition, endPosition, layer, index, isOther=False): self.alwaysShowLabels = getDefault(f"{KEY}.alwaysShowLabels", defaultValue=False) self.startPosition = startPosition @@ -47,11 +47,10 @@ def __init__(self, startPosition, endPosition, layer, index, isOther=False): self.layer = layer self.color = BLUESCOLOR if not self.isOther else OTHERBLUESCOLOR self.index = index - - self.blue = self.layer.appendRectangleSublayer() + + self.blue = self.layer.appendRectangleSublayer() self.arrow = self.layer.appendPathSublayer() - - + self.startText = self.layer.appendTextLineSublayer() self.endText = self.layer.appendTextLineSublayer() @@ -64,10 +63,10 @@ def __init__(self, startPosition, endPosition, layer, index, isOther=False): def __repr__(self): o = " (Other)" if self.isOther else "" return f"" - + def moveSelection(self, delta, isKeyed=False): - xOffset, yOffset = delta - + xOffset, yOffset = delta + if isKeyed: if (AppKit.NSEvent.modifierFlags() & AppKit.NSAlternateKeyMask): self.startSelected -= xOffset @@ -85,7 +84,7 @@ def moveSelection(self, delta, isKeyed=False): if self.endSelected: self.endSelected += xOffset self.endPosition -= yOffset - + # Keep the start lower than the end if self.startPosition > self.endPosition: self.startPosition, self.endPosition = self.endPosition, self.startPosition @@ -96,54 +95,54 @@ def moveSelection(self, delta, isKeyed=False): elif self.endSelected and not self.startSelected: self.startSelected = True self.endSelected = False - + self.startPosition = int(round(self.startPosition)) self.endPosition = int(round(self.endPosition)) - + w,h = self.blue.getSize() nh = (5 * round(int(self.endPosition - self.startPosition)/5)) if (AppKit.NSEvent.modifierFlags() & AppKit.NSShiftKeyMask) else int(self.endPosition - self.startPosition) if self.startSelected: self.blue.setPosition((-VIEWWIDTH,self.startPosition)) - + self.blue.setSize((w,nh)) self.draw() - - + + @property def selected(self): return self.startSelected or self.endSelected - + def deselect(self): self.startSelected = False self.endSelected = False - + def select(self, point): # Select whichever edge is closest to the point location self.startSelected = False self.endSelected = False if abs(self.startPosition - point[1]) < abs(self.endPosition - point[1]): self.startSelected = point[0] - else: self.endSelected = point[0] - + else: self.endSelected = point[0] + def distance(self, location): # Return the distance to either edge (whichever is closest) to the point distances = [abs(self.startPosition - location), abs(self.endPosition - location)] distances.sort() return distances[0] - + def pointInside(self, location): positions = [self.startPosition, self.endPosition] positions.sort() if positions[0] < location < positions[1]: return True else: return False - + def draw(self): # Draw the zone self.blue.setPosition((-VIEWWIDTH, self.startPosition)) self.blue.setSize((VIEWWIDTH*4, self.endPosition-self.startPosition)) self.blue.setFillColor(self.color) - + # See if any edges are selected selectedPoints = [] if self.startSelected: @@ -157,16 +156,16 @@ def draw(self): elif self.index == 0 or self.isOther: fill=(0.2, 0.2, 0.8, 1) bottom, top = self.endPosition-10, self.endPosition - + pen = MerzPen() pen.moveTo((0, top)) pen.lineTo((-5, bottom)) pen.lineTo((5, bottom)) pen.closePath() - + self.arrow.setFillColor(fill) self.arrow.setPath(pen.path) - + # Draw the zone locations and its type positions = [self.startPosition, self.endPosition] positions.sort() @@ -178,41 +177,40 @@ def draw(self): self.startText.setPosition((-50, positions[0]-20)) self.startText.setText(str(positions[0])) - + self.endText.setPosition((-50, positions[1]+20)) self.endText.setText(str(positions[1])) - def remove(self): for item in [self.blue,self.arrow,self.endText,self.startText]: item.setVisible(False) - + def flip(self): self.color = BLUESCOLOR if not self.isOther else OTHERBLUESCOLOR - self.blue.setFillColor(self.color) + self.blue.setFillColor(self.color) self.endSelected = self.startSelected = False self.highlight() - self.draw() - + self.draw() + def highlight(self): r,g,b,a = self.color strokeColor = (r,g,b,1) - + if self.endSelected and self.startSelected: self.blue.setStrokeWidth(2) self.blue.setStrokeColor(strokeColor) else: self.blue.setStrokeWidth(None) self.blue.setStrokeColor(None) - + def animate(self): x,y =(-VIEWWIDTH, self.startPosition) w,h =(VIEWWIDTH*4, self.endPosition-self.startPosition) - + pathLayer = self.layer.appendBaseSublayer( position=(x, y), size=(w, h)) - + r,g,b,a = self.color strokeColor = (r,g,b,1) ani = pathLayer.appendRectangleSublayer( @@ -222,7 +220,7 @@ def animate(self): strokeWidth=2) h *= 1.5 - + d = .8 with ani.propertyGroup( duration=d @@ -237,14 +235,14 @@ def animate(self): pathLayer.setOpacity(0) x,y = pathLayer.getPosition() pathLayer.setPosition((x,y-(h/6))) - + def removePointAnimation(self, layer): self.layer.removeSublayer(layer) - + debug = True class BlueEdit(BaseEventTool): - + def becomeActive(self): # Remember the current display settings, and turn the blues off (I'll draw them myself) self.previousDisplaySettings = {"Blues": getGlyphViewDisplaySettings()["Blues"], "FamilyBlues": getGlyphViewDisplaySettings()["FamilyBlues"]} @@ -253,7 +251,7 @@ def becomeActive(self): self.font = CurrentFont() self.zones = [] self.currentlyUpdatingInfo = False - + self.container = self.extensionContainer( identifier=f"{KEY}.foreground", location="foreground", @@ -261,17 +259,16 @@ def becomeActive(self): ) self.fontBecameCurrent(None) - + def becomeInactive(self): # Reset the display settings setGlyphViewDisplaySettings(self.previousDisplaySettings) # Observers self.container.clearSublayers() - if not self.font == None: + if self.font is not None: self.applyZones() - def getToolbarIcon(self): extBundle = ExtensionBundle("BlueZoneEditor") toolbarIcon = extBundle.get("BlueZoneToolIcon-2x") @@ -279,8 +276,7 @@ def getToolbarIcon(self): def getToolbarTip(self): return "Blue Zones" - - + # Observer callbacks def fontBecameCurrent(self, info): # Forget any font-specific settings and observe on the font info @@ -294,15 +290,14 @@ def fontBecameCurrent(self, info): self.font = cf if not self.font == None: self.collectZones() - - + def currentFontInfoDidChange(self, info): # The font info changed # Cache the blue zone data because it may have changed, # but only if this tool is not currently editing the font info. if not self.currentlyUpdatingInfo: self.collectZones() - + def mouseDown(self, point, count): yLoc = int(round(point[1])) if count == 2: @@ -314,7 +309,7 @@ def mouseDown(self, point, count): zone.isOther = not zone.isOther zone.flip() zone.animate() - + if not didFlipZone: # Double click not on a zone: add a new zone self.addZone(yLoc-10, yLoc+10) @@ -329,12 +324,11 @@ def mouseDown(self, point, count): zone.endSelected = True zone.highlight() - def mouseDragged(self, point, delta): # If the mouse is dragging, move selected zones for zone in self.zones: zone.moveSelection(delta) - + def mouseUp(self, point): # If any zones are selected, update the font info, they may have changed wasSelected = False @@ -343,7 +337,7 @@ def mouseUp(self, point): wasSelected = True if wasSelected: self.applyZones() - + def keyDown(self, event): e = extractNSEvent(event) # Arrow keys to move @@ -369,7 +363,7 @@ def keyDown(self, event): if zone.selected: zone.isOther = not zone.isOther zone.flip() - + def collectZones(self): self.zones = [] for k in BLUEKEYS: @@ -380,11 +374,11 @@ def collectZones(self): index = 0 for i in range(0, len(zoneValues), 2): z = BlueZone(zoneValues[i], zoneValues[i+1], self.container, index=index, isOther=isOther) - self.zones += [z] + self.zones += [z] index += 1 for zone in self.zones: zone.draw() - + def applyZones(self): for k in BLUEKEYS: isOther = False @@ -413,13 +407,11 @@ def applyZones(self): setattr(self.font.info, k, newZoneRanges) self.font.info.performUndo() self.currentlyUpdatingInfo = False - - def selectClosestZoneEdge(self, point, keepSelection=False, distance=6): # Find the closest zone edge to the location and select it # Optionally, keep the current selection of zones - if not self.font == None: + if self.font is not None: closestZone = None closestDist = distance for zone in self.zones: @@ -434,8 +426,7 @@ def selectClosestZoneEdge(self, point, keepSelection=False, distance=6): closestZone.select(point) return True return False - - + def countZones(self): # Return a count of the blues and otherBlues zoneCount = {"postscriptBlueValues": 0, "postscriptOtherBlues": 0} @@ -444,8 +435,7 @@ def countZones(self): zoneCount["postscriptOtherBlues"] += 1 else: zoneCount["postscriptBlueValues"] += 1 return zoneCount - - + def addZone(self, startPos, endPos, isOther=False): blueKey = "postscriptOtherBlues" if isOther else "postscriptBlueValues" if not self.font == None: @@ -456,7 +446,7 @@ def addZone(self, startPos, endPos, isOther=False): z.draw() z.animate() self.zones += [z] - + def removeSelectedZones(self): newZones = [] #self.container.clearSublayers() @@ -467,7 +457,6 @@ def removeSelectedZones(self): zone.remove() self.zones = newZones self.applyZones() - - -installTool(BlueEdit()) \ No newline at end of file + +installTool(BlueEdit())