aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/defconQt/__main__.py15
-rw-r--r--Lib/defconQt/fontView.py56
-rw-r--r--Lib/defconQt/glyphView.py269
-rw-r--r--Lib/defconQt/objects/defcon.py15
-rw-r--r--Lib/defconQt/objects/sizeGripItem.py205
-rw-r--r--Lib/defconQt/util/glyphList.py21
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