mirror of
https://github.com/kovidgoyal/calibre.git
synced 2026-04-03 07:41:58 -04:00
refactoring bookshelf view
This commit is contained in:
parent
49a4d6559c
commit
85bbba8f7c
@ -182,8 +182,14 @@ class LayoutButton(QToolButton):
|
||||
gui.iactions['Preferences'].do_config(initial_plugin=('Interface', 'Search'), close_after_initial=True)
|
||||
ev.accept()
|
||||
return
|
||||
tab_name = {'book_details':'book_details', 'cover_grid':'cover_grid', 'cover_browser':'cover_browser',
|
||||
'tag_browser':'tag_browser', 'quick_view':'quickview'}.get(self.name)
|
||||
tab_name = {
|
||||
'book_details':'book_details',
|
||||
'cover_grid':'cover_grid',
|
||||
'bookshelf_view':'bookshelf_view',
|
||||
'cover_browser':'cover_browser',
|
||||
'tag_browser':'tag_browser',
|
||||
'quick_view':'quickview',
|
||||
}.get(self.name)
|
||||
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)
|
||||
@ -320,7 +326,6 @@ class Visibility:
|
||||
book_list: bool = True
|
||||
cover_browser: bool = False
|
||||
quick_view: bool = False
|
||||
bookshelf: bool = False
|
||||
|
||||
def serialize(self):
|
||||
return asdict(self)
|
||||
@ -359,22 +364,18 @@ class CentralContainer(QWidget):
|
||||
self.cover_browser = Placeholder('cover browser', self)
|
||||
self.book_details = Placeholder('book details', self)
|
||||
self.quick_view = Placeholder('quick view', self)
|
||||
self.bookshelf = Placeholder('bookshelf', 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.bookshelf = QWidget(self)
|
||||
self.bookshelf.setMinimumSize(MIN_SIZE)
|
||||
self.cover_browser.setMinimumSize(MIN_SIZE)
|
||||
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')
|
||||
self.cover_browser_button = LayoutButton('cover_browser', 'cover_flow.png', _('Cover browser'), self, 'Shift+Alt+B')
|
||||
self.quick_view_button = LayoutButton('quick_view', 'quickview.png', _('Quickview'), self)
|
||||
self.bookshelf_button = LayoutButton('bookshelf', 'bookshelf.png', _('Book Shelf'), self, 'Shift+Alt+S')
|
||||
self.setMinimumSize(MIN_SIZE + QSize(200, 100))
|
||||
|
||||
def h(orientation: Qt.Orientation = Qt.Orientation.Vertical):
|
||||
@ -419,7 +420,6 @@ class CentralContainer(QWidget):
|
||||
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.bookshelf_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)
|
||||
@ -475,33 +475,7 @@ class CentralContainer(QWidget):
|
||||
b = self.sender()
|
||||
if b.name == 'quick_view':
|
||||
return
|
||||
# Mutual exclusivity: when bookshelf is shown, hide cover_browser
|
||||
# Bookshelf is a layout panel (like Cover Browser), not an alternate view
|
||||
# So it doesn't affect Cover Grid (which is an alternate view)
|
||||
orig = self.ignore_button_toggles
|
||||
self.ignore_button_toggles = True
|
||||
try:
|
||||
if b.name == 'bookshelf' and b.isChecked():
|
||||
# Hide cover_browser before showing bookshelf
|
||||
if self.is_visible.cover_browser:
|
||||
self.set_visibility_of('cover_browser', False)
|
||||
self.set_visibility_of('bookshelf', True)
|
||||
elif b.name == 'bookshelf' and not b.isChecked():
|
||||
self.set_visibility_of('bookshelf', False)
|
||||
elif b.name == 'cover_browser' and b.isChecked():
|
||||
# Hide bookshelf before showing cover_browser
|
||||
if self.is_visible.bookshelf:
|
||||
self.set_visibility_of('bookshelf', False)
|
||||
self.set_visibility_of('cover_browser', True)
|
||||
elif b.name == 'cover_browser' and not b.isChecked():
|
||||
self.set_visibility_of('cover_browser', False)
|
||||
else:
|
||||
# For other buttons, just set visibility normally
|
||||
self.set_visibility_of(b.name, b.isChecked())
|
||||
finally:
|
||||
self.ignore_button_toggles = orig
|
||||
# Update button text to reflect current state
|
||||
b.update_text()
|
||||
self.set_visibility_of(b.name, b.isChecked())
|
||||
self.relayout()
|
||||
|
||||
def unserialize_settings(self, s):
|
||||
@ -552,6 +526,8 @@ class CentralContainer(QWidget):
|
||||
|
||||
def set_visibility_of(self, which, visible):
|
||||
was_visible = getattr(self.is_visible, which)
|
||||
if visible == was_visible:
|
||||
return
|
||||
setattr(self.is_visible, which, visible)
|
||||
if not was_visible:
|
||||
if self.layout is Layout.wide:
|
||||
@ -586,9 +562,6 @@ class CentralContainer(QWidget):
|
||||
self.book_details_button.setChecked(self.is_visible.book_details)
|
||||
self.cover_browser_button.setChecked(self.is_visible.cover_browser)
|
||||
self.quick_view_button.setChecked(self.is_visible.quick_view)
|
||||
self.bookshelf_button.setChecked(self.is_visible.bookshelf)
|
||||
# Update button text after setting checked state
|
||||
self.bookshelf_button.update_text()
|
||||
finally:
|
||||
self.ignore_button_toggles = orig
|
||||
|
||||
@ -635,7 +608,6 @@ class CentralContainer(QWidget):
|
||||
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)
|
||||
self.bookshelf.setVisible(self.is_visible.bookshelf)
|
||||
if self.layout is Layout.wide:
|
||||
self.right_handle.set_orientation(Qt.Orientation.Vertical)
|
||||
self.do_wide_layout()
|
||||
@ -711,15 +683,14 @@ class CentralContainer(QWidget):
|
||||
h.resize(int(central_width), int(height))
|
||||
available_height -= height
|
||||
|
||||
# Calculate height for cover_browser or bookshelf (they're mutually exclusive)
|
||||
cb_height = max(self.cover_browser.minimumHeight(), int(self.wide_desires.cover_browser_height * self.height()))
|
||||
if not (self.is_visible.cover_browser or self.is_visible.bookshelf) or self.separate_cover_browser:
|
||||
cb_height = 0
|
||||
cb = max(self.cover_browser.minimumHeight(), int(self.wide_desires.cover_browser_height * self.height()))
|
||||
if not self.is_visible.cover_browser or self.separate_cover_browser:
|
||||
cb = 0
|
||||
qv = bl = 0
|
||||
if cb_height >= available_height:
|
||||
cb_height = available_height
|
||||
if cb >= available_height:
|
||||
cb = available_height
|
||||
else:
|
||||
available_height -= cb_height
|
||||
available_height -= cb
|
||||
min_bl_height = 50
|
||||
if available_height <= min_bl_height:
|
||||
bl = available_height
|
||||
@ -730,12 +701,9 @@ class CentralContainer(QWidget):
|
||||
bl = available_height - qv
|
||||
else:
|
||||
bl = available_height
|
||||
# Position cover_browser or bookshelf in the same location
|
||||
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_height))
|
||||
elif self.is_visible.bookshelf:
|
||||
self.bookshelf.setGeometry(int(central_x), 0, int(central_width), int(cb_height))
|
||||
self.top_handle.move(central_x, cb_height)
|
||||
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:
|
||||
self.book_list.setGeometry(int(central_x), int(self.top_handle.y() + self.top_handle.height()), int(central_width), int(bl))
|
||||
self.bottom_handle.move(central_x, self.book_list.y() + self.book_list.height())
|
||||
@ -844,14 +812,11 @@ class CentralContainer(QWidget):
|
||||
central_x = self.left_handle.x() + self.left_handle.width()
|
||||
central_width = self.width() - central_x
|
||||
central_height -= self.right_handle.height()
|
||||
# Calculate height for cover_browser or bookshelf (they're mutually exclusive)
|
||||
cb = min(max(0, central_height - 80), int(self.height() * self.narrow_desires.cover_browser_width)) if (self.is_visible.cover_browser or self.is_visible.bookshelf) else 0
|
||||
cb = min(max(0, central_height - 80), int(self.height() * self.narrow_desires.cover_browser_width)) if self.is_visible.cover_browser else 0
|
||||
if cb and cb < self.cover_browser.minimumHeight():
|
||||
cb = min(self.cover_browser.minimumHeight(), central_height)
|
||||
if self.is_visible.cover_browser:
|
||||
self.cover_browser.setGeometry(central_x, 0, central_width, cb)
|
||||
elif self.is_visible.bookshelf:
|
||||
self.bookshelf.setGeometry(central_x, 0, central_width, cb)
|
||||
self.right_handle.resize(central_width, self.right_handle.height())
|
||||
self.right_handle.move(central_x, cb)
|
||||
central_top = self.right_handle.y() + self.right_handle.height()
|
||||
@ -896,9 +861,8 @@ class CentralContainer(QWidget):
|
||||
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
|
||||
# Calculate width for cover_browser or bookshelf (they're mutually exclusive)
|
||||
cb = max(self.cover_browser.minimumWidth(),
|
||||
int(self.narrow_desires.cover_browser_width * self.width())) if (self.is_visible.cover_browser or self.is_visible.bookshelf) and not self.separate_cover_browser else 0
|
||||
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 > max(0, available_width - min_central_width):
|
||||
width_to_share = max(0, available_width - min_central_width)
|
||||
@ -915,8 +879,6 @@ class CentralContainer(QWidget):
|
||||
self.right_handle.move(tb + central_width + self.left_handle.width(), 0)
|
||||
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(central_height))
|
||||
elif self.is_visible.bookshelf:
|
||||
self.bookshelf.setGeometry(int(self.right_handle.x() + self.right_handle.width()), 0, int(cb), int(central_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()
|
||||
qv = 0
|
||||
|
||||
@ -35,6 +35,7 @@ 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.bookshelf_view import BookshelfView
|
||||
from calibre.gui2.library.views import BooksView, DeviceBooksView
|
||||
from calibre.gui2.notify import get_notifier
|
||||
from calibre.gui2.tag_browser.ui import TagBrowserWidget
|
||||
@ -84,10 +85,6 @@ class LibraryViewMixin: # {{{
|
||||
db.set_book_on_device_func(self.book_on_device)
|
||||
self.library_view.set_database(db)
|
||||
self.library_view.model().set_book_on_device_func(self.book_on_device)
|
||||
# Set model for bookshelf view (it's a layout panel, not an alternate view)
|
||||
if hasattr(self, 'bookshelf_view'):
|
||||
self.bookshelf_view.setModel(self.library_view._model)
|
||||
self.bookshelf_view.set_database(db, stage=0)
|
||||
prefs['library_path'] = self.library_path
|
||||
|
||||
for view in ('library', 'memory', 'card_a', 'card_b'):
|
||||
@ -246,19 +243,32 @@ class StatusBar(QStatusBar): # {{{
|
||||
# }}}
|
||||
|
||||
|
||||
class GridViewButton(LayoutButton): # {{{
|
||||
class AlternateViewsButtons(LayoutButton): # {{{
|
||||
|
||||
def __init__(self, gui):
|
||||
sc = 'Alt+Shift+G'
|
||||
LayoutButton.__init__(self, 'cover_grid', 'grid.png', _('Cover grid'), gui, shortcut=sc)
|
||||
buttons = set()
|
||||
ignore_toggles = False
|
||||
|
||||
def __init__(self, name: str, icon: str, label: str, view_name: str, gui: CentralContainer, shortcut=None, config_key=None):
|
||||
LayoutButton.__init__(self, name, icon, label, gui, shortcut=shortcut)
|
||||
self.set_state_to_show()
|
||||
self.action_toggle = QAction(self.icon(), _('Toggle') + ' ' + self.label, self)
|
||||
gui.addAction(self.action_toggle)
|
||||
gui.keyboard.register_shortcut('grid view toggle' + self.label, str(self.action_toggle.text()),
|
||||
default_keys=(sc,), action=self.action_toggle, group=_('Main window layout'))
|
||||
self.gui = gui
|
||||
self.gui.addAction(self.action_toggle)
|
||||
self.ck = config_key or name
|
||||
self.view_name = view_name
|
||||
if shortcut:
|
||||
self.gui.keyboard.register_shortcut(
|
||||
f'{self.ck} toggle {self.label}',
|
||||
str(self.action_toggle.text()),
|
||||
default_keys=(shortcut,),
|
||||
action=self.action_toggle,
|
||||
group=_('Main window layout'),
|
||||
)
|
||||
self.action_toggle.triggered.connect(self.toggle)
|
||||
self.action_toggle.changed.connect(self.update_shortcut)
|
||||
self.toggled.connect(self.update_state)
|
||||
self.toggled.connect(self.toggle_view)
|
||||
self.buttons.add(self)
|
||||
|
||||
@property
|
||||
def is_visible(self):
|
||||
@ -271,11 +281,54 @@ class GridViewButton(LayoutButton): # {{{
|
||||
self.set_state_to_show()
|
||||
|
||||
def save_state(self):
|
||||
gprefs['grid view visible'] = bool(self.isChecked())
|
||||
gprefs[f'{self.ck} visible'] = bool(self.isChecked())
|
||||
|
||||
def restore_state(self):
|
||||
if gprefs.get('grid view visible', False):
|
||||
if gprefs.get(f'{self.ck} visible', False):
|
||||
self.toggle()
|
||||
|
||||
def toggle_view(self, show):
|
||||
if AlternateViewsButtons.ignore_toggles:
|
||||
return
|
||||
AlternateViewsButtons.ignore_toggles = True
|
||||
for btn in self.buttons:
|
||||
if btn == self:
|
||||
continue
|
||||
if btn.isChecked():
|
||||
btn.update_state(False)
|
||||
self.gui.library_view.alternate_views.show_view(self.view_name if show else None)
|
||||
self.gui.sort_button.setVisible(show)
|
||||
AlternateViewsButtons.ignore_toggles = False
|
||||
# }}}
|
||||
|
||||
|
||||
class GridViewButton(AlternateViewsButtons): # {{{
|
||||
def __init__(self, gui):
|
||||
AlternateViewsButtons.__init__(
|
||||
self,
|
||||
'cover_grid',
|
||||
'grid.png',
|
||||
_('Cover grid'),
|
||||
'grid',
|
||||
gui,
|
||||
shortcut='Alt+Shift+G',
|
||||
config_key='grid view',
|
||||
)
|
||||
# }}}
|
||||
|
||||
|
||||
class BookshelfViewButton(AlternateViewsButtons): # {{{
|
||||
def __init__(self, gui):
|
||||
AlternateViewsButtons.__init__(
|
||||
self,
|
||||
'bookshelf_view',
|
||||
'bookshelf.png',
|
||||
_('Bookshelf view'),
|
||||
'bookshelf',
|
||||
gui,
|
||||
shortcut='Alt+Shift+B',
|
||||
config_key='bookshelf view',
|
||||
)
|
||||
# }}}
|
||||
|
||||
|
||||
@ -535,11 +588,16 @@ class LayoutMixin: # {{{
|
||||
for x in self.button_order:
|
||||
if x == 'gv':
|
||||
button = self.grid_view_button
|
||||
elif x == 'bs':
|
||||
button = self.bookshelf_view_button
|
||||
elif x == 'sb':
|
||||
button = self.search_bar_button
|
||||
else:
|
||||
button = self.layout_container.button_for({
|
||||
'tb': 'tag_browser', 'bd': 'book_details', 'cb': 'cover_browser', 'qv': 'quick_view', 'bs': 'bookshelf'
|
||||
'tb': 'tag_browser',
|
||||
'bd': 'book_details',
|
||||
'cb': 'cover_browser',
|
||||
'qv': 'quick_view',
|
||||
}[x])
|
||||
self.layout_buttons.append(button)
|
||||
button.setVisible(gprefs['show_layout_buttons'])
|
||||
@ -568,15 +626,9 @@ class LayoutMixin: # {{{
|
||||
self.grid_view = GridView(self)
|
||||
self.grid_view.setObjectName('grid_view')
|
||||
av.add_view('grid', self.grid_view)
|
||||
from calibre.gui2.library.bookshelf_view import BookshelfView
|
||||
self.bookshelf_view = BookshelfView(self)
|
||||
self.bookshelf_view.setObjectName('bookshelf_view')
|
||||
# Bookshelf is a layout panel (like Cover Browser), not an alternate view
|
||||
# Set it in the layout container's bookshelf widget
|
||||
self.layout_container.set_widget('bookshelf', self.bookshelf_view)
|
||||
# Set the model for bookshelf view (will be updated when database is set)
|
||||
if hasattr(self.library_view, '_model'):
|
||||
self.bookshelf_view.setModel(self.library_view._model)
|
||||
av.add_view('bookshelf', self.bookshelf_view)
|
||||
self.tb_widget = TagBrowserWidget(self)
|
||||
self.memory_view = DeviceBooksView(self)
|
||||
self.stack.addWidget(self.memory_view)
|
||||
@ -599,8 +651,8 @@ class LayoutMixin: # {{{
|
||||
self.tb_widget.set_pane_is_visible, Qt.ConnectionType.QueuedConnection)
|
||||
self.status_bar = StatusBar(self)
|
||||
self.grid_view_button = GridViewButton(self)
|
||||
self.bookshelf_view_button = BookshelfViewButton(self)
|
||||
self.search_bar_button = SearchBarButton(self)
|
||||
self.grid_view_button.toggled.connect(self.toggle_grid_view)
|
||||
self.search_bar_button.toggled.connect(self.toggle_search_bar)
|
||||
|
||||
self.layout_button = b = QToolButton(self)
|
||||
@ -718,16 +770,6 @@ class LayoutMixin: # {{{
|
||||
tb.item_search.lineEdit().setText(field + ':=' + value)
|
||||
tb.do_find()
|
||||
|
||||
def toggle_grid_view(self, show):
|
||||
self.library_view.alternate_views.show_view('grid' if show else None)
|
||||
self.sort_button.setVisible(show)
|
||||
# Mutual exclusivity: when grid view is shown, hide bookshelf
|
||||
if show:
|
||||
bookshelf_button = self.layout_container.button_for('bookshelf')
|
||||
if bookshelf_button and bookshelf_button.isChecked():
|
||||
bookshelf_button.setChecked(False)
|
||||
self.layout_container.set_visibility_of('bookshelf', False)
|
||||
|
||||
def toggle_search_bar(self, show):
|
||||
self.search_bar.setVisible(show)
|
||||
if show:
|
||||
@ -805,6 +847,7 @@ class LayoutMixin: # {{{
|
||||
getattr(self, x+'_view').save_state()
|
||||
self.layout_container.write_settings()
|
||||
self.grid_view_button.save_state()
|
||||
self.bookshelf_view_button.save_state()
|
||||
self.search_bar_button.save_state()
|
||||
|
||||
def read_layout_settings(self):
|
||||
@ -813,6 +856,7 @@ class LayoutMixin: # {{{
|
||||
self.book_details.change_layout(self.layout_container.is_wide)
|
||||
self.place_layout_buttons()
|
||||
self.grid_view_button.restore_state()
|
||||
self.bookshelf_view_button.restore_state()
|
||||
self.search_bar_button.restore_state()
|
||||
|
||||
def update_status_bar(self, *args):
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1266,6 +1266,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
||||
_('Running database shutdown plugins. This could take a few seconds...'))
|
||||
|
||||
self.grid_view.shutdown()
|
||||
self.bookshelf_view.shutdown()
|
||||
db = None
|
||||
try:
|
||||
db = self.library_view.model().db
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user