diff --git a/src/interface/dialogs/image.py b/src/interface/dialogs/image.py index 3edb46b..f921958 100644 --- a/src/interface/dialogs/image.py +++ b/src/interface/dialogs/image.py @@ -163,8 +163,20 @@ class Image(QObject): self.overlay_label.adjustSize() self.overlay_label.raise_() - x = parent.width() - self.overlay_label.width() - int(state.image_offset) - y = parent.height() - self.overlay_label.height() - int(state.image_offset) + pos = state.image_position + off = int(state.image_offset) + w = self.overlay_label.width() + h = self.overlay_label.height() + if pos == "top-left": + x, y = off, off + elif pos == "top-right": + x, y = parent.width() - w - off, off + elif pos == "bottom-left": + x, y = off, parent.height() - h - off + elif pos == "center": + x, y = (parent.width() - w) // 2, (parent.height() - h) // 2 + else: # bottom-right (default) + x, y = parent.width() - w - off, parent.height() - h - off self.opacity_effect.setOpacity(state.image_opacity / 100) diff --git a/src/interface/dialogs/settings.py b/src/interface/dialogs/settings.py index e815357..e71d1a4 100644 --- a/src/interface/dialogs/settings.py +++ b/src/interface/dialogs/settings.py @@ -13,8 +13,7 @@ from PySide6.QtWidgets import ( QDialog, QLabel, QHBoxLayout, - QSpinBox, - QCheckBox, + QSpinBox, QSlider, QCheckBox, QFileDialog, QComboBox, ) @@ -29,6 +28,8 @@ def settings_dialog(self): temp_image_offset = state.image_offset temp_image_opacity = state.image_opacity temp_image_enabled = state.image_enabled + temp_image_as_wallpaper = state.image_as_wallpaper + temp_image_position = state.image_position def create_widget(widget_type, label_text, **kwargs): container = QWidget() @@ -147,25 +148,80 @@ def settings_dialog(self): enable_image_checkbox.setChecked(state.image_enabled) enable_image_checkbox.toggled.connect(lambda checked: setattr(state, 'image_enabled', checked)) - # Image Width SpinBox - image_width_container, image_width = create_widget(QSpinBox, "Image Width: ", width=180, height=30) + # Image Mode Checkbox + image_mode_container, image_mode_checkbox = create_widget(QCheckBox, "Wallpaper Mode: ") + image_mode_checkbox.setChecked(state.image_as_wallpaper) + image_mode_checkbox.toggled.connect(lambda checked: setattr(state, 'image_as_wallpaper', checked)) + + # Image Position Preset + positions = ["bottom-right", "bottom-left", "top-right", "top-left", "center"] + image_position_container, image_position_combo = create_widget(QComboBox, "Position: ", width=180, height=30) + image_position_combo.addItems(positions) + idx = image_position_combo.findText(state.image_position) + image_position_combo.setCurrentIndex(idx if idx >= 0 else 0) + image_position_combo.currentTextChanged.connect(lambda val: setattr(state, 'image_position', val)) + + _slider_style = """ + QSlider::groove:horizontal { + height: 3px; + background: palette(mid); + border-radius: 1px; + } + QSlider::handle:horizontal { + width: 10px; + height: 10px; + margin: -4px 0; + border-radius: 5px; + } + """ + + # Image Width Slider + image_width_container = QWidget() + image_width_layout = QHBoxLayout(image_width_container) + image_width_layout.addWidget(QLabel("Image Width: ")) + image_width = QSlider(Qt.Orientation.Horizontal) + image_width.setFixedWidth(180) + image_width.setStyleSheet(_slider_style) image_width.setMinimum(0) image_width.setMaximum(2500) image_width.setValue(state.image_width) - image_width.valueChanged.connect(lambda val: setattr(state, 'image_width', val)) + image_width_val = QLabel(str(state.image_width)) + image_width_val.setFixedWidth(36) + image_width.valueChanged.connect(lambda val: (setattr(state, 'image_width', val), image_width_val.setText(str(val)))) + image_width_layout.addWidget(image_width_val) + image_width_layout.addWidget(image_width) - # Image Offset SpinBox - image_offset_container, image_offset = create_widget(QSpinBox, "Corner Offset: ", width=180, height=30) + # Image Offset Slider + image_offset_container = QWidget() + image_offset_layout = QHBoxLayout(image_offset_container) + image_offset_layout.addWidget(QLabel("Corner Offset: ")) + image_offset = QSlider(Qt.Orientation.Horizontal) + image_offset.setFixedWidth(180) + image_offset.setStyleSheet(_slider_style) image_offset.setMinimum(0) + image_offset.setMaximum(500) image_offset.setValue(state.image_offset) - image_offset.valueChanged.connect(lambda val: setattr(state, 'image_offset', val)) + image_offset_val = QLabel(str(state.image_offset)) + image_offset_val.setFixedWidth(36) + image_offset.valueChanged.connect(lambda val: (setattr(state, 'image_offset', val), image_offset_val.setText(str(val)))) + image_offset_layout.addWidget(image_offset_val) + image_offset_layout.addWidget(image_offset) - # Image Opacity SpinBox - image_opacity_container, image_opacity = create_widget(QSpinBox, "Image Opacity: ", width=180, height=30) + # Image Opacity Slider + image_opacity_container = QWidget() + image_opacity_layout = QHBoxLayout(image_opacity_container) + image_opacity_layout.addWidget(QLabel("Image Opacity: ")) + image_opacity = QSlider(Qt.Orientation.Horizontal) + image_opacity.setFixedWidth(180) + image_opacity.setStyleSheet(_slider_style) image_opacity.setMinimum(0) image_opacity.setMaximum(100) image_opacity.setValue(state.image_opacity) - image_opacity.valueChanged.connect(lambda val: setattr(state, 'image_opacity', val)) + image_opacity_val = QLabel(str(state.image_opacity)) + image_opacity_val.setFixedWidth(36) + image_opacity.valueChanged.connect(lambda val: (setattr(state, 'image_opacity', val), image_opacity_val.setText(str(val)))) + image_opacity_layout.addWidget(image_opacity_val) + image_opacity_layout.addWidget(image_opacity) # Speed Limiting down_speed_limit_container, down_speed_limit = create_widget(QSpinBox, "Max Download Speed (KiB, 0 for unlimited): ", width=180, height=30) @@ -231,7 +287,9 @@ def settings_dialog(self): interface_select.currentText(), image_width.value(), image_offset.value(), - image_opacity.value() + image_opacity.value(), + image_as_wallpaper=image_mode_checkbox.isChecked(), + image_position=image_position_combo.currentText() ) cancel_btn.clicked.connect(dialog.reject) @@ -240,7 +298,7 @@ def settings_dialog(self): tabs = QtWidgets.QTabWidget() create_tab("General", [autoresume_container, update_checkbox_container, transparent_window_container], tabs=tabs, stretch=True) - create_tab("Image", [enable_image_container, image_width_container, image_offset_container, image_opacity_container], tabs=tabs, stretch=True) + create_tab("Image", [enable_image_container, image_mode_container, image_position_container, image_width_container, image_offset_container, image_opacity_container], tabs=tabs, stretch=True) create_tab("Paths", [download_path_container, image_path_container], tabs=tabs, stretch=True) create_tab("Network", [interface_container, max_connections_container, max_downloads_container, up_speed_limit_container, down_speed_limit_container, api_url_container], tabs=tabs, stretch=True) @@ -254,6 +312,8 @@ def settings_dialog(self): state.image_offset = temp_image_offset state.image_opacity = temp_image_opacity state.image_enabled = temp_image_enabled + state.image_as_wallpaper = temp_image_as_wallpaper + state.image_position = temp_image_position dialog.finished.connect(on_dialog_finished) dialog.exec() diff --git a/src/utils/config/config.py b/src/utils/config/config.py index 23d024a..15cf7a4 100644 --- a/src/utils/config/config.py +++ b/src/utils/config/config.py @@ -35,7 +35,9 @@ def create_config(): "enable_image": str(state.image_enabled), "image_width": str(state.image_width), "image_offset": str(state.image_offset), - "image_opacity": str(state.image_opacity) + "image_opacity": str(state.image_opacity), + "image_as_wallpaper": str(state.image_as_wallpaper), + "image_position": str(state.image_position) } if platform.system() == "Windows": @@ -102,6 +104,8 @@ def read_config(): state.image_width = config.getint("Image", "image_width", fallback=state.image_width) state.image_offset = config.getint("Image", "image_offset", fallback=state.image_offset) state.image_opacity = config.getint("Image", "image_opacity", fallback=state.image_opacity) + state.image_as_wallpaper = config.getboolean("Image", "image_as_wallpaper", fallback=state.image_as_wallpaper) + state.image_position = config.get("Image", "image_position", fallback=state.image_position) create_config() diff --git a/src/utils/config/settings.py b/src/utils/config/settings.py index 947881b..2fc94a6 100644 --- a/src/utils/config/settings.py +++ b/src/utils/config/settings.py @@ -5,7 +5,7 @@ from utils.data.state import state -def save_settings(close=lambda: None, apiurl=None, download_path=None, down_speed_limit=None, up_speed_limit=None, image_path=None, autoresume=None, max_connections=None, max_downloads=None, bound_interface=None, image_width=None, image_offset=None, image_opacity=None): +def save_settings(close=lambda: None, apiurl=None, download_path=None, down_speed_limit=None, up_speed_limit=None, image_path=None, autoresume=None, max_connections=None, max_downloads=None, bound_interface=None, image_width=None, image_offset=None, image_opacity=None, image_as_wallpaper=None, image_position=None): if apiurl is not None: state.api_url = apiurl if download_path is not None: @@ -30,6 +30,10 @@ def save_settings(close=lambda: None, apiurl=None, download_path=None, down_spee state.image_offset = image_offset if image_opacity is not None: state.image_opacity = image_opacity + if image_as_wallpaper is not None: + state.image_as_wallpaper = image_as_wallpaper + if image_position is not None: + state.image_position = image_position update_settings() # Update LibTorrent Session Settings consoleLog("Saved Settings") diff --git a/src/utils/data/state.py b/src/utils/data/state.py index 1a918bf..75ed4eb 100644 --- a/src/utils/data/state.py +++ b/src/utils/data/state.py @@ -35,7 +35,8 @@ class AppState(QObject): self._image_width: int = 300 # Default to 300px self._image_offset: int = 50 self._image_opacity: int = 100 - self._image_as_wallpaper: bool = True + self._image_as_wallpaper: bool = False + self._image_position: str = "bottom-right" # top-left, top-right, bottom-left, bottom-right, center # Trackers / Scraping self.posts: list[Dict[str,str]] | None = None # titles, urls, author, seeders, leechers @@ -115,4 +116,44 @@ class AppState(QObject): self._image_as_wallpaper = new_state self.image_changed.emit(self._image_path) + @property + def image_position(self) -> str: + return self._image_position + + @image_position.setter + def image_position(self, new_pos: str): + if new_pos != self._image_position: + self._image_position = new_pos + self.image_changed.emit(self._image_path) + + @property + def image_custom_position(self) -> bool: + return self._image_custom_position + + @image_custom_position.setter + def image_custom_position(self, new_state: bool): + if new_state != self._image_custom_position: + self._image_custom_position = new_state + self.image_changed.emit(self._image_path) + + @property + def image_x(self) -> int: + return self._image_x + + @image_x.setter + def image_x(self, val: int): + if val != self._image_x: + self._image_x = val + self.image_changed.emit(self._image_path) + + @property + def image_y(self) -> int: + return self._image_y + + @image_y.setter + def image_y(self, val: int): + if val != self._image_y: + self._image_y = val + self.image_changed.emit(self._image_path) + state = AppState()