bbbd2056ae58bb77e6f846b5cd435d18dea29d53
[geeqie.git] / src / pan-view / pan-item.c
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 = 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);
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 = 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 *UNUSED(pw), PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *UNUSED(pr),
160                        gint x, gint y, gint width, gint height)
161 {
162         gint bw, bh;
163         gint *shadow;
164         gint rx, ry, rw, rh;
165
166         bw = pi->width;
167         bh = pi->height;
168
169         shadow = pi->data;
170         if (shadow)
171                 {
172                 bw -= shadow[0];
173                 bh -= shadow[0];
174
175                 if (pi->color_a > 254)
176                         {
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,
180                                            shadow[1],
181                                            PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
182                         pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + bh,
183                                            bw, shadow[0],
184                                            pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
185                                            shadow[1],
186                                            PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
187                         }
188                 else
189                         {
190                         gint a;
191                         a = pi->color_a * PAN_SHADOW_ALPHA >> 8;
192                         pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + shadow[0],
193                                            bw, bh,
194                                            pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
195                                            shadow[1],
196                                            PAN_SHADOW_COLOR, a);
197                         }
198                 }
199
200         if (util_clip_region(x, y, width, height,
201                              pi->x, pi->y, bw, bh,
202                              &rx, &ry, &rw, &rh))
203                 {
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);
207                 }
208         if (util_clip_region(x, y, width, height,
209                              pi->x, pi->y, bw, pi->border,
210                              &rx, &ry, &rw, &rh))
211                 {
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);
215                 }
216         if (util_clip_region(x, y, width, height,
217                              pi->x, pi->y + pi->border, pi->border, bh - pi->border * 2,
218                              &rx, &ry, &rw, &rh))
219                 {
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);
223                 }
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,
227                              &rx, &ry, &rw, &rh))
228                 {
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);
232                 }
233         if (util_clip_region(x, y, width, height,
234                              pi->x, pi->y + bh - pi->border,
235                              bw,  pi->border,
236                              &rx, &ry, &rw, &rh))
237                 {
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);
241                 }
242
243         return FALSE;
244 }
245
246
247 /*
248  *-----------------------------------------------------------------------------
249  * item triangle type
250  *-----------------------------------------------------------------------------
251  */
252
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)
256 {
257         PanItem *pi;
258         gint *coord;
259
260         pi = g_new0(PanItem, 1);
261         pi->type = PAN_ITEM_TRIANGLE;
262         pi->x = x;
263         pi->y = y;
264         pi->width = width;
265         pi->height = height;
266
267         pi->color_r = r;
268         pi->color_g = g;
269         pi->color_b = b;
270         pi->color_a = a;
271
272         coord = g_new0(gint, 6);
273         coord[0] = x1;
274         coord[1] = y1;
275         coord[2] = x2;
276         coord[3] = y2;
277         coord[4] = x3;
278         coord[5] = y3;
279
280         pi->data = coord;
281
282         pi->border = PAN_BORDER_NONE;
283
284         pw->list = g_list_prepend(pw->list, pi);
285
286         return pi;
287 }
288
289 void pan_item_tri_border(PanItem *pi, gint borders,
290                          guint8 r, guint8 g, guint8 b, guint8 a)
291 {
292         if (!pi || pi->type != PAN_ITEM_TRIANGLE) return;
293
294         pi->border = borders;
295
296         pi->color2_r = r;
297         pi->color2_g = g;
298         pi->color2_b = b;
299         pi->color2_a = a;
300 }
301
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)
304 {
305         gint rx, ry, rw, rh;
306
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)
310                 {
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);
318
319                 if (pi->border & PAN_BORDER_1)
320                         {
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);
326                         }
327                 if (pi->border & PAN_BORDER_2)
328                         {
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);
334                         }
335                 if (pi->border & PAN_BORDER_3)
336                         {
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);
342                         }
343                 }
344
345         return FALSE;
346 }
347
348
349 /*
350  *-----------------------------------------------------------------------------
351  * item text type
352  *-----------------------------------------------------------------------------
353  */
354
355 static PangoLayout *pan_item_text_layout(PanItem *pi, GtkWidget *widget)
356 {
357         PangoLayout *layout;
358
359         layout = gtk_widget_create_pango_layout(widget, NULL);
360
361         if (pi->text_attr & PAN_TEXT_ATTR_MARKUP)
362                 {
363                 pango_layout_set_markup(layout, pi->text, -1);
364                 return layout;
365                 }
366
367         if (pi->text_attr & PAN_TEXT_ATTR_BOLD ||
368             pi->text_attr & PAN_TEXT_ATTR_HEADING)
369                 {
370                 PangoAttrList *pal;
371                 PangoAttribute *pa;
372
373                 pal = pango_attr_list_new();
374                 if (pi->text_attr & PAN_TEXT_ATTR_BOLD)
375                         {
376                         pa = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
377                         pa->start_index = 0;
378                         pa->end_index = G_MAXINT;
379                         pango_attr_list_insert(pal, pa);
380                         }
381                 if (pi->text_attr & PAN_TEXT_ATTR_HEADING)
382                         {
383                         pa = pango_attr_scale_new(PANGO_SCALE_LARGE);
384                         pa->start_index = 0;
385                         pa->end_index = G_MAXINT;
386                         pango_attr_list_insert(pal, pa);
387                         }
388                 pango_layout_set_attributes(layout, pal);
389                 pango_attr_list_unref(pal);
390                 }
391
392         pango_layout_set_text(layout, pi->text, -1);
393         return layout;
394 }
395
396 static void pan_item_text_compute_size(PanItem *pi, GtkWidget *widget)
397 {
398         PangoLayout *layout;
399
400         if (!pi || !pi->text || !widget) return;
401
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));
405
406         pi->width += pi->border * 2;
407         pi->height += pi->border * 2;
408 }
409
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)
413 {
414         PanItem *pi;
415
416         pi = g_new0(PanItem, 1);
417         pi->type = PAN_ITEM_TEXT;
418         pi->x = x;
419         pi->y = y;
420         pi->text = g_strdup(text);
421         pi->text_attr = attr;
422
423         pi->color_r = r;
424         pi->color_g = g;
425         pi->color_b = b;
426         pi->color_a = a;
427
428         pi->border = border;
429
430         pan_item_text_compute_size(pi, pw->imd->pr);
431
432         pw->list = g_list_prepend(pw->list, pi);
433
434         return pi;
435 }
436
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))
439 {
440         PangoLayout *layout;
441
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));
447
448         return FALSE;
449 }
450
451
452 /*
453  *-----------------------------------------------------------------------------
454  * item thumbnail type
455  *-----------------------------------------------------------------------------
456  */
457
458 PanItem *pan_item_thumb_new(PanWindow *pw, FileData *fd, gint x, gint y)
459 {
460         PanItem *pi;
461
462         pi = g_new0(PanItem, 1);
463
464         pi->type = PAN_ITEM_THUMB;
465         pi->fd = fd;
466         pi->x = x;
467         pi->y = y;
468         pi->width = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
469         pi->height = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
470
471         pw->list = g_list_prepend(pw->list, pi);
472
473         return pi;
474 }
475
476 gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *UNUSED(pr),
477                          gint x, gint y, gint width, gint height)
478 {
479         gint tx, ty, tw, th;
480         gint rx, ry, rw, rh;
481
482         if (pi->pixbuf)
483                 {
484                 tw = gdk_pixbuf_get_width(pi->pixbuf);
485                 th = gdk_pixbuf_get_height(pi->pixbuf);
486
487                 tx = pi->x + (pi->width - tw) / 2;
488                 ty = pi->y + (pi->height - th) / 2;
489
490                 if (gdk_pixbuf_get_has_alpha(pi->pixbuf))
491                         {
492                         if (util_clip_region(x, y, width, height,
493                                              tx + PAN_SHADOW_OFFSET, ty + PAN_SHADOW_OFFSET, tw, th,
494                                              &rx, &ry, &rw, &rh))
495                                 {
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,
499                                                    PAN_SHADOW_FADE,
500                                                    PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
501                                 }
502                         }
503                 else
504                         {
505                         if (util_clip_region(x, y, width, height,
506                                              tx + tw, ty + PAN_SHADOW_OFFSET,
507                                              PAN_SHADOW_OFFSET, th - PAN_SHADOW_OFFSET,
508                                              &rx, &ry, &rw, &rh))
509                                 {
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,
513                                                    PAN_SHADOW_FADE,
514                                                    PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
515                                 }
516                         if (util_clip_region(x, y, width, height,
517                                              tx + PAN_SHADOW_OFFSET, ty + th, tw, 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                         }
527
528                 if (util_clip_region(x, y, width, height,
529                                      tx, ty, tw, th,
530                                      &rx, &ry, &rw, &rh))
531                         {
532                         gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
533                                              (gdouble) tx - x,
534                                              (gdouble) ty - y,
535                                              1.0, 1.0, GDK_INTERP_NEAREST,
536                                              255);
537                         }
538
539                 if (util_clip_region(x, y, width, height,
540                                      tx, ty, tw, PAN_OUTLINE_THICKNESS,
541                                      &rx, &ry, &rw, &rh))
542                         {
543                         pixbuf_draw_rect_fill(pixbuf,
544                                               rx - x, ry - y, rw, rh,
545                                               PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
546                         }
547                 if (util_clip_region(x, y, width, height,
548                                      tx, ty, PAN_OUTLINE_THICKNESS, th,
549                                      &rx, &ry, &rw, &rh))
550                         {
551                         pixbuf_draw_rect_fill(pixbuf,
552                                               rx - x, ry - y, rw, rh,
553                                               PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
554                         }
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,
558                                      &rx, &ry, &rw, &rh))
559                         {
560                         pixbuf_draw_rect_fill(pixbuf,
561                                               rx - x, ry - y, rw, rh,
562                                               PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
563                         }
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,
567                                      &rx, &ry, &rw, &rh))
568                         {
569                         pixbuf_draw_rect_fill(pixbuf,
570                                               rx - x, ry - y, rw, rh,
571                                               PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
572                         }
573                 }
574         else
575                 {
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;
580
581                 if (util_clip_region(x, y, width, height,
582                                      tx, ty, tw, th,
583                                      &rx, &ry, &rw, &rh))
584                         {
585                         gint d;
586
587                         d = (pw->size <= PAN_IMAGE_SIZE_THUMB_NONE) ? 2 : 8;
588                         pixbuf_draw_rect_fill(pixbuf,
589                                               rx - x, ry - y, rw, rh,
590                                               PAN_SHADOW_COLOR,
591                                               PAN_SHADOW_ALPHA / d);
592                         }
593                 }
594
595         return (pi->pixbuf == NULL);
596 }
597
598
599 /*
600  *-----------------------------------------------------------------------------
601  * item image type
602  *-----------------------------------------------------------------------------
603  */
604
605 static void pan_item_image_find_size(PanWindow *pw, PanItem *pi, gint w, gint h)
606 {
607         GList *work;
608
609         pi->width = w;
610         pi->height = h;
611
612         if (!pi->fd) return;
613
614         work = pw->cache_list;
615         while (work)
616                 {
617                 PanCacheData *pc;
618
619                 pc = work->data;
620                 work = work->next;
621
622                 if (pc->cd && pc->cd->dimensions &&
623                     pc->fd && pc->fd == pi->fd)
624                         {
625                         pi->width = MAX(1, pc->cd->width * pw->image_size / 100);
626                         pi->height = MAX(1, pc->cd->height * pw->image_size / 100);
627
628                         pw->cache_list = g_list_remove(pw->cache_list, pc);
629                         cache_sim_data_free(pc->cd);
630                         file_data_unref(pc->fd);
631                         g_free(pc);
632                         return;
633                         }
634                 }
635 }
636
637 PanItem *pan_item_image_new(PanWindow *pw, FileData *fd, gint x, gint y, gint w, gint h)
638 {
639         PanItem *pi;
640
641         pi = g_new0(PanItem, 1);
642         pi->type = PAN_ITEM_IMAGE;
643         pi->fd = fd;
644         pi->x = x;
645         pi->y = y;
646
647         pi->color_a = 255;
648
649         pi->color2_r = 0;
650         pi->color2_g = 0;
651         pi->color2_b = 0;
652         pi->color2_a = PAN_SHADOW_ALPHA / 2;
653
654         pan_item_image_find_size(pw, pi, w, h);
655
656         pw->list = g_list_prepend(pw->list, pi);
657
658         return pi;
659 }
660
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)
663 {
664         gint rx, ry, rw, rh;
665
666         if (util_clip_region(x, y, width, height,
667                              pi->x, pi->y, pi->width, pi->height,
668                              &rx, &ry, &rw, &rh))
669                 {
670                 if (pi->pixbuf)
671                         {
672                         gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
673                                              (gdouble) pi->x - x,
674                                              (gdouble) pi->y - y,
675                                              1.0, 1.0, GDK_INTERP_NEAREST,
676                                              pi->color_a);
677                         }
678                 else
679                         {
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);
683                         }
684                 }
685
686         return (pi->pixbuf == NULL);
687 }
688
689
690 /*
691  *-----------------------------------------------------------------------------
692  * item lookup/search
693  *-----------------------------------------------------------------------------
694  */
695
696 PanItem *pan_item_find_by_key(PanWindow *pw, PanItemType type, const gchar *key)
697 {
698         GList *work;
699
700         if (!key) return NULL;
701
702         work = g_list_last(pw->list);
703         while (work)
704                 {
705                 PanItem *pi;
706
707                 pi = work->data;
708                 if ((pi->type == type || type == PAN_ITEM_NONE) &&
709                      pi->key && strcmp(pi->key, key) == 0)
710                         {
711                         return pi;
712                         }
713                 work = work->prev;
714                 }
715         work = g_list_last(pw->list_static);
716         while (work)
717                 {
718                 PanItem *pi;
719
720                 pi = work->data;
721                 if ((pi->type == type || type == PAN_ITEM_NONE) &&
722                      pi->key && strcmp(pi->key, key) == 0)
723                         {
724                         return pi;
725                         }
726                 work = work->prev;
727                 }
728
729         return NULL;
730 }
731
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)
736 {
737         GList *work;
738
739         work = g_list_last(search_list);
740         while (work)
741                 {
742                 PanItem *pi;
743
744                 pi = work->data;
745                 if ((pi->type == type || type == PAN_ITEM_NONE) && pi->fd)
746                         {
747                         gboolean match = FALSE;
748
749                         if (path[0] == G_DIR_SEPARATOR)
750                                 {
751                                 if (pi->fd->path && strcmp(path, pi->fd->path) == 0) match = TRUE;
752                                 }
753                         else if (pi->fd->name)
754                                 {
755                                 if (partial)
756                                         {
757                                         if (ignore_case)
758                                                 {
759                                                 gchar *haystack;
760
761                                                 haystack = g_utf8_strdown(pi->fd->name, -1);
762                                                 match = (strstr(haystack, path) != NULL);
763                                                 g_free(haystack);
764                                                 }
765                                         else
766                                                 {
767                                                 if (strstr(pi->fd->name, path)) match = TRUE;
768                                                 }
769                                         }
770                                 else if (ignore_case)
771                                         {
772                                         if (g_ascii_strcasecmp(path, pi->fd->name) == 0) match = TRUE;
773                                         }
774                                 else
775                                         {
776                                         if (strcmp(path, pi->fd->name) == 0) match = TRUE;
777                                         }
778                                 }
779
780                         if (match) list = g_list_prepend(list, pi);
781                         }
782                 work = work->prev;
783                 }
784
785         return list;
786 }
787
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)
791 {
792         GList *list = NULL;
793
794         if (!path) return NULL;
795         if (partial && path[0] == G_DIR_SEPARATOR) return NULL;
796
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);
799
800         return g_list_reverse(list);
801 }
802
803 GList *pan_item_find_by_fd(PanWindow *pw, PanItemType type, FileData *fd,
804                            gboolean ignore_case, gboolean partial)
805 {
806         if (!fd) return NULL;
807         return pan_item_find_by_path(pw, type, fd->path, ignore_case, partial);
808 }
809
810
811 static PanItem *pan_item_find_by_coord_l(GList *list, PanItemType type, gint x, gint y, const gchar *key)
812 {
813         GList *work;
814
815         work = list;
816         while (work)
817                 {
818                 PanItem *pi;
819
820                 pi = work->data;
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)))
825                         {
826                         return pi;
827                         }
828                 work = work->next;
829                 }
830
831         return NULL;
832 }
833
834 PanItem *pan_item_find_by_coord(PanWindow *pw, PanItemType type,
835                                 gint x, gint y, const gchar *key)
836 {
837         PanItem *pi;
838
839         pi = pan_item_find_by_coord_l(pw->list, type, x, y, key);
840         if (pi) return pi;
841
842         return pan_item_find_by_coord_l(pw->list_static, type, x, y, key);
843 }
844
845
846 /*
847  *-----------------------------------------------------------------------------
848  * text alignments
849  *-----------------------------------------------------------------------------
850  */
851
852 PanTextAlignment *pan_text_alignment_new(PanWindow *pw, gint x, gint y, const gchar *key)
853 {
854         PanTextAlignment *ta;
855
856         ta = g_new0(PanTextAlignment, 1);
857
858         ta->pw = pw;
859         ta->x = x;
860         ta->y = y;
861         ta->key = g_strdup(key);
862
863         return ta;
864 }
865
866 void pan_text_alignment_free(PanTextAlignment *ta)
867 {
868         if (!ta) return;
869
870         g_list_free(ta->column1);
871         g_list_free(ta->column2);
872         g_free(ta->key);
873         g_free(ta);
874 }
875
876 PanItem *pan_text_alignment_add(PanTextAlignment *ta, const gchar *label, const gchar *text)
877 {
878         PanItem *item;
879
880         if (label)
881                 {
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);
886                 }
887         else
888                 {
889                 item = NULL;
890                 }
891         ta->column1 = g_list_append(ta->column1, item);
892
893         if (text)
894                 {
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);
899                 }
900         else
901                 {
902                 item = NULL;
903                 }
904         ta->column2 = g_list_append(ta->column2, item);
905
906         return item;
907 }
908
909 void pan_text_alignment_calc(PanTextAlignment *ta, PanItem *box)
910 {
911         gint cw1, cw2;
912         gint x, y;
913         GList *work1;
914         GList *work2;
915
916         cw1 = 0;
917         cw2 = 0;
918
919         work1 = ta->column1;
920         while (work1)
921                 {
922                 PanItem *p;
923
924                 p = work1->data;
925                 work1 = work1->next;
926
927                 if (p && p->width > cw1) cw1 = p->width;
928                 }
929
930         work2 = ta->column2;
931         while (work2)
932                 {
933                 PanItem *p;
934
935                 p = work2->data;
936                 work2 = work2->next;
937
938                 if (p && p->width > cw2) cw2 = p->width;
939                 }
940
941         x = ta->x;
942         y = ta->y;
943         work1 = ta->column1;
944         work2 = ta->column2;
945         while (work1 && work2)
946                 {
947                 PanItem *p1;
948                 PanItem *p2;
949                 gint height = 0;
950
951                 p1 = work1->data;
952                 p2 = work2->data;
953                 work1 = work1->next;
954                 work2 = work2->next;
955
956                 if (p1)
957                         {
958                         p1->x = x;
959                         p1->y = y;
960                         pan_item_size_by_item(box, p1, PREF_PAD_BORDER);
961                         height = p1->height;
962                         }
963                 if (p2)
964                         {
965                         p2->x = x + cw1 + PREF_PAD_SPACE;
966                         p2->y = y;
967                         pan_item_size_by_item(box, p2, PREF_PAD_BORDER);
968                         if (height < p2->height) height = p2->height;
969                         }
970
971                 if (!p1 && !p2) height = PREF_PAD_GROUP;
972
973                 y += height;
974                 }
975 }
976 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */