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