pygpt-net 2.6.20__py3-none-any.whl → 2.6.22__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.
- pygpt_net/CHANGELOG.txt +13 -0
- pygpt_net/__init__.py +3 -3
- pygpt_net/app.py +3 -1
- pygpt_net/controller/__init__.py +4 -8
- pygpt_net/controller/access/voice.py +2 -2
- pygpt_net/controller/agent/agent.py +130 -2
- pygpt_net/controller/agent/experts.py +93 -96
- pygpt_net/controller/agent/llama.py +2 -1
- pygpt_net/controller/assistant/assistant.py +18 -1
- pygpt_net/controller/assistant/batch.py +2 -3
- pygpt_net/controller/assistant/editor.py +2 -2
- pygpt_net/controller/assistant/files.py +2 -3
- pygpt_net/controller/assistant/store.py +2 -2
- pygpt_net/controller/attachment/attachment.py +17 -1
- pygpt_net/controller/audio/audio.py +2 -2
- pygpt_net/controller/camera/camera.py +15 -7
- pygpt_net/controller/chat/chat.py +2 -2
- pygpt_net/controller/chat/common.py +50 -33
- pygpt_net/controller/chat/image.py +67 -77
- pygpt_net/controller/chat/input.py +94 -166
- pygpt_net/controller/chat/output.py +83 -140
- pygpt_net/controller/chat/response.py +83 -102
- pygpt_net/controller/chat/text.py +116 -149
- pygpt_net/controller/ctx/common.py +2 -1
- pygpt_net/controller/ctx/ctx.py +87 -6
- pygpt_net/controller/files/files.py +13 -1
- pygpt_net/controller/idx/idx.py +26 -2
- pygpt_net/controller/idx/indexer.py +85 -76
- pygpt_net/controller/kernel/reply.py +53 -66
- pygpt_net/controller/kernel/stack.py +16 -16
- pygpt_net/controller/lang/lang.py +52 -34
- pygpt_net/controller/model/importer.py +3 -2
- pygpt_net/controller/model/model.py +62 -3
- pygpt_net/controller/notepad/notepad.py +86 -84
- pygpt_net/controller/plugins/settings.py +3 -4
- pygpt_net/controller/settings/editor.py +4 -4
- pygpt_net/controller/settings/profile.py +105 -124
- pygpt_net/controller/theme/menu.py +154 -57
- pygpt_net/controller/theme/nodes.py +51 -44
- pygpt_net/controller/theme/theme.py +33 -9
- pygpt_net/controller/tools/tools.py +2 -2
- pygpt_net/controller/ui/tabs.py +2 -3
- pygpt_net/controller/ui/ui.py +16 -2
- pygpt_net/core/agents/observer/evaluation.py +3 -3
- pygpt_net/core/agents/provider.py +25 -3
- pygpt_net/core/agents/runner.py +4 -1
- pygpt_net/core/agents/runners/llama_workflow.py +19 -7
- pygpt_net/core/agents/runners/loop.py +3 -1
- pygpt_net/core/agents/runners/openai_workflow.py +17 -3
- pygpt_net/core/agents/tools.py +4 -1
- pygpt_net/core/bridge/context.py +34 -37
- pygpt_net/core/ctx/container.py +13 -12
- pygpt_net/core/ctx/ctx.py +1 -1
- pygpt_net/core/ctx/output.py +7 -4
- pygpt_net/core/db/database.py +2 -2
- pygpt_net/core/debug/console/console.py +2 -2
- pygpt_net/core/debug/debug.py +12 -1
- pygpt_net/core/dispatcher/dispatcher.py +24 -1
- pygpt_net/core/events/app.py +7 -7
- pygpt_net/core/events/control.py +26 -26
- pygpt_net/core/events/event.py +6 -3
- pygpt_net/core/events/kernel.py +2 -2
- pygpt_net/core/events/render.py +13 -13
- pygpt_net/core/experts/experts.py +76 -82
- pygpt_net/core/experts/worker.py +12 -12
- pygpt_net/core/filesystem/actions.py +1 -2
- pygpt_net/core/models/models.py +5 -1
- pygpt_net/core/models/ollama.py +14 -5
- pygpt_net/core/render/plain/helpers.py +2 -5
- pygpt_net/core/render/plain/renderer.py +26 -30
- pygpt_net/core/render/web/body.py +1 -1
- pygpt_net/core/render/web/helpers.py +2 -2
- pygpt_net/core/render/web/renderer.py +4 -4
- pygpt_net/core/settings/settings.py +43 -13
- pygpt_net/core/tabs/tabs.py +20 -13
- pygpt_net/core/types/__init__.py +2 -1
- pygpt_net/core/types/agent.py +4 -4
- pygpt_net/core/types/base.py +19 -0
- pygpt_net/core/types/console.py +6 -6
- pygpt_net/core/types/mode.py +8 -8
- pygpt_net/core/types/multimodal.py +3 -3
- pygpt_net/core/types/openai.py +2 -1
- pygpt_net/data/config/config.json +5 -5
- pygpt_net/data/config/models.json +19 -3
- pygpt_net/data/config/settings.json +14 -14
- pygpt_net/data/locale/locale.de.ini +4 -1
- pygpt_net/data/locale/locale.en.ini +6 -3
- pygpt_net/data/locale/locale.es.ini +4 -1
- pygpt_net/data/locale/locale.fr.ini +4 -1
- pygpt_net/data/locale/locale.it.ini +4 -1
- pygpt_net/data/locale/locale.pl.ini +5 -4
- pygpt_net/data/locale/locale.uk.ini +4 -1
- pygpt_net/data/locale/locale.zh.ini +4 -1
- pygpt_net/item/ctx.py +256 -240
- pygpt_net/item/model.py +59 -116
- pygpt_net/item/preset.py +122 -105
- pygpt_net/plugin/twitter/plugin.py +2 -2
- pygpt_net/provider/agents/llama_index/workflow/planner.py +3 -3
- pygpt_net/provider/agents/openai/agent.py +4 -12
- pygpt_net/provider/agents/openai/agent_b2b.py +10 -15
- pygpt_net/provider/agents/openai/agent_planner.py +4 -4
- pygpt_net/provider/agents/openai/agent_with_experts.py +3 -7
- pygpt_net/provider/agents/openai/agent_with_experts_feedback.py +4 -8
- pygpt_net/provider/agents/openai/agent_with_feedback.py +4 -8
- pygpt_net/provider/agents/openai/bot_researcher.py +2 -18
- pygpt_net/provider/agents/openai/bots/__init__.py +0 -0
- pygpt_net/provider/agents/openai/bots/research_bot/__init__.py +0 -0
- pygpt_net/provider/agents/openai/bots/research_bot/agents/__init__.py +0 -0
- pygpt_net/provider/agents/openai/bots/research_bot/agents/planner_agent.py +1 -1
- pygpt_net/provider/agents/openai/bots/research_bot/agents/search_agent.py +1 -0
- pygpt_net/provider/agents/openai/bots/research_bot/agents/writer_agent.py +1 -1
- pygpt_net/provider/agents/openai/bots/research_bot/manager.py +1 -10
- pygpt_net/provider/agents/openai/evolve.py +5 -9
- pygpt_net/provider/agents/openai/supervisor.py +4 -8
- pygpt_net/provider/core/config/patch.py +10 -3
- pygpt_net/provider/core/ctx/db_sqlite/utils.py +43 -43
- pygpt_net/provider/core/model/patch.py +11 -1
- pygpt_net/provider/core/preset/json_file.py +47 -49
- pygpt_net/provider/gpt/agents/experts.py +2 -2
- pygpt_net/tools/audio_transcriber/ui/dialogs.py +44 -54
- pygpt_net/tools/code_interpreter/body.py +1 -2
- pygpt_net/tools/code_interpreter/tool.py +7 -4
- pygpt_net/tools/code_interpreter/ui/html.py +1 -3
- pygpt_net/tools/code_interpreter/ui/widgets.py +2 -3
- pygpt_net/tools/html_canvas/ui/widgets.py +1 -3
- pygpt_net/tools/image_viewer/ui/dialogs.py +40 -37
- pygpt_net/tools/indexer/ui/widgets.py +2 -4
- pygpt_net/tools/media_player/tool.py +2 -5
- pygpt_net/tools/media_player/ui/widgets.py +60 -36
- pygpt_net/tools/text_editor/ui/widgets.py +18 -19
- pygpt_net/tools/translator/ui/widgets.py +39 -35
- pygpt_net/ui/base/context_menu.py +9 -4
- pygpt_net/ui/dialog/db.py +1 -3
- pygpt_net/ui/dialog/models.py +1 -3
- pygpt_net/ui/dialog/models_importer.py +2 -4
- pygpt_net/ui/dialogs.py +34 -30
- pygpt_net/ui/layout/chat/attachments.py +72 -84
- pygpt_net/ui/layout/chat/attachments_ctx.py +40 -44
- pygpt_net/ui/layout/chat/attachments_uploaded.py +36 -39
- pygpt_net/ui/layout/chat/calendar.py +100 -70
- pygpt_net/ui/layout/chat/chat.py +23 -17
- pygpt_net/ui/layout/chat/input.py +95 -118
- pygpt_net/ui/layout/chat/output.py +100 -162
- pygpt_net/ui/layout/chat/painter.py +89 -61
- pygpt_net/ui/layout/ctx/ctx_list.py +43 -52
- pygpt_net/ui/layout/status.py +23 -14
- pygpt_net/ui/layout/toolbox/agent.py +27 -38
- pygpt_net/ui/layout/toolbox/agent_llama.py +42 -45
- pygpt_net/ui/layout/toolbox/assistants.py +42 -38
- pygpt_net/ui/layout/toolbox/computer_env.py +32 -23
- pygpt_net/ui/layout/toolbox/footer.py +13 -16
- pygpt_net/ui/layout/toolbox/image.py +18 -21
- pygpt_net/ui/layout/toolbox/indexes.py +46 -89
- pygpt_net/ui/layout/toolbox/mode.py +20 -7
- pygpt_net/ui/layout/toolbox/model.py +12 -10
- pygpt_net/ui/layout/toolbox/presets.py +68 -52
- pygpt_net/ui/layout/toolbox/prompt.py +31 -58
- pygpt_net/ui/layout/toolbox/toolbox.py +25 -21
- pygpt_net/ui/layout/toolbox/vision.py +20 -22
- pygpt_net/ui/main.py +2 -4
- pygpt_net/ui/menu/about.py +64 -84
- pygpt_net/ui/menu/audio.py +87 -63
- pygpt_net/ui/menu/config.py +121 -127
- pygpt_net/ui/menu/debug.py +69 -76
- pygpt_net/ui/menu/file.py +32 -35
- pygpt_net/ui/menu/menu.py +2 -3
- pygpt_net/ui/menu/plugins.py +69 -33
- pygpt_net/ui/menu/theme.py +45 -46
- pygpt_net/ui/menu/tools.py +56 -60
- pygpt_net/ui/menu/video.py +20 -25
- pygpt_net/ui/tray.py +1 -2
- pygpt_net/ui/widget/audio/bar.py +1 -3
- pygpt_net/ui/widget/audio/input_button.py +3 -4
- pygpt_net/ui/widget/calendar/select.py +1 -2
- pygpt_net/ui/widget/dialog/base.py +12 -9
- pygpt_net/ui/widget/dialog/editor_file.py +20 -23
- pygpt_net/ui/widget/dialog/find.py +25 -24
- pygpt_net/ui/widget/dialog/profile.py +57 -53
- pygpt_net/ui/widget/draw/painter.py +62 -93
- pygpt_net/ui/widget/element/button.py +42 -30
- pygpt_net/ui/widget/element/checkbox.py +23 -15
- pygpt_net/ui/widget/element/group.py +6 -5
- pygpt_net/ui/widget/element/labels.py +1 -2
- pygpt_net/ui/widget/filesystem/explorer.py +93 -102
- pygpt_net/ui/widget/image/display.py +1 -2
- pygpt_net/ui/widget/lists/assistant.py +1 -2
- pygpt_net/ui/widget/lists/attachment.py +1 -2
- pygpt_net/ui/widget/lists/attachment_ctx.py +1 -2
- pygpt_net/ui/widget/lists/context.py +2 -4
- pygpt_net/ui/widget/lists/index.py +1 -2
- pygpt_net/ui/widget/lists/model.py +1 -2
- pygpt_net/ui/widget/lists/model_editor.py +1 -2
- pygpt_net/ui/widget/lists/model_importer.py +1 -2
- pygpt_net/ui/widget/lists/preset.py +1 -2
- pygpt_net/ui/widget/lists/preset_plugins.py +1 -2
- pygpt_net/ui/widget/lists/profile.py +1 -2
- pygpt_net/ui/widget/lists/uploaded.py +1 -2
- pygpt_net/ui/widget/option/checkbox.py +2 -4
- pygpt_net/ui/widget/option/checkbox_list.py +1 -4
- pygpt_net/ui/widget/option/cmd.py +1 -4
- pygpt_net/ui/widget/option/dictionary.py +25 -28
- pygpt_net/ui/widget/option/input.py +1 -3
- pygpt_net/ui/widget/tabs/Input.py +16 -12
- pygpt_net/ui/widget/tabs/body.py +5 -3
- pygpt_net/ui/widget/tabs/layout.py +36 -25
- pygpt_net/ui/widget/tabs/output.py +96 -74
- pygpt_net/ui/widget/textarea/calendar_note.py +1 -2
- pygpt_net/ui/widget/textarea/editor.py +41 -73
- pygpt_net/ui/widget/textarea/find.py +11 -10
- pygpt_net/ui/widget/textarea/html.py +3 -6
- pygpt_net/ui/widget/textarea/input.py +63 -64
- pygpt_net/ui/widget/textarea/notepad.py +54 -38
- pygpt_net/ui/widget/textarea/output.py +65 -54
- pygpt_net/ui/widget/textarea/search_input.py +5 -4
- pygpt_net/ui/widget/textarea/web.py +2 -4
- pygpt_net/ui/widget/vision/camera.py +2 -31
- {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/METADATA +25 -154
- {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/RECORD +218 -217
- {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/LICENSE +0 -0
- {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/WHEEL +0 -0
- {pygpt_net-2.6.20.dist-info → pygpt_net-2.6.22.dist-info}/entry_points.txt +0 -0
|
@@ -6,18 +6,18 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.
|
|
9
|
+
# Updated Date: 2025.08.24 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
import datetime
|
|
13
|
+
from collections import deque
|
|
13
14
|
|
|
14
15
|
from PySide6.QtCore import Qt, QPoint
|
|
15
|
-
from PySide6.QtGui import QImage, QPainter, QPen, QAction, QIcon
|
|
16
|
+
from PySide6.QtGui import QImage, QPainter, QPen, QAction, QIcon
|
|
16
17
|
from PySide6.QtWidgets import QMenu, QWidget, QFileDialog, QMessageBox, QApplication
|
|
17
18
|
|
|
18
19
|
from pygpt_net.core.tabs.tab import Tab
|
|
19
20
|
from pygpt_net.utils import trans
|
|
20
|
-
import pygpt_net.icons_rc
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class PainterWidget(QWidget):
|
|
@@ -31,13 +31,50 @@ class PainterWidget(QWidget):
|
|
|
31
31
|
self.brushColor = Qt.black
|
|
32
32
|
self.lastPoint = QPoint()
|
|
33
33
|
self.originalImage = None
|
|
34
|
-
self.undoStack = []
|
|
35
|
-
self.redoStack = []
|
|
36
34
|
self.undoLimit = 10
|
|
35
|
+
self.undoStack = deque(maxlen=self.undoLimit)
|
|
36
|
+
self.redoStack = deque()
|
|
37
37
|
self.setFocusPolicy(Qt.StrongFocus)
|
|
38
38
|
self.setFocus()
|
|
39
39
|
self.installEventFilter(self)
|
|
40
40
|
self.tab = None
|
|
41
|
+
self._pen = QPen(self.brushColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin)
|
|
42
|
+
self.setAttribute(Qt.WA_OpaquePaintEvent, True)
|
|
43
|
+
self.setAttribute(Qt.WA_StaticContents, True)
|
|
44
|
+
|
|
45
|
+
self._act_undo = QAction(QIcon(":/icons/undo.svg"), trans('action.undo'), self)
|
|
46
|
+
self._act_undo.triggered.connect(self.undo)
|
|
47
|
+
|
|
48
|
+
self._act_redo = QAction(QIcon(":/icons/redo.svg"), trans('action.redo'), self)
|
|
49
|
+
self._act_redo.triggered.connect(self.redo)
|
|
50
|
+
|
|
51
|
+
self._act_copy = QAction(QIcon(":/icons/copy.svg"), trans('action.copy'), self)
|
|
52
|
+
self._act_copy.triggered.connect(self.handle_copy)
|
|
53
|
+
|
|
54
|
+
self._act_paste = QAction(QIcon(":/icons/paste.svg"), trans('action.paste'), self)
|
|
55
|
+
self._act_paste.triggered.connect(self.handle_paste)
|
|
56
|
+
|
|
57
|
+
self._act_open = QAction(QIcon(":/icons/folder_filled.svg"), trans('action.open'), self)
|
|
58
|
+
self._act_open.triggered.connect(self.action_open)
|
|
59
|
+
|
|
60
|
+
self._act_capture = QAction(QIcon(":/icons/fullscreen.svg"), trans('painter.btn.capture'), self)
|
|
61
|
+
self._act_capture.triggered.connect(self.action_capture)
|
|
62
|
+
|
|
63
|
+
self._act_save = QAction(QIcon(":/icons/save.svg"), trans('img.action.save'), self)
|
|
64
|
+
self._act_save.triggered.connect(self.action_save)
|
|
65
|
+
|
|
66
|
+
self._act_clear = QAction(QIcon(":/icons/close.svg"), trans('painter.btn.clear'), self)
|
|
67
|
+
self._act_clear.triggered.connect(self.action_clear)
|
|
68
|
+
|
|
69
|
+
self._ctx_menu = QMenu(self)
|
|
70
|
+
self._ctx_menu.addAction(self._act_undo)
|
|
71
|
+
self._ctx_menu.addAction(self._act_redo)
|
|
72
|
+
self._ctx_menu.addAction(self._act_open)
|
|
73
|
+
self._ctx_menu.addAction(self._act_capture)
|
|
74
|
+
self._ctx_menu.addAction(self._act_copy)
|
|
75
|
+
self._ctx_menu.addAction(self._act_paste)
|
|
76
|
+
self._ctx_menu.addAction(self._act_save)
|
|
77
|
+
self._ctx_menu.addAction(self._act_clear)
|
|
41
78
|
|
|
42
79
|
def set_tab(self, tab: Tab):
|
|
43
80
|
"""
|
|
@@ -67,66 +104,14 @@ class PainterWidget(QWidget):
|
|
|
67
104
|
|
|
68
105
|
:param event: Event
|
|
69
106
|
"""
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
actions['undo'].triggered.connect(
|
|
73
|
-
lambda: self.undo())
|
|
74
|
-
if self.has_undo():
|
|
75
|
-
actions['undo'].setEnabled(True)
|
|
76
|
-
else:
|
|
77
|
-
actions['undo'].setEnabled(False)
|
|
78
|
-
|
|
79
|
-
actions['redo'] = QAction(QIcon(":/icons/redo.svg"), trans('action.redo'), self)
|
|
80
|
-
actions['redo'].triggered.connect(
|
|
81
|
-
lambda: self.redo())
|
|
82
|
-
if self.has_redo():
|
|
83
|
-
actions['redo'].setEnabled(True)
|
|
84
|
-
else:
|
|
85
|
-
actions['redo'].setEnabled(False)
|
|
86
|
-
|
|
87
|
-
actions['copy'] = QAction(QIcon(":/icons/copy.svg"), trans('action.copy'), self)
|
|
88
|
-
actions['copy'].triggered.connect(
|
|
89
|
-
lambda: self.handle_copy()
|
|
90
|
-
)
|
|
107
|
+
self._act_undo.setEnabled(self.has_undo())
|
|
108
|
+
self._act_redo.setEnabled(self.has_redo())
|
|
91
109
|
|
|
92
|
-
is_paste = False
|
|
93
110
|
clipboard = QApplication.clipboard()
|
|
94
111
|
mime_data = clipboard.mimeData()
|
|
95
|
-
|
|
96
|
-
is_paste = True
|
|
112
|
+
self._act_paste.setEnabled(bool(mime_data.hasImage()))
|
|
97
113
|
|
|
98
|
-
|
|
99
|
-
actions['paste'].triggered.connect(
|
|
100
|
-
lambda: self.handle_paste()
|
|
101
|
-
)
|
|
102
|
-
if is_paste:
|
|
103
|
-
actions['paste'].setEnabled(True)
|
|
104
|
-
else:
|
|
105
|
-
actions['paste'].setEnabled(False)
|
|
106
|
-
|
|
107
|
-
actions['open'] = QAction(QIcon(":/icons/folder_filled.svg"), trans('action.open'), self)
|
|
108
|
-
actions['open'].triggered.connect(
|
|
109
|
-
lambda: self.action_open())
|
|
110
|
-
actions['capture'] = QAction(QIcon(":/icons/fullscreen.svg"), trans('painter.btn.capture'), self)
|
|
111
|
-
actions['capture'].triggered.connect(
|
|
112
|
-
lambda: self.action_capture())
|
|
113
|
-
actions['save'] = QAction(QIcon(":/icons/save.svg"), trans('img.action.save'), self)
|
|
114
|
-
actions['save'].triggered.connect(
|
|
115
|
-
lambda: self.action_save())
|
|
116
|
-
actions['clear'] = QAction(QIcon(":/icons/close.svg"), trans('painter.btn.clear'), self)
|
|
117
|
-
actions['clear'].triggered.connect(
|
|
118
|
-
lambda: self.action_clear())
|
|
119
|
-
|
|
120
|
-
menu = QMenu(self)
|
|
121
|
-
menu.addAction(actions['undo'])
|
|
122
|
-
menu.addAction(actions['redo'])
|
|
123
|
-
menu.addAction(actions['open'])
|
|
124
|
-
menu.addAction(actions['capture'])
|
|
125
|
-
menu.addAction(actions['copy'])
|
|
126
|
-
menu.addAction(actions['paste'])
|
|
127
|
-
menu.addAction(actions['save'])
|
|
128
|
-
menu.addAction(actions['clear'])
|
|
129
|
-
menu.exec_(event.globalPos())
|
|
114
|
+
self._ctx_menu.exec(event.globalPos())
|
|
130
115
|
|
|
131
116
|
def action_open(self):
|
|
132
117
|
"""Open the image"""
|
|
@@ -195,7 +180,6 @@ class PainterWidget(QWidget):
|
|
|
195
180
|
if image.width() == self.width():
|
|
196
181
|
new = image
|
|
197
182
|
else:
|
|
198
|
-
# to fit the width
|
|
199
183
|
if image.width() > image.height():
|
|
200
184
|
width = self.width()
|
|
201
185
|
height = (image.height() * self.width()) / image.width()
|
|
@@ -215,11 +199,8 @@ class PainterWidget(QWidget):
|
|
|
215
199
|
Qt.SmoothTransformation,
|
|
216
200
|
)
|
|
217
201
|
|
|
218
|
-
self.image
|
|
219
|
-
self.
|
|
220
|
-
self.height(),
|
|
221
|
-
QImage.Format_RGB32,
|
|
222
|
-
)
|
|
202
|
+
if self.image.size() != self.size():
|
|
203
|
+
self.image = QImage(self.size(), QImage.Format_RGB32)
|
|
223
204
|
self.image.fill(Qt.white)
|
|
224
205
|
painter = QPainter(self.image)
|
|
225
206
|
painter.drawImage(0, 0, new)
|
|
@@ -229,22 +210,20 @@ class PainterWidget(QWidget):
|
|
|
229
210
|
|
|
230
211
|
def saveForUndo(self):
|
|
231
212
|
"""Save current state for undo"""
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
self.undoStack.append(self.image.copy())
|
|
235
|
-
self.redoStack.clear() # clear redo on new action
|
|
213
|
+
self.undoStack.append(QImage(self.image))
|
|
214
|
+
self.redoStack.clear()
|
|
236
215
|
|
|
237
216
|
def undo(self):
|
|
238
217
|
"""Undo the last action"""
|
|
239
218
|
if self.undoStack:
|
|
240
|
-
self.redoStack.append(self.image
|
|
219
|
+
self.redoStack.append(QImage(self.image))
|
|
241
220
|
self.image = self.undoStack.pop()
|
|
242
221
|
self.update()
|
|
243
222
|
|
|
244
223
|
def redo(self):
|
|
245
224
|
"""Redo the last undo action"""
|
|
246
225
|
if self.redoStack:
|
|
247
|
-
self.undoStack.append(self.image
|
|
226
|
+
self.undoStack.append(QImage(self.image))
|
|
248
227
|
self.image = self.redoStack.pop()
|
|
249
228
|
self.update()
|
|
250
229
|
|
|
@@ -263,6 +242,7 @@ class PainterWidget(QWidget):
|
|
|
263
242
|
:param color: Color
|
|
264
243
|
"""
|
|
265
244
|
self.brushColor = color
|
|
245
|
+
self._pen.setColor(color)
|
|
266
246
|
|
|
267
247
|
def set_brush_size(self, size):
|
|
268
248
|
"""
|
|
@@ -271,6 +251,7 @@ class PainterWidget(QWidget):
|
|
|
271
251
|
:param size: Brush size
|
|
272
252
|
"""
|
|
273
253
|
self.brushSize = size
|
|
254
|
+
self._pen.setWidth(size)
|
|
274
255
|
|
|
275
256
|
def clear_image(self):
|
|
276
257
|
"""Clear the image"""
|
|
@@ -289,16 +270,9 @@ class PainterWidget(QWidget):
|
|
|
289
270
|
self.lastPoint = event.pos()
|
|
290
271
|
self.saveForUndo()
|
|
291
272
|
painter = QPainter(self.image)
|
|
292
|
-
painter.setPen(
|
|
293
|
-
QPen(
|
|
294
|
-
self.brushColor,
|
|
295
|
-
self.brushSize,
|
|
296
|
-
Qt.SolidLine,
|
|
297
|
-
Qt.RoundCap,
|
|
298
|
-
Qt.RoundJoin,
|
|
299
|
-
)
|
|
300
|
-
)
|
|
273
|
+
painter.setPen(self._pen)
|
|
301
274
|
painter.drawPoint(self.lastPoint)
|
|
275
|
+
painter.end()
|
|
302
276
|
self.update()
|
|
303
277
|
|
|
304
278
|
def mouseMoveEvent(self, event):
|
|
@@ -309,16 +283,9 @@ class PainterWidget(QWidget):
|
|
|
309
283
|
"""
|
|
310
284
|
if (event.buttons() & Qt.LeftButton) and self.drawing:
|
|
311
285
|
painter = QPainter(self.image)
|
|
312
|
-
painter.setPen(
|
|
313
|
-
QPen(
|
|
314
|
-
self.brushColor,
|
|
315
|
-
self.brushSize,
|
|
316
|
-
Qt.SolidLine,
|
|
317
|
-
Qt.RoundCap,
|
|
318
|
-
Qt.RoundJoin,
|
|
319
|
-
)
|
|
320
|
-
)
|
|
286
|
+
painter.setPen(self._pen)
|
|
321
287
|
painter.drawLine(self.lastPoint, event.pos())
|
|
288
|
+
painter.end()
|
|
322
289
|
self.lastPoint = event.pos()
|
|
323
290
|
self.update()
|
|
324
291
|
|
|
@@ -350,12 +317,13 @@ class PainterWidget(QWidget):
|
|
|
350
317
|
"""
|
|
351
318
|
painter = QPainter(self)
|
|
352
319
|
painter.drawImage(self.rect(), self.image, self.image.rect())
|
|
320
|
+
painter.end()
|
|
353
321
|
self.originalImage = self.image
|
|
354
322
|
|
|
355
323
|
def resizeEvent(self, event):
|
|
356
324
|
"""
|
|
357
325
|
Update coords on resize
|
|
358
|
-
|
|
326
|
+
|
|
359
327
|
:param event: Event
|
|
360
328
|
"""
|
|
361
329
|
if self.image.size() != self.size():
|
|
@@ -363,6 +331,7 @@ class PainterWidget(QWidget):
|
|
|
363
331
|
new.fill(Qt.white)
|
|
364
332
|
painter = QPainter(new)
|
|
365
333
|
painter.drawImage(QPoint(0, 0), self.image)
|
|
334
|
+
painter.end()
|
|
366
335
|
self.image = new
|
|
367
336
|
|
|
368
337
|
def eventFilter(self, source, event):
|
|
@@ -376,4 +345,4 @@ class PainterWidget(QWidget):
|
|
|
376
345
|
if self.tab is not None:
|
|
377
346
|
col_idx = self.tab.column_idx
|
|
378
347
|
self.window.controller.ui.tabs.on_column_focus(col_idx)
|
|
379
|
-
return super().eventFilter(source, event)
|
|
348
|
+
return super().eventFilter(source, event)
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date:
|
|
9
|
+
# Updated Date: 2025.08.24 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt
|
|
13
|
-
from PySide6.QtGui import
|
|
13
|
+
from PySide6.QtGui import QIcon
|
|
14
14
|
from PySide6.QtWidgets import QPushButton, QMenu
|
|
15
15
|
|
|
16
16
|
from pygpt_net.utils import trans
|
|
@@ -22,13 +22,17 @@ class ContextMenuButton(QPushButton):
|
|
|
22
22
|
self.action = action
|
|
23
23
|
|
|
24
24
|
def mousePressEvent(self, event):
|
|
25
|
-
|
|
25
|
+
btn = event.button()
|
|
26
|
+
if btn == Qt.LeftButton or btn == Qt.RightButton:
|
|
26
27
|
self.action(self, event.pos())
|
|
27
28
|
else:
|
|
28
29
|
super().mousePressEvent(event)
|
|
29
30
|
|
|
30
31
|
|
|
31
32
|
class NewCtxButton(QPushButton):
|
|
33
|
+
_icon_add = None
|
|
34
|
+
_icon_folder_filled = None
|
|
35
|
+
|
|
32
36
|
def __init__(self, title: str = None, window=None):
|
|
33
37
|
super().__init__(title)
|
|
34
38
|
self.window = window
|
|
@@ -36,6 +40,12 @@ class NewCtxButton(QPushButton):
|
|
|
36
40
|
lambda: self.window.controller.ctx.new()
|
|
37
41
|
)
|
|
38
42
|
|
|
43
|
+
@classmethod
|
|
44
|
+
def _ensure_icons(cls):
|
|
45
|
+
if cls._icon_add is None:
|
|
46
|
+
cls._icon_add = QIcon(":/icons/add.svg")
|
|
47
|
+
cls._icon_folder_filled = QIcon(":/icons/folder_filled.svg")
|
|
48
|
+
|
|
39
49
|
def mousePressEvent(self, event):
|
|
40
50
|
if event.button() == Qt.RightButton:
|
|
41
51
|
self.new_context_menu(self, event.pos())
|
|
@@ -49,32 +59,30 @@ class NewCtxButton(QPushButton):
|
|
|
49
59
|
:param parent: parent widget
|
|
50
60
|
:param pos: mouse position
|
|
51
61
|
"""
|
|
62
|
+
type(self)._ensure_icons()
|
|
52
63
|
group_id = self.window.controller.ctx.group_id
|
|
53
|
-
menu = QMenu(
|
|
54
|
-
actions = {}
|
|
55
|
-
actions['new'] = QAction(QIcon(":/icons/add.svg"), trans('action.ctx.new'), self)
|
|
56
|
-
actions['new'].triggered.connect(
|
|
57
|
-
lambda: self.window.controller.ctx.new_ungrouped()
|
|
58
|
-
)
|
|
64
|
+
menu = QMenu(parent)
|
|
59
65
|
if group_id is not None and group_id > 0:
|
|
60
66
|
group_name = self.window.controller.ctx.get_group_name(group_id)
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
act_new_in_group = menu.addAction(type(self)._icon_add, trans('action.ctx.new.in_group').format(group=group_name))
|
|
68
|
+
act_new_in_group.triggered.connect(
|
|
63
69
|
lambda checked=False, id=group_id: self.window.controller.ctx.new(force=False, group_id=id)
|
|
64
70
|
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
lambda: self.window.controller.ctx.
|
|
71
|
+
act_new = menu.addAction(type(self)._icon_add, trans('action.ctx.new'))
|
|
72
|
+
act_new.triggered.connect(
|
|
73
|
+
lambda checked=False: self.window.controller.ctx.new_ungrouped()
|
|
74
|
+
)
|
|
75
|
+
act_new_group = menu.addAction(type(self)._icon_folder_filled, trans('menu.file.group.new'))
|
|
76
|
+
act_new_group.triggered.connect(
|
|
77
|
+
lambda checked=False: self.window.controller.ctx.new_group()
|
|
68
78
|
)
|
|
69
|
-
|
|
70
|
-
if group_id is not None and group_id > 0:
|
|
71
|
-
menu.addAction(actions['new_in_group'])
|
|
72
|
-
menu.addAction(actions['new'])
|
|
73
|
-
menu.addAction(actions['new_group'])
|
|
74
79
|
menu.exec_(parent.mapToGlobal(pos))
|
|
80
|
+
menu.deleteLater()
|
|
75
81
|
|
|
76
82
|
|
|
77
83
|
class SyncButton(QPushButton):
|
|
84
|
+
_icon_download = None
|
|
85
|
+
|
|
78
86
|
def __init__(self, title: str = None, window=None):
|
|
79
87
|
super().__init__(title)
|
|
80
88
|
self.window = window
|
|
@@ -82,6 +90,11 @@ class SyncButton(QPushButton):
|
|
|
82
90
|
lambda: self.window.controller.assistant.batch.import_files_current()
|
|
83
91
|
)
|
|
84
92
|
|
|
93
|
+
@classmethod
|
|
94
|
+
def _ensure_icons(cls):
|
|
95
|
+
if cls._icon_download is None:
|
|
96
|
+
cls._icon_download = QIcon(":/icons/download.svg")
|
|
97
|
+
|
|
85
98
|
def mousePressEvent(self, event):
|
|
86
99
|
if event.button() == Qt.RightButton:
|
|
87
100
|
self.new_context_menu(self, event.pos())
|
|
@@ -95,16 +108,15 @@ class SyncButton(QPushButton):
|
|
|
95
108
|
:param parent: parent widget
|
|
96
109
|
:param pos: mouse position
|
|
97
110
|
"""
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
lambda: self.window.controller.assistant.batch.import_files_current()
|
|
111
|
+
type(self)._ensure_icons()
|
|
112
|
+
menu = QMenu(parent)
|
|
113
|
+
act_current = menu.addAction(type(self)._icon_download, trans('attachments_uploaded.btn.sync.current'))
|
|
114
|
+
act_current.triggered.connect(
|
|
115
|
+
lambda checked=False: self.window.controller.assistant.batch.import_files_current()
|
|
103
116
|
)
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
lambda: self.window.controller.assistant.batch.import_files()
|
|
117
|
+
act_all = menu.addAction(type(self)._icon_download, trans('attachments_uploaded.btn.sync.all'))
|
|
118
|
+
act_all.triggered.connect(
|
|
119
|
+
lambda checked=False: self.window.controller.assistant.batch.import_files()
|
|
107
120
|
)
|
|
108
|
-
menu.
|
|
109
|
-
menu.
|
|
110
|
-
menu.exec_(parent.mapToGlobal(pos))
|
|
121
|
+
menu.exec_(parent.mapToGlobal(pos))
|
|
122
|
+
menu.deleteLater()
|
|
@@ -6,12 +6,12 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date:
|
|
9
|
+
# Updated Date: 2025.08.24 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtWidgets import QWidget, QCheckBox, QHBoxLayout, QLabel
|
|
13
|
-
from PySide6.QtGui import QPainter, QPixmap
|
|
14
|
-
from PySide6.QtCore import Qt
|
|
13
|
+
from PySide6.QtGui import QPainter, QPixmap, QIcon
|
|
14
|
+
from PySide6.QtCore import Qt, QSize
|
|
15
15
|
|
|
16
16
|
from pygpt_net.utils import trans
|
|
17
17
|
|
|
@@ -31,33 +31,36 @@ class ColorCheckbox(QWidget):
|
|
|
31
31
|
layout.addWidget(self.window.ui.nodes['filter.ctx.label.colors'])
|
|
32
32
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
33
33
|
labels = self.window.controller.ui.get_colors()
|
|
34
|
+
icon_size = 20
|
|
35
|
+
icon_qsize = QSize(icon_size, icon_size)
|
|
34
36
|
|
|
35
|
-
for
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
lambda state, idx=id: self.update_colors(state, idx)
|
|
39
|
-
)
|
|
40
|
-
pixmap = QPixmap(20, 20)
|
|
37
|
+
for color_id, status in labels.items():
|
|
38
|
+
cb = QCheckBox(self)
|
|
39
|
+
pixmap = QPixmap(icon_size, icon_size)
|
|
41
40
|
pixmap.fill(Qt.transparent)
|
|
42
41
|
painter = QPainter(pixmap)
|
|
43
42
|
painter.setBrush(status['color'])
|
|
44
|
-
painter.drawRect(0, 0,
|
|
43
|
+
painter.drawRect(0, 0, icon_size, icon_size)
|
|
45
44
|
painter.end()
|
|
46
45
|
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
cb.setIcon(QIcon(pixmap))
|
|
47
|
+
cb.setIconSize(icon_qsize)
|
|
48
|
+
cb.toggled.connect(lambda checked, idx=color_id: self.update_colors(checked, idx))
|
|
49
|
+
self.boxes[color_id] = cb
|
|
50
|
+
layout.addWidget(cb)
|
|
49
51
|
|
|
50
52
|
layout.addStretch()
|
|
51
53
|
self.setLayout(layout)
|
|
52
54
|
|
|
53
|
-
def update_colors(self, state
|
|
55
|
+
def update_colors(self, state, idx: int):
|
|
54
56
|
"""
|
|
55
57
|
Update selected colors list
|
|
56
58
|
|
|
57
59
|
:param state: checkbox state
|
|
58
60
|
:param idx: color index
|
|
59
61
|
"""
|
|
60
|
-
if state ==
|
|
62
|
+
checked = state if isinstance(state, bool) else state == Qt.Checked
|
|
63
|
+
if checked:
|
|
61
64
|
if idx not in self.selected:
|
|
62
65
|
self.selected.append(idx)
|
|
63
66
|
else:
|
|
@@ -74,4 +77,9 @@ class ColorCheckbox(QWidget):
|
|
|
74
77
|
"""
|
|
75
78
|
self.selected = selected
|
|
76
79
|
for idx in selected:
|
|
77
|
-
self.boxes
|
|
80
|
+
cb = self.boxes.get(idx)
|
|
81
|
+
if cb is not None:
|
|
82
|
+
prev = cb.blockSignals(True)
|
|
83
|
+
cb.setChecked(True)
|
|
84
|
+
cb.blockSignals(prev)
|
|
85
|
+
self.window.controller.ctx.label_filters_changed(self.selected)
|
|
@@ -6,15 +6,13 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date:
|
|
9
|
+
# Updated Date: 2025.08.24 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt
|
|
13
13
|
from PySide6.QtGui import QIcon
|
|
14
14
|
from PySide6.QtWidgets import QCheckBox, QWidget, QVBoxLayout, QFrame
|
|
15
15
|
|
|
16
|
-
import pygpt_net.icons_rc
|
|
17
|
-
|
|
18
16
|
|
|
19
17
|
class CollapsedGroup(QWidget):
|
|
20
18
|
def __init__(self, window=None, id=None, title=None, value=False, section=None):
|
|
@@ -54,6 +52,9 @@ class CollapsedGroup(QWidget):
|
|
|
54
52
|
height: 0px;
|
|
55
53
|
}
|
|
56
54
|
""")
|
|
55
|
+
|
|
56
|
+
self._icon_collapse = QIcon(":/icons/collapse.svg")
|
|
57
|
+
self._icon_expand = QIcon(":/icons/expand.svg")
|
|
57
58
|
self.update_icon(self.box.checkState())
|
|
58
59
|
|
|
59
60
|
# options layout
|
|
@@ -78,9 +79,9 @@ class CollapsedGroup(QWidget):
|
|
|
78
79
|
:param state:checkbox state
|
|
79
80
|
"""
|
|
80
81
|
if state == Qt.Checked:
|
|
81
|
-
self.box.setIcon(
|
|
82
|
+
self.box.setIcon(self._icon_collapse)
|
|
82
83
|
else:
|
|
83
|
-
self.box.setIcon(
|
|
84
|
+
self.box.setIcon(self._icon_expand)
|
|
84
85
|
|
|
85
86
|
def collapse(self, value):
|
|
86
87
|
"""
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
# GitHub: https://github.com/szczyglis-dev/py-gpt #
|
|
7
7
|
# MIT License #
|
|
8
8
|
# Created By : Marcin Szczygliński #
|
|
9
|
-
# Updated Date: 2025.08.
|
|
9
|
+
# Updated Date: 2025.08.24 23:00:00 #
|
|
10
10
|
# ================================================== #
|
|
11
11
|
|
|
12
12
|
from PySide6.QtCore import Qt, QTimer, QRect, Signal, QUrl, QEvent
|
|
@@ -14,7 +14,6 @@ from PySide6.QtGui import QCursor, QAction, QIcon, QDesktopServices, QPainter, Q
|
|
|
14
14
|
from PySide6.QtWidgets import QLabel, QLineEdit, QToolTip
|
|
15
15
|
|
|
16
16
|
from pygpt_net.utils import trans
|
|
17
|
-
import pygpt_net.icons_rc
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
class HelpLabel(QLabel):
|