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