def cw_btn_clicked(self, *args): def cleanup(arg): del self.cw self.cw = None if not self.cw: home = expanduser("~") self.cw = CoverWindow(self.source.plugin, self.cw_btn.get_toplevel(), home) self.cw.connect('close-window', cleanup) self.cw.show_all(' ', self.pixbuf)
class ResultsGrid(Gtk.Grid): # signals __gsignals__ = { 'update-cover': (GObject.SIGNAL_RUN_LAST, None, (GObject.Object, RB.RhythmDBEntry)), 'whats-playing': (GObject.SIGNAL_RUN_LAST, None, (bool, )) } image_width = 0 def __init__(self, *args, **kwargs): super(ResultsGrid, self).__init__(*args, **kwargs) def initialise(self, entry_view_grid, source): self.pixbuf = None self.entry_view_grid = entry_view_grid self.source = source self.oldval = 0 self.stack = Gtk.Stack() self.stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE) self.stack.set_transition_duration(350) self.image1 = Gtk.Image() self.image1.props.hexpand = True self.image1.props.vexpand = True self.stack.add_named(self.image1, "image1") self.image2 = Gtk.Image() self.image2.props.hexpand = True self.image2.props.vexpand = True self.stack.add_named(self.image2, "image2") self.frame = Gtk.Frame.new() # "", 0.5, 0.5, 1, False) try: # correct from Gtk 3.12 onwards self.frame.set_margin_end(5) except: self.frame.set_margin_right(5) self.update_cover(None, None, None) self.scroll = Gtk.ScrolledWindow() self.scroll.add(self.stack) self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.scroll.set_resize_mode(Gtk.ResizeMode.QUEUE) self.frame.add(self.scroll) self._signal_connected = None ''' when we hover over the coverart then a zoom icon is overlayed with the coverart when we move the mouse pointer from the coverart then the zoom icon is hidden this is achieved by a GtkOverlay - the stack doesnt normally have a mouse over event so we need to understand when a mouse pointer enters or leaves the stack. Also a peculiarity is that moving the pointer over the overlay zoom icon causes enter and leave events ... so we need to monitor the mouse over for the icon as well ''' self.overlay = Gtk.Overlay() self.overlay.add(self.frame) image = Gtk.Image.new_from_icon_name(Gtk.STOCK_ZOOM_FIT, Gtk.IconSize.SMALL_TOOLBAR) self.cw_btn = Gtk.Button(label=None, image=image) self.cw_btn.set_valign(Gtk.Align.END) self.cw_btn.set_halign(Gtk.Align.CENTER) self.cw_btn_state = False self.hover = False self.overlay.add_overlay(self.cw_btn) self.attach(self.overlay, 6, 0, 1, 1) self.stack.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK) self.stack.add_events(Gdk.EventMask.LEAVE_NOTIFY_MASK) self.stack.add_events(Gdk.EventMask.POINTER_MOTION_MASK) self.cw_btn.add_events(Gdk.EventMask.POINTER_MOTION_MASK) self.stack.connect('enter-notify-event', self.stack_notify_event) self.stack.connect('leave-notify-event', self.stack_notify_event) self.stack.connect('motion-notify-event', self.motion_notify_event) self.cw_btn.connect('clicked', self.cw_btn_clicked) self.cw_btn.connect('motion-notify-event', self.motion_notify_event) self.cw_btn.connect('show', self.cw_btn_show_event) self.cw = None self.hover_time_out = None self.connect('update-cover', self.update_cover) self.connect('whats-playing', self.display_whats_playing) # lets fix the situation where some-themes background colour is incorrectly defined # in these cases the background colour is black context = self.get_style_context() bg_colour = context.get_background_color(Gtk.StateFlags.NORMAL) if bg_colour == Gdk.RGBA(0, 0, 0, 0): color = context.get_color(Gtk.StateFlags.NORMAL) self.override_background_color(Gtk.StateType.NORMAL, color) ''' when a show, show_all is used lets make sure we set the icon visibility correctly ''' def cw_btn_show_event(self, *args): self.cw_btn.set_visible(self.hover) ''' when mousing over the stack/icon we need to remember that we are hovering ... so the visibility is set correctly - in the stack notify event ''' def motion_notify_event(self, *args): self.hover = True def cw_btn_clicked(self, *args): def cleanup(arg): del self.cw self.cw = None if not self.cw: home = expanduser("~") self.cw = CoverWindow(self.source.plugin, self.cw_btn.get_toplevel(), home) self.cw.connect('close-window', cleanup) self.cw.show_all(' ', self.pixbuf) ''' when entering and leaving the stack (also the icon) then we assume the icon is to be invisible Use a short delay to allow the motion events to kick in - if we are still in the stack/icon then the hover visibility will be changed ''' def stack_notify_event(self, widget, event_crossing): if self.hover_time_out: GLib.source_remove(self.hover_time_out) self.hover_time_out = None def set_hover(): if self.pixbuf: self.cw_btn.set_visible(self.hover) else: self.cw_btn.set_visible(False) self.hover_time_out = None return False self.hover = False self.hover_time_out = GLib.timeout_add(350, set_hover) return False def update_cover(self, widget, source, entry): print('update_cover') self.oldval = 0 # force a redraw if entry: print('entry') album = source.album_manager.model.get_from_dbentry(entry) self.pixbuf = GdkPixbuf.Pixbuf().new_from_file( album.cover.original) self.window_resize(None) self.frame.set_shadow_type(Gtk.ShadowType.NONE) else: print('no pixbuf') self.pixbuf = None self.frame.set_shadow_type(Gtk.ShadowType.ETCHED_OUT) if self.stack.get_visible_child_name() == "image1": self.image1.queue_draw() else: self.image2.queue_draw() def display_whats_playing(self, show_playing): view = self.get_child_at(0, 0) view.display_playing_tracks(show_playing) def window_resize(self, widget): alloc = self.get_allocation() if alloc.height < 10: return entry_grid_alloc = self.entry_view_grid.get_allocation() if (alloc.width / 4) <= (MIN_IMAGE_SIZE + 30) or \ (entry_grid_alloc.height) <= (MIN_IMAGE_SIZE + 30): self.overlay.set_visible(False) return else: self.overlay.set_visible(True) vbar = self.scroll.get_vscrollbar() if vbar: vbar.set_visible(False) hbar = self.scroll.get_hscrollbar() if hbar: hbar.set_visible(False) minval = min((alloc.width / 4), (alloc.height)) if self.oldval == minval: return self.oldval = minval if minval < MIN_IMAGE_SIZE: minval = MIN_IMAGE_SIZE if self.pixbuf: p = self.pixbuf.scale_simple(minval - 15, minval - 15, GdkPixbuf.InterpType.BILINEAR) else: p = None if self.stack.get_visible_child_name() == "image1": self.image2.set_from_pixbuf(p) self.stack.set_visible_child_name("image2") else: self.image1.set_from_pixbuf(p) self.stack.set_visible_child_name("image1") def change_view(self, entry_view, show_coverart): print("debug - change_view") widget = self.get_child_at(0, 0) if widget: self.remove(widget) if not show_coverart: widget = self.get_child_at(6, 0) if widget: self.remove(widget) entry_view.props.hexpand = True entry_view.props.vexpand = True self.attach(entry_view, 0, 0, 3, 1) if show_coverart: self.attach(self.overlay, 6, 0, 1, 1) self.show_all() self.cw_btn.set_visible(self.hover)
class ResultsGrid(Gtk.Grid): # signals __gsignals__ = { 'update-cover': (GObject.SIGNAL_RUN_LAST, None, (GObject.Object, RB.RhythmDBEntry)), 'whats-playing': (GObject.SIGNAL_RUN_LAST, None, (bool,)) } image_width = 0 def __init__(self, *args, **kwargs): super(ResultsGrid, self).__init__(*args, **kwargs) def initialise(self, entry_view_grid, source): self.pixbuf = None self.entry_view_grid = entry_view_grid self.source = source self.oldval = 0 self.stack = Gtk.Stack() self.stack.set_transition_type(Gtk.StackTransitionType.CROSSFADE) self.stack.set_transition_duration(350) self.image1 = Gtk.Image() self.image1.props.hexpand = True self.image1.props.vexpand = True self.stack.add_named(self.image1, "image1") self.image2 = Gtk.Image() self.image2.props.hexpand = True self.image2.props.vexpand = True self.stack.add_named(self.image2, "image2") self.frame = Gtk.Frame.new() # "", 0.5, 0.5, 1, False) try: # correct from Gtk 3.12 onwards self.frame.set_margin_end(5) except: self.frame.set_margin_right(5) self.update_cover(None, None, None) self.scroll = Gtk.ScrolledWindow() self.scroll.add(self.stack) self.scroll.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.scroll.set_resize_mode(Gtk.ResizeMode.QUEUE) self.frame.add(self.scroll) self._signal_connected = None ''' when we hover over the coverart then a zoom icon is overlayed with the coverart when we move the mouse pointer from the coverart then the zoom icon is hidden this is achieved by a GtkOverlay - the stack doesnt normally have a mouse over event so we need to understand when a mouse pointer enters or leaves the stack. Also a peculiarity is that moving the pointer over the overlay zoom icon causes enter and leave events ... so we need to monitor the mouse over for the icon as well ''' self.overlay = Gtk.Overlay() self.overlay.add(self.frame) image = Gtk.Image.new_from_icon_name(Gtk.STOCK_ZOOM_FIT, Gtk.IconSize.SMALL_TOOLBAR) self.cw_btn = Gtk.Button(label=None, image=image) self.cw_btn.set_valign(Gtk.Align.END) self.cw_btn.set_halign(Gtk.Align.CENTER) self.cw_btn_state = False self.hover = False self.overlay.add_overlay(self.cw_btn) self.attach(self.overlay, 6, 0, 1, 1) self.stack.add_events(Gdk.EventMask.ENTER_NOTIFY_MASK) self.stack.add_events(Gdk.EventMask.LEAVE_NOTIFY_MASK) self.stack.add_events(Gdk.EventMask.POINTER_MOTION_MASK) self.cw_btn.add_events(Gdk.EventMask.POINTER_MOTION_MASK) self.stack.connect('enter-notify-event', self.stack_notify_event) self.stack.connect('leave-notify-event', self.stack_notify_event) self.stack.connect('motion-notify-event', self.motion_notify_event) self.cw_btn.connect('clicked', self.cw_btn_clicked) self.cw_btn.connect('motion-notify-event', self.motion_notify_event) self.cw_btn.connect('show', self.cw_btn_show_event) self.cw = None self.hover_time_out = None self.connect('update-cover', self.update_cover) self.connect('whats-playing', self.display_whats_playing) # lets fix the situation where some-themes background colour is incorrectly defined # in these cases the background colour is black context = self.get_style_context() bg_colour = context.get_background_color(Gtk.StateFlags.NORMAL) if bg_colour == Gdk.RGBA(0, 0, 0, 0): color = context.get_color(Gtk.StateFlags.NORMAL) self.override_background_color(Gtk.StateType.NORMAL, color) ''' when a show, show_all is used lets make sure we set the icon visibility correctly ''' def cw_btn_show_event(self, *args): self.cw_btn.set_visible(self.hover) ''' when mousing over the stack/icon we need to remember that we are hovering ... so the visibility is set correctly - in the stack notify event ''' def motion_notify_event(self, *args): self.hover = True def cw_btn_clicked(self, *args): def cleanup(arg): del self.cw self.cw = None if not self.cw: home = expanduser("~") self.cw = CoverWindow(self.source.plugin, self.cw_btn.get_toplevel(), home) self.cw.connect('close-window', cleanup) self.cw.show_all(' ', self.pixbuf) ''' when entering and leaving the stack (also the icon) then we assume the icon is to be invisible Use a short delay to allow the motion events to kick in - if we are still in the stack/icon then the hover visibility will be changed ''' def stack_notify_event(self, widget, event_crossing): if self.hover_time_out: GLib.source_remove(self.hover_time_out) self.hover_time_out = None def set_hover(): if self.pixbuf: self.cw_btn.set_visible(self.hover) else: self.cw_btn.set_visible(False) self.hover_time_out = None return False self.hover = False self.hover_time_out = GLib.timeout_add(350, set_hover) return False def update_cover(self, widget, source, entry): print('update_cover') self.oldval = 0 # force a redraw if entry: print('entry') album = source.album_manager.model.get_from_dbentry(entry) self.pixbuf = GdkPixbuf.Pixbuf().new_from_file(album.cover.original) self.window_resize(None) self.frame.set_shadow_type(Gtk.ShadowType.NONE) else: print('no pixbuf') self.pixbuf = None self.frame.set_shadow_type(Gtk.ShadowType.ETCHED_OUT) if self.stack.get_visible_child_name() == "image1": self.image1.queue_draw() else: self.image2.queue_draw() def display_whats_playing(self, show_playing): view = self.get_child_at(0, 0) view.display_playing_tracks(show_playing) def window_resize(self, widget): alloc = self.get_allocation() if alloc.height < 10: return entry_grid_alloc = self.entry_view_grid.get_allocation() if (alloc.width / 4) <= (MIN_IMAGE_SIZE + 30) or \ (entry_grid_alloc.height) <= (MIN_IMAGE_SIZE + 30): self.overlay.set_visible(False) return else: self.overlay.set_visible(True) vbar = self.scroll.get_vscrollbar() if vbar: vbar.set_visible(False) hbar = self.scroll.get_hscrollbar() if hbar: hbar.set_visible(False) minval = min((alloc.width / 4), (alloc.height)) if self.oldval == minval: return self.oldval = minval if minval < MIN_IMAGE_SIZE: minval = MIN_IMAGE_SIZE if self.pixbuf: p = self.pixbuf.scale_simple(minval - 15, minval - 15, GdkPixbuf.InterpType.BILINEAR) else: p = None if self.stack.get_visible_child_name() == "image1": self.image2.set_from_pixbuf(p) self.stack.set_visible_child_name("image2") else: self.image1.set_from_pixbuf(p) self.stack.set_visible_child_name("image1") def change_view(self, entry_view, show_coverart): print("debug - change_view") widget = self.get_child_at(0, 0) if widget: self.remove(widget) if not show_coverart: widget = self.get_child_at(6, 0) if widget: self.remove(widget) entry_view.props.hexpand = True entry_view.props.vexpand = True self.attach(entry_view, 0, 0, 3, 1) if show_coverart: self.attach(self.overlay, 6, 0, 1, 1) self.show_all() self.cw_btn.set_visible(self.hover)