split py files
[android/external-libkmsxx.git] / py / kmsmodeview.py
1 #!/usr/bin/python3
3 import urwid
4 import pykms
6 def exit_on_q(key):
7         if key in ('q', 'Q'):
8                 raise urwid.ExitMainLoop()
9         elif key == 'a':
10                 apply_mode()
12 alarm_handle = None
14 def recalc_info(l, d):
15         global alarm_handle
17         alarm_handle = None
19         for w in recalc_list:
20                 w.recalc()
22 def div_or_zero(n, d):
23         if d == 0:
24                 return 0
25         else:
26                 return n / d
28 class MyIntEdit(urwid.IntEdit):
29         _metaclass_ = urwid.signals.MetaSignals
30         signals = ['value_change']
32         def __init__(self, caption, calc=None):
33                 self._myval = 0
34                 self._disable_change = False
35                 self._calc = calc
36                 self._updlist = None
38                 super().__init__(caption, 0)
40         def set_edit_text(self, text):
41                 global alarm_handle
43                 super().set_edit_text(text)
44                 newtext = super().get_edit_text()
45                 new_val = int(newtext) if newtext != "" else 0
46                 if new_val != self._myval:
47                         self._myval = new_val
48                         if not self._disable_change:
49                                 urwid.emit_signal(self, 'value_change', self, self._myval)
51                                 if alarm_handle == None:
52                                         alarm_handle = loop.set_alarm_in(0, recalc_info)
54                                 if self._updlist != None:
55                                         for w in self._updlist:
56                                                 w.recalc()
58         def recalc(self):
59                 self._disable_change = True
60                 self.set_val(self._calc())
61                 self._disable_change = False
63         def set_val(self, val):
64                 self.set_edit_text(str(int(val)))
66         def get_val(self):
67                 return self._myval
69         def set_updlist(self, list):
70                 self._updlist = list
72         def keypress(self, size, key):
73                 if key == '+':
74                         self.set_edit_text(str(self.value() + 1))
75                 elif key == '-':
76                         self.set_edit_text(str(self.value() - 1))
77                 else:
78                         return super().keypress(size, key)
80 class MyIntText(urwid.Text):
81         def __init__(self, fmt, calc=None):
82                 super().__init__("")
83                 self._fmt = fmt
84                 self._calc = calc
86         def recalc(self):
87                 val = self._calc()
88                 super().set_text(self._fmt.format(val))
90 def khz_to_ps(khz):
91         if khz == 0:
92                 return 0
93         else:
94                 return 1.0 / khz * 1000 * 1000 * 1000
96 def khz_to_us(khz):
97         if khz == 0:
98                 return 0
99         else:
100                 return 1.0 / khz * 1000
102 pclk_khz_widget = MyIntEdit(u"pclk (kHz) ")
103 pclk_ps_widget = MyIntText(fmt="pclk {:.2f} ps", calc = lambda: khz_to_ps(pclk_khz_widget.get_val()))
105 pclk_widgets = [pclk_khz_widget, pclk_ps_widget]
107 pclk_columns = urwid.LineBox(urwid.Columns(pclk_widgets), title = "Pixel clock")
109 # Horizontal widgets
111 hdisp_widget = MyIntEdit(u"hdisp ", calc = lambda: hdisp2_widget.get_val())
112 hfp_widget = MyIntEdit(u"hfp   ", calc = lambda: hss_widget.get_val() - hdisp_widget.get_val())
113 hsw_widget = MyIntEdit(u"hsw   ", calc = lambda: hse_widget.get_val() - hss_widget.get_val())
114 hbp_widget = MyIntEdit(u"hbp   ", calc = lambda: htot_widget.get_val() - hse_widget.get_val())
116 hdisp2_widget = MyIntEdit(u"hdisp ", calc = lambda: hdisp_widget.get_val())
117 hss_widget = MyIntEdit(u"hss   ",
118         calc = lambda: hdisp_widget.get_val() + hfp_widget.get_val())
119 hse_widget = MyIntEdit(u"hse   ",
120         calc = lambda: hdisp_widget.get_val() + hfp_widget.get_val() + hsw_widget.get_val())
121 htot_widget = MyIntEdit(u"htot  ",
122         calc = lambda: hdisp_widget.get_val() + hfp_widget.get_val() + hsw_widget.get_val() + hbp_widget.get_val())
124 hwidgets1 = [hdisp_widget, hfp_widget, hsw_widget, hbp_widget]
125 hwidgets2 = [hdisp2_widget, hss_widget, hse_widget, htot_widget]
127 horiz_pile1 = urwid.Pile(hwidgets1)
128 horiz_pile2 = urwid.Pile(hwidgets2)
130 h_columns = urwid.LineBox(urwid.Columns([(15, horiz_pile1), (15, horiz_pile2)]), title = "Horizontal")
132 # Vertical columns
134 vdisp_widget = MyIntEdit(u"vdisp ", calc = lambda: vdisp2_widget.get_val())
135 vfp_widget = MyIntEdit(u"vfp   ", calc = lambda: vss_widget.get_val() - vdisp_widget.get_val())
136 vsw_widget = MyIntEdit(u"vsw   ", calc = lambda: vse_widget.get_val() - vss_widget.get_val())
137 vbp_widget = MyIntEdit(u"vbp   ", calc = lambda: vtot_widget.get_val() - vse_widget.get_val())
139 vdisp2_widget = MyIntEdit(u"vdisp ", calc = lambda: vdisp_widget.get_val())
140 vss_widget = MyIntEdit(u"vss   ",
141         calc = lambda: vdisp_widget.get_val() + vfp_widget.get_val())
142 vse_widget = MyIntEdit(u"vse   ",
143         calc = lambda: vdisp_widget.get_val() + vfp_widget.get_val() + vsw_widget.get_val())
144 vtot_widget = MyIntEdit(u"vtot  ",
145         calc = lambda: vdisp_widget.get_val() + vfp_widget.get_val() + vsw_widget.get_val() + vbp_widget.get_val())
147 vwidgets1 = [vdisp_widget, vfp_widget, vsw_widget, vbp_widget]
148 vwidgets2 = [vdisp2_widget, vss_widget, vse_widget, vtot_widget]
150 vert_pile1 = urwid.Pile(vwidgets1)
151 vert_pile2 = urwid.Pile(vwidgets2)
153 v_columns = urwid.LineBox(urwid.Columns([(15, vert_pile1), (15, vert_pile2)]), title = "Vertical")
155 # Info widgets
157 line_us_widget = MyIntText(fmt="line {:.2f} us",
158         calc = lambda: khz_to_us(pclk_khz_widget.get_val()) * htot_widget.get_val())
159 line_khz_widget = MyIntText(fmt="line {:.2f} kHz",
160         calc = lambda: div_or_zero(pclk_khz_widget.get_val(), htot_widget.get_val()))
162 frame_tot_widget = MyIntText(fmt="tot {} pix",
163         calc = lambda: htot_widget.get_val() * vtot_widget.get_val())
164 frame_us_widget = MyIntText(fmt="frame {:.2f} ms",
165         calc = lambda: khz_to_us(pclk_khz_widget.get_val()) * htot_widget.get_val() * vtot_widget.get_val() / 1000)
166 frame_khz_widget = MyIntText(fmt="frame {:.2f} Hz",
167         calc = lambda: div_or_zero(pclk_khz_widget.get_val() * 1000,  htot_widget.get_val() * vtot_widget.get_val()))
169 info_box = urwid.LineBox(urwid.Pile([line_us_widget, line_khz_widget, urwid.Divider(), frame_tot_widget, frame_us_widget, frame_khz_widget]), title = "Info")
171 # Set update lists
173 recalc_list = [ pclk_ps_widget, line_us_widget, line_khz_widget, frame_tot_widget, frame_us_widget, frame_khz_widget ]
175 hdisp_widget.set_updlist([hdisp2_widget, hss_widget, hse_widget, htot_widget])
176 hfp_widget.set_updlist([hss_widget, hse_widget, htot_widget])
177 hsw_widget.set_updlist([hse_widget, htot_widget])
178 hbp_widget.set_updlist([htot_widget])
179 hdisp2_widget.set_updlist([hdisp_widget, hfp_widget])
180 hss_widget.set_updlist([hfp_widget, hsw_widget])
181 hse_widget.set_updlist([hsw_widget, hbp_widget])
182 htot_widget.set_updlist([hbp_widget])
184 vdisp_widget.set_updlist([vdisp2_widget, vss_widget, vse_widget, vtot_widget])
185 vfp_widget.set_updlist([vss_widget, vse_widget, vtot_widget])
186 vsw_widget.set_updlist([vse_widget, vtot_widget])
187 vbp_widget.set_updlist([vtot_widget])
188 vdisp2_widget.set_updlist([vdisp_widget, vfp_widget])
189 vss_widget.set_updlist([vfp_widget, vsw_widget])
190 vse_widget.set_updlist([vsw_widget, vbp_widget])
191 vtot_widget.set_updlist([vbp_widget])
193 # Flags
195 fb = None
197 DRM_MODE_FLAG_PHSYNC = (1<<0)
198 DRM_MODE_FLAG_NHSYNC = (1<<1)
199 DRM_MODE_FLAG_PVSYNC = (1<<2)
200 DRM_MODE_FLAG_NVSYNC = (1<<3)
201 DRM_MODE_FLAG_INTERLACE = (1<<4)
202 DRM_MODE_FLAG_DBLCLK = (1<<12)
204 def mode_is_ilace(mode):
205         return (mode.flags & DRM_MODE_FLAG_INTERLACE) != 0
207 def apply_mode():
208         global fb
210         mode = pykms.Videomode()
211         mode.clock = pclk_khz_widget.get_val()
213         mode.hdisplay = hdisp2_widget.get_val()
214         mode.hsync_start = hss_widget.get_val()
215         mode.hsync_end = hse_widget.get_val()
216         mode.htotal = htot_widget.get_val()
218         mode.vdisplay = vdisp2_widget.get_val()
219         mode.vsync_start = vss_widget.get_val()
220         mode.vsync_end = vse_widget.get_val()
221         mode.vtotal = vtot_widget.get_val()
223         if ilace_box.state:
224                 mode.flags |= DRM_MODE_FLAG_INTERLACE
226         if dblclk_box.state:
227                 mode.flags |= DRM_MODE_FLAG_DBLCLK
229         if hsync_pol.state == True:
230                 mode.flags |= DRM_MODE_FLAG_PHSYNC
231         elif hsync_pol.state == False:
232                 mode.flags |= DRM_MODE_FLAG_NHSYNC
234         if vsync_pol.state == True:
235                 mode.flags |= DRM_MODE_FLAG_PVSYNC
236         elif vsync_pol.state == False:
237                 mode.flags |= DRM_MODE_FLAG_NVSYNC
239         fb = pykms.DumbFramebuffer(card, mode.hdisplay, mode.vdisplay, "XR24");
240         pykms.draw_test_pattern(fb);
242         crtc.set_mode(conn, fb, mode)
244 def read_mode(mode):
245         pclk_khz_widget.set_val(mode.clock)
246         hdisp2_widget.set_val(mode.hdisplay)
247         hss_widget.set_val(mode.hsync_start)
248         hse_widget.set_val(mode.hsync_end)
249         htot_widget.set_val(mode.htotal)
251         vdisp2_widget.set_val(mode.vdisplay)
252         vss_widget.set_val(mode.vsync_start)
253         vse_widget.set_val(mode.vsync_end)
254         vtot_widget.set_val(mode.vtotal)
256         ilace_box.set_state(mode_is_ilace(mode))
257         dblclk_box.set_state((mode.flags & DRM_MODE_FLAG_DBLCLK) != 0)
259         sync = 'mixed'
260         if (mode.flags & DRM_MODE_FLAG_PHSYNC) != 0:
261                 sync = True
262         elif (mode.flags & DRM_MODE_FLAG_NHSYNC) != 0:
263                 sync = False
264         hsync_pol.set_state(sync)
266         sync = 'mixed'
267         if (mode.flags & DRM_MODE_FLAG_PVSYNC) != 0:
268                 sync = True
269         elif (mode.flags & DRM_MODE_FLAG_NVSYNC) != 0:
270                 sync = False
271         vsync_pol.set_state(sync)
273 def apply_press(w):
274         apply_mode()
276 ilace_box = urwid.CheckBox('interlace')
277 hsync_pol = urwid.CheckBox('hsync positive', has_mixed=True)
278 vsync_pol = urwid.CheckBox('vsync positive', has_mixed=True)
279 dblclk_box = urwid.CheckBox('double clock')
281 flags_pile = urwid.LineBox(urwid.Pile([ilace_box, hsync_pol, vsync_pol, dblclk_box]), title = "Flags")
283 apply_button = urwid.LineBox(urwid.Padding(urwid.Button('apply', on_press=apply_press)))
285 # Main
287 def mode_press(w, mode):
288         read_mode(mode)
290 def mode_to_str(mode):
291         return "{}@{}{}".format(mode.name, mode.vrefresh, "i" if mode_is_ilace(mode) else "")
293 mode_buttons = []
295 card = pykms.Card()
296 conn = card.get_first_connected_connector()
297 crtc = conn.get_current_crtc()
298 modes = conn.get_modes()
299 i = 0
300 for m in modes:
301         mode_buttons.append(urwid.Button(mode_to_str(m), on_press=mode_press, user_data=m))
302         i += 1
304 modes_pile = urwid.LineBox(urwid.Pile(mode_buttons), title = "Video modes")
306 main_pile = urwid.Pile([modes_pile, pclk_columns, urwid.Columns([ h_columns, v_columns ]), info_box, flags_pile, apply_button])
308 main_columns = urwid.Filler(main_pile, valign='top')
310 loop = urwid.MainLoop(main_columns, unhandled_input=exit_on_q, handle_mouse=False)
312 # select the first mode
313 mode_press(None, modes[0])
315 loop.run()
317 fb = None