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