pygpt-net 2.4.54__py3-none-any.whl → 2.4.56__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.
Files changed (77) hide show
  1. CHANGELOG.md +10 -0
  2. README.md +11 -1
  3. pygpt_net/CHANGELOG.txt +10 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/controller/access/__init__.py +1 -3
  6. pygpt_net/controller/access/voice.py +20 -7
  7. pygpt_net/controller/{attachment.py → attachment/__init__.py} +0 -0
  8. pygpt_net/controller/{camera.py → camera/__init__.py} +1 -1
  9. pygpt_net/controller/{files.py → files/__init__.py} +0 -0
  10. pygpt_net/controller/{finder.py → finder/__init__.py} +0 -0
  11. pygpt_net/controller/lang/mapping.py +2 -1
  12. pygpt_net/controller/{launcher.py → launcher/__init__.py} +0 -0
  13. pygpt_net/controller/{layout.py → layout/__init__.py} +0 -0
  14. pygpt_net/controller/{notepad.py → notepad/__init__.py} +0 -0
  15. pygpt_net/controller/settings/editor.py +4 -0
  16. pygpt_net/core/access/shortcuts.py +48 -29
  17. pygpt_net/core/{camera.py → camera/__init__.py} +5 -4
  18. pygpt_net/core/{command.py → command/__init__.py} +4 -3
  19. pygpt_net/core/{dispatcher.py → dispatcher/__init__.py} +0 -0
  20. pygpt_net/core/{history.py → history/__init__.py} +0 -2
  21. pygpt_net/core/{image.py → image/__init__.py} +0 -0
  22. pygpt_net/core/{info.py → info/__init__.py} +0 -0
  23. pygpt_net/core/{locale.py → locale/__init__.py} +0 -0
  24. pygpt_net/core/{notepad.py → notepad/__init__.py} +0 -0
  25. pygpt_net/core/{platforms.py → platforms/__init__.py} +0 -0
  26. pygpt_net/core/{plugins.py → plugins/__init__.py} +0 -0
  27. pygpt_net/core/{settings.py → settings/__init__.py} +0 -0
  28. pygpt_net/core/tabs/__init__.py +8 -6
  29. pygpt_net/core/{tokens.py → tokens/__init__.py} +0 -0
  30. pygpt_net/data/config/config.json +11 -9
  31. pygpt_net/data/config/models.json +3 -3
  32. pygpt_net/data/config/modes.json +3 -3
  33. pygpt_net/data/config/settings.json +24 -0
  34. pygpt_net/data/locale/locale.de.ini +3 -0
  35. pygpt_net/data/locale/locale.en.ini +3 -0
  36. pygpt_net/data/locale/locale.es.ini +3 -0
  37. pygpt_net/data/locale/locale.fr.ini +3 -0
  38. pygpt_net/data/locale/locale.it.ini +3 -0
  39. pygpt_net/data/locale/locale.pl.ini +4 -1
  40. pygpt_net/data/locale/locale.uk.ini +3 -0
  41. pygpt_net/data/locale/locale.zh.ini +3 -0
  42. pygpt_net/launcher.py +3 -2
  43. pygpt_net/plugin/audio_input/simple.py +10 -7
  44. pygpt_net/plugin/audio_input/worker.py +1 -1
  45. pygpt_net/provider/core/config/patch.py +21 -1
  46. pygpt_net/tools/code_interpreter/__init__.py +2 -1
  47. pygpt_net/tools/code_interpreter/ui/dialogs.py +10 -1
  48. pygpt_net/tools/code_interpreter/ui/widgets.py +56 -1
  49. pygpt_net/tools/html_canvas/__init__.py +2 -1
  50. pygpt_net/tools/html_canvas/ui/dialogs.py +10 -1
  51. pygpt_net/tools/html_canvas/ui/widgets.py +33 -1
  52. pygpt_net/ui/__init__.py +1 -1
  53. pygpt_net/ui/layout/chat/calendar.py +5 -2
  54. pygpt_net/ui/layout/chat/explorer.py +4 -2
  55. pygpt_net/ui/layout/chat/painter.py +4 -2
  56. pygpt_net/ui/main.py +63 -2
  57. pygpt_net/ui/widget/calendar/select.py +29 -1
  58. pygpt_net/ui/widget/draw/painter.py +25 -1
  59. pygpt_net/ui/widget/filesystem/explorer.py +24 -1
  60. pygpt_net/ui/widget/tabs/body.py +54 -4
  61. pygpt_net/ui/widget/textarea/calendar_note.py +26 -2
  62. pygpt_net/ui/widget/textarea/html.py +21 -2
  63. pygpt_net/ui/widget/textarea/notepad.py +37 -3
  64. pygpt_net/ui/widget/textarea/web.py +4 -2
  65. {pygpt_net-2.4.54.dist-info → pygpt_net-2.4.56.dist-info}/METADATA +12 -2
  66. {pygpt_net-2.4.54.dist-info → pygpt_net-2.4.56.dist-info}/RECORD +77 -77
  67. /pygpt_net/controller/{command.py → command/__init__.py} +0 -0
  68. /pygpt_net/controller/{mode.py → mode/__init__.py} +0 -0
  69. /pygpt_net/core/{installer.py → installer/__init__.py} +0 -0
  70. /pygpt_net/core/{models.py → models/__init__.py} +0 -0
  71. /pygpt_net/core/{modes.py → modes/__init__.py} +0 -0
  72. /pygpt_net/core/{presets.py → presets/__init__.py} +0 -0
  73. /pygpt_net/core/{profile.py → profile/__init__.py} +0 -0
  74. /pygpt_net/core/{worker.py → worker/__init__.py} +0 -0
  75. {pygpt_net-2.4.54.dist-info → pygpt_net-2.4.56.dist-info}/LICENSE +0 -0
  76. {pygpt_net-2.4.54.dist-info → pygpt_net-2.4.56.dist-info}/WHEEL +0 -0
  77. {pygpt_net-2.4.54.dist-info → pygpt_net-2.4.56.dist-info}/entry_points.txt +0 -0
@@ -878,6 +878,9 @@ settings.audio.input.rate = 采样率
878
878
  settings.audio.input.rate.desc = 采样率,默认: 44100
879
879
  settings.audio.input.stop_interval = 连续录音自动转录间隔
880
880
  settings.audio.input.stop_interval.desc = 自动转录音频片段的间隔(以秒为单位),默认:10
881
+ settings.audio.input.timeout = 录音超时
882
+ settings.audio.input.timeout.desc = 自动停止录音的超时时间(秒),0为禁用,默认:120
883
+ settings.audio.input.timeout.continuous = 在连续模式下启用超时
881
884
  settings.check_updates = 啟動時檢查更新
882
885
  settings.check_updates.bg = 在後台檢查更新
883
886
  settings.cmd.field.desc = 启用 `{cmd}` 工具。
pygpt_net/launcher.py CHANGED
@@ -6,8 +6,9 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.11.20 21:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
+
11
12
  import os
12
13
  import sys
13
14
  import argparse
@@ -266,5 +267,5 @@ class Launcher:
266
267
  self.window.ui.tray.setup(self.app)
267
268
  self.window.controller.after_setup()
268
269
  self.window.dispatch(AppEvent(AppEvent.APP_STARTED)) # app event
269
- self.window.installEventFilter(self.shortcut_filter)
270
+ self.window.setup_global_shortcuts()
270
271
  sys.exit(self.app.exec())
@@ -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.01.17 02:00:00 #
9
+ # Updated Date: 2025.01.18 23:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -20,7 +20,6 @@ from pygpt_net.utils import trans
20
20
 
21
21
  class Simple:
22
22
 
23
- TIMEOUT_SECONDS = 120 # 2 minutes, max recording time before timeout
24
23
  MIN_FRAMES = 25 # minimum frames to start transcription
25
24
 
26
25
  def __init__(self, plugin=None):
@@ -92,10 +91,14 @@ class Simple:
92
91
  )
93
92
 
94
93
  # start timeout timer to prevent infinite recording
95
- if self.timer is None:
96
- self.timer = QTimer()
97
- self.timer.timeout.connect(self.stop_timeout)
98
- self.timer.start(self.TIMEOUT_SECONDS * 1000)
94
+ # disable in continuous mode
95
+ timeout = int(self.plugin.window.core.config.get('audio.input.timeout', 120) or 0) # get timeout
96
+ timeout_continuous = self.plugin.window.core.config.get('audio.input.timeout.continuous', False) # enable continuous timeout
97
+ if timeout > 0:
98
+ if self.timer is None and (not continuous_enabled or timeout_continuous):
99
+ self.timer = QTimer()
100
+ self.timer.timeout.connect(self.stop_timeout)
101
+ self.timer.start(timeout * 1000)
99
102
 
100
103
  if not force:
101
104
  if not self.plugin.window.core.audio.capture.check_audio_input():
@@ -141,7 +144,7 @@ class Simple:
141
144
  self.plugin.window.core.audio.capture.stop() # stop recording
142
145
  # abort if timeout
143
146
  if timeout:
144
- self.plugin.window.update_status("Aborted.".format(self.TIMEOUT_SECONDS))
147
+ self.plugin.window.update_status("Aborted.".format(timeout))
145
148
  return
146
149
 
147
150
  if self.plugin.window.core.audio.capture.has_frames():
@@ -16,7 +16,7 @@ import audioop
16
16
 
17
17
  from PySide6.QtCore import Slot, Signal
18
18
 
19
- from pygpt_net.core.tabs import Tab
19
+ from pygpt_net.core.tabs.tab import Tab
20
20
  from pygpt_net.utils import trans
21
21
  from pygpt_net.plugin.base.worker import BaseWorker, BaseSignals
22
22
 
@@ -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.01.17 02:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import copy
@@ -1811,6 +1811,26 @@ class Patch:
1811
1811
  if 'audio.input.continuous' not in data:
1812
1812
  data["audio.input.continuous"] = False
1813
1813
 
1814
+ # < 2.4.55
1815
+ if old < parse_version("2.4.55"):
1816
+ print("Migrating config from < 2.4.55...")
1817
+ if 'audio.input.timeout' not in data:
1818
+ data["audio.input.timeout"] = 120
1819
+ if 'audio.input.timeout.continuous' not in data:
1820
+ data["audio.input.timeout.continuous"] = False
1821
+
1822
+ # < 2.4.56
1823
+ if old < parse_version("2.4.56"):
1824
+ print("Migrating config from < 2.4.56...")
1825
+ remove_modifiers = ["Meta", "Keypad", "GroupSwitch"]
1826
+ if 'access.shortcuts' in data:
1827
+ for item in data['access.shortcuts']:
1828
+ if 'key_modifier' in item and item['key_modifier'] == 'Control':
1829
+ item['key_modifier'] = 'Ctrl'
1830
+ elif 'key_modifier' in item and item['key_modifier'] in remove_modifiers:
1831
+ item['key_modifier'] = ''
1832
+ updated = True
1833
+
1814
1834
  # update file
1815
1835
  migrated = False
1816
1836
  if updated:
@@ -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: 2024.12.14 22:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -539,6 +539,7 @@ class CodeInterpreter(BaseTool):
539
539
  widget.setLayout(layout)
540
540
  self.load_history()
541
541
  self.load_output()
542
+ tool.set_tab(tab)
542
543
  return widget
543
544
 
544
545
  def setup_dialogs(self):
@@ -6,13 +6,14 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.12.12 01:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt
13
13
  from PySide6.QtGui import QAction, QIcon
14
14
  from PySide6.QtWidgets import QMenuBar
15
15
 
16
+ from pygpt_net.core.tabs.tab import Tab
16
17
  from pygpt_net.tools.code_interpreter.ui.widgets import ToolWidget
17
18
  from pygpt_net.ui.widget.dialog.base import BaseDialog
18
19
  from pygpt_net.utils import trans
@@ -33,6 +34,14 @@ class Tool:
33
34
  self.menu = {}
34
35
  self.actions = {} # menu actions
35
36
 
37
+ def set_tab(self, tab: Tab):
38
+ """
39
+ Set tab
40
+
41
+ :param tab: Tab
42
+ """
43
+ self.widget.set_tab(tab)
44
+
36
45
  def setup_menu(self) -> QMenuBar:
37
46
  """
38
47
  Setup dialog menu
@@ -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: 2024.12.12 01:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6 import QtCore
@@ -42,6 +42,15 @@ class ToolWidget:
42
42
  self.label_output = None # output label
43
43
  self.label_history = None # history label
44
44
 
45
+ def set_tab(self, tab):
46
+ """
47
+ Set tab
48
+
49
+ :param tab: Tab
50
+ """
51
+ self.output.set_tab(tab)
52
+ self.input.set_tab(tab)
53
+
45
54
  def setup(self, all: bool = True) -> QVBoxLayout:
46
55
  """
47
56
  Setup widget body
@@ -297,6 +306,29 @@ class PythonInput(QTextEdit):
297
306
  lambda: self.tool.update_input()
298
307
  )
299
308
  self.setFocus()
309
+ self.tab = None
310
+ self.installEventFilter(self)
311
+
312
+ def set_tab(self, tab):
313
+ """
314
+ Set tab
315
+
316
+ :param tab: Tab
317
+ """
318
+ self.tab = tab
319
+
320
+ def eventFilter(self, source, event):
321
+ """
322
+ Focus event filter
323
+
324
+ :param source: source
325
+ :param event: event
326
+ """
327
+ if event.type() == event.Type.FocusIn:
328
+ if self.tab is not None:
329
+ col_idx = self.tab.column_idx
330
+ self.window.controller.ui.tabs.on_column_focus(col_idx)
331
+ return super().eventFilter(source, event)
300
332
 
301
333
  def update_stylesheet(self, data: str):
302
334
  """
@@ -364,6 +396,29 @@ class PythonOutput(BaseCodeEditor):
364
396
  self.setProperty('class', 'interpreter-output')
365
397
  self.default_stylesheet = ""
366
398
  self.setStyleSheet(self.default_stylesheet)
399
+ self.tab = None
400
+ self.installEventFilter(self)
401
+
402
+ def set_tab(self, tab):
403
+ """
404
+ Set tab
405
+
406
+ :param tab: Tab
407
+ """
408
+ self.tab = tab
409
+
410
+ def eventFilter(self, source, event):
411
+ """
412
+ Focus event filter
413
+
414
+ :param source: source
415
+ :param event: event
416
+ """
417
+ if event.type() == event.Type.FocusIn:
418
+ if self.tab is not None:
419
+ col_idx = self.tab.column_idx
420
+ self.window.controller.ui.tabs.on_column_focus(col_idx)
421
+ return super().eventFilter(source, event)
367
422
 
368
423
  def clear_content(self):
369
424
  """Clear content"""
@@ -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: 2024.12.14 22:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -295,6 +295,7 @@ class HtmlCanvas(BaseTool):
295
295
  layout = canvas.widget.setup()
296
296
  widget = QWidget()
297
297
  widget.setLayout(layout)
298
+ canvas.set_tab(tab)
298
299
  self.load_output()
299
300
  return widget
300
301
 
@@ -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: 2024.12.09 23:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import re
@@ -15,6 +15,7 @@ from PySide6.QtCore import Qt
15
15
  from PySide6.QtGui import QAction, QIcon
16
16
  from PySide6.QtWidgets import QMenuBar, QVBoxLayout
17
17
 
18
+ from pygpt_net.core.tabs.tab import Tab
18
19
  from pygpt_net.ui.widget.dialog.base import BaseDialog
19
20
  from pygpt_net.utils import trans
20
21
 
@@ -71,6 +72,14 @@ class Tool:
71
72
  self.menu["file"].addAction(self.actions["file.clear"])
72
73
  return self.menu_bar
73
74
 
75
+ def set_tab(self, tab: Tab):
76
+ """
77
+ Set tab
78
+
79
+ :param tab: Tab
80
+ """
81
+ self.widget.set_tab(tab)
82
+
74
83
  def setup(self):
75
84
  """Setup canvas dialog"""
76
85
  self.layout = self.widget.setup()
@@ -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: 2024.12.09 23:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt, Slot, QUrl, QObject, Signal
@@ -34,6 +34,15 @@ class ToolWidget:
34
34
  self.edit = None # canvas edit
35
35
  self.btn_edit = None # edit checkbox
36
36
 
37
+ def set_tab(self, tab):
38
+ """
39
+ Set tab
40
+
41
+ :param tab: Tab
42
+ """
43
+ self.output.set_tab(tab)
44
+ self.edit.set_tab(tab)
45
+
37
46
  def setup(self) -> QVBoxLayout:
38
47
  """
39
48
  Setup widget body
@@ -128,6 +137,29 @@ class CanvasEdit(BaseCodeEditor):
128
137
  self.setProperty('class', 'interpreter-output')
129
138
  self.default_stylesheet = ""
130
139
  self.setStyleSheet(self.default_stylesheet)
140
+ self.tab = None
141
+ self.installEventFilter(self)
142
+
143
+ def set_tab(self, tab):
144
+ """
145
+ Set tab
146
+
147
+ :param tab: Tab
148
+ """
149
+ self.tab = tab
150
+
151
+ def eventFilter(self, source, event):
152
+ """
153
+ Focus event filter
154
+
155
+ :param source: source
156
+ :param event: event
157
+ """
158
+ if event.type() == event.Type.FocusIn:
159
+ if self.tab is not None:
160
+ col_idx = self.tab.column_idx
161
+ self.window.controller.ui.tabs.on_column_focus(col_idx)
162
+ return super().eventFilter(source, event)
131
163
 
132
164
 
133
165
  class ToolSignals(QObject):
pygpt_net/ui/__init__.py CHANGED
@@ -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.01.17 13:00:00 #
9
+ # Updated Date: 2025.01.19 03:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import os
@@ -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: 2024.11.05 23:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt
@@ -44,7 +44,10 @@ class Calendar:
44
44
  :return: QWidget
45
45
  """
46
46
  self.init()
47
- return self.window.core.tabs.from_widget(self.setup_calendar())
47
+ body = self.window.core.tabs.from_widget(self.setup_calendar())
48
+ body.append(self.window.ui.calendar['note'])
49
+ body.append(self.window.ui.calendar['select'])
50
+ return body
48
51
 
49
52
  def setup_filters(self) -> QWidget:
50
53
  """
@@ -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: 2024.11.05 23:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from pygpt_net.ui.widget.tabs.body import TabBody
@@ -36,4 +36,6 @@ class Explorer:
36
36
  self.window.ui.nodes['output_files'] = FileExplorer(self.window, path, index_data)
37
37
 
38
38
  # build tab body
39
- return self.window.core.tabs.from_widget(self.window.ui.nodes['output_files'])
39
+ body = self.window.core.tabs.from_widget(self.window.ui.nodes['output_files'])
40
+ body.append(self.window.ui.nodes['output_files'])
41
+ return body
@@ -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: 2024.11.05 23:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QPixmap, QIcon
@@ -83,7 +83,9 @@ class Painter:
83
83
  """
84
84
  # build tab body
85
85
  self.init()
86
- return self.window.core.tabs.from_layout(self.setup_painter())
86
+ body = self.window.core.tabs.from_layout(self.setup_painter())
87
+ body.append(self.window.ui.painter)
88
+ return body
87
89
 
88
90
  def setup_painter(self) -> QVBoxLayout:
89
91
  """
pygpt_net/ui/main.py CHANGED
@@ -6,16 +6,19 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.12.09 23:00:00 #
9
+ # Updated Date: 2025.01.19 03:00:00 #
10
10
  # ================================================== #
11
11
 
12
+ import copy
12
13
  import os
13
14
 
15
+ from PySide6 import QtWidgets
14
16
  from PySide6.QtCore import QTimer, Signal, Slot, QThreadPool, QEvent, Qt, QLoggingCategory
17
+ from PySide6.QtGui import QShortcut, QKeySequence
15
18
  from PySide6.QtWidgets import QApplication, QMainWindow
16
19
  from qt_material import QtStyleTools
17
20
 
18
- from pygpt_net.core.events import BaseEvent, KernelEvent
21
+ from pygpt_net.core.events import BaseEvent, KernelEvent, ControlEvent
19
22
  from pygpt_net.container import Container
20
23
  from pygpt_net.controller import Controller
21
24
  from pygpt_net.tools import Tools
@@ -85,6 +88,9 @@ class MainWindow(QMainWindow, QtStyleTools):
85
88
  self.ui = UI(self)
86
89
  self.ui.init()
87
90
 
91
+ # global shortcuts
92
+ self.shortcuts = []
93
+
88
94
  # setup signals
89
95
  self.statusChanged.connect(self.update_status)
90
96
  self.stateChanged.connect(self.update_state)
@@ -338,3 +344,58 @@ class MainWindow(QMainWindow, QtStyleTools):
338
344
  self.showNormal()
339
345
  self.activateWindow()
340
346
  self.ui.tray_menu['restore'].setVisible(False)
347
+
348
+ def setup_global_shortcuts(self):
349
+ """Setup global shortcuts"""
350
+ if not hasattr(self, 'core') or not hasattr(self.core, 'config'):
351
+ return
352
+
353
+ # unregister existing shortcuts
354
+ if hasattr(self, 'shortcuts'):
355
+ for shortcut in self.shortcuts:
356
+ # disconnect signals
357
+ shortcut.activated.disconnect()
358
+ # disable the shortcut to prevent it from handling events
359
+ shortcut.setEnabled(False)
360
+ # remove the parent to break the QObject tree
361
+ shortcut.setParent(None)
362
+ # schedule the shortcut for deletion
363
+ shortcut.deleteLater()
364
+ # clear the list of shortcuts
365
+ self.shortcuts.clear()
366
+ # process events to delete shortcuts immediately
367
+ QtWidgets.QApplication.processEvents()
368
+ else:
369
+ self.shortcuts = []
370
+
371
+ # Handle the Escape key
372
+ escape_shortcut = QShortcut(QKeySequence(Qt.Key_Escape), self)
373
+ escape_shortcut.setContext(Qt.ApplicationShortcut)
374
+ escape_shortcut.activated.connect(self.controller.access.on_escape)
375
+ self.shortcuts.append(escape_shortcut)
376
+
377
+ config = copy.deepcopy(self.core.config.get("access.shortcuts"))
378
+ for shortcut_conf in config:
379
+ print(shortcut_conf)
380
+ key = shortcut_conf.get('key', '')
381
+ key_modifier = shortcut_conf.get('key_modifier', '')
382
+ action_name = shortcut_conf.get('action')
383
+
384
+ if not key or not action_name:
385
+ continue
386
+
387
+ key_sequence_parts = []
388
+ if key_modifier and key_modifier != '---':
389
+ if key_modifier == "Control":
390
+ key_modifier = "Ctrl"
391
+ key_sequence_parts.append(key_modifier)
392
+ key_sequence_parts.append(key)
393
+ key_sequence_str = '+'.join(key_sequence_parts)
394
+ key_sequence = QKeySequence(key_sequence_str)
395
+
396
+ shortcut = QShortcut(key_sequence, self)
397
+ shortcut.setContext(Qt.ApplicationShortcut)
398
+ shortcut.activated.connect(
399
+ lambda checked=False, action=action_name: self.dispatch(ControlEvent(action))
400
+ )
401
+ self.shortcuts.append(shortcut)
@@ -6,13 +6,14 @@
6
6
  # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
7
  # MIT License #
8
8
  # Created By : Marcin Szczygliński #
9
- # Updated Date: 2024.08.29 04:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import QRect, QDate
13
13
  from PySide6.QtGui import QColor, QBrush, QFont, Qt, QAction, QContextMenuEvent, QIcon, QPixmap, QPen
14
14
  from PySide6.QtWidgets import QCalendarWidget, QMenu
15
15
 
16
+ from pygpt_net.core.tabs.tab import Tab
16
17
  from pygpt_net.utils import trans
17
18
  import pygpt_net.icons_rc
18
19
 
@@ -44,6 +45,29 @@ class CalendarSelect(QCalendarWidget):
44
45
  self.setContextMenuPolicy(Qt.CustomContextMenu)
45
46
  self.customContextMenuRequested.connect(self.open_context_menu)
46
47
  self.setProperty('class', 'calendar')
48
+ self.tab = None
49
+ self.installEventFilter(self)
50
+
51
+ def set_tab(self, tab: Tab):
52
+ """
53
+ Set tab
54
+
55
+ :param tab: Tab
56
+ """
57
+ self.tab = tab
58
+
59
+ def eventFilter(self, source, event):
60
+ """
61
+ Focus event filter
62
+
63
+ :param source: source
64
+ :param event: event
65
+ """
66
+ if event.type() == event.Type.FocusIn:
67
+ if self.tab is not None:
68
+ col_idx = self.tab.column_idx
69
+ self.window.controller.ui.tabs.on_column_focus(col_idx)
70
+ return super().eventFilter(source, event)
47
71
 
48
72
  def page_changed(self, year, month):
49
73
  """
@@ -172,6 +196,10 @@ class CalendarSelect(QCalendarWidget):
172
196
  # if date in self.counters['ctx']:
173
197
  self.window.controller.calendar.on_ctx_select(year, month, day)
174
198
 
199
+ if self.tab is not None:
200
+ col_idx = self.tab.column_idx
201
+ self.window.controller.ui.tabs.on_column_focus(col_idx)
202
+
175
203
  def add_ctx(self, date: QDate, num: int):
176
204
  """
177
205
  Add ctx counter to counter list
@@ -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: 2024.04.12 08:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import datetime
@@ -15,6 +15,7 @@ from PySide6.QtCore import Qt, QPoint
15
15
  from PySide6.QtGui import QImage, QPainter, QPen, QAction, QIcon, QKeySequence
16
16
  from PySide6.QtWidgets import QMenu, QWidget, QFileDialog, QMessageBox, QApplication
17
17
 
18
+ from pygpt_net.core.tabs.tab import Tab
18
19
  from pygpt_net.utils import trans
19
20
  import pygpt_net.icons_rc
20
21
 
@@ -35,6 +36,16 @@ class PainterWidget(QWidget):
35
36
  self.undoLimit = 10
36
37
  self.setFocusPolicy(Qt.StrongFocus)
37
38
  self.setFocus()
39
+ self.installEventFilter(self)
40
+ self.tab = None
41
+
42
+ def set_tab(self, tab: Tab):
43
+ """
44
+ Set tab
45
+
46
+ :param tab: Tab
47
+ """
48
+ self.tab = tab
38
49
 
39
50
  def handle_paste(self):
40
51
  """Handle clipboard paste"""
@@ -353,3 +364,16 @@ class PainterWidget(QWidget):
353
364
  painter = QPainter(new)
354
365
  painter.drawImage(QPoint(0, 0), self.image)
355
366
  self.image = new
367
+
368
+ def eventFilter(self, source, event):
369
+ """
370
+ Focus event filter
371
+
372
+ :param source: source
373
+ :param event: event
374
+ """
375
+ if event.type() == event.Type.FocusIn:
376
+ if self.tab is not None:
377
+ col_idx = self.tab.column_idx
378
+ self.window.controller.ui.tabs.on_column_focus(col_idx)
379
+ return super().eventFilter(source, event)
@@ -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: 2024.12.12 04:00:00 #
9
+ # Updated Date: 2025.01.19 02:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import datetime
@@ -118,6 +118,29 @@ class FileExplorer(QWidget):
118
118
  vertical-align: middle;
119
119
  }
120
120
  """)
121
+ self.tab = None
122
+ self.installEventFilter(self)
123
+
124
+ def eventFilter(self, source, event):
125
+ """
126
+ Focus event filter
127
+
128
+ :param source: source
129
+ :param event: event
130
+ """
131
+ if event.type() == event.Type.FocusIn:
132
+ if self.tab is not None:
133
+ col_idx = self.tab.column_idx
134
+ self.window.controller.ui.tabs.on_column_focus(col_idx)
135
+ return super().eventFilter(source, event)
136
+
137
+ def set_tab(self, tab: Tab):
138
+ """
139
+ Set tab
140
+
141
+ :param tab: Tab
142
+ """
143
+ self.tab = tab
121
144
 
122
145
  def setOwner(self, owner: Tab):
123
146
  """