Coverage for /usr/local/lib/python3.13/dist-packages/pyrocko/gui/state.py: 83%
127 statements
« prev ^ index » next coverage.py v7.6.0, created at 2025-12-04 10:41 +0000
« prev ^ index » next coverage.py v7.6.0, created at 2025-12-04 10:41 +0000
1# https://pyrocko.org - GPLv3
2#
3# The Pyrocko Developers, 21st Century
4# ---|P------/S----------~Lg----------
6'''
72-way state binding utilities for Qt/talkie.
8'''
10import logging
12from pyrocko.gui import util as gui_util
13from pyrocko.color import Color
15logger = logging.getLogger('pyrocko.gui.state')
18def state_bind(
19 owner, state, paths, update_state,
20 widget, signals, update_widget, attribute=None):
22 def make_wrappers(widget):
23 def wrap_update_widget(*args):
24 if attribute:
25 update_widget(state, attribute, widget)
26 else:
27 update_widget(state, widget)
28 gui_util.de_errorize(widget)
30 def wrap_update_state(*args):
31 try:
32 if attribute:
33 update_state(widget, state, attribute)
34 else:
35 update_state(widget, state)
36 gui_util.de_errorize(widget)
37 except Exception as e:
38 logger.warning('Caught exception: %s' % e)
39 gui_util.errorize(widget)
41 return wrap_update_widget, wrap_update_state
43 wrap_update_widget, wrap_update_state = make_wrappers(widget)
45 for sig in signals:
46 sig.connect(wrap_update_state)
48 for path in paths:
49 owner.talkie_connect(state, path, wrap_update_widget)
51 wrap_update_widget()
54def state_bind_slider(
55 owner, state, path, widget, factor=1.,
56 dtype=float,
57 min_is_none=False,
58 max_is_none=False):
60 viewer = gui_util.get_app().get_main_window()
61 widget.sliderPressed.connect(viewer.disable_capture)
62 widget.sliderReleased.connect(viewer.enable_capture)
64 def make_funcs():
65 def update_state(widget, state):
66 val = widget.value()
67 if (min_is_none and val == widget.minimum()) \
68 or (max_is_none and val == widget.maximum()):
69 state.set(path, None)
70 else:
71 viewer.status('%g' % (val * factor))
72 state.set(path, dtype(val * factor))
74 def update_widget(state, widget):
75 val = state.get(path)
76 widget.blockSignals(True)
77 if min_is_none and val is None:
78 widget.setValue(widget.minimum())
79 elif max_is_none and val is None:
80 widget.setValue(widget.maximum())
81 else:
82 widget.setValue(int(state.get(path) * 1. / factor))
83 widget.blockSignals(False)
85 return update_state, update_widget
87 update_state, update_widget = make_funcs()
89 state_bind(
90 owner, state, [path], update_state, widget, [widget.valueChanged],
91 update_widget)
94def state_bind_slider_float(
95 owner, state, path, widget,
96 min_is_none=False,
97 max_is_none=False):
99 assert isinstance(widget, gui_util.QSliderFloat)
101 viewer = gui_util.get_app().get_main_window()
102 widget.sliderPressed.connect(viewer.disable_capture)
103 widget.sliderReleased.connect(viewer.enable_capture)
105 def make_funcs():
106 def update_state(widget, state):
107 val = widget.valueFloat()
108 if (min_is_none and val == widget.minimumFloat()) \
109 or (max_is_none and val == widget.maximumFloat()):
110 state.set(path, None)
111 else:
112 viewer.status('%g' % (val))
113 state.set(path, val)
115 def update_widget(state, widget):
116 val = state.get(path)
117 widget.blockSignals(True)
118 if min_is_none and val is None:
119 widget.setValueFloat(widget.minimumFloat())
120 elif max_is_none and val is None:
121 widget.setValueFloat(widget.maximumFloat())
122 else:
123 widget.setValueFloat(state.get(path))
124 widget.blockSignals(False)
126 return update_state, update_widget
128 update_state, update_widget = make_funcs()
130 state_bind(
131 owner, state, [path], update_state, widget, [widget.valueChanged],
132 update_widget)
135def state_bind_spinbox(owner, state, path, widget, factor=1., dtype=float):
136 return state_bind_slider(owner, state, path, widget, factor, dtype)
139def state_bind_combobox(owner, state, path, widget):
141 def make_funcs():
142 def update_state(widget, state):
143 state.set(path, str(widget.currentText()))
145 def update_widget(state, widget):
146 widget.blockSignals(True)
147 val = state.get(path)
148 for i in range(widget.count()):
149 if str(widget.itemText(i)) == val:
150 widget.setCurrentIndex(i)
151 widget.blockSignals(False)
153 return update_state, update_widget
155 update_state, update_widget = make_funcs()
157 state_bind(
158 owner, state, [path], update_state, widget, [widget.activated],
159 update_widget)
162def state_bind_combobox_color(owner, state, path, widget):
164 def make_funcs():
165 def update_state(widget, state):
166 value = str(widget.currentText())
167 state.set(path, Color(value))
169 def update_widget(state, widget):
170 widget.blockSignals(True)
171 val = str(state.get(path))
172 for i in range(widget.count()):
173 if str(widget.itemText(i)) == val:
174 widget.setCurrentIndex(i)
175 widget.blockSignals(False)
177 return update_state, update_widget
179 update_state, update_widget = make_funcs()
181 state_bind(
182 owner, state, [path], update_state, widget, [widget.activated],
183 update_widget)
186def state_bind_checkbox(owner, state, path, widget):
188 def make_funcs():
189 def update_state(widget, state):
190 state.set(path, bool(widget.isChecked()))
192 def update_widget(state, widget):
193 widget.blockSignals(True)
194 widget.setChecked(state.get(path))
195 widget.blockSignals(False)
197 return update_state, update_widget
199 update_state, update_widget = make_funcs()
201 state_bind(
202 owner, state, [path], update_state, widget, [widget.toggled],
203 update_widget)
206def state_bind_lineedit(
207 owner, state, path, widget, from_string=str, to_string=str):
209 def make_funcs():
211 def update_state(widget, state):
212 state.set(path, from_string(widget.text()))
214 def update_widget(state, widget):
215 widget.blockSignals(True)
216 widget.setText(to_string(state.get(path)))
217 widget.blockSignals(False)
219 return update_state, update_widget
221 update_state, update_widget = make_funcs()
223 state_bind(
224 owner,
225 state, [path], update_state,
226 widget, [widget.editingFinished, widget.returnPressed], update_widget)