Trim trailing white spaces on empty lines.
[geeqie.git] / src / pan-item.c
1 /*
2  * Geeqie
3  * (C) 2006 John Ellis
4  * Copyright (C) 2008 - 2012 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
454         pi->type = PAN_ITEM_THUMB;
455         pi->fd = fd;
456         pi->x = x;
457         pi->y = y;
458         pi->width = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
459         pi->height = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
460
461         pw->list = g_list_prepend(pw->list, pi);
462
463         return pi;
464 }
465
466 gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
467                          gint x, gint y, gint width, gint height)
468 {
469         gint tx, ty, tw, th;
470         gint rx, ry, rw, rh;
471
472         if (pi->pixbuf)
473                 {
474                 tw = gdk_pixbuf_get_width(pi->pixbuf);
475                 th = gdk_pixbuf_get_height(pi->pixbuf);
476
477                 tx = pi->x + (pi->width - tw) / 2;
478                 ty = pi->y + (pi->height - th) / 2;
479
480                 if (gdk_pixbuf_get_has_alpha(pi->pixbuf))
481                         {
482                         if (util_clip_region(x, y, width, height,
483                                              tx + PAN_SHADOW_OFFSET, ty + PAN_SHADOW_OFFSET, tw, th,
484                                              &rx, &ry, &rw, &rh))
485                                 {
486                                 pixbuf_draw_shadow(pixbuf,
487                                                    rx - x, ry - y, rw, rh,
488                                                    tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
489                                                    PAN_SHADOW_FADE,
490                                                    PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
491                                 }
492                         }
493                 else
494                         {
495                         if (util_clip_region(x, y, width, height,
496                                              tx + tw, ty + PAN_SHADOW_OFFSET,
497                                              PAN_SHADOW_OFFSET, th - PAN_SHADOW_OFFSET,
498                                              &rx, &ry, &rw, &rh))
499                                 {
500                                 pixbuf_draw_shadow(pixbuf,
501                                                    rx - x, ry - y, rw, rh,
502                                                    tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
503                                                    PAN_SHADOW_FADE,
504                                                    PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
505                                 }
506                         if (util_clip_region(x, y, width, height,
507                                              tx + PAN_SHADOW_OFFSET, ty + th, tw, PAN_SHADOW_OFFSET,
508                                              &rx, &ry, &rw, &rh))
509                                 {
510                                 pixbuf_draw_shadow(pixbuf,
511                                                    rx - x, ry - y, rw, rh,
512                                                    tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
513                                                    PAN_SHADOW_FADE,
514                                                    PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
515                                 }
516                         }
517
518                 if (util_clip_region(x, y, width, height,
519                                      tx, ty, tw, th,
520                                      &rx, &ry, &rw, &rh))
521                         {
522                         gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
523                                              (gdouble) tx - x,
524                                              (gdouble) ty - y,
525                                              1.0, 1.0, GDK_INTERP_NEAREST,
526                                              255);
527                         }
528
529                 if (util_clip_region(x, y, width, height,
530                                      tx, ty, tw, PAN_OUTLINE_THICKNESS,
531                                      &rx, &ry, &rw, &rh))
532                         {
533                         pixbuf_draw_rect_fill(pixbuf,
534                                               rx - x, ry - y, rw, rh,
535                                               PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
536                         }
537                 if (util_clip_region(x, y, width, height,
538                                      tx, ty, PAN_OUTLINE_THICKNESS, th,
539                                      &rx, &ry, &rw, &rh))
540                         {
541                         pixbuf_draw_rect_fill(pixbuf,
542                                               rx - x, ry - y, rw, rh,
543                                               PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
544                         }
545                 if (util_clip_region(x, y, width, height,
546                                      tx + tw - PAN_OUTLINE_THICKNESS, ty +  PAN_OUTLINE_THICKNESS,
547                                      PAN_OUTLINE_THICKNESS, th - PAN_OUTLINE_THICKNESS,
548                                      &rx, &ry, &rw, &rh))
549                         {
550                         pixbuf_draw_rect_fill(pixbuf,
551                                               rx - x, ry - y, rw, rh,
552                                               PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
553                         }
554                 if (util_clip_region(x, y, width, height,
555                                      tx +  PAN_OUTLINE_THICKNESS, ty + th - PAN_OUTLINE_THICKNESS,
556                                      tw - PAN_OUTLINE_THICKNESS * 2, PAN_OUTLINE_THICKNESS,
557                                      &rx, &ry, &rw, &rh))
558                         {
559                         pixbuf_draw_rect_fill(pixbuf,
560                                               rx - x, ry - y, rw, rh,
561                                               PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
562                         }
563                 }
564         else
565                 {
566                 tw = pi->width - PAN_SHADOW_OFFSET * 2;
567                 th = pi->height - PAN_SHADOW_OFFSET * 2;
568                 tx = pi->x + PAN_SHADOW_OFFSET;
569                 ty = pi->y + PAN_SHADOW_OFFSET;
570
571                 if (util_clip_region(x, y, width, height,
572                                      tx, ty, tw, th,
573                                      &rx, &ry, &rw, &rh))
574                         {
575                         gint d;
576
577                         d = (pw->size <= PAN_IMAGE_SIZE_THUMB_NONE) ? 2 : 8;
578                         pixbuf_draw_rect_fill(pixbuf,
579                                               rx - x, ry - y, rw, rh,
580                                               PAN_SHADOW_COLOR,
581                                               PAN_SHADOW_ALPHA / d);
582                         }
583                 }
584
585         return (pi->pixbuf == NULL);
586 }
587
588
589 /*
590  *-----------------------------------------------------------------------------
591  * item image type
592  *-----------------------------------------------------------------------------
593  */
594
595 static void pan_item_image_find_size(PanWindow *pw, PanItem *pi, gint w, gint h)
596 {
597         GList *work;
598
599         pi->width = w;
600         pi->height = h;
601
602         if (!pi->fd) return;
603
604         work = pw->cache_list;
605         while (work)
606                 {
607                 PanCacheData *pc;
608
609                 pc = work->data;
610                 work = work->next;
611
612                 if (pc->cd && pc->cd->dimensions &&
613                     pc->fd && pc->fd == pi->fd)
614                         {
615                         pi->width = MAX(1, pc->cd->width * pw->image_size / 100);
616                         pi->height = MAX(1, pc->cd->height * pw->image_size / 100);
617
618                         pw->cache_list = g_list_remove(pw->cache_list, pc);
619                         cache_sim_data_free(pc->cd);
620                         file_data_unref(pc->fd);
621                         g_free(pc);
622                         return;
623                         }
624                 }
625 }
626
627 PanItem *pan_item_image_new(PanWindow *pw, FileData *fd, gint x, gint y, gint w, gint h)
628 {
629         PanItem *pi;
630
631         pi = g_new0(PanItem, 1);
632         pi->type = PAN_ITEM_IMAGE;
633         pi->fd = fd;
634         pi->x = x;
635         pi->y = y;
636
637         pi->color_a = 255;
638
639         pi->color2_r = 0;
640         pi->color2_g = 0;
641         pi->color2_b = 0;
642         pi->color2_a = PAN_SHADOW_ALPHA / 2;
643
644         pan_item_image_find_size(pw, pi, w, h);
645
646         pw->list = g_list_prepend(pw->list, pi);
647
648         return pi;
649 }
650
651 gint pan_item_image_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
652                          gint x, gint y, gint width, gint height)
653 {
654         gint rx, ry, rw, rh;
655
656         if (util_clip_region(x, y, width, height,
657                              pi->x, pi->y, pi->width, pi->height,
658                              &rx, &ry, &rw, &rh))
659                 {
660                 if (pi->pixbuf)
661                         {
662                         gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
663                                              (gdouble) pi->x - x,
664                                              (gdouble) pi->y - y,
665                                              1.0, 1.0, GDK_INTERP_NEAREST,
666                                              pi->color_a);
667                         }
668                 else
669                         {
670                         pixbuf_draw_rect_fill(pixbuf,
671                                               rx - x, ry - y, rw, rh,
672                                               pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
673                         }
674                 }
675
676         return (pi->pixbuf == NULL);
677 }
678
679
680 /*
681  *-----------------------------------------------------------------------------
682  * item lookup/search
683  *-----------------------------------------------------------------------------
684  */
685
686 PanItem *pan_item_find_by_key(PanWindow *pw, PanItemType type, const gchar *key)
687 {
688         GList *work;
689
690         if (!key) return NULL;
691
692         work = g_list_last(pw->list);
693         while (work)
694                 {
695                 PanItem *pi;
696
697                 pi = work->data;
698                 if ((pi->type == type || type == PAN_ITEM_NONE) &&
699                      pi->key && strcmp(pi->key, key) == 0)
700                         {
701                         return pi;
702                         }
703                 work = work->prev;
704                 }
705         work = g_list_last(pw->list_static);
706         while (work)
707                 {
708                 PanItem *pi;
709
710                 pi = work->data;
711                 if ((pi->type == type || type == PAN_ITEM_NONE) &&
712                      pi->key && strcmp(pi->key, key) == 0)
713                         {
714                         return pi;
715                         }
716                 work = work->prev;
717                 }
718
719         return NULL;
720 }
721
722 /* when ignore_case and partial are TRUE, path should be converted to lower case */
723 static GList *pan_item_find_by_path_l(GList *list, GList *search_list,
724                                       PanItemType type, const gchar *path,
725                                       gboolean ignore_case, gboolean partial)
726 {
727         GList *work;
728
729         work = g_list_last(search_list);
730         while (work)
731                 {
732                 PanItem *pi;
733
734                 pi = work->data;
735                 if ((pi->type == type || type == PAN_ITEM_NONE) && pi->fd)
736                         {
737                         gboolean match = FALSE;
738
739                         if (path[0] == G_DIR_SEPARATOR)
740                                 {
741                                 if (pi->fd->path && strcmp(path, pi->fd->path) == 0) match = TRUE;
742                                 }
743                         else if (pi->fd->name)
744                                 {
745                                 if (partial)
746                                         {
747                                         if (ignore_case)
748                                                 {
749                                                 gchar *haystack;
750
751                                                 haystack = g_utf8_strdown(pi->fd->name, -1);
752                                                 match = (strstr(haystack, path) != NULL);
753                                                 g_free(haystack);
754                                                 }
755                                         else
756                                                 {
757                                                 if (strstr(pi->fd->name, path)) match = TRUE;
758                                                 }
759                                         }
760                                 else if (ignore_case)
761                                         {
762                                         if (g_ascii_strcasecmp(path, pi->fd->name) == 0) match = TRUE;
763                                         }
764                                 else
765                                         {
766                                         if (strcmp(path, pi->fd->name) == 0) match = TRUE;
767                                         }
768                                 }
769
770                         if (match) list = g_list_prepend(list, pi);
771                         }
772                 work = work->prev;
773                 }
774
775         return list;
776 }
777
778 /* when ignore_case and partial are TRUE, path should be converted to lower case */
779 GList *pan_item_find_by_path(PanWindow *pw, PanItemType type, const gchar *path,
780                              gboolean ignore_case, gboolean partial)
781 {
782         GList *list = NULL;
783
784         if (!path) return NULL;
785         if (partial && path[0] == G_DIR_SEPARATOR) return NULL;
786
787         list = pan_item_find_by_path_l(list, pw->list_static, type, path, ignore_case, partial);
788         list = pan_item_find_by_path_l(list, pw->list, type, path, ignore_case, partial);
789
790         return g_list_reverse(list);
791 }
792
793 GList *pan_item_find_by_fd(PanWindow *pw, PanItemType type, FileData *fd,
794                            gboolean ignore_case, gboolean partial)
795 {
796         if (!fd) return NULL;
797         return pan_item_find_by_path(pw, type, fd->path, ignore_case, partial);
798 }
799
800
801 static PanItem *pan_item_find_by_coord_l(GList *list, PanItemType type, gint x, gint y, const gchar *key)
802 {
803         GList *work;
804
805         work = list;
806         while (work)
807                 {
808                 PanItem *pi;
809
810                 pi = work->data;
811                 if ((pi->type == type || type == PAN_ITEM_NONE) &&
812                      x >= pi->x && x < pi->x + pi->width &&
813                      y >= pi->y && y < pi->y + pi->height &&
814                     (!key || (pi->key && strcmp(pi->key, key) == 0)))
815                         {
816                         return pi;
817                         }
818                 work = work->next;
819                 }
820
821         return NULL;
822 }
823
824 PanItem *pan_item_find_by_coord(PanWindow *pw, PanItemType type,
825                                 gint x, gint y, const gchar *key)
826 {
827         PanItem *pi;
828
829         pi = pan_item_find_by_coord_l(pw->list, type, x, y, key);
830         if (pi) return pi;
831
832         return pan_item_find_by_coord_l(pw->list_static, type, x, y, key);
833 }
834
835
836 /*
837  *-----------------------------------------------------------------------------
838  * text alignments
839  *-----------------------------------------------------------------------------
840  */
841
842 PanTextAlignment *pan_text_alignment_new(PanWindow *pw, gint x, gint y, const gchar *key)
843 {
844         PanTextAlignment *ta;
845
846         ta = g_new0(PanTextAlignment, 1);
847
848         ta->pw = pw;
849         ta->x = x;
850         ta->y = y;
851         ta->key = g_strdup(key);
852
853         return ta;
854 }
855
856 void pan_text_alignment_free(PanTextAlignment *ta)
857 {
858         if (!ta) return;
859
860         g_list_free(ta->column1);
861         g_list_free(ta->column2);
862         g_free(ta->key);
863         g_free(ta);
864 }
865
866 PanItem *pan_text_alignment_add(PanTextAlignment *ta, const gchar *label, const gchar *text)
867 {
868         PanItem *item;
869
870         if (label)
871                 {
872                 item = pan_item_text_new(ta->pw, ta->x, ta->y, label,
873                                          PAN_TEXT_ATTR_BOLD, 0,
874                                          PAN_POPUP_TEXT_COLOR, 255);
875                 pan_item_set_key(item, ta->key);
876                 }
877         else
878                 {
879                 item = NULL;
880                 }
881         ta->column1 = g_list_append(ta->column1, item);
882
883         if (text)
884                 {
885                 item = pan_item_text_new(ta->pw, ta->x, ta->y, text,
886                                          PAN_TEXT_ATTR_NONE, 0,
887                                          PAN_POPUP_TEXT_COLOR, 255);
888                 pan_item_set_key(item, ta->key);
889                 }
890         else
891                 {
892                 item = NULL;
893                 }
894         ta->column2 = g_list_append(ta->column2, item);
895
896         return item;
897 }
898
899 void pan_text_alignment_calc(PanTextAlignment *ta, PanItem *box)
900 {
901         gint cw1, cw2;
902         gint x, y;
903         GList *work1;
904         GList *work2;
905
906         cw1 = 0;
907         cw2 = 0;
908
909         work1 = ta->column1;
910         while (work1)
911                 {
912                 PanItem *p;
913
914                 p = work1->data;
915                 work1 = work1->next;
916
917                 if (p && p->width > cw1) cw1 = p->width;
918                 }
919
920         work2 = ta->column2;
921         while (work2)
922                 {
923                 PanItem *p;
924
925                 p = work2->data;
926                 work2 = work2->next;
927
928                 if (p && p->width > cw2) cw2 = p->width;
929                 }
930
931         x = ta->x;
932         y = ta->y;
933         work1 = ta->column1;
934         work2 = ta->column2;
935         while (work1 && work2)
936                 {
937                 PanItem *p1;
938                 PanItem *p2;
939                 gint height = 0;
940
941                 p1 = work1->data;
942                 p2 = work2->data;
943                 work1 = work1->next;
944                 work2 = work2->next;
945
946                 if (p1)
947                         {
948                         p1->x = x;
949                         p1->y = y;
950                         pan_item_size_by_item(box, p1, PREF_PAD_BORDER);
951                         height = p1->height;
952                         }
953                 if (p2)
954                         {
955                         p2->x = x + cw1 + PREF_PAD_SPACE;
956                         p2->y = y;
957                         pan_item_size_by_item(box, p2, PREF_PAD_BORDER);
958                         if (height < p2->height) height = p2->height;
959                         }
960
961                 if (!p1 && !p2) height = PREF_PAD_GROUP;
962
963                 y += height;
964                 }
965 }
966 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */