diff options
| author | Adrien Tétar | 2015-07-03 23:21:20 +0200 |
|---|---|---|
| committer | Adrien Tétar | 2015-07-03 23:21:20 +0200 |
| commit | c9e2e049549d25c2b8ef5757547fc1f7533e7186 (patch) | |
| tree | 95a994fd7b6c7da3c06109ce555cde9badeb2042 /Lib | |
| parent | 2cb5646c5c49258398ad346bd1a975c6b9c79bd6 (diff) | |
| download | trufont-c9e2e049549d25c2b8ef5757547fc1f7533e7186.tar.bz2 | |
glyphView: ruler tool, minor nits and refactorings
Diffstat (limited to 'Lib')
| -rw-r--r-- | Lib/defconQt/featureTextEditor.py | 9 | ||||
| -rw-r--r-- | Lib/defconQt/glyphView.py | 188 | ||||
| -rw-r--r-- | Lib/defconQt/spaceCenter.py | 11 |
3 files changed, 147 insertions, 61 deletions
diff --git a/Lib/defconQt/featureTextEditor.py b/Lib/defconQt/featureTextEditor.py index 9b32290..5363034 100644 --- a/Lib/defconQt/featureTextEditor.py +++ b/Lib/defconQt/featureTextEditor.py @@ -3,6 +3,7 @@ from PyQt5.QtGui import QColor, QFont, QKeySequence, QPainter, QSyntaxHighlighte from PyQt5.QtWidgets import (QApplication, QFileDialog, QMainWindow, QMenu, QMessageBox, QPlainTextEdit, QWidget) +# TODO: implement search and replace class MainEditWindow(QMainWindow): def __init__(self, font=None, parent=None): super(MainEditWindow, self).__init__(parent) @@ -60,13 +61,14 @@ class LineNumberArea(QWidget): def paintEvent(self, event): self.parent().lineNumberAreaPaintEvent(event) - + class TextEditor(QPlainTextEdit): def __init__(self, text=None, parent=None): super(TextEditor, self).__init__(parent) # https://gist.github.com/murphyrandle/2921575 font = QFont('Roboto Mono', 10) - #font.setFixedPitch(True) + font.setFixedPitch(True) + self.setFont(font) self._indent = " " self.highlighter = Highlighter(self.document()) @@ -75,11 +77,10 @@ class TextEditor(QPlainTextEdit): self.updateRequest.connect(self.updateLineNumberArea) self.setPlainText(text) - self.setFont(font) def setFontParams(self, family='Roboto Mono', ptSize=10, isMono=True): font = QFont(family, ptSize) - #font.setFixedPitch(isMono) + font.setFixedPitch(isMono) self.setFont(font) def write(self, features): diff --git a/Lib/defconQt/glyphView.py b/Lib/defconQt/glyphView.py index 728c677..6f485fb 100644 --- a/Lib/defconQt/glyphView.py +++ b/Lib/defconQt/glyphView.py @@ -1,3 +1,4 @@ +from enum import Enum from math import copysign from PyQt5.QtCore import *#QFile, QLineF, QObject, QPointF, QRectF, QSize, Qt from PyQt5.QtGui import *#QBrush, QColor, QImage, QKeySequence, QPainter, QPainterPath, QPixmap, QPen @@ -29,9 +30,14 @@ class MainGfxWindow(QMainWindow): self.drawingTool.setCheckable(True) self.drawingTool.toggled.connect(self.view.setSceneDrawing) + self.rulerTool = toolsMenu.addAction("&Ruler") + self.rulerTool.setCheckable(True) + self.rulerTool.toggled.connect(self.view.setSceneRuler) + self.toolsGroup = QActionGroup(self) self.toolsGroup.addAction(self.selectTool) self.toolsGroup.addAction(self.drawingTool) + self.toolsGroup.addAction(self.rulerTool) self.selectTool.setChecked(True) self.menuBar().addMenu(toolsMenu) @@ -125,6 +131,11 @@ onCurvePointColor = offCurvePointColor pointStrokeColor = QColor.fromRgbF(1, 1, 1, 1) pointSelectionColor = Qt.red +class SceneTools(Enum): + SelectionTool = 0 + DrawingTool = 1 + RulerTool = 2 + class HandleLineItem(QGraphicsLineItem): def __init__(self, x1, y1, x2, y2, parent): super(HandleLineItem, self).__init__(x1, y1, x2, y2, parent) @@ -163,6 +174,7 @@ class OffCurvePointItem(QGraphicsEllipseItem): value.setY(copysign(avg, value.y())) else: value.setY(0) + elif change == QGraphicsItem.ItemPositionHasChanged: self.parentItem()._CPMoved(value) return value @@ -279,8 +291,6 @@ class OnCurvePointItem(QGraphicsPathItem): value.setX(round(value.x())) value.setY(round(value.y())) elif change == QGraphicsItem.ItemPositionHasChanged: - if self.scene() is None: return QGraphicsItem.itemChange(self, change, value) - # TODO: if we're snapped to int round self.pos to int # have a look at defcon FuzzyNumber as well pointIndex = self.getPointIndex() self._contour[pointIndex].x = self.pos().x() @@ -427,6 +437,13 @@ class GlyphScene(QGraphicsScene): super(GlyphScene, self).__init__(parent) self._editing = False self._integerPlane = True + self._cachedRuler = None + self._rulerObject = None + + font = self.font() + font.setFamily("Roboto Mono") + font.setFixedPitch(True) + self.setFont(font) def dragEnterEvent(self, event): if event.mimeData().hasUrls(): @@ -519,14 +536,20 @@ class GlyphScene(QGraphicsScene): super(GlyphScene, self).keyReleaseEvent(event) def mousePressEvent(self, event): - forceSelect = False - if not self.views()[0]._drawingTool: super(GlyphScene, self).mousePressEvent(event); return + currentTool = self.views()[0]._currentTool touched = self.itemAt(event.scenePos(), self.views()[0].transform()) + if not currentTool == SceneTools.DrawingTool: + if currentTool == SceneTools.RulerTool: + self.rulerMousePress(event) + return + self._itemUnderMouse = touched + super(GlyphScene, self).mousePressEvent(event) + return + forceSelect = False sel = self.selectedItems() x, y = event.scenePos().x(), event.scenePos().y() if self._integerPlane: - x = int(x) - y = int(y) + x, y = round(x), round(y) # XXX: not sure why isinstance does not work here if len(sel) == 1: isLastOnCurve = type(sel[0]) is OnCurvePointItem and sel[0]._contour.open and \ @@ -662,26 +685,104 @@ class GlyphScene(QGraphicsScene): # eat the event event.accept() else: + currentTool = self.views()[0]._currentTool + if currentTool == SceneTools.RulerTool: + self.rulerMouseMove(event) + return super(GlyphScene, self).mouseMoveEvent(event) def mouseReleaseEvent(self, event): self._editing = False - # cleanup extra point elements if we dealt w curved first point - touched = self.itemAt(event.scenePos(), self.views()[0].transform()) - if touched and isinstance(touched, OffCurvePointItem): - onCurve = touched.parentItem() - children = onCurve.childItems() - if len(children) > 4: - # l1, p1, l3, p3, l2, p2 - children[3].prepareGeometryChange() - self.removeItem(children[3]) - children[2].prepareGeometryChange() - self.removeItem(children[2]) + currentTool = self.views()[0]._currentTool + if currentTool == SceneTools.DrawingTool: + # cleanup extra point elements if we dealt w curved first point + touched = self.itemAt(event.scenePos(), self.views()[0].transform()) + if touched and isinstance(touched, OffCurvePointItem): + onCurve = touched.parentItem() + children = onCurve.childItems() + if len(children) > 4: + # l1, p1, l3, p3, l2, p2 + children[3].prepareGeometryChange() + self.removeItem(children[3]) + children[2].prepareGeometryChange() + self.removeItem(children[2]) - onCurve._isSmooth = False - onCurve.setPointPath() - onCurve._point.smooth = False + onCurve._isSmooth = False + onCurve.setPointPath() + onCurve._point.smooth = False + elif currentTool == SceneTools.RulerTool: + self.rulerMouseRelease(event) super(GlyphScene, self).mouseReleaseEvent(event) + + def rulerMousePress(self, event): + touched = self.itemAt(event.scenePos(), self.views()[0].transform()) + if touched is not None and isinstance(touched, OnCurvePointItem) or \ + isinstance(touched, OffCurvePointItem): + x, y = touched.scenePos().x(), touched.scenePos().y() + else: + x, y = event.scenePos().x(), event.scenePos().y() + if self._integerPlane: + x, y = round(x), round(y) + if self._cachedRuler is not None: + self.removeItem(self._cachedRuler) + self._cachedRuler = None + path = QPainterPath() + path.moveTo(x, y) + path.lineTo(x+1, y) + path.lineTo(x+1, y+1) + path.closeSubpath() + self._rulerObject = self.addPath(path) + item = QGraphicsSimpleTextItem("0", self._rulerObject) + font = self.font() + font.setPointSize(9) + item.setFont(font) + item.setTransform(QTransform().fromScale(1, -1)) + event.accept() + + def rulerMouseMove(self, event): + # XXX: shouldnt have to do this, it seems mouseTracking is wrongly activated + if self._rulerObject is None: return + touched = self.itemAt(event.scenePos(), self.views()[0].transform()) + if touched is not None and isinstance(touched, OnCurvePointItem) or \ + isinstance(touched, OffCurvePointItem): + x, y = touched.scenePos().x(), touched.scenePos().y() + else: + # TODO: 45deg clamp w ShiftModifier + # maybe make a function for that + other occurences... + x, y = event.scenePos().x(), event.scenePos().y() + if self._integerPlane: + x, y = round(x), round(y) + path = self._rulerObject.path() + baseElem = path.elementAt(0) + path.setElementPositionAt(1, x, baseElem.y) + path.setElementPositionAt(2, x, y) + path.setElementPositionAt(3, baseElem.x, baseElem.y) + self._rulerObject.setPath(path) + textItem = self._rulerObject.childItems()[0] + line = QLineF(baseElem.x, baseElem.y, x, y) + l = line.length() + # XXX: angle() doesnt go by trigonometric direction. Weird. + # TODO: maybe split in positive/negative 180s (ff) + a = 360 - line.angle() + line.setP2(QPointF(x, baseElem.y)) + h = line.length() + line.setP1(QPointF(x, y)) + v = line.length() + text = "%d\n↔ %d\n↕ %d\nα %dº" % (l, h, v, a) + textItem.setText(text) + dx = x - baseElem.x + if dx >= 0: px = x + else: px = x - textItem.boundingRect().width() + dy = y - baseElem.y + if dy >= 0: py = baseElem.y + else: py = baseElem.y + textItem.boundingRect().height() + textItem.setPos(px, py) + event.accept() + + def rulerMouseRelease(self, event): + self._cachedRuler = self._rulerObject + self._rulerObject = None + event.accept() class GlyphView(QGraphicsView): Native, OpenGL, Image = range(3) @@ -696,8 +797,6 @@ class GlyphView(QGraphicsView): self._impliedPointSize = 1000 self._pointSize = None - self._drawingTool = False - self._inverseScale = 0.1 self._scale = 10 self._noPointSizePadding = 200 @@ -713,12 +812,18 @@ class GlyphView(QGraphicsView): self.setBackgroundBrush(QBrush(Qt.lightGray)) self.setScene(GlyphScene(self)) #self.scene().setSceneRect(0, self._font.info.ascender, self._glyph.width, self._font.info.unitsPerEm) + font = self.font() + font.setFamily("Roboto Mono") + font.setFixedPitch(True) + self.setFont(font) self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QGraphicsView.AnchorUnderMouse) - self.setDragMode(QGraphicsView.RubberBandDrag) #self.setViewportUpdateMode(QGraphicsView.BoundingRectViewportUpdate) + self._drawingTool = SceneTools.SelectionTool + self.setDragMode(QGraphicsView.RubberBandDrag) + self.setRenderHint(QPainter.Antialiasing) #self.translate(0, self.height()*(1+self._font.info.descender/self._font.info.unitsPerEm)) self.scale(1, -1) @@ -820,7 +925,6 @@ class GlyphView(QGraphicsView): if self._showMetricsTitles:# and self._impliedPointSize > 150: fontSize = 9# * self._inverseScale font = self.font() - font.setFamily("Roboto Mono") font.setPointSize(fontSize) for position, names in sorted(positions.items()): y = position - (fontSize / 2) @@ -974,20 +1078,23 @@ class GlyphView(QGraphicsView): def mousePressEvent(self, event): if (event.button() == Qt.MidButton): - if self.dragMode() == QGraphicsView.RubberBandDrag: + dragMode = self.dragMode() + if dragMode == QGraphicsView.RubberBandDrag: self.setDragMode(QGraphicsView.ScrollHandDrag) - else: + elif dragMode == QGraphicsView.ScrollHandDrag: self.setDragMode(QGraphicsView.RubberBandDrag) super(GlyphView, self).mousePressEvent(event) - - # XXX: should not have to set bools like this, should rely on QGroupBox - # data which is mutually-exclusive instead + def setSceneDrawing(self): - self._drawingTool = True + self._currentTool = SceneTools.DrawingTool + self.setDragMode(QGraphicsView.NoDrag) + + def setSceneRuler(self): + self._currentTool = SceneTools.RulerTool self.setDragMode(QGraphicsView.NoDrag) def setSceneSelection(self): - self._drawingTool = False + self._currentTool = SceneTools.SelectionTool self.setDragMode(QGraphicsView.RubberBandDrag) # Lock/release handdrag does not seem to work… @@ -998,29 +1105,14 @@ class GlyphView(QGraphicsView): super(GlyphView, self).mouseReleaseEvent(event) ''' - ''' - def paintEvent(self, event): - if self.renderer == GlyphView.Image: - if self.image.size() != self.viewport().size(): - self.image = QImage(self.viewport().size(), - QImage.Format_ARGB32_Premultiplied) - - imagePainter = QPainter(self.image) - QGraphicsView.render(self, imagePainter) - imagePainter.end() - - p = QPainter(self.viewport()) - p.drawImage(0, 0, self.image) - else: - super(GlyphView, self).paintEvent(event) - ''' - def wheelEvent(self, event): factor = pow(1.2, event.angleDelta().y() / 120.0) #self._calcScale() #self._setFrame() self.scale(factor, factor) + # XXX: SimpleTextItems need scaling as well, but finding way to use ItemIgnoresTransformations + # on them would be in-order... scale = self.transform().m11() if scale < 4 and scale > .4: offCPS = offCurvePointSize / scale diff --git a/Lib/defconQt/spaceCenter.py b/Lib/defconQt/spaceCenter.py index 3920d03..9fabaa5 100644 --- a/Lib/defconQt/spaceCenter.py +++ b/Lib/defconQt/spaceCenter.py @@ -468,17 +468,10 @@ class GlyphsCanvas(QWidget): class SpaceTableWidgetItem(QTableWidgetItem): def setData(self, role, value): if role & Qt.EditRole: - # don't set empty or non-number data + # don't set empty data + # XXX: maybe fetch the value from cell back to the editor if value == "": return - else: - try: - int(value) - except ValueError: - try: - value = str(round(float(value))) - except ValueError: - return super(SpaceTableWidgetItem, self).setData(role, value) class GlyphCellItemDelegate(QStyledItemDelegate): |
