aboutsummaryrefslogtreecommitdiffstats
path: root/Lib/defconQt
diff options
context:
space:
mode:
authorAdrien Tétar2015-05-09 18:46:10 +0200
committerAdrien Tétar2015-05-09 18:46:10 +0200
commite83660ec042e9d6fe0daab5459c19c681639a4a9 (patch)
treeb4911a11b65c4a952162f973f691d234eb7abdb0 /Lib/defconQt
parent7dd7d2f4ccb2337f3f14e3317c7f328023420bb8 (diff)
downloadtrufont-e83660ec042e9d6fe0daab5459c19c681639a4a9.tar.bz2
Checkpoint
Diffstat (limited to 'Lib/defconQt')
-rw-r--r--Lib/defconQt/fontView.py41
-rw-r--r--Lib/defconQt/fontinfo.py36
-rw-r--r--Lib/defconQt/representationFactories/__init__.py21
-rw-r--r--Lib/defconQt/spacecenter.py197
-rw-r--r--Lib/defconQt/svgViewer.py188
-rw-r--r--Lib/defconQt/syntaxhighlighter.py1
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)