Skip to content

Commit 5d8551d

Browse files
author
Shengjie Xu
committed
Initial code for PySide6 GUI
1 parent 17cfb0c commit 5d8551d

20 files changed

+883
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,9 @@ _antlr_generated
157157
# generated asset packs
158158
src/preppipe/assets/_install
159159

160+
# generated ui forms
161+
src/preppipe_gui_pyside6/forms/generated
162+
160163
# gui settings
161164
*.settings.db
162165
*.settings.db.*

src/preppipe_gui_pyside6/__init__.py

Whitespace-only changes.
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
UIC=pyside6-uic
2+
UI_FILES=$(wildcard *.ui)
3+
PY_FILES=$(addprefix generated/ui_, $(UI_FILES:.ui=.py))
4+
5+
all: $(PY_FILES)
6+
.PHONY: clean
7+
8+
generated/ui_%.py: %.ui
9+
$(UIC) $< -o $@
10+
11+
clean:
12+
rm -f $(PY_FILES)

src/preppipe_gui_pyside6/forms/__init__.py

Whitespace-only changes.

src/preppipe_gui_pyside6/forms/generated/GENERATED_FILES_ONLY_DO_NOT_PUT_FILES_HERE

Whitespace-only changes.

src/preppipe_gui_pyside6/forms/generated/__init__.py

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ui version="4.0">
3+
<class>HomeWidget</class>
4+
<widget class="QWidget" name="HomeWidget">
5+
<property name="geometry">
6+
<rect>
7+
<x>0</x>
8+
<y>0</y>
9+
<width>400</width>
10+
<height>300</height>
11+
</rect>
12+
</property>
13+
<property name="windowTitle">
14+
<string>Form</string>
15+
</property>
16+
<layout class="QVBoxLayout" name="verticalLayout">
17+
<property name="leftMargin">
18+
<number>0</number>
19+
</property>
20+
<property name="topMargin">
21+
<number>0</number>
22+
</property>
23+
<property name="rightMargin">
24+
<number>0</number>
25+
</property>
26+
<property name="bottomMargin">
27+
<number>0</number>
28+
</property>
29+
<item>
30+
<widget class="QLabel" name="label">
31+
<property name="text">
32+
<string>TODO Home</string>
33+
</property>
34+
</widget>
35+
</item>
36+
</layout>
37+
</widget>
38+
<resources/>
39+
<connections/>
40+
</ui>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ui version="4.0">
3+
<class>MainWindow</class>
4+
<widget class="QMainWindow" name="MainWindow">
5+
<property name="geometry">
6+
<rect>
7+
<x>0</x>
8+
<y>0</y>
9+
<width>927</width>
10+
<height>611</height>
11+
</rect>
12+
</property>
13+
<property name="windowTitle">
14+
<string>MainWindow</string>
15+
</property>
16+
<widget class="QWidget" name="centralwidget">
17+
<layout class="QVBoxLayout" name="verticalLayout">
18+
<item>
19+
<widget class="QTabWidget" name="tabWidget">
20+
<property name="currentIndex">
21+
<number>-1</number>
22+
</property>
23+
<property name="tabsClosable">
24+
<bool>true</bool>
25+
</property>
26+
<property name="movable">
27+
<bool>true</bool>
28+
</property>
29+
</widget>
30+
</item>
31+
</layout>
32+
</widget>
33+
<widget class="QMenuBar" name="menubar">
34+
<property name="geometry">
35+
<rect>
36+
<x>0</x>
37+
<y>0</y>
38+
<width>927</width>
39+
<height>19</height>
40+
</rect>
41+
</property>
42+
</widget>
43+
<widget class="QStatusBar" name="statusbar"/>
44+
</widget>
45+
<resources/>
46+
<connections/>
47+
</ui>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ui version="4.0">
3+
<class>NavigatorWidget</class>
4+
<widget class="QWidget" name="NavigatorWidget">
5+
<property name="geometry">
6+
<rect>
7+
<x>0</x>
8+
<y>0</y>
9+
<width>800</width>
10+
<height>600</height>
11+
</rect>
12+
</property>
13+
<layout class="QHBoxLayout" name="horizontalLayout">
14+
<item>
15+
<widget class="QSplitter" name="splitter">
16+
<property name="orientation">
17+
<enum>Qt::Horizontal</enum>
18+
</property>
19+
<widget class="QTreeView" name="treeView"/>
20+
<widget class="QListView" name="listView">
21+
<property name="viewMode">
22+
<enum>QListView::IconMode</enum>
23+
</property>
24+
<property name="iconSize">
25+
<size>
26+
<width>64</width>
27+
<height>64</height>
28+
</size>
29+
</property>
30+
<property name="resizeMode">
31+
<enum>QListView::Adjust</enum>
32+
</property>
33+
</widget>
34+
</widget>
35+
</item>
36+
</layout>
37+
</widget>
38+
<resources/>
39+
<connections/>
40+
</ui>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ui version="4.0">
3+
<class>SettingWidget</class>
4+
<widget class="QWidget" name="SettingWidget">
5+
<property name="geometry">
6+
<rect>
7+
<x>0</x>
8+
<y>0</y>
9+
<width>400</width>
10+
<height>300</height>
11+
</rect>
12+
</property>
13+
<property name="windowTitle">
14+
<string>Form</string>
15+
</property>
16+
<layout class="QVBoxLayout" name="verticalLayout">
17+
<property name="leftMargin">
18+
<number>0</number>
19+
</property>
20+
<property name="topMargin">
21+
<number>0</number>
22+
</property>
23+
<property name="rightMargin">
24+
<number>0</number>
25+
</property>
26+
<property name="bottomMargin">
27+
<number>0</number>
28+
</property>
29+
<item>
30+
<widget class="QTabWidget" name="tabWidget">
31+
<property name="currentIndex">
32+
<number>0</number>
33+
</property>
34+
<widget class="QWidget" name="generalTab">
35+
<attribute name="title">
36+
<string>General</string>
37+
</attribute>
38+
<layout class="QFormLayout" name="formLayout">
39+
<item row="0" column="0">
40+
<widget class="QLabel" name="languageLabel">
41+
<property name="text">
42+
<string>Language</string>
43+
</property>
44+
</widget>
45+
</item>
46+
<item row="0" column="1">
47+
<widget class="QComboBox" name="languageComboBox"/>
48+
</item>
49+
</layout>
50+
</widget>
51+
</widget>
52+
</item>
53+
</layout>
54+
</widget>
55+
<resources/>
56+
<connections/>
57+
</ui>

src/preppipe_gui_pyside6/guiassets.py

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# SPDX-FileCopyrightText: 2024 PrepPipe's Contributors
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
import os
5+
import typing
6+
import PIL
7+
import PIL.Image
8+
import preppipe
9+
import preppipe.assets
10+
from preppipe.assets.assetmanager import AssetManager
11+
12+
class GUIAssetLoader:
13+
GUI_ASSET_NAME : typing.ClassVar[str] = 'gui_assets'
14+
asset_rootpath : typing.ClassVar[typing.Optional[str]] = None
15+
16+
@staticmethod
17+
def get_asset_rootpath() -> str | None:
18+
if GUIAssetLoader.asset_rootpath is None:
19+
inst = AssetManager.get_instance()
20+
if assets := inst.get_asset(GUIAssetLoader.GUI_ASSET_NAME):
21+
GUIAssetLoader.asset_rootpath = assets.path
22+
return GUIAssetLoader.asset_rootpath
23+
24+
@staticmethod
25+
def try_get_asset_path(relpath : str) -> str | None:
26+
if asset_path := GUIAssetLoader.get_asset_rootpath():
27+
path = os.path.join(asset_path, relpath)
28+
if os.path.exists(path):
29+
return path
30+
return None
31+
32+
@staticmethod
33+
def try_get_image_asset(relpath : str) -> PIL.Image.Image | None:
34+
if asset_path := GUIAssetLoader.try_get_asset_path(relpath=relpath):
35+
return PIL.Image.open(asset_path)
36+
return None

src/preppipe_gui_pyside6/main.py

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import sys
2+
from PySide6.QtWidgets import QApplication
3+
from .mainwindow import MainWindow
4+
5+
def main():
6+
app = QApplication(sys.argv)
7+
QApplication.setOrganizationDomain("preppipe.org")
8+
QApplication.setOrganizationName("PrepPipe")
9+
QApplication.setApplicationName("PrepPipe GUI")
10+
MainWindow.initialize()
11+
window = MainWindow()
12+
window.show()
13+
sys.exit(app.exec())
14+
15+
if __name__ == "__main__":
16+
main()
+66
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
from __future__ import annotations
2+
from PySide6.QtWidgets import QMainWindow
3+
from PySide6.QtCore import *
4+
from .forms.generated.ui_mainwindow import Ui_MainWindow
5+
from .navigatorwidget import *
6+
from .toolwidgets.home import *
7+
from .toolwidgets.setting import *
8+
from .mainwindowinterface import *
9+
10+
class MainWindow(QMainWindow, MainWindowInterface):
11+
def __init__(self):
12+
super(MainWindow, self).__init__()
13+
self.ui = Ui_MainWindow()
14+
self.ui.setupUi(self)
15+
self.setWindowTitle(Translatable.tr_program_name.get())
16+
self.requestOpenWithType(NavigatorWidget)
17+
self.requestOpenWithType(HomeWidget)
18+
19+
def requestOpen(self, info : ToolWidgetInfo) -> None:
20+
if info.widget is None:
21+
return
22+
numtabs = self.ui.tabWidget.count()
23+
for i in range(numtabs):
24+
curtab = self.ui.tabWidget.widget(i)
25+
if not isinstance(curtab, ToolWidgetInterface):
26+
raise PPInternalError(f"Tab {i} is not a ToolWidgetInterface")
27+
cur_info = curtab.getWidgetIdentificationInfo()
28+
if cur_info.idstr != info.idstr:
29+
continue
30+
if cur_info.uniquelevel == ToolWidgetUniqueLevel.SINGLE_INSTANCE:
31+
self.ui.tabWidget.setCurrentIndex(i)
32+
return
33+
if cur_info.data != info.data or cur_info.uniquelevel == ToolWidgetUniqueLevel.UNLIMITED:
34+
continue
35+
if cur_info.uniquelevel == ToolWidgetUniqueLevel.SINGLE_INSTANCE_WITH_DIFFERENT_DATA:
36+
self.ui.tabWidget.setCurrentIndex(i)
37+
return
38+
raise PPInternalError(f"Unhandled unique level {cur_info.uniquelevel.name}")
39+
40+
widget = info.widget(self)
41+
if not isinstance(widget, ToolWidgetInterface):
42+
raise PPInternalError(f"Widget {widget} is not a ToolWidgetInterface")
43+
widget.setWidgetIdentificationInfo(info)
44+
if info.data is not None:
45+
widget.setData(**info.data)
46+
else:
47+
widget.setData()
48+
self.ui.tabWidget.addTab(widget, info.name.get() if isinstance(info.name, Translatable) else info.name)
49+
self.ui.tabWidget.setCurrentWidget(widget)
50+
return
51+
52+
def handleLanguageChange(self) -> None:
53+
for i in range(self.ui.tabWidget.count()):
54+
curtab = self.ui.tabWidget.widget(i)
55+
if not isinstance(curtab, ToolWidgetInterface):
56+
raise PPInternalError(f"Tab {i} is not a ToolWidgetInterface")
57+
curtab.update_text()
58+
self.ui.tabWidget.setTabText(i, curtab.windowTitle())
59+
self.ui.tabWidget.setTabToolTip(i, curtab.toolTip())
60+
self.setWindowTitle(Translatable.tr_program_name.get())
61+
return
62+
63+
@staticmethod
64+
def initialize():
65+
# 读取已保存的设置
66+
SettingWidget.initialize()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from preppipe.language import *
2+
from .toolwidgetinterface import *
3+
4+
# 部分内容不止在 MainWindow 中使用,所以放在这里
5+
TR_gui_mainwindow = TranslationDomain("gui_mainwindow")
6+
7+
class MainWindowInterface:
8+
def __init__(self, *args, **kwargs):
9+
super().__init__(*args, **kwargs)
10+
11+
def requestOpen(self, info : ToolWidgetInfo) -> None:
12+
raise NotImplementedError("Subclasses must implement the addTab() method.")
13+
14+
def requestOpenWithType(self, widget : type[ToolWidgetInterface]) -> None:
15+
info = widget.getToolInfo()
16+
self.requestOpen(info)
17+
18+
def handleLanguageChange(self) -> None:
19+
raise NotImplementedError("Subclasses must implement the handleLanguageChange() method.")

0 commit comments

Comments
 (0)