| 1 | # -*- coding: utf-8 -*- |
|---|
| 2 | |
|---|
| 3 | """Aligner |
|---|
| 4 | |
|---|
| 5 | A FontLab Studio/RoboFab macro class implementing alignment |
|---|
| 6 | left/right/top/bottom functions for contours, oddly missing from |
|---|
| 7 | FontLab Studio. |
|---|
| 8 | |
|---|
| 9 | Simple usage (with an open FontLab glyph window and two or more |
|---|
| 10 | contours selected): |
|---|
| 11 | |
|---|
| 12 | from aligner import Aligner |
|---|
| 13 | |
|---|
| 14 | aligner = Aligner() |
|---|
| 15 | aligner.align('top') |
|---|
| 16 | |
|---|
| 17 | If you put this file in |
|---|
| 18 | ~/Library/Application Support/FontLab/Studio 5/Macros/System/Modules |
|---|
| 19 | youâll be able to call it from other scripts from within FontLab. |
|---|
| 20 | |
|---|
| 21 | I have several of these in my Macros/Aligner/ folder called |
|---|
| 22 | align_top.py, align_bottom.py⊠that only have the code shown above. I |
|---|
| 23 | then hooked them up to keystrokes. |
|---|
| 24 | |
|---|
| 25 | Known issues: |
|---|
| 26 | |
|---|
| 27 | - RoboFab doesnât deal with Multiple Masters, so this script will only |
|---|
| 28 | align contours on the first master of MM fonts or on non-MM fonts; |
|---|
| 29 | |
|---|
| 30 | - Aligner currently only works with contours, not single points; |
|---|
| 31 | """ |
|---|
| 32 | |
|---|
| 33 | __author__ = "Antonio Cavedoni <http://cavedoni.com/>" |
|---|
| 34 | __version__ = "0.1" |
|---|
| 35 | __svnid__ = "$Id$" |
|---|
| 36 | __license__ = "Python" |
|---|
| 37 | |
|---|
| 38 | from FL import * |
|---|
| 39 | from robofab.world import CurrentGlyph |
|---|
| 40 | |
|---|
| 41 | class Aligner: |
|---|
| 42 | def __init__(self): |
|---|
| 43 | self.glyph = CurrentGlyph() |
|---|
| 44 | self.contours = [x for x in self.glyph.contours if x.selected] |
|---|
| 45 | if len(self.contours) <= 1: |
|---|
| 46 | fl.Message('Please select more than one contour.') |
|---|
| 47 | self.max_x = 0 |
|---|
| 48 | self.min_x = 1000 |
|---|
| 49 | self.max_y = 0 |
|---|
| 50 | self.min_y = 1000 |
|---|
| 51 | |
|---|
| 52 | def align(self, location='top'): |
|---|
| 53 | for contour in self.contours: |
|---|
| 54 | if location == 'top': |
|---|
| 55 | m_y = max([x.y for x in contour.points]) |
|---|
| 56 | if m_y > self.max_y: self.max_y = m_y |
|---|
| 57 | elif location == 'bottom': |
|---|
| 58 | m_y = min([x.y for x in contour.points]) |
|---|
| 59 | if m_y < self.min_y: self.min_y = m_y |
|---|
| 60 | elif location == 'left': |
|---|
| 61 | m_x = min([x.x for x in contour.points]) |
|---|
| 62 | if m_x < self.min_x: self.min_x = m_x |
|---|
| 63 | elif location == 'right': |
|---|
| 64 | m_x = max([x.x for x in contour.points]) |
|---|
| 65 | if m_x > self.max_x: self.max_x = m_x |
|---|
| 66 | |
|---|
| 67 | for contour in self.contours: |
|---|
| 68 | if location == 'top' or location == 'bottom': |
|---|
| 69 | if location == 'top': |
|---|
| 70 | y = self.max_y - contour.box[3] |
|---|
| 71 | elif location == 'bottom': |
|---|
| 72 | y = self.min_y - contour.box[1] |
|---|
| 73 | contour.move((0, y)) |
|---|
| 74 | else: |
|---|
| 75 | if location == 'left': |
|---|
| 76 | x = self.min_x - contour.box[0] |
|---|
| 77 | elif location == 'right': |
|---|
| 78 | x = self.max_x - contour.box[2] |
|---|
| 79 | contour.move((x, 0)) |
|---|
| 80 | self.glyph.update() |
|---|