diff options
| author | Adrien Tétar | 2015-05-04 22:37:24 +0200 |
|---|---|---|
| committer | Adrien Tétar | 2015-05-04 22:37:24 +0200 |
| commit | 64b9388cc4d480fbc8ab87b889e7632c1040a048 (patch) | |
| tree | ce5bd9d481ace204a6870a76e4eec424ea552f3b /Lib | |
| parent | 2cb4fead2e5af288eac686b182ba5d1ad17ae540 (diff) | |
| download | trufont-64b9388cc4d480fbc8ab87b889e7632c1040a048.tar.bz2 | |
More
Diffstat (limited to 'Lib')
| -rw-r--r-- | Lib/defconQt/fontView.py | 10 | ||||
| -rw-r--r-- | Lib/defconQt/spacecenter.py | 105 | ||||
| -rw-r--r-- | Lib/defconQt/svgViewer.py | 160 |
3 files changed, 225 insertions, 50 deletions
diff --git a/Lib/defconQt/fontView.py b/Lib/defconQt/fontView.py index b17dc52..61e7792 100644 --- a/Lib/defconQt/fontView.py +++ b/Lib/defconQt/fontView.py @@ -119,6 +119,9 @@ class CharacterWidget(QWidget): endRow = redrawRect.bottom() // self.squareSize beginColumn = redrawRect.left() // self.squareSize endColumn = redrawRect.right() // self.squareSize + + painter.drawLine(redrawRect.left(), redrawRect.top(), redrawRect.left(), redrawRect.bottom()) + painter.drawLine(0, 0, redrawRect.right(), 0) # selection code firstKey = min(self.lastKey, self.moveKey) @@ -134,9 +137,10 @@ class CharacterWidget(QWidget): key = row * self.columns + column if key > len(self.glyphs)-1: break - painter.drawRect(column * self.squareSize, - row * self.squareSize, self.squareSize, - self.squareSize) + rightEdgeX = column * self.squareSize + self.squareSize + bottomEdgeY = row * self.squareSize + self.squareSize + painter.drawLine(rightEdgeX, row * self.squareSize + 1, rightEdgeX, bottomEdgeY) + painter.drawLine(rightEdgeX, bottomEdgeY, column * self.squareSize + 1, bottomEdgeY) # selection code if key == firstKey: diff --git a/Lib/defconQt/spacecenter.py b/Lib/defconQt/spacecenter.py index e82dcad..9b139a8 100644 --- a/Lib/defconQt/spacecenter.py +++ b/Lib/defconQt/spacecenter.py @@ -4,8 +4,10 @@ from PyQt5.QtGui import (QBrush, QColor, QFont, QLinearGradient, QPainter, from PyQt5.QtWidgets import (QAbstractItemView, QApplication, QComboBox, QGridLayout, QLabel, QLineEdit, QMainWindow, QScrollArea, QTableView, QTableWidget, QTableWidgetItem, QVBoxLayout, QSizePolicy, QSpinBox, QToolBar, QWidget) +defaultPointSize = 150 + class MainSpaceWindow(QWidget): - def __init__(self, font, string, pointSize=200, parent=None): + def __init__(self, font, string="Hello World", pointSize=defaultPointSize, parent=None): super(MainSpaceWindow, self).__init__(parent) self.font = font @@ -22,6 +24,10 @@ class MainSpaceWindow(QWidget): layout.setSpacing(0) self.setLayout(layout) self.resize(600,500) + self.toolbar.comboBox.lineEdit().editingFinished.connect(self.canvas._pointSizeChanged) + self.toolbar.textField.textEdited.connect(self.canvas._textChanged) + self.toolbar.textField.textEdited.connect(self.table._textChanged) + self.table.cellChanged.connect(self.canvas._metricsChanged) self.setWindowTitle("%s%s%s%s" % ("Space center – ", self.font.info.familyName, " ", self.font.info.styleName)) @@ -37,35 +43,64 @@ pointSizes = [50, 75, 100, 125, 150, 200, 250, 300, 350, 400, 450, 500] class FontToolBar(QToolBar): def __init__(self, font, pointSize, string, parent=None): super(FontToolBar, self).__init__(parent) - self.addWidget(QLineEdit(string)) - comboBox = QComboBox() - comboBox.setEditable(True) + self.textField = QLineEdit(string) + self.comboBox = QComboBox() + self.comboBox.setEditable(True) + # Should I allow this? What does robofont do here? + #self.comboBox.setInsertPolicy(QComboBox.NoInsert) for p in pointSizes: - comboBox.addItem(str(p)) - comboBox.lineEdit().setText(str(pointSize)) - self.addWidget(comboBox) + self.comboBox.addItem(str(p)) + self.comboBox.lineEdit().setText(str(pointSize)) + + self.addWidget(self.textField) + self.addWidget(self.comboBox) class GlyphsCanvas(QWidget): - def __init__(self, font, string, pointSize=150, parent=None): + def __init__(self, font, string, pointSize=defaultPointSize, parent=None): super(GlyphsCanvas, self).__init__(parent) self.font = font self.string = string self.ptSize = pointSize - self.calculateScale(self.font, self.ptSize) - self.padding = 12 + self.calculateScale() + self.padding = 10 - def calculateScale(self, font, ptSize): - if font.info.unitsPerEm is None: return - upm = font.info.unitsPerEm + def calculateScale(self): + if self.font.info.unitsPerEm is None: return + upm = self.font.info.unitsPerEm if not upm > 0: upm = 1000 - scale = ptSize / float(self.font.info.unitsPerEm) + scale = self.ptSize / float(self.font.info.unitsPerEm) if scale < .01: scale = 0.01 self.scale = scale + def _pointSizeChanged(self, pointSize): + self.ptSize = int(pointSize) + self.calculateScale() + self.update() + + def _textChanged(self, newText): + self.string = newText + self.update() + + def _metricsChanged(self, row, col): + item = int(self.parent().table.item(row, col).text()) + # TODO: update width on the QTableWidget when sidebearing changes. + # stop passing signals and use defcon notificationHandler instead + # -1 because the first col contains descriptive text + glyph = self.font.unicodeData.glyphNameForUnicode(ord(self.string[col-1])) + if row == 1: + self.font[glyph].width = item + elif row == 2: + self.font[glyph].leftMargin = item + elif row == 3: + self.font[glyph].rightMargin = item + self.update() + # if we have a cell clicked in and we click on the canvas, # give focus to the canvas in order to quit editing + # TODO: Focus on individual chars and show BBox + active cell (see how rf does active cells) + # QTableWidget.scrollToItem() def mousePressEvent(self, event): self.setFocus(Qt.MouseFocusReason) @@ -73,7 +108,8 @@ class GlyphsCanvas(QWidget): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) painter.fillRect(0, 0, self.width(), self.height(), Qt.white) - painter.translate(self.padding, self.ptSize+self.font.info.descender*self.scale) + # TODO: should padding be added for the right boundary as well? I'd say no but not sure + painter.translate(self.padding, self.padding+self.ptSize+self.font.info.descender*self.scale) cur_width = 0 for c in self.string: @@ -81,7 +117,7 @@ class GlyphsCanvas(QWidget): if glyph not in self.font: continue # line wrapping if cur_width + self.font[glyph].width*self.scale + self.padding > self.width(): - painter.translate(-cur_width+self.padding, self.ptSize) + painter.translate(-cur_width, self.ptSize) cur_width = self.font[glyph].width*self.scale else: cur_width += self.font[glyph].width*self.scale @@ -114,16 +150,25 @@ class SpaceTable(QTableWidget): # don't set ItemIsEditable cell.setFlags(Qt.ItemIsEnabled) self.setItem(index, 0, cell) + # let's use this one column to compute the width of others + self._cellWidth = .7*self.columnWidth(0) self.setColumnWidth(0, .6*self.columnWidth(0)) self.horizontalHeader().hide() self.verticalHeader().hide() + # always show a scrollbar to fix layout self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self.resizeRowsToContents() self.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)) - self.fillGlyphs(self.font, self.string) + self.fillGlyphs() + # edit cell on single click, not double self.setEditTriggers(QAbstractItemView.CurrentChanged) + def _textChanged(self, newText): + self.string = newText + # TODO: we don't need to reallocate cells, split alloc and fill + self.fillGlyphs() + def sizeHint(self): # http://stackoverflow.com/a/7216486/2037879 height = sum(self.rowHeight(k) for k in range(self.rowCount())) @@ -132,31 +177,33 @@ class SpaceTable(QTableWidget): height += margins.top() + margins.bottom() return QSize(self.width(), height) - def fillGlyphs(self, font, string): + def fillGlyphs(self): def glyphTableWidgetItem(content, blockEdition=False): if content is not None: content = str(content) item = QTableWidgetItem(content) if content is None or blockEdition: # don't set ItemIsEditable item.setFlags(Qt.ItemIsEnabled) + # TODO: also set alignment during edition + # or leave it as it is now, is fine by me... #item.setTextAlignment(Qt.AlignCenter) return item - self.setColumnCount(len(string)+1) + self.setColumnCount(len(self.string)+1) dropped = 0 - for index, char in enumerate(string): - glyph = font.unicodeData.glyphNameForUnicode(ord(char)) + for index, char in enumerate(self.string): + glyph = self.font.unicodeData.glyphNameForUnicode(ord(char)) i = index-dropped+1 - if glyph not in font: dropped += 1; continue + if glyph not in self.font: dropped += 1; continue # TODO: should glyph name edit really be permitted here? # TODO: also find glyphs by /name or should be abstracted by input area or main object? - self.setItem(0, i, glyphTableWidgetItem(font[glyph].name, True)) - self.setItem(1, i, glyphTableWidgetItem(font[glyph].width)) - self.setItem(2, i, glyphTableWidgetItem(font[glyph].leftMargin)) - self.setItem(3, i, glyphTableWidgetItem(font[glyph].rightMargin)) - self.setColumnWidth(i, .7*self.columnWidth(i)) - self.setColumnCount(len(string)+1-dropped) - + self.setItem(0, i, glyphTableWidgetItem(self.font[glyph].name, True)) + self.setItem(1, i, glyphTableWidgetItem(self.font[glyph].width)) + self.setItem(2, i, glyphTableWidgetItem(self.font[glyph].leftMargin)) + self.setItem(3, i, glyphTableWidgetItem(self.font[glyph].rightMargin)) + self.setColumnWidth(i, self._cellWidth) + self.setColumnCount(len(self.string)+1-dropped) + def wheelEvent(self, event): cur = self.horizontalScrollBar().value() self.horizontalScrollBar().setValue(cur - event.angleDelta().y() / 120) diff --git a/Lib/defconQt/svgViewer.py b/Lib/defconQt/svgViewer.py index 9a919a4..5e7b80a 100644 --- a/Lib/defconQt/svgViewer.py +++ b/Lib/defconQt/svgViewer.py @@ -1,4 +1,4 @@ -from PyQt5.QtCore import QFile, QSize, Qt +from PyQt5.QtCore import QFile, QRectF, QSize, Qt from PyQt5.QtGui import QBrush, QColor, QImage, QPainter, QPainterPath, QPixmap, QPen from PyQt5.QtWidgets import (QActionGroup, QApplication, QFileDialog, QGraphicsItem, QGraphicsRectItem, QGraphicsScene, QGraphicsView, @@ -11,8 +11,7 @@ class MainGfxWindow(QMainWindow): def __init__(self, font=None, glyph=None, parent=None): super(MainGfxWindow, self).__init__(parent) - self.view = SvgView() - self.view.setGlyph(font, glyph) + self.view = SvgView(font, glyph, self) fileMenu = QMenu("&File", self) quitAction = fileMenu.addAction("E&xit") @@ -76,12 +75,12 @@ class MainGfxWindow(QMainWindow): class SvgView(QGraphicsView): Native, OpenGL, Image = range(3) - def __init__(self, parent=None): + def __init__(self, font, glyph, parent=None): super(SvgView, self).__init__(parent) self.renderer = SvgView.Native - self._font = None - self._glyph = None + self._font = font + self._glyph = glyph self._impliedPointSize = 1000 self._pointSize = None @@ -92,8 +91,8 @@ class SvgView(QGraphicsView): self._drawStroke = True self._showOffCurvePoints = True self._showOnCurvePoints = True - self._bezierHandleColor = QColor.fromRgbF(1, 1, 1, .2) - self._startPointColor = QColor.fromRgbF(1, 1, 1, .2)#Qt.blue + self._bezierHandleColor = QColor.fromRgbF(0, 0, 0, .2) + self._startPointColor = QColor.fromRgbF(0, 0, 0, .2)#Qt.blue self._backgroundColor = Qt.white#Qt.green self._offCurvePointColor = QColor.fromRgbF(.6, .6, .6, 1)#Qt.black self._onCurvePointColor = self._offCurvePointColor#Qt.red @@ -102,15 +101,22 @@ class SvgView(QGraphicsView): self._componentFillColor = QColor.fromRgbF(.2, .2, .3, .4)#Qt.darkGray self.setScene(QGraphicsScene(self)) + #self.scene().setSceneRect(0, self._font.info.ascender, self._glyph.width, self._font.info.unitsPerEm) # XXX: this should allow us to move the view but doesn't happen... self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) # TODO: only set this for moving tool, also set bounding box... self.setDragMode(QGraphicsView.ScrollHandDrag) # This rewinds view when scrolling, needed for check-board background - self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) + #self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) self.setRenderHint(QPainter.Antialiasing) + self.translate(0, self.height()*(1+self._font.info.descender/self._font.info.unitsPerEm)) + self.scale(1, -1) + self.addBackground() + self.addBlues() + self.addOutlines() + self.addPoints() # Prepare background check-board pattern. tilePixmap = QPixmap(64, 64) @@ -121,7 +127,7 @@ class SvgView(QGraphicsView): tilePainter.fillRect(32, 32, 32, 32, color) tilePainter.end() - self.setBackgroundBrush(QBrush(tilePixmap)) + #self.setBackgroundBrush(QBrush(tilePixmap)) def _getGlyphWidthHeight(self): if self._glyph.bounds: @@ -152,8 +158,8 @@ class SvgView(QGraphicsView): self._inverseScale = 1.0 / self._scale self._impliedPointSize = self._font.info.unitsPerEm * self._scale - def drawBackground(self, painter): - painter.fillRect(self.viewport().rect(), self._backgroundColor) + def drawBackground_(self, painter): + painter.fillRect(QRectF(self.viewport().rect()), self._backgroundColor) ''' p.save() p.resetTransform() @@ -163,7 +169,7 @@ class SvgView(QGraphicsView): ''' def drawBlues(self, painter): - width = self.viewport().width()# * self._inverseScale + width = self.width()# * self._inverseScale font = self._glyph.getParent() #painter.setCompositionMode(QPainter.CompositionMode_SourceOver) if font is None: @@ -316,6 +322,123 @@ class SvgView(QGraphicsView): text = "%d %d" % (x, y) self._drawTextAtPoint(text, attributes, (posX, posY), 3) """ + + def addBackground(self): + s = self.scene() + s.addRect(QRectF(self.viewport().rect()), QPen(Qt.NoPen), QBrush(self._backgroundColor)) + + def addBlues(self): + s = self.scene() + width = self._glyph.width# * self._inverseScale + font = self._glyph.getParent() + #painter.setCompositionMode(QPainter.CompositionMode_SourceOver) + if font is None: + return + attrs = ["postscriptBlueValues", "postscriptOtherBlues"] + for attr in attrs: + values = getattr(font.info, attr) + if not values: + continue + yMins = [i for index, i in enumerate(values) if not index % 2] + yMaxs = [i for index, i in enumerate(values) if index % 2] + for yMin, yMax in zip(yMins, yMaxs): + s.addRect(0, yMin, width, yMax - yMin, QPen(Qt.NoPen), QBrush(self._bluesColor)) + + def addOutlines(self): + s = self.scene() + # outlines + path = self._glyph.getRepresentation("defconQt.NoComponentsQPainterPath") + s.addPath(path, brush=QBrush(self._fillColor)) + # components + path = self._glyph.getRepresentation("defconQt.OnlyComponentsQPainterPath") + s.addPath(path, brush=QBrush(self._componentFillColor)) + + def addPoints(self): + s = self.scene() + # work out appropriate sizes and + # skip if the glyph is too small + pointSize = self._impliedPointSize + if pointSize > 550: + startPointSize = 21 + offCurvePointSize = 5 + onCurvePointSize = 6 + onCurveSmoothPointSize = 7 + elif pointSize > 250: + startPointSize = 15 + offCurvePointSize = 3 + onCurvePointSize = 4 + onCurveSmoothPointSize = 5 + elif pointSize > 175: + startPointSize = 9 + offCurvePointSize = 1 + onCurvePointSize = 2 + onCurveSmoothPointSize = 3 + else: + return + if pointSize > 250: + coordinateSize = 9 + else: + coordinateSize = 0 + # use the data from the outline representation + outlineData = self._glyph.getRepresentation("defconQt.OutlineInformation") + points = [] + # start point + if self._showOnCurvePoints and outlineData["startPoints"]: + startWidth = startHeight = self.roundPosition(startPointSize)# * self._inverseScale) + startHalf = startWidth / 2.0 + path = QPainterPath() + for point, angle in outlineData["startPoints"]: + x, y = point + if angle is not None: + path.moveTo(x, y) + path.arcTo(x-startHalf, y-startHalf, 2*startHalf, 2*startHalf, angle-90, -180) + path.closeSubpath() + else: + path.addEllipse(x-startHalf, y-startHalf, startWidth, startHeight) + s.addPath(path, QPen(Qt.NoPen), brush=QBrush(self._startPointColor)) + # off curve + if self._showOffCurvePoints and outlineData["offCurvePoints"]: + # lines + path = QPainterPath() + for point1, point2 in outlineData["bezierHandles"]: + path.moveTo(*point1) + path.lineTo(*point2) + s.addPath(path, QPen(self._bezierHandleColor, 1.0)) + # points + offWidth = offHeight = self.roundPosition(offCurvePointSize)# * self._inverseScale) + offHalf = offWidth / 2.0 + path = QPainterPath() + for point in outlineData["offCurvePoints"]: + x, y = point["point"] + points.append((x, y)) + x = self.roundPosition(x - offHalf) + y = self.roundPosition(y - offHalf) + path.addEllipse(x, y, offWidth, offHeight) + if self._drawStroke: + s.addPath(path, QPen(self._pointStrokeColor, 3.0)) + s.addPath(path, QPen(Qt.NoPen), brush=QBrush(self._backgroundColor)) + s.addPath(path, QPen(self._offCurvePointColor, 1.0)) + # on curve + if self._showOnCurvePoints and outlineData["onCurvePoints"]: + width = height = self.roundPosition(onCurvePointSize)# * self._inverseScale) + half = width / 2.0 + smoothWidth = smoothHeight = self.roundPosition(onCurveSmoothPointSize)# * self._inverseScale) + smoothHalf = smoothWidth / 2.0 + path = QPainterPath() + for point in outlineData["onCurvePoints"]: + x, y = point["point"] + points.append((x, y)) + if point["smooth"]: + x = self.roundPosition(x - smoothHalf) + y = self.roundPosition(y - smoothHalf) + path.addEllipse(x, y, smoothWidth, smoothHeight) + else: + x = self.roundPosition(x - half) + y = self.roundPosition(y - half) + path.addRect(x, y, width, height) + if self._drawStroke: + s.addPath(path, QPen(self._pointStrokeColor, 3.0)) + s.addPath(path, QPen(Qt.NoPen), brush=QBrush(self._onCurvePointColor)) def roundPosition(self, value): value = value * self._scale @@ -347,15 +470,15 @@ class SvgView(QGraphicsView): self.outlineItem.setVisible(enable) def paintEvent(self, event): - scene = self.scene() + #self.scene().clear() + super(SvgView, self).paintEvent(event) + ''' painter = QPainter(self.viewport()) - painter.setRenderHint(QPainter.Antialiasing) - painter.translate(0, self.height()*(1+self._font.info.descender/self._font.info.unitsPerEm)) - painter.scale(1, -1) self.drawBackground(painter) self.drawBlues(painter) self.drawOutlines(painter) self.drawPoints(painter) + ''' ''' if self.renderer == SvgView.Image: @@ -381,7 +504,8 @@ class SvgView(QGraphicsView): #oldPos = self.mapToScene(event.pos()) #self._calcScale() #self._setFrame() - #self.scale(factor, factor) + self.scale(factor, factor) + self.update() #newPos = self.mapToScene(event.pos()) #delta = newPos - oldPos #self.translate(delta.x(), delta.y()) |
