Work on plugging the new layout code into the actual GUI

This commit is contained in:
Kovid Goyal 2023-12-22 13:03:14 +05:30
parent 3f446ae4af
commit 4c753c6f63
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
9 changed files with 227 additions and 589 deletions

View File

@ -3,7 +3,7 @@
from enum import Enum
from functools import partial
from qt.core import QIcon, QToolButton
from qt.core import QToolButton
from calibre.gui2.actions import InterfaceAction
@ -33,7 +33,7 @@ class LayoutActions(InterfaceAction):
m.addAction(_('Hide all'), self.hide_all)
for button, name in zip(self.gui.layout_buttons, self.gui.button_order):
m.addSeparator()
ic = QIcon.ic(button.icname)
ic = button.icon()
m.addAction(ic, _('Show {}').format(button.label), partial(self.set_visible, Panel(name), True))
m.addAction(ic, _('Hide {}').format(button.label), partial(self.set_visible, Panel(name), False))

View File

@ -10,38 +10,7 @@ from qt.core import QAction, QTimer
from calibre.gui2.actions import InterfaceAction
from calibre.gui2.dialogs.quickview import Quickview
from calibre.gui2 import error_dialog, gprefs
from calibre.gui2.widgets import LayoutButton
class QuickviewButton(LayoutButton): # {{{
def __init__(self, gui, quickview_manager):
self.qv = quickview_manager
qaction = quickview_manager.qaction
LayoutButton.__init__(self, 'quickview.png', _('Quickview'),
parent=gui, shortcut=qaction.shortcut().toString())
self.toggled.connect(self.update_state)
self.action_toggle = qaction
self.action_toggle.triggered.connect(self.toggle)
self.action_toggle.changed.connect(self.update_shortcut)
def update_state(self, checked):
if checked:
self.set_state_to_hide()
self.qv._show_quickview()
else:
self.set_state_to_show()
self.qv._hide_quickview()
def save_state(self):
gprefs['quickview visible'] = bool(self.isChecked())
def restore_state(self):
if gprefs.get('quickview visible', False):
self.toggle()
# }}}
from calibre.gui2 import error_dialog
current_qv_action_pi = None
@ -104,10 +73,13 @@ class ShowQuickviewAction(InterfaceAction):
group=self.action_spec[0])
self.search_action.triggered.connect(self.search_quickview)
self.qv_button = QuickviewButton(self.gui, self)
@property
def qv_button(self):
return self.gui.layout_container.quick_view_button
def initialization_complete(self):
set_quickview_action_plugin(self)
self.qv_button.update_shortcut(self.qaction)
def _hide_quickview(self):
'''

View File

@ -1156,9 +1156,9 @@ class DetailsLayout(QSplitter): # {{{
self.restoreState(s)
self.setOrientation(Qt.Orientation.Vertical if self.vertical else Qt.Orientation.Horizontal)
def setGeometry(self, r):
super().setGeometry(r)
self.do_layout(r)
def setGeometry(self, *a):
super().setGeometry(*a)
self.do_layout(self.geometry())
def do_splitter_moved(self, *args):
gprefs['book_details_widget_splitter_state'] = bytearray(self.saveState())

View File

@ -5,12 +5,12 @@ from copy import copy
from dataclasses import asdict, dataclass, fields
from enum import Enum, auto
from qt.core import (
QDialog, QHBoxLayout, QIcon, QKeySequence, QLabel, QPalette, QPointF, QSize,
QSizePolicy, QStyle, QStyleOption, QStylePainter, Qt, QToolButton, QVBoxLayout,
QWidget, pyqtSignal,
QAction, QDialog, QHBoxLayout, QIcon, QKeySequence, QLabel, QPalette, QPointF,
QSize, QSizePolicy, QStyle, QStyleOption, QStylePainter, Qt, QToolButton,
QVBoxLayout, QWidget, pyqtSignal,
)
from calibre.gui2 import Application, gprefs
from calibre.gui2 import Application, config, gprefs
from calibre.gui2.cover_flow import MIN_SIZE
HIDE_THRESHOLD = 10
@ -30,7 +30,9 @@ class Placeholder(QLabel):
class LayoutButton(QToolButton):
def __init__(self, name: str, icon: str, label: str, central: 'Central', shortcut=None):
on_action_trigger = pyqtSignal(bool)
def __init__(self, name: str, icon: str, label: str, central: 'CentralContainer', shortcut=None):
super().__init__(central)
self.central = central
self.label = label
@ -39,14 +41,30 @@ class LayoutButton(QToolButton):
self.setIcon(QIcon.ic(icon))
self.setCheckable(True)
self.setChecked(self.is_visible)
self.toggled.connect(central.layout_button_toggled)
self.setCursor(Qt.CursorShape.PointingHandCursor)
if isinstance(central, CentralContainer):
self.toggled.connect(central.layout_button_toggled)
def initialize_with_gui(self, gui):
if self.shortcut is not None:
self.action_toggle = QAction(self.icon(), _('Toggle') + ' ' + self.label, self)
self.action_toggle.changed.connect(self.update_shortcut)
self.action_toggle.triggered.connect(self.toggle_triggered)
gui.addAction(self.action_toggle)
gui.keyboard.register_shortcut(
f'toggle_central_panel_{self.name}', self.action_toggle.text(), default_keys=(self.shortcut,), action=self.action_toggle)
def toggle_triggered(self):
self.toggle()
self.on_action_trigger.emit(self.isChecked())
@property
def is_visible(self):
return getattr(self.central.is_visible, self.name)
def update_shortcut(self, action_toggle=None):
action_toggle = action_toggle or getattr(self, 'action_toggle', None)
if not isinstance(action_toggle, QAction):
action_toggle = getattr(self, 'action_toggle', None)
if action_toggle:
sc = ', '.join(sc.toString(QKeySequence.SequenceFormat.NativeText)
for sc in action_toggle.shortcuts())
@ -230,23 +248,31 @@ class Visibility:
setattr(self, f.name, getattr(c, f.name))
class Central(QWidget):
class CentralContainer(QWidget):
layout: Layout = Layout.wide
def __init__(self, parent=None, prefs_name='main_window_central_widget_state'):
def __init__(self, parent=None, prefs_name='main_window_central_widget_state', separate_cover_browser=None, for_develop=False):
self.separate_cover_browser = config['separate_cover_flow'] if separate_cover_browser is None else separate_cover_browser
self.prefs_name = prefs_name
super().__init__(parent)
self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
self.wide_desires = WideDesires()
self.narrow_desires = NarrowDesires()
self.is_visible = Visibility()
self.tag_browser = Placeholder('tag browser', self)
self.book_list = Placeholder('book list', self)
self.cover_browser = Placeholder('cover browser', self)
if for_develop:
self.tag_browser = Placeholder('tag browser', self)
self.book_list = Placeholder('book list', self)
self.cover_browser = Placeholder('cover browser', self)
self.book_details = Placeholder('book details', self)
self.quick_view = Placeholder('quick view', self)
else:
self.tag_browser = QWidget(self)
self.book_list = QWidget(self)
self.cover_browser = QWidget(self)
self.book_details = QWidget(self)
self.quick_view = QWidget(self)
self.cover_browser.setMinimumSize(MIN_SIZE)
self.book_details = Placeholder('book details', self)
self.quick_view = Placeholder('quick view', self)
self.ignore_button_toggles = False
self.tag_browser_button = LayoutButton('tag_browser', 'tags.png', _('Tag browser'), self, 'Shift+Alt+T')
self.book_details_button = LayoutButton('book_details', 'book.png', _('Book details'), self, 'Shift+Alt+D')
@ -265,6 +291,28 @@ class Central(QWidget):
self.top_handle = h(Qt.Orientation.Horizontal)
self.bottom_handle = h(Qt.Orientation.Horizontal)
def set_widget(self, which, w):
existing = getattr(self, which)
existing.setVisible(False)
existing.setParent(None)
setattr(self, which, w)
w.setParent(self)
def initialize_with_gui(self, gui, book_list_widget):
self.tag_browser_button.initialize_with_gui(gui)
self.book_details_button.initialize_with_gui(gui)
self.cover_browser_button.initialize_with_gui(gui)
self.quick_view_button.initialize_with_gui(gui)
self.set_widget('book_details', gui.book_details)
self.set_widget('tag_browser', gui.tb_widget)
self.set_widget('book_list', book_list_widget)
# cover browser is set in CoverFlowMixin
# Quickview is set in quickview.py code
@property
def is_wide(self):
return self.layout is Layout.wide
def serialized_settings(self):
return {
'layout': self.layout.name,
@ -296,6 +344,7 @@ class Central(QWidget):
before = self.serialized_settings()
self.unserialize_settings(gprefs.get(self.prefs_name) or {})
if self.serialized_settings() != before:
self.update_button_states_from_visibility()
self.relayout()
def reset_to_defaults(self):
@ -305,6 +354,7 @@ class Central(QWidget):
self.wide_desires.reset_to_defaults()
self.narrow_desires.reset_to_defaults()
if self.serialized_settings() != before:
self.update_button_states_from_visibility()
self.relayout()
def toggle_panel(self, which):
@ -322,6 +372,16 @@ class Central(QWidget):
setattr(self.is_visible, which, visible)
self.update_button_states_from_visibility()
def show_panel(self, which):
if not getattr(self.is_visible, which):
self.set_visibility_of(which, True)
self.relayout()
def hide_panel(self, which):
if getattr(self.is_visible, which):
self.set_visibility_of(which, False)
self.relayout()
def panel_name_for_handle(self, handle):
return self.panel_name_for_handle_wide(handle) if self.layout is Layout.wide else self.panel_name_for_handle_narrow(handle)
@ -381,7 +441,7 @@ class Central(QWidget):
def relayout(self):
self.tag_browser.setVisible(self.is_visible.tag_browser)
self.book_details.setVisible(self.is_visible.book_details)
self.cover_browser.setVisible(self.is_visible.cover_browser)
self.cover_browser.setVisible(self.is_visible.cover_browser and not self.separate_cover_browser)
self.book_list.setVisible(self.is_visible.book_list)
self.quick_view.setVisible(self.is_visible.quick_view)
if self.layout is Layout.wide:
@ -394,6 +454,12 @@ class Central(QWidget):
self.layout = Layout.narrow if self.layout is Layout.wide else Layout.wide
self.relayout()
def button_for(self, which):
return getattr(self, which + '_button')
def sizeHint(self):
return QSize(800, 600)
# Wide {{{
def wide_handle_state(self, handle):
if handle is self.left_handle:
@ -401,7 +467,7 @@ class Central(QWidget):
if handle is self.right_handle:
return HandleState.both_visible if self.is_visible.book_details else HandleState.only_main_visible
if handle is self.top_handle:
if self.is_visible.cover_browser:
if self.is_visible.cover_browser and not self.separate_cover_browser:
return HandleState.both_visible if self.is_visible.book_list else HandleState.only_side_visible
return HandleState.only_main_visible
if handle is self.bottom_handle:
@ -443,13 +509,13 @@ class Central(QWidget):
hs = h.state
if hs is HandleState.both_visible or hs is HandleState.only_side_visible:
height = normal_handle_width
if h is self.bottom_handle and hs is HandleState.only_main_visible:
if hs is HandleState.only_main_visible and h is self.bottom_handle or (h is self.top_handle and self.separate_cover_browser):
height = 0
h.resize(int(central_width), int(height))
available_height -= height
cb = max(self.cover_browser.minimumHeight(), int(self.wide_desires.cover_browser_height * self.height()))
if not self.is_visible.cover_browser:
if not self.is_visible.cover_browser or self.separate_cover_browser:
cb = 0
qv = bl = 0
if cb >= available_height:
@ -466,7 +532,7 @@ class Central(QWidget):
bl = available_height - qv
else:
bl = available_height
if self.is_visible.cover_browser:
if self.is_visible.cover_browser and not self.separate_cover_browser:
self.cover_browser.setGeometry(int(central_x), 0, int(central_width), int(cb))
self.top_handle.move(central_x, cb)
if self.is_visible.book_list:
@ -532,7 +598,7 @@ class Central(QWidget):
if handle is self.left_handle:
return HandleState.both_visible if self.is_visible.tag_browser else HandleState.only_main_visible
if handle is self.right_handle:
if self.is_visible.cover_browser:
if self.is_visible.cover_browser and not self.separate_cover_browser:
return HandleState.both_visible if self.is_visible.book_list else HandleState.only_side_visible
return HandleState.only_main_visible
if handle is self.top_handle:
@ -569,12 +635,15 @@ class Central(QWidget):
hs = h.state
if hs is HandleState.both_visible or hs is HandleState.only_side_visible:
width = normal_handle_width
if h is self.right_handle and self.separate_cover_browser:
width = 0
h.resize(int(width), int(central_height))
available_width -= width
tb = int(self.narrow_desires.tag_browser_width * self.width()) if self.is_visible.tag_browser else 0
cb = max(self.cover_browser.minimumWidth(), int(self.narrow_desires.cover_browser_width * self.width())) if self.is_visible.cover_browser else 0
cb = max(self.cover_browser.minimumWidth(),
int(self.narrow_desires.cover_browser_width * self.width())) if self.is_visible.cover_browser and not self.separate_cover_browser else 0
min_central_width = self.min_central_width_narrow()
if tb + cb > available_width - min_central_width:
if tb + cb > max(0, available_width - min_central_width):
width_to_share = max(0, available_width - min_central_width)
cb = int(cb * width_to_share / (tb + cb))
cb = max(self.cover_browser.minimumWidth(), cb)
@ -587,7 +656,7 @@ class Central(QWidget):
self.left_handle.move(tb, 0)
central_x = self.left_handle.x() + self.left_handle.width()
self.right_handle.move(tb + central_width + self.left_handle.width(), 0)
if self.is_visible.cover_browser:
if self.is_visible.cover_browser and not self.separate_cover_browser:
self.cover_browser.setGeometry(int(self.right_handle.x() + self.right_handle.width()), 0, int(cb), int(self.height()))
self.top_handle.resize(int(central_width), int(normal_handle_width if self.is_visible.quick_view else 0))
central_height -= self.top_handle.height()
@ -661,9 +730,6 @@ class Central(QWidget):
return {self.left_handle: 'tag_browser', self.right_handle: 'cover_browser', self.top_handle: 'quick_view', self.bottom_handle: 'book_details'}[handle]
# }}}
def sizeHint(self):
return QSize(800, 600)
# develop {{{
def develop():
@ -675,7 +741,7 @@ def develop():
l.setContentsMargins(0, 0, 0, 0)
h = QHBoxLayout()
l.addLayout(h)
self.central = Central(self, prefs_name='develop_central_layout_widget_state')
self.central = CentralContainer(self, for_develop=True, prefs_name='develop_central_layout_widget_state', separate_cover_browser=False)
h.addWidget(self.central.tag_browser_button)
h.addWidget(self.central.book_details_button)
h.addWidget(self.central.cover_browser_button)

View File

@ -353,8 +353,12 @@ class CoverFlowMixin:
disable_cover_browser_refresh = False
@property
def cb_button(self):
return self.layout_container.cover_browser_button
def one_auto_scroll(self):
cb_visible = self.cover_flow is not None and self.cb_splitter.button.isChecked()
cb_visible = self.cover_flow is not None and self.cb_button.isChecked()
if cb_visible:
self.cover_flow.one_auto_scroll()
else:
@ -388,18 +392,17 @@ class CoverFlowMixin:
self.cover_flow.setImages(self.db_images)
self.cover_flow.itemActivated.connect(self.iactions['View'].view_specific_book)
self.update_cover_flow_subtitle_font()
button = self.cb_button
if self.separate_cover_browser:
self.separate_cover_browser = True
self.cb_splitter.button.clicked.connect(self.toggle_cover_browser)
self.cb_splitter.button.set_state_to_show()
self.cb_splitter.action_toggle.triggered.connect(self.toggle_cover_browser)
button.clicked.connect(self.toggle_cover_browser)
button.set_state_to_show()
button.on_action_trigger.connect(self.toggle_cover_browser)
self.cover_flow.stop.connect(self.hide_cover_browser)
self.cover_flow.setVisible(False)
else:
self.separate_cover_browser = False
self.cb_splitter.insertWidget(self.cb_splitter.side_index, self.cover_flow)
self.cover_flow.stop.connect(self.cb_splitter.hide_side_pane)
self.cb_splitter.button.toggled.connect(self.cover_browser_toggled, type=Qt.ConnectionType.QueuedConnection)
self.cover_flow.stop.connect(button.set_state_to_hide)
self.layout_container.set_widget('cover_browser', self.cover_flow)
button.toggled.connect(self.cover_browser_toggled, type=Qt.ConnectionType.QueuedConnection)
def update_cover_flow_subtitle_font(self):
db = self.current_db.new_api
@ -419,7 +422,7 @@ class CoverFlowMixin:
self.show_cover_browser()
def cover_browser_toggled(self, *args):
if self.cb_splitter.button.isChecked():
if self.cb_button.isChecked():
self.cover_browser_shown()
else:
self.cover_browser_hidden()
@ -447,25 +450,25 @@ class CoverFlowMixin:
def show_cover_browser(self):
d = CBDialog(self, self.cover_flow)
d.addAction(self.cb_splitter.action_toggle)
d.addAction(self.cb_button.action_toggle)
self.cover_flow.setVisible(True)
self.cover_flow.setFocus(Qt.FocusReason.OtherFocusReason)
d.show_fullscreen() if gprefs['cb_fullscreen'] else d.show()
self.cb_splitter.button.set_state_to_hide()
self.cb_button.set_state_to_hide()
d.closed.connect(self.cover_browser_closed)
self.cb_dialog = d
self.cb_splitter.button.set_state_to_hide()
self.cb_button.set_state_to_hide()
def cover_browser_closed(self, *args):
self.cb_dialog = None
self.cb_splitter.button.set_state_to_show()
self.cb_button.set_state_to_show()
def hide_cover_browser(self, *args):
cbd = getattr(self, 'cb_dialog', None)
if cbd is not None:
cbd.accept()
self.cb_dialog = None
self.cb_splitter.button.set_state_to_show()
self.cb_button.set_state_to_show()
def is_cover_browser_visible(self):
try:
@ -473,7 +476,7 @@ class CoverFlowMixin:
return self.cover_flow.isVisible()
except AttributeError:
return False # called before init_cover_flow_mixin
return not self.cb_splitter.is_side_index_hidden
return self.cb_button.isChecked()
def refresh_cover_browser(self):
if self.disable_cover_browser_refresh:

View File

@ -269,7 +269,7 @@ class Quickview(QDialog, Ui_Quickview):
# Remove the ampersands from the buttons because shortcuts exist.
self.lock_qv.setText(_('Lock Quickview contents'))
self.refresh_button.setText(_('Refresh'))
self.gui.quickview_splitter.add_quickview_dialog(self)
self.gui.layout_container.set_widget('quick_view', self)
self.close_button.setVisible(False)
else:
self.dock_button.setToolTip(_('Embed the Quickview panel into the main calibre window'))
@ -324,7 +324,7 @@ class Quickview(QDialog, Ui_Quickview):
t.start()
def item_doubleclicked(self, item):
tb = self.gui.stack.tb_widget
tb = self.gui.tb_widget
tb.set_focus_to_find_box()
tb.item_search.lineEdit().setText(self.current_key + ':=' + item.text())
tb.do_find()
@ -456,7 +456,7 @@ class Quickview(QDialog, Ui_Quickview):
def show(self):
QDialog.show(self)
if self.is_pane:
self.gui.quickview_splitter.show_quickview_widget()
self.gui.show_panel('quick_view')
def show_as_pane_changed(self):
gprefs['quickview_is_pane'] = not gprefs.get('quickview_is_pane', False)
@ -707,10 +707,6 @@ class Quickview(QDialog, Ui_Quickview):
def resizeEvent(self, *args):
QDialog.resizeEvent(self, *args)
# Do this if we are resizing for the first time to reset state.
if self.is_pane and self.height() == 0:
self.gui.quickview_splitter.set_sizes()
if self.books_table_column_widths is not None:
for c,w in enumerate(self.books_table_column_widths):
self.books_table.setColumnWidth(c, w)
@ -868,7 +864,7 @@ class Quickview(QDialog, Ui_Quickview):
def _reject(self):
if self.is_pane:
self.gui.quickview_splitter.hide_quickview_widget()
self.gui.hide_panel('quick_view')
self.gui.library_view.setFocus(Qt.FocusReason.ActiveWindowFocusReason)
self._close()
QDialog.reject(self)

View File

@ -7,23 +7,21 @@ __docformat__ = 'restructuredtext en'
import functools
from qt.core import (
QAction, QApplication, QDialog, QEvent, QIcon, QLabel, QMenu, QPixmap, QSizePolicy,
QSplitter, QStackedWidget, QStatusBar, QStyle, QStyleOption, QStylePainter, Qt,
QTabBar, QTimer, QToolButton, QUrl, QVBoxLayout, QWidget,
QAction, QApplication, QDialog, QEvent, QIcon, QLabel, QMenu, QPixmap,
QStackedWidget, QStatusBar, QStyle, QStyleOption, QStylePainter, Qt, QTabBar,
QTimer, QToolButton, QUrl,
)
from calibre.constants import get_appname_for_display, get_version, ismacos
from calibre.customize.ui import find_plugin
from calibre.gui2 import (
config, error_dialog, gprefs, is_widescreen, open_local_file, open_url,
)
from calibre.gui2 import config, error_dialog, gprefs, open_local_file, open_url
from calibre.gui2.book_details import BookDetails
from calibre.gui2.central import CentralContainer, LayoutButton
from calibre.gui2.layout_menu import LayoutMenu
from calibre.gui2.library.alternate_views import GridView
from calibre.gui2.library.views import BooksView, DeviceBooksView
from calibre.gui2.notify import get_notifier
from calibre.gui2.tag_browser.ui import TagBrowserWidget
from calibre.gui2.widgets import LayoutButton, Splitter
from calibre.utils.config import prefs
from calibre.utils.icu import sort_key
from calibre.utils.localization import localize_website_link, ngettext
@ -111,105 +109,6 @@ class LibraryViewMixin: # {{{
# }}}
class QuickviewSplitter(QSplitter): # {{{
def __init__(self, parent=None, orientation=Qt.Orientation.Vertical, qv_widget=None):
super().__init__(parent=parent, orientation=orientation)
self.splitterMoved.connect(self.splitter_moved)
self.setChildrenCollapsible(False)
self.qv_widget = qv_widget
def splitter_moved(self):
gprefs['quickview_dialog_heights'] = self.sizes()
def resizeEvent(self, *args):
super().resizeEvent(*args)
if self.sizes()[1] != 0:
gprefs['quickview_dialog_heights'] = self.sizes()
def set_sizes(self):
sizes = gprefs.get('quickview_dialog_heights', [])
if len(sizes) == 2:
self.setSizes(sizes)
def add_quickview_dialog(self, qv_dialog):
self.qv_widget.layout().addWidget(qv_dialog)
def show_quickview_widget(self):
self.qv_widget.show()
def hide_quickview_widget(self):
self.qv_widget.hide()
# }}}
class LibraryWidget(Splitter): # {{{
def __init__(self, parent):
orientation = Qt.Orientation.Vertical
if config['gui_layout'] == 'narrow':
orientation = Qt.Orientation.Horizontal if is_widescreen() else Qt.Orientation.Vertical
idx = 0 if orientation == Qt.Orientation.Vertical else 1
size = 300 if orientation == Qt.Orientation.Vertical else 550
Splitter.__init__(self, 'cover_browser_splitter', _('Cover browser'),
'cover_flow.png',
orientation=orientation, parent=parent,
connect_button=not config['separate_cover_flow'],
side_index=idx, initial_side_size=size, initial_show=False,
shortcut='Shift+Alt+B')
quickview_widget = QWidget()
parent.quickview_splitter = QuickviewSplitter(
parent=self, orientation=Qt.Orientation.Vertical, qv_widget=quickview_widget)
parent.library_view = BooksView(parent)
parent.library_view.setObjectName('library_view')
stack = QStackedWidget(self)
av = parent.library_view.alternate_views
parent.pin_container = av.set_stack(stack)
parent.grid_view = GridView(parent)
parent.grid_view.setObjectName('grid_view')
av.add_view('grid', parent.grid_view)
parent.quickview_splitter.addWidget(stack)
l = QVBoxLayout()
l.setContentsMargins(4, 0, 0, 0)
quickview_widget.setLayout(l)
parent.quickview_splitter.addWidget(quickview_widget)
parent.quickview_splitter.hide_quickview_widget()
self.addWidget(parent.quickview_splitter)
# }}}
class Stack(QStackedWidget): # {{{
def __init__(self, parent):
QStackedWidget.__init__(self, parent)
parent.cb_splitter = LibraryWidget(parent)
self.tb_widget = TagBrowserWidget(parent)
parent.tb_splitter = Splitter('tag_browser_splitter',
_('Tag browser'), 'tags.png',
parent=parent, side_index=0, initial_side_size=200,
shortcut='Shift+Alt+T')
parent.tb_splitter.state_changed.connect(
self.tb_widget.set_pane_is_visible, Qt.ConnectionType.QueuedConnection)
parent.tb_splitter.addWidget(self.tb_widget)
parent.tb_splitter.addWidget(parent.cb_splitter)
parent.tb_splitter.setCollapsible(parent.tb_splitter.other_index, False)
self.addWidget(parent.tb_splitter)
for x in ('memory', 'card_a', 'card_b'):
name = x+'_view'
w = DeviceBooksView(parent)
setattr(parent, name, w)
self.addWidget(w)
w.setObjectName(name)
# }}}
class UpdateLabel(QLabel): # {{{
def __init__(self, *args, **kwargs):
@ -220,7 +119,6 @@ class UpdateLabel(QLabel): # {{{
pass
# }}}
class VersionLabel(QLabel): # {{{
def __init__(self, parent):
@ -258,7 +156,6 @@ class VersionLabel(QLabel): # {{{
return QLabel.paintEvent(self, ev)
# }}}
class StatusBar(QStatusBar): # {{{
def __init__(self, parent=None):
@ -327,12 +224,11 @@ class StatusBar(QStatusBar): # {{{
# }}}
class GridViewButton(LayoutButton): # {{{
def __init__(self, gui):
sc = 'Alt+Shift+G'
LayoutButton.__init__(self, 'grid.png', _('Cover grid'), parent=gui, shortcut=sc)
LayoutButton.__init__(self, 'cover_grid', 'grid.png', _('Cover grid'), gui, shortcut=sc)
self.set_state_to_show()
self.action_toggle = QAction(self.icon(), _('Toggle') + ' ' + self.label, self)
gui.addAction(self.action_toggle)
@ -342,6 +238,10 @@ class GridViewButton(LayoutButton): # {{{
self.action_toggle.changed.connect(self.update_shortcut)
self.toggled.connect(self.update_state)
@property
def is_visible(self):
return self.isChecked()
def update_state(self, checked):
if checked:
self.set_state_to_hide()
@ -362,7 +262,7 @@ class SearchBarButton(LayoutButton): # {{{
def __init__(self, gui):
sc = 'Alt+Shift+F'
LayoutButton.__init__(self, 'search.png', _('Search bar'), parent=gui, shortcut=sc)
LayoutButton.__init__(self, 'search', 'search.png', _('Search bar'), gui, shortcut=sc)
self.set_state_to_hide()
self.action_toggle = QAction(self.icon(), _('Toggle') + ' ' + self.label, self)
gui.addAction(self.action_toggle)
@ -372,6 +272,10 @@ class SearchBarButton(LayoutButton): # {{{
self.action_toggle.changed.connect(self.update_shortcut)
self.toggled.connect(self.update_state)
@property
def is_visible(self):
return self.isChecked()
def update_state(self, checked):
if checked:
self.set_state_to_hide()
@ -560,7 +464,6 @@ class VLTabs(QTabBar): # {{{
# }}}
class LayoutMixin: # {{{
def __init__(self, *args, **kwargs):
@ -569,35 +472,34 @@ class LayoutMixin: # {{{
def init_layout_mixin(self):
self.vl_tabs = VLTabs(self)
self.centralwidget.layout().addWidget(self.vl_tabs)
self.layout_container = CentralContainer(self)
self.centralwidget.layout().addWidget(self.layout_container)
self.book_details = BookDetails(self.layout_container.is_wide, self)
self.stack = QStackedWidget(self)
self.library_view = BooksView(self)
self.library_view.setObjectName('library_view')
stack = QStackedWidget(self)
self.stack.addWidget(stack)
av = self.library_view.alternate_views
self.pin_container = av.set_stack(stack)
self.grid_view = GridView(self)
self.grid_view.setObjectName('grid_view')
av.add_view('grid', self.grid_view)
self.tb_widget = TagBrowserWidget(self)
self.memory_view = DeviceBooksView(self)
self.stack.addWidget(self.memory_view)
self.memory_view.setObjectName('memory_view')
self.card_a_view = DeviceBooksView(self)
self.stack.addWidget(self.card_a_view)
self.card_a_view.setObjectName('card_a_view')
self.card_b_view = DeviceBooksView(self)
self.stack.addWidget(self.card_b_view)
self.card_b_view.setObjectName('card_b_view')
if config['gui_layout'] == 'narrow': # narrow {{{
self.book_details = BookDetails(False, self)
self.stack = Stack(self)
self.bd_splitter = Splitter('book_details_splitter',
_('Book details'), 'book.png',
orientation=Qt.Orientation.Vertical, parent=self, side_index=1,
shortcut='Shift+Alt+D')
self.bd_splitter.addWidget(self.stack)
self.bd_splitter.addWidget(self.book_details)
self.bd_splitter.setCollapsible(self.bd_splitter.other_index, False)
self.centralwidget.layout().addWidget(self.bd_splitter)
self.button_order = button_order = ('sb', 'tb', 'bd', 'gv', 'cb', 'qv')
# }}}
else: # wide {{{
self.bd_splitter = Splitter('book_details_splitter',
_('Book details'), 'book.png', initial_side_size=200,
orientation=Qt.Orientation.Horizontal, parent=self, side_index=1,
shortcut='Shift+Alt+D')
self.stack = Stack(self)
self.bd_splitter.addWidget(self.stack)
self.book_details = BookDetails(True, self)
self.bd_splitter.addWidget(self.book_details)
self.bd_splitter.setCollapsible(self.bd_splitter.other_index, False)
self.bd_splitter.setSizePolicy(QSizePolicy(QSizePolicy.Policy.Expanding,
QSizePolicy.Policy.Expanding))
self.centralwidget.layout().addWidget(self.bd_splitter)
self.button_order = button_order = ('sb', 'tb', 'cb', 'gv', 'qv', 'bd')
# }}}
if self.layout_container.is_wide:
self.button_order = 'sb', 'tb', 'cb', 'gv', 'qv', 'bd'
else:
self.button_order = 'sb', 'tb', 'bd', 'gv', 'cb', 'qv'
# This must use the base method to find the plugin because it hasn't
# been fully initialized yet
@ -605,6 +507,9 @@ class LayoutMixin: # {{{
if self.qv and self.qv.actual_plugin_:
self.qv = self.qv.actual_plugin_
self.layout_container.initialize_with_gui(self, self.stack)
self.layout_container.tag_browser_button.toggled.connect(
self.tb_widget.set_pane_is_visible, Qt.ConnectionType.QueuedConnection)
self.status_bar = StatusBar(self)
stylename = str(self.style().objectName())
self.grid_view_button = GridViewButton(self)
@ -613,40 +518,33 @@ class LayoutMixin: # {{{
self.search_bar_button.toggled.connect(self.toggle_search_bar)
self.layout_buttons = []
for x in button_order:
if hasattr(self, x + '_splitter'):
button = getattr(self, x + '_splitter').button
for x in self.button_order:
if x == 'gv':
button = self.grid_view_button
elif x == 'sb':
button = self.search_bar_button
else:
if x == 'gv':
button = self.grid_view_button
elif x == 'qv':
if self.qv is None:
continue
button = self.qv.qv_button
else:
button = self.search_bar_button
button = self.layout_container.button_for({
'tb': 'tag_browser', 'bd': 'book_details', 'cb': 'cover_browser', 'qv': 'quick_view'
}[x])
self.layout_buttons.append(button)
button.setVisible(False)
button.setVisible(gprefs['show_layout_buttons'])
if ismacos and stylename != 'Calibre':
button.setStyleSheet('''
QToolButton { background: none; border:none; padding: 0px; }
QToolButton:checked { background: rgba(0, 0, 0, 25%); }
''')
self.status_bar.addPermanentWidget(button)
if gprefs['show_layout_buttons']:
for b in self.layout_buttons:
b.setVisible(True)
self.status_bar.addPermanentWidget(b)
else:
self.layout_button = b = QToolButton(self)
b.setAutoRaise(True), b.setCursor(Qt.CursorShape.PointingHandCursor)
b.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
b.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
b.setText(_('Layout')), b.setIcon(QIcon.ic('layout.png'))
b.setMenu(LayoutMenu(self))
b.setToolTip(_(
'Show and hide various parts of the calibre main window'))
self.status_bar.addPermanentWidget(b)
self.layout_button = b = QToolButton(self)
b.setAutoRaise(True), b.setCursor(Qt.CursorShape.PointingHandCursor)
b.setPopupMode(QToolButton.ToolButtonPopupMode.InstantPopup)
b.setToolButtonStyle(Qt.ToolButtonStyle.ToolButtonTextBesideIcon)
b.setText(_('Layout')), b.setIcon(QIcon.ic('layout.png'))
b.setMenu(LayoutMenu(self))
b.setToolTip(_(
'Show and hide various parts of the calibre main window'))
self.status_bar.addPermanentWidget(b)
b.setVisible(not gprefs['show_layout_buttons'])
self.status_bar.addPermanentWidget(self.jobs_button)
self.setStatusBar(self.status_bar)
self.status_bar.update_label.linkActivated.connect(self.update_link_clicked)
@ -698,6 +596,12 @@ class LayoutMixin: # {{{
self.library_view.currentIndex())
self.library_view.setFocus(Qt.FocusReason.OtherFocusReason)
def show_panel(self, name):
self.layout_container.show_panel(name)
def hide_panel(self, name):
self.layout_container.hide_panel(name)
def set_search_string_with_append(self, expression, append=''):
current = self.search.text().strip()
if append:
@ -727,7 +631,7 @@ class LayoutMixin: # {{{
def find_in_tag_browser_triggered(self, field, value):
if field and value:
tb = self.stack.tb_widget
tb = self.tb_widget
tb.set_focus_to_find_box()
tb.item_search.lineEdit().setText(field + ':=' + value)
tb.do_find()
@ -812,22 +716,15 @@ class LayoutMixin: # {{{
for x in ('library', 'memory', 'card_a', 'card_b'):
getattr(self, x+'_view').save_state()
for x in ('cb', 'tb', 'bd'):
s = getattr(self, x+'_splitter')
s.update_desired_state()
s.save_state()
self.layout_container.write_settings()
self.grid_view_button.save_state()
self.search_bar_button.save_state()
if self.qv:
self.qv.qv_button.save_state()
def read_layout_settings(self):
# View states are restored automatically when set_database is called
for x in ('cb', 'tb', 'bd'):
getattr(self, x+'_splitter').restore_state()
self.layout_container.read_settings()
self.grid_view_button.restore_state()
self.search_bar_button.restore_state()
# Can't do quickview here because the gui isn't totally set up. Do it in ui
def update_status_bar(self, *args):
v = self.current_view()

View File

@ -17,7 +17,6 @@ import sys
import textwrap
import time
from collections import OrderedDict, deque
from functools import partial
from io import BytesIO
from qt.core import (
QAction, QApplication, QDialog, QFont, QIcon, QMenu, QSystemTrayIcon, Qt, QTimer,
@ -56,7 +55,7 @@ from calibre.gui2.search_box import SavedSearchBoxMixin, SearchBoxMixin
from calibre.gui2.search_restriction_mixin import SearchRestrictionMixin
from calibre.gui2.tag_browser.ui import TagBrowserMixin
from calibre.gui2.update import UpdateMixin
from calibre.gui2.widgets import ProgressIndicator
from calibre.gui2.widgets import ProgressIndicator, BusyCursor
from calibre.library import current_library_name
from calibre.srv.library_broker import GuiLibraryBroker, db_matches
from calibre.utils.config import dynamic, prefs
@ -398,7 +397,13 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
do_hide_windows = True
show_gui = False
setattr(self, '__systray_minimized', True)
QTimer.singleShot(0, partial(self.post_initialize_actions, show_gui, do_hide_windows))
if do_hide_windows:
self.hide_windows()
if show_gui:
timed_print('GUI main window shown')
self.show()
self.layout_container.relayout()
QTimer.singleShot(0, self.post_initialize_actions)
self.read_settings()
self.finalize_layout()
@ -430,43 +435,12 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
self.iactions['Connect Share'].check_smartdevice_menus()
QTimer.singleShot(100, self.update_toggle_to_tray_action)
def post_initialize_actions(self, show_gui, do_hide_windows):
def post_initialize_actions(self):
# Various post-initialization actions after an event loop tick
self.listener.start_listening()
self.start_smartdevice()
# Collect cycles now
gc.collect()
self.listener.start_listening()
if do_hide_windows:
self.hide_windows()
if show_gui:
timed_print('GUI main window shown')
self.show()
# Force repaint of the book details splitter because it otherwise ends
# up with the wrong size. I don't know why.
self.bd_splitter.repaint()
# Once the gui is initialized we can restore the quickview state
# The same thing will be true for any action-based operation with a
# layout button. We need to let a book be selected in the book list
# before initializing quickview, so run it after an event loop tick
QTimer.singleShot(0, self.start_quickview)
# Start the smartdevice later so that the network time doesn't affect
# the gui repaint debouncing. Wait 3 seconds before starting to be sure
# that all other initialization (plugins etc) has completed. Yes, 3
# seconds is an arbitrary value and probably too long, but it will do
# until the underlying structure changes to make it unnecessary.
QTimer.singleShot(3000, self.start_smartdevice)
def start_quickview(self):
from calibre.gui2.actions.show_quickview import get_quickview_action_plugin
qv = get_quickview_action_plugin()
if qv:
timed_print('QuickView starting')
qv.qv_button.restore_state()
timed_print('QuickView started')
self.save_layout_state()
self.focus_library_view()
def show_gui_debug_msg(self):
@ -498,14 +472,15 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
timed_print('Starting the smartdevice driver')
message = None
if self.device_manager.get_option('smartdevice', 'autostart'):
try:
message = self.device_manager.start_plugin('smartdevice')
timed_print('Finished starting smartdevice')
except Exception as e:
message = str(e)
timed_print(f'Starting smartdevice driver failed: {message}')
import traceback
traceback.print_exc()
with BusyCursor():
try:
message = self.device_manager.start_plugin('smartdevice')
timed_print('Finished starting smartdevice')
except Exception as e:
message = str(e)
timed_print(f'Starting smartdevice driver failed: {message}')
import traceback
traceback.print_exc()
if message:
if not self.device_manager.is_running('Wireless Devices'):
error_dialog(self, _('Problem starting the wireless device'),
@ -1043,9 +1018,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
page = 0 if location == 'library' else 1 if location == 'main' else 2 if location == 'carda' else 3
self.stack.setCurrentIndex(page)
self.book_details.reset_info()
for x in ('tb', 'cb'):
splitter = getattr(self, x+'_splitter')
splitter.button.setEnabled(location == 'library')
self.layout_container.tag_browser_button.setEnabled(location == 'library')
self.layout_container.cover_browser_button.setEnabled(location == 'library')
for action in self.iactions.values():
action.location_selected(location)
if location == 'library':
@ -1168,7 +1142,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
self.save_geometry(gprefs, 'calibre_main_window_geometry')
dynamic.set('sort_history', self.library_view.model().sort_history)
self.save_layout_state()
self.stack.tb_widget.save_state()
self.tb_widget.save_state()
def quit(self, checked=True, restart=False, debug_on_restart=False,
confirm_quit=True, no_plugins_on_restart=False):

View File

@ -6,11 +6,11 @@ Miscellaneous widgets used in the GUI
import os
import re
from qt.core import (
QAction, QApplication, QClipboard, QColor, QComboBox, QCompleter, QCursor, QEvent,
QFont, QGraphicsScene, QGraphicsView, QIcon, QKeySequence, QLabel, QLineEdit,
QListWidget, QListWidgetItem, QMenu, QPageSize, QPainter, QPalette, QPen, QPixmap,
QPrinter, QRect, QSize, QSplitter, QSplitterHandle, QStringListModel,
QSyntaxHighlighter, Qt, QTextCharFormat, QTimer, QToolButton, QWidget, pyqtSignal,
QApplication, QClipboard, QColor, QComboBox, QCompleter, QCursor, QEvent, QFont,
QGraphicsScene, QGraphicsView, QIcon, QLabel, QLineEdit, QListWidget,
QListWidgetItem, QMenu, QPageSize, QPainter, QPalette, QPen, QPixmap, QPrinter,
QRect, QSize, QSplitterHandle, QStringListModel, QSyntaxHighlighter, Qt,
QTextCharFormat, QWidget, pyqtSignal,
)
from calibre import fit_image, force_unicode, strftime
@ -1063,276 +1063,6 @@ class SplitterHandle(QSplitterHandle):
self.double_clicked.emit(self)
class LayoutButton(QToolButton):
def __init__(self, icon, text, splitter=None, parent=None, shortcut=None):
QToolButton.__init__(self, parent)
self.label = text
self.setIcon(QIcon.ic(icon))
self.setCheckable(True)
self.icname = os.path.basename(icon).rpartition('.')[0]
self.splitter = splitter
if splitter is not None:
splitter.state_changed.connect(self.update_state)
self.setCursor(Qt.CursorShape.PointingHandCursor)
self.shortcut = shortcut or ''
def update_shortcut(self, action_toggle=None):
action_toggle = action_toggle or getattr(self, 'action_toggle', None)
if action_toggle:
sc = ', '.join(sc.toString(QKeySequence.SequenceFormat.NativeText)
for sc in action_toggle.shortcuts())
self.shortcut = sc or ''
self.update_text()
def update_text(self):
t = _('Hide {}') if self.isChecked() else _('Show {}')
t = t.format(self.label)
if self.shortcut:
t += f' [{self.shortcut}]'
self.setText(t), self.setToolTip(t), self.setStatusTip(t)
def set_state_to_show(self, *args):
self.setChecked(False)
self.update_text()
def set_state_to_hide(self, *args):
self.setChecked(True)
self.update_text()
def update_state(self, *args):
if self.splitter.is_side_index_hidden:
self.set_state_to_show()
else:
self.set_state_to_hide()
def mouseReleaseEvent(self, ev):
if ev.button() == Qt.MouseButton.RightButton:
from calibre.gui2.ui import get_gui
gui = get_gui()
if self.icname == 'search':
gui.iactions['Preferences'].do_config(initial_plugin=('Interface', 'Search'), close_after_initial=True)
ev.accept()
return
tab_name = {'book':'book_details', 'grid':'cover_grid', 'cover_flow':'cover_browser',
'tags':'tag_browser', 'quickview':'quickview'}.get(self.icname)
if tab_name:
if gui is not None:
gui.iactions['Preferences'].do_config(initial_plugin=('Interface', 'Look & Feel', tab_name+'_tab'), close_after_initial=True)
ev.accept()
return
return QToolButton.mouseReleaseEvent(self, ev)
class Splitter(QSplitter):
state_changed = pyqtSignal(object)
reapply_sizes = pyqtSignal(object)
def __init__(self, name, label, icon, initial_show=True,
initial_side_size=120, connect_button=True,
orientation=Qt.Orientation.Horizontal, side_index=0, parent=None,
shortcut=None, hide_handle_on_single_panel=True):
super().__init__(parent)
self.reapply_sizes.connect(self.setSizes, type=Qt.ConnectionType.QueuedConnection)
self.hide_handle_on_single_panel = hide_handle_on_single_panel
if hide_handle_on_single_panel:
self.state_changed.connect(self.update_handle_width)
self.original_handle_width = self.handleWidth()
self.resize_timer = QTimer(self)
self.resize_timer.setSingleShot(True)
self.desired_side_size = initial_side_size
self.desired_show = initial_show
self.resize_timer.setInterval(5)
self.resize_timer.timeout.connect(self.do_resize)
self.setOrientation(orientation)
self.side_index = side_index
self._name = name
self.label = label
self.initial_side_size = initial_side_size
self.initial_show = initial_show
self.splitterMoved.connect(self.splitter_moved, type=Qt.ConnectionType.QueuedConnection)
self.button = LayoutButton(icon, label, self, shortcut=shortcut)
if connect_button:
self.button.clicked.connect(self.double_clicked)
if shortcut is not None:
self.action_toggle = QAction(QIcon.ic(icon), _('Toggle') + ' ' + label,
self)
self.action_toggle.changed.connect(self.update_shortcut)
self.action_toggle.triggered.connect(self.toggle_triggered)
if parent is not None:
parent.addAction(self.action_toggle)
if hasattr(parent, 'keyboard'):
parent.keyboard.register_shortcut('splitter %s %s'%(name,
label), str(self.action_toggle.text()),
default_keys=(shortcut,), action=self.action_toggle)
else:
self.action_toggle.setShortcut(shortcut)
else:
self.action_toggle.setShortcut(shortcut)
def update_shortcut(self):
self.button.update_shortcut(self.action_toggle)
def toggle_triggered(self, *args):
self.toggle_side_pane()
def createHandle(self):
return SplitterHandle(self.orientation(), self)
def initialize(self):
for i in range(self.count()):
h = self.handle(i)
if h is not None:
h.splitter_moved()
self.state_changed.emit(not self.is_side_index_hidden)
def splitter_moved(self, *args):
self.desired_side_size = self.side_index_size
self.state_changed.emit(not self.is_side_index_hidden)
def update_handle_width(self, not_one_panel):
self.setHandleWidth(self.original_handle_width if not_one_panel else 0)
@property
def is_side_index_hidden(self):
sizes = list(self.sizes())
try:
return sizes[self.side_index] == 0
except IndexError:
return True
@property
def save_name(self):
ori = 'horizontal' if self.orientation() == Qt.Orientation.Horizontal \
else 'vertical'
return self._name + '_' + ori
def print_sizes(self):
if self.count() > 1:
print(self.save_name, 'side:', self.side_index_size, 'other:', end=' ')
print(list(self.sizes())[self.other_index])
@property
def side_index_size(self):
if self.count() < 2:
return 0
return self.sizes()[self.side_index]
@side_index_size.setter
def side_index_size(self, val):
if self.count() < 2:
return
side_index_hidden = self.is_side_index_hidden
if val == 0 and not side_index_hidden:
self.save_state()
sizes = list(self.sizes())
for i in range(len(sizes)):
sizes[i] = val if i == self.side_index else 10
self.setSizes(sizes)
sizes = list(self.sizes())
total = sum(sizes)
total_needs_adjustment = self.hide_handle_on_single_panel and side_index_hidden
if total_needs_adjustment:
total -= self.original_handle_width
for i in range(len(sizes)):
sizes[i] = val if i == self.side_index else total-val
self.setSizes(sizes)
self.initialize()
if total_needs_adjustment:
# the handle visibility and therefore size distribution will change
# when the event loop ticks
self.reapply_sizes.emit(sizes)
def ignore_child_paints(self, ignore=True):
for widget in self:
if hasattr(widget, 'ignore_paint_events'):
widget.ignore_paint_events = ignore
def do_resize(self, *args):
orig = self.desired_side_size
super().resizeEvent(self._resize_ev)
if orig > 20 and self.desired_show:
c = 0
while abs(self.side_index_size - orig) > 10 and c < 5:
self.apply_state(self.get_state(), save_desired=False)
c += 1
self.ignore_child_paints(False)
def __iter__(self):
for i in range(self.count()):
yield self.widget(i)
def resizeEvent(self, ev):
self.ignore_child_paints()
self._resize_ev = ev
self.resize_timer.start()
def get_state(self):
if self.count() < 2:
return (False, 200)
return (self.desired_show, self.desired_side_size)
def apply_state(self, state, save_desired=True):
if state[0]:
self.side_index_size = state[1]
if save_desired:
self.desired_side_size = self.side_index_size
else:
self.side_index_size = 0
self.desired_show = state[0]
def default_state(self):
return (self.initial_show, self.initial_side_size)
# Public API {{{
def update_desired_state(self):
self.desired_show = not self.is_side_index_hidden
def save_state(self):
if self.count() > 1:
gprefs[self.save_name+'_state'] = self.get_state()
@property
def other_index(self):
return (self.side_index+1)%2
def restore_state(self):
if self.count() > 1:
state = gprefs.get(self.save_name+'_state',
self.default_state())
self.apply_state(state, save_desired=False)
self.desired_side_size = state[1]
def toggle_side_pane(self, hide=None):
if hide is None:
action = 'show' if self.is_side_index_hidden else 'hide'
else:
action = 'hide' if hide else 'show'
getattr(self, action+'_side_pane')()
def show_side_pane(self):
if self.count() < 2 or not self.is_side_index_hidden:
return
if self.desired_side_size == 0:
self.desired_side_size = self.initial_side_size
self.apply_state((True, self.desired_side_size))
def hide_side_pane(self):
if self.count() < 2 or self.is_side_index_hidden:
return
self.apply_state((False, self.desired_side_size))
def double_clicked(self, *args):
self.toggle_side_pane()
# }}}
# }}}
class PaperSizes(QComboBox): # {{{