diff --git a/docs/widgets/(Widget)-Media.md b/docs/widgets/(Widget)-Media.md index 35ddad4c4..33c629b4f 100644 --- a/docs/widgets/(Widget)-Media.md +++ b/docs/widgets/(Widget)-Media.md @@ -7,6 +7,7 @@ | `separator` | string | `" - "` | The dynamic separator. Automatically stripped. More below. | | `class_name` | string | `""` | The custom CSS class name for the widget. | | `label_shadow` | boolean | false | Whether to show a shadow effect on the label. | +| `size_mode` | string | `"auto"` | The size mode for the widget. Can be `auto` or `max`. | | `max_field_size` | dict | | Maximum field sizes for labels. | | `max_field_size.label` | integer | 20 | Maximum size for the main label. | | `max_field_size.label_alt` | integer | 30 | Maximum size for the alternative label. | @@ -49,6 +50,7 @@ media: on_left: "toggle_label" on_middle: "do_nothing" on_right: "do_nothing" + size_mode: "auto" max_field_size: label: 20 label_alt: 30 @@ -179,6 +181,7 @@ media: - **class_name:** The CSS class name for the widget. This allows you to apply custom styles to the widget. (optional) - **hide_empty:** Whether to hide the widget when there is no media information available. - **callbacks:** A dictionary specifying the callbacks for mouse events. The keys are `on_left`, `on_middle`, `on_right`. +- **size_mode:** The size mode for the widget. Can be `auto` or `max`. If set to `auto`, the widget will resize itself to fit the label. If set to `max`, the widget will resize itself to the maximum size set by `max_field_size`. - **max_field_size:** Maximum field sizes for the labels. - **label:** Maximum size for the main label. If the label exceeds this size, it will be truncated. - **label_alt:** Maximum size for the alternative label. If the label exceeds this size, it will be truncated. diff --git a/src/core/utils/utilities.py b/src/core/utils/utilities.py index 86f4c5b58..ae9d47476 100644 --- a/src/core/utils/utilities.py +++ b/src/core/utils/utilities.py @@ -9,7 +9,7 @@ from functools import lru_cache from pathlib import Path from threading import Lock -from typing import Any, TypeGuard, cast, override +from typing import Any, Literal, TypeGuard, cast, override import yaml from pydantic import ValidationError @@ -911,6 +911,7 @@ def __init__( self, parent: QWidget | None = None, text: str = "", + size_mode: Literal["auto", "max"] = "auto", max_width: int | None = None, options: dict[str, Any] | None = None, ): @@ -937,6 +938,7 @@ def __init__( self._bounce_direction = -1 self._offset = 0 self._scrolling_needed = False + self._size_mode = size_mode # Store the original, un-padded/un-separated text self._raw_text = text @@ -1013,7 +1015,10 @@ def _build_text_and_metrics(self): self._text_bb_width = self._font_metrics.boundingRect(self._text).width() self._text_y = (self.height() + self._font_metrics.ascent() - self._font_metrics.descent() + 1) // 2 - if self._max_width: + if self._size_mode == "max": + self.setMaximumWidth(self._font_metrics.averageCharWidth() * self._max_width) + self.setMinimumWidth(self._font_metrics.averageCharWidth() * self._max_width) + elif self._size_mode == "auto" and self._max_width: self.setMaximumWidth(self._font_metrics.averageCharWidth() * self._max_width) @pyqtSlot() diff --git a/src/core/validation/widgets/yasb/media.py b/src/core/validation/widgets/yasb/media.py index 44900272a..93bdbfbdc 100644 --- a/src/core/validation/widgets/yasb/media.py +++ b/src/core/validation/widgets/yasb/media.py @@ -81,6 +81,7 @@ class MediaWidgetConfig(CustomBaseModel): container_padding: PaddingConfig = PaddingConfig() scrolling_label: ScrollingLabelConfig = ScrollingLabelConfig() progress_bar: ProgressBarConfig = ProgressBarConfig() + size_mode: Literal["auto", "max"] = "auto" max_field_size: MaxFieldSizeConfig = MaxFieldSizeConfig() show_thumbnail: bool = True controls_only: bool = False diff --git a/src/core/widgets/yasb/media.py b/src/core/widgets/yasb/media.py index 371f359d9..8e813e607 100644 --- a/src/core/widgets/yasb/media.py +++ b/src/core/widgets/yasb/media.py @@ -10,24 +10,10 @@ from PyQt6 import QtCore from PyQt6.QtCore import QEvent, QObject, Qt, QTimer, pyqtSlot from PyQt6.QtGui import QMouseEvent, QPixmap, QWheelEvent -from PyQt6.QtWidgets import ( - QFrame, - QGridLayout, - QHBoxLayout, - QLabel, - QProgressBar, - QSizePolicy, - QSlider, - QVBoxLayout, -) +from PyQt6.QtWidgets import QFrame, QGridLayout, QHBoxLayout, QLabel, QProgressBar, QSizePolicy, QSlider, QVBoxLayout from qasync import asyncSlot # type: ignore -from core.utils.utilities import ( - PopupWidget, - ScrollingLabel, - add_shadow, - refresh_widget_style, -) +from core.utils.utilities import PopupWidget, ScrollingLabel, add_shadow, refresh_widget_style from core.utils.widgets.animation_manager import AnimationManager from core.utils.widgets.media.aumid_process import get_process_name_for_aumid from core.utils.widgets.media.media import MediaSession, SessionState, WindowsMedia @@ -115,6 +101,7 @@ def __init__(self, config: MediaWidgetConfig): if self.config.scrolling_label.enabled: self._label = ScrollingLabel( self, + size_mode=self.config.size_mode, max_width=self.config.max_field_size.label, options=self.config.scrolling_label.model_dump(), ) @@ -852,7 +839,10 @@ def _on_media_properties_changed(self): # Only update the thumbnail if the title/artist changes or if we did a toggle (resize) try: if self.current_session and self.current_session.title and self.current_session.thumbnail: - thumbnail = self._crop_thumbnail(self.current_session.thumbnail, active_label.sizeHint().width()) + if self.config.size_mode == "max": + thumbnail = self._crop_thumbnail(self.current_session.thumbnail, active_label.maximumWidth()) + else: + thumbnail = self._crop_thumbnail(self.current_session.thumbnail, active_label.sizeHint().width()) pixmap = QPixmap.fromImage(ImageQt(thumbnail)) self._thumbnail_label.setPixmap(pixmap)