qpuiq 0.23__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- PUI/PySide6/__init__.py +49 -0
- PUI/PySide6/application.py +58 -0
- PUI/PySide6/base.py +285 -0
- PUI/PySide6/button.py +21 -0
- PUI/PySide6/canvas.py +345 -0
- PUI/PySide6/checkbox.py +32 -0
- PUI/PySide6/combobox.py +85 -0
- PUI/PySide6/dialog.py +72 -0
- PUI/PySide6/divider.py +23 -0
- PUI/PySide6/image.py +48 -0
- PUI/PySide6/label.py +33 -0
- PUI/PySide6/layout.py +141 -0
- PUI/PySide6/matplotlib.py +23 -0
- PUI/PySide6/mdi.py +33 -0
- PUI/PySide6/menu.py +85 -0
- PUI/PySide6/modal.py +132 -0
- PUI/PySide6/progressbar.py +17 -0
- PUI/PySide6/radiobutton.py +29 -0
- PUI/PySide6/scroll.py +155 -0
- PUI/PySide6/splitter.py +25 -0
- PUI/PySide6/tab.py +39 -0
- PUI/PySide6/table.py +147 -0
- PUI/PySide6/text.py +35 -0
- PUI/PySide6/textfield.py +62 -0
- PUI/PySide6/toolbar.py +57 -0
- PUI/PySide6/tree.py +290 -0
- PUI/PySide6/window.py +82 -0
- PUI/__init__.py +46 -0
- PUI/common.py +26 -0
- PUI/decorator.py +20 -0
- PUI/dom.py +263 -0
- PUI/flet/__init__.py +22 -0
- PUI/flet/application.py +42 -0
- PUI/flet/base.py +37 -0
- PUI/flet/button.py +20 -0
- PUI/flet/canvas.py +86 -0
- PUI/flet/checkbox.py +23 -0
- PUI/flet/divider.py +14 -0
- PUI/flet/label.py +27 -0
- PUI/flet/layout.py +50 -0
- PUI/flet/progressbar.py +21 -0
- PUI/flet/radiobutton.py +27 -0
- PUI/flet/scroll.py +83 -0
- PUI/flet/tab.py +42 -0
- PUI/flet/text.py +55 -0
- PUI/flet/textfield.py +58 -0
- PUI/flet/window.py +25 -0
- PUI/interfaces.py +97 -0
- PUI/node.py +432 -0
- PUI/state.py +711 -0
- PUI/textual/__init__.py +35 -0
- PUI/textual/application.py +82 -0
- PUI/textual/base.py +148 -0
- PUI/textual/button.py +17 -0
- PUI/textual/checkbox.py +21 -0
- PUI/textual/label.py +36 -0
- PUI/textual/layout.py +52 -0
- PUI/textual/progressbar.py +17 -0
- PUI/textual/radiobutton.py +24 -0
- PUI/textual/scroll.py +74 -0
- PUI/textual/tab.py +75 -0
- PUI/textual/text.py +32 -0
- PUI/textual/textfield.py +55 -0
- PUI/textual/window.py +7 -0
- PUI/timeline.py +36 -0
- PUI/tkinter/__init__.py +43 -0
- PUI/tkinter/application.py +49 -0
- PUI/tkinter/base.py +68 -0
- PUI/tkinter/button.py +15 -0
- PUI/tkinter/canvas.py +52 -0
- PUI/tkinter/checkbox.py +27 -0
- PUI/tkinter/label.py +17 -0
- PUI/tkinter/layout.py +114 -0
- PUI/tkinter/progressbar.py +17 -0
- PUI/tkinter/radiobutton.py +26 -0
- PUI/tkinter/scroll.py +201 -0
- PUI/tkinter/tab.py +52 -0
- PUI/tkinter/text.py +20 -0
- PUI/tkinter/textfield.py +53 -0
- PUI/tkinter/window.py +51 -0
- PUI/utils.py +15 -0
- PUI/view.py +161 -0
- PUI/wx/__init__.py +19 -0
- PUI/wx/application.py +44 -0
- PUI/wx/base.py +246 -0
- PUI/wx/button.py +16 -0
- PUI/wx/canvas.py +255 -0
- PUI/wx/checkbox.py +25 -0
- PUI/wx/combobox.py +81 -0
- PUI/wx/dialog.py +66 -0
- PUI/wx/divider.py +19 -0
- PUI/wx/label.py +18 -0
- PUI/wx/layout.py +52 -0
- PUI/wx/progressbar.py +19 -0
- PUI/wx/radiobutton.py +27 -0
- PUI/wx/scroll.py +55 -0
- PUI/wx/text.py +23 -0
- PUI/wx/textfield.py +66 -0
- PUI/wx/window.py +64 -0
- qpuiq-0.23.dist-info/LICENSE.txt +21 -0
- qpuiq-0.23.dist-info/METADATA +234 -0
- qpuiq-0.23.dist-info/RECORD +104 -0
- qpuiq-0.23.dist-info/WHEEL +5 -0
- qpuiq-0.23.dist-info/top_level.txt +1 -0
PUI/PySide6/table.py
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class QtTableModelAdapter(QtCore.QAbstractTableModel):
|
|
5
|
+
def __init__(self, model: "BaseTableAdapter"):
|
|
6
|
+
super().__init__()
|
|
7
|
+
self.model = model
|
|
8
|
+
|
|
9
|
+
def data(self, index, role):
|
|
10
|
+
if role == QtCore.Qt.DisplayRole:
|
|
11
|
+
return self.model.data(index.row(), index.column())
|
|
12
|
+
elif role == QtCore.Qt.EditRole:
|
|
13
|
+
return self.model.editData(index.row(), index.column())
|
|
14
|
+
|
|
15
|
+
def setData(self, index, value, role):
|
|
16
|
+
if role == QtCore.Qt.EditRole:
|
|
17
|
+
self.model.setData(index.row(), index.column(), value)
|
|
18
|
+
return True
|
|
19
|
+
|
|
20
|
+
def flags(self, index):
|
|
21
|
+
flags = super().flags(index)
|
|
22
|
+
if self.model.editable(index.row(), index.column()):
|
|
23
|
+
flags |= QtCore.Qt.ItemIsEditable
|
|
24
|
+
return flags
|
|
25
|
+
|
|
26
|
+
def headerData(self, section, orientation, role):
|
|
27
|
+
if role == QtCore.Qt.DisplayRole:
|
|
28
|
+
if orientation == QtCore.Qt.Horizontal:
|
|
29
|
+
if hasattr(self.model, "columnHeader"):
|
|
30
|
+
if self.model.columnHeader is None:
|
|
31
|
+
return None
|
|
32
|
+
else:
|
|
33
|
+
return self.model.columnHeader(section)
|
|
34
|
+
else:
|
|
35
|
+
return super().headerData(section, orientation, role)
|
|
36
|
+
else:
|
|
37
|
+
if hasattr(self.model, "rowHeader"):
|
|
38
|
+
if self.model.rowHeader is None:
|
|
39
|
+
return None
|
|
40
|
+
else:
|
|
41
|
+
return self.model.rowHeader(section)
|
|
42
|
+
else:
|
|
43
|
+
return super().headerData(section, orientation, role)
|
|
44
|
+
|
|
45
|
+
def rowCount(self, index):
|
|
46
|
+
return self.model.rowCount()
|
|
47
|
+
|
|
48
|
+
def columnCount(self, index):
|
|
49
|
+
return self.model.columnCount()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class QtTableNodeModelAdapter(QtCore.QAbstractTableModel):
|
|
53
|
+
def __init__(self, children):
|
|
54
|
+
super().__init__()
|
|
55
|
+
self.children = children
|
|
56
|
+
|
|
57
|
+
def data(self, index, role):
|
|
58
|
+
if role == QtCore.Qt.DisplayRole:
|
|
59
|
+
data = self.children[index.row()].children[index.column()].data
|
|
60
|
+
if isinstance(data, BaseBinding):
|
|
61
|
+
return str(data.value)
|
|
62
|
+
return data
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
def setData(self, index, value, role):
|
|
66
|
+
if role == QtCore.Qt.EditRole:
|
|
67
|
+
n = self.children[index.row()].children[index.column()]
|
|
68
|
+
if isinstance(n.data, BaseBinding):
|
|
69
|
+
n.data.value = value
|
|
70
|
+
else:
|
|
71
|
+
n._set(value)
|
|
72
|
+
return True
|
|
73
|
+
|
|
74
|
+
def flags(self, index):
|
|
75
|
+
flags = super().flags(index)
|
|
76
|
+
n = self.children[index.row()].children[index.column()]
|
|
77
|
+
if isinstance(n.data, BaseBinding) or n._set_callback:
|
|
78
|
+
flags |= QtCore.Qt.ItemIsEditable
|
|
79
|
+
return flags
|
|
80
|
+
|
|
81
|
+
def rowCount(self, index):
|
|
82
|
+
return len(self.children)
|
|
83
|
+
|
|
84
|
+
def columnCount(self, index):
|
|
85
|
+
if self.children:
|
|
86
|
+
return len(self.children[0].children)
|
|
87
|
+
return 0
|
|
88
|
+
|
|
89
|
+
class Table(QtBaseWidget):
|
|
90
|
+
def __init__(self, model=None, autofit=True):
|
|
91
|
+
super().__init__()
|
|
92
|
+
self.layout_weight = 1
|
|
93
|
+
self.model = model
|
|
94
|
+
self.autofit = autofit
|
|
95
|
+
self.curr_model = None
|
|
96
|
+
|
|
97
|
+
def update(self, prev):
|
|
98
|
+
if prev and prev.ui:
|
|
99
|
+
self.ui = prev.ui
|
|
100
|
+
self.qt_model = prev.qt_model
|
|
101
|
+
self.curr_model = prev.curr_model
|
|
102
|
+
else:
|
|
103
|
+
self.qt_model = None
|
|
104
|
+
self.curr_model = Prop()
|
|
105
|
+
self.ui = QtWidgets.QTableView()
|
|
106
|
+
|
|
107
|
+
if self.model:
|
|
108
|
+
if self.model.columnHeader is None:
|
|
109
|
+
self.ui.horizontalHeader().hide()
|
|
110
|
+
else:
|
|
111
|
+
self.ui.horizontalHeader().show()
|
|
112
|
+
|
|
113
|
+
if self.model.rowHeader is None:
|
|
114
|
+
self.ui.verticalHeader().hide()
|
|
115
|
+
else:
|
|
116
|
+
self.ui.verticalHeader().show()
|
|
117
|
+
|
|
118
|
+
if self.curr_model.set(self.model):
|
|
119
|
+
self.qt_model = QtTableModelAdapter(self.model)
|
|
120
|
+
self.ui.setModel(self.qt_model)
|
|
121
|
+
else:
|
|
122
|
+
self.qt_model.refresh()
|
|
123
|
+
else:
|
|
124
|
+
self.ui.horizontalHeader().hide()
|
|
125
|
+
self.ui.verticalHeader().hide()
|
|
126
|
+
self.qt_model = QtTableNodeModelAdapter(self.children)
|
|
127
|
+
self.ui.setModel(self.qt_model)
|
|
128
|
+
|
|
129
|
+
if self.autofit:
|
|
130
|
+
self.ui.resizeColumnsToContents()
|
|
131
|
+
|
|
132
|
+
super().update(prev)
|
|
133
|
+
|
|
134
|
+
class TableNode(PUINode):
|
|
135
|
+
def __init__(self, data=""):
|
|
136
|
+
super().__init__()
|
|
137
|
+
self._set_callback = None
|
|
138
|
+
self.data = data
|
|
139
|
+
|
|
140
|
+
def set(self, cb, *args, **kwargs):
|
|
141
|
+
self._set_callback = (cb, args, kwargs)
|
|
142
|
+
return self
|
|
143
|
+
|
|
144
|
+
def _set(self, data):
|
|
145
|
+
if self._set_callback:
|
|
146
|
+
cb, args, kwargs = self._set_callback
|
|
147
|
+
cb(data, *args, **kwargs)
|
PUI/PySide6/text.py
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
from ..utils import *
|
|
4
|
+
from PySide6.QtWidgets import QSizePolicy
|
|
5
|
+
|
|
6
|
+
class Text(QtBaseWidget):
|
|
7
|
+
textformat = QtCore.Qt.TextFormat.PlainText
|
|
8
|
+
def __init__(self, text, selectable=False):
|
|
9
|
+
super().__init__()
|
|
10
|
+
self.text = str(text)
|
|
11
|
+
self.selectable = selectable
|
|
12
|
+
|
|
13
|
+
def update(self, prev):
|
|
14
|
+
if prev and prev.ui:
|
|
15
|
+
self.ui = prev.ui
|
|
16
|
+
self.ui.setText(self.text)
|
|
17
|
+
else:
|
|
18
|
+
self.ui = QtWidgets.QLabel(self.text)
|
|
19
|
+
self.ui.setTextFormat(self.textformat)
|
|
20
|
+
self.ui.setAlignment(QtCore.Qt.AlignmentFlag.AlignTop)
|
|
21
|
+
self.ui.setWordWrap(True)
|
|
22
|
+
|
|
23
|
+
if self.selectable:
|
|
24
|
+
self.ui.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.TextSelectableByMouse)
|
|
25
|
+
else:
|
|
26
|
+
self.ui.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.NoTextInteraction)
|
|
27
|
+
|
|
28
|
+
super().update(prev)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class Html(Text):
|
|
32
|
+
textformat = QtCore.Qt.TextFormat.RichText
|
|
33
|
+
|
|
34
|
+
class MarkDown(Text):
|
|
35
|
+
textformat = QtCore.Qt.TextFormat.MarkdownText
|
PUI/PySide6/textfield.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class TextField(QtBaseWidget):
|
|
5
|
+
def __init__(self, model, edit_model=None):
|
|
6
|
+
super().__init__()
|
|
7
|
+
self.model = model
|
|
8
|
+
self.edit_model = edit_model
|
|
9
|
+
self.editing = False
|
|
10
|
+
|
|
11
|
+
def update(self, prev):
|
|
12
|
+
model_value = str(self.model.value)
|
|
13
|
+
if prev and prev.ui:
|
|
14
|
+
self.editing = prev.editing
|
|
15
|
+
self.ui = prev.ui
|
|
16
|
+
self.curr_value = prev.curr_value
|
|
17
|
+
self.ui.node = self
|
|
18
|
+
self.ui.textChanged.disconnect()
|
|
19
|
+
if self.curr_value.set(model_value) and not self.editing:
|
|
20
|
+
self.ui.setText(model_value)
|
|
21
|
+
self.ui.textChanged.connect(self.on_textchanged)
|
|
22
|
+
self.ui.editingFinished.disconnect()
|
|
23
|
+
self.ui.editingFinished.connect(self.on_editing_finished)
|
|
24
|
+
else:
|
|
25
|
+
self.ui = QtWidgets.QLineEdit()
|
|
26
|
+
self.ui.setFocusPolicy(QtCore.Qt.ClickFocus | QtCore.Qt.NoFocus)
|
|
27
|
+
self.ui.node = self
|
|
28
|
+
self.ui.setText(model_value)
|
|
29
|
+
self.curr_value = Prop(model_value)
|
|
30
|
+
self.ui.textChanged.connect(self.on_textchanged)
|
|
31
|
+
self.ui.editingFinished.connect(self.on_editing_finished)
|
|
32
|
+
|
|
33
|
+
if self.edit_model and not self.editing:
|
|
34
|
+
self.edit_model.value = model_value
|
|
35
|
+
|
|
36
|
+
super().update(prev)
|
|
37
|
+
|
|
38
|
+
def on_editing_finished(self): # finish editing
|
|
39
|
+
node = self.get_node()
|
|
40
|
+
node.editing = False
|
|
41
|
+
value = self.ui.text()
|
|
42
|
+
node.model.value = value
|
|
43
|
+
if node.edit_model:
|
|
44
|
+
node.edit_model.value = value
|
|
45
|
+
model_value = str(self.model.value)
|
|
46
|
+
self.ui.blockSignals(True)
|
|
47
|
+
self.ui.setText(model_value)
|
|
48
|
+
self.ui.blockSignals(False)
|
|
49
|
+
e = PUIEvent()
|
|
50
|
+
e.value = value
|
|
51
|
+
self._change(e)
|
|
52
|
+
node.ui.clearFocus()
|
|
53
|
+
|
|
54
|
+
def on_textchanged(self): # editing
|
|
55
|
+
node = self.get_node()
|
|
56
|
+
self.editing = True
|
|
57
|
+
value = self.ui.text()
|
|
58
|
+
if node.edit_model:
|
|
59
|
+
node.edit_model.value = value
|
|
60
|
+
e = PUIEvent()
|
|
61
|
+
e.value = value
|
|
62
|
+
self._input(e)
|
PUI/PySide6/toolbar.py
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
|
|
4
|
+
class ToolBar(PUINode):
|
|
5
|
+
pui_outoforder = True
|
|
6
|
+
def update(self, prev):
|
|
7
|
+
if prev and prev.ui:
|
|
8
|
+
self.ui = prev.ui
|
|
9
|
+
self.actions = prev.actions
|
|
10
|
+
else:
|
|
11
|
+
self.ui = QtWidgets.QToolBar()
|
|
12
|
+
self.actions = []
|
|
13
|
+
|
|
14
|
+
super().update(prev)
|
|
15
|
+
|
|
16
|
+
def addChild(self, idx, child):
|
|
17
|
+
if idx < len(self.actions):
|
|
18
|
+
if isinstance(child, ToolBarAction):
|
|
19
|
+
self.actions.insert(idx, self.ui.insertAction(self.actions[idx], child.outer))
|
|
20
|
+
else:
|
|
21
|
+
self.actions.insert(idx, self.ui.insertWidget(self.actions[idx], child.outer))
|
|
22
|
+
else:
|
|
23
|
+
if isinstance(child, ToolBarAction):
|
|
24
|
+
self.actions.append(self.ui.addAction(child.outer))
|
|
25
|
+
else:
|
|
26
|
+
self.actions.append(self.ui.addWidget(child.outer))
|
|
27
|
+
|
|
28
|
+
def removeChild(self, idx, child):
|
|
29
|
+
self.ui.removeAction(self.actions[idx])
|
|
30
|
+
|
|
31
|
+
class ToolBarAction(PUINode):
|
|
32
|
+
def __init__(self, text, icon=None):
|
|
33
|
+
super().__init__()
|
|
34
|
+
self.text = text
|
|
35
|
+
self.icon = icon
|
|
36
|
+
self.onTriggered = None
|
|
37
|
+
|
|
38
|
+
def update(self, prev):
|
|
39
|
+
if prev and prev.ui:
|
|
40
|
+
self.ui = prev.ui
|
|
41
|
+
self.ui.setText(self.text)
|
|
42
|
+
self.ui.triggered.disconnect()
|
|
43
|
+
else:
|
|
44
|
+
self.ui = QtGui.QAction(self.text)
|
|
45
|
+
if self.icon:
|
|
46
|
+
self.ui.setIcon(self.icon)
|
|
47
|
+
self.ui.triggered.connect(self._triggered)
|
|
48
|
+
|
|
49
|
+
super().update(prev)
|
|
50
|
+
|
|
51
|
+
def _triggered(self):
|
|
52
|
+
node = self.get_node()
|
|
53
|
+
if node.onTriggered:
|
|
54
|
+
node.onTriggered[0](*node.onTriggered[1], **node.onTriggered[2])
|
|
55
|
+
|
|
56
|
+
def trigger(self, callback, *cb_args, **cb_kwargs):
|
|
57
|
+
self.onTriggered = (callback, cb_args, cb_kwargs)
|
PUI/PySide6/tree.py
ADDED
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
from PySide6.QtCore import Qt, QModelIndex, QAbstractItemModel
|
|
4
|
+
|
|
5
|
+
# XXX
|
|
6
|
+
# If click handler triggers a model reset, dblclick handler will not be called
|
|
7
|
+
|
|
8
|
+
class QAbstractItemModelAdapter(QtCore.QAbstractItemModel):
|
|
9
|
+
def __init__(self, model: "BaseTreeAdapter"):
|
|
10
|
+
super().__init__()
|
|
11
|
+
self.model = model
|
|
12
|
+
self.node = None
|
|
13
|
+
|
|
14
|
+
def index(self, row, column, parent = QtCore.QModelIndex()):
|
|
15
|
+
parent_node = parent.internalPointer() if parent.isValid() else None
|
|
16
|
+
if 0 <= row and row < self.model.rowCount(parent_node):
|
|
17
|
+
child = self.model.child(parent_node, row)
|
|
18
|
+
return self.createIndex(row, column, child)
|
|
19
|
+
return QtCore.QModelIndex()
|
|
20
|
+
|
|
21
|
+
def flags(self, index):
|
|
22
|
+
if not index.isValid():
|
|
23
|
+
return QtCore.Qt.ItemIsDropEnabled
|
|
24
|
+
|
|
25
|
+
defaultFlags = super().flags(index)
|
|
26
|
+
|
|
27
|
+
return defaultFlags | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled
|
|
28
|
+
|
|
29
|
+
def canDropMimeData(self, data, action, row, column, parent):
|
|
30
|
+
if parent.isValid():
|
|
31
|
+
pass
|
|
32
|
+
else:
|
|
33
|
+
return bool(self.node._onDropped)
|
|
34
|
+
|
|
35
|
+
def dropMimeData(self, data, action, row, column, parent):
|
|
36
|
+
if parent.isValid():
|
|
37
|
+
pass
|
|
38
|
+
else:
|
|
39
|
+
event = QtGui.QDropEvent(QtCore.QPoint(0,0), action, data, QtCore.Qt.MouseButton.LeftButton, QtCore.Qt.KeyboardModifier.NoModifier, QtCore.QEvent.Drop)
|
|
40
|
+
self.node._onDropped[0](event, *self.node._onDropped[1], **self.node._onDropped[2])
|
|
41
|
+
|
|
42
|
+
def parent(self, index):
|
|
43
|
+
if not index.isValid():
|
|
44
|
+
return QModelIndex()
|
|
45
|
+
node = index.internalPointer()
|
|
46
|
+
parent_node = self.model.parent(node)
|
|
47
|
+
if parent_node:
|
|
48
|
+
return self.createIndex(0, 0, parent_node)
|
|
49
|
+
return QModelIndex()
|
|
50
|
+
|
|
51
|
+
def data(self, index, role):
|
|
52
|
+
if not index.isValid():
|
|
53
|
+
return None
|
|
54
|
+
node = index.internalPointer()
|
|
55
|
+
if role == QtCore.Qt.DisplayRole:
|
|
56
|
+
return self.model.data(node)
|
|
57
|
+
return None
|
|
58
|
+
|
|
59
|
+
def rowCount(self, parent):
|
|
60
|
+
parent_node = parent.internalPointer() if parent.isValid() else None
|
|
61
|
+
return self.model.rowCount(parent_node)
|
|
62
|
+
|
|
63
|
+
def columnCount(self, parent):
|
|
64
|
+
return 1
|
|
65
|
+
|
|
66
|
+
def hasChildren(self, parent):
|
|
67
|
+
parent_node = parent.internalPointer() if parent.isValid() else None
|
|
68
|
+
return self.model.rowCount(parent_node) > 0
|
|
69
|
+
|
|
70
|
+
def clicked(self, node):
|
|
71
|
+
self.model.clicked(node)
|
|
72
|
+
|
|
73
|
+
def dblclicked(self, node):
|
|
74
|
+
self.model.dblclicked(node)
|
|
75
|
+
|
|
76
|
+
def expanded(self, node):
|
|
77
|
+
self.model.expanded(node)
|
|
78
|
+
|
|
79
|
+
def collapsed(self, node):
|
|
80
|
+
self.model.collapsed(node)
|
|
81
|
+
|
|
82
|
+
class QTreeNodeModelAdapter(QtCore.QAbstractItemModel):
|
|
83
|
+
def __init__(self):
|
|
84
|
+
super().__init__()
|
|
85
|
+
self.node = None
|
|
86
|
+
|
|
87
|
+
def index(self, row, column, parent = QtCore.QModelIndex()):
|
|
88
|
+
parent_node = parent.internalPointer() if parent.isValid() else self.node
|
|
89
|
+
if 0 <= row and row < len(parent_node.children):
|
|
90
|
+
child = parent_node.children[row]
|
|
91
|
+
return self.createIndex(row, column, child)
|
|
92
|
+
return QtCore.QModelIndex()
|
|
93
|
+
|
|
94
|
+
def flags(self, index):
|
|
95
|
+
if not index.isValid():
|
|
96
|
+
return QtCore.Qt.ItemIsDropEnabled
|
|
97
|
+
|
|
98
|
+
defaultFlags = super().flags(index)
|
|
99
|
+
|
|
100
|
+
return defaultFlags | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled
|
|
101
|
+
|
|
102
|
+
def canDropMimeData(self, data, action, row, column, parent):
|
|
103
|
+
if parent.isValid():
|
|
104
|
+
pass
|
|
105
|
+
else:
|
|
106
|
+
return bool(self.node._onDropped)
|
|
107
|
+
|
|
108
|
+
def dropMimeData(self, data, action, row, column, parent):
|
|
109
|
+
if parent.isValid():
|
|
110
|
+
pass
|
|
111
|
+
else:
|
|
112
|
+
event = QtGui.QDropEvent(QtCore.QPoint(0,0), action, data, QtCore.Qt.MouseButton.LeftButton, QtCore.Qt.KeyboardModifier.NoModifier, QtCore.QEvent.Drop)
|
|
113
|
+
self.node._onDropped[0](event, *self.node._onDropped[1], **self.node._onDropped[2])
|
|
114
|
+
|
|
115
|
+
def parent(self, index):
|
|
116
|
+
if not index.isValid():
|
|
117
|
+
return QModelIndex()
|
|
118
|
+
node = index.internalPointer()
|
|
119
|
+
parent_node = node.parent
|
|
120
|
+
if not isinstance(parent_node, TreeNode):
|
|
121
|
+
parent_node = None
|
|
122
|
+
if parent_node:
|
|
123
|
+
return self.createIndex(0, 0, parent_node)
|
|
124
|
+
return QModelIndex()
|
|
125
|
+
|
|
126
|
+
def data(self, index, role):
|
|
127
|
+
if not index.isValid():
|
|
128
|
+
return None
|
|
129
|
+
node = index.internalPointer()
|
|
130
|
+
if role == QtCore.Qt.DisplayRole:
|
|
131
|
+
return node.data
|
|
132
|
+
return None
|
|
133
|
+
|
|
134
|
+
def rowCount(self, parent):
|
|
135
|
+
parent_node = parent.internalPointer() if parent.isValid() else self.node
|
|
136
|
+
return len(parent_node.children)
|
|
137
|
+
|
|
138
|
+
def columnCount(self, parent):
|
|
139
|
+
return 1
|
|
140
|
+
|
|
141
|
+
def hasChildren(self, parent):
|
|
142
|
+
parent_node = parent.internalPointer() if parent.isValid() else self.node
|
|
143
|
+
return len(parent_node.children) > 0
|
|
144
|
+
|
|
145
|
+
def clicked(self, node):
|
|
146
|
+
node._clicked(None)
|
|
147
|
+
|
|
148
|
+
def dblclicked(self, node):
|
|
149
|
+
node._dblclicked(None)
|
|
150
|
+
|
|
151
|
+
def expanded(self, node):
|
|
152
|
+
node._expanded()
|
|
153
|
+
|
|
154
|
+
def collapsed(self, node):
|
|
155
|
+
node._collapsed()
|
|
156
|
+
|
|
157
|
+
class Tree(QtBaseWidget):
|
|
158
|
+
def __init__(self, model=None):
|
|
159
|
+
super().__init__()
|
|
160
|
+
self.layout_weight = 1
|
|
161
|
+
self.model = model
|
|
162
|
+
self.curr_model = None
|
|
163
|
+
self.pendings = []
|
|
164
|
+
self._expand_callback = None
|
|
165
|
+
self._collapse_callback = None
|
|
166
|
+
|
|
167
|
+
def update(self, prev):
|
|
168
|
+
if prev and prev.ui:
|
|
169
|
+
self.ui = prev.ui
|
|
170
|
+
self.qt_model = prev.qt_model
|
|
171
|
+
self.curr_model = prev.curr_model
|
|
172
|
+
|
|
173
|
+
self.ui.clicked.disconnect()
|
|
174
|
+
self.ui.doubleClicked.disconnect()
|
|
175
|
+
self.ui.expanded.disconnect()
|
|
176
|
+
self.ui.collapsed.disconnect()
|
|
177
|
+
else:
|
|
178
|
+
self.qt_model = None
|
|
179
|
+
self.curr_model = Prop()
|
|
180
|
+
self.ui = QtWidgets.QTreeView()
|
|
181
|
+
self.ui.setHeaderHidden(True)
|
|
182
|
+
|
|
183
|
+
self.ui.clicked.connect(self.on_item_clicked)
|
|
184
|
+
self.ui.doubleClicked.connect(self.on_item_double_clicked)
|
|
185
|
+
self.ui.expanded.connect(self.on_item_expanded)
|
|
186
|
+
self.ui.collapsed.connect(self.on_item_collapsed)
|
|
187
|
+
|
|
188
|
+
if self.model:
|
|
189
|
+
if self.curr_model.set(self.model):
|
|
190
|
+
self.qt_model = QAbstractItemModelAdapter(self.model)
|
|
191
|
+
self.qt_model.node = self
|
|
192
|
+
self.ui.setModel(self.qt_model)
|
|
193
|
+
else:
|
|
194
|
+
self.qt_model.modelReset.emit()
|
|
195
|
+
else:
|
|
196
|
+
if not self.qt_model:
|
|
197
|
+
self.qt_model = QTreeNodeModelAdapter()
|
|
198
|
+
self.qt_model.node = self
|
|
199
|
+
self.ui.setModel(self.qt_model)
|
|
200
|
+
else:
|
|
201
|
+
self.qt_model.beginResetModel()
|
|
202
|
+
self.qt_model.node = self
|
|
203
|
+
self.qt_model.endResetModel()
|
|
204
|
+
|
|
205
|
+
for pending in self.pendings:
|
|
206
|
+
pending[0](*pending[1:])
|
|
207
|
+
self.pendings = []
|
|
208
|
+
|
|
209
|
+
super().update(prev)
|
|
210
|
+
|
|
211
|
+
def expandAll(self):
|
|
212
|
+
if self.ui:
|
|
213
|
+
self.ui.expandAll()
|
|
214
|
+
else:
|
|
215
|
+
self.pendings.append([self.expandAll])
|
|
216
|
+
return self
|
|
217
|
+
|
|
218
|
+
def collapseAll(self):
|
|
219
|
+
if self.ui:
|
|
220
|
+
self.ui.collapseAll()
|
|
221
|
+
else:
|
|
222
|
+
self.pendings.append([self.collapseAll])
|
|
223
|
+
return self
|
|
224
|
+
|
|
225
|
+
def expandable(self, enabled):
|
|
226
|
+
if self.ui:
|
|
227
|
+
self.ui.setItemsExpandable(enabled)
|
|
228
|
+
else:
|
|
229
|
+
self.pendings.append([self.expandable, enabled])
|
|
230
|
+
return self
|
|
231
|
+
|
|
232
|
+
def expand(self, cb, *args, **kwargs):
|
|
233
|
+
self._expand_callback = (cb, args, kwargs)
|
|
234
|
+
return self
|
|
235
|
+
|
|
236
|
+
def _expanded(self):
|
|
237
|
+
if self._expand_callback:
|
|
238
|
+
cb, args, kwargs = self._expand_callback
|
|
239
|
+
cb(*args, **kwargs)
|
|
240
|
+
|
|
241
|
+
def collapse(self, cb, *args, **kwargs):
|
|
242
|
+
self._collapse_callback = (cb, args, kwargs)
|
|
243
|
+
return self
|
|
244
|
+
|
|
245
|
+
def _collapsed(self):
|
|
246
|
+
if self._collapse_callback:
|
|
247
|
+
cb, args, kwargs = self._collapse_callback
|
|
248
|
+
cb(*args, **kwargs)
|
|
249
|
+
|
|
250
|
+
def on_item_clicked(self, index):
|
|
251
|
+
treenode = index.internalPointer()
|
|
252
|
+
self.get_node().qt_model.clicked(treenode)
|
|
253
|
+
|
|
254
|
+
def on_item_double_clicked(self, index):
|
|
255
|
+
treenode = index.internalPointer()
|
|
256
|
+
self.get_node().qt_model.dblclicked(treenode)
|
|
257
|
+
|
|
258
|
+
def on_item_expanded(self, index):
|
|
259
|
+
treenode = index.internalPointer()
|
|
260
|
+
self.get_node().qt_model.expanded(treenode)
|
|
261
|
+
|
|
262
|
+
def on_item_collapsed(self, index):
|
|
263
|
+
treenode = index.internalPointer()
|
|
264
|
+
self.get_node().qt_model.collapsed(treenode)
|
|
265
|
+
|
|
266
|
+
class TreeNode(PUINode):
|
|
267
|
+
def __init__(self, data=""):
|
|
268
|
+
super().__init__()
|
|
269
|
+
self._set_callback = None
|
|
270
|
+
self.data = data
|
|
271
|
+
self._expand_callback = None
|
|
272
|
+
self._collapse_callback = None
|
|
273
|
+
|
|
274
|
+
def expand(self, cb, *args, **kwargs):
|
|
275
|
+
self._expand_callback = (cb, args, kwargs)
|
|
276
|
+
return self
|
|
277
|
+
|
|
278
|
+
def _expanded(self):
|
|
279
|
+
if self._expand_callback:
|
|
280
|
+
cb, args, kwargs = self._expand_callback
|
|
281
|
+
cb(*args, **kwargs)
|
|
282
|
+
|
|
283
|
+
def collapse(self, cb, *args, **kwargs):
|
|
284
|
+
self._collapse_callback = (cb, args, kwargs)
|
|
285
|
+
return self
|
|
286
|
+
|
|
287
|
+
def _collapsed(self):
|
|
288
|
+
if self._collapse_callback:
|
|
289
|
+
cb, args, kwargs = self._collapse_callback
|
|
290
|
+
cb(*args, **kwargs)
|
PUI/PySide6/window.py
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from .. import *
|
|
2
|
+
from .base import *
|
|
3
|
+
from .menu import *
|
|
4
|
+
from .modal import *
|
|
5
|
+
from .toolbar import *
|
|
6
|
+
from PySide6 import QtWidgets
|
|
7
|
+
|
|
8
|
+
class QMainWindow(QtWidgets.QMainWindow):
|
|
9
|
+
def keyPressEvent(self, event):
|
|
10
|
+
e = PUIEvent()
|
|
11
|
+
e.text = event.text()
|
|
12
|
+
self.puinode._keypress(e)
|
|
13
|
+
|
|
14
|
+
def mousePressEvent(self, event):
|
|
15
|
+
focused_widget = QtWidgets.QApplication.focusWidget()
|
|
16
|
+
if isinstance(focused_widget, QtWidgets.QLineEdit):
|
|
17
|
+
focused_widget.clearFocus()
|
|
18
|
+
super().mousePressEvent(event)
|
|
19
|
+
|
|
20
|
+
class Window(QtBaseWidget):
|
|
21
|
+
pui_terminal = False
|
|
22
|
+
|
|
23
|
+
def __init__(self, title=None, icon=None, size=None, maximize=None, fullscreen=None):
|
|
24
|
+
super().__init__()
|
|
25
|
+
self.title = title
|
|
26
|
+
if icon:
|
|
27
|
+
self.icon = QtGui.QIcon(icon)
|
|
28
|
+
else:
|
|
29
|
+
self.icon = None
|
|
30
|
+
self.size = size
|
|
31
|
+
self.maximize = maximize
|
|
32
|
+
self.fullscreen = fullscreen
|
|
33
|
+
|
|
34
|
+
def update(self, prev=None):
|
|
35
|
+
if prev and prev.ui:
|
|
36
|
+
self.ui = prev.ui
|
|
37
|
+
self.ui.puinode = self
|
|
38
|
+
self.curr_size = prev.curr_size
|
|
39
|
+
self.curr_maximize = prev.curr_maximize
|
|
40
|
+
self.curr_fullscreen = prev.curr_fullscreen
|
|
41
|
+
else:
|
|
42
|
+
self.ui = QMainWindow()
|
|
43
|
+
self.ui.puinode = self
|
|
44
|
+
self.ui.show()
|
|
45
|
+
self.curr_size = Prop()
|
|
46
|
+
self.curr_maximize = Prop()
|
|
47
|
+
self.curr_fullscreen = Prop()
|
|
48
|
+
|
|
49
|
+
if self.curr_size.set(self.size):
|
|
50
|
+
self.ui.resize(*self.size)
|
|
51
|
+
if self.curr_maximize.set(self.maximize):
|
|
52
|
+
self.ui.resize(800, 600) # workaround on windows ref: https://stackoverflow.com/questions/27157312/qt-showmaximized-not-working-in-windows
|
|
53
|
+
self.ui.showMaximized()
|
|
54
|
+
if self.curr_fullscreen.set(self.fullscreen):
|
|
55
|
+
self.ui.showFullScreen()
|
|
56
|
+
if not self.title is None:
|
|
57
|
+
self.ui.setWindowTitle(self.title)
|
|
58
|
+
if not self.icon is None:
|
|
59
|
+
self.ui.setWindowIcon(self.icon)
|
|
60
|
+
super().update(prev)
|
|
61
|
+
|
|
62
|
+
def addChild(self, idx, child):
|
|
63
|
+
if isinstance(child, MenuBar):
|
|
64
|
+
self.ui.setMenuBar(child.outer)
|
|
65
|
+
elif isinstance(child, ToolBar):
|
|
66
|
+
self.ui.addToolBar(child.outer)
|
|
67
|
+
elif isinstance(child, Modal):
|
|
68
|
+
pass
|
|
69
|
+
elif isinstance(child, QtBaseWidget) or isinstance(child, QtBaseLayout):
|
|
70
|
+
self.ui.setCentralWidget(child.outer)
|
|
71
|
+
else:
|
|
72
|
+
self.addChild(idx, child.children[0])
|
|
73
|
+
|
|
74
|
+
def removeChild(self, idx, child):
|
|
75
|
+
if isinstance(child, MenuBar):
|
|
76
|
+
child.outer.close()
|
|
77
|
+
elif isinstance(child, Modal):
|
|
78
|
+
pass
|
|
79
|
+
elif isinstance(child, QtBaseWidget) or isinstance(child, QtBaseLayout):
|
|
80
|
+
child.outer.setParent(None)
|
|
81
|
+
else:
|
|
82
|
+
self.removeChild(idx, child.children[0])
|