blueman icon indicating copy to clipboard operation
blueman copied to clipboard

ManagerDeviceList: Custom cellrenderer with fading for signal bars

Open infirit opened this issue 8 years ago • 1 comments

Documented my very hacky and nowhere near complete but properly fading custom CellRenderer. This to eventually replace the pixbuf cell renderer that currently has a broken(ish) fade

from gi.repository import Gtk, Gdk, GLib
from gi.repository import GdkPixbuf
import cairo

class CellRenderFade(Gtk.CellRendererPixbuf):
    def __init__(self):
        super(CellRenderFade, self).__init__()
        self._fading = False
        self._alpha = 0
        self._fps = 20
        self._step = 0

    def do_render(self, cr, widget, bg_area, cell_area, flags):
        path, column, cell_x, cell_y = widget.get_path_at_pos(cell_area.x, cell_area.y)
        model = widget.get_model()
        #itr = model.get_iter(path)
        row = model[path]
        self._fading = row[-1]
        fade_direction = row[-2]
        
        pix_rect = Gdk.Rectangle()
        x_off, y_off, width, height = self.get_size(widget, cell_area)
        x_pad, y_pad = self.get_padding()
        pix_rect.x = cell_area.x + x_off + x_pad
        pix_rect.y = cell_area.y + y_off + y_pad
        pix_rect.width = cell_area.width - 2 * x_pad
        pix_rect.height = cell_area.height - 2 * y_pad

        icon_theme = Gtk.IconTheme.new()
        pixbuf = icon_theme.load_icon(
            self.props.icon_name, Gtk.IconSize.BUTTON,
            Gtk.IconLookupFlags.NO_SVG)

        if self._fading and fade_direction == "in":
            self.start_fade(widget, path, 0.0, 1.0, 2000)
        elif self._fading and fade_direction == "out":
            self.start_fade(widget, path, 1.0, 0.0, 2000)

        Gdk.cairo_set_source_pixbuf(cr, pixbuf, pix_rect.x, pix_rect.y)
        cr.paint_with_alpha(self._alpha)

    def start_fade(self, widget, path, start, end, duration):
        print('Fade', self._alpha)
        self._step = (end - start) / (self._fps * (duration / 1000.0))
        
        GLib.timeout_add(int(1.0 / self._fps * 1000), self.queue_draw, widget, path)

    def queue_draw(self, widget, path):
        row = widget.get_model()[path]
        print(self._step)
        self._alpha += self._step
        widget.queue_draw()
        if self._alpha >= 1:
            self._alpha = 1
            row[-1] = False
            print("End", self._alpha)
            return False
        elif self._alpha <= 0:
            self._alpha = 0
            row[-1] = False
            print("End", self._alpha)
            return False
        
        
        
class CellRendererFadeWindow(Gtk.Window):

    def __init__(self):
        super(CellRendererFadeWindow, self).__init__(title="CellRendererFade Example")

        self.grid = Gtk.Grid()
        self.grid.props.column_homogeneous = True
        self.grid.props.row_homogeneous = True
        self.add(self.grid)
        
        self.set_default_size(400, 200)

        self.liststore = Gtk.ListStore(str, str, str, bool)
        self.liststore.append(["New", 'document-new', "in", True])
        self.liststore.append(["Open", 'document-open', "in", True])
        self.liststore.append(["Save", 'document-save', "in", True])

        treeview = Gtk.TreeView(model=self.liststore)

        renderer_text = Gtk.CellRendererText()
        column_text = Gtk.TreeViewColumn("Text", renderer_text, text=0)
        treeview.append_column(column_text)

        renderer_pixbuf = CellRenderFade()

        column_pixbuf = Gtk.TreeViewColumn("Image", renderer_pixbuf, icon_name=1)
        treeview.append_column(column_pixbuf)

        self.grid.attach(treeview, 0, 0, 1, 1)

        toggle_button = Gtk.Button.new_with_label("Toggle image")
        toggle_button.connect("clicked", self.on_toggle_clicked)

        self.grid.attach(toggle_button, 0, 1, 1, 1)

    def on_toggle_clicked(self, button):
        for row in self.liststore:
            row[-1] = not(row[-1])
            row[-2] = "out" if row[-2] != "out" else "in"

win = CellRendererFadeWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

edit: updated 2017-01-15

infirit avatar Aug 22 '16 17:08 infirit

This is a nifty piece of code! I learned a lot just figuring out how it works. Thanks.

FilipDominec avatar Aug 25 '16 12:08 FilipDominec