Skip to content

Commit 394bb35

Browse files
authored
Adds slider view widget (#161)
1 parent dc26ba2 commit 394bb35

File tree

11 files changed

+1209
-47
lines changed

11 files changed

+1209
-47
lines changed

rascal2/ui/view.py

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from rascal2.dialogs.settings_dialog import SettingsDialog
99
from rascal2.dialogs.startup_dialog import PROJECT_FILES, LoadDialog, LoadR1Dialog, NewProjectDialog, StartupDialog
1010
from rascal2.settings import MDIGeometries, Settings, get_global_settings
11-
from rascal2.widgets import ControlsWidget, PlotWidget, TerminalWidget
11+
from rascal2.widgets import ControlsWidget, PlotWidget, SlidersViewWidget, TerminalWidget
1212
from rascal2.widgets.project import ProjectWidget
1313
from rascal2.widgets.startup import StartUpWidget
1414

@@ -22,6 +22,11 @@ class MainWindowView(QtWidgets.QMainWindow):
2222

2323
def __init__(self):
2424
super().__init__()
25+
# Public interface
26+
self.disabled_elements = []
27+
self.show_sliders = False # no one displays sliders initially except got from configuration
28+
# (not implemented yet)
29+
2530
self.setWindowTitle(MAIN_WINDOW_TITLE)
2631

2732
window_icon = QtGui.QIcon(path_for("logo.png"))
@@ -38,14 +43,21 @@ def __init__(self):
3843
self.plot_widget = PlotWidget(self)
3944
self.terminal_widget = TerminalWidget()
4045
self.controls_widget = ControlsWidget(self)
46+
self.sliders_view_widget = SlidersViewWidget(self)
4147
self.project_widget = ProjectWidget(self)
4248

43-
self.disabled_elements = []
49+
## protected interface and public properties construction
50+
51+
# define menu controlling switch between table and slider views
52+
self._sliders_menu_control_text = {
53+
"ShowSliders": "&Show Sliders", # if state is show sliders, click will show them
54+
"HideSliders": "&Hide Sliders",
55+
} # if state is show table, click will show sliders
4456

4557
self.create_actions()
4658

47-
self.main_menu = self.menuBar()
48-
self.add_submenus(self.main_menu)
59+
main_menu = self.menuBar()
60+
self.add_submenus(main_menu)
4961

5062
self.create_toolbar()
5163
self.create_status_bar()
@@ -166,6 +178,20 @@ def create_actions(self):
166178
open_help_action.triggered.connect(self.open_docs)
167179
self.open_help_action = open_help_action
168180

181+
# done this way expecting the value "show_sliders" being stored
182+
# in configuration in a future + "show_sliders" is public for this reason
183+
if self.show_sliders:
184+
# if show_sliders state is True, action will be hide
185+
show_or_hide_slider_action = QtGui.QAction(self._sliders_menu_control_text["HideSliders"], self)
186+
else:
187+
# if display_sliders state is False, action will be show
188+
show_or_hide_slider_action = QtGui.QAction(self._sliders_menu_control_text["ShowSliders"], self)
189+
show_or_hide_slider_action.setStatusTip("Show or Hide Sliders")
190+
show_or_hide_slider_action.triggered.connect(lambda: self.show_or_hide_sliders(None))
191+
self._show_or_hide_slider_action = show_or_hide_slider_action
192+
self._show_or_hide_slider_action.setEnabled(False)
193+
self.disabled_elements.append(self._show_or_hide_slider_action)
194+
169195
open_about_action = QtGui.QAction("&About", self)
170196
open_about_action.setStatusTip("Report RAT version&info")
171197
open_about_action.triggered.connect(self.open_about_info)
@@ -242,6 +268,8 @@ def add_submenus(self, main_menu: QtWidgets.QMenuBar):
242268

243269
tools_menu = main_menu.addMenu("&Tools")
244270
tools_menu.setObjectName("&Tools")
271+
tools_menu.addAction(self._show_or_hide_slider_action)
272+
tools_menu.addSeparator()
245273
tools_menu.addAction(self.clear_terminal_action)
246274
tools_menu.addSeparator()
247275
tools_menu.addAction(self.setup_matlab_action)
@@ -251,6 +279,32 @@ def add_submenus(self, main_menu: QtWidgets.QMenuBar):
251279
help_menu.addAction(self.open_about_action)
252280
help_menu.addAction(self.open_help_action)
253281

282+
def show_or_hide_sliders(self, do_show_sliders=None):
283+
"""Depending on current state, show or hide sliders for
284+
table properties within Project class view.
285+
286+
Parameters:
287+
-----------
288+
289+
do_show_sliders: bool,default None
290+
if provided, sets self.show_sliders logical variable into the requested state
291+
(True/False), forcing sliders widget to appear/disappear. if None, applies not to current state.
292+
"""
293+
if do_show_sliders is None:
294+
self.show_sliders = not self.show_sliders
295+
else:
296+
self.show_sliders = do_show_sliders
297+
298+
if self.show_sliders:
299+
self._show_or_hide_slider_action.setText(self._sliders_menu_control_text["HideSliders"])
300+
self.sliders_view_widget.show()
301+
self.project_widget.setWindowTitle("Sliders View")
302+
self.project_widget.stacked_widget.setCurrentIndex(2)
303+
else:
304+
self._show_or_hide_slider_action.setText(self._sliders_menu_control_text["ShowSliders"])
305+
self.sliders_view_widget.hide()
306+
self.project_widget.show_project_view()
307+
254308
def open_about_info(self):
255309
"""Opens about menu containing information about RASCAL gui"""
256310
self.about_dialog.update_rascal_info(self)
@@ -311,7 +365,9 @@ def setup_mdi(self):
311365
self.setCentralWidget(self.mdi)
312366

313367
def setup_mdi_widgets(self):
314-
"""Performs setup of MDI widgets that relies on the Project existing."""
368+
"""
369+
Performs initialization of MDI widgets that rely on the Project being defined.
370+
"""
315371
self.controls_widget.setup_controls()
316372
self.project_widget.show_project_view()
317373
self.plot_widget.clear()
@@ -333,7 +389,6 @@ def reset_mdi_layout(self):
333389
window.showMinimized()
334390
else:
335391
window.showNormal()
336-
337392
window.setGeometry(x, y, width, height)
338393

339394
def save_mdi_layout(self):

rascal2/widgets/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from rascal2.widgets.controls import ControlsWidget
22
from rascal2.widgets.inputs import AdaptiveDoubleSpinBox, MultiSelectComboBox, MultiSelectList, get_validated_input
33
from rascal2.widgets.plot import PlotWidget
4+
from rascal2.widgets.sliders_view import SlidersViewWidget
45
from rascal2.widgets.terminal import TerminalWidget
56

67
__all__ = [
@@ -11,4 +12,5 @@
1112
"MultiSelectList",
1213
"PlotWidget",
1314
"TerminalWidget",
15+
"SlidersViewWidget",
1416
]

rascal2/widgets/project/project.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,22 +72,27 @@ def __init__(self, parent):
7272
self.stacked_widget = QtWidgets.QStackedWidget()
7373
self.stacked_widget.addWidget(project_view)
7474
self.stacked_widget.addWidget(project_edit)
75+
self.stacked_widget.addWidget(self.parent.sliders_view_widget)
7576

7677
layout = QtWidgets.QVBoxLayout()
7778
layout.setContentsMargins(0, 0, 0, 0)
7879
layout.addWidget(self.stacked_widget)
7980
self.setLayout(layout)
8081

81-
def create_project_view(self) -> None:
82+
def create_project_view(self) -> QtWidgets.QWidget:
8283
"""Creates the project (non-edit) view"""
8384
project_widget = QtWidgets.QWidget()
8485
main_layout = QtWidgets.QVBoxLayout()
8586
main_layout.setSpacing(20)
8687

88+
show_sliders_button = QtWidgets.QPushButton("Show sliders", self, objectName="ShowSliders")
89+
show_sliders_button.clicked.connect(lambda: self.parent.show_or_hide_sliders(True))
90+
8791
self.edit_project_button = QtWidgets.QPushButton("Edit Project", self, icon=QtGui.QIcon(path_for("edit.png")))
8892
self.edit_project_button.clicked.connect(self.show_edit_view)
8993
button_layout = QtWidgets.QHBoxLayout()
9094
button_layout.setAlignment(QtCore.Qt.AlignmentFlag.AlignRight)
95+
button_layout.addWidget(show_sliders_button)
9196
button_layout.addWidget(self.edit_project_button)
9297

9398
main_layout.addLayout(button_layout)
@@ -142,7 +147,7 @@ def create_project_view(self) -> None:
142147

143148
return project_widget
144149

145-
def create_edit_view(self) -> None:
150+
def create_edit_view(self) -> QtWidgets.QWidget:
146151
"""Creates the project edit view"""
147152

148153
edit_project_widget = QtWidgets.QWidget()
@@ -360,6 +365,8 @@ def show_project_view(self) -> None:
360365

361366
def show_edit_view(self) -> None:
362367
"""Show edit view"""
368+
369+
# will be updated according to edit changes
363370
self.update_project_view(0)
364371
self.setWindowTitle("Edit Project")
365372
self.parent.controls_widget.run_button.setEnabled(False)
@@ -540,6 +547,7 @@ def __init__(self, fields: list[str], parent, edit_mode: bool = False):
540547
self.tables[field] = DataWidget(field, self)
541548
else:
542549
self.tables[field] = ProjectFieldWidget(field, self)
550+
self.tables[field].setObjectName(field)
543551
layout.addWidget(self.tables[field])
544552

545553
scroll_area = QtWidgets.QScrollArea()

rascal2/widgets/project/tables.py

Lines changed: 39 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,27 @@ def data(self, index, role=QtCore.Qt.ItemDataRole.DisplayRole):
7575
elif role == QtCore.Qt.ItemDataRole.CheckStateRole and self.index_header(index) == "fit":
7676
return QtCore.Qt.CheckState.Checked if data else QtCore.Qt.CheckState.Unchecked
7777

78-
def setData(self, index, value, role=QtCore.Qt.ItemDataRole.EditRole) -> bool:
78+
def setData(
79+
self, index: QtCore.QModelIndex, value, role=QtCore.Qt.ItemDataRole.EditRole, recalculate_proj=True
80+
) -> bool:
81+
"""Implement abstract setData method of QAbstractTableModel.
82+
83+
Parameters
84+
----------
85+
index: QtCore.QModelIndex
86+
QModelIndex representing the row and column indices of edited cell wrt. the edited table
87+
value:
88+
new value of appropriate cell of the table.
89+
role: QtCore.Qt.ItemDataRole
90+
not sure what it is but apparently controls table behaviour amd needs to be Edit.
91+
it nof Edit, method does nothing.
92+
recalculate_proj: bool,default True
93+
Additional control for RAT project recalculation. Set it to False when modifying
94+
a bunch of properties in a loop changing it to True for the last value to recalculate
95+
project and update all table's dependent widgets.
96+
IMPORTANT: ensure last value differs from the existing one for this property as project
97+
will be not recalculated otherwise.
98+
"""
7999
if role == QtCore.Qt.ItemDataRole.EditRole or role == QtCore.Qt.ItemDataRole.CheckStateRole:
80100
row = index.row()
81101
param = self.index_header(index)
@@ -93,7 +113,7 @@ def setData(self, index, value, role=QtCore.Qt.ItemDataRole.EditRole) -> bool:
93113
return False
94114
if not self.edit_mode:
95115
# recalculate plots if value was changed
96-
recalculate = self.index_header(index) == "value"
116+
recalculate = self.index_header(index) == "value" and recalculate_proj
97117
self.parent.update_project(recalculate)
98118
self.dataChanged.emit(index, index)
99119
return True
@@ -175,6 +195,7 @@ def __init__(self, field: str, parent):
175195
self.parent = parent
176196
self.project_widget = parent.parent
177197
self.table = QtWidgets.QTableView(parent)
198+
178199
self.table.horizontalHeader().setCascadingSectionResizes(True)
179200
self.table.setMinimumHeight(100)
180201

@@ -231,7 +252,7 @@ def resize_columns(self):
231252

232253
header.setStretchLastSection(True)
233254

234-
def update_model(self, classlist):
255+
def update_model(self, classlist: ratapi.classlist.ClassList):
235256
"""Update the table model to synchronise with the project field."""
236257
self.model = self.classlist_model(classlist, self)
237258

@@ -248,10 +269,18 @@ def update_model(self, classlist):
248269
def set_item_delegates(self):
249270
"""Set item delegates and open persistent editors for the table."""
250271
for i, header in enumerate(self.model.headers):
251-
self.table.setItemDelegateForColumn(
252-
i + self.model.col_offset,
253-
delegates.ValidatedInputDelegate(self.model.item_type.model_fields[header], self.table),
254-
)
272+
delegate = delegates.ValidatedInputDelegate(self.model.item_type.model_fields[header], self.table)
273+
self.table.setItemDelegateForColumn(i + self.model.col_offset, delegate)
274+
275+
def get_item_delegates(self, fields_list: list):
276+
"""Return list of delegates attached to the fields
277+
with the names provided as input
278+
"""
279+
dlgts = []
280+
for i, header in enumerate(self.model.headers):
281+
if header in fields_list:
282+
dlgts.append(self.table.itemDelegateForColumn(i + self.model.col_offset))
283+
return dlgts
255284

256285
def append_item(self):
257286
"""Append an item to the model if the model exists."""
@@ -354,13 +383,14 @@ class ParameterFieldWidget(ProjectFieldWidget):
354383
def set_item_delegates(self):
355384
for i, header in enumerate(self.model.headers):
356385
if header in ["min", "value", "max"]:
357-
self.table.setItemDelegateForColumn(i + 1, delegates.ValueSpinBoxDelegate(header, self.table))
386+
delegate = delegates.ValueSpinBoxDelegate(header, self.table)
387+
self.table.setItemDelegateForColumn(i + 1, delegate)
358388
else:
359389
self.table.setItemDelegateForColumn(
360390
i + 1, delegates.ValidatedInputDelegate(self.model.item_type.model_fields[header], self.table)
361391
)
362392

363-
def update_model(self, classlist):
393+
def update_model(self, classlist: ratapi.classlist.ClassList):
364394
super().update_model(classlist)
365395
header = self.table.horizontalHeader()
366396
header.setSectionResizeMode(

0 commit comments

Comments
 (0)