/*
 *  Copyright (C) 2001 Ricardo Fernández Pascual
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "dnd-hints.h"

#include <gtk/gtkwidget.h>
#include <gtk/gtkwindow.h>
#include <gtk/gtkpixmap.h>
#include <gdk/gdk.h>
#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-util.h>
#include <gdk-pixbuf/gdk-pixbuf.h>

typedef struct {
	GtkWidget *widget;
	gchar *filename;
	gint ox;
	gint oy;
} HintWindowInfo;

/**
 * Info about each hint widget. See DndHintWindowId enum.
 */
HintWindowInfo hint_windows[] = { 
	{ NULL, "tb_drag_arrow_up.xpm",   -13/2,     0 },
	{ NULL, "tb_drag_arrow_down.xpm", -13/2,   -16 },
	{ NULL, "tb_drag_arrow_left.xpm",     0, -13/2 },
	{ NULL, "tb_drag_arrow_right.xpm",  -16, -13/2 },
	{ NULL, NULL, 0, 0 }
};

static GtkWidget *dnd_hints_init_window (const gchar *fname);
static void get_widget_coords (GtkWidget *w, gint *x1, gint *y1, 
			       gint *x2, gint *y2);

/**
 * Makes sure that all the widgets have been created.
 */
static void
dnd_hints_init (void)
{
	gint i;

	static gboolean done = FALSE;
	if (done) return;
	done = TRUE;

	for (i = 0; hint_windows[i].filename != NULL; i++)
	{
		gchar *fname= g_concat_dir_and_file (SHARE_DIR,
						     hint_windows[i].filename);
		hint_windows[i].widget = dnd_hints_init_window (fname);
		g_free (fname);
	}
}

/**
 * Hides all the hint widgets.
 */
void
dnd_hints_hide_all (void)
{
	gint i;
	for (i = 0; hint_windows[i].filename != NULL; i++)
		dnd_hints_hide (i);
}

/**
 * Hides a hint widget.
 */
void 
dnd_hints_hide (DndHintWindowId i)
{
	GtkWidget *w = hint_windows[i].widget;
	if (w && GTK_IS_WIDGET (w))
		gtk_widget_hide (w);
}

/**
 * Shows a hint widget and places it at the given screen coords.
 */
void 
dnd_hints_show (DndHintWindowId i, gint x, gint y)
{
	GtkWidget *w;
	dnd_hints_init ();
	w = hint_windows[i].widget;
	if (w && GTK_IS_WIDGET (w))
	{
		gtk_widget_set_uposition 
			(w, hint_windows[i].ox + x, hint_windows[i].oy + y);
		gtk_widget_show (w);
	}
}

/**
 * Shows a hint widget and places it at the given position with respect to
 * the given widget
 */
void 
dnd_hints_show_relative (DndHintWindowId i, GtkWidget *w, 
			 DndHintPosition horizontal,
			 DndHintPosition vertical)
{
	gint x1, x2, y1, y2;
	gint x = 0, y = 0;
	get_widget_coords (w, &x1, &y1, &x2, &y2);
	switch (horizontal)
	{
	case HINT_POSITION_RIGHT:
		x = x2; break;
	case HINT_POSITION_LEFT:
		x = x1; break;
	case HINT_POSITION_CENTER:
		x = (x1 + x2) / 2;
		break;
	default:
		/* should not happen */
		g_warning ("Invalid parameter to dnd_hints_show_relative");
		break;
	}
	switch (vertical)
	{
	case HINT_POSITION_TOP:
		y = y1; break;
	case HINT_POSITION_BOTTOM:
		y = y2; break;
	case HINT_POSITION_CENTER:
		y = (y1 + y2) / 2;
		break;
	default:
		/* should not happen */
		g_warning ("Invalid parameter to dnd_hints_show_relative");
		break;
	}
	dnd_hints_show (i, x, y);
}

static GtkWidget *
dnd_hints_init_window (const gchar *fname)
{
	GdkPixbuf *pixbuf;
        GdkPixmap *pixmap;
        GdkBitmap *bitmap;
	GtkWidget *pix;
	GtkWidget *win;
        
        pixbuf = gdk_pixbuf_new_from_file (fname);
        gdk_pixbuf_render_pixmap_and_mask (pixbuf, &pixmap, &bitmap, 128);
        gdk_pixbuf_unref (pixbuf);

        gtk_widget_push_visual (gdk_rgb_get_visual ());
        gtk_widget_push_colormap (gdk_rgb_get_cmap ());
        win = gtk_window_new (GTK_WINDOW_POPUP);
        pix = gtk_pixmap_new (pixmap, bitmap);
        gtk_widget_realize (win);
        gtk_container_add (GTK_CONTAINER (win), pix);
        gtk_widget_shape_combine_mask (win, bitmap, 0, 0);
        gtk_widget_pop_visual ();
        gtk_widget_pop_colormap ();
        
        gdk_pixmap_unref (pixmap);
        gdk_bitmap_unref (bitmap);

	gtk_widget_show_all (pix);

	return win;
}

static void
get_widget_coords (GtkWidget *w, gint *x1, gint *y1, gint *x2, gint *y2)
{
	gint ox, oy, width, height;

	if (w->parent && (w->parent->window == w->window))
	{
		get_widget_coords (w->parent, &ox, &oy, NULL, NULL);
		ox += w->allocation.x;
		oy += w->allocation.y;
		height = w->allocation.height;
		width = w->allocation.width;
	}
	else
	{
		gdk_window_get_origin (w->window, &ox, &oy);
		gdk_window_get_size (w->window, &width, &height);
	}

	if (x1) *x1 = ox;
	if (y1) *y1 = oy;
	if (x2) *x2 = ox + width;
	if (y2) *y2 = oy + height;
}
