blueman
blueman copied to clipboard
ManagerDeviceList: Custom cellrenderer with fading for signal bars
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
This is a nifty piece of code! I learned a lot just figuring out how it works. Thanks.