Fix include-what-you-use warnings
[geeqie.git] / src / pan-view / pan-item.cc
1 /*
2  * Copyright (C) 2006 John Ellis
3  * Copyright (C) 2008 - 2016 The Geeqie Team
4  *
5  * Author: John Ellis
6  *
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.
11  *
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.
16  *
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.
20  */
21
22 #include "pan-item.h"
23
24 #include <cstring>
25
26 #include <glib-object.h>
27 #include <gtk/gtk.h>
28 #include <pango/pango.h>
29
30 #include "cache.h"
31 #include "filedata.h"
32 #include "image.h"
33 #include "pan-types.h"
34 #include "pixbuf-util.h"
35 #include "ui-misc.h"
36
37 /*
38  *-----------------------------------------------------------------------------
39  * item base functions
40  *-----------------------------------------------------------------------------
41  */
42
43 void pan_item_free(PanItem *pi)
44 {
45         if (!pi) return;
46
47         if (pi->pixbuf) g_object_unref(pi->pixbuf);
48         if (pi->fd) file_data_unref(pi->fd);
49         g_free(pi->text);
50         g_free(pi->key);
51         g_free(pi->data);
52
53         g_free(pi);
54 }
55
56 void pan_item_set_key(PanItem *pi, const gchar *key)
57 {
58         gchar *tmp;
59
60         if (!pi) return;
61
62         tmp = pi->key;
63         pi->key = g_strdup(key);
64         g_free(tmp);
65 }
66
67 void pan_item_added(PanWindow *pw, PanItem *pi)
68 {
69         if (!pi) return;
70         image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height);
71 }
72
73 void pan_item_remove(PanWindow *pw, PanItem *pi)
74 {
75         if (!pi) return;
76
77         if (pw->click_pi == pi) pw->click_pi = nullptr;
78         if (pw->queue_pi == pi) pw->queue_pi = nullptr;
79         if (pw->search_pi == pi) pw->search_pi = nullptr;
80         pw->queue = g_list_remove(pw->queue, pi);
81
82         pw->list = g_list_remove(pw->list, pi);
83         image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height);
84         pan_item_free(pi);
85 }
86
87 void pan_item_size_by_item(PanItem *pi, PanItem *child, gint border)
88 {
89         if (!pi || !child) return;
90
91         if (pi->x + pi->width < child->x + child->width + border)
92                 pi->width = child->x + child->width + border - pi->x;
93
94         if (pi->y + pi->height < child->y + child->height + border)
95                 pi->height = child->y + child->height + border - pi->y;
96 }
97
98 void pan_item_size_coordinates(PanItem *pi, gint border, gint *w, gint *h)
99 {
100         if (!pi) return;
101
102         if (*w < pi->x + pi->width + border) *w = pi->x + pi->width + border;
103         if (*h < pi->y + pi->height + border) *h = pi->y + pi->height + border;
104 }
105
106
107 /*
108  *-----------------------------------------------------------------------------
109  * item box type
110  *-----------------------------------------------------------------------------
111  */
112
113 PanItem *pan_item_box_new(PanWindow *pw, FileData *fd, gint x, gint y, gint width, gint height,
114                           gint border_size,
115                           guint8 base_r, guint8 base_g, guint8 base_b, guint8 base_a,
116                           guint8 bord_r, guint8 bord_g, guint8 bord_b, guint8 bord_a)
117 {
118         PanItem *pi;
119
120         pi = g_new0(PanItem, 1);
121         pi->type = PAN_ITEM_BOX;
122         pi->fd = fd;
123         pi->x = x;
124         pi->y = y;
125         pi->width = width;
126         pi->height = height;
127
128         pi->color_r = base_r;
129         pi->color_g = base_g;
130         pi->color_b = base_b;
131         pi->color_a = base_a;
132
133         pi->color2_r = bord_r;
134         pi->color2_g = bord_g;
135         pi->color2_b = bord_b;
136         pi->color2_a = bord_a;
137         pi->border = border_size;
138
139         pw->list = g_list_prepend(pw->list, pi);
140
141         return pi;
142 }
143
144 void pan_item_box_shadow(PanItem *pi, gint offset, gint fade)
145 {
146         gint *shadow;
147
148         if (!pi || pi->type != PAN_ITEM_BOX) return;
149
150         shadow = static_cast<gint *>(pi->data);
151         if (shadow)
152                 {
153                 pi->width -= shadow[0];
154                 pi->height -= shadow[0];
155                 }
156
157         shadow = g_new0(gint, 2);
158         shadow[0] = offset;
159         shadow[1] = fade;
160
161         pi->width += offset;
162         pi->height += offset;
163
164         g_free(pi->data);
165         pi->data = shadow;
166 }
167
168 gint pan_item_box_draw(PanWindow *, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *,
169                        gint x, gint y, gint width, gint height)
170 {
171         gint bw;
172         gint bh;
173         gint *shadow;
174         gint rx;
175         gint ry;
176         gint rw;
177         gint rh;
178
179         bw = pi->width;
180         bh = pi->height;
181
182         shadow = static_cast<gint *>(pi->data);
183         if (shadow)
184                 {
185                 bw -= shadow[0];
186                 bh -= shadow[0];
187
188                 if (pi->color_a > 254)
189                         {
190                         pixbuf_draw_shadow(pixbuf, pi->x - x + bw, pi->y - y + shadow[0],
191                                            shadow[0], bh - shadow[0],
192                                            pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
193                                            shadow[1],
194                                            PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
195                         pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + bh,
196                                            bw, shadow[0],
197                                            pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
198                                            shadow[1],
199                                            PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
200                         }
201                 else
202                         {
203                         gint a;
204                         a = pi->color_a * PAN_SHADOW_ALPHA >> 8;
205                         pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + shadow[0],
206                                            bw, bh,
207                                            pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
208                                            shadow[1],
209                                            PAN_SHADOW_COLOR, a);
210                         }
211                 }
212
213         if (util_clip_region(x, y, width, height,
214                              pi->x, pi->y, bw, bh,
215                              &rx, &ry, &rw, &rh))
216                 {
217                 pixbuf_draw_rect_fill(pixbuf,
218                                       rx - x, ry - y, rw, rh,
219                                       pi->color_r, pi->color_g, pi->color_b, pi->color_a);
220                 }
221         if (util_clip_region(x, y, width, height,
222                              pi->x, pi->y, bw, pi->border,
223                              &rx, &ry, &rw, &rh))
224                 {
225                 pixbuf_draw_rect_fill(pixbuf,
226                                       rx - x, ry - y, rw, rh,
227                                       pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
228                 }
229         if (util_clip_region(x, y, width, height,
230                              pi->x, pi->y + pi->border, pi->border, bh - pi->border * 2,
231                              &rx, &ry, &rw, &rh))
232                 {
233                 pixbuf_draw_rect_fill(pixbuf,
234                                       rx - x, ry - y, rw, rh,
235                                       pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
236                 }
237         if (util_clip_region(x, y, width, height,
238                              pi->x + bw - pi->border, pi->y + pi->border,
239                              pi->border, bh - pi->border * 2,
240                              &rx, &ry, &rw, &rh))
241                 {
242                 pixbuf_draw_rect_fill(pixbuf,
243                                       rx - x, ry - y, rw, rh,
244                                       pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
245                 }
246         if (util_clip_region(x, y, width, height,
247                              pi->x, pi->y + bh - pi->border,
248                              bw,  pi->border,
249                              &rx, &ry, &rw, &rh))
250                 {
251                 pixbuf_draw_rect_fill(pixbuf,
252                                       rx - x, ry - y, rw, rh,
253                                       pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
254                 }
255
256         return FALSE;
257 }
258
259
260 /*
261  *-----------------------------------------------------------------------------
262  * item triangle type
263  *-----------------------------------------------------------------------------
264  */
265
266 PanItem *pan_item_tri_new(PanWindow *pw, FileData *, gint x, gint y, gint width, gint height,
267                           gint x1, gint y1, gint x2, gint y2, gint x3, gint y3,
268                           guint8 r, guint8 g, guint8 b, guint8 a)
269 {
270         PanItem *pi;
271         gint *coord;
272
273         pi = g_new0(PanItem, 1);
274         pi->type = PAN_ITEM_TRIANGLE;
275         pi->x = x;
276         pi->y = y;
277         pi->width = width;
278         pi->height = height;
279
280         pi->color_r = r;
281         pi->color_g = g;
282         pi->color_b = b;
283         pi->color_a = a;
284
285         coord = g_new0(gint, 6);
286         coord[0] = x1;
287         coord[1] = y1;
288         coord[2] = x2;
289         coord[3] = y2;
290         coord[4] = x3;
291         coord[5] = y3;
292
293         pi->data = coord;
294
295         pi->border = PAN_BORDER_NONE;
296
297         pw->list = g_list_prepend(pw->list, pi);
298
299         return pi;
300 }
301
302 void pan_item_tri_border(PanItem *pi, gint borders,
303                          guint8 r, guint8 g, guint8 b, guint8 a)
304 {
305         if (!pi || pi->type != PAN_ITEM_TRIANGLE) return;
306
307         pi->border = borders;
308
309         pi->color2_r = r;
310         pi->color2_g = g;
311         pi->color2_b = b;
312         pi->color2_a = a;
313 }
314
315 gint pan_item_tri_draw(PanWindow *, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *, gint x, gint y, gint width, gint height)
316 {
317         gint rx;
318         gint ry;
319         gint rw;
320         gint rh;
321
322         if (util_clip_region(x, y, width, height,
323                              pi->x, pi->y, pi->width, pi->height,
324                              &rx, &ry, &rw, &rh) && pi->data)
325                 {
326                 auto coord = static_cast<gint *>(pi->data);
327                 pixbuf_draw_triangle(pixbuf,
328                                      rx - x, ry - y, rw, rh,
329                                      coord[0] - x, coord[1] - y,
330                                      coord[2] - x, coord[3] - y,
331                                      coord[4] - x, coord[5] - y,
332                                      pi->color_r, pi->color_g, pi->color_b, pi->color_a);
333
334                 if (pi->border & PAN_BORDER_1)
335                         {
336                         pixbuf_draw_line(pixbuf,
337                                          rx - x, ry - y, rw, rh,
338                                          coord[0] - x, coord[1] - y,
339                                          coord[2] - x, coord[3] - y,
340                                          pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
341                         }
342                 if (pi->border & PAN_BORDER_2)
343                         {
344                         pixbuf_draw_line(pixbuf,
345                                          rx - x, ry - y, rw, rh,
346                                          coord[2] - x, coord[3] - y,
347                                          coord[4] - x, coord[5] - y,
348                                          pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
349                         }
350                 if (pi->border & PAN_BORDER_3)
351                         {
352                         pixbuf_draw_line(pixbuf,
353                                          rx - x, ry - y, rw, rh,
354                                          coord[4] - x, coord[5] - y,
355                                          coord[0] - x, coord[1] - y,
356                                          pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
357                         }
358                 }
359
360         return FALSE;
361 }
362
363
364 /*
365  *-----------------------------------------------------------------------------
366  * item text type
367  *-----------------------------------------------------------------------------
368  */
369
370 static PangoLayout *pan_item_text_layout(PanItem *pi, GtkWidget *widget)
371 {
372         PangoLayout *layout;
373
374         layout = gtk_widget_create_pango_layout(widget, nullptr);
375
376         if (pi->text_attr & PAN_TEXT_ATTR_MARKUP)
377                 {
378                 pango_layout_set_markup(layout, pi->text, -1);
379                 return layout;
380                 }
381
382         if (pi->text_attr & PAN_TEXT_ATTR_BOLD ||
383             pi->text_attr & PAN_TEXT_ATTR_HEADING)
384                 {
385                 PangoAttrList *pal;
386                 PangoAttribute *pa;
387
388                 pal = pango_attr_list_new();
389                 if (pi->text_attr & PAN_TEXT_ATTR_BOLD)
390                         {
391                         pa = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
392                         pa->start_index = 0;
393                         pa->end_index = G_MAXINT;
394                         pango_attr_list_insert(pal, pa);
395                         }
396                 if (pi->text_attr & PAN_TEXT_ATTR_HEADING)
397                         {
398                         pa = pango_attr_scale_new(PANGO_SCALE_LARGE);
399                         pa->start_index = 0;
400                         pa->end_index = G_MAXINT;
401                         pango_attr_list_insert(pal, pa);
402                         }
403                 pango_layout_set_attributes(layout, pal);
404                 pango_attr_list_unref(pal);
405                 }
406
407         pango_layout_set_text(layout, pi->text, -1);
408         return layout;
409 }
410
411 static void pan_item_text_compute_size(PanItem *pi, GtkWidget *widget)
412 {
413         PangoLayout *layout;
414
415         if (!pi || !pi->text || !widget) return;
416
417         layout = pan_item_text_layout(pi, widget);
418         pango_layout_get_pixel_size(layout, &pi->width, &pi->height);
419         g_object_unref(G_OBJECT(layout));
420
421         pi->width += pi->border * 2;
422         pi->height += pi->border * 2;
423 }
424
425 PanItem *pan_item_text_new(PanWindow *pw, gint x, gint y, const gchar *text,
426                            PanTextAttrType attr, PanBorderType border,
427                            guint8 r, guint8 g, guint8 b, guint8 a)
428 {
429         PanItem *pi;
430
431         pi = g_new0(PanItem, 1);
432         pi->type = PAN_ITEM_TEXT;
433         pi->x = x;
434         pi->y = y;
435         pi->text = g_strdup(text);
436         pi->text_attr = attr;
437
438         pi->color_r = r;
439         pi->color_g = g;
440         pi->color_b = b;
441         pi->color_a = a;
442
443         pi->border = border;
444
445         pan_item_text_compute_size(pi, pw->imd->pr);
446
447         pw->list = g_list_prepend(pw->list, pi);
448
449         return pi;
450 }
451
452 gint pan_item_text_draw(PanWindow *, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr, gint x, gint y, gint, gint)
453 {
454         PangoLayout *layout;
455
456         layout = pan_item_text_layout(pi, reinterpret_cast<GtkWidget *>(pr));
457         pixbuf_draw_layout(pixbuf, layout, reinterpret_cast<GtkWidget *>(pr),
458                            pi->x - x + pi->border, pi->y - y + pi->border,
459                            pi->color_r, pi->color_g, pi->color_b, pi->color_a);
460         g_object_unref(G_OBJECT(layout));
461
462         return FALSE;
463 }
464
465
466 /*
467  *-----------------------------------------------------------------------------
468  * item thumbnail type
469  *-----------------------------------------------------------------------------
470  */
471
472 PanItem *pan_item_thumb_new(PanWindow *pw, FileData *fd, gint x, gint y)
473 {
474         PanItem *pi;
475
476         pi = g_new0(PanItem, 1);
477
478         pi->type = PAN_ITEM_THUMB;
479         pi->fd = fd;
480         pi->x = x;
481         pi->y = y;
482         pi->width = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
483         pi->height = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
484
485         pw->list = g_list_prepend(pw->list, pi);
486
487         return pi;
488 }
489
490 gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *, gint x, gint y, gint width, gint height)
491 {
492         gint tx;
493         gint ty;
494         gint tw;
495         gint th;
496         gint rx;
497         gint ry;
498         gint rw;
499         gint rh;
500
501         if (pi->pixbuf)
502                 {
503                 tw = gdk_pixbuf_get_width(pi->pixbuf);
504                 th = gdk_pixbuf_get_height(pi->pixbuf);
505
506                 tx = pi->x + (pi->width - tw) / 2;
507                 ty = pi->y + (pi->height - th) / 2;
508
509                 if (gdk_pixbuf_get_has_alpha(pi->pixbuf))
510                         {
511                         if (util_clip_region(x, y, width, height,
512                                              tx + PAN_SHADOW_OFFSET, ty + PAN_SHADOW_OFFSET, tw, th,
513                                              &rx, &ry, &rw, &rh))
514                                 {
515                                 pixbuf_draw_shadow(pixbuf,
516                                                    rx - x, ry - y, rw, rh,
517                                                    tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
518                                                    PAN_SHADOW_FADE,
519                                                    PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
520                                 }
521                         }
522                 else
523                         {
524                         if (util_clip_region(x, y, width, height,
525                                              tx + tw, ty + PAN_SHADOW_OFFSET,
526                                              PAN_SHADOW_OFFSET, th - PAN_SHADOW_OFFSET,
527                                              &rx, &ry, &rw, &rh))
528                                 {
529                                 pixbuf_draw_shadow(pixbuf,
530                                                    rx - x, ry - y, rw, rh,
531                                                    tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
532                                                    PAN_SHADOW_FADE,
533                                                    PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
534                                 }
535                         if (util_clip_region(x, y, width, height,
536                                              tx + PAN_SHADOW_OFFSET, ty + th, tw, PAN_SHADOW_OFFSET,
537                                              &rx, &ry, &rw, &rh))
538                                 {
539                                 pixbuf_draw_shadow(pixbuf,
540                                                    rx - x, ry - y, rw, rh,
541                                                    tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
542                                                    PAN_SHADOW_FADE,
543                                                    PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
544                                 }
545                         }
546
547                 if (util_clip_region(x, y, width, height,
548                                      tx, ty, tw, th,
549                                      &rx, &ry, &rw, &rh))
550                         {
551                         gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
552                                              static_cast<gdouble>(tx) - x,
553                                              static_cast<gdouble>(ty) - y,
554                                              1.0, 1.0, GDK_INTERP_NEAREST,
555                                              255);
556                         }
557
558                 if (util_clip_region(x, y, width, height,
559                                      tx, ty, tw, PAN_OUTLINE_THICKNESS,
560                                      &rx, &ry, &rw, &rh))
561                         {
562                         pixbuf_draw_rect_fill(pixbuf,
563                                               rx - x, ry - y, rw, rh,
564                                               PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
565                         }
566                 if (util_clip_region(x, y, width, height,
567                                      tx, ty, PAN_OUTLINE_THICKNESS, th,
568                                      &rx, &ry, &rw, &rh))
569                         {
570                         pixbuf_draw_rect_fill(pixbuf,
571                                               rx - x, ry - y, rw, rh,
572                                               PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
573                         }
574                 if (util_clip_region(x, y, width, height,
575                                      tx + tw - PAN_OUTLINE_THICKNESS, ty +  PAN_OUTLINE_THICKNESS,
576                                      PAN_OUTLINE_THICKNESS, th - PAN_OUTLINE_THICKNESS,
577                                      &rx, &ry, &rw, &rh))
578                         {
579                         pixbuf_draw_rect_fill(pixbuf,
580                                               rx - x, ry - y, rw, rh,
581                                               PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
582                         }
583                 if (util_clip_region(x, y, width, height,
584                                      tx +  PAN_OUTLINE_THICKNESS, ty + th - PAN_OUTLINE_THICKNESS,
585                                      tw - PAN_OUTLINE_THICKNESS * 2, PAN_OUTLINE_THICKNESS,
586                                      &rx, &ry, &rw, &rh))
587                         {
588                         pixbuf_draw_rect_fill(pixbuf,
589                                               rx - x, ry - y, rw, rh,
590                                               PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
591                         }
592                 }
593         else
594                 {
595                 tw = pi->width - PAN_SHADOW_OFFSET * 2;
596                 th = pi->height - PAN_SHADOW_OFFSET * 2;
597                 tx = pi->x + PAN_SHADOW_OFFSET;
598                 ty = pi->y + PAN_SHADOW_OFFSET;
599
600                 if (util_clip_region(x, y, width, height,
601                                      tx, ty, tw, th,
602                                      &rx, &ry, &rw, &rh))
603                         {
604                         gint d;
605
606                         d = (pw->size <= PAN_IMAGE_SIZE_THUMB_NONE) ? 2 : 8;
607                         pixbuf_draw_rect_fill(pixbuf,
608                                               rx - x, ry - y, rw, rh,
609                                               PAN_SHADOW_COLOR,
610                                               PAN_SHADOW_ALPHA / d);
611                         }
612                 }
613
614         return (pi->pixbuf == nullptr);
615 }
616
617
618 /*
619  *-----------------------------------------------------------------------------
620  * item image type
621  *-----------------------------------------------------------------------------
622  */
623
624 static void pan_item_image_find_size(PanWindow *pw, PanItem *pi, gint w, gint h)
625 {
626         GList *work;
627
628         pi->width = w;
629         pi->height = h;
630
631         if (!pi->fd) return;
632
633         work = pw->cache_list;
634         while (work)
635                 {
636                 PanCacheData *pc;
637
638                 pc = static_cast<PanCacheData *>(work->data);
639                 work = work->next;
640
641                 if (pc->cd && pc->cd->dimensions &&
642                     pc->fd && pc->fd == pi->fd)
643                         {
644                         pi->width = MAX(1, pc->cd->width * pw->image_size / 100);
645                         pi->height = MAX(1, pc->cd->height * pw->image_size / 100);
646
647                         pw->cache_list = g_list_remove(pw->cache_list, pc);
648                         cache_sim_data_free(pc->cd);
649                         file_data_unref(pc->fd);
650                         g_free(pc);
651                         return;
652                         }
653                 }
654 }
655
656 PanItem *pan_item_image_new(PanWindow *pw, FileData *fd, gint x, gint y, gint w, gint h)
657 {
658         PanItem *pi;
659
660         pi = g_new0(PanItem, 1);
661         pi->type = PAN_ITEM_IMAGE;
662         pi->fd = fd;
663         pi->x = x;
664         pi->y = y;
665
666         pi->color_a = 255;
667
668         pi->color2_r = 0;
669         pi->color2_g = 0;
670         pi->color2_b = 0;
671         pi->color2_a = PAN_SHADOW_ALPHA / 2;
672
673         pan_item_image_find_size(pw, pi, w, h);
674
675         pw->list = g_list_prepend(pw->list, pi);
676
677         return pi;
678 }
679
680 gint pan_item_image_draw(PanWindow *, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *, gint x, gint y, gint width, gint height)
681 {
682         gint rx;
683         gint ry;
684         gint rw;
685         gint rh;
686
687         if (util_clip_region(x, y, width, height,
688                              pi->x, pi->y, pi->width, pi->height,
689                              &rx, &ry, &rw, &rh))
690                 {
691                 if (pi->pixbuf)
692                         {
693                         gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
694                                              static_cast<gdouble>(pi->x) - x,
695                                              static_cast<gdouble>(pi->y) - y,
696                                              1.0, 1.0, GDK_INTERP_NEAREST,
697                                              pi->color_a);
698                         }
699                 else
700                         {
701                         pixbuf_draw_rect_fill(pixbuf,
702                                               rx - x, ry - y, rw, rh,
703                                               pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
704                         }
705                 }
706
707         return (pi->pixbuf == nullptr);
708 }
709
710
711 /*
712  *-----------------------------------------------------------------------------
713  * item lookup/search
714  *-----------------------------------------------------------------------------
715  */
716
717 PanItem *pan_item_find_by_key(PanWindow *pw, PanItemType type, const gchar *key)
718 {
719         GList *work;
720
721         if (!key) return nullptr;
722
723         work = g_list_last(pw->list);
724         while (work)
725                 {
726                 PanItem *pi;
727
728                 pi = static_cast<PanItem *>(work->data);
729                 if ((pi->type == type || type == PAN_ITEM_NONE) &&
730                      pi->key && strcmp(pi->key, key) == 0)
731                         {
732                         return pi;
733                         }
734                 work = work->prev;
735                 }
736         work = g_list_last(pw->list_static);
737         while (work)
738                 {
739                 PanItem *pi;
740
741                 pi = static_cast<PanItem *>(work->data);
742                 if ((pi->type == type || type == PAN_ITEM_NONE) &&
743                      pi->key && strcmp(pi->key, key) == 0)
744                         {
745                         return pi;
746                         }
747                 work = work->prev;
748                 }
749
750         return nullptr;
751 }
752
753 /* when ignore_case and partial are TRUE, path should be converted to lower case */
754 static GList *pan_item_find_by_path_l(GList *list, GList *search_list,
755                                       PanItemType type, const gchar *path,
756                                       gboolean ignore_case, gboolean partial)
757 {
758         GList *work;
759
760         work = g_list_last(search_list);
761         while (work)
762                 {
763                 PanItem *pi;
764
765                 pi = static_cast<PanItem *>(work->data);
766                 if ((pi->type == type || type == PAN_ITEM_NONE) && pi->fd)
767                         {
768                         gboolean match = FALSE;
769
770                         if (path[0] == G_DIR_SEPARATOR)
771                                 {
772                                 if (pi->fd->path && strcmp(path, pi->fd->path) == 0) match = TRUE;
773                                 }
774                         else if (pi->fd->name)
775                                 {
776                                 if (partial)
777                                         {
778                                         if (ignore_case)
779                                                 {
780                                                 gchar *haystack;
781
782                                                 haystack = g_utf8_strdown(pi->fd->name, -1);
783                                                 match = (strstr(haystack, path) != nullptr);
784                                                 g_free(haystack);
785                                                 }
786                                         else
787                                                 {
788                                                 if (strstr(pi->fd->name, path)) match = TRUE;
789                                                 }
790                                         }
791                                 else if (ignore_case)
792                                         {
793                                         if (g_ascii_strcasecmp(path, pi->fd->name) == 0) match = TRUE;
794                                         }
795                                 else
796                                         {
797                                         if (strcmp(path, pi->fd->name) == 0) match = TRUE;
798                                         }
799                                 }
800
801                         if (match) list = g_list_prepend(list, pi);
802                         }
803                 work = work->prev;
804                 }
805
806         return list;
807 }
808
809 /* when ignore_case and partial are TRUE, path should be converted to lower case */
810 GList *pan_item_find_by_path(PanWindow *pw, PanItemType type, const gchar *path,
811                              gboolean ignore_case, gboolean partial)
812 {
813         GList *list = nullptr;
814
815         if (!path) return nullptr;
816         if (partial && path[0] == G_DIR_SEPARATOR) return nullptr;
817
818         list = pan_item_find_by_path_l(list, pw->list_static, type, path, ignore_case, partial);
819         list = pan_item_find_by_path_l(list, pw->list, type, path, ignore_case, partial);
820
821         return g_list_reverse(list);
822 }
823
824 GList *pan_item_find_by_fd(PanWindow *pw, PanItemType type, FileData *fd,
825                            gboolean ignore_case, gboolean partial)
826 {
827         if (!fd) return nullptr;
828         return pan_item_find_by_path(pw, type, fd->path, ignore_case, partial);
829 }
830
831
832 static PanItem *pan_item_find_by_coord_l(GList *list, PanItemType type, gint x, gint y, const gchar *key)
833 {
834         GList *work;
835
836         work = list;
837         while (work)
838                 {
839                 PanItem *pi;
840
841                 pi = static_cast<PanItem *>(work->data);
842                 if ((pi->type == type || type == PAN_ITEM_NONE) &&
843                      x >= pi->x && x < pi->x + pi->width &&
844                      y >= pi->y && y < pi->y + pi->height &&
845                     (!key || (pi->key && strcmp(pi->key, key) == 0)))
846                         {
847                         return pi;
848                         }
849                 work = work->next;
850                 }
851
852         return nullptr;
853 }
854
855 PanItem *pan_item_find_by_coord(PanWindow *pw, PanItemType type,
856                                 gint x, gint y, const gchar *key)
857 {
858         PanItem *pi;
859
860         pi = pan_item_find_by_coord_l(pw->list, type, x, y, key);
861         if (pi) return pi;
862
863         return pan_item_find_by_coord_l(pw->list_static, type, x, y, key);
864 }
865
866
867 /*
868  *-----------------------------------------------------------------------------
869  * text alignments
870  *-----------------------------------------------------------------------------
871  */
872
873 PanTextAlignment *pan_text_alignment_new(PanWindow *pw, gint x, gint y, const gchar *key)
874 {
875         PanTextAlignment *ta;
876
877         ta = g_new0(PanTextAlignment, 1);
878
879         ta->pw = pw;
880         ta->x = x;
881         ta->y = y;
882         ta->key = g_strdup(key);
883
884         return ta;
885 }
886
887 void pan_text_alignment_free(PanTextAlignment *ta)
888 {
889         if (!ta) return;
890
891         g_list_free(ta->column1);
892         g_list_free(ta->column2);
893         g_free(ta->key);
894         g_free(ta);
895 }
896
897 PanItem *pan_text_alignment_add(PanTextAlignment *ta, const gchar *label, const gchar *text)
898 {
899         PanItem *item;
900
901         if (label)
902                 {
903                 item = pan_item_text_new(ta->pw, ta->x, ta->y, label,
904                                          PAN_TEXT_ATTR_BOLD, PAN_BORDER_NONE,
905                                          PAN_POPUP_TEXT_COLOR, 255);
906                 pan_item_set_key(item, ta->key);
907                 }
908         else
909                 {
910                 item = nullptr;
911                 }
912         ta->column1 = g_list_append(ta->column1, item);
913
914         if (text)
915                 {
916                 item = pan_item_text_new(ta->pw, ta->x, ta->y, text,
917                                          PAN_TEXT_ATTR_NONE, PAN_BORDER_NONE,
918                                          PAN_POPUP_TEXT_COLOR, 255);
919                 pan_item_set_key(item, ta->key);
920                 }
921         else
922                 {
923                 item = nullptr;
924                 }
925         ta->column2 = g_list_append(ta->column2, item);
926
927         return item;
928 }
929
930 void pan_text_alignment_calc(PanTextAlignment *ta, PanItem *box)
931 {
932         gint cw1;
933         gint cw2;
934         gint x;
935         gint y;
936         GList *work1;
937         GList *work2;
938
939         cw1 = 0;
940         cw2 = 0;
941
942         work1 = ta->column1;
943         while (work1)
944                 {
945                 PanItem *p;
946
947                 p = static_cast<PanItem *>(work1->data);
948                 work1 = work1->next;
949
950                 if (p && p->width > cw1) cw1 = p->width;
951                 }
952
953         work2 = ta->column2;
954         while (work2)
955                 {
956                 PanItem *p;
957
958                 p = static_cast<PanItem *>(work2->data);
959                 work2 = work2->next;
960
961                 if (p && p->width > cw2) cw2 = p->width;
962                 }
963
964         x = ta->x;
965         y = ta->y;
966         work1 = ta->column1;
967         work2 = ta->column2;
968         while (work1 && work2)
969                 {
970                 PanItem *p1;
971                 PanItem *p2;
972                 gint height = 0;
973
974                 p1 = static_cast<PanItem *>(work1->data);
975                 p2 = static_cast<PanItem *>(work2->data);
976                 work1 = work1->next;
977                 work2 = work2->next;
978
979                 if (p1)
980                         {
981                         p1->x = x;
982                         p1->y = y;
983                         pan_item_size_by_item(box, p1, PREF_PAD_BORDER);
984                         height = p1->height;
985                         }
986                 if (p2)
987                         {
988                         p2->x = x + cw1 + PREF_PAD_SPACE;
989                         p2->y = y;
990                         pan_item_size_by_item(box, p2, PREF_PAD_BORDER);
991                         if (height < p2->height) height = p2->height;
992                         }
993
994                 if (!p1 && !p2) height = PREF_PAD_GROUP;
995
996                 y += height;
997                 }
998 }
999 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */