Slant Only Paths and Anchors without Slanting Components

Is this possible yet? I’m slanting an entire font and dont want to manually do every glyph that’s a component+path

Job for a simple script.

Sorry this is beyond me, I’m not sure how to to skew it so that the metrics stay the same, I understand it’s something to do with with the centre of the x-height box but I don’t know how to set that in

layer = Glyphs.font.selectedLayers[0] # current layer

layer.applyTransform([
                        0.5, # x scale factor
                        0.0, # x skew factor
                        0.0, # y skew factor
                        0.5, # y scale factor
                        0.0, # x position
                        0.0  # y position
                        ])

Any tips would be appreciated, thanks!

[edit

Solved :sweat_smile: https://gist.github.com/weiweihuanghuang/b0266db3aa7a1fe91a2d9c636c1b1d19#file-skew-only-paths-and-anchors-py

Here is a shorter version:

#MenuTitle: Skew only Paths and Anchors
# -*- coding: utf-8 -*-
__doc__="""
"""

import GlyphsApp
import math 
from AppKit import NSAffineTransform

def slantLayers(layers, angle):
	Font.disableUpdateInterface()
	xHeight = layers[0].associatedFontMaster().xHeight
	transform = NSAffineTransform.new()
	slant = math.tan(skewAngle * math.pi / 180.0)
	transform.shearXBy_atCenter_(slant, -xHeight / 2.0)
	
	for layer in layers:
		for path in layer.paths:
			for node in path.nodes:
				node.position = transform.transformPoint_(node.position)
		for anchor in layer.anchors:
			anchor.position = transform.transformPoint_(anchor.position)
		
	Font.enableUpdateInterface()

skewAngle = 13
slantLayers(Glyphs.font.selectedLayers, skewAngle)
1 Like

Thank you @GeorgSeifert, this is perfect and accurate!

You can also use the transform tab trigger in the Python for Glyphs repo, find it via the Extend page. The trab trigger expands to a self-explanatory transform() function which returns the NSAffineTransform object you need for the slant, scale, rotate, etc. transformation you had in mind.

Just tried running this, but I get this error (when I run it from the macro window):

Traceback (most recent call last):
  File "<macro panel>", line 22
  File "<macro panel>", line 12, in slantLayers
NameError: name 'selectedLayers' is not defined

Substitute selectedLayers for layers (or the other way round, in either case, the argument passed is not actually used properly).

I fixed the code sample.

Now it doesn’t error out, but the transformation is only performed on the visible layer, not all the selected layers.

Works for me. What do you mean by “visible” vs “selected” layers?

A slightly updated version:

#MenuTitle: Skew only Paths and Anchors
# -*- coding: utf-8 -*-

import GlyphsApp
import math 
from AppKit import NSAffineTransform

def slantLayers(layers, angle):
	Font.disableUpdateInterface()
	slantHeight = layers[0].slantHeight()
	transform = NSAffineTransform.new()
	slant = math.tan(skewAngle * math.pi / 180.0)
	transform.shearXBy_atCenter_(slant, -slantHeight)
	
	for layer in layers:
		layer.transform_checkForSelection_(transform, False)

	Font.enableUpdateInterface()

skewAngle = 13
slantLayers(Font.selectedLayers, skewAngle)

I mean that it only work on the layer I’m currently on, nothing else, even if I have other layers selected.

Say I want to run it on the selected layers like in the screenshot:

Then the script only transforms whatever layer I am currently viewing/editing.

Is this a bug: I select two (or more) layers, and press Cmd+J to copy to the background layer, but only the visible layer is actually copied to the background. Should I not be able to do these operations on all of the selected layers?

Selected Layers doesn’t refers to the selection in the layer panel. It is the selection from the font/edit view.

Is there any way of selecting the content of more layers (and here I’m talking about the layers I have in the layers palette) at once?

Are you talking about another thing also called ‘layers’???

Any way to poll the selection in the layer panel for a script?

You can access everything inside Glyphs. Sometimes the path is a bit hacky.

palettes = Font.parent.windowController().panelSidebarViewController().valueForKey_("paletteInstances")
for palette in palettes:
	if "GlyphsPaletteLayers" in palette.__class__.__name__:
		break
selectedRows = palette.layersList().selectedRowIndexes()
layers = palette.allSelectedLayers_(selectedRows)
print(layers)

This will return all layers from all glyphs that are selected in Edit/Font view for all selected rows in the layer list.

2 Likes

Perfect, thanks a lot!

So, Claus, you can just use this code sample and replace Font.selectedLayers in the code further up accordingly. This should work (can’t test right now):

#MenuTitle: Skew only Paths and Anchors
# -*- coding: utf-8 -*-

import GlyphsApp
import math 
from AppKit import NSAffineTransform

def slantLayers(layers, angle):
	Font.disableUpdateInterface()
	slantHeight = layers[0].slantHeight()
	transform = NSAffineTransform.new()
	slant = math.tan(skewAngle * math.pi / 180.0)
	transform.shearXBy_atCenter_(slant, -slantHeight)
	
	for layer in layers:
		layer.transform_checkForSelection_(transform, False)

	Font.enableUpdateInterface()

palettes = Font.parent.windowController().panelSidebarViewController().valueForKey_("paletteInstances")
for palette in palettes:
	if "GlyphsPaletteLayers" in palette.__class__.__name__:
		break
selectedRows = palette.layersList().selectedRowIndexes()
layers = palette.allSelectedLayers_(selectedRows)

skewAngle = 13
slantLayers(layers, skewAngle)