diff --git a/src/calibre/gui2/book_details.py b/src/calibre/gui2/book_details.py index fbbb1bd4b6..a8f025736e 100644 --- a/src/calibre/gui2/book_details.py +++ b/src/calibre/gui2/book_details.py @@ -8,7 +8,7 @@ from collections import namedtuple from functools import partial from qt.core import ( QAction, QApplication, QClipboard, QColor, QDialog, QEasingCurve, QIcon, - QKeySequence, QMenu, QMimeData, QPainter, QPen, QPixmap, + QKeySequence, QMenu, QMimeData, QPainter, QPen, QPixmap, QSplitter, QPropertyAnimation, QRect, QSize, QSizePolicy, Qt, QUrl, QWidget, pyqtProperty, pyqtSignal ) @@ -30,7 +30,6 @@ from calibre.gui2.dialogs.confirm_delete import confirm, confirm as confirm_dele from calibre.gui2.dnd import ( dnd_get_files, dnd_get_image, dnd_has_extension, dnd_has_image, image_extensions ) -from calibre.gui2.widgets import BasicSplitter from calibre.gui2.widgets2 import HTMLDisplay from calibre.utils.config import tweaks from calibre.utils.img import blend_image, image_from_x @@ -914,11 +913,11 @@ class BookInfo(HTMLDisplay): # }}} -class DetailsLayout(BasicSplitter): # {{{ +class DetailsLayout(QSplitter): # {{{ def __init__(self, vertical, parent): orientation = Qt.Orientation.Vertical if vertical else Qt.Orientation.Horizontal - BasicSplitter.__init__(self, orientation, parent) + super().__init__(orientation, parent) self.vertical = vertical self._children = [] self.min_size = QSize(190, 200) if vertical else QSize(120, 120) diff --git a/src/calibre/gui2/dialogs/book_info.py b/src/calibre/gui2/dialogs/book_info.py index 6d2d1954b1..696651a308 100644 --- a/src/calibre/gui2/dialogs/book_info.py +++ b/src/calibre/gui2/dialogs/book_info.py @@ -7,7 +7,7 @@ from qt.core import ( QAction, QApplication, QBrush, QCheckBox, QDialog, QGridLayout, QHBoxLayout, QIcon, QKeySequence, QLabel, QListView, QModelIndex, QPalette, QPixmap, QPushButton, QShortcut, QSize, Qt, QTimer, QToolButton, - QVBoxLayout, QWidget, pyqtSignal, QDialogButtonBox + QVBoxLayout, QWidget, pyqtSignal, QDialogButtonBox, QSplitter ) from calibre import fit_image @@ -17,7 +17,7 @@ from calibre.gui2.book_details import ( set_html ) from calibre.gui2.ui import get_gui -from calibre.gui2.widgets import CoverView, BasicSplitter +from calibre.gui2.widgets import CoverView from calibre.gui2.widgets2 import Dialog, HTMLDisplay @@ -136,7 +136,7 @@ class BookInfo(QDialog): QDialog.__init__(self, parent) self.marked = None self.gui = parent - self.splitter = BasicSplitter(self) + self.splitter = QSplitter(self) self._l = l = QVBoxLayout(self) self.setLayout(l) l.addWidget(self.splitter) diff --git a/src/calibre/gui2/dialogs/check_library.py b/src/calibre/gui2/dialogs/check_library.py index a5d0607ec9..a407eb5dcc 100644 --- a/src/calibre/gui2/dialogs/check_library.py +++ b/src/calibre/gui2/dialogs/check_library.py @@ -11,13 +11,12 @@ from qt.core import ( QApplication, QCheckBox, QCursor, QDialog, QDialogButtonBox, QGridLayout, QHBoxLayout, QIcon, QLabel, QLineEdit, QProgressBar, QPushButton, QStackedLayout, Qt, QTextEdit, QTreeWidget, QTreeWidgetItem, QVBoxLayout, - QWidget, pyqtSignal + QWidget, pyqtSignal, QSplitter ) from threading import Thread from calibre import as_unicode, prints from calibre.gui2.dialogs.confirm_delete import confirm -from calibre.gui2.widgets import BasicSplitter from calibre.library.check_library import CHECKS, CheckLibrary from calibre.utils.recycle_bin import delete_file, delete_tree @@ -126,7 +125,7 @@ class CheckLibraryDialog(QDialog): self._tl = QHBoxLayout() self.setLayout(self._tl) - self.splitter = BasicSplitter(self) + self.splitter = QSplitter(self) self.left = QWidget(self) self.splitter.addWidget(self.left) self.helpw = QTextEdit(self) diff --git a/src/calibre/gui2/init.py b/src/calibre/gui2/init.py index 5e916c1240..c1b8484f80 100644 --- a/src/calibre/gui2/init.py +++ b/src/calibre/gui2/init.py @@ -8,7 +8,7 @@ __docformat__ = 'restructuredtext en' import functools from qt.core import ( QAction, QApplication, QDialog, QEvent, QIcon, QLabel, QMenu, QPixmap, QUrl, - QSizePolicy, QStackedWidget, QStatusBar, QStyle, QStyleOption, + QSizePolicy, QStackedWidget, QStatusBar, QStyle, QStyleOption, QSplitter, QStylePainter, Qt, QTabBar, QTimer, QToolButton, QVBoxLayout, QWidget ) @@ -23,7 +23,7 @@ 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, BasicSplitter +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 @@ -112,10 +112,10 @@ class LibraryViewMixin: # {{{ # }}} -class QuickviewSplitter(BasicSplitter): # {{{ +class QuickviewSplitter(QSplitter): # {{{ def __init__(self, parent=None, orientation=Qt.Orientation.Vertical, qv_widget=None): - BasicSplitter.__init__(self, parent=parent, orientation=orientation) + super().__init__(parent=parent, orientation=orientation) self.splitterMoved.connect(self.splitter_moved) self.setChildrenCollapsible(False) self.qv_widget = qv_widget @@ -124,7 +124,7 @@ class QuickviewSplitter(BasicSplitter): # {{{ gprefs['quickview_dialog_heights'] = self.sizes() def resizeEvent(self, *args): - BasicSplitter.resizeEvent(self, *args) + super().resizeEvent(*args) if self.sizes()[1] != 0: gprefs['quickview_dialog_heights'] = self.sizes() diff --git a/src/calibre/gui2/metadata/single.py b/src/calibre/gui2/metadata/single.py index 0525eff188..2dffa514f0 100644 --- a/src/calibre/gui2/metadata/single.py +++ b/src/calibre/gui2/metadata/single.py @@ -12,8 +12,8 @@ from functools import partial from qt.core import ( QDialog, QDialogButtonBox, QFrame, QGridLayout, QGroupBox, QHBoxLayout, QIcon, QInputDialog, QKeySequence, QMenu, QPushButton, QScrollArea, QShortcut, QSize, - QSizePolicy, QSpacerItem, Qt, QTabWidget, QToolButton, QVBoxLayout, - QWidget, pyqtSignal + QSizePolicy, QSpacerItem, QSplitter, Qt, QTabWidget, QToolButton, QVBoxLayout, + QWidget, pyqtSignal, ) from calibre.constants import ismacos @@ -26,10 +26,9 @@ from calibre.gui2.metadata.basic_widgets import ( AuthorsEdit, AuthorSortEdit, BuddyLabel, CommentsEdit, Cover, DateEdit, FormatsManager, IdentifiersEdit, LanguagesEdit, PubdateEdit, PublisherEdit, RatingEdit, RightClickButton, SeriesEdit, SeriesIndexEdit, TagsEdit, TitleEdit, - TitleSortEdit, show_locked_file_error + TitleSortEdit, show_locked_file_error, ) from calibre.gui2.metadata.single_download import FullFetch -from calibre.gui2.widgets import BasicSplitter from calibre.gui2.widgets2 import CenteredToolButton from calibre.library.comments import merge_comments as merge_two_comments from calibre.utils.date import local_tz @@ -732,13 +731,13 @@ class MetadataSingleDialogBase(QDialog): # }}} -class Splitter(BasicSplitter): +class Splitter(QSplitter): frame_resized = pyqtSignal(object) def resizeEvent(self, ev): self.frame_resized.emit(ev) - return BasicSplitter.resizeEvent(self, ev) + return super().resizeEvent(ev) class MetadataSingleDialog(MetadataSingleDialogBase): # {{{ @@ -1040,7 +1039,7 @@ class MetadataSingleDialogAlt1(MetadataSingleDialogBase): # {{{ QSizePolicy.Policy.Expanding)) wgl.addWidget(self.formats_manager) - self.splitter = BasicSplitter(Qt.Orientation.Horizontal, tab1) + self.splitter = Splitter(Qt.Orientation.Horizontal, tab1) tab1.l.addWidget(self.splitter) self.splitter.addWidget(self.cover) self.splitter.addWidget(wsp) @@ -1208,7 +1207,7 @@ class MetadataSingleDialogAlt2(MetadataSingleDialogBase): # {{{ cover_layout.addLayout(hl) sto(self.cover.buttons[-2], self.cover.buttons[-1]) # Splitter for both cover & formats boxes - self.cover_and_formats = cover_and_formats = BasicSplitter(Qt.Orientation.Vertical) + self.cover_and_formats = cover_and_formats = Splitter(Qt.Orientation.Vertical) # Put a very small margin on the left so that the word "Cover" doesn't # touch the splitter cover_and_formats.setContentsMargins(1, 0, 0, 0) diff --git a/src/calibre/gui2/metadata/single_download.py b/src/calibre/gui2/metadata/single_download.py index 29abe1d871..40928ecc0e 100644 --- a/src/calibre/gui2/metadata/single_download.py +++ b/src/calibre/gui2/metadata/single_download.py @@ -17,7 +17,7 @@ from qt.core import ( QStyledItemDelegate, QTextDocument, QRectF, QIcon, Qt, QApplication, QDialog, QVBoxLayout, QLabel, QDialogButtonBox, QStyle, QStackedWidget, QWidget, QTableView, QGridLayout, QPalette, QTimer, pyqtSignal, - QAbstractTableModel, QSize, QListView, QPixmap, QModelIndex, + QAbstractTableModel, QSize, QListView, QPixmap, QModelIndex, QSplitter, QAbstractListModel, QRect, QTextBrowser, QStringListModel, QMenu, QItemSelectionModel, QCursor, QHBoxLayout, QPushButton, QSizePolicy, QAbstractItemView) @@ -29,7 +29,6 @@ from calibre.ebooks.metadata.book.base import Metadata from calibre.ebooks.metadata.opf2 import OPF from calibre.gui2 import error_dialog, rating_font, gprefs from calibre.gui2.progress_indicator import SpinAnimator -from calibre.gui2.widgets import BasicSplitter from calibre.gui2.widgets2 import HTMLDisplay from calibre.utils.date import (utcnow, fromordinal, format_date, UNDEFINED_DATE, as_utc) @@ -446,7 +445,7 @@ class IdentifyWidget(QWidget): # {{{ self.top.setWordWrap(True) l.addWidget(self.top) - self.splitter = s = BasicSplitter(self) + self.splitter = s = QSplitter(self) s.setChildrenCollapsible(False) l.addWidget(s, 100) self.results_view = ResultsView(self) diff --git a/src/calibre/gui2/pin_columns.py b/src/calibre/gui2/pin_columns.py index d2f2a11bc8..f7da595886 100644 --- a/src/calibre/gui2/pin_columns.py +++ b/src/calibre/gui2/pin_columns.py @@ -2,11 +2,10 @@ # License: GPLv3 Copyright: 2018, Kovid Goyal -from qt.core import QTableView +from qt.core import QTableView, QSplitter from calibre.gui2.library import DEFAULT_SORT from calibre.gui2 import gprefs -from calibre.gui2.widgets import BasicSplitter class PinTableView(QTableView): @@ -125,10 +124,10 @@ class PinTableView(QTableView): self.apply_state(state) -class PinContainer(BasicSplitter): +class PinContainer(QSplitter): def __init__(self, books_view, parent=None): - BasicSplitter.__init__(self, parent) + super().__init__(parent) self.setChildrenCollapsible(False) self.books_view = books_view self.addWidget(books_view) diff --git a/src/calibre/gui2/preferences/tweaks.py b/src/calibre/gui2/preferences/tweaks.py index 8770e334b6..f260400c8d 100644 --- a/src/calibre/gui2/preferences/tweaks.py +++ b/src/calibre/gui2/preferences/tweaks.py @@ -11,7 +11,7 @@ from calibre import isbytestring, prepare_string_for_xml from calibre.gui2 import error_dialog, info_dialog from calibre.gui2.preferences import AbortCommit, ConfigWidgetBase, test_widget from calibre.gui2.search_box import SearchBox2 -from calibre.gui2.widgets import PythonHighlighter, BasicSplitter +from calibre.gui2.widgets import PythonHighlighter from calibre.utils.config_base import (default_tweaks_raw, exec_tweaks, normalize_tweak, read_custom_tweaks, write_custom_tweaks) @@ -22,7 +22,7 @@ from qt.core import (QAbstractItemView, QAbstractListModel, QApplication, QComboBox, QDialog, QDialogButtonBox, QFont, QGridLayout, QGroupBox, QIcon, QItemSelectionModel, QLabel, QListView, QMenu, QModelIndex, QPlainTextEdit, QPushButton, - QSizePolicy, Qt, QVBoxLayout, QWidget, + QSizePolicy, Qt, QVBoxLayout, QWidget, QSplitter, pyqtSignal) ROOT = QModelIndex() @@ -371,7 +371,7 @@ class ConfigWidget(ConfigWidgetBase): _("Values for the tweaks are shown below. Edit them to change the behavior of calibre." " Your changes will only take effect after a restart of calibre.")) l.addWidget(la), la.setWordWrap(True) - self.splitter = s = BasicSplitter(self) + self.splitter = s = QSplitter(self) s.setChildrenCollapsible(False) l.addWidget(s, 10) diff --git a/src/calibre/gui2/progress_indicator/QProgressIndicator.cpp b/src/calibre/gui2/progress_indicator/QProgressIndicator.cpp index c5735f38a5..c9077bbc8b 100644 --- a/src/calibre/gui2/progress_indicator/QProgressIndicator.cpp +++ b/src/calibre/gui2/progress_indicator/QProgressIndicator.cpp @@ -336,6 +336,29 @@ void CalibreStyle::drawPrimitive(PrimitiveElement element, const QStyleOption * void CalibreStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const { const QStyleOptionViewItem *vopt = NULL; switch(element) { + case CE_Splitter: { + painter->save(); + // draw the separator bar. + painter->setPen(Qt::PenStyle::NoPen); + painter->setBrush(option->palette.color(QPalette::ColorGroup::Normal, QPalette::ColorRole::AlternateBase)); + painter->drawRect(option->rect); + // draw the dots + painter->setBrush(option->palette.color(QPalette::ColorGroup::Normal, QPalette::ColorRole::Shadow)); + bool horizontal = option->state & QStyle::State_Horizontal ? true : false; + static const int dot_count = 4; + int handle_width = horizontal ? option->rect.width() : option->rect.height(); + int dot_size = std::max(1, handle_width); + int start_point = (horizontal ? option->rect.height()/2 : option->rect.width()/2) - (dot_count*dot_size/2); + QRect dot_rect; + for (int i = 0; i < dot_count; i++) { + // Move the rect to leave spaces between the dots + if (horizontal) dot_rect = QRect(0, start_point + i*dot_size*2, dot_size, dot_size); + else dot_rect = QRect(start_point + i*dot_size*2, 0, dot_size, dot_size); + painter->drawEllipse(dot_rect); + } + painter->restore(); + return; + } break; case CE_ItemViewItem: { if (option->state & QStyle::State_HasFocus && (vopt = qstyleoption_cast(option)) && widget && widget->property("highlight_current_item").toBool()) { if (is_color_dark(option->palette.color(QPalette::Window))) { diff --git a/src/calibre/gui2/widgets.py b/src/calibre/gui2/widgets.py index f434131aa8..2daed5bc0e 100644 --- a/src/calibre/gui2/widgets.py +++ b/src/calibre/gui2/widgets.py @@ -980,46 +980,12 @@ class PythonHighlighter(QSyntaxHighlighter): # {{{ # Splitter {{{ -class BasicSplitterHandle(QSplitterHandle): - - def paintEvent(self, event): - rect = event.rect() - painter = QPainter(self) - # draw the separator bar. - painter.setPen(Qt.NoPen) - palette = QApplication.palette() - painter.setBrush(palette.color(QPalette.ColorGroup.Normal, QPalette.ColorRole.AlternateBase)) - painter.drawRect(rect) - # draw the dots - painter.setBrush(palette.color(QPalette.ColorGroup.Normal, QPalette.ColorRole.Shadow)) - horizontal = self.orientation() == Qt.Orientation.Horizontal - dot_count = 4 - cr = self.contentsRect() - handle_width = cr.width() if horizontal else cr.height() - dot_size = int(max(1, handle_width)) - start_point = max(0, int((rect.height()/2 if horizontal else rect.width()/2) - (dot_count*dot_size/2))) - for i in range(dot_count): - # Move the rect to leave spaces between the dots - if horizontal: - dot_rect = QRect(0, start_point + i*dot_size*2, dot_size, dot_size) - else: - dot_rect = QRect(start_point + i*dot_size*2, 0, dot_size, dot_size) - painter.drawEllipse(dot_rect) - painter.end() - - -class BasicSplitter(QSplitter): - - def createHandle(self): - return BasicSplitterHandle(self.orientation(), self) - - -class SplitterHandle(BasicSplitterHandle): +class SplitterHandle(QSplitterHandle): double_clicked = pyqtSignal(object) def __init__(self, orientation, splitter): - BasicSplitterHandle.__init__(self, orientation, splitter) + super().__init__(orientation, splitter) splitter.splitterMoved.connect(self.splitter_moved, type=Qt.ConnectionType.QueuedConnection) self.double_clicked.connect(splitter.double_clicked, @@ -1099,7 +1065,7 @@ class LayoutButton(QToolButton): return QToolButton.mouseReleaseEvent(self, ev) -class Splitter(BasicSplitter): +class Splitter(QSplitter): state_changed = pyqtSignal(object) reapply_sizes = pyqtSignal(object) @@ -1108,7 +1074,7 @@ class Splitter(BasicSplitter): initial_side_size=120, connect_button=True, orientation=Qt.Orientation.Horizontal, side_index=0, parent=None, shortcut=None, hide_handle_on_single_panel=True): - BasicSplitter.__init__(self, parent) + 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: @@ -1222,7 +1188,7 @@ class Splitter(BasicSplitter): def do_resize(self, *args): orig = self.desired_side_size - BasicSplitter.resizeEvent(self, self._resize_ev) + 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: