/*****************************************************************************

GRAOUMF TRACKER 2

Copyright (c) 1996 - 2002 Laurent de Soras

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
of the License, 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.

Contact the author : laurent@ohmforce.com
More information about this license : http://www.gnu.org/licenses/gpl.html

*****************************************************************************/



/*\\\ FICHIERS INCLUDE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

#include <math.h>

#include "base.h"
#include "intrface.h"
#include "resource.h"
#include	"sliders.h"



/*\\\ CONSTANTES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

/* Taille minimum d'un slider */
#define	SLID_MIX_SLIDER_LEN	8



/*\\\ TYPES & STRUCTURES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ PROTOTYPES DES FONCTIONS PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

void	SLID_display_v_slider (SLID_INFO *slider_ptr);
void	SLID_display_h_slider (SLID_INFO *slider_ptr);

void	SLID_slider_virtual_2_pixel (SLID_INFO *slider_ptr, int pix_len);
void	SLID_slider_pixel_2_virtual (SLID_INFO *slider_ptr, int pix_len);



/*\\\ VARIABLES EXTERNES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ VARIABLES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/

clock_t	SLID_last_call = 0;	/* Dernier appel a la routine de gestion de slider */



/*\\\ FONCTIONS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*==========================================================================*/
/*      Nom: SLID_display_slider                                            */
/*      Description: Affiche un slider en utilisant les donnees virtuelles. */
/*      Parametres en entree/sortie:                                        */
/*        - slider_ptr: pointeur sur une structure SLID_INFO representant   */
/*                      les donnees du slider. Les numeros d'objet et les   */
/*                      parametres virtuels sont en entree, ainsi que la    */
/*                      direction du slider. Les parametres en pixels sont  */
/*                      en sortie.                                          */
/*==========================================================================*/

void	SLID_display_slider (SLID_INFO *slider_ptr)
{
	if (slider_ptr->direction == SLID_DIRECTION_HORIZONTAL)
	{
		SLID_display_h_slider (slider_ptr);
	}
	else
	{
		SLID_display_v_slider (slider_ptr);
	}
}



/*==========================================================================*/
/*      Nom: SLID_display_v_slider                                          */
/*      Description: Affiche un slider vertical en utilisant les donnees    */
/*                   virtuelles.                                            */
/*      Parametres en entree/sortie:                                        */
/*        - slider_ptr: pointeur sur une structure SLID_INFO representant   */
/*                      les donnees du slider. Les numeros d'objet et les   */
/*                      parametres virtuels sont en entree, les parametres  */
/*                      en pixels sont en sortie.                           */
/*==========================================================================*/

void	SLID_display_v_slider (SLID_INFO *slider_ptr)
{
	int		pix_len;

	/* On assume que pix_len est fourni >= SLID_MIX_SLIDER_LEN */
	pix_len = RSC_get_height (slider_ptr->sbar_object);
	SLID_slider_virtual_2_pixel (slider_ptr, pix_len);

	RSC_set_height (slider_ptr->slider_object, slider_ptr->pix_win);
	RSC_set_relative_object_position (slider_ptr->slider_object, 0, slider_ptr->pix_pos);
	RSC_display_object (slider_ptr->sbar_object);
}



/*==========================================================================*/
/*      Nom: SLID_display_h_slider                                          */
/*      Description: Affiche un slider horizontal en utilisant les donnees  */
/*                   virtuelles.                                            */
/*      Parametres en entree/sortie:                                        */
/*        - slider_ptr: pointeur sur une structure SLID_INFO representant   */
/*                      les donnees du slider. Les numeros d'objet et les   */
/*                      parametres virtuels sont en entree, les parametres  */
/*                      en pixels sont en sortie.                           */
/*==========================================================================*/

void	SLID_display_h_slider (SLID_INFO *slider_ptr)
{
	int		pix_len;

	/* On assume que pix_len est fourni >= SLID_MIX_SLIDER_LEN */
	pix_len = RSC_get_width (slider_ptr->sbar_object);
	SLID_slider_virtual_2_pixel (slider_ptr, pix_len);

	RSC_set_width (slider_ptr->slider_object, slider_ptr->pix_win);
	RSC_set_relative_object_position (slider_ptr->slider_object, slider_ptr->pix_pos, 0);
	RSC_display_object (slider_ptr->sbar_object);
}



/*==========================================================================*/
/*      Nom: SLID_slider_virtual_2_pixel                                    */
/*      Description: Transforme les coordonnees virtuelles d'un slider en   */
/*                   coordonnees en pixels.                                 */
/*      Parametres en entree:                                               */
/*        - pix_len: taille totale du slider en pixels.                     */
/*      Parametres en entree/sortie:                                        */
/*        - slider_ptr: pointeur sur une structure SLID_INFO representant   */
/*                      les donnees du slider. Les numeros d'objet et les   */
/*                      parametres virtuels sont en entree, les parametres  */
/*                      en pixels sont en sortie.                           */
/*==========================================================================*/

void	SLID_slider_virtual_2_pixel (SLID_INFO *slider_ptr, int pix_len)
{
	int		pix_pos;
	int		pix_win;
	long		vir_len;
	long		vir_pos;
	long		vir_win;

	vir_len = MAX (slider_ptr->virtual_len, 0);
	vir_pos = MAX (slider_ptr->virtual_pos, 0);
	vir_pos = MIN (vir_pos, vir_len);
	vir_win = MAX (slider_ptr->virtual_win, 0);

	if (vir_len > 0 && vir_len >= vir_win)
	{
		pix_win = (int) ((double)vir_win * pix_len / vir_len);
		pix_win = MAX (pix_win, SLID_MIX_SLIDER_LEN);
		pix_pos = (int) ((double)vir_pos * (pix_len - pix_win) / (vir_len - vir_win));
		pix_pos = MIN (pix_pos, pix_len - pix_win);
	}
	else
	{
		pix_pos = 0;
		pix_win = pix_len;
	}

	slider_ptr->pix_pos = pix_pos;
	slider_ptr->pix_win = pix_win;
}



/*==========================================================================*/
/*      Nom: SLID_slider_pixel_2_virtual                                    */
/*      Description: Transforme les coordonnees en pixels d'un slider en    */
/*                   coordonnees virtuelles.                                */
/*      Parametres en entree:                                               */
/*        - pix_len: taille totale du slider en pixels.                     */
/*      Parametres en entree/sortie:                                        */
/*        - slider_ptr: pointeur sur une structure SLID_INFO representant   */
/*                      les donnees du slider.                              */
/*==========================================================================*/

void	SLID_slider_pixel_2_virtual (SLID_INFO *slider_ptr, int pix_len)
{
	int		pix_pos;
	int		pix_win;
	long		vir_len;
	long		vir_pos;
	long		vir_win;

	vir_len = MAX (slider_ptr->virtual_len, 0);
	vir_win = MAX (slider_ptr->virtual_win, 0);
	if (! slider_ptr->no_graphic_limit_flag)
	{
		pix_pos = MAX (slider_ptr->pix_pos, 0);
	}
	pix_win = MAX (slider_ptr->pix_win, 0);

	if (vir_len > 0 && vir_len >= vir_win)
	{
		vir_pos = (int) ceil ((double)pix_pos * (vir_len - vir_win) / (pix_len - pix_win));
		if (slider_ptr->no_graphic_limit_flag)
		{
			vir_pos = MIN (vir_pos, slider_ptr->sup - vir_win);
			vir_pos = MAX (vir_pos, slider_ptr->inf);
		}
		else
		{
			vir_pos = MIN (vir_pos, vir_len - vir_win);
		}
	}
	else
	{
		vir_pos = 0;
	}

	slider_ptr->virtual_pos = vir_pos;
}



/*==========================================================================*/
/*      Nom: SLID_gere_slider                                               */
/*      Description: Gere un slider.                                        */
/*      Parametres en entree/sortie:                                        */
/*        - slider_ptr: pointeur sur une structure SLID_INFO representant   */
/*                      les donnees du slider.                              */
/*        - sel_object: objet du slider qui a ete clique.                   */
/*==========================================================================*/

void	SLID_gere_slider (SLID_INFO *slider_ptr, int sel_object)
{
	int		sbar_pixpos;
	int		slider_pixpos;
	int		pix_len;
	int		pix_win;
	int		mouse_pixpos;
	signed int	pix_pos;
	signed int	glisse_pos;
	long		old_virtual_pos;
	long		vir_pos;

	INTR_graph_ptr->show_mouse ();
	INTR_graph_ptr->get_mouse (&INTR_mouse);
	old_virtual_pos = slider_ptr->virtual_pos;

	/* On assume que pix_len est fourni >= SLID_MIX_SLIDER_LEN */
	if (slider_ptr->direction == SLID_DIRECTION_HORIZONTAL)
	{
		pix_len = RSC_get_width (slider_ptr->sbar_object);
		sbar_pixpos = RSC_absolute_object_pixxpos [slider_ptr->sbar_object];
		slider_pixpos = RSC_absolute_object_pixxpos [slider_ptr->slider_object];
		mouse_pixpos = INTR_mouse.x;
	}
	else
	{
		pix_len = RSC_get_height (slider_ptr->sbar_object);
		sbar_pixpos = RSC_absolute_object_pixypos [slider_ptr->sbar_object];
		slider_pixpos = RSC_absolute_object_pixypos [slider_ptr->slider_object];
		mouse_pixpos = INTR_mouse.y;
	}
	SLID_slider_virtual_2_pixel (slider_ptr, pix_len);
	pix_win = slider_ptr->pix_win;

	/* Si on relache (maintenant ou depuis le dernier appel) */
	if (   INTR_mouse.k == 0
	    || INTR_mouse.last_released > SLID_last_call)
	{
		slider_ptr->glisse_pos = -1;
	}

	SLID_last_call = clock ();

	glisse_pos = slider_ptr->glisse_pos;
	slider_ptr->pix_pos = slider_pixpos - sbar_pixpos;

/*______________________________________________
 *
 * On n'est pas en train de glisser
 *______________________________________________
 */

	if (glisse_pos < 0)
	{
		/* On a clique sur le slider, on va donc commencer a glisser */
		if (sel_object == slider_ptr->slider_object)
		{
			glisse_pos = mouse_pixpos - slider_pixpos;
		}

		/* On a clique a cote, sur le fond de la barre */
		else if (sel_object == slider_ptr->sbar_object)
		{
			/* Vers le haut/gauche */
			if (mouse_pixpos < slider_pixpos)
			{
				vir_pos = slider_ptr->virtual_pos - slider_ptr->virtual_win;
			}
			/* Vers le bas/droite */
			else
			{
				vir_pos = slider_ptr->virtual_pos + slider_ptr->virtual_win;
			}
			vir_pos = MIN (vir_pos, slider_ptr->virtual_len - slider_ptr->virtual_win);
			vir_pos = MAX (vir_pos, 0);
			slider_ptr->virtual_pos = vir_pos;
			glisse_pos = -2;
		}

		/* Pas de clic ou a cote, on ne fait rien */
		else
		{
			glisse_pos = -1;
		}
	}

/*______________________________________________
 *
 * On est en train de glisser
 *______________________________________________
 */

	else
	{
		pix_pos = mouse_pixpos - sbar_pixpos - glisse_pos;
		if (! slider_ptr->no_graphic_limit_flag)
		{
			pix_pos = MIN (pix_pos, pix_len - pix_win);
			pix_pos = MAX (pix_pos, 0);
		}
		slider_ptr->pix_pos = pix_pos;
		SLID_slider_pixel_2_virtual (slider_ptr, pix_len);
	}

	slider_ptr->glisse_pos = glisse_pos;

	/* Regarde si la position du slider a vraiment change */
	if (slider_ptr->virtual_pos != old_virtual_pos)
	{
		SLID_display_slider (slider_ptr);
		slider_ptr->changed_pos_flag = true;
	}
	else
	{
		slider_ptr->changed_pos_flag = false;
	}
}



/*==========================================================================*/
/*      Nom: SLID_check_slider                                              */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/

void	SLID_check_slider (SLID_INFO *slider_ptr)
{
	int		sbar_pix_len;
	int		slider_pix_len;
	int		pix_x_pos;
	int		pix_y_pos;

	/* Slider horizontal */
	if (slider_ptr->direction == SLID_DIRECTION_HORIZONTAL)
	{
		RSC_get_relative_object_position (slider_ptr->slider_object, pix_x_pos, pix_y_pos);
		pix_x_pos = MAX (pix_x_pos, 0);
		pix_y_pos = 0;
		RSC_set_relative_object_position (slider_ptr->slider_object, pix_x_pos, pix_y_pos);

		sbar_pix_len = RSC_get_width (slider_ptr->sbar_object);
		sbar_pix_len = MAX (sbar_pix_len, SLID_MIX_SLIDER_LEN);
		RSC_set_width (slider_ptr->sbar_object, sbar_pix_len);

		slider_pix_len = RSC_get_width (slider_ptr->slider_object);
		slider_pix_len = MIN (slider_pix_len, sbar_pix_len);
		slider_pix_len = MAX (slider_pix_len, SLID_MIX_SLIDER_LEN);
		RSC_set_width (slider_ptr->slider_object, slider_pix_len);
	}

	/* Slider vertical */
	else
	{
		RSC_get_relative_object_position (slider_ptr->slider_object, pix_x_pos, pix_y_pos);
		pix_y_pos = MAX (pix_y_pos, 0);
		pix_x_pos = 0;
		RSC_set_relative_object_position (slider_ptr->slider_object, pix_x_pos, pix_y_pos);

		sbar_pix_len = RSC_get_height (slider_ptr->sbar_object);
		sbar_pix_len = MAX (sbar_pix_len, SLID_MIX_SLIDER_LEN);
		RSC_set_height (slider_ptr->sbar_object, sbar_pix_len);

		slider_pix_len = RSC_get_height (slider_ptr->slider_object);
		slider_pix_len = MIN (slider_pix_len, sbar_pix_len);
		slider_pix_len = MAX (slider_pix_len, SLID_MIX_SLIDER_LEN);
		RSC_set_height (slider_ptr->slider_object, slider_pix_len);
	}
}



/****************************************************************************/
/*                                                                          */
/*                                                                          */
/*                                                                          */
/****************************************************************************/



/*==========================================================================*/
/*      Nom:                                                                */
/*      Description:                                                        */
/*      Parametres en entree:                                               */
/*      Parametres en sortie:                                               */
/*      Parametres en entree/sortie:                                        */
/*      Retour:                                                             */
/*==========================================================================*/
