diff options
| author | Adrien Tétar | 2015-05-24 22:49:37 +0200 |
|---|---|---|
| committer | Adrien Tétar | 2015-05-24 22:49:37 +0200 |
| commit | aa47b725346d05c4c4a47d9185549e2457dfba0b (patch) | |
| tree | 6f8776df777175951d4956fbae3cc59736b8591a /Lib/defconQt/fontView.py | |
| parent | 24551076e86106e06ec70e2414747dfdbdde9a52 (diff) | |
| download | trufont-aa47b725346d05c4c4a47d9185549e2457dfba0b.tar.bz2 | |
fontView: refinements
Diffstat (limited to 'Lib/defconQt/fontView.py')
| -rw-r--r-- | Lib/defconQt/fontView.py | 115 |
1 files changed, 88 insertions, 27 deletions
diff --git a/Lib/defconQt/fontView.py b/Lib/defconQt/fontView.py index 3f556d3..b3502f3 100644 --- a/Lib/defconQt/fontView.py +++ b/Lib/defconQt/fontView.py @@ -17,22 +17,31 @@ glyphSortDescriptors = [ dict(type="decompositionBase", allowPseudoUnicode=True) ] +cellGridColor = QColor(130, 130, 130) +cellHeaderBaseColor = QColor(230, 230, 230) +cellHeaderLineColor = QColor(220, 220, 220) +cellHeaderHighlightLineColor = QColor(240, 240, 240) +cellSelectionColor = QColor.fromRgbF(.2, .3, .7, .15) + +GlyphCellBufferHeight = .2 +GlyphCellHeaderHeight = 14 + class CharacterWidget(QWidget): characterSelected = pyqtSignal(int, str) glyphOpened = pyqtSignal(str) - def __init__(self, font, squareSize=48, scrollArea=None, parent=None): + def __init__(self, font, squareSize=56, scrollArea=None, parent=None): super(CharacterWidget, self).__init__(parent) self.font = font self.glyphs = [font[k] for k in font.unicodeData.sortGlyphNames(font.keys(), glyphSortDescriptors)] self.scrollArea = scrollArea + self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) self.squareSize = squareSize - self.columns = 11 + self.columns = 10 self.lastKey = -1 self.moveKey = -1 #self.setMouseTracking(True) - self.col = QColor.fromRgbF(.2, .3, .7, .15) def updateFont(self, font): self.font = font @@ -46,7 +55,6 @@ class CharacterWidget(QWidget): self.update() def _sizeEvent(self, width, squareSize=None): - # TODO: Still some horizontal scrollbar appearing, should disable it entirely if self.scrollArea is not None: sw = self.scrollArea.verticalScrollBar().width() + self.scrollArea.contentsMargins().right() else: sw = 0 if squareSize is not None: self.squareSize = squareSize @@ -54,7 +62,6 @@ class CharacterWidget(QWidget): if not columns > 0: return self.columns = columns self.adjustSize() - #super(CharacterWidget, self).resizeEvent(event) def sizeHint(self): return QSize(self.columns * self.squareSize, @@ -65,8 +72,7 @@ class CharacterWidget(QWidget): self.lastKey = (event.y() // self.squareSize) * self.columns + event.x() // self.squareSize self.moveKey = -1 if self.lastKey > len(self.glyphs)-1: return - - self.col = QColor.fromRgbF(.2, .3, .7, .15) + self.characterSelected.emit(1, self.glyphs[self.lastKey].name) event.accept() self.update() @@ -75,7 +81,7 @@ class CharacterWidget(QWidget): def mouseMoveEvent(self, event): if event.buttons() & Qt.LeftButton: - moveKey = (event.y() // self.squareSize) * self.columns + event.x() // self.squareSize + moveKey = (event.y() // self.squareSize) * self.columns + min(event.x() // self.squareSize, self.columns-1) event.accept() if (moveKey == self.lastKey and self.moveKey != -1): self.moveKey = -1 @@ -103,7 +109,7 @@ class CharacterWidget(QWidget): def mouseDoubleClickEvent(self, event): if event.button() == Qt.LeftButton: - key = (event.y() // self.squareSize) * self.columns + event.x() // self.squareSize + key = (event.y() // self.squareSize) * self.columns + min(event.x() // self.squareSize, self.columns-1) if key != self.lastKey: return event.accept() self.glyphOpened.emit(self.glyphs[key].name) @@ -113,7 +119,6 @@ class CharacterWidget(QWidget): def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) - painter.fillRect(event.rect(), Qt.white) redrawRect = event.rect() beginRow = redrawRect.top() // self.squareSize @@ -121,6 +126,7 @@ class CharacterWidget(QWidget): beginColumn = redrawRect.left() // self.squareSize endColumn = redrawRect.right() // self.squareSize + painter.setPen(cellGridColor) painter.drawLine(redrawRect.left(), redrawRect.top(), redrawRect.left(), redrawRect.bottom()) painter.drawLine(0, 0, redrawRect.right(), 0) @@ -131,43 +137,79 @@ class CharacterWidget(QWidget): select = False if firstKey != -1 and firstKey < minKeyInViewport and lastKey > minKeyInViewport: select = True + + gradient = QLinearGradient(0, 0, 0, GlyphCellHeaderHeight) + gradient.setColorAt(0.0, cellHeaderBaseColor) + gradient.setColorAt(1.0, cellHeaderLineColor) - painter.setPen(Qt.gray) for row in range(beginRow, endRow + 1): for column in range(beginColumn, endColumn + 1): key = row * self.columns + column if key > len(self.glyphs)-1: break + painter.save() + painter.translate(column * self.squareSize, row * self.squareSize) + # background + painter.fillRect(0, 0, self.squareSize, self.squareSize, Qt.white) + # header gradient + painter.fillRect(0, 0, self.squareSize, + GlyphCellHeaderHeight, QBrush(gradient)) + # header lines + painter.setPen(cellHeaderHighlightLineColor) + minOffset = painter.pen().width() + painter.setRenderHint(QPainter.Antialiasing, False) + painter.drawLine(0, 0, 0, GlyphCellHeaderHeight - 1) + painter.drawLine(self.squareSize - 2, 0, self.squareSize - 2, GlyphCellHeaderHeight -1) + painter.setPen(QColor(170, 170, 170)) + painter.drawLine(0, GlyphCellHeaderHeight, self.squareSize, GlyphCellHeaderHeight) + painter.setRenderHint(QPainter.Antialiasing) + # header text + headerFont = QFont() + headerFont.setFamily('Lucida Sans Unicode') + painter.setFont(headerFont) + painter.setPen(QColor(80, 80, 80)) + metrics = QFontMetrics(headerFont) + name = metrics.elidedText(self.glyphs[key].name, Qt.ElideRight, self.squareSize - 2) + painter.drawText(1, 0, self.squareSize - 2, GlyphCellHeaderHeight - minOffset, + Qt.TextSingleLine | Qt.AlignCenter, name) + painter.restore() + + painter.setPen(cellGridColor) rightEdgeX = column * self.squareSize + self.squareSize bottomEdgeY = row * self.squareSize + self.squareSize painter.drawLine(rightEdgeX, row * self.squareSize + 1, rightEdgeX, bottomEdgeY) painter.drawLine(rightEdgeX, bottomEdgeY, column * self.squareSize + 1, bottomEdgeY) + painter.setRenderHint(QPainter.Antialiasing, False) # selection code if key == firstKey: select = not select if select or (key == self.lastKey and self.moveKey == -1): painter.fillRect(column * self.squareSize + 1, - row * self.squareSize + 1, self.squareSize - 2, - self.squareSize - 2, self.col) + row * self.squareSize + 1, self.squareSize - 3, + self.squareSize - 3, cellSelectionColor) if key == lastKey and self.moveKey != -1: select = not select + painter.setRenderHint(QPainter.Antialiasing) glyph = self.glyphs[key].getRepresentation("defconQt.QPainterPath") if self.font.info.unitsPerEm is None: break if not self.font.info.unitsPerEm > 0: self.font.info.unitsPerEm = 1000 - factor = self.squareSize/(self.font.info.unitsPerEm*(1+2*.125)) + factor = (self.squareSize-GlyphCellHeaderHeight)/(self.font.info.unitsPerEm*(1+2*GlyphCellBufferHeight)) x_offset = (self.squareSize-self.glyphs[key].width*factor)/2 + # If the glyph overflows horizontally we need to adjust the scaling factor if x_offset < 0: factor *= 1+2*x_offset/(self.glyphs[key].width*factor) x_offset = 0 - y_offset = self.font.info.descender*factor + # TODO: the * 1.8 below is somewhat artificial + y_offset = self.font.info.descender*factor * 1.8 painter.save() + painter.setClipRect(column * self.squareSize, row * self.squareSize+GlyphCellHeaderHeight, + self.squareSize, self.squareSize-GlyphCellHeaderHeight) painter.translate(column * self.squareSize + x_offset, row * self.squareSize + self.squareSize + y_offset) painter.scale(factor, -factor) painter.fillPath(glyph, Qt.black) painter.restore() - class MainWindow(QMainWindow): def __init__(self, font=Font()): @@ -178,27 +220,27 @@ class MainWindow(QMainWindow): # TODO: have the scrollarea be part of the widget itself? # or better yet, switch to QGraphicsScene self.scrollArea = QScrollArea(self) - squareSize = 48 + squareSize = 56 self.characterWidget = CharacterWidget(self.font, squareSize, self.scrollArea, self) self.scrollArea.setWidget(self.characterWidget) # TODO: make shortcuts platform-independent - # TODO: work out sensible shortcuts fileMenu = QMenu("&File", self) self.menuBar().addMenu(fileMenu) - fileMenu.addAction("&New...", self.newFile, QKeySequence.New) - fileMenu.addAction("&Open...", self.openFile, QKeySequence.Open) + fileMenu.addAction("&New…", self.newFile, QKeySequence.New) + fileMenu.addAction("&Open…", self.openFile, QKeySequence.Open) # TODO: add functionality #fileMenu.addMenu(QMenu("Open &Recent...", self)) fileMenu.addSeparator() fileMenu.addAction("&Save", self.saveFile, QKeySequence.Save) - fileMenu.addAction("Save &As...", self.saveFileAs, QKeySequence.SaveAs) + fileMenu.addAction("Save &As…", self.saveFileAs, QKeySequence.SaveAs) fileMenu.addAction("E&xit", self.close, QKeySequence.Quit) fontMenu = QMenu("&Font", self) self.menuBar().addMenu(fontMenu) + # TODO: work out sensible shortcuts fontMenu.addAction("Font &info", self.fontInfo, "Ctrl+I") fontMenu.addAction("Font &features", self.fontFeatures, "Ctrl+F") fontMenu.addAction("&Add glyph", self.addGlyph, "Ctrl+U") @@ -212,21 +254,19 @@ class MainWindow(QMainWindow): helpMenu.addAction("About &Qt", QApplication.instance().aboutQt) self.sqSizeSlider = QSlider(Qt.Horizontal, self) - self.sqSizeSlider.setMinimum(24) + self.sqSizeSlider.setMinimum(36) self.sqSizeSlider.setMaximum(96) - #sz = self.sqSizeSlider.sizeHint() - #self.sqSizeSlider.setSize(.7*sz.width(), sz.height()) + self.sqSizeSlider.setFixedWidth(.9*self.sqSizeSlider.width()) self.sqSizeSlider.setValue(squareSize) self.sqSizeSlider.valueChanged.connect(self._squareSizeChanged) self.selectionLabel = QLabel(self) - self.selectionLabel.setFixedWidth(self.selectionLabel.fontMetrics().width('M') * 15) self.characterWidget.characterSelected.connect(self._selectionChanged) self.statusBar().addPermanentWidget(self.sqSizeSlider) self.statusBar().addWidget(self.selectionLabel) self.setCentralWidget(self.scrollArea) self.characterWidget.glyphOpened.connect(self._glyphOpened) - self.setWindowTitle(os.path.basename(self.font.path.rstrip(os.sep))) + self.setWindowTitle() # TODO: dump the hardcoded path #self.setWindowIcon(QIcon("C:\\Users\\Adrien\\Downloads\\defconQt\\Lib\\defconQt\\resources\\icon.png")) @@ -251,9 +291,11 @@ class MainWindow(QMainWindow): path = os.path.dirname(path) self.font = Font(path) self.characterWidget.updateFont(self.font) + self.setWindowTitle() def saveFile(self, path=None): self.font.save(path=path) +# self.font.dirty = False # self.font.path = path # done by defcon def saveFileAs(self): @@ -261,11 +303,26 @@ class MainWindow(QMainWindow): "UFO Fonts (*.ufo)") if ok: self.saveFile(path) + #return ok def close(self): # TODO: check if font changed self.font.removeObserver(self, "Font.Changed") QApplication.instance().quit() + + def closeEvent(self, event): + if self.font.dirty: + closeDialog = QMessageBox(QMessageBox.Question, "Save your work?", "Will you save, dear", + QMessageBox.Yes | QMessageBox.No | QMessageBox.Cancel, self) + closeDialog.setModal(True) + ret = closeDialog.exec_() + if ret == QMessageBox.Yes: + self.saveFile() + event.accept() + elif ret == QMessageBox.No: + event.accept() + elif ret == QMessageBox.Cancel: + event.ignore() def _fontChanged(self, event): self.characterWidget.update() @@ -287,6 +344,10 @@ class MainWindow(QMainWindow): def resizeEvent(self, event): if self.isVisible(): self.characterWidget._sizeEvent(event.size().width()) super(MainWindow, self).resizeEvent(event) + + def setWindowTitle(self, title=None): + if title is None: title = os.path.basename(self.font.path.rstrip(os.sep)) + super(MainWindow, self).setWindowTitle(title) def fontInfo(self): # If a window is already opened, bring it to the front, else spawn one. @@ -347,6 +408,6 @@ if __name__ == '__main__': # 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.resize(605, 430) window.show() sys.exit(app.exec_()) |
