A nicer font family chooser combobox

This commit is contained in:
Kovid Goyal 2012-10-01 15:05:48 +05:30
parent 24a9d26176
commit 473ced12de
4 changed files with 184 additions and 24 deletions

View File

@ -19,6 +19,7 @@ from calibre.ebooks.conversion.config import load_defaults, \
load_specifics, GuiRecommendations load_specifics, GuiRecommendations
from calibre import prepare_string_for_xml from calibre import prepare_string_for_xml
from calibre.customize.ui import plugin_for_input_format from calibre.customize.ui import plugin_for_input_format
from calibre.gui2.font_family_chooser import FontFamilyChooser
def config_widget_for_input_plugin(plugin): def config_widget_for_input_plugin(plugin):
name = plugin.name.lower().replace(' ', '_') name = plugin.name.lower().replace(' ', '_')
@ -144,6 +145,8 @@ class Widget(QWidget):
return ans return ans
elif isinstance(g, QFontComboBox): elif isinstance(g, QFontComboBox):
return unicode(QFontInfo(g.currentFont()).family()) return unicode(QFontInfo(g.currentFont()).family())
elif isinstance(g, FontFamilyChooser):
return g.font_family
elif isinstance(g, EncodingComboBox): elif isinstance(g, EncodingComboBox):
ans = unicode(g.currentText()).strip() ans = unicode(g.currentText()).strip()
try: try:
@ -208,6 +211,8 @@ class Widget(QWidget):
getattr(g, 'setCursorPosition', lambda x: x)(0) getattr(g, 'setCursorPosition', lambda x: x)(0)
elif isinstance(g, QFontComboBox): elif isinstance(g, QFontComboBox):
g.setCurrentFont(QFont(val or '')) g.setCurrentFont(QFont(val or ''))
elif isinstance(g, FontFamilyChooser):
g.font_family = val
elif isinstance(g, EncodingComboBox): elif isinstance(g, EncodingComboBox):
if val: if val:
g.setEditText(val) g.setEditText(val)

View File

@ -6,11 +6,8 @@ __license__ = 'GPL v3'
__copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2009, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
from PyQt4.Qt import Qt
from calibre.gui2.convert.lrf_output_ui import Ui_Form from calibre.gui2.convert.lrf_output_ui import Ui_Form
from calibre.gui2.convert import Widget from calibre.gui2.convert import Widget
from calibre.gui2.widgets import FontFamilyModel
font_family_model = None font_family_model = None
@ -30,13 +27,6 @@ class PluginWidget(Widget, Ui_Form):
'header_separation', 'minimum_indent'] 'header_separation', 'minimum_indent']
) )
self.db, self.book_id = db, book_id 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.initialize_options(get_option, get_help, db, book_id)
self.opt_header.toggle(), self.opt_header.toggle() self.opt_header.toggle(), self.opt_header.toggle()
@ -44,14 +34,4 @@ class PluginWidget(Widget, Ui_Form):
self.opt_render_tables_as_images.toggle() 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

View File

@ -176,13 +176,13 @@
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="0" column="1">
<widget class="QComboBox" name="opt_serif_family"/> <widget class="FontFamilyChooser" name="opt_serif_family"/>
</item> </item>
<item row="1" column="1"> <item row="1" column="1">
<widget class="QComboBox" name="opt_sans_family"/> <widget class="FontFamilyChooser" name="opt_sans_family"/>
</item> </item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QComboBox" name="opt_mono_family"/> <widget class="FontFamilyChooser" name="opt_mono_family"/>
</item> </item>
</layout> </layout>
</widget> </widget>
@ -202,6 +202,13 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<customwidgets>
<customwidget>
<class>FontFamilyChooser</class>
<extends>QComboBox</extends>
<header>calibre/gui2/font_family_chooser.h</header>
</customwidget>
</customwidgets>
<resources/> <resources/>
<connections> <connections>
<connection> <connection>

View File

@ -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 <kovid at kovidgoyal.net>'
__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_()