|
10 | 10 | import math
|
11 | 11 | import shutil
|
12 | 12 |
|
13 |
| -from PyQt6.QtCore import Qt, QPoint, QSize, QDir, QRect, QMimeData, QUrl, QFileSystemWatcher, QFileInfo, QTimer, QRegularExpression |
| 13 | +from PyQt6.QtCore import Qt, QPoint, QSize, QDir, QRect, QMimeData, QUrl, QFileSystemWatcher, QFileInfo, QTimer, QRegularExpression, QObject, QEvent |
14 | 14 | from PyQt6.QtGui import QFontMetrics, QPainter, QPen, QAction, QDrag, QColor, QPainter, QPen, QBrush, QPixmap, QKeySequence, QFont, QIcon, QShortcut, QRegularExpressionValidator, QCursor
|
15 | 15 | from PyQt6.QtWidgets import QApplication, QWidget, QVBoxLayout, QScrollArea, QLabel, QSizePolicy, QMainWindow, QDialogButtonBox
|
16 |
| -from PyQt6.QtWidgets import QStatusBar, QComboBox, QFileIconProvider, QMenuBar, QGridLayout, QMessageBox, QMenu, QDialog, QLineEdit, QInputDialog |
| 16 | +from PyQt6.QtWidgets import QStatusBar, QComboBox, QFileIconProvider, QMenuBar, QGridLayout, QMessageBox, QMenu, QDialog, QLineEdit, QGraphicsScene, QGraphicsPixmapItem |
17 | 17 |
|
18 | 18 | if sys.platform == "win32":
|
19 | 19 | from win32com.client import Dispatch
|
@@ -129,6 +129,21 @@ def __init__(self, path=None, is_desktop_window=False):
|
129 | 129 | self.file_watcher.fileChanged.connect(self.file_changed)
|
130 | 130 | self.file_watcher.addPath(self.path)
|
131 | 131 |
|
| 132 | + # To keep track of spring-loaded folders needing to be closed |
| 133 | + self.installEventFilter(self) |
| 134 | + |
| 135 | + # To keep track of spring-loaded folders needing to be closed |
| 136 | + def eventFilter(self, obj: QObject, event: QEvent) -> bool: |
| 137 | + if event.type() == QEvent.Type.DragLeave: |
| 138 | + # Check whether mouse coordinates are inside or outside of the window, and print the result |
| 139 | + mouse_is_inside = self.rect().contains(self.mapFromGlobal(QCursor.pos())) |
| 140 | + print("Mouse is inside:", mouse_is_inside) |
| 141 | + if not mouse_is_inside and self.is_spring_opened: |
| 142 | + self.close() |
| 143 | + # Handle the drag leave event here |
| 144 | + return True # Return True if the event is handled |
| 145 | + return super().eventFilter(obj, event) |
| 146 | + |
132 | 147 | def keyPressEvent(self, event):
|
133 | 148 | # Handle Tab and Shift-Tab to select the next and previous item
|
134 | 149 | if event.key() == Qt.Key.Key_Tab:
|
@@ -532,16 +547,37 @@ def mousePressEvent(self, event):
|
532 | 547 | self.dragging = True
|
533 | 548 | self.last_pos = adjusted_pos
|
534 | 549 | self.update_menu_state()
|
535 |
| - # Set mime data for all selected items |
| 550 | + |
| 551 | + # Create a QGraphicsScene to hold the icons |
| 552 | + scene = QGraphicsScene() |
| 553 | + icon_spacing = 10 # Space between icons |
| 554 | + x_offset = 0 |
| 555 | + |
| 556 | + # Add each selected item's icon to the scene |
| 557 | + for item in self.selected_files: |
| 558 | + icon_pixmap = item.icon_label.pixmap() |
| 559 | + pixmap_item = QGraphicsPixmapItem(icon_pixmap) |
| 560 | + pixmap_item.setPos(x_offset, 0) # Position the icon |
| 561 | + scene.addItem(pixmap_item) |
| 562 | + x_offset += icon_pixmap.width() + icon_spacing # Update offset for next icon |
| 563 | + # FIXME: Use the items' real positions instead; can this be done without using a QGraphicsView? |
| 564 | + |
| 565 | + # Create a QPixmap from the scene |
| 566 | + scene_rect = scene.itemsBoundingRect() |
| 567 | + combined_pixmap = QPixmap(scene_rect.size().toSize()) |
| 568 | + combined_pixmap.fill(QColor(0, 0, 0, 0)) |
| 569 | + painter = QPainter(combined_pixmap) |
| 570 | + scene.render(painter, target=scene_rect, source=scene_rect) |
| 571 | + painter.end() |
| 572 | + |
| 573 | + # Set the combined pixmap for the drag |
| 574 | + drag = QDrag(self) |
536 | 575 | mime_data = QMimeData()
|
537 | 576 | for item in self.selected_files:
|
538 | 577 | mime_data.setUrls([QUrl.fromLocalFile(f.path) for f in self.selected_files])
|
539 |
| - drag = QDrag(self) |
540 | 578 | drag.setMimeData(mime_data)
|
541 |
| - drag.setPixmap(self.selected_files[0].icon_label.pixmap()) |
542 |
| - # TODO: Make it so that the icon doesn't jump to be at the top left corner of the mouse cursor |
543 |
| - # FIXME: Instead of hardcoding the hot spot to be half the icon size, it should be the position of the mouse cursor relative to the item |
544 |
| - drag.setHotSpot(QPoint(int(app.icon_size/2), int(app.icon_size/2))) |
| 579 | + drag.setPixmap(combined_pixmap) |
| 580 | + drag.setHotSpot(QPoint(int(app.icon_size / 2), int(app.icon_size / 2))) |
545 | 581 | drag.exec()
|
546 | 582 | else:
|
547 | 583 | self.is_selecting = True
|
@@ -658,17 +694,6 @@ def dragEnterEvent(self, event):
|
658 | 694 |
|
659 | 695 | def startDrag(self, event):
|
660 | 696 | self.initial_position = event.pos()
|
661 |
| - |
662 |
| - def dragLeaveEvent(self, event): |
663 |
| - # If this window was spring-loaded, close it when the drag leaves the window |
664 |
| - if self.is_spring_opened: |
665 |
| - # FIXME: For some reason, the following line does not work. May need to iterate through all item rects |
666 |
| - # to see if the mouse is within them (and possibly some margin) |
667 |
| - if any(item.underMouse() for item in self.items): |
668 |
| - event.ignore() |
669 |
| - else: |
670 |
| - self.close() |
671 |
| - event.accept() |
672 | 697 |
|
673 | 698 | def dropEvent(self, event):
|
674 | 699 | initial_position = self.initial_position
|
@@ -1128,6 +1153,14 @@ def get_info(self):
|
1128 | 1153 |
|
1129 | 1154 | def spring_open(self):
|
1130 | 1155 | self.open(event=None, spring_open=True)
|
| 1156 | + |
| 1157 | + parent = self.parent() |
| 1158 | + while parent: |
| 1159 | + parent = parent.parent() |
| 1160 | + print(parent.__class__.__name__) |
| 1161 | + if parent.__class__.__name__ == "SpatialFiler" and not parent.is_desktop_window: |
| 1162 | + parent.close() |
| 1163 | + |
1131 | 1164 |
|
1132 | 1165 | def open(self, event=None, spring_open=False):
|
1133 | 1166 | print(f"Asked to open {self.path}")
|
|
0 commit comments