How to rotate the text label created with drawAtPoint or any other method

Hi! I make a plugin for myself that will show a text label rotated with a specified angle.
I started with drawAtPoint_ , drawTextAtPoint and using NSAffineTransform.
But I can’t realize how to apply transformation to the drawn text.

The result I expect to achieve:
text-label-rotated

text = "211"
position = NSPoint(x, y)
angle = 25
attr = {fontsize, color}

label = NSAttributedString.alloc().initWithString_attributes_(text, attr)
#label.applyTransform(NSAffineTransform.transform().rotateByDegrees_(angle))
label.drawAtPoint_(position)

The Macro panel output printed an error for applyTransform:

AttributeError: 'NSConcreteAttributedString' object has no attribute 'applyTransform'

If this logic is wrong, the next thought is… to draw a rectangle/image, place the text in it, and transform it. Any ideas?

There is a helper method provided by Glyphs:

handleSize = -1 # if -1, it will follow the user defaults UI size. Otherwise use 0–2
color = None # if None, it will use "NSColor.textColor()"
"""
alignment can pick from one of the following.
GSTopLeft
GSTopCenter
GSTopRight
GSCenterLeft
GSCenterCenter
GSCenterRight
GSBottomLeft
GSBottomCenter
GSBottomRight
"""
alignment = GSCenterLeft
label.drawAtPoint_angle_offset_handleSize_color_alignment_(position, angle, 4, handleSize, color, alignment)

@GeorgSeifert Thanks.
Should I import some additional module to make that helper works?
I tried it on both Glyphs 3.1.2 and the latest cutting edge version.

from __future__ import division, print_function
from GlyphsApp import *
from GlyphsApp.plugins import *

@objc.python_method
def foreground(self, layer):
	label = NSAttributedString.alloc().initWithString_attributes_(
		'Hello',
		{
			NSFontAttributeName: NSFont.labelFontOfSize_(10 / self.getScale()),
			NSForegroundColorAttributeName: NSColor.brownColor()
		}
	)
	label.drawAtPoint_angle_offset_handleSize_color_alignment_(
		NSPoint(300, 100), 25, 4, -1, None, GSBottomCenter
	)

An error message:

AttributeError: 'NSConcreteAttributedString' object has no attribute 'drawAtPoint_angle_offset_handleSize_color_alignment_'

I also tried a few different options:

label.drawAtPoint_() # works
label.drawAtPoint_alignment_() # works
label.drawAtPoint_angle_offset_handleSize_color_alignment_() # error

you don’t need the attributed string. Use the NSString directly.

If you need the attributed string, you can use this:

	NSGraphicsContext.saveGraphicsState()
	transform = NSAffineTransform.new()
	transform.translateXBy_yBy_(postion.x, postion.y)
	transform.rotateByDegrees_(angle)
	transform.translateXBy_yBy_(-postion.x, -postion.y)
	transform.concat()
	label.drawAtPoint_(position)
	NSGraphicsContext.restoreGraphicsState()

(import from AppKit whatever is missing)

@GeorgSeifert
The transform approach actually works! :tada:
And just this was required:
from AppKit import NSGraphicsContext


But I suppose an approach with drawAtPoint_angle_offset_handleSize_color_alignment_() will be simpler (in terms of the number of memory operations). However, it still doesn’t work for me. As I understand, NSString doesn’t support attributes (?) such as font size so I call it like this:

text = "Hello"
label = NSString.stringWithString_(text)
label.drawAtPoint_angle_offset_handleSize_color_alignment_(
	NSPoint(300, 100), 25, 4, -1, None, GSBottomCenter
)

An error message is very similar to a previous one:

AttributeError: 'NSTaggedPointerString' object has no attribute 'drawAtPoint_angle_offset_handleSize_color_alignment_'

Ah, that is only available in 3.2.
in 3.1.2:

text = "Hello"
label = NSString.stringWithString_(text)
label.drawAtPoint_angle_offset_size_color_alignment_(
	(300, 100), 25, 4, 13, None, GSBottomCenter
)
1 Like

Thanks, I added the conditions for checking the Glyphs version.


Yes, it works now!
The only thing I can’t understand is what does offset and size/handleSize affect? I tried to set different values for them but it doesn’t change anything.

For size I set 10 / self.getScale() and also tried just 10 and -1 value but the drawn text continues to change its visual size when scaling interface.

I expect that the font size (rotated text colored with brown on the image below) will always be optically the same (as the black colored text drawn with drawTextAtPoint). @GeorgSeifert is it possible with this approach, or do I have to go back to the drawTextAtPoint + transform approach anyway?

drawAtPoint_angle_offset_size_color_alignment_ :

scale

drawTextAtPoint + transform :

scale_affine_transform


Just ran a performance test (selecting the path to draw the coordinates, and unselecting it, every half a second) and both methods described above load the CPU exactly the same – somewhere by 5—5.7%.

You should use one of the “InViewCoords” methods. There you need to scale the position but not the size.

It gets too complicated, especially with the lack of documentation for such specific things like InViewCoords. So I’ll stick to using Affine Transform. It works as I need it to :tada:, and I haven’t seen any difference in performance between the approaches.

@GeorgSeifert, many thanks for the explanation and your time :slight_smile: