-
Notifications
You must be signed in to change notification settings - Fork 379
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(ui): show filenames in thumbnail grid (Closes #85) #633
Changes from 6 commits
d527e8e
723dfbd
a93809d
1243257
c54599a
15567a1
05bb5c8
901ec7c
167f859
9251fb2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,15 +25,7 @@ | |
import structlog | ||
from humanfriendly import format_timespan | ||
from PySide6 import QtCore | ||
from PySide6.QtCore import ( | ||
QObject, | ||
QSettings, | ||
Qt, | ||
QThread, | ||
QThreadPool, | ||
QTimer, | ||
Signal, | ||
) | ||
from PySide6.QtCore import QObject, QSettings, Qt, QThread, QThreadPool, QTimer, Signal | ||
from PySide6.QtGui import ( | ||
QAction, | ||
QColor, | ||
|
@@ -264,9 +256,9 @@ def start(self) -> None: | |
|
||
file_menu = QMenu("&File", menu_bar) | ||
edit_menu = QMenu("&Edit", menu_bar) | ||
view_menu = QMenu("&View", menu_bar) | ||
tools_menu = QMenu("&Tools", menu_bar) | ||
macros_menu = QMenu("&Macros", menu_bar) | ||
window_menu = QMenu("&Window", menu_bar) | ||
help_menu = QMenu("&Help", menu_bar) | ||
|
||
# File Menu ============================================================ | ||
|
@@ -322,6 +314,17 @@ def start(self) -> None: | |
close_library_action = QAction("&Close Library", menu_bar) | ||
close_library_action.triggered.connect(self.close_library) | ||
file_menu.addAction(close_library_action) | ||
file_menu.addSeparator() | ||
|
||
open_on_start_action = QAction("Open Library on Start", self) | ||
open_on_start_action.setCheckable(True) | ||
open_on_start_action.setChecked( | ||
bool(self.settings.value(SettingItems.START_LOAD_LAST, defaultValue=True, type=bool)) | ||
) | ||
open_on_start_action.triggered.connect( | ||
lambda checked: self.settings.setValue(SettingItems.START_LOAD_LAST, checked) | ||
) | ||
file_menu.addAction(open_on_start_action) | ||
|
||
# Edit Menu ============================================================ | ||
new_tag_action = QAction("New &Tag", menu_bar) | ||
|
@@ -364,15 +367,42 @@ def start(self) -> None: | |
tag_database_action.triggered.connect(lambda: self.show_tag_database()) | ||
edit_menu.addAction(tag_database_action) | ||
|
||
check_action = QAction("Open library on start", self) | ||
check_action.setCheckable(True) | ||
check_action.setChecked( | ||
# View Menu ============================================================ | ||
open_on_start_action = QAction("Open Library on Start", self) | ||
open_on_start_action.setCheckable(True) | ||
open_on_start_action.setChecked( | ||
bool(self.settings.value(SettingItems.START_LOAD_LAST, defaultValue=True, type=bool)) | ||
) | ||
check_action.triggered.connect( | ||
open_on_start_action.triggered.connect( | ||
lambda checked: self.settings.setValue(SettingItems.START_LOAD_LAST, checked) | ||
) | ||
window_menu.addAction(check_action) | ||
view_menu.addAction(open_on_start_action) | ||
|
||
show_libs_list_action = QAction("Show Recent Libraries", menu_bar) | ||
show_libs_list_action.setCheckable(True) | ||
show_libs_list_action.setChecked( | ||
bool(self.settings.value(SettingItems.WINDOW_SHOW_LIBS, defaultValue=True, type=bool)) | ||
) | ||
show_libs_list_action.triggered.connect( | ||
lambda checked: ( | ||
self.settings.setValue(SettingItems.WINDOW_SHOW_LIBS, checked), | ||
self.toggle_libs_list(checked), | ||
) | ||
) | ||
view_menu.addAction(show_libs_list_action) | ||
|
||
show_filenames_action = QAction("Show Filenames in Grid", menu_bar) | ||
show_filenames_action.setCheckable(True) | ||
show_filenames_action.setChecked( | ||
bool(self.settings.value(SettingItems.SHOW_FILENAMES, defaultValue=True, type=bool)) | ||
) | ||
show_filenames_action.triggered.connect( | ||
lambda checked: ( | ||
self.settings.setValue(SettingItems.SHOW_FILENAMES, checked), | ||
self.toggle_grid_filenames(checked), | ||
) | ||
) | ||
view_menu.addAction(show_filenames_action) | ||
|
||
# Tools Menu =========================================================== | ||
def create_fix_unlinked_entries_modal(): | ||
|
@@ -407,19 +437,6 @@ def create_dupe_files_modal(): | |
) | ||
macros_menu.addAction(self.autofill_action) | ||
|
||
show_libs_list_action = QAction("Show Recent Libraries", menu_bar) | ||
show_libs_list_action.setCheckable(True) | ||
show_libs_list_action.setChecked( | ||
bool(self.settings.value(SettingItems.WINDOW_SHOW_LIBS, defaultValue=True, type=bool)) | ||
) | ||
show_libs_list_action.triggered.connect( | ||
lambda checked: ( | ||
self.settings.setValue(SettingItems.WINDOW_SHOW_LIBS, checked), | ||
self.toggle_libs_list(checked), | ||
) | ||
) | ||
window_menu.addAction(show_libs_list_action) | ||
|
||
def create_folders_tags_modal(): | ||
if not hasattr(self, "folders_modal"): | ||
self.folders_modal = FoldersToTagsModal(self.lib, self) | ||
|
@@ -429,7 +446,7 @@ def create_folders_tags_modal(): | |
folders_to_tags_action.triggered.connect(create_folders_tags_modal) | ||
macros_menu.addAction(folders_to_tags_action) | ||
|
||
# Help Menu ========================================================== | ||
# Help Menu ============================================================ | ||
self.repo_action = QAction("Visit GitHub Repository", menu_bar) | ||
self.repo_action.triggered.connect( | ||
lambda: webbrowser.open("https://github.com/TagStudioDev/TagStudio") | ||
|
@@ -439,9 +456,9 @@ def create_folders_tags_modal(): | |
|
||
menu_bar.addMenu(file_menu) | ||
menu_bar.addMenu(edit_menu) | ||
menu_bar.addMenu(view_menu) | ||
menu_bar.addMenu(tools_menu) | ||
menu_bar.addMenu(macros_menu) | ||
menu_bar.addMenu(window_menu) | ||
menu_bar.addMenu(help_menu) | ||
|
||
self.main_window.searchField.textChanged.connect(self.update_completions_list) | ||
|
@@ -551,6 +568,10 @@ def toggle_libs_list(self, value: bool): | |
self.preview_panel.libs_flow_container.hide() | ||
self.preview_panel.update() | ||
|
||
def toggle_grid_filenames(self, value: bool): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't "toggle" it "sets"; it should probably not be called |
||
for thumb in self.item_thumbs: | ||
thumb.toggle_filename(value) | ||
|
||
def callback_library_needed_check(self, func): | ||
"""Check if loaded library has valid path before executing the button function.""" | ||
if self.lib.library_dir: | ||
|
@@ -829,9 +850,9 @@ def thumb_size_callback(self, index: int): | |
it.thumb_button.setIcon(blank_icon) | ||
it.resize(self.thumb_size, self.thumb_size) | ||
it.thumb_size = (self.thumb_size, self.thumb_size) | ||
it.setMinimumSize(self.thumb_size, self.thumb_size) | ||
it.setMaximumSize(self.thumb_size, self.thumb_size) | ||
it.setFixedSize(self.thumb_size, self.thumb_size) | ||
it.thumb_button.thumb_size = (self.thumb_size, self.thumb_size) | ||
it.toggle_filename(it.show_filename_label) | ||
self.flow_container.layout().setSpacing( | ||
min(self.thumb_size // spacing_divisor, min_spacing) | ||
) | ||
|
@@ -879,7 +900,14 @@ def _init_thumb_grid(self): | |
# TODO - init after library is loaded, it can have different page_size | ||
for grid_idx in range(self.filter.page_size): | ||
item_thumb = ItemThumb( | ||
None, self.lib, self, (self.thumb_size, self.thumb_size), grid_idx | ||
None, | ||
self.lib, | ||
self, | ||
(self.thumb_size, self.thumb_size), | ||
grid_idx, | ||
bool( | ||
self.settings.value(SettingItems.SHOW_FILENAMES, defaultValue=True, type=bool) | ||
), | ||
) | ||
|
||
layout.addWidget(item_thumb) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -110,13 +110,16 @@ class ItemThumb(FlowWidget): | |
"padding-left: 1px;" | ||
) | ||
|
||
filename_style = "font-size:10px;" | ||
|
||
def __init__( | ||
self, | ||
mode: ItemType, | ||
library: Library, | ||
driver: "QtDriver", | ||
thumb_size: tuple[int, int], | ||
grid_idx: int, | ||
show_filename_label: bool = False, | ||
): | ||
super().__init__() | ||
self.grid_idx = grid_idx | ||
|
@@ -125,17 +128,33 @@ def __init__( | |
self.driver = driver | ||
self.item_id: int | None = None | ||
self.thumb_size: tuple[int, int] = thumb_size | ||
self.show_filename_label: bool = show_filename_label | ||
self.label_height = 12 | ||
self.label_spacing = 4 | ||
self.setMinimumSize(*thumb_size) | ||
self.setMaximumSize(*thumb_size) | ||
self.setMouseTracking(True) | ||
check_size = 24 | ||
self.setFixedSize( | ||
thumb_size[0], | ||
thumb_size[1] | ||
+ ((self.label_height + self.label_spacing) if show_filename_label else 0), | ||
) | ||
|
||
self.thumb_container = QWidget() | ||
self.base_layout = QVBoxLayout(self) | ||
self.base_layout.setContentsMargins(0, 0, 0, 0) | ||
self.base_layout.setSpacing(0) | ||
self.setLayout(self.base_layout) | ||
|
||
# +----------+ | ||
# | ARC FAV| Top Right: Favorite & Archived Badges | ||
# | | | ||
# | | | ||
# |EXT #| Lower Left: File Type, Tag Group Icon, or Collation Icon | ||
# +----------+ Lower Right: Collation Count, Video Length, or Word Count | ||
# | ||
# Filename Underneath: (Optional) Filename | ||
|
||
# Thumbnail ============================================================ | ||
|
||
|
@@ -145,9 +164,9 @@ def __init__( | |
# || || | ||
# |*--------*| | ||
# +----------+ | ||
self.base_layout = QVBoxLayout(self) | ||
self.base_layout.setObjectName("baseLayout") | ||
self.base_layout.setContentsMargins(0, 0, 0, 0) | ||
self.thumb_layout = QVBoxLayout(self.thumb_container) | ||
self.thumb_layout.setObjectName("baseLayout") | ||
self.thumb_layout.setContentsMargins(0, 0, 0, 0) | ||
|
||
# +----------+ | ||
# |[~~~~~~~~]| | ||
|
@@ -160,15 +179,15 @@ def __init__( | |
self.top_layout.setContentsMargins(6, 6, 6, 6) | ||
self.top_container = QWidget() | ||
self.top_container.setLayout(self.top_layout) | ||
self.base_layout.addWidget(self.top_container) | ||
self.thumb_layout.addWidget(self.top_container) | ||
|
||
# +----------+ | ||
# |[~~~~~~~~]| | ||
# | ^ | | ||
# | | | | ||
# | v | | ||
# +----------+ | ||
self.base_layout.addStretch(2) | ||
self.thumb_layout.addStretch(2) | ||
|
||
# +----------+ | ||
# |[~~~~~~~~]| | ||
|
@@ -181,19 +200,20 @@ def __init__( | |
self.bottom_layout.setContentsMargins(6, 6, 6, 6) | ||
self.bottom_container = QWidget() | ||
self.bottom_container.setLayout(self.bottom_layout) | ||
self.base_layout.addWidget(self.bottom_container) | ||
self.thumb_layout.addWidget(self.bottom_container) | ||
|
||
self.thumb_button = ThumbButton(self, thumb_size) | ||
self.thumb_button = ThumbButton(self.thumb_container, thumb_size) | ||
self.renderer = ThumbRenderer() | ||
self.renderer.updated.connect( | ||
lambda ts, i, s, ext: ( | ||
lambda ts, i, s, fn, ext: ( | ||
self.update_thumb(ts, image=i), | ||
self.update_size(ts, size=s), | ||
self.set_filename(fn), | ||
self.set_extension(ext), | ||
) | ||
) | ||
self.thumb_button.setFlat(True) | ||
self.thumb_button.setLayout(self.base_layout) | ||
self.thumb_button.setLayout(self.thumb_layout) | ||
self.thumb_button.setContextMenuPolicy(Qt.ContextMenuPolicy.ActionsContextMenu) | ||
|
||
self.opener = FileOpenerHelper("") | ||
|
@@ -285,6 +305,15 @@ def __init__( | |
self.badges[badge_type] = badge | ||
self.cb_layout.addWidget(badge) | ||
|
||
# Filename Label ======================================================= | ||
self.file_label = QLabel(text="Filename") | ||
self.file_label.setStyleSheet(ItemThumb.filename_style) | ||
self.file_label.setMaximumHeight(self.label_height) | ||
self.file_label.setHidden(not show_filename_label) | ||
|
||
self.base_layout.addWidget(self.thumb_container) | ||
self.base_layout.addWidget(self.file_label) | ||
|
||
self.set_mode(mode) | ||
|
||
@property | ||
|
@@ -298,11 +327,11 @@ def is_archived(self): | |
def set_mode(self, mode: ItemType | None) -> None: | ||
if mode is None: | ||
self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, on=True) | ||
self.unsetCursor() | ||
self.thumb_button.unsetCursor() | ||
self.thumb_button.setHidden(True) | ||
elif mode == ItemType.ENTRY and self.mode != ItemType.ENTRY: | ||
self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, on=False) | ||
self.setCursor(Qt.CursorShape.PointingHandCursor) | ||
self.thumb_button.setCursor(Qt.CursorShape.PointingHandCursor) | ||
self.thumb_button.setHidden(False) | ||
self.cb_container.setHidden(False) | ||
# Count Badge depends on file extension (video length, word count) | ||
|
@@ -312,7 +341,7 @@ def set_mode(self, mode: ItemType | None) -> None: | |
self.ext_badge.setHidden(True) | ||
elif mode == ItemType.COLLATION and self.mode != ItemType.COLLATION: | ||
self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, on=False) | ||
self.setCursor(Qt.CursorShape.PointingHandCursor) | ||
self.thumb_button.setCursor(Qt.CursorShape.PointingHandCursor) | ||
self.thumb_button.setHidden(False) | ||
self.cb_container.setHidden(True) | ||
self.ext_badge.setHidden(True) | ||
|
@@ -321,7 +350,7 @@ def set_mode(self, mode: ItemType | None) -> None: | |
self.item_type_badge.setHidden(False) | ||
elif mode == ItemType.TAG_GROUP and self.mode != ItemType.TAG_GROUP: | ||
self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, on=False) | ||
self.setCursor(Qt.CursorShape.PointingHandCursor) | ||
self.thumb_button.setCursor(Qt.CursorShape.PointingHandCursor) | ||
self.thumb_button.setHidden(False) | ||
self.ext_badge.setHidden(True) | ||
self.count_badge.setHidden(False) | ||
|
@@ -366,14 +395,39 @@ def set_count(self, count: str) -> None: | |
self.ext_badge.setHidden(True) | ||
self.count_badge.setHidden(True) | ||
|
||
def set_filename(self, filename: Path | str | None): | ||
self.file_label.setText(str(filename)) | ||
|
||
def toggle_filename(self, value: bool): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here as with the other method; Doesn't toggle and should therefore probably not be called such |
||
"""Toggle the visibility of the filename label. | ||
|
||
Args: | ||
value (bool): Show the filename, true or false. | ||
""" | ||
if value: | ||
self.file_label.setHidden(False) | ||
self.setFixedHeight(self.thumb_size[1] + self.label_height + self.label_spacing) | ||
else: | ||
self.file_label.setHidden(True) | ||
self.setFixedHeight(self.thumb_size[1]) | ||
self.show_filename_label = value | ||
|
||
def update_thumb(self, timestamp: float, image: QPixmap | None = None): | ||
"""Update attributes of a thumbnail element.""" | ||
if timestamp > ItemThumb.update_cutoff: | ||
self.thumb_button.setIcon(image if image else QPixmap()) | ||
|
||
def update_size(self, timestamp: float, size: QSize): | ||
"""Updates attributes of a thumbnail element.""" | ||
if timestamp > ItemThumb.update_cutoff and self.thumb_button.iconSize != size: | ||
"""Updates attributes of a thumbnail element. | ||
|
||
Args: | ||
timestamp (float | None): The UTC timestamp for when this call was | ||
originally dispatched. Used to skip outdated jobs. | ||
|
||
size (QSize): The new thumbnail size to set. | ||
""" | ||
if timestamp > ItemThumb.update_cutoff: | ||
self.thumb_size = size.toTuple() # type: ignore | ||
self.thumb_button.setIconSize(size) | ||
self.thumb_button.setMinimumSize(size) | ||
self.thumb_button.setMaximumSize(size) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "Open Library on Start" option exists twice, once in View and once in File, and (un)checking one of them doesn't update the visual state of the other