1 /*
2  * scaled-image.c
3  * Copyright 2012-2013 John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  *    this list of conditions, and the following disclaimer in the documentation
13  *    provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 #include <libaudgui/libaudgui-gtk.h>
21 
get_scaled(GtkWidget * widget,int maxwidth,int maxheight)22 static GdkPixbuf * get_scaled (GtkWidget * widget, int maxwidth, int maxheight)
23 {
24     GdkPixbuf * unscaled = (GdkPixbuf *) g_object_get_data ((GObject *) widget, "pixbuf-unscaled");
25 
26     if (! unscaled)
27         return nullptr;
28 
29     int width = gdk_pixbuf_get_width (unscaled);
30     int height = gdk_pixbuf_get_height (unscaled);
31 
32     if (width > maxwidth || height > maxheight)
33     {
34         if (width * maxheight > height * maxwidth)
35         {
36             height = aud::rescale (height, width, maxwidth);
37             width = maxwidth;
38         }
39         else
40         {
41             width = aud::rescale (width, height, maxheight);
42             height = maxheight;
43         }
44     }
45 
46     GdkPixbuf * scaled = (GdkPixbuf *) g_object_get_data ((GObject *) widget, "pixbuf-scaled");
47 
48     if (scaled)
49     {
50         if (gdk_pixbuf_get_width (scaled) == width && gdk_pixbuf_get_height (scaled) == height)
51             return scaled;
52     }
53 
54     scaled = gdk_pixbuf_scale_simple (unscaled, width, height, GDK_INTERP_BILINEAR);
55     g_object_set_data_full ((GObject *) widget, "pixbuf-scaled", scaled, g_object_unref);
56 
57     return scaled;
58 }
59 
expose_cb(GtkWidget * widget,GdkEventExpose * event)60 static int expose_cb (GtkWidget * widget, GdkEventExpose * event)
61 {
62     GdkRectangle rect;
63     gtk_widget_get_allocation (widget, & rect);
64 
65     GdkPixbuf * scaled = get_scaled (widget, rect.width, rect.height);
66 
67     if (scaled)
68     {
69         int x = (rect.width - gdk_pixbuf_get_width (scaled)) / 2;
70         int y = (rect.height - gdk_pixbuf_get_height (scaled)) / 2;
71 
72         cairo_t * cr = gdk_cairo_create (gtk_widget_get_window (widget));
73         gdk_cairo_set_source_pixbuf (cr, scaled, x, y);
74         cairo_paint (cr);
75         cairo_destroy (cr);
76     }
77 
78     return true;
79 }
80 
audgui_scaled_image_set(GtkWidget * widget,GdkPixbuf * pixbuf)81 EXPORT void audgui_scaled_image_set (GtkWidget * widget, GdkPixbuf * pixbuf)
82 {
83     if (pixbuf)
84         g_object_ref (pixbuf);
85 
86     g_object_set_data_full ((GObject *) widget, "pixbuf-unscaled", pixbuf, g_object_unref);
87     g_object_set_data_full ((GObject *) widget, "pixbuf-scaled", nullptr, g_object_unref);
88 
89     gtk_widget_queue_draw (widget);
90 }
91 
audgui_scaled_image_new(GdkPixbuf * pixbuf)92 EXPORT GtkWidget * audgui_scaled_image_new (GdkPixbuf * pixbuf)
93 {
94     GtkWidget * widget = gtk_drawing_area_new ();
95 
96     g_signal_connect (widget, "expose-event", (GCallback) expose_cb, nullptr);
97 
98     audgui_scaled_image_set (widget, pixbuf);
99 
100     return widget;
101 }
102