PyDragsView/Manager.py

244 lines
9.5 KiB
Python
Raw Normal View History

2023-12-31 09:38:12 +00:00
from PyQt5.QtWidgets import QWidget, QApplication, QMainWindow, QMessageBox
2023-12-30 09:43:16 +00:00
from PyQt5.QtCore import QObject, QEvent, QRect, QMargins, Qt, QMimeData
from PyQt5.QtGui import QPainter, QColor, QDragEnterEvent, QDropEvent
2023-12-31 02:53:10 +00:00
from enum import Enum
2023-12-30 09:43:16 +00:00
import re
2023-12-30 08:15:07 +00:00
2023-12-31 09:38:12 +00:00
class PlaceArea(Enum):
LeftArea = 0,
RightArea = 1,
TopArea = 2,
BottomArea = 3,
CenterArea = 4,
UndefineArea = 5,
2023-12-31 02:53:10 +00:00
2023-12-30 08:15:07 +00:00
class AcceptPanel(QWidget):
2023-12-30 09:43:16 +00:00
def __init__(self, mgr):
super(AcceptPanel, self).__init__(None)
2023-12-30 08:15:07 +00:00
self.left_rect = QRect()
self.right_rect = QRect()
self.top_rect = QRect()
self.bottom_rect = QRect()
self.center_rect = QRect()
self.hover_rect = QRect()
self.setMouseTracking(True)
self.setAcceptDrops(True)
2023-12-30 09:43:16 +00:00
self.mgr_inst = mgr
self.target_anchor :QWidget = None
2023-12-31 09:38:12 +00:00
self.target_area = PlaceArea.UndefineArea
2023-12-30 09:43:16 +00:00
2023-12-30 08:15:07 +00:00
def resizeEvent(self, a0):
total_rect = self.rect()
total_rect = total_rect - QMargins(5, 5, 5, 5)
anchor_width = 30
2023-12-31 09:38:12 +00:00
self.target_area = PlaceArea.UndefineArea
2023-12-30 08:15:07 +00:00
self.left_rect = QRect(int(total_rect.left()), int(total_rect.center().y() - anchor_width / 2), int(anchor_width), int(anchor_width))
self.right_rect = QRect(int(total_rect.right() - anchor_width), int(total_rect.center().y() - anchor_width / 2), int(anchor_width), int(anchor_width))
self.top_rect = QRect(int(total_rect.center().x() - anchor_width / 2), int(total_rect.top()), int(anchor_width), int(anchor_width))
self.bottom_rect = QRect(int(total_rect.center().x() - anchor_width / 2), int(total_rect.bottom() - anchor_width), int(anchor_width), int(anchor_width))
self.center_rect = QRect(int(total_rect.center().x() - anchor_width / 2), int(total_rect.center().y() - anchor_width / 2), int(anchor_width), int(anchor_width))
def async_with(self, target_view: QWidget):
self.resize(target_view.size())
self.target_anchor = target_view
2023-12-30 08:15:07 +00:00
def paintEvent(self, a0):
super(AcceptPanel, self).paintEvent(a0)
painter = QPainter(self)
painter.fillRect(self.rect(), Qt.lightGray)
painter.fillRect(self.hover_rect, Qt.gray)
painter.fillRect(self.top_rect, Qt.green)
painter.fillRect(self.bottom_rect, Qt.green)
painter.fillRect(self.left_rect, Qt.green)
painter.fillRect(self.right_rect, Qt.green)
painter.fillRect(self.center_rect, Qt.green)
2023-12-31 02:53:10 +00:00
def dragMoveEvent(self, a0):
2023-12-30 08:15:07 +00:00
self.hover_rect = self.rect()
if self.left_rect.contains(a0.pos()):
self.hover_rect.setWidth(int(self.hover_rect.width() / 3))
2023-12-31 09:38:12 +00:00
self.target_area = PlaceArea.LeftArea
2023-12-30 08:15:07 +00:00
elif self.right_rect.contains(a0.pos()):
2023-12-31 09:38:12 +00:00
self.target_area = PlaceArea.RightArea
2023-12-30 08:15:07 +00:00
self.hover_rect.setWidth(int(self.hover_rect.width() / 3))
self.hover_rect.moveLeft(int(self.rect().right() - self.hover_rect.width()))
elif self.top_rect.contains(a0.pos()):
2023-12-31 09:38:12 +00:00
self.target_area = PlaceArea.TopArea
2023-12-30 08:15:07 +00:00
self.hover_rect.setHeight(int(self.hover_rect.height() / 3))
elif self.center_rect.contains(a0.pos()):
2023-12-31 09:38:12 +00:00
self.target_area = PlaceArea.CenterArea
2023-12-30 08:15:07 +00:00
pass
elif self.bottom_rect.contains(a0.pos()):
2023-12-31 09:38:12 +00:00
self.target_area = PlaceArea.BottomArea
2023-12-30 08:15:07 +00:00
self.hover_rect.setHeight(int(self.hover_rect.height() / 3))
self.hover_rect.moveTop(int(self.rect().bottom() - self.hover_rect.height()))
else:
self.hover_rect = QRect()
2023-12-31 09:38:12 +00:00
self.target_area = PlaceArea.UndefineArea
2023-12-30 08:15:07 +00:00
self.update()
2023-12-30 09:43:16 +00:00
def dragEnterEvent(self, a0: QDragEnterEvent):
if a0.mimeData().hasFormat("text/plain"):
content = a0.mimeData().text()
regex = re.compile("view-drags\\(([^\\(\\)]+)\\)")
if regex.match(content):
a0.acceptProposedAction()
def dropEvent(self, a0: QDropEvent):
regex = re.compile("view-drags\\(([^\\(\\)]+)\\)")
result = regex.match(a0.mimeData().text())
if result:
2023-12-31 02:53:10 +00:00
from SplitPanel import SplitPanel, SplitType
from DockPanel import DockPanel
2023-12-30 09:43:16 +00:00
view_id = result.group(1)
2023-12-31 02:53:10 +00:00
adjust_view: DockPanel = self.mgr_inst.get_dockpanel(view_id)
2023-12-31 09:38:12 +00:00
abandon_frame = adjust_view.parent_res
if abandon_frame is None:
QMessageBox.critical(self, "操作无效", "视图不能与自身进行替换和拼接操作!");
self.setVisible(False)
self.setParent(self.__peak_window(self.target_anchor))
return
remains_attach_frame = abandon_frame.parent_res
2023-12-31 02:53:10 +00:00
target_view: DockPanel = self.target_anchor
2023-12-31 09:38:12 +00:00
if self.target_area == PlaceArea.CenterArea and not target_view.can_replace:
2023-12-31 02:53:10 +00:00
self.setVisible(False)
return
2023-12-31 09:38:12 +00:00
if self.target_area == PlaceArea.UndefineArea:
2023-12-31 02:53:10 +00:00
self.setVisible(False)
return
# 移除源视图
2023-12-31 09:38:12 +00:00
self_siblings = abandon_frame.child()
if remains_attach_frame is None:
main_window:QMainWindow = abandon_frame.parent()
views = [self_siblings[0], self_siblings[1]]
views.pop(views.index(adjust_view))
main_window.setCentralWidget(views[0])
2023-12-31 09:38:12 +00:00
views[0].setParent(main_window)
views[0].parent_res = None
else:
if self_siblings[0] == adjust_view:
2023-12-31 09:38:12 +00:00
remains_attach_frame.replace_view(self_siblings[1], abandon_frame)
else:
2023-12-31 09:38:12 +00:00
remains_attach_frame.replace_view(self_siblings[0], abandon_frame)
abandon_frame.setParent(None)
abandon_frame.parent_res = None
del abandon_frame
2023-12-31 02:53:10 +00:00
place_frame = target_view.parent_res
2023-12-31 09:38:12 +00:00
split_group:QWidget = None # 声明类型
if self.target_area == PlaceArea.LeftArea:
2023-12-31 02:53:10 +00:00
split_group = SplitPanel(adjust_view, target_view, SplitType.SPLIT_H)
split_group.set_split_info(SplitType.SPLIT_H, 1/3)
2023-12-31 09:38:12 +00:00
elif self.target_area == PlaceArea.RightArea:
2023-12-31 02:53:10 +00:00
split_group = SplitPanel(target_view, adjust_view, SplitType.SPLIT_H)
split_group.set_split_info(SplitType.SPLIT_H, 2/3)
2023-12-31 09:38:12 +00:00
elif self.target_area == PlaceArea.TopArea:
2023-12-31 02:53:10 +00:00
split_group = SplitPanel(adjust_view, target_view, SplitType.SPLIT_V)
split_group.set_split_info(SplitType.SPLIT_V, 1/3)
2023-12-31 09:38:12 +00:00
elif self.target_area == PlaceArea.BottomArea:
2023-12-31 02:53:10 +00:00
split_group = SplitPanel(target_view, adjust_view, SplitType.SPLIT_V)
split_group.set_split_info(SplitType.SPLIT_V, 2/3)
2023-12-31 09:38:12 +00:00
elif self.target_area == PlaceArea.CenterArea:
2023-12-31 02:53:10 +00:00
split_group = adjust_view
if place_frame is None:
main_window = target_view.parent()
main_window.setCentralWidget(split_group)
2023-12-31 09:38:12 +00:00
split_group.parent_res = None
target_view.setVisible(False)
self.mgr_inst.remove_dockpanel(target_view)
del target_view
2023-12-31 02:53:10 +00:00
else:
place_frame.replace_view(split_group, target_view)
2023-12-30 09:43:16 +00:00
self.setVisible(False)
2023-12-31 09:38:12 +00:00
self.setParent(self.__peak_window(self.target_anchor))
def __peak_window(self, obj: QWidget):
if obj is None:
return None
if obj.__class__.__name__ == "QMainWindow":
return obj
return self.__peak_window(obj.parent())
2023-12-30 08:15:07 +00:00
class DragManager(QObject):
__unique_inst: 'DragManager' = None
def __init__(self):
super(DragManager, self).__init__()
self.__dock_map = {}
2023-12-30 09:43:16 +00:00
self.__accept_panel = AcceptPanel(self)
self.__accept_panel.setVisible(False)
2023-12-30 08:15:07 +00:00
@classmethod
def instance(cls):
if cls.__unique_inst is None:
cls.__unique_inst = DragManager()
return cls.__unique_inst
def __peak_window(self, obj: QWidget):
if obj is None:
return None
if obj.__class__.__name__ == "QMainWindow":
return obj
return self.__peak_window(obj.parent())
def eventFilter(self, sender: QObject | None, event: QEvent | None):
if event.type() == QEvent.Type.DragMove:
if sender.isWindowType():
sender.requestActivate()
for ip in self.__dock_map:
view_inst: QWidget = self.get_dockpanel(ip)
if view_inst is None:
return False
gpos = sender.mapToGlobal(event.pos())
point = view_inst.mapFromGlobal(gpos)
if (view_inst.rect().contains(point)) and (self.__peak_window(view_inst).isActiveWindow()):
2023-12-30 09:43:16 +00:00
self.__accept_panel.setParent(view_inst)
self.__accept_panel.raise_()
self.__accept_panel.async_with(view_inst)
self.__accept_panel.setVisible(True)
pass
pass
2023-12-30 08:15:07 +00:00
pass
return super(DragManager, self).eventFilter(sender, event)
def register_dockpanel(self, view):
self.__dock_map[str(view.__hash__())] = view
def remove_dockpanel(self, view):
if str(view.__hash__()) in self.__dock_map:
self.__dock_map.pop(str(view.__hash__()))
def get_dockpanel(self, address: str):
if address in self.__dock_map:
return self.__dock_map[address]
return None
if __name__ == "__main__":
app = QApplication([])
accept = AcceptPanel(None)
accept.show()
app.exec()