diff options
| author | Adrien Tétar | 2015-07-17 21:12:21 +0200 |
|---|---|---|
| committer | Adrien Tétar | 2015-07-17 21:12:21 +0200 |
| commit | 0bef879f6d5a9bf46b7aac548b97a7e9fdb889d4 (patch) | |
| tree | 2ea931616d850f19bc8c5bb1d8d72642cb229f46 /Lib/defconQt | |
| parent | d4f95092152c93604c60db39659c3a5f316232a3 (diff) | |
| download | trufont-0bef879f6d5a9bf46b7aac548b97a7e9fdb889d4.tar.bz2 | |
glyphView: proper deletion method (+ can break contour w Shift), make scene._editing tristate so as to not smooth/unsmooth out of sliding, scale pts upon creation, fixes
Diffstat (limited to 'Lib/defconQt')
| -rw-r--r-- | Lib/defconQt/fontView.py | 1 | ||||
| -rw-r--r-- | Lib/defconQt/glyphView.py | 202 |
2 files changed, 119 insertions, 84 deletions
diff --git a/Lib/defconQt/fontView.py b/Lib/defconQt/fontView.py index a4f1e5c..a701562 100644 --- a/Lib/defconQt/fontView.py +++ b/Lib/defconQt/fontView.py @@ -617,7 +617,6 @@ class MainWindow(QMainWindow): def _glyphOpened(self, name): from glyphView import MainGfxWindow glyphViewWindow = MainGfxWindow(self.font, self.font[name], self) - glyphViewWindow.setAttribute(Qt.WA_DeleteOnClose) glyphViewWindow.show() def _selectionChanged(self, count, glyph): diff --git a/Lib/defconQt/glyphView.py b/Lib/defconQt/glyphView.py index 7ff1226..d72b0c7 100644 --- a/Lib/defconQt/glyphView.py +++ b/Lib/defconQt/glyphView.py @@ -11,6 +11,7 @@ from PyQt5.QtOpenGL import QGL, QGLFormat, QGLWidget class MainGfxWindow(QMainWindow): def __init__(self, font=None, glyph=None, parent=None): super(MainGfxWindow, self).__init__(parent) + self.setAttribute(Qt.WA_DeleteOnClose) self.setAttribute(Qt.WA_KeyCompression) self.view = GlyphView(font, glyph, self) @@ -83,6 +84,7 @@ class MainGfxWindow(QMainWindow): self.setCentralWidget(self.view) self.setWindowTitle(glyph.name, font) + self.adjustSize() def close(self): self.view._glyph.removeObserver(self, "Glyph.Changed") @@ -110,10 +112,9 @@ def roundPosition(value): value = value * .1#self._inverseScale return value -# TODO: proper size scaling mechanism -offCurvePointSize = 7#5 -onCurvePointSize = 8#6 -onCurveSmoothPointSize = 9#7 +offCurvePointSize = 8#5 +onCurvePointSize = 9#6 +onCurveSmoothPointSize = 10#7 offWidth = offHeight = roundPosition(offCurvePointSize)# * self._inverseScale) offHalf = offWidth / 2.0 onWidth = onHeight = roundPosition(onCurvePointSize)# * self._inverseScale) @@ -144,16 +145,15 @@ class HandleLineItem(QGraphicsLineItem): class OffCurvePointItem(QGraphicsEllipseItem): def __init__(self, x, y, parent=None): - super(OffCurvePointItem, self).__init__(-offHalf, -offHalf, offWidth, offHeight, parent) + super(OffCurvePointItem, self).__init__(parent) # since we have a parent, setPos must be relative to it + self.setPointPath() self.setPos(x, y) # TODO: abstract and use pointX-self.parent().pos().x() self.setFlag(QGraphicsItem.ItemIsMovable) self.setFlag(QGraphicsItem.ItemIsSelectable) - # TODO: stop doing this and go back to mouse events –> won't permit multiple selection self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) self.setFlag(QGraphicsItem.ItemStacksBehindParent) - # TODO: redo this with scaling - self.setPen(QPen(offCurvePointColor, 1.0)) + self.setBrush(QBrush(backgroundColor)) self._needsUngrab = False @@ -201,55 +201,92 @@ class OffCurvePointItem(QGraphicsEllipseItem): pen.setColor(offCurvePointColor) self.setPen(pen) super(OffCurvePointItem, self).paint(painter, newOption, widget) + + def setPointPath(self, scale=None): + if scale is None: + scene = self.scene() + if scene is not None: + scale = scene.getViewScale() + else: + scale = 1 + if scale > 4: scale = 4 + elif scale < .4: scale = .4 + self.prepareGeometryChange() + self.setRect(-offHalf/scale, -offHalf/scale, offWidth/scale, offHeight/scale) + self.setPen(QPen(offCurvePointColor, 1.0/scale)) -# TODO: enforce 2 OCP there convention in ctor class OnCurvePointItem(QGraphicsPathItem): - def __init__(self, x, y, isSmooth, contour, point, parent=None): + def __init__(self, x, y, isSmooth, contour, point, scale=1, parent=None): super(OnCurvePointItem, self).__init__(parent) self._contour = contour self._point = point self._isSmooth = isSmooth + self._posBeforeMove = None - self.setPointPath() + self.setPointPath(scale) self.setPos(x, y) self.setFlag(QGraphicsItem.ItemIsMovable) self.setFlag(QGraphicsItem.ItemIsSelectable) self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) - self.setPen(QPen(pointStrokeColor, 1.5)) self.setBrush(QBrush(onCurvePointColor)) - def delete(self): - if len(self._contour.segments) < 2: - self.scene()._glyphObject.removeContour(self._contour) - else: - self._contour.removeSegment(self.getSegmentIndex(), True) - index = 0 + def delete(self, preserveShape=True): + def findNextOnCurve(self, index=0): for _ in self._contour: if self._contour[index].segmentType is not None: - self._contour.setStartPoint(index) break index = (index+1) % len(self._contour) - self.scene().removeItem(self) + return index + + scene = self.scene() + glyph = scene._glyphObject + scene._blocked = True + if len(self._contour.segments) < 2: + glyph.removeContour(self._contour) + else: + ptIndex = self.getPointIndex() + if self._contour.open and ptIndex == 0: + nextOnCurveIndex = findNextOnCurve(self, 1) + self._contour._points = self._contour[nextOnCurveIndex:] + self._contour[0].segmentType = "move" + self._contour.dirty = True + else: + # Using preserveShape at the edge of an open contour will traceback + if ptIndex == len(self._contour): preserveShape = False + self._contour.removeSegment(self.getSegmentIndex(), preserveShape) + nextOnCurveIndex = findNextOnCurve(self) + self._contour.setStartPoint(nextOnCurveIndex) + scene._blocked = False + scene.removeItem(self) - def setPointPath(self): + def setPointPath(self, scale=None): path = QPainterPath() + if scale is None: + scene = self.scene() + if scene is not None: + scale = scene.getViewScale() + else: + scale = 1 + if scale > 4: scale = 4 + elif scale < .4: scale = .4 if self._isSmooth: - path.addEllipse(-smoothHalf, -smoothHalf, smoothWidth, smoothHeight) + path.addEllipse(-smoothHalf/scale, -smoothHalf/scale, smoothWidth/scale, smoothHeight/scale) else: - path.addRect(-onHalf, -onHalf, onWidth, onHeight) + path.addRect(-onHalf/scale, -onHalf/scale, onWidth/scale, onHeight/scale) self.prepareGeometryChange() self.setPath(path) + self.setPen(QPen(pointStrokeColor, 1.5/scale)) def getPointIndex(self): return self._contour.index(self._point) def getSegmentIndex(self): - # is there a contour.segments.index() method? - index = 0 + # closed contour cycles and so the "previous" segment goes to current point + index = 0 if self._contour.open else -1 for pt in self._contour: if pt == self._point: break if pt.segmentType is not None: index += 1 - return (index-1) % len(self._contour.segments) + return index % len(self._contour.segments) def _CPMoved(self, newValue): pointIndex = self.getPointIndex() @@ -332,6 +369,7 @@ class OnCurvePointItem(QGraphicsPathItem): return ptIndex = self.getPointIndex() scene = self.scene() + scene._blocked = True # if we have line segment, insert offCurve points insertIndex = (ptIndex+(i-1)//2) % len(self._contour) if self._contour[insertIndex].segmentType == "line": @@ -356,6 +394,7 @@ class OnCurvePointItem(QGraphicsPathItem): scene.sendEvent(children[i], QEvent(QEvent.MouseButtonPress)) children[i].setSelected(True) children[i].grabMouse() + scene._blocked = False event.accept() def mouseDoubleClickEvent(self, event): @@ -381,8 +420,11 @@ class OnCurvePointItem(QGraphicsPathItem): class ResizeHandleItem(QGraphicsRectItem): def __init__(self, parent=None): - super(QGraphicsRectItem, self).__init__(-3, -3, 6, 6, parent) - self.setBrush(QBrush(Qt.lightGray)) + super(QGraphicsRectItem, self).__init__(parent) + self.setPointPath() + self.setBrush(QBrush(QColor(60, 60, 60))) + self.setPen(QPen(Qt.NoPen)) + self.setFlag(QGraphicsItem.ItemIgnoresParentOpacity) self.setFlag(QGraphicsItem.ItemIsMovable) #self.setFlag(QGraphicsItem.ItemIsSelectable) self.setCursor(Qt.SizeFDiagCursor) @@ -397,6 +439,17 @@ class ResizeHandleItem(QGraphicsRectItem): def mouseMoveEvent(self, event): self.parentItem()._pixmapGeometryChanged(event) + + def setPointPath(self, scale=None): + if scale is None: + scene = self.scene() + if scene is not None: + scale = scene.getViewScale() + else: + scale = 1 + if scale > 4: scale = 4 + self.prepareGeometryChange() + self.setRect(-onHalf/scale, -onHalf/scale, onWidth/scale, onHeight/scale) class PixmapItem(QGraphicsPixmapItem): def __init__(self, x, y, pixmap, parent=None): @@ -488,6 +541,9 @@ class GlyphScene(QGraphicsScene): if isinstance(item, OnCurvePointItem) and item._point == point: return item return None + + def getViewScale(self): + return self.views()[0].transform().m11() # TODO: implement key multiplex in a set() # http://stackoverflow.com/a/10568233/2037879 @@ -506,7 +562,7 @@ class GlyphScene(QGraphicsScene): elif key == Qt.Key_Delete: for item in self.selectedItems(): if isinstance(item, OnCurvePointItem): - item.delete() + item.delete(not event.modifiers() & Qt.ShiftModifier) elif isinstance(item, PixmapItem): self.removeItem(item) event.accept() @@ -543,7 +599,7 @@ class GlyphScene(QGraphicsScene): sel = self.selectedItems() if len(sel) == 1 and isinstance(sel[0], OffCurvePointItem) and \ sel[0].parentItem().getPointIndex() == len(sel[0].parentItem()._contour)-2 and \ - key == Qt.Key_Alt and self._editing: + key == Qt.Key_Alt and self._editing is not False: sel[0].parentItem().setIsSmooth(False) super(GlyphScene, self).keyPressEvent(event) return @@ -561,7 +617,7 @@ class GlyphScene(QGraphicsScene): sel = self.selectedItems() if len(sel) == 1 and isinstance(sel[0], OffCurvePointItem) and \ sel[0].parentItem().getPointIndex() == len(sel[0].parentItem()._contour)-2 and \ - event.key() == Qt.Key_Alt and self._editing: + event.key() == Qt.Key_Alt and self._editing is not False: sel[0].parentItem().setIsSmooth(True) super(GlyphScene, self).keyReleaseEvent(event) @@ -624,7 +680,7 @@ class GlyphScene(QGraphicsScene): lastContour.addPoint((x,y), "curve") else: lastContour.addPoint((x,y), "line") - item = OnCurvePointItem(x, y, False, lastContour, lastContour[-1]) + item = OnCurvePointItem(x, y, False, lastContour, lastContour[-1], self.getViewScale()) self.addItem(item) for _ in range(2): lineObj = HandleLineItem(0, 0, 0, 0, item) @@ -640,7 +696,7 @@ class GlyphScene(QGraphicsScene): self._glyphObject.appendContour(nextC) nextC.addPoint((x,y), "move") - item = OnCurvePointItem(x, y, False, self._glyphObject[-1], self._glyphObject[-1][-1]) + item = OnCurvePointItem(x, y, False, self._glyphObject[-1], self._glyphObject[-1][-1], self.getViewScale()) self.addItem(item) for _ in range(2): lineObj = HandleLineItem(0, 0, 0, 0, item) @@ -653,15 +709,21 @@ class GlyphScene(QGraphicsScene): if forceSelect: item.setSelected(True) def mouseMoveEvent(self, event): - if self._editing: + if self._editing is True: sel = self.selectedItems() if len(sel) == 1: if isinstance(sel[0], OnCurvePointItem) and (event.scenePos() - sel[0].pos()).manhattanLength() >= 2: + mouseGrabberItem = self.mouseGrabberItem() + # If we drawn an onCurve w Shift and we're not touching the item, we wont have + # a mouse grabber (anyways), return early here. + if mouseGrabberItem is None: + event.accept() + return self._blocked = True if len(sel[0]._contour) < 2: # release current onCurve self.sendEvent(sel[0], QEvent(QEvent.MouseButtonRelease)) - self.mouseGrabberItem().ungrabMouse() + mouseGrabberItem.ungrabMouse() sel[0].setSelected(False) # append an offCurve point and start moving it sel[0]._contour.addPoint((event.scenePos().x(), event.scenePos().y())) @@ -675,7 +737,7 @@ class GlyphScene(QGraphicsScene): from defcon.objects.point import Point # release current onCurve, delete from contour self.sendEvent(sel[0], QEvent(QEvent.MouseButtonRelease)) - self.mouseGrabberItem().ungrabMouse() + mouseGrabberItem.ungrabMouse() sel[0].setSelected(False) # construct a curve segment to the current point if there is not one @@ -716,7 +778,7 @@ class GlyphScene(QGraphicsScene): self.sendEvent(nextCP, QEvent(QEvent.MouseButtonPress)) nextCP.grabMouse() self._blocked = False - self._editing = False + self._editing = None super(GlyphScene, self).mouseMoveEvent(event) else: # eat the event @@ -726,7 +788,14 @@ class GlyphScene(QGraphicsScene): if currentTool == SceneTools.RulerTool: self.rulerMouseMove(event) return - super(GlyphScene, self).mouseMoveEvent(event) + items = self.items(event.scenePos()) + # XXX: we must cater w mouse tracking + # we dont need isSelected() once its rid + if len(items) > 1 and isinstance(items[0], OnCurvePointItem) and \ + isinstance(items[1], OffCurvePointItem) and items[1].isSelected(): + items[1].setPos(0, 0) + else: + super(GlyphScene, self).mouseMoveEvent(event) def mouseReleaseEvent(self, event): self._editing = False @@ -773,7 +842,7 @@ class GlyphScene(QGraphicsScene): font = self.font() font.setPointSize(9) textItem.setFont(font) - textItem.setTransform(QTransform().fromScale(1, -1)) + textItem.setFlag(QGraphicsItem.ItemIgnoresTransformations) textItem.setPos(x, y + textItem.boundingRect().height()) event.accept() @@ -849,7 +918,6 @@ 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) @@ -870,11 +938,6 @@ class GlyphView(QGraphicsView): self.addHorizontalMetrics() self.addOutlines() self.addPoints() - - #self.fitInView(0, self._font.info.descender, self._glyph.width, self._font.info.unitsPerEm, Qt.KeepAspectRatio) - #sc = self.height()/self.scene().height() - #self.scale(sc, sc); - #self.scene().setSceneRect(-1000, -1000, 3000, 3000) def _glyphChanged(self, notification): # TODO: maybe detect sidebearing changes (space center) and then only @@ -884,7 +947,7 @@ class GlyphView(QGraphicsView): path = self._glyph.getRepresentation("defconQt.NoComponentsQPainterPath") scene = self.scene() scene._outlineItem.setPath(path) - scene._outlineItem.update() + #scene._outlineItem.update() if not scene._blocked: # TODO: also rewind anchors and components for item in scene.items(): @@ -981,7 +1044,7 @@ class GlyphView(QGraphicsView): text = " %s " % text item = scene.addSimpleText(text, font) item.setBrush(self._metricsColor) - item.setTransform(QTransform().fromScale(1, -1)) + item.setFlag(QGraphicsItem.ItemIgnoresTransformations) item.setPos(width, y) item.setZValue(-997) @@ -1028,19 +1091,14 @@ class GlyphView(QGraphicsView): outlineData = self._glyph.getRepresentation("defconQt.OutlineInformation") points = [] # TODO: remove this unless we need it # useful for text drawing, add it startObjects = [] - offWidth = offHeight = self.roundPosition(offCurvePointSize)# * self._inverseScale) - offHalf = offWidth / 2.0 - width = height = self.roundPosition(onCurvePointSize)# * self._inverseScale) - half = width / 2.0 - smoothWidth = smoothHeight = self.roundPosition(onCurveSmoothPointSize)# * self._inverseScale) - smoothHalf = smoothWidth / 2.0 + scale = self.transform().m11() if outlineData["onCurvePoints"]: for onCurve in outlineData["onCurvePoints"]: # on curve x, y = onCurve.x, onCurve.y points.append((x, y)) item = OnCurvePointItem(x, y, onCurve.isSmooth, self._glyph[onCurve.contourIndex], - self._glyph[onCurve.contourIndex][onCurve.pointIndex]) + self._glyph[onCurve.contourIndex][onCurve.pointIndex], scale) scene.addItem(item) # off curve for CP in [onCurve.prevCP, onCurve.nextCP]: @@ -1068,11 +1126,11 @@ class GlyphView(QGraphicsView): path = QPainterPath() path.moveTo(x, y) path.arcTo(x-startHalf, y-startHalf, 2*startHalf, 2*startHalf, angle-90, -180) - item = s.addPath(path, QPen(Qt.NoPen), QBrush(self._startPointColor)) + item = scene.addPath(path, QPen(Qt.NoPen), QBrush(self._startPointColor)) startObjects.append(item) #path.closeSubpath() else: - item = s.addEllipse(x-startHalf, y-startHalf, startWidth, startHeight, + item = scene.addEllipse(x-startHalf, y-startHalf, startWidth, startHeight, QPen(Qt.NoPen), QBrush(self._startPointColor)) startObjects.append(item) #s.addPath(path, QPen(Qt.NoPen), brush=QBrush(self._startPointColor)) @@ -1160,35 +1218,13 @@ class GlyphView(QGraphicsView): #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... + # TODO: stop displaying SimpleTextItems at certains sizes, maybe anchor them differently as well scale = self.transform().m11() - if scale < 4 and scale > .4: - offCPS = offCurvePointSize / scale - onCPS = onCurvePointSize / scale - onCSPS = onCurveSmoothPointSize / scale - onCPW = onCurvePenWidth / scale - offCPW = offCurvePenWidth / scale + if scale < 4: for item in self.scene().items(): - if isinstance(item, OnCurvePointItem): - path = QPainterPath() - if item._isSmooth: - width = height = self.roundPosition(onCSPS)# * self._inverseScale) - half = width / 2.0 - path.addEllipse(-half, -half, width, height) - else: - width = height = self.roundPosition(onCPS)# * self._inverseScale) - half = width / 2.0 - path.addRect(-half, -half, width, height) - item.prepareGeometryChange() - item.setPath(path) - item.setPen(QPen(Qt.white, onCPW)) - elif isinstance(item, OffCurvePointItem): - width = height = self.roundPosition(offCPS)# * self._inverseScale) - half = width / 2.0 - item.prepareGeometryChange() - item.setRect(-half, -half, width, height) - item.setPen(QPen(Qt.white, offCPW)) + if isinstance(item, OnCurvePointItem) or isinstance(item, OffCurvePointItem) or \ + isinstance(item, ResizeHandleItem): + item.setPointPath(scale) self.update() event.accept() |
