Line data Source code
1 : # SPDX-FileCopyrightText: 2025 Pairinteraction Developers
2 : # SPDX-License-Identifier: LGPL-3.0-or-later
3 :
4 0 : from typing import Callable, Optional, Union
5 :
6 0 : from PySide6.QtWidgets import (
7 : QCheckBox,
8 : QLabel,
9 : QSpacerItem,
10 : QWidget,
11 : )
12 :
13 0 : from pairinteraction_gui.qobjects import parse_html
14 0 : from pairinteraction_gui.qobjects.spin_boxes import DoubleSpinBox, HalfIntSpinBox, IntSpinBox
15 0 : from pairinteraction_gui.qobjects.widget import WidgetH
16 :
17 :
18 0 : class Item(WidgetH):
19 0 : margin = (20, 0, 20, 0)
20 0 : spacing = 10
21 :
22 0 : def __init__(
23 : self,
24 : parent: QWidget,
25 : label: str,
26 : spinboxes: dict[str, Union[IntSpinBox, HalfIntSpinBox, DoubleSpinBox]],
27 : unit: str = "",
28 : checked: bool = True,
29 : ) -> None:
30 0 : self.checkbox = QCheckBox()
31 0 : self.checkbox.setChecked(checked)
32 0 : self.checkbox.stateChanged.connect(self._on_checkbox_changed)
33 :
34 0 : self.label = label
35 0 : self._label = QLabel(parse_html(label))
36 0 : self._label.setMinimumWidth(25)
37 :
38 0 : self.spinboxes = spinboxes
39 :
40 0 : self.unit = unit
41 :
42 0 : super().__init__(parent)
43 :
44 0 : def setupWidget(self) -> None:
45 0 : self.layout().addWidget(self.checkbox)
46 0 : self.layout().addWidget(self._label)
47 :
48 0 : def postSetupWidget(self) -> None:
49 0 : self._unit = None
50 0 : if self.unit is not None and len(self.unit) > 0:
51 0 : self._unit = QLabel(self.unit)
52 0 : self.layout().addWidget(self._unit)
53 :
54 0 : self.layout().addStretch()
55 :
56 : # Initial state
57 0 : self._on_checkbox_changed(self.isChecked())
58 :
59 0 : def _on_checkbox_changed(self, state: bool) -> None:
60 : """Update the enabled state of widgets when checkbox changes."""
61 0 : self.setStyleSheet("color: black" if state else "color: gray")
62 0 : for spinbox in self.spinboxes.values():
63 0 : spinbox.setEnabled(state)
64 :
65 0 : def isChecked(self) -> bool:
66 : """Return the state of the checkbox."""
67 0 : return self.checkbox.isChecked()
68 :
69 0 : def connectAll(self, func: Callable[[], None]) -> None:
70 : """Connect the function to the spinbox.valueChanged signal."""
71 0 : self.checkbox.stateChanged.connect(lambda state: func())
72 0 : for spinbox in self.spinboxes.values():
73 0 : spinbox.valueChanged.connect(lambda value: func())
74 :
75 :
76 0 : class QnItem(Item):
77 : """Widget for displaying a Qn value with a single spinbox."""
78 :
79 0 : def __init__(
80 : self,
81 : parent: QWidget,
82 : label: str,
83 : spinbox: Union[IntSpinBox, HalfIntSpinBox, DoubleSpinBox],
84 : unit: str = "",
85 : checked: bool = True,
86 : ) -> None:
87 0 : spinbox.setObjectName(label)
88 0 : spinbox.setMinimumWidth(100)
89 :
90 0 : spinboxes = {"value": spinbox}
91 0 : super().__init__(parent, label, spinboxes, unit, checked)
92 :
93 0 : def setupWidget(self) -> None:
94 0 : super().setupWidget()
95 0 : self.layout().addWidget(self.spinboxes["value"])
96 :
97 0 : def value(self) -> Union[int, float]:
98 : """Return the value of the spinbox."""
99 0 : return self.spinboxes["value"].value()
100 :
101 :
102 0 : class RangeItem(WidgetH):
103 : """Widget for displaying a range with min and max spinboxes."""
104 :
105 0 : margin = (20, 0, 20, 0)
106 0 : spacing = 10
107 :
108 0 : def __init__(
109 : self,
110 : parent: QWidget,
111 : label: str,
112 : value_range: tuple[float, float] = (0, 999),
113 : value_defaults: tuple[float, float] = (0, 0),
114 : unit: str = "",
115 : tooltip_label: Optional[str] = None,
116 : checkable: bool = True,
117 : checked: bool = True,
118 : ) -> None:
119 0 : tooltip_label = tooltip_label if tooltip_label is not None else label
120 :
121 0 : self.checkbox: Union[QCheckBox, QSpacerItem]
122 0 : if checkable:
123 0 : self.checkbox = QCheckBox()
124 0 : self.checkbox.setChecked(checked)
125 0 : self.checkbox.stateChanged.connect(self._on_checkbox_changed)
126 : else:
127 0 : self.checkbox = QSpacerItem(25, 0)
128 :
129 0 : self.label = QLabel(label)
130 0 : self.label.setMinimumWidth(25)
131 :
132 0 : self.min_spinbox = DoubleSpinBox(
133 : parent, *value_range, value_defaults[0], tooltip=f"Minimum {tooltip_label} in {unit}"
134 : )
135 0 : self.max_spinbox = DoubleSpinBox(
136 : parent, *value_range, value_defaults[1], tooltip=f"Maximum {tooltip_label} in {unit}"
137 : )
138 0 : self.min_spinbox.setObjectName(f"{label.lower()}_min")
139 0 : self.max_spinbox.setObjectName(f"{label.lower()}_max")
140 :
141 0 : self.unit = QLabel(unit)
142 :
143 0 : super().__init__(parent)
144 :
145 0 : def setupWidget(self) -> None:
146 0 : if isinstance(self.checkbox, QCheckBox):
147 0 : self.layout().addWidget(self.checkbox)
148 0 : elif isinstance(self.checkbox, QSpacerItem):
149 0 : self.layout().addItem(self.checkbox)
150 0 : self.layout().addWidget(self.label)
151 :
152 0 : self.layout().addWidget(self.min_spinbox)
153 0 : self.layout().addWidget(QLabel("to"))
154 0 : self.layout().addWidget(self.max_spinbox)
155 :
156 0 : self.layout().addWidget(self.unit)
157 0 : self.layout().addStretch()
158 :
159 0 : def postSetupWidget(self) -> None:
160 0 : self._on_checkbox_changed(self.isChecked())
161 :
162 0 : @property
163 0 : def spinboxes(self) -> tuple[DoubleSpinBox, DoubleSpinBox]:
164 : """Return the min and max spinboxes."""
165 0 : return (self.min_spinbox, self.max_spinbox)
166 :
167 0 : def connectAll(self, func: Callable[[], None]) -> None:
168 : """Connect the function to the spinbox.valueChanged signal."""
169 0 : if isinstance(self.checkbox, QCheckBox):
170 0 : self.checkbox.stateChanged.connect(lambda state: func())
171 0 : for spinbox in self.spinboxes:
172 0 : spinbox.valueChanged.connect(lambda value: func())
173 :
174 0 : def _on_checkbox_changed(self, state: bool) -> None:
175 : """Update the enabled state of widgets when checkbox changes."""
176 0 : self.setStyleSheet("color: black" if state else "color: gray")
177 0 : for spinbox in self.spinboxes:
178 0 : spinbox.setEnabled(state)
179 :
180 0 : def isChecked(self) -> bool:
181 : """Return the state of the checkbox."""
182 0 : if isinstance(self.checkbox, QSpacerItem):
183 0 : return True
184 0 : return self.checkbox.isChecked()
185 :
186 0 : def values(self) -> tuple[float, float]:
187 : """Return the values of the min and max spinboxes."""
188 0 : return (self.min_spinbox.value(), self.max_spinbox.value())
|