aboutsummaryrefslogtreecommitdiffstats
path: root/Lib
diff options
context:
space:
mode:
authorAdrien Tétar2015-05-04 22:37:24 +0200
committerAdrien Tétar2015-05-04 22:37:24 +0200
commit64b9388cc4d480fbc8ab87b889e7632c1040a048 (patch)
treece5bd9d481ace204a6870a76e4eec424ea552f3b /Lib
parent2cb4fead2e5af288eac686b182ba5d1ad17ae540 (diff)
downloadtrufont-64b9388cc4d480fbc8ab87b889e7632c1040a048.tar.bz2
More
Diffstat (limited to 'Lib')
-rw-r--r--Lib/defconQt/fontView.py10
-rw-r--r--Lib/defconQt/spacecenter.py105
-rw-r--r--Lib/defconQt/svgViewer.py160
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())