mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-06-23 15:30:45 -04:00
Editor preferences
This commit is contained in:
parent
43770ce0f2
commit
ea49fe8462
@ -13,7 +13,7 @@ from PyQt4.Qt import (QFontInfo, QFontMetrics, Qt, QFont, QFontDatabase, QPen,
|
||||
QStyledItemDelegate, QSize, QStyle, QStringListModel, pyqtSignal,
|
||||
QDialog, QVBoxLayout, QApplication, QFontComboBox, QPushButton,
|
||||
QToolButton, QGridLayout, QListView, QWidget, QDialogButtonBox, QIcon,
|
||||
QHBoxLayout, QLabel, QModelIndex, QLineEdit)
|
||||
QHBoxLayout, QLabel, QModelIndex, QLineEdit, QSizePolicy)
|
||||
|
||||
from calibre.constants import config_dir
|
||||
from calibre.gui2 import choose_files, error_dialog, info_dialog
|
||||
@ -230,9 +230,11 @@ class FontFamilyDialog(QDialog):
|
||||
|
||||
def find(self, backwards=False):
|
||||
i = self.view.currentIndex().row()
|
||||
if i < 0: i = 0
|
||||
if i < 0:
|
||||
i = 0
|
||||
q = icu_lower(unicode(self.search.text())).strip()
|
||||
if not q: return
|
||||
if not q:
|
||||
return
|
||||
r = (xrange(i-1, -1, -1) if backwards else xrange(i+1,
|
||||
len(self.families)))
|
||||
for j in r:
|
||||
@ -263,7 +265,8 @@ class FontFamilyDialog(QDialog):
|
||||
files = choose_files(self, 'add fonts to calibre',
|
||||
_('Select font files'), filters=[(_('TrueType/OpenType Fonts'),
|
||||
['ttf', 'otf'])], all_files=False)
|
||||
if not files: return
|
||||
if not files:
|
||||
return
|
||||
families = set()
|
||||
for f in files:
|
||||
try:
|
||||
@ -298,7 +301,8 @@ class FontFamilyDialog(QDialog):
|
||||
@property
|
||||
def font_family(self):
|
||||
idx = self.view.currentIndex().row()
|
||||
if idx == 0: return None
|
||||
if idx == 0:
|
||||
return None
|
||||
return self.families[idx]
|
||||
|
||||
def current_changed(self):
|
||||
@ -313,9 +317,11 @@ class FontFamilyChooser(QWidget):
|
||||
def __init__(self, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self.l = l = QHBoxLayout()
|
||||
l.setContentsMargins(0, 0, 0, 0)
|
||||
self.setLayout(l)
|
||||
self.button = QPushButton(self)
|
||||
self.button.setIcon(QIcon(I('font.png')))
|
||||
self.button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
||||
l.addWidget(self.button)
|
||||
self.default_text = _('Choose &font family')
|
||||
self.font_family = None
|
||||
|
@ -66,7 +66,9 @@ class Boss(QObject):
|
||||
|
||||
def preferences(self):
|
||||
p = Preferences(self.gui)
|
||||
p.exec_()
|
||||
if p.exec_() == p.Accepted:
|
||||
for ed in editors.itervalues():
|
||||
ed.apply_settings()
|
||||
|
||||
def mkdtemp(self, prefix=''):
|
||||
self.container_count += 1
|
||||
|
@ -55,12 +55,12 @@ class TextEdit(QPlainTextEdit):
|
||||
self.current_cursor_line = None
|
||||
self.current_search_mark = None
|
||||
self.highlighter = SyntaxHighlighter(self)
|
||||
self.line_number_area = LineNumbers(self)
|
||||
self.apply_settings()
|
||||
self.setMouseTracking(True)
|
||||
self.cursorPositionChanged.connect(self.highlight_cursor_line)
|
||||
self.blockCountChanged[int].connect(self.update_line_number_area_width)
|
||||
self.updateRequest.connect(self.update_line_number_area)
|
||||
self.line_number_area = LineNumbers(self)
|
||||
self.syntax = None
|
||||
|
||||
@dynamic_property
|
||||
@ -118,6 +118,7 @@ class TextEdit(QPlainTextEdit):
|
||||
self.number_width = max(map(lambda x:w.width(str(x)), xrange(10)))
|
||||
self.size_hint = QSize(100 * w.averageCharWidth(), 50 * w.height())
|
||||
self.highlight_color = theme_color(theme, 'HighlightRegion', 'bg')
|
||||
self.highlight_cursor_line()
|
||||
# }}}
|
||||
|
||||
def load_text(self, text, syntax='html', process_template=False):
|
||||
|
@ -77,6 +77,9 @@ class Editor(QMainWindow):
|
||||
if current != raw:
|
||||
self.editor.replace_text(raw)
|
||||
|
||||
def apply_settings(self, prefs=None):
|
||||
self.editor.apply_settings(prefs=None)
|
||||
|
||||
def set_focus(self):
|
||||
self.editor.setFocus(Qt.OtherFocusReason)
|
||||
|
||||
|
@ -6,12 +6,135 @@ from __future__ import (unicode_literals, division, absolute_import,
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
|
||||
from operator import attrgetter, methodcaller
|
||||
from collections import namedtuple
|
||||
|
||||
from PyQt4.Qt import (
|
||||
QDialog, QGridLayout, QStackedWidget, QDialogButtonBox, QListWidget,
|
||||
QListWidgetItem, QIcon)
|
||||
QListWidgetItem, QIcon, QWidget, QSize, QFormLayout, Qt, QSpinBox,
|
||||
QCheckBox, pyqtSignal, QDoubleSpinBox, QComboBox)
|
||||
|
||||
from calibre.gui2.keyboard import ShortcutConfig
|
||||
from calibre.gui2.tweak_book import tprefs
|
||||
from calibre.gui2.tweak_book.editor.themes import default_theme, THEMES
|
||||
from calibre.gui2.font_family_chooser import FontFamilyChooser
|
||||
|
||||
class BasicSettings(QWidget): # {{{
|
||||
|
||||
changed_signal = pyqtSignal()
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self.settings = {}
|
||||
self._prevent_changed = False
|
||||
self.Setting = namedtuple('Setting', 'name prefs widget getter setter initial_value')
|
||||
|
||||
def __call__(self, name, widget=None, getter=None, setter=None, prefs=None):
|
||||
prefs = prefs or tprefs
|
||||
defval = prefs.defaults[name]
|
||||
inval = prefs[name]
|
||||
if widget is None:
|
||||
if isinstance(defval, bool):
|
||||
widget = QCheckBox(self)
|
||||
getter = getter or methodcaller('isChecked')
|
||||
setter = setter or (lambda x, v: x.setChecked(v))
|
||||
widget.toggled.connect(self.emit_changed)
|
||||
elif isinstance(defval, (int, float)):
|
||||
widget = (QSpinBox if isinstance(defval, int) else QDoubleSpinBox)(self)
|
||||
getter = getter or methodcaller('value')
|
||||
setter = setter or (lambda x, v:x.setValue(v))
|
||||
widget.valueChanged.connect(self.emit_changed)
|
||||
else:
|
||||
raise TypeError('Unknown setting type for setting: %s' % name)
|
||||
else:
|
||||
if getter is None or setter is None:
|
||||
raise ValueError("getter or setter not provided for: %s" % name)
|
||||
self._prevent_changed = True
|
||||
setter(widget, inval)
|
||||
self._prevent_changed = False
|
||||
|
||||
self.settings[name] = self.Setting(name, prefs, widget, getter, setter, inval)
|
||||
return widget
|
||||
|
||||
def choices_widget(self, name, choices, fallback_val, none_val, prefs=None):
|
||||
prefs = prefs or tprefs
|
||||
widget = QComboBox(self)
|
||||
widget.currentIndexChanged[int].connect(self.emit_changed)
|
||||
for key, human in choices.iteritems():
|
||||
widget.addItem(human or key, key)
|
||||
|
||||
def getter(w):
|
||||
ans = unicode(w.itemData(w.currentIndex()).toString())
|
||||
return {none_val:None}.get(ans, ans)
|
||||
|
||||
def setter(w, val):
|
||||
val = {None:none_val}.get(val, val)
|
||||
idx = w.findData(val, flags=Qt.MatchFixedString|Qt.MatchCaseSensitive)
|
||||
if idx == -1:
|
||||
idx = w.findData(fallback_val, flags=Qt.MatchFixedString|Qt.MatchCaseSensitive)
|
||||
w.setCurrentIndex(idx)
|
||||
|
||||
return self(name, widget=widget, getter=getter, setter=setter, prefs=prefs)
|
||||
|
||||
def emit_changed(self, *args):
|
||||
if not self._prevent_changed:
|
||||
self.changed_signal.emit()
|
||||
|
||||
def commit(self):
|
||||
with tprefs:
|
||||
for name in self.settings:
|
||||
cv = self.current_value(name)
|
||||
if self.initial_value(name) != cv:
|
||||
prefs = self.settings[name].prefs
|
||||
if cv == self.default_value(name):
|
||||
del prefs[name]
|
||||
else:
|
||||
prefs[name] = cv
|
||||
|
||||
def restore_defaults(self):
|
||||
for setting in self.settings.itervalues():
|
||||
setting.setter(setting.widget, self.default_value(setting.name))
|
||||
|
||||
def initial_value(self, name):
|
||||
return self.settings[name].initial_value
|
||||
|
||||
def current_value(self, name):
|
||||
s = self.settings[name]
|
||||
return s.getter(s.widget)
|
||||
|
||||
def default_value(self, name):
|
||||
s = self.settings[name]
|
||||
return s.prefs.defaults[name]
|
||||
|
||||
def setting_changed(self, name):
|
||||
return self.current_value(name) != self.initial_value(name)
|
||||
# }}}
|
||||
|
||||
class EditorSettings(BasicSettings):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
BasicSettings.__init__(self, parent)
|
||||
self.l = l = QFormLayout(self)
|
||||
self.setLayout(l)
|
||||
|
||||
fc = FontFamilyChooser(self)
|
||||
self('editor_font_family', widget=fc, getter=attrgetter('font_family'), setter=lambda x, val: setattr(x, 'font_family', val))
|
||||
fc.family_changed.connect(self.emit_changed)
|
||||
l.addRow(_('Editor font &family:'), fc)
|
||||
|
||||
fs = self('editor_font_size')
|
||||
fs.setMinimum(8), fs.setSuffix(' pt'), fs.setMaximum(50)
|
||||
l.addRow(_('Editor font &size:'), fs)
|
||||
|
||||
auto_theme = _('Automatic (%s)') % default_theme()
|
||||
choices = {k:k for k in THEMES}
|
||||
choices['auto'] = auto_theme
|
||||
theme = self.choices_widget('editor_theme', choices, 'auto', 'auto')
|
||||
l.addRow(_('&Color scheme:'), theme)
|
||||
|
||||
lw = self('editor_line_wrap')
|
||||
lw.setText(_('&Wrap long lines in the editor'))
|
||||
l.addRow(lw)
|
||||
|
||||
class Preferences(QDialog):
|
||||
|
||||
@ -32,7 +155,7 @@ class Preferences(QDialog):
|
||||
cl.setFlow(cl.TopToBottom)
|
||||
cl.setMovement(cl.Static)
|
||||
cl.setWrapping(False)
|
||||
cl.setSpacing(10)
|
||||
cl.setSpacing(15)
|
||||
cl.setWordWrap(True)
|
||||
l.addWidget(cl, 0, 0, 1, 1)
|
||||
|
||||
@ -40,7 +163,11 @@ class Preferences(QDialog):
|
||||
bb.accepted.connect(self.accept)
|
||||
bb.rejected.connect(self.reject)
|
||||
self.rdb = b = bb.addButton(_('Restore all defaults'), bb.ResetRole)
|
||||
b.setToolTip(_('Restore defaults for all preferences'))
|
||||
b.clicked.connect(self.restore_all_defaults)
|
||||
self.rcdb = b = bb.addButton(_('Restore current defaults'), bb.ResetRole)
|
||||
b.setToolTip(_('Restore defaults for currently displayed preferences'))
|
||||
b.clicked.connect(self.restore_current_defaults)
|
||||
l.addWidget(bb, 1, 0, 1, 2)
|
||||
|
||||
self.resize(800, 600)
|
||||
@ -50,22 +177,34 @@ class Preferences(QDialog):
|
||||
|
||||
self.keyboard_panel = ShortcutConfig(self)
|
||||
self.keyboard_panel.initialize(gui.keyboard)
|
||||
self.editor_panel = EditorSettings(self)
|
||||
|
||||
for name, icon, panel in [(_('Keyboard Shortcuts'), 'keyboard-prefs.png', 'keyboard')]:
|
||||
for name, icon, panel in [
|
||||
(_('Editor settings'), 'modified.png', 'editor'),
|
||||
(_('Keyboard Shortcuts'), 'keyboard-prefs.png', 'keyboard')
|
||||
]:
|
||||
i = QListWidgetItem(QIcon(I(icon)), name, cl)
|
||||
cl.addItem(i)
|
||||
self.stacks.addWidget(getattr(self, panel + '_panel'))
|
||||
|
||||
cl.setCurrentRow(0)
|
||||
cl.item(0).setSelected(True)
|
||||
cl.setMaximumWidth(cl.sizeHintForColumn(0) + 30)
|
||||
l.setColumnStretch(1, 10)
|
||||
w, h = cl.sizeHintForColumn(0), 0
|
||||
for i in xrange(cl.count()):
|
||||
h = max(h, cl.sizeHintForRow(i))
|
||||
cl.item(i).setSizeHint(QSize(w, h))
|
||||
|
||||
cl.setMaximumWidth(cl.sizeHintForColumn(0) + 35)
|
||||
cl.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
|
||||
def restore_all_defaults(self):
|
||||
for i in xrange(self.stacks.count()):
|
||||
w = self.stacks.widget(i)
|
||||
w.restore_defaults()
|
||||
|
||||
def restore_current_defaults(self):
|
||||
self.stacks.currentWidget().restore_defaults()
|
||||
|
||||
def accept(self):
|
||||
tprefs.set('preferences_geom', bytearray(self.saveGeometry()))
|
||||
for i in xrange(self.stacks.count()):
|
||||
|
Loading…
x
Reference in New Issue
Block a user