def __createDockingSide(self, position): ''' creates dockbar, which are next to the edges of the content view ''' dockingSideObj = Group(self.dockingRectPosSizes[position], blendingMode=None) objBarView = dockingSideObj.getNSView() objBarView.dockingSidePositionName = position objBarView.setWantsLayer_(True) objBarView.layer().setBackgroundColor_(NSColor.clearColor().CGColor()) objName = f"{position}_dockbar" setattr(self, objName, dockingSideObj)
def __init__(self, posSize, gridActive, ctrlsAmount, activeCtrls, offgridActive, callback): Group.__init__(self, posSize) assert activeCtrls <= ctrlsAmount self.ctrlHeight = posSize[3] self.gridActive = gridActive self.ctrlsAmount = ctrlsAmount self.activeCtrls = activeCtrls self.offgridActive = offgridActive self.gridIndexes = [ '{:d}'.format(integer) for integer in range(1, ctrlsAmount + 1) ] self.callback = callback self.gridsDB = [{ 'horizontal': False, 'vertical': False, 'step': None, 'color': color } for color in GRID_COLOR_INIT] jumpin_Y = 4 self.gridActiveCheck = CheckBox( (0, jumpin_Y, NET_WIDTH * .6, vanillaControlsSize['CheckBoxRegularHeight']), "Show grids", value=self.gridActive, callback=self.gridActiveCheckCallback) for eachI in range(1, ctrlsAmount + 1): jumpin_Y += vanillaControlsSize[ 'EditTextRegularHeight'] + MARGIN_VER gridCtrl = SingleGridController( (0, jumpin_Y, NET_WIDTH, vanillaControlsSize['EditTextRegularHeight']), index=eachI, isVertical=False, isHorizontal=False, step=None, gridColor=GRID_COLOR_INIT[eachI - 1], callback=self.gridCtrlCallback) gridCtrl.enable(self.gridActive) setattr(self, 'grid{:0>2}'.format(eachI), gridCtrl) jumpin_Y += vanillaControlsSize['EditTextRegularHeight'] + MARGIN_VER self.showOffgridCheck = CheckBox( (0, jumpin_Y, NET_WIDTH, vanillaControlsSize['CheckBoxRegularHeight']), "Show offgrid points", value=self.offgridActive, callback=self.showOffgridCheckCallback)
def __init__(self, posSize, text, minValue, maxValue, value, callback): Group.__init__(self, posSize) self.text = TextBox((0, 0, -0, 20), text) self.slider = Slider((2, 20, -60, 17), minValue=minValue, maxValue=maxValue, value=value, sizeStyle="small", callback=self.sliderChanged) self.edit = EditText((-40, 15, -0, 22), text=str(value), placeholder=str(value), callback=self.editChanged) self.callback = callback
class LoadedDockingGroup(EmptyDockingGroup): ''' DockedWindowView group that represents docked windows ''' def __init__(self, dockingWindow): self._dockingWindow = dockingWindow testPosSize = (0, 0, -0, -0) ### TEST blendingMode = None # ? check what exacly it does super(LoadedDockingGroup, self).__init__(posSize=testPosSize, blendingMode=blendingMode) self._nsObject.setWantsLayer_(True) self._nsObject.layer().setBorderWidth_(1) self._nsObject.layer().setBorderColor_(NSColor.gridColor().CGColor()) self.__addTitleView() self.__addContentView() self.__transferDockedContent() def __addTitleView(self): self._titleView = Group((0, 0, -0, titleHeight)) self._dockingWindow.getTitle() self._titleView.title = TextBox((0, 0, -0, titleHeight), self._dockingWindow.getTitle(), sizeStyle='mini', alignment='center') self._titleView.undockBtn = GradientButton( (-titleHeight, 0, titleHeight, titleHeight), title="❏", bordered=False, callback=self._undock, sizeStyle='mini') self._titleView.getNSView().setWantsLayer_(True) self._titleView.getNSView().layer().setBackgroundColor_( NSColor.gridColor().CGColor()) def __addContentView(self): self._contentView = Group((0, titleHeight, -0, -0)) def __transferDockedContent(self): for objName in self._dockingWindow.__dict__: obj = getattr(self._dockingWindow, objName) if isinstance(obj, VanillaBaseObject): setattr(self._contentView, objName, obj) # I don't know if it is a proper way to change the posi def _undock(self, sender): print("undock not implemented yet")
def __init__(self, posSize, openedFontPaths, lftNeighborActive, lftFontPath, lftGlyphName, cntNeighborActive, cntFontPath, cntGlyphName, rgtNeighborActive, rgtFontPath, rgtGlyphName, callback): Group.__init__(self, posSize) self.callback = callback self.ctrlHeight = posSize[3] self.neighborsDB = {} self.neighborsDB['lft'] = [ lftNeighborActive, lftFontPath, lftGlyphName ] self.neighborsDB['cnt'] = [ cntNeighborActive, cntFontPath, cntGlyphName ] self.neighborsDB['rgt'] = [ rgtNeighborActive, rgtFontPath, rgtGlyphName ] jumpin_X = 0 self.lftController = SingleNeighborController( (jumpin_X, 0, 60, self.ctrlHeight), 'Left', isActive=lftNeighborActive, openedFontPaths=openedFontPaths, activeFontPath=lftFontPath, activeGlyphName=lftGlyphName, callback=self.lftControllerCallback) jumpin_X += 60 + MARGIN_HOR self.cntController = SingleNeighborController( (jumpin_X, 0, 60, self.ctrlHeight), 'Center', isActive=cntNeighborActive, openedFontPaths=openedFontPaths, activeFontPath=cntFontPath, activeGlyphName=cntGlyphName, callback=self.cntControllerCallback) jumpin_X += 60 + MARGIN_HOR self.rgtController = SingleNeighborController( (jumpin_X, 0, 60, self.ctrlHeight), 'Right', isActive=rgtNeighborActive, openedFontPaths=openedFontPaths, activeFontPath=rgtFontPath, activeGlyphName=rgtGlyphName, callback=self.rgtControllerCallback)
def __init__(self, posSize, minValue, maxValue, value, callback): Group.__init__(self, posSize) self.slider = Slider( (2, 3, -55, 17), minValue=minValue, maxValue=maxValue, value=value, sizeStyle="regular", callback=self.sliderChanged) self.edit = EditText( (-40, 0, -0, 22), text=str(value), placeholder=str(value), callback=self.editChanged) self.callback = callback
def __init__(self): self.w = Window((300, 100)) self.w.inner = Group((10, 10, -10, -10)) p1 = VanillaSingleValueParameter('main', 10, (0, 100), 'int') p2 = VanillaSingleValueParameter('ratio', 10, (0, 100), 'int', master=p1, mode='ratio', dissociable=True) p3 = VanillaSingleValueParameter('offset', 10, (0, 100), 'int', master=p1, mode='offset', dissociable=True) self.w.inner.p1 = ParameterSliderTextInput(p1, (0, 0, -0, 22), 'master') self.w.inner.p2 = ParameterSliderTextInput(p2, (0, 25, -0, 22), 'ratio') self.w.inner.p3 = ParameterSliderTextInput(p3, (0, 50, -0, 22), 'offset') self.w.open()
def __addTitleView(self): self._titleView = Group((0, 0, -0, titleHeight)) self._dockingWindow.getTitle() self._titleView.title = TextBox((0, 0, -0, titleHeight), self._dockingWindow.getTitle(), sizeStyle='mini', alignment='center') self._titleView.undockBtn = GradientButton( (-titleHeight, 0, titleHeight, titleHeight), title="❏", bordered=False, callback=self._undock, sizeStyle='mini') self._titleView.getNSView().setWantsLayer_(True) self._titleView.getNSView().layer().setBackgroundColor_( NSColor.gridColor().CGColor())
def showWindow_(self, sender): try: from vanilla import Group, Slider, TextBox, Window self.windowWidth = 300 self.windowHeight = 240 self.w = Window((self.windowWidth, self.windowWidth), "Rotate View", minSize=(self.windowWidth, self.windowWidth + 20)) self.w.Preview = RoatatePreview((0, 0, -0, -60)) self.w.controlBox = Group((0, -60, -0, -0)) self.w.controlBox.slider = Slider((10, 6, -10, 23), tickMarkCount=17, callback=self.sliderCallback, value=0, minValue=-360, maxValue=360) self.w.controlBox.textBox = TextBox((10, -25, -10, 22), text="0.00°", alignment="center") self.w.controlBox.slider.getNSSlider().setEnabled_(False) self.w.open() self.changeGlyph_(None) Glyphs.addCallback( self.changeGlyph_, UPDATEINTERFACE ) #will be called on ever change to the interface except: print(traceback.format_exc())
def __init__(self): self.w = Window((300, 500), minSize=(200, 100)) y = 10 self.w.g = Group((0, 0, 0, 0)) for i, tag in enumerate(["liga", "calt", "dlig", "smcp", "kern", "locl"]): setattr(self.w.g, f"tag{i}", TagView((10, y, 60, 20), tag, None, self.callback)) y += 26 self.w.open()
def __init__(self): self.filters = PenBallFiltersManager() self.filters.loadFiltersFromJSON('/'.join([LOCALPATH, JSONFILE])) self.glyphNames = [] self.observedGlyphs = [] self.cachedFont = RFont(showUI=False) self.currentFont = CurrentFont() filtersList = self.filters.keys() if len(filtersList) > 0: self.currentFilterName = filtersList[0] else: self.currentFilterName = None self.fill = True self.observers = [ ('fontChanged', 'fontBecameCurrent'), ('fontChanged', 'fontDidOpen'), ('fontChanged', 'fontDidClose'), ] self.w = Window((100, 100, 800, 500), 'PenBall Wizard v{0}'.format(__version__), minSize=(500, 400)) self.w.filtersPanel = Group((0, 0, 300, -0)) self.w.filtersPanel.filtersList = List((0, 0, -0, -40), filtersList, selectionCallback=self.filterSelectionChanged, doubleClickCallback=self.filterEdit, allowsMultipleSelection=False, allowsEmptySelection=False, rowHeight=22) self.w.filtersPanel.controls = Group((0, -40, -0, 0)) self.w.filtersPanel.addFilter = SquareButton((0, -40, 100, 40), 'Add filter', sizeStyle='small', callback=self.addFilter) self.w.filtersPanel.addFilterChain = SquareButton((100, -40, 100, 40), 'Add operations', sizeStyle='small', callback=self.addFilterChain) self.w.filtersPanel.removeFilter = SquareButton((-100, -40, 100, 40), 'Remove filter', sizeStyle='small', callback=self.removeFilter) self.w.textInput = EditText((300, 0, -90, 22), '', callback=self.stringInput) self.w.generate = SquareButton((-90, 0, 90, 22), 'Generate', callback=self.generateGlyphsToFont, sizeStyle='small') self.w.preview = MultiLineView((300, 22, -0, -0)) self.w.switchFillStroke = SquareButton((-75, -40, 60, 25), 'Stroke', callback=self.switchFillStroke, sizeStyle='small') displayStates = self.w.preview.getDisplayStates() for key in ['Show Metrics','Upside Down','Stroke','Beam','Inverse','Water Fall','Multi Line']: displayStates[key] = False for key in ['Fill','Single Line']: displayStates[key] = True self.w.preview.setDisplayStates(displayStates) for callback, event in self.observers: addObserver(self, callback, event) self.updateControls() self.w.bind('close', self.end) self.launchWindow() self.w.open()
def __init__(self, posSize, title, options, chosenOption, sizeStyle, callback): Group.__init__(self, posSize) self.callback = callback self.options = options width = posSize[2] height = posSize[3] self.caption = TextBox((0, 2, width*.5, height), title, sizeStyle=sizeStyle, alignment='right') self.combo = ComboBox((width*.5, 0, width*.5-1, height), options, continuous=False, sizeStyle=sizeStyle, callback=self.comboCallback) self.combo.set(chosenOption)
def __init__(self, posSize, index, isVertical, isHorizontal, step, gridColor, callback): Group.__init__(self, posSize) # from arguments to attributes self.ctrlX, self.ctrlY, self.ctrlWidth, self.ctrlHeight = posSize self.index = index self.isVertical = isVertical self.isHorizontal = isHorizontal self.step = step self.gridColor = gridColor self.callback = callback # ctrls jumpin_X = 12 self.indexText = TextBox( (jumpin_X, 0, 16, vanillaControlsSize['TextBoxRegularHeight']), '{:d})'.format(index)) jumpin_X += self.indexText.getPosSize()[2] self.stepCtrl = EditText( (jumpin_X, 0, 38, vanillaControlsSize['EditTextRegularHeight']), callback=self.stepCtrlCallback) jumpin_X += self.stepCtrl.getPosSize()[2] + 16 self.isHorizontalCheck = CheckBox( (jumpin_X, 0, 32, vanillaControlsSize['CheckBoxRegularHeight']), "H", value=self.isHorizontal, callback=self.isHorizontalCheckCallback) jumpin_X += self.isHorizontalCheck.getPosSize()[2] + 2 self.isVerticalCheck = CheckBox( (jumpin_X, 0, 32, vanillaControlsSize['CheckBoxRegularHeight']), "V", value=self.isVertical, callback=self.isVerticalCheckCallback) jumpin_X += self.isVerticalCheck.getPosSize()[2] + 10 self.whichColorWell = ColorWell( (jumpin_X, 0, 46, self.ctrlHeight), color=NSColor.colorWithCalibratedRed_green_blue_alpha_(*gridColor), callback=self.whichColorWellCallback)
def __init__(self): NSUserDefaults.standardUserDefaults().registerDefaults_({"ToucheWindowHeight":340}) self.windowHeight = NSUserDefaults.standardUserDefaults().integerForKey_("ToucheWindowHeight") self.minWindowHeight = 340 if self.windowHeight < self.minWindowHeight: self.windowHeight = self.minWindowHeight self.closedWindowHeight = 100 self.w = FloatingWindow((180, self.windowHeight), u'Touché!', minSize=(180,340), maxSize=(250,898)) self.w.bind("resize", self.windowResized) self.isResizing = False p = 10 w = 160 # options self.w.options = Group((0, 0, 180, 220)) buttons = { "checkSelBtn": {"text": "Check selected glyphs", "callback": self.checkSel, "y": p}, } for button, data in buttons.iteritems(): setattr(self.w.options, button, Button((p, data["y"], w - 22, 22), data["text"], callback=data["callback"], sizeStyle="small")) self.w.options.zeroCheck = CheckBox((p, 35, w, 20), "Ignore zero-width glyphs", value=True, sizeStyle="small") self.w.options.progress = ProgressSpinner((w - 8, 13, 16, 16), sizeStyle="small") # results self.w.results = Group((0, 220, 180, -0)) self.w.results.show(False) textBoxes = {"stats": -34, "result": -18} for box, y in textBoxes.iteritems(): setattr(self.w.results, box, TextBox((p, y, w, 14), "", sizeStyle="small")) # list and preview self.w.outputList = List((0,58,-0,-40), [{"left glyph": "", "right glyph": ""}], columnDescriptions=[{"title": "left glyph", "width": 90}, {"title": "right glyph"}], showColumnTitles=False, allowsMultipleSelection=False, enableDelete=False, selectionCallback=self.showPair) self.w.outputList._setColumnAutoresizing() self._resizeWindow(False) self.w.open()
def _testWind(): win = Window((20, 200, 200, 270), minSize=(200, 270), title="Docked Window Demo") win.color = Group((0, 0, -0, -0)) win.color.txt = TextBox((0, 0, -0, -0), f"demo window {globals()['testNum']}", alignment='center') globals()['testNum'] = globals()['testNum'] + 1 # win.color.getNSView().setWantsLayer_(True) # win.color.getNSView().layer().setBackgroundColor_(color.CGColor()) # win.btn = GradientButton((10, 10, 50, 50), # title="❏", sizeStyle='regular') return win
def __init__(self, posSize, sqrActive, bcpLengthActive, callback): Group.__init__(self, posSize) self.ctrlHeight = posSize[3] self.sqrActive = sqrActive self.bcpLengthActive = bcpLengthActive self.callback = callback jumpin_Y = 2 self.sqrCheck = CheckBox( (0, jumpin_Y, NET_WIDTH, vanillaControlsSize['CheckBoxRegularHeight']), "Show squarings", value=self.sqrActive, callback=self.sqrCheckCallback) jumpin_Y += vanillaControlsSize['CheckBoxRegularHeight'] self.bcpLengthCheck = CheckBox( (0, jumpin_Y, NET_WIDTH, vanillaControlsSize['CheckBoxRegularHeight']), "Show bcp length", value=self.bcpLengthActive, callback=self.bcpLengthCheckCallback)
def __init__(self, posSize, title, isActive, openedFontPaths, activeFontPath, activeGlyphName, callback): Group.__init__(self, posSize) self.isActive = isActive self.openedFontPaths = openedFontPaths self.activeFontPath = activeFontPath self.activeGlyphName = activeGlyphName self.callback = callback ctrlWidth = posSize[2] # ui jumpingY = 4 self.isActiveCheck = CheckBox( (0, jumpingY, ctrlWidth, vanillaControlsSize['CheckBoxRegularHeight']), title, value=self.isActive, callback=self.isActiveCallback) jumpingY += vanillaControlsSize['CheckBoxRegularHeight'] + 2 self.fontPop = PopUpButton( (1, jumpingY, ctrlWidth - 1, vanillaControlsSize['PopUpButtonRegularHeight']), makeFontList(openedFontPaths), callback=self.fontPopCallback) jumpingY += vanillaControlsSize['PopUpButtonRegularHeight'] + MARGIN_VER if self.activeFontPath == CURRENT_FONT_REPR: activeFont = CurrentFont() else: activeFont = getOpenedFontFromPath(AllFonts(), self.activeFontPath) self.glyphPop = PopUpButton( (1, jumpingY, ctrlWidth - 1, vanillaControlsSize['ComboBoxRegularHeight']), makeGlyphList(activeFont), callback=self.glyphPopCallback)
def initUI(self): self.prevSelection = [0] w, h = self.minSize self.w = HUDFloatingWindow((0, 0, w, h),self.windowTitle,minSize=self.minSize,autosaveName=key) self.w.getNSWindow().setHasShadow_(False) columnInfo = [ dict(title='icon', cell=ImageListCell(), width=self.rowHeight+self.rowHeight/8), dict(title='tool', cell=VerticallyCenteredTextFieldCell('mini'), editable=False), dict(title='active', cell=CheckBoxListCell(), editable=True, width=17), ] self.w.palette = Group((0,0,-0,-0)) self.w.palette.list = List((0,0,-0,-66),[], columnDescriptions=columnInfo, rowHeight=self.rowHeight, selectionCallback=self.selectionCallback,showColumnTitles=False, allowsEmptySelection=True, allowsMultipleSelection=False, drawHorizontalLines=True,drawFocusRing=True,editCallback=self.listChangedCallback)#,dragSettings=dict(type=toolOrderDragType, callback=self.dragCallback), selfDropSettings=dict(type=toolOrderDragType, operation=NSDragOperationMove, callback=self.dropListSelfCallback)) self.selectionCallback(self.w.palette.list) self.w.palette.openSettings = GradientButton((5,-66+5,-5,-5),imageNamed=NSImageNameActionTemplate,sizeStyle='mini',callback=self.openSettingsCallback) self.w.settings = Group((-self.settingsWidth,0,self.settingsWidth,-0)) columnInfo = [ dict(title='hotkey', editable=True), dict(title='modifier',cell=PopUpButtonListCell(self.modifiers), binding="selectedValue") ] self.w.settings.list = List((5,0,-0,-66),[], columnDescriptions=columnInfo, rowHeight=self.rowHeight, showColumnTitles=False, allowsEmptySelection=True, allowsMultipleSelection=False, drawVerticalLines=True, drawFocusRing=True,editCallback=self.hotkeyEditCallback) self.w.settings.hideToolbar = CheckBox((5,-66+5,-5,15),'hide toolbar',sizeStyle='mini', callback=self.hideToolbarCallback,value=self.hideToolbar) # self.w.settings.sortDefaulr = SquareButton((self.settingsWidth/2+2.5,-66+5,-5,15),'sort default bar',sizeStyle='mini',callback=self.sortDefaultToolsCallback) self.w.settings.showOnLaunchChB = CheckBox((5,-44+5,-5,15),'show on launch',sizeStyle='mini', callback=self.showOnLaunchCallback,value=self.showOnLaunch) self.w.settings.exportBtn = SquareButton((5,-22+2,self.settingsWidth/2-5-2.5,15),'export prefs',sizeStyle='mini',callback=self.exportImportCallback) self.w.settings.importBtn = SquareButton((self.settingsWidth/2+2.5,-22+2,-5,15),'import prefs',sizeStyle='mini',callback=self.exportImportCallback) self.w.settings.show(False) self.hideToolbarCallback(self.w.settings.hideToolbar) self._rebuildToolPalette() self.w.palette.list.setSelection(self.prevSelection) self.w.bind('close', self.windowClose) self.w.bind('resize', self.windowResize) self.windowResize(self.w) self.w.open()
def __init__(self, font): self.font = font self.recipients = FontRecipients(self.font) if 'pm.ghostlines.ghostlines.registry_token' in self.font.lib: self.roster_token = self.font.lib[ 'pm.ghostlines.ghostlines.registry_token'] else: self.roster_token = None self.window.content = Group((15, 15, -15, -15)) self.window.content.font_name_label = TextBox((0, 0, -0, 22), "Font Name", sizeStyle="small") self.window.content.font_name = TextBox((0, 19, -0, 22), self.font.info.familyName) self.window.content.font_author_label = TextBox((0, 55, -0, 22), "Designer", sizeStyle="small") self.window.content.font_author = TextBox( (0, 74, -0, 22), self.font.info.openTypeNameDesigner) self.window.content.recipients_label = TextBox((0, 114, -15, 22), "Subscribers", sizeStyle="small") self.window.content.recipients = List((0, 135, -0, 190), self.recipients, drawFocusRing=False, allowsEmptySelection=True) self.window.content.recipients.setSelection([]) self.window.content.roster_label = TextBox((0, 350, -15, 22), "Application Page", sizeStyle="small") self.window.content.roster_status = TextBox((0, 370, -15, 22), self.roster_status) self.window.content.confirmation_button = Button((0, -24, 0, 24), "Complete Migration", callback=self.migrate) self.window.content.explainer = TextBox( (0, 405, -15, 66), "A new font entry will be created on Ghostlines with the details above. Any pending applicants will be retained if you have activated that feature.", sizeStyle="small") self.window.setDefaultButton(self.window.content.confirmation_button)
def __init__(self): self.modifiedGlyph = None self.w = FloatingWindow((400, 170), 'Corner Tool') self.w.getNSWindow().setBackgroundColor_(NSColor.whiteColor()) self.modes = ['Break', 'Build','Pit'] self.objectTypes = {'Build':'Segment', 'Break':'Corner point', 'Pit':'Corner point'} self.parameters = { 'radius': VanillaSingleValueParameter('radius', 20, (-200, 200), numType='int'), 'roundness': VanillaSingleValueParameter('roundness', 1.25, (0, 4), numType='float'), 'depth': VanillaSingleValueParameter('depth', 30, (-100, 100), numType='int'), 'breadth': VanillaSingleValueParameter('breadth', 30, (0, 150), numType='int'), 'bottom': VanillaSingleValueParameter('bottom', 5, (0, 40), numType='int') } self.currentMode = 'Break' self.previewGlyph = None self.w.modes = RadioGroup((15, 15, 70, -15), self.modes, callback=self.changeMode) for i, mode in enumerate(self.modes): setattr(self.w, mode, Group((120, 15, -15, -15))) modeGroup = getattr(self.w, mode) modeGroup.apply = GradientButton((-35, 0, -0, -0), title=u'>', callback=self.apply) modeGroup.infoBox = Box((0, 0, -50, 35)) modeGroup.info = TextBox((10, 8, -50, 20), 'No selection') if i > 0: modeGroup.show(False) self.w.Break.radius = ParameterSliderTextInput(self.parameters['radius'], (0, 60, -25, 25), title='Radius', callback=self.makePreviewGlyph) self.w.Break.roundness = ParameterSliderTextInput(self.parameters['roundness'], (0, 95, -25, 25), title='Roundness', callback=self.makePreviewGlyph) self.w.Pit.depth = ParameterSliderTextInput(self.parameters['depth'], (0, 50, -25, 25), title='Depth', callback=self.makePreviewGlyph) self.w.Pit.breadth = ParameterSliderTextInput(self.parameters['breadth'], (0, 80, -25, 25), title='Breadth', callback=self.makePreviewGlyph) self.w.Pit.bottom = ParameterSliderTextInput(self.parameters['bottom'], (0, 110, -25, 25), title='bottom', callback=self.makePreviewGlyph) addObserver(self, 'preview', 'draw') addObserver(self, 'preview', 'drawInactive') addObserver(self, 'previewSolid', 'drawPreview') addObserver(self, 'makePreviewGlyph', 'mouseDown') addObserver(self, 'makePreviewGlyph', 'mouseDragged') addObserver(self, 'makePreviewGlyph', 'keyDown') addObserver(self, 'makePreviewGlyph', 'keyUp') addObserver(self, 'setControls', 'mouseUp') addObserver(self, 'setControls', 'selectAll') addObserver(self, 'setControls', 'deselectAll') addObserver(self, 'setControls', 'currentGlyphChanged') self.w.bind('close', self.windowClose) self.setControls() self.w.open()
def loadPlugin(self): self.menuName = "Italic Extremes" self.actionButtonLabel = 'Add Nodes' self.keyboardShortcut = None windowWidth = 300 windowHeight = 120 m, h, yPos = 10, 18, 10 self.w = FloatingWindow((windowWidth, windowHeight)) self.w.group = Group((0, 0, windowWidth, windowHeight)) self.w.group.angle = EditText((m, yPos, -50, h), "", placeholder='Angles', sizeStyle='small', callback=self.editAngles_callback, continuous=True) self.w.group.refresh = Button((-40, yPos, -m, h), u"↺", callback=self.revertAngles_callback) yPos += m + h self.w.group.tabs = Tabs((m, yPos, -m, -m), ["Add slanted nodes", "Add H/V extremes"], callback=self.tab_callback) self.tab1 = self.w.group.tabs[0] self.tab1.removeV = CheckBox((m, 0, -m, h), "Delete vertical extremes", sizeStyle='small', value=False, callback=self.removeV_callback) yPos = h self.tab1.removeH = CheckBox((m, yPos, -m, h), "Delete horizontal extremes", sizeStyle='small', value=False, callback=self.removeH_callback) self.tab2 = self.w.group.tabs[1] yPos = 0 self.tab2.removeI = CheckBox((m, yPos, -m, h), "Delete slanted nodes", sizeStyle='small', value=False, callback=self.removeI_callback) self.dialog = self.w.group.getNSView()
def showWindow_(self, sender): try: from vanilla import Group, Slider, TextBox, Window self.windowWidth = 300 self.windowHeight = 240 self.w = Window((self.windowWidth, self.windowWidth), "Rotate View", minSize=(self.windowWidth, self.windowWidth)) window = self.w.getNSWindow() window.setStyleMask_(window.styleMask() | NSFullSizeContentViewWindowMask) try: # only available in 10.10 window.setTitlebarAppearsTransparent_(True) except: pass #window.toolbar = nil; window.setMovableByWindowBackground_(True) self.w.Preview = RoatatePreview((0, 0, -0, -28)) self.w.controlBox = Group((0, -28, -0, -0)) self.w.controlBox.slider = Slider((10, 2, -55, 28), tickMarkCount=17, callback=self.sliderCallback, value=0, minValue=-360, maxValue=360) self.w.controlBox.textBox = TextBox((-55, -23, -5, -3), text="0°", alignment="center") self.w.controlBox.slider.getNSSlider().setEnabled_(False) self.w.open() self.changeGlyph_(None) Glyphs.addCallback( self.changeGlyph_, UPDATEINTERFACE ) #will be called on ever change to the interface except: print(traceback.format_exc())
class AdjustAnchors(BaseWindowController): def __init__(self): self.font = CurrentFont() self.glyph = CurrentGlyph() self.upm = self.font.info.unitsPerEm self.glyphPreviewCacheDict = {} # key: glyph name -- value: list containing assembled glyphs self.anchorsOnMarksDict = {} # key: anchor name -- value: list of mark glyph names self.anchorsOnBasesDict = {} # key: anchor name -- value: list of base glyph names self.marksDict = {} # key: mark glyph name -- value: anchor name (NOTE: It's expected that each mark glyph only has one type of anchor) self.fillAnchorsAndMarksDicts() self.glyphNamesList = [] # list of glyph names that will be displayed in the UI list self.selectedGlyphNamesList = [] # list of glyph names selected in the UI list self.extraGlyphsList = [] # list of the glyph objects that should be inserted before and after the accented glyphs self.Blue, self.Alpha = 1, 0.6 self.font.naked().addObserver(self, "fontWasModified", "Font.Changed") addObserver(self, "_fontWillClose", "fontWillClose") addObserver(self, "_currentFontChanged", "fontResignCurrent") addObserver(self, "_currentGlyphChanged", "currentGlyphChanged") addObserver(self, "_drawFill", "draw") addObserver(self, "_drawFill", "drawInactive") addObserver(self, "_previewFill", "drawPreview") addObserver(self, "_drawGlyphs", "draw") # observer for the draw event addObserver(self, "_drawGlyphs", "drawInactive") # draw the glyphs when the glyph window is not in focus addObserver(self, "_drawGlyphs", "drawPreview") integerNumFormatter = NSNumberFormatter.alloc().init() integerNumFormatter.setAllowsFloats_(False) integerNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter = NSNumberFormatter.alloc().init() intPosMinZeroNumFormatter.setAllowsFloats_(False) intPosMinZeroNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter.setMinimum_(NSNumber.numberWithInt_(0)) intPosMinOneNumFormatter = NSNumberFormatter.alloc().init() intPosMinOneNumFormatter.setAllowsFloats_(False) intPosMinOneNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinOneNumFormatter.setMinimum_(NSNumber.numberWithInt_(1)) self.textSize = getExtensionDefault("%s.%s" % (extensionKey, "textSize")) if not self.textSize: self.textSize = 150 self.lineHeight = getExtensionDefault("%s.%s" % (extensionKey, "lineHeight")) if not self.lineHeight: self.lineHeight = 200 self.extraSidebearings = getExtensionDefault("%s.%s" % (extensionKey, "extraSidebearings")) if not self.extraSidebearings: self.extraSidebearings = [0, 0] self.extraGlyphs = getExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs")) if not self.extraGlyphs: self.extraGlyphs = '' posSize = getExtensionDefault("%s.%s" % (extensionKey, "posSize")) if not posSize: posSize = (100, 100, 1200, 400) self.calibrateMode = getExtensionDefault("%s.%s" % (extensionKey, "calibrateMode")) if not self.calibrateMode: self.calibrateMode = False calibrateModeStrings = getExtensionDefault("%s.%s" % (extensionKey, "calibrateModeStrings")) if not calibrateModeStrings: calibrateModeStrings = { 'group1.baseInput': 'dotlessi o s', 'group1.markInput': 'dieresis circumflex macron breve caron', 'group2.baseInput': 'I O S', 'group2.markInput': 'dieresis.cap circumflex.cap macron.cap breve.cap caron.cap', 'group3.baseInput': 'I.sc O.sc S.sc', 'group3.markInput': 'dieresis circumflex macron breve caron', 'group4.baseInput': '', 'group4.markInput': '', } # -- Window -- self.w = FloatingWindow(posSize, extensionName, minSize=(500, 400)) self.w.fontList = List((10, 10, 190, -41), self.glyphNamesList, selectionCallback=self.listSelectionCallback) if roboFontVersion < '1.7': self.w.fontList.getNSTableView().sizeToFit() # use the full width of the column self.w.fontList.show(not self.calibrateMode) self.w.lineView = MultiLineView((210, 10, -10, -41), pointSize = self.textSize, lineHeight = self.lineHeight, displayOptions={"Beam" : False, "displayMode" : "Multi Line"} ) # -- Calibration Mode -- baseLabel = "Bases" markLabel = "Marks" width, height = 190, 140 self.cm = Group((0, 0, 0, 0)) # --- self.cm.group1 = Group((5, height*0, width, height-10)) self.cm.group1.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group1.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group1.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group1.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group1.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group2 = Group((5, height*1, width, height-10)) self.cm.group2.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group2.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group2.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group2.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group2.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group3 = Group((5, height*2, width, height-10)) self.cm.group3.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group3.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group3.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group3.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group3.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group4 = Group((5, height*3, width, height-10)) self.cm.group4.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group4.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group4.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group4.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group4.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group4.markInput'], callback=self.updateCalibrateMode, continuous=False) # --- view = DefconAppKitTopAnchoredNSView.alloc().init() view.addSubview_(self.cm.getNSView()) view.setFrame_(((0, 0), (width+10, height*4-23))) self.cm.setPosSize((0, 0, width+10, height*4-22)) self.w.scrollView = ScrollView((5, 10, width+10, -41), view, drawsBackground=False, hasHorizontalScroller=False) self.w.scrollView.getNSScrollView().setBorderType_(NSNoBorder) self.w.scrollView.getNSScrollView().setVerticalScrollElasticity_(1) # NSScrollElasticityNone self.w.scrollView.show(self.calibrateMode) # -- Footer -- self.w.calibrateModeCheck = CheckBox((10, -32, 200, -10), "Calibration Mode", callback=self.calibrateModeCallback, value=self.calibrateMode) self.w.textSizeLabel = TextBox((210, -30, 100, -10), "Text Size") self.w.textSize = EditText((270, -32, 35, -10), self.textSize, callback=self.textSizeCallback, continuous=False, formatter=intPosMinOneNumFormatter) self.w.lineHeightLabel = TextBox((320, -30, 100, -10), "Line Height") self.w.lineHeight = EditText((395, -32, 35, -10), self.lineHeight, callback=self.lineHeightCallback, continuous=False, formatter=integerNumFormatter) self.w.extraSidebearingsLabel = TextBox((446, -30, 180, -10), "Extra Sidebearings") self.w.extraSidebearingsChar = TextBox((602, -30, 20, -10), "&") self.w.extraSidebearingLeft = EditText((567, -32, 35, -10), self.extraSidebearings[0], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.extraSidebearingRight = EditText((614, -32, 35, -10), self.extraSidebearings[1], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.extraGlyphsLabel = TextBox((665, -30, 180, -10), "Extra Glyphs") self.w.extraGlyphs = EditText((749, -32, -10, -10), self.extraGlyphs, callback=self.extraGlyphsCallback, continuous=False) # trigger the initial state and contents of the window self.extraGlyphsCallback() # this will call self.updateExtensionWindow() self.w.bind("close", self.windowClose) self.w.open() self.w.makeKey() def calibrateModeCallback(self, sender): self.calibrateMode = not self.calibrateMode self.w.fontList.show(not sender.get()) self.w.scrollView.show(self.calibrateMode) self.updateExtensionWindow() def textSizeCallback(self, sender): try: # in case the user submits an empty field self.textSize = int(sender.get()) except: # reset to the previous value NSBeep() self.sender.set(self.textSize) self.w.lineView.setPointSize(self.textSize) def lineHeightCallback(self, sender): try: self.lineHeight = int(sender.get()) except: NSBeep() self.sender.set(self.lineHeight) self.w.lineView.setLineHeight(self.lineHeight) def extraSidebearingsCallback(self, sender): left = self.w.extraSidebearingLeft right = self.w.extraSidebearingRight try: self.extraSidebearings = [int(left.get()), int(right.get())] except: NSBeep() left.set(self.extraSidebearings[0]) right.set(self.extraSidebearings[1]) self.extraGlyphsCallback() # this will call self.updateExtensionWindow() def extraGlyphsCallback(self, *sender): del self.extraGlyphsList[:] # empty the list self.extraGlyphs = self.w.extraGlyphs.get() glyphNamesList = self.extraGlyphs.split() for gName in glyphNamesList: try: extraGlyph = self.font[gName] # must create a new glyph in order to be able to increase the sidebearings without modifying the font newGlyph = RGlyph() newGlyph.setParent(self.font) # must use deepAppend because the extra glyph may have components (which will cause problems to the MultiLineView) newGlyph = self.deepAppendGlyph(newGlyph, extraGlyph) newGlyph.width = extraGlyph.width except RoboFontError: continue newGlyph.leftMargin += self.extraSidebearings[0] newGlyph.rightMargin += self.extraSidebearings[1] self.extraGlyphsList.append(newGlyph) self.glyphPreviewCacheDict.clear() self.updateExtensionWindow() def windowClose(self, sender): self.font.naked().removeObserver(self, "Font.Changed") removeObserver(self, "fontWillClose") removeObserver(self, "fontResignCurrent") removeObserver(self, "currentGlyphChanged") removeObserver(self, "draw") removeObserver(self, "drawInactive") removeObserver(self, "drawPreview") self.saveExtensionDefaults() def getCalibrateModeStrings(self): calibrateModeStringsDict = {} for i in range(1,5): group = getattr(self.cm, "group%d" % i) calibrateModeStringsDict["group%d.baseInput" % i] = group.baseInput.get() calibrateModeStringsDict["group%d.markInput" % i] = group.markInput.get() return calibrateModeStringsDict def saveExtensionDefaults(self): setExtensionDefault("%s.%s" % (extensionKey, "posSize"), self.w.getPosSize()) setExtensionDefault("%s.%s" % (extensionKey, "textSize"), self.textSize) setExtensionDefault("%s.%s" % (extensionKey, "lineHeight"), self.lineHeight) setExtensionDefault("%s.%s" % (extensionKey, "extraSidebearings"), self.extraSidebearings) setExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs"), self.extraGlyphs) setExtensionDefault("%s.%s" % (extensionKey, "calibrateMode"), self.calibrateMode) setExtensionDefault("%s.%s" % (extensionKey, "calibrateModeStrings"), self.getCalibrateModeStrings()) def _previewFill(self, info): self.Blue, self.Alpha = 0, 1 def _drawFill(self, info): self.Blue, self.Alpha = 1, 0.6 def _fontWillClose(self, info): """ Close the window when the last font is closed """ if len(AllFonts()) < 2: self.windowClose(self) self.w.close() def _currentFontChanged(self, info): self.font.naked().removeObserver(self, "Font.Changed") self.font = CurrentFont() self.font.naked().addObserver(self, "fontWasModified", "Font.Changed") self.fillAnchorsAndMarksDicts() del self.glyphNamesList[:] del self.selectedGlyphNamesList[:] self.updateExtensionWindow() def _currentGlyphChanged(self, info): self.updateExtensionWindow() def fontWasModified(self, info): OutputWindow().clear() self.fillAnchorsAndMarksDicts() del self.glyphNamesList[:] del self.selectedGlyphNamesList[:] self.updateExtensionWindow() def deepAppendGlyph(self, glyph, gToAppend, offset=(0,0)): if not gToAppend.components: glyph.appendGlyph(gToAppend, offset) else: for component in gToAppend.components: compGlyph = self.font[component.baseGlyph].copy() # handle component transformations componentTransformation = component.transformation # when undoing a paste anchor or a delete anchor action, RoboFont returns component.transformation as a list instead of a tuple if type(componentTransformation) is list: componentTransformation = tuple(componentTransformation) if componentTransformation != (1, 0, 0, 1, 0, 0): # if component is skewed and/or is shifted matrix = componentTransformation[0:4] if matrix != (1, 0, 0, 1): # if component is skewed transformObj = Identity.transform(matrix + (0, 0)) # ignore the original component's shifting values compGlyph.transform(transformObj) glyph.appendGlyph(compGlyph, map(sum, zip(component.offset, offset))) # add the two tuples of offset for contour in gToAppend: glyph.appendContour(contour, offset) # if the assembled glyph still has components, recursively remove and replace them 1-by-1 by the glyphs they reference if glyph.components: nestedComponent = glyph.components[-1] # start from the end glyph.removeComponent(nestedComponent) glyph = self.deepAppendGlyph(glyph, self.font[nestedComponent.baseGlyph], nestedComponent.offset) return glyph def updateCalibrateMode(self, *sender): glyphsList = [] newLine = self.w.lineView.createNewLineGlyph() # cycle thru the UI Groups and collect the strings for i in range(1,5): group = getattr(self.cm, "group%d" % i) baseGlyphsNamesList = group.baseInput.get().split() markGlyphsNamesList = group.markInput.get().split() # iterate thru the base+mark combinations for gBaseName, gMarkName in product(baseGlyphsNamesList, markGlyphsNamesList): newGlyph = RGlyph() newGlyph.setParent(self.font) # skip invalid glyph names try: baseGlyph = self.font[gBaseName] markGlyph = self.font[gMarkName] except RoboFontError: continue # append base glyph newGlyph = self.deepAppendGlyph(newGlyph, baseGlyph) # append mark glyph newGlyph = self.deepAppendGlyph(newGlyph, markGlyph, self.getAnchorOffsets(baseGlyph, markGlyph)) # set the advanced width dfltSidebearings = self.upm * .05 # 5% of the UPM newGlyph.leftMargin = dfltSidebearings + self.extraSidebearings[0] newGlyph.rightMargin = dfltSidebearings + self.extraSidebearings[1] # append the assembled glyph to the list glyphsList.extend(self.extraGlyphsList) glyphsList.append(newGlyph) # add line break, if both input fields have content if baseGlyphsNamesList and markGlyphsNamesList: glyphsList.extend(self.extraGlyphsList) glyphsList.append(newLine) # update the contents of the MultiLineView self.w.lineView.set(glyphsList) def updateExtensionWindow(self): if self.calibrateMode: self.updateCalibrateMode() return if CurrentGlyph() is not None: # NOTE: CurrentGlyph() will return zero (its length), so "is not None" is necessary self.glyph = CurrentGlyph() self.glyphNamesList = self.makeGlyphNamesList(self.glyph) self.updateListView() currentGlyphName = self.glyph.name # base glyph + accent combinations preview # first check if there's a cached glyph if currentGlyphName in self.glyphPreviewCacheDict: self.w.lineView.set(self.glyphPreviewCacheDict[currentGlyphName]) # assemble the glyphs else: glyphsList = [] for glyphNameInUIList in self.glyphNamesList: newGlyph = RGlyph() newGlyph.setParent(self.font) # the glyph in the UI list is a mark if glyphNameInUIList in self.marksDict: markGlyph = self.font[glyphNameInUIList] # append base glyph newGlyph = self.deepAppendGlyph(newGlyph, self.glyph) # append mark glyph newGlyph = self.deepAppendGlyph(newGlyph, markGlyph, self.getAnchorOffsets(self.glyph, markGlyph)) # set the advanced width if self.glyph.width < 10: # combining marks or other glyphs with a small advanced width newGlyph.leftMargin = self.upm * .05 # 5% of the UPM newGlyph.rightMargin = newGlyph.leftMargin else: newGlyph.width = self.glyph.width # the glyph in the UI list is a base else: baseGlyph = self.font[glyphNameInUIList] # append base glyph newGlyph = self.deepAppendGlyph(newGlyph, baseGlyph) # append mark glyph newGlyph = self.deepAppendGlyph(newGlyph, self.glyph, self.getAnchorOffsets(baseGlyph, self.glyph)) # set the advanced width if self.glyph.width < 10: # combining marks or other glyphs with a small advanced width newGlyph.leftMargin = self.upm * .05 newGlyph.rightMargin = newGlyph.leftMargin else: newGlyph.width = baseGlyph.width # pad the new glyph if it has too much overhang if newGlyph.leftMargin < self.upm * .15: newGlyph.leftMargin = self.upm * .05 if newGlyph.rightMargin < self.upm * .15: newGlyph.rightMargin = self.upm * .05 # add extra sidebearings newGlyph.leftMargin += self.extraSidebearings[0] newGlyph.rightMargin += self.extraSidebearings[1] # one last check for making sure the new glyph can be displayed if not newGlyph.components: glyphsList.extend(self.extraGlyphsList) glyphsList.append(newGlyph) else: print "Combination with mark glyph %s can't be previewed because it contains component %s." % (glyphNameInUIList, newGlyph.components[0].baseGlyph) glyphsList.extend(self.extraGlyphsList) self.w.lineView.set(glyphsList) # add to the cache self.glyphPreviewCacheDict[currentGlyphName] = glyphsList else: self.w.lineView.set([]) def listSelectionCallback(self, sender): selectedGlyphNamesList = [] for index in sender.getSelection(): selectedGlyphNamesList.append(self.glyphNamesList[index]) self.selectedGlyphNamesList = selectedGlyphNamesList self.updateGlyphView() def updateGlyphView(self): # update the current glyph view UpdateCurrentGlyphView() def fillAnchorsAndMarksDicts(self): # reset all the dicts self.glyphPreviewCacheDict.clear() self.anchorsOnMarksDict.clear() self.anchorsOnBasesDict.clear() self.marksDict.clear() markGlyphsWithMoreThanOneAnchorTypeList = [] for glyphName in self.font.glyphOrder: glyphAnchorsList = self.font[glyphName].anchors for anchor in glyphAnchorsList: if anchor.name[0] == '_': anchorName = anchor.name[1:] # add to AnchorsOnMarks dictionary if anchorName not in self.anchorsOnMarksDict: self.anchorsOnMarksDict[anchorName] = [glyphName] else: tempList = self.anchorsOnMarksDict[anchorName] tempList.append(glyphName) self.anchorsOnMarksDict[anchorName] = tempList # add to Marks dictionary if glyphName not in self.marksDict: self.marksDict[glyphName] = anchorName else: if glyphName not in markGlyphsWithMoreThanOneAnchorTypeList: markGlyphsWithMoreThanOneAnchorTypeList.append(glyphName) else: anchorName = anchor.name # add to AnchorsOnBases dictionary if anchorName not in self.anchorsOnBasesDict: self.anchorsOnBasesDict[anchorName] = [glyphName] else: tempList = self.anchorsOnBasesDict[anchorName] tempList.append(glyphName) self.anchorsOnBasesDict[anchorName] = tempList if markGlyphsWithMoreThanOneAnchorTypeList: for glyphName in markGlyphsWithMoreThanOneAnchorTypeList: print "ERROR: Glyph %s has more than one type of anchor." % glyphName def makeGlyphNamesList(self, glyph): glyphNamesList = [] markGlyphIsAbleToBeBase = False if glyph is not None: # NOTE: "if glyph" will return zero (its length), so "is not None" is necessary # assemble the list for the UI list for anchor in glyph.anchors: anchorName = anchor.name if anchorName in self.anchorsOnMarksDict: glyphNamesList.extend(self.anchorsOnMarksDict[anchorName]) elif anchorName[1:] in self.anchorsOnBasesDict: # skips the leading underscore glyphNamesList.extend(self.anchorsOnBasesDict[anchorName[1:]]) # for mark glyphs, test if they're able to get other mark glyphs attached to them # this will (correctly) prevent the UI list from including glyph names that cannot be displayed with the current glyph if glyph.name in self.marksDict: for anchor in glyph.anchors: if anchor.name[0] != '_': # the current mark glyph has anchors that allow it to be a base for other marks markGlyphIsAbleToBeBase = True break # remove marks from the glyph list if the current mark glyph can't work as a base if not markGlyphIsAbleToBeBase: for glyphName in glyphNamesList[::-1]: # iterate from the end of the list if glyphName in self.marksDict: glyphNamesList.remove(glyphName) return glyphNamesList def updateListView(self): self.w.fontList.set(self.glyphNamesList) def getAnchorOffsets(self, canvasGlyph, glyphToDraw): # the current glyph is a mark if canvasGlyph.name in self.marksDict: # glyphToDraw is also a mark (mark-to-mark case) if glyphToDraw.name in self.marksDict: # pick the (mark glyph) anchor to draw on for anchor in canvasGlyph.anchors: if anchor.name[0] != '_': anchorName = anchor.name markAnchor = anchor break # pick the (base glyph) anchor to draw on for anchor in glyphToDraw.anchors: try: if anchor.name == '_'+ anchorName: baseAnchor = anchor break except UnboundLocalError: continue # glyphToDraw is not a mark else: # pick the (mark glyph) anchor to draw on for anchor in canvasGlyph.anchors: if anchor.name[0] == '_': anchorName = anchor.name[1:] markAnchor = anchor break # pick the (base glyph) anchor to draw on for anchor in glyphToDraw.anchors: try: if anchor.name == anchorName: baseAnchor = anchor break except UnboundLocalError: continue try: offsetX = markAnchor.x - baseAnchor.x offsetY = markAnchor.y - baseAnchor.y except UnboundLocalError: offsetX = 0 offsetY = 0 # the current glyph is a base else: try: anchorName = self.marksDict[glyphToDraw.name] except KeyError: anchorName = None if anchorName: # pick the (base glyph) anchor to draw on for anchor in canvasGlyph.anchors: if anchor.name == anchorName: baseAnchor = anchor break # pick the (mark glyph) anchor to draw on for anchor in glyphToDraw.anchors: if anchor.name == '_'+ anchorName: markAnchor = anchor break try: offsetX = baseAnchor.x - markAnchor.x offsetY = baseAnchor.y - markAnchor.y except UnboundLocalError: offsetX = 0 offsetY = 0 return (offsetX, offsetY) def _drawGlyphs(self, info): """ draw stuff in the glyph window view """ translateBefore = (0, 0) for glyphName in self.selectedGlyphNamesList: glyphToDraw = self.font[glyphName] # determine the offset of the anchors offset = self.getAnchorOffsets(self.glyph, glyphToDraw) # set the offset of the drawing translate(offset[0] - translateBefore[0], offset[1] - translateBefore[1]) # record the shift amounts (these are needed for resetting the drawing position when more than one mark is selected on the list) translateBefore = offset # set the fill & stroke fill(0, 0, self.Blue, self.Alpha) strokeWidth(None) # draw it mojoPen = MojoDrawingToolsPen(glyphToDraw, self.font) glyphToDraw.draw(mojoPen) mojoPen.draw()
def updateControls(self): if self.currentFilterName is not None: if hasattr(self.w.filtersPanel, 'controls'): delattr(self.w.filtersPanel, 'controls') currentFilter = self.filters[self.currentFilterName] self.w.filtersPanel.controls = Group((0, 0, 0, 0)) hasSubfilters = self.filters.hasSubfilters(self.currentFilterName) if hasSubfilters: argumentBlocks = [(subfilterName, self.filters[subfilterName].arguments) for subfilterName, mode, source in currentFilter.subfilters] else: argumentBlocks = [(currentFilter.name, currentFilter.arguments)] gap = 5 height = gap end = 0 lineheight = 27 top = 35 boxes = 0 for j, (filterName, arguments) in enumerate(argumentBlocks): if len(arguments) > 0: blockfilterName = '{0}{1}'.format(filterName, j) setattr(self.w.filtersPanel.controls, blockfilterName, Box((5, 5, 0, 0))) block = getattr(self.w.filtersPanel.controls, blockfilterName) if hasSubfilters: _, filterMode, filterSource = currentFilter.subfilters[j] modes = '({0}) [{1}]'.format(filterMode, filterSource) block.modes = TextBox((-150, 11, -8, 12), modes, alignment='right', sizeStyle='mini') block.title = TextBox((8, 8, -150, 22), filterName.upper()) start = height boxHeight = top for i, (arg, value) in enumerate(arguments.items()): valueType = None if hasSubfilters: argumentName = currentFilter.joinSubfilterArgumentName(filterName, arg, j) if argumentName in currentFilter.arguments: value = currentFilter.arguments[argumentName] else: value = self.filters[filterName].arguments[argumentName] currentFilter.setArgumentValue(argumentName, value) else: argumentName = arg limits = currentFilter.getLimits(argumentName) if limits is None: limits = (0, 100) if isinstance(value, bool): setattr(block, arg, CheckBox((8, top + (i*lineheight), -8, 22), arg, value=value, callback=self.setArgumentValue, sizeStyle='small')) valueType = 'bool' elif isinstance(value, (str, unicode)): setattr(block, arg, EditText((8, top + (i*lineheight), -8, 22), value, callback=self.setArgumentValue, sizeStyle='small')) elif isinstance(value, (int, float)): parameter = VanillaSingleValueParameter(arg, value, limits=limits) setattr(block, arg, ParameterSliderTextInput(parameter, (8, top + (i*lineheight), -8, 22), title=arg, callback=self.setArgumentValue)) control = getattr(block, arg) control.name = argumentName control.type = valueType boxHeight += lineheight boxHeight += 12 block.setPosSize((5, start, -5, boxHeight)) height += boxHeight + gap height += 40 self.w.filtersPanel.filtersList.setPosSize((0, 0, -0, -height)) self.w.filtersPanel.controls.setPosSize((0, -height, -0, -45))
def __init__(self): self.font = CurrentFont() self.glyph = CurrentGlyph() self.upm = self.font.info.unitsPerEm self.glyphPreviewCacheDict = {} # key: glyph name -- value: list containing assembled glyphs self.anchorsOnMarksDict = {} # key: anchor name -- value: list of mark glyph names self.anchorsOnBasesDict = {} # key: anchor name -- value: list of base glyph names self.marksDict = {} # key: mark glyph name -- value: anchor name (NOTE: It's expected that each mark glyph only has one type of anchor) self.fillAnchorsAndMarksDicts() self.glyphNamesList = [] # list of glyph names that will be displayed in the UI list self.selectedGlyphNamesList = [] # list of glyph names selected in the UI list self.extraGlyphsList = [] # list of the glyph objects that should be inserted before and after the accented glyphs self.Blue, self.Alpha = 1, 0.6 self.font.naked().addObserver(self, "fontWasModified", "Font.Changed") addObserver(self, "_fontWillClose", "fontWillClose") addObserver(self, "_currentFontChanged", "fontResignCurrent") addObserver(self, "_currentGlyphChanged", "currentGlyphChanged") addObserver(self, "_drawFill", "draw") addObserver(self, "_drawFill", "drawInactive") addObserver(self, "_previewFill", "drawPreview") addObserver(self, "_drawGlyphs", "draw") # observer for the draw event addObserver(self, "_drawGlyphs", "drawInactive") # draw the glyphs when the glyph window is not in focus addObserver(self, "_drawGlyphs", "drawPreview") integerNumFormatter = NSNumberFormatter.alloc().init() integerNumFormatter.setAllowsFloats_(False) integerNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter = NSNumberFormatter.alloc().init() intPosMinZeroNumFormatter.setAllowsFloats_(False) intPosMinZeroNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter.setMinimum_(NSNumber.numberWithInt_(0)) intPosMinOneNumFormatter = NSNumberFormatter.alloc().init() intPosMinOneNumFormatter.setAllowsFloats_(False) intPosMinOneNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinOneNumFormatter.setMinimum_(NSNumber.numberWithInt_(1)) self.textSize = getExtensionDefault("%s.%s" % (extensionKey, "textSize")) if not self.textSize: self.textSize = 150 self.lineHeight = getExtensionDefault("%s.%s" % (extensionKey, "lineHeight")) if not self.lineHeight: self.lineHeight = 200 self.extraSidebearings = getExtensionDefault("%s.%s" % (extensionKey, "extraSidebearings")) if not self.extraSidebearings: self.extraSidebearings = [0, 0] self.extraGlyphs = getExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs")) if not self.extraGlyphs: self.extraGlyphs = '' posSize = getExtensionDefault("%s.%s" % (extensionKey, "posSize")) if not posSize: posSize = (100, 100, 1200, 400) self.calibrateMode = getExtensionDefault("%s.%s" % (extensionKey, "calibrateMode")) if not self.calibrateMode: self.calibrateMode = False calibrateModeStrings = getExtensionDefault("%s.%s" % (extensionKey, "calibrateModeStrings")) if not calibrateModeStrings: calibrateModeStrings = { 'group1.baseInput': 'dotlessi o s', 'group1.markInput': 'dieresis circumflex macron breve caron', 'group2.baseInput': 'I O S', 'group2.markInput': 'dieresis.cap circumflex.cap macron.cap breve.cap caron.cap', 'group3.baseInput': 'I.sc O.sc S.sc', 'group3.markInput': 'dieresis circumflex macron breve caron', 'group4.baseInput': '', 'group4.markInput': '', } # -- Window -- self.w = FloatingWindow(posSize, extensionName, minSize=(500, 400)) self.w.fontList = List((10, 10, 190, -41), self.glyphNamesList, selectionCallback=self.listSelectionCallback) if roboFontVersion < '1.7': self.w.fontList.getNSTableView().sizeToFit() # use the full width of the column self.w.fontList.show(not self.calibrateMode) self.w.lineView = MultiLineView((210, 10, -10, -41), pointSize = self.textSize, lineHeight = self.lineHeight, displayOptions={"Beam" : False, "displayMode" : "Multi Line"} ) # -- Calibration Mode -- baseLabel = "Bases" markLabel = "Marks" width, height = 190, 140 self.cm = Group((0, 0, 0, 0)) # --- self.cm.group1 = Group((5, height*0, width, height-10)) self.cm.group1.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group1.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group1.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group1.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group1.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group2 = Group((5, height*1, width, height-10)) self.cm.group2.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group2.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group2.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group2.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group2.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group3 = Group((5, height*2, width, height-10)) self.cm.group3.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group3.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group3.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group3.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group3.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group4 = Group((5, height*3, width, height-10)) self.cm.group4.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group4.baseInput = EditText((0, 21, width, 22), calibrateModeStrings['group4.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group4.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group4.markInput = EditText((0, 71, width, 44), calibrateModeStrings['group4.markInput'], callback=self.updateCalibrateMode, continuous=False) # --- view = DefconAppKitTopAnchoredNSView.alloc().init() view.addSubview_(self.cm.getNSView()) view.setFrame_(((0, 0), (width+10, height*4-23))) self.cm.setPosSize((0, 0, width+10, height*4-22)) self.w.scrollView = ScrollView((5, 10, width+10, -41), view, drawsBackground=False, hasHorizontalScroller=False) self.w.scrollView.getNSScrollView().setBorderType_(NSNoBorder) self.w.scrollView.getNSScrollView().setVerticalScrollElasticity_(1) # NSScrollElasticityNone self.w.scrollView.show(self.calibrateMode) # -- Footer -- self.w.calibrateModeCheck = CheckBox((10, -32, 200, -10), "Calibration Mode", callback=self.calibrateModeCallback, value=self.calibrateMode) self.w.textSizeLabel = TextBox((210, -30, 100, -10), "Text Size") self.w.textSize = EditText((270, -32, 35, -10), self.textSize, callback=self.textSizeCallback, continuous=False, formatter=intPosMinOneNumFormatter) self.w.lineHeightLabel = TextBox((320, -30, 100, -10), "Line Height") self.w.lineHeight = EditText((395, -32, 35, -10), self.lineHeight, callback=self.lineHeightCallback, continuous=False, formatter=integerNumFormatter) self.w.extraSidebearingsLabel = TextBox((446, -30, 180, -10), "Extra Sidebearings") self.w.extraSidebearingsChar = TextBox((602, -30, 20, -10), "&") self.w.extraSidebearingLeft = EditText((567, -32, 35, -10), self.extraSidebearings[0], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.extraSidebearingRight = EditText((614, -32, 35, -10), self.extraSidebearings[1], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.extraGlyphsLabel = TextBox((665, -30, 180, -10), "Extra Glyphs") self.w.extraGlyphs = EditText((749, -32, -10, -10), self.extraGlyphs, callback=self.extraGlyphsCallback, continuous=False) # trigger the initial state and contents of the window self.extraGlyphsCallback() # this will call self.updateExtensionWindow() self.w.bind("close", self.windowClose) self.w.open() self.w.makeKey()
def __init__(self, font, document=None): self.font = font self.note_draft_storage = LibStorage(self.font.lib, "releaseNotesDraft") self.license_storage = LibStorage(self.font.lib, "licenseFilepath") self.family_id_storage = LibStorage(self.font.lib, "fontFamilyId") self.subscribers = self.font_family["subscribers"] if document is not None: self.window.assignToDocument(document) self.window.background = Background((301, -52, 299, 52), alpha=0.05) self.window.release_info = Group((315, 15, 270, -15)) self.window.release_info.font_name_label = TextBox((0, 0, -0, 22), "Font Name", sizeStyle="small") self.window.release_info.font_name = TextBox((0, 19, -0, 22), self.font_family["name"]) self.window.release_info.font_author_label = TextBox((0, 60, -0, 22), "Designer", sizeStyle="small") self.window.release_info.font_author = TextBox( (0, 79, -0, 22), self.font_family["designer_name"]) self.window.release_info.version_label = TextBox((0, 120, -0, 22), "Version Number", sizeStyle="small") self.window.release_info.version = TextBox((0, 139, -0, 22), self.font_version) self.window.release_info.notes_field_label = TextBox((0, 176, -0, 22), "Release Notes", sizeStyle="small") self.window.release_info.notes_field = NotesEditor( (0, 198, -0, 175), draft_storage=self.note_draft_storage) self.window.release_info.license_field_label = TextBox( (0, 393, -0, 22), "Attach License", sizeStyle="small") self.window.release_info.license_field = FileUploadField( (0, 410, -0, 22), storage=self.license_storage) self.window.release_info.send_button = CounterButton( (0, -24, -0, 24), ("Send Release to All", "Send Release to {}"), callback=self.send) self.window.release_subscriber_divider = VerticalLine((300, 0, 1, -0)) self.window.subscriber_info = Group((15, 15, 270, -15)) self.window.subscriber_info.subscribers_label = TextBox( (0, 0, -0, 22), "Subscribers", sizeStyle="small") self.window.subscriber_info.subscribers = List( (0, 22, -0, 205), self.subscribers, columnDescriptions=[{ "title": "Name", "key": "name", "editable": False }, { "title": "Email Address", "key": "email_address", "editable": False }], selectionCallback=self.update_send_button) self.window.subscriber_info.subscribers.setSelection([]) self.window.subscriber_info.subscribers_tip = TextBox( (0, 238, -0, 14), "cmd+click to select subset", alignment="right", sizeStyle="small") self.window.subscriber_info.show_subscriber_sheet_button = Button( (0, 233, 30, 24), "+", callback=self.show_subscriber_sheet) self.window.subscriber_info.remove_subscriber_button = Button( (40, 233, 30, 24), "-", callback=self.remove_subscriber) self.window.subscriber_info.applicants = \ ApplicantList((0, 280, 270, 210), self.font_family["applicant_roster"], self.family_id_storage.retrieve(), after_approve=self.refresh_subscribers) self.window.release_releases_divider = VerticalLine((600, 0, 1, -0)) self.window.releases_info = Group((615, 15, 270, -15)) self.window.releases_info.log_label = TextBox((0, 0, -0, 22), "Releases", sizeStyle="small") self.window.releases_info.log = \ ReleaseLog((0, 22, -0, -0), self.font_family["releases"][::-1], columnDescriptions=[ { "title": "Created", "key": "created_at", "editable": False }, { "title": "Version", "key": "version", "editable": False, "width": 50 }, { "title": "# subs.", "key": "subscriber_count", "editable": False, "width": 50 } ]) self.resize_window_for_releases() self.window.bind("became main", self.fetch_applicants)
def settings(self): from vanilla import Group, Slider, TextBox, Window self.name = 'Scrawl' self.slider_value = 1 # current slider value # Create Vanilla window and group with controls viewWidth = 266 viewHeight = 42 self.sliderMenuView = Window((viewWidth, viewHeight)) self.sliderMenuView.group = Group((0, 0, viewWidth, viewHeight)) self.w = self.sliderMenuView.group y = 0 self.w.text = TextBox((20, y, -20, 17), "%s Pen Size" % self.name) y += 18 self.w.pen_size = Slider( (20, y, -60, 24), minValue=1, maxValue=256, value=float(self.slider_value), tickMarkCount=0, # stopOnTickMarks = False, # continuuous = True, callback=self.slider_callback, sizeStyle="small", ) self.w.pen_size_text = TextBox((-50, y + 3, -20, 17), "%s" % default_pen_size) self.generalContextMenus = [ { "view": self.sliderMenuView.group.getNSView() }, { "name": Glyphs.localize({ 'en': u'Delete Scrawl', 'de': u'Gekritzel löschen' }), "action": self.delete_data }, { "name": Glyphs.localize({ 'en': u'Save Scrawl To Background Image', 'de': u'Gekritzel als Hintergrundbild speichern' }), "action": self.save_background }, # { # "name": Glyphs.localize({ # 'en': u'Save current size as master default', # 'de': u'Aktuelle Größe als Master-Standard speichern' # }), # "action": self.save_background # }, ] self.keyboardShortcut = 'c' self.pen_size = default_pen_size self.pixel_size = default_pixel_size self.pixel_ratio = default_pixel_ratio self.rect = NSMakeRect(0, 0, 1000, 1000) self.data = None self.prev_location = None self.erase = False self.mouse_position = None self.layer = None self.needs_save = False self.current_layer = self.get_current_layer()
def __init__(self): self.locations = [ 'User Agents', 'Global Agents', 'Global Daemons', 'System Agents', 'System Daemons' ] self.listItems = [] self.selected = {} # Preferences self.homedir = os.path.expanduser('~') self.prefsFolder = self.homedir + "/Library/Preferences/" self.prefsFile = "de.nelsonfritsch.unicron.plist" if os.path.isfile(self.prefsFolder + self.prefsFile): self.prefs = self._loadPrefs(self) else: self.prefs = dict(showSystemWarning=True, windowStyle='System') self._savePrefs(self) # Preferences Window self.prefsWindow = Window((300, 105), 'Preferences') self.styles = ['System', 'Light', 'Dark'] self.prefsWindow.styleTxt = TextBox((10, 10, -10, 20), "Window Style:") self.prefsWindow.style = PopUpButton((30, 35, -10, 20), self.styles, callback=self.prefsSetStyle) self.prefsWindow.restore = Button((10, 75, -10, 20), 'Restore Warnings', callback=self.prefsRestoreWarnings) # Main Window minsize = 285 self.w = Window((minsize, 400), 'Unicron', closable=True, fullSizeContentView=True, titleVisible=False, minSize=(minsize, minsize), maxSize=(600, 1200), autosaveName="UnicronMainWindow") self.pathList = NSPopUpButton.alloc().initWithFrame_( ((0, 0), (160, 20))) self.pathList.addItemsWithTitles_(self.locations) refreshIcon = NSImage.alloc().initWithSize_((32, 32)) sourceImage = NSImage.imageNamed_(NSImageNameRefreshTemplate) w, h = sourceImage.size() if w > h: diffx = 0 diffy = w - h else: diffx = h - w diffy = 0 maxSize = max([w, h]) refreshIcon.lockFocus() sourceImage.drawInRect_fromRect_operation_fraction_( NSMakeRect(diffx, diffy + 4, 22, 22), NSMakeRect(0, 0, maxSize, maxSize), NSCompositeSourceOver, 1) refreshIcon.unlockFocus() refreshIcon.setTemplate_(True) toolbarItems = [ dict(itemIdentifier="Daemons", label="Daemons", toolTip="Daemon Group", view=self.pathList, callback=self.populateList), dict(itemIdentifier="image", label="Image", imageObject=refreshIcon, callback=self.populateList), ] self.w.addToolbar("Unicron Toolbar", toolbarItems=toolbarItems, displayMode="icon") self.w.blend = Group((0, 0, 0, 0), blendingMode='behindWindow') self.listColumnDescriptions = [{ 'title': '', 'key': 'image', 'width': 25, 'typingSensitive': True, 'allowsSorting': True, 'cell': ImageListCell() }, { 'title': 'Name', 'key': 'name', 'typingSensitive': True, 'allowsSorting': True, }] self.rowHeight = 20 self.w.list = List((0, 37, -0, 0), items=self.listItems, columnDescriptions=self.listColumnDescriptions, showColumnTitles=True, allowsEmptySelection=True, allowsMultipleSelection=False, autohidesScrollers=True, drawFocusRing=False, rowHeight=self.rowHeight, selectionCallback=self._selectionCallback, menuCallback=self._menuCallback) self.w.list._nsObject.setBorderType_(NSNoBorder) self.w.statusbar = Group((0, -26, 0, 0), blendingMode='behindWindow') self.w.statusbar.border = HorizontalLine((0, 0, 0, 1)) self.w.counter = TextBox((16, -20, -16, 15), '', alignment='center', sizeStyle='small') self.populateList(self) self.w.rowIndicator = Group((0, 0, 0, 10)) self.prefsSetStyle(self) self.w.open()
def __addContentView(self): self._contentView = Group((0, titleHeight, -0, -0))
def __init__(self): self.w = Window((180, 340), u'Touché!', minSize=(180, 340), maxSize=(1000, 898)) p = 10 w = 160 # options self.w.options = Group((0, 0, 180, 220)) buttons = { "checkSelBtn": { "text": "Check selected glyphs\nfor touching pairs", "callback": self.checkSel, "y": p }, "checkAllBtn": { "text": "Check entire font\n(can take several minutes!)", "callback": self.checkAll, "y": 60 } } for button, data in buttons.items(): setattr( self.w.options, button, SquareButton((p, data["y"], w, 40), data["text"], callback=data["callback"], sizeStyle="small")) self.w.options.zeroCheck = CheckBox((p, 108, w, 20), "Ignore zero-width glyphs", value=True, sizeStyle="small") self.w.options.progress = ProgressSpinner((82, 174, 16, 16), sizeStyle="small") # results self.w.results = Group((0, 220, 180, -0)) self.w.results.show(False) textBoxes = {"stats": 24, "result": 42} for box, y in textBoxes.items(): setattr(self.w.results, box, TextBox((p, y, w, 14), "", sizeStyle="small")) moreButtons = { "spaceView": { "text": "View all in Space Center", "callback": self.showAllPairs, "y": 65 }, "exportTxt": { "text": "Export as MM pair list", "callback": self.exportPairList, "y": 90 } } for button, data in moreButtons.items(): setattr( self.w.results, button, SquareButton((p, data["y"], w, 20), data["text"], callback=data["callback"], sizeStyle="small")) # list and preview self.w.outputList = List((180, 0, 188, -0), [{ "left glyph": "", "right glyph": "" }], columnDescriptions=[{ "title": "left glyph" }, { "title": "right glyph" }], showColumnTitles=False, allowsMultipleSelection=False, enableDelete=False, selectionCallback=self.showPair) self.w.preview = MultiLineView((368, 0, -0, -0), pointSize=256) self.w.open()
def __init__(self): self.font = CurrentFont() self.glyph = CurrentGlyph() self.upm = self.font.info.unitsPerEm self.rf3 = int(roboFontVersion.split(".")[0]) >= 3 if self.rf3: self.layer = CurrentLayer() # key: glyph name -- value: list containing assembled glyphs self.glyphPreviewCacheDict = {} # key: anchor name -- value: list of mark glyph names self.anchorsOnMarksDict = {} # key: anchor name -- value: list of base glyph names self.anchorsOnBasesDict = {} self.CXTanchorsOnBasesDict = {} # key: mark glyph name -- value: anchor name # NOTE: It's expected that each mark glyph only has one type of anchor self.marksDict = {} self.fillAnchorsAndMarksDicts() # list of glyph names that will be displayed in the UI list self.glyphNamesList = [] # list of glyph names selected in the UI list self.selectedGlyphNamesList = [] # list of the glyph objects that should be inserted # before and after the accented glyphs self.extraGlyphsList = [] self.Blue, self.Alpha = 1, 0.6 self.font.naked().addObserver(self, "fontWasModified", "Font.Changed") addObserver(self, "_fontWillClose", "fontWillClose") addObserver(self, "_currentFontChanged", "fontResignCurrent") addObserver(self, "_currentGlyphChanged", "currentGlyphChanged") addObserver(self, "_drawFill", "draw") addObserver(self, "_drawFill", "drawInactive") addObserver(self, "_previewFill", "drawPreview") # observer for the draw event addObserver(self, "_drawGlyphs", "draw") # draw the glyphs when the glyph window is not in focus addObserver(self, "_drawGlyphs", "drawInactive") addObserver(self, "_drawGlyphs", "drawPreview") integerNumFormatter = NSNumberFormatter.alloc().init() integerNumFormatter.setAllowsFloats_(False) integerNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter = NSNumberFormatter.alloc().init() intPosMinZeroNumFormatter.setAllowsFloats_(False) intPosMinZeroNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter.setMinimum_(NSNumber.numberWithInt_(0)) intPosMinOneNumFormatter = NSNumberFormatter.alloc().init() intPosMinOneNumFormatter.setAllowsFloats_(False) intPosMinOneNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinOneNumFormatter.setMinimum_(NSNumber.numberWithInt_(1)) self.textSize = getExtensionDefault("%s.%s" % (extensionKey, "textSize")) if not self.textSize: self.textSize = 150 self.lineHeight = getExtensionDefault("%s.%s" % (extensionKey, "lineHeight")) if not self.lineHeight: self.lineHeight = 200 self.extraSidebearings = getExtensionDefault( "%s.%s" % (extensionKey, "extraSidebearings")) if not self.extraSidebearings: self.extraSidebearings = [0, 0] self.extraGlyphs = getExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs")) if not self.extraGlyphs: self.extraGlyphs = '' posSize = getExtensionDefault("%s.%s" % (extensionKey, "posSize")) if not posSize: posSize = (100, 100, 1200, 400) self.calibrateMode = getExtensionDefault( "%s.%s" % (extensionKey, "calibrateMode")) if not self.calibrateMode: self.calibrateMode = False calibrateModeStrings = getExtensionDefault( "%s.%s" % (extensionKey, "calibrateModeStrings")) if not calibrateModeStrings: calibrateModeStrings = { 'group1.baseInput': 'dotlessi o s', 'group1.markInput': 'dieresis circumflex macron breve caron', 'group2.baseInput': 'I O S', 'group2.markInput': 'dieresis.cap circumflex.cap macron.cap ' 'breve.cap caron.cap', 'group3.baseInput': 'I.sc O.sc S.sc', 'group3.markInput': 'dieresis circumflex macron breve caron', 'group4.baseInput': '', 'group4.markInput': '', } # -- Window -- self.w = FloatingWindow(posSize, extensionName, minSize=(500, 400)) self.w.fontList = List((10, 10, 190, -41), self.glyphNamesList, selectionCallback=self.listSelectionCallback) if roboFontVersion < '1.7': # use the full width of the column self.w.fontList.getNSTableView().sizeToFit() self.w.fontList.show(not self.calibrateMode) self.w.lineView = MultiLineView((210, 10, -10, -41), pointSize=self.textSize, lineHeight=self.lineHeight, displayOptions={ "Beam": False, "displayMode": "Multi Line" }) self.w.lineView.setFont(self.font) # -- Calibration Mode -- baseLabel = "Bases" markLabel = "Marks" width, height = 190, 140 self.cm = Group((0, 0, 0, 0)) # --- self.cm.group1 = Group((5, height * 0, width, height - 10)) self.cm.group1.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group1.baseInput = EditText( (0, 21, width, 22), calibrateModeStrings['group1.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group1.markInput = EditText( (0, 71, width, 44), calibrateModeStrings['group1.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group2 = Group((5, height * 1, width, height - 10)) self.cm.group2.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group2.baseInput = EditText( (0, 21, width, 22), calibrateModeStrings['group2.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group2.markInput = EditText( (0, 71, width, 44), calibrateModeStrings['group2.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group3 = Group((5, height * 2, width, height - 10)) self.cm.group3.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group3.baseInput = EditText( (0, 21, width, 22), calibrateModeStrings['group3.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group3.markInput = EditText( (0, 71, width, 44), calibrateModeStrings['group3.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group4 = Group((5, height * 3, width, height - 10)) self.cm.group4.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group4.baseInput = EditText( (0, 21, width, 22), calibrateModeStrings['group4.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group4.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group4.markInput = EditText( (0, 71, width, 44), calibrateModeStrings['group4.markInput'], callback=self.updateCalibrateMode, continuous=False) # --- view = DefconAppKitTopAnchoredNSView.alloc().init() view.addSubview_(self.cm.getNSView()) view.setFrame_(((0, 0), (width + 10, height * 4 - 23))) self.cm.setPosSize((0, 0, width + 10, height * 4 - 22)) self.w.scrollView = ScrollView((5, 10, width + 10, -41), view, drawsBackground=False, hasHorizontalScroller=False) self.w.scrollView.getNSScrollView().setBorderType_(NSNoBorder) # NSScrollElasticityNone self.w.scrollView.getNSScrollView().setVerticalScrollElasticity_(1) self.w.scrollView.show(self.calibrateMode) # -- Footer -- self.w.footer = Group((10, -32, -10, -10)) self.w.footer.calibrateModeCheck = CheckBox( (0, 0, 200, -0), "Calibration Mode", callback=self.calibrateModeCallback, value=self.calibrateMode) self.w.footer.textSizeLabel = TextBox((200, 2, 100, -0), "Text Size") self.w.footer.textSize = EditText((260, 0, 35, -0), self.textSize, callback=self.textSizeCallback, continuous=False, formatter=intPosMinOneNumFormatter) self.w.footer.lineHeightLabel = TextBox((310, 2, 100, -0), "Line Height") self.w.footer.lineHeight = EditText((385, 0, 35, -0), self.lineHeight, callback=self.lineHeightCallback, continuous=False, formatter=integerNumFormatter) self.w.footer.extraSidebearingsLabel = TextBox((436, 2, 180, -0), "Extra Sidebearings") self.w.footer.extraSidebearingsChar = TextBox((592, 2, 20, -0), "&") self.w.footer.extraSidebearingLeft = EditText( (557, 0, 35, -0), self.extraSidebearings[0], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.footer.extraSidebearingRight = EditText( (604, 0, 35, -0), self.extraSidebearings[1], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.footer.extraGlyphsLabel = TextBox((655, 2, 180, -0), "Extra Glyphs") self.w.footer.extraGlyphs = EditText((739, 0, -0, -0), self.extraGlyphs, callback=self.extraGlyphsCallback, continuous=False) # trigger the initial state and contents of the window self.extraGlyphsCallback() # calls self.updateExtensionWindow() self.w.bind("close", self.windowClose) self.w.open() self.w.makeKey()
class AdjustAnchors(BaseWindowController): def __init__(self): self.font = CurrentFont() self.glyph = CurrentGlyph() self.upm = self.font.info.unitsPerEm self.rf3 = int(roboFontVersion.split(".")[0]) >= 3 if self.rf3: self.layer = CurrentLayer() # key: glyph name -- value: list containing assembled glyphs self.glyphPreviewCacheDict = {} # key: anchor name -- value: list of mark glyph names self.anchorsOnMarksDict = {} # key: anchor name -- value: list of base glyph names self.anchorsOnBasesDict = {} self.CXTanchorsOnBasesDict = {} # key: mark glyph name -- value: anchor name # NOTE: It's expected that each mark glyph only has one type of anchor self.marksDict = {} self.fillAnchorsAndMarksDicts() # list of glyph names that will be displayed in the UI list self.glyphNamesList = [] # list of glyph names selected in the UI list self.selectedGlyphNamesList = [] # list of the glyph objects that should be inserted # before and after the accented glyphs self.extraGlyphsList = [] self.Blue, self.Alpha = 1, 0.6 self.font.naked().addObserver(self, "fontWasModified", "Font.Changed") addObserver(self, "_fontWillClose", "fontWillClose") addObserver(self, "_currentFontChanged", "fontResignCurrent") addObserver(self, "_currentGlyphChanged", "currentGlyphChanged") addObserver(self, "_drawFill", "draw") addObserver(self, "_drawFill", "drawInactive") addObserver(self, "_previewFill", "drawPreview") # observer for the draw event addObserver(self, "_drawGlyphs", "draw") # draw the glyphs when the glyph window is not in focus addObserver(self, "_drawGlyphs", "drawInactive") addObserver(self, "_drawGlyphs", "drawPreview") integerNumFormatter = NSNumberFormatter.alloc().init() integerNumFormatter.setAllowsFloats_(False) integerNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter = NSNumberFormatter.alloc().init() intPosMinZeroNumFormatter.setAllowsFloats_(False) intPosMinZeroNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinZeroNumFormatter.setMinimum_(NSNumber.numberWithInt_(0)) intPosMinOneNumFormatter = NSNumberFormatter.alloc().init() intPosMinOneNumFormatter.setAllowsFloats_(False) intPosMinOneNumFormatter.setGeneratesDecimalNumbers_(False) intPosMinOneNumFormatter.setMinimum_(NSNumber.numberWithInt_(1)) self.textSize = getExtensionDefault("%s.%s" % (extensionKey, "textSize")) if not self.textSize: self.textSize = 150 self.lineHeight = getExtensionDefault("%s.%s" % (extensionKey, "lineHeight")) if not self.lineHeight: self.lineHeight = 200 self.extraSidebearings = getExtensionDefault( "%s.%s" % (extensionKey, "extraSidebearings")) if not self.extraSidebearings: self.extraSidebearings = [0, 0] self.extraGlyphs = getExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs")) if not self.extraGlyphs: self.extraGlyphs = '' posSize = getExtensionDefault("%s.%s" % (extensionKey, "posSize")) if not posSize: posSize = (100, 100, 1200, 400) self.calibrateMode = getExtensionDefault( "%s.%s" % (extensionKey, "calibrateMode")) if not self.calibrateMode: self.calibrateMode = False calibrateModeStrings = getExtensionDefault( "%s.%s" % (extensionKey, "calibrateModeStrings")) if not calibrateModeStrings: calibrateModeStrings = { 'group1.baseInput': 'dotlessi o s', 'group1.markInput': 'dieresis circumflex macron breve caron', 'group2.baseInput': 'I O S', 'group2.markInput': 'dieresis.cap circumflex.cap macron.cap ' 'breve.cap caron.cap', 'group3.baseInput': 'I.sc O.sc S.sc', 'group3.markInput': 'dieresis circumflex macron breve caron', 'group4.baseInput': '', 'group4.markInput': '', } # -- Window -- self.w = FloatingWindow(posSize, extensionName, minSize=(500, 400)) self.w.fontList = List((10, 10, 190, -41), self.glyphNamesList, selectionCallback=self.listSelectionCallback) if roboFontVersion < '1.7': # use the full width of the column self.w.fontList.getNSTableView().sizeToFit() self.w.fontList.show(not self.calibrateMode) self.w.lineView = MultiLineView((210, 10, -10, -41), pointSize=self.textSize, lineHeight=self.lineHeight, displayOptions={ "Beam": False, "displayMode": "Multi Line" }) self.w.lineView.setFont(self.font) # -- Calibration Mode -- baseLabel = "Bases" markLabel = "Marks" width, height = 190, 140 self.cm = Group((0, 0, 0, 0)) # --- self.cm.group1 = Group((5, height * 0, width, height - 10)) self.cm.group1.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group1.baseInput = EditText( (0, 21, width, 22), calibrateModeStrings['group1.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group1.markInput = EditText( (0, 71, width, 44), calibrateModeStrings['group1.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group1.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group2 = Group((5, height * 1, width, height - 10)) self.cm.group2.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group2.baseInput = EditText( (0, 21, width, 22), calibrateModeStrings['group2.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group2.markInput = EditText( (0, 71, width, 44), calibrateModeStrings['group2.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group2.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group3 = Group((5, height * 2, width, height - 10)) self.cm.group3.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group3.baseInput = EditText( (0, 21, width, 22), calibrateModeStrings['group3.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group3.markInput = EditText( (0, 71, width, 44), calibrateModeStrings['group3.markInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group3.divider = HorizontalLine((0, -1, -0, 1)) # --- self.cm.group4 = Group((5, height * 3, width, height - 10)) self.cm.group4.baseLabel = TextBox((0, 0, width, 20), baseLabel) self.cm.group4.baseInput = EditText( (0, 21, width, 22), calibrateModeStrings['group4.baseInput'], callback=self.updateCalibrateMode, continuous=False) self.cm.group4.markLabel = TextBox((0, 50, width, 20), markLabel) self.cm.group4.markInput = EditText( (0, 71, width, 44), calibrateModeStrings['group4.markInput'], callback=self.updateCalibrateMode, continuous=False) # --- view = DefconAppKitTopAnchoredNSView.alloc().init() view.addSubview_(self.cm.getNSView()) view.setFrame_(((0, 0), (width + 10, height * 4 - 23))) self.cm.setPosSize((0, 0, width + 10, height * 4 - 22)) self.w.scrollView = ScrollView((5, 10, width + 10, -41), view, drawsBackground=False, hasHorizontalScroller=False) self.w.scrollView.getNSScrollView().setBorderType_(NSNoBorder) # NSScrollElasticityNone self.w.scrollView.getNSScrollView().setVerticalScrollElasticity_(1) self.w.scrollView.show(self.calibrateMode) # -- Footer -- self.w.footer = Group((10, -32, -10, -10)) self.w.footer.calibrateModeCheck = CheckBox( (0, 0, 200, -0), "Calibration Mode", callback=self.calibrateModeCallback, value=self.calibrateMode) self.w.footer.textSizeLabel = TextBox((200, 2, 100, -0), "Text Size") self.w.footer.textSize = EditText((260, 0, 35, -0), self.textSize, callback=self.textSizeCallback, continuous=False, formatter=intPosMinOneNumFormatter) self.w.footer.lineHeightLabel = TextBox((310, 2, 100, -0), "Line Height") self.w.footer.lineHeight = EditText((385, 0, 35, -0), self.lineHeight, callback=self.lineHeightCallback, continuous=False, formatter=integerNumFormatter) self.w.footer.extraSidebearingsLabel = TextBox((436, 2, 180, -0), "Extra Sidebearings") self.w.footer.extraSidebearingsChar = TextBox((592, 2, 20, -0), "&") self.w.footer.extraSidebearingLeft = EditText( (557, 0, 35, -0), self.extraSidebearings[0], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.footer.extraSidebearingRight = EditText( (604, 0, 35, -0), self.extraSidebearings[1], callback=self.extraSidebearingsCallback, continuous=False, formatter=intPosMinZeroNumFormatter) self.w.footer.extraGlyphsLabel = TextBox((655, 2, 180, -0), "Extra Glyphs") self.w.footer.extraGlyphs = EditText((739, 0, -0, -0), self.extraGlyphs, callback=self.extraGlyphsCallback, continuous=False) # trigger the initial state and contents of the window self.extraGlyphsCallback() # calls self.updateExtensionWindow() self.w.bind("close", self.windowClose) self.w.open() self.w.makeKey() def calibrateModeCallback(self, sender): self.calibrateMode = not self.calibrateMode self.w.fontList.show(not sender.get()) self.w.scrollView.show(self.calibrateMode) self.updateExtensionWindow() def textSizeCallback(self, sender): try: # in case the user submits an empty field self.textSize = int(sender.get()) except Exception: # reset to the previous value NSBeep() self.sender.set(self.textSize) self.w.lineView.setPointSize(self.textSize) def lineHeightCallback(self, sender): try: self.lineHeight = int(sender.get()) except Exception: NSBeep() self.sender.set(self.lineHeight) self.w.lineView.setLineHeight(self.lineHeight) def extraSidebearingsCallback(self, sender): left = self.w.footer.extraSidebearingLeft right = self.w.footer.extraSidebearingRight try: self.extraSidebearings = [int(left.get()), int(right.get())] except Exception: NSBeep() left.set(self.extraSidebearings[0]) right.set(self.extraSidebearings[1]) self.extraGlyphsCallback() # calls self.updateExtensionWindow() def extraGlyphsCallback(self, *sender): del self.extraGlyphsList[:] # empty the list self.extraGlyphs = self.w.footer.extraGlyphs.get() glyphNamesList = self.extraGlyphs.split() for gName in glyphNamesList: try: extraGlyph = self.font[gName] # must create a new glyph in order to be able to # increase the sidebearings without modifying the font newGlyph = RGlyph() if self.rf3: newGlyph.layer = self.layer else: newGlyph.font = newGlyph.getParent() # must use deepAppend because the extra glyph may have # components (which will cause problems to the MultiLineView) newGlyph = self.deepAppendGlyph(newGlyph, extraGlyph) newGlyph.width = extraGlyph.width except Exception: continue newGlyph.leftMargin += self.extraSidebearings[0] newGlyph.rightMargin += self.extraSidebearings[1] self.extraGlyphsList.append(newGlyph) self.glyphPreviewCacheDict.clear() self.updateExtensionWindow() def windowClose(self, sender): self.font.naked().removeObserver(self, "Font.Changed") removeObserver(self, "fontWillClose") removeObserver(self, "fontResignCurrent") removeObserver(self, "currentGlyphChanged") removeObserver(self, "draw") removeObserver(self, "drawInactive") removeObserver(self, "drawPreview") self.saveExtensionDefaults() def getCalibrateModeStrings(self): calibrateModeStringsDict = {} for i in range(1, 5): group = getattr(self.cm, "group%d" % i) calibrateModeStringsDict["group%d.baseInput" % i] = group.baseInput.get() calibrateModeStringsDict["group%d.markInput" % i] = group.markInput.get() return calibrateModeStringsDict def saveExtensionDefaults(self): setExtensionDefault("%s.%s" % (extensionKey, "posSize"), self.w.getPosSize()) setExtensionDefault("%s.%s" % (extensionKey, "textSize"), self.textSize) setExtensionDefault("%s.%s" % (extensionKey, "lineHeight"), self.lineHeight) setExtensionDefault("%s.%s" % (extensionKey, "extraSidebearings"), self.extraSidebearings) setExtensionDefault("%s.%s" % (extensionKey, "extraGlyphs"), self.extraGlyphs) setExtensionDefault("%s.%s" % (extensionKey, "calibrateMode"), self.calibrateMode) setExtensionDefault("%s.%s" % (extensionKey, "calibrateModeStrings"), self.getCalibrateModeStrings()) def _previewFill(self, info): self.Blue, self.Alpha = 0, 1 def _drawFill(self, info): self.Blue, self.Alpha = 1, 0.6 def _fontWillClose(self, info): """ Close the window when the last font is closed """ if len(AllFonts()) < 2: self.windowClose(self) self.w.close() def _currentFontChanged(self, info): self.font.naked().removeObserver(self, "Font.Changed") self.font = CurrentFont() self.font.naked().addObserver(self, "fontWasModified", "Font.Changed") self.w.lineView.setFont(self.font) self.fillAnchorsAndMarksDicts() del self.glyphNamesList[:] del self.selectedGlyphNamesList[:] self.updateExtensionWindow() def _currentGlyphChanged(self, info): self.updateExtensionWindow() def fontWasModified(self, info): OutputWindow().clear() self.fillAnchorsAndMarksDicts() del self.glyphNamesList[:] del self.selectedGlyphNamesList[:] self.updateExtensionWindow() def deepAppendGlyph(self, glyph, gToAppend, offset=(0, 0)): if not gToAppend.components: glyph.appendGlyph(gToAppend, offset) else: for component in gToAppend.components: # avoid traceback in the case where the selected glyph is # referencing a component whose glyph is not in the font if component.baseGlyph not in self.font.keys(): print("WARNING: %s is referencing a glyph named %s, which " "does not exist in the font." % (self.font.selection[0], component.baseGlyph)) continue compGlyph = self.font[component.baseGlyph].copy() # handle component transformations componentTransformation = component.transformation # when undoing a paste anchor or a delete anchor action, # RoboFont returns component.transformation as a list instead # of a tuple if type(componentTransformation) is list: componentTransformation = tuple(componentTransformation) # if component is skewed and/or is shifted if componentTransformation != (1, 0, 0, 1, 0, 0): matrix = componentTransformation[0:4] if matrix != (1, 0, 0, 1): # if component is skewed # ignore the original component's shifting values transformObj = Identity.transform(matrix + (0, 0)) compGlyph.transform(transformObj) # add the two tuples of offset glyph.appendGlyph( compGlyph, tuple(map(sum, zip(component.offset, offset)))) for contour in gToAppend: glyph.appendContour(contour, offset) # if the assembled glyph still has components, recursively # remove and replace them 1-by-1 by the glyphs they reference if glyph.components: nestedComponent = glyph.components[-1] # start from the end glyph.removeComponent(nestedComponent) glyph = self.deepAppendGlyph(glyph, self.font[nestedComponent.baseGlyph], nestedComponent.offset) return glyph def updateCalibrateMode(self, *sender): glyphsList = [] newLine = self.w.lineView.createNewLineGlyph() # cycle thru the UI Groups and collect the strings for i in range(1, 5): group = getattr(self.cm, "group%d" % i) baseGlyphsNamesList = group.baseInput.get().split() markGlyphsNamesList = group.markInput.get().split() # iterate thru the base+mark combinations for gBaseName, gMarkName in product(baseGlyphsNamesList, markGlyphsNamesList): newGlyph = RGlyph() if self.rf3: newGlyph.layer = self.layer else: newGlyph.font = newGlyph.getParent() # skip invalid glyph names try: baseGlyph = self.font[gBaseName] markGlyph = self.font[gMarkName] except Exception: continue # append base glyph newGlyph = self.deepAppendGlyph(newGlyph, baseGlyph) # append mark glyph newGlyph = self.deepAppendGlyph( newGlyph, markGlyph, self.getAnchorOffsets(baseGlyph, markGlyph)) # set the advanced width dfltSidebearings = self.upm * .05 # 5% of UPM newGlyph.leftMargin = (dfltSidebearings + self.extraSidebearings[0]) newGlyph.rightMargin = (dfltSidebearings + self.extraSidebearings[1]) # append the assembled glyph to the list glyphsList.extend(self.extraGlyphsList) glyphsList.append(newGlyph) # add line break, if both input fields have content if baseGlyphsNamesList and markGlyphsNamesList: glyphsList.extend(self.extraGlyphsList) glyphsList.append(newLine) # update the contents of the MultiLineView self.w.lineView.set(glyphsList) def updateExtensionWindow(self): if self.calibrateMode: self.updateCalibrateMode() return # NOTE: CurrentGlyph() will return zero (its length), # so "is not None" is necessary if CurrentGlyph() is not None: self.glyph = CurrentGlyph() self.glyphNamesList = self.makeGlyphNamesList(self.glyph) self.updateListView() currentGlyphName = self.glyph.name # base glyph + accent combinations preview # first check if there's a cached glyph if currentGlyphName in self.glyphPreviewCacheDict: self.w.lineView.set( self.glyphPreviewCacheDict[currentGlyphName]) # assemble the glyphs else: glyphsList = [] for glyphNameInUIList in self.glyphNamesList: # trim the contextual portion of the UI glyph name # and keep track of it if CONTEXTUAL_ANCHOR_TAG in glyphNameInUIList: cxtTagIndex = glyphNameInUIList.find( CONTEXTUAL_ANCHOR_TAG) glyphNameCXTportion = glyphNameInUIList[cxtTagIndex:] # this line must be last! glyphNameInUIList = glyphNameInUIList[:cxtTagIndex] else: glyphNameCXTportion = '' newGlyph = RGlyph() if self.rf3: newGlyph.layer = self.layer else: newGlyph.font = newGlyph.getParent() # the glyph in the UI list is a mark if glyphNameInUIList in self.marksDict: markGlyph = self.font[glyphNameInUIList] # append base glyph newGlyph = self.deepAppendGlyph(newGlyph, self.glyph) # append mark glyph newGlyph = self.deepAppendGlyph( newGlyph, markGlyph, self.getAnchorOffsets(self.glyph, markGlyph, glyphNameCXTportion)) # set the advanced width # combining marks or other glyphs with # a small advanced width if self.glyph.width < 10: newGlyph.leftMargin = self.upm * .05 # 5% of UPM newGlyph.rightMargin = newGlyph.leftMargin else: newGlyph.width = self.glyph.width # the glyph in the UI list is a base else: baseGlyph = self.font[glyphNameInUIList] # append base glyph newGlyph = self.deepAppendGlyph(newGlyph, baseGlyph) # append mark glyph newGlyph = self.deepAppendGlyph( newGlyph, self.glyph, self.getAnchorOffsets(baseGlyph, self.glyph)) # set the advanced width # combining marks or other glyphs with # a small advanced width if self.glyph.width < 10: newGlyph.leftMargin = self.upm * .05 newGlyph.rightMargin = newGlyph.leftMargin else: newGlyph.width = baseGlyph.width # pad the new glyph if it has too much overhang if newGlyph.leftMargin < self.upm * .15: newGlyph.leftMargin = self.upm * .05 if newGlyph.rightMargin < self.upm * .15: newGlyph.rightMargin = self.upm * .05 # add extra sidebearings newGlyph.leftMargin += self.extraSidebearings[0] newGlyph.rightMargin += self.extraSidebearings[1] # one last check for making sure the new glyph # can be displayed if not newGlyph.components: glyphsList.extend(self.extraGlyphsList) glyphsList.append(newGlyph) else: print("Combination with mark glyph %s can't be " "previewed because it contains component %s." % (glyphNameInUIList + glyphNameCXTportion, newGlyph.components[0].baseGlyph)) glyphsList.extend(self.extraGlyphsList) self.w.lineView.set(glyphsList) # add to the cache self.glyphPreviewCacheDict[currentGlyphName] = glyphsList else: self.w.lineView.set([]) def listSelectionCallback(self, sender): selectedGlyphNamesList = [] for index in sender.getSelection(): selectedGlyphNamesList.append(self.glyphNamesList[index]) self.selectedGlyphNamesList = selectedGlyphNamesList self.updateGlyphView() def updateGlyphView(self): UpdateCurrentGlyphView() def fillAnchorsAndMarksDicts(self): # reset all the dicts self.glyphPreviewCacheDict.clear() self.anchorsOnMarksDict.clear() self.anchorsOnBasesDict.clear() self.CXTanchorsOnBasesDict.clear() self.marksDict.clear() markGlyphsWithMoreThanOneAnchorTypeList = [] for glyphName in self.font.glyphOrder: glyphAnchorsList = self.font[glyphName].anchors for anchor in glyphAnchorsList: if anchor.name[0] == '_': anchorName = anchor.name[1:] # add to AnchorsOnMarks dictionary if anchorName not in self.anchorsOnMarksDict: self.anchorsOnMarksDict[anchorName] = [glyphName] else: tempList = self.anchorsOnMarksDict[anchorName] tempList.append(glyphName) self.anchorsOnMarksDict[anchorName] = tempList # add to Marks dictionary if glyphName not in self.marksDict: self.marksDict[glyphName] = anchorName else: if (glyphName not in markGlyphsWithMoreThanOneAnchorTypeList): markGlyphsWithMoreThanOneAnchorTypeList.append( glyphName) else: anchorName = anchor.name if CONTEXTUAL_ANCHOR_TAG in anchorName: # add to AnchorsOnBases dictionary if anchorName not in self.CXTanchorsOnBasesDict: self.CXTanchorsOnBasesDict[anchorName] = [ glyphName ] else: tempList = self.CXTanchorsOnBasesDict[anchorName] tempList.append(glyphName) self.CXTanchorsOnBasesDict[anchorName] = tempList else: # add to AnchorsOnBases dictionary if anchorName not in self.anchorsOnBasesDict: self.anchorsOnBasesDict[anchorName] = [glyphName] else: tempList = self.anchorsOnBasesDict[anchorName] tempList.append(glyphName) self.anchorsOnBasesDict[anchorName] = tempList if markGlyphsWithMoreThanOneAnchorTypeList: for glyphName in markGlyphsWithMoreThanOneAnchorTypeList: print("ERROR: Glyph %s has more than one type of anchor." % glyphName) def makeGlyphNamesList(self, glyph): glyphNamesList = [] markGlyphIsAbleToBeBase = False # NOTE: "if glyph" will return zero (its length), # so "is not None" is necessary if glyph is not None: # assemble the list for the UI list for anchor in glyph.anchors: anchorName = anchor.name # the glyph selected is a base if anchorName in self.anchorsOnMarksDict: glyphNamesList.extend(self.anchorsOnMarksDict[anchorName]) # the glyph selected is a mark # skips the leading underscore elif anchorName[1:] in self.anchorsOnBasesDict: glyphNamesList.extend( self.anchorsOnBasesDict[anchorName[1:]]) # the glyph selected is a base elif anchorName[0] != '_' and (anchorName in self.CXTanchorsOnBasesDict): cxtTagIndex = anchorName.find(CONTEXTUAL_ANCHOR_TAG) anchorNameNOTCXTportion = anchorName[:cxtTagIndex] anchorNameCXTportion = anchorName[cxtTagIndex:] # XXX here only the first mark glyph that has an anchor of # the kind 'anchorNameNOTCXTportion' is considered. # This is probably harmless, but... glyphName = '%s%s' % ( self.anchorsOnMarksDict[anchorNameNOTCXTportion][0], anchorNameCXTportion) glyphNamesList.append(glyphName) # for mark glyphs, test if they're able to get # other mark glyphs attached to them. # this will (correctly) prevent the UI list from including # glyph names that cannot be displayed with the current glyph if glyph.name in self.marksDict: for anchor in glyph.anchors: # the current mark glyph has anchors that # allow it to be a base for other marks if anchor.name[0] != '_': markGlyphIsAbleToBeBase = True break # remove marks from the glyph list if the # current mark glyph can't work as a base if not markGlyphIsAbleToBeBase: # iterate from the end of the list for glyphName in glyphNamesList[::-1]: if glyphName in self.marksDict: glyphNamesList.remove(glyphName) glyphNamesList.sort() return glyphNamesList def updateListView(self): self.w.fontList.set(self.glyphNamesList) def getAnchorOffsets(self, canvasGlyph, glyphToDraw, anchorNameCXTportion=''): # the current glyph is a mark if canvasGlyph.name in self.marksDict: # glyphToDraw is also a mark (mark-to-mark case) if glyphToDraw.name in self.marksDict: # pick the (mark glyph) anchor to draw on for anchor in canvasGlyph.anchors: if anchor.name[0] != '_': anchorName = anchor.name markAnchor = anchor break # pick the (base glyph) anchor to draw on for anchor in glyphToDraw.anchors: try: if anchor.name == '_' + anchorName: baseAnchor = anchor break except UnboundLocalError: continue # glyphToDraw is not a mark else: # pick the (mark glyph) anchor to draw on for anchor in canvasGlyph.anchors: if anchor.name[0] == '_': anchorName = anchor.name[1:] markAnchor = anchor break # pick the (base glyph) anchor to draw on for anchor in glyphToDraw.anchors: try: if anchor.name == anchorName: baseAnchor = anchor break except UnboundLocalError: continue try: offsetX = markAnchor.x - baseAnchor.x offsetY = markAnchor.y - baseAnchor.y except UnboundLocalError: offsetX = 0 offsetY = 0 # the current glyph is a base else: try: anchorName = self.marksDict[glyphToDraw.name] except KeyError: anchorName = None if anchorName: # pick the (base glyph) anchor to draw on for anchor in canvasGlyph.anchors: if anchor.name == anchorName + anchorNameCXTportion: baseAnchor = anchor break # pick the (mark glyph) anchor to draw on for anchor in glyphToDraw.anchors: if anchor.name == '_' + anchorName: markAnchor = anchor break try: offsetX = baseAnchor.x - markAnchor.x offsetY = baseAnchor.y - markAnchor.y except UnboundLocalError: offsetX = 0 offsetY = 0 return (offsetX, offsetY) def _drawGlyphs(self, info): """ draw stuff in the glyph window view """ translateBefore = (0, 0) for glyphName in self.selectedGlyphNamesList: # trim the contextual portion of the UI glyph name # and keep track of it if CONTEXTUAL_ANCHOR_TAG in glyphName: cxtTagIndex = glyphName.find(CONTEXTUAL_ANCHOR_TAG) glyphNameCXTportion = glyphName[cxtTagIndex:] glyphName = glyphName[:cxtTagIndex] # this line must be last! else: glyphNameCXTportion = '' glyphToDraw = self.font[glyphName] # determine the offset of the anchors offset = self.getAnchorOffsets(self.glyph, glyphToDraw, glyphNameCXTportion) # set the offset of the drawing translate(offset[0] - translateBefore[0], offset[1] - translateBefore[1]) # record the shift amounts (these are needed for resetting the # drawing position when more than one mark is selected on the list) translateBefore = offset # set the fill & stroke fill(0, 0, self.Blue, self.Alpha) strokeWidth(None) # draw it mojoPen = MojoDrawingToolsPen(glyphToDraw, self.font) glyphToDraw.draw(mojoPen) mojoPen.draw()
def addInterface(self, notification): self.window = notification['window'] # self.cleanup(self.window) # CONTAINER xywh = (margin, -55, -margin, height) self.sbui = CanvasGroup(xywh, delegate=CanvasStuff(self.window)) # LEFT x, y, w, h = xywh = (0, -height, dfltLwidth, height) this = self.sbui.L = Group(xywh) # text input xywh = (x, y + 3, width * 1.5, height * .75) this.Ltext = EditText(xywh, placeholder='angledLeftMargin', sizeStyle='mini', continuous=False, callback=self.setSB) # quick mod buttons xywh = (x + width * 1.5 + (gap * 1), y, width, height) this.Lminus = Button(xywh, iconminus, sizeStyle='mini', callback=self.setLminus) this.Lminus.getNSButton().setToolTip_('Adjust LSB -' + str(unit)) xywh = (x + width * 2.5 + (gap * 2), y, width, height) this.Lplus = Button(xywh, iconplus, sizeStyle='mini', callback=self.setLplus) this.Lplus.getNSButton().setToolTip_('Adjust LSB +' + str(unit)) xywh = (x + width * 3.5 + (gap * 3), y, width, height) this.Lround = Button(xywh, iconround, sizeStyle='mini', callback=self.setLround) this.Lround.getNSButton().setToolTip_('Round LSB to ' + str(unit)) xywh = (x + width * 4.5 + (gap * 4), y, width, height) this.Lright = Button(xywh, iconcopyR, sizeStyle='mini', callback=self.setLright) this.Lright.getNSButton().setToolTip_('Copy Right Value') # stylize this.Ltext.getNSTextField().setBezeled_(False) this.Ltext.getNSTextField().setBackgroundColor_(NSColor.clearColor()) self.flatButt(this.Lminus) self.flatButt(this.Lplus) self.flatButt(this.Lround) self.flatButt(this.Lright) # RIGHT x, y, w, h = xywh = (-dfltRwidth, y, dfltRwidth, h) this = self.sbui.R = Group(xywh) # text input xywh = (-x - width * 1.5, y + 3, width * 1.5, height * .75) this.Rtext = EditText(xywh, placeholder='angledRightMargin', sizeStyle='mini', continuous=False, callback=self.setSB) # quick mod buttons xywh = (-x - width * 5.5 - (gap * 4), y, width, height) this.Rleft = Button(xywh, iconcopyL, sizeStyle='mini', callback=self.setRleft) this.Rleft.getNSButton().setToolTip_('Copy Left Value') xywh = (-x - width * 4.5 - (gap * 3), y, width, height) this.Rround = Button(xywh, iconround, sizeStyle='mini', callback=self.setRround) this.Rround.getNSButton().setToolTip_('Round RSB to ' + str(unit)) xywh = (-x - width * 3.5 - (gap * 2), y, width, height) this.Rminus = Button(xywh, iconminus, sizeStyle='mini', callback=self.setRminus) this.Rminus.getNSButton().setToolTip_('Adjust RSB -' + str(unit)) xywh = (-x - width * 2.5 - (gap * 1), y, width, height) this.Rplus = Button(xywh, iconplus, sizeStyle='mini', callback=self.setRplus) this.Rplus.getNSButton().setToolTip_('Adjust RSB +' + str(unit)) # stylize this.Rtext.getNSTextField().setBezeled_(False) this.Rtext.getNSTextField().setBackgroundColor_(NSColor.clearColor()) this.Rtext.getNSTextField().setAlignment_(NSTextAlignmentRight) self.flatButt(this.Rminus) self.flatButt(this.Rplus) self.flatButt(this.Rround) self.flatButt(this.Rleft) # CENTER winX, winY, winW, winH = self.window.getVisibleRect() winW = winW - margin * 5 x, y, w, h = xywh = ((winW / 2) - (dfltCwidth / 2), y, dfltCwidth, h) this = self.sbui.C = Group(xywh) x = 0 # text input c = (dfltCwidth / 2) xywh = (c - (width * .75), y + 3, width * 1.5, height * .75) this.Ctext = EditText(xywh, placeholder='width', sizeStyle='mini', continuous=False, callback=self.setSB) # quick mod buttons xywh = (c - (width * .75) - width * 2 - (gap * 2), y, width, height) this.Ccenter = Button(xywh, iconcenter, sizeStyle='mini', callback=self.setCcenter) this.Ccenter.getNSButton().setToolTip_('Center on Width') xywh = (c - (width * .75) - width - (gap * 1), y, width, height) this.Cround = Button(xywh, iconround, sizeStyle='mini', callback=self.setCround) this.Cround.getNSButton().setToolTip_('Round Width to ' + str(unit)) xywh = (c + (width * .75) + (gap * 1), y, width, height) this.Cminus = Button(xywh, iconminus, sizeStyle='mini', callback=self.setCminus) this.Cminus.getNSButton().setToolTip_('Adjust Width -' + str(2 * unit)) xywh = (c + (width * .75) + width + (gap * 2), y, width, height) this.Cplus = Button(xywh, iconplus, sizeStyle='mini', callback=self.setCplus) this.Cplus.getNSButton().setToolTip_('Adjust Width +' + str(2 * unit)) # stylize this.Ctext.getNSTextField().setBezeled_(False) this.Ctext.getNSTextField().setBackgroundColor_(NSColor.clearColor()) this.Ctext.getNSTextField().setAlignment_(NSTextAlignmentCenter) self.flatButt(this.Cminus) self.flatButt(this.Cplus) self.flatButt(this.Cround) self.flatButt(this.Ccenter) # hide self.sbui.L.Lminus.show(False) self.sbui.L.Lround.show(False) self.sbui.L.Lplus.show(False) self.sbui.L.Lright.show(False) self.sbui.R.Rminus.show(False) self.sbui.R.Rround.show(False) self.sbui.R.Rplus.show(False) self.sbui.R.Rleft.show(False) self.sbui.C.Cminus.show(False) self.sbui.C.Cround.show(False) self.sbui.C.Ccenter.show(False) self.sbui.C.Cplus.show(False) # make it real self.sbWatcherInitialize() self.window.addGlyphEditorSubview(self.sbui) self.updateValues() self.buildMatchBase() windowViewManger[self.window] = self.sbui