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

1# https://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

4# ---|P------/S----------~Lg---------- 

5 

6''' 

72-way state binding utilities for Qt/talkie. 

8''' 

9 

10import logging 

11 

12from pyrocko.gui import util as gui_util 

13from pyrocko.color import Color 

14 

15logger = logging.getLogger('pyrocko.gui.state') 

16 

17 

18def state_bind( 

19 owner, state, paths, update_state, 

20 widget, signals, update_widget, attribute=None): 

21 

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) 

29 

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) 

40 

41 return wrap_update_widget, wrap_update_state 

42 

43 wrap_update_widget, wrap_update_state = make_wrappers(widget) 

44 

45 for sig in signals: 

46 sig.connect(wrap_update_state) 

47 

48 for path in paths: 

49 owner.talkie_connect(state, path, wrap_update_widget) 

50 

51 wrap_update_widget() 

52 

53 

54def state_bind_slider( 

55 owner, state, path, widget, factor=1., 

56 dtype=float, 

57 min_is_none=False, 

58 max_is_none=False): 

59 

60 viewer = gui_util.get_app().get_main_window() 

61 widget.sliderPressed.connect(viewer.disable_capture) 

62 widget.sliderReleased.connect(viewer.enable_capture) 

63 

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

73 

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) 

84 

85 return update_state, update_widget 

86 

87 update_state, update_widget = make_funcs() 

88 

89 state_bind( 

90 owner, state, [path], update_state, widget, [widget.valueChanged], 

91 update_widget) 

92 

93 

94def state_bind_slider_float( 

95 owner, state, path, widget, 

96 min_is_none=False, 

97 max_is_none=False): 

98 

99 assert isinstance(widget, gui_util.QSliderFloat) 

100 

101 viewer = gui_util.get_app().get_main_window() 

102 widget.sliderPressed.connect(viewer.disable_capture) 

103 widget.sliderReleased.connect(viewer.enable_capture) 

104 

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) 

114 

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) 

125 

126 return update_state, update_widget 

127 

128 update_state, update_widget = make_funcs() 

129 

130 state_bind( 

131 owner, state, [path], update_state, widget, [widget.valueChanged], 

132 update_widget) 

133 

134 

135def state_bind_spinbox(owner, state, path, widget, factor=1., dtype=float): 

136 return state_bind_slider(owner, state, path, widget, factor, dtype) 

137 

138 

139def state_bind_combobox(owner, state, path, widget): 

140 

141 def make_funcs(): 

142 def update_state(widget, state): 

143 state.set(path, str(widget.currentText())) 

144 

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) 

152 

153 return update_state, update_widget 

154 

155 update_state, update_widget = make_funcs() 

156 

157 state_bind( 

158 owner, state, [path], update_state, widget, [widget.activated], 

159 update_widget) 

160 

161 

162def state_bind_combobox_color(owner, state, path, widget): 

163 

164 def make_funcs(): 

165 def update_state(widget, state): 

166 value = str(widget.currentText()) 

167 state.set(path, Color(value)) 

168 

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) 

176 

177 return update_state, update_widget 

178 

179 update_state, update_widget = make_funcs() 

180 

181 state_bind( 

182 owner, state, [path], update_state, widget, [widget.activated], 

183 update_widget) 

184 

185 

186def state_bind_checkbox(owner, state, path, widget): 

187 

188 def make_funcs(): 

189 def update_state(widget, state): 

190 state.set(path, bool(widget.isChecked())) 

191 

192 def update_widget(state, widget): 

193 widget.blockSignals(True) 

194 widget.setChecked(state.get(path)) 

195 widget.blockSignals(False) 

196 

197 return update_state, update_widget 

198 

199 update_state, update_widget = make_funcs() 

200 

201 state_bind( 

202 owner, state, [path], update_state, widget, [widget.toggled], 

203 update_widget) 

204 

205 

206def state_bind_lineedit( 

207 owner, state, path, widget, from_string=str, to_string=str): 

208 

209 def make_funcs(): 

210 

211 def update_state(widget, state): 

212 state.set(path, from_string(widget.text())) 

213 

214 def update_widget(state, widget): 

215 widget.blockSignals(True) 

216 widget.setText(to_string(state.get(path))) 

217 widget.blockSignals(False) 

218 

219 return update_state, update_widget 

220 

221 update_state, update_widget = make_funcs() 

222 

223 state_bind( 

224 owner, 

225 state, [path], update_state, 

226 widget, [widget.editingFinished, widget.returnPressed], update_widget)