Mercurial > geeqie
comparison src/pan-view.c @ 12:147f4c4b9025
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
##### an offical release when making enhancements and translation updates. #####
Tue Mar 1 11:32:26 2005 John Ellis <johne@verizon.net>
* src/Makefile.am: Add pan-view.[ch]:
* image.[ch]: Add support for using a grid of tiles as soource image. Added
scroll_notify callback for when the viewable regionis scrolled. Added ability
to set min and max for the zoom range. Removed unnecessary
gtk_widget_size_request from image_size_sync. Added image_scroll_to_point.
* layout_util.c: Add menu item and callback for the new 'Pan view'.
* pixbuf_util.c (pixbuf_draw_layout): Fix for when offset is non-zero.
* typedefs.h: Add source tile stuff for ImageWindow.
* ui_tabcomp.c: Fix tab completion pop-up menu placement.
* pan-view.[ch]: New files for the pan view - 2.1 is officially started :)
author | gqview |
---|---|
date | Tue, 01 Mar 2005 17:16:34 +0000 |
parents | |
children | ef790149ae21 |
comparison
equal
deleted
inserted
replaced
11:3c3b40dbde11 | 12:147f4c4b9025 |
---|---|
1 /* | |
2 * GQview | |
3 * (C) 2005 John Ellis | |
4 * | |
5 * Author: John Ellis | |
6 * | |
7 * This software is released under the GNU General Public License (GNU GPL). | |
8 * Please read the included file COPYING for more information. | |
9 * This software comes with no warranty of any kind, use at your own risk! | |
10 */ | |
11 | |
12 | |
13 #include "gqview.h" | |
14 #include "pan-view.h" | |
15 | |
16 #include "cache.h" | |
17 #include "dnd.h" | |
18 #include "editors.h" | |
19 #include "filelist.h" | |
20 #include "fullscreen.h" | |
21 #include "image.h" | |
22 #include "image-load.h" | |
23 #include "img-view.h" | |
24 #include "info.h" | |
25 #include "menu.h" | |
26 #include "pixbuf_util.h" | |
27 #include "thumb.h" | |
28 #include "utilops.h" | |
29 #include "ui_bookmark.h" | |
30 #include "ui_fileops.h" | |
31 #include "ui_menu.h" | |
32 #include "ui_misc.h" | |
33 #include "ui_tabcomp.h" | |
34 | |
35 #include <gdk/gdkkeysyms.h> /* for keyboard values */ | |
36 #include <math.h> | |
37 | |
38 | |
39 #define PAN_WINDOW_DEFAULT_WIDTH 720 | |
40 #define PAN_WINDOW_DEFAULT_HEIGHT 500 | |
41 | |
42 #define PAN_TILE_SIZE 512 | |
43 | |
44 #define PAN_THUMB_SIZE_NONE 24 | |
45 #define PAN_THUMB_SIZE_SMALL 64 | |
46 #define PAN_THUMB_SIZE_NORMAL 128 | |
47 #define PAN_THUMB_SIZE_LARGE 256 | |
48 #define PAN_THUMB_SIZE pw->thumb_size | |
49 | |
50 #define PAN_THUMB_GAP_SMALL 14 | |
51 #define PAN_THUMB_GAP_NORMAL 30 | |
52 #define PAN_THUMB_GAP_LARGE 40 | |
53 #define PAN_THUMB_GAP_HUGE 50 | |
54 #define PAN_THUMB_GAP pw->thumb_gap | |
55 | |
56 #define PAN_SHADOW_OFFSET 6 | |
57 #define PAN_SHADOW_FADE 5 | |
58 #define PAN_SHADOW_COLOR 0, 0, 0 | |
59 #define PAN_SHADOW_ALPHA 64 | |
60 | |
61 #define PAN_OUTLINE_THICKNESS 1 | |
62 #define PAN_OUTLINE_COLOR_1 255, 255, 255 | |
63 #define PAN_OUTLINE_COLOR_2 64, 64, 64 | |
64 #define PAN_OUTLINE_ALPHA 180 | |
65 | |
66 #define PAN_BACKGROUND_COLOR 255, 255, 230 | |
67 | |
68 #define PAN_GRID_SIZE 10 | |
69 #define PAN_GRID_COLOR 0, 0, 0 | |
70 #define PAN_GRID_ALPHA 20 | |
71 | |
72 #define PAN_FOLDER_BOX_COLOR 0, 0, 255 | |
73 #define PAN_FOLDER_BOX_ALPHA 10 | |
74 #define PAN_FOLDER_BOX_BORDER 20 | |
75 | |
76 #define PAN_FOLDER_BOX_OUTLINE_THICKNESS 4 | |
77 #define PAN_FOLDER_BOX_OUTLINE_COLOR 0, 0, 255 | |
78 #define PAN_FOLDER_BOX_OUTLINE_ALPHA 64 | |
79 | |
80 #define PAN_TEXT_BORDER_SIZE 4 | |
81 #define PAN_TEXT_COLOR 0, 0, 0 | |
82 | |
83 #define PAN_POPUP_COLOR 255, 255, 220 | |
84 #define PAN_POPUP_ALPHA 255 | |
85 #define PAN_POPUP_BORDER 1 | |
86 #define PAN_POPUP_BORDER_COLOR 0, 0, 0 | |
87 #define PAN_POPUP_TEXT_COLOR 0, 0, 0 | |
88 | |
89 #define PAN_GROUP_MAX 16 | |
90 | |
91 #define ZOOM_INCREMENT 1.0 | |
92 #define ZOOM_LABEL_WIDTH 64 | |
93 | |
94 | |
95 typedef enum { | |
96 LAYOUT_TIMELINE = 0, | |
97 LAYOUT_FOLDERS_LINEAR, | |
98 LAYOUT_FOLDERS_FLOWER, | |
99 LAYOUT_GRID, | |
100 } LayoutType; | |
101 | |
102 typedef enum { | |
103 LAYOUT_SIZE_THUMB_NONE = 0, | |
104 LAYOUT_SIZE_THUMB_SMALL, | |
105 LAYOUT_SIZE_THUMB_NORMAL, | |
106 LAYOUT_SIZE_THUMB_LARGE, | |
107 LAYOUT_SIZE_10, | |
108 LAYOUT_SIZE_25, | |
109 LAYOUT_SIZE_33, | |
110 LAYOUT_SIZE_50, | |
111 LAYOUT_SIZE_100 | |
112 } LayoutSize; | |
113 | |
114 typedef enum { | |
115 ITEM_NONE, | |
116 ITEM_THUMB, | |
117 ITEM_BOX, | |
118 ITEM_TRIANGLE, | |
119 ITEM_TEXT, | |
120 ITEM_IMAGE | |
121 } ItemType; | |
122 | |
123 typedef enum { | |
124 TEXT_ATTR_NONE = 0, | |
125 TEXT_ATTR_BOLD = 1 << 0, | |
126 TEXT_ATTR_HEADING = 1 << 1, | |
127 TEXT_ATTR_MARKUP = 1 << 2 | |
128 } TextAttrType; | |
129 | |
130 enum { | |
131 BORDER_NONE = 0, | |
132 BORDER_1 = 1 << 0, | |
133 BORDER_2 = 1 << 1, | |
134 BORDER_3 = 1 << 2, | |
135 BORDER_4 = 1 << 3 | |
136 }; | |
137 | |
138 typedef struct _PanItem PanItem; | |
139 struct _PanItem { | |
140 ItemType type; | |
141 gint x; | |
142 gint y; | |
143 gint width; | |
144 gint height; | |
145 gchar *key; | |
146 | |
147 FileData *fd; | |
148 | |
149 GdkPixbuf *pixbuf; | |
150 gint refcount; | |
151 | |
152 gchar *text; | |
153 TextAttrType text_attr; | |
154 | |
155 guint8 color_r; | |
156 guint8 color_g; | |
157 guint8 color_b; | |
158 guint8 color_a; | |
159 | |
160 guint8 color2_r; | |
161 guint8 color2_g; | |
162 guint8 color2_b; | |
163 guint8 color2_a; | |
164 gint border; | |
165 | |
166 gpointer data; | |
167 | |
168 gint queued; | |
169 }; | |
170 | |
171 typedef struct _PanWindow PanWindow; | |
172 struct _PanWindow | |
173 { | |
174 GtkWidget *window; | |
175 ImageWindow *imd; | |
176 ImageWindow *imd_normal; | |
177 FullScreenData *fs; | |
178 | |
179 GtkWidget *path_entry; | |
180 | |
181 GtkWidget *label_message; | |
182 GtkWidget *label_zoom; | |
183 | |
184 GtkWidget *search_box; | |
185 GtkWidget *search_entry; | |
186 GtkWidget *search_label; | |
187 GtkWidget *search_button; | |
188 GtkWidget *search_button_arrow; | |
189 | |
190 GtkWidget *scrollbar_h; | |
191 GtkWidget *scrollbar_v; | |
192 | |
193 gint overlay_id; | |
194 | |
195 gchar *path; | |
196 LayoutType layout; | |
197 LayoutSize size; | |
198 gint thumb_size; | |
199 gint thumb_gap; | |
200 gint image_size; | |
201 | |
202 GList *list; | |
203 | |
204 GList *cache_list; | |
205 GList *cache_todo; | |
206 gint cache_count; | |
207 gint cache_total; | |
208 gint cache_tick; | |
209 | |
210 ImageLoader *il; | |
211 ThumbLoader *tl; | |
212 PanItem *queue_pi; | |
213 GList *queue; | |
214 | |
215 PanItem *click_pi; | |
216 | |
217 gint idle_id; | |
218 }; | |
219 | |
220 typedef struct _PanCacheData PanCacheData; | |
221 struct _PanCacheData { | |
222 FileData fd; | |
223 CacheData *cd; | |
224 }; | |
225 | |
226 | |
227 static GList *pan_window_list = NULL; | |
228 | |
229 | |
230 static GList *pan_window_layout_list(const gchar *path, SortType sort, gint ascend); | |
231 | |
232 static GtkWidget *pan_popup_menu(PanWindow *pw); | |
233 static void pan_fullscreen_toggle(PanWindow *pw, gint force_off); | |
234 static void pan_overlay_toggle(PanWindow *pw); | |
235 | |
236 static void pan_window_close(PanWindow *pw); | |
237 | |
238 static void pan_window_dnd_init(PanWindow *pw); | |
239 | |
240 | |
241 static gint util_clip_region(gint x, gint y, gint w, gint h, | |
242 gint clip_x, gint clip_y, gint clip_w, gint clip_h, | |
243 gint *rx, gint *ry, gint *rw, gint *rh) | |
244 { | |
245 if (clip_x + clip_w <= x || | |
246 clip_x >= x + w || | |
247 clip_y + clip_h <= y || | |
248 clip_y >= y + h) | |
249 { | |
250 return FALSE; | |
251 } | |
252 | |
253 *rx = MAX(x, clip_x); | |
254 *rw = MIN((x + w), (clip_x + clip_w)) - *rx; | |
255 | |
256 *ry = MAX(y, clip_y); | |
257 *rh = MIN((y + h), (clip_y + clip_h)) - *ry; | |
258 | |
259 return TRUE; | |
260 } | |
261 | |
262 static gint util_clip_region_test(gint x, gint y, gint w, gint h, | |
263 gint clip_x, gint clip_y, gint clip_w, gint clip_h) | |
264 { | |
265 gint rx, ry, rw, rh; | |
266 | |
267 return util_clip_region(x, y, w, h, | |
268 clip_x, clip_y, clip_w, clip_h, | |
269 &rx, &ry, &rw, &rh); | |
270 } | |
271 | |
272 typedef enum { | |
273 DATE_LENGTH_EXACT, | |
274 DATE_LENGTH_HOUR, | |
275 DATE_LENGTH_DAY, | |
276 DATE_LENGTH_WEEK, | |
277 DATE_LENGTH_MONTH, | |
278 DATE_LENGTH_YEAR | |
279 } DateLengthType; | |
280 | |
281 static gint date_compare(time_t a, time_t b, DateLengthType length) | |
282 { | |
283 struct tm ta; | |
284 struct tm tb; | |
285 | |
286 if (length == DATE_LENGTH_EXACT) return (a == b); | |
287 | |
288 if (!localtime_r(&a, &ta) || | |
289 !localtime_r(&b, &tb)) return FALSE; | |
290 | |
291 if (ta.tm_year != tb.tm_year) return FALSE; | |
292 if (length == DATE_LENGTH_YEAR) return TRUE; | |
293 | |
294 if (ta.tm_mon != tb.tm_mon) return FALSE; | |
295 if (length == DATE_LENGTH_MONTH) return TRUE; | |
296 | |
297 if (length == DATE_LENGTH_WEEK) return (ta.tm_yday / 7 == tb.tm_yday / 7); | |
298 | |
299 if (ta.tm_mday != tb.tm_mday) return FALSE; | |
300 if (length == DATE_LENGTH_DAY) return TRUE; | |
301 | |
302 return (ta.tm_hour == tb.tm_hour); | |
303 } | |
304 | |
305 static gchar *date_value_string(time_t d, DateLengthType length) | |
306 { | |
307 struct tm td; | |
308 gchar buf[128]; | |
309 gchar *format = NULL; | |
310 | |
311 if (!localtime_r(&d, &td)) return g_strdup(""); | |
312 | |
313 switch (length) | |
314 { | |
315 case DATE_LENGTH_DAY: | |
316 return g_strdup_printf("%d", td.tm_mday); | |
317 break; | |
318 case DATE_LENGTH_WEEK: | |
319 format = "%A %e"; | |
320 break; | |
321 case DATE_LENGTH_MONTH: | |
322 format = "%B %Y"; | |
323 break; | |
324 case DATE_LENGTH_YEAR: | |
325 return g_strdup_printf("%d", td.tm_year + 1900); | |
326 break; | |
327 case DATE_LENGTH_EXACT: | |
328 default: | |
329 return g_strdup(text_from_time(d)); | |
330 break; | |
331 } | |
332 | |
333 | |
334 if (format && strftime(buf, sizeof(buf), format, &td) > 0) | |
335 { | |
336 gchar *ret = g_locale_to_utf8(buf, -1, NULL, NULL, NULL); | |
337 if (ret) return ret; | |
338 } | |
339 | |
340 return g_strdup(""); | |
341 } | |
342 | |
343 static time_t date_to_time(gint year, gint month, gint day) | |
344 { | |
345 struct tm lt; | |
346 | |
347 lt.tm_sec = 0; | |
348 lt.tm_min = 0; | |
349 lt.tm_hour = 0; | |
350 lt.tm_mday = (day >= 1 && day <= 31) ? day : 1; | |
351 lt.tm_mon = (month >= 1 && month <= 12) ? month - 1 : 0; | |
352 lt.tm_year = year - 1900; | |
353 lt.tm_isdst = 0; | |
354 | |
355 return mktime(<); | |
356 } | |
357 | |
358 /* | |
359 *----------------------------------------------------------------------------- | |
360 * drawing utils | |
361 *----------------------------------------------------------------------------- | |
362 */ | |
363 | |
364 static void triangle_rect_region(gint x1, gint y1, gint x2, gint y2, gint x3, gint y3, | |
365 gint *rx, gint *ry, gint *rw, gint *rh) | |
366 { | |
367 gint tx, ty, tw, th; | |
368 | |
369 tx = MIN(x1, x2); | |
370 tx = MIN(tx, x3); | |
371 ty = MIN(y1, y2); | |
372 ty = MIN(ty, y3); | |
373 tw = MAX(abs(x1 - x2), abs(x2 - x3)); | |
374 tw = MAX(tw, abs(x3 - x1)); | |
375 th = MAX(abs(y1 - y2), abs(y2 - y3)); | |
376 th = MAX(th, abs(y3 - y1)); | |
377 | |
378 *rx = tx; | |
379 *ry = ty; | |
380 *rw = tw; | |
381 *rh = th; | |
382 } | |
383 | |
384 static void pixbuf_draw_triangle(GdkPixbuf *pb, | |
385 gint clip_x, gint clip_y, gint clip_w, gint clip_h, | |
386 gint x1, gint y1, gint x2, gint y2, gint x3, gint y3, | |
387 guint8 r, guint8 g, guint8 b, guint8 a) | |
388 { | |
389 gint p_alpha; | |
390 gint pw, ph, prs; | |
391 gint rx, ry, rw, rh; | |
392 gint tx, ty, tw, th; | |
393 gint fx1, fy1; | |
394 gint fx2, fy2; | |
395 gint fw, fh; | |
396 guchar *p_pix; | |
397 guchar *pp; | |
398 gint p_step; | |
399 gint i, j; | |
400 | |
401 if (!pb) return; | |
402 | |
403 pw = gdk_pixbuf_get_width(pb); | |
404 ph = gdk_pixbuf_get_height(pb); | |
405 | |
406 if (!util_clip_region(0, 0, pw, ph, | |
407 clip_x, clip_y, clip_w, clip_h, | |
408 &rx, &ry, &rw, &rh)) return; | |
409 | |
410 triangle_rect_region(x1, y1, x2, y2, x3, y3, | |
411 &tx, &ty, &tw, &th); | |
412 | |
413 if (!util_clip_region(rx, ry, rw, rh, | |
414 tx, ty, tw, th, | |
415 &fx1, &fy1, &fw, &fh)) return; | |
416 fx2 = fx1 + fw; | |
417 fy2 = fy1 + fh; | |
418 | |
419 p_alpha = gdk_pixbuf_get_has_alpha(pb); | |
420 prs = gdk_pixbuf_get_rowstride(pb); | |
421 p_pix = gdk_pixbuf_get_pixels(pb); | |
422 | |
423 p_step = (p_alpha) ? 4 : 3; | |
424 for (i = fy1; i < fy2; i++) | |
425 { | |
426 pp = p_pix + i * prs + (fx1 * p_step); | |
427 for (j = fx1; j < fx2; j++) | |
428 { | |
429 gint z1, z2; | |
430 | |
431 z1 = (y1 - y2)*(j - x2) + (x2 - x1)*(i - y2); | |
432 z2 = (y2 - y3)*(j - x3) + (x3 - x2)*(i - y3); | |
433 if ((z1 ^ z2) >= 0) | |
434 { | |
435 z2 = (y3 - y1)*(j - x1) + (x1 - x3)*(i - y1); | |
436 if ((z1 ^ z2) >= 0) | |
437 { | |
438 pp[0] = (r * a + pp[0] * (256-a)) >> 8; | |
439 pp[1] = (g * a + pp[1] * (256-a)) >> 8; | |
440 pp[2] = (b * a + pp[2] * (256-a)) >> 8; | |
441 } | |
442 } | |
443 pp += p_step; | |
444 } | |
445 } | |
446 } | |
447 | |
448 static void pixbuf_draw_line(GdkPixbuf *pb, | |
449 gint clip_x, gint clip_y, gint clip_w, gint clip_h, | |
450 gint x1, gint y1, gint x2, gint y2, | |
451 guint8 r, guint8 g, guint8 b, guint8 a) | |
452 { | |
453 gint p_alpha; | |
454 gint pw, ph, prs; | |
455 gint rx, ry, rw, rh; | |
456 gint fx1, fy1, fx2, fy2; | |
457 guchar *p_pix; | |
458 guchar *pp; | |
459 gint p_step; | |
460 gint xd, yd; | |
461 gint xa, ya; | |
462 gdouble xstep, ystep; | |
463 gdouble i, j; | |
464 gint n, nt; | |
465 gint x, y; | |
466 | |
467 if (!pb) return; | |
468 | |
469 pw = gdk_pixbuf_get_width(pb); | |
470 ph = gdk_pixbuf_get_height(pb); | |
471 | |
472 if (!util_clip_region(0, 0, pw, ph, | |
473 clip_x, clip_y, clip_w, clip_h, | |
474 &rx, &ry, &rw, &rh)) return; | |
475 | |
476 fx1 = rx; | |
477 fy1 = ry; | |
478 fx2 = rx + rw; | |
479 fy2 = ry + rh; | |
480 | |
481 xd = x2 - x1; | |
482 yd = y2 - y1; | |
483 xa = abs(xd); | |
484 ya = abs(yd); | |
485 | |
486 if (xa == 0 && ya == 0) return; | |
487 #if 0 | |
488 nt = sqrt(xd * xd + yd * yd); | |
489 #endif | |
490 nt = (xa > ya) ? xa : ya; | |
491 xstep = (double)xd / nt; | |
492 ystep = (double)yd / nt; | |
493 | |
494 p_alpha = gdk_pixbuf_get_has_alpha(pb); | |
495 prs = gdk_pixbuf_get_rowstride(pb); | |
496 p_pix = gdk_pixbuf_get_pixels(pb); | |
497 | |
498 p_step = (p_alpha) ? 4 : 3; | |
499 | |
500 i = (double)y1; | |
501 j = (double)x1; | |
502 for (n = 0; n < nt; n++) | |
503 { | |
504 x = (gint)(j + 0.5); | |
505 y = (gint)(i + 0.5); | |
506 | |
507 if (x >= fx1 && x < fx2 && | |
508 y >= fy1 && y < fy2) | |
509 { | |
510 pp = p_pix + y * prs + x * p_step; | |
511 *pp = (r * a + *pp * (256-a)) >> 8; | |
512 pp++; | |
513 *pp = (g * a + *pp * (256-a)) >> 8; | |
514 pp++; | |
515 *pp = (b * a + *pp * (256-a)) >> 8; | |
516 } | |
517 i += ystep; | |
518 j += xstep; | |
519 } | |
520 } | |
521 | |
522 static void pixbuf_draw_fade_linear(guchar *p_pix, gint prs, gint p_alpha, | |
523 gint s, gint vertical, gint border, | |
524 gint x1, gint y1, gint x2, gint y2, | |
525 guint8 r, guint8 g, guint8 b, guint8 a) | |
526 { | |
527 guchar *pp; | |
528 gint p_step; | |
529 guint8 n = a; | |
530 gint i, j; | |
531 | |
532 p_step = (p_alpha) ? 4 : 3; | |
533 for (j = y1; j < y2; j++) | |
534 { | |
535 pp = p_pix + j * prs + x1 * p_step; | |
536 if (!vertical) n = a - a * abs(j - s) / border; | |
537 for (i = x1; i < x2; i++) | |
538 { | |
539 if (vertical) n = a - a * abs(i - s) / border; | |
540 *pp = (r * n + *pp * (256-n)) >> 8; | |
541 pp++; | |
542 *pp = (g * n + *pp * (256-n)) >> 8; | |
543 pp++; | |
544 *pp = (b * n + *pp * (256-n)) >> 8; | |
545 pp++; | |
546 if (p_alpha) pp++; | |
547 } | |
548 } | |
549 } | |
550 | |
551 static void pixbuf_draw_fade_radius(guchar *p_pix, gint prs, gint p_alpha, | |
552 gint sx, gint sy, gint border, | |
553 gint x1, gint y1, gint x2, gint y2, | |
554 guint8 r, guint8 g, guint8 b, guint8 a) | |
555 { | |
556 guchar *pp; | |
557 gint p_step; | |
558 gint i, j; | |
559 | |
560 p_step = (p_alpha) ? 4 : 3; | |
561 for (j = y1; j < y2; j++) | |
562 { | |
563 pp = p_pix + j * prs + x1 * p_step; | |
564 for (i = x1; i < x2; i++) | |
565 { | |
566 guint8 n; | |
567 gint r; | |
568 | |
569 r = MIN(border, (gint)sqrt((i-sx)*(i-sx) + (j-sy)*(j-sy))); | |
570 n = a - a * r / border; | |
571 *pp = (r * n + *pp * (256-n)) >> 8; | |
572 pp++; | |
573 *pp = (g * n + *pp * (256-n)) >> 8; | |
574 pp++; | |
575 *pp = (b * n + *pp * (256-n)) >> 8; | |
576 pp++; | |
577 if (p_alpha) pp++; | |
578 } | |
579 } | |
580 } | |
581 | |
582 static void pixbuf_draw_shadow(GdkPixbuf *pb, | |
583 gint clip_x, gint clip_y, gint clip_w, gint clip_h, | |
584 gint x, gint y, gint w, gint h, gint border, | |
585 guint8 r, guint8 g, guint8 b, guint8 a) | |
586 { | |
587 gint p_alpha; | |
588 gint pw, ph, prs; | |
589 gint rx, ry, rw, rh; | |
590 gint fx, fy, fw, fh; | |
591 guchar *p_pix; | |
592 | |
593 if (!pb) return; | |
594 | |
595 pw = gdk_pixbuf_get_width(pb); | |
596 ph = gdk_pixbuf_get_height(pb); | |
597 | |
598 if (!util_clip_region(0, 0, pw, ph, | |
599 clip_x, clip_y, clip_w, clip_h, | |
600 &rx, &ry, &rw, &rh)) return; | |
601 | |
602 p_alpha = gdk_pixbuf_get_has_alpha(pb); | |
603 prs = gdk_pixbuf_get_rowstride(pb); | |
604 p_pix = gdk_pixbuf_get_pixels(pb); | |
605 | |
606 if (util_clip_region(x + border, y + border, w - border * 2, h - border * 2, | |
607 rx, ry, rw, rh, | |
608 &fx, &fy, &fw, &fh)) | |
609 { | |
610 pixbuf_draw_rect_fill(pb, fx, fy, fw, fh, r, g, b, a); | |
611 } | |
612 | |
613 if (border < 1) return; | |
614 | |
615 if (util_clip_region(x, y + border, border, h - border * 2, | |
616 rx, ry, rw, rh, | |
617 &fx, &fy, &fw, &fh)) | |
618 { | |
619 pixbuf_draw_fade_linear(p_pix, prs, p_alpha, | |
620 x + border, TRUE, border, | |
621 fx, fy, fx + fw, fy + fh, | |
622 r, g, b, a); | |
623 } | |
624 if (util_clip_region(x + w - border, y + border, border, h - border * 2, | |
625 rx, ry, rw, rh, | |
626 &fx, &fy, &fw, &fh)) | |
627 { | |
628 pixbuf_draw_fade_linear(p_pix, prs, p_alpha, | |
629 x + w - border, TRUE, border, | |
630 fx, fy, fx + fw, fy + fh, | |
631 r, g, b, a); | |
632 } | |
633 if (util_clip_region(x + border, y, w - border * 2, border, | |
634 rx, ry, rw, rh, | |
635 &fx, &fy, &fw, &fh)) | |
636 { | |
637 pixbuf_draw_fade_linear(p_pix, prs, p_alpha, | |
638 y + border, FALSE, border, | |
639 fx, fy, fx + fw, fy + fh, | |
640 r, g, b, a); | |
641 } | |
642 if (util_clip_region(x + border, y + h - border, w - border * 2, border, | |
643 rx, ry, rw, rh, | |
644 &fx, &fy, &fw, &fh)) | |
645 { | |
646 pixbuf_draw_fade_linear(p_pix, prs, p_alpha, | |
647 y + h - border, FALSE, border, | |
648 fx, fy, fx + fw, fy + fh, | |
649 r, g, b, a); | |
650 } | |
651 if (util_clip_region(x, y, border, border, | |
652 rx, ry, rw, rh, | |
653 &fx, &fy, &fw, &fh)) | |
654 { | |
655 pixbuf_draw_fade_radius(p_pix, prs, p_alpha, | |
656 x + border, y + border, border, | |
657 fx, fy, fx + fw, fy + fh, | |
658 r, g, b, a); | |
659 } | |
660 if (util_clip_region(x + w - border, y, border, border, | |
661 rx, ry, rw, rh, | |
662 &fx, &fy, &fw, &fh)) | |
663 { | |
664 pixbuf_draw_fade_radius(p_pix, prs, p_alpha, | |
665 x + w - border, y + border, border, | |
666 fx, fy, fx + fw, fy + fh, | |
667 r, g, b, a); | |
668 } | |
669 if (util_clip_region(x, y + h - border, border, border, | |
670 rx, ry, rw, rh, | |
671 &fx, &fy, &fw, &fh)) | |
672 { | |
673 pixbuf_draw_fade_radius(p_pix, prs, p_alpha, | |
674 x + border, y + h - border, border, | |
675 fx, fy, fx + fw, fy + fh, | |
676 r, g, b, a); | |
677 } | |
678 if (util_clip_region(x + w - border, y + h - border, border, border, | |
679 rx, ry, rw, rh, | |
680 &fx, &fy, &fw, &fh)) | |
681 { | |
682 pixbuf_draw_fade_radius(p_pix, prs, p_alpha, | |
683 x + w - border, y + h - border, border, | |
684 fx, fy, fx + fw, fy + fh, | |
685 r, g, b, a); | |
686 } | |
687 } | |
688 | |
689 | |
690 /* | |
691 *----------------------------------------------------------------------------- | |
692 * cache | |
693 *----------------------------------------------------------------------------- | |
694 */ | |
695 | |
696 static void pan_cache_free(PanWindow *pw) | |
697 { | |
698 GList *work; | |
699 | |
700 work = pw->cache_list; | |
701 while (work) | |
702 { | |
703 PanCacheData *pc; | |
704 | |
705 pc = work->data; | |
706 work = work->next; | |
707 | |
708 cache_sim_data_free(pc->cd); | |
709 file_data_free((FileData *)pc); | |
710 } | |
711 | |
712 g_list_free(pw->cache_list); | |
713 pw->cache_list = NULL; | |
714 | |
715 filelist_free(pw->cache_todo); | |
716 pw->cache_todo = NULL; | |
717 | |
718 pw->cache_count = 0; | |
719 pw->cache_total = 0; | |
720 pw->cache_tick = 0; | |
721 } | |
722 | |
723 static void pan_cache_fill(PanWindow *pw, const gchar *path) | |
724 { | |
725 GList *list; | |
726 | |
727 pan_cache_free(pw); | |
728 | |
729 list = pan_window_layout_list(path, SORT_NAME, TRUE); | |
730 pw->cache_todo = g_list_reverse(list); | |
731 | |
732 pw->cache_total = g_list_length(pw->cache_todo); | |
733 } | |
734 | |
735 static gint pan_cache_step(PanWindow *pw) | |
736 { | |
737 FileData *fd; | |
738 PanCacheData *pc; | |
739 CacheData *cd = NULL; | |
740 | |
741 if (!pw->cache_todo) return FALSE; | |
742 | |
743 fd = pw->cache_todo->data; | |
744 pw->cache_todo = g_list_remove(pw->cache_todo, fd); | |
745 | |
746 if (enable_thumb_caching) | |
747 { | |
748 gchar *found; | |
749 | |
750 found = cache_find_location(CACHE_TYPE_SIM, fd->path); | |
751 if (found && filetime(found) == fd->date) | |
752 { | |
753 cd = cache_sim_data_load(found); | |
754 } | |
755 g_free(found); | |
756 } | |
757 | |
758 if (!cd) cd = cache_sim_data_new(); | |
759 | |
760 if (!cd->dimensions) | |
761 { | |
762 cd->dimensions = image_load_dimensions(fd->path, &cd->width, &cd->height); | |
763 if (enable_thumb_caching && | |
764 cd->dimensions) | |
765 { | |
766 gchar *base; | |
767 mode_t mode = 0755; | |
768 | |
769 base = cache_get_location(CACHE_TYPE_SIM, fd->path, FALSE, &mode); | |
770 if (cache_ensure_dir_exists(base, mode)) | |
771 { | |
772 g_free(cd->path); | |
773 cd->path = cache_get_location(CACHE_TYPE_SIM, fd->path, TRUE, NULL); | |
774 if (cache_sim_data_save(cd)) | |
775 { | |
776 filetime_set(cd->path, filetime(fd->path)); | |
777 } | |
778 } | |
779 g_free(base); | |
780 } | |
781 | |
782 pw->cache_tick = 9; | |
783 } | |
784 | |
785 pc = g_new0(PanCacheData, 1); | |
786 memcpy(pc, fd, sizeof(FileData)); | |
787 g_free(fd); | |
788 | |
789 pc->cd = cd; | |
790 | |
791 pw->cache_list = g_list_prepend(pw->cache_list, pc); | |
792 | |
793 return TRUE; | |
794 } | |
795 | |
796 | |
797 /* | |
798 *----------------------------------------------------------------------------- | |
799 * item objects | |
800 *----------------------------------------------------------------------------- | |
801 */ | |
802 | |
803 static void pan_item_free(PanItem *pi) | |
804 { | |
805 if (!pi) return; | |
806 | |
807 if (pi->pixbuf) g_object_unref(pi->pixbuf); | |
808 if (pi->fd) file_data_free(pi->fd); | |
809 g_free(pi->text); | |
810 g_free(pi->key); | |
811 g_free(pi->data); | |
812 | |
813 g_free(pi); | |
814 } | |
815 | |
816 static void pan_window_items_free(PanWindow *pw) | |
817 { | |
818 GList *work; | |
819 | |
820 work = pw->list; | |
821 while (work) | |
822 { | |
823 PanItem *pi = work->data; | |
824 work = work->next; | |
825 | |
826 pan_item_free(pi); | |
827 } | |
828 | |
829 g_list_free(pw->list); | |
830 pw->list = NULL; | |
831 | |
832 g_list_free(pw->queue); | |
833 pw->queue = NULL; | |
834 pw->queue_pi = NULL; | |
835 | |
836 image_loader_free(pw->il); | |
837 pw->il = NULL; | |
838 | |
839 thumb_loader_free(pw->tl); | |
840 pw->tl = NULL; | |
841 | |
842 pw->click_pi = NULL; | |
843 } | |
844 | |
845 static PanItem *pan_item_new_thumb(PanWindow *pw, FileData *fd, gint x, gint y) | |
846 { | |
847 PanItem *pi; | |
848 | |
849 pi = g_new0(PanItem, 1); | |
850 pi->type = ITEM_THUMB; | |
851 pi->fd = fd; | |
852 pi->x = x; | |
853 pi->y = y; | |
854 pi->width = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2; | |
855 pi->height = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2; | |
856 | |
857 pi->pixbuf = NULL; | |
858 | |
859 pi->queued = FALSE; | |
860 | |
861 pw->list = g_list_prepend(pw->list, pi); | |
862 | |
863 return pi; | |
864 } | |
865 | |
866 static PanItem *pan_item_new_box(PanWindow *pw, FileData *fd, gint x, gint y, gint width, gint height, | |
867 gint border_size, | |
868 guint8 base_r, guint8 base_g, guint8 base_b, guint8 base_a, | |
869 guint8 bord_r, guint8 bord_g, guint8 bord_b, guint8 bord_a) | |
870 { | |
871 PanItem *pi; | |
872 | |
873 pi = g_new0(PanItem, 1); | |
874 pi->type = ITEM_BOX; | |
875 pi->fd = fd; | |
876 pi->x = x; | |
877 pi->y = y; | |
878 pi->width = width; | |
879 pi->height = height; | |
880 | |
881 pi->color_r = base_r; | |
882 pi->color_g = base_g; | |
883 pi->color_b = base_b; | |
884 pi->color_a = base_a; | |
885 | |
886 pi->color2_r = bord_r; | |
887 pi->color2_g = bord_g; | |
888 pi->color2_b = bord_b; | |
889 pi->color2_a = bord_a; | |
890 pi->border = border_size; | |
891 | |
892 pw->list = g_list_prepend(pw->list, pi); | |
893 | |
894 return pi; | |
895 } | |
896 | |
897 static void pan_item_box_shadow(PanItem *pi, gint offset, gint fade) | |
898 { | |
899 gint *shadow; | |
900 | |
901 if (!pi || pi->type != ITEM_BOX) return; | |
902 | |
903 shadow = pi->data; | |
904 if (shadow) | |
905 { | |
906 pi->width -= shadow[0]; | |
907 pi->height -= shadow[0]; | |
908 } | |
909 | |
910 shadow = g_new0(gint, 2); | |
911 shadow[0] = offset; | |
912 shadow[1] = fade; | |
913 | |
914 pi->width += offset; | |
915 pi->height += offset; | |
916 | |
917 g_free(pi->data); | |
918 pi->data = shadow; | |
919 } | |
920 | |
921 static PanItem *pan_item_new_tri(PanWindow *pw, FileData *fd, gint x, gint y, gint width, gint height, | |
922 gint x1, gint y1, gint x2, gint y2, gint x3, gint y3, | |
923 guint8 r, guint8 g, guint8 b, guint8 a) | |
924 { | |
925 PanItem *pi; | |
926 gint *coord; | |
927 | |
928 pi = g_new0(PanItem, 1); | |
929 pi->type = ITEM_TRIANGLE; | |
930 pi->x = x; | |
931 pi->y = y; | |
932 pi->width = width; | |
933 pi->height = height; | |
934 | |
935 pi->color_r = r; | |
936 pi->color_g = g; | |
937 pi->color_b = b; | |
938 pi->color_a = a; | |
939 | |
940 coord = g_new0(gint, 6); | |
941 coord[0] = x1; | |
942 coord[1] = y1; | |
943 coord[2] = x2; | |
944 coord[3] = y2; | |
945 coord[4] = x3; | |
946 coord[5] = y3; | |
947 | |
948 pi->data = coord; | |
949 | |
950 pi->border = BORDER_NONE; | |
951 | |
952 pw->list = g_list_prepend(pw->list, pi); | |
953 | |
954 return pi; | |
955 } | |
956 | |
957 static void pan_item_tri_border(PanItem *pi, gint borders, | |
958 guint8 r, guint8 g, guint8 b, guint8 a) | |
959 { | |
960 if (!pi || pi->type != ITEM_TRIANGLE) return; | |
961 | |
962 pi->border = borders; | |
963 | |
964 pi->color2_r = r; | |
965 pi->color2_g = g; | |
966 pi->color2_b = b; | |
967 pi->color2_a = a; | |
968 } | |
969 | |
970 static PangoLayout *pan_item_text_layout(PanItem *pi, GtkWidget *widget) | |
971 { | |
972 PangoLayout *layout; | |
973 | |
974 layout = gtk_widget_create_pango_layout(widget, NULL); | |
975 | |
976 if (pi->text_attr & TEXT_ATTR_MARKUP) | |
977 { | |
978 pango_layout_set_markup(layout, pi->text, -1); | |
979 return layout; | |
980 } | |
981 | |
982 if (pi->text_attr & TEXT_ATTR_BOLD || | |
983 pi->text_attr & TEXT_ATTR_HEADING) | |
984 { | |
985 PangoAttrList *pal; | |
986 PangoAttribute *pa; | |
987 | |
988 pal = pango_attr_list_new(); | |
989 if (pi->text_attr & TEXT_ATTR_BOLD) | |
990 { | |
991 pa = pango_attr_weight_new(PANGO_WEIGHT_BOLD); | |
992 pa->start_index = 0; | |
993 pa->end_index = G_MAXINT; | |
994 pango_attr_list_insert(pal, pa); | |
995 } | |
996 if (pi->text_attr & TEXT_ATTR_HEADING) | |
997 { | |
998 pa = pango_attr_scale_new(PANGO_SCALE_LARGE); | |
999 pa->start_index = 0; | |
1000 pa->end_index = G_MAXINT; | |
1001 pango_attr_list_insert(pal, pa); | |
1002 } | |
1003 pango_layout_set_attributes(layout, pal); | |
1004 pango_attr_list_unref(pal); | |
1005 } | |
1006 | |
1007 pango_layout_set_text(layout, pi->text, -1); | |
1008 return layout; | |
1009 } | |
1010 | |
1011 static void pan_item_text_compute_size(PanItem *pi, GtkWidget *widget) | |
1012 { | |
1013 PangoLayout *layout; | |
1014 | |
1015 if (!pi || !pi->text || !widget) return; | |
1016 | |
1017 layout = pan_item_text_layout(pi, widget); | |
1018 pango_layout_get_pixel_size(layout, &pi->width, &pi->height); | |
1019 g_object_unref(G_OBJECT(layout)); | |
1020 | |
1021 pi->width += PAN_TEXT_BORDER_SIZE * 2; | |
1022 pi->height += PAN_TEXT_BORDER_SIZE * 2; | |
1023 } | |
1024 | |
1025 static PanItem *pan_item_new_text(PanWindow *pw, gint x, gint y, const gchar *text, TextAttrType attr, | |
1026 guint8 r, guint8 g, guint8 b, guint8 a) | |
1027 { | |
1028 PanItem *pi; | |
1029 | |
1030 pi = g_new0(PanItem, 1); | |
1031 pi->type = ITEM_TEXT; | |
1032 pi->x = x; | |
1033 pi->y = y; | |
1034 pi->text = g_strdup(text); | |
1035 pi->text_attr = attr; | |
1036 | |
1037 pi->color_r = r; | |
1038 pi->color_g = g; | |
1039 pi->color_b = b; | |
1040 pi->color_a = a; | |
1041 | |
1042 pan_item_text_compute_size(pi, pw->imd->widget); | |
1043 | |
1044 pw->list = g_list_prepend(pw->list, pi); | |
1045 | |
1046 return pi; | |
1047 } | |
1048 | |
1049 static void pan_item_set_key(PanItem *pi, const gchar *key) | |
1050 { | |
1051 gchar *tmp; | |
1052 | |
1053 if (!pi) return; | |
1054 | |
1055 tmp = pi->key; | |
1056 pi->key = g_strdup(key); | |
1057 g_free(tmp); | |
1058 } | |
1059 | |
1060 static void pan_item_added(PanWindow *pw, PanItem *pi) | |
1061 { | |
1062 if (!pi) return; | |
1063 image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height); | |
1064 } | |
1065 | |
1066 static void pan_item_remove(PanWindow *pw, PanItem *pi) | |
1067 { | |
1068 if (!pi) return; | |
1069 | |
1070 if (pw->click_pi == pi) pw->click_pi = NULL; | |
1071 | |
1072 pw->list = g_list_remove(pw->list, pi); | |
1073 image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height); | |
1074 pan_item_free(pi); | |
1075 } | |
1076 | |
1077 static void pan_item_size_by_item(PanItem *pi, PanItem *child, gint border) | |
1078 { | |
1079 if (!pi || !child) return; | |
1080 | |
1081 if (pi->x + pi->width < child->x + child->width + border) | |
1082 pi->width = child->x + child->width + border - pi->x; | |
1083 | |
1084 if (pi->y + pi->height < child->y + child->height + border) | |
1085 pi->height = child->y + child->height + border - pi->y; | |
1086 } | |
1087 | |
1088 static void pan_item_image_find_size(PanWindow *pw, PanItem *pi, gint w, gint h) | |
1089 { | |
1090 GList *work; | |
1091 | |
1092 pi->width = w; | |
1093 pi->height = h; | |
1094 | |
1095 if (!pi->fd) return; | |
1096 | |
1097 work = pw->cache_list; | |
1098 while (work) | |
1099 { | |
1100 PanCacheData *pc; | |
1101 gchar *path; | |
1102 | |
1103 pc = work->data; | |
1104 work = work->next; | |
1105 | |
1106 path = ((FileData *)pc)->path; | |
1107 | |
1108 if (pc->cd && pc->cd->dimensions && | |
1109 path && strcmp(path, pi->fd->path) == 0) | |
1110 { | |
1111 pi->width = MAX(1, pc->cd->width * pw->image_size / 100); | |
1112 pi->height = MAX(1, pc->cd->height * pw->image_size / 100); | |
1113 | |
1114 pw->cache_list = g_list_remove(pw->cache_list, pc); | |
1115 cache_sim_data_free(pc->cd); | |
1116 file_data_free((FileData *)pc); | |
1117 return; | |
1118 } | |
1119 } | |
1120 } | |
1121 | |
1122 static PanItem *pan_item_new_image(PanWindow *pw, FileData *fd, gint x, gint y, gint w, gint h) | |
1123 { | |
1124 PanItem *pi; | |
1125 | |
1126 pi = g_new0(PanItem, 1); | |
1127 pi->type = ITEM_IMAGE; | |
1128 pi->fd = fd; | |
1129 pi->x = x; | |
1130 pi->y = y; | |
1131 | |
1132 pan_item_image_find_size(pw, pi, w, h); | |
1133 | |
1134 pw->list = g_list_prepend(pw->list, pi); | |
1135 | |
1136 return pi; | |
1137 } | |
1138 | |
1139 static PanItem *pan_item_find_by_key(PanWindow *pw, ItemType type, const gchar *key) | |
1140 { | |
1141 GList *work; | |
1142 | |
1143 if (!key) return NULL; | |
1144 | |
1145 work = g_list_last(pw->list); | |
1146 while (work) | |
1147 { | |
1148 PanItem *pi; | |
1149 | |
1150 pi = work->data; | |
1151 if ((pi->type == type || type == ITEM_NONE) && | |
1152 pi->key && strcmp(pi->key, key) == 0) | |
1153 { | |
1154 return pi; | |
1155 } | |
1156 work = work->prev; | |
1157 } | |
1158 | |
1159 return NULL; | |
1160 } | |
1161 | |
1162 /* when ignore_case and partial are TRUE, path should be converted to lower case */ | |
1163 static PanItem *pan_item_find_by_path(PanWindow *pw, ItemType type, const gchar *path, | |
1164 gint ignore_case, gint partial) | |
1165 { | |
1166 GList *work; | |
1167 | |
1168 if (!path) return NULL; | |
1169 if (partial && path[0] == '/') return NULL; | |
1170 | |
1171 work = g_list_last(pw->list); | |
1172 while (work) | |
1173 { | |
1174 PanItem *pi; | |
1175 | |
1176 pi = work->data; | |
1177 if ((pi->type == type || type == ITEM_NONE) && pi->fd) | |
1178 { | |
1179 if (path[0] == '/') | |
1180 { | |
1181 if (pi->fd->path && strcmp(path, pi->fd->path) == 0) return pi; | |
1182 } | |
1183 else if (pi->fd->name) | |
1184 { | |
1185 if (partial) | |
1186 { | |
1187 if (ignore_case) | |
1188 { | |
1189 gchar *haystack; | |
1190 gint match; | |
1191 | |
1192 haystack = g_utf8_strdown(pi->fd->name, -1); | |
1193 match = (strstr(haystack, path) != NULL); | |
1194 g_free(haystack); | |
1195 if (match) return pi; | |
1196 } | |
1197 else | |
1198 { | |
1199 if (strstr(pi->fd->name, path)) return pi; | |
1200 } | |
1201 } | |
1202 else if (ignore_case) | |
1203 { | |
1204 if (strcasecmp(path, pi->fd->name) == 0) return pi; | |
1205 } | |
1206 else | |
1207 { | |
1208 if (strcmp(path, pi->fd->name) == 0) return pi; | |
1209 } | |
1210 } | |
1211 } | |
1212 work = work->prev; | |
1213 } | |
1214 | |
1215 return NULL; | |
1216 } | |
1217 | |
1218 static PanItem *pan_item_find_by_coord(PanWindow *pw, ItemType type, gint x, gint y) | |
1219 { | |
1220 GList *work; | |
1221 | |
1222 if (x < 0 || x >= pw->imd->image_width || | |
1223 y < 0 || y >= pw->imd->image_height) return NULL; | |
1224 | |
1225 work = pw->list; | |
1226 while (work) | |
1227 { | |
1228 PanItem *pi; | |
1229 | |
1230 pi = work->data; | |
1231 if ((pi->type == type || type == ITEM_NONE) && | |
1232 x >= pi->x && x < pi->x + pi->width && | |
1233 y >= pi->y && y < pi->y + pi->height) | |
1234 { | |
1235 return pi; | |
1236 } | |
1237 work = work->next; | |
1238 } | |
1239 | |
1240 return NULL; | |
1241 } | |
1242 | |
1243 /* | |
1244 *----------------------------------------------------------------------------- | |
1245 * layout generation | |
1246 *----------------------------------------------------------------------------- | |
1247 */ | |
1248 | |
1249 static GList *pan_window_layout_list(const gchar *path, SortType sort, gint ascend) | |
1250 { | |
1251 GList *flist = NULL; | |
1252 GList *dlist = NULL; | |
1253 GList *result; | |
1254 GList *folders; | |
1255 | |
1256 filelist_read(path, &flist, &dlist); | |
1257 if (sort != SORT_NONE) | |
1258 { | |
1259 flist = filelist_sort(flist, sort, ascend); | |
1260 dlist = filelist_sort(dlist, sort, ascend); | |
1261 } | |
1262 | |
1263 result = flist; | |
1264 folders = dlist; | |
1265 while (folders) | |
1266 { | |
1267 FileData *fd; | |
1268 | |
1269 fd = folders->data; | |
1270 folders = g_list_remove(folders, fd); | |
1271 | |
1272 if (filelist_read(fd->path, &flist, &dlist)) | |
1273 { | |
1274 if (sort != SORT_NONE) | |
1275 { | |
1276 flist = filelist_sort(flist, sort, ascend); | |
1277 dlist = filelist_sort(dlist, sort, ascend); | |
1278 } | |
1279 | |
1280 result = g_list_concat(result, flist); | |
1281 folders = g_list_concat(dlist, folders); | |
1282 } | |
1283 | |
1284 file_data_free(fd); | |
1285 } | |
1286 | |
1287 return result; | |
1288 } | |
1289 | |
1290 static void pan_window_layout_compute_grid(PanWindow *pw, const gchar *path, gint *width, gint *height) | |
1291 { | |
1292 GList *list; | |
1293 GList *work; | |
1294 gint x, y; | |
1295 gint w, h; | |
1296 gint grid_size; | |
1297 gint next_y; | |
1298 | |
1299 list = pan_window_layout_list(path, SORT_NAME, TRUE); | |
1300 | |
1301 grid_size = (gint)sqrt((double)g_list_length(list)); | |
1302 if (pw->size > LAYOUT_SIZE_THUMB_LARGE) | |
1303 { | |
1304 grid_size = grid_size * (512 + PAN_THUMB_GAP) * pw->image_size / 100; | |
1305 } | |
1306 else | |
1307 { | |
1308 grid_size = grid_size * (PAN_THUMB_SIZE + PAN_THUMB_GAP); | |
1309 } | |
1310 | |
1311 next_y = 0; | |
1312 | |
1313 w = PAN_THUMB_GAP * 2; | |
1314 h = PAN_THUMB_GAP * 2; | |
1315 | |
1316 x = PAN_THUMB_GAP; | |
1317 y = PAN_THUMB_GAP; | |
1318 work = list; | |
1319 while (work) | |
1320 { | |
1321 FileData *fd; | |
1322 PanItem *pi; | |
1323 | |
1324 fd = work->data; | |
1325 work = work->next; | |
1326 | |
1327 if (pw->size > LAYOUT_SIZE_THUMB_LARGE) | |
1328 { | |
1329 pi = pan_item_new_image(pw, fd, x, y, 10, 10); | |
1330 | |
1331 x += pi->width + PAN_THUMB_GAP; | |
1332 if (y + pi->height + PAN_THUMB_GAP > next_y) next_y = y + pi->height + PAN_THUMB_GAP; | |
1333 if (x > grid_size) | |
1334 { | |
1335 x = PAN_THUMB_GAP; | |
1336 y = next_y; | |
1337 } | |
1338 } | |
1339 else | |
1340 { | |
1341 pi = pan_item_new_thumb(pw, fd, x, y); | |
1342 | |
1343 x += PAN_THUMB_SIZE + PAN_THUMB_GAP; | |
1344 if (x > grid_size) | |
1345 { | |
1346 x = PAN_THUMB_GAP; | |
1347 y += PAN_THUMB_SIZE + PAN_THUMB_GAP; | |
1348 } | |
1349 } | |
1350 | |
1351 if (w < pi->x + pi->width + PAN_THUMB_GAP) w = pi->x + pi->width + PAN_THUMB_GAP; | |
1352 if (h < pi->y + pi->height + PAN_THUMB_GAP) h = pi->y + pi->height + PAN_THUMB_GAP; | |
1353 } | |
1354 | |
1355 if (width) *width = w; | |
1356 if (height) *height = h; | |
1357 | |
1358 g_list_free(list); | |
1359 } | |
1360 | |
1361 static void pan_window_Layout_compute_folders_flower_size(PanWindow *pw, gint *width, gint *height) | |
1362 { | |
1363 GList *work; | |
1364 gint x1, y1, x2, y2; | |
1365 | |
1366 x1 = 0; | |
1367 y1 = 0; | |
1368 x2 = 0; | |
1369 y2 = 0; | |
1370 | |
1371 work = pw->list; | |
1372 while (work) | |
1373 { | |
1374 PanItem *pi; | |
1375 | |
1376 pi = work->data; | |
1377 work = work->next; | |
1378 | |
1379 if (x1 > pi->x) x1 = pi->x; | |
1380 if (y1 > pi->y) y1 = pi->y; | |
1381 if (x2 < pi->x + pi->width) x2 = pi->x + pi->width; | |
1382 if (y2 < pi->y + pi->height) y2 = pi->y + pi->height; | |
1383 } | |
1384 | |
1385 x1 -= PAN_FOLDER_BOX_BORDER; | |
1386 y1 -= PAN_FOLDER_BOX_BORDER; | |
1387 x2 += PAN_FOLDER_BOX_BORDER; | |
1388 y2 += PAN_FOLDER_BOX_BORDER; | |
1389 | |
1390 work = pw->list; | |
1391 while (work) | |
1392 { | |
1393 PanItem *pi; | |
1394 | |
1395 pi = work->data; | |
1396 work = work->next; | |
1397 | |
1398 pi->x -= x1; | |
1399 pi->y -= y1; | |
1400 | |
1401 if (pi->type == ITEM_TRIANGLE && pi->data) | |
1402 { | |
1403 gint *coord; | |
1404 | |
1405 coord = pi->data; | |
1406 coord[0] -= x1; | |
1407 coord[1] -= y1; | |
1408 coord[2] -= x1; | |
1409 coord[3] -= y1; | |
1410 coord[4] -= x1; | |
1411 coord[5] -= y1; | |
1412 } | |
1413 } | |
1414 | |
1415 if (width) *width = x2 - x1; | |
1416 if (height) *height = y2 - y1; | |
1417 } | |
1418 | |
1419 typedef struct _FlowerGroup FlowerGroup; | |
1420 struct _FlowerGroup { | |
1421 GList *items; | |
1422 GList *children; | |
1423 gint x; | |
1424 gint y; | |
1425 gint width; | |
1426 gint height; | |
1427 | |
1428 gdouble angle; | |
1429 gint circumference; | |
1430 gint diameter; | |
1431 }; | |
1432 | |
1433 static void pan_window_layout_compute_folder_flower_move(FlowerGroup *group, gint x, gint y) | |
1434 { | |
1435 GList *work; | |
1436 | |
1437 work = group->items; | |
1438 while (work) | |
1439 { | |
1440 PanItem *pi; | |
1441 | |
1442 pi = work->data; | |
1443 work = work->next; | |
1444 | |
1445 pi->x += x; | |
1446 pi->y += y; | |
1447 } | |
1448 | |
1449 group->x += x; | |
1450 group->y += y; | |
1451 } | |
1452 | |
1453 #define PI 3.14159 | |
1454 | |
1455 static void pan_window_layout_compute_folder_flower_position(FlowerGroup *group, FlowerGroup *parent, | |
1456 gint *result_x, gint *result_y) | |
1457 { | |
1458 gint x, y; | |
1459 gint radius; | |
1460 gdouble a; | |
1461 | |
1462 radius = parent->circumference / (2*PI); | |
1463 radius = MAX(radius, parent->diameter / 2 + group->diameter / 2); | |
1464 | |
1465 a = 2*PI * group->diameter / parent->circumference; | |
1466 | |
1467 x = (gint)((double)radius * cos(parent->angle + a / 2)); | |
1468 y = (gint)((double)radius * sin(parent->angle + a / 2)); | |
1469 | |
1470 parent->angle += a; | |
1471 | |
1472 x += parent->x; | |
1473 y += parent->y; | |
1474 | |
1475 x += parent->width / 2; | |
1476 y += parent->height / 2; | |
1477 | |
1478 x -= group->width / 2; | |
1479 y -= group->height / 2; | |
1480 | |
1481 *result_x = x; | |
1482 *result_y = y; | |
1483 } | |
1484 | |
1485 static void pan_window_layout_compute_folder_flower_build(PanWindow *pw, FlowerGroup *group, FlowerGroup *parent) | |
1486 { | |
1487 GList *work; | |
1488 gint x, y; | |
1489 | |
1490 if (!group) return; | |
1491 | |
1492 if (parent && parent->children) | |
1493 { | |
1494 pan_window_layout_compute_folder_flower_position(group, parent, &x, &y); | |
1495 } | |
1496 else | |
1497 { | |
1498 x = 0; | |
1499 y = 0; | |
1500 } | |
1501 | |
1502 pan_window_layout_compute_folder_flower_move(group, x, y); | |
1503 | |
1504 if (parent) | |
1505 { | |
1506 PanItem *pi; | |
1507 gint px, py, gx, gy; | |
1508 gint x1, y1, x2, y2; | |
1509 | |
1510 px = parent->x + parent->width / 2; | |
1511 py = parent->y + parent->height / 2; | |
1512 | |
1513 gx = group->x + group->width / 2; | |
1514 gy = group->y + group->height / 2; | |
1515 | |
1516 x1 = MIN(px, gx); | |
1517 y1 = MIN(py, gy); | |
1518 | |
1519 x2 = MAX(px, gx + 5); | |
1520 y2 = MAX(py, gy + 5); | |
1521 | |
1522 pi = pan_item_new_tri(pw, NULL, x1, y1, x2 - x1, y2 - y1, | |
1523 px, py, gx, gy, gx + 5, gy + 5, | |
1524 255, 40, 40, 128); | |
1525 pan_item_tri_border(pi, BORDER_1 | BORDER_3, | |
1526 255, 0, 0, 128); | |
1527 } | |
1528 | |
1529 pw->list = g_list_concat(group->items, pw->list); | |
1530 group->items = NULL; | |
1531 | |
1532 group->circumference = 0; | |
1533 work = group->children; | |
1534 while (work) | |
1535 { | |
1536 FlowerGroup *child; | |
1537 | |
1538 child = work->data; | |
1539 work = work->next; | |
1540 | |
1541 group->circumference += child->diameter; | |
1542 } | |
1543 | |
1544 work = g_list_last(group->children); | |
1545 while (work) | |
1546 { | |
1547 FlowerGroup *child; | |
1548 | |
1549 child = work->data; | |
1550 work = work->prev; | |
1551 | |
1552 pan_window_layout_compute_folder_flower_build(pw, child, group); | |
1553 } | |
1554 | |
1555 g_list_free(group->children); | |
1556 g_free(group); | |
1557 } | |
1558 | |
1559 static FlowerGroup *pan_window_layout_compute_folders_flower_path(PanWindow *pw, const gchar *path, | |
1560 gint x, gint y) | |
1561 { | |
1562 FlowerGroup *group; | |
1563 GList *f; | |
1564 GList *d; | |
1565 GList *work; | |
1566 PanItem *pi_box; | |
1567 gint x_start; | |
1568 gint y_height; | |
1569 gint grid_size; | |
1570 gint grid_count; | |
1571 | |
1572 if (!filelist_read(path, &f, &d)) return NULL; | |
1573 if (!f && !d) return NULL; | |
1574 | |
1575 f = filelist_sort(f, SORT_NAME, TRUE); | |
1576 d = filelist_sort(d, SORT_NAME, TRUE); | |
1577 | |
1578 pi_box = pan_item_new_text(pw, x, y, path, TEXT_ATTR_NONE, | |
1579 PAN_TEXT_COLOR, 255); | |
1580 | |
1581 y += pi_box->height; | |
1582 | |
1583 pi_box = pan_item_new_box(pw, file_data_new_simple(path), | |
1584 x, y, | |
1585 PAN_FOLDER_BOX_BORDER * 2, PAN_FOLDER_BOX_BORDER * 2, | |
1586 PAN_FOLDER_BOX_OUTLINE_THICKNESS, | |
1587 PAN_FOLDER_BOX_COLOR, PAN_FOLDER_BOX_ALPHA, | |
1588 PAN_FOLDER_BOX_OUTLINE_COLOR, PAN_FOLDER_BOX_OUTLINE_ALPHA); | |
1589 | |
1590 x += PAN_FOLDER_BOX_BORDER; | |
1591 y += PAN_FOLDER_BOX_BORDER; | |
1592 | |
1593 grid_size = (gint)(sqrt(g_list_length(f)) + 0.9); | |
1594 grid_count = 0; | |
1595 x_start = x; | |
1596 y_height = y; | |
1597 | |
1598 work = f; | |
1599 while (work) | |
1600 { | |
1601 FileData *fd; | |
1602 PanItem *pi; | |
1603 | |
1604 fd = work->data; | |
1605 work = work->next; | |
1606 | |
1607 if (pw->size > LAYOUT_SIZE_THUMB_LARGE) | |
1608 { | |
1609 pi = pan_item_new_image(pw, fd, x, y, 10, 10); | |
1610 x += pi->width + PAN_THUMB_GAP; | |
1611 if (pi->height > y_height) y_height = pi->height; | |
1612 } | |
1613 else | |
1614 { | |
1615 pi = pan_item_new_thumb(pw, fd, x, y); | |
1616 x += PAN_THUMB_SIZE + PAN_THUMB_GAP; | |
1617 y_height = PAN_THUMB_SIZE; | |
1618 } | |
1619 | |
1620 grid_count++; | |
1621 if (grid_count >= grid_size) | |
1622 { | |
1623 grid_count = 0; | |
1624 x = x_start; | |
1625 y += y_height + PAN_THUMB_GAP; | |
1626 y_height = 0; | |
1627 } | |
1628 | |
1629 pan_item_size_by_item(pi_box, pi, PAN_FOLDER_BOX_BORDER); | |
1630 } | |
1631 | |
1632 g_list_free(f); | |
1633 | |
1634 group = g_new0(FlowerGroup, 1); | |
1635 group->items = pw->list; | |
1636 pw->list = NULL; | |
1637 | |
1638 group->width = pi_box->width; | |
1639 group->height = pi_box->y + pi_box->height; | |
1640 group->diameter = (int)sqrt(group->width * group->width + group->height * group->height); | |
1641 | |
1642 group->children = NULL; | |
1643 | |
1644 work = d; | |
1645 while (work) | |
1646 { | |
1647 FileData *fd; | |
1648 FlowerGroup *child; | |
1649 | |
1650 fd = work->data; | |
1651 work = work->next; | |
1652 | |
1653 child = pan_window_layout_compute_folders_flower_path(pw, fd->path, 0, 0); | |
1654 if (child) group->children = g_list_prepend(group->children, child); | |
1655 } | |
1656 | |
1657 filelist_free(d); | |
1658 | |
1659 return group; | |
1660 } | |
1661 | |
1662 static void pan_window_layout_compute_folders_flower(PanWindow *pw, const gchar *path, | |
1663 gint *width, gint *height, | |
1664 gint *scroll_x, gint *scroll_y) | |
1665 { | |
1666 FlowerGroup *group; | |
1667 PanItem *pi; | |
1668 | |
1669 group = pan_window_layout_compute_folders_flower_path(pw, path, 0, 0); | |
1670 pan_window_layout_compute_folder_flower_build(pw, group, NULL); | |
1671 | |
1672 pan_window_Layout_compute_folders_flower_size(pw, width, height); | |
1673 | |
1674 pi = pan_item_find_by_path(pw, ITEM_BOX, path, FALSE, FALSE); | |
1675 if (pi) | |
1676 { | |
1677 *scroll_x = pi->x - PAN_FOLDER_BOX_BORDER; | |
1678 *scroll_y = pi->y - PAN_FOLDER_BOX_BORDER; | |
1679 } | |
1680 } | |
1681 | |
1682 static void pan_window_layout_compute_folders_linear_path(PanWindow *pw, const gchar *path, | |
1683 gint *x, gint *y, gint *level, | |
1684 PanItem *parent, | |
1685 gint *width, gint *height) | |
1686 { | |
1687 GList *f; | |
1688 GList *d; | |
1689 GList *work; | |
1690 PanItem *pi_box; | |
1691 gint y_height = 0; | |
1692 | |
1693 if (!filelist_read(path, &f, &d)) return; | |
1694 if (!f && !d) return; | |
1695 | |
1696 f = filelist_sort(f, SORT_NAME, TRUE); | |
1697 d = filelist_sort(d, SORT_NAME, TRUE); | |
1698 | |
1699 *x = PAN_THUMB_GAP + ((*level) * (PAN_THUMB_GAP * 2)); | |
1700 | |
1701 pi_box = pan_item_new_text(pw, *x, *y, path, TEXT_ATTR_NONE, | |
1702 PAN_TEXT_COLOR, 255); | |
1703 | |
1704 *y += pi_box->height; | |
1705 | |
1706 pi_box = pan_item_new_box(pw, file_data_new_simple(path), | |
1707 *x, *y, | |
1708 PAN_FOLDER_BOX_BORDER, PAN_FOLDER_BOX_BORDER, | |
1709 PAN_FOLDER_BOX_OUTLINE_THICKNESS, | |
1710 PAN_FOLDER_BOX_COLOR, PAN_FOLDER_BOX_ALPHA, | |
1711 PAN_FOLDER_BOX_OUTLINE_COLOR, PAN_FOLDER_BOX_OUTLINE_ALPHA); | |
1712 | |
1713 *x += PAN_FOLDER_BOX_BORDER; | |
1714 *y += PAN_FOLDER_BOX_BORDER; | |
1715 | |
1716 work = f; | |
1717 while (work) | |
1718 { | |
1719 FileData *fd; | |
1720 PanItem *pi; | |
1721 | |
1722 fd = work->data; | |
1723 work = work->next; | |
1724 | |
1725 if (pw->size > LAYOUT_SIZE_THUMB_LARGE) | |
1726 { | |
1727 pi = pan_item_new_image(pw, fd, *x, *y, 10, 10); | |
1728 *x += pi->width + PAN_THUMB_GAP; | |
1729 if (pi->height > y_height) y_height = pi->height; | |
1730 } | |
1731 else | |
1732 { | |
1733 pi = pan_item_new_thumb(pw, fd, *x, *y); | |
1734 *x += PAN_THUMB_SIZE + PAN_THUMB_GAP; | |
1735 y_height = PAN_THUMB_SIZE; | |
1736 } | |
1737 | |
1738 pan_item_size_by_item(pi_box, pi, PAN_FOLDER_BOX_BORDER); | |
1739 } | |
1740 | |
1741 if (f) *y = pi_box->y + pi_box->height; | |
1742 | |
1743 g_list_free(f); | |
1744 | |
1745 work = d; | |
1746 while (work) | |
1747 { | |
1748 FileData *fd; | |
1749 | |
1750 fd = work->data; | |
1751 work = work->next; | |
1752 | |
1753 *level = *level + 1; | |
1754 pan_window_layout_compute_folders_linear_path(pw, fd->path, x, y, level, | |
1755 pi_box, width, height); | |
1756 *level = *level - 1; | |
1757 } | |
1758 | |
1759 filelist_free(d); | |
1760 | |
1761 pan_item_size_by_item(parent, pi_box, PAN_FOLDER_BOX_BORDER); | |
1762 | |
1763 if (*y < pi_box->y + pi_box->height + PAN_FOLDER_BOX_BORDER) | |
1764 *y = pi_box->y + pi_box->height + PAN_FOLDER_BOX_BORDER; | |
1765 | |
1766 if (*width < pi_box->x + pi_box->width + PAN_FOLDER_BOX_BORDER) | |
1767 *width = pi_box->x + pi_box->width + PAN_FOLDER_BOX_BORDER; | |
1768 if (*height < pi_box->y + pi_box->height + PAN_FOLDER_BOX_BORDER) | |
1769 *height = pi_box->y + pi_box->height + PAN_FOLDER_BOX_BORDER; | |
1770 } | |
1771 | |
1772 static void pan_window_layout_compute_folders_linear(PanWindow *pw, const gchar *path, gint *width, gint *height) | |
1773 { | |
1774 gint x, y; | |
1775 gint level; | |
1776 gint w, h; | |
1777 | |
1778 level = 0; | |
1779 x = PAN_FOLDER_BOX_BORDER; | |
1780 y = PAN_FOLDER_BOX_BORDER; | |
1781 w = PAN_FOLDER_BOX_BORDER * 2; | |
1782 h = PAN_FOLDER_BOX_BORDER * 2; | |
1783 | |
1784 pan_window_layout_compute_folders_linear_path(pw, path, &x, &y, &level, NULL, &w, &h); | |
1785 | |
1786 if (width) *width = w; | |
1787 if (height) *height = h; | |
1788 } | |
1789 | |
1790 static void pan_window_layout_compute_timeline(PanWindow *pw, const gchar *path, gint *width, gint *height) | |
1791 { | |
1792 GList *list; | |
1793 GList *work; | |
1794 gint x, y; | |
1795 gint w, h; | |
1796 time_t tc; | |
1797 gint total; | |
1798 gint count; | |
1799 PanItem *pi_month = NULL; | |
1800 PanItem *pi_day = NULL; | |
1801 gint month_start; | |
1802 gint day_start; | |
1803 gint x_width; | |
1804 gint y_height; | |
1805 | |
1806 pw->cache_list = filelist_sort(pw->cache_list, SORT_TIME, TRUE); | |
1807 | |
1808 list = pan_window_layout_list(path, SORT_NONE, TRUE); | |
1809 list = filelist_sort(list, SORT_TIME, TRUE); | |
1810 | |
1811 w = PAN_FOLDER_BOX_BORDER * 2; | |
1812 h = PAN_FOLDER_BOX_BORDER * 2; | |
1813 | |
1814 x = 0; | |
1815 y = 0; | |
1816 month_start = y; | |
1817 day_start = month_start; | |
1818 x_width = 0; | |
1819 y_height = 0; | |
1820 tc = 0; | |
1821 total = 0; | |
1822 count = 0; | |
1823 work = list; | |
1824 while (work) | |
1825 { | |
1826 FileData *fd; | |
1827 PanItem *pi; | |
1828 | |
1829 fd = work->data; | |
1830 work = work->next; | |
1831 | |
1832 if (!date_compare(fd->date, tc, DATE_LENGTH_DAY)) | |
1833 { | |
1834 GList *needle; | |
1835 gchar *buf; | |
1836 | |
1837 if (!date_compare(fd->date, tc, DATE_LENGTH_MONTH)) | |
1838 { | |
1839 pi_day = NULL; | |
1840 | |
1841 if (pi_month) | |
1842 { | |
1843 x = pi_month->x + pi_month->width + PAN_FOLDER_BOX_BORDER; | |
1844 } | |
1845 else | |
1846 { | |
1847 x = PAN_FOLDER_BOX_BORDER; | |
1848 } | |
1849 | |
1850 y = PAN_FOLDER_BOX_BORDER; | |
1851 | |
1852 buf = date_value_string(fd->date, DATE_LENGTH_MONTH); | |
1853 pi = pan_item_new_text(pw, x, y, buf, | |
1854 TEXT_ATTR_BOLD | TEXT_ATTR_HEADING, | |
1855 PAN_TEXT_COLOR, 255); | |
1856 y += pi->height; | |
1857 | |
1858 pi_month = pan_item_new_box(pw, file_data_new_simple(fd->path), | |
1859 x, y, 0, 0, | |
1860 PAN_FOLDER_BOX_OUTLINE_THICKNESS, | |
1861 PAN_FOLDER_BOX_COLOR, PAN_FOLDER_BOX_ALPHA, | |
1862 PAN_FOLDER_BOX_OUTLINE_COLOR, PAN_FOLDER_BOX_OUTLINE_ALPHA); | |
1863 | |
1864 x += PAN_FOLDER_BOX_BORDER; | |
1865 y += PAN_FOLDER_BOX_BORDER; | |
1866 month_start = y; | |
1867 } | |
1868 | |
1869 if (pi_day) x = pi_day->x + pi_day->width + PAN_FOLDER_BOX_BORDER; | |
1870 | |
1871 tc = fd->date; | |
1872 total = 1; | |
1873 count = 0; | |
1874 | |
1875 needle = work; | |
1876 while (needle) | |
1877 { | |
1878 FileData *nfd; | |
1879 | |
1880 nfd = needle->data; | |
1881 if (date_compare(nfd->date, tc, DATE_LENGTH_DAY)) | |
1882 { | |
1883 needle = needle->next; | |
1884 total++; | |
1885 } | |
1886 else | |
1887 { | |
1888 needle = NULL; | |
1889 } | |
1890 } | |
1891 | |
1892 buf = date_value_string(fd->date, DATE_LENGTH_WEEK); | |
1893 pi = pan_item_new_text(pw, x, y, buf, TEXT_ATTR_NONE, | |
1894 PAN_TEXT_COLOR, 255); | |
1895 g_free(buf); | |
1896 | |
1897 y += pi->height; | |
1898 | |
1899 pi_day = pan_item_new_box(pw, file_data_new_simple(fd->path), x, y, 0, 0, | |
1900 PAN_FOLDER_BOX_OUTLINE_THICKNESS, | |
1901 PAN_FOLDER_BOX_COLOR, PAN_FOLDER_BOX_ALPHA, | |
1902 PAN_FOLDER_BOX_OUTLINE_COLOR, PAN_FOLDER_BOX_OUTLINE_ALPHA); | |
1903 | |
1904 x += PAN_FOLDER_BOX_BORDER; | |
1905 y += PAN_FOLDER_BOX_BORDER; | |
1906 day_start = y; | |
1907 } | |
1908 | |
1909 if (pw->size > LAYOUT_SIZE_THUMB_LARGE) | |
1910 { | |
1911 pi = pan_item_new_image(pw, fd, x, y, 10, 10); | |
1912 if (pi->width > x_width) x_width = pi->width; | |
1913 y_height = pi->height; | |
1914 } | |
1915 else | |
1916 { | |
1917 pi = pan_item_new_thumb(pw, fd, x, y); | |
1918 x_width = PAN_THUMB_SIZE; | |
1919 y_height = PAN_THUMB_SIZE; | |
1920 } | |
1921 | |
1922 pan_item_size_by_item(pi_day, pi, PAN_FOLDER_BOX_BORDER); | |
1923 pan_item_size_by_item(pi_month, pi_day, PAN_FOLDER_BOX_BORDER); | |
1924 #if 0 | |
1925 if (pi_day) | |
1926 { | |
1927 if (pi->x + pi->width + PAN_FOLDER_BOX_BORDER > pi_day->x + pi_day->width) | |
1928 pi_day->width = pi->x + pi->width + PAN_FOLDER_BOX_BORDER - pi_day->x; | |
1929 if (pi->y + pi->height + PAN_FOLDER_BOX_BORDER > pi_day->y + pi_day->height) | |
1930 pi_day->height = pi->y + pi->height + PAN_FOLDER_BOX_BORDER - pi_day->y; | |
1931 } | |
1932 | |
1933 if (pi_month && pi_day) | |
1934 { | |
1935 if (pi_day->x + pi_day->width + PAN_FOLDER_BOX_BORDER > pi_month->x + pi_month->width) | |
1936 pi_month->width = pi_day->x + pi_day->width + PAN_FOLDER_BOX_BORDER - pi_month->x; | |
1937 if (pi_day->y + pi_day->height + PAN_FOLDER_BOX_BORDER > pi_month->y + pi_month->height) | |
1938 pi_month->height = pi_day->y + pi_day->height + PAN_FOLDER_BOX_BORDER - pi_month->y; | |
1939 } | |
1940 #endif | |
1941 | |
1942 total--; | |
1943 count++; | |
1944 | |
1945 if (total > 0 && count < PAN_GROUP_MAX) | |
1946 { | |
1947 y += y_height + PAN_THUMB_GAP; | |
1948 } | |
1949 else | |
1950 { | |
1951 x += x_width + PAN_THUMB_GAP; | |
1952 x_width = 0; | |
1953 count = 0; | |
1954 | |
1955 if (total > 0) | |
1956 y = day_start; | |
1957 else | |
1958 y = month_start; | |
1959 } | |
1960 | |
1961 if (w < pi->x + pi->width + PAN_THUMB_GAP) w = pi->x + pi->width + PAN_THUMB_GAP; | |
1962 if (h < pi->y + pi->height + PAN_THUMB_GAP) h = pi->y + pi->height + PAN_THUMB_GAP; | |
1963 } | |
1964 | |
1965 w += PAN_FOLDER_BOX_BORDER; | |
1966 h += PAN_FOLDER_BOX_BORDER; | |
1967 | |
1968 if (width) *width = w; | |
1969 if (height) *height = h; | |
1970 | |
1971 g_list_free(list); | |
1972 } | |
1973 | |
1974 static void pan_window_layout_compute(PanWindow *pw, const gchar *path, | |
1975 gint *width, gint *height, | |
1976 gint *scroll_x, gint *scroll_y) | |
1977 { | |
1978 pan_window_items_free(pw); | |
1979 | |
1980 switch (pw->size) | |
1981 { | |
1982 case LAYOUT_SIZE_THUMB_NONE: | |
1983 pw->thumb_size = PAN_THUMB_SIZE_NONE; | |
1984 pw->thumb_gap = PAN_THUMB_GAP_SMALL; | |
1985 break; | |
1986 case LAYOUT_SIZE_THUMB_SMALL: | |
1987 pw->thumb_size = PAN_THUMB_SIZE_SMALL; | |
1988 pw->thumb_gap = PAN_THUMB_GAP_SMALL; | |
1989 break; | |
1990 case LAYOUT_SIZE_THUMB_NORMAL: | |
1991 default: | |
1992 pw->thumb_size = PAN_THUMB_SIZE_NORMAL; | |
1993 pw->thumb_gap = PAN_THUMB_GAP_NORMAL; | |
1994 break; | |
1995 case LAYOUT_SIZE_THUMB_LARGE: | |
1996 pw->thumb_size = PAN_THUMB_SIZE_LARGE; | |
1997 pw->thumb_gap = PAN_THUMB_GAP_LARGE; | |
1998 break; | |
1999 case LAYOUT_SIZE_10: | |
2000 pw->image_size = 10; | |
2001 pw->thumb_gap = PAN_THUMB_GAP_NORMAL; | |
2002 break; | |
2003 case LAYOUT_SIZE_25: | |
2004 pw->image_size = 25; | |
2005 pw->thumb_gap = PAN_THUMB_GAP_NORMAL; | |
2006 break; | |
2007 case LAYOUT_SIZE_33: | |
2008 pw->image_size = 33; | |
2009 pw->thumb_gap = PAN_THUMB_GAP_LARGE; | |
2010 break; | |
2011 case LAYOUT_SIZE_50: | |
2012 pw->image_size = 50; | |
2013 pw->thumb_gap = PAN_THUMB_GAP_HUGE; | |
2014 break; | |
2015 case LAYOUT_SIZE_100: | |
2016 pw->image_size = 100; | |
2017 pw->thumb_gap = PAN_THUMB_GAP_HUGE; | |
2018 break; | |
2019 } | |
2020 | |
2021 *width = 0; | |
2022 *height = 0; | |
2023 *scroll_x = 0; | |
2024 *scroll_y = 0; | |
2025 | |
2026 switch (pw->layout) | |
2027 { | |
2028 case LAYOUT_GRID: | |
2029 default: | |
2030 pan_window_layout_compute_grid(pw, path, width, height); | |
2031 break; | |
2032 case LAYOUT_FOLDERS_LINEAR: | |
2033 pan_window_layout_compute_folders_linear(pw, path, width, height); | |
2034 break; | |
2035 case LAYOUT_FOLDERS_FLOWER: | |
2036 pan_window_layout_compute_folders_flower(pw, path, width, height, scroll_x, scroll_y); | |
2037 break; | |
2038 case LAYOUT_TIMELINE: | |
2039 pan_window_layout_compute_timeline(pw, path, width, height); | |
2040 break; | |
2041 } | |
2042 | |
2043 pan_cache_free(pw); | |
2044 | |
2045 printf("computed %d objects\n", g_list_length(pw->list)); | |
2046 } | |
2047 | |
2048 static GList *pan_layout_intersect(PanWindow *pw, gint x, gint y, gint width, gint height) | |
2049 { | |
2050 GList *list = NULL; | |
2051 GList *work; | |
2052 | |
2053 work = pw->list; | |
2054 while (work) | |
2055 { | |
2056 PanItem *pi; | |
2057 | |
2058 pi = work->data; | |
2059 work = work->next; | |
2060 | |
2061 if (util_clip_region_test(x, y, width, height, | |
2062 pi->x, pi->y, pi->width, pi->height)) | |
2063 { | |
2064 list = g_list_prepend(list, pi); | |
2065 } | |
2066 } | |
2067 | |
2068 return list; | |
2069 } | |
2070 | |
2071 | |
2072 | |
2073 /* | |
2074 *----------------------------------------------------------------------------- | |
2075 * tile generation | |
2076 *----------------------------------------------------------------------------- | |
2077 */ | |
2078 | |
2079 static gint pan_layout_queue_step(PanWindow *pw); | |
2080 | |
2081 | |
2082 static void pan_layout_queue_thumb_done_cb(ThumbLoader *tl, gpointer data) | |
2083 { | |
2084 PanWindow *pw = data; | |
2085 | |
2086 if (pw->queue_pi) | |
2087 { | |
2088 PanItem *pi; | |
2089 gint rc; | |
2090 | |
2091 pi = pw->queue_pi; | |
2092 pw->queue_pi = NULL; | |
2093 | |
2094 pi->queued = FALSE; | |
2095 | |
2096 if (pi->pixbuf) g_object_unref(pi->pixbuf); | |
2097 pi->pixbuf = thumb_loader_get_pixbuf(tl, TRUE); | |
2098 | |
2099 rc = pi->refcount; | |
2100 image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height); | |
2101 pi->refcount = rc; | |
2102 } | |
2103 | |
2104 thumb_loader_free(pw->tl); | |
2105 pw->tl = NULL; | |
2106 | |
2107 while (pan_layout_queue_step(pw)); | |
2108 } | |
2109 | |
2110 static void pan_layout_queue_image_done_cb(ImageLoader *il, gpointer data) | |
2111 { | |
2112 PanWindow *pw = data; | |
2113 | |
2114 if (pw->queue_pi) | |
2115 { | |
2116 PanItem *pi; | |
2117 gint rc; | |
2118 | |
2119 pi = pw->queue_pi; | |
2120 pw->queue_pi = NULL; | |
2121 | |
2122 pi->queued = FALSE; | |
2123 | |
2124 if (pi->pixbuf) g_object_unref(pi->pixbuf); | |
2125 pi->pixbuf = image_loader_get_pixbuf(pw->il); | |
2126 if (pi->pixbuf) g_object_ref(pi->pixbuf); | |
2127 | |
2128 if (pi->pixbuf && pw->size != LAYOUT_SIZE_100 && | |
2129 (gdk_pixbuf_get_width(pi->pixbuf) > pi->width || | |
2130 gdk_pixbuf_get_height(pi->pixbuf) > pi->height)) | |
2131 { | |
2132 GdkPixbuf *tmp; | |
2133 | |
2134 tmp = pi->pixbuf; | |
2135 pi->pixbuf = gdk_pixbuf_scale_simple(tmp, pi->width, pi->height, | |
2136 (GdkInterpType)zoom_quality); | |
2137 g_object_unref(tmp); | |
2138 } | |
2139 | |
2140 rc = pi->refcount; | |
2141 image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height); | |
2142 pi->refcount = rc; | |
2143 } | |
2144 | |
2145 image_loader_free(pw->il); | |
2146 pw->il = NULL; | |
2147 | |
2148 while (pan_layout_queue_step(pw)); | |
2149 } | |
2150 | |
2151 #if 0 | |
2152 static void pan_layout_queue_image_area_cb(ImageLoader *il, guint x, guint y, | |
2153 guint width, guint height, gpointer data) | |
2154 { | |
2155 PanWindow *pw = data; | |
2156 | |
2157 if (pw->queue_pi) | |
2158 { | |
2159 PanItem *pi; | |
2160 gint rc; | |
2161 | |
2162 pi = pw->queue_pi; | |
2163 | |
2164 if (!pi->pixbuf) | |
2165 { | |
2166 pi->pixbuf = image_loader_get_pixbuf(pw->il); | |
2167 if (pi->pixbuf) g_object_ref(pi->pixbuf); | |
2168 } | |
2169 | |
2170 rc = pi->refcount; | |
2171 image_area_changed(pw->imd, pi->x + x, pi->y + y, width, height); | |
2172 pi->refcount = rc; | |
2173 } | |
2174 } | |
2175 #endif | |
2176 | |
2177 static gint pan_layout_queue_step(PanWindow *pw) | |
2178 { | |
2179 PanItem *pi; | |
2180 | |
2181 if (!pw->queue) return FALSE; | |
2182 | |
2183 pi = pw->queue->data; | |
2184 pw->queue = g_list_remove(pw->queue, pi); | |
2185 pw->queue_pi = pi; | |
2186 | |
2187 image_loader_free(pw->il); | |
2188 pw->il = NULL; | |
2189 thumb_loader_free(pw->tl); | |
2190 pw->tl = NULL; | |
2191 | |
2192 if (pi->type == ITEM_IMAGE) | |
2193 { | |
2194 pw->il = image_loader_new(pi->fd->path); | |
2195 | |
2196 if (pw->size != LAYOUT_SIZE_100) | |
2197 { | |
2198 image_loader_set_requested_size(pw->il, pi->width, pi->height); | |
2199 } | |
2200 | |
2201 #if 0 | |
2202 image_loader_set_area_ready_func(pw->il, pan_layout_queue_image_area_cb, pw); | |
2203 #endif | |
2204 image_loader_set_error_func(pw->il, pan_layout_queue_image_done_cb, pw); | |
2205 | |
2206 if (image_loader_start(pw->il, pan_layout_queue_image_done_cb, pw)) return FALSE; | |
2207 | |
2208 image_loader_free(pw->il); | |
2209 pw->il = NULL; | |
2210 } | |
2211 else if (pi->type == ITEM_THUMB) | |
2212 { | |
2213 pw->tl = thumb_loader_new(PAN_THUMB_SIZE, PAN_THUMB_SIZE); | |
2214 | |
2215 if (!pw->tl->standard_loader) | |
2216 { | |
2217 /* The classic loader will recreate a thumbnail any time we | |
2218 * request a different size than what exists. This view will | |
2219 * almost never use the user configured sizes so disable cache. | |
2220 */ | |
2221 thumb_loader_set_cache(pw->tl, FALSE, FALSE, FALSE); | |
2222 } | |
2223 | |
2224 thumb_loader_set_callbacks(pw->tl, | |
2225 pan_layout_queue_thumb_done_cb, | |
2226 pan_layout_queue_thumb_done_cb, | |
2227 NULL, pw); | |
2228 | |
2229 if (thumb_loader_start(pw->tl, pi->fd->path)) return FALSE; | |
2230 | |
2231 thumb_loader_free(pw->tl); | |
2232 pw->tl = NULL; | |
2233 } | |
2234 | |
2235 pw->queue_pi->queued = FALSE; | |
2236 pw->queue_pi = NULL; | |
2237 return TRUE; | |
2238 } | |
2239 | |
2240 static void pan_layout_queue(PanWindow *pw, PanItem *pi) | |
2241 { | |
2242 if (!pi || pi->queued || pi->pixbuf) return; | |
2243 if (pw->size == LAYOUT_SIZE_THUMB_NONE) return; | |
2244 | |
2245 pi->queued = TRUE; | |
2246 pw->queue = g_list_prepend(pw->queue, pi); | |
2247 | |
2248 if (!pw->tl && !pw->il) while(pan_layout_queue_step(pw)); | |
2249 } | |
2250 | |
2251 static gint pan_window_request_tile_cb(ImageWindow *imd, gint x, gint y, gint width, gint height, | |
2252 GdkPixbuf *pixbuf, gpointer data) | |
2253 { | |
2254 PanWindow *pw = data; | |
2255 GList *list; | |
2256 GList *work; | |
2257 gint i; | |
2258 | |
2259 pixbuf_draw_rect_fill(pixbuf, | |
2260 0, 0, width, height, | |
2261 PAN_BACKGROUND_COLOR, 255); | |
2262 | |
2263 for (i = (x / PAN_GRID_SIZE) * PAN_GRID_SIZE; i < x + width; i += PAN_GRID_SIZE) | |
2264 { | |
2265 gint rx, ry, rw, rh; | |
2266 | |
2267 if (util_clip_region(x, y, width, height, | |
2268 i, y, 1, height, | |
2269 &rx, &ry, &rw, &rh)) | |
2270 { | |
2271 pixbuf_draw_rect_fill(pixbuf, | |
2272 rx - x, ry - y, rw, rh, | |
2273 PAN_GRID_COLOR, PAN_GRID_ALPHA); | |
2274 } | |
2275 } | |
2276 for (i = (y / PAN_GRID_SIZE) * PAN_GRID_SIZE; i < y + height; i += PAN_GRID_SIZE) | |
2277 { | |
2278 gint rx, ry, rw, rh; | |
2279 | |
2280 if (util_clip_region(x, y, width, height, | |
2281 x, i, width, 1, | |
2282 &rx, &ry, &rw, &rh)) | |
2283 { | |
2284 pixbuf_draw_rect_fill(pixbuf, | |
2285 rx - x, ry - y, rw, rh, | |
2286 PAN_GRID_COLOR, PAN_GRID_ALPHA); | |
2287 } | |
2288 } | |
2289 | |
2290 list = pan_layout_intersect(pw, x, y, width, height); | |
2291 work = list; | |
2292 while (work) | |
2293 { | |
2294 PanItem *pi; | |
2295 gint tx, ty, tw, th; | |
2296 gint rx, ry, rw, rh; | |
2297 | |
2298 pi = work->data; | |
2299 work = work->next; | |
2300 | |
2301 pi->refcount++; | |
2302 | |
2303 if (pi->type == ITEM_THUMB && pi->pixbuf) | |
2304 { | |
2305 tw = gdk_pixbuf_get_width(pi->pixbuf); | |
2306 th = gdk_pixbuf_get_height(pi->pixbuf); | |
2307 | |
2308 tx = pi->x + (pi->width - tw) / 2; | |
2309 ty = pi->y + (pi->height - th) / 2; | |
2310 | |
2311 if (gdk_pixbuf_get_has_alpha(pi->pixbuf)) | |
2312 { | |
2313 if (util_clip_region(x, y, width, height, | |
2314 tx + PAN_SHADOW_OFFSET, ty + PAN_SHADOW_OFFSET, tw, th, | |
2315 &rx, &ry, &rw, &rh)) | |
2316 { | |
2317 pixbuf_draw_shadow(pixbuf, | |
2318 rx - x, ry - y, rw, rh, | |
2319 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th, | |
2320 PAN_SHADOW_FADE, | |
2321 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA); | |
2322 } | |
2323 } | |
2324 else | |
2325 { | |
2326 if (util_clip_region(x, y, width, height, | |
2327 tx + tw, ty + PAN_SHADOW_OFFSET, | |
2328 PAN_SHADOW_OFFSET, th - PAN_SHADOW_OFFSET, | |
2329 &rx, &ry, &rw, &rh)) | |
2330 { | |
2331 pixbuf_draw_shadow(pixbuf, | |
2332 rx - x, ry - y, rw, rh, | |
2333 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th, | |
2334 PAN_SHADOW_FADE, | |
2335 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA); | |
2336 } | |
2337 if (util_clip_region(x, y, width, height, | |
2338 tx + PAN_SHADOW_OFFSET, ty + th, tw, PAN_SHADOW_OFFSET, | |
2339 &rx, &ry, &rw, &rh)) | |
2340 { | |
2341 pixbuf_draw_shadow(pixbuf, | |
2342 rx - x, ry - y, rw, rh, | |
2343 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th, | |
2344 PAN_SHADOW_FADE, | |
2345 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA); | |
2346 } | |
2347 } | |
2348 | |
2349 if (util_clip_region(x, y, width, height, | |
2350 tx, ty, tw, th, | |
2351 &rx, &ry, &rw, &rh)) | |
2352 { | |
2353 gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh, | |
2354 (double) tx - x, | |
2355 (double) ty - y, | |
2356 1.0, 1.0, GDK_INTERP_NEAREST, | |
2357 255); | |
2358 } | |
2359 | |
2360 if (util_clip_region(x, y, width, height, | |
2361 tx, ty, tw, PAN_OUTLINE_THICKNESS, | |
2362 &rx, &ry, &rw, &rh)) | |
2363 { | |
2364 pixbuf_draw_rect_fill(pixbuf, | |
2365 rx - x, ry - y, rw, rh, | |
2366 PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA); | |
2367 } | |
2368 if (util_clip_region(x, y, width, height, | |
2369 tx, ty, PAN_OUTLINE_THICKNESS, th, | |
2370 &rx, &ry, &rw, &rh)) | |
2371 { | |
2372 pixbuf_draw_rect_fill(pixbuf, | |
2373 rx - x, ry - y, rw, rh, | |
2374 PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA); | |
2375 } | |
2376 if (util_clip_region(x, y, width, height, | |
2377 tx + tw - PAN_OUTLINE_THICKNESS, ty + PAN_OUTLINE_THICKNESS, | |
2378 PAN_OUTLINE_THICKNESS, th - PAN_OUTLINE_THICKNESS, | |
2379 &rx, &ry, &rw, &rh)) | |
2380 { | |
2381 pixbuf_draw_rect_fill(pixbuf, | |
2382 rx - x, ry - y, rw, rh, | |
2383 PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA); | |
2384 } | |
2385 if (util_clip_region(x, y, width, height, | |
2386 tx + PAN_OUTLINE_THICKNESS, ty + th - PAN_OUTLINE_THICKNESS, | |
2387 tw - PAN_OUTLINE_THICKNESS * 2, PAN_OUTLINE_THICKNESS, | |
2388 &rx, &ry, &rw, &rh)) | |
2389 { | |
2390 pixbuf_draw_rect_fill(pixbuf, | |
2391 rx - x, ry - y, rw, rh, | |
2392 PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA); | |
2393 } | |
2394 } | |
2395 else if (pi->type == ITEM_THUMB) | |
2396 { | |
2397 tw = pi->width - PAN_SHADOW_OFFSET * 2; | |
2398 th = pi->height - PAN_SHADOW_OFFSET * 2; | |
2399 tx = pi->x + PAN_SHADOW_OFFSET; | |
2400 ty = pi->y + PAN_SHADOW_OFFSET; | |
2401 | |
2402 if (util_clip_region(x, y, width, height, | |
2403 tx, ty, tw, th, | |
2404 &rx, &ry, &rw, &rh)) | |
2405 { | |
2406 gint d; | |
2407 | |
2408 d = (pw->size == LAYOUT_SIZE_THUMB_NONE) ? 2 : 8; | |
2409 pixbuf_draw_rect_fill(pixbuf, | |
2410 rx - x, ry - y, rw, rh, | |
2411 PAN_SHADOW_COLOR, | |
2412 PAN_SHADOW_ALPHA / d); | |
2413 } | |
2414 | |
2415 pan_layout_queue(pw, pi); | |
2416 } | |
2417 else if (pi->type == ITEM_IMAGE) | |
2418 { | |
2419 if (util_clip_region(x, y, width, height, | |
2420 pi->x, pi->y, pi->width, pi->height, | |
2421 &rx, &ry, &rw, &rh)) | |
2422 { | |
2423 if (pi->pixbuf) | |
2424 { | |
2425 gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh, | |
2426 (double) pi->x - x, | |
2427 (double) pi->y - y, | |
2428 1.0, 1.0, GDK_INTERP_NEAREST, | |
2429 255); | |
2430 } | |
2431 else | |
2432 { | |
2433 pixbuf_draw_rect_fill(pixbuf, | |
2434 rx - x, ry - y, rw, rh, | |
2435 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA / 2); | |
2436 pan_layout_queue(pw, pi); | |
2437 } | |
2438 } | |
2439 } | |
2440 else if (pi->type == ITEM_BOX) | |
2441 { | |
2442 gint bw, bh; | |
2443 gint *shadow; | |
2444 | |
2445 bw = pi->width; | |
2446 bh = pi->height; | |
2447 | |
2448 shadow = pi->data; | |
2449 if (shadow) | |
2450 { | |
2451 bw -= shadow[0]; | |
2452 bh -= shadow[0]; | |
2453 | |
2454 if (pi->color_a > 254) | |
2455 { | |
2456 pixbuf_draw_shadow(pixbuf, pi->x - x + bw, pi->y - y + shadow[0], | |
2457 shadow[0], bh - shadow[0], | |
2458 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh, | |
2459 shadow[1], | |
2460 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA); | |
2461 pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + bh, | |
2462 bw, shadow[0], | |
2463 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh, | |
2464 shadow[1], | |
2465 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA); | |
2466 } | |
2467 else | |
2468 { | |
2469 gint a; | |
2470 a = pi->color_a * PAN_SHADOW_ALPHA >> 8; | |
2471 pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + shadow[0], | |
2472 bw, bh, | |
2473 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh, | |
2474 shadow[1], | |
2475 PAN_SHADOW_COLOR, a); | |
2476 } | |
2477 } | |
2478 | |
2479 if (util_clip_region(x, y, width, height, | |
2480 pi->x, pi->y, bw, bh, | |
2481 &rx, &ry, &rw, &rh)) | |
2482 { | |
2483 pixbuf_draw_rect_fill(pixbuf, | |
2484 rx - x, ry - y, rw, rh, | |
2485 pi->color_r, pi->color_g, pi->color_b, pi->color_a); | |
2486 } | |
2487 if (util_clip_region(x, y, width, height, | |
2488 pi->x, pi->y, bw, pi->border, | |
2489 &rx, &ry, &rw, &rh)) | |
2490 { | |
2491 pixbuf_draw_rect_fill(pixbuf, | |
2492 rx - x, ry - y, rw, rh, | |
2493 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a); | |
2494 } | |
2495 if (util_clip_region(x, y, width, height, | |
2496 pi->x, pi->y + pi->border, pi->border, bh - pi->border * 2, | |
2497 &rx, &ry, &rw, &rh)) | |
2498 { | |
2499 pixbuf_draw_rect_fill(pixbuf, | |
2500 rx - x, ry - y, rw, rh, | |
2501 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a); | |
2502 } | |
2503 if (util_clip_region(x, y, width, height, | |
2504 pi->x + bw - pi->border, pi->y + pi->border, | |
2505 pi->border, bh - pi->border * 2, | |
2506 &rx, &ry, &rw, &rh)) | |
2507 { | |
2508 pixbuf_draw_rect_fill(pixbuf, | |
2509 rx - x, ry - y, rw, rh, | |
2510 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a); | |
2511 } | |
2512 if (util_clip_region(x, y, width, height, | |
2513 pi->x, pi->y + bh - pi->border, | |
2514 bw, pi->border, | |
2515 &rx, &ry, &rw, &rh)) | |
2516 { | |
2517 pixbuf_draw_rect_fill(pixbuf, | |
2518 rx - x, ry - y, rw, rh, | |
2519 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a); | |
2520 } | |
2521 } | |
2522 else if (pi->type == ITEM_TRIANGLE) | |
2523 { | |
2524 if (util_clip_region(x, y, width, height, | |
2525 pi->x, pi->y, pi->width, pi->height, | |
2526 &rx, &ry, &rw, &rh) && pi->data) | |
2527 { | |
2528 gint *coord = pi->data; | |
2529 pixbuf_draw_triangle(pixbuf, | |
2530 rx - x, ry - y, rw, rh, | |
2531 coord[0] - x, coord[1] - y, | |
2532 coord[2] - x, coord[3] - y, | |
2533 coord[4] - x, coord[5] - y, | |
2534 pi->color_r, pi->color_g, pi->color_b, pi->color_a); | |
2535 | |
2536 if (pi->border & BORDER_1) | |
2537 { | |
2538 pixbuf_draw_line(pixbuf, | |
2539 rx - x, ry - y, rw, rh, | |
2540 coord[0] - x, coord[1] - y, | |
2541 coord[2] - x, coord[3] - y, | |
2542 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a); | |
2543 } | |
2544 if (pi->border & BORDER_2) | |
2545 { | |
2546 pixbuf_draw_line(pixbuf, | |
2547 rx - x, ry - y, rw, rh, | |
2548 coord[2] - x, coord[3] - y, | |
2549 coord[4] - x, coord[5] - y, | |
2550 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a); | |
2551 } | |
2552 if (pi->border & BORDER_3) | |
2553 { | |
2554 pixbuf_draw_line(pixbuf, | |
2555 rx - x, ry - y, rw, rh, | |
2556 coord[4] - x, coord[5] - y, | |
2557 coord[0] - x, coord[1] - y, | |
2558 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a); | |
2559 } | |
2560 } | |
2561 } | |
2562 else if (pi->type == ITEM_TEXT && pi->text) | |
2563 { | |
2564 PangoLayout *layout; | |
2565 | |
2566 layout = pan_item_text_layout(pi, imd->image); | |
2567 pixbuf_draw_layout(pixbuf, layout, imd->image, | |
2568 pi->x - x + PAN_TEXT_BORDER_SIZE, pi->y - y + PAN_TEXT_BORDER_SIZE, | |
2569 pi->color_r, pi->color_g, pi->color_b, pi->color_a); | |
2570 g_object_unref(G_OBJECT(layout)); | |
2571 } | |
2572 } | |
2573 g_list_free(list); | |
2574 | |
2575 if (0) | |
2576 { | |
2577 static gint count = 0; | |
2578 PangoLayout *layout; | |
2579 gint lx, ly; | |
2580 gint lw, lh; | |
2581 GdkPixmap *pixmap; | |
2582 gchar *buf; | |
2583 | |
2584 layout = gtk_widget_create_pango_layout(imd->image, NULL); | |
2585 | |
2586 buf = g_strdup_printf("%d,%d\n(#%d)", x, y, | |
2587 (x / imd->source_tile_width) + | |
2588 (y / imd->source_tile_height * (imd->image_width/imd->source_tile_width + 1))); | |
2589 pango_layout_set_text(layout, buf, -1); | |
2590 g_free(buf); | |
2591 | |
2592 pango_layout_get_pixel_size(layout, &lw, &lh); | |
2593 | |
2594 pixmap = gdk_pixmap_new(imd->widget->window, lw, lh, -1); | |
2595 gdk_draw_rectangle(pixmap, imd->widget->style->black_gc, TRUE, 0, 0, lw, lh); | |
2596 gdk_draw_layout(pixmap, imd->widget->style->white_gc, 0, 0, layout); | |
2597 g_object_unref(G_OBJECT(layout)); | |
2598 | |
2599 lx = MAX(0, width / 2 - lw / 2); | |
2600 ly = MAX(0, height / 2 - lh / 2); | |
2601 lw = MIN(lw, width - lx); | |
2602 lh = MIN(lh, height - ly); | |
2603 gdk_pixbuf_get_from_drawable(pixbuf, pixmap, gdk_drawable_get_colormap(imd->image->window), | |
2604 0, 0, lx, ly, lw, lh); | |
2605 g_object_unref(pixmap); | |
2606 | |
2607 count++; | |
2608 } | |
2609 | |
2610 return TRUE; | |
2611 } | |
2612 | |
2613 static void pan_window_dispose_tile_cb(ImageWindow *imd, gint x, gint y, gint width, gint height, | |
2614 GdkPixbuf *pixbuf, gpointer data) | |
2615 { | |
2616 PanWindow *pw = data; | |
2617 GList *list; | |
2618 GList *work; | |
2619 | |
2620 list = pan_layout_intersect(pw, x, y, width, height); | |
2621 work = list; | |
2622 while (work) | |
2623 { | |
2624 PanItem *pi; | |
2625 | |
2626 pi = work->data; | |
2627 work = work->next; | |
2628 | |
2629 if (pi->refcount > 0) | |
2630 { | |
2631 pi->refcount--; | |
2632 | |
2633 if ((pi->type == ITEM_THUMB || pi->type == ITEM_IMAGE) && | |
2634 pi->refcount == 0) | |
2635 { | |
2636 if (pi->queued) | |
2637 { | |
2638 pw->queue = g_list_remove(pw->queue, pi); | |
2639 pi->queued = FALSE; | |
2640 } | |
2641 if (pw->queue_pi == pi) pw->queue_pi = NULL; | |
2642 if (pi->pixbuf) | |
2643 { | |
2644 g_object_unref(pi->pixbuf); | |
2645 pi->pixbuf = NULL; | |
2646 } | |
2647 } | |
2648 } | |
2649 } | |
2650 | |
2651 g_list_free(list); | |
2652 } | |
2653 | |
2654 | |
2655 /* | |
2656 *----------------------------------------------------------------------------- | |
2657 * misc | |
2658 *----------------------------------------------------------------------------- | |
2659 */ | |
2660 | |
2661 static void pan_window_message(PanWindow *pw, const gchar *text) | |
2662 { | |
2663 GList *work; | |
2664 gint count = 0; | |
2665 gint64 size = 0; | |
2666 gchar *ss; | |
2667 gchar *buf; | |
2668 | |
2669 if (text) | |
2670 { | |
2671 gtk_label_set_text(GTK_LABEL(pw->label_message), text); | |
2672 return; | |
2673 } | |
2674 | |
2675 work = pw->list; | |
2676 while (work) | |
2677 { | |
2678 PanItem *pi; | |
2679 | |
2680 pi = work->data; | |
2681 work = work->next; | |
2682 | |
2683 if (pi->fd && | |
2684 (pi->type == ITEM_THUMB || pi->type == ITEM_IMAGE)) | |
2685 { | |
2686 size += pi->fd->size; | |
2687 count++; | |
2688 } | |
2689 } | |
2690 | |
2691 ss = text_from_size_abrev(size); | |
2692 buf = g_strdup_printf(_("%d images, %s"), count, ss); | |
2693 g_free(ss); | |
2694 gtk_label_set_text(GTK_LABEL(pw->label_message), buf); | |
2695 g_free(buf); | |
2696 } | |
2697 | |
2698 static ImageWindow *pan_window_active_image(PanWindow *pw) | |
2699 { | |
2700 if (pw->fs) return pw->fs->imd; | |
2701 | |
2702 return pw->imd; | |
2703 } | |
2704 | |
2705 static void pan_window_zoom_limit(PanWindow *pw) | |
2706 { | |
2707 gdouble min; | |
2708 | |
2709 switch (pw->size) | |
2710 { | |
2711 case LAYOUT_SIZE_THUMB_NONE: | |
2712 case LAYOUT_SIZE_THUMB_SMALL: | |
2713 case LAYOUT_SIZE_THUMB_NORMAL: | |
2714 #if 0 | |
2715 /* easily requires > 512mb ram when window size > 1024x768 and zoom is <= -8 */ | |
2716 min = -16.0; | |
2717 break; | |
2718 #endif | |
2719 case LAYOUT_SIZE_THUMB_LARGE: | |
2720 min = -6.0; | |
2721 break; | |
2722 case LAYOUT_SIZE_10: | |
2723 case LAYOUT_SIZE_25: | |
2724 min = -4.0; | |
2725 break; | |
2726 case LAYOUT_SIZE_33: | |
2727 case LAYOUT_SIZE_50: | |
2728 case LAYOUT_SIZE_100: | |
2729 default: | |
2730 min = -2.0; | |
2731 break; | |
2732 } | |
2733 | |
2734 image_zoom_set_limits(pw->imd, min, 32.0); | |
2735 } | |
2736 | |
2737 static gint pan_window_layout_update_idle_cb(gpointer data) | |
2738 { | |
2739 PanWindow *pw = data; | |
2740 gint width; | |
2741 gint height; | |
2742 gint scroll_x; | |
2743 gint scroll_y; | |
2744 | |
2745 if (pw->size > LAYOUT_SIZE_THUMB_LARGE) | |
2746 { | |
2747 if (!pw->cache_list && !pw->cache_todo) | |
2748 { | |
2749 pan_cache_fill(pw, pw->path); | |
2750 if (pw->cache_todo) | |
2751 { | |
2752 pan_window_message(pw, _("Reading dimensions...")); | |
2753 return TRUE; | |
2754 } | |
2755 } | |
2756 if (pan_cache_step(pw)) | |
2757 { | |
2758 pw->cache_count++; | |
2759 pw->cache_tick++; | |
2760 if (pw->cache_count == pw->cache_total) | |
2761 { | |
2762 pan_window_message(pw, _("Sorting images...")); | |
2763 } | |
2764 else if (pw->cache_tick > 9) | |
2765 { | |
2766 gchar *buf; | |
2767 | |
2768 buf = g_strdup_printf("%s %d", _("Reading dimensions..."), | |
2769 pw->cache_total - pw->cache_count); | |
2770 pan_window_message(pw, buf); | |
2771 g_free(buf); | |
2772 | |
2773 pw->cache_tick = 0; | |
2774 } | |
2775 | |
2776 return TRUE; | |
2777 } | |
2778 } | |
2779 | |
2780 pan_window_layout_compute(pw, pw->path, &width, &height, &scroll_x, &scroll_y); | |
2781 | |
2782 pan_window_zoom_limit(pw); | |
2783 | |
2784 if (width > 0 && height > 0) | |
2785 { | |
2786 image_set_image_as_tiles(pw->imd, width, height, | |
2787 PAN_TILE_SIZE, PAN_TILE_SIZE, 8, | |
2788 pan_window_request_tile_cb, | |
2789 pan_window_dispose_tile_cb, pw, 1.0); | |
2790 image_scroll_to_point(pw->imd, scroll_x, scroll_y); | |
2791 } | |
2792 | |
2793 pan_window_message(pw, NULL); | |
2794 | |
2795 pw->idle_id = -1; | |
2796 | |
2797 return FALSE; | |
2798 } | |
2799 | |
2800 static void pan_window_layout_update_idle(PanWindow *pw) | |
2801 { | |
2802 if (pw->idle_id == -1) | |
2803 { | |
2804 pan_window_message(pw, _("Sorting images...")); | |
2805 pw->idle_id = g_idle_add(pan_window_layout_update_idle_cb, pw); | |
2806 } | |
2807 } | |
2808 | |
2809 /* | |
2810 *----------------------------------------------------------------------------- | |
2811 * pan window keyboard | |
2812 *----------------------------------------------------------------------------- | |
2813 */ | |
2814 | |
2815 static const gchar *pan_menu_click_path(PanWindow *pw) | |
2816 { | |
2817 if (pw->click_pi && pw->click_pi->fd) return pw->click_pi->fd->path; | |
2818 return NULL; | |
2819 } | |
2820 | |
2821 static void pan_window_menu_pos_cb(GtkMenu *menu, gint *x, gint *y, gboolean *push_in, gpointer data) | |
2822 { | |
2823 PanWindow *pw = data; | |
2824 ImageWindow *imd; | |
2825 | |
2826 imd = pan_window_active_image(pw); | |
2827 gdk_window_get_origin(imd->image->window, x, y); | |
2828 popup_menu_position_clamp(menu, x, y, 0); | |
2829 } | |
2830 | |
2831 static gint pan_window_key_press_cb(GtkWidget *widget, GdkEventKey *event, gpointer data) | |
2832 { | |
2833 PanWindow *pw = data; | |
2834 ImageWindow *imd; | |
2835 const gchar *path; | |
2836 gint stop_signal = FALSE; | |
2837 GtkWidget *menu; | |
2838 gint x = 0; | |
2839 gint y = 0; | |
2840 gint focused; | |
2841 | |
2842 focused = (pw->fs || GTK_WIDGET_HAS_FOCUS(pw->imd->widget)); | |
2843 | |
2844 imd = pan_window_active_image(pw); | |
2845 path = pan_menu_click_path(pw); | |
2846 | |
2847 if (focused) | |
2848 { | |
2849 switch (event->keyval) | |
2850 { | |
2851 case GDK_Left: case GDK_KP_Left: | |
2852 x -= 1; | |
2853 stop_signal = TRUE; | |
2854 break; | |
2855 case GDK_Right: case GDK_KP_Right: | |
2856 x += 1; | |
2857 stop_signal = TRUE; | |
2858 break; | |
2859 case GDK_Up: case GDK_KP_Up: | |
2860 y -= 1; | |
2861 stop_signal = TRUE; | |
2862 break; | |
2863 case GDK_Down: case GDK_KP_Down: | |
2864 y += 1; | |
2865 stop_signal = TRUE; | |
2866 break; | |
2867 case GDK_Page_Up: case GDK_KP_Page_Up: | |
2868 image_scroll(imd, 0, 0-imd->vis_height / 2); | |
2869 break; | |
2870 case GDK_Page_Down: case GDK_KP_Page_Down: | |
2871 image_scroll(imd, 0, imd->vis_height / 2); | |
2872 break; | |
2873 case GDK_Home: case GDK_KP_Home: | |
2874 image_scroll(imd, 0-imd->vis_width / 2, 0); | |
2875 break; | |
2876 case GDK_End: case GDK_KP_End: | |
2877 image_scroll(imd, imd->vis_width / 2, 0); | |
2878 break; | |
2879 } | |
2880 } | |
2881 | |
2882 if (focused && !(event->state & GDK_CONTROL_MASK) ) | |
2883 switch (event->keyval) | |
2884 { | |
2885 case '+': case '=': case GDK_KP_Add: | |
2886 image_zoom_adjust(imd, ZOOM_INCREMENT); | |
2887 break; | |
2888 case '-': case GDK_KP_Subtract: | |
2889 image_zoom_adjust(imd, -ZOOM_INCREMENT); | |
2890 break; | |
2891 case 'Z': case 'z': case GDK_KP_Divide: case '1': | |
2892 image_zoom_set(imd, 1.0); | |
2893 break; | |
2894 case '2': | |
2895 image_zoom_set(imd, 2.0); | |
2896 break; | |
2897 case '3': | |
2898 image_zoom_set(imd, 3.0); | |
2899 break; | |
2900 case '4': | |
2901 image_zoom_set(imd, 4.0); | |
2902 break; | |
2903 case '7': | |
2904 image_zoom_set(imd, -4.0); | |
2905 break; | |
2906 case '8': | |
2907 image_zoom_set(imd, -3.0); | |
2908 break; | |
2909 case '9': | |
2910 image_zoom_set(imd, -2.0); | |
2911 break; | |
2912 case 'F': case 'f': | |
2913 case 'V': case 'v': | |
2914 pan_fullscreen_toggle(pw, FALSE); | |
2915 stop_signal = TRUE; | |
2916 break; | |
2917 case 'I': case 'i': | |
2918 pan_overlay_toggle(pw); | |
2919 break; | |
2920 case GDK_Delete: case GDK_KP_Delete: | |
2921 break; | |
2922 case '/': | |
2923 if (!pw->fs) | |
2924 { | |
2925 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pw->search_button), TRUE); | |
2926 stop_signal = TRUE; | |
2927 } | |
2928 break; | |
2929 case GDK_Escape: | |
2930 if (pw->fs) | |
2931 { | |
2932 pan_fullscreen_toggle(pw, TRUE); | |
2933 stop_signal = TRUE; | |
2934 } | |
2935 else if (GTK_WIDGET_VISIBLE(pw->search_entry)) | |
2936 { | |
2937 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pw->search_button), FALSE); | |
2938 stop_signal = TRUE; | |
2939 } | |
2940 break; | |
2941 case GDK_Menu: | |
2942 case GDK_F10: | |
2943 menu = pan_popup_menu(pw); | |
2944 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, pan_window_menu_pos_cb, pw, 0, GDK_CURRENT_TIME); | |
2945 stop_signal = TRUE; | |
2946 break; | |
2947 } | |
2948 | |
2949 if (event->state & GDK_CONTROL_MASK) | |
2950 { | |
2951 gint n = -1; | |
2952 switch (event->keyval) | |
2953 { | |
2954 case '1': | |
2955 n = 0; | |
2956 break; | |
2957 case '2': | |
2958 n = 1; | |
2959 break; | |
2960 case '3': | |
2961 n = 2; | |
2962 break; | |
2963 case '4': | |
2964 n = 3; | |
2965 break; | |
2966 case '5': | |
2967 n = 4; | |
2968 break; | |
2969 case '6': | |
2970 n = 5; | |
2971 break; | |
2972 case '7': | |
2973 n = 6; | |
2974 break; | |
2975 case '8': | |
2976 n = 7; | |
2977 break; | |
2978 case '9': | |
2979 n = 8; | |
2980 break; | |
2981 case '0': | |
2982 n = 9; | |
2983 break; | |
2984 case 'C': case 'c': | |
2985 if (path) file_util_copy(path, NULL, NULL, imd->widget); | |
2986 break; | |
2987 case 'M': case 'm': | |
2988 if (path) file_util_move(path, NULL, NULL, imd->widget); | |
2989 break; | |
2990 case 'R': case 'r': | |
2991 if (path) file_util_rename(path, NULL, imd->widget); | |
2992 break; | |
2993 case 'D': case 'd': | |
2994 if (path) file_util_delete(path, NULL, imd->widget); | |
2995 break; | |
2996 case 'P': case 'p': | |
2997 if (path) info_window_new(path, NULL); | |
2998 break; | |
2999 case 'W': case 'w': | |
3000 pan_window_close(pw); | |
3001 break; | |
3002 } | |
3003 if (n != -1 && path) | |
3004 { | |
3005 pan_fullscreen_toggle(pw, TRUE); | |
3006 start_editor_from_file(n, path); | |
3007 stop_signal = TRUE; | |
3008 } | |
3009 } | |
3010 else if (event->state & GDK_SHIFT_MASK) | |
3011 { | |
3012 x *= 3; | |
3013 y *= 3; | |
3014 } | |
3015 else if (!focused) | |
3016 { | |
3017 switch (event->keyval) | |
3018 { | |
3019 case GDK_Escape: | |
3020 if (pw->fs) | |
3021 { | |
3022 pan_fullscreen_toggle(pw, TRUE); | |
3023 stop_signal = TRUE; | |
3024 } | |
3025 else if (GTK_WIDGET_HAS_FOCUS(pw->search_entry)) | |
3026 { | |
3027 gtk_widget_grab_focus(pw->imd->widget); | |
3028 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pw->search_button), FALSE); | |
3029 stop_signal = TRUE; | |
3030 } | |
3031 break; | |
3032 default: | |
3033 break; | |
3034 } | |
3035 } | |
3036 | |
3037 if (x != 0 || y!= 0) | |
3038 { | |
3039 keyboard_scroll_calc(&x, &y, event); | |
3040 image_scroll(imd, x, y); | |
3041 } | |
3042 | |
3043 return stop_signal; | |
3044 } | |
3045 | |
3046 /* | |
3047 *----------------------------------------------------------------------------- | |
3048 * info popup | |
3049 *----------------------------------------------------------------------------- | |
3050 */ | |
3051 | |
3052 static void pan_info_update(PanWindow *pw, PanItem *pi) | |
3053 { | |
3054 PanItem *pbox; | |
3055 PanItem *plabel; | |
3056 PanItem *p; | |
3057 gchar *buf; | |
3058 gint x1, y1, x2, y2, x3, y3; | |
3059 gint x, y, w, h; | |
3060 | |
3061 if (pw->click_pi == pi) return; | |
3062 if (pi && !pi->fd) pi = NULL; | |
3063 | |
3064 while ((p = pan_item_find_by_key(pw, ITEM_NONE, "info"))) pan_item_remove(pw, p); | |
3065 pw->click_pi = pi; | |
3066 | |
3067 if (!pi) return; | |
3068 | |
3069 printf("info set to %s\n", pi->fd->path); | |
3070 | |
3071 pbox = pan_item_new_box(pw, NULL, pi->x + pi->width + 4, pi->y, 10, 10, | |
3072 PAN_POPUP_BORDER, | |
3073 PAN_POPUP_COLOR, PAN_POPUP_ALPHA, | |
3074 PAN_POPUP_BORDER_COLOR, PAN_POPUP_ALPHA); | |
3075 pan_item_set_key(pbox, "info"); | |
3076 | |
3077 if (pi->type == ITEM_THUMB && pi->pixbuf) | |
3078 { | |
3079 w = gdk_pixbuf_get_width(pi->pixbuf); | |
3080 h = gdk_pixbuf_get_height(pi->pixbuf); | |
3081 | |
3082 x1 = pi->x + pi->width - (pi->width - w) / 2 - 8; | |
3083 y1 = pi->y + (pi->height - h) / 2 + 8; | |
3084 } | |
3085 else | |
3086 { | |
3087 x1 = pi->x + pi->width - 8; | |
3088 y1 = pi->y + 8; | |
3089 } | |
3090 | |
3091 x2 = pbox->x + 1; | |
3092 y2 = pbox->y + 36; | |
3093 x3 = pbox->x + 1; | |
3094 y3 = pbox->y + 12; | |
3095 triangle_rect_region(x1, y1, x2, y2, x3, y3, | |
3096 &x, &y, &w, &h); | |
3097 | |
3098 p = pan_item_new_tri(pw, NULL, x, y, w, h, | |
3099 x1, y1, x2, y2, x3, y3, | |
3100 PAN_POPUP_COLOR, PAN_POPUP_ALPHA); | |
3101 pan_item_tri_border(p, BORDER_1 | BORDER_3, PAN_POPUP_BORDER_COLOR, PAN_POPUP_ALPHA); | |
3102 pan_item_set_key(p, "info"); | |
3103 pan_item_added(pw, p); | |
3104 | |
3105 plabel = pan_item_new_text(pw, pbox->x, pbox->y, | |
3106 _("Filename:"), TEXT_ATTR_BOLD, | |
3107 PAN_POPUP_TEXT_COLOR, 255); | |
3108 pan_item_set_key(plabel, "info"); | |
3109 p = pan_item_new_text(pw, plabel->x + plabel->width, plabel->y, | |
3110 pi->fd->name, TEXT_ATTR_NONE, | |
3111 PAN_POPUP_TEXT_COLOR, 255); | |
3112 pan_item_set_key(p, "info"); | |
3113 pan_item_size_by_item(pbox, p, 0); | |
3114 | |
3115 plabel = pan_item_new_text(pw, plabel->x, plabel->y + plabel->height, | |
3116 _("Date:"), TEXT_ATTR_BOLD, | |
3117 PAN_POPUP_TEXT_COLOR, 255); | |
3118 pan_item_set_key(plabel, "info"); | |
3119 p = pan_item_new_text(pw, plabel->x + plabel->width, plabel->y, | |
3120 text_from_time(pi->fd->date), TEXT_ATTR_NONE, | |
3121 PAN_POPUP_TEXT_COLOR, 255); | |
3122 pan_item_set_key(p, "info"); | |
3123 pan_item_size_by_item(pbox, p, 0); | |
3124 | |
3125 plabel = pan_item_new_text(pw, plabel->x, plabel->y + plabel->height, | |
3126 _("Size:"), TEXT_ATTR_BOLD, | |
3127 PAN_POPUP_TEXT_COLOR, 255); | |
3128 pan_item_set_key(plabel, "info"); | |
3129 buf = text_from_size(pi->fd->size); | |
3130 p = pan_item_new_text(pw, plabel->x + plabel->width, plabel->y, | |
3131 buf, TEXT_ATTR_NONE, | |
3132 PAN_POPUP_TEXT_COLOR, 255); | |
3133 g_free(buf); | |
3134 pan_item_set_key(p, "info"); | |
3135 pan_item_size_by_item(pbox, p, 0); | |
3136 | |
3137 pan_item_box_shadow(pbox, PAN_SHADOW_OFFSET * 2, PAN_SHADOW_FADE * 2); | |
3138 pan_item_added(pw, pbox); | |
3139 } | |
3140 | |
3141 | |
3142 /* | |
3143 *----------------------------------------------------------------------------- | |
3144 * search | |
3145 *----------------------------------------------------------------------------- | |
3146 */ | |
3147 | |
3148 static void pan_search_status(PanWindow *pw, const gchar *text) | |
3149 { | |
3150 gtk_label_set_text(GTK_LABEL(pw->search_label), (text) ? text : ""); | |
3151 } | |
3152 | |
3153 static gint pan_search_by_path(PanWindow *pw, const gchar *path) | |
3154 { | |
3155 PanItem *pi; | |
3156 ItemType type; | |
3157 | |
3158 type = (pw->size > LAYOUT_SIZE_THUMB_LARGE) ? ITEM_IMAGE : ITEM_THUMB; | |
3159 | |
3160 pi = pan_item_find_by_path(pw, type, path, FALSE, FALSE); | |
3161 if (!pi) return FALSE; | |
3162 | |
3163 pan_info_update(pw, pi); | |
3164 image_scroll_to_point(pw->imd, pi->x - PAN_THUMB_GAP, pi->y - PAN_THUMB_GAP); | |
3165 | |
3166 pan_search_status(pw, (path[0] == '/') ? _("path found") : _("filename found")); | |
3167 | |
3168 return TRUE; | |
3169 } | |
3170 | |
3171 static gint pan_search_by_partial(PanWindow *pw, const gchar *text) | |
3172 { | |
3173 PanItem *pi; | |
3174 ItemType type; | |
3175 | |
3176 type = (pw->size > LAYOUT_SIZE_THUMB_LARGE) ? ITEM_IMAGE : ITEM_THUMB; | |
3177 | |
3178 pi = pan_item_find_by_path(pw, type, text, TRUE, FALSE); | |
3179 if (!pi) pi = pan_item_find_by_path(pw, type, text, FALSE, TRUE); | |
3180 if (!pi) | |
3181 { | |
3182 gchar *needle; | |
3183 | |
3184 needle = g_utf8_strdown(text, -1); | |
3185 pi = pan_item_find_by_path(pw, type, needle, TRUE, TRUE); | |
3186 g_free(needle); | |
3187 } | |
3188 if (!pi) return FALSE; | |
3189 | |
3190 pan_info_update(pw, pi); | |
3191 image_scroll_to_point(pw->imd, pi->x - PAN_THUMB_GAP, pi->y - PAN_THUMB_GAP); | |
3192 | |
3193 pan_search_status(pw, _("partial match")); | |
3194 | |
3195 return TRUE; | |
3196 } | |
3197 | |
3198 static gint valid_date_separator(gchar c) | |
3199 { | |
3200 return (c == '/' || c == '-' || c == ' ' || c == '.' || c == ','); | |
3201 } | |
3202 | |
3203 static PanItem *pan_search_by_date_val(PanWindow *pw, gint year, gint month, gint day) | |
3204 { | |
3205 GList *work; | |
3206 | |
3207 work = g_list_last(pw->list); | |
3208 while (work) | |
3209 { | |
3210 PanItem *pi; | |
3211 | |
3212 pi = work->data; | |
3213 work = work->prev; | |
3214 | |
3215 if (pi->fd) | |
3216 { | |
3217 struct tm *tl; | |
3218 | |
3219 tl = localtime(&pi->fd->date); | |
3220 if (tl) | |
3221 { | |
3222 gint match; | |
3223 | |
3224 match = (tl->tm_year == year - 1900); | |
3225 if (match && month >= 0) match = (tl->tm_mon == month - 1); | |
3226 if (match && day > 0) match = (tl->tm_mday == day); | |
3227 | |
3228 if (match) return pi; | |
3229 } | |
3230 } | |
3231 } | |
3232 | |
3233 return NULL; | |
3234 } | |
3235 | |
3236 static gint pan_search_by_date(PanWindow *pw, const gchar *text) | |
3237 { | |
3238 PanItem *pi; | |
3239 gint year; | |
3240 gint month = -1; | |
3241 gint day = -1; | |
3242 gchar *ptr; | |
3243 gchar *mptr; | |
3244 struct tm *lt; | |
3245 time_t t; | |
3246 gchar *message; | |
3247 gchar *buf; | |
3248 | |
3249 if (!text) return FALSE; | |
3250 | |
3251 ptr = (gchar *)text; | |
3252 while (*ptr != '\0') | |
3253 { | |
3254 if (!g_unichar_isdigit(*ptr) && !valid_date_separator(*ptr)) return FALSE; | |
3255 ptr++; | |
3256 } | |
3257 | |
3258 t = time(NULL); | |
3259 if (t == -1) return FALSE; | |
3260 lt = localtime(&t); | |
3261 if (!lt) return FALSE; | |
3262 | |
3263 if (valid_date_separator(*text)) | |
3264 { | |
3265 year = -1; | |
3266 mptr = (gchar *)text; | |
3267 } | |
3268 else | |
3269 { | |
3270 year = (gint)strtol(text, &mptr, 10); | |
3271 if (mptr == text) return FALSE; | |
3272 } | |
3273 | |
3274 if (*mptr != '\0' && valid_date_separator(*mptr)) | |
3275 { | |
3276 gchar *dptr; | |
3277 | |
3278 mptr++; | |
3279 month = strtol(mptr, &dptr, 10); | |
3280 if (dptr == mptr) | |
3281 { | |
3282 if (valid_date_separator(*dptr)) | |
3283 { | |
3284 month = lt->tm_mon + 1; | |
3285 dptr++; | |
3286 } | |
3287 else | |
3288 { | |
3289 month = -1; | |
3290 } | |
3291 } | |
3292 if (dptr != mptr && *dptr != '\0' && valid_date_separator(*dptr)) | |
3293 { | |
3294 gchar *eptr; | |
3295 dptr++; | |
3296 day = strtol(dptr, &eptr, 10); | |
3297 if (dptr == eptr) | |
3298 { | |
3299 day = lt->tm_mday; | |
3300 } | |
3301 } | |
3302 } | |
3303 | |
3304 if (year == -1) | |
3305 { | |
3306 year = lt->tm_year + 1900; | |
3307 } | |
3308 else if (year < 100) | |
3309 { | |
3310 if (year > 70) | |
3311 year+= 1900; | |
3312 else | |
3313 year+= 2000; | |
3314 } | |
3315 | |
3316 if (year < 1970 || | |
3317 month < -1 || month == 0 || month > 12 || | |
3318 day < -1 || day == 0 || day > 31) return FALSE; | |
3319 | |
3320 t = date_to_time(year, month, day); | |
3321 if (t < 0) return FALSE; | |
3322 | |
3323 pi = pan_search_by_date_val(pw, year, month, day); | |
3324 if (pi) | |
3325 { | |
3326 pan_info_update(pw, pi); | |
3327 image_scroll_to_point(pw->imd, pi->x - PAN_THUMB_GAP, pi->y - PAN_THUMB_GAP); | |
3328 } | |
3329 | |
3330 if (month > 0) | |
3331 { | |
3332 buf = date_value_string(t, DATE_LENGTH_MONTH); | |
3333 if (day > 0) | |
3334 { | |
3335 gchar *tmp; | |
3336 tmp = buf; | |
3337 buf = g_strdup_printf("%d %s", day, tmp); | |
3338 g_free(tmp); | |
3339 } | |
3340 } | |
3341 else | |
3342 { | |
3343 buf = date_value_string(t, DATE_LENGTH_YEAR); | |
3344 } | |
3345 message = g_strdup_printf("%s%s%s%s %s", | |
3346 (pi) ? "" : "(", (pi) ? "" : _("no match"), (pi) ? "" : ") " , | |
3347 _("Date:"), buf); | |
3348 g_free(buf); | |
3349 pan_search_status(pw, message); | |
3350 g_free(message); | |
3351 | |
3352 return TRUE; | |
3353 } | |
3354 | |
3355 static void pan_search_activate_cb(const gchar *text, gpointer data) | |
3356 { | |
3357 PanWindow *pw = data; | |
3358 | |
3359 if (!text) return; | |
3360 | |
3361 tab_completion_append_to_history(pw->search_entry, text); | |
3362 | |
3363 if (pan_search_by_path(pw, text)) return; | |
3364 | |
3365 if (pw->layout == LAYOUT_TIMELINE && pan_search_by_date(pw, text)) return; | |
3366 | |
3367 if (pan_search_by_partial(pw, text)) return; | |
3368 | |
3369 pan_search_status(pw, _("no match")); | |
3370 } | |
3371 | |
3372 static void pan_search_toggle_cb(GtkWidget *button, gpointer data) | |
3373 { | |
3374 PanWindow *pw = data; | |
3375 gint visible; | |
3376 | |
3377 visible = GTK_WIDGET_VISIBLE(pw->search_box); | |
3378 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)) == visible) return; | |
3379 | |
3380 if (visible) | |
3381 { | |
3382 gtk_widget_hide(pw->search_box); | |
3383 gtk_arrow_set(GTK_ARROW(pw->search_button_arrow), GTK_ARROW_UP, GTK_SHADOW_NONE); | |
3384 } | |
3385 else | |
3386 { | |
3387 gtk_widget_show(pw->search_box); | |
3388 gtk_arrow_set(GTK_ARROW(pw->search_button_arrow), GTK_ARROW_DOWN, GTK_SHADOW_NONE); | |
3389 gtk_widget_grab_focus(pw->search_entry); | |
3390 } | |
3391 } | |
3392 | |
3393 | |
3394 /* | |
3395 *----------------------------------------------------------------------------- | |
3396 * view window main routines | |
3397 *----------------------------------------------------------------------------- | |
3398 */ | |
3399 | |
3400 static void button_cb(ImageWindow *imd, gint button, guint32 time, | |
3401 gdouble x, gdouble y, guint state, gpointer data) | |
3402 { | |
3403 PanWindow *pw = data; | |
3404 PanItem *pi = NULL; | |
3405 GtkWidget *menu; | |
3406 | |
3407 if (pw->imd->scale) | |
3408 { | |
3409 pi = pan_item_find_by_coord(pw, (pw->size > LAYOUT_SIZE_THUMB_LARGE) ? ITEM_IMAGE : ITEM_THUMB, | |
3410 (gint)((double)(pw->imd->x_scroll + x - pw->imd->x_offset) / pw->imd->scale), | |
3411 (gint)((double)(pw->imd->y_scroll + y - pw->imd->y_offset) / pw->imd->scale)); | |
3412 } | |
3413 | |
3414 switch (button) | |
3415 { | |
3416 case 1: | |
3417 pan_info_update(pw, pi); | |
3418 break; | |
3419 case 2: | |
3420 break; | |
3421 case 3: | |
3422 pan_info_update(pw, pi); | |
3423 menu = pan_popup_menu(pw); | |
3424 gtk_menu_popup (GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, time); | |
3425 break; | |
3426 default: | |
3427 break; | |
3428 } | |
3429 } | |
3430 | |
3431 static void scroll_cb(ImageWindow *imd, GdkScrollDirection direction, guint32 time, | |
3432 gdouble x, gdouble y, guint state, gpointer data) | |
3433 { | |
3434 #if 0 | |
3435 PanWindow *pw = data; | |
3436 #endif | |
3437 | |
3438 if (state & GDK_CONTROL_MASK) | |
3439 { | |
3440 switch (direction) | |
3441 { | |
3442 case GDK_SCROLL_UP: | |
3443 image_zoom_adjust_at_point(imd, ZOOM_INCREMENT, x, y); | |
3444 break; | |
3445 case GDK_SCROLL_DOWN: | |
3446 image_zoom_adjust_at_point(imd, -ZOOM_INCREMENT, x, y); | |
3447 break; | |
3448 default: | |
3449 break; | |
3450 } | |
3451 } | |
3452 else if ( (state & GDK_SHIFT_MASK) != (mousewheel_scrolls)) | |
3453 { | |
3454 switch (direction) | |
3455 { | |
3456 case GDK_SCROLL_UP: | |
3457 image_scroll(imd, 0, -MOUSEWHEEL_SCROLL_SIZE); | |
3458 break; | |
3459 case GDK_SCROLL_DOWN: | |
3460 image_scroll(imd, 0, MOUSEWHEEL_SCROLL_SIZE); | |
3461 break; | |
3462 case GDK_SCROLL_LEFT: | |
3463 image_scroll(imd, -MOUSEWHEEL_SCROLL_SIZE, 0); | |
3464 break; | |
3465 case GDK_SCROLL_RIGHT: | |
3466 image_scroll(imd, MOUSEWHEEL_SCROLL_SIZE, 0); | |
3467 break; | |
3468 default: | |
3469 break; | |
3470 } | |
3471 } | |
3472 else | |
3473 { | |
3474 switch (direction) | |
3475 { | |
3476 case GDK_SCROLL_UP: | |
3477 break; | |
3478 case GDK_SCROLL_DOWN: | |
3479 break; | |
3480 default: | |
3481 break; | |
3482 } | |
3483 } | |
3484 } | |
3485 | |
3486 static void pan_image_set_buttons(PanWindow *pw, ImageWindow *imd) | |
3487 { | |
3488 image_set_button_func(imd, button_cb, pw); | |
3489 image_set_scroll_func(imd, scroll_cb, pw); | |
3490 } | |
3491 | |
3492 static void pan_fullscreen_stop_func(FullScreenData *fs, gpointer data) | |
3493 { | |
3494 PanWindow *pw = data; | |
3495 | |
3496 pw->fs = NULL; | |
3497 } | |
3498 | |
3499 static void pan_fullscreen_toggle(PanWindow *pw, gint force_off) | |
3500 { | |
3501 if (force_off && !pw->fs) return; | |
3502 | |
3503 if (pw->fs) | |
3504 { | |
3505 fullscreen_stop(pw->fs); | |
3506 pw->imd = pw->imd_normal; | |
3507 } | |
3508 else | |
3509 { | |
3510 pw->fs = fullscreen_start(pw->window, pw->imd, pan_fullscreen_stop_func, pw); | |
3511 | |
3512 pan_image_set_buttons(pw, pw->fs->imd); | |
3513 g_signal_connect(G_OBJECT(pw->fs->window), "key_press_event", | |
3514 G_CALLBACK(pan_window_key_press_cb), pw); | |
3515 | |
3516 pw->imd = pw->fs->imd; | |
3517 } | |
3518 } | |
3519 | |
3520 static void pan_overlay_toggle(PanWindow *pw) | |
3521 { | |
3522 ImageWindow *imd; | |
3523 | |
3524 imd = pan_window_active_image(pw); | |
3525 #if 0 | |
3526 if (pw->overlay_id == -1) | |
3527 { | |
3528 pw->overlay_id = image_overlay_info_enable(imd); | |
3529 } | |
3530 else | |
3531 { | |
3532 image_overlay_info_disable(imd, pw->overlay_id); | |
3533 pw->overlay_id = -1; | |
3534 } | |
3535 #endif | |
3536 } | |
3537 | |
3538 static void pan_window_image_update_cb(ImageWindow *imd, gpointer data) | |
3539 { | |
3540 PanWindow *pw = data; | |
3541 gchar *text; | |
3542 | |
3543 text = image_zoom_get_as_text(imd); | |
3544 gtk_label_set_text(GTK_LABEL(pw->label_zoom), text); | |
3545 g_free(text); | |
3546 } | |
3547 | |
3548 static void pan_window_image_scroll_notify_cb(ImageWindow *imd, gint x, gint y, | |
3549 gint width, gint height, gpointer data) | |
3550 { | |
3551 PanWindow *pw = data; | |
3552 GtkAdjustment *adj; | |
3553 | |
3554 adj = gtk_range_get_adjustment(GTK_RANGE(pw->scrollbar_h)); | |
3555 adj->page_size = (gdouble)imd->vis_width / imd->scale; | |
3556 adj->page_increment = adj->page_size / 2.0; | |
3557 adj->step_increment = 48.0 / imd->scale; | |
3558 adj->lower = 0.0; | |
3559 adj->upper = MAX((gdouble)width + adj->page_size, 1.0); | |
3560 adj->value = (gdouble)x; | |
3561 | |
3562 pref_signal_block_data(pw->scrollbar_h, pw); | |
3563 gtk_adjustment_changed(adj); | |
3564 pref_signal_unblock_data(pw->scrollbar_h, pw); | |
3565 | |
3566 adj = gtk_range_get_adjustment(GTK_RANGE(pw->scrollbar_v)); | |
3567 adj->page_size = (gdouble)imd->vis_height / imd->scale; | |
3568 adj->page_increment = adj->page_size / 2.0; | |
3569 adj->step_increment = 48.0 / imd->scale; | |
3570 adj->lower = 0.0; | |
3571 adj->upper = MAX((gdouble)height + adj->page_size, 1.0); | |
3572 adj->value = (gdouble)y; | |
3573 | |
3574 pref_signal_block_data(pw->scrollbar_v, pw); | |
3575 gtk_adjustment_changed(adj); | |
3576 pref_signal_unblock_data(pw->scrollbar_v, pw); | |
3577 | |
3578 // printf("scrolled to %d,%d @ %d x %d\n", x, y, width, height); | |
3579 } | |
3580 | |
3581 static void pan_window_scrollbar_h_value_cb(GtkRange *range, gpointer data) | |
3582 { | |
3583 PanWindow *pw = data; | |
3584 gint x; | |
3585 | |
3586 if (!pw->imd->scale) return; | |
3587 | |
3588 x = (gint)gtk_range_get_value(range); | |
3589 | |
3590 image_scroll_to_point(pw->imd, x, (gint)((gdouble)pw->imd->y_scroll / pw->imd->scale)); | |
3591 } | |
3592 | |
3593 static void pan_window_scrollbar_v_value_cb(GtkRange *range, gpointer data) | |
3594 { | |
3595 PanWindow *pw = data; | |
3596 gint y; | |
3597 | |
3598 if (!pw->imd->scale) return; | |
3599 | |
3600 y = (gint)gtk_range_get_value(range); | |
3601 | |
3602 image_scroll_to_point(pw->imd, (gint)((gdouble)pw->imd->x_scroll / pw->imd->scale), y); | |
3603 } | |
3604 | |
3605 static void pan_window_layout_change_cb(GtkWidget *combo, gpointer data) | |
3606 { | |
3607 PanWindow *pw = data; | |
3608 | |
3609 pw->layout = gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); | |
3610 pan_window_layout_update_idle(pw); | |
3611 } | |
3612 | |
3613 static void pan_window_layout_size_cb(GtkWidget *combo, gpointer data) | |
3614 { | |
3615 PanWindow *pw = data; | |
3616 | |
3617 pw->size = gtk_combo_box_get_active(GTK_COMBO_BOX(combo)); | |
3618 pan_window_layout_update_idle(pw); | |
3619 } | |
3620 | |
3621 static void pan_window_entry_activate_cb(const gchar *new_text, gpointer data) | |
3622 { | |
3623 PanWindow *pw = data; | |
3624 gchar *path; | |
3625 | |
3626 path = remove_trailing_slash(new_text); | |
3627 parse_out_relatives(path); | |
3628 | |
3629 if (!isdir(path)) | |
3630 { | |
3631 warning_dialog(_("Folder not found"), | |
3632 _("The entered path is not a folder"), | |
3633 GTK_STOCK_DIALOG_WARNING, pw->path_entry); | |
3634 return; | |
3635 } | |
3636 | |
3637 tab_completion_append_to_history(pw->path_entry, path); | |
3638 | |
3639 g_free(pw->path); | |
3640 pw->path = g_strdup(path); | |
3641 | |
3642 pan_window_layout_update_idle(pw); | |
3643 } | |
3644 | |
3645 static void pan_window_entry_change_cb(GtkWidget *combo, gpointer data) | |
3646 { | |
3647 PanWindow *pw = data; | |
3648 gchar *text; | |
3649 | |
3650 if (gtk_combo_box_get_active(GTK_COMBO_BOX(combo)) < 0) return; | |
3651 | |
3652 text = g_strdup(gtk_entry_get_text(GTK_ENTRY(pw->path_entry))); | |
3653 pan_window_entry_activate_cb(text, pw); | |
3654 g_free(text); | |
3655 } | |
3656 | |
3657 static void pan_window_close(PanWindow *pw) | |
3658 { | |
3659 pan_window_list = g_list_remove(pan_window_list, pw); | |
3660 | |
3661 if (pw->idle_id != -1) | |
3662 { | |
3663 g_source_remove(pw->idle_id); | |
3664 } | |
3665 | |
3666 pan_fullscreen_toggle(pw, TRUE); | |
3667 gtk_widget_destroy(pw->window); | |
3668 | |
3669 pan_window_items_free(pw); | |
3670 | |
3671 g_free(pw->path); | |
3672 | |
3673 g_free(pw); | |
3674 } | |
3675 | |
3676 static gint pan_window_delete_cb(GtkWidget *w, GdkEventAny *event, gpointer data) | |
3677 { | |
3678 PanWindow *pw = data; | |
3679 | |
3680 pan_window_close(pw); | |
3681 return TRUE; | |
3682 } | |
3683 | |
3684 void pan_window_new(const gchar *path) | |
3685 { | |
3686 PanWindow *pw; | |
3687 GtkWidget *vbox; | |
3688 GtkWidget *box; | |
3689 GtkWidget *combo; | |
3690 GtkWidget *hbox; | |
3691 GtkWidget *frame; | |
3692 GtkWidget *table; | |
3693 GdkGeometry geometry; | |
3694 | |
3695 pw = g_new0(PanWindow, 1); | |
3696 | |
3697 pw->path = g_strdup(path); | |
3698 pw->layout = LAYOUT_TIMELINE; | |
3699 pw->size = LAYOUT_SIZE_THUMB_NORMAL; | |
3700 pw->thumb_size = PAN_THUMB_SIZE_NORMAL; | |
3701 pw->thumb_gap = PAN_THUMB_GAP_NORMAL; | |
3702 pw->list = NULL; | |
3703 | |
3704 pw->fs = NULL; | |
3705 pw->overlay_id = -1; | |
3706 pw->idle_id = -1; | |
3707 | |
3708 pw->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | |
3709 | |
3710 geometry.min_width = 8; | |
3711 geometry.min_height = 8; | |
3712 gtk_window_set_geometry_hints(GTK_WINDOW(pw->window), NULL, &geometry, GDK_HINT_MIN_SIZE); | |
3713 | |
3714 gtk_window_set_resizable(GTK_WINDOW(pw->window), TRUE); | |
3715 gtk_window_set_title (GTK_WINDOW(pw->window), "Pan View - GQview"); | |
3716 gtk_window_set_wmclass(GTK_WINDOW(pw->window), "view", "GQview"); | |
3717 gtk_container_set_border_width(GTK_CONTAINER(pw->window), 0); | |
3718 | |
3719 window_set_icon(pw->window, NULL, NULL); | |
3720 | |
3721 vbox = gtk_vbox_new(FALSE, 0); | |
3722 gtk_container_add(GTK_CONTAINER(pw->window), vbox); | |
3723 gtk_widget_show(vbox); | |
3724 | |
3725 box = pref_box_new(vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, PREF_PAD_SPACE); | |
3726 | |
3727 pref_spacer(box, 0); | |
3728 pref_label_new(box, _("Location:")); | |
3729 combo = tab_completion_new_with_history(&pw->path_entry, path, "pan_view", -1, | |
3730 pan_window_entry_activate_cb, pw); | |
3731 g_signal_connect(G_OBJECT(pw->path_entry->parent), "changed", | |
3732 G_CALLBACK(pan_window_entry_change_cb), pw); | |
3733 gtk_box_pack_start(GTK_BOX(box), combo, TRUE, TRUE, 0); | |
3734 gtk_widget_show(combo); | |
3735 | |
3736 combo = gtk_combo_box_new_text(); | |
3737 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Timeline")); | |
3738 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Folders")); | |
3739 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Folders (flower)")); | |
3740 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Grid")); | |
3741 | |
3742 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), pw->layout); | |
3743 g_signal_connect(G_OBJECT(combo), "changed", | |
3744 G_CALLBACK(pan_window_layout_change_cb), pw); | |
3745 gtk_box_pack_start(GTK_BOX(box), combo, FALSE, FALSE, 0); | |
3746 gtk_widget_show(combo); | |
3747 | |
3748 combo = gtk_combo_box_new_text(); | |
3749 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("No Images")); | |
3750 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Small Thumbnails")); | |
3751 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Normal Thumbnails")); | |
3752 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Large Thumbnails")); | |
3753 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("1:10 (10%)")); | |
3754 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("1:4 (25%)")); | |
3755 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("1:3 (33%)")); | |
3756 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("1:2 (50%)")); | |
3757 gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("1:1 (100%)")); | |
3758 | |
3759 gtk_combo_box_set_active(GTK_COMBO_BOX(combo), pw->size); | |
3760 g_signal_connect(G_OBJECT(combo), "changed", | |
3761 G_CALLBACK(pan_window_layout_size_cb), pw); | |
3762 gtk_box_pack_start(GTK_BOX(box), combo, FALSE, FALSE, 0); | |
3763 gtk_widget_show(combo); | |
3764 | |
3765 table = pref_table_new(vbox, 2, 2, FALSE, TRUE); | |
3766 gtk_table_set_row_spacings(GTK_TABLE(table), 2); | |
3767 gtk_table_set_col_spacings(GTK_TABLE(table), 2); | |
3768 | |
3769 pw->imd = image_new(TRUE); | |
3770 pw->imd_normal = pw->imd; | |
3771 | |
3772 if (black_window_background) image_background_set_black(pw->imd, TRUE); | |
3773 image_set_update_func(pw->imd, pan_window_image_update_cb, pw); | |
3774 | |
3775 image_set_scroll_notify_func(pw->imd, pan_window_image_scroll_notify_cb, pw); | |
3776 | |
3777 #if 0 | |
3778 gtk_box_pack_start(GTK_BOX(vbox), pw->imd->widget, TRUE, TRUE, 0); | |
3779 #endif | |
3780 gtk_table_attach(GTK_TABLE(table), pw->imd->widget, 0, 1, 0, 1, | |
3781 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0); | |
3782 gtk_widget_show(pw->imd->widget); | |
3783 | |
3784 pan_window_dnd_init(pw); | |
3785 | |
3786 pan_image_set_buttons(pw, pw->imd); | |
3787 | |
3788 pw->scrollbar_h = gtk_hscrollbar_new(NULL); | |
3789 g_signal_connect(G_OBJECT(pw->scrollbar_h), "value_changed", | |
3790 G_CALLBACK(pan_window_scrollbar_h_value_cb), pw); | |
3791 gtk_table_attach(GTK_TABLE(table), pw->scrollbar_h, 0, 1, 1, 2, | |
3792 GTK_FILL | GTK_EXPAND, 0, 0, 0); | |
3793 gtk_widget_show(pw->scrollbar_h); | |
3794 | |
3795 pw->scrollbar_v = gtk_vscrollbar_new(NULL); | |
3796 g_signal_connect(G_OBJECT(pw->scrollbar_v), "value_changed", | |
3797 G_CALLBACK(pan_window_scrollbar_v_value_cb), pw); | |
3798 gtk_table_attach(GTK_TABLE(table), pw->scrollbar_v, 1, 2, 0, 1, | |
3799 0, GTK_FILL | GTK_EXPAND, 0, 0); | |
3800 gtk_widget_show(pw->scrollbar_v); | |
3801 | |
3802 /* find bar */ | |
3803 | |
3804 pw->search_box = gtk_hbox_new(FALSE, PREF_PAD_SPACE); | |
3805 gtk_box_pack_start(GTK_BOX(vbox), pw->search_box, FALSE, FALSE, 2); | |
3806 | |
3807 pref_spacer(pw->search_box, 0); | |
3808 pref_label_new(pw->search_box, _("Find:")); | |
3809 | |
3810 hbox = gtk_hbox_new(TRUE, PREF_PAD_SPACE); | |
3811 gtk_box_pack_start(GTK_BOX(pw->search_box), hbox, TRUE, TRUE, 0); | |
3812 gtk_widget_show(hbox); | |
3813 | |
3814 combo = tab_completion_new_with_history(&pw->search_entry, "", "pan_view_search", -1, | |
3815 pan_search_activate_cb, pw); | |
3816 gtk_box_pack_start(GTK_BOX(hbox), combo, TRUE, TRUE, 0); | |
3817 gtk_widget_show(combo); | |
3818 | |
3819 pw->search_label = gtk_label_new(""); | |
3820 gtk_box_pack_start(GTK_BOX(hbox), pw->search_label, TRUE, TRUE, 0); | |
3821 gtk_widget_show(pw->search_label); | |
3822 | |
3823 /* status bar */ | |
3824 | |
3825 box = pref_box_new(vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0); | |
3826 | |
3827 frame = gtk_frame_new(NULL); | |
3828 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); | |
3829 gtk_widget_set_size_request(frame, ZOOM_LABEL_WIDTH, -1); | |
3830 gtk_box_pack_start(GTK_BOX(box), frame, TRUE, TRUE, 0); | |
3831 gtk_widget_show(frame); | |
3832 | |
3833 hbox = gtk_hbox_new(FALSE, PREF_PAD_SPACE); | |
3834 gtk_container_add(GTK_CONTAINER(frame), hbox); | |
3835 gtk_widget_show(hbox); | |
3836 | |
3837 pref_spacer(hbox, PREF_PAD_SPACE); | |
3838 pw->label_message = pref_label_new(hbox, ""); | |
3839 | |
3840 frame = gtk_frame_new(NULL); | |
3841 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN); | |
3842 gtk_widget_set_size_request(frame, ZOOM_LABEL_WIDTH, -1); | |
3843 gtk_box_pack_end(GTK_BOX(box), frame, FALSE, FALSE, 0); | |
3844 gtk_widget_show(frame); | |
3845 | |
3846 pw->label_zoom = gtk_label_new(""); | |
3847 gtk_container_add(GTK_CONTAINER(frame), pw->label_zoom); | |
3848 gtk_widget_show(pw->label_zoom); | |
3849 | |
3850 pw->search_button = gtk_toggle_button_new(); | |
3851 gtk_button_set_relief(GTK_BUTTON(pw->search_button), GTK_RELIEF_NONE); | |
3852 gtk_button_set_focus_on_click(GTK_BUTTON(pw->search_button), FALSE); | |
3853 hbox = gtk_hbox_new(FALSE, PREF_PAD_GAP); | |
3854 gtk_container_add(GTK_CONTAINER(pw->search_button), hbox); | |
3855 gtk_widget_show(hbox); | |
3856 pw->search_button_arrow = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_NONE); | |
3857 gtk_box_pack_start(GTK_BOX(hbox), pw->search_button_arrow, FALSE, FALSE, 0); | |
3858 gtk_widget_show(pw->search_button_arrow); | |
3859 pref_label_new(hbox, _("Find")); | |
3860 | |
3861 gtk_box_pack_end(GTK_BOX(box), pw->search_button, FALSE, FALSE, 0); | |
3862 gtk_widget_show(pw->search_button); | |
3863 g_signal_connect(G_OBJECT(pw->search_button), "clicked", | |
3864 G_CALLBACK(pan_search_toggle_cb), pw); | |
3865 | |
3866 g_signal_connect(G_OBJECT(pw->window), "delete_event", | |
3867 G_CALLBACK(pan_window_delete_cb), pw); | |
3868 g_signal_connect(G_OBJECT(pw->window), "key_press_event", | |
3869 G_CALLBACK(pan_window_key_press_cb), pw); | |
3870 | |
3871 gtk_window_set_default_size(GTK_WINDOW(pw->window), PAN_WINDOW_DEFAULT_WIDTH, PAN_WINDOW_DEFAULT_HEIGHT); | |
3872 | |
3873 pan_window_layout_update_idle(pw); | |
3874 | |
3875 gtk_widget_grab_focus(pw->imd->widget); | |
3876 gtk_widget_show(pw->window); | |
3877 | |
3878 pan_window_list = g_list_append(pan_window_list, pw); | |
3879 } | |
3880 | |
3881 /* | |
3882 *----------------------------------------------------------------------------- | |
3883 * public | |
3884 *----------------------------------------------------------------------------- | |
3885 */ | |
3886 | |
3887 /* | |
3888 *----------------------------------------------------------------------------- | |
3889 * view window menu routines and callbacks | |
3890 *----------------------------------------------------------------------------- | |
3891 */ | |
3892 | |
3893 static void pan_new_window_cb(GtkWidget *widget, gpointer data) | |
3894 { | |
3895 PanWindow *pw = data; | |
3896 const gchar *path; | |
3897 | |
3898 path = pan_menu_click_path(pw); | |
3899 if (path) | |
3900 { | |
3901 pan_fullscreen_toggle(pw, TRUE); | |
3902 view_window_new(path); | |
3903 } | |
3904 } | |
3905 | |
3906 static void pan_edit_cb(GtkWidget *widget, gpointer data) | |
3907 { | |
3908 PanWindow *pw; | |
3909 const gchar *path; | |
3910 gint n; | |
3911 | |
3912 pw = submenu_item_get_data(widget); | |
3913 n = GPOINTER_TO_INT(data); | |
3914 if (!pw) return; | |
3915 | |
3916 path = pan_menu_click_path(pw); | |
3917 if (path) | |
3918 { | |
3919 pan_fullscreen_toggle(pw, TRUE); | |
3920 start_editor_from_file(n, path); | |
3921 } | |
3922 } | |
3923 | |
3924 static void pan_info_cb(GtkWidget *widget, gpointer data) | |
3925 { | |
3926 PanWindow *pw = data; | |
3927 const gchar *path; | |
3928 | |
3929 path = pan_menu_click_path(pw); | |
3930 if (path) info_window_new(path, NULL); | |
3931 } | |
3932 | |
3933 static void pan_zoom_in_cb(GtkWidget *widget, gpointer data) | |
3934 { | |
3935 PanWindow *pw = data; | |
3936 | |
3937 image_zoom_adjust(pan_window_active_image(pw), ZOOM_INCREMENT); | |
3938 } | |
3939 | |
3940 static void pan_zoom_out_cb(GtkWidget *widget, gpointer data) | |
3941 { | |
3942 PanWindow *pw = data; | |
3943 | |
3944 image_zoom_adjust(pan_window_active_image(pw), -ZOOM_INCREMENT); | |
3945 } | |
3946 | |
3947 static void pan_zoom_1_1_cb(GtkWidget *widget, gpointer data) | |
3948 { | |
3949 PanWindow *pw = data; | |
3950 | |
3951 image_zoom_set(pan_window_active_image(pw), 1.0); | |
3952 } | |
3953 | |
3954 static void pan_copy_cb(GtkWidget *widget, gpointer data) | |
3955 { | |
3956 PanWindow *pw = data; | |
3957 const gchar *path; | |
3958 | |
3959 path = pan_menu_click_path(pw); | |
3960 if (path) file_util_copy(path, NULL, NULL, pw->imd->widget); | |
3961 } | |
3962 | |
3963 static void pan_move_cb(GtkWidget *widget, gpointer data) | |
3964 { | |
3965 PanWindow *pw = data; | |
3966 const gchar *path; | |
3967 | |
3968 path = pan_menu_click_path(pw); | |
3969 if (path) file_util_move(path, NULL, NULL, pw->imd->widget); | |
3970 } | |
3971 | |
3972 static void pan_rename_cb(GtkWidget *widget, gpointer data) | |
3973 { | |
3974 PanWindow *pw = data; | |
3975 const gchar *path; | |
3976 | |
3977 path = pan_menu_click_path(pw); | |
3978 if (path) file_util_rename(path, NULL, pw->imd->widget); | |
3979 } | |
3980 | |
3981 static void pan_delete_cb(GtkWidget *widget, gpointer data) | |
3982 { | |
3983 PanWindow *pw = data; | |
3984 const gchar *path; | |
3985 | |
3986 path = pan_menu_click_path(pw); | |
3987 if (path) file_util_delete(path, NULL, pw->imd->widget); | |
3988 } | |
3989 | |
3990 static void pan_fullscreen_cb(GtkWidget *widget, gpointer data) | |
3991 { | |
3992 PanWindow *pw = data; | |
3993 | |
3994 pan_fullscreen_toggle(pw, FALSE); | |
3995 } | |
3996 | |
3997 static void pan_close_cb(GtkWidget *widget, gpointer data) | |
3998 { | |
3999 PanWindow *pw = data; | |
4000 | |
4001 pan_window_close(pw); | |
4002 } | |
4003 | |
4004 static GtkWidget *pan_popup_menu(PanWindow *pw) | |
4005 { | |
4006 GtkWidget *menu; | |
4007 GtkWidget *item; | |
4008 gint active; | |
4009 | |
4010 active = (pw->click_pi != NULL); | |
4011 | |
4012 menu = popup_menu_short_lived(); | |
4013 | |
4014 menu_item_add_stock(menu, _("Zoom _in"), GTK_STOCK_ZOOM_IN, | |
4015 G_CALLBACK(pan_zoom_in_cb), pw); | |
4016 menu_item_add_stock(menu, _("Zoom _out"), GTK_STOCK_ZOOM_OUT, | |
4017 G_CALLBACK(pan_zoom_out_cb), pw); | |
4018 menu_item_add_stock(menu, _("Zoom _1:1"), GTK_STOCK_ZOOM_100, | |
4019 G_CALLBACK(pan_zoom_1_1_cb), pw); | |
4020 menu_item_add_divider(menu); | |
4021 | |
4022 submenu_add_edit(menu, &item, G_CALLBACK(pan_edit_cb), pw); | |
4023 gtk_widget_set_sensitive(item, active); | |
4024 | |
4025 menu_item_add_stock_sensitive(menu, _("_Properties"), GTK_STOCK_PROPERTIES, active, | |
4026 G_CALLBACK(pan_info_cb), pw); | |
4027 | |
4028 menu_item_add_stock_sensitive(menu, _("View in _new window"), GTK_STOCK_NEW, active, | |
4029 G_CALLBACK(pan_new_window_cb), pw); | |
4030 | |
4031 menu_item_add_divider(menu); | |
4032 menu_item_add_stock_sensitive(menu, _("_Copy..."), GTK_STOCK_COPY, active, | |
4033 G_CALLBACK(pan_copy_cb), pw); | |
4034 menu_item_add_sensitive(menu, _("_Move..."), active, | |
4035 G_CALLBACK(pan_move_cb), pw); | |
4036 menu_item_add_sensitive(menu, _("_Rename..."), active, | |
4037 G_CALLBACK(pan_rename_cb), pw); | |
4038 menu_item_add_stock_sensitive(menu, _("_Delete..."), GTK_STOCK_DELETE, active, | |
4039 G_CALLBACK(pan_delete_cb), pw); | |
4040 | |
4041 menu_item_add_divider(menu); | |
4042 | |
4043 if (pw->fs) | |
4044 { | |
4045 menu_item_add(menu, _("Exit _full screen"), G_CALLBACK(pan_fullscreen_cb), pw); | |
4046 } | |
4047 else | |
4048 { | |
4049 menu_item_add(menu, _("_Full screen"), G_CALLBACK(pan_fullscreen_cb), pw); | |
4050 } | |
4051 | |
4052 menu_item_add_divider(menu); | |
4053 menu_item_add_stock(menu, _("C_lose window"), GTK_STOCK_CLOSE, G_CALLBACK(pan_close_cb), pw); | |
4054 | |
4055 return menu; | |
4056 } | |
4057 | |
4058 /* | |
4059 *----------------------------------------------------------------------------- | |
4060 * image drag and drop routines | |
4061 *----------------------------------------------------------------------------- | |
4062 */ | |
4063 | |
4064 static void pan_window_get_dnd_data(GtkWidget *widget, GdkDragContext *context, | |
4065 gint x, gint y, | |
4066 GtkSelectionData *selection_data, guint info, | |
4067 guint time, gpointer data) | |
4068 { | |
4069 PanWindow *pw = data; | |
4070 ImageWindow *imd; | |
4071 | |
4072 if (gtk_drag_get_source_widget(context) == pw->imd->image) return; | |
4073 | |
4074 imd = pw->imd; | |
4075 | |
4076 if (info == TARGET_URI_LIST) | |
4077 { | |
4078 GList *list; | |
4079 | |
4080 list = uri_list_from_text(selection_data->data, TRUE); | |
4081 if (list && isdir((gchar *)list->data)) | |
4082 { | |
4083 printf("FIXME: change to this folder: %s\n", (gchar *)list->data); | |
4084 } | |
4085 | |
4086 path_list_free(list); | |
4087 } | |
4088 } | |
4089 | |
4090 static void pan_window_set_dnd_data(GtkWidget *widget, GdkDragContext *context, | |
4091 GtkSelectionData *selection_data, guint info, | |
4092 guint time, gpointer data) | |
4093 { | |
4094 printf("FIXME: set dnd data\n"); | |
4095 } | |
4096 | |
4097 static void pan_window_dnd_init(PanWindow *pw) | |
4098 { | |
4099 ImageWindow *imd; | |
4100 | |
4101 imd = pw->imd; | |
4102 | |
4103 gtk_drag_source_set(imd->image, GDK_BUTTON2_MASK, | |
4104 dnd_file_drag_types, dnd_file_drag_types_count, | |
4105 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); | |
4106 g_signal_connect(G_OBJECT(imd->image), "drag_data_get", | |
4107 G_CALLBACK(pan_window_set_dnd_data), pw); | |
4108 | |
4109 gtk_drag_dest_set(imd->image, | |
4110 GTK_DEST_DEFAULT_MOTION | GTK_DEST_DEFAULT_DROP, | |
4111 dnd_file_drop_types, dnd_file_drop_types_count, | |
4112 GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK); | |
4113 g_signal_connect(G_OBJECT(imd->image), "drag_data_received", | |
4114 G_CALLBACK(pan_window_get_dnd_data), pw); | |
4115 } | |
4116 | |
4117 /* | |
4118 *----------------------------------------------------------------------------- | |
4119 * maintenance (for rename, move, remove) | |
4120 *----------------------------------------------------------------------------- | |
4121 */ | |
4122 |