mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
Make the layout menu nicer
This commit is contained in:
parent
4cebbfd766
commit
b22fdd6d08
@ -12,7 +12,7 @@ from PyQt5.Qt import (Qt, QApplication, QStackedWidget, QMenu, QTimer,
|
||||
QVBoxLayout, QWidget, QSplitter, QToolButton, QIcon, QPainter, QStyleOption)
|
||||
|
||||
from calibre.utils.config import prefs
|
||||
from calibre.utils.icu import sort_key, primary_sort_key
|
||||
from calibre.utils.icu import sort_key
|
||||
from calibre.constants import (isosx, __appname__, preferred_encoding,
|
||||
get_version)
|
||||
from calibre.gui2 import config, is_widescreen, gprefs, error_dialog, open_url
|
||||
@ -22,6 +22,7 @@ from calibre.gui2.widgets import Splitter, LayoutButton
|
||||
from calibre.gui2.tag_browser.ui import TagBrowserWidget
|
||||
from calibre.gui2.book_details import BookDetails
|
||||
from calibre.gui2.notify import get_notifier
|
||||
from calibre.gui2.layout_menu import LayoutMenu
|
||||
|
||||
_keep_refs = []
|
||||
|
||||
@ -591,7 +592,7 @@ class LayoutMixin(object): # {{{
|
||||
b.setPopupMode(b.InstantPopup)
|
||||
b.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
||||
b.setText(_('Layout')), b.setIcon(QIcon(I('config.png')))
|
||||
b.setMenu(QMenu()), b.menu().aboutToShow.connect(self.populate_layout_menu)
|
||||
b.setMenu(LayoutMenu(self))
|
||||
b.setToolTip(_(
|
||||
'Show and hide various parts of the calibre main window'))
|
||||
self.status_bar.addPermanentWidget(b)
|
||||
@ -599,13 +600,6 @@ class LayoutMixin(object): # {{{
|
||||
self.setStatusBar(self.status_bar)
|
||||
self.status_bar.update_label.linkActivated.connect(self.update_link_clicked)
|
||||
|
||||
def populate_layout_menu(self):
|
||||
m = self.layout_button.menu()
|
||||
m.clear()
|
||||
buttons = sorted(self.layout_buttons, key=lambda b:primary_sort_key(b.label))
|
||||
for b in buttons:
|
||||
m.addAction(b.icon(), b.text(), b.click)
|
||||
|
||||
def finalize_layout(self):
|
||||
self.status_bar.initialize(self.system_tray_icon)
|
||||
self.book_details.show_book_info.connect(self.iactions['Show Book Details'].show_book_info)
|
||||
|
148
src/calibre/gui2/layout_menu.py
Normal file
148
src/calibre/gui2/layout_menu.py
Normal file
@ -0,0 +1,148 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=utf-8
|
||||
# License: GPLv3 Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
from PyQt5.Qt import (
|
||||
QFontMetrics, QHBoxLayout, QIcon, QMenu, QPainter, QPushButton, QSize,
|
||||
QSizePolicy, Qt, QWidget, QStyleOption, QStyle)
|
||||
|
||||
from calibre.utils.icu import primary_sort_key
|
||||
|
||||
ICON_SZ = 64
|
||||
|
||||
|
||||
class LayoutItem(QWidget):
|
||||
|
||||
def __init__(self, button, parent=None):
|
||||
QWidget.__init__(self, parent)
|
||||
self.mouse_over = False
|
||||
self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
||||
self.button = button
|
||||
self.text = button.label
|
||||
self.setCursor(Qt.PointingHandCursor)
|
||||
self.fm = QFontMetrics(self.font())
|
||||
self._bi = self._di = None
|
||||
|
||||
@property
|
||||
def bright_icon(self):
|
||||
if self._bi is None:
|
||||
self._bi = self.button.icon().pixmap(ICON_SZ, ICON_SZ)
|
||||
return self._bi
|
||||
|
||||
@property
|
||||
def dull_icon(self):
|
||||
if self._di is None:
|
||||
self._di = self.button.icon().pixmap(ICON_SZ, ICON_SZ, mode=QIcon.Disabled)
|
||||
return self._di
|
||||
|
||||
def event(self, ev):
|
||||
m = None
|
||||
et = ev.type()
|
||||
if et == ev.Enter:
|
||||
m = True
|
||||
elif et == ev.Leave:
|
||||
m = False
|
||||
if m is not None and m != self.mouse_over:
|
||||
self.mouse_over = m
|
||||
self.update()
|
||||
return QWidget.event(self, ev)
|
||||
|
||||
def sizeHint(self):
|
||||
br = self.fm.boundingRect(self.text)
|
||||
w = max(br.width(), ICON_SZ) + 10
|
||||
h = 2 * self.fm.lineSpacing() + ICON_SZ + 8
|
||||
return QSize(w, h)
|
||||
|
||||
def paintEvent(self, ev):
|
||||
shown = self.button.isChecked()
|
||||
ls = self.fm.lineSpacing()
|
||||
painter = QPainter(self)
|
||||
if self.mouse_over:
|
||||
tool = QStyleOption()
|
||||
tool.rect = self.rect()
|
||||
tool.state = QStyle.State_Raised | QStyle.State_Active | QStyle.State_MouseOver
|
||||
s = self.style()
|
||||
s.drawPrimitive(QStyle.PE_PanelButtonTool, tool, painter, self)
|
||||
painter.drawText(
|
||||
0, 0,
|
||||
self.width(),
|
||||
ls, Qt.AlignCenter | Qt.TextSingleLine, self.text)
|
||||
text = _('Hide') if shown else _('Show')
|
||||
f = self.font()
|
||||
f.setBold(True)
|
||||
painter.setFont(f)
|
||||
painter.drawText(
|
||||
0, self.height() - ls,
|
||||
self.width(),
|
||||
ls, Qt.AlignCenter | Qt.TextSingleLine, text)
|
||||
x = (self.width() - ICON_SZ) // 2
|
||||
y = ls + (self.height() - ICON_SZ - 2 * ls) // 2
|
||||
pmap = self.bright_icon if shown else self.dull_icon
|
||||
painter.drawPixmap(x, y, pmap)
|
||||
painter.end()
|
||||
|
||||
|
||||
class LayoutMenu(QMenu):
|
||||
|
||||
def __init__(self, parent=None):
|
||||
QMenu.__init__(self, parent)
|
||||
self.l = l = QHBoxLayout(self)
|
||||
l.setSpacing(20)
|
||||
self.items = []
|
||||
if parent is None:
|
||||
buttons = [
|
||||
QPushButton(QIcon(I(i + '.png')), i, self)
|
||||
for i in 'search tags cover_flow grid book'.split()]
|
||||
for b in buttons:
|
||||
b.setVisible(False), b.setCheckable(True), b.setChecked(b.text() in 'tags grid')
|
||||
b.label = b.text().capitalize()
|
||||
else:
|
||||
buttons = sorted(
|
||||
parent.layout_buttons, key=lambda b: primary_sort_key(b.label))
|
||||
for b in buttons:
|
||||
self.items.append(LayoutItem(b, self))
|
||||
l.addWidget(self.items[-1])
|
||||
self.current_item = None
|
||||
|
||||
def sizeHint(self):
|
||||
return QWidget.sizeHint(self)
|
||||
|
||||
def paintEvent(self, ev):
|
||||
return QWidget.paintEvent(self, ev)
|
||||
|
||||
def item_for_ev(self, ev):
|
||||
for item in self.items:
|
||||
if item.geometry().contains(ev.pos()):
|
||||
return item
|
||||
|
||||
def mousePressEvent(self, ev):
|
||||
if ev.button() != Qt.LeftButton:
|
||||
ev.ignore()
|
||||
return
|
||||
if (ev.pos().isNull() and not ev.screenPos().isNull()) or not self.rect().contains(ev.pos()):
|
||||
self.hide()
|
||||
self.current_item = self.item_for_ev(ev)
|
||||
if self.current_item is not None:
|
||||
ev.accept()
|
||||
else:
|
||||
ev.ignore()
|
||||
|
||||
def mouseReleaseEvent(self, ev):
|
||||
if ev.button() != Qt.LeftButton:
|
||||
ev.ignore()
|
||||
return
|
||||
item = self.item_for_ev(ev)
|
||||
if item is not None and item is self.current_item:
|
||||
ev.accept()
|
||||
self.hide()
|
||||
item.button.click()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from calibre.gui2 import Application
|
||||
app = Application([])
|
||||
w = LayoutMenu()
|
||||
w.show()
|
||||
w.exec_()
|
Loading…
x
Reference in New Issue
Block a user