aboutsummaryrefslogtreecommitdiff
path: root/voctogui/lib/ui.py
blob: 4106967b24d638a37a8846f4e96597e9c6a4607b (plain)
  1. #!/usr/bin/python3
  2. import gi, logging
  3. from gi.repository import Gtk, Gst, Gdk, GLib
  4. from lib.config import Config
  5. from lib.uibuilder import UiBuilder
  6. from lib.videodisplay import VideoDisplay
  7. class Ui(UiBuilder):
  8. def __init__(self, uifile):
  9. self.log = logging.getLogger('Ui')
  10. super().__init__(uifile)
  11. def setup(self):
  12. self.log.info('Initializing Ui')
  13. # Aquire the Main-Window from the UI-File
  14. self.win = self.get_check_widget('window')
  15. # Connect Close-Handler
  16. self.win.connect('delete-event', Gtk.main_quit)
  17. self.previews = {}
  18. self.preview_players = {}
  19. self.configure_toolbar_accelerators()
  20. self.configure_video_main()
  21. self.configure_video_previews()
  22. self.configure_audio_selector()
  23. self.configure_streamblank_selector()
  24. def configure_toolbar_accelerators(self):
  25. accelerators = Gtk.AccelGroup()
  26. self.win.add_accel_group(accelerators)
  27. composites = [
  28. 'composite-fullscreen',
  29. 'composite-picture-in-picture',
  30. 'composite-side-by-side-equal',
  31. 'composite-side-by-side-preview'
  32. ]
  33. for idx, name in enumerate(composites):
  34. key, mod = Gtk.accelerator_parse('F%u' % (idx+1))
  35. btn = self.find_widget_recursive(self.win, name)
  36. btn.set_name(name)
  37. # Thanks to http://stackoverflow.com/a/19739855/1659732
  38. btn.get_child().add_accelerator('clicked', accelerators, key, mod, Gtk.AccelFlags.VISIBLE)
  39. btn.connect('toggled', self.composite_btn_toggled)
  40. def composite_btn_toggled(self, btn):
  41. if not btn.get_active():
  42. return
  43. self.log.info("composite_btn_toggled: %s", btn.get_name())
  44. def configure_video_main(self):
  45. self.log.info('Initializing Main Video and Main Audio-Level View')
  46. video = self.find_widget_recursive(self.win, 'video_main')
  47. audiolevel = self.find_widget_recursive(self.win, 'audiolevel_main')
  48. self.video_main_player = VideoDisplay(11000, video, audiolevel,
  49. playaudio=Config.getboolean('mainvideo', 'playaudio'),
  50. allowoverlay=True)
  51. def configure_video_previews(self):
  52. self.log.info('Initializing Video Previews')
  53. sources = ['cam1', 'cam2', 'grabber']
  54. box = self.find_widget_recursive(self.win, 'box_left')
  55. try:
  56. width = Config.getint('previews', 'width')
  57. self.log.debug('Preview-Width configured to %u', width)
  58. except:
  59. width = 320
  60. self.log.debug('Preview-Width selected as %u', width)
  61. try:
  62. height = Config.getint('previews', 'height')
  63. self.log.debug('Preview-Height configured to %u', width)
  64. except:
  65. height = width*9/16
  66. self.log.debug('Preview-Height calculated to %u', width)
  67. # Accelerators
  68. accelerators = Gtk.AccelGroup()
  69. self.win.add_accel_group(accelerators)
  70. group_a = None
  71. group_b = None
  72. for idx, source in enumerate(sources):
  73. self.log.info('Initializing Video Preview %s', source)
  74. preview = self.get_check_widget('widget_preview', clone=True)
  75. video = self.find_widget_recursive(preview, 'video')
  76. video.set_size_request(width, height)
  77. box.pack_start(preview, fill=False, expand=False, padding=0)
  78. player = VideoDisplay(13000 + idx, video)
  79. self.find_widget_recursive(preview, 'label').set_label(source)
  80. btn_a = self.find_widget_recursive(preview, 'btn_a')
  81. btn_b = self.find_widget_recursive(preview, 'btn_b')
  82. btn_a.set_name("%c %u" % ('a', idx))
  83. btn_b.set_name("%c %u" % ('b', idx))
  84. if not group_a:
  85. group_a = btn_a
  86. else:
  87. btn_a.join_group(group_a)
  88. if not group_b:
  89. group_b = btn_b
  90. else:
  91. btn_b.join_group(group_b)
  92. btn_a.connect('toggled', self.preview_btn_toggled)
  93. btn_b.connect('toggled', self.preview_btn_toggled)
  94. key, mod = Gtk.accelerator_parse('%u' % (idx+1))
  95. btn_a.add_accelerator('activate', accelerators, key, mod, Gtk.AccelFlags.VISIBLE)
  96. key, mod = Gtk.accelerator_parse('<Ctrl>%u' % (idx+1))
  97. btn_b.add_accelerator('activate', accelerators, key, mod, Gtk.AccelFlags.VISIBLE)
  98. self.preview_players[source] = player
  99. self.previews[source] = preview
  100. def preview_btn_toggled(self, btn):
  101. if not btn.get_active():
  102. return
  103. self.log.info('preview_btn_toggled: %s', btn.get_name())
  104. def configure_audio_selector(self):
  105. self.log.info('Initializing Audio Selector')
  106. combo = self.find_widget_recursive(self.win, 'combo_audio')
  107. combo.set_sensitive(True)
  108. # FIXME access via combo_audio?
  109. liststore = self.get_check_widget('liststore_audio')
  110. liststore.clear()
  111. row = liststore.append()
  112. liststore.set(row, [0], ['foobar'])
  113. row = liststore.append('')
  114. liststore.set(row, [0], ['moofar'])
  115. combo.set_active_id('moofar')
  116. def configure_streamblank_selector(self):
  117. livebtn = self.get_check_widget('stream_live')
  118. blankbtn = self.get_check_widget('stream_blank')
  119. toolbar = blankbtn.get_parent()
  120. pos = toolbar.get_item_index(blankbtn)
  121. self.blink_btn = None
  122. self.blink_btn_state = False
  123. livebtn.connect('toggled', self.streamblank_button_toggled)
  124. livebtn.set_name('live')
  125. GLib.timeout_add_seconds(1, self.blink_streamblank_button)
  126. for idx, name in enumerate(['pause', 'nostream']):
  127. if idx == 0:
  128. new_btn = blankbtn
  129. else:
  130. new_icon = Gtk.Image.new_from_pixbuf(blankbtn.get_icon_widget().get_pixbuf())
  131. new_btn = Gtk.RadioToolButton(group=livebtn)
  132. new_btn.set_icon_widget(new_icon)
  133. toolbar.insert(new_btn, pos+1)
  134. new_btn.set_label("Stream %s" % name)
  135. new_btn.connect('toggled', self.streamblank_button_toggled)
  136. new_btn.set_name(name)
  137. def blink_streamblank_button(self):
  138. self.blink_btn_state = not self.blink_btn_state
  139. return True
  140. def streamblank_button_toggled(self, btn):
  141. if not btn.get_active():
  142. return
  143. if btn.get_name() != 'live':
  144. self.blink_btn = btn
  145. self.blink_btn_state = False
  146. self.streamblank_mode = btn.get_name()
  147. self.video_main_player.set_overlay_callback(self.draw_streamblank_warning)
  148. else:
  149. self.blink_btn = None
  150. self.video_main_player.set_overlay_callback(None)
  151. def draw_streamblank_warning(self, cairooverlay, cr, timestamp, duration):
  152. h = 1080/20
  153. w = 1920
  154. if self.blink_btn_state:
  155. cr.set_source_rgba(1.0, 0.0, 0.0, 0.8)
  156. else:
  157. cr.set_source_rgba(1.0, 0.5, 0.0, 0.8)
  158. cr.rectangle(0, 0, w, h)
  159. cr.fill()
  160. text = "Stream is Blanked: {}".format(self.streamblank_mode)
  161. cr.set_font_size(h*0.75)
  162. xbearing, ybearing, txtwidth, txtheight, xadvance, yadvance = cr.text_extents(text)
  163. cr.move_to(w/2 - txtwidth/2, h*0.75)
  164. cr.set_source_rgba(1.0, 1.0, 1.0, 1.0)
  165. cr.show_text(text)
  166. def show(self):
  167. self.log.info('Running Video-Playback Pipelines')
  168. self.video_main_player.run()
  169. for name, player in self.preview_players.items():
  170. player.run()
  171. self.log.info('Showing Main-Window')
  172. self.win.show_all()