1# https://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6import vtk 

7 

8from pyrocko.guts import Bool, List, String, StringChoice, Float, get_elements 

9from pyrocko.gui.qt_compat import qw, qc 

10from pyrocko import util 

11 

12 

13from .base import Element, ElementState 

14from .. import common 

15 

16guts_prefix = 'sparrow' 

17 

18 

19class HudPositionChoice(StringChoice): 

20 choices = ['bottom', 'bottom-left', 'bottom-right', 

21 'top', 'top-left', 'top-right'] 

22 

23 

24class HudState(ElementState): 

25 visible = Bool.T(default=True) 

26 variables = List.T(String.T(optional=True)) 

27 template = String.T() 

28 position = HudPositionChoice.T(default='bottom') 

29 lightness = Float.T(default=1.0) 

30 fontsize = Float.T(default=0.05) 

31 

32 def create(self): 

33 element = HudElement() 

34 return element 

35 

36 

37def none_or(f): 

38 def g(x): 

39 if x is None: 

40 return '' 

41 else: 

42 return f(x) 

43 

44 return g 

45 

46 

47class Stringer(object): 

48 def __init__(self, d): 

49 self._d = d 

50 self._formatters = { 

51 'date': none_or(lambda v: util.time_to_str(v, format='%Y-%m-%d')), 

52 'datetime': none_or(lambda v: util.time_to_str(v))} 

53 

54 def __getitem__(self, key): 

55 key = key.split('|', 1) 

56 if len(key) == 2: 

57 key, formatter = key[0], self._formatters.get(key[1], str) 

58 else: 

59 key, formatter = key[0], str 

60 

61 if key in self._d: 

62 return formatter(self._d[key]) 

63 else: 

64 return '{' + key + '}' 

65 

66 

67class HudElement(Element): 

68 

69 def __init__(self): 

70 Element.__init__(self) 

71 self._controls = None 

72 self._actor = None 

73 self._listeners2 = [] 

74 

75 def get_name(self): 

76 return 'HUD' 

77 

78 def bind_state(self, state): 

79 Element.bind_state(self, state) 

80 

81 for var in ['visible', 'lightness', 'fontsize', 'template', 

82 'position']: 

83 self.register_state_listener3(self.update, state, var) 

84 

85 self.register_state_listener3(self.update_bindings, state, 'variables') 

86 

87 def unbind_state(self): 

88 self._listeners.clear() 

89 self._listeners2.clear() 

90 self._state = None 

91 

92 def set_parent(self, parent): 

93 self._parent = parent 

94 self._parent.add_panel( 

95 self.get_name(), 

96 self._get_controls(), 

97 visible=True, 

98 title_controls=[ 

99 self.get_title_control_remove(), 

100 self.get_title_control_visible()]) 

101 

102 self.register_state_listener3( 

103 self.update, self._parent.gui_state, 'size') 

104 

105 self.update_bindings() 

106 self.update() 

107 

108 def unset_parent(self): 

109 self.unbind_state() 

110 if self._parent: 

111 if self._actor is not None: 

112 self._parent.remove_actor_2d(self._actor) 

113 

114 if self._controls is not None: 

115 self._parent.remove_panel(self._controls) 

116 self._controls = None 

117 

118 self._parent.update_view() 

119 self._parent = None 

120 

121 def update_bindings(self, *args): 

122 while self._listeners2: 

123 listener_ref = self._listeners2.pop() 

124 listener_ref.release() 

125 

126 for variable in self._state.variables: 

127 self._listeners2.append( 

128 self._parent.state.add_listener(self.update, variable)) 

129 

130 def update(self, *args): 

131 state = self._state 

132 if not self._state: 

133 return 

134 pstate = self._parent.state 

135 

136 if self._actor is None: 

137 self._actor = vtk.vtkTextActor() 

138 

139 actor = self._actor 

140 

141 vs = [ 

142 get_elements(pstate, variable)[0] 

143 for variable in self._state.variables] 

144 

145 s = Stringer(d=dict((str(i), v) for (i, v) in enumerate(vs))) 

146 actor.SetInput(self._state.template.format_map(s)) 

147 

148 sx, sy = self._parent.gui_state.size 

149 cx = 0.5 * sx 

150 # cy = 0.5 * sy 

151 off = 0.1 * sy 

152 pos = { 

153 'top': (cx, sy - off, 1, 2), 

154 'top-left': (off, sy - off, 0, 2), 

155 'top-right': (sx - off, sy - off, 2, 2), 

156 'bottom': (cx, off, 1, 0), 

157 'bottom-left': (off, off, 0, 0), 

158 'bottom-right': (sx - off, off, 2, 0)} 

159 x, y, hj, vj = pos[state.position] 

160 

161 actor.SetPosition(x, y) 

162 # actor.SetPosition2(200, 100) 

163 prop = actor.GetTextProperty() 

164 prop.SetFontSize(int(round(state.fontsize*sy))) 

165 

166 lightness = state.lightness 

167 prop.SetColor(lightness*0.8, lightness*0.8, lightness*0.7) 

168 prop.SetJustification(hj) 

169 prop.SetVerticalJustification(vj) 

170 

171 if state.visible: 

172 self._parent.add_actor_2d(actor) 

173 else: 

174 self._parent.remove_actor_2d(actor) 

175 

176 self._parent.update_view() 

177 

178 def _get_controls(self): 

179 if not self._controls: 

180 from ..state import state_bind_lineedit, \ 

181 state_bind_combobox, state_bind_slider 

182 

183 frame = qw.QFrame() 

184 layout = qw.QGridLayout() 

185 frame.setLayout(layout) 

186 

187 layout.addWidget(qw.QLabel('Template'), 0, 0) 

188 le = qw.QLineEdit() 

189 layout.addWidget(le, 0, 1) 

190 state_bind_lineedit(self, self._state, 'template', le) 

191 

192 cb = common.string_choices_to_combobox(HudPositionChoice) 

193 layout.addWidget(qw.QLabel('Position'), 1, 0) 

194 layout.addWidget(cb, 1, 1) 

195 state_bind_combobox(self, self._state, 'position', cb) 

196 

197 layout.addWidget(qw.QLabel('Lightness'), 2, 0) 

198 

199 slider = qw.QSlider(qc.Qt.Horizontal) 

200 slider.setSizePolicy( 

201 qw.QSizePolicy( 

202 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

203 slider.setMinimum(0) 

204 slider.setMaximum(1000) 

205 layout.addWidget(slider, 2, 1) 

206 

207 state_bind_slider( 

208 self, self._state, 'lightness', slider, factor=0.001) 

209 

210 layout.addWidget(qw.QLabel('Fontsize'), 3, 0) 

211 

212 slider = qw.QSlider(qc.Qt.Horizontal) 

213 slider.setSizePolicy( 

214 qw.QSizePolicy( 

215 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

216 slider.setMinimum(0) 

217 slider.setMaximum(1000) 

218 layout.addWidget(slider, 3, 1) 

219 

220 state_bind_slider( 

221 self, self._state, 'fontsize', slider, factor=0.001) 

222 

223 layout.addWidget(qw.QFrame(), 4, 0) 

224 

225 self._controls = frame 

226 

227 return self._controls 

228 

229 

230__all__ = [ 

231 'HudElement', 

232 'HudState']