Source code for ewoksfluo.gui.dynamic_tab_widget
from typing import Any
from typing import Callable
from typing import Dict
from typing import List
from typing import Optional
from typing import TypeVar
from AnyQt import QtWidgets
from AnyQt.QtCore import Signal
TabWidgetType = TypeVar("TabWidgetType", bound=QtWidgets.QWidget)
[docs]
class DynamicTabWidget(QtWidgets.QWidget):
"""
Tab container with '+' and '-' tabs to add and remove tabs at runtime.
At least one tab is ensured to be present.
"""
tab_added = Signal(QtWidgets.QWidget)
tab_removed = Signal(QtWidgets.QWidget)
def __init__(
self,
create_widget: Callable[[Optional[dict]], TabWidgetType],
tab_label: str,
initial_values: Optional[Dict[str, Any]] = None,
parent=None,
):
super().__init__(parent=parent)
self._create_widget = create_widget
self._tab_label = tab_label
layout = QtWidgets.QVBoxLayout(self)
self._tab_widget = QtWidgets.QTabWidget(self)
layout.addWidget(self._tab_widget)
self._tab_widget.addTab(QtWidgets.QWidget(), "+")
self._tab_widget.addTab(QtWidgets.QWidget(), "-")
self._tab_widget.tabBar().setSelectionBehaviorOnRemove(
QtWidgets.QTabBar.SelectionBehavior.SelectLeftTab
)
self._tab_widget.currentChanged.connect(self._handle_special_tabs)
self._initialize_tabs(initial_values)
if self._n_tabs < 1:
raise RuntimeError(
"DynamicTabWidget._initialize_tabs should add at least one tab"
)
def _initialize_tabs(self, initial_values: Optional[Dict[str, Any]]):
raise NotImplementedError
@property
def _n_tabs(self) -> int:
return self._tab_widget.count() - 2
@property
def _plus_index(self) -> int:
return self._n_tabs
@property
def _minus_index(self) -> int:
return self._n_tabs + 1
@property
def tabs(self) -> List[TabWidgetType]:
return [self._tab_widget.widget(i) for i in range(self._n_tabs)]
def _handle_special_tabs(self, index):
if index == self._plus_index:
self.add_tab()
elif index == self._minus_index:
self.remove_tab()
[docs]
def add_tab(
self,
initial_values: Optional[dict] = None,
) -> None:
new_tab_index = self._plus_index
widget = self._create_widget(initial_values)
self._tab_widget.insertTab(
new_tab_index, widget, self._tab_label.format(new_tab_index + 1)
)
self._tab_widget.setCurrentIndex(new_tab_index)
self.tab_added.emit(widget)
[docs]
def remove_tab(self) -> None:
last_tab_index = self._plus_index - 1
self._tab_widget.setCurrentIndex(last_tab_index)
if last_tab_index == 0:
# Never delete the first
return
widget = self._tab_widget.widget(last_tab_index)
self._tab_widget.removeTab(last_tab_index)
self._tab_widget.setCurrentIndex(last_tab_index - 1)
self.tab_removed.emit(widget)
widget.deleteLater()