#include <stdlib.h>
#include <string.h>
#include "fr_quickitems.h"
#include "asc.h"
#include "cursors.h"
#include "elwindows.h"
#include "gamewin.h"
#include "gl_init.h"
#include "hud.h"
#include "init.h"
#include "interface.h"
#include "items.h"
#include "storage.h"
#include "multiplayer.h"
#include "textures.h"
#include "translate.h"
#include "events.h"
#include "sound.h"
#include "errors.h"
#include "io/elpathwrapper.h"
#ifdef FR_THEMES
#include "themes.h"
#endif //FR_THEMES
#ifdef CONTEXT_MENUS
#include "context_menu.h"
#endif //CONTEXT_MENUS


item fr_quickitem_list[FR_QUICKITEMS_MAXSIZE];
int fr_quickitem_dragged = -1;

void init_fr_quickitems();
int get_fr_quickitems_y_base();

int display_fr_quickitems_handler(window_info *win);
int mouseover_fr_quickitems_handler(window_info *win, int mx, int my);
int click_fr_quickitems_handler(window_info *win, int mx, int my, Uint32 flags);

#ifdef CONTEXT_MENUS
static int context_fr_quickitems_handler(window_info *win, int widget_id, int mx, int my, int option);
static size_t cm_quickbar_id = CM_INIT_VALUE;
int cm_quickbar_enabled = 0;
int cm_quickbar_protected = 0;
enum { CMQB_ENABLE=0, CMQB_ALTKEY, CMQB_SEP1, CMQB_RELOC, CMQB_DRAG, CMQB_FLIP, CMQB_RESET, CMQB_SEP2, CMQB_CLEAN, CMQB_COMPLETE, CMQB_AUTOADD, CMQB_AUTOREM, CMQB_COMPRESS, CMQB_AUTOZIP, CMQB_INSERT };
#endif

int fr_quickitems_insertmode = 0;
int fr_quickitems_autocompress = 0;
int fr_quickitems_autocomplete = 0;
int fr_quickitems_autoremove = 0;

#ifndef FR_THEMES
/* Paramètres par défaut de la barre (utilisés lors d'un reset de la barre) */
int fr_quickitems_dim = 30;        // dimension d'une case (largeur=hauteur, hors cadre)
int fr_quickitems_x = 3+30;        // position horizontale par défaut
int fr_quickitems_y = 64;          // position verticale par défaut
int fr_quickitems_dir = VERTICAL;  // orientation par défaut de la barre
int fr_quickitems_delta = 3;       // taille du séparateur entre les groupes de cases
int fr_quickitems_division = 4;    // nombre de cases formant un groupe

/* Paramètres courants de la barre (écrasés par les valeurs personnelles mémorisées) */
int quickbar_x = 3+30;
int quickbar_y = 64;
int quickbar_dir = VERTICAL;
#endif //FR_THEMES
int quickitems_size = 6;
int quickbar_x_len = (1+30)*1 +1;
int quickbar_y_len = (1+30)*6 +1;
int quickbar_draggable = 0;
int quickbar_loaded = 0;


/* Retourne les coordonnées de la case en position 'p' de la barre rapide (utilisé par display & click handler) */
void set_quickcase_coords(int p, int *x_start, int *x_end, int *y_start, int *y_end)
{
	*x_start= 1;
	*x_end  = *x_start + fr_quickitems_dim;
	*y_start= 1 + (int)(p/fr_quickitems_division) * fr_quickitems_delta + (fr_quickitems_dim+1)*p;
	*y_end  = *y_start + fr_quickitems_dim;

	if (quickbar_dir != VERTICAL)
	{
		p = *x_start; *x_start = *y_start; *y_start = p;
		p = *x_end; *x_end = *y_end; *y_end = p;
	}
}

/* Retourne l'indice de la case de la barre rapide correspondant aux coordonnées de la souris */
int get_quickcase_from_mouse(int mx, int my)
{
	int i, x_start, x_end, y_start, y_end;
	for (i = 0; i < quickitems_size; i++)
	{
		set_quickcase_coords(i, &x_start, &x_end, &y_start, &y_end);
		if (mx>=x_start && mx<=x_end && my>=y_start && my<=y_end) return i;
	}
	return -1;
}

/* Détermine la place occupée en hauteur par la barre dans l'interface */
int get_fr_quickitems_y_base()
{
	if ((quickbar_draggable) || (quickbar_dir!=VERTICAL) || (quickbar_x!=fr_quickitems_x) || (quickbar_y!=fr_quickitems_y))
		return fr_quickitems_y;
	else
		return fr_quickitems_y + quickbar_y_len;
}


void drag_quickitem(int item)
{
	if ((item < 0) || (item >= FR_QUICKITEMS_MAXSIZE) || (fr_quickitem_list[item].quantity < 0))
	{
		fr_quickitem_dragged = -1;
		return;
	}

	// dessine l'item avec la texture correspondante dans la case
	draw_item(fr_quickitem_list[item].image_id, mouse_x-25, mouse_y-25, 50+1);

	// Affichage "grisé" de la case en cas d'indisponibilité de l'item
	if (fr_quickitem_list[item].quantity == 0)
	{
		glDisable(GL_TEXTURE_2D);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glBegin(GL_QUADS);
#ifdef FR_THEMES
			glColor4f(fr_quickitems_zerocolor.rouge, fr_quickitems_zerocolor.vert, fr_quickitems_zerocolor.bleu, fr_quickitems_zerocolor.alpha);
#else //FR_THEMES
			glColor4f(0.8f, 0.0f, 0.0f, 0.50f);
#endif //FR_THEMES
			glVertex2f(mouse_x-25, mouse_y-25);
			glVertex2f(mouse_x-25, mouse_y+25);
			glVertex2f(mouse_x+25, mouse_y+25);
			glVertex2f(mouse_x+25, mouse_y-25);
		glEnd();
		glDisable(GL_BLEND);
		glEnable(GL_TEXTURE_2D);
	}
}




/* Modification de la barre pour la rendre déplaçable (avec barre de titre) ou non */
void toggle_fr_quickitems_draggable()
{
	Uint32 flags = get_flags(quickbar_win);
	if (!quickbar_draggable)
	{
		flags &= ~ELW_SHOW_LAST;
		flags |= ELW_DRAGGABLE | ELW_TITLE_BAR;
		change_flags (quickbar_win, flags);
		quickbar_draggable = 1;
	}
	else
	{
		flags |= ELW_SHOW_LAST;
		flags &= ~(ELW_DRAGGABLE | ELW_TITLE_BAR);
		change_flags (quickbar_win, flags);
		quickbar_draggable = 0;
		quickbar_x = window_width - windows_list.window[quickbar_win].cur_x;
		quickbar_y = windows_list.window[quickbar_win].cur_y;
	}
}

/* Changement de l'orientation de la barre rapide (vertical/horizontal) */
void flip_fr_quickitems()
{
	if (quickbar_dir==VERTICAL)
	{
		quickbar_dir = HORIZONTAL;
		init_window(quickbar_win, -1, 0, windows_list.window[quickbar_win].cur_x, windows_list.window[quickbar_win].cur_y, quickbar_y_len, quickbar_x_len);
	}
	else if (quickbar_dir==HORIZONTAL)
	{
		quickbar_dir = VERTICAL;
		init_window(quickbar_win, -1, 0, windows_list.window[quickbar_win].cur_x, windows_list.window[quickbar_win].cur_y, quickbar_x_len, quickbar_y_len);
	}
}

/* Redéfinition de la barre rapide dans sa position par défaut */
void reset_fr_quickitems()
{
	//Necessary Variables
	quickbar_x_len = (1+fr_quickitems_dim)*1 +1;
	quickbar_y_len = (1+fr_quickitems_dim)*quickitems_size + (int)((quickitems_size-1)/fr_quickitems_division)*fr_quickitems_delta +1;
	quickbar_x = fr_quickitems_x;
	quickbar_y = fr_quickitems_y;
	//Re-set to default orientation
	quickbar_dir = fr_quickitems_dir;
	quickbar_draggable = 0;
	init_window(quickbar_win, -1, 0, quickbar_x, quickbar_y, quickbar_x_len, quickbar_y_len);
	//Re-set  Flags
	change_flags(quickbar_win, ELW_TITLE_NONE|ELW_SHOW|ELW_USE_BACKGROUND|ELW_SHOW_LAST);
	//NEED x_offset
	move_window(quickbar_win, -1, 0, window_width-quickbar_x, quickbar_y);
}


void clean_fr_quickitems()
{
	int i;
	for (i=0; i<FR_QUICKITEMS_MAXSIZE; i++) fr_quickitem_list[i].quantity = -1;
}

void compress_fr_quickitems()
{
	int i, empty_slot = -1;
	for (i=0; i<FR_QUICKITEMS_MAXSIZE; i++)
	{
		if ((empty_slot >= 0) && (fr_quickitem_list[i].quantity >= 0))
		{
			fr_quickitem_list[empty_slot] = fr_quickitem_list[i];
			fr_quickitem_list[i].quantity = -1;
			empty_slot++;
		}
		else if ((empty_slot < 0) && (fr_quickitem_list[i].quantity < 0)) empty_slot = i;
	}
}

void sync_fr_quickitems()
{
	int i, j;

	// Comptage du nombre d'item similaire disponibles dans l'inventaire
	for (i=0; i<FR_QUICKITEMS_MAXSIZE; i++)
	{
		if (fr_quickitem_list[i].quantity < 0) continue;

		fr_quickitem_list[i].pos = -1;
		fr_quickitem_list[i].quantity = 0;
		for (j=0; j<ITEM_WEAR_START; j++)
		{
			// On compare les images. Le soucis est que parfois la même image sert pour 2 objets différents.
			if ((item_list[j].quantity>0) && (item_list[j].image_id == fr_quickitem_list[i].image_id))
			{
				fr_quickitem_list[i].quantity += item_list[j].quantity;
				if (fr_quickitem_list[i].pos < 0)
				{
					fr_quickitem_list[i].pos = j;
					fr_quickitem_list[i].cooldown_time = item_list[j].cooldown_time;
					fr_quickitem_list[i].cooldown_rate = item_list[j].cooldown_rate;
				}
				// si l'objet est empilable, inutile de continuer le parcours du sac
				if (fr_quickitem_list[i].is_stackable == 1) break;
			}
		}
	}
}


void build_fr_quickitems(int force_complete)
{
	// Synchronisation des raccourcis avec l'inventaire (position, quantité, cooldown)
	sync_fr_quickitems();

	// En option : suppression du raccourci quand objet indisponible
	if (fr_quickitems_autoremove)
	{
		int i;
		for (i=0; i<FR_QUICKITEMS_MAXSIZE; i++)
			if (fr_quickitem_list[i].quantity == 0)
				fr_quickitem_list[i].quantity = -1;
		// lancer la compression puisque des trous ont pu être créés
		if (fr_quickitems_autocompress) compress_fr_quickitems();
	}

	// En option : complete les raccourcis avec tout objet disponible
	if (fr_quickitems_autocomplete || force_complete)
	{
		int i, j, empty_slot, already_here;
		for (i=0; i<ITEM_WEAR_START; i++)
		{
			if (item_list[i].quantity<1) continue;
			empty_slot = -1;
			already_here = 0;
			for (j=0; j<FR_QUICKITEMS_MAXSIZE; j++)
			{
				if (fr_quickitem_list[j].quantity < 0)
				{
					if (empty_slot < 0) empty_slot = j;
				}
				else if (fr_quickitem_list[j].image_id == item_list[i].image_id)
				{
					already_here = 1; break;
				}
			}
			if (already_here) continue;
			if (empty_slot < 0) break;
			fr_quickitem_list[empty_slot] = item_list[i];
		}
		// relancer une synchro puisque des raccourcis ont pu être ajoutés
		sync_fr_quickitems();
	}
}


/* Ajoute un raccourci pour l'objet indiqué dans l'inventaire à la 1ère case possible de la barre rapide */
int affect_fr_quickitems(int pos)
{
	int i;
	int id_quick = -1;

	for (i=0; i < FR_QUICKITEMS_MAXSIZE; i++)
	{
		if ((fr_quickitem_list[i].quantity>=0) && (fr_quickitem_list[i].image_id==item_list[pos].image_id))
		{
			fr_quickitem_list[i].quantity = -1;
		}
		if ((id_quick < 0) && (fr_quickitem_list[i].quantity < 0)) id_quick = i;
	}

	if (id_quick >= 0)
	{
		fr_quickitem_list[id_quick] = item_list[pos];
		fr_quickitem_list[id_quick].pos = id_quick;
#ifdef NEW_SOUND
		add_sound_object(get_index_for_sound_type_name("Drop Item"), 0, 0, 1);
#endif // NEW_SOUND
		build_fr_quickitems(0);
		return 1;
	}

#ifdef NEW_SOUND
	add_sound_object(get_index_for_sound_type_name("alert1"), 0, 0, 1);
#endif // NEW_SOUND
	return 0;
}


/* Initialisation (fenêtre, handlers et menu contextuel */
void init_fr_quickitems ()
{
	Uint32 flags = ELW_USE_BACKGROUND; // | ELW_USE_BORDER;
	quickbar_x_len = (1+fr_quickitems_dim)*1 +1;
	quickbar_y_len = (1+fr_quickitems_dim)*quickitems_size + (int)((quickitems_size-1)/fr_quickitems_division)*fr_quickitems_delta +1;

	if (!quickbar_relocatable)
	{
		flags |= ELW_SHOW_LAST;
		quickbar_draggable = 0;
	}
	if (quickbar_draggable) flags |= ELW_TITLE_BAR | ELW_DRAGGABLE;

	if (quickbar_win < 0)
	{
		if (quickbar_dir == VERTICAL)
			quickbar_win = create_window("Quickbar", -1, 0, window_width - quickbar_x, quickbar_y, quickbar_x_len, quickbar_y_len, flags);
		else
			quickbar_win = create_window("Quickbar", -1, 0, window_width - quickbar_x, quickbar_y, quickbar_y_len, quickbar_x_len, flags);

		set_window_handler(quickbar_win, ELW_HANDLER_DISPLAY, &display_fr_quickitems_handler);
		set_window_handler(quickbar_win, ELW_HANDLER_CLICK, &click_fr_quickitems_handler);
		set_window_handler(quickbar_win, ELW_HANDLER_MOUSEOVER, &mouseover_fr_quickitems_handler );

#ifdef CONTEXT_MENUS
		cm_quickbar_id = cm_create(cm_quickbar_menu_str, context_fr_quickitems_handler);
		cm_bool_line(cm_quickbar_id, CMQB_ENABLE, &cm_quickbar_enabled, NULL);
		cm_bool_line(cm_quickbar_id, CMQB_ALTKEY, &cm_quickbar_protected, NULL);
		cm_bool_line(cm_quickbar_id, CMQB_RELOC,  &quickbar_relocatable, "relocate_quickbar");
		cm_bool_line(cm_quickbar_id, CMQB_DRAG,   &quickbar_draggable, NULL);
		cm_bool_line(cm_quickbar_id, CMQB_AUTOREM, &fr_quickitems_autoremove, NULL);
		cm_bool_line(cm_quickbar_id, CMQB_AUTOADD, &fr_quickitems_autocomplete, NULL);
		cm_bool_line(cm_quickbar_id, CMQB_AUTOZIP, &fr_quickitems_autocompress, NULL);
		cm_bool_line(cm_quickbar_id, CMQB_INSERT,  &fr_quickitems_insertmode, NULL);
#ifdef FR_SWAPITEMS
		cm_bool_line(cm_quickbar_id, CMQB_INSERT+2, &allow_wheel_quantity_drag, NULL);
#endif //FR_SWAPITEMS
#endif
	}
	else
	{
		change_flags(quickbar_win, flags);
		if (quickbar_draggable)
		{
			show_window(quickbar_win);
		}
		else if (quickbar_y > window_height || quickbar_x > window_width)
		{
			// The player has done something stupid... let him/her correct it
			move_window(quickbar_win, -1, 0, window_width - fr_quickitems_x, fr_quickitems_y);
		}
		else
		{
			move_window(quickbar_win, -1, 0, window_width - quickbar_x, quickbar_y);
		}
	}
}


/* Affichage de la barre rapide */
int display_fr_quickitems_handler(window_info *win)
{
    char str[80];
	int delta, i; //, j;
	Uint32 _cur_time = SDL_GetTicks(); /* grab a snapshot of current time */

	glEnable(GL_TEXTURE_2D);
	glColor3f(1.0f,1.0f,1.0f);

	// dessin du contenu de chaque case (item, qty, cooldown)
	for (i = 0; i < quickitems_size; i++)
 	{
		if (fr_quickitem_list[i].quantity >= 0)
		{
			int x_start,x_end,y_start,y_end;

			//get the x and y
			set_quickcase_coords(i, &x_start, &x_end, &y_start, &y_end);

			// dessine l'item avec la texture correspondante dans la case
			draw_item(fr_quickitem_list[i].image_id, x_start, y_start, fr_quickitems_dim+1);

			// Affichage "grisé" de la case en cas d'indisponibilité de l'item
			if (fr_quickitem_list[i].quantity == 0)
			{
				glDisable(GL_TEXTURE_2D);
				glEnable(GL_BLEND);
				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				glBegin(GL_QUADS);
#ifdef FR_THEMES
					glColor4f(fr_quickitems_zerocolor.rouge, fr_quickitems_zerocolor.vert, fr_quickitems_zerocolor.bleu, fr_quickitems_zerocolor.alpha);
#else //FR_THEMES
					glColor4f(0.8f, 0.0f, 0.0f, 0.50f);
#endif //FR_THEMES
					glVertex2f(x_start, y_start);
					glVertex2f(x_start, y_end);
					glVertex2f(x_end, y_end);
					glVertex2f(x_end, y_start);
				glEnd();
				glDisable(GL_BLEND);
				glEnable(GL_TEXTURE_2D);
			}

			// Affichage de la durée du cooldown de l'item
			else if (fr_quickitem_list[i].cooldown_time > _cur_time)
			{
				float cooldown = ((float)(fr_quickitem_list[i].cooldown_time - _cur_time)) / ((float)fr_quickitem_list[i].cooldown_rate);
				float x_center = (x_start + x_end)*0.5f;
				float y_center = (y_start + y_end)*0.5f;

				if (cooldown < 0.0f)
					cooldown = 0.0f;
				else if (cooldown > 1.0f)
					cooldown = 1.0f;

				glDisable(GL_TEXTURE_2D);
				glEnable(GL_BLEND);

				glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
				glBegin(GL_TRIANGLE_FAN);
#ifdef FR_THEMES
					glColor4f(fr_quickitems_coolcolor.rouge, fr_quickitems_coolcolor.vert, fr_quickitems_coolcolor.bleu, fr_quickitems_coolcolor.alpha);
#else //FR_THEMES
					glColor4f(0.14f, 0.35f, 0.82f, 0.50f);
#endif //FR_THEMES

					glVertex2f(x_center, y_center);

					if (cooldown >= 0.875f)
                    {
						float t = tan(2.0f*M_PI*(1.0f - cooldown));
						glVertex2f(t*x_end + (1.0f - t)*x_center, y_start);
						glVertex2f(x_end, y_start);
						glVertex2f(x_end, y_end);
						glVertex2f(x_start, y_end);
						glVertex2f(x_start, y_start);
					}
                    else if (cooldown >= 0.625f)
                    {
						float t = 0.5f + 0.5f*tan(2.0f*M_PI*(0.75f - cooldown));
						glVertex2f(x_end, t*y_end + (1.0f - t)*y_start);
						glVertex2f(x_end, y_end);
						glVertex2f(x_start, y_end);
						glVertex2f(x_start, y_start);
					}
                    else if (cooldown >= 0.375f)
                    {
						float t = 0.5f + 0.5f*tan(2.0f*M_PI*(0.5f - cooldown));
						glVertex2f(t*x_start + (1.0f - t)*x_end, y_end);
						glVertex2f(x_start, y_end);
						glVertex2f(x_start, y_start);
					}
                    else if (cooldown >= 0.125f)
                    {
						float t = 0.5f + 0.5f*tan(2.0f*M_PI*(0.25f - cooldown));
						glVertex2f(x_start, t*y_start + (1.0f - t)*y_end);
						glVertex2f(x_start, y_start);
					}
                    else
                    {
						float t = tan(2.0f*M_PI*(cooldown));
						glVertex2f(t*x_start + (1.0f - t)*x_center, y_start);
					}

					glVertex2f(x_center, y_start);
				glEnd();

				glDisable(GL_BLEND);
				glEnable(GL_TEXTURE_2D);
			}

			// Affichage de la quantité disponible dans l'inventaire
			safe_snprintf(str, sizeof(str), "%i", fr_quickitem_list[i].quantity);
    		draw_string_small_shadowed(x_start, y_end-15, (unsigned char*)str, 1, 1.0f,1.0f,1.0f, 0.0f,0.0f,0.0f);
		}
	}

	glDisable(GL_TEXTURE_2D);
	use_window_color(quickbar_win, ELW_COLOR_LINE);

	// dessin des cadres de chaque case
	for (i = 0; i < quickitems_size; i++)
	{
		delta = (int)(i/fr_quickitems_division) * fr_quickitems_delta;
		glBegin(GL_LINE_LOOP);
			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
			if (quickbar_dir==VERTICAL)
			{
				glVertex3i(0,                  1 + delta + (fr_quickitems_dim+1)* i, 0);
				glVertex3i(fr_quickitems_dim+1, 1 + delta + (fr_quickitems_dim+1)* i, 0);
				glVertex3i(fr_quickitems_dim+1, 1 + delta + (fr_quickitems_dim+1)*(i+1), 0);
				glVertex3i(0,                  1 + delta + (fr_quickitems_dim+1)*(i+1), 0);
			}
			else
			{
				glVertex3i(delta + (fr_quickitems_dim+1)* i,    1, 0);
				glVertex3i(delta + (fr_quickitems_dim+1)*(i+1), 1, 0);
				glVertex3i(delta + (fr_quickitems_dim+1)*(i+1), 1+fr_quickitems_dim+1, 0);
				glVertex3i(delta + (fr_quickitems_dim+1)* i,    1+fr_quickitems_dim+1, 0);
			}
			glEnd();
		glEnd();
	}
	glEnable(GL_TEXTURE_2D);

#ifdef OPENGL_TRACE
CHECK_GL_ERRORS();
#endif //OPENGL_TRACE

	return 1;
}

/* Comportement en cas de survol de la barre */
int mouseover_fr_quickitems_handler(window_info *win, int mx, int my)
{
	int id_quick = get_quickcase_from_mouse(mx, my);
	if (id_quick < 0) return 0;
	if (fr_quickitem_list[id_quick].quantity < 0) return 0;

	if (fr_quickitem_list[id_quick].quantity > 0)
	{
		switch (qb_action_mode)
		{
			case ACTION_LOOK      : elwin_mouse=CURSOR_EYE; break;
			case ACTION_USE       : elwin_mouse=CURSOR_USE; break;
			case ACTION_USE_WITEM : elwin_mouse=CURSOR_USE_WITEM; break;
			default               : elwin_mouse=CURSOR_PICK;
		}
	}
	else elwin_mouse=CURSOR_PICK;
	return 1;
}

/* Comportement en cas de clic sur la barre */
int click_fr_quickitems_handler(window_info *win, int mx, int my, Uint32 flags)
{
	int i, id_quick, id_item;
	Uint8 str[100];
	int trigger=ELW_RIGHT_MOUSE|ELW_CTRL|ELW_SHIFT;//flags we'll use for the quickbar relocation handling
	int right_click = flags & ELW_RIGHT_MOUSE;
	int ctrl_on = flags & ELW_CTRL;

#ifdef FR_SWAPITEMS
	if (flags & ELW_WHEEL)
	{
		// modification de la quantité de l'objet en cours de drag avec la molette
		if ((allow_wheel_quantity_drag) && (item_dragged!=-1))
		{
			if (quantities.selected != ITEM_EDIT_QUANT)
			{
				*quantities.quantity[ITEM_EDIT_QUANT].str = *quantities.quantity[quantities.selected].str;
				quantities.quantity[ITEM_EDIT_QUANT].len = quantities.quantity[quantities.selected].len;
				quantities.quantity[ITEM_EDIT_QUANT].val = quantities.quantity[quantities.selected].val;
				quantities.selected = ITEM_EDIT_QUANT;
			}
			wheel_change_quantity(flags);
			return 1;
		}
	}
#endif //FR_SWAPITEMS

	// only handle mouse button clicks, not scroll wheels moves
	if ((flags & ELW_MOUSE_BUTTON) == 0) return 0;

	// Gestion des actions effectuées avec le clic droit
	if (right_click)
	{
#ifdef CONTEXT_MENUS
		// affichage du menu contextuel si option activée (+ éventuellement protection avec ALT)
		if (cm_quickbar_enabled && (!cm_quickbar_protected || (flags & ELW_ALT)))
		{
			cm_show_direct(cm_quickbar_id, quickbar_win, -1);
			if (cm_quickbar_protected) return 1;
		}
#endif

		// déplacements de la quickbar (avec clic droit et non gauche !)
		if (quickbar_relocatable > 0) switch (flags&trigger) {
			//toggle draggable (fenetre volante ou non)
			case (ELW_RIGHT_MOUSE|ELW_CTRL) : toggle_fr_quickitems_draggable(); return 1;
			//toggle vertical/horisontal (meme si non draggable)
			case (ELW_RIGHT_MOUSE|ELW_SHIFT) : flip_fr_quickitems(); return 1;
			//reset (retour position par défaut)
			case (ELW_RIGHT_MOUSE|ELW_CTRL|ELW_SHIFT) : reset_fr_quickitems(); return 1;
		}

		// si un objet est en cours de drag, un clic-droit le repose (annulation)
		if (item_dragged >= 0) { item_dragged = -1; return 1; }
		if (fr_quickitem_dragged >= 0) { fr_quickitem_dragged = -1; return 1; }

		// action par défaut sur clic-droit : rotation des actions du curseur
		switch(qb_action_mode)
		{
			case ACTION_WALK: qb_action_mode=ACTION_LOOK; break;
			case ACTION_LOOK: qb_action_mode=ACTION_USE; break;
			case ACTION_USE : qb_action_mode=ACTION_USE_WITEM; break;
			case ACTION_USE_WITEM: if (use_item < 0) qb_action_mode=ACTION_WALK; else use_item=-1; break;
			default : use_item=-1; qb_action_mode=ACTION_WALK;
		}

		return 1;
	}

	if (qb_action_mode==ACTION_USE_WITEM) action_mode=ACTION_USE_WITEM;
	if (qb_action_mode==ACTION_USE) action_mode=ACTION_USE;


	// Recherche l'id de la case cliquée dans la quickbar
	id_quick = get_quickcase_from_mouse(mx, my);
	if (id_quick < 0) return 0;


	// tentatives de drop d'un objet en cours de drag venant du sac
	if (item_dragged >= 0)
	{
		int empty_slot = -1;

		// recherche si l'objet est déjà sur la quickbar
		for (i=0; i < FR_QUICKITEMS_MAXSIZE; i++)
		{
			if ((fr_quickitem_list[i].quantity>=0) && (fr_quickitem_list[i].image_id==item_list[item_dragged].image_id))
			{
				// suppression du raccourci déjà existant dans une autre case
				if (i != id_quick)
				{
					if ((empty_slot < 0) && !fr_quickitems_insertmode) empty_slot = i;
					fr_quickitem_list[i].quantity = -1;
				}
				// tentative d'équipement auto (considéré comme un double-clic)
				else if (fr_quickitem_list[i].quantity > 0)
				{
					for (i = ITEM_WEAR_START; i < ITEM_WEAR_START+ITEM_NUM_WEAR; i++)
					{
						if (item_list[i].quantity<1) { move_item(item_dragged, i); break; }
					}
					item_dragged = -1;
					return 1;
				}
			}
		}

		// case de destination dans la quickbar déjà occupée
		if (fr_quickitem_list[id_quick].quantity >= 0)
		{
			/* mode par échange */
			if (! fr_quickitems_insertmode)
			{
				// si aucun raccourci n'existait avant, empty_slot non initialisé pour échange
				// on se contente alors de déplacer vers la 1ère case libre de la barre
				for (i=0; i<FR_QUICKITEMS_MAXSIZE && empty_slot<0; i++)
				{
					if (fr_quickitem_list[i].quantity<0) empty_slot = i;
				}
				if (empty_slot >= 0)
				{
					fr_quickitem_list[empty_slot] = fr_quickitem_list[id_quick];
				}
				fr_quickitem_list[id_quick].quantity = -1;
			}
			/* mode par insertion */
			else
			{
				// on cherche la 1ère case vide à partir de l'insertion (ou dernière case sinon)
				for (empty_slot=id_quick; empty_slot<FR_QUICKITEMS_MAXSIZE; empty_slot++)
				{
					if (fr_quickitem_list[empty_slot].quantity<0) break;
				}
				// on effectue les décalages de la case vide en remontant à la base de l'insertion
				for (i=empty_slot; i>id_quick; i--)
				{
					fr_quickitem_list[i] = fr_quickitem_list[i-1];
					fr_quickitem_list[i-1].quantity = -1;
				}
			}
		}

		// case de destination en quickbar libre
		if (fr_quickitem_list[id_quick].quantity < 0)
		{
			// enregistrement du raccourci pour l'item du drag
			fr_quickitem_list[id_quick] = item_list[item_dragged];
			fr_quickitem_list[id_quick].pos = item_dragged;
#ifdef NEW_SOUND
			add_sound_object(get_index_for_sound_type_name("Drop Item"), 0, 0, 1);
#endif // NEW_SOUND
			build_fr_quickitems(0);
			item_dragged = -1;
			return 1;
		}

		// sinon ? (case occupée par un autre raccourci n'ayant pu être déplacé)
#ifdef NEW_SOUND
		add_sound_object(get_index_for_sound_type_name("alert1"), 0, 0, 1);
#endif // NEW_SOUND
		return 0;
	}


	// tentatives de drop d'un raccourci de la barre
	if (fr_quickitem_dragged >= 0)
	{
		item temp_item;
		int empty_slot = -1;

		// lacher sur la case d'origine : abandon du drag
		if (fr_quickitem_dragged == id_quick)
		{
			fr_quickitem_dragged = -1; return 0;
		}

		temp_item = fr_quickitem_list[fr_quickitem_dragged];
		fr_quickitem_list[fr_quickitem_dragged].quantity = -1;

		// case de destination dans la quickbar déjà occupée
		if (fr_quickitem_list[id_quick].quantity >= 0)
		{
			/* mode par échange */
			if (! fr_quickitems_insertmode)
			{
				fr_quickitem_list[fr_quickitem_dragged] = fr_quickitem_list[id_quick];
				fr_quickitem_list[id_quick].quantity = -1;
			}
			/* mode par insertion */
			else
			{
				// on cherche la 1ère case vide à partir de l'insertion (ou dernière case sinon)
				for (empty_slot=id_quick; empty_slot<FR_QUICKITEMS_MAXSIZE; empty_slot++)
				{
					if (fr_quickitem_list[empty_slot].quantity<0) break;
				}
				// on effectue les décalages de la case vide en remontant à la base de l'insertion
				for (i=empty_slot; i>id_quick; i--)
				{
					fr_quickitem_list[i] = fr_quickitem_list[i-1];
					fr_quickitem_list[i-1].quantity = -1;
				}
			}
		}

		// case de destination en quickbar libre
		if (fr_quickitem_list[id_quick].quantity < 0)
		{
			// enregistrement du raccourci pour l'item du drag
			fr_quickitem_list[id_quick] = temp_item;
#ifdef NEW_SOUND
			add_sound_object(get_index_for_sound_type_name("Drop Item"), 0, 0, 1);
#endif // NEW_SOUND
			if (fr_quickitems_autocompress) compress_fr_quickitems();
			fr_quickitem_dragged = -1;
			return 1;
		}

		// sinon ? (case occupée par un autre raccourci n'ayant pu être déplacé)
#ifdef NEW_SOUND
		add_sound_object(get_index_for_sound_type_name("alert1"), 0, 0, 1);
#endif // NEW_SOUND
		return 0;
	}

	// Suppression de l'item enregistré dans la quickbar (ctrl+clic)
    if (ctrl_on && !shift_on && (fr_quickitem_list[id_quick].quantity >= 0))
	{
		fr_quickitem_list[id_quick].quantity = -1;
#ifdef NEW_SOUND
		add_sound_object(get_index_for_sound_type_name("Button Click"), 0, 0, 1);
#endif // NEW_SOUND
		if (fr_quickitems_autocompress) compress_fr_quickitems();
		return 1;
	}


	// Sur un raccourci existant mais quantité vide, alors drag spécial pour déplacement quickbar
	if (fr_quickitem_list[id_quick].quantity == 0)
	{
		fr_quickitem_dragged = id_quick;
		return 1;
	}


	// Recherche l'item dans l'inventaire correspondant au clic sur la quickbar
	id_item = -1;
	if (fr_quickitem_list[id_quick].quantity > 0)
	{
		// TODO: if (fr_quickitem_list[id_quick].is_stackable) id_item = fr_quickitem_list[id_quick].pos; else
		// Ou même directement : id_item = fr_quickitem_list[id_quick].pos;
		for (i = 0; i < ITEM_WEAR_START; i++)
		{
			// TODO: mériterait d'être amélioré avec le support de ITEM_UID !
			if ((item_list[i].quantity>0) && (item_list[i].image_id==fr_quickitem_list[id_quick].image_id))
			{
				id_item = i;
				break;
			}
		}
	}
	if (id_item < 0) return 0;


	// Ctrl + Shift + Left : dépose tous les items correspondant au sol
	if (ctrl_on && shift_on)
	{
		str[0] = DROP_ITEM;
		str[1] = item_list[id_item].pos;
		*((Uint32 *)(str+2)) = SDL_SwapLE32(fr_quickitem_list[id_quick].quantity);
		my_tcp_send(my_socket, str, 4);
#ifdef NEW_SOUND
		add_sound_object(get_index_for_sound_type_name("Drop Item"), 0, 0, 1);
#endif // NEW_SOUND
		return 1;
	}

	// Shift + Left : range tous les items correspondant dans le dépot
	else if (shift_on)
	{
		if ((storage_win<0) || view_only_storage || !get_show_window(storage_win)) return 0;
		str[0] = DEPOSITE_ITEM;
		str[1] = item_list[id_item].pos;
		*((Uint32 *)(str+2)) = SDL_SwapLE32(fr_quickitem_list[id_quick].quantity);
		my_tcp_send(my_socket, str, 6);
#ifdef NEW_SOUND
		add_sound_object(get_index_for_sound_type_name("Drop Item"), 0, 0, 1);
#endif // NEW_SOUND
		return 1;
	}


	switch (qb_action_mode)
	{
		case ACTION_LOOK :
			click_time = cur_time;
			str[0] = LOOK_AT_INVENTORY_ITEM;
			str[1] = item_list[id_item].pos;
			my_tcp_send(my_socket, str, 2);
			break;

		case ACTION_USE :
			if (! fr_quickitem_list[id_quick].use_with_inventory) return 1;
			str[0] = USE_INVENTORY_ITEM;
			str[1] = item_list[id_item].pos;
			my_tcp_send(my_socket, str, 2);
#ifdef NEW_SOUND
			item_list[id_item].action = USE_INVENTORY_ITEM;
#endif // NEW_SOUND
			return 1;

		case ACTION_USE_WITEM :
			if (use_item < 0) { use_item = id_item; return 1;}
			str[0] = ITEM_ON_ITEM;
			str[1] = item_list[use_item].pos;
			str[2] = item_list[id_item].pos;
			my_tcp_send(my_socket,str,3);
#ifdef NEW_SOUND
			item_list[use_item].action = ITEM_ON_ITEM;
			item_list[id_item].action = ITEM_ON_ITEM;
#endif // NEW_SOUND
			use_item = -1;
			return 1;

		default :
			if (item_dragged < 0)
			{
#ifdef FR_SWAPITEMS
				// calcul lors de la saisie de l'objet de la quantité max transportable
				int i;
				item_dragged_max_quantity = 0;
				if (item_list[id_item].is_stackable) item_dragged_max_quantity = item_list[id_item].quantity;
				else
				{
					// parcours du contenu du sac pour les items non empilables
					for (i=0; i<ITEM_WEAR_START; i++)
						if ( (item_list[i].quantity > 0)
						/* TODO: fiabiliser ce test avec le support des ITEM_UID */
						  && (item_list[i].image_id == item_list[id_item].image_id)
						  && (! item_list[i].is_stackable)
						) item_dragged_max_quantity++;
				}
#endif //FR_SWAPITEMS
				item_dragged = id_item;
#ifdef NEW_SOUND
				add_sound_object(get_index_for_sound_type_name("Drag Item"), 0, 0, 1);
#endif // NEW_SOUND
			}
	}

	return 1;
}

/* Actions du menu contextuel de la barre */
#ifdef CONTEXT_MENUS
static int context_fr_quickitems_handler(window_info *win, int widget_id, int mx, int my, int option)
{
	switch (option)
	{
		case CMQB_DRAG: quickbar_draggable ^= 1; toggle_fr_quickitems_draggable(); break;
		case CMQB_FLIP: flip_fr_quickitems(); break;
		case CMQB_RESET: reset_fr_quickitems(); break;
		case CMQB_CLEAN: clean_fr_quickitems(); break;
		case CMQB_COMPLETE: build_fr_quickitems(1); break;
		case CMQB_COMPRESS: compress_fr_quickitems(); break;
		case CMQB_AUTOREM: if (fr_quickitems_autoremove) build_fr_quickitems(0); break;
		case CMQB_AUTOADD: if (fr_quickitems_autocomplete) build_fr_quickitems(0); break;
		case CMQB_AUTOZIP: if (fr_quickitems_autocompress) build_fr_quickitems(0); break;
	}
	return 1;
}
#endif //CONTEXT_MENUS


/* Chargement des raccourcis de la barre depuis le fichier du perso */
void load_fr_quickitems()
{
	char nom_fichier[128];
	FILE *fichier;
	int i;

	quickbar_loaded = 1;  // même si le chargement échoue (permet de sauver le fichier initial)

	memset(fr_quickitem_list, 0, sizeof(fr_quickitem_list));

	safe_snprintf(nom_fichier, sizeof(nom_fichier), "barre_inventaire_%s.dat", username_str);
	my_tolower(nom_fichier);
	fichier = open_file_config(nom_fichier, "rb");
	if (fichier == NULL)
	{
		for (i=0; i<FR_QUICKITEMS_MAXSIZE; i++) fr_quickitem_list[i].quantity = -1;
		LOG_ERROR("%s: %s \"%s\"\n", reg_error_str, cant_open_file, nom_fichier);
		return;
	}

	fread(fr_quickitem_list, sizeof(fr_quickitem_list), 1, fichier);
	fclose(fichier);

	build_fr_quickitems(0);
}

/* Sauvegarde des raccourcis de la barre dans le fichier du perso */
void save_fr_quickitems()
{
	char nom_fichier[128];
	FILE *fichier;

	if (!quickbar_loaded) return;

	safe_snprintf(nom_fichier, sizeof(nom_fichier), "barre_inventaire_%s.dat", username_str);
	my_tolower(nom_fichier);
	fichier = open_file_config(nom_fichier, "wb");
	if (fichier == NULL)
	{
		LOG_ERROR("%s: %s \"%s\"\n", reg_error_str, cant_open_file, nom_fichier);
		return;
	}

    fwrite(fr_quickitem_list, sizeof(fr_quickitem_list), 1, fichier);
    fclose(fichier);
}

