aboutsummaryrefslogtreecommitdiffstats
path: root/Lib/defconQt/spaceCenter.py
diff options
context:
space:
mode:
authorAdrien Tétar2015-10-29 21:09:19 +0100
committerAdrien Tétar2015-10-29 21:23:31 +0100
commit1a889dc612c036763d80815a00d4b9a8fc73ba78 (patch)
tree83d9b76e4fb6a40d096e63a122b989061cf1bc65 /Lib/defconQt/spaceCenter.py
parent5d62be8c4dfb601b92f9153400e3e1cc8712cf94 (diff)
downloadtrufont-1a889dc612c036763d80815a00d4b9a8fc73ba78.tar.bz2
meta: shufflings, loadMostRecentFile, metricsWindow: canvas key shortcuts
Diffstat (limited to 'Lib/defconQt/spaceCenter.py')
-rw-r--r--Lib/defconQt/spaceCenter.py826
1 files changed, 0 insertions, 826 deletions
diff --git a/Lib/defconQt/spaceCenter.py b/Lib/defconQt/spaceCenter.py
deleted file mode 100644
index e360653..0000000
--- a/Lib/defconQt/spaceCenter.py
+++ /dev/null
@@ -1,826 +0,0 @@
-from defconQt import icons_db # noqa
-from defconQt.glyphCollectionView import cellSelectionColor
-from defconQt.glyphView import MainGfxWindow
-from getpass import getuser
-from PyQt5.QtCore import QEvent, QSettings, QSize, Qt
-from PyQt5.QtGui import (
- QBrush, QColor, QIcon, QIntValidator, QKeySequence, QPainter, QPalette,
- QPen)
-from PyQt5.QtWidgets import (
- QAbstractItemView, QActionGroup, QApplication, QComboBox, QLineEdit, QMenu,
- QPushButton, QScrollArea, QStyledItemDelegate, QTableWidget,
- QTableWidgetItem, QVBoxLayout, QSizePolicy, QToolBar, QWidget)
-
-comboBoxItems = [
- "abcdefghijklmnopqrstuvwxyz",
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
- "0123456789",
- "nn/? nono/? oo",
- "HH/? HOHO/? OO",
-]
-
-defaultPointSize = 150
-glyphSelectionColor = QColor(cellSelectionColor)
-glyphSelectionColor.setAlphaF(.09)
-
-
-class MainSpaceWindow(QWidget):
-
- def __init__(self, font, string=None, pointSize=defaultPointSize,
- parent=None):
- super(MainSpaceWindow, self).__init__(parent, Qt.Window)
-
- if string is None:
- try:
- string = getuser()
- except:
- string = "World"
- string = "Hello %s" % string
- # TODO: drop self.font and self.glyphs, store in the widgets only
- self.font = font
- self.glyphs = []
- self.toolbar = FontToolBar(pointSize, self)
- self.canvas = GlyphsCanvas(font, pointSize, self)
- self.table = SpaceTable(self)
- self.toolbar.comboBox.currentIndexChanged[
- str].connect(self.canvas.setPointSize)
- self.canvas.doubleClickCallback = self._glyphOpened
- self.canvas.pointSizeChangedCallback = self.toolbar.setPointSize
- self.canvas.selectionChangedCallback = self.table.setCurrentGlyph
- self.table.selectionChangedCallback = self.canvas.setSelected
-
- self.toolbar.textField.editTextChanged.connect(self._textChanged)
- self.toolbar.textField.setEditText(string)
- app = QApplication.instance()
- app.currentGlyphChanged.connect(self._textChanged)
-
- layout = QVBoxLayout(self)
- layout.addWidget(self.toolbar)
- layout.addWidget(self.canvas.scrollArea())
- layout.addWidget(self.table)
- layout.setContentsMargins(0, 0, 0, 0)
- layout.setSpacing(0)
- self.setLayout(layout)
- self.resize(600, 500)
-
- self.font.info.addObserver(self, "_fontInfoChanged", "Info.Changed")
-
- self.setWindowTitle("Space center – %s %s" % (
- self.font.info.familyName, self.font.info.styleName))
-
- def setupFileMenu(self):
- fileMenu = QMenu("&File", self)
- fileMenu.addAction("&Save...", self.save, QKeySequence.Save)
- fileMenu.addAction("E&xit", self.close, QKeySequence.Quit)
- self.menuBar().addMenu(fileMenu)
-
- def close(self):
- self.font.info.removeObserver(self, "Info.Changed")
- self._unsubscribeFromGlyphs()
- super(MainSpaceWindow, self).close()
-
- def _fontInfoChanged(self, notification):
- self.canvas.fetchFontMetrics()
- self.canvas.update()
-
- def _glyphChanged(self, notification):
- self.canvas.update()
- self.table.updateCells()
-
- def _glyphOpened(self, glyph):
- glyphViewWindow = MainGfxWindow(glyph, self.parent())
- glyphViewWindow.show()
-
- def _textChanged(self):
- # unsubscribe from the old glyphs
- self._unsubscribeFromGlyphs()
- # subscribe to the new glyphs
- left = self.textToGlyphNames(self.toolbar.leftTextField.text())
- newText = self.textToGlyphNames(self.toolbar.textField.currentText())
- right = self.textToGlyphNames(self.toolbar.rightTextField.text())
- leftGlyphs = []
- for name in left:
- if name in self.font:
- leftGlyphs.append(self.font[name])
- rightGlyphs = []
- for name in right:
- if name in self.font:
- rightGlyphs.append(self.font[name])
- finalGlyphs = []
- for name in newText:
- if name in self.font:
- finalGlyphs.extend(leftGlyphs)
- finalGlyphs.append(self.font[name])
- finalGlyphs.extend(rightGlyphs)
- self._subscribeToGlyphs(finalGlyphs)
- # set the records into the view
- self.canvas.setGlyphs(self.glyphs)
- self.table.setGlyphs(self.glyphs)
-
- # Tal Leming. Edited.
- def textToGlyphNames(self, text):
- def catchCompile():
- if compileStack[0] == "?":
- glyph = app.currentGlyph()
- if glyph is not None:
- glyphNames.append(glyph.name)
- elif compileStack:
- glyphNames.append("".join(compileStack))
-
- app = QApplication.instance()
- # escape //
- text = text.replace("//", "/slash ")
- #
- glyphNames = []
- compileStack = None
- for c in text:
- # start a glyph name compile.
- if c == "/":
- # finishing a previous compile.
- if compileStack is not None:
- # only add the compile if something has been added to the
- # stack.
- if compileStack:
- glyphNames.append("".join(compileStack))
- # reset the stack.
- compileStack = []
- # adding to or ending a glyph name compile.
- elif compileStack is not None:
- # space. conclude the glyph name compile.
- if c == " ":
- # only add the compile if something has been added to the
- # stack.
- catchCompile()
- compileStack = None
- # add the character to the stack.
- else:
- compileStack.append(c)
- # adding a character that needs to be converted to a glyph name.
- else:
- glyphName = self.font.unicodeData.glyphNameForUnicode(ord(c))
- glyphNames.append(glyphName)
- # catch remaining compile.
- if compileStack is not None and compileStack:
- catchCompile()
- return glyphNames
-
- def _subscribeToGlyphs(self, glyphs):
- 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, glyphs):
- # unsubscribe from the old glyphs
- self._unsubscribeFromGlyphs()
- # subscribe to the new glyphs
- self._subscribeToGlyphs(glyphs)
- glyphNames = []
- for glyph in glyphs:
- if glyph.unicode:
- glyphNames.append(chr(glyph.unicode))
- else:
- glyphNames.append("".join(("/", glyph.name, " ")))
- self.toolbar.textField.setEditText("".join(glyphNames))
- # set the records into the view
- self.canvas.setGlyphs(self.glyphs)
- self.table.setGlyphs(self.glyphs)
-
-pointSizes = [50, 75, 100, 125, 150, 200, 250, 300, 350, 400, 450, 500]
-
-
-class FontToolBar(QToolBar):
-
- def __init__(self, pointSize, parent=None):
- super(FontToolBar, self).__init__(parent)
- auxiliaryWidth = self.fontMetrics().width('0') * 8
- self.leftTextField = QLineEdit(self)
- self.leftTextField.setMaximumWidth(auxiliaryWidth)
- self.textField = QComboBox(self)
- self.textField.setEditable(True)
- completer = self.textField.completer()
- completer.setCaseSensitivity(Qt.CaseSensitive)
- self.textField.setCompleter(completer)
- # XXX: had to use Maximum because Preferred did entend the widget(?)
- self.textField.setSizePolicy(QSizePolicy.Expanding,
- QSizePolicy.Maximum)
- items = QSettings().value("spaceCenter/comboBoxItems", comboBoxItems,
- str)
- self.textField.addItems(items)
- self.rightTextField = QLineEdit(self)
- self.rightTextField.setMaximumWidth(auxiliaryWidth)
- self.leftTextField.textEdited.connect(self.textField.editTextChanged)
- self.rightTextField.textEdited.connect(self.textField.editTextChanged)
- self.comboBox = QComboBox(self)
- self.comboBox.setEditable(True)
- self.comboBox.setValidator(QIntValidator(self))
- for p in pointSizes:
- self.comboBox.addItem(str(p))
- self.comboBox.setEditText(str(pointSize))
-
- self.configBar = QPushButton(self)
- self.configBar.setFlat(True)
- self.configBar.setIcon(QIcon(":/resources/settings.svg"))
- self.configBar.setStyleSheet("padding: 2px 0px; padding-right: 10px")
- self.toolsMenu = QMenu(self)
- showKerning = self.toolsMenu.addAction(
- "Show Kerning", self.showKerning)
- showKerning.setCheckable(True)
- showMetrics = self.toolsMenu.addAction(
- "Show Metrics", self.showMetrics)
- showMetrics.setCheckable(True)
- self.toolsMenu.addSeparator()
- wrapLines = self.toolsMenu.addAction("Wrap lines", self.wrapLines)
- wrapLines.setCheckable(True)
- noWrapLines = self.toolsMenu.addAction("No wrap", self.noWrapLines)
- noWrapLines.setCheckable(True)
- self.toolsMenu.addSeparator()
- verticalFlip = self.toolsMenu.addAction(
- "Vertical flip", self.verticalFlip)
- verticalFlip.setCheckable(True)
- """
- lineHeight = QWidgetAction(self.toolsMenu)
- lineHeight.setText("Line height:")
- lineHeightSlider = QSlider(Qt.Horizontal, self)
- # QSlider works with integers so we'll just divide by 100 what comes
- # out of it
- lineHeightSlider.setMinimum(80)
- lineHeightSlider.setMaximum(160)
- lineHeightSlider.setValue(100)
- #lineHeightSlider.setContentsMargins(30, 0, 30, 0)
- lineHeightSlider.valueChanged.connect(self.lineHeight)
- lineHeight.setDefaultWidget(lineHeightSlider)
- self.toolsMenu.addAction(lineHeight)
- """
-
- wrapLinesGroup = QActionGroup(self)
- wrapLinesGroup.addAction(wrapLines)
- wrapLinesGroup.addAction(noWrapLines)
- wrapLines.setChecked(True)
- # self.toolsMenu.setActiveAction(wrapLines)
- self.configBar.setMenu(self.toolsMenu)
-
- self.addWidget(self.leftTextField)
- self.addWidget(self.textField)
- self.addWidget(self.rightTextField)
- self.addWidget(self.comboBox)
- self.addWidget(self.configBar)
-
- def showEvent(self, event):
- super(FontToolBar, self).showEvent(event)
- self.textField.setFocus(True)
-
- def setPointSize(self, pointSize):
- self.comboBox.blockSignals(True)
- self.comboBox.setEditText(str(pointSize))
- self.comboBox.blockSignals(False)
-
- def showKerning(self):
- action = self.sender()
- self.parent().canvas.setShowKerning(action.isChecked())
-
- def showMetrics(self):
- action = self.sender()
- self.parent().canvas.setShowMetrics(action.isChecked())
-
- def verticalFlip(self):
- action = self.sender()
- self.parent().canvas.setVerticalFlip(action.isChecked())
-
- def lineHeight(self, value):
- self.parent().canvas.setLineHeight(value / 100)
-
- def wrapLines(self):
- self.parent().canvas.setWrapLines(True)
-
- def noWrapLines(self):
- self.parent().canvas.setWrapLines(False)
-
-
-class GlyphsCanvas(QWidget):
-
- def __init__(self, font, pointSize=defaultPointSize, parent=None):
- super(GlyphsCanvas, self).__init__(parent)
- # XXX: make canvas font-agnostic as in defconAppkit and use
- # glyph.getParent() instead
- self.font = font
- self.fetchFontMetrics()
- self.glyphs = []
- self.ptSize = pointSize
- self.calculateScale()
- self.padding = 10
- self._showKerning = False
- self._showMetrics = False
- self._verticalFlip = False
- self._lineHeight = 1.1
- self._positions = None
- self._selected = None
- self.doubleClickCallback = None
- self.pointSizeChangedCallback = None
- self.selectionChangedCallback = None
-
- self._wrapLines = True
- self._scrollArea = QScrollArea(self.parent())
- self._scrollArea.resizeEvent = self.resizeEvent
- self._scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
- self._scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
- self._scrollArea.setWidget(self)
- self.resize(581, 400)
-
- def scrollArea(self):
- return self._scrollArea
-
- def calculateScale(self):
- scale = self.ptSize / self.upm
- if scale < .01:
- scale = 0.01
- self.scale = scale
-
- def setShowKerning(self, showKerning):
- self._showKerning = showKerning
- self.update()
-
- def setShowMetrics(self, showMetrics):
- self._showMetrics = showMetrics
- self.update()
-
- def setVerticalFlip(self, verticalFlip):
- self._verticalFlip = verticalFlip
- self.update()
-
- def setLineHeight(self, lineHeight):
- self._lineHeight = lineHeight
- self.update()
-
- def setWrapLines(self, wrapLines):
- if self._wrapLines == wrapLines:
- return
- self._wrapLines = wrapLines
- if self._wrapLines:
- self.resize(self._scrollArea.viewport().width(), self.height())
- self._scrollArea.setHorizontalScrollBarPolicy(
- Qt.ScrollBarAlwaysOff)
- self._scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
- else:
- self.resize(self.width(), self._scrollArea.viewport().height())
- self._scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
- self._scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
- self.update()
-
- def fetchFontMetrics(self):
- self.ascender = self.font.info.ascender
- if self.ascender is None:
- self.ascender = 750
- self.descender = self.font.info.descender
- if self.descender is None:
- self.descender = 250
- self.upm = self.font.info.unitsPerEm
- if self.upm is None or not self.upm > 0:
- self.upm = 1000
-
- def setGlyphs(self, newGlyphs):
- self.glyphs = newGlyphs
- self._selected = None
- self.update()
-
- def setPointSize(self, pointSize):
- self.ptSize = int(pointSize)
- self.calculateScale()
- self.update()
-
- def setSelected(self, selected):
- self._selected = selected
- if self._positions is not None:
- cur_len = 0
- line = -1
- for index, li in enumerate(self._positions):
- if cur_len + len(li) > self._selected:
- pos, width = li[self._selected - cur_len]
- line = index
- break
- cur_len += len(li)
- if line > -1:
- x = self.padding + pos + width / 2
- y = self.padding + (line + .5) * self.ptSize * self._lineHeight
- self._scrollArea.ensureVisible(
- x, y, width / 2 + 20,
- .5 * self.ptSize * self._lineHeight + 20)
- self.update()
-
- def resizeEvent(self, event):
- if self._wrapLines:
- self.resize(self._scrollArea.viewport().width(), self.height())
- else:
- self.resize(self.width(), self._scrollArea.viewport().height())
-
- def wheelEvent(self, event):
- if event.modifiers() & Qt.ControlModifier:
- # TODO: should it snap to predefined pointSizes?
- # is the scaling factor okay?
- # XXX: current alg. is not reversible...
- decay = event.angleDelta().y() / 120.0
- scale = round(self.ptSize / 10)
- if scale == 0 and decay >= 0:
- scale = 1
- newPointSize = self.ptSize + int(decay) * scale
- if newPointSize <= 0:
- return
-
- self.setPointSize(newPointSize)
- if self.pointSizeChangedCallback is not None:
- self.pointSizeChangedCallback(newPointSize)
- event.accept()
- else:
- super(GlyphsCanvas, self).wheelEvent(event)
-
- # Tal Leming. Edited.
- def lookupKerningValue(self, first, second):
- kerning = self.font.kerning
- groups = self.font.groups
- # quickly check to see if the pair is in the kerning dictionary
- pair = (first, second)
- if pair in kerning:
- return kerning[pair]
- # get group names and make sure first and second are glyph names
- firstGroup = secondGroup = None
- if first.startswith("@MMK_L"):
- firstGroup = first
- first = None
- else:
- for group, groupMembers in groups.items():
- if group.startswith("@MMK_L"):
- if first in groupMembers:
- firstGroup = group
- break
- if second.startswith("@MMK_R"):
- secondGroup = second
- second = None
- else:
- for group, groupMembers in groups.items():
- if group.startswith("@MMK_R"):
- if second in groupMembers:
- secondGroup = group
- break
- # make an ordered list of pairs to look up
- pairs = [
- (first, second),
- (first, secondGroup),
- (firstGroup, second),
- (firstGroup, secondGroup)
- ]
- # look up the pairs and return any matches
- for pair in pairs:
- if pair in kerning:
- return kerning[pair]
- return 0
-
- def mousePressEvent(self, event):
- # Take focus to quit eventual cell editing
- # XXX: shouldnt set focus if we are in input field...
- self.setFocus(Qt.MouseFocusReason)
- if event.button() == Qt.LeftButton:
- # XXX: investigate, baselineShift is unused
- # if self._verticalFlip:
- # baselineShift = -self.descender
- # else:
- # baselineShift = self.ascender
- found = False
- line = \
- (event.y() - self.padding) // (self.ptSize * self._lineHeight)
- # XXX: Shouldnt // yield an int?
- line = int(line)
- if line >= len(self._positions):
- self._selected = None
- # XXX: find a way to DRY notification of self._selected changed
- # w ability to block notifications as well
- if self.selectionChangedCallback is not None:
- self.selectionChangedCallback(self._selected)
- event.accept()
- self.update()
- return
- x = event.x() - self.padding
- for index, data in enumerate(self._positions[line]):
- pos, width = data
- if pos <= x and pos + width > x:
- count = 0
- for i in range(line):
- count += len(self._positions[i])
- self._selected = count + index
- found = True
- break
- if not found:
- self._selected = None
- if self.selectionChangedCallback is not None:
- self.selectionChangedCallback(self._selected)
- event.accept()
- self.update()
- else:
- super(GlyphsCanvas, self).mousePressEvent(event)
-
- def mouseDoubleClickEvent(self, event):
- if event.button() == Qt.LeftButton and self._selected is not None:
- if self.doubleClickCallback is not None:
- self.doubleClickCallback(self.glyphs[self._selected])
- else:
- super(GlyphsCanvas, self).mouseDoubleClickEvent(event)
-
- def paintEvent(self, event):
- linePen = QPen(Qt.black)
- linePen.setWidth(3)
- width = self.width() / self.scale
-
- def paintLineMarks(painter):
- painter.save()
- painter.scale(self.scale, yDirection * self.scale)
- painter.setPen(linePen)
- painter.drawLine(0, self.ascender, width, self.ascender)
- painter.drawLine(0, 0, width, 0)
- painter.drawLine(0, self.descender, width, self.descender)
- painter.restore()
-
- painter = QPainter(self)
- painter.setRenderHint(QPainter.Antialiasing)
- painter.fillRect(0, 0, self.width(), self.height(), Qt.white)
- if self._verticalFlip:
- baselineShift = -self.descender
- yDirection = 1
- else:
- baselineShift = self.ascender
- yDirection = -1
- painter.translate(self.padding, self.padding +
- baselineShift * self.scale * self._lineHeight)
- # TODO: scale painter here to avoid g*scale everywhere below
-
- cur_width = 0
- lines = 1
- self._positions = [[]]
- if self._showMetrics:
- paintLineMarks(painter)
- for index, glyph in enumerate(self.glyphs):
- # line wrapping
- gWidth = glyph.width * self.scale
- doKern = index > 0 and self._showKerning and cur_width > 0
- if doKern:
- kern = self.lookupKerningValue(
- self.glyphs[index - 1].name, glyph.name) * self.scale
- else:
- kern = 0
- if (self._wrapLines and
- cur_width + gWidth + kern + 2 * self.padding >
- self.width()):
- painter.translate(-cur_width, self.ptSize * self._lineHeight)
- if self._showMetrics:
- paintLineMarks(painter)
- self._positions.append([(0, gWidth)])
- cur_width = gWidth
- lines += 1
- else:
- if doKern:
- painter.translate(kern, 0)
- self._positions[-1].append((cur_width, gWidth))
- cur_width += gWidth + kern
- glyphPath = glyph.getRepresentation("defconQt.QPainterPath")
- painter.save()
- painter.scale(self.scale, yDirection * self.scale)
- if self._showMetrics:
- halfDescent = self.descender / 2
- painter.drawLine(0, 0, 0, halfDescent)
- painter.drawLine(glyph.width, 0, glyph.width, halfDescent)
- if self._selected is not None and index == self._selected:
- painter.fillRect(0, self.descender, glyph.width,
- self.upm, glyphSelectionColor)
- painter.fillPath(glyphPath, Qt.black)
- painter.restore()
- painter.translate(gWidth, 0)
-
- innerHeight = self._scrollArea.viewport().height()
- if not self._wrapLines:
- innerWidth = self._scrollArea.viewport().width()
- width = max(innerWidth, cur_width + self.padding * 2)
- else:
- width = self.width()
- self.resize(width, max(innerHeight, lines * self.ptSize *
- self._lineHeight + 2 * self.padding))
-
-
-class SpaceTableWidgetItem(QTableWidgetItem):
-
- def setData(self, role, value):
- if role & Qt.EditRole:
- # don't set empty data
- # XXX: maybe fetch the value from cell back to the editor
- if value == "":
- return
- super(SpaceTableWidgetItem, self).setData(role, value)
-
-
-class GlyphCellItemDelegate(QStyledItemDelegate):
-
- def createEditor(self, parent, option, index):
- editor = super(GlyphCellItemDelegate, self).createEditor(
- parent, option, index)
- # editor.setAlignment(Qt.AlignCenter)
- editor.setValidator(QIntValidator(self))
- return editor
-
- # TODO: implement =... lexer
- # TODO: Alt+left or Alt+right don't SelectAll of the new cell
- # cell by default. Implement this.
- # TODO: cycle b/w editable cell area
- def eventFilter(self, editor, event):
- if event.type() == QEvent.KeyPress:
- chg = None
- count = event.count()
- key = event.key()
- if key == Qt.Key_Up:
- chg = count
- elif key == Qt.Key_Down:
- chg = -count
- elif not key == Qt.Key_Return:
- return False
- if chg is not None:
- modifiers = event.modifiers()
- if modifiers & Qt.AltModifier:
- return False
- elif modifiers & Qt.ShiftModifier:
- chg *= 10
- if modifiers & Qt.ControlModifier:
- chg *= 10
- cur = int(editor.text())
- editor.setText(str(cur + chg))
- self.commitData.emit(editor)
- editor.selectAll()
- return True
- return False
-
-
-class SpaceTable(QTableWidget):
-
- def __init__(self, parent=None):
- super(SpaceTable, self).__init__(4, 1, parent)
- self.setAttribute(Qt.WA_KeyCompression)
- self.setItemDelegate(GlyphCellItemDelegate(self))
- data = [None, "Width", "Left", "Right"]
- # Don't grey-out disabled cells
- palette = self.palette()
- fgColor = palette.color(QPalette.Text)
- palette.setColor(QPalette.Disabled, QPalette.Text, fgColor)
- self.setPalette(palette)
- for index, title in enumerate(data):
- item = SpaceTableWidgetItem(title)
- item.setFlags(Qt.NoItemFlags)
- self.setItem(index, 0, item)
- # let's use this one column to compute the width of others
- self._cellWidth = .5 * self.columnWidth(0)
- self.setColumnWidth(0, self._cellWidth)
- self.horizontalHeader().hide()
- self.verticalHeader().hide()
-
- # always show a scrollbar to fix layout
- self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
- self.setSizePolicy(QSizePolicy(
- QSizePolicy.Preferred, QSizePolicy.Fixed))
- self.glyphs = []
- self.fillGlyphs()
- self.resizeRowsToContents()
- self.currentItemChanged.connect(self._itemChanged)
- self.cellChanged.connect(self._cellEdited)
- self.setSelectionMode(QAbstractItemView.SingleSelection)
- # edit cell on single click, not double
- self.setEditTriggers(QAbstractItemView.CurrentChanged)
- self._editing = False
- self.selectionChangedCallback = None
- self._coloredColumn = None
-
- def setGlyphs(self, newGlyphs):
- self.glyphs = newGlyphs
- # TODO: we don't need to reallocate cells, split alloc and fill
- self.updateCells()
-
- def updateCells(self):
- self.blockSignals(True)
- if self._editing:
- coloredColumn = self._coloredColumn
- self.fillGlyphs()
- if self._editing:
- self._coloredColumn = coloredColumn
- self.blockSignals(False)
-
- 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 convert
- # that to a scalar
- if not item:
- return
- item = int(item)
- # -1 because the first col contains descriptive text
- glyph = self.glyphs[col - 1]
- # != comparisons avoid making glyph dirty when editor content is
- # unchanged
- self._editing = True
- if row == 1:
- if item != glyph.width:
- glyph.width = item
- elif row == 2:
- if item != glyph.leftMargin:
- glyph.leftMargin = item
- elif row == 3:
- if item != glyph.rightMargin:
- glyph.rightMargin = item
- self._editing = False
- # defcon callbacks do the update
-
- def _itemChanged(self, current, previous):
- if current is not None:
- cur = current.column()
- if previous is not None:
- prev = previous.column()
- if current is not None and cur == prev:
- return
- self.colorColumn(current if current is None else cur)
- if self.selectionChangedCallback is not None:
- if current is not None:
- self.selectionChangedCallback(cur - 1)
- else:
- self.selectionChangedCallback(None)
-
- def colorColumn(self, column):
- emptyBrush = QBrush(Qt.NoBrush)
- selectionColor = QColor(235, 235, 235)
- for i in range(4):
- if self._coloredColumn is not None:
- item = self.item(i, self._coloredColumn)
- # cached column might be invalid if user input deleted it
- if item is not None:
- item.setBackground(emptyBrush)
- if column is not None:
- self.item(i, column).setBackground(selectionColor)
- self._coloredColumn = column
-
- def sizeHint(self):
- # http://stackoverflow.com/a/7216486/2037879
- height = sum(self.rowHeight(k) for k in range(self.rowCount()))
- height += self.horizontalScrollBar().sizeHint().height()
- margins = self.contentsMargins()
- height += margins.top() + margins.bottom()
- return QSize(self.width(), height)
-
- def setCurrentGlyph(self, glyphIndex):
- self.blockSignals(True)
- if glyphIndex is not None:
- # so we can scroll to the item
- self.setCurrentCell(1, glyphIndex + 1)
- self.setCurrentItem(None)
- if glyphIndex is not None:
- self.colorColumn(glyphIndex + 1)
- else:
- self.colorColumn(glyphIndex)
- self.blockSignals(False)
-
- def fillGlyphs(self):
- def glyphTableWidgetItem(content, disableCell=False):
- if isinstance(content, float):
- content = round(content)
- if content is not None:
- content = str(content)
- item = SpaceTableWidgetItem(content)
- if disableCell:
- item.setFlags(Qt.NoItemFlags)
- elif content is None:
- item.setFlags(Qt.ItemIsEnabled)
- # TODO: should fields be centered? I find left-aligned more
- # natural to read, personally...
- # item.setTextAlignment(Qt.AlignCenter)
- return item
-
- self.setColumnCount(len(self.glyphs) + 1)
- for index, glyph in enumerate(self.glyphs):
- # TODO: see about allowing glyph name edit here
- 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):
- # A mouse can only scroll along the y-axis. Use x-axis if we have one
- # (e.g. from touchpad), otherwise use y-axis.
- angleDelta = event.angleDelta().x() or event.angleDelta().y()
- cur = self.horizontalScrollBar().value()
- self.horizontalScrollBar().setValue(cur - angleDelta / 120)
- event.accept()