diff --git a/.idea/SimpleIDE.iml b/.idea/SimpleIDE.iml
new file mode 100644
index 0000000..6cb8b9a
--- /dev/null
+++ b/.idea/SimpleIDE.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 0000000..a55e7a1
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..de071b2
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..bc24bff
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..5ecedbf
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1703843144486
+
+
+ 1703843144486
+
+
+
+
\ No newline at end of file
diff --git a/DockPanel.py b/DockPanel.py
new file mode 100644
index 0000000..46f440a
--- /dev/null
+++ b/DockPanel.py
@@ -0,0 +1,120 @@
+from PyQt5.QtWidgets import QWidget
+from PyQt5.QtWidgets import QApplication
+from PyQt5.QtWidgets import QLabel
+from PyQt5.QtWidgets import QVBoxLayout
+from PyQt5.QtWidgets import QHBoxLayout
+from PyQt5.QtWidgets import QFrame
+from PyQt5.QtWidgets import QPushButton
+from PyQt5.QtCore import Qt, pyqtSignal
+from PyQt5.QtCore import QSize, QPoint, QMimeData
+from PyQt5.QtGui import QDrag
+from Manager import DragManager
+
+
+class DragHeader(QFrame):
+ close_request = pyqtSignal(QWidget)
+ retrieve_request = pyqtSignal(QWidget)
+ adjust_request = pyqtSignal(QWidget, QPoint)
+
+ def __init__(self, title: str, parent: 'DockPanel'):
+ super().__init__(parent)
+
+ self.__place_cube = parent
+ self.__pressed_mark = (False, QPoint)
+
+ self.layout_inst = QHBoxLayout(self)
+ self.layout_inst.setSpacing(0)
+ self.layout_inst.setContentsMargins(0,0,0,0)
+
+ self.show_label=QLabel(title, self)
+ self.show_label.setContentsMargins(2, 0, 0, 0)
+ self.layout_inst.addWidget(self.show_label, stretch=1, alignment=Qt.AlignLeft)
+
+ self.min_button=QPushButton("-")
+ self.min_button.clicked.connect(lambda : self.retrieve_request[QWidget].emit(parent))
+ self.min_button.setMaximumSize(22,22)
+ self.min_button.setMaximumSize(22,22)
+ self.layout_inst.addWidget(self.min_button,stretch=0, alignment=Qt.AlignRight)
+ self.close_button=QPushButton("x")
+ self.close_button.clicked.connect(lambda : self.close_request[QWidget].emit(parent))
+ self.close_button.setMaximumSize(22,22)
+ self.close_button.setMaximumSize(22,22)
+ self.layout_inst.addWidget(self.close_button, stretch=0, alignment=Qt.AlignRight)
+ pass
+
+ def mousePressEvent(self, a0):
+ super(DragHeader, self).mousePressEvent(a0)
+ self.__pressed_mark = (True, self.__place_cube.mapToParent(a0.pos()))
+ pass
+
+ def mouseReleaseEvent(self, a0):
+ super(DragHeader, self).mouseReleaseEvent(a0)
+ self.__pressed_mark = (False, QPoint())
+ pass
+
+ def mouseMoveEvent(self, a0):
+ super(DragHeader, self).mouseMoveEvent(a0)
+ if self.__pressed_mark[0]:
+ self.adjust_request[QWidget,QPoint].emit(self, self.__place_cube.mapToParent(a0.pos()))
+
+
+class DockPanel(QWidget):
+
+ def __init__(self, title:str, show_inst:QWidget|None, pinst:QWidget):
+ super(DockPanel, self).__init__(pinst)
+
+ self.setMinimumSize(60, 40)
+ self.setWindowTitle(title)
+ self.parent_res = pinst
+
+ self.layout_inst = QVBoxLayout(self)
+ self.layout_inst.setSpacing(0)
+ self.layout_inst.setContentsMargins(0,2,0,0)
+
+ self.drag_header = DragHeader(title, self)
+ self.layout_inst.addWidget(self.drag_header)
+ self.drag_header.setMinimumHeight(26)
+ self.drag_header.setMaximumHeight(26)
+ self.drag_header.setFrameShape(QFrame.Shape.Panel)
+ self.drag_header.setFrameShadow(QFrame.Shadow.Raised)
+ self.drag_header.setLineWidth(3)
+ self.drag_header.adjust_request[QWidget,QPoint].connect(self.__adjust_accept)
+
+ if show_inst is not None:
+ self.layout_inst.addWidget(show_inst)
+ else:
+ self.layout_inst.addWidget(QWidget())
+
+ self.default_header = True
+ self.can_replace = True
+ self.can_retrieve = True
+ self.can_close = True
+
+ DragManager.instance().register_dockpanel(self)
+ pass
+
+ def reset_parent_res(self, pinst):
+ self.parent_res = pinst
+
+ def __adjust_accept(self, view: QWidget, pt: QPoint):
+ drag_trans = QDrag(self)
+ mine_data = QMimeData()
+ mine_data.setText("view-drags(" + str(self.__hash__()) + ")")
+ drag_trans.setMimeData(mine_data)
+ drag_trans.setPixmap(self.grab(self.rect()))
+ drag_trans.setHotSpot(QPoint(5,5))
+ drag_trans.exec()
+
+ def __del__(self):
+ DragManager.instance().remove_dockpanel(self)
+
+ def sync_status(self):
+ self.drag_header.setVisible(self.default_header)
+
+
+if __name__ == "__main__":
+ app=QApplication([])
+ app.installEventFilter(DragManager())
+ win=DockPanel("empty-window",None,None)
+ win.show()
+ app.exec()
\ No newline at end of file
diff --git a/Manager.py b/Manager.py
new file mode 100644
index 0000000..562b52b
--- /dev/null
+++ b/Manager.py
@@ -0,0 +1,127 @@
+from PyQt5.QtWidgets import QWidget, QApplication
+from PyQt5.QtCore import QObject, QEvent, QRect, QMargins, Qt
+from PyQt5.QtGui import QPainter, QColor
+from enum import Enum
+
+
+class AcceptPanel(QWidget):
+
+ def __init__(self, parent):
+ super(AcceptPanel, self).__init__(parent)
+ 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)
+
+ def resizeEvent(self, a0):
+ total_rect = self.rect()
+ total_rect = total_rect - QMargins(5, 5, 5, 5)
+ anchor_width = 30
+
+ 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())
+
+ 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)
+
+ def mouseMoveEvent(self, a0):
+ self.hover_rect = self.rect()
+ print(a0.pos())
+
+ if self.left_rect.contains(a0.pos()):
+ self.hover_rect.setWidth(int(self.hover_rect.width() / 3))
+ elif self.right_rect.contains(a0.pos()):
+ 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()):
+ self.hover_rect.setHeight(int(self.hover_rect.height() / 3))
+ elif self.center_rect.contains(a0.pos()):
+ pass
+ elif self.bottom_rect.contains(a0.pos()):
+ 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()
+
+ self.update()
+
+
+class DragManager(QObject):
+ __unique_inst: 'DragManager' = None
+
+ def __init__(self):
+ super(DragManager, self).__init__()
+ self.__dock_map = {}
+
+ @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()):
+ print(view_inst.rect())
+
+ 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()
diff --git a/SplitPanel.py b/SplitPanel.py
new file mode 100644
index 0000000..58ceb87
--- /dev/null
+++ b/SplitPanel.py
@@ -0,0 +1,122 @@
+import Manager
+from DockPanel import DockPanel
+from PyQt5.QtWidgets import QApplication, QWidget, QFrame
+from enum import Enum
+from PyQt5.QtCore import pyqtSignal, QPoint
+from PyQt5.QtCore import QRect, Qt
+from PyQt5.QtWidgets import QMainWindow
+
+
+class SplitType(Enum):
+ SPLIT_H = 0
+ SPLIT_V = 1
+
+
+class DragSplitter(QFrame):
+ adjustSignal = pyqtSignal(QPoint)
+
+ def __init__(self, split:SplitType, parent:QWidget):
+ super(DragSplitter, self).__init__(parent)
+
+ self.setFrameShape(QFrame.Shape.WinPanel)
+ self.setFrameShadow(QFrame.Shadow.Raised)
+
+ if split == SplitType.SPLIT_H:
+ self.setCursor(Qt.CursorShape.SplitHCursor)
+ else:
+ self.setCursor(Qt.CursorShape.SplitVCursor)
+
+ pass
+
+ def mouseMoveEvent(self, a0):
+ super().mouseMoveEvent(a0)
+ up_point = self.mapToParent(a0.pos())
+ self.adjustSignal.emit(up_point)
+
+
+class SplitPanel(QWidget):
+ def __init__(self, a: DockPanel, b: DockPanel, split: SplitType, parent:QWidget = None):
+ super(SplitPanel, self).__init__(parent)
+
+ self.splitter_widget = DragSplitter(split, self)
+ self.splitter_widget.adjustSignal[QPoint].connect(self.__splitter_adjust)
+
+ self.split_member = (a, b)
+ self.split_member[0].setParent(self)
+ self.split_member[1].setParent(self)
+
+ self.split_info = (split, 0.5, 7)
+ self.sync_status()
+ pass
+
+ def __view_list(self) -> [DockPanel]:
+ retval: [DockPanel] = [self.split_member[0], self.split_member[1]]
+ return retval
+
+ def set_split_info(self, o: SplitType, pos: float, width: float = 8):
+ self.split_info = (o, pos, width)
+ self.sync_status()
+
+ def sync_status(self):
+ if self.split_info[0] == SplitType.SPLIT_H:
+ total_width = self.width()
+ width_a = total_width * self.split_info[1]
+ width_b = total_width - width_a - self.split_info[2]
+
+ self.split_member[0].setGeometry(0, 0, int(width_a), self.height())
+ self.split_member[1].setGeometry(int(width_a + self.split_info[2]), 0, int(width_b), self.height())
+
+ handle_rect = QRect(int(width_a), 0, int(self.split_info[2]), self.height())
+ self.splitter_widget.setGeometry(handle_rect)
+ else:
+ total_height = self.height()
+ height_a = total_height * self.split_info[1]
+ height_b = total_height - height_a - self.split_info[2]
+
+ self.split_member[0].setGeometry(0, 0, self.width(), int(height_a))
+ self.split_member[1].setGeometry(0, int(height_a + self.split_info[2]) - 1, self.width(), int(height_b) + 1)
+
+ handle_rect = QRect(0, int(height_a), self.width(), int(self.split_info[2]))
+ self.splitter_widget.setGeometry(handle_rect)
+ pass
+
+ def resizeEvent(self, a0):
+ super().resizeEvent(a0)
+ self.sync_status()
+
+ def __splitter_adjust(self, pos: QPoint):
+ if self.split_info[0] == SplitType.SPLIT_H:
+ leftw = self.split_member[0].minimumWidth()
+ rightw = self.split_member[1].minimumWidth()
+ if (pos.x() >= leftw) and (pos.x() <= self.width() - rightw):
+ self.split_info = (self.split_info[0], pos.x() / self.width(), self.split_info[2])
+ else:
+ toph = self.split_member[0].minimumHeight()
+ bottomh = self.split_member[1].minimumHeight()
+ if (pos.y() >= toph) and (pos.y() <= self.height() - bottomh):
+ self.split_info = (self.split_info[0], pos.y() / self.height(), self.split_info[2])
+ self.sync_status()
+
+ def replace_view(self, new: DockPanel, old: DockPanel):
+ if old in self.__view_list() and new not in self.__view_list():
+ if self.split_member[0] == old:
+ self.split_member = (new, self.split_member[1], self.split_member[2])
+ else:
+ self.split_member = (self.split_member[0], new, self.split_member[2])
+ old.setParent(None)
+ self.sync_status()
+ pass
+
+
+if __name__ == "__main__":
+ app = QApplication([])
+ ow = QMainWindow()
+ app.installEventFilter(Manager.DragManager.instance())
+
+ a = DockPanel("docka", None, None)
+ b = DockPanel("dockb", None, None)
+ win = SplitPanel(a, b, SplitType.SPLIT_H)
+ ow.setCentralWidget(win)
+
+ ow.show()
+ app.exec()
\ No newline at end of file
diff --git a/__pycache__/DockPanel.cpython-312.pyc b/__pycache__/DockPanel.cpython-312.pyc
new file mode 100644
index 0000000..82689ea
Binary files /dev/null and b/__pycache__/DockPanel.cpython-312.pyc differ
diff --git a/__pycache__/Manager.cpython-312.pyc b/__pycache__/Manager.cpython-312.pyc
new file mode 100644
index 0000000..9b8cf98
Binary files /dev/null and b/__pycache__/Manager.cpython-312.pyc differ
diff --git a/test.py b/test.py
new file mode 100644
index 0000000..26fb453
--- /dev/null
+++ b/test.py
@@ -0,0 +1,2 @@
+dict = {}
+print(dict.__class__.__name__)
\ No newline at end of file