Last active
April 5, 2021 17:50
-
-
Save okay-type/3d15b8aab357cb709adcd53fa8032321 to your computer and use it in GitHub Desktop.
quick and dirty udpate of addoverlap with ui for robofont 4
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
from vanilla import * | |
from mojo.UI import CurrentGlyphWindow | |
from mojo.events import addObserver, removeObserver | |
from mojo.subscriber import Subscriber, registerGlyphEditorSubscriber | |
from merz import * | |
from AppKit import NSColor, NSTextAlignmentRight, NSTextAlignmentLeft | |
from fontTools.ufoLib.pointPen import AbstractPointPen | |
from mojo.extensions import setExtensionDefault, getExtensionDefault, registerExtensionDefaults | |
import math | |
import re | |
''' | |
quick and dirty udpate of addoverlap with ui for robofont 4 | |
big changes: | |
this never really made sense as a toolbar button | |
it should probably be a contextual menu option | |
but i didnt want to figure out how to build one of those for glyph edit window | |
instead I simply added a button and an edittext field to to bottom Status Bar | |
next: | |
needs to be tested for bugs | |
''' | |
class CustomGlyphWindowDisplayMenu(Subscriber): | |
debug = False | |
def build(self): | |
self.name = self.__class__.__name__ | |
if self.debug == True: | |
print(self.name, 'build!') | |
self.prefKey = 'com.okaytype.addOverlap' | |
initialDefaults = { | |
self.pref: '30'} | |
registerExtensionDefaults(initialDefaults) | |
self.toolValue = getExtensionDefault(self.pref) | |
self.bar = self.getGlyphEditor().getGlyphStatusBar() | |
self.addOverlapUI() | |
def destroy(self): | |
if self.debug == True: | |
print(self.name, 'destroy!') | |
setExtensionDefault(self.prefKey + '.addOverlapValue', self.ui.menuEditNo.get()) | |
if hasattr(self.bar, 'overlapUI'): | |
del self.bar.overlapUI | |
@property | |
def pref(self): | |
return self.prefKey + '.' + 'addOverlapValue' | |
# def glyphEditorDidOpen(self, info): | |
# if self.debug == True: | |
# print(self.name, 'glyphEditorDidOpen!') | |
# def glyphEditorDidSetGlyph(self, info): | |
# if self.debug == True: | |
# print('glyphEditorDidSetGlyph!') | |
# self.addOverlapUI() | |
def addOverlapUI(self): | |
self.bar.overlapUI = Group((125, 0, 100, -1)) | |
self.ui = self.bar.overlapUI | |
self.ui.menuButton = Button((0, 0, 25, -0), '⋉', callback=self.addOverlap) | |
self.ui.menuEditNo = EditText((23, 3, -0, -0), self.toolValue, sizeStyle='small', callback=self.editTextCallback) | |
t = self.ui.menuEditNo.getNSTextField() | |
t.setBezeled_(False) | |
t.setBackgroundColor_(NSColor.clearColor()) | |
b = self.ui.menuButton.getNSButton() | |
b.setBezelStyle_(7) | |
b.setToolTip_('Add Overlap to Selected Points') | |
def editTextCallback(self, sender): | |
self.toolValue = self.onlynumbers(sender.get()) | |
if len(self.toolValue) > 0 and self.toolValue[-1] != '-': | |
sender.set(self.toolValue) | |
# setExtensionDefault(self.prefKey + '.addOverlapValue', self.toolValue) | |
def onlynumbers(self, v): | |
v = v.replace(' ', '') | |
if v is None or v == '': | |
v = '0' | |
if v == '-0': | |
v = '0' | |
negpos = '' | |
if v[0] and v[0] == '-' and v != '0': | |
negpos = '-' | |
v = negpos + re.sub(r'[-\D]', '', v) | |
return v | |
def addOverlap(self, sender): | |
offset = self.toolValue | |
if self.toolValue == '': | |
offset = 0 | |
g = CurrentGlyph() | |
selection = [] | |
for p in g.selectedPoints: | |
p.selected = False | |
selection.append((p.x, p.y)) | |
pen = AddOverlapPointPen(selection, offset) | |
g.drawPoints(pen) | |
g.prepareUndo('addOverlap') | |
g.clearContours() | |
pen.drawPoints(g.getPointPen()) | |
g.performUndo() | |
g.changed() | |
def getLength(pt1, pt2): | |
x1, y1 = pt1 | |
x2, y2 = pt2 | |
return math.sqrt((x2 - x1)**2 + (y2 - y1)**2) | |
def pointOnACurve(curve, value): | |
(x1, y1), (cx1, cy1), (cx2, cy2), (x2, y2) = curve | |
dx = x1 | |
cx = (cx1 - dx) * 3.0 | |
bx = (cx2 - cx1) * 3.0 - cx | |
ax = x2 - dx - cx - bx | |
dy = y1 | |
cy = (cy1 - dy) * 3.0 | |
by = (cy2 - cy1) * 3.0 - cy | |
ay = y2 - dy - cy - by | |
mx = ax * (value)**3 + bx * (value)**2 + cx * (value) + dx | |
my = ay * (value)**3 + by * (value)**2 + cy * (value) + dy | |
return mx, my | |
class AddOverlapPointPen(AbstractPointPen): | |
def __init__(self, selectedPoints=[], offset=30): | |
self.offset = int(offset) | |
self.selectedPoints = selectedPoints | |
self._contours = [] | |
self._components = [] | |
def beginPath(self): | |
self._contours.append([]) | |
self.firstSegment = None | |
self.prevOncurve = None | |
def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs): | |
data = dict(point=pt, segmentType=segmentType, smooth=smooth, name=name, kwargs=kwargs) | |
self._contours[-1].append(data) | |
def endPath(self): | |
pass | |
def addComponent(self, baseGlyphName, transformation): | |
pass | |
def _offset(self, pt1, pt2): | |
x1, y1 = pt1 | |
x2, y2 = pt2 | |
length = getLength((x1, y1), (x2, y2)) | |
if length == 0: | |
return 0, 0 | |
ox = (x2 - x1) / length * self.offset | |
oy = (y2 - y1) / length * self.offset | |
return int(round(ox)), int(round(oy)) | |
def drawPoints(self, outpen): | |
for pointsData in self._contours: | |
if len(pointsData) == 1: | |
# ignore single movetos and anchors | |
continue | |
outpen.beginPath() | |
lenPointsData = len(pointsData) | |
for i, pointData in enumerate(pointsData): | |
currentPoint = pointData["point"] | |
addExtraPoint = None | |
if pointData["segmentType"] and pointData["point"] in self.selectedPoints: | |
prevPointData = pointsData[i - 1] | |
nextPointData = pointsData[(i + 1) % lenPointsData] | |
prevOffsetX, prevOffsetY = self._offset(prevPointData["point"], pointData["point"]) | |
nextOffsetX, nextOffsetY = self._offset(pointData["point"], nextPointData["point"]) | |
if (nextOffsetX, nextOffsetY) == (0, 0) and nextPointData["segmentType"] is None: | |
nextSegment = [ | |
pointsData[(i + 3) % lenPointsData]["point"], | |
pointsData[(i + 2) % lenPointsData]["point"], | |
nextPointData["point"], | |
pointData["point"]] | |
newPoint = pointOnACurve(nextSegment, 0.9) | |
nextOffsetX, nextOffsetY = self._offset(pointData["point"], newPoint) | |
addExtraPoint = currentPoint[0] - nextOffsetX, currentPoint[1] - nextOffsetY | |
if (prevOffsetX, prevOffsetY) == (0, 0) and prevPointData["segmentType"] is None: | |
prevSegment = [ | |
pointsData[i - 3]["point"], | |
pointsData[i - 2]["point"], | |
prevPointData["point"], | |
pointData["point"]] | |
newPoint = pointOnACurve(prevSegment, 0.9) | |
prevOffsetX, prevOffsetY = self._offset(newPoint, pointData["point"]) | |
currentPoint = currentPoint[0] + prevOffsetX, currentPoint[1] + prevOffsetY | |
outpen.addPoint( | |
currentPoint, | |
pointData["segmentType"], | |
pointData["smooth"], | |
pointData["name"], | |
**pointData["kwargs"]) | |
if addExtraPoint: | |
outpen.addPoint(addExtraPoint, "line") | |
outpen.endPath() | |
for baseGlyphName, transformation in self._components: | |
outpen.addComponent(baseGlyphName, transformation) | |
registerGlyphEditorSubscriber(CustomGlyphWindowDisplayMenu) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment