/*
 * GQmpeg
 * (C)1998, 1999 John Ellis
 *
 * Author: John Ellis
 *
 * This software is released under the GNU General Public License.
 * Please read the included file COPYING for more information.
 * This software comes with no warranty of any kind, use at you own risk!
 */

#include "gqmpeg.h"

static gint in_drag;
static gint in_move;
static gint move_x_pos;
static gint move_y_pos;
static gint orig_x_mpos;
static gint orig_y_mpos;

static ButtonData *current_button;
static SliderData *current_slider;

	/* table to convert iso_8859 chars to similar ascii counterpart
	 * only used in draw_font()
	 */
static const gchar iso_ascii[]=
{
	' ','|','c','L','c','Y','|','S','\"','c',' ','<','!','-','r','~',
	'o',' ','2','3','\'','u','p','.',',','1',' ','>',' ',' ',' ','?',
	'A','A','A','A','A','A','A','C','E','E','E','E','I','I','I','I',
	'D','N','O','O','O','O','O','x','0','U','U','U','U','Y','P','B',
	'a','a','a','a','a','a','a','c','e','e','e','e','i','i','i','i',
	'o','n','o','o','o','o','o','/','o','u','u','u','u','y','p','y'
};

static void free_button(ButtonData *button);
static void free_digit(DigitData *digit);
static void free_font(FontData *font);
static void free_number(NumberData *number, gint include_digit);
static void free_item(ItemData *item);
static void free_slider(SliderData *slider);
static void draw_digit(DigitData *digit, gint n, gint x, gint y);
static void draw_slider_private(SliderData *slider, float position, gint absolute, gint move,
			gint prelight, gint pushed, gint force);
static void font_leave_proximity(FontData *font);
static void check_font_motion_proximity(FontData *font, gint x, gint y);
static void check_button_motion_proximity(ButtonData *button, gint x, gint y);
static void check_slider_motion_proximity(SliderData *slider, gint x, gint y);
static void slider_motion(SliderData *slider,gint x, gint y);
static void display_motion(GtkWidget *w, GdkEventMotion *event, gpointer data);
static gint check_button_press_proximity(ButtonData *button, gint x, gint y);
static gint check_slider_press_proximity(SliderData *slider, gint x, gint y);
static void display_pressed(GtkWidget *w, GdkEventButton *event, gpointer data);
static void slider_released(SliderData *slider, gint x , gint y);
static void display_released(GtkWidget *w, GdkEventButton *event, gpointer data);
static void display_leave();

GdkPixmap *get_pixmap_from_data(gchar **data)
{
	GdkPixmap *pixmap = NULL;
	GdkBitmap *mask = NULL;

	if (!double_size_mode)
		{
		gdk_imlib_data_to_pixmap(data, &pixmap, &mask);
		}
	else
		{
		GdkImlibImage *im = NULL;
		im = gdk_imlib_create_image_from_xpm_data(data);
		if (im)
			{
			gdk_imlib_render(im, im->rgb_width *2, im->rgb_height *2);
			pixmap = gdk_imlib_move_image(im);
			mask = gdk_imlib_move_mask(im);
			gdk_imlib_destroy_image(im);
			}
		}
	if (mask) gdk_imlib_free_bitmap(mask);
	return pixmap;
}

GdkPixmap *get_pixmap_from_file(gchar *path)
{
	GdkPixmap *pixmap = NULL;
	GdkBitmap *mask = NULL;

	if (!isfile(path)) return NULL;

	if (!double_size_mode)
		{
		gdk_imlib_load_file_to_pixmap(path, &pixmap, &mask);
		}
	else
		{
		GdkImlibImage *im = NULL;
		im = gdk_imlib_load_image(path);
		if (im)
			{
			gdk_imlib_render(im, im->rgb_width *2, im->rgb_height *2);
			pixmap = gdk_imlib_move_image(im);
			mask = gdk_imlib_move_mask(im);
			gdk_imlib_destroy_image(im);
			}
		}
	if (mask) gdk_imlib_free_bitmap(mask);
	return pixmap;
}

GdkBitmap *get_bitmap_from_file(gchar *path)
{
	GdkPixmap *pixmap = NULL;
	GdkBitmap *mask = NULL;

	if (!isfile(path)) return NULL;

	if (!double_size_mode)
		{
		gdk_imlib_load_file_to_pixmap(path, &pixmap, &mask);
		}
	else
		{
		GdkImlibImage *im = NULL;
		im = gdk_imlib_load_image(path);
		if (im)
			{
			gdk_imlib_render(im, im->rgb_width *2, im->rgb_height *2);
			pixmap = gdk_imlib_move_image(im);
			mask = gdk_imlib_move_mask(im);
			gdk_imlib_destroy_image(im);
			}
		}
	if (pixmap) gdk_imlib_free_pixmap(pixmap);
	return mask;
}

void redraw_skin()
{
	gdk_window_set_back_pixmap(display_area->window,skin->background,FALSE);
	gdk_window_clear(display_area->window);
}

ButtonData *new_button(GdkPixmap *pixmap, gint prelight, gint light, gint x, gint y,
		void (*click_func)(void *), void (*press_func)(void *), void (*release_func)(void *))
{
	ButtonData *button;
	gint width;
	gint height;

	if (double_size_mode)
		{
		x *= 2;
		y *= 2;
		}

	button = g_new0(ButtonData, 1);

	gdk_window_get_size (pixmap, &width, &height);

	button->pixmap = pixmap;
	button->has_light = light;
	button->has_prelight = prelight;
	button->pushed = FALSE;
	button->lit = FALSE;
	button->prelit = FALSE;
	button->x = x;
	button->y = y;

	button->width = width / (2 + (light * prelight) + prelight + (2 * light));
	button->height = height;

	button->press_func = press_func;
	button->release_func = release_func;
	button->click_func = click_func;

	return button;
}

ButtonData *new_button_from_data(gchar **data, gint prelight, gint light, gint x, gint y,
		void (*click_func)(void *), void (*press_func)(void *), void (*release_func)(void *))
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_data(data);
	
	return new_button(pixmap, prelight, light, x, y, click_func, press_func, release_func);
}


ButtonData *new_button_from_file(gchar *file, gint prelight, gint light, gint x, gint y,
		void (*click_func)(void *), void (*press_func)(void *), void (*release_func)(void *))
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_file(file);
	if (!pixmap) return NULL;

	return new_button(pixmap, prelight, light, x, y, click_func, press_func, release_func);
}

static void free_button(ButtonData *button)
{
	if (!button) return;
	if (button->pixmap) gdk_imlib_free_pixmap(button->pixmap);
	g_free(button);
}

DigitData *new_digit(GdkPixmap *pixmap)
{
	DigitData *digit;
	gint width;
	gint height;

	digit = g_new0(DigitData, 1);

	gdk_window_get_size (pixmap, &width, &height);

	digit->pixmap = pixmap;
	digit->width = width / 11;
	digit->height = height;

	return digit;
}

DigitData *new_digit_from_data(gchar **data)
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_data(data);

	return new_digit(pixmap);
}

DigitData *new_digit_from_file(gchar *file)
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_file(file);
	if (!pixmap) return NULL;

	return new_digit(pixmap);
}

static void free_digit(DigitData *digit)
{
	if (!digit) return;
	if (digit->pixmap) gdk_imlib_free_pixmap(digit->pixmap);
	g_free(digit);
}

FontData * new_font(GdkPixmap *pixmap, gint length, gint extended, gint x, gint y)
{
	FontData *font;
	gint width;
	gint height;

	if (double_size_mode)
		{
		x *= 2;
		y *= 2;
		}

	font = g_new0(FontData, 1);

	gdk_window_get_size (pixmap, &width, &height);

	font->pixmap = pixmap;

	font->length = length;
	font->char_width = width / 32;

	if (extended)
		font->char_height = height / 6;
	else
		font->char_height = height / 3;

	font->width = font->char_width * length;
	font->height = font->char_height;
	font->x = x;
	font->y = y;
	font->text = NULL;
	font->extended = extended;

	return font;
}

FontData * new_font_from_data(gchar **data, gint length, gint extended, gint x, gint y)
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_data(data);

	return new_font(pixmap, length, extended, x, y);
}

FontData * new_font_from_file(gchar *file, gint length, gint extended, gint x, gint y)
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_file(file);
	if (!pixmap) return NULL;

	return new_font(pixmap, length, extended, x, y);
}

static void free_font(FontData *font)
{
	if (!font) return;
	if (font->pixmap) gdk_imlib_free_pixmap(font->pixmap);
	g_free(font->text);
	g_free(font);
}

NumberData *new_number(DigitData *digits, gint length, gint zeros, gint x, gint y)
{
	NumberData *number;

	if (double_size_mode)
		{
		x *= 2;
		y *= 2;
		}

	number = g_new0(NumberData, 1);

	number->digits = digits;
	number->length = length;
	number->zeros = zeros;
	number->x = x;
	number->y = y;

	return number;
}

NumberData *new_number_from_data(gchar **data, gint length, gint zeros, gint x, gint y)
{
	DigitData *digits;

	digits = new_digit_from_data(data);
	return new_number(digits, length, zeros, x, y);
}

NumberData *new_number_from_file(gchar *file, gint length, gint zeros, gint x, gint y)
{
	DigitData *digits;

	digits = new_digit_from_file(file);
	if (!digits) return NULL;

	return new_number(digits, length, zeros, x, y);
}

static void free_number(NumberData *number, gint include_digit)
{
	if (!number) return;
	if (include_digit && number->digits) free_digit(number->digits);
	g_free(number);
}

ItemData *new_item(GdkPixmap *pixmap, gint sections, gint x, gint y)
{
	ItemData *item;
	gint width;
	gint height;

	if (double_size_mode)
		{
		x *= 2;
		y *= 2;
		}

	item = g_new0(ItemData, 1);

	gdk_window_get_size (pixmap, &width, &height);

	item->pixmap = pixmap;
	item->width = width;
	item->height = height / sections;
	item->sections = sections;
	item->x = x;
	item->y = y;

	return item;
}

ItemData *new_item_from_data(gchar **data, gint sections, gint x, gint y)
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_data(data);

	return new_item(pixmap, sections, x, y);
}

ItemData *new_item_from_file(gchar *file, gint sections, gint x, gint y)
{
	GdkPixmap *pixmap;

	pixmap = get_pixmap_from_file(file);
	if (!pixmap) return NULL;

	return new_item(pixmap, sections, x, y);
}

static void free_item(ItemData *item)
{
	if (!item) return;
	if (item->pixmap) gdk_imlib_free_pixmap(item->pixmap);
	g_free(item);
}

SliderData *new_slider(GdkPixmap *pixmap, gint prelight, gint verticle, gint reversed,
			gint length, gint x, gint y, ItemData *item,
			void (*press_func)(float), void (*release_func)(float),
			void (*move_func)(float))
{
	SliderData *slider;
	gint width;
	gint height;

	if (double_size_mode)
		{
		x *= 2;
		y *= 2;
		length *= 2;
		}

	slider = g_new0(SliderData, 1);

	gdk_window_get_size (pixmap, &width, &height);

	slider->pixmap = pixmap;
	slider->verticle = verticle;
	slider->reversed = reversed;
	if (verticle)
		{
		slider->width = length;
		slider->height = width;
		slider->handle_width = (height - length) / (2 + prelight);
		slider->handle_height = width;
		}
	else
		{
		slider->width = length;
		slider->height = height;
		slider->handle_width = (width - length) / (2 + prelight);
		slider->handle_height = height;
		}
	slider->has_prelight = prelight;
	slider->position = 0;
	slider->x = x;
	slider->y = y;
	slider->item = item;
	slider->press_func = press_func;
	slider->release_func = release_func;
	slider->move_func = move_func;

	return slider;
}

SliderData *new_slider_from_data(gchar **data, gint prelight, gint verticle, gint reversed,
			gint length, gint x, gint y, ItemData *item,
			void (*press_func)(float), void (*release_func)(float),
			void (*move_func)(float))
{
	GdkPixmap *pixmap = get_pixmap_from_data(data);

	return new_slider(pixmap, prelight, verticle, reversed, length, x, y, item,
			  press_func, release_func, move_func);
}

SliderData *new_slider_from_file(gchar *file, gint prelight, gint verticle, gint reversed,
			gint length, gint x, gint y, ItemData *item,
			void (*press_func)(float), void (*release_func)(float),
			void (*move_func)(float))
{
	GdkPixmap *pixmap = get_pixmap_from_file(file);
	if (!pixmap) return NULL;

	return new_slider(pixmap, prelight, verticle, reversed, length, x, y, item,
			  press_func, release_func, move_func);
}

static void free_slider(SliderData *slider)
{
	if (!slider) return;
	if (slider->pixmap) gdk_imlib_free_pixmap(slider->pixmap);
	g_free(slider);
}

SkinData *new_skin()
{
	SkinData *s;
	s = g_new0(SkinData, 1);
	return s;
}

void sync_window_to_skin()
{
	if (!skin) return;

	if (!skin->mask)
		{
		GdkGC *gc;
		GdkColor white;

		if (debug_mode) printf("Creating rect mask for non shaped skin\n");

		skin->mask = gdk_pixmap_new(NULL, skin->width, skin->height, 1);
		gc = gdk_gc_new(skin->mask);

		gdk_color_parse("white", &white);
		gdk_color_alloc(gtk_widget_get_colormap(display_area), &white);
		gdk_gc_set_foreground(gc, &white);

                gdk_draw_rectangle(skin->mask, gc /* GdkGC *gc */,
                          TRUE, 0, 0, skin->width, skin->height);
		gdk_gc_unref(gc);
		}

	gtk_drawing_area_size(GTK_DRAWING_AREA(display_area), skin->width, skin->height);
	gtk_widget_set_usize(mainwindow, skin->width, skin->height);
	gtk_widget_shape_combine_mask(mainwindow, skin->mask, 0, 0);

	display_draw_all(TRUE);
}

static void free_number_and_maybe_digit(NumberData *n, SkinData *s)
{
	if ( n && ( (s->dig_large && n->digits == s->dig_large) ||
		    (s->dig_small && n->digits == s->dig_small) ))
		free_number(n, FALSE);
	else
		free_number(n, TRUE);
}

void free_skin(SkinData *s)
{
	gint i;
	if (!s) return;
	if (s->background) gdk_imlib_free_pixmap(s->background);
	if (s->mask) gdk_imlib_free_bitmap(s->mask);
	free_button(s->play);
	free_button(s->stop);
	free_button(s->pause);
	free_button(s->next);
	free_button(s->prev);
	free_button(s->ff);
	free_button(s->rw);
	free_button(s->shuffle);
	free_button(s->repeat);
	free_button(s->playlist);
	free_button(s->config);
	free_button(s->iconify);
	free_button(s->exit);
	free_button(s->mixer);
	free_button(s->skin_mode);
	free_number_and_maybe_digit(s->hour, s);
	free_number_and_maybe_digit(s->min, s);
	free_number_and_maybe_digit(s->sec, s);
	free_number_and_maybe_digit(s->hour_total, s);
	free_number_and_maybe_digit(s->min_total, s);
	free_number_and_maybe_digit(s->sec_total, s);
	free_number_and_maybe_digit(s->song_current, s);
	free_number_and_maybe_digit(s->song_total, s);
	free_number_and_maybe_digit(s->input_bits, s);
	free_number_and_maybe_digit(s->input_hz, s);
	free_number_and_maybe_digit(s->output_bits, s);
	free_number_and_maybe_digit(s->output_hz, s);
	free_number_and_maybe_digit(s->frame, s);
	free_number_and_maybe_digit(s->frame_total, s);
	free_number_and_maybe_digit(s->cpu, s);
	free_number_and_maybe_digit(s->song_min, s);
	free_number_and_maybe_digit(s->song_sec, s);
	free_digit(s->dig_small);
	free_digit(s->dig_large);
	free_item(s->stereo);
	free_item(s->item_shuffle);
	free_item(s->item_repeat);
	free_item(s->mpegver);
	free_item(s->layer);
	free_item(s->mode);
	free_item(s->status);
	free_font(s->title);
	free_font(s->artist);
	free_font(s->album);
	free_font(s->genre);
	free_slider(s->position);
	free_item(s->position_item);
	free_slider(s->volume);
	free_item(s->volume_item);
	free_button(s->volume_dn);
	free_button(s->volume_up);
	free_slider(s->balance);
	free_item(s->balance_item);
	free_button(s->balance_left);
	free_button(s->balance_right);

	for (i=0; i<10; i++)
		{
		free_button(s->preset[i]);
		}

	g_free(s);
}

static void draw_digit(DigitData *digit, gint n, gint x, gint y)
{
	if (!digit) return;

	if (n == -1)
		gdk_draw_pixmap(skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
			digit->pixmap, digit->width * 10, 0, x, y, digit->width, digit->height);
	if (n >= 0 && n <= 9)
		gdk_draw_pixmap(skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
			digit->pixmap, n * digit->width, 0, x, y, digit->width, digit->height);

	redraw_skin();
}

void draw_number(NumberData *number, gint n)
{
	gint i, d;
	gint t = 1;
	gint x;
	gint z;
	DigitData *digit;

	if (!number) return;

	x = number->x;
	z = number->zeros;
	digit = number->digits;

	for (i=0; i< number->length - 1; i++) t = t * 10;
	x += number->length * digit->width;
	for (i=number->length; i > 0; i--)
		{
		d = n / t;
		n -= d * t;
		t = t / 10;
		if (d == 0 && i>1 && (!z))
			d = -1;
		else
			z = TRUE;
		draw_digit(digit, d, x - (i * digit->width), number->y);
		}
}

void draw_font(FontData *font)
{
	gint i;
	gint px, py;
	guint8 c;
	gint l;
	gchar *start;

	if (!font) return;

	if (font->text)
		l = strlen(font->text);
	else
		l = 0;

	if (font->offset >= l) font->offset = l - 1;
	if (font->offset < 0) font->offset = 0;

	if (font->text)
		start = font->text + font->offset;
	else
		start = NULL;
	l -= font->offset;

	for (i=0; i < font->length; i++)
		{
		if (i < l)
			{
			c = start[i];
			if (font->extended)
				{
				if(c >= 32 && c < 128)
					c -= 32;
				else if(c >= 160 && c < 256)
					c -= 64;
				else
					c = 0;
				}
			else
				{
				if (c >= 32 && c < 128)
					c -= 32;
				else if (c >= 160 && c < 256)
					{
					/* translate to a limited set */
					c = iso_ascii[c - 160];
					c -= 32;
					}
				else
					c = 0;
				}
			py = c / 32;
			px = c - (py * 32);
			px = px * font->char_width;
			py = py * font->char_height;
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				font->pixmap, px, py, font->x + i * font->char_width, font->y,
				font->char_width, font->char_height);
			}
		else
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				font->pixmap, 0, 0, font->x + i * font->char_width, font->y,
				font->char_width, font->char_height);
			
		}

	redraw_skin();
}

void set_font_text(FontData *font, gchar *text)
{
	if (!font) return;

	g_free(font->text);
	
	if (text)
		font->text = g_strdup(text);
	else
		font->text = NULL;

	font->offset = 0;

	draw_font(font);
}

void update_font(FontData *font)
{
	if (!font || !font->text) return;

	if (font->scroll > 0)
		{
		gint l = strlen(font->text);
		if (font->offset < l - font->length && l > font->length)
			{
			font->offset++;
			draw_font(font);
			}
		}
	else if (font->offset > 0)
		{
		font->offset--;
		draw_font(font);
		}
}

void draw_item(ItemData *item, gint section)
{
	if (!item) return;

	gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
		item->pixmap, 0, item->height * section, item->x, item->y, item->width, item->height);
	
}

void change_button_light(ButtonData *button, gint lit)
{
	gint l = 0;

	if (!button || !button->has_light) return;

	if (button->lit == lit) return;

	button->lit = lit;

	if (button->pushed)
		l = button->width * (1 + (2 * button->lit));
	else
		if (button->prelit)
			l = button->width * (4 + button->lit);
		else
			l = button->width * 2 * button->lit;

	gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
			button->pixmap, l, 0, button->x, button->y, button->width, button->height);
	redraw_skin();
}

void draw_button(ButtonData *button, gint prelight, gint pressed, gint force)
{
	gint l = 0;

	if (!button) return;

	if (force)
		{
		if (button->prelit)
			l = button->width * (2 + (2 * button->has_light) + button->lit);
		else
			l = button->width * (button->pushed + (2 * button->lit));
		gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				button->pixmap, l, 0, button->x, button->y, button->width, button->height);
		redraw_skin();
		return;
		}
	if (button->has_prelight && prelight && !button->prelit)
		{
		button->prelit = TRUE;
		l = button->width * ((2 * button->has_light) + 2 + button->lit);
		gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				button->pixmap, l, 0, button->x, button->y, button->width, button->height);
		redraw_skin();
		}
	if (!prelight && button->prelit)
		{
		button->prelit = FALSE;
		if (pressed && !button->pushed)
			{
			button->pushed = TRUE;
			l = button->width * (1 + ( 2 * button->lit));
			}
		else
			l = button->width * button->lit * 2;
		
		gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				button->pixmap, l, 0, button->x, button->y, button->width, button->height);
		redraw_skin();
		}
	if (!pressed && button->pushed)
		{
		button->pushed = FALSE;
		if (prelight)
			{
			if (button->has_prelight)
				l = button->width * (2 + (2 * button->has_light) + button->lit);
			else
				l = button->width * (2 * button->lit);
			}
		else
			l = button->width * 2 * button->lit;
		gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				button->pixmap, l, 0, button->x, button->y, button->width, button->height);
		redraw_skin();
		}
	if (pressed && !button->pushed)
		{
		button->pushed = TRUE;
		l = button->width * (1 + ( 2 * button->lit));
		gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				button->pixmap, l, 0, button->x, button->y, button->width, button->height);
		redraw_skin();
		}
}

static void draw_slider_private(SliderData *slider, float position, gint absolute, gint move,
			gint prelight, gint pushed, gint force)
{
	gint new_pos;
	gint l;

	if (!slider) return;

	if (move)
		{
		if (absolute)
			new_pos = (float)position;
		else
			new_pos = (float)(slider->width - slider->handle_width) * position;
		if (new_pos < 0) new_pos = 0;
		if (new_pos > (slider->width - slider->handle_width))
			new_pos = slider->width - slider->handle_width;
		}
	else
		new_pos = slider->position;

	if (force)
		{
		if (move) slider->position = new_pos;
		if (slider->verticle)
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, 0, 0, slider->x , slider->y,
				slider->height, slider->width);
			}
		else
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, 0, 0, slider->x , slider->y,
				slider->width, slider->height);
			}

		if (slider->item)
			{
			gint section = (float)slider->position / (slider->width - slider->handle_width)
					* (slider->item->sections - 1);
			draw_item(slider->item, section);
			}

		l = slider->width + (slider->handle_width * (slider->pushed + (2 * slider->prelit)));
		if (slider->verticle)
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, 0, l, slider->x, slider->y + slider->position,
				slider->handle_height, slider->handle_width);
			}
		else
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, l, 0, slider->x + slider->position, slider->y,
				slider->handle_width, slider->handle_height);
			}
		return;
		}

	if (slider->position != new_pos)
		{
		if (absolute)
			{
			slider->pushed = pushed;
			if (slider->has_prelight) slider->prelit = prelight;
			}
		if (slider->verticle)
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, 0, slider->position, slider->x, slider->y + slider->position,
				slider->handle_height, slider->handle_width);
			}
		else
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, slider->position, 0, slider->x + slider->position, slider->y,
				slider->handle_width, slider->handle_height);
			}

		if (slider->item)
			{
			gint section = (float)new_pos / (slider->width - slider->handle_width)
					* (slider->item->sections - 1);
			draw_item(slider->item, section);
			}

		l = slider->width + (slider->handle_width * (slider->pushed + (2 * slider->prelit)));
		if (slider->verticle)
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, 0, l, slider->x, slider->y + new_pos,
				slider->handle_height, slider->handle_width);
			}
		else
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, l, 0, slider->x + new_pos, slider->y,
				slider->handle_width, slider->handle_height);
			}
		slider->position = new_pos;
		redraw_skin();
		}
	else if (move && !absolute)
		{
		return;
		}
	else if (slider->pushed != pushed)
		{
		slider->pushed = pushed;
		if (slider->pushed)
			slider->prelit = FALSE;
		else
			{
			if (slider->has_prelight) slider->prelit = prelight;
			}
		l = slider->width + (slider->handle_width * (slider->pushed + (2 * slider->prelit))); 
		if (slider->verticle)
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, 0, l, slider->x, slider->y + slider->position,
				slider->handle_height, slider->handle_width);
			}
		else
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, l, 0, slider->x + slider->position, slider->y,
				slider->handle_width, slider->handle_height);
			}
		redraw_skin();
		}
	else if (slider->has_prelight && slider->prelit != prelight)
		{
		slider->prelit = prelight;
		l = slider->width + (slider->handle_width * slider->prelit *2);
		if (slider->verticle)
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, 0, l, slider->x, slider->y + slider->position,
				slider->handle_height, slider->handle_width);
			}
		else
			{
			gdk_draw_pixmap (skin->background,display_area->style->fg_gc[GTK_WIDGET_STATE(display_area)],
				slider->pixmap, l, 0, slider->x + slider->position, slider->y,
				slider->handle_width, slider->handle_height);
			}
		redraw_skin();
		}
}


void draw_slider(SliderData *slider, float position, gint absolute, gint move,
			gint prelight, gint pushed, gint force)
{
	if (!slider) return;

	if (slider->reversed)
		{
		if (absolute)
			position = (slider->width - slider->handle_width) - position;
		else
			position = 1.0 - position;
		}

	draw_slider_private(slider, position, absolute, move, prelight, pushed, force);
}


static void font_leave_proximity(FontData *font)
{
	if (!font) return;

	font->scroll = -1;
}

static void check_font_motion_proximity(FontData *font, gint x, gint y)
{
	if (!font) return;

	if (x >= font->x && x < font->x + font->width &&
			y >= font->y && y < font->y + font->height)
		font->scroll = 1;
	else
		font->scroll = -1;
}

static void check_button_motion_proximity(ButtonData *button, gint x, gint y)
{
	if (!button) return;

	if (x >= button->x && x < button->x + button->width &&
			y >= button->y && y < button->y + button->height)
		{
		draw_button(button, TRUE, FALSE, FALSE);
		}
	else
		{
		draw_button(button, FALSE, FALSE, FALSE);
		}
}

static void check_slider_motion_proximity(SliderData *slider, gint x, gint y)
{
	if (!slider) return;

	if ((slider->verticle && x >= slider->x && x < slider->x + slider->height &&
			y >= slider->y && y < slider->y + slider->width) ||
			(!slider->verticle && x >= slider->x && x < slider->x + slider->width &&
			y >= slider->y && y < slider->y + slider->height))
		{
		draw_slider_private(slider, 0, FALSE, FALSE, TRUE, FALSE, FALSE);
		}
	else
		{
		draw_slider_private(slider, 0, FALSE, FALSE, FALSE, FALSE, FALSE);
		}
}

static void slider_motion(SliderData *slider,gint x, gint y)
{
	float pos;
	if (!slider) return;

	if (slider->verticle)
		pos = y - slider->y - (slider->handle_width / 2);
	else
		pos = x - slider->x - (slider->handle_width / 2);

	if (pos < 0) pos = 0;
	if (pos > slider->width - slider->handle_width)
		pos = slider->width - slider->handle_width;

	if (slider->position != pos && slider->move_func)
		{
		if (slider->reversed)
			slider->move_func((float)1.0 - ((float)pos / (slider->width - slider->handle_width)));
		else
			slider->move_func((float)pos / (slider->width - slider->handle_width));
		}
	draw_slider_private(slider, pos, TRUE, TRUE, FALSE, TRUE, FALSE);
}

static void display_motion(GtkWidget *w, GdkEventMotion *event, gpointer data)
{
	ButtonData *button;
	gint i;
	gint x = (float)event->x;
	gint y = (float)event->y;

	if (debug_skin) printf("motion:%d x %d\n", x, y);

	if (current_slider)
		{
		slider_motion(current_slider, x ,y);
		return;
		}

	if (in_move)
		{
		GdkModifierType modmask;
		gint pos_x, pos_y;
		gint new_x, new_y;
		gdk_window_get_pointer (NULL, &pos_x, &pos_y, &modmask);
		new_x = pos_x - move_x_pos;
		new_y = pos_y - move_y_pos;
		if (smart_window_placement)
			{
			gint root_x = gdk_screen_width();
			gint root_y = gdk_screen_height();
			if (new_x < 8 && new_x > -8)
				new_x = 0;
			if (new_y < 8 && new_y > -8)
				new_y = 0;
			if (new_x + skin->width > root_x - 8 && new_x + skin->width < root_x +8)
				new_x = root_x - skin->width;
			if (new_y + skin->height > root_y - 8 && new_y + skin->height < root_y +8)
				new_y = root_y - skin->height;
			}
		gdk_window_move (mainwindow->window, new_x, new_y);
		return;
		}

	if (current_button)
		{
		button = current_button;

		if (x >= button->x && x < button->x + button->width &&
				y >= button->y && y < button->y + button->height)
			{
			draw_button(button, FALSE, TRUE, FALSE);
			}
		else
			{
			draw_button(button, FALSE, FALSE, FALSE);
			}
		return;
		}

	check_button_motion_proximity(skin->play, x ,y);
	check_button_motion_proximity(skin->stop, x ,y);
	check_button_motion_proximity(skin->pause, x ,y);
	check_button_motion_proximity(skin->prev, x ,y);
	check_button_motion_proximity(skin->next, x ,y);
	check_button_motion_proximity(skin->ff, x ,y);
	check_button_motion_proximity(skin->rw, x ,y);
	check_button_motion_proximity(skin->shuffle, x ,y);
	check_button_motion_proximity(skin->repeat, x ,y);
	check_button_motion_proximity(skin->config, x ,y);
	check_button_motion_proximity(skin->playlist, x ,y);
	check_button_motion_proximity(skin->exit, x ,y);
	check_button_motion_proximity(skin->iconify, x ,y);
	check_button_motion_proximity(skin->mixer, x ,y);
	check_button_motion_proximity(skin->skin_mode, x ,y);
	check_slider_motion_proximity(skin->position,x ,y);
	check_slider_motion_proximity(skin->volume,x ,y);
	check_button_motion_proximity(skin->volume_up, x ,y);
	check_button_motion_proximity(skin->volume_dn, x ,y);
	check_slider_motion_proximity(skin->balance,x ,y);
	check_button_motion_proximity(skin->balance_left, x ,y);
	check_button_motion_proximity(skin->balance_right, x ,y);

	for (i=0; i<10; i++)
		{
		check_button_motion_proximity(skin->preset[i], x ,y);
		}

	check_font_motion_proximity(skin->title, x, y);
	check_font_motion_proximity(skin->artist, x, y);
	check_font_motion_proximity(skin->album, x, y);
	check_font_motion_proximity(skin->genre, x, y);
}	

static gint check_button_press_proximity(ButtonData *button, gint x, gint y)
{
	if (!button) return FALSE;

	if (x >= button->x && x < button->x + button->width &&
			y >= button->y && y < button->y + button->height)
		{
		draw_button(button, FALSE, TRUE, FALSE);
		current_button = button;
		if (button->press_func)
			button->press_func();
		in_drag = TRUE;
		return TRUE;
		}

	return FALSE;
}

static gint check_slider_press_proximity(SliderData *slider, gint x, gint y)
{
	if (!slider) return FALSE;

	if ((slider->verticle && x >= slider->x && x < slider->x + slider->height &&
			y >= slider->y && y < slider->y + slider->width) ||
			(!slider->verticle && x >= slider->x && x < slider->x + slider->width &&
			y >= slider->y && y < slider->y + slider->height))
		{
		float pos;

		if (slider->verticle)
			pos = y - slider->y - (slider->handle_width / 2);
		else
			pos = x - slider->x - (slider->handle_width / 2);

		if (pos < 0) pos = 0;
		if (pos > slider->width - slider->handle_width)
			pos = slider->width - slider->handle_width;

		draw_slider_private(slider, pos, TRUE, TRUE, FALSE, TRUE, FALSE);
		current_slider = slider;
		if (slider->press_func)
			{
			if (slider->reversed)
				slider->press_func((float)1.0 - ((float)pos / (slider->width - slider->handle_width)));
			else
				slider->press_func((float)pos / (slider->width - slider->handle_width));
			}
		return TRUE;
		}

	return FALSE;
}

static void display_pressed(GtkWidget *w, GdkEventButton *event, gpointer data)
{
	GdkModifierType modmask;
	gint i;
	gint x = (float)event->x;
	gint y = (float)event->y;
	if (debug_mode) printf("pressed:%d x %d\n", x, y);

	if (event->button == 3 || (dock_mode && event->button == 2))
		{
		gtk_menu_popup (GTK_MENU(main_menu), NULL, NULL, NULL, NULL,
				event->button, event->time);
		return;
		}

	if (check_button_press_proximity(skin->play, x, y)) return;
	if (check_button_press_proximity(skin->stop, x, y)) return;
	if (check_button_press_proximity(skin->pause, x, y)) return;
	if (check_button_press_proximity(skin->prev, x, y)) return;
	if (check_button_press_proximity(skin->next, x, y)) return;
	if (check_button_press_proximity(skin->ff, x, y)) return;
	if (check_button_press_proximity(skin->rw, x, y)) return;
	if (check_button_press_proximity(skin->shuffle, x, y)) return;
	if (check_button_press_proximity(skin->repeat, x, y)) return;
	if (check_button_press_proximity(skin->playlist, x, y)) return;
	if (check_button_press_proximity(skin->config, x, y)) return;
	if (check_button_press_proximity(skin->exit, x, y)) return;
	if (check_button_press_proximity(skin->iconify, x, y)) return;
	if (check_button_press_proximity(skin->mixer, x, y)) return;
	if (check_button_press_proximity(skin->skin_mode, x, y)) return;
	if (check_slider_press_proximity(skin->position, x, y))
		{
		pos_slider_in_drag = TRUE;
		return;
		}
	if (check_slider_press_proximity(skin->volume, x, y)) return;
	if (check_button_press_proximity(skin->volume_up, x, y)) return;
	if (check_button_press_proximity(skin->volume_dn, x, y)) return;
	if (check_slider_press_proximity(skin->balance, x, y)) return;
	if (check_button_press_proximity(skin->balance_left, x, y)) return;
	if (check_button_press_proximity(skin->balance_right, x, y)) return;

	for (i=0; i<10; i++)
		{
		if (check_button_press_proximity(skin->preset[i], x ,y)) return;
		}


	if (!dock_mode)
		{
		in_move = TRUE;
		gdk_window_get_pointer (NULL, &orig_x_mpos, &orig_y_mpos, &modmask);
		move_x_pos = x;
		move_y_pos = y;
		}
	in_drag = TRUE;
}

static void slider_released(SliderData *slider, gint x , gint y)
{
	float pos;
	if (!slider) return;

	if (slider->verticle)
		pos = y - slider->y - (slider->handle_width / 2);
	else
		pos = x - slider->x - (slider->handle_width / 2);

	if (pos < 0) pos = 0;
	if (pos > slider->width - slider->handle_width)
		pos = slider->width - slider->handle_width;

	if ((slider->verticle && x >= slider->x && x < slider->x + slider->height &&
			y >= slider->y && y < slider->y + slider->width) ||
			(!slider->verticle && x >= slider->x && x < slider->x + slider->width &&
			y >= slider->y && y < slider->y + slider->height))
		draw_slider_private(slider, pos, TRUE, TRUE, TRUE, FALSE, FALSE);
	else
		draw_slider_private(slider, pos, TRUE, TRUE, FALSE, FALSE, FALSE);

	if (slider->release_func)
		{
		if (slider->reversed)
			slider->release_func((float)1.0 - ((float)pos / (slider->width - slider->handle_width)));
		else
			slider->release_func((float)pos / (slider->width - slider->handle_width));
		}
}

static void display_released(GtkWidget *w, GdkEventButton *event, gpointer data)
{
	gint x = (float)event->x;
	gint y = (float)event->y;

	if (debug_mode) printf("released:%d x %d\n", x, y);

	if (current_slider)
		{
		slider_released(current_slider, x , y);
		}
	else if (current_button)
		{
		ButtonData *button = current_button;
		if (x >= button->x && x < button->x + button->width &&
				y >= button->y && y < button->y + button->height)
			{
			draw_button(button, TRUE, FALSE, FALSE);

			if (button->release_func)
				button->release_func();
			if (button->click_func)
				button->click_func();
			}
		else
			{
			if (button && button->release_func)
				button->release_func();
			}
		}
	else
		{
		GdkModifierType modmask;
		gint pos_x;
		gint pos_y;
		gdk_window_get_pointer (NULL, &pos_x, &pos_y, &modmask);
		if (pos_x == orig_x_mpos && pos_y == orig_y_mpos)
			gdk_window_raise (mainwindow->window);
		}

	current_button = NULL;
	current_slider = NULL;
	in_drag = FALSE;
	pos_slider_in_drag = FALSE;
	in_move = FALSE;
}

static void display_leave()
{
	if (!current_button)
		{
		gint i;

		draw_button(skin->prev, FALSE, FALSE, FALSE);
		draw_button(skin->pause, FALSE, FALSE, FALSE);
		draw_button(skin->play, FALSE, FALSE, FALSE);
		draw_button(skin->stop, FALSE, FALSE, FALSE);
		draw_button(skin->next, FALSE, FALSE, FALSE);
		draw_button(skin->ff, FALSE, FALSE, FALSE);
		draw_button(skin->rw, FALSE, FALSE, FALSE);
		draw_button(skin->shuffle, FALSE, FALSE, FALSE);
		draw_button(skin->repeat, FALSE, FALSE, FALSE);
		draw_button(skin->playlist, FALSE, FALSE, FALSE);
		draw_button(skin->config, FALSE, FALSE, FALSE);
		draw_button(skin->exit, FALSE, FALSE, FALSE);
		draw_button(skin->iconify, FALSE, FALSE, FALSE);
		draw_button(skin->mixer, FALSE, FALSE, FALSE);
		draw_button(skin->skin_mode, FALSE, FALSE, FALSE);
		draw_button(skin->volume_up, FALSE, FALSE, FALSE);
		draw_button(skin->volume_dn, FALSE, FALSE, FALSE);
		draw_button(skin->balance_left, FALSE, FALSE, FALSE);
		draw_button(skin->balance_right, FALSE, FALSE, FALSE);

		for (i=0; i<10; i++)
			{
			draw_button(skin->preset[i], FALSE, FALSE, FALSE);
			}

		}

	if (!current_slider)
		{
		draw_slider_private(skin->position, 0, FALSE, FALSE, FALSE, FALSE, FALSE);
		draw_slider_private(skin->volume, 0, FALSE, FALSE, FALSE, FALSE, FALSE);
		draw_slider_private(skin->balance, 0, FALSE, FALSE, FALSE, FALSE, FALSE);
		}

	font_leave_proximity(skin->title);
	font_leave_proximity(skin->artist);
	font_leave_proximity(skin->album);
	font_leave_proximity(skin->genre);
}

void setup_display()
{
	gtk_widget_set_events (display_area, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_POINTER_MOTION_MASK |
			GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK);
	gtk_signal_connect(GTK_OBJECT(display_area),"motion_notify_event",(GtkSignalFunc) display_motion, NULL);
	gtk_signal_connect(GTK_OBJECT(display_area),"button_press_event",(GtkSignalFunc) display_pressed, NULL);
	gtk_signal_connect(GTK_OBJECT(display_area),"button_release_event",(GtkSignalFunc) display_released, NULL);
	gtk_signal_connect(GTK_OBJECT(display_area),"leave_notify_event",(GtkSignalFunc) display_leave, NULL);
	current_button = NULL;
	current_slider = NULL;
}

void mode_button_pressed()
{
	gint old_x, old_y;
	gint new_x, new_y;
	gint move = FALSE;
	if (!skin_small) return;

	if (smart_window_placement)
		{
		gdk_window_get_position(mainwindow->window, &old_x, &old_y);
		if (old_y + (skin_normal->height / 2) > gdk_screen_height() / 2)
			{
			move = TRUE;
			if (skin == skin_normal)
				{
				new_x = old_x;
				new_y = old_y + skin_normal->height - skin_small->height;
				if (new_y > gdk_screen_height() - skin_small->height)
					new_y = gdk_screen_height() - skin_small->height;
				}
			else
				{
				new_x = old_x;
				new_y = old_y + skin_small->height - skin_normal->height;
				}
			}
		else
			{
			if (old_y < 0)
				{
				move = TRUE;
				new_x = old_x;
				new_y = 0;
				}

			}
		}

	if (skin == skin_normal)
		skin = skin_small;
	else
		skin = skin_normal;

	sync_window_to_skin();
	if (move)
		gdk_window_move(mainwindow->window, new_x, new_y);
}

