def buildCircledGlyph(thisGlyph,
                      circleName,
                      scaleFactors,
                      minDistanceBetweenTwoLayers=90.0,
                      suffix=None):
    isBlack = "black" in circleName.lower()

    thisFont = thisGlyph.font()
    thisGlyph.widthMetricsKey = None  # "=%i" % thisFont.upm )
    thisGlyph.leftMetricsKey = "=40"
    thisGlyph.rightMetricsKey = "=|"

    for i, thisMaster in enumerate(thisFont.masters):
        figureHeight = None
        scaleFactor = scaleFactors[i]
        if isBlack:
            scaleFactor = max(0.6, scaleFactor)
        circleGlyph = thisFont.glyphs[circleName]
        circleLayer = circleGlyph.layers[thisMaster.id]
        circleScaleFactor = thisFont.upm * 0.92 / max(
            thisFont.upm * 0.66, circleLayer.bounds.size.width)

        # prepare layer
        thisLayer = thisGlyph.layers[thisMaster.id]
        thisLayer.clear()

        # add circle:
        assumedCenter = NSPoint(thisFont.upm * 0.5,
                                thisFont.upm * 0.3)  # hardcoded
        circleComponent = GSComponent(circleName)
        thisLayer.components.append(circleComponent)

        # scale circle:
        circleScale = transform(scale=circleScaleFactor).transformStruct()
        circleComponent.applyTransform(circleScale)

        # move circle:
        circleBounds = thisLayer.components[0].bounds
        circleCenter = centerOfRect(circleBounds)
        xShift = assumedCenter.x - circleCenter.x
        yShift = assumedCenter.y - circleCenter.y
        circleShift = transform(shiftX=xShift, shiftY=yShift).transformStruct()
        circleComponent.applyTransform(circleShift)

        # update metrics:
        thisLayer.updateMetrics()
        thisLayer.syncMetrics()

        # find number and letter components to add:
        suffixlessName = thisGlyph.name
        if "." in suffixlessName:
            suffixlessName = thisGlyph.name[:thisGlyph.name.find(".")]
        componentNames = suffixlessName.split("_")

        # add one component in the center:
        if componentNames:
            advance = 0
            for j, compName in enumerate(componentNames):
                lfName = "%s.lf" % compName
                osfName = "%s.osf" % compName

                namesToCheck = [compName]
                extraSuffixes = (".osf", ".lf")
                for extraSuffix in extraSuffixes:
                    namesToCheck.insert(0, compName + extraSuffix)
                if suffix:
                    for existingName in namesToCheck[:]:
                        namesToCheck.insert(0, existingName + suffix)

                for nameToCheck in namesToCheck:
                    if thisFont.glyphs[nameToCheck]:
                        compName = nameToCheck
                        break

                innerComponent = GSComponent(compName)
                innerComponent.automaticAlignment = False
                thisLayer.components.append(innerComponent)
                innerComponent.position = NSPoint(advance, 0.0)

                if j > 0:
                    innerComponent.disableAlignment = True
                    placeComponentsAtDistance(
                        thisLayer,
                        thisLayer.components[-2],
                        thisLayer.components[-1],  # same as innerComponent
                        distance=minDistanceBetweenTwoLayers)

                originalLayerWidth = thisFont.glyphs[compName].layers[
                    thisMaster.id].width
                advance += originalLayerWidth

            collectedBounds = [c.bounds for c in thisLayer.components[1:]]
            compCenter = centerOfRect(combinedBounds(collectedBounds))
            centerAnchor = thisLayer.anchorForName_traverseComponents_(
                "#center", True)
            if centerAnchor:
                circleCenter = centerAnchor.position
            else:
                circleCenter = centerOfRect(circleComponent.bounds)

            # scale and move it in place:
            shift = transform(shiftX=-compCenter.x,
                              shiftY=-compCenter.y).transformStruct()
            scaleToFit = transform(scale=scaleFactor *
                                   circleScaleFactor).transformStruct()
            backshift = transform(shiftX=circleCenter.x,
                                  shiftY=circleCenter.y).transformStruct()

            compensateStroke = []
            for innerComponent in thisLayer.components[1:]:

                # optically shift so top anchor is in center:
                originalLayer = topAnchor = innerComponent.component.layers[
                    thisMaster.id]
                topAnchor = originalLayer.anchors["top"]
                if topAnchor:
                    anchorCenter = topAnchor.x
                    boundsCenter = centerOfRect(originalLayer.bounds).x
                    opticalCorrection = boundsCenter - anchorCenter
                    if opticalCorrection != 0.0:
                        threshold = 35.0
                        if abs(opticalCorrection) > threshold:
                            posNeg = opticalCorrection / abs(opticalCorrection)
                            rest = abs(opticalCorrection) - threshold
                            opticalCorrection = posNeg * (threshold +
                                                          rest * 1 / rest**0.3)
                            print("--", opticalCorrection)
                        opticalShift = transform(
                            shiftX=opticalCorrection).transformStruct()
                        innerComponent.applyTransform(opticalShift)

                innerComponent.applyTransform(shift)
                innerComponent.applyTransform(scaleToFit)
                innerComponent.applyTransform(backshift)

                # move components closer to center:
                #move = 15.0
                #hOffset = circleCenter.x - centerOfRect(innerComponent.bounds).x
                #if abs(hOffset) > move:
                #	hOffset = (hOffset/abs(hOffset))*move
                #if hOffset != 0.0:
                #	moveCloser = transform( shiftX=hOffset ).transformStruct()
                #	innerComponent.applyTransform( moveCloser )

                # compensatory shift:
                if thisGlyph.name in ("two_zero.circled", "one_nine.circled",
                                      "one_zero.circled"):
                    compensate = transform(shiftX=10.0).transformStruct()
                    innerComponent.applyTransform(compensate)

                if innerComponent.component.glyphInfo.category == "Number":
                    if figureHeight == None:
                        figureHeight = innerComponent.position.y
                    else:
                        innerComponent.position.y = figureHeight

                compensateStroke.append(innerComponent)

            # make slightly bolder:
            isNumber = False
            for i in range(len(compensateStroke))[::-1]:
                componentToDecompose = compensateStroke[i]
                if componentToDecompose.component.category == "Number":
                    isNumber = True
                thisLayer.decomposeComponent_(componentToDecompose)

            offsetLayer(thisLayer, 4.0)  #4.0 if isNumber else 3.0 )
            if thisLayer.paths and isBlack:
                thisLayer.removeOverlap()
                for thisPath in thisLayer.paths:

                    # set first node (make compatible again after remove overlap):
                    lowestY = thisPath.bounds.origin.y
                    lowestNodes = [n for n in thisPath.nodes if n.y <= lowestY]
                    if len(lowestNodes) == 0:
                        lowestNode = sorted(lowestNodes,
                                            key=lambda node: node.y)[0]
                    elif len(lowestNodes) == 1:
                        lowestNode = lowestNodes[0]
                    elif len(lowestNodes) > 1:
                        lowestNode = sorted(lowestNodes,
                                            key=lambda node: node.x)[0]
                    while lowestNode.type == GSOFFCURVE:
                        lowestNode = lowestNode.nextNode
                    thisPath.makeNodeFirst_(lowestNode)

                    # reverse (white on black):
                    thisPath.reverse()

            thisLayer.anchors = None
            for thisComp in thisLayer.components:
                if thisComp.componentName == circleName:
                    thisComp.locked = True
Esempio n. 2
0
    def BatchInsertAnchorMain(self, sender):
        try:
            # update settings to the latest user input:
            if not self.SavePreferences(self):
                print(
                    "Note: 'Batch Insert Anchor' could not write preferences.")

            thisFont = Glyphs.font  # frontmost font
            print("Batch Insert Anchor Report for %s" % thisFont.familyName)
            print(thisFont.filepath)
            print()

            anchorName = Glyphs.defaults[
                "com.mekkablue.BatchInsertAnchor.anchorName"]
            xPos = Glyphs.defaults["com.mekkablue.BatchInsertAnchor.xPos"]
            yPos = Glyphs.defaults["com.mekkablue.BatchInsertAnchor.yPos"]
            replaceExisting = Glyphs.defaults[
                "com.mekkablue.BatchInsertAnchor.replaceExisting"]

            selectedLayers = thisFont.selectedLayers
            selectedGlyphNames = list(
                set([l.parent.name for l in selectedLayers if l.parent]))

            print("Inserting anchor '%s' at %s and %s in %i glyphs...\n" % (
                anchorName,
                xPositions[xPos],
                yPositions[yPos],
                len(selectedGlyphNames),
            ))

            for glyphName in selectedGlyphNames:
                print("🔠 %s" % glyphName)
                glyph = thisFont.glyphs[glyphName]
                if not glyph:
                    print("⛔️ Error: could not find glyph %s. Skipping.\n" %
                          glyphName)
                else:
                    for thisLayer in glyph.layers:
                        if replaceExisting or not thisLayer.anchors[anchorName]:
                            if xPos == 0:
                                x = thisLayer.width // 2
                            elif xPos == 1:  # "LSB"
                                x = 0.0
                            elif xPos == 2:  # "RSB"
                                x = thisLayer.width
                            elif xPos == 3:  # "BBox Left Edge"
                                x = thisLayer.bounds.origin.x
                            elif xPos == 4:  # "BBox Horizontal Center"
                                x = thisLayer.bounds.origin.x + thisLayer.bounds.size.width // 2
                            elif xPos == 5:  # "BBox Right Edge"
                                x = thisLayer.bounds.origin.x + thisLayer.bounds.size.width

                            if yPos == 0:  # "Baseline"
                                y = 0.0
                            if yPos == 1:  # "x-Height"
                                y = thisLayer.master.xHeight
                            if yPos == 2:  # "Smallcap Height"
                                y = thisLayer.master.customParameters[
                                    "smallCapHeight"]
                                if not y:  # Fallback if not set:
                                    y = thisLayer.master.xHeight
                            if yPos == 3:  # "Cap Height"
                                y = thisLayer.master.capHeight
                            if yPos == 4:  # "Ascender"
                                y = thisLayer.master.ascender
                            if yPos == 5:  # "Shoulder Height"
                                y = thisLayer.master.customParameters[
                                    "shoulderHeight"]
                                if not y:  # Fallback if not set:
                                    y = thisLayer.master.capHeight
                            if yPos == 6:  # "Descender"
                                y = thisLayer.master.descender
                            if yPos == 7:  # "BBox Top"
                                y = thisLayer.bounds.origin.y + thisLayer.bounds.size.height
                            if yPos == 8:  # "BBox Center"
                                y = thisLayer.bounds.origin.y + thisLayer.bounds.size.height // 2
                            if yPos == 9:  # "BBox Bottom"
                                y = thisLayer.bounds.origin.y

                            anchor = GSAnchor()
                            anchor.name = anchorName
                            anchor.position = NSPoint(x, y)
                            thisLayer.anchors.append(anchor)

        except Exception as e:
            # brings macro window to front and reports error:
            Glyphs.showMacroWindow()
            print("Batch Insert Anchor Error: %s" % e)
            import traceback
            print(traceback.format_exc())
def circleInsideRect(rect):
    """Returns a GSPath for a circle inscribed into the NSRect rect."""
    MAGICNUMBER = 4.0 * (2.0**0.5 - 1.0) / 3.0
    x = rect.origin.x
    y = rect.origin.y
    height = rect.size.height
    width = rect.size.width
    fullHeight = y + height
    fullWidth = x + width
    halfHeight = y + 0.5 * height
    halfWidth = x + 0.5 * width
    horHandle = width * 0.5 * MAGICNUMBER * 1.05
    verHandle = height * 0.5 * MAGICNUMBER * 1.05

    segments = ((NSPoint(x, halfHeight - verHandle),
                 NSPoint(halfWidth - horHandle, y), NSPoint(halfWidth, y)),
                (NSPoint(halfWidth + horHandle,
                         y), NSPoint(fullWidth, halfHeight - verHandle),
                 NSPoint(fullWidth,
                         halfHeight)), (NSPoint(fullWidth,
                                                halfHeight + verHandle),
                                        NSPoint(halfWidth + horHandle,
                                                fullHeight),
                                        NSPoint(halfWidth, fullHeight)),
                (NSPoint(halfWidth - horHandle, fullHeight),
                 NSPoint(x, halfHeight + verHandle), NSPoint(x, halfHeight)))

    circlePath = GSPath()

    for thisSegment in segments:
        for i in range(3):
            nodeType = (GSOFFCURVE, GSOFFCURVE, GSCURVE)[i]
            nodePos = thisSegment[i]
            newNode = GSNode()
            newNode.position = nodePos
            newNode.type = nodeType
            newNode.connection = GSSMOOTH
            circlePath.nodes.append(newNode)

    print(circlePath)
    for n in circlePath.nodes:
        print("   ", n)
    circlePath.closed = True
    return circlePath
Esempio n. 4
0
 def interpolatedPosition(self, foregroundPosition, foregroundFactor,
                          backgroundPosition, backgroundFactor):
     interpolatedX = foregroundPosition.x * foregroundFactor + backgroundPosition.x * backgroundFactor
     interpolatedY = foregroundPosition.y * foregroundFactor + backgroundPosition.y * backgroundFactor
     interpolatedPosition = NSPoint(interpolatedX, interpolatedY)
     return interpolatedPosition
def lerp(t, a, b):
    return NSValue.valueWithPoint_(
        NSPoint(int((1 - t) * a.x + t * b.x), int((1 - t) * a.y + t * b.y)))
    def realignLayer(self,
                     thisLayer,
                     shouldRealign=False,
                     shouldReport=False,
                     shouldVerbose=False):
        moveForward = NSPoint(1, 0)
        moveBackward = NSPoint(-1, 0)
        noModifier = NSNumber.numberWithUnsignedInteger_(0)
        layerCount = 0

        if thisLayer:
            for thisPath in thisLayer.paths:
                oldPathCoordinates = [n.position for n in thisPath.nodes]
                for i, thisNode in enumerate(thisPath.nodes):
                    if thisNode.type == GSOFFCURVE:
                        # oldPosition = NSPoint(thisNode.position.x, thisNode.position.y)
                        oncurve = None
                        if thisNode.prevNode.type != GSOFFCURVE:
                            oncurve = thisNode.prevNode
                            opposingPoint = oncurve.prevNode
                        elif thisNode.nextNode.type != GSOFFCURVE:
                            oncurve = thisNode.nextNode
                            opposingPoint = oncurve.nextNode

                        handleStraight = (oncurve.x - thisNode.x) * (
                            oncurve.y - thisNode.y) == 0.0
                        if oncurve and oncurve.smooth and not handleStraight:
                            # thisNode = angled handle, straighten it
                            thisPath.setSmooth_withCenterPoint_oppositePoint_(
                                thisNode,
                                oncurve.position,
                                opposingPoint.position,
                            )
                        elif oncurve and opposingPoint and oncurve.smooth and handleStraight and opposingPoint.type == GSOFFCURVE:
                            # thisNode = straight handle: align opposite handle
                            thisPath.setSmooth_withCenterPoint_oppositePoint_(
                                opposingPoint,
                                oncurve.position,
                                thisNode.position,
                            )
                        else:
                            selectedNode = NSMutableArray.arrayWithObject_(
                                thisNode)
                            thisLayer.setSelection_(selectedNode)
                            self.Tool.moveSelectionLayer_shadowLayer_withPoint_withModifier_(
                                thisLayer, thisLayer, moveForward, noModifier)
                            self.Tool.moveSelectionLayer_shadowLayer_withPoint_withModifier_(
                                thisLayer, thisLayer, moveBackward, noModifier)
                            # TODO:
                            # recode with GSPath.setSmooth_withCenterNode_oppositeNode_()

                for i, coordinate in enumerate(oldPathCoordinates):
                    if thisPath.nodes[i].position != coordinate:
                        layerCount += 1

                        # put handle back if not desired by user:
                        if not shouldRealign:
                            thisPath.nodes[i].position = coordinate
        thisLayer.setSelection_(())

        if shouldReport and shouldVerbose:
            if layerCount:
                if shouldRealign:
                    print(u"   ⚠️ Realigned %i handle%s." %
                          (layerCount, "" if layerCount == 1 else "s"))
                else:
                    print(u"   ❌ %i handle%s are unaligned." %
                          (layerCount, "" if layerCount == 1 else "s"))
            else:
                print(u"   ✅ All BCPs OK.")

        return layerCount
Esempio n. 7
0
def interruptwait():
    """
    If waituntil() has been called, this will interrupt the waiting process so
    it can check whether it should stop waiting.
    """
    evt = NSEvent.otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(NSApplicationDefined, NSPoint(), NSApplicationDefined, 0, 1, None, LIGHTBLUE_NOTIFY_ID, 0, 0)
    NSApplication.sharedApplication().postEvent_atStart_(evt, True)    
Esempio n. 8
0
	def smallFigureBuilderMain( self, sender ):
		try:
			if not self.SavePreferences( self ):
				print("Note: 'Build Small Figures' could not write preferences.")
			
			thisFont = Glyphs.font # frontmost font
			
			# report in macro window:
			Glyphs.clearLog()
			print("Build Small Figures, report for: %s" % thisFont.familyName)
			if thisFont.filepath:
				print(thisFont.filepath)
			print()
			
			# parse user entries and preferences:
			default = Glyphs.defaults["com.mekkablue.smallFigureBuilder.default"].strip()
			derive = Glyphs.defaults["com.mekkablue.smallFigureBuilder.derive"]
			currentMasterOnly = Glyphs.defaults["com.mekkablue.smallFigureBuilder.currentMasterOnly"]
			decomposeDefaultFigures = Glyphs.defaults["com.mekkablue.smallFigureBuilder.decomposeDefaultFigures"]
			figures = ("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine")
			offsets={}
			for suffixPair in [pair.split(":") for pair in derive.split(",")]:
				suffix = suffixPair[0].strip()
				value = float(suffixPair[1].strip())
				offsets[suffix] = value
			
			createdGlyphCount = 0
			updatedGlyphCount = 0
			
			# go through 1, 2, 3, 4, 5...
			for i,fig in enumerate(figures):
				# determine default glyph:
				defaultGlyphName = "%s%s" % (fig,default)
				defaultGlyph = thisFont.glyphs[defaultGlyphName]
				
				if not defaultGlyph:
					print("\nNot found: %s" % defaultGlyphName)
				else:
					print("\n%s Deriving from %s:" % (
						"0️⃣1️⃣2️⃣3️⃣4️⃣5️⃣6️⃣7️⃣8️⃣9️⃣"[i*3:i*3+3], # it is actually three unicodes
						defaultGlyphName,
						))
					
					# decompose if necessary:
					if decomposeDefaultFigures:
						print(" - decomposing %s" % defaultGlyphName)
						if currentMasterOnly:
							mID = thisFont.selectedFontMaster.id
						else:
							mID = None
						self.decomposeComponents(defaultGlyph)
					
					# step through derivative suffixes:
					for deriveSuffix in offsets:
						
						# create or overwrite derived glyph:
						deriveGlyphName = "%s%s" % (fig,deriveSuffix)
						deriveGlyph = thisFont.glyphs[deriveGlyphName]
						if not deriveGlyph:
							deriveGlyph = GSGlyph(deriveGlyphName)
							thisFont.glyphs.append(deriveGlyph)
							print(" - creating new glyph %s" % deriveGlyphName)
							createdGlyphCount += 1
						else:
							print(" - overwriting glyph %s" % deriveGlyphName)
							updatedGlyphCount += 1
							
						# copy glyph attributes:
						deriveGlyph.leftKerningGroup = defaultGlyph.leftKerningGroup
						deriveGlyph.rightKerningGroup = defaultGlyph.rightKerningGroup
						
						# reset category & subcategory:
						deriveGlyph.updateGlyphInfo()
						
						# add component on each master layer:
						for thisMaster in thisFont.masters:
							isCurrentMaster = thisMaster is thisFont.selectedFontMaster
							if isCurrentMaster or not currentMasterOnly:
								mID = thisMaster.id
								offset = offsets[deriveSuffix]
								offsetPos = NSPoint(0,offset)
								if thisMaster.italicAngle != 0.0:
									offsetPos = italicize(offsetPos,italicAngle=thisMaster.italicAngle)
								defaultComponent = GSComponent(defaultGlyphName,offsetPos)
								deriveLayer = deriveGlyph.layers[mID]
								deriveLayer.clear()
								try:
									# GLYPHS 3:
									deriveLayer.shapes.append(defaultComponent)
								except:
									# GLYPHS 2:
									deriveLayer.components.append(defaultComponent)
						
			# open a new tab if requested
			if Glyphs.defaults["com.mekkablue.smallFigureBuilder.openTab"]:
				tabText = ""
				for suffix in [default] + sorted(offsets.keys()):
					escapedFigureNames = ["/%s%s"%(fig,suffix) for fig in figures]
					tabText += "".join(escapedFigureNames)
					tabText += "\n"
				tabText = tabText.strip()
				if thisFont.currentTab and Glyphs.defaults["com.mekkablue.smallFigureBuilder.reuseTab"]:
					# reuses current tab:
					thisFont.currentTab.text = tabText
				else:
					# opens new Edit tab:
					thisFont.newTab( tabText )
			
			# Floating notification:
			Glyphs.showNotification( 
				u"%s: small figures built" % (thisFont.familyName),
				u"%i glyph%s created, %i glyph%s updated. Detailed info in Macro Window." % (
					createdGlyphCount,
					"" if createdGlyphCount==1 else "s",
					updatedGlyphCount,
					"" if updatedGlyphCount==1 else "s",
				),
				)
			
				
		except Exception as e:
			# brings macro window to front and reports error:
			Glyphs.showMacroWindow()
			print("Build Small Figures Error: %s" % e)
			import traceback
			print(traceback.format_exc())
    def drawTopOrBottom(self, bbox, defaultColor, zones, top, xHeight,
                        italicAngle):
        try:
            bboxOrigin = bbox.origin
            bboxSize = bbox.size
            left = bboxOrigin.x
            right = left + bboxSize.width
            middle = left + bboxSize.width / 2.0
            position = bboxOrigin.y

            surplus = 30.0
            scale = self.getScale()
            numberDistance = 25.0 / scale
            lineDistance = 10.0 / scale

            # adjust values for top/bottom:
            if top:
                position += bboxSize.height
                numberDistance -= 10.0 / scale
            else:
                numberDistance *= -1
                lineDistance *= -1

            # adjust values for italic angle:
            if italicAngle != 0.0:
                offset = (position - xHeight * 0.5) * math.tan(
                    italicAngle * math.pi / 180.0)
                left += offset
                right += offset
                middle += offset

            # draw it red if it is not inside a zone:
            drawColor = NSColor.redColor()
            for thisZone in zones:
                zoneBegin = thisZone[0]
                zoneEnd = zoneBegin + thisZone[1]
                zoneBottom = min((zoneBegin, zoneEnd))
                zoneTop = max((zoneBegin, zoneEnd))
                if position <= zoneTop and position >= zoneBottom:
                    drawColor = defaultColor

            # set line attributes:
            drawColor.set()
            storedLineWidth = NSBezierPath.defaultLineWidth()
            NSBezierPath.setDefaultLineWidth_(1.0 / scale)

            # draw horizontal line on canvas:
            leftPoint = NSPoint(left - surplus, position)
            rightPoint = NSPoint(right + surplus, position)
            NSBezierPath.strokeLineFromPoint_toPoint_(leftPoint, rightPoint)

            # draw vertical line on canvas:
            startPoint = NSPoint(middle, position)
            endPoint = NSPoint(middle, position + lineDistance)
            NSBezierPath.strokeLineFromPoint_toPoint_(startPoint, endPoint)

            # restore default line width:
            NSBezierPath.setDefaultLineWidth_(storedLineWidth)

            # draw number on canvas:
            self.drawTextAtPoint("%.1f" % position,
                                 NSPoint(middle, position + numberDistance),
                                 fontColor=drawColor)
        except Exception as e:
            self.logToConsole("drawBottom: %s" % str(e))
Esempio n. 10
0
#MenuTitle: Cut Cap
# -*- coding: utf-8 -*-
__doc__ = """
Cut the terminal of strokes with a `_cap.cup` glyph.
"""

from Foundation import NSPoint

CAP_SIZE = 100.0
CAP_NAME = '_cap.cup'

for path in Glyphs.font.selectedLayers[0].paths:
    selected_nodes = [i for i in path.nodes if i.selected]
    if len(selected_nodes) == 2:
        (node0, node1) = tuple(selected_nodes)
        scale = abs(node0.y - node1.y) / CAP_SIZE
        cap = GSHint()
        cap.type = CAP
        cap.name = CAP_NAME
        cap.scale = NSPoint(scale, scale)
        (cap.originNode, cap.targetNode) = (node0, node1)
        Glyphs.font.selectedLayers[0].hints.append(cap)
Esempio n. 11
0
def copyAnchor(thisLayer, anchorName, anchorX, anchorY):
    newAnchor = GSAnchor.alloc().init()
    newAnchor.name = anchorName
    thisLayer.addAnchor_(newAnchor)
    newPosition = NSPoint(anchorX, anchorY)
    newAnchor.setPosition_(newPosition)
Esempio n. 12
0
              pivotalY=0.0
              ):  # don't change x to y for horizontal / vertical DIRECTION
    x = thisPoint.x
    yOffset = thisPoint.y - pivotalY  # calculate vertical offset
    italicAngle = radians(italicAngle)  # convert to radians
    tangens = tan(italicAngle)  # math.tan needs radians
    horizontalDeviance = tangens * yOffset  # vertical distance from pivotal point
    x += horizontalDeviance  # x of point that is yOffset from pivotal point
    return NSPoint(int(x), thisPoint.y)


# move on curves
for node in selection:
    if node.nextNode.type != 'offcurve' and node.nextNode.nextNode.type == 'offcurve':
        #  oncurve
        node.nextNode.x = node.x
        node.nextNode.y = node.y
        node.nextNode.smooth = False
        # offcurve
        node.nextNode.nextNode.x = italicize(
            NSPoint(node.x, node.nextNode.nextNode.y), italicAngle, node.y)[0]

    elif node.prevNode.type != 'offcurve' and node.prevNode.prevNode.type == 'offcurve':
        # oncurve
        node.prevNode.x = node.x
        node.prevNode.y = node.y
        node.prevNode.smooth = False
        # offcurve
        node.prevNode.prevNode.x = italicize(
            NSPoint(node.x, node.prevNode.prevNode.y), italicAngle, node.y)[0]
Esempio n. 13
0
    
    def set_content_size(self, size):
        ns = self._ns_view
        self.size = NSScrollView.\
            frameSizeForContentSize_hasHorizontalScroller_hasVerticalScroller_borderType_(
            size, ns.hasHorizontalScroller(), ns.hasVerticalScroller(), ns.borderType())

    def get_scroll_offset(self):
        ns_clip_view = self._ns_view.contentView()
        x, y = ns_clip_view.bounds().origin
        return x, y
    
    def set_scroll_offset(self, (x, y)):
        ns_view = self._ns_view
        ns_clip_view = ns_view.contentView()
        new_pt = ns_clip_view.constrainScrollPoint_(NSPoint(x, y))
        ns_clip_view.scrollToPoint_(new_pt)
        ns_view.reflectScrolledClipView_(ns_clip_view)

    def get_line_scroll_amount(self):
        ns_view = self._ns_view
        x = ns_view.horizontalLineScroll()
        y = ns_view.verticalLineScroll()
        return x, y
    
    def set_line_scroll_amount(self, (x, y)):
        ns_view = self._ns_view
        ns_view.setHorizontalLineScroll_(x)
        ns_view.setVerticalLineScroll_(y)
        ns_view.setHorizontalPageScroll_(x)
        ns_view.setVerticalPageScroll_(y)
def middleBetweenTwoPoints(p1, p2):
    x = (p1.x + p2.x) * 0.5
    y = (p1.y + p2.y) * 0.5
    return NSPoint(x, y)
Esempio n. 15
0
    def insertAnchorsMain(self, sender):
        try:
            # update settings to the latest user input:
            if not self.SavePreferences(self):
                print("Note: 'Quote Manager' could not write preferences.")

            Glyphs.clearLog()
            Font = Glyphs.font  # frontmost font

            # query suffix
            dotSuffix = self.getDotSuffix()

            # report:
            self.reportFont()
            print(
                "Inserting cursive attachment anchors in single quotes, and auto-aligning double quotes%s."
                % (" with suffix '%s'" % dotSuffix if dotSuffix else ""))

            defaultSingle, defaultDouble = self.defaultQuotes(dotSuffix)

            if defaultSingle and not Font.glyphs[defaultSingle]:
                self.reportMissingGlyph(defaultSingle)
            elif defaultDouble and not Font.glyphs[defaultDouble]:
                self.reportMissingGlyph(defaultDouble)
            else:
                for singleName in names:
                    doubleName = names[singleName]
                    if dotSuffix:
                        doubleName += dotSuffix
                        singleName += dotSuffix

                    if singleName == "quotesingle" and Glyphs.defaults[
                            "com.mekkablue.QuoteManager.excludeDumbQuotes"]:
                        print(u"\n⚠️ Skipping %s/%s" %
                              (singleName, doubleName))
                    else:
                        print("\n%s/%s:" % (singleName, doubleName))

                        g = Font.glyphs[singleName]  # single quote glyph
                        gg = Font.glyphs[doubleName]  # double quote glyph

                        if not g:
                            self.reportMissingGlyph(singleName)
                        elif not gg:
                            self.reportMissingGlyph(doubleName)
                        else:
                            for master in Font.masters:
                                mID = master.id
                                gl = g.layers[mID]  # single quote layer
                                ggl = gg.layers[mID]  # double quote layer

                                # check if a default quote has been determined by the user:
                                if defaultSingle:
                                    referenceGlyph = Font.glyphs[defaultDouble]
                                    referenceLayer = referenceGlyph.layers[mID]
                                else:
                                    referenceGlyph = gg
                                    referenceLayer = ggl  # layer for measuring, depends on user input

                                # measure referenceLayer:
                                xPos = [
                                    c.position.x
                                    for c in referenceLayer.components
                                ]
                                if xPos and len(xPos) == 2:

                                    # add anchors in single quote:
                                    print(xPos[1] - xPos[0], master.name)
                                    dist = abs(xPos[1] - xPos[0])
                                    for aName in ("entry", "exit"):
                                        if aName == "exit":
                                            x = dist
                                        else:
                                            x = 0
                                        newAnchor = GSAnchor(
                                            "#%s" % aName, NSPoint(x, 0))
                                        gl.anchors.append(newAnchor)
                                    print(
                                        u"    ✅ %s: Added #exit and #entry anchors."
                                        % g.name)

                                    # auto align components
                                    for comp in ggl.components:
                                        comp.automaticAlignment = True

                                    # update metrics:
                                    ggl.updateMetrics()
                                    ggl.syncMetrics()

                                    print(
                                        u"    ✅ %s: Auto-aligned components." %
                                        gg.name)
                                else:
                                    print(
                                        u"    ⚠️ WARNING: No components in %s, layer '%s'. Cannot add anchors."
                                        % (referenceLayer.parent.name,
                                           referenceLayer.name))

            self.openTabIfRequested()
            Font.updateInterface()
            Font.currentTab.redraw()

        except Exception as e:
            # brings macro window to front and reports error:
            Glyphs.showMacroWindow()
            print("Quote Manager Error: %s" % e)
            import traceback
            print(traceback.format_exc())
Esempio n. 16
0
    def MoveCallback(self, sender):
        Font = Glyphs.font
        selectedLayers = Font.selectedLayers
        selectedMaster = Font.selectedFontMaster
        italicAngle = selectedMaster.italicAngle
        anchor_index = self.w.anchor_name.get()
        anchor_name = self.w.anchor_name.getItems()[anchor_index]
        horizontal_index = Glyphs.defaults[
            "com.mekkablue.AnchorMover2.hTarget"]
        horizontal_change = self.prefAsFloat(
            "com.mekkablue.AnchorMover2.hChange")
        vertical_index = Glyphs.defaults["com.mekkablue.AnchorMover2.vTarget"]
        vertical_change = self.prefAsFloat(
            "com.mekkablue.AnchorMover2.vChange")

        # Keep inquiries to the objects to a minimum:
        selectedAscender = selectedMaster.ascender
        selectedCapheight = selectedMaster.capHeight
        selectedXheight = selectedMaster.xHeight
        selectedDescender = selectedMaster.descender

        # respecting italic angle
        respectItalic = Glyphs.defaults["com.mekkablue.AnchorMover2.italic"]
        if italicAngle:
            italicCorrection = italicSkew(0.0, selectedXheight / 2.0,
                                          italicAngle)
            print("italicCorrection", italicCorrection)
        else:
            italicCorrection = 0.0

        evalCodeH = listHorizontal[horizontal_index][1]
        evalCodeV = listVertical[vertical_index][1]

        if not selectedLayers:
            print("No glyphs selected.")
            Message(title="No Glyphs Selected",
                    message="Could not move anchors. No glyphs were selected.",
                    OKButton=None)
        else:
            print("Processing %i glyphs..." % (len(selectedLayers)))
            Font.disableUpdateInterface()
            for originalLayer in selectedLayers:
                if originalLayer.name != None:
                    if len(originalLayer.anchors) > 0:
                        thisGlyph = originalLayer.parent

                        # create a layer copy that can be slanted backwards if necessary
                        copyLayer = originalLayer.copyDecomposedLayer()
                        thisGlyph.beginUndo()  # not working?

                        try:
                            if italicAngle and respectItalic:
                                # slant the layer copy backwards
                                for mPath in copyLayer.paths:
                                    for mNode in mPath.nodes:
                                        mNode.x = italicSkew(
                                            mNode.x, mNode.y,
                                            -italicAngle) + italicCorrection
                                for mAnchor in copyLayer.anchors:
                                    mAnchor.x = italicSkew(
                                        mAnchor.x, mAnchor.y,
                                        -italicAngle) + italicCorrection

                            for copyAnchor in copyLayer.anchors:
                                if copyAnchor.name == anchor_name:
                                    old_anchor_x = copyAnchor.x
                                    old_anchor_y = copyAnchor.y
                                    xMove = eval(evalCodeH) + horizontal_change
                                    yMove = eval(evalCodeV) + vertical_change

                                    # Ignore moves relative to bbox if there are no paths:
                                    if not copyLayer.paths:
                                        if "bounds" in evalCodeH:
                                            xMove = old_anchor_x

                                        if "bounds" in evalCodeV:
                                            yMove = old_anchor_y

                                    # Only move if the calculated position differs from the original one:
                                    if [int(old_anchor_x),
                                            int(old_anchor_y)
                                        ] != [int(xMove),
                                              int(yMove)]:

                                        if italicAngle and respectItalic:
                                            # skew back
                                            xMove = italicSkew(
                                                xMove, yMove,
                                                italicAngle) - italicCorrection
                                            old_anchor_x = italicSkew(
                                                old_anchor_x, old_anchor_y,
                                                italicAngle) - italicCorrection

                                        originalAnchor = [
                                            a for a in originalLayer.anchors
                                            if a.name == anchor_name
                                        ][0]
                                        originalAnchor.position = NSPoint(
                                            xMove, yMove)

                                        print(
                                            "Moved %s anchor from %i, %i to %i, %i in %s."
                                            % (anchor_name, old_anchor_x,
                                               old_anchor_y, xMove, yMove,
                                               thisGlyph.name))
                                    else:
                                        print(
                                            "Keeping %s anchor at %i, %i in %s."
                                            % (anchor_name, old_anchor_x,
                                               old_anchor_y, thisGlyph.name))

                        except Exception as e:
                            print("ERROR: Failed to move anchor in %s." %
                                  thisGlyph.name)
                            print(e)
                        finally:
                            thisGlyph.endUndo()

            Font.enableUpdateInterface()
        print("Done.")
Esempio n. 17
0
        height = path.bounds.size.height
        move_to = (ascender_height / 2) - (height / 2)
        move_by = bottom - move_to
        move_by *= -1
        print(move_by)

        if move_by == 0:
            print("Path is already centered")
        else:
            print("Centering path, moving by %s" % move_by)
            path.applyTransform((
                1.0,  # x scale factor
                0.0,  # x skew factor
                0.0,  # y skew factor
                1.0,  # y scale factor
                0.0,  # x position			
                move_by  # y position
            ))

if selected_anchors:
    for anchor in selected_anchors:
        layer = font.selectedLayers[0]
        height = layer.master.ascender
        y = height / 2
        x = anchor.position.x
        print("Moving anchor %s to (%s,%s)" % (anchor.name, x, y))
        anchor.position = NSPoint(x, y)

if not selected_paths and not selected_anchors:
    print("You haven't selected anything to center.")
Esempio n. 18
0
def interpolatePointPos(p1, p2, factor):
    factor = factor % 1.0
    x = p1.x * factor + p2.x * (1.0 - factor)
    y = p1.y * factor + p2.y * (1.0 - factor)
    return NSPoint(x, y)
Esempio n. 19
0
    def RewireFireMain(self, sender):
        try:
            Glyphs.clearLog()

            # update settings to the latest user input:
            if not self.SavePreferences(self):
                print("Note: 'Rewire Fire' could not write preferences.")

            thisFont = Glyphs.font  # frontmost font
            print("Rewire Fire Report for %s" % thisFont.familyName)
            print(thisFont.filepath)

            duplicateCount = 0
            affectedLayers = []
            for thisGlyph in thisFont.glyphs:
                if thisGlyph.export or Glyphs.defaults[
                        "com.mekkablue.RewireFire.includeNonExporting"]:
                    for thisLayer in thisGlyph.layers:
                        if thisLayer.isMasterLayer or thisLayer.isSpecialLayer:
                            thisLayer.selection = None
                            allCoordinates = []
                            duplicateCoordinates = []

                            for thisPath in thisLayer.paths:
                                for thisNode in thisPath.nodes:
                                    if thisNode.type != OFFCURVE:
                                        if thisNode.position in allCoordinates:
                                            thisNode.selected = True
                                            duplicateCoordinates.append(
                                                thisNode.position)
                                            duplicateCount += 1
                                            if Glyphs.defaults[
                                                    "com.mekkablue.RewireFire.setFireToNode"]:
                                                thisNode.name = self.nodeMarker
                                        else:
                                            allCoordinates.append(
                                                thisNode.position)
                                            if thisNode.name == self.nodeMarker:
                                                thisNode.name = None

                            if duplicateCoordinates:
                                print()
                                print(u"%s, layer: '%s'" %
                                      (thisGlyph.name, thisLayer.name))
                                for dupe in duplicateCoordinates:
                                    print(u"   %s x %.1f, y %.1f" %
                                          (self.nodeMarker, dupe.x, dupe.y))

                                if Glyphs.defaults[
                                        "com.mekkablue.RewireFire.markWithCircle"]:
                                    coords = set([(p.x, p.y)
                                                  for p in duplicateCoordinates
                                                  ])
                                    for dupeCoord in coords:
                                        x, y = dupeCoord
                                        self.circleInLayerAtPosition(
                                            thisLayer, NSPoint(x, y))

                                affectedLayers.append(thisLayer)

            print(
                "\nFound a total of %i duplicate coordinates. (Triplets count as two.)"
                % duplicateCount)

            if not affectedLayers:
                Message(
                    title="No Duplicates Found",
                    message=u"Could not find any duplicate coordinates in %s."
                    % thisFont.familyName,
                    OKButton=u"😇 Cool")
            elif Glyphs.defaults[
                    "com.mekkablue.RewireFire.openTabWithAffectedLayers"]:
                # opens new Edit tab:
                newTab = thisFont.newTab()
                newTab.layers = affectedLayers
            else:
                Glyphs.showMacroWindow()

            self.w.close()  # delete if you want window to stay open
        except Exception as e:
            # brings macro window to front and reports error:
            Glyphs.showMacroWindow()
            print("Rewire Fire Error: %s" % e)
            import traceback
            print(traceback.format_exc())
def bezierWithPoints(A, B, C, D, t):
    x, y = bezier(A.x, A.y, B.x, B.y, C.x, C.y, D.x, D.y, t)
    return NSPoint(x, y)
    def RealignStackingAnchorsMain(self, sender):
        try:
            Glyphs.clearLog()  # clears macro window log

            # update settings to the latest user input:
            if not self.SavePreferences(self):
                print(
                    "Note: 'Realign Stacking Anchors in Combining Accents' could not write preferences."
                )

            whichAnchorPairs = Glyphs.defaults[
                "com.mekkablue.RealignStackingAnchors.whichAnchorPairs"]
            anchorPairs = [a.strip() for a in whichAnchorPairs.split(",")]
            allGlyphs = Glyphs.defaults[
                "com.mekkablue.RealignStackingAnchors.allGlyphs"]
            limitToCombiningMarks = Glyphs.defaults[
                "com.mekkablue.RealignStackingAnchors.limitToCombiningMarks"]
            includeNonExporting = Glyphs.defaults[
                "com.mekkablue.RealignStackingAnchors.includeNonExporting"]

            thisFont = Glyphs.font  # frontmost font
            print("Realign Stacking Anchors, Report for %s" %
                  thisFont.familyName)
            if thisFont.filepath:
                print(thisFont.filepath)
            print()

            if not allGlyphs:
                if includeNonExporting:
                    glyphs = [l.parent for l in thisFont.selectedLayers]
                else:
                    glyphs = [
                        l.parent for l in thisFont.selectedLayers
                        if l.parent.export
                    ]
            else:
                if includeNonExporting:
                    glyphs = thisFont.glyphs
                else:
                    glyphs = [g for g in thisFont.glyphs if g.export]

            if limitToCombiningMarks:
                glyphs = [
                    g for g in glyphs
                    if g.category == "Mark" and g.subCategory == "Nonspacing"
                ]

            print("Processing %i glyph%s..." % (
                len(glyphs),
                "" if len(glyphs) == 1 else "s",
            ))

            movedAnchorCount = 0
            for thisGlyph in glyphs:
                print("\n%s:" % thisGlyph.name)
                for thisLayer in thisGlyph.layers:
                    if thisLayer.isMasterLayer or thisLayer.isSpecialLayer:

                        # Nomenclature:
                        #  top: default anchor
                        # _top: underscore Anchor
                        for defaultAnchorName in anchorPairs:

                            # sanitize user entry:
                            # get the default anchor name by getting rid of leading underscores
                            while defaultAnchorName[0] == "_" and len(
                                    anchorName) > 1:
                                defaultAnchorName = defaultAnchorName[1:]

                            # derive underscore anchor from default anchor
                            underscoreAnchorName = "_%s" % defaultAnchorName
                            underscoreAnchor = thisLayer.anchors[
                                underscoreAnchorName]

                            # only proceed if there are both anchors:
                            if not underscoreAnchor:
                                print("   ⚠️ No anchor ‘%s’ found" %
                                      underscoreAnchorName)
                            else:
                                defaultAnchor = thisLayer.anchors[
                                    defaultAnchorName]
                                if not defaultAnchor:
                                    print("   ⚠️ No anchor ‘%s’ found" %
                                          defaultAnchorName)
                                else:
                                    # record original position:
                                    oldPosition = defaultAnchor.position

                                    # determine italic angle and move the anchor accordingly:
                                    italicAngle = thisLayer.associatedFontMaster(
                                    ).italicAngle
                                    straightPosition = NSPoint(
                                        underscoreAnchor.position.x,
                                        defaultAnchor.position.y)
                                    if italicAngle:
                                        defaultAnchor.position = italicize(
                                            straightPosition, italicAngle,
                                            underscoreAnchor.position.y)
                                    else:
                                        defaultAnchor.position = straightPosition

                                    # compare new position to original position, and report if moved:
                                    if defaultAnchor.position != oldPosition:
                                        print("   ↔️ Moved %s on layer '%s'" %
                                              (defaultAnchorName,
                                               thisLayer.name))
                                        movedAnchorCount += 1
                                    else:
                                        print("   ✅ Anchor %s on layer '%s'" %
                                              (defaultAnchorName,
                                               thisLayer.name))

            self.w.close()  # delete if you want window to stay open

            # wrap up and report:
            report = "Moved %i anchor%s in %i glyph%s." % (
                movedAnchorCount,
                "" if movedAnchorCount == 1 else "s",
                len(glyphs),
                "" if len(glyphs) == 1 else "s",
            )
            print("\n%s\nDone." % report)
            Message(
                title="Realigned Anchors",
                message="%s Detailed report in Macro Window." % report,
                OKButton=None,
            )

        except Exception as e:
            # brings macro window to front and reports error:
            Glyphs.showMacroWindow()
            print("Realign Stacking Anchors in Combining Accents Error: %s" %
                  e)
            import traceback
            print(traceback.format_exc())
Esempio n. 22
0
    circlePath.closed = True
    return circlePath


if not thisFont.glyphs[".notdef"]:
    if thisFont.glyphs["question"]:
        sourceMasterID = thisFont.masters[len(thisFont.masters) - 1].id
        sourceLayer = thisFont.glyphs["question"].layers[sourceMasterID]
        if sourceLayer:
            # Build .notdef from question mark and circle:
            questionmarkLayer = sourceLayer.copyDecomposedLayer()
            scaleLayerByFactor(questionmarkLayer, 0.8)
            qOrigin = questionmarkLayer.bounds.origin
            qWidth = questionmarkLayer.bounds.size.width
            qHeight = questionmarkLayer.bounds.size.height
            qCenter = NSPoint(qOrigin.x + 0.5 * qWidth,
                              qOrigin.y + 0.5 * qHeight)
            side = max((qWidth, qHeight)) * 1.5
            circleRect = NSRect(
                NSPoint(qCenter.x - 0.5 * side, qCenter.y - 0.5 * side),
                NSSize(side, side))
            circle = circleInsideRect(circleRect)
            questionmarkLayer.paths.append(circle)
            questionmarkLayer.correctPathDirection()

            # Create glyph:
            notdefName = ".notdef"
            notdefGlyph = GSGlyph()
            notdefGlyph.name = notdefName
            thisFont.glyphs.append(notdefGlyph)
            if thisFont.glyphs[notdefName]:
                print("%s added successfully" % notdefName)
"""
import GlyphsApp
from Foundation import NSPoint
import math

font = Glyphs.font
allSelectedGlyphs = [l.parent for l in font.selectedLayers]


def angle(angle, height, yPos):
    offset = math.tan(math.radians(angle)) * height / 2
    shift = math.tan(math.radians(angle)) * yPos - offset
    return shift


for thisGlyph in allSelectedGlyphs:

    for thisLayer in thisGlyph.layers:
        #Set variables
        masterID = thisLayer.associatedMasterId
        thisMasterXheight = font.masters[masterID].xHeight
        thisMasterAngle = thisLayer.italicAngle
        width = thisLayer.width

        for thisAnchor in thisLayer.anchors:
            posY = thisLayer.anchors[thisAnchor.name].position.y
            centerOfLayer = width / 2 + angle(thisMasterAngle,
                                              thisMasterXheight, posY)

            thisLayer.anchors[thisAnchor.name].position = NSPoint(
                centerOfLayer, posY)
Esempio n. 24
0
def moveHandle(a,b,intersection,bPercentage):
	x = a.x + (intersection.x-a.x) * bPercentage
	y = a.y + (intersection.y-a.y) * bPercentage
	return NSPoint(x,y)
Esempio n. 25
0
 def get_center(self, layer):
     center = NSPoint(layer.bounds.origin.x + layer.bounds.size.width / 2,
                      layer.bounds.origin.y + layer.bounds.size.height / 2)
     return center
    def smallFigureBuilderMain(self, sender):
        try:
            # brings macro window to front and clears its log:
            Glyphs.clearLog()

            thisFont = Glyphs.font  # frontmost font
            default = Glyphs.defaults[
                "com.mekkablue.smallFigureBuilder.default"].strip()
            derive = Glyphs.defaults["com.mekkablue.smallFigureBuilder.derive"]
            figures = ("zero", "one", "two", "three", "four", "five", "six",
                       "seven", "eight", "nine")

            offsets = {}
            for suffixPair in [pair.split(":") for pair in derive.split(",")]:
                suffix = suffixPair[0].strip()
                value = float(suffixPair[1].strip())
                offsets[suffix] = value

            # go through
            for fig in figures:
                # determine default glyph:
                defaultGlyphName = "%s%s" % (fig, default)
                defaultGlyph = thisFont.glyphs[defaultGlyphName]

                if not defaultGlyph:
                    print "\nNot found: %s" % defaultGlyphName
                else:
                    print "\nDeriving from %s:" % defaultGlyphName
                    for deriveSuffix in offsets:
                        # create or overwrite derived glyph:
                        deriveGlyphName = "%s%s" % (fig, deriveSuffix)
                        deriveGlyph = thisFont.glyphs[deriveGlyphName]
                        if not deriveGlyph:
                            deriveGlyph = GSGlyph(deriveGlyphName)
                            thisFont.glyphs.append(deriveGlyph)
                            print " - creating new glyph %s" % deriveGlyphName
                        else:
                            print " - overwriting glyph %s" % deriveGlyphName

                        # copy glyph attributes:
                        deriveGlyph.leftKerningGroup = defaultGlyph.leftKerningGroup
                        deriveGlyph.rightKerningGroup = defaultGlyph.rightKerningGroup

                        # reset category & subcategory:
                        deriveGlyph.updateGlyphInfo()

                        # add component on each master layer:
                        for thisMaster in thisFont.masters:
                            isCurrentMaster = thisMaster is thisFont.selectedFontMaster
                            if isCurrentMaster or not Glyphs.defaults[
                                    "com.mekkablue.smallFigureBuilder.currentMasterOnly"]:
                                mID = thisMaster.id
                                offset = offsets[deriveSuffix]
                                offsetPos = NSPoint(0, offset)
                                if thisMaster.italicAngle != 0.0:
                                    offsetPos = italicize(
                                        offsetPos,
                                        italicAngle=thisMaster.italicAngle)
                                defaultComponent = GSComponent(
                                    defaultGlyphName, offsetPos)
                                deriveLayer = deriveGlyph.layers[mID]
                                deriveLayer.clear()
                                deriveLayer.components.append(defaultComponent)

            if not self.SavePreferences(self):
                print "Note: 'Build Small Figures' could not write preferences."

            # self.w.close() # delete if you want window to stay open
        except Exception, e:
            # brings macro window to front and reports error:
            Glyphs.showMacroWindow()
            print "Build Small Figures Error: %s" % e
            import traceback
            print traceback.format_exc()
Esempio n. 27
0
class Window(GWindow):
    #  _ns_window        PyGUI_NSWindow
    #  _ns_style_mask    int

    def __init__(self, style='standard', zoomable=None, **kwds):
        # We ignore zoomable, since it's the same as resizable.
        self._style = style
        options = dict(_default_options_for_style[style])
        for option in ['movable', 'closable', 'hidable', 'resizable']:
            if option in kwds:
                options[option] = kwds.pop(option)
        self._ns_style_mask = self._ns_window_style_mask(**options)
        if style == 'fullscreen':
            ns_rect = NSScreen.mainScreen().frame()
        else:
            ns_rect = NSRect(NSPoint(0, 0),
                             NSSize(self._default_width, self._default_height))
        ns_window = PyGUI_NSWindow.alloc()
        ns_window.initWithContentRect_styleMask_backing_defer_(
            ns_rect, self._ns_style_mask, AppKit.NSBackingStoreBuffered, True)
        ns_content = PyGUI_NS_ContentView.alloc()
        ns_content.initWithFrame_(NSRect(NSPoint(0, 0), NSSize(0, 0)))
        ns_content.pygui_component = self
        ns_window.setContentView_(ns_content)
        ns_window.setAcceptsMouseMovedEvents_(True)
        ns_window.setDelegate_(ns_window)
        ns_window.pygui_component = self
        self._ns_window = ns_window
        GWindow.__init__(self,
                         style=style,
                         closable=options['closable'],
                         _ns_view=ns_window.contentView(),
                         _ns_responder=ns_window,
                         _ns_set_autoresizing_mask=False,
                         **kwds)

    def _ns_window_style_mask(self, movable, closable, hidable, resizable):
        if movable or closable or hidable or resizable:
            mask = AppKit.NSTitledWindowMask
            if closable:
                mask |= AppKit.NSClosableWindowMask
            if hidable:
                mask |= AppKit.NSMiniaturizableWindowMask
            if resizable:
                mask |= AppKit.NSResizableWindowMask
        else:
            mask = AppKit.NSBorderlessWindowMask
        return mask

    def destroy(self):
        #print "Window.destroy:", self ###
        self.hide()
        app = application()
        if app._ns_key_window is self:
            app._ns_key_window = None
        GWindow.destroy(self)
        #  We can't drop all references to the NSWindow yet, because this method
        #  can be called from its windowShouldClose: method, and allowing an
        #  NSWindow to be released while executing one of its own methods seems
        #  to be a very bad idea (Cocoa hangs). So we hide the NSWindow and store
        #  a reference to it in a global. It will be released the next time a
        #  window is closed and the global is re-used.
        global _ns_zombie_window
        _ns_zombie_window = self._ns_window
        self._ns_window.pygui_component = None
        #self._ns_window = None

    def get_bounds(self):
        ns_window = self._ns_window
        ns_frame = ns_window.frame()
        (l, y), (w, h) = ns_window.contentRectForFrameRect_styleMask_(
            ns_frame, self._ns_style_mask)
        b = Globals.ns_screen_height - y
        result = (l, b - h, l + w, b)
        return result

    def set_bounds(self, (l, t, r, b)):
        y = Globals.ns_screen_height - b
        ns_rect = NSRect(NSPoint(l, y), NSSize(r - l, b - t))
        ns_window = self._ns_window
        ns_frame = ns_window.frameRectForContentRect_styleMask_(
            ns_rect, self._ns_style_mask)
        ns_window.setFrame_display_(ns_frame, False)
def buildCirclePart(thisFont, glyphName, isBlack=False):
    partCircle = (((353.0, 0.0), ((152.0, 0.0), (0.0, 150.0), (0.0, 348.0)),
                   ((0.0, 549.0), (152.0, 700.0), (353.0, 700.0)),
                   ((556.0, 700.0), (708.0, 549.0), (708.0, 348.0)),
                   ((708.0, 149.0), (556.0, 0.0), (353.0, 0.0))), )

    thisGlyph = thisFont.glyphs[glyphName]
    if not thisGlyph:
        thisGlyph = GSGlyph()
        thisGlyph.name = glyphName
        thisFont.glyphs.append(thisGlyph)
        thisGlyph.leftMetricsKey = "=40"
        thisGlyph.rightMetricsKey = "=|"
        print("Generated %s" % glyphName)

    thisGlyph.export = False

    # draw in every layer:
    for thisLayer in thisGlyph.layers:
        # make sure it is empty:
        thisLayer.clear()

        # draw outer circle:
        for thisPath in partCircle:
            pen = thisLayer.getPen()
            pen.moveTo(thisPath[0])
            for thisSegment in thisPath[1:]:
                if len(thisSegment) == 2:  # lineto
                    pen.lineTo(thisSegment)
                elif len(thisSegment) == 3:  # curveto
                    pen.curveTo(thisSegment[0], thisSegment[1], thisSegment[2])
                else:
                    print(
                        "%s: Path drawing error. Could not process this segment:\n"
                        % (glyphName, thisSegment))
            pen.closePath()
            pen.endPath()

        # scale:
        refHeight = thisFont.upm - 80
        actualHeight = thisLayer.bounds.size.height
        scaleFactor = refHeight / actualHeight
        thisLayer.applyTransform(
            transform(scale=scaleFactor).transformStruct())

        # shift to align with capHeight:
        refY = thisLayer.associatedFontMaster().capHeight * 0.5
        actualY = thisLayer.bounds.origin.y + thisLayer.bounds.size.height * 0.5
        shift = refY - actualY
        thisLayer.applyTransform(transform(shiftY=shift).transformStruct())

        if not isBlack:
            # inner circle, scaled down:
            currentHeight = thisLayer.bounds.size.height
            outerCircle = thisLayer.paths[0]
            innerCircle = outerCircle.copy()
            thisLayer.paths.append(innerCircle)

            # scale down inner circle:
            stemSize = 50.0
            hstems = thisLayer.associatedFontMaster().horizontalStems
            vstems = thisLayer.associatedFontMaster().verticalStems
            if hstems and vstems:
                stemSize = (hstems[0] + vstems[0]) * 0.25

            maximumStemSize = currentHeight * 0.28
            stemSize = min(maximumStemSize, stemSize)
            smallerBy = stemSize * 2 * 1.06
            newHeight = currentHeight - smallerBy
            scaleFactor = newHeight / currentHeight
            scale = transform(scale=scaleFactor).transformStruct()

            centerX = innerCircle.bounds.origin.x + innerCircle.bounds.size.width * 0.5
            centerY = innerCircle.bounds.origin.y + innerCircle.bounds.size.height * 0.5
            shift = transform(shiftX=-centerX,
                              shiftY=-centerY).transformStruct()
            shiftBack = transform(shiftX=centerX,
                                  shiftY=centerY).transformStruct()

            innerCircle.applyTransform(shift)
            innerCircle.applyTransform(scale)
            innerCircle.applyTransform(shiftBack)

        # tidy up paths and set width:
        thisLayer.correctPathDirection()
        thisLayer.cleanUpPaths()
        thisLayer.updateMetrics()
        thisLayer.syncMetrics()

        # add anchor:
        centerX = thisLayer.bounds.origin.x + thisLayer.bounds.size.width * 0.5
        centerY = thisLayer.bounds.origin.y + thisLayer.bounds.size.height * 0.5
        centerAnchor = GSAnchor()
        centerAnchor.name = "#center"
        centerAnchor.position = NSPoint(centerX, centerY)
        thisLayer.anchors.append(centerAnchor)
    def rotate(self, sender):
        # update settings to the latest user input:
        if not self.SavePreferences(self):
            print("Note: 'Rotate Around Anchor' could not write preferences.")

        selectedLayers = Glyphs.currentDocument.selectedLayers()
        originatingButton = sender.getTitle()

        if "ccw" in originatingButton:
            rotationDirection = 1
        else:
            rotationDirection = -1

        if "+" in originatingButton:
            repeatCount = int(Glyphs.defaults[
                "com.mekkablue.rotateAroundAnchor.stepAndRepeat_times"])
        else:
            repeatCount = 0

        rotationDegrees = float(
            Glyphs.defaults["com.mekkablue.rotateAroundAnchor.rotate_degrees"])
        rotationCenter = NSPoint(
            int(Glyphs.defaults["com.mekkablue.rotateAroundAnchor.anchor_x"]),
            int(Glyphs.defaults["com.mekkablue.rotateAroundAnchor.anchor_y"]),
        )

        if len(selectedLayers) == 1:
            selectionCounts = True
        else:
            selectionCounts = False

        for thisLayer in selectedLayers:
            # rotate individually selected nodes and components
            try:
                thisGlyph = thisLayer.parent
                selectionCounts = selectionCounts and bool(
                    thisLayer.selection)  # True only if both are True
                RotationTransform = self.rotationTransform(
                    rotationCenter, rotationDegrees, rotationDirection)
                print("rotationCenter, rotationDegrees, rotationDirection:",
                      rotationCenter, rotationDegrees, rotationDirection)
                RotationTransformMatrix = RotationTransform.transformStruct()

                thisGlyph.beginUndo()

                if repeatCount == 0:  # simple rotation
                    for thisThing in selection:
                        thisLayer.transform_checkForSelection_doComponents_(
                            RotationTransform, selectionCounts, True)
                else:  # step and repeat paths and components
                    newPaths, newComps = [], []
                    for i in range(repeatCount):
                        for thisPath in thisLayer.paths:
                            if thisPath.selected or not selectionCounts:
                                rotatedPath = thisPath.copy()
                                for j in range(i + 1):
                                    rotatedPath.applyTransform(
                                        RotationTransformMatrix)
                                newPaths.append(rotatedPath)
                        for thisComp in thisLayer.components:
                            if thisComp.selected or not selectionCounts:
                                rotatedComp = thisComp.copy()
                                for j in range(i + 1):
                                    rotatedComp.applyTransform(
                                        RotationTransformMatrix)
                                newComps.append(rotatedComp)
                    for newPath in newPaths:
                        thisLayer.paths.append(newPath)
                    for newComp in newComps:
                        thisLayer.components.append(newComp)

                thisGlyph.endUndo()
            except Exception as e:
                import traceback
                print(traceback.format_exc())