[gnome-boxes] collection-view: Move thumbnailing to own class



commit d78869d8623b399e70e235e12f56a1167a28e086
Author: Adrien Plazas <kekun plazas laposte net>
Date:   Wed Jul 1 10:15:42 2015 +0200

    collection-view: Move thumbnailing to own class
    
    Move the responsability of rendering a machine's thumbnail out of
    CollectionView and to the new MachineThumbnailer class.
    
    This is needed to make CollectionView simpler, especially as the
    thumbnail drawing code is expected to get more complex in next commits.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=730258

 src/Makefile.am              |    1 +
 src/collection-view.vala     |   79 ++-------------------------
 src/machine-thumbnailer.vala |  121 ++++++++++++++++++++++++++++++++++++++++++
 src/machine.vala             |    4 ++
 4 files changed, 131 insertions(+), 74 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 6e66c84..e22575f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -118,6 +118,7 @@ gnome_boxes_SOURCES =                               \
        libvirt-machine.vala                    \
        libvirt-machine-properties.vala         \
        machine.vala                            \
+       machine-thumbnailer.vala                \
        main.vala                               \
        media-manager.vala                      \
        resource-graph.vala                     \
diff --git a/src/collection-view.vala b/src/collection-view.vala
index ac64cfa..1a5380e 100644
--- a/src/collection-view.vala
+++ b/src/collection-view.vala
@@ -84,81 +84,12 @@ private class Boxes.CollectionView: Gd.MainView, Boxes.UI {
         store.get (iter, ModelColumns.ITEM, out item);
         Machine machine = item as Machine;
         return_if_fail (machine != null);
-        var pixbuf = is_stopped (machine) ? paint_stopped_machine_thumbnail () : machine.pixbuf;
-
-        if ("favorite" in machine.config.categories)
-            pixbuf = add_emblem_icon (pixbuf, "starred-symbolic", Gtk.CornerType.BOTTOM_LEFT);
+        var pixbuf = machine.thumbnailer.thumbnail;
 
         store.set (iter, ModelColumns.SCREENSHOT, pixbuf);
         queue_draw ();
     }
 
-    private bool is_stopped (Machine machine) {
-        return machine.state == Machine.MachineState.FORCE_STOPPED || machine.state == 
Machine.MachineState.STOPPED;
-    }
-
-    private Gdk.Pixbuf paint_stopped_machine_thumbnail () {
-        // FIXME The frame is currently drawn lacking its right border because of this bug in libgd:
-        // https://bugzilla.gnome.org/show_bug.cgi?id=751494
-        var frame = paint_empty_frame (Machine.SCREENSHOT_WIDTH, Machine.SCREENSHOT_HEIGHT, FRAME_RADIUS,
-                                       FRAME_BORDER_COLOR, FRAME_BACKGROUND_COLOR);
-        return add_centered_emblem_icon (frame, "system-shutdown-symbolic", BIG_EMBLEM_SIZE);
-    }
-
-    private Gdk.Pixbuf add_centered_emblem_icon (Gdk.Pixbuf pixbuf, string icon_name, int size) {
-        Gdk.Pixbuf? emblem = null;
-
-        var theme = Gtk.IconTheme.get_default ();
-        try {
-            var icon_info = theme.lookup_icon (icon_name, size, Gtk.IconLookupFlags.FORCE_SIZE);
-            emblem = icon_info.load_symbolic (CENTERED_EMBLEM_COLOR);
-        } catch (GLib.Error error) {
-            warning (@"Unable to get icon '$icon_name': $(error.message)");
-            return pixbuf;
-        }
-
-        if (emblem == null)
-            return pixbuf;
-
-        double offset_x = pixbuf.width / 2.0 - emblem.width / 2.0;
-        double offset_y = pixbuf.height / 2.0 - emblem.height / 2.0;
-
-        var emblemed = pixbuf.copy ();
-        emblem.composite (emblemed, (int) offset_x, (int) offset_y, size, size,
-                          offset_x, offset_y, 1.0, 1.0, Gdk.InterpType.BILINEAR, 255);
-
-        return emblemed;
-    }
-
-
-    private Gdk.Pixbuf add_emblem_icon (Gdk.Pixbuf pixbuf, string icon_name, Gtk.CornerType corner_type) {
-        Gdk.Pixbuf? emblem = null;
-
-        var theme = Gtk.IconTheme.get_default ();
-        try {
-            var icon_info = theme.lookup_icon (icon_name, SMALL_EMBLEM_SIZE, Gtk.IconLookupFlags.FORCE_SIZE);
-            emblem = icon_info.load_symbolic (SMALL_EMBLEM_COLOR);
-        } catch (GLib.Error error) {
-            warning (@"Unable to get icon '$icon_name': $(error.message)");
-            return pixbuf;
-        }
-
-        if (emblem == null)
-            return pixbuf;
-
-        var offset_x = corner_type in right_corners ? pixbuf.width - emblem.width - EMBLEM_PADDING :
-                                                      EMBLEM_PADDING;
-
-        var offset_y = corner_type in bottom_corners ? pixbuf.height - emblem.height - EMBLEM_PADDING :
-                                                       EMBLEM_PADDING;
-
-        var emblemed = pixbuf.copy ();
-        emblem.composite (emblemed, offset_x, offset_y, SMALL_EMBLEM_SIZE, SMALL_EMBLEM_SIZE,
-                          offset_x, offset_y, 1.0, 1.0, Gdk.InterpType.BILINEAR, 255);
-
-        return emblemed;
-    }
-
     private Gtk.TreeIter append (string title,
                                  string? info,
                                  CollectionItem item) {
@@ -208,11 +139,11 @@ private class Boxes.CollectionView: Gd.MainView, Boxes.UI {
         }
 
         var iter = append (machine.name, machine.info,  item);
-        var pixbuf_id = machine.notify["pixbuf"].connect (() => {
+        var thumbnail_id = machine.thumbnailer.notify["thumbnail"].connect (() => {
             // apparently iter is stable after insertion/removal/sort
             update_screenshot (iter);
         });
-        item.set_data<ulong> ("pixbuf_id", pixbuf_id);
+        item.set_data<ulong> ("thumbnail_id", thumbnail_id);
 
         var categories_id = machine.config.notify["categories"].connect (() => {
             // apparently iter is stable after insertion/removal/sort
@@ -282,8 +213,8 @@ private class Boxes.CollectionView: Gd.MainView, Boxes.UI {
         store.remove (iter);
         item.set_data<Gtk.TreeIter?> ("iter", null);
 
-        var pixbuf_id = item.get_data<ulong> ("pixbuf_id");
-        item.disconnect (pixbuf_id);
+        var thumbnail_id = item.get_data<ulong> ("thumbnail_id");
+        item.disconnect (thumbnail_id);
         var name_id = item.get_data<ulong> ("name_id");
         item.disconnect (name_id);
         var info_id = item.get_data<ulong> ("info_id");
diff --git a/src/machine-thumbnailer.vala b/src/machine-thumbnailer.vala
new file mode 100644
index 0000000..8eec3ce
--- /dev/null
+++ b/src/machine-thumbnailer.vala
@@ -0,0 +1,121 @@
+// This file is part of GNOME Boxes. License: LGPLv2+
+
+private class Boxes.MachineThumbnailer: Object {
+    private const Gtk.CornerType[] right_corners = { Gtk.CornerType.TOP_RIGHT, Gtk.CornerType.BOTTOM_RIGHT };
+    private const Gtk.CornerType[] bottom_corners = { Gtk.CornerType.BOTTOM_LEFT, 
Gtk.CornerType.BOTTOM_RIGHT };
+
+    public const Gdk.RGBA FRAME_BORDER_COLOR = { 0x3b / 255.0, 0x3c / 255.0, 0x38 / 255.0, 1.0 };
+    public const Gdk.RGBA FRAME_BACKGROUND_COLOR = { 0x2d / 255.0, 0x2d / 255.0, 0x2d / 255.0, 1.0 };
+    public const double FRAME_RADIUS = 2.0;
+
+    public const Gdk.RGBA CENTERED_EMBLEM_COLOR = { 0xbe / 255.0, 0xbe / 255.0, 0xbe / 255.0, 1.0 };
+    public const Gdk.RGBA SMALL_EMBLEM_COLOR = { 1.0, 1.0, 1.0, 1.0 };
+    public const int BIG_EMBLEM_SIZE = 32;
+    public const int SMALL_EMBLEM_SIZE = 16;
+    public const int EMBLEM_PADDING = 8;
+
+    public weak Machine machine { get; construct; }
+
+    public Gdk.Pixbuf thumbnail { get; private set; }
+
+    public MachineThumbnailer (Machine machine) {
+        Object (machine: machine);
+    }
+
+    construct {
+        machine.notify["pixbuf"].connect (() => {
+            update_thumbnail ();
+        });
+
+        machine.config.notify["categories"].connect (() => {
+            update_thumbnail ();
+        });
+
+        update_thumbnail ();
+    }
+
+    private void update_thumbnail () {
+        var new_thumbnail = machine.is_stopped ? get_stopped_thumbnail () : machine.pixbuf;
+
+        if ("favorite" in machine.config.categories)
+            new_thumbnail = add_emblem_icon (new_thumbnail, "starred-symbolic", Gtk.CornerType.BOTTOM_LEFT);
+
+        thumbnail = new_thumbnail;
+    }
+
+    private static Gdk.Pixbuf? empty_thumbnail;
+    private static Gdk.Pixbuf get_empty_thumbnail () {
+        if (empty_thumbnail != null)
+            return empty_thumbnail;
+
+        empty_thumbnail = paint_empty_frame (Machine.SCREENSHOT_WIDTH, Machine.SCREENSHOT_HEIGHT, 
FRAME_RADIUS,
+                                             FRAME_BORDER_COLOR, FRAME_BACKGROUND_COLOR);
+
+        return empty_thumbnail;
+    }
+
+    private static Gdk.Pixbuf? stopped_thumbnail;
+    private static Gdk.Pixbuf get_stopped_thumbnail () {
+        if (stopped_thumbnail != null)
+            return stopped_thumbnail;
+
+        var frame = get_empty_thumbnail ();
+        stopped_thumbnail = add_centered_emblem_icon (frame, "system-shutdown-symbolic", BIG_EMBLEM_SIZE);
+
+        return stopped_thumbnail;
+    }
+
+    private static Gdk.Pixbuf add_centered_emblem_icon (Gdk.Pixbuf pixbuf, string icon_name, int size) {
+        Gdk.Pixbuf? emblem = null;
+
+        var theme = Gtk.IconTheme.get_default ();
+        try {
+            var icon_info = theme.lookup_icon (icon_name, size, Gtk.IconLookupFlags.FORCE_SIZE);
+            emblem = icon_info.load_symbolic (CENTERED_EMBLEM_COLOR);
+        } catch (GLib.Error error) {
+            warning (@"Unable to get icon '$icon_name': $(error.message)");
+            return pixbuf;
+        }
+
+        if (emblem == null)
+            return pixbuf;
+
+        double offset_x = pixbuf.width / 2.0 - emblem.width / 2.0;
+        double offset_y = pixbuf.height / 2.0 - emblem.height / 2.0;
+
+        var emblemed = pixbuf.copy ();
+        emblem.composite (emblemed, (int) offset_x, (int) offset_y, size, size,
+                          offset_x, offset_y, 1.0, 1.0, Gdk.InterpType.BILINEAR, 255);
+
+        return emblemed;
+    }
+
+
+    private static Gdk.Pixbuf add_emblem_icon (Gdk.Pixbuf pixbuf, string icon_name, Gtk.CornerType 
corner_type) {
+        Gdk.Pixbuf? emblem = null;
+
+        var theme = Gtk.IconTheme.get_default ();
+        try {
+            var icon_info = theme.lookup_icon (icon_name, SMALL_EMBLEM_SIZE, Gtk.IconLookupFlags.FORCE_SIZE);
+            emblem = icon_info.load_symbolic (SMALL_EMBLEM_COLOR);
+        } catch (GLib.Error error) {
+            warning (@"Unable to get icon '$icon_name': $(error.message)");
+            return pixbuf;
+        }
+
+        if (emblem == null)
+            return pixbuf;
+
+        var offset_x = corner_type in right_corners ? pixbuf.width - emblem.width - EMBLEM_PADDING :
+                                                      EMBLEM_PADDING;
+
+        var offset_y = corner_type in bottom_corners ? pixbuf.height - emblem.height - EMBLEM_PADDING :
+                                                       EMBLEM_PADDING;
+
+        var emblemed = pixbuf.copy ();
+        emblem.composite (emblemed, offset_x, offset_y, SMALL_EMBLEM_SIZE, SMALL_EMBLEM_SIZE,
+                          offset_x, offset_y, 1.0, 1.0, Gdk.InterpType.BILINEAR, 255);
+
+        return emblemed;
+    }
+}
diff --git a/src/machine.vala b/src/machine.vala
index c323cc3..39aced0 100644
--- a/src/machine.vala
+++ b/src/machine.vala
@@ -8,6 +8,7 @@ private abstract class Boxes.Machine: Boxes.CollectionItem, Boxes.IPropertiesPro
     public Boxes.CollectionSource source;
     public Boxes.BoxConfig config;
     public Gdk.Pixbuf? pixbuf { get; set; }
+    public MachineThumbnailer thumbnailer { get; private set; }
     public bool stay_on_display;
     public string? info { get; protected set; }
     public string status { get; set; }
@@ -248,6 +249,9 @@ private abstract class Boxes.Machine: Boxes.CollectionItem, Boxes.IPropertiesPro
         });
 
         create_display_config (uuid);
+
+        // This needs to be set after the 'config' prop has been set.
+        thumbnailer = new MachineThumbnailer (this);
     }
 
     protected void load_screenshot () {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]