pygpt-net 2.4.37__py3-none-any.whl → 2.4.39__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 (81) hide show
  1. CHANGELOG.md +11 -0
  2. README.md +24 -5
  3. pygpt_net/CHANGELOG.txt +11 -0
  4. pygpt_net/__init__.py +3 -3
  5. pygpt_net/controller/__init__.py +3 -1
  6. pygpt_net/controller/calendar/__init__.py +3 -1
  7. pygpt_net/controller/chat/render.py +8 -5
  8. pygpt_net/controller/config/placeholder.py +29 -0
  9. pygpt_net/controller/ctx/__init__.py +32 -24
  10. pygpt_net/controller/ctx/common.py +3 -2
  11. pygpt_net/controller/dialogs/confirm.py +2 -2
  12. pygpt_net/controller/lang/custom.py +2 -7
  13. pygpt_net/controller/lang/mapping.py +2 -2
  14. pygpt_net/controller/layout.py +2 -2
  15. pygpt_net/controller/notepad.py +8 -5
  16. pygpt_net/controller/settings/editor.py +6 -0
  17. pygpt_net/controller/theme/__init__.py +33 -8
  18. pygpt_net/controller/theme/common.py +22 -1
  19. pygpt_net/controller/theme/markdown.py +26 -14
  20. pygpt_net/controller/theme/menu.py +26 -5
  21. pygpt_net/controller/ui/tabs.py +201 -58
  22. pygpt_net/core/attachments/context.py +14 -12
  23. pygpt_net/core/audio/__init__.py +59 -1
  24. pygpt_net/core/ctx/__init__.py +11 -1
  25. pygpt_net/core/ctx/container.py +16 -9
  26. pygpt_net/core/ctx/output.py +86 -67
  27. pygpt_net/core/debug/tabs.py +3 -2
  28. pygpt_net/core/filesystem/__init__.py +5 -19
  29. pygpt_net/core/filesystem/url.py +7 -3
  30. pygpt_net/core/render/base.py +14 -3
  31. pygpt_net/core/render/markdown/renderer.py +3 -1
  32. pygpt_net/core/render/plain/renderer.py +3 -3
  33. pygpt_net/core/render/web/body.py +39 -17
  34. pygpt_net/core/render/web/renderer.py +7 -5
  35. pygpt_net/core/tabs/__init__.py +180 -71
  36. pygpt_net/core/tabs/tab.py +13 -4
  37. pygpt_net/data/config/config.json +14 -4
  38. pygpt_net/data/config/models.json +3 -3
  39. pygpt_net/data/config/modes.json +3 -3
  40. pygpt_net/data/config/settings.json +55 -10
  41. pygpt_net/data/config/settings_section.json +3 -0
  42. pygpt_net/data/css/style.light.css +1 -0
  43. pygpt_net/data/css/{web.css → web-blocks.css} +144 -133
  44. pygpt_net/data/css/web-chatgpt.css +342 -0
  45. pygpt_net/data/css/web-chatgpt.dark.css +64 -0
  46. pygpt_net/data/css/web-chatgpt.light.css +75 -0
  47. pygpt_net/data/css/web-chatgpt_wide.css +342 -0
  48. pygpt_net/data/css/web-chatgpt_wide.dark.css +64 -0
  49. pygpt_net/data/css/web-chatgpt_wide.light.css +75 -0
  50. pygpt_net/data/locale/locale.de.ini +12 -0
  51. pygpt_net/data/locale/locale.en.ini +14 -1
  52. pygpt_net/data/locale/locale.es.ini +12 -0
  53. pygpt_net/data/locale/locale.fr.ini +12 -0
  54. pygpt_net/data/locale/locale.it.ini +12 -0
  55. pygpt_net/data/locale/locale.pl.ini +12 -0
  56. pygpt_net/data/locale/locale.uk.ini +12 -0
  57. pygpt_net/data/locale/locale.zh.ini +12 -0
  58. pygpt_net/plugin/audio_input/simple.py +21 -5
  59. pygpt_net/provider/core/config/patch.py +22 -1
  60. pygpt_net/provider/core/ctx/base.py +4 -1
  61. pygpt_net/provider/core/ctx/db_sqlite/__init__.py +10 -1
  62. pygpt_net/provider/core/ctx/db_sqlite/storage.py +22 -1
  63. pygpt_net/ui/layout/chat/input.py +10 -18
  64. pygpt_net/ui/layout/chat/output.py +26 -44
  65. pygpt_net/ui/layout/toolbox/footer.py +18 -2
  66. pygpt_net/ui/menu/config.py +7 -11
  67. pygpt_net/ui/menu/theme.py +9 -2
  68. pygpt_net/ui/widget/lists/context.py +1 -0
  69. pygpt_net/ui/widget/tabs/layout.py +195 -0
  70. pygpt_net/ui/widget/tabs/output.py +124 -35
  71. pygpt_net/ui/widget/textarea/html.py +11 -1
  72. pygpt_net/ui/widget/textarea/output.py +10 -1
  73. pygpt_net/ui/widget/textarea/search_input.py +4 -1
  74. pygpt_net/ui/widget/textarea/web.py +49 -9
  75. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/METADATA +25 -6
  76. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/RECORD +81 -74
  77. /pygpt_net/data/css/{web.dark.css → web-blocks.dark.css} +0 -0
  78. /pygpt_net/data/css/{web.light.css → web-blocks.light.css} +0 -0
  79. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/LICENSE +0 -0
  80. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/WHEEL +0 -0
  81. {pygpt_net-2.4.37.dist-info → pygpt_net-2.4.39.dist-info}/entry_points.txt +0 -0
@@ -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.24 02:00:00 #
9
+ # Updated Date: 2024.12.07 21:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction, QIcon
@@ -28,10 +28,14 @@ class Theme:
28
28
  def setup(self):
29
29
  """Setup theme menu"""
30
30
  self.window.ui.menu['theme'] = {}
31
+ self.window.ui.menu['theme_style'] = {}
31
32
  self.window.ui.menu['theme_syntax'] = {}
32
33
  self.window.ui.menu['theme.layout.density'] = {}
33
34
  self.window.ui.menu['menu.theme'] = QMenu(trans("menu.theme"), self.window)
34
35
 
36
+ # styles
37
+ self.window.ui.menu['theme.style'] = QMenu(trans("menu.theme.style"), self.window)
38
+
35
39
  # color themes
36
40
  self.window.ui.menu['theme.dark'] = QMenu(trans("menu.theme.dark"), self.window)
37
41
  self.window.ui.menu['theme.light'] = QMenu(trans("menu.theme.light"), self.window)
@@ -40,12 +44,14 @@ class Theme:
40
44
  # layout density
41
45
  self.window.ui.menu['theme.density'] = QMenu(trans("menu.theme.density"), self.window)
42
46
 
47
+ """
43
48
  # blocks
44
49
  self.window.ui.menu['theme.blocks'] = QAction(trans("menu.theme.blocks"), self.window, checkable=True)
45
50
  self.window.ui.menu['theme.blocks'].triggered.connect(
46
51
  lambda: self.window.controller.theme.toggle_option('render.blocks'))
47
52
  self.window.ui.menu['theme.blocks'].setCheckable(True)
48
53
  self.window.ui.menu['theme.blocks'].setChecked(self.window.core.config.get('render.blocks'))
54
+ """
49
55
 
50
56
  # tooltips
51
57
  self.window.ui.menu['theme.tooltips'] = QAction(trans("menu.theme.tooltips"), self.window, checkable=True)
@@ -62,10 +68,11 @@ class Theme:
62
68
  self.window.ui.menu['theme.settings'].triggered.connect(
63
69
  lambda: self.window.controller.settings.open_section('layout'))
64
70
 
71
+ self.window.ui.menu['menu.theme'].addMenu(self.window.ui.menu['theme.style'])
65
72
  self.window.ui.menu['menu.theme'].addMenu(self.window.ui.menu['theme.dark'])
66
73
  self.window.ui.menu['menu.theme'].addMenu(self.window.ui.menu['theme.light'])
67
74
  self.window.ui.menu['menu.theme'].addMenu(self.window.ui.menu['theme.syntax'])
68
75
  self.window.ui.menu['menu.theme'].addMenu(self.window.ui.menu['theme.density'])
69
- self.window.ui.menu['menu.theme'].addAction(self.window.ui.menu['theme.blocks'])
76
+ # self.window.ui.menu['menu.theme'].addAction(self.window.ui.menu['theme.blocks'])
70
77
  self.window.ui.menu['menu.theme'].addAction(self.window.ui.menu['theme.tooltips'])
71
78
  self.window.ui.menu['menu.theme'].addAction(self.window.ui.menu['theme.settings'])
@@ -494,3 +494,4 @@ class SectionItem(QStandardItem):
494
494
  self.setTextAlignment(QtCore.Qt.AlignRight)
495
495
  font = self.font()
496
496
  font.setBold(True)
497
+ self.setFont(font)
@@ -0,0 +1,195 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ # ================================================== #
4
+ # This file is a part of PYGPT package #
5
+ # Website: https://pygpt.net #
6
+ # GitHub: https://github.com/szczyglis-dev/py-gpt #
7
+ # MIT License #
8
+ # Created By : Marcin Szczygliński #
9
+ # Updated Date: 2024.12.09 03:00:00 #
10
+ # ================================================== #
11
+
12
+ from PySide6.QtCore import Qt, QObject, QEvent
13
+ from PySide6.QtWidgets import QTabWidget, QWidget, QVBoxLayout, QSplitter, QSizePolicy
14
+
15
+ from pygpt_net.ui.widget.tabs.output import OutputTabs
16
+
17
+
18
+ class OutputColumn(QWidget):
19
+ def __init__(self, window=None):
20
+ """
21
+ Output column
22
+
23
+ :param window: window instance
24
+ """
25
+ super(OutputColumn, self).__init__(window)
26
+ self.window = window
27
+ self.idx = -1
28
+ self.tabs = OutputTabs(self.window, column=self)
29
+ self.layout = QVBoxLayout()
30
+ self.layout.addWidget(self.tabs)
31
+ self.layout.setContentsMargins(0, 0, 0, 0)
32
+ self.setLayout(self.layout)
33
+ self.filter = FocusEventFilter(self, self.on_focus)
34
+ self.installEventFilter(self.filter)
35
+ self.setFocusPolicy(Qt.StrongFocus)
36
+
37
+ def on_focus(self, widget):
38
+ """
39
+ On widget clicked
40
+
41
+ :param widget: widget
42
+ """
43
+ self.window.controller.ui.tabs.on_column_focus(self.idx)
44
+ widget.setFocus()
45
+
46
+ def set_idx(self, idx: int):
47
+ """
48
+ Set index
49
+
50
+ :param idx: int
51
+ """
52
+ self.idx = idx
53
+
54
+ def get_idx(self) -> int:
55
+ """
56
+ Get index
57
+
58
+ :return: int
59
+ """
60
+ return self.idx
61
+
62
+ def set_tabs(self, tabs: QTabWidget):
63
+ """
64
+ Set tabs widget
65
+
66
+ :param tabs: QTabWidget
67
+ """
68
+ self.tabs = tabs
69
+
70
+ def get_tabs(self) -> OutputTabs:
71
+ """
72
+ Get tabs
73
+
74
+ :return: OutputTabs
75
+ """
76
+ return self.tabs
77
+
78
+
79
+ class OutputLayout(QWidget):
80
+ def __init__(self, window=None):
81
+ """
82
+ Output layout
83
+
84
+ :param window: window instance
85
+ """
86
+ super(OutputLayout, self).__init__(window)
87
+ self.window = window
88
+ self.columns = []
89
+
90
+ column1 = OutputColumn(self.window)
91
+ column2 = OutputColumn(self.window)
92
+ self.add_column(column1)
93
+ self.add_column(column2)
94
+
95
+ self.splitter = QSplitter(Qt.Horizontal)
96
+ self.splitter.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
97
+ for column in self.columns:
98
+ self.splitter.addWidget(column)
99
+
100
+ self.window.ui.splitters['columns'] = self.splitter
101
+
102
+ self.layout = QVBoxLayout()
103
+ self.layout.addWidget(self.splitter, stretch=1)
104
+ self.layout.setContentsMargins(0, 0, 0, 0)
105
+ self.setLayout(self.layout)
106
+
107
+ def get_next_idx(self) -> int:
108
+ """
109
+ Get next index
110
+
111
+ :return: int
112
+ """
113
+ return len(self.columns)
114
+
115
+ def add_column(self, column: OutputColumn):
116
+ """
117
+ Add column
118
+
119
+ :param column: OutputColumn
120
+ """
121
+ idx = self.get_next_idx()
122
+ column.set_idx(idx)
123
+ self.columns.append(column)
124
+
125
+ def get_tabs_by_idx(self, idx: int) -> OutputTabs:
126
+ """
127
+ Get tabs by column index
128
+
129
+ :param idx: int
130
+ :return: OutputTabs
131
+ """
132
+ for column in self.columns:
133
+ if column.idx == idx:
134
+ return column.tabs
135
+ return None
136
+
137
+ def get_active_tabs(self) -> OutputTabs:
138
+ """
139
+ Get active tabs
140
+
141
+ :return: OutputTabs
142
+ """
143
+ current = self.window.controller.ui.tabs.get_current_column_idx()
144
+ for column in self.columns:
145
+ if column.idx == current:
146
+ return column.tabs
147
+
148
+ def get_column_by_idx(self, idx: int) -> OutputColumn:
149
+ """
150
+ Get column by index
151
+
152
+ :param idx: int
153
+ :return: OutputColumn
154
+ """
155
+ for column in self.columns:
156
+ if column.idx == idx:
157
+ return column
158
+ return None
159
+
160
+ def get_active_column(self) -> OutputColumn:
161
+ """
162
+ Get active column
163
+
164
+ :return: OutputColumn
165
+ """
166
+ current = self.window.controller.ui.tabs.get_current_column_idx()
167
+ for column in self.columns:
168
+ if column.idx == current:
169
+ return column
170
+
171
+ class FocusEventFilter(QObject):
172
+ def __init__(self, column, callback):
173
+ """
174
+ Column event filter
175
+
176
+ :param column: parent column
177
+ :param callback: callback
178
+ """
179
+ super().__init__()
180
+ self.column = column
181
+ self.callback = callback
182
+
183
+ def eventFilter(self, obj, event):
184
+ """
185
+ Click event filter
186
+
187
+ :param obj: object
188
+ :param event: event
189
+ """
190
+ if event.type() == QEvent.MouseButtonPress or event.type() == QEvent.FocusIn:
191
+ widget = obj
192
+ if widget is not None:
193
+ self.callback(widget)
194
+ return False
195
+ return False
@@ -6,10 +6,10 @@
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: 2024.12.09 03:00:00 #
10
10
  # ================================================== #
11
11
 
12
- from PySide6.QtWidgets import QTabWidget, QMenu
12
+ from PySide6.QtWidgets import QTabWidget, QMenu, QPushButton
13
13
  from PySide6.QtCore import Qt, Slot
14
14
  from PySide6.QtGui import QAction, QIcon
15
15
 
@@ -19,16 +19,59 @@ import pygpt_net.icons_rc
19
19
 
20
20
 
21
21
  class OutputTabs(QTabWidget):
22
- def __init__(self, window=None):
22
+ def __init__(self, window=None, column=None):
23
23
  super(OutputTabs, self).__init__(window)
24
24
  self.window = window
25
+ self.column = column
25
26
  self.setMinimumHeight(1)
26
27
  self.owner = None
27
28
  self.setMovable(True)
29
+ self.init()
30
+
31
+ def init(self):
32
+ """Initialize"""
33
+ # create the [+] button
34
+ add_button = QPushButton(QIcon(":/icons/add.svg"), "")
35
+ add_button.setFixedSize(30, 25)
36
+ add_button.setFlat(True)
37
+ add_button.clicked.connect(
38
+ lambda: self.window.controller.ui.tabs.new_tab(self.column.get_idx())
39
+ )
40
+ add_button.setObjectName('tab-add')
41
+ add_button.setProperty('tabAdd', True)
42
+ add_button.setToolTip(trans('action.tab.add.chat'))
43
+
44
+ # add the button to the top right corner of the tab bar
45
+ self.setCornerWidget(add_button, corner=Qt.TopRightCorner)
46
+
47
+ # connect signals
48
+ self.currentChanged.connect(
49
+ lambda: self.window.controller.ui.tabs.on_tab_changed(self.currentIndex(), self.column.get_idx())
50
+ )
51
+ self.tabBarClicked.connect(
52
+ lambda: self.window.controller.ui.tabs.on_tab_clicked(self.currentIndex(), self.column.get_idx())
53
+ )
54
+ self.tabBarDoubleClicked.connect(
55
+ lambda: self.window.controller.ui.tabs.on_tab_dbl_clicked(self.currentIndex(), self.column.get_idx())
56
+ )
57
+ self.tabCloseRequested.connect(
58
+ lambda: self.window.controller.ui.tabs.on_tab_closed(self.currentIndex(), self.column.get_idx())
59
+ )
60
+ self.tabBar().tabMoved.connect(
61
+ lambda: self.window.controller.ui.tabs.on_tab_moved(self.currentIndex(), self.column.get_idx())
62
+ )
63
+
64
+ def get_column(self):
65
+ """
66
+ Get column
67
+
68
+ :return: OutputColumn
69
+ """
70
+ return self.column
28
71
 
29
72
  def setOwner(self, owner: Tab):
30
73
  """
31
- Set parent
74
+ Set internal tab instance
32
75
 
33
76
  :param owner: parent tab instance
34
77
  """
@@ -42,56 +85,67 @@ class OutputTabs(QTabWidget):
42
85
  """
43
86
  if event.button() == Qt.RightButton:
44
87
  idx = self.tabBar().tabAt(event.pos())
45
- tab = self.window.core.tabs.get_tab_by_index(idx)
88
+ column_idx = self.column.get_idx()
89
+ tab = self.window.core.tabs.get_tab_by_index(idx, column_idx)
46
90
  if tab is not None:
47
91
  if tab.type == Tab.TAB_NOTEPAD:
48
- self.show_notepad_menu(idx, event.globalPos()) # notepad
92
+ self.show_notepad_menu(idx, column_idx, event.globalPos()) # notepad
49
93
  elif tab.type == Tab.TAB_CHAT:
50
- self.show_chat_menu(idx, event.globalPos()) # chat
94
+ self.show_chat_menu(idx, column_idx, event.globalPos()) # chat
51
95
  elif tab.type == Tab.TAB_FILES:
52
- self.show_files_menu(idx, event.globalPos()) # files
96
+ self.show_files_menu(idx, column_idx, event.globalPos()) # files
53
97
  else:
54
- self.show_default_menu(idx, event.globalPos()) # default
98
+ self.show_default_menu(idx, column_idx, event.globalPos()) # default
55
99
  super(OutputTabs, self).mousePressEvent(event)
56
100
 
57
- def get_common_actions(self, index):
101
+ def get_common_actions(self, index: int, column_idx: int):
58
102
  """
59
103
  Get common actions
60
104
 
61
105
  :param index: index
106
+ :param column_idx: column index
62
107
  :return: dict
63
108
  """
64
109
  actions = {}
65
110
  actions['add_chat'] = QAction(QIcon(":/icons/add.svg"), trans('action.tab.add.chat'), self)
66
111
  actions['add_chat'].triggered.connect(
67
- lambda: self.add_tab(index, Tab.TAB_CHAT)
112
+ lambda: self.add_tab(index, column_idx, Tab.TAB_CHAT)
68
113
  )
69
114
  actions['add_notepad'] = QAction(QIcon(":/icons/add.svg"), trans('action.tab.add.notepad'), self)
70
115
  actions['add_notepad'].triggered.connect(
71
- lambda: self.add_tab(index, Tab.TAB_NOTEPAD)
116
+ lambda: self.add_tab(index, column_idx, Tab.TAB_NOTEPAD)
72
117
  )
73
118
  actions['edit'] = QAction(QIcon(":/icons/edit.svg"), trans('action.rename'), self)
74
119
  actions['edit'].triggered.connect(
75
- lambda: self.rename_tab(index)
120
+ lambda: self.rename_tab(index, column_idx)
121
+ )
122
+ actions['move_right'] = QAction(QIcon(":/icons/forward"), trans('action.tab.move.right'), self)
123
+ actions['move_right'].triggered.connect(
124
+ lambda: self.window.controller.ui.tabs.move_tab(index, column_idx, 1)
125
+ )
126
+ actions['move_left'] = QAction(QIcon(":/icons/back"), trans('action.tab.move.left'), self)
127
+ actions['move_left'].triggered.connect(
128
+ lambda: self.window.controller.ui.tabs.move_tab(index, column_idx, 0)
76
129
  )
77
130
  return actions
78
131
 
79
- def show_notepad_menu(self, index, global_pos):
132
+ def show_notepad_menu(self, index: int, column_idx: int, global_pos):
80
133
  """
81
134
  Show notepad menu
82
135
 
83
136
  :param index: index
137
+ :param column_idx: column index
84
138
  :param global_pos: global position
85
139
  """
86
140
  context_menu = QMenu()
87
- actions = self.get_common_actions(index)
141
+ actions = self.get_common_actions(index, column_idx)
88
142
  actions['close'] = QAction(QIcon(":/icons/close.svg"), trans('action.tab.close'), self)
89
143
  actions['close'].triggered.connect(
90
- lambda: self.close_tab(index)
144
+ lambda: self.close_tab(index, column_idx)
91
145
  )
92
146
  actions['close_all'] = QAction(QIcon(":/icons/close.svg"), trans('action.tab.close_all.notepad'), self)
93
147
  actions['close_all'].triggered.connect(
94
- lambda: self.close_all(Tab.TAB_NOTEPAD)
148
+ lambda: self.close_all(Tab.TAB_NOTEPAD, column_idx)
95
149
  )
96
150
  context_menu.addAction(actions['add_chat'])
97
151
  context_menu.addAction(actions['add_notepad'])
@@ -100,24 +154,32 @@ class OutputTabs(QTabWidget):
100
154
 
101
155
  if self.window.core.tabs.count_by_type(Tab.TAB_NOTEPAD) > 1:
102
156
  context_menu.addAction(actions['close_all'])
157
+
158
+ # move
159
+ if column_idx != 0:
160
+ context_menu.addAction(actions['move_left'])
161
+ if column_idx != 1:
162
+ context_menu.addAction(actions['move_right'])
163
+
103
164
  context_menu.exec(global_pos)
104
165
 
105
- def show_chat_menu(self, index, global_pos):
166
+ def show_chat_menu(self, index: int, column_idx: int, global_pos):
106
167
  """
107
168
  Show chat menu
108
169
 
109
170
  :param index: index
171
+ :param column_idx: column index
110
172
  :param global_pos: global position
111
173
  """
112
174
  context_menu = QMenu()
113
- actions = self.get_common_actions(index)
175
+ actions = self.get_common_actions(index, column_idx)
114
176
  actions['close'] = QAction(QIcon(":/icons/close.svg"), trans('action.tab.close'), self)
115
177
  actions['close'].triggered.connect(
116
- lambda: self.close_tab(index)
178
+ lambda: self.close_tab(index, column_idx)
117
179
  )
118
180
  actions['close_all'] = QAction(QIcon(":/icons/close.svg"), trans('action.tab.close_all.chat'), self)
119
181
  actions['close_all'].triggered.connect(
120
- lambda: self.close_all(Tab.TAB_CHAT)
182
+ lambda: self.close_all(Tab.TAB_CHAT, column_idx)
121
183
  )
122
184
  context_menu.addAction(actions['add_chat'])
123
185
  context_menu.addAction(actions['add_notepad'])
@@ -126,21 +188,26 @@ class OutputTabs(QTabWidget):
126
188
  # at least one chat tab must be open
127
189
  if self.window.core.tabs.count_by_type(Tab.TAB_CHAT) > 1:
128
190
  context_menu.addAction(actions['close'])
129
-
130
- if self.window.core.tabs.count_by_type(Tab.TAB_CHAT) > 1:
131
191
  context_menu.addAction(actions['close_all'])
132
192
 
193
+ # move
194
+ if column_idx != 0:
195
+ context_menu.addAction(actions['move_left'])
196
+ if column_idx != 1:
197
+ context_menu.addAction(actions['move_right'])
198
+
133
199
  context_menu.exec(global_pos)
134
200
 
135
- def show_files_menu(self, index, global_pos):
201
+ def show_files_menu(self, index: int, column_idx: int, global_pos):
136
202
  """
137
203
  Show files menu
138
204
 
139
205
  :param index: index
206
+ :param column_idx: column index
140
207
  :param global_pos: global position
141
208
  """
142
209
  context_menu = QMenu()
143
- actions = self.get_common_actions(index)
210
+ actions = self.get_common_actions(index, column_idx)
144
211
  actions['refresh'] = QAction(QIcon(":/icons/reload.svg"), trans('action.refresh'), self)
145
212
  actions['refresh'].triggered.connect(
146
213
  lambda: self.window.controller.files.update_explorer()
@@ -149,51 +216,73 @@ class OutputTabs(QTabWidget):
149
216
  context_menu.addAction(actions['add_notepad'])
150
217
  context_menu.addAction(actions['refresh'])
151
218
  context_menu.addAction(actions['edit'])
219
+
220
+ # move
221
+ if column_idx != 0:
222
+ context_menu.addAction(actions['move_left'])
223
+ if column_idx != 1:
224
+ context_menu.addAction(actions['move_right'])
225
+
152
226
  context_menu.exec(global_pos)
153
227
 
154
- def show_default_menu(self, index, global_pos):
228
+ def show_default_menu(self, index: int, column_idx: int, global_pos):
155
229
  """
156
230
  Show default menu
157
231
 
158
232
  :param index: index
233
+ :param column_idx: column index
159
234
  :param global_pos: global position
160
235
  """
161
236
  context_menu = QMenu()
162
- actions = self.get_common_actions(index)
237
+ actions = self.get_common_actions(index, column_idx)
163
238
  context_menu.addAction(actions['add_chat'])
164
239
  context_menu.addAction(actions['add_notepad'])
165
240
  context_menu.addAction(actions['edit'])
241
+
242
+ # move
243
+ if column_idx != 0:
244
+ context_menu.addAction(actions['move_left'])
245
+ if column_idx != 1:
246
+ context_menu.addAction(actions['move_right'])
247
+
166
248
  context_menu.exec(global_pos)
167
249
 
168
250
  @Slot()
169
- def rename_tab(self, index):
251
+ def rename_tab(self, index: int, column_idx: int):
170
252
  """
171
253
  Rename tab
254
+
172
255
  :param index: index
256
+ :param column_idx: column index
173
257
  """
174
- self.window.controller.ui.tabs.rename(index)
258
+ self.window.controller.ui.tabs.rename(index, column_idx)
175
259
 
176
260
  @Slot()
177
- def close_tab(self, index):
261
+ def close_tab(self, index: int, column_idx: int):
178
262
  """
179
263
  Close tab
264
+
180
265
  :param index: index
266
+ :param column_idx: column index
181
267
  """
182
- self.window.controller.ui.tabs.close(index)
268
+ self.window.controller.ui.tabs.close(index, column_idx)
183
269
 
184
270
  @Slot()
185
- def close_all(self, type):
271
+ def close_all(self, type, column_idx: int):
186
272
  """
187
273
  Close all tabs
274
+
188
275
  :param type: type
276
+ :param column_idx: column index
189
277
  """
190
- self.window.controller.ui.tabs.close_all(type)
278
+ self.window.controller.ui.tabs.close_all(type, column_idx)
191
279
 
192
280
  @Slot()
193
- def add_tab(self, index, type):
281
+ def add_tab(self, index: int, column_idx: int, type):
194
282
  """
195
283
  Add tab
196
284
  :param index: index
285
+ :param column_idx: column index
197
286
  :param type: type
198
287
  """
199
- self.window.controller.ui.tabs.append(type, index)
288
+ self.window.controller.ui.tabs.append(type, index, column_idx)
@@ -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.20 21:00:00 #
9
+ # Updated Date: 2024.12.09 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  import re
@@ -42,6 +42,15 @@ class HtmlOutput(QWebEngineView):
42
42
  self.plain = ""
43
43
  self.html_content = ""
44
44
  self.meta = None
45
+ self.tab = None
46
+
47
+ def set_tab(self, tab):
48
+ """
49
+ Set tab
50
+
51
+ :param tab: Tab
52
+ """
53
+ self.tab = tab
45
54
 
46
55
  def set_meta(self, meta: CtxMeta):
47
56
  """
@@ -163,6 +172,7 @@ class HtmlOutput(QWebEngineView):
163
172
  if success:
164
173
  event = RenderEvent(RenderEvent.ON_PAGE_LOAD, {
165
174
  "meta": self.meta,
175
+ "tab": self.tab,
166
176
  })
167
177
  self.window.dispatch(event)
168
178
 
@@ -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.24 01:00:00 #
9
+ # Updated Date: 2024.12.09 00:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtCore import Qt
@@ -38,6 +38,15 @@ class ChatOutput(QTextBrowser):
38
38
  self.setOpenLinks(False)
39
39
  self.anchorClicked.connect(self.open_external_link)
40
40
  self.setWordWrapMode(QTextOption.WordWrap)
41
+ self.tab = None
42
+
43
+ def set_tab(self, tab):
44
+ """
45
+ Set tab
46
+
47
+ :param tab: Tab
48
+ """
49
+ self.tab = tab
41
50
 
42
51
  def open_external_link(self, url):
43
52
  """
@@ -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 10:00:00 #
9
+ # Updated Date: 2024.12.07 21:00:00 #
10
10
  # ================================================== #
11
11
 
12
12
  from PySide6.QtGui import QAction, QIcon
@@ -32,6 +32,9 @@ class CtxSearchInput(QLineEdit):
32
32
  self.clear_action.triggered.connect(self.clear_search_string)
33
33
  self.addAction(self.clear_action, QLineEdit.TrailingPosition)
34
34
  self.clear_action.setVisible(False)
35
+ action = QAction(self)
36
+ action.setIcon(QIcon(":/icons/search.svg"))
37
+ self.addAction(action, QLineEdit.LeadingPosition)
35
38
 
36
39
  self.textChanged.connect(self.on_text_changed)
37
40