diff options
Diffstat (limited to 'Lib')
| -rw-r--r-- | Lib/defconQt/__main__.py | 15 | ||||
| -rw-r--r-- | Lib/defconQt/fontView.py | 56 | ||||
| -rw-r--r-- | Lib/defconQt/glyphView.py | 269 | ||||
| -rw-r--r-- | Lib/defconQt/objects/defcon.py | 15 | ||||
| -rw-r--r-- | Lib/defconQt/objects/sizeGripItem.py | 205 | ||||
| -rw-r--r-- | Lib/defconQt/util/glyphList.py | 21 | 
6 files changed, 460 insertions, 121 deletions
| diff --git a/Lib/defconQt/__main__.py b/Lib/defconQt/__main__.py index 270764d..517f8ce 100644 --- a/Lib/defconQt/__main__.py +++ b/Lib/defconQt/__main__.py @@ -1,9 +1,10 @@ -from defconQt.objects.defcon import TFont  from defconQt import representationFactories  from defconQt import icons_db  # noqa  from defconQt.fontView import Application, MainWindow +from defconQt.objects.defcon import TFont  import sys  import os +from PyQt5.QtCore import QSettings  from PyQt5.QtGui import QIcon @@ -17,10 +18,20 @@ def main():      representationFactories.registerAllFactories()      app = Application(sys.argv)      # TODO: http://stackoverflow.com/a/21330349/2037879 -    app.setOrganizationName("A. Tétar & Co.") +    app.setOrganizationName("TruFont")      app.setOrganizationDomain("trufont.github.io")      app.setApplicationName("TruFont")      app.setWindowIcon(QIcon(":/resources/app.png")) +    settings = QSettings() +    glyphListPath = settings.value("settings/glyphListPath", "", type=str) +    if glyphListPath and os.path.exists(glyphListPath): +        from defconQt.util import glyphList +        try: +            glyphList = glyphList.parseGlyphList(glyphListPath) +        except Exception as e: +            print(e) +        else: +            app.GL2UV = glyphList      window = MainWindow(font)      window.show()      sys.exit(app.exec_()) diff --git a/Lib/defconQt/fontView.py b/Lib/defconQt/fontView.py index 56bfbfe..70f7f44 100644 --- a/Lib/defconQt/fontView.py +++ b/Lib/defconQt/fontView.py @@ -19,8 +19,8 @@ from PyQt5.QtGui import (      QTextCursor)  from PyQt5.QtWidgets import (      QAbstractItemView, QAction, QApplication, QCheckBox, QComboBox, QDialog, -    QDialogButtonBox, QFileDialog, QGridLayout, QGroupBox, QLabel, QLineEdit, -    QListWidget, QListWidgetItem, QMainWindow, QMenu, QMessageBox, +    QDialogButtonBox, QFileDialog, QGridLayout, QGroupBox, QHBoxLayout, QLabel, +    QLineEdit, QListWidget, QListWidgetItem, QMainWindow, QMenu, QMessageBox,      QPlainTextEdit, QPushButton, QRadioButton, QSlider, QSplitter, QTabWidget,      QTextEdit, QToolTip, QTreeView, QVBoxLayout, QWidget)  from collections import OrderedDict @@ -74,6 +74,7 @@ class Application(QApplication):          super(Application, self).__init__(*args, **kwargs)          self._currentGlyph = None          self._currentMainWindow = None +        self.GL2UV = None      def allFonts(self):          fonts = [] @@ -1342,17 +1343,36 @@ class GlyphSetTab(QWidget):          importMenu.addAction("Import from current font",                               self.importFromCurrentFont)          self.importButton.setMenu(importMenu) - -        mainLayout = QGridLayout() +        glyphListPath = settings.value("settings/glyphListPath", type=str) +        self.glyphListBox = QCheckBox("Glyph list path:", self) +        self.glyphListBox.setChecked(bool(glyphListPath)) +        self.glyphListEdit = QLineEdit(glyphListPath, self) +        self.glyphListEdit.setEnabled(bool(glyphListPath)) +        self.glyphListEdit.setReadOnly(True) +        self.glyphListButton = QPushButton("Browse…", self) +        self.glyphListButton.setEnabled(bool(glyphListPath)) +        self.glyphListButton.pressed.connect(self.getGlyphList) +        self.glyphListButton.setFixedWidth(72) +        self.glyphListBox.toggled.connect(self.glyphListEdit.setEnabled) +        self.glyphListBox.toggled.connect(self.glyphListButton.setEnabled) + +        firstLayout = QGridLayout()          l = 0 -        mainLayout.addWidget(self.defaultGlyphSetBox, l, 0, 1, 2) -        mainLayout.addWidget(self.defaultGlyphSetDrop, l, 3, 1, 3) +        firstLayout.addWidget(self.defaultGlyphSetBox, l, 0, 1, 2) +        firstLayout.addWidget(self.defaultGlyphSetDrop, l, 3, 1, 3)          l += 1 -        mainLayout.addWidget(splitter, l, 0, 1, 6) +        firstLayout.addWidget(splitter, l, 0, 1, 6)          l += 1 -        mainLayout.addWidget(self.addGlyphSetButton, l, 0) -        mainLayout.addWidget(self.removeGlyphSetButton, l, 1) -        mainLayout.addWidget(self.importButton, l, 2) +        firstLayout.addWidget(self.addGlyphSetButton, l, 0) +        firstLayout.addWidget(self.removeGlyphSetButton, l, 1) +        firstLayout.addWidget(self.importButton, l, 2) +        secondLayout = QHBoxLayout() +        secondLayout.addWidget(self.glyphListBox, 0) +        secondLayout.addWidget(self.glyphListEdit, 1) +        secondLayout.addWidget(self.glyphListButton, 2) +        mainLayout = QVBoxLayout() +        mainLayout.addLayout(firstLayout) +        mainLayout.addLayout(secondLayout)          self.setLayout(mainLayout)      def addGlyphSet(self, glyphNames=[], glyphSetName="New glyph set"): @@ -1384,7 +1404,7 @@ class GlyphSetTab(QWidget):          del self.glyphSets[self._cachedName]      def importFromCurrentFont(self): -        currentMainWindow = QApplication.instance().currentMainWindow +        currentMainWindow = QApplication.instance().currentMainWindow()          glyphs = currentMainWindow.getGlyphs()          info = currentMainWindow.font.info          name = "%s %s" % (info.familyName, info.styleName) @@ -1419,6 +1439,17 @@ class GlyphSetTab(QWidget):              index += 1          settings.endArray() +    def getGlyphList(self): +        fileFormats = ( +            "Text file (*.txt)", +            "All files (*.*)", +        ) +        path, _ = QFileDialog.getOpenFileName( +            self, "Open File", '', ";;".join(fileFormats) +        ) +        if path: +            self.glyphListEdit.setText(path) +      def writeValues(self):          # store content of the textEdit in the glyphSet dict          glyphNames = self.glyphSetContents.toPlainText().split() @@ -1433,6 +1464,9 @@ class GlyphSetTab(QWidget):              defaultGlyphSet = self.defaultGlyphSetDrop.currentText()              if defaultGlyphSet != latinDefault.name:                  settings.setValue("settings/defaultGlyphSet", defaultGlyphSet) +        glyphListPath = self.glyphListEdit.text() +        if glyphListPath: +            settings.setValue("settings/glyphListPath", glyphListPath)  class MetricsWindowTab(QTabWidget): diff --git a/Lib/defconQt/glyphView.py b/Lib/defconQt/glyphView.py index c2aeafe..811dd14 100644 --- a/Lib/defconQt/glyphView.py +++ b/Lib/defconQt/glyphView.py @@ -6,6 +6,7 @@ import pickle  from defcon import Anchor, Component  from defconQt import icons_db  # noqa  from defconQt.objects.defcon import TContour, TGlyph +from defconQt.objects.sizeGripItem import ResizeHandleItem, SizeGripItem  from defconQt.pens.copySelectionPen import CopySelectionPen  from defconQt.util import platformSpecific  from fontTools.misc import bezierTools @@ -16,7 +17,7 @@ from PyQt5.QtGui import (  from PyQt5.QtWidgets import (      QAction, QActionGroup, QApplication, QColorDialog, QComboBox, QDialog,      QDialogButtonBox, QGraphicsEllipseItem, QGraphicsItem, QGraphicsLineItem, -    QGraphicsPathItem, QGraphicsPixmapItem, QGraphicsRectItem, QGraphicsScene, +    QGraphicsPathItem, QGraphicsPixmapItem, QGraphicsScene,      QGraphicsSimpleTextItem, QGraphicsView, QGridLayout, QLabel, QLineEdit,      QListWidget, QMainWindow, QMenu, QRadioButton, QSizePolicy, QStyle,      QStyleOptionGraphicsItem, QToolBar, QWidget) @@ -197,6 +198,65 @@ class AddLayerDialog(QDialog):          return (name, result) +class LayerActionsDialog(QDialog): + +    def __init__(self, currentGlyph, parent=None): +        super().__init__(parent) +        self.setWindowModality(Qt.WindowModal) +        self.setWindowTitle("Layer actions…") +        self._workableLayers = [] +        for layer in currentGlyph.layerSet: +            if layer != currentGlyph.layer: +                self._workableLayers.append(layer) + +        layout = QGridLayout(self) + +        copyBox = QRadioButton("Copy", self) +        moveBox = QRadioButton("Move", self) +        swapBox = QRadioButton("Swap", self) +        self.otherCheckBoxes = (moveBox, swapBox) +        copyBox.setChecked(True) + +        self.layersList = QListWidget(self) +        self.layersList.addItems( +            layer.name for layer in self._workableLayers) +        if self.layersList.count(): +            self.layersList.setCurrentRow(0) +        self.layersList.itemDoubleClicked.connect(self.accept) + +        buttonBox = QDialogButtonBox( +            QDialogButtonBox.Ok | QDialogButtonBox.Cancel) +        buttonBox.accepted.connect(self.accept) +        buttonBox.rejected.connect(self.reject) + +        l = 0 +        layout.addWidget(copyBox, l, 0, 1, 2) +        layout.addWidget(moveBox, l, 2, 1, 2) +        layout.addWidget(swapBox, l, 4, 1, 2) +        l += 1 +        layout.addWidget(self.layersList, l, 0, 1, 6) +        l += 1 +        layout.addWidget(buttonBox, l, 0, 1, 6) +        self.setLayout(layout) + +    @classmethod +    def getLayerAndAction(cls, parent, currentGlyph): +        dialog = cls(currentGlyph, parent) +        result = dialog.exec_() +        currentItem = dialog.layersList.currentItem() +        newLayer = None +        if currentItem is not None: +            newLayerName = currentItem.text() +            for layer in dialog._workableLayers: +                if layer.name == newLayerName: +                    newLayer = layer +        action = "Copy" +        for checkBox in dialog.otherCheckBoxes: +            if checkBox.isChecked(): +                action = checkBox.text() +        return (newLayer, action, result) + +  class GenericSettings(object):      def __init__(self, title, parent, callback): @@ -307,7 +367,8 @@ class MainGfxWindow(QMainWindow):          menuBar.addMenu(fileMenu)          glyphMenu = QMenu("&Glyph", self) -        glyphMenu.addAction("&Go to…", self.changeGlyph, "G") +        glyphMenu.addAction("&Go To…", self.changeGlyph, "G") +        glyphMenu.addAction("&Layer Actions…", self.layerActions, "L")          menuBar.addMenu(glyphMenu)          self._displaySettings = DisplayStyleSettings( @@ -364,6 +425,10 @@ class MainGfxWindow(QMainWindow):          self.setWindowTitle(glyph.name, glyph.getParent())          self.adjustSize() +    def layerActions(self): +        if self.view is not None: +            self.view.layerActions() +      def _changeGlyph(self, glyph):          oldView = self.view          # Preserve the selected layer (by setting the glyph from that layer) @@ -626,7 +691,7 @@ class OffCurvePointItem(QGraphicsEllipseItem):          self._needsUngrab = False      def delete(self): -        self.parentItem()._CPDeleted() +        self.parentItem()._CPDeleted(self)      def itemChange(self, change, value):          if change == QGraphicsItem.ItemPositionChange: @@ -646,10 +711,9 @@ class OffCurvePointItem(QGraphicsEllipseItem):                  else:                      value.setY(0)          elif change == QGraphicsItem.ItemPositionHasChanged: -            self.parentItem()._CPMoved(value) -        # TODO: consider what to do w offCurves -        # elif change == QGraphicsItem.ItemSelectedHasChanged: -        #    pass#self.parentItem()._CPSelChanged(value) +            self.parentItem()._CPMoved(self, value) +        elif change == QGraphicsItem.ItemSelectedHasChanged: +            self.parentItem()._CPSelected(self, value)          return value      def mousePressEvent(self, event): @@ -775,26 +839,33 @@ class OnCurvePointItem(QGraphicsPathItem):                  index += 1          return index % len(self._contour.segments) -    def _CPDeleted(self): +    def _CPDeleted(self, item): +        # XXX: is this sufficient guard? +        if self.isSelected(): +            return          pointIndex = self.getPointIndex()          children = self.childItems() -        selected = 1 -        if not (children[1].isVisible() and children[1].isSelected()): -            selected = 3 +        if item == children[1]: +            delta = -1 +            segmentOn = 0 +        else: +            delta = 1 +            segmentOn = 3 -        firstSibling = self._contour[pointIndex + selected - 2] -        secondSibling = self._contour[pointIndex + (selected - 2) * 2] +        firstSibling = self._contour.getPoint(pointIndex + delta) +        secondSibling = self._contour.getPoint(pointIndex + delta * 2)          if (firstSibling.segmentType is None and                  secondSibling.segmentType is None):              # we have two offCurves, wipe them +            self._contour.getPoint(pointIndex + segmentOn).segmentType = "line"              self._contour.removePoint(firstSibling)              self._contour.removePoint(secondSibling) -    def _CPMoved(self, newValue): +    def _CPMoved(self, item, newValue):          pointIndex = self.getPointIndex()          children = self.childItems()          # nodes are stored after lines (for stacking order) -        if children[1].isSelected(): +        if item == children[1]:              selected = 1              propagate = 3          else: @@ -806,8 +877,8 @@ class OnCurvePointItem(QGraphicsPathItem):          if not len(children) > 4:              elemIndex = pointIndex - 2 + selected -            self._contour[elemIndex].x = self.pos().x() + newValue.x() -            self._contour[elemIndex].y = self.pos().y() + newValue.y() +            self._contour.getPoint(elemIndex).x = self.pos().x() + newValue.x() +            self._contour.getPoint(elemIndex).y = self.pos().y() + newValue.y()          if not (self._isSmooth and children[propagate].isVisible()):              self.setShallowDirty()              return @@ -829,11 +900,21 @@ class OnCurvePointItem(QGraphicsPathItem):          children[propagate].setFlag(QGraphicsItem.ItemSendsGeometryChanges)          children[propagate - 1].setLine(line.x1(),                                          line.y1(), tmpLine.x2(), tmpLine.y2()) -        propagateInContour = pointIndex - 2 + propagate -        self._contour[propagateInContour].x = self.pos().x() + tmpLine.x2() -        self._contour[propagateInContour].y = self.pos().y() + tmpLine.y2() +        propagateIn = pointIndex - 2 + propagate +        self._contour.getPoint(propagateIn).x = self.pos().x() + tmpLine.x2() +        self._contour.getPoint(propagateIn).y = self.pos().y() + tmpLine.y2()          self.setShallowDirty() +    def _CPSelected(self, item, value): +        pointIndex = self.getPointIndex() +        children = self.childItems() +        if item == children[1]: +            delta = -1 +        else: +            delta = 1 + +        self._contour[pointIndex + delta].selected = value +      def itemChange(self, change, value):          if change == QGraphicsItem.ItemPositionChange:              if self.scene()._integerPlane: @@ -848,12 +929,14 @@ class OnCurvePointItem(QGraphicsPathItem):              children = self.childItems()              if children[1].isVisible():                  prevPos = children[1].pos() -                self._contour[pointIndex - 1].x = self.pos().x() + prevPos.x() -                self._contour[pointIndex - 1].y = self.pos().y() + prevPos.y() +                point = self._contour.getPoint(pointIndex - 1) +                point.x = self.pos().x() + prevPos.x() +                point.y = self.pos().y() + prevPos.y()              if children[3].isVisible():                  nextPos = children[3].pos() -                self._contour[pointIndex + 1].x = self.pos().x() + nextPos.x() -                self._contour[pointIndex + 1].y = self.pos().y() + nextPos.y() +                point = self._contour.getPoint(pointIndex + 1) +                point.x = self.pos().x() + nextPos.x() +                point.y = self.pos().y() + nextPos.y()              self.setShallowDirty()          elif change == QGraphicsItem.ItemSelectedHasChanged:              self._point.selected = value @@ -886,11 +969,11 @@ class OnCurvePointItem(QGraphicsPathItem):          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": -            nextToCP = self._contour[(ptIndex - 2 + i) % len(self._contour)] +        insertIndex = ptIndex + (i - 1) // 2 +        if self._contour.getPoint(insertIndex).segmentType == "line": +            nextToCP = self._contour.getPoint(ptIndex - 2 + i)              assert(nextToCP.segmentType is not None) -            self._contour[insertIndex].segmentType = "curve" +            self._contour.getPoint(insertIndex).segmentType = "curve"              if i == 1:                  first, second = (                      self._point.x, self._point.y), (nextToCP.x, nextToCP.y) @@ -1104,86 +1187,32 @@ class VGuidelinesTextItem(QGraphicsSimpleTextItem):          self.setFont(font) -class ResizeHandleItem(QGraphicsRectItem): - -    def __init__(self, parent=None): -        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) - -        rect = self.parentItem().boundingRect() -        self.setPos(rect.width(), rect.height()) - -    def itemChange(self, change, value): -        if change == QGraphicsItem.ItemSelectedChange: -            if not value: -                self.setVisible(value) -        return value - -    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): +    def __init__(self, x, y, pixmap, scale, parent=None):          super(QGraphicsPixmapItem, self).__init__(pixmap, parent) -        self.setPos(x, y) -        self.setFlag(QGraphicsItem.ItemIsMovable) +        self._pixmap = pixmap +        self.setOffset(x, -y)          self.setFlag(QGraphicsItem.ItemIsSelectable) +        self.setShapeMode(QGraphicsPixmapItem.BoundingRectShape)          self.setTransform(QTransform().fromScale(1, -1)) -        self.setOpacity(.5) +        self.setOpacity(.6)          self.setZValue(-1) - -        rect = self.boundingRect() -        self._rWidth = rect.width() -        self._rHeight = rect.height() -        handle = ResizeHandleItem(self) -        handle.setVisible(False) - -    def _pixmapGeometryChanged(self, event): -        modifiers = event.modifiers() -        pos = event.scenePos() -        if modifiers & Qt.ControlModifier: -            # rotate -            refLine = QLineF(self.x(), self.y(), self.x() + -                             self._rWidth, self.y() - self._rHeight) -            curLine = QLineF(self.x(), self.y(), pos.x(), pos.y()) -            self.setRotation(refLine.angleTo(curLine)) -        else: -            # scale -            dy = (pos.y() - self.y()) / self._rHeight -            if modifiers & Qt.ShiftModifier: -                # keep original aspect ratio -                dx = -dy -            else: -                dx = (pos.x() - self.x()) / self._rWidth -            self.setTransform(QTransform().fromScale(dx, dy)) -        event.accept() +        sizeGripItem = SizeGripItem(scale, self) +        sizeGripItem.setVisible(False) + +    def setRect(self, rect): +        dTopLeft = rect.topLeft() - self.pos() +        if not dTopLeft.isNull(): +            self.setOffset(dTopLeft) +        self.setPixmap(self._pixmap.scaled( +            rect.size().toSize() +        ))      def itemChange(self, change, value):          if change == QGraphicsItem.ItemSelectedChange: -            children = self.childItems() -            if not children[0].isUnderMouse(): -                children[0].setVisible(value) +            sizeGripItem = self.childItems()[0] +            sizeGripItem.setVisible(value)          return value @@ -1247,8 +1276,8 @@ class GlyphScene(QGraphicsScene):          else:              return          pos = event.scenePos() -        newPix = PixmapItem(pos.x(), pos.y(), dragPix) -        self._addRegisterItem(newPix) +        pixmapItem = PixmapItem(pos.x(), pos.y(), dragPix, self.getViewScale()) +        self._addRegisterItem(pixmapItem)          event.acceptProposedAction()      def getItemForPoint(self, point): @@ -1289,8 +1318,6 @@ class GlyphScene(QGraphicsScene):                  elif isinstance(item, (AnchorItem, ComponentItem,                                         OffCurvePointItem)):                      item.delete() -                elif isinstance(item, PixmapItem): -                    self.removeItem(item)              self._blocked = False              self._glyphObject.dirty = True              event.accept() @@ -1776,6 +1803,8 @@ class GlyphScene(QGraphicsScene):          for contour in glyph:              segments = contour.segments              for index, seg in enumerate(segments): +                if seg[-1].segmentType == "move": +                    continue                  prev = segments[index - 1][-1]                  if len(seg) == 3:                      i = self.computeIntersections( @@ -1805,6 +1834,9 @@ class GlyphScene(QGraphicsScene):          for dot in self._knifeDots:              self.removeItem(dot)          self._knifeDots = [] +        # no-move clicks +        if self._cachedIntersections is None: +            return          # reverse so as to not invalidate our cached segment indexes          for loc, ts in reversed(list(self._cachedIntersections.items())):              contour, index = loc @@ -2181,14 +2213,13 @@ class GlyphView(QGraphicsView):      def updateActiveLayerPath(self):          self.updateLayerPath(              self._layer, representationKey="defconQt.NoComponentsQPainterPath") +        self.addStartPoints()      def updateLayerPath(self, layer,                          representationKey="defconQt.QPainterPath"):          glyph = layer[self._name] -        # scene = self.scene()  # unused          path = glyph.getRepresentation(representationKey)          self._sceneItems[layer].setPath(path) -        self.addStartPoints()      def _getSceneItems(self, key, clear=False):          items = self._sceneItems.get(key, None) @@ -2317,6 +2348,34 @@ class GlyphView(QGraphicsView):              component.baseGlyph = newGlyph.name              self._glyph.appendComponent(component) +    def layerActions(self): +        newLayer, action, ok = LayerActionsDialog.getLayerAndAction( +            self, self._glyph) +        if ok and newLayer is not None: +            # TODO: whole glyph for now, but consider selection too +            if not self._glyph.name in newLayer: +                newLayer.newGlyph(self._glyph.name) +            otherGlyph = newLayer[self._glyph.name] +            otherGlyph.disableNotifications() +            if action == "Swap": +                tempGlyph = TGlyph() +                otherGlyph.drawPoints(tempGlyph.getPointPen()) +                tempGlyph.width = otherGlyph.width +                otherGlyph.clearContours() +            self._glyph.drawPoints(otherGlyph.getPointPen()) +            otherGlyph.width = self._glyph.width +            if action != "Copy": +                self._glyph.disableNotifications() +                self._glyph.clearContours() +                # XXX: we shouldn't have to do this manually but it seems there +                # is a timing problem +                self._glyph.destroyAllRepresentations() +                if action == "Swap": +                    tempGlyph.drawPoints(self._glyph.getPointPen()) +                    self._glyph.width = tempGlyph.width +                self._glyph.enableNotifications() +            otherGlyph.enableNotifications() +      def _makeLayerGlyph(self, layer):          name = self._name          glyph = layer.newGlyph(name) diff --git a/Lib/defconQt/objects/defcon.py b/Lib/defconQt/objects/defcon.py index 496f1c6..48de173 100644 --- a/Lib/defconQt/objects/defcon.py +++ b/Lib/defconQt/objects/defcon.py @@ -1,6 +1,7 @@  from defcon import Font, Contour, Glyph, Point  from defcon.objects.base import BaseObject -from fontTools.agl import AGL2UV +from PyQt5.QtWidgets import QApplication +import fontTools  class TFont(Font): @@ -59,10 +60,15 @@ class TGlyph(Glyph):      dirty = property(BaseObject._get_dirty, _set_dirty)      def autoUnicodes(self): +        app = QApplication.instance() +        if app.GL2UV is not None: +            GL2UV = app.GL2UV +        else: +            GL2UV = fontTools.agl.AGL2UV          hexes = "ABCDEF0123456789"          name = self.name -        if name in AGL2UV: -            uni = AGL2UV[name] +        if name in GL2UV: +            uni = GL2UV[name]          elif (name.startswith("uni") and len(name) == 7 and                all(c in hexes for c in name[3:])):              uni = int(name[3:], 16) @@ -93,6 +99,9 @@ class TContour(Contour):                                selected=point.selected)          pointPen.endPath() +    def getPoint(self, index): +        return self[index % len(self)] +  class TPoint(Point):      __slots__ = ["_selected"] diff --git a/Lib/defconQt/objects/sizeGripItem.py b/Lib/defconQt/objects/sizeGripItem.py new file mode 100644 index 0000000..94e07ba --- /dev/null +++ b/Lib/defconQt/objects/sizeGripItem.py @@ -0,0 +1,205 @@ +# SizeGripItem - A size grip QGraphicsItem for interactive resizing. +# +# Python port by Felipe Correa da Silva Sanches +# based on the original C++ code by Cesar L. B. Silveira +# +# Copyright 2011, Cesar L. B. Silveira. +# Copyright 2015, Felipe Correa da Silva Sanches <juca@members.fsf.org>. +# Copyright 2015, Adrien Tétar. +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. + +from PyQt5.QtCore import Qt +from PyQt5.QtGui import QBrush, QPen +from PyQt5.QtWidgets import QGraphicsItem, QGraphicsRectItem + +Top = 1 << 0 +Bottom = 1 << 1 +Left = 1 << 2 +Right = 1 << 3 +Center = 1 << 4 +TopLeft = Top | Left +BottomLeft = Bottom | Left +TopRight = Top | Right +BottomRight = Bottom | Right + +possibleFlags = (Top, Bottom, Left, TopLeft, BottomLeft, Right, TopRight, +                 BottomRight, Center) + + +class ResizeHandleItem(QGraphicsRectItem): +    def __init__(self, positionFlags, scale, parent): +        super(ResizeHandleItem, self).__init__(parent) +        self.setPointPath(scale) +        self.positionFlags = positionFlags +        self.setBrush(QBrush(Qt.lightGray)) +        self.setFlag(QGraphicsItem.ItemIsMovable) +        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) +        if self.positionFlags in (Top, Bottom): +            cursor = Qt.SizeVerCursor +        elif self.positionFlags in (Left, Right): +            cursor = Qt.SizeHorCursor +        elif self.positionFlags in (BottomLeft, TopRight): +            cursor = Qt.SizeBDiagCursor +        elif self.positionFlags in (TopLeft, BottomRight): +            cursor = Qt.SizeFDiagCursor +        elif self.positionFlags == Center: +            cursor = Qt.SizeAllCursor +        self.setCursor(cursor) + +    def itemChange(self, change, value): +        if change == QGraphicsItem.ItemPositionChange: +            return self.restrictPosition(value) +        return value + +    def mouseMoveEvent(self, event): +        pos = self.mapToParent(event.pos()) +        parent = self.parentItem() +        if self.positionFlags == TopLeft: +            parent.setTopLeft(pos) +        elif self.positionFlags == Top: +            parent.setTop(pos.y()) +        elif self.positionFlags == TopRight: +            parent.setTopRight(pos) +        elif self.positionFlags == Right: +            parent.setRight(pos.x()) +        elif self.positionFlags == BottomRight: +            parent.setBottomRight(pos) +        elif self.positionFlags == Bottom: +            parent.setBottom(pos.y()) +        elif self.positionFlags == BottomLeft: +            parent.setBottomLeft(pos) +        elif self.positionFlags == Left: +            parent.setLeft(pos.x()) +        elif self.positionFlags == Center: +            parent.setCenter(pos) +        parent.doResize() + +    def restrictPosition(self, newPos): +        parent = self.parentItem() +        retVal = newPos + +        if self.positionFlags & Top or self.positionFlags & Bottom: +            retVal.setY(newPos.y()) +        if self.positionFlags & Left or self.positionFlags & Right: +            retVal.setX(newPos.x()) + +        if self.positionFlags & Top and retVal.y() > parent.rect.bottom(): +            retVal.setY(parent.rect.bottom()) +        elif self.positionFlags & Bottom and retVal.y() < parent.rect.top(): +            retVal.setY(parent.rect.top()) + +        if self.positionFlags & Left and retVal.x() > parent.rect.right(): +            retVal.setX(parent.rect.right()) +        elif self.positionFlags & Right and retVal.x() < parent.rect.left(): +            retVal.setX(parent.rect.left()) + +        return retVal + +    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.setPen(QPen(Qt.black, 1.0 / scale)) +        self.setRect(-4 / scale, -4 / scale, 8 / scale, 8 / scale) + + +class SizeGripItem(QGraphicsItem): +    def __init__(self, scale, parent): +        super(SizeGripItem, self).__init__(parent) +        self.setFlag(QGraphicsItem.ItemIgnoresParentOpacity) + +        for flag in possibleFlags: +            ResizeHandleItem(flag, scale, self) +        self.updateBoundingRect() + +    def boundingRect(self): +        return self.rect + +    def paint(self, painter, option, widget): +        pass + +    def setTopLeft(self, pos): +        self.rect.setTopLeft(pos) + +    def setTop(self, y): +        self.rect.setTop(y) + +    def setTopRight(self, pos): +        self.rect.setTopRight(pos) + +    def setRight(self, x): +        self.rect.setRight(x) + +    def setBottomRight(self, pos): +        self.rect.setBottomRight(pos) + +    def setBottom(self, y): +        self.rect.setBottom(y) + +    def setBottomLeft(self, pos): +        self.rect.setBottomLeft(pos) + +    def setLeft(self, x): +        self.rect.setLeft(x) + +    def setCenter(self, pos): +        self.rect.moveCenter(pos) + +    def doResize(self): +        self.parentItem().setRect(self.rect) +        self.updateHandleItemPositions() + +    def updateBoundingRect(self): +        self.rect = self.parentItem().boundingRect() +        self.updateHandleItemPositions() + +    def updateHandleItemPositions(self): +        for item in self.childItems(): +            item.setFlag(QGraphicsItem.ItemSendsGeometryChanges, False) +            flags = item.positionFlags +            if flags == TopLeft: +                item.setPos(self.rect.topLeft()) +            elif flags == Top: +                item.setPos(self.rect.left() + self.rect.width() / 2 - 1, +                            self.rect.top()) +            elif flags == TopRight: +                item.setPos(self.rect.topRight()) +            elif flags == Right: +                item.setPos(self.rect.right(), +                            self.rect.top() + self.rect.height() / 2 - 1) +            elif flags == BottomRight: +                item.setPos(self.rect.bottomRight()) +            elif flags == Bottom: +                item.setPos(self.rect.left() + self.rect.width() / 2 - 1, +                            self.rect.bottom()) +            elif flags == BottomLeft: +                item.setPos(self.rect.bottomLeft()) +            elif flags == Left: +                item.setPos(self.rect.left(), +                            self.rect.top() + self.rect.height() / 2 - 1) +            elif flags == Center: +                item.setPos(self.rect.center()) +            item.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True) diff --git a/Lib/defconQt/util/glyphList.py b/Lib/defconQt/util/glyphList.py new file mode 100644 index 0000000..ee97d78 --- /dev/null +++ b/Lib/defconQt/util/glyphList.py @@ -0,0 +1,21 @@ +import re + +_parseGL_RE = re.compile("([A-Za-z_0-9.]+);([0-9A-F]{4})") + + +def parseGlyphList(path): +    GL2UV = {} +    with open(path) as file: +        for line in file: +            if not line or line[:1] == '#': +                continue +            m = _parseGL_RE.match(line) +            if not m: +                raise SyntaxError("syntax error in glyphlist: %s" +                                  .format(repr(line[:20]))) +            glyphName = m.group(1) +            if glyphName in GL2UV: +                print("warning: glyphName redefined in glyphList: {}".format( +                    glyphName)) +            GL2UV[glyphName] = int(m.group(2), 16) +    return GL2UV | 
