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