class TRGlyphInfo(QtGui.QVBoxLayout): # - Split/Break contour def __init__(self): super(TRGlyphInfo, self).__init__() # -- Init self.table_dict = {0: {0: None}} # Empty table # -- Widgets self.lay_head = QtGui.QGridLayout() self.edt_glyphName = QtGui.QLineEdit() self.edt_glyphsSeq = QtGui.QLineEdit() self.edt_glyphName.setToolTip('Current Glyph Name.') self.edt_glyphsSeq.setToolTip( 'Manual entry for Glyph names to populate stats info. Separated by SPACE' ) self.cmb_query = QtGui.QComboBox() self.cmb_charset = QtGui.QComboBox() self.cmb_query.setToolTip('Select query type.') self.cmb_charset.setToolTip('Select character set to compare with.') # --- Add queries self.query_list = [ '(BBox) Bounding Box Width', '(BBox) Bounding Box Height', '(Metrics) Advance Width', '(Metrics) Left Side-bearing', '(Metrics) Right Side-bearing' ] self.cmb_query.addItems(self.query_list) self.btn_refresh = QtGui.QPushButton('&Refresh') self.btn_populate = QtGui.QPushButton('&Populate') self.btn_get = QtGui.QPushButton('&Window') self.btn_probe = QtGui.QPushButton('Glyph') self.btn_units = QtGui.QPushButton('Percent') self.btn_refresh.setToolTip('Refresh active glyph and table.') self.btn_populate.setToolTip( 'Populate character set selector from current font.') self.btn_get.setToolTip('Get current string from active Glyph Window.') self.btn_probe.setToolTip( 'Toggle between Row (Glyph) or Column (Layer) based comparison.') self.btn_units.setToolTip( 'Toggle the results beeing shown as (Units) or (Percent).') self.btn_probe.setCheckable(True) self.btn_units.setCheckable(True) self.btn_probe.setChecked(False) self.btn_units.setChecked(False) # !!! Disable for now self.cmb_charset.setEnabled(False) self.btn_populate.setEnabled(False) # -- Build Layout self.lay_head.addWidget(QtGui.QLabel('G:'), 0, 0, 1, 1) self.lay_head.addWidget(self.edt_glyphName, 0, 1, 1, 5) self.lay_head.addWidget(self.btn_refresh, 0, 6, 1, 2) #self.lay_head.addWidget(QtGui.QLabel('C:'), 1,0,1,1) #self.lay_head.addWidget(self.cmb_charset, 1,1,1,5) #self.lay_head.addWidget(self.btn_populate, 1,6,1,2) self.lay_head.addWidget(QtGui.QLabel('C:'), 2, 0, 1, 1) self.lay_head.addWidget(self.edt_glyphsSeq, 2, 1, 1, 5) self.lay_head.addWidget(self.btn_get, 2, 6, 1, 2) self.lay_head.addWidget(QtGui.QLabel('Q:'), 3, 0, 1, 1) self.lay_head.addWidget(self.cmb_query, 3, 1, 1, 5) self.lay_head.addWidget(self.btn_probe, 3, 6, 1, 2) self.addLayout(self.lay_head) # -- Table self.tab_stats = TRTableView(self.table_dict) #self.refresh() # -- Note/Descriotion self.addWidget(self.tab_stats) self.addWidget(self.btn_units) # -- Addons self.btn_refresh.clicked.connect(self.refresh) self.btn_populate.clicked.connect(self.populate) self.btn_get.clicked.connect(self.get_string) self.btn_probe.clicked.connect(self.toggle_query) self.btn_units.clicked.connect(self.toggle_units) self.cmb_query.currentIndexChanged.connect(self.refresh) # -- Table Styling self.tab_stats.horizontalHeader().setStretchLastSection(False) self.tab_stats.resizeColumnsToContents() self.tab_stats.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self.tab_stats.selectionModel().selectionChanged.connect( self.change_selection) def populate(self): font = pFont() self.glyphNames = font.getGlyphNamesDict() self.cmb_charset.addItems(sorted(self.glyphNames.keys())) def get_string(self): workspace = pWorkspace() glyphsSeq = ' '.join( sorted( list( set([ glyph.name for glyph in workspace.getTextBlockGlyphs() ])))) self.edt_glyphsSeq.setText(glyphsSeq) def refresh(self, layer=None): # - Init font = pFont() glyph = eGlyph() pLayers = ( True, True, False, False ) # !!! Quickfix: Stats crashes FL after mode switch + refresh wLayers = glyph._prepareLayers(pLayers) self.table_data, self.table_proc = {}, {} current_glyph_name = eGlyph().name self.edt_glyphName.setText(current_glyph_name) # - Populate table process_glyph_names = [current_glyph_name ] + self.edt_glyphsSeq.text.split(' ') if len( self.edt_glyphsSeq.text) else [ current_glyph_name ] for glyph_name in process_glyph_names: wGlyph = font.glyph(glyph_name) self.table_data[glyph_name] = { layer: self.process_query(wGlyph, layer, self.cmb_query.currentText) for layer in wLayers } self.tab_stats.setTable(self.table_data) self.tab_stats.resizeColumnsToContents() def change_selection(self): # - Helper for avoiding ZeroDivision error def noZero(value): return value if value != 0 else 1 # - Init base_index = self.tab_stats.selectionModel().selectedIndexes[0] base_name = self.tab_stats.verticalHeaderItem(base_index.row()).text() base_layer = self.tab_stats.horizontalHeaderItem( base_index.column()).text() for glyph_name, glyph_layers in self.table_data.iteritems(): if not self.btn_probe.isChecked(): if self.btn_units.isChecked(): self.table_proc[glyph_name] = { layer_name: -round( self.table_data[base_name][layer_name] - layer_value, 2) for layer_name, layer_value in glyph_layers.iteritems() } else: self.table_proc[glyph_name] = { layer_name: '%s %%' % round( ratfrac( noZero(layer_value), noZero( self.table_data[base_name][layer_name])), 2) for layer_name, layer_value in glyph_layers.iteritems() } else: if self.btn_units.isChecked(): self.table_proc[glyph_name] = { layer_name: -round( self.table_data[glyph_name][base_layer] - layer_value, 2) for layer_name, layer_value in glyph_layers.iteritems() } else: self.table_proc[glyph_name] = { layer_name: '%s %%' % round( ratfrac( noZero(layer_value), noZero( self.table_data[glyph_name][base_layer])), 2) for layer_name, layer_value in glyph_layers.iteritems() } self.tab_stats.setTable(self.table_proc) self.tab_stats.resizeColumnsToContents() def toggle_query(self): if self.btn_probe.isChecked(): self.btn_probe.setText('Layer') self.tab_stats.setSelectionBehavior( QtGui.QAbstractItemView.SelectColumns) else: self.btn_probe.setText('Glyph') self.tab_stats.setSelectionBehavior( QtGui.QAbstractItemView.SelectRows) def toggle_units(self): if self.btn_units.isChecked(): self.btn_units.setText('Units') else: self.btn_units.setText('Percent') def process_query(self, glyph, layer, query): if 'bbox' in query.lower() and 'width' in query.lower(): return glyph.getBounds(layer).width() if 'bbox' in query.lower() and 'height' in query.lower(): return glyph.getBounds(layer).height() if 'metrics' in query.lower() and 'advance' in query.lower(): return glyph.getAdvance(layer) if 'metrics' in query.lower() and 'left' in query.lower(): return glyph.getLSB(layer) if 'metrics' in query.lower() and 'right' in query.lower(): return glyph.getRSB(layer)
class TRSmartCorner(QtGui.QVBoxLayout): # - Split/Break contour def __init__(self, parentWidget): super(TRSmartCorner, self).__init__() self.upper_widget = parentWidget # -- Init self.active_font = pFont() self.builder = None self.font_masters = self.active_font.masters() self.empty_preset = lambda row: OrderedDict([(row, OrderedDict([('Preset', 'Preset %s' %row)] + [(master, '0') for master in self.font_masters]))]) self.table_dict = self.empty_preset(0) self.last_preset = 0 # -- Widgets self.lay_head = QtGui.QGridLayout() self.edt_glyphName = QtGui.QLineEdit() self.edt_glyphName.setPlaceholderText('Glyph name') # -- Buttons self.btn_getBuilder = QtGui.QPushButton('Set &Builder') self.btn_findBuilder = QtGui.QPushButton('&From Font') self.btn_addPreset = QtGui.QPushButton('Add') self.btn_delPreset = QtGui.QPushButton('Remove') self.btn_resetPreset = QtGui.QPushButton('Reset') self.btn_loadPreset = QtGui.QPushButton('&Load Presets') self.btn_savePreset = QtGui.QPushButton('&Save Presets') self.btn_apply_smartCorner = QtGui.QPushButton('&Apply Smart Corner') self.btn_remove_smartCorner = QtGui.QPushButton('R&emove Smart Corner') self.btn_remove_presetCorner = QtGui.QPushButton('&Find and Remove') self.btn_apply_smartCorner.setToolTip('Apply Smart Corner preset on SELECTED nodes.') self.btn_remove_smartCorner.setToolTip('Remove Smart Corner on SELECTED nodes.') self.btn_remove_presetCorner.setToolTip('Find and remove all Smart Corners that equal the currently selected preset.') self.btn_apply_round = QtGui.QPushButton('&Round') self.btn_apply_mitre = QtGui.QPushButton('&Mitre') self.btn_apply_overlap = QtGui.QPushButton('&Overlap') self.btn_apply_trap = QtGui.QPushButton('&Trap') self.btn_rebuild = QtGui.QPushButton('Rebuild corner') self.btn_getBuilder.setMinimumWidth(70) self.btn_findBuilder.setMinimumWidth(70) self.btn_apply_round.setMinimumWidth(70) self.btn_apply_mitre.setMinimumWidth(70) self.btn_apply_overlap.setMinimumWidth(70) self.btn_apply_trap.setMinimumWidth(70) self.btn_rebuild.setMinimumWidth(70) self.btn_addPreset.setMinimumWidth(70) self.btn_delPreset.setMinimumWidth(70) self.btn_loadPreset.setMinimumWidth(140) self.btn_savePreset.setMinimumWidth(140) self.btn_apply_smartCorner.setMinimumWidth(140) self.btn_remove_smartCorner.setMinimumWidth(140) self.btn_remove_presetCorner.setMinimumWidth(140) self.btn_getBuilder.setCheckable(True) self.btn_getBuilder.setChecked(False) self.btn_findBuilder.setEnabled(False) self.btn_apply_round.setEnabled(False) self.btn_getBuilder.clicked.connect(lambda: self.getBuilder()) self.btn_addPreset.clicked.connect(lambda: self.preset_modify(False)) self.btn_delPreset.clicked.connect(lambda: self.preset_modify(True)) self.btn_resetPreset.clicked.connect(lambda: self.preset_reset()) self.btn_loadPreset.clicked.connect(lambda: self.preset_load()) self.btn_savePreset.clicked.connect(lambda: self.preset_save()) self.btn_apply_smartCorner.clicked.connect(lambda: self.apply_SmartCorner(False)) self.btn_remove_smartCorner.clicked.connect(lambda: self.apply_SmartCorner(True)) self.btn_remove_presetCorner.clicked.connect(lambda: self.remove_SmartCorner()) #self.btn_apply_round.clicked.connect(lambda: self.apply_round()) self.btn_apply_mitre.clicked.connect(lambda: self.apply_mitre(False)) self.btn_apply_overlap.clicked.connect(lambda: self.apply_mitre(True)) self.btn_apply_trap.clicked.connect(lambda: self.apply_trap()) self.btn_rebuild.clicked.connect(lambda: self.rebuild()) # -- Preset Table self.tab_presets = TRTableView(None) self.preset_reset() # -- Build Layout self.lay_head.addWidget(QtGui.QLabel('Value Presets:'), 0,0,1,8) self.lay_head.addWidget(self.btn_loadPreset, 1,0,1,4) self.lay_head.addWidget(self.btn_savePreset, 1,4,1,4) self.lay_head.addWidget(self.btn_addPreset, 2,0,1,2) self.lay_head.addWidget(self.btn_delPreset, 2,2,1,2) self.lay_head.addWidget(self.btn_resetPreset, 2,4,1,4) self.lay_head.addWidget(self.tab_presets, 3,0,5,8) self.lay_head.addWidget(QtGui.QLabel('Corner Actions:'),10, 0, 1, 8) self.lay_head.addWidget(self.btn_apply_round, 11, 0, 1, 2) self.lay_head.addWidget(self.btn_apply_mitre, 11, 2, 1, 2) self.lay_head.addWidget(self.btn_apply_overlap, 11, 4, 1, 2) self.lay_head.addWidget(self.btn_apply_trap, 11, 6, 1, 2) self.lay_head.addWidget(self.btn_rebuild, 12, 0, 1, 8) self.lay_head.addWidget(QtGui.QLabel('Smart Corner:'), 13,0,1,8) self.lay_head.addWidget(QtGui.QLabel('Builder: '), 14,0,1,1) self.lay_head.addWidget(self.edt_glyphName, 14,1,1,3) self.lay_head.addWidget(self.btn_getBuilder, 14,4,1,2) self.lay_head.addWidget(self.btn_findBuilder, 14,6,1,2) self.lay_head.addWidget(self.btn_remove_smartCorner, 15,0,1,4) self.lay_head.addWidget(self.btn_remove_presetCorner, 15,4,1,4) self.lay_head.addWidget(self.btn_apply_smartCorner, 16,0,1,8) self.addLayout(self.lay_head) # - Presets management ------------------------------------------------ def preset_reset(self): self.builder = None self.active_font = pFont() self.font_masters = self.active_font.masters() self.table_dict = self.empty_preset(0) self.tab_presets.clear() self.tab_presets.setTable(self.table_dict, sortData=(False, False)) self.tab_presets.horizontalHeader().setStretchLastSection(False) self.tab_presets.verticalHeader().hide() #self.tab_presets.resizeColumnsToContents() def preset_modify(self, delete=False): table_rawList = self.tab_presets.getTable(raw=True) if delete: for selection in self.tab_presets.selectionModel().selectedIndexes: table_rawList.pop(selection.row()) print selection.row() new_entry = OrderedDict() for key, data in table_rawList: new_entry[key] = OrderedDict(data) if not delete: new_entry[len(table_rawList)] = self.empty_preset(len(table_rawList)).items()[0][1] self.tab_presets.setTable(new_entry, sortData=(False, False)) def preset_load(self): fontPath = os.path.split(self.active_font.fg.path)[0] fname = QtGui.QFileDialog.getOpenFileName(self.upper_widget, 'Load presets from file', fontPath, 'TypeRig JSON (*.json)') if fname != None: with open(fname, 'r') as importFile: imported_data = json.load(importFile) # - Convert Data new_data = OrderedDict() for key, data in imported_data: new_data[key] = OrderedDict(data) self.tab_presets.setTable(new_data, sortData=(False, False)) print 'LOAD:\t Font:%s; Presets loaded from: %s.' %(self.active_font.name, fname) def preset_save(self): fontPath = os.path.split(self.active_font.fg.path)[0] fname = QtGui.QFileDialog.getSaveFileName(self.upper_widget, 'Save presets to file', fontPath, 'TypeRig JSON (*.json)') if fname != None: with open(fname, 'w') as exportFile: json.dump(self.tab_presets.getTable(raw=True), exportFile) print 'SAVE:\t Font:%s; Presets saved to: %s.' %(self.active_font.name, fname) def getPreset(self): table_raw = self.tab_presets.getTable(raw=True) ''' try: active_preset_index = self.tab_presets.selectionModel().selectedIndexes[0].row() except IndexError: active_preset_index = None ''' active_preset_index = self.tab_presets.selectionModel().selectedIndexes[0].row() if active_preset_index is None: active_preset_index = self.last_preset else: self.last_preset = active_preset_index return dict(table_raw[active_preset_index][1][1:]) # - Basic Corner ------------------------------------------------ def apply_mitre(self, doKnot=False): # - Init process_glyphs = getProcessGlyphs(pMode) active_preset = self.getPreset() # - Process if len(process_glyphs): for glyph in process_glyphs: if glyph is not None: wLayers = glyph._prepareLayers(pLayers) for layer in reversed(wLayers): if layer in active_preset.keys(): selection = glyph.selectedNodes(layer, filterOn=True, extend=eNode, deep=True) for node in reversed(selection): if not doKnot: node.cornerMitre(float(active_preset[layer])) else: node.cornerMitre(-float(active_preset[layer]), True) action = 'Mitre Corner' if not doKnot else 'Overlap Corner' glyph.update() glyph.updateObject(glyph.fl, '%s @ %s.' %(action, '; '.join(active_preset.keys()))) def apply_trap(self): # - Init process_glyphs = getProcessGlyphs(pMode) active_preset = self.getPreset() # - Process if len(process_glyphs): for glyph in process_glyphs: if glyph is not None: wLayers = glyph._prepareLayers(pLayers) for layer in reversed(wLayers): if layer in active_preset.keys(): selection = glyph.selectedNodes(layer, filterOn=True, extend=eNode, deep=True) for node in reversed(selection): preset_values = tuple([float(item.strip()) for item in active_preset[layer].split(',')]) node.cornerTrapInc(*preset_values) glyph.update() glyph.updateObject(glyph.fl, '%s @ %s.' %('Ink Trap', '; '.join(active_preset.keys()))) def rebuild(self): # - Init process_glyphs = getProcessGlyphs(pMode) # - Process if len(process_glyphs): for glyph in process_glyphs: if glyph is not None: wLayers = glyph._prepareLayers(pLayers) for layer in wLayers: selection = glyph.selectedNodes(layer, filterOn=True, extend=eNode, deep=True) if len(selection) > 1: node_first = selection[0] node_last = selection[-1] line_in = node_first.getPrevLine() if node_first.getPrevOn(False) not in selection else node_first.getNextLine() line_out = node_last.getNextLine() if node_last.getNextOn(False) not in selection else node_last.getPrevLine() crossing = line_in & line_out node_first.smartReloc(*crossing) node_first.parent.removeNodesBetween(node_first.fl, node_last.getNextOn()) glyph.update() glyph.updateObject(glyph.fl, 'Rebuild corner: %s nodes reduced; At layers: %s' %(len(selection), '; '.join(wLayers))) # - Smart Corner ------------------------------------------------ def getBuilder(self): if self.btn_getBuilder.isChecked(): if len(self.edt_glyphName.text): builder_glyph = self.active_font.glyph(self.edt_glyphName.text) else: builder_glyph = eGlyph() self.edt_glyphName.setText(builder_glyph.name) if builder_glyph is not None: temp_builder = builder_glyph.getBuilders() if len(temp_builder.keys()) and filter_name in temp_builder.keys(): self.builder = temp_builder[filter_name][0] self.btn_getBuilder.setText('Release') else: self.builder = None self.edt_glyphName.clear() self.btn_getBuilder.setText('Set Builder') def process_setFilter(self, glyph, shape, layer, builder, suffix='.old'): new_container = fl6.flShape() new_container.shapeData.name = shape.shapeData.name if len(shape.shapeData.name): shape.shapeData.name += suffix #!!!! TODO: transformation copy and delete new_container.include(shape, glyph.layer(layer)) new_container.shapeBuilder = builder.clone() new_container.update() glyph.layer(layer).addShape(new_container) #glyph.layer(layer).update() def process_smartCorner(self, glyph, preset): wLayers = glyph._prepareLayers(pLayers) nodes_at_shapes = {} # - Build selection for work_layer in wLayers: if work_layer in preset.keys(): # - Init selection_deep = [(item[0], item[2]) for item in glyph.selectedAtShapes(layer=work_layer, index=False, deep=True)] selection_shallow = [(item[0], item[2]) for item in glyph.selectedAtShapes(layer=work_layer, index=False, deep=False)] selection = selection_deep + selection_shallow # - Build note to shape reference nodes_at_shapes[work_layer] = [(shape, [node for shape, node in list(nodes)]) for shape, nodes in groupby(selection, key=itemgetter(0))] # - Process glyph for work_layer in wLayers: if work_layer in nodes_at_shapes.keys(): # - Build filter if not present for work_shape, node_list in nodes_at_shapes[work_layer]: if len(glyph.containers(work_layer)): for container in glyph.containers(work_layer): if work_shape not in container.includesList: self.process_setFilter(glyph, work_shape, work_layer, self.builder) else: self.process_setFilter(glyph, work_shape, work_layer, self.builder) # - Process the nodes process_nodes = [pNode(node) for shape, node_list in nodes_at_shapes[work_layer] for node in node_list] for work_node in process_nodes: angle_value = preset[work_layer] if 'DEL' not in angle_value.upper(): work_node.setSmartAngle(float(angle_value)) else: work_node.delSmartAngle() #glyph.update() #glyph.updateObject(glyph.fl, 'DONE:\t Glyph: %s; Filter: Smart corner; Parameters: %s' %(glyph.name, preset)) def apply_SmartCorner(self, remove=False): # NOTE: apply and remove here apply only to soelected nodes. if self.builder is not None: # - Init process_glyphs = getProcessGlyphs(pMode) active_preset = self.getPreset() if remove: # Build a special preset that deletes active_preset = {key:'DEL' for key in active_preset.keys()} # - Process if len(process_glyphs): for work_glyph in process_glyphs: if work_glyph is not None: self.process_smartCorner(work_glyph, active_preset) self.update_glyphs(process_glyphs, True) print 'DONE:\t Filter: Smart Corner; Glyphs: %s' %'; '.join([g.name for g in process_glyphs]) else: print 'ERROR:\t Please specify a Glyph with suitable Shape Builder (Smart corner) first!' def remove_SmartCorner(self): # Finds active preset in glyphs smart corners and removes them # - Init process_glyphs = getProcessGlyphs(pMode) active_preset = self.getPreset() # - Process if len(process_glyphs): for work_glyph in process_glyphs: if work_glyph is not None: # - Init wLayers = work_glyph._prepareLayers(pLayers) smart_corners, target_corners = [], [] # - Get all smart nodes/corners for layer in wLayers: for builder in work_glyph.getBuilders(layer)[filter_name]: smart_corners += builder.getSmartNodes() if len(smart_corners): for node in smart_corners: wNode = eNode(node) if wNode.getSmartAngleRadius() == float(active_preset[layer]): wNode.delSmartAngle() self.update_glyphs(process_glyphs, True) print 'DONE:\t Filter: Remove Smart Corner; Glyphs: %s' %'; '.join([g.name for g in process_glyphs]) def update_glyphs(self, glyphs, complete=False): for glyph in glyphs: glyph.update() if not complete: # Partial update - contour only for contour in glyph.contours(): contour.changed() else: # Full update - with undo snapshot glyph.updateObject(glyph.fl, verbose=False)
class TRContourSelect(QtGui.QVBoxLayout): # - Split/Break contour def __init__(self): super(TRContourSelect, self).__init__() # -- Init self.table_dict = {0: {0: None}} # Empty table self.layer_names = [] # Empty layer list #self.table_columns = 'N,Shape,Contour,X,Y,Type,Relative'.split(',') self.table_columns = 'N,Sh,Cn,X,Y,Type,Rel'.split(',') # -- Widgets self.lay_head = QtGui.QGridLayout() self.edt_glyphName = QtGui.QLineEdit() self.cmb_layer = QtGui.QComboBox() self.btn_refresh = QtGui.QPushButton('&Refresh') self.btn_apply = QtGui.QPushButton('&Apply') self.btn_apply.setEnabled(False) # -- Build Layout self.lay_head.addWidget(QtGui.QLabel('G:'), 0, 0, 1, 1) self.lay_head.addWidget(self.edt_glyphName, 0, 1, 1, 5) self.lay_head.addWidget(self.btn_refresh, 0, 6, 1, 2) self.lay_head.addWidget(QtGui.QLabel('L:'), 1, 0, 1, 1) self.lay_head.addWidget(self.cmb_layer, 1, 1, 1, 5) self.lay_head.addWidget(self.btn_apply, 1, 6, 1, 2) self.addLayout(self.lay_head) # -- Node List Table self.tab_nodes = TRTableView(self.table_dict) self.addWidget(self.tab_nodes) #self.refresh() # Build Table self.btn_refresh.clicked.connect(lambda: self.refresh()) self.cmb_layer.currentIndexChanged.connect(lambda: self.changeLayer()) # -- Table Styling self.tab_nodes.horizontalHeader().setStretchLastSection(False) self.tab_nodes.setSortingEnabled(True) self.tab_nodes.horizontalHeader().sortIndicatorChanged.connect( lambda: self.tab_nodes.resizeColumnsToContents()) self.tab_nodes.verticalHeader().hide() self.tab_nodes.resizeColumnsToContents() self.tab_nodes.selectionModel().selectionChanged.connect( self.selectionChanged) self.tab_nodes.itemChanged.connect(self.valueChanged) def refresh(self, layer=None): # - Init self.glyph = eGlyph() self.edt_glyphName.setText(eGlyph().name) self.table_dict = {} node_count = 0 # - Populate layers if layer is None: self.layer_names = [ item.name for item in self.glyph.layers() if '#' not in item.name ] self.cmb_layer.clear() self.cmb_layer.addItems(self.layer_names) self.cmb_layer.setCurrentIndex( self.layer_names.index(self.glyph.activeLayer().name)) # - Populate table try: # Dirty Quick Fix - Solve later for sID, shape in enumerate(self.glyph.shapes(layer)): for cID, contour in enumerate(shape.contours): for nID, node in enumerate(contour.nodes()): table_values = [ node_count, sID, cID, round(node.x, 2), round(node.y, 2), node.type, round(eNode(node).distanceToPrev(), 2) ] self.table_dict[node_count] = OrderedDict( zip(self.table_columns, table_values)) node_count += 1 self.tab_nodes.setTable(self.table_dict, (False, False)) self.tab_nodes.resizeColumnsToContents() except AttributeError: pass def doCheck(self): if self.glyph.fg.id != fl6.CurrentGlyph( ).id and self.glyph.fl.name != fl6.CurrentGlyph().name: print '\nERRO:\tGlyph mismatch:\n\tCurrent active glyph: %s\n\tOutline panel glyph: %s' % ( fl6.CurrentGlyph(), self.glyph.fg) print 'WARN:\tNo action taken! Forcing refresh!' self.refresh() return 0 return 1 def changeLayer(self): if self.doCheck(): self.refresh(self.cmb_layer.currentText) def selectionChanged(self): if self.doCheck(): if self.cmb_layer.currentText == self.glyph.activeLayer().name: # - Prepare self.glyph.fl.unselectAllNodes() # - Process for cel_coords in self.tab_nodes.selectionModel( ).selectedIndexes: #print self.tab_nodes.item(cel_coords.row(), cel_coords.column()).text() selected_nid = int( self.tab_nodes.item(cel_coords.row(), 0).text()) self.glyph.nodes(self.cmb_layer.currentText )[selected_nid].selected = True # - Finish self.glyph.updateObject(self.glyph.fl, verbose=False) def valueChanged(self, item): if self.doCheck(): #print item.text(), item.row() try: # Dirty Quick Fix - Solve later # - Init x_col, y_col = self.table_columns.index( 'X'), self.table_columns.index('Y') active_nid = int(self.tab_nodes.item(item.row(), 0).text()) # - Process if item.column() == x_col or item.column() == y_col: new_x = float( self.tab_nodes.item(item.row(), x_col).text()) new_y = float( self.tab_nodes.item(item.row(), y_col).text()) active_node = eNode( self.glyph.nodes( self.cmb_layer.currentText)[active_nid]) active_node.reloc(new_x, new_y) # -- Finish self.glyph.update() self.glyph.updateObject(self.glyph.fl, verbose=False) except AttributeError: pass
class WFontMetrics(QtGui.QWidget): def __init__(self, parentWidget): super(WFontMetrics, self).__init__() # - Init self.grid = QtGui.QGridLayout() self.upperWidget = parentWidget self.activeFont = pFont() self.metricData = { layer: self.activeFont.fontMetrics().asDict(layer) for layer in self.activeFont.masters() } # - Interface self.btn_apply = QtGui.QPushButton('Apply Changes') self.btn_reset = QtGui.QPushButton('Reset') self.btn_open = QtGui.QPushButton('Open') self.btn_save = QtGui.QPushButton('Save') self.btn_apply.clicked.connect(self.applyChanges) self.btn_reset.clicked.connect(self.resetChanges) self.btn_save.clicked.connect(self.exportMetrics) self.btn_open.clicked.connect(self.importMetrics) self.tab_fontMetrics = TRTableView(self.metricData) # - Build lbl_name = QtGui.QLabel('Font Metrics (All Masters)') lbl_name.setMaximumHeight(20) self.grid.addWidget(lbl_name, 0, 0, 1, 24) self.grid.addWidget(self.tab_fontMetrics, 1, 0, 5, 21) self.grid.addWidget(self.btn_save, 1, 21, 1, 3) self.grid.addWidget(self.btn_open, 2, 21, 1, 3) self.grid.addWidget(self.btn_reset, 4, 21, 1, 3) self.grid.addWidget(self.btn_apply, 5, 21, 1, 3) for i in range(1, 6): self.grid.setRowStretch(i, 2) self.setLayout(self.grid) def applyChanges(self): oldMetricData = self.activeFont.fontMetrics() newMetricData = self.tab_fontMetrics.getTable() for layer, metrics in newMetricData.iteritems(): oldMetricData.fromDict(metrics, layer) self.activeFont.fl.update() self.activeFont.updateObject( self.activeFont.fl, 'Font:%s; Font Metrics Updated!.' % self.activeFont.name) def resetChanges(self): self.tab_fontMetrics.setTable(self.metricData, True) print 'DONE:\t Font:%s; Font Metrics realoaded.' % self.activeFont.name def exportMetrics(self): fontPath = os.path.split(self.activeFont.fg.path)[0] fname = QtGui.QFileDialog.getSaveFileName(self.upperWidget, 'Save Font Metrics to file', fontPath, '*.json') if fname != None: with open(fname, 'w') as exportFile: json.dump(self.metricData, exportFile) print 'SAVE:\t Font:%s; Font Metrics saved to %s.' % ( self.activeFont.name, fname) def importMetrics(self): fontPath = os.path.split(self.activeFont.fg.path)[0] fname = QtGui.QFileDialog.getOpenFileName( self.upperWidget, 'Open Metric Expressions from file', fontPath) if fname != None: with open(fname, 'r') as importFile: loadedData = json.load(importFile) self.tab_fontMetrics.setTable(loadedData) print 'LOAD:\t Font:%s; Font Metrics loaded from %s.' % ( self.activeFont.name, fname) print 'NOTE:\t Use < Apply > to apply loaded metrics to active Font!'