# # # from gi.repository import Gtk from gi.repository import Gdk from gi.repository import GdkPixbuf from .. import constants as C _DEVICE_ICON_SIZE = 48 _STATUS_ICON_SIZE = 64 _PLACEHOLDER = '~' _images = None _MAX_DEVICES = 7 _ICONS = {} def _icon(icon, title, size=_DEVICE_ICON_SIZE, fallback=None): icon = icon or Gtk.Image() if title and title in _ICONS: icon.set_from_pixbuf(_ICONS[title]) else: icon_file = _images(title) if title else None if icon_file: pixbuf = GdkPixbuf.Pixbuf().new_from_file(icon_file) if pixbuf.get_width() > size or pixbuf.get_height() > size: if pixbuf.get_width() > pixbuf.get_height(): new_width = size new_height = size * pixbuf.get_height() / pixbuf.get_width() else: new_width = size * pixbuf.get_width() / pixbuf.get_height() new_height = size pixbuf = pixbuf.scale_simple(new_width, new_height, GdkPixbuf.InterpType.HYPER) icon.set_from_pixbuf(pixbuf) _ICONS[title] = pixbuf elif fallback: icon.set_from_icon_name(fallback, size if size < _DEVICE_ICON_SIZE else Gtk.IconSize.DIALOG) if size >= _DEVICE_ICON_SIZE: icon.set_size_request(size, size) return icon def update(window, ur_available, devices): if not window or not window.get_child(): return controls = list(window.get_child().get_children()) first = controls[0] first.set_visible(not ur_available or not devices) if ur_available: ur_status = C.FOUND_RECEIVER if devices else C.NO_DEVICES else: ur_status = C.NO_RECEIVER _, label = first.get_children() label.set_markup('%s\n%s' % (C.UNIFYING_RECEIVER, ur_status)) for index in range(1, _MAX_DEVICES): box = controls[index] devstatus = [d for d in devices if d.number == index] devstatus = devstatus[0] if devstatus else None box.set_visible(devstatus is not None) if devstatus: box.set_sensitive(devstatus.code >= 0) icon, expander = box.get_children() if not expander.get_data('devstatus'): expander.set_data('devstatus', devstatus,) _icon(icon, 'devices/' + devstatus.name, fallback=devstatus.type.lower()) label = expander.get_label_widget() if expander.get_expanded(): label.set_markup('%s' % devstatus.name) else: label.set_markup('%s\n%s' % (devstatus.name, devstatus.props['text'])) ebox = expander.get_child() # refresh_button = ebox.get_children()[0] # refresh_button.connect('activate', devstatus.refresh) texts = [] battery_icon = ebox.get_children()[-1] if 'battery-level' in devstatus.props: level = devstatus.props['battery-level'] icon_name = 'battery/' + str((level + 10) // 20) _icon(battery_icon, icon_name, _STATUS_ICON_SIZE) texts.append('Battery: ' + str(level) + '%') else: _icon(battery_icon, 'battery/unknown', _STATUS_ICON_SIZE) texts.append('Battery: unknown') battery_icon.set_tooltip_text(texts[-1]) light_icon = ebox.get_children()[-2] if 'light-level' in devstatus.props: lux = devstatus.props['light-level'] icon_name = 'light/' + str((lux + 50) // 100) _icon(light_icon, icon_name, _STATUS_ICON_SIZE) texts.append('Light: ' + str(lux) + ' lux') light_icon.set_tooltip_text(texts[-1]) light_icon.set_visible(True) else: light_icon.set_visible(False) label = ebox.get_children()[-3] label.set_text('\n'.join(texts)) def _expander_activate(expander): devstatus = expander.get_data('devstatus') if devstatus: label = expander.get_label_widget() if expander.get_expanded(): label.set_markup('%s\n%s' % (devstatus.name, devstatus.props['text'])) else: label.set_markup('%s' % devstatus.name) def _device_box(title): icon = _icon(None, 'devices/' + title) icon.set_alignment(0.5, 0) label = Gtk.Label() label.set_markup('%s' % title) label.set_alignment(0, 0.5) label.set_can_focus(False) box = Gtk.HBox(spacing=10) box.pack_start(icon, False, False, 0) if title == C.UNIFYING_RECEIVER: box.add(label) else: expander = Gtk.Expander() expander.set_can_focus(False) expander.set_label_widget(label) expander.connect('activate', _expander_activate) ebox = Gtk.HBox(False, 10) ebox.set_border_width(4) # refresh_button = Gtk.Button() # refresh_button.set_image(_icon(None, None, size=Gtk.IconSize.SMALL_TOOLBAR, fallback='reload')) # refresh_button.set_focus_on_click(False) # refresh_button.set_can_focus(False) # refresh_button.set_image_position(Gtk.PositionType.TOP) # refresh_button.set_alignment(0.5, 0.5) # refresh_button.set_relief(Gtk.ReliefStyle.NONE) # refresh_button.set_size_request(20, 20) # refresh_button.set_tooltip_text('Refresh') # ebox.pack_start(refresh_button, False, False, 2) label = Gtk.Label() label.set_alignment(0, 0.5) ebox.pack_start(label, False, True, 8) light_icon = _icon(None, 'light/unknown', _STATUS_ICON_SIZE) ebox.pack_end(light_icon, False, True, 0) battery_icon = _icon(None, 'battery/unknown', _STATUS_ICON_SIZE) ebox.pack_end(battery_icon, False, True, 0) expander.add(ebox) box.pack_start(expander, True, True, 1) box.show_all() box.set_visible(title != _PLACEHOLDER) return box def create(title, images=None): global _images _images = images or (lambda x: None) vbox = Gtk.VBox(spacing=8) vbox.set_border_width(6) vbox.add(_device_box(C.UNIFYING_RECEIVER)) for i in range(1, _MAX_DEVICES): vbox.add(_device_box(_PLACEHOLDER)) vbox.set_visible(True) window = Gtk.Window() # Gtk.WindowType.POPUP) window.set_title(title) window.set_icon_from_file(_images('icon')) window.set_keep_above(True) window.set_decorated(False) window.set_skip_taskbar_hint(True) window.set_skip_pager_hint(True) window.set_deletable(False) window.set_resizable(False) window.set_position(Gtk.WindowPosition.MOUSE) window.set_type_hint(Gdk.WindowTypeHint.TOOLTIP) window.connect('focus-out-event', _hide) window.add(vbox) return window def _hide(window, _): window.set_visible(False) def toggle(_, window): if window.get_visible(): window.set_visible(False) else: window.present()