4 * Copyright (C) 2008 The Geeqie Team
8 * This software is released under the GNU General Public License (GNU GPL).
9 * Please read the included file COPYING for more information.
10 * This software comes with no warranty of any kind, use at your own risk!
15 #include "pan-types.h"
19 *-----------------------------------------------------------------------------
21 *-----------------------------------------------------------------------------
24 void pan_item_free(PanItem *pi)
28 if (pi->pixbuf) g_object_unref(pi->pixbuf);
29 if (pi->fd) file_data_unref(pi->fd);
37 void pan_item_set_key(PanItem *pi, const gchar *key)
44 pi->key = g_strdup(key);
48 void pan_item_added(PanWindow *pw, PanItem *pi)
51 image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height);
54 void pan_item_remove(PanWindow *pw, PanItem *pi)
58 if (pw->click_pi == pi) pw->click_pi = NULL;
59 if (pw->queue_pi == pi) pw->queue_pi = NULL;
60 if (pw->search_pi == pi) pw->search_pi = NULL;
61 pw->queue = g_list_remove(pw->queue, pi);
63 pw->list = g_list_remove(pw->list, pi);
64 image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height);
68 void pan_item_size_by_item(PanItem *pi, PanItem *child, gint border)
70 if (!pi || !child) return;
72 if (pi->x + pi->width < child->x + child->width + border)
73 pi->width = child->x + child->width + border - pi->x;
75 if (pi->y + pi->height < child->y + child->height + border)
76 pi->height = child->y + child->height + border - pi->y;
79 void pan_item_size_coordinates(PanItem *pi, gint border, gint *w, gint *h)
83 if (*w < pi->x + pi->width + border) *w = pi->x + pi->width + border;
84 if (*h < pi->y + pi->height + border) *h = pi->y + pi->height + border;
89 *-----------------------------------------------------------------------------
91 *-----------------------------------------------------------------------------
94 PanItem *pan_item_box_new(PanWindow *pw, FileData *fd, gint x, gint y, gint width, gint height,
96 guint8 base_r, guint8 base_g, guint8 base_b, guint8 base_a,
97 guint8 bord_r, guint8 bord_g, guint8 bord_b, guint8 bord_a)
101 pi = g_new0(PanItem, 1);
102 pi->type = PAN_ITEM_BOX;
109 pi->color_r = base_r;
110 pi->color_g = base_g;
111 pi->color_b = base_b;
112 pi->color_a = base_a;
114 pi->color2_r = bord_r;
115 pi->color2_g = bord_g;
116 pi->color2_b = bord_b;
117 pi->color2_a = bord_a;
118 pi->border = border_size;
120 pw->list = g_list_prepend(pw->list, pi);
125 void pan_item_box_shadow(PanItem *pi, gint offset, gint fade)
129 if (!pi || pi->type != PAN_ITEM_BOX) return;
134 pi->width -= shadow[0];
135 pi->height -= shadow[0];
138 shadow = g_new0(gint, 2);
143 pi->height += offset;
149 gint pan_item_box_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
150 gint x, gint y, gint width, gint height)
165 if (pi->color_a > 254)
167 pixbuf_draw_shadow(pixbuf, pi->x - x + bw, pi->y - y + shadow[0],
168 shadow[0], bh - shadow[0],
169 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
171 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
172 pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + bh,
174 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
176 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
181 a = pi->color_a * PAN_SHADOW_ALPHA >> 8;
182 pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + shadow[0],
184 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
186 PAN_SHADOW_COLOR, a);
190 if (util_clip_region(x, y, width, height,
191 pi->x, pi->y, bw, bh,
194 pixbuf_draw_rect_fill(pixbuf,
195 rx - x, ry - y, rw, rh,
196 pi->color_r, pi->color_g, pi->color_b, pi->color_a);
198 if (util_clip_region(x, y, width, height,
199 pi->x, pi->y, bw, pi->border,
202 pixbuf_draw_rect_fill(pixbuf,
203 rx - x, ry - y, rw, rh,
204 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
206 if (util_clip_region(x, y, width, height,
207 pi->x, pi->y + pi->border, pi->border, bh - pi->border * 2,
210 pixbuf_draw_rect_fill(pixbuf,
211 rx - x, ry - y, rw, rh,
212 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
214 if (util_clip_region(x, y, width, height,
215 pi->x + bw - pi->border, pi->y + pi->border,
216 pi->border, bh - pi->border * 2,
219 pixbuf_draw_rect_fill(pixbuf,
220 rx - x, ry - y, rw, rh,
221 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
223 if (util_clip_region(x, y, width, height,
224 pi->x, pi->y + bh - pi->border,
228 pixbuf_draw_rect_fill(pixbuf,
229 rx - x, ry - y, rw, rh,
230 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
238 *-----------------------------------------------------------------------------
240 *-----------------------------------------------------------------------------
243 PanItem *pan_item_tri_new(PanWindow *pw, FileData *fd, gint x, gint y, gint width, gint height,
244 gint x1, gint y1, gint x2, gint y2, gint x3, gint y3,
245 guint8 r, guint8 g, guint8 b, guint8 a)
250 pi = g_new0(PanItem, 1);
251 pi->type = PAN_ITEM_TRIANGLE;
262 coord = g_new0(gint, 6);
272 pi->border = PAN_BORDER_NONE;
274 pw->list = g_list_prepend(pw->list, pi);
279 void pan_item_tri_border(PanItem *pi, gint borders,
280 guint8 r, guint8 g, guint8 b, guint8 a)
282 if (!pi || pi->type != PAN_ITEM_TRIANGLE) return;
284 pi->border = borders;
292 gint pan_item_tri_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
293 gint x, gint y, gint width, gint height)
297 if (util_clip_region(x, y, width, height,
298 pi->x, pi->y, pi->width, pi->height,
299 &rx, &ry, &rw, &rh) && pi->data)
301 gint *coord = pi->data;
302 pixbuf_draw_triangle(pixbuf,
303 rx - x, ry - y, rw, rh,
304 coord[0] - x, coord[1] - y,
305 coord[2] - x, coord[3] - y,
306 coord[4] - x, coord[5] - y,
307 pi->color_r, pi->color_g, pi->color_b, pi->color_a);
309 if (pi->border & PAN_BORDER_1)
311 pixbuf_draw_line(pixbuf,
312 rx - x, ry - y, rw, rh,
313 coord[0] - x, coord[1] - y,
314 coord[2] - x, coord[3] - y,
315 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
317 if (pi->border & PAN_BORDER_2)
319 pixbuf_draw_line(pixbuf,
320 rx - x, ry - y, rw, rh,
321 coord[2] - x, coord[3] - y,
322 coord[4] - x, coord[5] - y,
323 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
325 if (pi->border & PAN_BORDER_3)
327 pixbuf_draw_line(pixbuf,
328 rx - x, ry - y, rw, rh,
329 coord[4] - x, coord[5] - y,
330 coord[0] - x, coord[1] - y,
331 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
340 *-----------------------------------------------------------------------------
342 *-----------------------------------------------------------------------------
345 static PangoLayout *pan_item_text_layout(PanItem *pi, GtkWidget *widget)
349 layout = gtk_widget_create_pango_layout(widget, NULL);
351 if (pi->text_attr & PAN_TEXT_ATTR_MARKUP)
353 pango_layout_set_markup(layout, pi->text, -1);
357 if (pi->text_attr & PAN_TEXT_ATTR_BOLD ||
358 pi->text_attr & PAN_TEXT_ATTR_HEADING)
363 pal = pango_attr_list_new();
364 if (pi->text_attr & PAN_TEXT_ATTR_BOLD)
366 pa = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
368 pa->end_index = G_MAXINT;
369 pango_attr_list_insert(pal, pa);
371 if (pi->text_attr & PAN_TEXT_ATTR_HEADING)
373 pa = pango_attr_scale_new(PANGO_SCALE_LARGE);
375 pa->end_index = G_MAXINT;
376 pango_attr_list_insert(pal, pa);
378 pango_layout_set_attributes(layout, pal);
379 pango_attr_list_unref(pal);
382 pango_layout_set_text(layout, pi->text, -1);
386 static void pan_item_text_compute_size(PanItem *pi, GtkWidget *widget)
390 if (!pi || !pi->text || !widget) return;
392 layout = pan_item_text_layout(pi, widget);
393 pango_layout_get_pixel_size(layout, &pi->width, &pi->height);
394 g_object_unref(G_OBJECT(layout));
396 pi->width += pi->border * 2;
397 pi->height += pi->border * 2;
400 PanItem *pan_item_text_new(PanWindow *pw, gint x, gint y, const gchar *text,
401 PanTextAttrType attr, PanBorderType border,
402 guint8 r, guint8 g, guint8 b, guint8 a)
406 pi = g_new0(PanItem, 1);
407 pi->type = PAN_ITEM_TEXT;
410 pi->text = g_strdup(text);
411 pi->text_attr = attr;
420 pan_item_text_compute_size(pi, pw->imd->pr);
422 pw->list = g_list_prepend(pw->list, pi);
427 gint pan_item_text_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
428 gint x, gint y, gint width, gint height)
432 layout = pan_item_text_layout(pi, (GtkWidget *)pr);
433 pixbuf_draw_layout(pixbuf, layout, (GtkWidget *)pr,
434 pi->x - x + pi->border, pi->y - y + pi->border,
435 pi->color_r, pi->color_g, pi->color_b, pi->color_a);
436 g_object_unref(G_OBJECT(layout));
443 *-----------------------------------------------------------------------------
444 * item thumbnail type
445 *-----------------------------------------------------------------------------
448 PanItem *pan_item_thumb_new(PanWindow *pw, FileData *fd, gint x, gint y)
452 pi = g_new0(PanItem, 1);
453 pi->type = PAN_ITEM_THUMB;
457 pi->width = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
458 pi->height = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
464 pw->list = g_list_prepend(pw->list, pi);
469 gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
470 gint x, gint y, gint width, gint height)
477 tw = gdk_pixbuf_get_width(pi->pixbuf);
478 th = gdk_pixbuf_get_height(pi->pixbuf);
480 tx = pi->x + (pi->width - tw) / 2;
481 ty = pi->y + (pi->height - th) / 2;
483 if (gdk_pixbuf_get_has_alpha(pi->pixbuf))
485 if (util_clip_region(x, y, width, height,
486 tx + PAN_SHADOW_OFFSET, ty + PAN_SHADOW_OFFSET, tw, th,
489 pixbuf_draw_shadow(pixbuf,
490 rx - x, ry - y, rw, rh,
491 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
493 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
498 if (util_clip_region(x, y, width, height,
499 tx + tw, ty + PAN_SHADOW_OFFSET,
500 PAN_SHADOW_OFFSET, th - PAN_SHADOW_OFFSET,
503 pixbuf_draw_shadow(pixbuf,
504 rx - x, ry - y, rw, rh,
505 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
507 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
509 if (util_clip_region(x, y, width, height,
510 tx + PAN_SHADOW_OFFSET, ty + th, tw, PAN_SHADOW_OFFSET,
513 pixbuf_draw_shadow(pixbuf,
514 rx - x, ry - y, rw, rh,
515 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
517 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
521 if (util_clip_region(x, y, width, height,
525 gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
528 1.0, 1.0, GDK_INTERP_NEAREST,
532 if (util_clip_region(x, y, width, height,
533 tx, ty, tw, PAN_OUTLINE_THICKNESS,
536 pixbuf_draw_rect_fill(pixbuf,
537 rx - x, ry - y, rw, rh,
538 PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
540 if (util_clip_region(x, y, width, height,
541 tx, ty, PAN_OUTLINE_THICKNESS, th,
544 pixbuf_draw_rect_fill(pixbuf,
545 rx - x, ry - y, rw, rh,
546 PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
548 if (util_clip_region(x, y, width, height,
549 tx + tw - PAN_OUTLINE_THICKNESS, ty + PAN_OUTLINE_THICKNESS,
550 PAN_OUTLINE_THICKNESS, th - PAN_OUTLINE_THICKNESS,
553 pixbuf_draw_rect_fill(pixbuf,
554 rx - x, ry - y, rw, rh,
555 PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
557 if (util_clip_region(x, y, width, height,
558 tx + PAN_OUTLINE_THICKNESS, ty + th - PAN_OUTLINE_THICKNESS,
559 tw - PAN_OUTLINE_THICKNESS * 2, PAN_OUTLINE_THICKNESS,
562 pixbuf_draw_rect_fill(pixbuf,
563 rx - x, ry - y, rw, rh,
564 PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
569 tw = pi->width - PAN_SHADOW_OFFSET * 2;
570 th = pi->height - PAN_SHADOW_OFFSET * 2;
571 tx = pi->x + PAN_SHADOW_OFFSET;
572 ty = pi->y + PAN_SHADOW_OFFSET;
574 if (util_clip_region(x, y, width, height,
580 d = (pw->size <= PAN_IMAGE_SIZE_THUMB_NONE) ? 2 : 8;
581 pixbuf_draw_rect_fill(pixbuf,
582 rx - x, ry - y, rw, rh,
584 PAN_SHADOW_ALPHA / d);
588 return (pi->pixbuf == NULL);
593 *-----------------------------------------------------------------------------
595 *-----------------------------------------------------------------------------
598 static void pan_item_image_find_size(PanWindow *pw, PanItem *pi, gint w, gint h)
607 work = pw->cache_list;
615 if (pc->cd && pc->cd->dimensions &&
616 pc->fd && pc->fd == pi->fd)
618 pi->width = MAX(1, pc->cd->width * pw->image_size / 100);
619 pi->height = MAX(1, pc->cd->height * pw->image_size / 100);
621 pw->cache_list = g_list_remove(pw->cache_list, pc);
622 cache_sim_data_free(pc->cd);
623 file_data_unref(pc->fd);
630 PanItem *pan_item_image_new(PanWindow *pw, FileData *fd, gint x, gint y, gint w, gint h)
634 pi = g_new0(PanItem, 1);
635 pi->type = PAN_ITEM_IMAGE;
645 pi->color2_a = PAN_SHADOW_ALPHA / 2;
647 pan_item_image_find_size(pw, pi, w, h);
649 pw->list = g_list_prepend(pw->list, pi);
654 gint pan_item_image_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
655 gint x, gint y, gint width, gint height)
659 if (util_clip_region(x, y, width, height,
660 pi->x, pi->y, pi->width, pi->height,
665 gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
668 1.0, 1.0, GDK_INTERP_NEAREST,
673 pixbuf_draw_rect_fill(pixbuf,
674 rx - x, ry - y, rw, rh,
675 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
679 return (pi->pixbuf == NULL);
684 *-----------------------------------------------------------------------------
686 *-----------------------------------------------------------------------------
689 PanItem *pan_item_find_by_key(PanWindow *pw, PanItemType type, const gchar *key)
693 if (!key) return NULL;
695 work = g_list_last(pw->list);
701 if ((pi->type == type || type == PAN_ITEM_NONE) &&
702 pi->key && strcmp(pi->key, key) == 0)
708 work = g_list_last(pw->list_static);
714 if ((pi->type == type || type == PAN_ITEM_NONE) &&
715 pi->key && strcmp(pi->key, key) == 0)
725 /* when ignore_case and partial are TRUE, path should be converted to lower case */
726 static GList *pan_item_find_by_path_l(GList *list, GList *search_list,
727 PanItemType type, const gchar *path,
728 gint ignore_case, gint partial)
732 work = g_list_last(search_list);
738 if ((pi->type == type || type == PAN_ITEM_NONE) && pi->fd)
742 if (path[0] == G_DIR_SEPARATOR)
744 if (pi->fd->path && strcmp(path, pi->fd->path) == 0) match = TRUE;
746 else if (pi->fd->name)
754 haystack = g_utf8_strdown(pi->fd->name, -1);
755 match = (strstr(haystack, path) != NULL);
760 if (strstr(pi->fd->name, path)) match = TRUE;
763 else if (ignore_case)
765 if (strcasecmp(path, pi->fd->name) == 0) match = TRUE;
769 if (strcmp(path, pi->fd->name) == 0) match = TRUE;
773 if (match) list = g_list_prepend(list, pi);
781 /* when ignore_case and partial are TRUE, path should be converted to lower case */
782 GList *pan_item_find_by_path(PanWindow *pw, PanItemType type, const gchar *path,
783 gint ignore_case, gint partial)
787 if (!path) return NULL;
788 if (partial && path[0] == G_DIR_SEPARATOR) return NULL;
790 list = pan_item_find_by_path_l(list, pw->list_static, type, path, ignore_case, partial);
791 list = pan_item_find_by_path_l(list, pw->list, type, path, ignore_case, partial);
793 return g_list_reverse(list);
796 static PanItem *pan_item_find_by_coord_l(GList *list, PanItemType type, gint x, gint y, const gchar *key)
806 if ((pi->type == type || type == PAN_ITEM_NONE) &&
807 x >= pi->x && x < pi->x + pi->width &&
808 y >= pi->y && y < pi->y + pi->height &&
809 (!key || (pi->key && strcmp(pi->key, key) == 0)))
819 PanItem *pan_item_find_by_coord(PanWindow *pw, PanItemType type,
820 gint x, gint y, const gchar *key)
824 pi = pan_item_find_by_coord_l(pw->list, type, x, y, key);
827 return pan_item_find_by_coord_l(pw->list_static, type, x, y, key);
832 *-----------------------------------------------------------------------------
834 *-----------------------------------------------------------------------------
837 PanTextAlignment *pan_text_alignment_new(PanWindow *pw, gint x, gint y, const gchar *key)
839 PanTextAlignment *ta;
841 ta = g_new0(PanTextAlignment, 1);
848 ta->key = g_strdup(key);
853 void pan_text_alignment_free(PanTextAlignment *ta)
857 g_list_free(ta->column1);
858 g_list_free(ta->column2);
863 PanItem *pan_text_alignment_add(PanTextAlignment *ta, const gchar *label, const gchar *text)
869 item = pan_item_text_new(ta->pw, ta->x, ta->y, label,
870 PAN_TEXT_ATTR_BOLD, 0,
871 PAN_POPUP_TEXT_COLOR, 255);
872 pan_item_set_key(item, ta->key);
878 ta->column1 = g_list_append(ta->column1, item);
882 item = pan_item_text_new(ta->pw, ta->x, ta->y, text,
883 PAN_TEXT_ATTR_NONE, 0,
884 PAN_POPUP_TEXT_COLOR, 255);
885 pan_item_set_key(item, ta->key);
891 ta->column2 = g_list_append(ta->column2, item);
896 void pan_text_alignment_calc(PanTextAlignment *ta, PanItem *box)
914 if (p && p->width > cw1) cw1 = p->width;
925 if (p && p->width > cw2) cw2 = p->width;
932 while (work1 && work2)
947 pan_item_size_by_item(box, p1, PREF_PAD_BORDER);
952 p2->x = x + cw1 + PREF_PAD_SPACE;
954 pan_item_size_by_item(box, p2, PREF_PAD_BORDER);
955 if (height < p2->height) height = p2->height;
958 if (!p1 && !p2) height = PREF_PAD_GROUP;