summaryrefslogtreecommitdiff
path: root/src/imageview.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/imageview.c')
-rw-r--r--src/imageview.c314
1 files changed, 314 insertions, 0 deletions
diff --git a/src/imageview.c b/src/imageview.c
new file mode 100644
index 0000000..19b1b13
--- /dev/null
+++ b/src/imageview.c
@@ -0,0 +1,314 @@
1/*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2013 Hiroyuki Yamamoto
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 */
19
20#ifdef HAVE_CONFIG_H
21# include "config.h"
22#endif
23
24#include <glib.h>
25#include <glib/gi18n.h>
26#include <gtk/gtkscrolledwindow.h>
27#include <gtk/gtkimage.h>
28#include <gdk-pixbuf/gdk-pixbuf.h>
29#include <stdlib.h>
30
31#include "mainwindow.h"
32#include "prefs_common.h"
33#include "procmime.h"
34#include "imageview.h"
35#include "utils.h"
36
37static gboolean get_resized_size(gint w,
38 gint h,
39 gint aw,
40 gint ah,
41 gint *sw,
42 gint *sh);
43
44static gint button_press_cb (GtkWidget *widget,
45 GdkEventButton *event,
46 gpointer data);
47static void size_allocate_cb (GtkWidget *widget,
48 GtkAllocation *allocation,
49 gpointer data);
50
51ImageView *imageview_create(void)
52{
53 ImageView *imageview;
54 GtkWidget *scrolledwin;
55
56 debug_print(_("Creating image view...\n"));
57 imageview = g_new0(ImageView, 1);
58
59 scrolledwin = gtk_scrolled_window_new(NULL, NULL);
60 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledwin),
61 GTK_POLICY_AUTOMATIC,
62 GTK_POLICY_AUTOMATIC);
63 gtk_widget_set_size_request
64 (scrolledwin, prefs_common.mainview_width, -1);
65
66 g_signal_connect(G_OBJECT(scrolledwin), "button_press_event",
67 G_CALLBACK(button_press_cb), imageview);
68 g_signal_connect(G_OBJECT(scrolledwin), "size_allocate",
69 G_CALLBACK(size_allocate_cb), imageview);
70
71 gtk_widget_show_all(scrolledwin);
72
73 imageview->scrolledwin = scrolledwin;
74 imageview->image = NULL;
75 imageview->image_data = NULL;
76 imageview->resize = FALSE;
77 imageview->resizing = FALSE;
78
79 return imageview;
80}
81
82void imageview_init(ImageView *imageview)
83{
84}
85
86void imageview_show_image(ImageView *imageview, MimeInfo *mimeinfo,
87 const gchar *file, gboolean resize)
88{
89 GdkPixbuf *pixbuf;
90 GdkPixbuf *rotated;
91 GError *error = NULL;
92
93 g_return_if_fail(imageview != NULL);
94 g_return_if_fail(imageview->scrolledwin != NULL);
95 g_return_if_fail(imageview->scrolledwin->parent != NULL);
96
97 if (file) {
98 imageview_clear(imageview);
99 pixbuf = gdk_pixbuf_new_from_file(file, &error);
100 imageview->image_data = pixbuf;
101 } else {
102 pixbuf = (GdkPixbuf *)imageview->image_data;
103 }
104
105 if (error != NULL) {
106 g_warning("%s\n", error->message);
107 g_error_free(error);
108 }
109
110 if (!pixbuf) {
111 g_warning(_("Can't load the image."));
112 return;
113 }
114
115 imageview->resize = resize;
116
117 pixbuf = rotated = imageview_get_rotated_pixbuf(pixbuf);
118
119 if (resize) {
120 pixbuf = imageview_get_resized_pixbuf
121 (pixbuf, imageview->scrolledwin->parent, 8);
122 } else
123 g_object_ref(pixbuf);
124
125 g_object_unref(rotated);
126
127 if (!imageview->image) {
128 imageview->image = gtk_image_new_from_pixbuf(pixbuf);
129
130 gtk_scrolled_window_add_with_viewport
131 (GTK_SCROLLED_WINDOW(imageview->scrolledwin),
132 imageview->image);
133 } else
134 gtk_image_set_from_pixbuf(GTK_IMAGE(imageview->image), pixbuf);
135
136 g_object_unref(pixbuf);
137
138 gtk_widget_show(imageview->image);
139}
140
141void imageview_clear(ImageView *imageview)
142{
143 GtkAdjustment *hadj, *vadj;
144
145 if (imageview->image)
146 gtk_image_set_from_pixmap(GTK_IMAGE(imageview->image),
147 NULL, NULL);
148 hadj = gtk_scrolled_window_get_hadjustment
149 (GTK_SCROLLED_WINDOW(imageview->scrolledwin));
150 gtk_adjustment_set_value(hadj, 0.0);
151 vadj = gtk_scrolled_window_get_vadjustment
152 (GTK_SCROLLED_WINDOW(imageview->scrolledwin));
153 gtk_adjustment_set_value(vadj, 0.0);
154
155 if (imageview->image_data) {
156 g_object_unref(imageview->image_data);
157 imageview->image_data = NULL;
158 }
159}
160
161void imageview_destroy(ImageView *imageview)
162{
163 imageview_clear(imageview);
164 g_free(imageview);
165}
166
167GdkPixbuf *imageview_get_resized_pixbuf(GdkPixbuf *pixbuf, GtkWidget *parent,
168 gint margin)
169{
170 gint avail_width;
171 gint avail_height;
172 gint new_width;
173 gint new_height;
174
175 avail_width = parent->allocation.width;
176 avail_height = parent->allocation.height;
177 if (avail_width > margin) avail_width -= margin;
178 if (avail_height > margin) avail_height -= margin;
179
180 if (get_resized_size(gdk_pixbuf_get_width(pixbuf),
181 gdk_pixbuf_get_height(pixbuf),
182 avail_width, avail_height,
183 &new_width, &new_height))
184 return gdk_pixbuf_scale_simple
185 (pixbuf, new_width, new_height, GDK_INTERP_BILINEAR);
186
187 g_object_ref(pixbuf);
188 return pixbuf;
189}
190
191static gboolean get_resized_size(gint w, gint h, gint aw, gint ah,
192 gint *sw, gint *sh)
193{
194 gfloat wratio = 1.0;
195 gfloat hratio = 1.0;
196 gfloat ratio = 1.0;
197
198 if (w <= aw && h <= ah) {
199 *sw = w;
200 *sh = h;
201 return FALSE;
202 }
203
204 if (w > aw)
205 wratio = (gfloat)aw / (gfloat)w;
206 if (h > ah)
207 hratio = (gfloat)ah / (gfloat)h;
208
209 ratio = (wratio > hratio) ? hratio : wratio;
210
211 *sw = (gint)(w * ratio);
212 *sh = (gint)(h * ratio);
213
214 /* restrict minimum size */
215 if (*sw < 16 || *sh < 16) {
216 wratio = 16.0 / (gfloat)w;
217 hratio = 16.0 / (gfloat)h;
218 ratio = (wratio > hratio) ? wratio : hratio;
219 if (ratio >= 1.0) {
220 *sw = w;
221 *sh = h;
222 } else {
223 *sw = (gint)(w * ratio);
224 *sh = (gint)(h * ratio);
225 }
226 }
227
228 return TRUE;
229}
230
231GdkPixbuf *imageview_get_rotated_pixbuf(GdkPixbuf *pixbuf)
232{
233#if GTK_CHECK_VERSION(2, 12, 0)
234 return gdk_pixbuf_apply_embedded_orientation(pixbuf);
235#else
236 const gchar *orientation_str;
237 gint orientation;
238 GdkPixbuf *rotated;
239 GdkPixbuf *new_pixbuf;
240
241 orientation_str = gdk_pixbuf_get_option(pixbuf, "orientation");
242 if (!orientation_str)
243 return g_object_ref(pixbuf);
244
245 orientation = strtol(orientation_str, NULL, 10);
246
247 switch (orientation) {
248 case 1:
249 new_pixbuf = g_object_ref(pixbuf);
250 break;
251 case 2:
252 new_pixbuf = gdk_pixbuf_flip(pixbuf, TRUE);
253 break;
254 case 3:
255 new_pixbuf = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_UPSIDEDOWN);
256 break;
257 case 4:
258 new_pixbuf = gdk_pixbuf_flip(pixbuf, FALSE);
259 break;
260 case 5:
261 rotated = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
262 new_pixbuf = gdk_pixbuf_flip(rotated, TRUE);
263 g_object_unref(rotated);
264 break;
265 case 6:
266 new_pixbuf = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
267 break;
268 case 7:
269 rotated = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_CLOCKWISE);
270 new_pixbuf = gdk_pixbuf_flip(rotated, FALSE);
271 g_object_unref(rotated);
272 break;
273 case 8:
274 new_pixbuf = gdk_pixbuf_rotate_simple(pixbuf, GDK_PIXBUF_ROTATE_COUNTERCLOCKWISE);
275 break;
276 default:
277 new_pixbuf = g_object_ref(pixbuf);
278 break;
279 }
280
281 return new_pixbuf;
282#endif
283}
284
285static gint button_press_cb(GtkWidget *widget, GdkEventButton *event,
286 gpointer data)
287{
288 ImageView *imageview = (ImageView *)data;
289
290 if (event->button == 1 && imageview->image) {
291 imageview_show_image(imageview, NULL, NULL, !imageview->resize);
292 return TRUE;
293 }
294 return FALSE;
295}
296
297static void size_allocate_cb(GtkWidget *widget,GtkAllocation *allocation,
298 gpointer data)
299{
300 ImageView *imageview = (ImageView *)data;
301
302 if (imageview->resize) {
303 if (imageview->resizing) {
304 imageview->resizing = FALSE;
305 return;
306 }
307 if (!imageview->scrolledwin->parent)
308 return;
309 if (!imageview->image_data)
310 return;
311 imageview_show_image(imageview, NULL, NULL, TRUE);
312 imageview->resizing = TRUE;
313 }
314}