1# https://pyrocko.org - GPLv3 

2# 

3# The Pyrocko Developers, 21st Century 

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

5 

6from __future__ import absolute_import, print_function, division 

7 

8import vtk 

9 

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

11from pyrocko.gui.qt_compat import qw, qc 

12from pyrocko import util 

13 

14 

15from .base import Element, ElementState 

16from .. import common 

17 

18guts_prefix = 'sparrow' 

19 

20 

21class HudPositionChoice(StringChoice): 

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

23 'top', 'top-left', 'top-right'] 

24 

25 

26class HudState(ElementState): 

27 visible = Bool.T(default=True) 

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

29 template = String.T() 

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

31 lightness = Float.T(default=1.0) 

32 fontsize = Float.T(default=0.05) 

33 

34 def create(self): 

35 element = HudElement() 

36 return element 

37 

38 

39def none_or(f): 

40 def g(x): 

41 if x is None: 

42 return '' 

43 else: 

44 return f(x) 

45 

46 return g 

47 

48 

49class Stringer(object): 

50 def __init__(self, d): 

51 self._d = d 

52 self._formatters = { 

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

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

55 

56 def __getitem__(self, key): 

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

58 if len(key) == 2: 

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

60 else: 

61 key, formatter = key[0], str 

62 

63 if key in self._d: 

64 return formatter(self._d[key]) 

65 else: 

66 return '{' + key + '}' 

67 

68 

69class HudElement(Element): 

70 

71 def __init__(self): 

72 Element.__init__(self) 

73 self._controls = None 

74 self._actor = None 

75 self._listeners2 = [] 

76 

77 def get_name(self): 

78 return 'HUD' 

79 

80 def bind_state(self, state): 

81 Element.bind_state(self, state) 

82 

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

84 'position']: 

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

86 

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

88 

89 def unbind_state(self): 

90 self._listeners.clear() 

91 self._listeners2.clear() 

92 self._state = None 

93 

94 def set_parent(self, parent): 

95 self._parent = parent 

96 self._parent.add_panel( 

97 self.get_name(), 

98 self._get_controls(), 

99 visible=True, 

100 title_controls=[ 

101 self.get_title_control_remove(), 

102 self.get_title_control_visible()]) 

103 

104 self.register_state_listener3( 

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

106 

107 self.update_bindings() 

108 self.update() 

109 

110 def unset_parent(self): 

111 self.unbind_state() 

112 if self._parent: 

113 if self._actor is not None: 

114 self._parent.remove_actor_2d(self._actor) 

115 

116 if self._controls is not None: 

117 self._parent.remove_panel(self._controls) 

118 self._controls = None 

119 

120 self._parent.update_view() 

121 self._parent = None 

122 

123 def update_bindings(self, *args): 

124 while self._listeners2: 

125 listener_ref = self._listeners2.pop() 

126 listener_ref.release() 

127 

128 for variable in self._state.variables: 

129 self._listeners2.append( 

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

131 

132 def update(self, *args): 

133 state = self._state 

134 if not self._state: 

135 return 

136 pstate = self._parent.state 

137 

138 if self._actor is None: 

139 self._actor = vtk.vtkTextActor() 

140 

141 actor = self._actor 

142 

143 vs = [ 

144 get_elements(pstate, variable)[0] 

145 for variable in self._state.variables] 

146 

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

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

149 

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

151 cx = 0.5 * sx 

152 # cy = 0.5 * sy 

153 off = 0.1 * sy 

154 pos = { 

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

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

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

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

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

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

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

162 

163 actor.SetPosition(x, y) 

164 # actor.SetPosition2(200, 100) 

165 prop = actor.GetTextProperty() 

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

167 

168 lightness = state.lightness 

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

170 prop.SetJustification(hj) 

171 prop.SetVerticalJustification(vj) 

172 

173 if state.visible: 

174 self._parent.add_actor_2d(actor) 

175 else: 

176 self._parent.remove_actor_2d(actor) 

177 

178 self._parent.update_view() 

179 

180 def _get_controls(self): 

181 if not self._controls: 

182 from ..state import state_bind_lineedit, \ 

183 state_bind_combobox, state_bind_slider 

184 

185 frame = qw.QFrame() 

186 layout = qw.QGridLayout() 

187 frame.setLayout(layout) 

188 

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

190 le = qw.QLineEdit() 

191 layout.addWidget(le, 0, 1) 

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

193 

194 cb = common.string_choices_to_combobox(HudPositionChoice) 

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

196 layout.addWidget(cb, 1, 1) 

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

198 

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

200 

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

202 slider.setSizePolicy( 

203 qw.QSizePolicy( 

204 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

205 slider.setMinimum(0) 

206 slider.setMaximum(1000) 

207 layout.addWidget(slider, 2, 1) 

208 

209 state_bind_slider( 

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

211 

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

213 

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

215 slider.setSizePolicy( 

216 qw.QSizePolicy( 

217 qw.QSizePolicy.Expanding, qw.QSizePolicy.Fixed)) 

218 slider.setMinimum(0) 

219 slider.setMaximum(1000) 

220 layout.addWidget(slider, 3, 1) 

221 

222 state_bind_slider( 

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

224 

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

226 

227 self._controls = frame 

228 

229 return self._controls 

230 

231 

232__all__ = [ 

233 'HudElement', 

234 'HudState']