Thu Nov 9 17:43:06 2006 John Ellis <johne@verizon.net>
[geeqie.git] / src / pan-item.c
1 /*
2  * GQview
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_free(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                 gchar *path;
611
612                 pc = work->data;
613                 work = work->next;
614
615                 path = ((FileData *)pc)->path;
616
617                 if (pc->cd && pc->cd->dimensions &&
618                     path && strcmp(path, pi->fd->path) == 0)
619                         {
620                         pi->width = MAX(1, pc->cd->width * pw->image_size / 100);
621                         pi->height = MAX(1, pc->cd->height * pw->image_size / 100);
622
623                         pw->cache_list = g_list_remove(pw->cache_list, pc);
624                         cache_sim_data_free(pc->cd);
625                         file_data_free((FileData *)pc);
626                         return;
627                         }
628                 }
629 }
630
631 PanItem *pan_item_image_new(PanWindow *pw, FileData *fd, gint x, gint y, gint w, gint h)
632 {
633         PanItem *pi;
634
635         pi = g_new0(PanItem, 1);
636         pi->type = PAN_ITEM_IMAGE;
637         pi->fd = fd;
638         pi->x = x;
639         pi->y = y;
640
641         pi->color_a = 255;
642
643         pi->color2_r = 0;
644         pi->color2_g = 0;
645         pi->color2_b = 0;
646         pi->color2_a = PAN_SHADOW_ALPHA / 2;
647
648         pan_item_image_find_size(pw, pi, w, h);
649
650         pw->list = g_list_prepend(pw->list, pi);
651
652         return pi;
653 }
654
655 gint pan_item_image_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
656                          gint x, gint y, gint width, gint height)
657 {
658         gint rx, ry, rw, rh;
659
660         if (util_clip_region(x, y, width, height,
661                              pi->x, pi->y, pi->width, pi->height,
662                              &rx, &ry, &rw, &rh))
663                 {
664                 if (pi->pixbuf)
665                         {
666                         gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
667                                              (double) pi->x - x,
668                                              (double) pi->y - y,
669                                              1.0, 1.0, GDK_INTERP_NEAREST,
670                                              pi->color_a);
671                         }
672                 else
673                         {
674                         pixbuf_draw_rect_fill(pixbuf,
675                                               rx - x, ry - y, rw, rh,
676                                               pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
677                         }
678                 }
679
680         return (pi->pixbuf == NULL);
681 }
682
683
684 /*
685  *-----------------------------------------------------------------------------
686  * item lookup/search
687  *-----------------------------------------------------------------------------
688  */
689
690 PanItem *pan_item_find_by_key(PanWindow *pw, PanItemType type, const gchar *key)
691 {
692         GList *work;
693
694         if (!key) return NULL;
695
696         work = g_list_last(pw->list);
697         while (work)
698                 {
699                 PanItem *pi;
700
701                 pi = work->data;
702                 if ((pi->type == type || type == PAN_ITEM_NONE) &&
703                      pi->key && strcmp(pi->key, key) == 0)
704                         {
705                         return pi;
706                         }
707                 work = work->prev;
708                 }
709         work = g_list_last(pw->list_static);
710         while (work)
711                 {
712                 PanItem *pi;
713
714                 pi = work->data;
715                 if ((pi->type == type || type == PAN_ITEM_NONE) &&
716                      pi->key && strcmp(pi->key, key) == 0)
717                         {
718                         return pi;
719                         }
720                 work = work->prev;
721                 }
722
723         return NULL;
724 }
725
726 /* when ignore_case and partial are TRUE, path should be converted to lower case */
727 static GList *pan_item_find_by_path_l(GList *list, GList *search_list,
728                                       PanItemType type, const gchar *path,
729                                       gint ignore_case, gint partial)
730 {
731         GList *work;
732
733         work = g_list_last(search_list);
734         while (work)
735                 {
736                 PanItem *pi;
737
738                 pi = work->data;
739                 if ((pi->type == type || type == PAN_ITEM_NONE) && pi->fd)
740                         {
741                         gint match = FALSE;
742
743                         if (path[0] == '/')
744                                 {
745                                 if (pi->fd->path && strcmp(path, pi->fd->path) == 0) match = TRUE;
746                                 }
747                         else if (pi->fd->name)
748                                 {
749                                 if (partial)
750                                         {
751                                         if (ignore_case)
752                                                 {
753                                                 gchar *haystack;
754
755                                                 haystack = g_utf8_strdown(pi->fd->name, -1);
756                                                 match = (strstr(haystack, path) != NULL);
757                                                 g_free(haystack);
758                                                 }
759                                         else
760                                                 {
761                                                 if (strstr(pi->fd->name, path)) match = TRUE;
762                                                 }
763                                         }
764                                 else if (ignore_case)
765                                         {
766                                         if (strcasecmp(path, pi->fd->name) == 0) match = TRUE;
767                                         }
768                                 else
769                                         {
770                                         if (strcmp(path, pi->fd->name) == 0) match = TRUE;
771                                         }
772                                 }
773
774                         if (match) list = g_list_prepend(list, pi);
775                         }
776                 work = work->prev;
777                 }
778
779         return list;
780 }
781
782 /* when ignore_case and partial are TRUE, path should be converted to lower case */
783 GList *pan_item_find_by_path(PanWindow *pw, PanItemType type, const gchar *path,
784                              gint ignore_case, gint partial)
785 {
786         GList *list = NULL;
787
788         if (!path) return NULL;
789         if (partial && path[0] == '/') return NULL;
790
791         list = pan_item_find_by_path_l(list, pw->list_static, type, path, ignore_case, partial);
792         list = pan_item_find_by_path_l(list, pw->list, type, path, ignore_case, partial);
793
794         return g_list_reverse(list);
795 }
796
797 static PanItem *pan_item_find_by_coord_l(GList *list, PanItemType type, gint x, gint y, const gchar *key)
798 {
799         GList *work;
800
801         work = list;
802         while (work)
803                 {
804                 PanItem *pi;
805
806                 pi = work->data;
807                 if ((pi->type == type || type == PAN_ITEM_NONE) &&
808                      x >= pi->x && x < pi->x + pi->width &&
809                      y >= pi->y && y < pi->y + pi->height &&
810                     (!key || (pi->key && strcmp(pi->key, key) == 0)))
811                         {
812                         return pi;
813                         }
814                 work = work->next;
815                 }
816
817         return NULL;
818 }
819
820 PanItem *pan_item_find_by_coord(PanWindow *pw, PanItemType type,
821                                 gint x, gint y, const gchar *key)
822 {
823         PanItem *pi;
824
825         pi = pan_item_find_by_coord_l(pw->list, type, x, y, key);
826         if (pi) return pi;
827
828         return pan_item_find_by_coord_l(pw->list_static, type, x, y, key);
829 }
830
831
832 /*
833  *-----------------------------------------------------------------------------
834  * text alignments
835  *-----------------------------------------------------------------------------
836  */
837
838 PanTextAlignment *pan_text_alignment_new(PanWindow *pw, gint x, gint y, const gchar *key)
839 {
840         PanTextAlignment *ta;
841
842         ta = g_new0(PanTextAlignment, 1);
843
844         ta->pw = pw;
845         ta->column1 = NULL;
846         ta->column2 = NULL;
847         ta->x = x;
848         ta->y = y;
849         ta->key = g_strdup(key);
850
851         return ta;
852 }
853
854 void pan_text_alignment_free(PanTextAlignment *ta)
855 {
856         if (!ta) return;
857
858         g_list_free(ta->column1);
859         g_list_free(ta->column2);
860         g_free(ta->key);
861         g_free(ta);
862 }
863
864 PanItem *pan_text_alignment_add(PanTextAlignment *ta, const gchar *label, const gchar *text)
865 {
866         PanItem *item;
867
868         if (label)
869                 {
870                 item = pan_item_text_new(ta->pw, ta->x, ta->y, label,
871                                          PAN_TEXT_ATTR_BOLD, 0,
872                                          PAN_POPUP_TEXT_COLOR, 255);
873                 pan_item_set_key(item, ta->key);
874                 }
875         else
876                 {
877                 item = NULL;
878                 }
879         ta->column1 = g_list_append(ta->column1, item);
880
881         if (text)
882                 {
883                 item = pan_item_text_new(ta->pw, ta->x, ta->y, text,
884                                          PAN_TEXT_ATTR_NONE, 0,
885                                          PAN_POPUP_TEXT_COLOR, 255);
886                 pan_item_set_key(item, ta->key);
887                 }
888         else
889                 {
890                 item = NULL;
891                 }
892         ta->column2 = g_list_append(ta->column2, item);
893
894         return item;
895 }
896
897 void pan_text_alignment_calc(PanTextAlignment *ta, PanItem *box)
898 {
899         gint cw1, cw2;
900         gint x, y;
901         GList *work1;
902         GList *work2;
903
904         cw1 = 0;
905         cw2 = 0;
906
907         work1 = ta->column1;
908         while (work1)
909                 {
910                 PanItem *p;
911
912                 p = work1->data;
913                 work1 = work1->next;
914
915                 if (p && p->width > cw1) cw1 = p->width;
916                 }
917
918         work2 = ta->column2;
919         while (work2)
920                 {
921                 PanItem *p;
922
923                 p = work2->data;
924                 work2 = work2->next;
925
926                 if (p && p->width > cw2) cw2 = p->width;
927                 }
928
929         x = ta->x;
930         y = ta->y;
931         work1 = ta->column1;
932         work2 = ta->column2;
933         while (work1 && work2)
934                 {
935                 PanItem *p1;
936                 PanItem *p2;
937                 gint height = 0;
938
939                 p1 = work1->data;
940                 p2 = work2->data;
941                 work1 = work1->next;
942                 work2 = work2->next;
943
944                 if (p1)
945                         {
946                         p1->x = x;
947                         p1->y = y;
948                         pan_item_size_by_item(box, p1, PREF_PAD_BORDER);
949                         height = p1->height;
950                         }
951                 if (p2)
952                         {
953                         p2->x = x + cw1 + PREF_PAD_SPACE;
954                         p2->y = y;
955                         pan_item_size_by_item(box, p2, PREF_PAD_BORDER);
956                         if (height < p2->height) height = p2->height;
957                         }
958
959                 if (!p1 && !p2) height = PREF_PAD_GROUP;
960
961                 y += height;
962                 }
963 }
964
965