|
4 | 4 | QWidget, QHBoxLayout, QVBoxLayout, QListWidget, QLabel, QPushButton, |
5 | 5 | QFrame, QGridLayout, QApplication |
6 | 6 | ) |
7 | | -from PyQt6.QtCore import Qt, pyqtSignal, QTimer, QPoint |
| 7 | +from PyQt6.QtCore import Qt, pyqtSignal, QTimer, QPoint, QRect |
8 | 8 | from PyQt6.QtGui import QIcon |
9 | 9 |
|
10 | 10 | from translator import tr |
@@ -236,16 +236,37 @@ def _show_color_palette(self, target_btn, current_color, signal_name, colors): |
236 | 236 | btn.clicked.connect(lambda checked, c=color: self._apply_color(c, target_btn, signal_name, palette)) |
237 | 237 | layout.addWidget(btn, row, col) |
238 | 238 |
|
| 239 | + palette.ensurePolished() |
239 | 240 | palette.adjustSize() |
240 | | - pos = target_btn.mapToGlobal(QPoint(0, target_btn.height() + 5)) |
241 | 241 |
|
242 | | - target_x = pos.x() |
243 | | - target_y = pos.y() |
| 242 | + # Determine current screen based on button center |
| 243 | + btn_center_global = target_btn.mapToGlobal(target_btn.rect().center()) |
| 244 | + screen = QApplication.screenAt(btn_center_global) |
| 245 | + if not screen: |
| 246 | + screen = self.window().screen() if self.window() else QApplication.primaryScreen() |
| 247 | + |
| 248 | + screen_geo = screen.availableGeometry() |
| 249 | + |
| 250 | + # Use the absolute maximum possible width/height for safest clamping |
| 251 | + pw = max(palette.width(), palette.sizeHint().width(), palette.minimumWidth()) |
| 252 | + ph = max(palette.height(), palette.sizeHint().height(), palette.minimumHeight()) |
| 253 | + |
| 254 | + btn_rect_global = QRect(target_btn.mapToGlobal(QPoint(0, 0)), target_btn.size()) |
| 255 | + target_x = btn_rect_global.left() |
| 256 | + target_y = btn_rect_global.bottom() + 5 |
| 257 | + |
| 258 | + # Clamp strictly within available geometry |
| 259 | + margin_x = 20 |
| 260 | + margin_right = 30 |
| 261 | + margin_top = 20 |
244 | 262 |
|
245 | | - # Screen boundary check |
246 | | - screen = self.screen().availableGeometry() |
247 | | - target_x = max(screen.left(), min(target_x, screen.right() - palette.width())) |
248 | | - target_y = max(screen.top(), min(target_y, screen.bottom() - palette.height())) |
| 263 | + min_x = screen_geo.left() + margin_x |
| 264 | + max_x = screen_geo.left() + screen_geo.width() - pw - margin_right |
| 265 | + min_y = screen_geo.top() + margin_top |
| 266 | + max_y = screen_geo.top() + screen_geo.height() - ph # No bottom margin |
| 267 | + |
| 268 | + target_x = max(min_x, min(target_x, max_x)) |
| 269 | + target_y = max(min_y, min(target_y, max_y)) |
249 | 270 |
|
250 | 271 | palette.move(target_x, target_y) |
251 | 272 | palette.show() |
@@ -393,17 +414,40 @@ def show_popup(self): |
393 | 414 | return |
394 | 415 |
|
395 | 416 | # Position popup above the button |
396 | | - self.popup.adjustSize() |
397 | 417 | self.popup.setSubtitlesEnabled(self.subtitles_enabled) |
398 | | - pos = self.mapToGlobal(QPoint(0, 0)) |
| 418 | + self.popup.ensurePolished() |
| 419 | + self.popup.adjustSize() |
| 420 | + |
| 421 | + # Determine current screen based on button center |
| 422 | + button_rect_global = QRect(self.mapToGlobal(QPoint(0, 0)), self.size()) |
| 423 | + button_center_global = button_rect_global.center() |
| 424 | + |
| 425 | + screen = QApplication.screenAt(button_center_global) |
| 426 | + if not screen: |
| 427 | + screen = self.window().screen() if self.window() else QApplication.primaryScreen() |
| 428 | + |
| 429 | + screen_geo = screen.availableGeometry() |
| 430 | + |
| 431 | + # Use adjusted size directly |
| 432 | + pw = self.popup.width() |
| 433 | + ph = self.popup.height() |
| 434 | + |
| 435 | + # Calculate ideal target (above button) |
| 436 | + target_x = button_center_global.x() - pw // 2 |
| 437 | + target_y = button_rect_global.top() - ph - 5 |
| 438 | + |
| 439 | + # Clamp strictly within available geometry |
| 440 | + margin_x = 20 |
| 441 | + margin_right = 30 |
| 442 | + margin_top = 20 |
399 | 443 |
|
400 | | - target_x = pos.x() + (self.width() - self.popup.width()) // 2 |
401 | | - target_y = pos.y() - self.popup.height() - 5 |
| 444 | + min_x = screen_geo.left() + margin_x |
| 445 | + max_x = screen_geo.left() + screen_geo.width() - pw - margin_right |
| 446 | + min_y = screen_geo.top() + margin_top |
| 447 | + max_y = screen_geo.top() + screen_geo.height() - ph # No bottom margin |
402 | 448 |
|
403 | | - # Screen boundary check |
404 | | - screen = self.screen().availableGeometry() |
405 | | - target_x = max(screen.left(), min(target_x, screen.right() - self.popup.width())) |
406 | | - target_y = max(screen.top(), min(target_y, screen.bottom() - self.popup.height())) |
| 449 | + target_x = max(min_x, min(target_x, max_x)) |
| 450 | + target_y = max(min_y, min(target_y, max_y)) |
407 | 451 |
|
408 | 452 | self.popup.move(target_x, target_y) |
409 | 453 | self.popup.show() |
|
0 commit comments