This commit is contained in:
Kovid Goyal 2023-12-20 18:50:15 +05:30
commit 7adb5eba8c
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
5 changed files with 86 additions and 27 deletions

View File

@ -425,6 +425,7 @@ def create_defs():
defs['allow_keyboard_search_in_library_views'] = True defs['allow_keyboard_search_in_library_views'] = True
defs['show_links_in_tag_browser'] = False defs['show_links_in_tag_browser'] = False
defs['show_notes_in_tag_browser'] = False defs['show_notes_in_tag_browser'] = False
defs['icons_on_right_in_tag_browser'] = True
def migrate_tweak(tweak_name, pref_name): def migrate_tweak(tweak_name, pref_name):
# If the tweak has been changed then leave the tweak in the file so # If the tweak has been changed then leave the tweak in the file so

View File

@ -648,6 +648,7 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
r('show_avg_rating', config) r('show_avg_rating', config)
r('show_links_in_tag_browser', gprefs) r('show_links_in_tag_browser', gprefs)
r('show_notes_in_tag_browser', gprefs) r('show_notes_in_tag_browser', gprefs)
r('icons_on_right_in_tag_browser', gprefs)
r('disable_animations', config) r('disable_animations', config)
r('systray_icon', config, restart_required=True) r('systray_icon', config, restart_required=True)
r('show_splash_screen', gprefs) r('show_splash_screen', gprefs)

View File

@ -1370,6 +1370,21 @@ box will cause these empty categories to be hidden.&lt;/p&gt;</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1">
<widget class="QCheckBox" name="opt_icons_on_right_in_tag_browser">
<property name="text">
<string>Place icons on the &amp;right, in columns</string>
</property>
<property name="toolTip">
<string>If checked the notes and links icons will be placed at the right, after
the count and in columns. If unchecked, the icons will be placed immediately after the text,
to the left of the count and not in columns.</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
</item>
<item row="2" column="2"> <item row="2" column="2">
<widget class="QCheckBox" name="opt_tag_browser_always_autocollapse"> <widget class="QCheckBox" name="opt_tag_browser_always_autocollapse">
<property name="toolTip"> <property name="toolTip">

View File

@ -782,10 +782,16 @@ class TagBrowserWidget(QFrame): # {{{
l.m.aboutToShow.connect(self.about_to_show_configure_menu) l.m.aboutToShow.connect(self.about_to_show_configure_menu)
# Show/hide counts # Show/hide counts
l.m.show_counts_action = ac = l.m.addAction('counts') l.m.show_counts_action = ac = l.m.addAction('counts')
parent.keyboard.register_shortcut('tag browser toggle counts',
_('Toggle counts'), default_keys=(),
action=ac, group=_('Tag browser'))
ac.triggered.connect(self.toggle_counts) ac.triggered.connect(self.toggle_counts)
# Show/hide average rating # Show/hide average rating
l.m.show_avg_rating_action = ac = l.m.addAction(QIcon.ic('rating.png'), 'avg rating') l.m.show_avg_rating_action = ac = l.m.addAction(QIcon.ic('rating.png'), 'avg rating')
ac.triggered.connect(self.toggle_avg_rating) ac.triggered.connect(self.toggle_avg_rating)
parent.keyboard.register_shortcut('tag browser toggle average ratings',
_('Toggle average ratings'), default_keys=(),
action=ac, group=_('Tag browser'))
# Show/hide notes icon # Show/hide notes icon
l.m.show_notes_icon_action = ac = l.m.addAction(QIcon.ic('notes.png'), 'notes icon') l.m.show_notes_icon_action = ac = l.m.addAction(QIcon.ic('notes.png'), 'notes icon')
ac.triggered.connect(self.toggle_notes_icon) ac.triggered.connect(self.toggle_notes_icon)

View File

@ -87,50 +87,86 @@ class TagDelegate(QStyledItemDelegate): # {{{
def draw_text(self, style, painter, option, widget, index, item): def draw_text(self, style, painter, option, widget, index, item):
tr = style.subElementRect(QStyle.SubElement.SE_ItemViewItemText, option, widget) tr = style.subElementRect(QStyle.SubElement.SE_ItemViewItemText, option, widget)
text = index.data(Qt.ItemDataRole.DisplayRole) text = index.data(Qt.ItemDataRole.DisplayRole)
flags = Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft | Qt.TextFlag.TextSingleLine
lr = QRect(tr)
lr.setRight(lr.right() * 2)
text_rec = painter.boundingRect(lr, flags, text)
hover = option.state & QStyle.StateFlag.State_MouseOver hover = option.state & QStyle.StateFlag.State_MouseOver
is_search = (True if item.type == TagTreeItem.TAG and is_search = (True if item.type == TagTreeItem.TAG and
item.tag.category == 'search' else False) item.tag.category == 'search' else False)
show_notes = gprefs['show_notes_in_tag_browser'] def render_count():
show_links = gprefs['show_links_in_tag_browser'] if not is_search and (hover or gprefs['tag_browser_show_counts']):
count = str(index.data(COUNT_ROLE))
width = painter.fontMetrics().boundingRect(count).width()
r = QRect(tr)
r.setRight(r.right() - 1), r.setLeft(r.right() - width - 4)
self.paint_text(painter, r, Qt.AlignmentFlag.AlignCenter | Qt.TextFlag.TextSingleLine, count, hover, option)
tr.setRight(r.left() - 1)
else:
tr.setRight(tr.right() - 1)
if item.type == TagTreeItem.TAG: if item.type == TagTreeItem.TAG:
category = item.tag.category category = item.tag.category
name = item.tag.original_name name = item.tag.original_name
tv = self.tags_view tv = self.tags_view
m = tv._model m = tv._model
if show_links and m.category_has_links(category): positions = {'links': (-1, -1), 'notes': (-1, -1)}
# The icons fits in a rectangle height/2 + 4 x height/2 + 4. This
# ensures they are a 'pleasant' size compared to the text.
icon_width = int(tr.height()/2) + 4
def render_link_icon():
icon = self.links_icon if m.item_has_link(category, name) else self.blank_icon icon = self.links_icon if m.item_has_link(category, name) else self.blank_icon
width = int(tr.height()/2)
r = QRect(tr) r = QRect(tr)
r.setRight(r.right() - 1), r.setLeft(r.right() - width - 4) r.setRight(r.right() - 1)
tv.category_button_positions[category]['links'] = (r.left(), r.left()+r.width()) r.setLeft(r.right() - icon_width)
positions['links'] = (r.left(), r.left()+r.width())
icon.paint(painter, r, option.decorationAlignment, QIcon.Mode.Normal, QIcon.State.On) icon.paint(painter, r, option.decorationAlignment, QIcon.Mode.Normal, QIcon.State.On)
tr.setRight(r.left() - 1) tr.setRight(r.left() - 1)
if show_notes and m.category_has_notes(category): def render_note_icon():
icon = self.notes_icon if m.item_has_note(category, name) else self.blank_icon icon = self.notes_icon if m.item_has_note(category, name) else self.blank_icon
width = int(tr.height()/2)
r = QRect(tr) r = QRect(tr)
r.setRight(r.right() - 1), r.setLeft(r.right() - width - 4) r.setRight(r.right() - 1)
tv.category_button_positions[category]['notes'] = (r.left(), r.left()+r.width()) r.setLeft(r.right() - icon_width)
positions['notes'] = (r.left(), r.left()+r.width())
icon.paint(painter, r, option.decorationAlignment, QIcon.Mode.Normal, QIcon.State.On) icon.paint(painter, r, option.decorationAlignment, QIcon.Mode.Normal, QIcon.State.On)
tr.setRight(r.left() - 1) tr.setRight(r.left() - 1)
if not is_search and (hover or gprefs['tag_browser_show_counts']):
count = str(index.data(COUNT_ROLE)) if gprefs['icons_on_right_in_tag_browser']:
width = painter.fontMetrics().boundingRect(count).width() # Icons go far right, in columns after the counts
r = QRect(tr) show_note_icon = gprefs['show_notes_in_tag_browser'] and m.category_has_notes(category)
r.setRight(r.right() - 1), r.setLeft(r.right() - width - 4) show_link_icon = gprefs['show_links_in_tag_browser'] and m.category_has_links(category)
self.paint_text(painter, r, Qt.AlignmentFlag.AlignCenter | Qt.TextFlag.TextSingleLine, count, hover, option) if show_link_icon:
tr.setRight(r.left() - 1) render_link_icon()
if show_note_icon:
render_note_icon()
render_count()
else:
# Icons go after the text to the left of the counts, not in columns
show_note_icon = gprefs['show_notes_in_tag_browser'] and m.item_has_note(category, name)
show_link_icon = gprefs['show_links_in_tag_browser'] and m.item_has_link(category, name)
render_count()
# The link icon has a margin of 1 px on each side. Account for
# this when computing the width of the icons. If you change the
# order of the icons then you must change this calculation
w = (int(show_link_icon) * (icon_width + 2)) + (int(show_note_icon) * icon_width)
# Leave a 5 px margin between the text and the icon.
tr.setWidth(min(tr.width(), text_rec.width() + 5 + w))
if show_link_icon:
render_link_icon()
if show_note_icon:
render_note_icon()
tv.category_button_positions[category][name] = positions
else: else:
tr.setRight(tr.right() - 1) render_count()
is_rating = item.type == TagTreeItem.TAG and not self.rating_pat.sub('', text) is_rating = item.type == TagTreeItem.TAG and not self.rating_pat.sub('', text)
if is_rating: if is_rating:
painter.setFont(self.rating_font) painter.setFont(self.rating_font)
flags = Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft | Qt.TextFlag.TextSingleLine if text_rec.width() > tr.width():
lr = QRect(tr)
lr.setRight(lr.right() * 2)
br = painter.boundingRect(lr, flags, text)
if br.width() > tr.width():
g = QLinearGradient(QPointF(tr.topLeft()), QPointF(tr.topRight())) g = QLinearGradient(QPointF(tr.topLeft()), QPointF(tr.topRight()))
c = option.palette.color(QPalette.ColorRole.WindowText) c = option.palette.color(QPalette.ColorRole.WindowText)
g.setColorAt(0, c), g.setColorAt(0.8, c) g.setColorAt(0, c), g.setColorAt(0.8, c)
@ -522,8 +558,8 @@ class TagsView(QTreeView): # {{{
joiner = ' and ' if self.match_all else ' or ' joiner = ' and ' if self.match_all else ' or '
return joiner.join(tokens) return joiner.join(tokens)
def click_in_button_range(self, val, category, kind): def click_in_button_range(self, val, category, item_name, kind):
range_tuple = self.category_button_positions[category].get(kind) range_tuple = self.category_button_positions[category].get(item_name, {}).get(kind)
return range_tuple and range_tuple[0] <= val <= range_tuple[1] return range_tuple and range_tuple[0] <= val <= range_tuple[1]
def toggle_current_index(self): def toggle_current_index(self):
@ -540,13 +576,13 @@ class TagsView(QTreeView): # {{{
category = t.tag.category category = t.tag.category
orig_name = t.tag.original_name orig_name = t.tag.original_name
x = self.mouse_clicked_point.x() x = self.mouse_clicked_point.x()
if self.click_in_button_range(x, category, 'notes'): if self.click_in_button_range(x, category, orig_name, 'notes'):
from calibre.gui2.dialogs.show_category_note import ShowNoteDialog from calibre.gui2.dialogs.show_category_note import ShowNoteDialog
item_id = db.get_item_id(category, orig_name) item_id = db.get_item_id(category, orig_name)
if db.notes_for(category, item_id): if db.notes_for(category, item_id):
ShowNoteDialog(category, item_id, db, parent=self).show() ShowNoteDialog(category, item_id, db, parent=self).show()
return return
if self.click_in_button_range(x, category, 'links'): if self.click_in_button_range(x, category, orig_name, 'links'):
link = db.get_link_map(category).get(orig_name) link = db.get_link_map(category).get(orig_name)
if link: if link:
safe_open_url(link) safe_open_url(link)