drawTextAtPoint() question

Hey there,

I’m writing a small plugin but since I want to test it without restarting Glyphs over and over again I’m using Skedge. The plugin needs to have a specific text in a position and I was wondering what should I do in order to use drawTextAtPoint() inside Skedge. Let’s say just to set a text in the originX, originY of the bounds of a Glyph.

Thanks a lot.

drawTextAtPoint() is a convenience method specific to plugins. You can extract it from plugins.py (find it in the GlyphsSDK) or you do something like this:

NSClassFromString("ReporterPlugin").alloc().init().drawTextAtPoint("hello",NSPoint(50,50))

…not sure though if that works in the context of Skedge.

2 Likes

The most direct way is this:

textString = "Hallo"
position = NSPoint(50, 50)
attributes = NSString.drawTextAttributes_(None) # or set a color (NSColor.greenColor)
NSString.stringWithString_(textString).drawAtPoint_withAttributes_(position, attributes)

NSString.drawTextAttributes_ will pick a font size depending on the handle size setting in Preferences. If you are drawing in a scaled context, it is a bit more complicated so I advise to draw in a unscaled callback.

1 Like

Thanks, Rainer! I knew that function is a convenience method for plugins but still I was wondering if there was a possibility of using it if I would import Glyphs’ plugin module. However, it didn’t work so I moved further and did a bit more of research.

Again, thanks a lot for your help, though!

Great! This works just as expected!

Before I got your response, I also came out with another option that works and scales the text. Here’s the code:

from AppKit import NSClassFromString

text = "Hello"
currentZoom = Glyphs.font.currentTab.scale
fontColor=NSColor.blackColor()

fontAttributes = {
				NSFontAttributeName: NSFont.labelFontOfSize_(10 / currentZoom),
				NSForegroundColorAttributeName: fontColor}

displayText = NSAttributedString.alloc().initWithString_attributes_(unicode(text), fontAttributes)
textAlignment = 0
displayText.drawAtPoint_alignment_((10,10), textAlignment)

It is a bit more complicated but does it make sense or do you think I’ll break at some point?

Thanks!

This is how it is done with objctiveC. Only the first and last lines is not needed:

text = "Hello"
currentZoom = Glyphs.font.currentTab.scale
fontColor = NSColor.textColor()

fontAttributes = {NSFontAttributeName: NSFont.labelFontOfSize_(10 / currentZoom),
				NSForegroundColorAttributeName: fontColor}

displayText = NSAttributedString.alloc().initWithString_attributes_(text, fontAttributes)
displayText.drawAtPoint_((10,10))

And better use NSColor.textColor() to support dark mode.
And I think the unicode(text) is not needed.

One problem with the 10 / currentZoom is that if you zoom in and out you get different optical sizes of the font.

2 Likes

Ah, great! Good to know. Also I didn’t consider how the text would behave in Dark Mode so it’s nice that you brought this issue as well.

Just one last question. I’m not sure if its a Skedge issue or (probably) mine but everything works as expected but when I put this block of code inside a function (because I want to use it several times) the Macro Panel prints this error:

Traceback (most recent call last):
  File "SkedgeModule.py", line 268, in drawCode
    exec self.code
  File "<macro>", line 15, in <module>
  File "<macro>", line 9, in testText2
NameError: global name 'NSFontAttributeName' is not defined

Do you know why this is happening?

Thanks again.

That error should come up all the time. So you need to import it.

from AppKit import NSFontAttributeName, NSForegroundColorAttributeName

It still prints this error… Don’t know what’s wrong with it.

I don’t know. What happens if you put the import into the function, too?

It only works if I write from AppKit import *.

However, it prints the following message:
<string>:4: SyntaxWarning: import * only allowed at module level

Then it seems to be somehow related how Skedge is running the code. I would say, ignore the warning for now.

1 Like

It’s ok. I managed to sketch a lot on a new reporter plugin and it worked fine. I just have a final question that is somethow related to this one. As said, I’m almost done sketching and I’m about to bring the plugin to the final stage by using SDK’s templates but I’m still testing one thing.

I want whatever the plugin reports to be drawn at the same position in the screen no matter if the user zooms in or out. Now I’m drawing a bezier path of the current character and the placement works as expected in the “x” axis but not in the “y” one with the following code:

thisTab = Glyphs.font.currentTab
currentVisibleRect = thisTab.frameView().visibleRect()
scale = thisTab.scale

xPos = currentVisibleRect[0].x / scale
yPos = ( currentVisibleRect[0].y + currentVisibleRect[1].height ) / scale

# Then using translateXBy_yBy_ to the bezier path in order to place it

I’ve also read this thread trying to bring the solution that worked here to my sketch without using functions inside SDK’s template since I still want to sketch a bit faster using Skedge. However, I couldn’t translate to my sketch. Any hint to solve this?

Thanks again!

@Ricard_Garcia

For drawing at an apparent “fixed” position, try to use the foregroundInViewCoords() method as described here (or the respective background pendant).

If you got trouble migrating code back and forth between Skedge and the Glyphs SDK, you can also @ me here in the forum. I just saw this thread by accident :slight_smile: I know about some quirks with Skedge, for example that you need to gloabal variables which you don’t pass as arguments, when you use create methods in Skedge. Maybe you ran into sth of that kind, but I can’t tell from your explanations, yet.

hi, @Mark . First of all, you are completely right and I don’t know why I didn’t tag you in this thread. I’m sure there’s stuff that has been discussed here that could have been solved easily with you around.

Regarding the foregroundInViewCoords , I’m sure it’s quite easy to understand but I’m still having the same sort of problem. The x value is in a fixed place in the screen (no matter the zoom), while the y value is shifting everytime I zoom in or out. I adapted one of your sample scripts for sketch to use the badge function in order to see whether I’m using x and y correctly. Maybe the following code helps you seeing what I’m doing incorrectly (I was using it in Skedge):

import traceback

Glyphs.clearLog()

scale = Glyphs.font.currentTab.scale
print(scale)
layer = Glyphs.font.glyphs[0].layers[0]
tab = Glyphs.font.currentTab

vP = Glyphs.font.currentTab.viewPort
print(vP[1])
vpOrigin = Glyphs.font.currentTab.viewPort.origin
print(vP)


def badge(x, y, s):
    path = NSBezierPath.alloc().init()
    rect = NSRect( (x-s/2, y-s/2), (s, s) )
    ovalInRect = NSBezierPath.bezierPathWithOvalInRect_( rect )

    path.appendBezierPath_( ovalInRect )

    NSColor.colorWithCalibratedRed_green_blue_alpha_( 1, .2, 0, .5 ).set()

    path.fill()


badge(vpOrigin.x/scale + 100/scale, vpOrigin.y/scale + vP[1].height/scale , 15 / scale )


Well, thanks again for your help or any hint regarding this issue. I really appreciate it.

Is there a similar option for the background color (opposite to textColor) that will also be adaptive for light and dark mode? I tried NSColor.backgroundColor(), but it doesn’t exist.

I also tried Glyphs.font.currentTab.graphicView().backgroundColor() but it report None

Try textBackgroundColor

1 Like

Thanks @Mark, that’s it!

Or use

Glyphs.font.currentTab.graphicView().canvasColor()

And it is advisable to only query the currentTab once. And in some plugins (e.g. Reporters), you can use the .controller property. That will be the currentTab already.