ui.tool_selection_page

tool_selection_page.py

This module defines the ToolChoicePage class — a PyQt6 page that allows the user to select the next processing step in the GliAAns pipeline.

The available options include:

  • Skull Stripping
  • Automatic Drawing
  • Deep Learning Segmentation (Linux + CUDA only)
  • Full Pipeline Execution

Depending on the selected option, the next page is dynamically loaded.

  1"""
  2tool_selection_page.py
  3
  4This module defines the `ToolChoicePage` class — a PyQt6 page that allows the user
  5to select the next processing step in the GliAAns pipeline.
  6
  7The available options include:
  8- Skull Stripping
  9- Automatic Drawing
 10- Deep Learning Segmentation (Linux + CUDA only)
 11- Full Pipeline Execution
 12
 13Depending on the selected option, the next page is dynamically loaded.
 14"""
 15
 16import platform
 17import torch
 18from PyQt6.QtWidgets import (
 19    QVBoxLayout, QLabel, QGroupBox, QRadioButton, QButtonGroup, QSizePolicy,
 20    QWidget, QHBoxLayout, QMessageBox, QApplication
 21)
 22from PyQt6.QtGui import QFont
 23from PyQt6.QtCore import Qt, QCoreApplication
 24
 25from components.info_label import InfoLabel
 26from ui.nifti_mask_selection_page import MaskNiftiSelectionPage
 27from ui.dl_selection_page import DlNiftiSelectionPage
 28from ui.pipeline_patient_selection_page import PipelinePatientSelectionPage
 29from ui.skull_stripping_page import SkullStrippingPage
 30from page import Page
 31
 32
 33class ToolSelectionPage(Page):
 34    """
 35    A UI page for selecting the next processing step in the workflow.
 36
 37    This class extends `Page` and displays a set of radio buttons representing
 38    different data processing operations. The user’s selection determines which
 39    next page in the pipeline will be opened.
 40
 41    Attributes
 42    ----------
 43    context : dict
 44        Shared application state, including navigation and configuration.
 45    previous_page : Page
 46        Reference to the previous page for backward navigation.
 47    selected_option : int or None
 48        The currently selected radio button ID.
 49    """
 50
 51    def __init__(self, context=None, previous_page=None):
 52        """Initialize the ToolSelectionPage UI."""
 53        super().__init__()
 54
 55        self.context = context
 56        self.previous_page = previous_page
 57
 58        # References to next pages for each option
 59        self.next_skull_stripping = None
 60        self.next_manual_draw = None
 61        self.next_deep_learning = None
 62        self.next_pipeline = None
 63
 64        # === Layout setup ===
 65        self.layout = QVBoxLayout(self)
 66        self.layout.setContentsMargins(40, 40, 40, 40)
 67        self.layout.setSpacing(30)
 68        self.setLayout(self.layout)
 69
 70        # --- Title ---
 71        self.title = QLabel("Select the Next Processing Step")
 72        self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
 73        self.title.setFont(QFont("Arial", 18, QFont.Weight.Bold))
 74        self.title.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
 75        self.layout.addWidget(self.title)
 76
 77        # --- GroupBox for options ---
 78        self.radio_group_box = QGroupBox("Available Processes")
 79        self.radio_group_box.setStyleSheet("""
 80            QGroupBox {
 81                font-size: 13px;
 82                border: 1px solid #bdc3c7;
 83                border-radius: 10px;
 84                padding: 20px;
 85                background-color: #e5e5e5;
 86            }
 87        """)
 88        self.radio_group_box.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
 89        self.radio_group_box.setMaximumHeight(400)
 90
 91        radio_layout = QVBoxLayout()
 92        radio_layout.setSpacing(20)
 93        radio_layout.setContentsMargins(10, 10, 10, 10)
 94
 95        self.radio_group = QButtonGroup(self)
 96
 97        # --- Radio Buttons for each processing option ---
 98        self.radio_skull = QRadioButton("Skull Stripping")
 99        self.radio_draw = QRadioButton("Automatic Drawing")
100        self.radio_dl = QRadioButton("Deep Learning Segmentation")
101        self.radio_analysis = QRadioButton("Full Pipeline")
102
103        self.radio_buttons = [
104            self.radio_skull,
105            self.radio_draw,
106            self.radio_dl,
107            self.radio_analysis,
108        ]
109
110        # Apply consistent style to all buttons
111        for btn in self.radio_buttons:
112            btn.setFont(QFont("Arial", 14))
113            btn.setStyleSheet("""
114                QRadioButton {
115                    padding: 5px;
116                    border: 1px solid #bdc3c7;
117                    border-radius: 8px;
118                    background-color: white;
119                    spacing: 10px;
120                }
121                QRadioButton::hover {
122                    background-color: #dff9fb;
123                    border: 1px solid #3498db;
124                }
125                QRadioButton::checked {
126                    background-color: #d6eaf8;
127                    border: 2px solid #2980b9;
128                }
129            """)
130            btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
131
132        # Add buttons to layout and group
133        for i, btn in enumerate(self.radio_buttons):
134            self.radio_group.addButton(btn, id=i)
135            if btn == self.radio_dl:
136                # Add info tooltip for Deep Learning option
137                dl_widget = QWidget()
138                dl_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
139                dl_layout = QHBoxLayout(dl_widget)
140                dl_layout.setContentsMargins(0, 0, 0, 0)
141                dl_layout.setSpacing(5)
142
143                self.dl_info_label = InfoLabel(
144                    text="i",
145                    tooltip_text=QCoreApplication.translate(
146                        "ToolSelectionPage",
147                        "To use this function you need Linux and a CUDA capable GPU"
148                    )
149                )
150                dl_layout.addWidget(self.radio_dl)
151                dl_layout.addWidget(self.dl_info_label)
152                radio_layout.addWidget(dl_widget)
153            else:
154                radio_layout.addWidget(btn)
155
156        self.radio_group.buttonToggled.connect(lambda: self.on_selection())
157
158        self.radio_group_box.setLayout(radio_layout)
159        self.layout.addWidget(self.radio_group_box)
160
161        self.selected_option = None
162
163        # Connect language change signal if available
164        self._translate_ui()
165        if context and "language_changed" in context:
166            context["language_changed"].connect(self._translate_ui)
167
168    # -------------------------------------------------------------------------
169    # Navigation
170    # -------------------------------------------------------------------------
171
172    def on_selection(self):
173        """Triggered when a radio button is toggled."""
174        self.selected_option = self.radio_group.checkedId()
175        if self.context and "update_main_buttons" in self.context:
176            self.context["update_main_buttons"]()
177
178    def is_ready_to_advance(self):
179        """Return True if an option has been selected."""
180        return self.radio_group.checkedId() != -1
181
182    def is_ready_to_go_back(self):
183        """Always allows going back from this page."""
184        return True
185
186    def next(self, context):
187        """
188        Return the next page based on the selected option.
189
190        Handles platform and CUDA availability checks for Deep Learning mode.
191        """
192        page_classes = {
193            0: ("next_skull_stripping", SkullStrippingPage),
194            1: ("next_manual_draw", MaskNiftiSelectionPage),
195            2: ("next_deep_learning", DlNiftiSelectionPage),
196            3: ("next_pipeline", PipelinePatientSelectionPage),
197        }
198
199        if self.selected_option not in page_classes:
200            return None
201
202        # Check CUDA and OS support for Deep Learning mode
203        is_linux = platform.system() == "Linux"
204        has_gpu = torch.cuda.is_available()
205
206        if self.selected_option == 2 and (not has_gpu or not is_linux):
207            QMessageBox.warning(
208                self,
209                QCoreApplication.translate("ToolSelectionPage", "Not available for this platform"),
210                QCoreApplication.translate(
211                    "ToolSelectionPage",
212                    "The deep learning segmentation is not available for this platform: {0}"
213                ).format(platform.system()),
214            )
215            return self
216
217        # Create or reuse the next page instance
218        attr_name, page_class = page_classes[self.selected_option]
219        next_page = getattr(self, attr_name, None)
220
221        if not next_page:
222            next_page = page_class(context, self)
223            setattr(self, attr_name, next_page)
224            self.context["history"].append(next_page)
225
226        next_page.on_enter()
227        return next_page
228
229    def back(self):
230        """Navigate back to the previous page if available."""
231        if self.previous_page:
232            self.previous_page.on_enter()
233            return self.previous_page
234        return None
235
236    def reset_page(self):
237        """Reset selection state when the page is revisited."""
238        self.radio_group.setExclusive(False)
239        for button in self.radio_group.buttons():
240            button.setChecked(False)
241        self.radio_group.setExclusive(True)
242        self.selected_option = None
243
244    def _translate_ui(self):
245        """Translate all text elements (supports multi-language UI)."""
246        self.title.setText(QApplication.translate("ToolSelectionPage", "Select the Next Processing Step"))
247        self.radio_group_box.setTitle(QApplication.translate("ToolSelectionPage", "Available Processes"))
248        self.radio_skull.setText(QApplication.translate("ToolSelectionPage", "Skull Stripping"))
249        self.radio_draw.setText(QApplication.translate("ToolSelectionPage", "Automatic Drawing"))
250        self.radio_dl.setText(QApplication.translate("ToolSelectionPage", "Deep Learning Segmentation"))
251        self.radio_analysis.setText(QApplication.translate("ToolSelectionPage", "Full Pipeline"))
252        self.dl_info_label.setToolTip(QApplication.translate("ToolSelectionPage", "To use this function you need Linux and a CUDA capable GPU"))
class ToolSelectionPage(page.Page):
 34class ToolSelectionPage(Page):
 35    """
 36    A UI page for selecting the next processing step in the workflow.
 37
 38    This class extends `Page` and displays a set of radio buttons representing
 39    different data processing operations. The user’s selection determines which
 40    next page in the pipeline will be opened.
 41
 42    Attributes
 43    ----------
 44    context : dict
 45        Shared application state, including navigation and configuration.
 46    previous_page : Page
 47        Reference to the previous page for backward navigation.
 48    selected_option : int or None
 49        The currently selected radio button ID.
 50    """
 51
 52    def __init__(self, context=None, previous_page=None):
 53        """Initialize the ToolSelectionPage UI."""
 54        super().__init__()
 55
 56        self.context = context
 57        self.previous_page = previous_page
 58
 59        # References to next pages for each option
 60        self.next_skull_stripping = None
 61        self.next_manual_draw = None
 62        self.next_deep_learning = None
 63        self.next_pipeline = None
 64
 65        # === Layout setup ===
 66        self.layout = QVBoxLayout(self)
 67        self.layout.setContentsMargins(40, 40, 40, 40)
 68        self.layout.setSpacing(30)
 69        self.setLayout(self.layout)
 70
 71        # --- Title ---
 72        self.title = QLabel("Select the Next Processing Step")
 73        self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
 74        self.title.setFont(QFont("Arial", 18, QFont.Weight.Bold))
 75        self.title.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
 76        self.layout.addWidget(self.title)
 77
 78        # --- GroupBox for options ---
 79        self.radio_group_box = QGroupBox("Available Processes")
 80        self.radio_group_box.setStyleSheet("""
 81            QGroupBox {
 82                font-size: 13px;
 83                border: 1px solid #bdc3c7;
 84                border-radius: 10px;
 85                padding: 20px;
 86                background-color: #e5e5e5;
 87            }
 88        """)
 89        self.radio_group_box.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
 90        self.radio_group_box.setMaximumHeight(400)
 91
 92        radio_layout = QVBoxLayout()
 93        radio_layout.setSpacing(20)
 94        radio_layout.setContentsMargins(10, 10, 10, 10)
 95
 96        self.radio_group = QButtonGroup(self)
 97
 98        # --- Radio Buttons for each processing option ---
 99        self.radio_skull = QRadioButton("Skull Stripping")
100        self.radio_draw = QRadioButton("Automatic Drawing")
101        self.radio_dl = QRadioButton("Deep Learning Segmentation")
102        self.radio_analysis = QRadioButton("Full Pipeline")
103
104        self.radio_buttons = [
105            self.radio_skull,
106            self.radio_draw,
107            self.radio_dl,
108            self.radio_analysis,
109        ]
110
111        # Apply consistent style to all buttons
112        for btn in self.radio_buttons:
113            btn.setFont(QFont("Arial", 14))
114            btn.setStyleSheet("""
115                QRadioButton {
116                    padding: 5px;
117                    border: 1px solid #bdc3c7;
118                    border-radius: 8px;
119                    background-color: white;
120                    spacing: 10px;
121                }
122                QRadioButton::hover {
123                    background-color: #dff9fb;
124                    border: 1px solid #3498db;
125                }
126                QRadioButton::checked {
127                    background-color: #d6eaf8;
128                    border: 2px solid #2980b9;
129                }
130            """)
131            btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
132
133        # Add buttons to layout and group
134        for i, btn in enumerate(self.radio_buttons):
135            self.radio_group.addButton(btn, id=i)
136            if btn == self.radio_dl:
137                # Add info tooltip for Deep Learning option
138                dl_widget = QWidget()
139                dl_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
140                dl_layout = QHBoxLayout(dl_widget)
141                dl_layout.setContentsMargins(0, 0, 0, 0)
142                dl_layout.setSpacing(5)
143
144                self.dl_info_label = InfoLabel(
145                    text="i",
146                    tooltip_text=QCoreApplication.translate(
147                        "ToolSelectionPage",
148                        "To use this function you need Linux and a CUDA capable GPU"
149                    )
150                )
151                dl_layout.addWidget(self.radio_dl)
152                dl_layout.addWidget(self.dl_info_label)
153                radio_layout.addWidget(dl_widget)
154            else:
155                radio_layout.addWidget(btn)
156
157        self.radio_group.buttonToggled.connect(lambda: self.on_selection())
158
159        self.radio_group_box.setLayout(radio_layout)
160        self.layout.addWidget(self.radio_group_box)
161
162        self.selected_option = None
163
164        # Connect language change signal if available
165        self._translate_ui()
166        if context and "language_changed" in context:
167            context["language_changed"].connect(self._translate_ui)
168
169    # -------------------------------------------------------------------------
170    # Navigation
171    # -------------------------------------------------------------------------
172
173    def on_selection(self):
174        """Triggered when a radio button is toggled."""
175        self.selected_option = self.radio_group.checkedId()
176        if self.context and "update_main_buttons" in self.context:
177            self.context["update_main_buttons"]()
178
179    def is_ready_to_advance(self):
180        """Return True if an option has been selected."""
181        return self.radio_group.checkedId() != -1
182
183    def is_ready_to_go_back(self):
184        """Always allows going back from this page."""
185        return True
186
187    def next(self, context):
188        """
189        Return the next page based on the selected option.
190
191        Handles platform and CUDA availability checks for Deep Learning mode.
192        """
193        page_classes = {
194            0: ("next_skull_stripping", SkullStrippingPage),
195            1: ("next_manual_draw", MaskNiftiSelectionPage),
196            2: ("next_deep_learning", DlNiftiSelectionPage),
197            3: ("next_pipeline", PipelinePatientSelectionPage),
198        }
199
200        if self.selected_option not in page_classes:
201            return None
202
203        # Check CUDA and OS support for Deep Learning mode
204        is_linux = platform.system() == "Linux"
205        has_gpu = torch.cuda.is_available()
206
207        if self.selected_option == 2 and (not has_gpu or not is_linux):
208            QMessageBox.warning(
209                self,
210                QCoreApplication.translate("ToolSelectionPage", "Not available for this platform"),
211                QCoreApplication.translate(
212                    "ToolSelectionPage",
213                    "The deep learning segmentation is not available for this platform: {0}"
214                ).format(platform.system()),
215            )
216            return self
217
218        # Create or reuse the next page instance
219        attr_name, page_class = page_classes[self.selected_option]
220        next_page = getattr(self, attr_name, None)
221
222        if not next_page:
223            next_page = page_class(context, self)
224            setattr(self, attr_name, next_page)
225            self.context["history"].append(next_page)
226
227        next_page.on_enter()
228        return next_page
229
230    def back(self):
231        """Navigate back to the previous page if available."""
232        if self.previous_page:
233            self.previous_page.on_enter()
234            return self.previous_page
235        return None
236
237    def reset_page(self):
238        """Reset selection state when the page is revisited."""
239        self.radio_group.setExclusive(False)
240        for button in self.radio_group.buttons():
241            button.setChecked(False)
242        self.radio_group.setExclusive(True)
243        self.selected_option = None
244
245    def _translate_ui(self):
246        """Translate all text elements (supports multi-language UI)."""
247        self.title.setText(QApplication.translate("ToolSelectionPage", "Select the Next Processing Step"))
248        self.radio_group_box.setTitle(QApplication.translate("ToolSelectionPage", "Available Processes"))
249        self.radio_skull.setText(QApplication.translate("ToolSelectionPage", "Skull Stripping"))
250        self.radio_draw.setText(QApplication.translate("ToolSelectionPage", "Automatic Drawing"))
251        self.radio_dl.setText(QApplication.translate("ToolSelectionPage", "Deep Learning Segmentation"))
252        self.radio_analysis.setText(QApplication.translate("ToolSelectionPage", "Full Pipeline"))
253        self.dl_info_label.setToolTip(QApplication.translate("ToolSelectionPage", "To use this function you need Linux and a CUDA capable GPU"))

A UI page for selecting the next processing step in the workflow.

This class extends Page and displays a set of radio buttons representing different data processing operations. The user’s selection determines which next page in the pipeline will be opened.

Attributes

context : dict Shared application state, including navigation and configuration. previous_page : Page Reference to the previous page for backward navigation. selected_option : int or None The currently selected radio button ID.

ToolSelectionPage(context=None, previous_page=None)
 52    def __init__(self, context=None, previous_page=None):
 53        """Initialize the ToolSelectionPage UI."""
 54        super().__init__()
 55
 56        self.context = context
 57        self.previous_page = previous_page
 58
 59        # References to next pages for each option
 60        self.next_skull_stripping = None
 61        self.next_manual_draw = None
 62        self.next_deep_learning = None
 63        self.next_pipeline = None
 64
 65        # === Layout setup ===
 66        self.layout = QVBoxLayout(self)
 67        self.layout.setContentsMargins(40, 40, 40, 40)
 68        self.layout.setSpacing(30)
 69        self.setLayout(self.layout)
 70
 71        # --- Title ---
 72        self.title = QLabel("Select the Next Processing Step")
 73        self.title.setAlignment(Qt.AlignmentFlag.AlignCenter)
 74        self.title.setFont(QFont("Arial", 18, QFont.Weight.Bold))
 75        self.title.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
 76        self.layout.addWidget(self.title)
 77
 78        # --- GroupBox for options ---
 79        self.radio_group_box = QGroupBox("Available Processes")
 80        self.radio_group_box.setStyleSheet("""
 81            QGroupBox {
 82                font-size: 13px;
 83                border: 1px solid #bdc3c7;
 84                border-radius: 10px;
 85                padding: 20px;
 86                background-color: #e5e5e5;
 87            }
 88        """)
 89        self.radio_group_box.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
 90        self.radio_group_box.setMaximumHeight(400)
 91
 92        radio_layout = QVBoxLayout()
 93        radio_layout.setSpacing(20)
 94        radio_layout.setContentsMargins(10, 10, 10, 10)
 95
 96        self.radio_group = QButtonGroup(self)
 97
 98        # --- Radio Buttons for each processing option ---
 99        self.radio_skull = QRadioButton("Skull Stripping")
100        self.radio_draw = QRadioButton("Automatic Drawing")
101        self.radio_dl = QRadioButton("Deep Learning Segmentation")
102        self.radio_analysis = QRadioButton("Full Pipeline")
103
104        self.radio_buttons = [
105            self.radio_skull,
106            self.radio_draw,
107            self.radio_dl,
108            self.radio_analysis,
109        ]
110
111        # Apply consistent style to all buttons
112        for btn in self.radio_buttons:
113            btn.setFont(QFont("Arial", 14))
114            btn.setStyleSheet("""
115                QRadioButton {
116                    padding: 5px;
117                    border: 1px solid #bdc3c7;
118                    border-radius: 8px;
119                    background-color: white;
120                    spacing: 10px;
121                }
122                QRadioButton::hover {
123                    background-color: #dff9fb;
124                    border: 1px solid #3498db;
125                }
126                QRadioButton::checked {
127                    background-color: #d6eaf8;
128                    border: 2px solid #2980b9;
129                }
130            """)
131            btn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
132
133        # Add buttons to layout and group
134        for i, btn in enumerate(self.radio_buttons):
135            self.radio_group.addButton(btn, id=i)
136            if btn == self.radio_dl:
137                # Add info tooltip for Deep Learning option
138                dl_widget = QWidget()
139                dl_widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
140                dl_layout = QHBoxLayout(dl_widget)
141                dl_layout.setContentsMargins(0, 0, 0, 0)
142                dl_layout.setSpacing(5)
143
144                self.dl_info_label = InfoLabel(
145                    text="i",
146                    tooltip_text=QCoreApplication.translate(
147                        "ToolSelectionPage",
148                        "To use this function you need Linux and a CUDA capable GPU"
149                    )
150                )
151                dl_layout.addWidget(self.radio_dl)
152                dl_layout.addWidget(self.dl_info_label)
153                radio_layout.addWidget(dl_widget)
154            else:
155                radio_layout.addWidget(btn)
156
157        self.radio_group.buttonToggled.connect(lambda: self.on_selection())
158
159        self.radio_group_box.setLayout(radio_layout)
160        self.layout.addWidget(self.radio_group_box)
161
162        self.selected_option = None
163
164        # Connect language change signal if available
165        self._translate_ui()
166        if context and "language_changed" in context:
167            context["language_changed"].connect(self._translate_ui)

Initialize the ToolSelectionPage UI.

context
previous_page
next_skull_stripping
next_manual_draw
next_deep_learning
next_pipeline
def layout(unknown):
title
radio_group_box
radio_group
radio_skull
radio_draw
radio_dl
radio_analysis
radio_buttons
selected_option
def on_selection(self):
173    def on_selection(self):
174        """Triggered when a radio button is toggled."""
175        self.selected_option = self.radio_group.checkedId()
176        if self.context and "update_main_buttons" in self.context:
177            self.context["update_main_buttons"]()

Triggered when a radio button is toggled.

def is_ready_to_advance(self):
179    def is_ready_to_advance(self):
180        """Return True if an option has been selected."""
181        return self.radio_group.checkedId() != -1

Return True if an option has been selected.

def is_ready_to_go_back(self):
183    def is_ready_to_go_back(self):
184        """Always allows going back from this page."""
185        return True

Always allows going back from this page.

def next(self, context):
187    def next(self, context):
188        """
189        Return the next page based on the selected option.
190
191        Handles platform and CUDA availability checks for Deep Learning mode.
192        """
193        page_classes = {
194            0: ("next_skull_stripping", SkullStrippingPage),
195            1: ("next_manual_draw", MaskNiftiSelectionPage),
196            2: ("next_deep_learning", DlNiftiSelectionPage),
197            3: ("next_pipeline", PipelinePatientSelectionPage),
198        }
199
200        if self.selected_option not in page_classes:
201            return None
202
203        # Check CUDA and OS support for Deep Learning mode
204        is_linux = platform.system() == "Linux"
205        has_gpu = torch.cuda.is_available()
206
207        if self.selected_option == 2 and (not has_gpu or not is_linux):
208            QMessageBox.warning(
209                self,
210                QCoreApplication.translate("ToolSelectionPage", "Not available for this platform"),
211                QCoreApplication.translate(
212                    "ToolSelectionPage",
213                    "The deep learning segmentation is not available for this platform: {0}"
214                ).format(platform.system()),
215            )
216            return self
217
218        # Create or reuse the next page instance
219        attr_name, page_class = page_classes[self.selected_option]
220        next_page = getattr(self, attr_name, None)
221
222        if not next_page:
223            next_page = page_class(context, self)
224            setattr(self, attr_name, next_page)
225            self.context["history"].append(next_page)
226
227        next_page.on_enter()
228        return next_page

Return the next page based on the selected option.

Handles platform and CUDA availability checks for Deep Learning mode.

def back(self):
230    def back(self):
231        """Navigate back to the previous page if available."""
232        if self.previous_page:
233            self.previous_page.on_enter()
234            return self.previous_page
235        return None

Navigate back to the previous page if available.

def reset_page(self):
237    def reset_page(self):
238        """Reset selection state when the page is revisited."""
239        self.radio_group.setExclusive(False)
240        for button in self.radio_group.buttons():
241            button.setChecked(False)
242        self.radio_group.setExclusive(True)
243        self.selected_option = None

Reset selection state when the page is revisited.