2 * Copyright (C) 2006 John Ellis
3 * Copyright (C) 2008 - 2016 The Geeqie Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include "pan-types.h"
27 *-----------------------------------------------------------------------------
29 *-----------------------------------------------------------------------------
32 void pan_item_free(PanItem *pi)
36 if (pi->pixbuf) g_object_unref(pi->pixbuf);
37 if (pi->fd) file_data_unref(pi->fd);
45 void pan_item_set_key(PanItem *pi, const gchar *key)
52 pi->key = g_strdup(key);
56 void pan_item_added(PanWindow *pw, PanItem *pi)
59 image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height);
62 void pan_item_remove(PanWindow *pw, PanItem *pi)
66 if (pw->click_pi == pi) pw->click_pi = NULL;
67 if (pw->queue_pi == pi) pw->queue_pi = NULL;
68 if (pw->search_pi == pi) pw->search_pi = NULL;
69 pw->queue = g_list_remove(pw->queue, pi);
71 pw->list = g_list_remove(pw->list, pi);
72 image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height);
76 void pan_item_size_by_item(PanItem *pi, PanItem *child, gint border)
78 if (!pi || !child) return;
80 if (pi->x + pi->width < child->x + child->width + border)
81 pi->width = child->x + child->width + border - pi->x;
83 if (pi->y + pi->height < child->y + child->height + border)
84 pi->height = child->y + child->height + border - pi->y;
87 void pan_item_size_coordinates(PanItem *pi, gint border, gint *w, gint *h)
91 if (*w < pi->x + pi->width + border) *w = pi->x + pi->width + border;
92 if (*h < pi->y + pi->height + border) *h = pi->y + pi->height + border;
97 *-----------------------------------------------------------------------------
99 *-----------------------------------------------------------------------------
102 PanItem *pan_item_box_new(PanWindow *pw, FileData *fd, gint x, gint y, gint width, gint height,
104 guint8 base_r, guint8 base_g, guint8 base_b, guint8 base_a,
105 guint8 bord_r, guint8 bord_g, guint8 bord_b, guint8 bord_a)
109 pi = g_new0(PanItem, 1);
110 pi->type = PAN_ITEM_BOX;
117 pi->color_r = base_r;
118 pi->color_g = base_g;
119 pi->color_b = base_b;
120 pi->color_a = base_a;
122 pi->color2_r = bord_r;
123 pi->color2_g = bord_g;
124 pi->color2_b = bord_b;
125 pi->color2_a = bord_a;
126 pi->border = border_size;
128 pw->list = g_list_prepend(pw->list, pi);
133 void pan_item_box_shadow(PanItem *pi, gint offset, gint fade)
137 if (!pi || pi->type != PAN_ITEM_BOX) return;
142 pi->width -= shadow[0];
143 pi->height -= shadow[0];
146 shadow = g_new0(gint, 2);
151 pi->height += offset;
157 gint pan_item_box_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
158 gint x, gint y, gint width, gint height)
173 if (pi->color_a > 254)
175 pixbuf_draw_shadow(pixbuf, pi->x - x + bw, pi->y - y + shadow[0],
176 shadow[0], bh - shadow[0],
177 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
179 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
180 pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + bh,
182 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
184 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
189 a = pi->color_a * PAN_SHADOW_ALPHA >> 8;
190 pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + shadow[0],
192 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
194 PAN_SHADOW_COLOR, a);
198 if (util_clip_region(x, y, width, height,
199 pi->x, pi->y, bw, bh,
202 pixbuf_draw_rect_fill(pixbuf,
203 rx - x, ry - y, rw, rh,
204 pi->color_r, pi->color_g, pi->color_b, pi->color_a);
206 if (util_clip_region(x, y, width, height,
207 pi->x, pi->y, bw, pi->border,
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, pi->y + pi->border, pi->border, bh - pi->border * 2,
218 pixbuf_draw_rect_fill(pixbuf,
219 rx - x, ry - y, rw, rh,
220 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
222 if (util_clip_region(x, y, width, height,
223 pi->x + bw - pi->border, pi->y + pi->border,
224 pi->border, bh - pi->border * 2,
227 pixbuf_draw_rect_fill(pixbuf,
228 rx - x, ry - y, rw, rh,
229 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
231 if (util_clip_region(x, y, width, height,
232 pi->x, pi->y + bh - pi->border,
236 pixbuf_draw_rect_fill(pixbuf,
237 rx - x, ry - y, rw, rh,
238 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
246 *-----------------------------------------------------------------------------
248 *-----------------------------------------------------------------------------
251 PanItem *pan_item_tri_new(PanWindow *pw, FileData *fd, gint x, gint y, gint width, gint height,
252 gint x1, gint y1, gint x2, gint y2, gint x3, gint y3,
253 guint8 r, guint8 g, guint8 b, guint8 a)
258 pi = g_new0(PanItem, 1);
259 pi->type = PAN_ITEM_TRIANGLE;
270 coord = g_new0(gint, 6);
280 pi->border = PAN_BORDER_NONE;
282 pw->list = g_list_prepend(pw->list, pi);
287 void pan_item_tri_border(PanItem *pi, gint borders,
288 guint8 r, guint8 g, guint8 b, guint8 a)
290 if (!pi || pi->type != PAN_ITEM_TRIANGLE) return;
292 pi->border = borders;
300 gint pan_item_tri_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
301 gint x, gint y, gint width, gint height)
305 if (util_clip_region(x, y, width, height,
306 pi->x, pi->y, pi->width, pi->height,
307 &rx, &ry, &rw, &rh) && pi->data)
309 gint *coord = pi->data;
310 pixbuf_draw_triangle(pixbuf,
311 rx - x, ry - y, rw, rh,
312 coord[0] - x, coord[1] - y,
313 coord[2] - x, coord[3] - y,
314 coord[4] - x, coord[5] - y,
315 pi->color_r, pi->color_g, pi->color_b, pi->color_a);
317 if (pi->border & PAN_BORDER_1)
319 pixbuf_draw_line(pixbuf,
320 rx - x, ry - y, rw, rh,
321 coord[0] - x, coord[1] - y,
322 coord[2] - x, coord[3] - y,
323 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
325 if (pi->border & PAN_BORDER_2)
327 pixbuf_draw_line(pixbuf,
328 rx - x, ry - y, rw, rh,
329 coord[2] - x, coord[3] - y,
330 coord[4] - x, coord[5] - y,
331 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
333 if (pi->border & PAN_BORDER_3)
335 pixbuf_draw_line(pixbuf,
336 rx - x, ry - y, rw, rh,
337 coord[4] - x, coord[5] - y,
338 coord[0] - x, coord[1] - y,
339 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
348 *-----------------------------------------------------------------------------
350 *-----------------------------------------------------------------------------
353 static PangoLayout *pan_item_text_layout(PanItem *pi, GtkWidget *widget)
357 layout = gtk_widget_create_pango_layout(widget, NULL);
359 if (pi->text_attr & PAN_TEXT_ATTR_MARKUP)
361 pango_layout_set_markup(layout, pi->text, -1);
365 if (pi->text_attr & PAN_TEXT_ATTR_BOLD ||
366 pi->text_attr & PAN_TEXT_ATTR_HEADING)
371 pal = pango_attr_list_new();
372 if (pi->text_attr & PAN_TEXT_ATTR_BOLD)
374 pa = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
376 pa->end_index = G_MAXINT;
377 pango_attr_list_insert(pal, pa);
379 if (pi->text_attr & PAN_TEXT_ATTR_HEADING)
381 pa = pango_attr_scale_new(PANGO_SCALE_LARGE);
383 pa->end_index = G_MAXINT;
384 pango_attr_list_insert(pal, pa);
386 pango_layout_set_attributes(layout, pal);
387 pango_attr_list_unref(pal);
390 pango_layout_set_text(layout, pi->text, -1);
394 static void pan_item_text_compute_size(PanItem *pi, GtkWidget *widget)
398 if (!pi || !pi->text || !widget) return;
400 layout = pan_item_text_layout(pi, widget);
401 pango_layout_get_pixel_size(layout, &pi->width, &pi->height);
402 g_object_unref(G_OBJECT(layout));
404 pi->width += pi->border * 2;
405 pi->height += pi->border * 2;
408 PanItem *pan_item_text_new(PanWindow *pw, gint x, gint y, const gchar *text,
409 PanTextAttrType attr, PanBorderType border,
410 guint8 r, guint8 g, guint8 b, guint8 a)
414 pi = g_new0(PanItem, 1);
415 pi->type = PAN_ITEM_TEXT;
418 pi->text = g_strdup(text);
419 pi->text_attr = attr;
428 pan_item_text_compute_size(pi, pw->imd->pr);
430 pw->list = g_list_prepend(pw->list, pi);
435 gint pan_item_text_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
436 gint x, gint y, gint width, gint height)
440 layout = pan_item_text_layout(pi, (GtkWidget *)pr);
441 pixbuf_draw_layout(pixbuf, layout, (GtkWidget *)pr,
442 pi->x - x + pi->border, pi->y - y + pi->border,
443 pi->color_r, pi->color_g, pi->color_b, pi->color_a);
444 g_object_unref(G_OBJECT(layout));
451 *-----------------------------------------------------------------------------
452 * item thumbnail type
453 *-----------------------------------------------------------------------------
456 PanItem *pan_item_thumb_new(PanWindow *pw, FileData *fd, gint x, gint y)
460 pi = g_new0(PanItem, 1);
462 pi->type = PAN_ITEM_THUMB;
466 pi->width = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
467 pi->height = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
469 pw->list = g_list_prepend(pw->list, pi);
474 gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
475 gint x, gint y, gint width, gint height)
482 tw = gdk_pixbuf_get_width(pi->pixbuf);
483 th = gdk_pixbuf_get_height(pi->pixbuf);
485 tx = pi->x + (pi->width - tw) / 2;
486 ty = pi->y + (pi->height - th) / 2;
488 if (gdk_pixbuf_get_has_alpha(pi->pixbuf))
490 if (util_clip_region(x, y, width, height,
491 tx + PAN_SHADOW_OFFSET, ty + PAN_SHADOW_OFFSET, tw, th,
494 pixbuf_draw_shadow(pixbuf,
495 rx - x, ry - y, rw, rh,
496 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
498 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
503 if (util_clip_region(x, y, width, height,
504 tx + tw, ty + PAN_SHADOW_OFFSET,
505 PAN_SHADOW_OFFSET, th - PAN_SHADOW_OFFSET,
508 pixbuf_draw_shadow(pixbuf,
509 rx - x, ry - y, rw, rh,
510 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
512 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
514 if (util_clip_region(x, y, width, height,
515 tx + PAN_SHADOW_OFFSET, ty + th, tw, PAN_SHADOW_OFFSET,
518 pixbuf_draw_shadow(pixbuf,
519 rx - x, ry - y, rw, rh,
520 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
522 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
526 if (util_clip_region(x, y, width, height,
530 gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
533 1.0, 1.0, GDK_INTERP_NEAREST,
537 if (util_clip_region(x, y, width, height,
538 tx, ty, tw, PAN_OUTLINE_THICKNESS,
541 pixbuf_draw_rect_fill(pixbuf,
542 rx - x, ry - y, rw, rh,
543 PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
545 if (util_clip_region(x, y, width, height,
546 tx, ty, PAN_OUTLINE_THICKNESS, th,
549 pixbuf_draw_rect_fill(pixbuf,
550 rx - x, ry - y, rw, rh,
551 PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
553 if (util_clip_region(x, y, width, height,
554 tx + tw - PAN_OUTLINE_THICKNESS, ty + PAN_OUTLINE_THICKNESS,
555 PAN_OUTLINE_THICKNESS, th - PAN_OUTLINE_THICKNESS,
558 pixbuf_draw_rect_fill(pixbuf,
559 rx - x, ry - y, rw, rh,
560 PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
562 if (util_clip_region(x, y, width, height,
563 tx + PAN_OUTLINE_THICKNESS, ty + th - PAN_OUTLINE_THICKNESS,
564 tw - PAN_OUTLINE_THICKNESS * 2, PAN_OUTLINE_THICKNESS,
567 pixbuf_draw_rect_fill(pixbuf,
568 rx - x, ry - y, rw, rh,
569 PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
574 tw = pi->width - PAN_SHADOW_OFFSET * 2;
575 th = pi->height - PAN_SHADOW_OFFSET * 2;
576 tx = pi->x + PAN_SHADOW_OFFSET;
577 ty = pi->y + PAN_SHADOW_OFFSET;
579 if (util_clip_region(x, y, width, height,
585 d = (pw->size <= PAN_IMAGE_SIZE_THUMB_NONE) ? 2 : 8;
586 pixbuf_draw_rect_fill(pixbuf,
587 rx - x, ry - y, rw, rh,
589 PAN_SHADOW_ALPHA / d);
593 return (pi->pixbuf == NULL);
598 *-----------------------------------------------------------------------------
600 *-----------------------------------------------------------------------------
603 static void pan_item_image_find_size(PanWindow *pw, PanItem *pi, gint w, gint h)
612 work = pw->cache_list;
620 if (pc->cd && pc->cd->dimensions &&
621 pc->fd && pc->fd == pi->fd)
623 pi->width = MAX(1, pc->cd->width * pw->image_size / 100);
624 pi->height = MAX(1, pc->cd->height * pw->image_size / 100);
626 pw->cache_list = g_list_remove(pw->cache_list, pc);
627 cache_sim_data_free(pc->cd);
628 file_data_unref(pc->fd);
635 PanItem *pan_item_image_new(PanWindow *pw, FileData *fd, gint x, gint y, gint w, gint h)
639 pi = g_new0(PanItem, 1);
640 pi->type = PAN_ITEM_IMAGE;
650 pi->color2_a = PAN_SHADOW_ALPHA / 2;
652 pan_item_image_find_size(pw, pi, w, h);
654 pw->list = g_list_prepend(pw->list, pi);
659 gint pan_item_image_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
660 gint x, gint y, gint width, gint height)
664 if (util_clip_region(x, y, width, height,
665 pi->x, pi->y, pi->width, pi->height,
670 gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
673 1.0, 1.0, GDK_INTERP_NEAREST,
678 pixbuf_draw_rect_fill(pixbuf,
679 rx - x, ry - y, rw, rh,
680 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
684 return (pi->pixbuf == NULL);
689 *-----------------------------------------------------------------------------
691 *-----------------------------------------------------------------------------
694 PanItem *pan_item_find_by_key(PanWindow *pw, PanItemType type, const gchar *key)
698 if (!key) return NULL;
700 work = g_list_last(pw->list);
706 if ((pi->type == type || type == PAN_ITEM_NONE) &&
707 pi->key && strcmp(pi->key, key) == 0)
713 work = g_list_last(pw->list_static);
719 if ((pi->type == type || type == PAN_ITEM_NONE) &&
720 pi->key && strcmp(pi->key, key) == 0)
730 /* when ignore_case and partial are TRUE, path should be converted to lower case */
731 static GList *pan_item_find_by_path_l(GList *list, GList *search_list,
732 PanItemType type, const gchar *path,
733 gboolean ignore_case, gboolean partial)
737 work = g_list_last(search_list);
743 if ((pi->type == type || type == PAN_ITEM_NONE) && pi->fd)
745 gboolean match = FALSE;
747 if (path[0] == G_DIR_SEPARATOR)
749 if (pi->fd->path && strcmp(path, pi->fd->path) == 0) match = TRUE;
751 else if (pi->fd->name)
759 haystack = g_utf8_strdown(pi->fd->name, -1);
760 match = (strstr(haystack, path) != NULL);
765 if (strstr(pi->fd->name, path)) match = TRUE;
768 else if (ignore_case)
770 if (g_ascii_strcasecmp(path, pi->fd->name) == 0) match = TRUE;
774 if (strcmp(path, pi->fd->name) == 0) match = TRUE;
778 if (match) list = g_list_prepend(list, pi);
786 /* when ignore_case and partial are TRUE, path should be converted to lower case */
787 GList *pan_item_find_by_path(PanWindow *pw, PanItemType type, const gchar *path,
788 gboolean ignore_case, gboolean partial)
792 if (!path) return NULL;
793 if (partial && path[0] == G_DIR_SEPARATOR) return NULL;
795 list = pan_item_find_by_path_l(list, pw->list_static, type, path, ignore_case, partial);
796 list = pan_item_find_by_path_l(list, pw->list, type, path, ignore_case, partial);
798 return g_list_reverse(list);
801 GList *pan_item_find_by_fd(PanWindow *pw, PanItemType type, FileData *fd,
802 gboolean ignore_case, gboolean partial)
804 if (!fd) return NULL;
805 return pan_item_find_by_path(pw, type, fd->path, ignore_case, partial);
809 static PanItem *pan_item_find_by_coord_l(GList *list, PanItemType type, gint x, gint y, const gchar *key)
819 if ((pi->type == type || type == PAN_ITEM_NONE) &&
820 x >= pi->x && x < pi->x + pi->width &&
821 y >= pi->y && y < pi->y + pi->height &&
822 (!key || (pi->key && strcmp(pi->key, key) == 0)))
832 PanItem *pan_item_find_by_coord(PanWindow *pw, PanItemType type,
833 gint x, gint y, const gchar *key)
837 pi = pan_item_find_by_coord_l(pw->list, type, x, y, key);
840 return pan_item_find_by_coord_l(pw->list_static, type, x, y, key);
845 *-----------------------------------------------------------------------------
847 *-----------------------------------------------------------------------------
850 PanTextAlignment *pan_text_alignment_new(PanWindow *pw, gint x, gint y, const gchar *key)
852 PanTextAlignment *ta;
854 ta = g_new0(PanTextAlignment, 1);
859 ta->key = g_strdup(key);
864 void pan_text_alignment_free(PanTextAlignment *ta)
868 g_list_free(ta->column1);
869 g_list_free(ta->column2);
874 PanItem *pan_text_alignment_add(PanTextAlignment *ta, const gchar *label, const gchar *text)
880 item = pan_item_text_new(ta->pw, ta->x, ta->y, label,
881 PAN_TEXT_ATTR_BOLD, 0,
882 PAN_POPUP_TEXT_COLOR, 255);
883 pan_item_set_key(item, ta->key);
889 ta->column1 = g_list_append(ta->column1, item);
893 item = pan_item_text_new(ta->pw, ta->x, ta->y, text,
894 PAN_TEXT_ATTR_NONE, 0,
895 PAN_POPUP_TEXT_COLOR, 255);
896 pan_item_set_key(item, ta->key);
902 ta->column2 = g_list_append(ta->column2, item);
907 void pan_text_alignment_calc(PanTextAlignment *ta, PanItem *box)
925 if (p && p->width > cw1) cw1 = p->width;
936 if (p && p->width > cw2) cw2 = p->width;
943 while (work1 && work2)
958 pan_item_size_by_item(box, p1, PREF_PAD_BORDER);
963 p2->x = x + cw1 + PREF_PAD_SPACE;
965 pan_item_size_by_item(box, p2, PREF_PAD_BORDER);
966 if (height < p2->height) height = p2->height;
969 if (!p1 && !p2) height = PREF_PAD_GROUP;
974 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */