view src/pan-item.c @ 594:4cfce4ed35e0

Use a dedicated option to enable keywords and comment saving as XMP tags in image's files. This new option is named "save_metadata_in_image_file" in configuration file. User can toggle it through Preferences > Advanced > Miscellaneous > Store keywords and comments as XMP tags in image files. Description of enable_metadata_dirs was modified as an attempt to improve clarity.
author zas_
date Tue, 06 May 2008 12:31:23 +0000
parents 48c8e49b571c
children a1dcef8cd1ae
line wrap: on
line source

/*
 * Geeqie
 * (C) 2006 John Ellis
 * Copyright (C) 2008 The Geeqie Team
 *
 * Author: John Ellis
 *
 * This software is released under the GNU General Public License (GNU GPL).
 * Please read the included file COPYING for more information.
 * This software comes with no warranty of any kind, use at your own risk!
 */


#include "main.h"
#include "pan-types.h"


/*
 *-----------------------------------------------------------------------------
 * item base functions
 *-----------------------------------------------------------------------------
 */

void pan_item_free(PanItem *pi)
{
	if (!pi) return;

	if (pi->pixbuf) g_object_unref(pi->pixbuf);
	if (pi->fd) file_data_unref(pi->fd);
	g_free(pi->text);
	g_free(pi->key);
	g_free(pi->data);

	g_free(pi);
}

void pan_item_set_key(PanItem *pi, const gchar *key)
{
	gchar *tmp;

	if (!pi) return;

	tmp = pi->key;
	pi->key = g_strdup(key);
	g_free(tmp);
}

void pan_item_added(PanWindow *pw, PanItem *pi)
{
	if (!pi) return;
	image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height);
}

void pan_item_remove(PanWindow *pw, PanItem *pi)
{
	if (!pi) return;

	if (pw->click_pi == pi) pw->click_pi = NULL;
	if (pw->queue_pi == pi)	pw->queue_pi = NULL;
	if (pw->search_pi == pi) pw->search_pi = NULL;
	pw->queue = g_list_remove(pw->queue, pi);

	pw->list = g_list_remove(pw->list, pi);
	image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height);
	pan_item_free(pi);
}

void pan_item_size_by_item(PanItem *pi, PanItem *child, gint border)
{
	if (!pi || !child) return;

	if (pi->x + pi->width < child->x + child->width + border)
		pi->width = child->x + child->width + border - pi->x;

	if (pi->y + pi->height < child->y + child->height + border)
		pi->height = child->y + child->height + border - pi->y;
}

void pan_item_size_coordinates(PanItem *pi, gint border, gint *w, gint *h)
{
	if (!pi) return;

	if (*w < pi->x + pi->width + border) *w = pi->x + pi->width + border;
	if (*h < pi->y + pi->height + border) *h = pi->y + pi->height + border;
}


/*
 *-----------------------------------------------------------------------------
 * item box type
 *-----------------------------------------------------------------------------
 */

PanItem *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)
{
	PanItem *pi;

	pi = g_new0(PanItem, 1);
	pi->type = PAN_ITEM_BOX;
	pi->fd = fd;
	pi->x = x;
	pi->y = y;
	pi->width = width;
	pi->height = height;

	pi->color_r = base_r;
	pi->color_g = base_g;
	pi->color_b = base_b;
	pi->color_a = base_a;

	pi->color2_r = bord_r;
	pi->color2_g = bord_g;
	pi->color2_b = bord_b;
	pi->color2_a = bord_a;
	pi->border = border_size;

	pw->list = g_list_prepend(pw->list, pi);

	return pi;
}

void pan_item_box_shadow(PanItem *pi, gint offset, gint fade)
{
	gint *shadow;

	if (!pi || pi->type != PAN_ITEM_BOX) return;

	shadow = pi->data;
	if (shadow)
		{
		pi->width -= shadow[0];
		pi->height -= shadow[0];
		}

	shadow = g_new0(gint, 2);
	shadow[0] = offset;
	shadow[1] = fade;

	pi->width += offset;
	pi->height += offset;

	g_free(pi->data);
	pi->data = shadow;
}

gint pan_item_box_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
		       gint x, gint y, gint width, gint height)
{
	gint bw, bh;
	gint *shadow;
	gint rx, ry, rw, rh;

	bw = pi->width;
	bh = pi->height;

	shadow = pi->data;
	if (shadow)
		{
		bw -= shadow[0];
		bh -= shadow[0];

		if (pi->color_a > 254)
			{
			pixbuf_draw_shadow(pixbuf, pi->x - x + bw, pi->y - y + shadow[0],
					   shadow[0], bh - shadow[0],
					   pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
					   shadow[1],
					   PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
			pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + bh,
					   bw, shadow[0],
					   pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
					   shadow[1],
					   PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
			}
		else
			{
			gint a;
			a = pi->color_a * PAN_SHADOW_ALPHA >> 8;
			pixbuf_draw_shadow(pixbuf, pi->x - x + shadow[0], pi->y - y + shadow[0],
					   bw, bh,
					   pi->x - x + shadow[0], pi->y - y + shadow[0], bw, bh,
					   shadow[1],
					   PAN_SHADOW_COLOR, a);
			}
		}

	if (util_clip_region(x, y, width, height,
			     pi->x, pi->y, bw, bh,
			     &rx, &ry, &rw, &rh))
		{
		pixbuf_draw_rect_fill(pixbuf,
				      rx - x, ry - y, rw, rh,
				      pi->color_r, pi->color_g, pi->color_b, pi->color_a);
		}
	if (util_clip_region(x, y, width, height,
			     pi->x, pi->y, bw, pi->border,
			     &rx, &ry, &rw, &rh))
		{
		pixbuf_draw_rect_fill(pixbuf,
				      rx - x, ry - y, rw, rh,
				      pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
		}
	if (util_clip_region(x, y, width, height,
			     pi->x, pi->y + pi->border, pi->border, bh - pi->border * 2,
			     &rx, &ry, &rw, &rh))
		{
		pixbuf_draw_rect_fill(pixbuf,
				      rx - x, ry - y, rw, rh,
				      pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
		}
	if (util_clip_region(x, y, width, height,
			     pi->x + bw - pi->border, pi->y + pi->border,
			     pi->border, bh - pi->border * 2,
			     &rx, &ry, &rw, &rh))
		{
		pixbuf_draw_rect_fill(pixbuf,
				      rx - x, ry - y, rw, rh,
				      pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
		}
	if (util_clip_region(x, y, width, height,
			     pi->x, pi->y + bh - pi->border,
			     bw,  pi->border,
			     &rx, &ry, &rw, &rh))
		{
		pixbuf_draw_rect_fill(pixbuf,
				      rx - x, ry - y, rw, rh,
				      pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
		}

	return FALSE;
}


/*
 *-----------------------------------------------------------------------------
 * item triangle type
 *-----------------------------------------------------------------------------
 */

PanItem *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)
{
	PanItem *pi;
	gint *coord;

	pi = g_new0(PanItem, 1);
	pi->type = PAN_ITEM_TRIANGLE;
	pi->x = x;
	pi->y = y;
	pi->width = width;
	pi->height = height;

	pi->color_r = r;
	pi->color_g = g;
	pi->color_b = b;
	pi->color_a = a;

	coord = g_new0(gint, 6);
	coord[0] = x1;
	coord[1] = y1;
	coord[2] = x2;
	coord[3] = y2;
	coord[4] = x3;
	coord[5] = y3;

	pi->data = coord;

	pi->border = PAN_BORDER_NONE;

	pw->list = g_list_prepend(pw->list, pi);

	return pi;
}

void pan_item_tri_border(PanItem *pi, gint borders,
			 guint8 r, guint8 g, guint8 b, guint8 a)
{
	if (!pi || pi->type != PAN_ITEM_TRIANGLE) return;

	pi->border = borders;

	pi->color2_r = r;
	pi->color2_g = g;
	pi->color2_b = b;
	pi->color2_a = a;
}

gint pan_item_tri_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
		       gint x, gint y, gint width, gint height)
{
	gint rx, ry, rw, rh;

	if (util_clip_region(x, y, width, height,
			     pi->x, pi->y, pi->width, pi->height,
			     &rx, &ry, &rw, &rh) && pi->data)
		{
		gint *coord = pi->data;
		pixbuf_draw_triangle(pixbuf,
				     rx - x, ry - y, rw, rh,
				     coord[0] - x, coord[1] - y,
				     coord[2] - x, coord[3] - y,
				     coord[4] - x, coord[5] - y,
				     pi->color_r, pi->color_g, pi->color_b, pi->color_a);

		if (pi->border & PAN_BORDER_1)
			{
			pixbuf_draw_line(pixbuf,
					 rx - x, ry - y, rw, rh,
					 coord[0] - x, coord[1] - y,
					 coord[2] - x, coord[3] - y,
					 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
			}
		if (pi->border & PAN_BORDER_2)
			{
			pixbuf_draw_line(pixbuf,
					 rx - x, ry - y, rw, rh,
					 coord[2] - x, coord[3] - y,
					 coord[4] - x, coord[5] - y,
					 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
			}
		if (pi->border & PAN_BORDER_3)
			{
			pixbuf_draw_line(pixbuf,
					 rx - x, ry - y, rw, rh,
					 coord[4] - x, coord[5] - y,
					 coord[0] - x, coord[1] - y,
					 pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
			}
		}

	return FALSE;
}


/*
 *-----------------------------------------------------------------------------
 * item text type
 *-----------------------------------------------------------------------------
 */

static PangoLayout *pan_item_text_layout(PanItem *pi, GtkWidget *widget)
{
	PangoLayout *layout;

	layout = gtk_widget_create_pango_layout(widget, NULL);

	if (pi->text_attr & PAN_TEXT_ATTR_MARKUP)
		{
		pango_layout_set_markup(layout, pi->text, -1);
		return layout;
		}

	if (pi->text_attr & PAN_TEXT_ATTR_BOLD ||
	    pi->text_attr & PAN_TEXT_ATTR_HEADING)
		{
		PangoAttrList *pal;
		PangoAttribute *pa;

		pal = pango_attr_list_new();
		if (pi->text_attr & PAN_TEXT_ATTR_BOLD)
			{
			pa = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
			pa->start_index = 0;
			pa->end_index = G_MAXINT;
			pango_attr_list_insert(pal, pa);
			}
		if (pi->text_attr & PAN_TEXT_ATTR_HEADING)
			{
			pa = pango_attr_scale_new(PANGO_SCALE_LARGE);
			pa->start_index = 0;
			pa->end_index = G_MAXINT;
			pango_attr_list_insert(pal, pa);
			}
		pango_layout_set_attributes(layout, pal);
		pango_attr_list_unref(pal);
		}

	pango_layout_set_text(layout, pi->text, -1);
	return layout;
}

static void pan_item_text_compute_size(PanItem *pi, GtkWidget *widget)
{
	PangoLayout *layout;

	if (!pi || !pi->text || !widget) return;

	layout = pan_item_text_layout(pi, widget);
	pango_layout_get_pixel_size(layout, &pi->width, &pi->height);
	g_object_unref(G_OBJECT(layout));

	pi->width += pi->border * 2;
	pi->height += pi->border * 2;
}

PanItem *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)
{
	PanItem *pi;

	pi = g_new0(PanItem, 1);
	pi->type = PAN_ITEM_TEXT;
	pi->x = x;
	pi->y = y;
	pi->text = g_strdup(text);
	pi->text_attr = attr;

	pi->color_r = r;
	pi->color_g = g;
	pi->color_b = b;
	pi->color_a = a;

	pi->border = border;

	pan_item_text_compute_size(pi, pw->imd->pr);

	pw->list = g_list_prepend(pw->list, pi);

	return pi;
}

gint pan_item_text_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
			gint x, gint y, gint width, gint height)
{
	PangoLayout *layout;

	layout = pan_item_text_layout(pi, (GtkWidget *)pr);
	pixbuf_draw_layout(pixbuf, layout, (GtkWidget *)pr,
			   pi->x - x + pi->border, pi->y - y + pi->border,
			   pi->color_r, pi->color_g, pi->color_b, pi->color_a);
	g_object_unref(G_OBJECT(layout));

	return FALSE;
}


/*
 *-----------------------------------------------------------------------------
 * item thumbnail type
 *-----------------------------------------------------------------------------
 */

PanItem *pan_item_thumb_new(PanWindow *pw, FileData *fd, gint x, gint y)
{
	PanItem *pi;

	pi = g_new0(PanItem, 1);
	pi->type = PAN_ITEM_THUMB;
	pi->fd = fd;
	pi->x = x;
	pi->y = y;
	pi->width = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;
	pi->height = PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2;

	pi->pixbuf = NULL;

	pi->queued = FALSE;

	pw->list = g_list_prepend(pw->list, pi);

	return pi;
}

gint pan_item_thumb_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
			 gint x, gint y, gint width, gint height)
{
	gint tx, ty, tw, th;
	gint rx, ry, rw, rh;

	if (pi->pixbuf)
		{
		tw = gdk_pixbuf_get_width(pi->pixbuf);
		th = gdk_pixbuf_get_height(pi->pixbuf);

		tx = pi->x + (pi->width - tw) / 2;
		ty = pi->y + (pi->height - th) / 2;

		if (gdk_pixbuf_get_has_alpha(pi->pixbuf))
			{
			if (util_clip_region(x, y, width, height,
					     tx + PAN_SHADOW_OFFSET, ty + PAN_SHADOW_OFFSET, tw, th,
					     &rx, &ry, &rw, &rh))
				{
				pixbuf_draw_shadow(pixbuf,
						   rx - x, ry - y, rw, rh,
						   tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
						   PAN_SHADOW_FADE,
						   PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
				}
			}
		else
			{
			if (util_clip_region(x, y, width, height,
					     tx + tw, ty + PAN_SHADOW_OFFSET,
					     PAN_SHADOW_OFFSET, th - PAN_SHADOW_OFFSET,
					     &rx, &ry, &rw, &rh))
				{
				pixbuf_draw_shadow(pixbuf,
						   rx - x, ry - y, rw, rh,
						   tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
						   PAN_SHADOW_FADE,
						   PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
				}
			if (util_clip_region(x, y, width, height,
					     tx + PAN_SHADOW_OFFSET, ty + th, tw, PAN_SHADOW_OFFSET,
					     &rx, &ry, &rw, &rh))
				{
				pixbuf_draw_shadow(pixbuf,
						   rx - x, ry - y, rw, rh,
						   tx + PAN_SHADOW_OFFSET - x, ty + PAN_SHADOW_OFFSET - y, tw, th,
						   PAN_SHADOW_FADE,
						   PAN_SHADOW_COLOR, PAN_SHADOW_ALPHA);
				}
			}

		if (util_clip_region(x, y, width, height,
				     tx, ty, tw, th,
				     &rx, &ry, &rw, &rh))
			{
			gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
					     (double) tx - x,
					     (double) ty - y,
					     1.0, 1.0, GDK_INTERP_NEAREST,
					     255);
			}

		if (util_clip_region(x, y, width, height,
				     tx, ty, tw, PAN_OUTLINE_THICKNESS,
				     &rx, &ry, &rw, &rh))
			{
			pixbuf_draw_rect_fill(pixbuf,
					      rx - x, ry - y, rw, rh,
					      PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
			}
		if (util_clip_region(x, y, width, height,
				     tx, ty, PAN_OUTLINE_THICKNESS, th,
				     &rx, &ry, &rw, &rh))
			{
			pixbuf_draw_rect_fill(pixbuf,
					      rx - x, ry - y, rw, rh,
					      PAN_OUTLINE_COLOR_1, PAN_OUTLINE_ALPHA);
			}
		if (util_clip_region(x, y, width, height,
				     tx + tw - PAN_OUTLINE_THICKNESS, ty +  PAN_OUTLINE_THICKNESS,
				     PAN_OUTLINE_THICKNESS, th - PAN_OUTLINE_THICKNESS,
				     &rx, &ry, &rw, &rh))
			{
			pixbuf_draw_rect_fill(pixbuf,
					      rx - x, ry - y, rw, rh,
					      PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
			}
		if (util_clip_region(x, y, width, height,
				     tx +  PAN_OUTLINE_THICKNESS, ty + th - PAN_OUTLINE_THICKNESS,
				     tw - PAN_OUTLINE_THICKNESS * 2, PAN_OUTLINE_THICKNESS,
				     &rx, &ry, &rw, &rh))
			{
			pixbuf_draw_rect_fill(pixbuf,
					      rx - x, ry - y, rw, rh,
					      PAN_OUTLINE_COLOR_2, PAN_OUTLINE_ALPHA);
			}
		}
	else
		{
		tw = pi->width - PAN_SHADOW_OFFSET * 2;
		th = pi->height - PAN_SHADOW_OFFSET * 2;
		tx = pi->x + PAN_SHADOW_OFFSET;
		ty = pi->y + PAN_SHADOW_OFFSET;

		if (util_clip_region(x, y, width, height,
				     tx, ty, tw, th,
				     &rx, &ry, &rw, &rh))
			{
			gint d;

			d = (pw->size <= PAN_IMAGE_SIZE_THUMB_NONE) ? 2 : 8;
			pixbuf_draw_rect_fill(pixbuf,
					      rx - x, ry - y, rw, rh,
					      PAN_SHADOW_COLOR,
					      PAN_SHADOW_ALPHA / d);
			}
		}

	return (pi->pixbuf == NULL);
}


/*
 *-----------------------------------------------------------------------------
 * item image type
 *-----------------------------------------------------------------------------
 */

static void pan_item_image_find_size(PanWindow *pw, PanItem *pi, gint w, gint h)
{
	GList *work;

	pi->width = w;
	pi->height = h;

	if (!pi->fd) return;

	work = pw->cache_list;
	while (work)
		{
		PanCacheData *pc;

		pc = work->data;
		work = work->next;

		if (pc->cd && pc->cd->dimensions &&
		    pc->fd && pc->fd == pi->fd)
			{
			pi->width = MAX(1, pc->cd->width * pw->image_size / 100);
			pi->height = MAX(1, pc->cd->height * pw->image_size / 100);

			pw->cache_list = g_list_remove(pw->cache_list, pc);
			cache_sim_data_free(pc->cd);
			file_data_unref(pc->fd);
			g_free(pc);
			return;
			}
		}
}

PanItem *pan_item_image_new(PanWindow *pw, FileData *fd, gint x, gint y, gint w, gint h)
{
	PanItem *pi;

	pi = g_new0(PanItem, 1);
	pi->type = PAN_ITEM_IMAGE;
	pi->fd = fd;
	pi->x = x;
	pi->y = y;

	pi->color_a = 255;

	pi->color2_r = 0;
	pi->color2_g = 0;
	pi->color2_b = 0;
	pi->color2_a = PAN_SHADOW_ALPHA / 2;

	pan_item_image_find_size(pw, pi, w, h);

	pw->list = g_list_prepend(pw->list, pi);

	return pi;
}

gint pan_item_image_draw(PanWindow *pw, PanItem *pi, GdkPixbuf *pixbuf, PixbufRenderer *pr,
			 gint x, gint y, gint width, gint height)
{
	gint rx, ry, rw, rh;

	if (util_clip_region(x, y, width, height,
			     pi->x, pi->y, pi->width, pi->height,
			     &rx, &ry, &rw, &rh))
		{
		if (pi->pixbuf)
			{
			gdk_pixbuf_composite(pi->pixbuf, pixbuf, rx - x, ry - y, rw, rh,
					     (double) pi->x - x,
					     (double) pi->y - y,
					     1.0, 1.0, GDK_INTERP_NEAREST,
					     pi->color_a);
			}
		else
			{
			pixbuf_draw_rect_fill(pixbuf,
					      rx - x, ry - y, rw, rh,
					      pi->color2_r, pi->color2_g, pi->color2_b, pi->color2_a);
			}
		}

	return (pi->pixbuf == NULL);
}


/*
 *-----------------------------------------------------------------------------
 * item lookup/search
 *-----------------------------------------------------------------------------
 */

PanItem *pan_item_find_by_key(PanWindow *pw, PanItemType type, const gchar *key)
{
	GList *work;

	if (!key) return NULL;

	work = g_list_last(pw->list);
	while (work)
		{
		PanItem *pi;

		pi = work->data;
		if ((pi->type == type || type == PAN_ITEM_NONE) &&
		     pi->key && strcmp(pi->key, key) == 0)
			{
			return pi;
			}
		work = work->prev;
		}
	work = g_list_last(pw->list_static);
	while (work)
		{
		PanItem *pi;

		pi = work->data;
		if ((pi->type == type || type == PAN_ITEM_NONE) &&
		     pi->key && strcmp(pi->key, key) == 0)
			{
			return pi;
			}
		work = work->prev;
		}

	return NULL;
}

/* when ignore_case and partial are TRUE, path should be converted to lower case */
static GList *pan_item_find_by_path_l(GList *list, GList *search_list,
				      PanItemType type, const gchar *path,
				      gint ignore_case, gint partial)
{
	GList *work;

	work = g_list_last(search_list);
	while (work)
		{
		PanItem *pi;

		pi = work->data;
		if ((pi->type == type || type == PAN_ITEM_NONE) && pi->fd)
			{
			gint match = FALSE;

			if (path[0] == '/')
				{
				if (pi->fd->path && strcmp(path, pi->fd->path) == 0) match = TRUE;
				}
			else if (pi->fd->name)
				{
				if (partial)
					{
					if (ignore_case)
						{
						gchar *haystack;

						haystack = g_utf8_strdown(pi->fd->name, -1);
						match = (strstr(haystack, path) != NULL);
						g_free(haystack);
						}
					else
						{
						if (strstr(pi->fd->name, path)) match = TRUE;
						}
					}
				else if (ignore_case)
					{
					if (strcasecmp(path, pi->fd->name) == 0) match = TRUE;
					}
				else
					{
					if (strcmp(path, pi->fd->name) == 0) match = TRUE;
					}
				}

			if (match) list = g_list_prepend(list, pi);
			}
		work = work->prev;
		}

	return list;
}

/* when ignore_case and partial are TRUE, path should be converted to lower case */
GList *pan_item_find_by_path(PanWindow *pw, PanItemType type, const gchar *path,
			     gint ignore_case, gint partial)
{
	GList *list = NULL;

	if (!path) return NULL;
	if (partial && path[0] == '/') return NULL;

	list = pan_item_find_by_path_l(list, pw->list_static, type, path, ignore_case, partial);
	list = pan_item_find_by_path_l(list, pw->list, type, path, ignore_case, partial);

	return g_list_reverse(list);
}

static PanItem *pan_item_find_by_coord_l(GList *list, PanItemType type, gint x, gint y, const gchar *key)
{
	GList *work;

	work = list;
	while (work)
		{
		PanItem *pi;

		pi = work->data;
		if ((pi->type == type || type == PAN_ITEM_NONE) &&
		     x >= pi->x && x < pi->x + pi->width &&
		     y >= pi->y && y < pi->y + pi->height &&
		    (!key || (pi->key && strcmp(pi->key, key) == 0)))
			{
			return pi;
			}
		work = work->next;
		}

	return NULL;
}

PanItem *pan_item_find_by_coord(PanWindow *pw, PanItemType type,
				gint x, gint y, const gchar *key)
{
	PanItem *pi;

	pi = pan_item_find_by_coord_l(pw->list, type, x, y, key);
	if (pi) return pi;

	return pan_item_find_by_coord_l(pw->list_static, type, x, y, key);
}


/*
 *-----------------------------------------------------------------------------
 * text alignments
 *-----------------------------------------------------------------------------
 */

PanTextAlignment *pan_text_alignment_new(PanWindow *pw, gint x, gint y, const gchar *key)
{
	PanTextAlignment *ta;

	ta = g_new0(PanTextAlignment, 1);

	ta->pw = pw;
	ta->column1 = NULL;
	ta->column2 = NULL;
	ta->x = x;
	ta->y = y;
	ta->key = g_strdup(key);

	return ta;
}

void pan_text_alignment_free(PanTextAlignment *ta)
{
	if (!ta) return;

	g_list_free(ta->column1);
	g_list_free(ta->column2);
	g_free(ta->key);
	g_free(ta);
}

PanItem *pan_text_alignment_add(PanTextAlignment *ta, const gchar *label, const gchar *text)
{
	PanItem *item;

	if (label)
		{
		item = pan_item_text_new(ta->pw, ta->x, ta->y, label,
					 PAN_TEXT_ATTR_BOLD, 0,
					 PAN_POPUP_TEXT_COLOR, 255);
		pan_item_set_key(item, ta->key);
		}
	else
		{
		item = NULL;
		}
	ta->column1 = g_list_append(ta->column1, item);

	if (text)
		{
		item = pan_item_text_new(ta->pw, ta->x, ta->y, text,
					 PAN_TEXT_ATTR_NONE, 0,
					 PAN_POPUP_TEXT_COLOR, 255);
		pan_item_set_key(item, ta->key);
		}
	else
		{
		item = NULL;
		}
	ta->column2 = g_list_append(ta->column2, item);

	return item;
}

void pan_text_alignment_calc(PanTextAlignment *ta, PanItem *box)
{
	gint cw1, cw2;
	gint x, y;
	GList *work1;
	GList *work2;

	cw1 = 0;
	cw2 = 0;

	work1 = ta->column1;
	while (work1)
		{
		PanItem *p;

		p = work1->data;
		work1 = work1->next;

		if (p && p->width > cw1) cw1 = p->width;
		}

	work2 = ta->column2;
	while (work2)
		{
		PanItem *p;

		p = work2->data;
		work2 = work2->next;

		if (p && p->width > cw2) cw2 = p->width;
		}

	x = ta->x;
	y = ta->y;
	work1 = ta->column1;
	work2 = ta->column2;
	while (work1 && work2)
		{
		PanItem *p1;
		PanItem *p2;
		gint height = 0;

		p1 = work1->data;
		p2 = work2->data;
		work1 = work1->next;
		work2 = work2->next;

		if (p1)
			{
			p1->x = x;
			p1->y = y;
			pan_item_size_by_item(box, p1, PREF_PAD_BORDER);
			height = p1->height;
			}
		if (p2)
			{
			p2->x = x + cw1 + PREF_PAD_SPACE;
			p2->y = y;
			pan_item_size_by_item(box, p2, PREF_PAD_BORDER);
			if (height < p2->height) height = p2->height;
			}

		if (!p1 && !p2) height = PREF_PAD_GROUP;

		y += height;
		}
}