Skip to content

Commit 2781de1

Browse files
committed
Tabs stuff
1 parent 1bc1b8b commit 2781de1

4 files changed

Lines changed: 228 additions & 21 deletions

File tree

activity_browser/app/main_window.py

Lines changed: 117 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,18 @@ def __init__(self, parent=None):
3636
self.setMenuBar(self.menu_bar)
3737

3838
self.central_widget = widgets.CentralTabWidget(self)
39+
self.central_widget.setTabsClosable(True)
3940
self.setCentralWidget(self.central_widget)
41+
42+
# Initialize all base pages upfront (name -> widget instance)
43+
self.base_pages = {}
44+
for page_name, page_class in app.pages.base_pages.items():
45+
page_instance = page_class()
46+
page_instance.setObjectName(page_name)
47+
self.base_pages[page_name] = page_instance
48+
49+
# Connect tab close signal
50+
self.central_widget.tabCloseRequested.connect(self._on_tab_close_requested)
4051

4152
self.connect_signals()
4253

@@ -82,21 +93,117 @@ def sync_pages(self):
8293
"""
8394
Synchronizes the central widget pages with the shown_pages setting.
8495
85-
This method clears existing pages and adds only those pages that are
86-
configured to be shown at startup.
96+
This method shows only those pages that are configured to be shown at startup.
97+
Pages are pre-initialized and just added/removed from tabs.
8798
"""
88-
# Clear existing pages
99+
# Get shown pages from settings
100+
shown_pages = app.settings["startup"].get("shown_pages", [])
101+
102+
# Remove all pages from tabs first
89103
while self.central_widget.count() > 0:
90104
self.central_widget.removeTab(0)
91105

92-
# Add pages based on shown_pages setting
93-
shown_pages = app.settings["startup"].get("shown_pages", [])
94-
106+
# Add only the pages that should be shown
95107
for page_name in shown_pages:
96-
if page_name in app.pages.base_pages:
97-
page_class = app.pages.base_pages[page_name]
98-
page_instance = page_class()
99-
self.central_widget.addTab(page_instance, page_name)
108+
if page_name in self.base_pages:
109+
page_instance = self.base_pages[page_name]
110+
# Base pages should show minimize button instead of close
111+
self.central_widget.addTab(page_instance, page_name, show_minimize=True)
112+
113+
def show_page(self, page_name: str):
114+
"""
115+
Show a page by adding it to the tabs.
116+
117+
Args:
118+
page_name: The name of the page to show
119+
"""
120+
if page_name not in self.base_pages:
121+
return
122+
123+
page_widget = self.base_pages[page_name]
124+
125+
# Check if page is already in tabs
126+
index = self.central_widget.indexOf(page_widget)
127+
if index >= 0:
128+
# Already shown, just switch to it
129+
self.central_widget.setCurrentIndex(index)
130+
else:
131+
# Add to tabs with minimize button
132+
self.central_widget.addTab(page_widget, page_name, show_minimize=True)
133+
self.central_widget.setCurrentWidget(page_widget)
134+
135+
def hide_page(self, page_name: str):
136+
"""
137+
Hide a page by removing it from the tabs (but not destroying it).
138+
139+
Args:
140+
page_name: The name of the page to hide
141+
"""
142+
if page_name not in self.base_pages:
143+
return
144+
145+
page_widget = self.base_pages[page_name]
146+
index = self.central_widget.indexOf(page_widget)
147+
if index >= 0:
148+
self.central_widget.removeTab(index)
149+
150+
def toggle_page(self, page_name: str):
151+
"""
152+
Toggle a page shown/hidden.
153+
154+
Args:
155+
page_name: The name of the page to toggle
156+
"""
157+
if page_name not in self.base_pages:
158+
return
159+
160+
page_widget = self.base_pages[page_name]
161+
index = self.central_widget.indexOf(page_widget)
162+
163+
if index >= 0:
164+
# Page is shown, hide it
165+
self.hide_page(page_name)
166+
else:
167+
# Page is hidden, show it
168+
self.show_page(page_name)
169+
170+
def is_page_visible(self, page_name: str) -> bool:
171+
"""
172+
Check if a page is currently visible in the tabs.
173+
174+
Args:
175+
page_name: The name of the page to check
176+
177+
Returns:
178+
bool: True if the page is visible, False otherwise
179+
"""
180+
if page_name not in self.base_pages:
181+
return False
182+
183+
page_widget = self.base_pages[page_name]
184+
return self.central_widget.indexOf(page_widget) >= 0
185+
186+
def _on_tab_close_requested(self, index: int):
187+
"""
188+
Handle when user clicks the close button on a tab.
189+
For base pages, we just hide them instead of destroying them.
190+
191+
Args:
192+
index: The index of the tab to close
193+
"""
194+
widget = self.central_widget.widget(index)
195+
if widget is None:
196+
return
197+
198+
# Check if this is a base page
199+
page_name = widget.objectName()
200+
if page_name in self.base_pages:
201+
# Just remove from tabs, don't destroy
202+
self.central_widget.removeTab(index)
203+
else:
204+
# For non-base pages, remove and destroy
205+
self.central_widget.removeTab(index)
206+
widget.deleteLater()
100207

101208
def apply_settings(self, load=False):
102209

activity_browser/app/menu_bar.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,28 @@ class ViewMenu(QtWidgets.QMenu):
116116
def __init__(self, parent=None) -> None:
117117
super().__init__(parent)
118118
self.setTitle("&View")
119+
120+
121+
# Populate pages
122+
self.page_actions = {}
123+
for page_name in app.pages.base_pages.keys():
124+
action = QtWidgets.QAction(page_name, self)
125+
action.setCheckable(True)
126+
action.triggered.connect(lambda checked, name=page_name: app.main_window.toggle_page(name))
127+
# Update checked state when menu is about to show
128+
self.page_actions[page_name] = action
129+
self.addAction(action)
130+
131+
# Update the checked state when menu is about to show
132+
self.aboutToShow.connect(self.update_page_actions)
133+
134+
self.addSeparator()
135+
136+
def update_page_actions(self):
137+
"""Update the checked state of page actions based on which pages are visible."""
138+
for page_name, action in self.page_actions.items():
139+
is_visible = app.main_window.is_page_visible(page_name)
140+
action.setChecked(is_visible)
119141

120142

121143
class CalculateMenu(QtWidgets.QMenu):
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
from qtpy import QtWidgets
2+
3+
4+
class ABAbstractPage(QtWidgets.QWidget):
5+
6+
def toggleViewAction(self, main_window):
7+
"""Return the toggle view action for this page."""
8+
return

activity_browser/ui/widgets/central.py

Lines changed: 81 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
from loguru import logger
22

3-
from qtpy import QtWidgets
3+
from qtpy import QtWidgets, QtCore
4+
from .dock_widget import CloseButton, MinimizeButton
5+
6+
7+
class CentralTabBar(QtWidgets.QTabBar):
8+
"""Custom tab bar for the CentralTabWidget."""
9+
10+
def __init__(self, parent=None):
11+
super().__init__(parent)
12+
self.setMovable(True)
13+
self.setDocumentMode(True)
414

515

616
class CentralTabWidget(QtWidgets.QTabWidget):
@@ -16,16 +26,79 @@ def __init__(self, *args):
1626
Initialize the CentralTabWidget.
1727
1828
Args:
19-
*args: Positional arguments passed to the parent QTabWidget.
29+
*args: Additional positional arguments passed to the parent QTabWidget.
2030
"""
2131
super().__init__(*args)
22-
self.connect_signals()
23-
24-
def connect_signals(self):
25-
from activity_browser.app import signals
26-
# this should be located in the app module
2732

28-
signals.project.changed.connect(self.reset)
33+
# Use custom tab bar with close/minimize buttons
34+
self.setTabBar(CentralTabBar(self))
35+
36+
def addTab(self, widget, label, show_minimize=False):
37+
"""Override addTab to add custom buttons to each tab.
38+
39+
Args:
40+
widget: The widget to add as a tab
41+
label: The label for the tab
42+
show_minimize: If True, show minimize button; if False, show close button
43+
"""
44+
index = super().addTab(widget, label)
45+
self._add_tab_buttons(index, show_minimize)
46+
return index
47+
48+
def insertTab(self, index, widget, label, show_minimize=False):
49+
"""Override insertTab to add custom buttons to each tab.
50+
51+
Args:
52+
index: The index at which to insert the tab
53+
widget: The widget to add as a tab
54+
label: The label for the tab
55+
show_minimize: If True, show minimize button; if False, show close button
56+
"""
57+
index = super().insertTab(index, widget, label)
58+
self._add_tab_buttons(index, show_minimize)
59+
return index
60+
61+
def _add_tab_buttons(self, index, show_minimize=False):
62+
"""Add close OR minimize button to a tab (mutually exclusive).
63+
64+
Args:
65+
index: The index of the tab
66+
show_minimize: If True, show minimize button; otherwise show close button
67+
"""
68+
widget = self.widget(index)
69+
if not widget:
70+
return
71+
72+
# Create a widget to hold the button
73+
button_widget = QtWidgets.QWidget()
74+
button_layout = QtWidgets.QHBoxLayout(button_widget)
75+
button_layout.setContentsMargins(0, 0, 0, 0)
76+
button_layout.setSpacing(2)
77+
78+
# Add either minimize or close button (mutually exclusive)
79+
if show_minimize:
80+
minimize_btn = MinimizeButton(button_widget)
81+
minimize_btn.clicked.connect(lambda w=widget: self._minimize_tab_by_widget(w))
82+
button_layout.addWidget(minimize_btn)
83+
else:
84+
close_btn = CloseButton(button_widget)
85+
close_btn.clicked.connect(lambda w=widget: self._close_tab_by_widget(w))
86+
button_layout.addWidget(close_btn)
87+
88+
# Set the button widget on the tab
89+
self.tabBar().setTabButton(index, QtWidgets.QTabBar.ButtonPosition.RightSide, button_widget)
90+
91+
def _close_tab_by_widget(self, widget):
92+
"""Handle close button click using the widget reference."""
93+
index = self.indexOf(widget)
94+
if index >= 0:
95+
self.tabCloseRequested.emit(index)
96+
97+
def _minimize_tab_by_widget(self, widget):
98+
"""Handle minimize button click using the widget reference."""
99+
index = self.indexOf(widget)
100+
if index >= 0:
101+
self.tabCloseRequested.emit(index)
29102

30103
@property
31104
def groups(self):
@@ -78,9 +151,6 @@ def addToGroup(self, group: str, page: QtWidgets.QWidget):
78151
group.setCurrentIndex(index)
79152
page.deleteLater() # Clean up the newly created page since it already exists
80153

81-
def reset(self):
82-
self.setCurrentIndex(0)
83-
84154

85155
class GroupTabWidget(QtWidgets.QTabWidget):
86156
"""

0 commit comments

Comments
 (0)