def _distributeSpacing(self, index, title): glyph = CurrentGlyph() if glyph is None: return rects, selectedContours, selectedBPoints = getSelectionData(glyph) if len(rects) < 3: return widths = [] heights = [] edgeRect = None for rect in rects: xMin, yMin, xMax, yMax = rect widths.append(xMax - xMin) heights.append(yMax - yMin) if edgeRect is None: edgeRect = rect else: edgeRect = unionRect(edgeRect, rect) objectWidth = sum(widths) objectHeight = sum(heights) xMin, yMin, xMax, yMax = edgeRect overallWidth = xMax - xMin overallHeight = yMax - yMin availableXSpace = overallWidth - objectWidth availableYSpace = overallHeight - objectHeight xSpace = availableXSpace / (len(rects) - 1) ySpace = availableYSpace / (len(rects) - 1) spaceBetweenObjects = (xSpace, ySpace)[index] ordered = [(bPoint.anchor[index], (bPoint.anchor[0], bPoint.anchor[1], bPoint.anchor[0], bPoint.anchor[1]), bPoint) for bPoint in selectedBPoints] ordered += [(contour.bounds[index], contour.bounds, contour) for contour in selectedContours] ordered.sort() glyph.prepareUndo(title) prevEdge = None for pos, bounds, obj in ordered[:-1]: xMin, yMin, xMax, yMax = bounds width = xMax - xMin height = yMax - yMin size = (width, height)[index] if prevEdge is None: newPos = (xMin, yMin)[index] else: newPos = prevEdge + spaceBetweenObjects d = newPos - pos print(d) if d != 0: if index == 0: obj.moveBy((d, 0)) else: obj.moveBy((0, d)) prevEdge = newPos + size for bPoint in selectedBPoints: bPoint.round() for contour in selectedContours: contour.round() glyph.changed() glyph.performUndo() UpdateCurrentGlyphView()
def nudgeSelected(offset): g = CurrentGlyph() for c in g.contours: for i, p in enumerate(c.bPoints): n = c.bPoints[i] if n.selected: g.prepareUndo(undoTitle='InterpolatedNudge') interpolateNode(i, g, c, offset) g.performUndo() g.update()
def nudgeSelected(x): g = CurrentGlyph() for c in g.contours: i = 0 for p in c.bPoints: n = c.bPoints[i] if n.selected: g.prepareUndo(undoTitle='InterpolatedNudge') interpolateNode(i, g, c, x) g.performUndo() g.update() i = i + 1
def _distribute(self, methods, title): glyph = CurrentGlyph() if glyph is None: return rects, selectedContours, selectedBPoints = getSelectionData(glyph) if len(rects) < 3: return glyph.prepareUndo(title) for method in methods: method(rects, selectedContours, selectedBPoints) for bPoint in selectedBPoints: bPoint.round() for contour in selectedContours: contour.round() glyph.changed() glyph.performUndo() UpdateCurrentGlyphView()
class alignPointsDialog(hConstants): """Align selected points vertically or horizontally.""" glyph = None points = [] x_pos_list = [] y_pos_list = [] axis = 1 mode = 1 def __init__(self): # window parameters self.title = 'align' self.width = 123 self.column1 = 45 self.height = (self.padding_y * 4) + self.button_height + (self.text_height * 2) # window self.w = FloatingWindow( (self.width, self.height), self.title) x = self.padding_x y = self.padding_y # options self.w.align_mode = RadioGroup( (x, y, -self.padding_x, self.text_height), [ '-', 'm', '+' ], isVertical=False, sizeStyle=self.size_style) self.w.align_mode.set(self.mode) y += (self.text_height + self.padding_y) # button x = self.padding_x self.w.align_button = SquareButton( (x, y, -self.padding_x, self.button_height), 'apply', callback=self.apply_callback, sizeStyle=self.size_style) y += (self.button_height + self.padding_y) # axis self.w.axis_label = TextBox( (x, y + 3, self.column1, self.text_height), "axis", sizeStyle=self.size_style) x = self.column1 self.w.axis = RadioGroup( (x, y, -self.padding_x, self.text_height), ["x", "y"], sizeStyle=self.size_style, isVertical=False) self.w.axis.set(self.axis) # open self.w.open() def _get_parameters(self): self.axis = self.w.axis.get() self.mode = self.w.align_mode.get() def apply_callback(self, sender): # get current glyph self.glyph = CurrentGlyph() # no glyph window open if self.glyph is None: print no_glyph_open else: # collect points self.points = [] for c in self.glyph: print c.selection for p in c.points: if p.selected: self.points.append(p) self.x_pos_list.append(p.x) self.y_pos_list.append(p.y) # not enough points selected if len(self.points) < 2: print at_least_two_points else: self._get_parameters() self.glyph.prepareUndo('align points') # select axis if self.axis == 0: values_list = self.x_pos_list else: values_list = self.y_pos_list # get aligment point if self.mode == 1: pos = get_med(values_list) elif self.mode == 2: pos = get_max(values_list) else: pos = get_min(values_list) # align points for p in self.points: # get delta if self.axis == 0: delta_x = pos - p.x delta_y = 0 else: delta_x = 0 delta_y = pos - p.y # move points p.move((delta_x, delta_y)) # done self.glyph.update() self.glyph.performUndo()
class alignPointsDialog(hDialog): """Align selected points vertically or horizontally.""" glyph = None points = [] x_pos_list = [] y_pos_list = [] axis = 1 mode = 1 def __init__(self): # window parameters self.title = 'align' self.width = 123 self.column1 = 45 self.height = (self.padding_y * 4) + self.button_height + (self.text_height * 2) # window self.w = FloatingWindow((self.width, self.height), self.title) x = self.padding_x y = self.padding_y # options self.w.align_mode = RadioGroup( (x, y, -self.padding_x, self.text_height), ['-', 'm', '+'], isVertical=False, sizeStyle=self.size_style) self.w.align_mode.set(self.mode) y += (self.text_height + self.padding_y) # button x = self.padding_x self.w.align_button = SquareButton( (x, y, -self.padding_x, self.button_height), 'apply', callback=self.apply_callback, sizeStyle=self.size_style) y += (self.button_height + self.padding_y) # axis self.w.axis_label = TextBox((x, y + 3, self.column1, self.text_height), "axis", sizeStyle=self.size_style) x = self.column1 self.w.axis = RadioGroup((x, y, -self.padding_x, self.text_height), ["x", "y"], sizeStyle=self.size_style, isVertical=False) self.w.axis.set(self.axis) # open self.w.open() def _get_parameters(self): self.axis = self.w.axis.get() self.mode = self.w.align_mode.get() def apply_callback(self, sender): # get current glyph self.glyph = CurrentGlyph() # no glyph window open if self.glyph is None: print(no_glyph_open) else: # collect points self.points = [] for c in self.glyph: print(c.selection) for p in c.points: if p.selected: self.points.append(p) self.x_pos_list.append(p.x) self.y_pos_list.append(p.y) # not enough points selected if len(self.points) < 2: print(at_least_two_points) else: self._get_parameters() self.glyph.prepareUndo('align points') # select axis if self.axis == 0: values_list = self.x_pos_list else: values_list = self.y_pos_list # get aligment point if self.mode == 1: pos = get_med(values_list) elif self.mode == 2: pos = get_max(values_list) else: pos = get_min(values_list) # align points for p in self.points: # get delta if self.axis == 0: delta_x = pos - p.x delta_y = 0 else: delta_x = 0 delta_y = pos - p.y # move points p.move((delta_x, delta_y)) # done self.glyph.update() self.glyph.performUndo()
class GlyphEditorSpaceStationController(object): def __init__(self, glyph): self.w = StatusInteractivePopUpWindow( (250, 0), centerInView=CurrentGlyphWindow().getGlyphView()) metrics = dict( border=15, padding1=10, padding2=5, titleWidth=45, inputSpace=70, # border + title + padding killButtonWidth=20, navigateButtonWidth=30, fieldHeight=22, ) rules = [ # Left "H:|-border-[leftTitle(==titleWidth)]-padding1-[leftField]-border-|", "H:|-inputSpace-[leftButton]-padding2-[leftKillButton(==killButtonWidth)]-border-|", "V:|-border-[leftTitle(==fieldHeight)]", "V:|-border-[leftField(==fieldHeight)]", "V:[leftField]-padding2-[leftButton]", "V:[leftField]-padding2-[leftKillButton(==leftButton)]", # Right "H:|-border-[rightTitle(==titleWidth)]-padding1-[rightField]-border-|", "H:|-inputSpace-[rightButton]-padding2-[rightKillButton(==killButtonWidth)]-border-|", "V:[leftButton]-padding1-[rightTitle(==fieldHeight)]", "V:[leftButton]-padding1-[rightField(==fieldHeight)]", "V:[rightField]-padding2-[rightButton]", "V:[rightField]-padding2-[rightKillButton(==rightButton)]", # Width "H:|-border-[widthTitle(==titleWidth)]-padding1-[widthField]-border-|", "H:|-inputSpace-[widthButton]-padding2-[widthKillButton(==killButtonWidth)]-border-|", "V:[rightButton]-padding1-[widthTitle(==fieldHeight)]", "V:[rightButton]-padding1-[widthField(==fieldHeight)]", "V:[widthField]-padding2-[widthButton]", "V:[widthField]-padding2-[widthKillButton(==rightButton)]", # Bottom "H:|-inputSpace-[line]-border-|", "H:|-inputSpace-[previousGlyphButton(==navigateButtonWidth)]-padding2-[nextGlyphButton(==navigateButtonWidth)]-padding1-[doneButton(>=0)]-border-|", "V:[widthButton]-padding1-[line]", "V:[line]-padding1-[previousGlyphButton]-border-|", "V:[line]-padding1-[nextGlyphButton]-border-|", "V:[line]-padding1-[doneButton]-border-|", ] self.w.leftTitle = vanilla.TextBox("auto", "Left:", alignment="right") self.w.leftField = vanilla.EditText("auto", "", continuous=False, callback=self.fieldCallback) self.w.leftButton = vanilla.Button("auto", "", callback=self.buttonCallback) self.w.leftKillButton = vanilla.ImageButton( "auto", imageNamed=NSImageNameStopProgressFreestandingTemplate, bordered=False, callback=self.buttonCallback) self.w.rightTitle = vanilla.TextBox("auto", "Right:", alignment="right") self.w.rightField = vanilla.EditText("auto", "", continuous=False, callback=self.fieldCallback) self.w.rightButton = vanilla.Button("auto", "", callback=self.buttonCallback) self.w.rightKillButton = vanilla.ImageButton( "auto", imageNamed=NSImageNameStopProgressFreestandingTemplate, bordered=False, callback=self.buttonCallback) self.w.widthTitle = vanilla.TextBox("auto", "Width:", alignment="right") self.w.widthField = vanilla.EditText("auto", "", continuous=False, callback=self.fieldCallback) self.w.widthButton = vanilla.Button("auto", "", callback=self.buttonCallback) self.w.widthKillButton = vanilla.ImageButton( "auto", imageNamed=NSImageNameStopProgressFreestandingTemplate, bordered=False, callback=self.buttonCallback) self.controlGroups = [ dict(attr="leftMargin", field=self.w.leftField, button=self.w.leftButton, kill=self.w.leftKillButton), dict(attr="rightMargin", field=self.w.rightField, button=self.w.rightButton, kill=self.w.rightKillButton), dict(attr="width", field=self.w.widthField, button=self.w.widthButton, kill=self.w.widthKillButton), ] for group in self.controlGroups: field = group["field"] button = group["button"] button.getNSButton().setAlignment_(NSLeftTextAlignment) self.w.line = vanilla.HorizontalLine("auto") self.w.doneButton = vanilla.Button("auto", "Close", callback=self.doneCallback) self.w.doneButton.bind(escapeCharacter, []) self.w.previousGlyphButton = vanilla.Button( "auto", "←", callback=self.previousGlyphCallback) self.w.previousGlyphButton.bind("[", ["command"]) self.w.nextGlyphButton = vanilla.Button( "auto", "→", callback=self.nextGlyphCallback) self.w.nextGlyphButton.bind("]", ["command"]) self.w.addAutoPosSizeRules(rules, metrics) self.loadGlyph() self.w.open() def setFirstResponder(self, control): self.w.getNSWindow().makeFirstResponder_(control.getNSTextField()) def _getControlGroup(self, sender): for group in self.controlGroups: field = group["field"] button = group["button"] kill = group["kill"] if sender == field: return group if sender == button: return group if sender == kill: return group def doneCallback(self, sender): self.w.close() # -------- # Updaters # -------- def loadGlyph(self): self._inGlyphLoad = True self.glyph = CurrentGlyph() if self.glyph.bounds is None: self.setFirstResponder(self.w.widthField) else: self.setFirstResponder(self.w.leftField) leftField = self.w.leftField.getNSTextField() rightField = self.w.rightField.getNSTextField() leftField.setNextKeyView_(rightField) rightField.setNextKeyView_(leftField) self._updateFields() self._updateButtons() self._inGlyphLoad = False def _updateFields(self): for group in self.controlGroups: attr = group["attr"] field = group["field"] if attr in ("leftMargin", "rightMargin") and self.glyph.bounds is None: value = "" else: value = getMetricValue(self.glyph, attr) value = roundint(value) field.set(value) def _updateButtons(self): for group in self.controlGroups: attr = group["attr"] button = group["button"] formula = getFormula(self.glyph, attr) if not formula: button.setTitle("") button.enable(False) continue calculatedValue = calculateFormula(self.glyph, formula, attr) value = getMetricValue(self.glyph, attr) if roundint(value) != roundint(calculatedValue): color = outSyncButtonColor else: color = inSyncButtonColor string = NSAttributedString.alloc().initWithString_attributes_( formula, {NSForegroundColorAttributeName: color}) button.setTitle(string) button.enable(True) # --------- # Callbacks # --------- def fieldCallback(self, sender): if self._inGlyphLoad: return group = self._getControlGroup(sender) attr = group["attr"] field = group["field"] button = group["button"] value = field.get().strip() if value.startswith("="): formula = value[1:] if not formula: NSBeep() return value = calculateFormula(self.glyph, formula, attr) if value is None: NSBeep() return field.set(str(roundint(value))) setFormula(self.glyph, attr, formula) else: try: value = int(value) except: NSBeep() return self.glyph.prepareUndo("Spacing Change") setMetricValue(self.glyph, attr, value) self.glyph.performUndo() self._updateFields() self._updateButtons() def buttonCallback(self, sender): group = self._getControlGroup(sender) attr = group["attr"] field = group["field"] button = group["button"] kill = group["kill"] if sender == kill: clearFormula(self.glyph, attr) else: formula = button.getTitle() value = calculateFormula(self.glyph, formula, attr) if value is None: NSBeep() return self.glyph.prepareUndo("Spacing Change") setMetricValue(self.glyph, attr, value) self.glyph.performUndo() self._updateFields() self._updateButtons() def previousGlyphCallback(self, sender): CurrentGlyphWindow().getGlyphView().previousGlyph_() self.loadGlyph() def nextGlyphCallback(self, sender): CurrentGlyphWindow().getGlyphView().nextGlyph_() self.loadGlyph()