添加代码

This commit is contained in:
玉宇清音 2023-12-30 16:15:07 +08:00
parent 52f5a3d7ff
commit 351b446a15
13 changed files with 582 additions and 0 deletions

10
.idea/SimpleIDE.iml Normal file
View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.12" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Default" />
</state>
</component>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.12 (SimpleIDE)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.12" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/SimpleIDE.iml" filepath="$PROJECT_DIR$/.idea/SimpleIDE.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml Normal file
View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

169
.idea/workspace.xml Normal file
View File

@ -0,0 +1,169 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AutoImportSettings">
<option name="autoReloadType" value="SELECTIVE" />
</component>
<component name="ChangeListManager">
<list default="true" id="55c45e43-6fd9-4244-902d-86f83a348f5b" name="Changes" comment="">
<change afterPath="$PROJECT_DIR$/.idea/codeStyles/codeStyleConfig.xml" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Python Script" />
</list>
</option>
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="HierarchyBrowserManager">
<option name="IS_AUTOSCROLL_TO_SOURCE" value="true" />
</component>
<component name="ProjectColorInfo"><![CDATA[{
"associatedIndex": 2
}]]></component>
<component name="ProjectId" id="2aDBCkoR2x9AbgMgSJixv1KIMSj" />
<component name="ProjectLevelVcsManager" settingsEditedManually="true">
<ConfirmationsSetting value="2" id="Add" />
</component>
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"Python.DockPanel.executor": "Debug",
"Python.Manager.executor": "Run",
"Python.SplitPanel.executor": "Run",
"Python.Widget.executor": "Run",
"Python.test.executor": "Run",
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true",
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
"git-widget-placeholder": "master",
"settings.editor.selected.configurable": "preferences.sourceCode"
}
}]]></component>
<component name="RunManager" selected="Python.Manager">
<configuration name="DockPanel" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="SimpleIDE" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="D:\Projects\Python\SimpleIDE\DockPanel.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="Manager" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="SimpleIDE" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/Manager.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="SplitPanel" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="SimpleIDE" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/SplitPanel.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="test" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
<module name="SimpleIDE" />
<option name="ENV_FILES" value="" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/test.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<recent_temporary>
<list>
<item itemvalue="Python.Manager" />
<item itemvalue="Python.SplitPanel" />
<item itemvalue="Python.DockPanel" />
<item itemvalue="Python.test" />
</list>
</recent_temporary>
</component>
<component name="SharedIndexes">
<attachedChunks>
<set>
<option value="bundled-python-sdk-50da183f06c8-d3b881c8e49f-com.jetbrains.pycharm.community.sharedIndexes.bundled-PC-233.13135.95" />
</set>
</attachedChunks>
</component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="55c45e43-6fd9-4244-902d-86f83a348f5b" name="Changes" comment="" />
<created>1703843144486</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1703843144486</updated>
</task>
<servers />
</component>
</project>

120
DockPanel.py Normal file
View File

@ -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()

127
Manager.py Normal file
View File

@ -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()

122
SplitPanel.py Normal file
View File

@ -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()

Binary file not shown.

Binary file not shown.

2
test.py Normal file
View File

@ -0,0 +1,2 @@
dict = {}
print(dict.__class__.__name__)