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