[gnome-games/wip/exalm/hidpi: 5/7] savestate-listbox-row: Draw thumbnails manually



commit aecb6ad5681d4e95e21339d077ef264da32d8b7e
Author: Alexander Mikhaylenko <exalm7659 gmail com>
Date:   Sat Aug 17 00:11:10 2019 +0500

    savestate-listbox-row: Draw thumbnails manually
    
    This allows to handle border-radius nicely and will be used in the next
    commit to draw larger images on hidpi.

 data/ui/savestate-listbox-row.ui  |  3 +-
 src/ui/savestate-listbox-row.vala | 69 +++++++++++++++++++++++++++++++++++----
 2 files changed, 65 insertions(+), 7 deletions(-)
---
diff --git a/data/ui/savestate-listbox-row.ui b/data/ui/savestate-listbox-row.ui
index 306dc617..77cf7d30 100644
--- a/data/ui/savestate-listbox-row.ui
+++ b/data/ui/savestate-listbox-row.ui
@@ -15,12 +15,13 @@
             <property name="visible">true</property>
             <property name="margin">2</property>
             <child>
-              <object class="GtkImage" id="image">
+              <object class="GtkDrawingArea" id="image">
                 <property name="visible">true</property>
                 <property name="valign">start</property>
                 <property name="width-request">66</property>
                 <property name="height-request">66</property>
                 <property name="margin">6</property>
+                <signal name="draw" handler="on_draw_image"/>
                 <style>
                   <class name="savestate-thumbnail"/>
                 </style>
diff --git a/src/ui/savestate-listbox-row.vala b/src/ui/savestate-listbox-row.vala
index ac65be9f..16fc057c 100644
--- a/src/ui/savestate-listbox-row.vala
+++ b/src/ui/savestate-listbox-row.vala
@@ -5,7 +5,7 @@ private class Games.SavestateListBoxRow : Gtk.ListBoxRow {
        public const int THUMBNAIL_SIZE = 64;
 
        [GtkChild]
-       private Gtk.Image image;
+       private Gtk.DrawingArea image;
        [GtkChild]
        private Gtk.Label name_label;
        [GtkChild]
@@ -59,11 +59,10 @@ private class Games.SavestateListBoxRow : Gtk.ListBoxRow {
                        }
 
                        try {
-                               var thumbnail = new Gdk.Pixbuf.from_file_at_scale (screenshot_path,
-                                                                                  thumbnail_width,
-                                                                                  thumbnail_height,
-                                                                                  false);
-                               image.set_from_pixbuf (thumbnail);
+                               pixbuf = new Gdk.Pixbuf.from_file_at_scale (screenshot_path,
+                                                                           thumbnail_width,
+                                                                           thumbnail_height,
+                                                                           false);
                        }
                        catch (Error e) {
                                warning ("Failed to load savestate thumbnail: %s", e.message);
@@ -71,6 +70,8 @@ private class Games.SavestateListBoxRow : Gtk.ListBoxRow {
                }
        }
 
+       private Gdk.Pixbuf pixbuf;
+
        public SavestateListBoxRow (Savestate savestate) {
                Object (savestate: savestate);
        }
@@ -91,5 +92,61 @@ private class Games.SavestateListBoxRow : Gtk.ListBoxRow {
                });
                revealer.reveal_child = false;
        }
+
+       [GtkCallback]
+       private bool on_draw_image (Cairo.Context cr) {
+               var width = image.get_allocated_width ();
+               var height = image.get_allocated_height ();
+
+               var style = image.get_style_context ();
+               style.render_background (cr, 0.0, 0.0, width, height);
+               style.render_frame (cr, 0.0, 0.0, width, height);
+
+               var mask = get_mask ();
+
+               var surface = Gdk.cairo_surface_create_from_pixbuf (pixbuf, 1, image.get_window ());
+               var x_offset = (width - pixbuf.width) / 2;
+               var y_offset = (height - pixbuf.height) / 2;
+
+               cr.set_source_surface (surface, x_offset, y_offset);
+               cr.mask_surface (mask, 0, 0);
+
+               return Gdk.EVENT_PROPAGATE;
+       }
+
+       // TODO: Share this with GameThumbnail
+       private Cairo.Surface get_mask () {
+               var width = image.get_allocated_width ();
+               var height = image.get_allocated_height ();
+
+               var mask = new Cairo.ImageSurface (Cairo.Format.A8, width, height);
+
+               var style = image.get_style_context ();
+               var flags = image.get_state_flags ();
+               var border_radius = (int) style.get_property (Gtk.STYLE_PROPERTY_BORDER_RADIUS, flags);
+               border_radius = border_radius.clamp (0, int.max (width / 2, height / 2));
+
+               var cr = new Cairo.Context (mask);
+               cr.set_source_rgb (0, 0, 0);
+               rounded_rectangle (cr, 0.5, 0.5, width - 1, height - 1, border_radius);
+               cr.fill ();
+
+               return mask;
+       }
+
+       // TODO: Share this with GameThumbnail
+       private void rounded_rectangle (Cairo.Context cr, double x, double y, double width, double height, 
double radius) {
+               const double ARC_0 = 0;
+               const double ARC_1 = Math.PI * 0.5;
+               const double ARC_2 = Math.PI;
+               const double ARC_3 = Math.PI * 1.5;
+
+               cr.new_sub_path ();
+               cr.arc (x + width - radius, y + radius,          radius, ARC_3, ARC_0);
+               cr.arc (x + width - radius, y + height - radius, radius, ARC_0, ARC_1);
+               cr.arc (x + radius,         y + height - radius, radius, ARC_1, ARC_2);
+               cr.arc (x + radius,         y + radius,          radius, ARC_2, ARC_3);
+               cr.close_path ();
+       }
 }
 


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