diff options
| author | Adrien Tétar | 2015-05-09 18:46:10 +0200 | 
|---|---|---|
| committer | Adrien Tétar | 2015-05-09 18:46:10 +0200 | 
| commit | e83660ec042e9d6fe0daab5459c19c681639a4a9 (patch) | |
| tree | b4911a11b65c4a952162f973f691d234eb7abdb0 /Lib/defconQt | |
| parent | 7dd7d2f4ccb2337f3f14e3317c7f328023420bb8 (diff) | |
| download | trufont-e83660ec042e9d6fe0daab5459c19c681639a4a9.tar.bz2 | |
Checkpoint
Diffstat (limited to 'Lib/defconQt')
| -rw-r--r-- | Lib/defconQt/fontView.py | 41 | ||||
| -rw-r--r-- | Lib/defconQt/fontinfo.py | 36 | ||||
| -rw-r--r-- | Lib/defconQt/representationFactories/__init__.py | 21 | ||||
| -rw-r--r-- | Lib/defconQt/spacecenter.py | 197 | ||||
| -rw-r--r-- | Lib/defconQt/svgViewer.py | 188 | ||||
| -rw-r--r-- | Lib/defconQt/syntaxhighlighter.py | 1 | 
6 files changed, 343 insertions, 141 deletions
diff --git a/Lib/defconQt/fontView.py b/Lib/defconQt/fontView.py index 61e7792..a13a60a 100644 --- a/Lib/defconQt/fontView.py +++ b/Lib/defconQt/fontView.py @@ -37,6 +37,12 @@ class CharacterWidget(QWidget):      def updateFont(self, font):          self.font = font          self.glyphs = [font[k] for k in font.unicodeData.sortGlyphNames(font.keys(), glyphSortDescriptors)] +        self.adjustSize() +        self.update() +     +    def updateGlyphs(self): +        self.glyphs = [self.font[k] for k in self.font.unicodeData.sortGlyphNames(self.font.keys(), glyphSortDescriptors)] +        self.adjustSize()          self.update()      def _sizeEvent(self, width, squareSize=None): @@ -199,9 +205,9 @@ class MainWindow(QMainWindow):          fontMenu.addAction("Font &info", self.fontInfo, "Ctrl+I")          fontMenu.addAction("Font &features", self.fontFeatures, "Ctrl+F") +        fontMenu.addAction("&Add glyph", self.addGlyph, "Ctrl+U")          fontMenu.addSeparator()          fontMenu.addAction("&Space center", self.spaceCenter, "Ctrl+Y") -        fontMenu.addAction("&Glyph view", self.glyphView, "Ctrl+G")          helpMenu = QMenu("&Help", self)          self.menuBar().addMenu(helpMenu) @@ -227,10 +233,12 @@ class MainWindow(QMainWindow):          self.characterWidget.glyphOpened.connect(self._glyphOpened)          self.setWindowTitle(os.path.basename(self.font.path.rstrip(os.sep)))          # TODO: dump the hardcoded path -        self.setWindowIcon(QIcon("C:\\Users\\Adrien\\Downloads\\defconQt\\Lib\\defconQt\\resources\\icon.png")); +        #self.setWindowIcon(QIcon("C:\\Users\\Adrien\\Downloads\\defconQt\\Lib\\defconQt\\resources\\icon.png"))      def newFile(self): +        # TODO: ask for save before leaving          self.font = Font() +        self.setWindowTitle("Untitled.ufo")          self.characterWidget.updateFont(self.font)      def openFile(self, path=None): @@ -249,10 +257,10 @@ class MainWindow(QMainWindow):  #        self.font.path = path # done by defcon      def saveFileAs(self): -        path, _ = QFileDialog.getSaveFileName(self, "Save File", '', +        path, ok = QFileDialog.getSaveFileName(self, "Save File", '',                  "UFO Fonts (*.ufo)") -        print(path) -        self.saveFile(path) +        if ok: +            self.saveFile(path)      def saveAndExit(self):          # TODO: check if font changed @@ -303,23 +311,20 @@ class MainWindow(QMainWindow):      def spaceCenter(self):          # TODO: see up here +        # TODO: show selection in a space center, rewind selection if we raise window (rf)          from spaceCenter import MainSpaceWindow          if not (hasattr(self, 'spaceCenterWindow') and self.spaceCenterWindow.isVisible()): -            # XXX: window collapses when passing self as parent... -            self.spaceCenterWindow = MainSpaceWindow(self.font, "Hiyazee otaHawa.") +            self.spaceCenterWindow = MainSpaceWindow(self.font, "Hiyazee otaHawa.", parent=self)              self.spaceCenterWindow.show()          else:              self.spaceCenterWindow.raise_() - -    def glyphView(self): -        # TODO: see up here -        from svgViewer import MainGfxWindow -        if not (hasattr(self, 'glyphViewWindow') and self.glyphViewWindow.isVisible()): -            # XXX: window collapses when passing self as parent... -            self.glyphViewWindow = MainGfxWindow(self.font, self.font["a"], self) -            self.glyphViewWindow.show() -        else: -            self.glyphViewWindow.raise_() +     +    def addGlyph(self): +        gName, ok = QInputDialog.getText(self, "Add glyph", "Name of the glyph:") +        # Not overwriting existing glyphs. Should it warn in this case? (rf) +        if ok and gName != '': +            self.font.newGlyph(gName) +            self.characterWidget.updateGlyphs()      def about(self):          QMessageBox.about(self, "About Me", @@ -337,6 +342,8 @@ if __name__ == '__main__':      representationFactories.registerAllFactories()      #with PyCallGraph(output=GraphvizOutput()):      app = QApplication(sys.argv) +    # TODO: http://stackoverflow.com/a/21330349/2037879 +    app.setWindowIcon(QIcon("C:\\Users\\Adrien\\Downloads\\defconQt\\Lib\\defconQt\\resources\\icon.png"))      window = MainWindow(Font("C:\\CharterNova-Regular.ufo"))      window.resize(565, 430)      window.show() diff --git a/Lib/defconQt/fontinfo.py b/Lib/defconQt/fontinfo.py index ce27b33..1ce956a 100644 --- a/Lib/defconQt/fontinfo.py +++ b/Lib/defconQt/fontinfo.py @@ -84,11 +84,11 @@ class GeneralTab(QWidget):          # TODO: give visual feedback of input data validity using QLineEdit lose focus event          # http://snorf.net/blog/2014/08/09/using-qvalidator-in-pyqt4-to-validate-user-input/          versionLabel = QLabel("Version:") -        self.versionMajorEdit = QLineEdit(str(font.info.versionMajor)) +        self.versionMajorEdit = QLineEdit(str(font.info.versionMajor or ''))          self.versionMajorEdit.setAlignment(Qt.AlignRight)          self.versionMajorEdit.setValidator(QIntValidator())          versionDotLabel = QLabel(".") -        self.versionMinorEdit = QLineEdit(str(font.info.versionMinor).zfill(3)) +        self.versionMinorEdit = QLineEdit(str(font.info.versionMinor or ''))#.zfill(3))          self.versionMinorEdit.setValidator(QIntValidator())          mainLayout.addWidget(versionLabel, 6, 0) @@ -97,7 +97,7 @@ class GeneralTab(QWidget):          mainLayout.addWidget(self.versionMinorEdit, 6, 3)          unitsPerEmLabel = QLabel("Units per em:") -        self.unitsPerEmEdit = QLineEdit(str(font.info.unitsPerEm)) +        self.unitsPerEmEdit = QLineEdit(str(font.info.unitsPerEm or ''))          self.unitsPerEmEdit.setValidator(QIntValidator())          mainLayout.addWidget(unitsPerEmLabel, 6, 4) @@ -137,15 +137,6 @@ class GeneralTab(QWidget):          font.info.openTypeNameLicense = self.licenseEdit.text()          font.info.openTypeNameLicenseURL = self.licenseURLEdit.text()          font.info.trademark = self.trademarkEdit.text() -        """ -        font.info.styleMapFamilyName = self.styleMapFamilyEdit.text() -        sn = self.styleMapStyleDrop.currentIndex() -        if sn == 1: font.info.styleMapStyleName = "regular" -        elif sn == 2: font.info.styleMapStyleName = "italic" -        elif sn == 3: font.info.styleMapStyleName = "bold" -        elif sn == 4: font.info.styleMapStyleName = "bold italic" -        else: font.info.styleMapStyleName = None -        """  class NextTab(QWidget):      def __init__(self, font, parent=None): @@ -183,15 +174,15 @@ class NextTab(QWidget):          mainLayout.addWidget(self.styleMapStyleDrop, 0, 5)          ascenderLabel = QLabel("Ascender:") -        self.ascenderEdit = QLineEdit(str(font.info.ascender)) +        self.ascenderEdit = QLineEdit(str(font.info.ascender or ''))          self.ascenderEdit.setValidator(QIntValidator())          descenderLabel = QLabel("Descender:") -        self.descenderEdit = QLineEdit(str(font.info.descender)) +        self.descenderEdit = QLineEdit(str(font.info.descender or ''))          self.descenderEdit.setValidator(QIntValidator())          italicAngleLabel = QLabel("Italic angle:") -        self.italicAngleEdit = QLineEdit(str(font.info.italicAngle)) +        self.italicAngleEdit = QLineEdit(str(font.info.italicAngle or ''))          self.italicAngleEdit.setValidator(QDoubleValidator())          mainLayout.addWidget(ascenderLabel, 1, 0) @@ -202,11 +193,11 @@ class NextTab(QWidget):          mainLayout.addWidget(self.italicAngleEdit, 1, 5)          xHeightLabel = QLabel("x-height:") -        self.xHeightEdit = QLineEdit(str(font.info.xHeight)) +        self.xHeightEdit = QLineEdit(str(font.info.xHeight or ''))          self.xHeightEdit.setValidator(QIntValidator())          capHeightLabel = QLabel("Cap height:") -        self.capHeightEdit = QLineEdit(str(font.info.capHeight)) +        self.capHeightEdit = QLineEdit(str(font.info.capHeight or ''))          self.capHeightEdit.setValidator(QIntValidator())          mainLayout.addWidget(xHeightLabel, 2, 0) @@ -214,4 +205,13 @@ class NextTab(QWidget):          mainLayout.addWidget(capHeightLabel, 2, 2)          mainLayout.addWidget(self.capHeightEdit, 2, 3) -        self.setLayout(mainLayout)
\ No newline at end of file +        self.setLayout(mainLayout) +         +    def writeValues(self, font): +        font.info.styleMapFamilyName = self.styleMapFamilyEdit.text() +        sn = self.styleMapStyleDrop.currentIndex() +        if sn == 1: font.info.styleMapStyleName = "regular" +        elif sn == 2: font.info.styleMapStyleName = "italic" +        elif sn == 3: font.info.styleMapStyleName = "bold" +        elif sn == 4: font.info.styleMapStyleName = "bold italic" +        else: font.info.styleMapStyleName = None
\ No newline at end of file diff --git a/Lib/defconQt/representationFactories/__init__.py b/Lib/defconQt/representationFactories/__init__.py index e2135e4..c2ea89e 100644 --- a/Lib/defconQt/representationFactories/__init__.py +++ b/Lib/defconQt/representationFactories/__init__.py @@ -83,10 +83,17 @@ class OutlineInformationPen(AbstractPointPen):          self._rawPointData = []          self._rawComponentData = []          self._bezierHandleData = [] +        self.index = 0      def getData(self): -        data = dict(startPoints=[], onCurvePoints=[], offCurvePoints=[], bezierHandles=[], anchors=[], components=self._rawComponentData) +        data = dict(startPoints=[], onCurvePoints=[], offCurvePoints=[], bezierHandles=[], anchors=[], lastSubpathPoints=[], components=self._rawComponentData) +          for contour in self._rawPointData: +            if type(contour) is str: +                print("Hill") +                data["lastSubpathPoints"].append(self.index) +                self.index += 1 +                continue              # anchor              if len(contour) == 1 and contour[0]["name"] is not None:                  anchor = contour[0] @@ -96,8 +103,11 @@ class OutlineInformationPen(AbstractPointPen):                  haveFirst = False                  for pointIndex, point in enumerate(contour):                      if point["segmentType"] is None: -                        data["offCurvePoints"].append(point) +                        print("OffCurve") +                        data["offCurvePoints"].append((point, self.index, not haveFirst)) +                        self.index += 1                          # look for handles +                        # TODO: calculate this when drawing                          back = contour[pointIndex - 1]                          forward = contour[(pointIndex + 1) % len(contour)]                          if back["segmentType"] in ("curve", "line"): @@ -111,7 +121,9 @@ class OutlineInformationPen(AbstractPointPen):                              if p1 != p2:                                  data["bezierHandles"].append((p1, p2))                      else: -                        data["onCurvePoints"].append(point) +                        data["onCurvePoints"].append((point, self.index, not haveFirst)) +                        print("OnCurve") +                        self.index += 1                          # catch first point                          if not haveFirst:                              haveFirst = True @@ -137,7 +149,8 @@ class OutlineInformationPen(AbstractPointPen):          self._rawPointData.append([])      def endPath(self): -        pass +        # TODO: appending a string may not be the most elegant thing to do +        self._rawPointData.append("Subpath")      def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):          d = dict(point=pt, segmentType=segmentType, smooth=smooth, name=name) diff --git a/Lib/defconQt/spacecenter.py b/Lib/defconQt/spacecenter.py index d518ace..087d319 100644 --- a/Lib/defconQt/spacecenter.py +++ b/Lib/defconQt/spacecenter.py @@ -8,13 +8,14 @@ defaultPointSize = 150  class MainSpaceWindow(QWidget):      def __init__(self, font, string="Hello World", pointSize=defaultPointSize, parent=None): -        super(MainSpaceWindow, self).__init__(parent) +        super(MainSpaceWindow, self).__init__(parent, Qt.Window)          self.font = font -        self.string = string -        self.toolbar = FontToolBar(self.font, pointSize, self.string, self) -        self.canvas = GlyphsCanvas(self.font, self.string, pointSize, self) -        self.table = SpaceTable(self.font, self.string, self) +        self.glyphs = [] +        self._subscribeToGlyphsText(string) +        self.toolbar = FontToolBar(string, pointSize, self) +        self.canvas = GlyphsCanvas(self.font, self.glyphs, pointSize, self) +        self.table = SpaceTable(self.glyphs, self)          layout = QVBoxLayout(self)          layout.addWidget(self.toolbar) @@ -25,9 +26,9 @@ class MainSpaceWindow(QWidget):          self.setLayout(layout)          self.resize(600,500)          self.toolbar.comboBox.currentIndexChanged[str].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.toolbar.textField.textEdited.connect(self._textChanged) +         +        self.font.info.addObserver(self, "_fontInfoChanged", "Info.Changed")          self.setWindowTitle("%s%s%s%s" % ("Space center – ", self.font.info.familyName, " ", self.font.info.styleName)) @@ -36,18 +37,71 @@ class MainSpaceWindow(QWidget):          self.menuBar().addMenu(fileMenu)          fileMenu.addAction("&Save...", self.save, "Ctrl+S") -        fileMenu.addAction("E&xit", QApplication.instance().quit, "Ctrl+Q") +        fileMenu.addAction("E&xit", self.close, "Ctrl+Q") +     +    def close(self): +        self.font.info.removeObserver(self, "Info.Changed") +        self._unsubscribeFromGlyphs() +        super(MainSpaceWindow, self).close() +     +    def _fontInfoChanged(self): +        self.canvas.update() +     +    def _glyphChanged(self, event): +        self.canvas.update() +        self.table.blockSignals(True) +        self.table.fillGlyphs() +        self.table.blockSignals(False) +     +    def _textChanged(self, newText): +        self.setGlyphs(newText) +        self.canvas._glyphsChanged(self.glyphs) +        self.table.blockSignals(True) +        self.table._glyphsChanged(self.glyphs) +        self.table.blockSignals(False) +     +    def _subscribeToGlyphsText(self, newText): +        glyphs = [] +        # TODO: lexer +        for c in newText: +            name = self.font.unicodeData.glyphNameForUnicode(ord(c)) +            if name not in self.font: continue +            glyphs.append(self.font[name]) +        self.glyphs = glyphs + +        handledGlyphs = set() +        for glyph in self.glyphs: +            if glyph in handledGlyphs: +                continue +            handledGlyphs.add(glyph) +            glyph.addObserver(self, "_glyphChanged", "Glyph.Changed") +         +    def _unsubscribeFromGlyphs(self): +        handledGlyphs = set() +        for glyph in self.glyphs: +            if glyph in handledGlyphs: +                continue +            handledGlyphs.add(glyph) +            glyph.removeObserver(self, "Glyph.Changed") +        #self.glyphs = None + +    def setGlyphs(self, string): +        # unsubscribe from the old glyphs +        self._unsubscribeFromGlyphs() +        # subscribe to the new glyphs +        self._subscribeToGlyphsText(string) +        # set the records into the view +        self.canvas._glyphsChanged(self.glyphs) +        self.table._glyphsChanged(self.glyphs)  pointSizes = [50, 75, 100, 125, 150, 200, 250, 300, 350, 400, 450, 500]  class FontToolBar(QToolBar): -    def __init__(self, font, pointSize, string, parent=None): +    def __init__(self, string, pointSize, parent=None):          super(FontToolBar, self).__init__(parent)          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:              self.comboBox.addItem(str(p))          self.comboBox.lineEdit().setText(str(pointSize)) @@ -56,21 +110,20 @@ class FontToolBar(QToolBar):          self.addWidget(self.comboBox)  class GlyphsCanvas(QWidget): -    def __init__(self, font, string, pointSize=defaultPointSize, parent=None): +    def __init__(self, font, glyphs, pointSize=defaultPointSize, parent=None):          super(GlyphsCanvas, self).__init__(parent) -        self.font = font -        self.string = string - +        self.descender = font.info.descender +        if self.descender is None: self.descender = 250 +        self.upm = font.info.unitsPerEm +        if self.upm is None or not self.upm > 0: self.upm = 1000 +        self.glyphs = glyphs          self.ptSize = pointSize          self.calculateScale()          self.padding = 10      def calculateScale(self): -        if self.font.info.unitsPerEm is None: return -        upm = self.font.info.unitsPerEm -        if not upm > 0: upm = 1000 -        scale = self.ptSize / float(self.font.info.unitsPerEm) +        scale = self.ptSize / float(self.upm)          if scale < .01: scale = 0.01          self.scale = scale @@ -79,22 +132,8 @@ class GlyphsCanvas(QWidget):          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 +    def _glyphsChanged(self, newGlyphs): +        self.glyphs = newGlyphs          self.update()      # if we have a cell clicked in and we click on the canvas, @@ -103,30 +142,40 @@ class GlyphsCanvas(QWidget):      # QTableWidget.scrollToItem()      def mousePressEvent(self, event):          self.setFocus(Qt.MouseFocusReason) +     +    def wheelEvent(self, event): +        # TODO: should it snap to predefined pointSizes? is the scaling factor okay? +        # see how rf behaves +        decay = event.angleDelta().y() / 120.0 +        newPointSize = self.ptSize + int(decay) * 10 +        self._pointSizeChanged(newPointSize) +         +        comboBox = self.parent().toolbar.comboBox +        comboBox.blockSignals(True) +        comboBox.setEditText(str(newPointSize)) +        comboBox.blockSignals(False)      def paintEvent(self, event):          painter = QPainter(self)          painter.setRenderHint(QPainter.Antialiasing)          painter.fillRect(0, 0, self.width(), self.height(), Qt.white)          # 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) +        painter.translate(self.padding, self.padding+self.ptSize+self.descender*self.scale)          cur_width = 0 -        for c in self.string: -            glyph = self.font.unicodeData.glyphNameForUnicode(ord(c)) -            if glyph not in self.font: continue +        for glyph in self.glyphs:              # line wrapping -            if cur_width + self.font[glyph].width*self.scale + self.padding > self.width(): +            if cur_width + glyph.width*self.scale + self.padding > self.width():                  painter.translate(-cur_width, self.ptSize) -                cur_width = self.font[glyph].width*self.scale +                cur_width = glyph.width*self.scale              else: -                cur_width += self.font[glyph].width*self.scale -            glyphPath = self.font[glyph].getRepresentation("defconQt.QPainterPath") +                cur_width += glyph.width*self.scale +            glyphPath = glyph.getRepresentation("defconQt.QPainterPath")              painter.save()              painter.scale(self.scale, -self.scale)              painter.fillPath(glyphPath, Qt.black)              painter.restore() -            painter.translate(self.font[glyph].width*self.scale, 0) +            painter.translate(glyph.width*self.scale, 0)      '''          painter.setPen( @@ -140,10 +189,13 @@ class GlyphsCanvas(QWidget):      '''  class SpaceTable(QTableWidget): -    def __init__(self, font, string="", parent=None): -        self.font = font -        self.string = string -        super(SpaceTable, self).__init__(4, len(self.string), parent) +    def __init__(self, glyphs, parent=None): +        self.glyphs = glyphs +        super(SpaceTable, self).__init__(4, len(glyphs)+1, parent) +        # XXX: dunno why but without updating col count +        # scrollbar reports incorrect height... +        # fillGlyphs() will change this value back +        self.setColumnCount(len(self.glyphs)+2)          data = [None, "Width", "Left", "Right"]          for index, item in enumerate(data):              cell = QTableWidgetItem(item) @@ -158,18 +210,36 @@ class SpaceTable(QTableWidget):          # always show a scrollbar to fix layout          self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn) -        self.resizeRowsToContents()          self.setSizePolicy(QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed))          self.fillGlyphs() +        self.resizeRowsToContents() +        self.cellChanged.connect(self._cellEdited)          # edit cell on single click, not double          self.setEditTriggers(QAbstractItemView.CurrentChanged) -        # TODO: insvestigate changing cell color as in robofont +        # TODO: investigate changing cell color as in robofont          # http://stackoverflow.com/a/13926342/2037879 -    def _textChanged(self, newText): -        self.string = newText +    def _glyphsChanged(self, newGlyphs): +        self.glyphs = newGlyphs          # TODO: we don't need to reallocate cells, split alloc and fill          self.fillGlyphs() +     +    def _cellEdited(self, row, col): +        if row == 0 or col == 0: return +        item = self.item(row, col).text() +        # Glyphs that do not have outlines leave empty cells, can't call +        # int() on that +        if not item: return +        item = int(item) +        # -1 because the first col contains descriptive text +        glyph = self.glyphs[col-1] +        if row == 1: +            glyph.width = item +        elif row == 2: +            glyph.leftMargin = item +        elif row == 3: +            glyph.rightMargin = item +        # defcon callbacks do the update      def sizeHint(self):          # http://stackoverflow.com/a/7216486/2037879 @@ -191,20 +261,14 @@ class SpaceTable(QTableWidget):              #item.setTextAlignment(Qt.AlignCenter)              return item -        self.setColumnCount(len(self.string)+1) -        dropped = 0 -        for index, char in enumerate(self.string): -            glyph = self.font.unicodeData.glyphNameForUnicode(ord(char)) -            i = index-dropped+1 -            if glyph not in self.font: dropped += 1; continue +        self.setColumnCount(len(self.glyphs)+1) +        for index, glyph in enumerate(self.glyphs):              # 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(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) +            self.setItem(0, index+1, glyphTableWidgetItem(glyph.name, True)) +            self.setItem(1, index+1, glyphTableWidgetItem(glyph.width)) +            self.setItem(2, index+1, glyphTableWidgetItem(glyph.leftMargin)) +            self.setItem(3, index+1, glyphTableWidgetItem(glyph.rightMargin)) +            self.setColumnWidth(index+1, self._cellWidth)      def wheelEvent(self, event):          cur = self.horizontalScrollBar().value() @@ -212,7 +276,6 @@ class SpaceTable(QTableWidget):          event.accept()  if __name__ == '__main__': -      import sys  # registerallfactories      app = QApplication(sys.argv) diff --git a/Lib/defconQt/svgViewer.py b/Lib/defconQt/svgViewer.py index 5e7b80a..c4d7d7f 100644 --- a/Lib/defconQt/svgViewer.py +++ b/Lib/defconQt/svgViewer.py @@ -2,7 +2,7 @@ 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, -        QMainWindow, QMenu, QMessageBox, QWidget) +        QMainWindow, QMenu, QMessageBox, QStyle, QStyleOptionGraphicsItem, QWidget)  from PyQt5.QtOpenGL import QGL, QGLFormat, QGLWidget  from PyQt5.QtSvg import QGraphicsSvgItem @@ -71,6 +71,74 @@ class MainGfxWindow(QMainWindow):          elif action == self.imageAction:              self.view.setRenderer(SvgView.Image) +# TODO: make QAbstractShapeItem as derive ellipse and rect, or just do path +class OnCurvePointItem(QGraphicsRectItem): +    def __init__(self, x, y, width, height, pointX, pointY, pointIndex, otherPointIndex=None, +            startPointObject=None, pen=None, brush=None, parent=None): +        super(OnCurvePointItem, self).__init__(x, y, width, height, parent) +        self.setFlag(QGraphicsItem.ItemIsMovable) +        self.setFlag(QGraphicsItem.ItemIsSelectable) +        # TODO: stop doing this and go back to mouse events +        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) +        if pen is not None: self._pen = pen; self.setPen(pen) +        if brush is not None: self.setBrush(brush) +         +        self._pointX = pointX +        self._pointY = pointY +        self._pointIndex = pointIndex +        # For the start point we must handle two instrs: the moveTo which is the initial start +        # point of the path and the last lineTo/curveTo which is the closing segment +        self._otherPointIndex = otherPointIndex +        self._startPointObject = startPointObject +     +    """ +    def mouseMoveEvent(self, event): +        pos = event.pos() +        print(pos) +        super(OnCurvePointItem, self).mouseMoveEvent(event) +        path = self.scene()._outlineItem.path() +        path.setElementPositionAt(0, pos.x(), pos.y()) +        self.scene()._outlineItem.setPath(path) +        #self.scene().update() +    """ +     +    def itemChange(self, change, value): +        if change == QGraphicsItem.ItemPositionHasChanged: +            path = self.scene()._outlineItem.path() +            """ +            for i in range(path.elementCount()): +                elem = path.elementAt(i) +                if elem.isCurveTo(): kind = "curve" +                elif elem.isLineTo(): kind = "line" +                else: kind = "move" +                print("{}: {} {}".format(kind, elem.x, elem.y)) +            print() +            """ +            # TODO: if we're snapped to int round self.pos to int +            newX = self._pointX+self.pos().x() +            newY = self._pointY+self.pos().y() +            path.setElementPositionAt(self._pointIndex, newX, newY) +            if self._otherPointIndex is not None: +                path.setElementPositionAt(self._otherPointIndex, newX, newY) +                # TODO: the angle ought to be recalculated +                # maybe make it disappear on move and recalc when releasing +                # what does rf do here? +                self._startPointObject.setPos(self.pos()) +            self.scene()._outlineItem.setPath(path) +        return QGraphicsItem.itemChange(self, change, value) +     +    # http://www.qtfr.org/viewtopic.php?pid=21045#p21045 +    def paint(self, painter, option, widget): +        newOption = QStyleOptionGraphicsItem(option) +        newOption.state = QStyle.State_None +        super(OnCurvePointItem, self).paint(painter, newOption, widget) +        if (option.state & QStyle.State_Selected): +            pen = self.pen() +            pen.setColor(Qt.red) +            #pen.setWidth +            self.setPen(pen) +        else: +            self.setPen(self._pen)  class SvgView(QGraphicsView):      Native, OpenGL, Image = range(3) @@ -102,11 +170,9 @@ class SvgView(QGraphicsView):          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) +        self.setDragMode(QGraphicsView.RubberBandDrag)          # This rewinds view when scrolling, needed for check-board background          #self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate) @@ -114,11 +180,12 @@ class SvgView(QGraphicsView):          self.translate(0, self.height()*(1+self._font.info.descender/self._font.info.unitsPerEm))          self.scale(1, -1)          self.addBackground() -        self.addBlues() +        #self.addBlues()          self.addOutlines()          self.addPoints()          # Prepare background check-board pattern. +        """          tilePixmap = QPixmap(64, 64)          tilePixmap.fill(Qt.white)          tilePainter = QPainter(tilePixmap) @@ -126,6 +193,7 @@ class SvgView(QGraphicsView):          tilePainter.fillRect(0, 0, 32, 32, color)          tilePainter.fillRect(32, 32, 32, 32, color)          tilePainter.end() +        """          #self.setBackgroundBrush(QBrush(tilePixmap)) @@ -143,10 +211,10 @@ class SvgView(QGraphicsView):          return width, height      def _calcScale(self): -        if self.parent() is None: -            return +        #if self.viewport() is None: +        #    return          if self._pointSize is None: -            visibleHeight = self.parent().height() +            visibleHeight = self.viewport().height()              fitHeight = visibleHeight              glyphWidth, glyphHeight = self._getGlyphWidthHeight()              glyphHeight += self._noPointSizePadding * 2 @@ -348,7 +416,7 @@ class SvgView(QGraphicsView):          s = self.scene()          # outlines          path = self._glyph.getRepresentation("defconQt.NoComponentsQPainterPath") -        s.addPath(path, brush=QBrush(self._fillColor)) +        self.scene()._outlineItem = s.addPath(path, brush=QBrush(self._fillColor))          # components          path = self._glyph.getRepresentation("defconQt.OnlyComponentsQPainterPath")          s.addPath(path, brush=QBrush(self._componentFillColor)) @@ -381,65 +449,94 @@ class SvgView(QGraphicsView):              coordinateSize = 0          # use the data from the outline representation          outlineData = self._glyph.getRepresentation("defconQt.OutlineInformation") -        points = [] +        points = [] # TODO: remove this unless we need it # useful for text drawing, add it +        startObjects = []          # 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 +                # TODO: do we really need to special-case with Qt?                  if angle is not None: +                    path = QPainterPath()                      path.moveTo(x, y)                      path.arcTo(x-startHalf, y-startHalf, 2*startHalf, 2*startHalf, angle-90, -180) -                    path.closeSubpath() +                    item = s.addPath(path, QPen(Qt.NoPen), QBrush(self._startPointColor)) +                    startObjects.append(item) +                    #path.closeSubpath()                  else: -                    path.addEllipse(x-startHalf, y-startHalf, startWidth, startHeight) -            s.addPath(path, QPen(Qt.NoPen), brush=QBrush(self._startPointColor)) +                    item = s.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))          # off curve          if self._showOffCurvePoints and outlineData["offCurvePoints"]:              # lines -            path = QPainterPath()              for point1, point2 in outlineData["bezierHandles"]: +                path = QPainterPath()                  path.moveTo(*point1)                  path.lineTo(*point2) -            s.addPath(path, QPen(self._bezierHandleColor, 1.0)) +                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"]: +            #path = QPainterPath() +            for point, index, isFirst 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)) +                item = s.addEllipse(x, y, offWidth, offHeight, +                    QPen(self._offCurvePointColor, 1.0), QBrush(self._backgroundColor)) +                item.setFlag(QGraphicsItem.ItemIsMovable) +            #if self._drawStroke: +            #    s.addPath(path, QPen(self._pointStrokeColor, 3.0)) +            #s.addPath(path, QPen(Qt.NoPen), brush=) +            #s.addPath(path, )          # 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"]: +            #path = QPainterPath() +            for point, index, isFirst 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) +                    item = s.addEllipse(x, y, smoothWidth, smoothHeight, +                        QPen(self._pointStrokeColor, 1.5), QBrush(self._onCurvePointColor)) +                    item.setFlag(QGraphicsItem.ItemIsMovable) +                    item.setFlag(QGraphicsItem.ItemIsSelectable)                  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)) -     +                    rx = self.roundPosition(x - half) +                    ry = self.roundPosition(y - half) + +                    lastPointInSubpath = None +                    startObject = None +                    if isFirst: +                        for lastPointIndex in outlineData["lastSubpathPoints"]: +                            if lastPointIndex > index: +                                lastPointInSubpath = lastPointIndex +                                break +                        startObject = startObjects.pop(0) + +                    item = OnCurvePointItem(rx, ry, width, height, x, y, index, lastPointInSubpath, +                        startObject, QPen(self._pointStrokeColor, 1.5), QBrush(self._onCurvePointColor)) +                    s.addItem(item) +                    #item = s.addRect(x, y, width, height, +                    #    QPen(self._pointStrokeColor, 1.5), QBrush(self._onCurvePointColor)) +                    #item.setFlag(QGraphicsItem.ItemIsMovable) +                    #item.setFlag(QGraphicsItem.ItemIsSelectable) +            #if self._drawStroke: +            #    s.addPath(path, ) +            #myRect = s.addPath(path, QPen(Qt.NoPen), brush=) +            #myRect.setFlag(QGraphicsItem.ItemIsSelectable) +            #myRect.setFlag(QGraphicsItem.ItemIsMovable +      def roundPosition(self, value):          value = value * self._scale          value = round(value) - .5 @@ -468,17 +565,37 @@ class SvgView(QGraphicsView):      def setViewOutline(self, enable):          if self.outlineItem:              self.outlineItem.setVisible(enable) +     +    def mousePressEvent(self, event): +        if (event.button() == Qt.MidButton): +            if self.dragMode() == QGraphicsView.RubberBandDrag: +                self.setDragMode(QGraphicsView.ScrollHandDrag) +            else: +                self.setDragMode(QGraphicsView.RubberBandDrag) +        super(SvgView, self).mousePressEvent(event) +     +    # Lock/release handdrag does not seem to work… +    ''' +    def mouseReleaseEvent(self, event): +        if (event.button() == Qt.MidButton): +            self.setDragMode(QGraphicsView.RubberBandDrag) +        super(SvgView, self).mouseReleaseEvent(event) +    '''      def paintEvent(self, event):          #self.scene().clear() -        super(SvgView, self).paintEvent(event) +          '''          painter = QPainter(self.viewport()) -        self.drawBackground(painter) +        painter.setRenderHint(QPainter.Antialiasing) +        painter.translate(0, self.height()*(1+self._font.info.descender/self._font.info.unitsPerEm)) +        painter.scale(1, -1)          self.drawBlues(painter) +        self.drawBackground(painter)          self.drawOutlines(painter)          self.drawPoints(painter)          ''' +        super(SvgView, self).paintEvent(event)          '''          if self.renderer == SvgView.Image: @@ -505,6 +622,7 @@ class SvgView(QGraphicsView):          #self._calcScale()          #self._setFrame()          self.scale(factor, factor) +        self._calcScale()          self.update()          #newPos = self.mapToScene(event.pos())          #delta = newPos - oldPos diff --git a/Lib/defconQt/syntaxhighlighter.py b/Lib/defconQt/syntaxhighlighter.py index 98d42e3..26972e4 100644 --- a/Lib/defconQt/syntaxhighlighter.py +++ b/Lib/defconQt/syntaxhighlighter.py @@ -56,6 +56,7 @@ class TextEditor(QPlainTextEdit):          self.setFont(font)          self.highlighter = Highlighter(self.document()) +        # TODO: get rid of jitter on opening          self.lineNumbers = LineNumberArea(self)          self.blockCountChanged.connect(self.updateLineNumberAreaWidth)          self.updateRequest.connect(self.updateLineNumberArea)  | 
