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.
25 #include "pixbuf-util.h"
29 *-----------------------------------------------------------------------------
31 *-----------------------------------------------------------------------------
34 void pan_item_free(PanItem *pi)
38 if (pi->pixbuf) g_object_unref(pi->pixbuf);
39 if (pi->fd) file_data_unref(pi->fd);
47 void pan_item_set_key(PanItem *pi, const gchar *key)
54 pi->key = g_strdup(key);
58 void pan_item_added(PanWindow *pw, PanItem *pi)
61 image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height);
64 void pan_item_remove(PanWindow *pw, PanItem *pi)
68 if (pw->click_pi == pi) pw->click_pi = NULL;
69 if (pw->queue_pi == pi) pw->queue_pi = NULL;
70 if (pw->search_pi == pi) pw->search_pi = NULL;
71 pw->queue = g_list_remove(pw->queue, pi);
73 pw->list = g_list_remove(pw->list, pi);
74 image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height);
78 void pan_item_size_by_item(PanItem *pi, PanItem *child, gint border)
80 if (!pi || !child) return;
82 if (pi->x + pi->width < child->x + child->width + border)
83 pi->width = child->x + child->width + border - pi->x;
85 if (pi->y + pi->height < child->y + child->height + border)
86 pi->height = child->y + child->height + border - pi->y;
89 void pan_item_size_coordinates(PanItem *pi, gint border, gint *w, gint *h)
93 if (*w < pi->x + pi->width + border) *w = pi->x + pi->width + border;
94 if (*h < pi->y + pi->height + border) *h = pi->y + pi->height + border;
99 *-----------------------------------------------------------------------------
101 *-----------------------------------------------------------------------------
104 PanItem *pan_item_box_new(PanWindow *pw, FileData *fd, gint x, gint y, gint width, gint height,
106 guint8 base_r, guint8 base_g, guint8 base_b, guint8 base_a,
107 guint8 bord_r, guint8 bord_g, guint8 bord_b, guint8 bord_a)
111 pi = g_new0(PanItem, 1);
112 pi->type = PAN_ITEM_BOX;
119 pi->color_r = base_r;
120 pi->color_g = base_g;
121 pi->color_b = base_b;
122 pi->color_a = base_a;
124 pi->color2_r = bord_r;
125 pi->color2_g = bord_g;
126 pi->color2_b = bord_b;
127 pi->color2_a = bord_a;
128 pi->border = border_size;
130 pw->list = g_list_prepend(pw->list, pi);
135 void pan_item_box_shadow(PanItem *pi, gint offset, gint fade)
139 if (!pi || pi->type != PAN_ITEM_BOX) return;
144 pi->width -= shadow[0];
145 pi->height -= shadow[0];
148 shadow = g_new0(gint, 2);
153 pi->height += offset;
159 gint pan_item_box_draw(PanWindow *UNUSED(pw), PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *UNUSED(pr),
160 gint x, gint y, gint width, gint height)
175 if (pi->color_a > 254)
177 pixbuf_draw_shadow(pixbuf, pi->x - x + bw, pi->y - y + shadow[0],
178 shadow[0], bh - shadow[0],
179 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
181 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
182 pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + bh,
184 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
186 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
191 a = pi->color_a * PAN_SHADOW_ALPHA >> 8;
192 pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + shadow[0],
194 pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
196 PAN_SHADOW_COLOR, a);
200 if (util_clip_region(x, y, width, height,
201 pi->x, pi->y, bw, bh,
204 pixbuf_draw_rect_fill(pixbuf,
205 rx - x, ry - y, rw, rh,
206 pi->color_r, pi->color_g, pi->color_b, pi->color_a);
208 if (util_clip_region(x, y, width, height,
209 pi->x, pi->y, bw, pi->border,
212 pixbuf_draw_rect_fill(pixbuf,
213 rx - x, ry - y, rw, rh,
214 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
216 if (util_clip_region(x, y, width, height,
217 pi->x, pi->y + pi->border, pi->border, bh - pi->border * 2,
220 pixbuf_draw_rect_fill(pixbuf,
221 rx - x, ry - y, rw, rh,
222 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
224 if (util_clip_region(x, y, width, height,
225 pi->x + bw - pi->border, pi->y + pi->border,
226 pi->border, bh - pi->border * 2,
229 pixbuf_draw_rect_fill(pixbuf,
230 rx - x, ry - y, rw, rh,
231 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
233 if (util_clip_region(x, y, width, height,
234 pi->x, pi->y + bh - pi->border,
238 pixbuf_draw_rect_fill(pixbuf,
239 rx - x, ry - y, rw, rh,
240 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
248 *-----------------------------------------------------------------------------
250 *-----------------------------------------------------------------------------
253 PanItem *pan_item_tri_new(PanWindow *pw, FileData *UNUSED(fd), gint x, gint y, gint width, gint height,
254 gint x1, gint y1, gint x2, gint y2, gint x3, gint y3,
255 guint8 r, guint8 g, guint8 b, guint8 a)
260 pi = g_new0(PanItem, 1);
261 pi->type = PAN_ITEM_TRIANGLE;
272 coord = g_new0(gint, 6);
282 pi->border = PAN_BORDER_NONE;
284 pw->list = g_list_prepend(pw->list, pi);
289 void pan_item_tri_border(PanItem *pi, gint borders,
290 guint8 r, guint8 g, guint8 b, guint8 a)
292 if (!pi || pi->type != PAN_ITEM_TRIANGLE) return;
294 pi->border = borders;
302 gint pan_item_tri_draw(PanWindow *UNUSED(pw), PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *UNUSED(pr),
303 gint x, gint y, gint width, gint height)
307 if (util_clip_region(x, y, width, height,
308 pi->x, pi->y, pi->width, pi->height,
309 &rx, &ry, &rw, &rh) && pi->data)
311 gint *coord = pi->data;
312 pixbuf_draw_triangle(pixbuf,
313 rx - x, ry - y, rw, rh,
314 coord[0] - x, coord[1] - y,
315 coord[2] - x, coord[3] - y,
316 coord[4] - x, coord[5] - y,
317 pi->color_r, pi->color_g, pi->color_b, pi->color_a);
319 if (pi->border & PAN_BORDER_1)
321 pixbuf_draw_line(pixbuf,
322 rx - x, ry - y, rw, rh,
323 coord[0] - x, coord[1] - y,
324 coord[2] - x, coord[3] - y,
325 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
327 if (pi->border & PAN_BORDER_2)
329 pixbuf_draw_line(pixbuf,
330 rx - x, ry - y, rw, rh,
331 coord[2] - x, coord[3] - y,
332 coord[4] - x, coord[5] - y,
333 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
335 if (pi->border & PAN_BORDER_3)
337 pixbuf_draw_line(pixbuf,
338 rx - x, ry - y, rw, rh,
339 coord[4] - x, coord[5] - y,
340 coord[0] - x, coord[1] - y,
341 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
350 *-----------------------------------------------------------------------------
352 *-----------------------------------------------------------------------------
355 static PangoLayout *pan_item_text_layout(PanItem *pi, GtkWidget *widget)
359 layout = gtk_widget_create_pango_layout(widget, NULL);
361 if (pi->text_attr & PAN_TEXT_ATTR_MARKUP)
363 pango_layout_set_markup(layout, pi->text, -1);
367 if (pi->text_attr & PAN_TEXT_ATTR_BOLD ||
368 pi->text_attr & PAN_TEXT_ATTR_HEADING)
373 pal = pango_attr_list_new();
374 if (pi->text_attr & PAN_TEXT_ATTR_BOLD)
376 pa = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
378 pa->end_index = G_MAXINT;
379 pango_attr_list_insert(pal, pa);
381 if (pi->text_attr & PAN_TEXT_ATTR_HEADING)
383 pa = pango_attr_scale_new(PANGO_SCALE_LARGE);
385 pa->end_index = G_MAXINT;
386 pango_attr_list_insert(pal, pa);
388 pango_layout_set_attributes(layout, pal);
389 pango_attr_list_unref(pal);
392 pango_layout_set_text(layout, pi->text, -1);
396 static void pan_item_text_compute_size(PanItem *pi, GtkWidget *widget)
400 if (!pi || !pi->text || !widget) return;
402 layout = pan_item_text_layout(pi, widget);
403 pango_layout_get_pixel_size(layout, &pi->width, &pi->height);
404 g_object_unref(G_OBJECT(layout));
406 pi->width += pi->border * 2;
407 pi->height += pi->border * 2;
410 PanItem *pan_item_text_new(PanWindow *pw, gint x, gint y, const gchar *text,
411 PanTextAttrType attr, PanBorderType border,
412 guint8 r, guint8 g, guint8 b, guint8 a)
416 pi = g_new0(PanItem, 1);
417 pi->type = PAN_ITEM_TEXT;
420 pi->text = g_strdup(text);
421 pi->text_attr = attr;
430 pan_item_text_compute_size(pi, pw->imd->pr);
432 pw->list = g_list_prepend(pw->list, pi);
437 gint pan_item_text_draw(PanWindow *UNUSED(pw), PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
438 gint x, gint y, gint UNUSED(width), gint UNUSED(height))
442 layout = pan_item_text_layout(pi, (GtkWidget *)pr);
443 pixbuf_draw_layout(pixbuf, layout, (GtkWidget *)pr,
444 pi->x - x + pi->border, pi->y - y + pi->border,
445 pi->color_r, pi->color_g, pi->color_b, pi->color_a);
446 g_object_unref(G_OBJECT(layout));
453 *-----------------------------------------------------------------------------
454 * item thumbnail type
455 *-----------------------------------------------------------------------------
458 PanItem *pan_item_thumb_new(PanWindow *pw, FileData *fd, gint x, gint y)
462 pi = g_new0(PanItem, 1);
464 pi->type = PAN_ITEM_THUMB;
468 pi->width = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
469 pi->height = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
471 pw->list = g_list_prepend(pw->list, pi);
476 gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *UNUSED(pr),
477 gint x, gint y, gint width, gint height)
484 tw = gdk_pixbuf_get_width(pi->pixbuf);
485 th = gdk_pixbuf_get_height(pi->pixbuf);
487 tx = pi->x + (pi->width - tw) / 2;
488 ty = pi->y + (pi->height - th) / 2;
490 if (gdk_pixbuf_get_has_alpha(pi->pixbuf))
492 if (util_clip_region(x, y, width, height,
493 tx + PAN_SHADOW_OFFSET, ty + PAN_SHADOW_OFFSET, tw, th,
496 pixbuf_draw_shadow(pixbuf,
497 rx - x, ry - y, rw, rh,
498 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
500 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
505 if (util_clip_region(x, y, width, height,
506 tx + tw, ty + PAN_SHADOW_OFFSET,
507 PAN_SHADOW_OFFSET, th - PAN_SHADOW_OFFSET,
510 pixbuf_draw_shadow(pixbuf,
511 rx - x, ry - y, rw, rh,
512 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
514 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
516 if (util_clip_region(x, y, width, height,
517 tx + PAN_SHADOW_OFFSET, ty + th, tw, PAN_SHADOW_OFFSET,
520 pixbuf_draw_shadow(pixbuf,
521 rx - x, ry - y, rw, rh,
522 tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
524 PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
528 if (util_clip_region(x, y, width, height,
532 gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
535 1.0, 1.0, GDK_INTERP_NEAREST,
539 if (util_clip_region(x, y, width, height,
540 tx, ty, tw, PAN_OUTLINE_THICKNESS,
543 pixbuf_draw_rect_fill(pixbuf,
544 rx - x, ry - y, rw, rh,
545 PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
547 if (util_clip_region(x, y, width, height,
548 tx, ty, PAN_OUTLINE_THICKNESS, th,
551 pixbuf_draw_rect_fill(pixbuf,
552 rx - x, ry - y, rw, rh,
553 PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
555 if (util_clip_region(x, y, width, height,
556 tx + tw - PAN_OUTLINE_THICKNESS, ty + PAN_OUTLINE_THICKNESS,
557 PAN_OUTLINE_THICKNESS, th - PAN_OUTLINE_THICKNESS,
560 pixbuf_draw_rect_fill(pixbuf,
561 rx - x, ry - y, rw, rh,
562 PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
564 if (util_clip_region(x, y, width, height,
565 tx + PAN_OUTLINE_THICKNESS, ty + th - PAN_OUTLINE_THICKNESS,
566 tw - PAN_OUTLINE_THICKNESS * 2, PAN_OUTLINE_THICKNESS,
569 pixbuf_draw_rect_fill(pixbuf,
570 rx - x, ry - y, rw, rh,
571 PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
576 tw = pi->width - PAN_SHADOW_OFFSET * 2;
577 th = pi->height - PAN_SHADOW_OFFSET * 2;
578 tx = pi->x + PAN_SHADOW_OFFSET;
579 ty = pi->y + PAN_SHADOW_OFFSET;
581 if (util_clip_region(x, y, width, height,
587 d = (pw->size <= PAN_IMAGE_SIZE_THUMB_NONE) ? 2 : 8;
588 pixbuf_draw_rect_fill(pixbuf,
589 rx - x, ry - y, rw, rh,
591 PAN_SHADOW_ALPHA / d);
595 return (pi->pixbuf == NULL);
600 *-----------------------------------------------------------------------------
602 *-----------------------------------------------------------------------------
605 static void pan_item_image_find_size(PanWindow *pw, PanItem *pi, gint w, gint h)
614 work = pw->cache_list;
622 if (pc->cd && pc->cd->dimensions &&
623 pc->fd && pc->fd == pi->fd)
625 pi->width = MAX(1, pc->cd->width * pw->image_size / 100);
626 pi->height = MAX(1, pc->cd->height * pw->image_size / 100);
628 pw->cache_list = g_list_remove(pw->cache_list, pc);
629 cache_sim_data_free(pc->cd);
630 file_data_unref(pc->fd);
637 PanItem *pan_item_image_new(PanWindow *pw, FileData *fd, gint x, gint y, gint w, gint h)
641 pi = g_new0(PanItem, 1);
642 pi->type = PAN_ITEM_IMAGE;
652 pi->color2_a = PAN_SHADOW_ALPHA / 2;
654 pan_item_image_find_size(pw, pi, w, h);
656 pw->list = g_list_prepend(pw->list, pi);
661 gint pan_item_image_draw(PanWindow *UNUSED(pw), PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *UNUSED(pr),
662 gint x, gint y, gint width, gint height)
666 if (util_clip_region(x, y, width, height,
667 pi->x, pi->y, pi->width, pi->height,
672 gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
675 1.0, 1.0, GDK_INTERP_NEAREST,
680 pixbuf_draw_rect_fill(pixbuf,
681 rx - x, ry - y, rw, rh,
682 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
686 return (pi->pixbuf == NULL);
691 *-----------------------------------------------------------------------------
693 *-----------------------------------------------------------------------------
696 PanItem *pan_item_find_by_key(PanWindow *pw, PanItemType type, const gchar *key)
700 if (!key) return NULL;
702 work = g_list_last(pw->list);
708 if ((pi->type == type || type == PAN_ITEM_NONE) &&
709 pi->key && strcmp(pi->key, key) == 0)
715 work = g_list_last(pw->list_static);
721 if ((pi->type == type || type == PAN_ITEM_NONE) &&
722 pi->key && strcmp(pi->key, key) == 0)
732 /* when ignore_case and partial are TRUE, path should be converted to lower case */
733 static GList *pan_item_find_by_path_l(GList *list, GList *search_list,
734 PanItemType type, const gchar *path,
735 gboolean ignore_case, gboolean partial)
739 work = g_list_last(search_list);
745 if ((pi->type == type || type == PAN_ITEM_NONE) && pi->fd)
747 gboolean match = FALSE;
749 if (path[0] == G_DIR_SEPARATOR)
751 if (pi->fd->path && strcmp(path, pi->fd->path) == 0) match = TRUE;
753 else if (pi->fd->name)
761 haystack = g_utf8_strdown(pi->fd->name, -1);
762 match = (strstr(haystack, path) != NULL);
767 if (strstr(pi->fd->name, path)) match = TRUE;
770 else if (ignore_case)
772 if (g_ascii_strcasecmp(path, pi->fd->name) == 0) match = TRUE;
776 if (strcmp(path, pi->fd->name) == 0) match = TRUE;
780 if (match) list = g_list_prepend(list, pi);
788 /* when ignore_case and partial are TRUE, path should be converted to lower case */
789 GList *pan_item_find_by_path(PanWindow *pw, PanItemType type, const gchar *path,
790 gboolean ignore_case, gboolean partial)
794 if (!path) return NULL;
795 if (partial && path[0] == G_DIR_SEPARATOR) return NULL;
797 list = pan_item_find_by_path_l(list, pw->list_static, type, path, ignore_case, partial);
798 list = pan_item_find_by_path_l(list, pw->list, type, path, ignore_case, partial);
800 return g_list_reverse(list);
803 GList *pan_item_find_by_fd(PanWindow *pw, PanItemType type, FileData *fd,
804 gboolean ignore_case, gboolean partial)
806 if (!fd) return NULL;
807 return pan_item_find_by_path(pw, type, fd->path, ignore_case, partial);
811 static PanItem *pan_item_find_by_coord_l(GList *list, PanItemType type, gint x, gint y, const gchar *key)
821 if ((pi->type == type || type == PAN_ITEM_NONE) &&
822 x >= pi->x && x < pi->x + pi->width &&
823 y >= pi->y && y < pi->y + pi->height &&
824 (!key || (pi->key && strcmp(pi->key, key) == 0)))
834 PanItem *pan_item_find_by_coord(PanWindow *pw, PanItemType type,
835 gint x, gint y, const gchar *key)
839 pi = pan_item_find_by_coord_l(pw->list, type, x, y, key);
842 return pan_item_find_by_coord_l(pw->list_static, type, x, y, key);
847 *-----------------------------------------------------------------------------
849 *-----------------------------------------------------------------------------
852 PanTextAlignment *pan_text_alignment_new(PanWindow *pw, gint x, gint y, const gchar *key)
854 PanTextAlignment *ta;
856 ta = g_new0(PanTextAlignment, 1);
861 ta->key = g_strdup(key);
866 void pan_text_alignment_free(PanTextAlignment *ta)
870 g_list_free(ta->column1);
871 g_list_free(ta->column2);
876 PanItem *pan_text_alignment_add(PanTextAlignment *ta, const gchar *label, const gchar *text)
882 item = pan_item_text_new(ta->pw, ta->x, ta->y, label,
883 PAN_TEXT_ATTR_BOLD, 0,
884 PAN_POPUP_TEXT_COLOR, 255);
885 pan_item_set_key(item, ta->key);
891 ta->column1 = g_list_append(ta->column1, item);
895 item = pan_item_text_new(ta->pw, ta->x, ta->y, text,
896 PAN_TEXT_ATTR_NONE, 0,
897 PAN_POPUP_TEXT_COLOR, 255);
898 pan_item_set_key(item, ta->key);
904 ta->column2 = g_list_append(ta->column2, item);
909 void pan_text_alignment_calc(PanTextAlignment *ta, PanItem *box)
927 if (p && p->width > cw1) cw1 = p->width;
938 if (p && p->width > cw2) cw2 = p->width;
945 while (work1 && work2)
960 pan_item_size_by_item(box, p1, PREF_PAD_BORDER);
965 p2->x = x + cw1 + PREF_PAD_SPACE;
967 pan_item_size_by_item(box, p2, PREF_PAD_BORDER);
968 if (height < p2->height) height = p2->height;
971 if (!p1 && !p2) height = PREF_PAD_GROUP;
976 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */