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()