aboutsummaryrefslogtreecommitdiffstats
path: root/Lib/defconQt
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/defconQt')
-rw-r--r--Lib/defconQt/featureTextEditor.py37
-rw-r--r--Lib/defconQt/fontView.py55
-rw-r--r--Lib/defconQt/groupsView.py71
3 files changed, 129 insertions, 34 deletions
diff --git a/Lib/defconQt/featureTextEditor.py b/Lib/defconQt/featureTextEditor.py
index 0786c03..9571229 100644
--- a/Lib/defconQt/featureTextEditor.py
+++ b/Lib/defconQt/featureTextEditor.py
@@ -148,7 +148,10 @@ class TextEditor(QPlainTextEdit):
cursor.movePosition(QTextCursor.NextCharacter, QTextCursor.KeepAnchor, len(self._indent))
if cursor.selectedText() == self._indent:
indent += 1
- cursor.movePosition(QTextCursor.NoMove)
+ else: break
+ # Now move the anchor back to the position()
+ #cursor.movePosition(QTextCursor.NoMove) # shouldn't NoMove work here?
+ cursor.setPosition(cursor.position())
lineLength -= 1
cursor.movePosition(QTextCursor.EndOfLine)
return indent
@@ -210,6 +213,22 @@ class TextEditor(QPlainTextEdit):
else:
super(TextEditor, self).keyPressEvent(event)
+keywordPatterns = ["\\bAscender\\b", "\\bAttach\\b", "\\bCapHeight\\b", "\\bCaretOffset\\b", "\\bCodePageRange\\b",
+ "\\bDescender\\b", "\\bFontRevision\\b", "\\bGlyphClassDef\\b", "\\bHorizAxis.BaseScriptList\\b",
+ "\\bHorizAxis.BaseTagList\\b", "\\bHorizAxis.MinMax\\b", "\\bIgnoreBaseGlyphs\\b", "\\bIgnoreLigatures\\b",
+ "\\bIgnoreMarks\\b", "\\bLigatureCaretByDev\\b", "\\bLigatureCaretByIndex\\b", "\\bLigatureCaretByPos\\b",
+ "\\bLineGap\\b", "\\bMarkAttachClass\\b", "\\bMarkAttachmentType\\b", "\\bNULL\\b", "\\bPanose\\b", "\\bRightToLeft\\b",
+ "\\bTypoAscender\\b", "\\bTypoDescender\\b", "\\bTypoLineGap\\b", "\\bUnicodeRange\\b", "\\bUseMarkFilteringSet\\b",
+ "\\bVendor\\b", "\\bVertAdvanceY\\b", "\\bVertAxis.BaseScriptList\\b", "\\bVertAxis.BaseTagList\\b",
+ "\\bVertAxis.MinMax\\b", "\\bVertOriginY\\b", "\\bVertTypoAscender\\b", "\\bVertTypoDescender\\b",
+ "\\bVertTypoLineGap\\b", "\\bXHeight\\b", "\\banchorDef\\b", "\\banchor\\b", "\\banonymous\\b", "\\banon\\b",
+ "\\bby\\b", "\\bcontour\\b", "\\bcursive\\b", "\\bdevice\\b", "\\benumerate\\b", "\\benum\\b", "\\bexclude_dflt\\b",
+ "\\bfeatureNames\\b", "\\bfeature\\b", "\\bfrom\\b", "\\bignore\\b", "\\binclude_dflt\\b", "\\binclude\\b",
+ "\\blanguagesystem\\b", "\\blanguage\\b", "\\blookupflag\\b", "\\blookup\\b", "\\bmarkClass\\b", "\\bmark\\b",
+ "\\bnameid\\b", "\\bname\\b", "\\bparameters\\b", "\\bposition\\b", "\\bpos\\b", "\\brequired\\b", "\\breversesub\\b",
+ "\\brsub\\b", "\\bscript\\b", "\\bsizemenuname\\b", "\\bsubstitute\\b", "\\bsubtable\\b", "\\bsub\\b", "\\btable\\b",
+ "\\buseExtension\\b", "\\bvalueRecordDef\\b", "\\bwinAscent\\b", "\\bwinDescent\\b"]
+
class Highlighter(QSyntaxHighlighter):
def __init__(self, parent=None):
super(Highlighter, self).__init__(parent)
@@ -218,22 +237,6 @@ class Highlighter(QSyntaxHighlighter):
keywordFormat.setForeground(QColor(30, 150, 220))
keywordFormat.setFontWeight(QFont.Bold)
- keywordPatterns = ["\\bAscender\\b", "\\bAttach\\b", "\\bCapHeight\\b", "\\bCaretOffset\\b", "\\bCodePageRange\\b",
- "\\bDescender\\b", "\\bFontRevision\\b", "\\bGlyphClassDef\\b", "\\bHorizAxis.BaseScriptList\\b",
- "\\bHorizAxis.BaseTagList\\b", "\\bHorizAxis.MinMax\\b", "\\bIgnoreBaseGlyphs\\b", "\\bIgnoreLigatures\\b",
- "\\bIgnoreMarks\\b", "\\bLigatureCaretByDev\\b", "\\bLigatureCaretByIndex\\b", "\\bLigatureCaretByPos\\b",
- "\\bLineGap\\b", "\\bMarkAttachClass\\b", "\\bMarkAttachmentType\\b", "\\bNULL\\b", "\\bPanose\\b", "\\bRightToLeft\\b",
- "\\bTypoAscender\\b", "\\bTypoDescender\\b", "\\bTypoLineGap\\b", "\\bUnicodeRange\\b", "\\bUseMarkFilteringSet\\b",
- "\\bVendor\\b", "\\bVertAdvanceY\\b", "\\bVertAxis.BaseScriptList\\b", "\\bVertAxis.BaseTagList\\b",
- "\\bVertAxis.MinMax\\b", "\\bVertOriginY\\b", "\\bVertTypoAscender\\b", "\\bVertTypoDescender\\b",
- "\\bVertTypoLineGap\\b", "\\bXHeight\\b", "\\banchorDef\\b", "\\banchor\\b", "\\banonymous\\b", "\\banon\\b",
- "\\bby\\b", "\\bcontour\\b", "\\bcursive\\b", "\\bdevice\\b", "\\benumerate\\b", "\\benum\\b", "\\bexclude_dflt\\b",
- "\\bfeatureNames\\b", "\\bfeature\\b", "\\bfrom\\b", "\\bignore\\b", "\\binclude_dflt\\b", "\\binclude\\b",
- "\\blanguagesystem\\b", "\\blanguage\\b", "\\blookupflag\\b", "\\blookup\\b", "\\bmarkClass\\b", "\\bmark\\b",
- "\\bnameid\\b", "\\bname\\b", "\\bparameters\\b", "\\bposition\\b", "\\bpos\\b", "\\brequired\\b", "\\breversesub\\b",
- "\\brsub\\b", "\\bscript\\b", "\\bsizemenuname\\b", "\\bsubstitute\\b", "\\bsubtable\\b", "\\bsub\\b", "\\btable\\b",
- "\\buseExtension\\b", "\\bvalueRecordDef\\b", "\\bwinAscent\\b", "\\bwinDescent\\b"]
-
self.highlightingRules = [(QRegExp("%s%s%s" % ("(", "|".join(keywordPatterns), ")")), keywordFormat)]
singleLineCommentFormat = QTextCharFormat()
diff --git a/Lib/defconQt/fontView.py b/Lib/defconQt/fontView.py
index 6168ffd..64019f2 100644
--- a/Lib/defconQt/fontView.py
+++ b/Lib/defconQt/fontView.py
@@ -8,6 +8,9 @@ from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
+cannedDesign = [
+ dict(type="cannedDesign", allowPseudoUnicode=True)
+]
glyphSortDescriptors = [
dict(type="alphabetical", allowPseudoUnicode=True),
dict(type="category", allowPseudoUnicode=True),
@@ -16,9 +19,6 @@ glyphSortDescriptors = [
dict(type="suffix", allowPseudoUnicode=True),
dict(type="decompositionBase", allowPseudoUnicode=True)
]
-cannedDesign = [
- dict(type="cannedDesign", allowPseudoUnicode=True)
-]
cellGridColor = QColor(130, 130, 130)
cellHeaderBaseColor = QColor(230, 230, 230)
@@ -37,26 +37,31 @@ class CharacterWidget(QWidget):
super(CharacterWidget, self).__init__(parent)
self.font = font
- #self.glyphs = [font[k] for k in font.unicodeData.sortGlyphNames(font.keys(), glyphSortDescriptors)]
- self.glyphs = [font[k] for k in font.unicodeData.sortGlyphNames(font.keys(), cannedDesign)]
+ self.glyphs = []
self.scrollArea = scrollArea
self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
+ self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
self.squareSize = squareSize
self.columns = 10
self._selection = set()
self.lastKey = -1
self.moveKey = -1
+ self._maybeDragPosition = None
self.setFocusPolicy(Qt.ClickFocus)
def updateFont(self, font):
self.font = font
- self.glyphs = [font[k] for k in font.unicodeData.sortGlyphNames(font.keys(), cannedDesign)]
+ self.updateGlyphsFromFont()
+
+ def updateGlyphsFromFont(self, descriptor=cannedDesign):
+ self.glyphs = [self.font[k] for k in self.font.unicodeData.sortGlyphNames(self.font.keys(), descriptor)]
self.adjustSize()
self.update()
- def updateGlyphs(self):
- self.glyphs = [self.font[k] for k in self.font.unicodeData.sortGlyphNames(self.font.keys(), cannedDesign)]
+ def setGlyphs(self, glyphs):
+ self.glyphs = glyphs
+ self._selection = set()
self.adjustSize()
self.update()
@@ -76,7 +81,11 @@ class CharacterWidget(QWidget):
def markSelection(self, color):
for key in self._selection:
glyph = self.glyphs[key]
- glyph.lib["public.markColor"] = ",".join(str(c) for c in color.getRgbF())
+ if color is None:
+ if "public.markColor" in glyph.lib:
+ del glyph.lib["public.markColor"]
+ else:
+ glyph.lib["public.markColor"] = ",".join(str(c) for c in color.getRgbF())
self.update()
# TODO: eventually get rid of the signal
@@ -101,6 +110,11 @@ class CharacterWidget(QWidget):
self.computeCharacterSelected()
self.update()
event.accept()
+ elif event.key() == Qt.Key_D and event.modifiers() & Qt.ControlModifier:
+ self._selection = set()
+ self.computeCharacterSelected()
+ self.update()
+ event.accept()
else:
super(CharacterWidget, self).keyPressEvent(event)
@@ -112,6 +126,10 @@ class CharacterWidget(QWidget):
if modifiers & Qt.ShiftModifier and len(self._selection)==1:
self.lastKey = self._selection.pop()
self.moveKey = key
+ elif key in self._selection:
+ self._maybeDragPosition = event.pos()
+ event.accept()
+ return
else:
self.lastKey = key
self.moveKey = self.lastKey
@@ -126,6 +144,19 @@ class CharacterWidget(QWidget):
def mouseMoveEvent(self, event):
if event.buttons() & Qt.LeftButton:
+ if self._maybeDragPosition is not None:
+ if ((event.pos() - self._maybeDragPosition).manhattanLength() \
+ < QApplication.startDragDistance()): return
+ # TODO: needs ordering or not?
+ glyphList = " ".join((self.glyphs[key].name for key in self._selection))
+ drag = QDrag(self)
+ mimeData = QMimeData()
+ mimeData.setData("text/plain", glyphList)
+ drag.setMimeData(mimeData)
+
+ dropAction = drag.exec_()
+ event.accept()
+ return
key = (event.y() // self.squareSize) * self.columns + min(event.x() // self.squareSize, self.columns-1)
if key > len(self.glyphs)-1: return
self.moveKey = key
@@ -138,6 +169,7 @@ class CharacterWidget(QWidget):
def mouseReleaseEvent(self, event):
if event.button() == Qt.LeftButton:
+ self._maybeDragPosition = None
lastKey = self.lastKey if self.lastKey < len(self.glyphs) else len(self.glyphs)-1
moveKey = self.moveKey if self.moveKey < len(self.glyphs) else len(self.glyphs)-1
if event.modifiers() & Qt.ControlModifier:
@@ -292,6 +324,7 @@ class MainWindow(QMainWindow):
self.scrollArea = QScrollArea(self)
squareSize = 56
self.characterWidget = CharacterWidget(self.font, squareSize, self.scrollArea, self)
+ self.characterWidget.updateGlyphsFromFont()
self.scrollArea.setWidget(self.characterWidget)
# TODO: make shortcuts platform-independent
@@ -312,6 +345,8 @@ class MainWindow(QMainWindow):
markColorMenu = QMenu("Mark color", self)
pixmap = QPixmap(24, 24)
+ none = markColorMenu.addAction("None", self.colorFill)
+ none.setData(None)
red = markColorMenu.addAction("Red", self.colorFill)
pixmap.fill(Qt.red)
red.setIcon(QIcon(pixmap))
@@ -504,7 +539,7 @@ class MainWindow(QMainWindow):
if ok and gName != '':
self.font.newGlyph(gName)
self.font[gName].width = 500
- self.characterWidget.updateGlyphs()
+ self.characterWidget.updateGlyphsFromFont()
def about(self):
QMessageBox.about(self, "About Me",
diff --git a/Lib/defconQt/groupsView.py b/Lib/defconQt/groupsView.py
index db4645f..a88d9eb 100644
--- a/Lib/defconQt/groupsView.py
+++ b/Lib/defconQt/groupsView.py
@@ -1,28 +1,64 @@
+from fontView import CharacterWidget
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
+class GroupCharacterWidget(CharacterWidget):
+ def __init__(self, font, squareSize=56, scrollArea=None, parent=None):
+ super(GroupCharacterWidget, self).__init__(font, squareSize, scrollArea, parent)
+ self.columns = 8
+ self.scrollArea.setAcceptDrops(True)
+ self.scrollArea.dragEnterEvent = self.pipeDragEnterEvent
+ self.scrollArea.dropEvent = self.pipeDropEvent
+
+ def keyPressEvent(self, event):
+ if event.key() == Qt.Key_Delete:
+ self.parent().parent().parent().characterDeleteEvent(self._selection)
+ event.accept()
+ else:
+ super(GroupCharacterWidget, self).keyPressEvent(event)
+
+ def pipeDragEnterEvent(self, event):
+ # TODO: the problem with text/plain is that any sort of text can get here.
+ # (It allows direct compatibility with featureTextEditor though.)
+ if (event.mimeData().hasFormat("text/plain")):
+ event.acceptProposedAction()
+
+ def pipeDropEvent(self, event):
+ self.parent().parent().parent().characterDropEvent(event)
+
class GroupsWindow(QWidget):
def __init__(self, font, parent=None):
super(GroupsWindow, self).__init__(parent, Qt.Window)
self.font = font
- self.groups = sorted(font.groups.keys(), key=lambda t: t[0])
self.groupsList = QListWidget(self)
- #self.groupsList.addItems(self.font.groups.keys())
- #self.groupsList.setEditTriggers(QAbstractItemView.DoubleClicked | QAbstractItemView.EditKeyPressed)
+ self.groupsList.setSelectionMode(QAbstractItemView.SingleSelection)
+ self.groupsList.setSortingEnabled(True)
for groupName in self.font.groups.keys():
item = QListWidgetItem(groupName, self.groupsList)
- #item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsEditable)
item.setFlags(item.flags() | Qt.ItemIsEditable)
self.groupsList.itemChanged.connect(self._groupRenamed)
- layout = QVBoxLayout(self)
+ self.scrollArea = QScrollArea(self)
+ self.characterWidget = GroupCharacterWidget(self.font, scrollArea=self.scrollArea, parent=self)
+ self.scrollArea.setWidget(self.characterWidget)
+ self.groupsList.currentItemChanged.connect(self._groupChanged)
+
+ layout = QHBoxLayout(self)
layout.addWidget(self.groupsList)
+ layout.addWidget(self.scrollArea)
self.setLayout(layout)
self.setWindowTitle("%s%s%s%s" % ("Groups window – ", self.font.info.familyName, " ", self.font.info.styleName))
+ def _groupChanged(self):
+ currentGroup = self.groupsList.currentItem().text()
+ glyphs = []
+ for gName in self.font.groups[currentGroup]:
+ glyphs.append(self.font[gName])
+ self.characterWidget.setGlyphs(glyphs)
+
def _groupRenamed(self):
cur = self.groupsList.currentItem()
# XXX: perf?
@@ -30,5 +66,26 @@ class GroupsWindow(QWidget):
newKey = cur.text()
self.font.groups[newKey] = self.font.groups[self.groups[index]]
del self.font.groups[self.groups[index]]
- self.groups[index] = newKey
- #print(self.groupsList.currentItem().text()) \ No newline at end of file
+ #print(self.groupsList.currentItem().text())
+
+ def characterDeleteEvent(self, selection):
+ currentGroup = self.groupsList.currentItem().text()
+ currentGroupList = self.font.groups[currentGroup]
+ # relying on ordered group elements
+ # reverse to not change index of smaller elements
+ for key in sorted(selection, reverse=True):
+ del currentGroupList[key]
+ self.font.groups[currentGroup] = currentGroupList
+ self.characterWidget.update()
+
+ def characterDropEvent(self, event):
+ currentGroup = self.groupsList.currentItem().text()
+ glyphNames = event.mimeData().text().split(" ")
+ for gName in glyphNames:
+ # Due to defcon limitations, we must fetch and update for the
+ # notification to pass through
+ currentGroupList = self.font.groups[currentGroup]
+ currentGroupList.append(gName)
+ self.font.groups[currentGroup] = currentGroupList
+ event.acceptProposedAction()
+ self._groupChanged() \ No newline at end of file