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