From 473ced12de8e86ff1e302ee1b6113b46bc843ea6 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Mon, 1 Oct 2012 15:05:48 +0530 Subject: [PATCH] A nicer font family chooser combobox --- src/calibre/gui2/convert/__init__.py | 5 + src/calibre/gui2/convert/lrf_output.py | 22 +--- src/calibre/gui2/convert/lrf_output.ui | 13 +- src/calibre/gui2/font_family_chooser.py | 168 ++++++++++++++++++++++++ 4 files changed, 184 insertions(+), 24 deletions(-) create mode 100644 src/calibre/gui2/font_family_chooser.py diff --git a/src/calibre/gui2/convert/__init__.py b/src/calibre/gui2/convert/__init__.py index 38fb641987..ac81816174 100644 --- a/src/calibre/gui2/convert/__init__.py +++ b/src/calibre/gui2/convert/__init__.py @@ -19,6 +19,7 @@ from calibre.ebooks.conversion.config import load_defaults, \ load_specifics, GuiRecommendations from calibre import prepare_string_for_xml from calibre.customize.ui import plugin_for_input_format +from calibre.gui2.font_family_chooser import FontFamilyChooser def config_widget_for_input_plugin(plugin): name = plugin.name.lower().replace(' ', '_') @@ -144,6 +145,8 @@ class Widget(QWidget): return ans elif isinstance(g, QFontComboBox): return unicode(QFontInfo(g.currentFont()).family()) + elif isinstance(g, FontFamilyChooser): + return g.font_family elif isinstance(g, EncodingComboBox): ans = unicode(g.currentText()).strip() try: @@ -208,6 +211,8 @@ class Widget(QWidget): getattr(g, 'setCursorPosition', lambda x: x)(0) elif isinstance(g, QFontComboBox): g.setCurrentFont(QFont(val or '')) + elif isinstance(g, FontFamilyChooser): + g.font_family = val elif isinstance(g, EncodingComboBox): if val: g.setEditText(val) diff --git a/src/calibre/gui2/convert/lrf_output.py b/src/calibre/gui2/convert/lrf_output.py index 75764164dd..a643da6ed0 100644 --- a/src/calibre/gui2/convert/lrf_output.py +++ b/src/calibre/gui2/convert/lrf_output.py @@ -6,11 +6,8 @@ __license__ = 'GPL v3' __copyright__ = '2009, Kovid Goyal ' __docformat__ = 'restructuredtext en' -from PyQt4.Qt import Qt - from calibre.gui2.convert.lrf_output_ui import Ui_Form from calibre.gui2.convert import Widget -from calibre.gui2.widgets import FontFamilyModel font_family_model = None @@ -30,13 +27,6 @@ class PluginWidget(Widget, Ui_Form): 'header_separation', 'minimum_indent'] ) self.db, self.book_id = db, book_id - global font_family_model - if font_family_model is None: - font_family_model = FontFamilyModel() - self.font_family_model = font_family_model - self.opt_serif_family.setModel(self.font_family_model) - self.opt_sans_family.setModel(self.font_family_model) - self.opt_mono_family.setModel(self.font_family_model) self.initialize_options(get_option, get_help, db, book_id) self.opt_header.toggle(), self.opt_header.toggle() @@ -44,14 +34,4 @@ class PluginWidget(Widget, Ui_Form): self.opt_render_tables_as_images.toggle() - def set_value_handler(self, g, val): - if unicode(g.objectName()) in ('opt_serif_family', - 'opt_sans_family', 'opt_mono_family'): - idx = -1 - if val: - idx = g.findText(val, Qt.MatchFixedString) - if idx < 0: - idx = 0 - g.setCurrentIndex(idx) - return True - return False + diff --git a/src/calibre/gui2/convert/lrf_output.ui b/src/calibre/gui2/convert/lrf_output.ui index ecbe673c61..753ec6110a 100644 --- a/src/calibre/gui2/convert/lrf_output.ui +++ b/src/calibre/gui2/convert/lrf_output.ui @@ -176,13 +176,13 @@ - + - + - + @@ -202,6 +202,13 @@ + + + FontFamilyChooser + QComboBox +
calibre/gui2/font_family_chooser.h
+
+
diff --git a/src/calibre/gui2/font_family_chooser.py b/src/calibre/gui2/font_family_chooser.py new file mode 100644 index 0000000000..04d9dfdfb6 --- /dev/null +++ b/src/calibre/gui2/font_family_chooser.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python +# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai +from __future__ import (unicode_literals, division, absolute_import, + print_function) + +__license__ = 'GPL v3' +__copyright__ = '2012, Kovid Goyal ' +__docformat__ = 'restructuredtext en' + +from PyQt4.Qt import (QFontInfo, QFontMetrics, Qt, QFont, QFontDatabase, QPen, + QStyledItemDelegate, QSize, QStyle, QComboBox, QStringListModel, + QDialog, QVBoxLayout, QApplication, QFontComboBox) + +from calibre.utils.icu import sort_key + +def writing_system_for_font(font): + has_latin = True + systems = QFontDatabase().writingSystems(font.family()) + + # this just confuses the algorithm below. Vietnamese is Latin with lots of + # special chars + try: + systems.remove(QFontDatabase.Vietnamese) + except ValueError: + pass + + system = QFontDatabase.Any + + if (QFontDatabase.Latin not in systems): + has_latin = False + # we need to show something + if systems: + system = systems[-1] + else: + systems.remove(QFontDatabase.Latin) + + if not systems: + return system, has_latin + + if (len(systems) == 1 and systems[0] > QFontDatabase.Cyrillic): + return systems[0], has_latin + + if (len(systems) <= 2 and + systems[-1] > QFontDatabase.Armenian and + systems[-1] < QFontDatabase.Vietnamese): + return systems[-1], has_latin + + if (len(systems) <= 5 and + systems[-1] >= QFontDatabase.SimplifiedChinese and + systems[-1] <= QFontDatabase.Korean): + system = systems[-1] + + return system, has_latin + +class FontFamilyDelegate(QStyledItemDelegate): + + def sizeHint(self, option, index): + text = index.data(Qt.DisplayRole).toString() + font = QFont(option.font) + font.setPointSize(QFontInfo(font).pointSize() * 1.5) + m = QFontMetrics(font) + return QSize(m.width(text), m.height()) + + def paint(self, painter, option, index): + text = unicode(index.data(Qt.DisplayRole).toString()) + font = QFont(option.font) + font.setPointSize(QFontInfo(font).pointSize() * 1.5) + font2 = QFont(font) + font2.setFamily(text) + + system, has_latin = writing_system_for_font(font2) + if has_latin: + font = font2 + + r = option.rect + + if option.state & QStyle.State_Selected: + painter.save() + painter.setBrush(option.palette.highlight()) + painter.setPen(Qt.NoPen) + painter.drawRect(option.rect) + painter.setPen(QPen(option.palette.highlightedText(), 0)) + + if (option.direction == Qt.RightToLeft): + r.setRight(r.right() - 4) + else: + r.setLeft(r.left() + 4) + + old = painter.font() + painter.setFont(font) + painter.drawText(r, Qt.AlignVCenter|Qt.AlignLeading|Qt.TextSingleLine, text) + + if (system != QFontDatabase.Any): + w = painter.fontMetrics().width(text + " ") + painter.setFont(font2) + sample = QFontDatabase().writingSystemSample(system) + if (option.direction == Qt.RightToLeft): + r.setRight(r.right() - w) + else: + r.setLeft(r.left() + w) + painter.drawText(r, Qt.AlignVCenter|Qt.AlignLeading|Qt.TextSingleLine, sample) + + painter.setFont(old) + + if (option.state & QStyle.State_Selected): + painter.restore() + +class FontFamilyChooser(QComboBox): + + def __init__(self, parent=None): + QComboBox.__init__(self, parent) + from calibre.utils.fonts import fontconfig + try: + self.families = fontconfig.find_font_families() + except: + self.families = [] + print ('WARNING: Could not load fonts') + import traceback + traceback.print_exc() + # Restrict to Qt families as we need the font to be available in + # QFontDatabase + qt_families = set([unicode(x) for x in QFontDatabase().families()]) + self.families = list(qt_families.intersection(set(self.families))) + self.families.sort(key=sort_key) + self.families.insert(0, _('None')) + + self.m = QStringListModel(self.families) + self.setModel(self.m) + self.d = FontFamilyDelegate(self) + self.setItemDelegate(self.d) + self.setCurrentIndex(0) + + def event(self, e): + if e.type() == e.Resize: + view = self.view() + view.window().setFixedWidth(self.width() * 5/3) + return QComboBox.event(self, e) + + def sizeHint(self): + ans = QComboBox.sizeHint(self) + ans.setWidth(QFontMetrics(self.font()).width('m'*14)) + return ans + + @dynamic_property + def font_family(self): + def fget(self): + idx= self.currentIndex() + if idx == 0: return None + return self.families[idx] + def fset(self, val): + if not val: + idx = 0 + try: + idx = self.families.index(type(u'')(val)) + except ValueError: + idx = 0 + self.setCurrentIndex(idx) + return property(fget=fget, fset=fset) + + +if __name__ == '__main__': + app = QApplication([]) + d = QDialog() + d.setLayout(QVBoxLayout()) + d.layout().addWidget(FontFamilyChooser(d)) + d.layout().addWidget(QFontComboBox(d)) + d.exec_() +