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

        GRAOUMF TRACKER 2
        Author: Laurent de Soras, 1996-2016

--- Legal stuff ---

This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://sam.zoy.org/wtfpl/COPYING for more details.

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



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

#include	<stdio.h>
#include	<math.h>

#include	"base.h"
#include	"base_ct.h"
#include	"gtracker.h"
#include	"ICWindow.h"
#include	"InterfaceComponent.h"
#include	"resource.h"
#include	"sliders.h"



/*\\\ CONSTANTES PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



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



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



/*\\\ DEFINITION DES VARIABLES DE CLASSE PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ DEFINITION DES VARIABLES DE CLASSE PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*\\\ METHODES PUBLIQUES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



/*==========================================================================*/
/*      Nom: (constructeur)                                                 */
/*      Description: Initialise la fenetre                                  */
/*      Parametres en entree:                                               */
/*        - ?_sbar: numero d'objet de la barre support de l'ascenseur.      */
/*        - ?_slider: numero d'objet de la barre mouvante de l'ascenseur.   */
/*        - arrow_?: numero d'objet des fleches de defilement.              */
/*        - ?_zoom_?: numero d'objet des zoomers.                           */
/*        - ?_length: taille de la fenetre virtuelle.                       */
/*        - ?_pos: position dans la fenetre virtuelle.                      */
/*        - ?_zoom: zoom de la fenetre (> 1: grossissement).                */
/*==========================================================================*/

ICWindow::ICWindow (int master_object, int h_offset, int window, int center,
                    signed int h_gadgets, signed int v_gadgets,
                    signed int h_sbar, signed int h_slider,
                    signed int v_sbar, signed int v_slider,
                    signed int arrow_left, signed int arrow_right,
                    signed int arrow_up, signed int arrow_down,
                    signed int h_zoom_in, signed int h_zoom_out,
                    signed int v_zoom_in, signed int v_zoom_out,
                    long h_length, long v_length, long h_pos, long v_pos,
                    double h_zoom, double v_zoom)
{
	const	SLID_INFO	slider =
	{
		0,
		0,
		0, 0, 0, 0, 0, -1,
		SLID_DIRECTION_HORIZONTAL,
		false, false, 0, 0
	};

	_master_object = master_object;

	_h_slider = slider;
	_h_slider.sbar_object = h_sbar;
	_h_slider.slider_object = h_slider;
	_h_slider.direction = SLID_DIRECTION_HORIZONTAL;

	_v_slider = slider;
	_v_slider.sbar_object = v_sbar;
	_v_slider.slider_object = v_slider;
	_v_slider.direction = SLID_DIRECTION_VERTICAL;

	_arrow_left = arrow_left;
	_arrow_right = arrow_right;
	_arrow_up = arrow_up;
	_arrow_down = arrow_down;
	_h_zoom_in = h_zoom_in;
	_h_zoom_out = h_zoom_out;
	_v_zoom_in = v_zoom_in;
	_v_zoom_out = v_zoom_out;
	_h_length = h_length;
	_v_length = v_length;
	_h_pos = h_pos;
	_v_pos = v_pos;
	_h_zoom = h_zoom;
	_v_zoom = v_zoom;

	_width = 150;
	_height = 150;
	_h_offset = h_offset;
	_center = center;
	_window = window;
	_h_gadgets = h_gadgets;
	_v_gadgets = v_gadgets;
}



/*==========================================================================*/
/*      Nom: (destructeur)                                                  */
/*      Description: Detruit                                                */
/*==========================================================================*/

ICWindow::~ICWindow (void)
{
}



/*==========================================================================*/
/*      Nom: redraw                                                         */
/*      Description: Affiche la composante d'interface.                     */
/*==========================================================================*/

void	ICWindow::redraw (void)
{
	pack ();

	set_width (_width);
	set_height (_height);

	RSC_display_object (_master_object);
	
	refresh ();
}



/*==========================================================================*/
/*      Nom: refresh                                                        */
/*      Description: Rafraichit l'affichage des donnees.                    */
/*==========================================================================*/

void	ICWindow::refresh (void)
{
	_h_slider.virtual_len = _h_length;
	_h_slider.virtual_pos = _h_pos;
	_h_slider.virtual_win = (long) ceil (RSC_get_width (_window) / _h_zoom);
	SLID_display_slider (&_h_slider);

	_v_slider.virtual_len = _v_length;
	_v_slider.virtual_win = (long) ceil (RSC_get_height (_window) / _v_zoom);
	if (_inversion_flag)
	{
		_v_slider.virtual_pos = _v_length - _v_pos - _v_slider.virtual_win;
	}
	else
	{
		_v_slider.virtual_pos = _v_pos;
	}
	SLID_display_slider (&_v_slider);

	refresh_dynamic (true);
}



/*==========================================================================*/
/*      Nom: refresh_dynamic                                                */
/*      Description: Rafraichit l'affichage des donnees dynamiques.         */
/*        - force_flag: true indique qu'on doit forcer le rafraichissement. */
/*==========================================================================*/

void	ICWindow::refresh_dynamic (bool force_flag)
{
}



/*==========================================================================*/
/*      Nom: manage                                                         */
/*      Description: Gere la composante d'interface                         */
/*      Parametres en entree:                                               */
/*        - sel_object: objet detecte par le gestionnaire d'interface       */
/*        - sel_elder: aine de sel_object                                   */
/*==========================================================================*/

void	ICWindow::manage (int sel_object, int sel_elder)
{
	long		val;

	/* Fenetre principale */
	if (sel_object == _window)
	{
		manage_main_window (sel_object, sel_elder);
	}

	/* Fleche vers la gauche */
	else if (sel_object == _arrow_left)
	{
		val = (long)ceil (RSC_get_width (_window) / (_h_zoom * 8));
		set_h_pos (get_h_pos () - val);
		refresh ();
//		_father_object_ptr->refresh ();	/*** Pour eviter le bug du refresh () ***/
	}

	/* Fleche vers la droite */
	else if (sel_object == _arrow_right)
	{
		val = (long)ceil (RSC_get_width (_window) / (_h_zoom * 8));
		set_h_pos (get_h_pos () + val);
		refresh ();
//		_father_object_ptr->refresh ();	/*** Pour eviter le bug du refresh () ***/
	}

	/* Fleche vers le haut */
	else if (sel_object == _arrow_up)
	{
		val = (long)ceil (RSC_get_height (_window) / (_v_zoom * 8));
		if (_inversion_flag)
		{
			val = -val;
		}
		set_v_pos (get_v_pos () - val);
		refresh ();
//		_father_object_ptr->refresh ();	/*** Pour eviter le bug du refresh () ***/
	}

	/* Fleche vers le haut */
	else if (sel_object == _arrow_down)
	{
		val = (long)ceil (RSC_get_height (_window) / (_v_zoom * 8));
		if (_inversion_flag)
		{
			val = -val;
		}
		set_v_pos (get_v_pos () + val);
		refresh ();
//		_father_object_ptr->refresh ();	/*** Pour eviter le bug du refresh () ***/
	}

	/* Zoom in horizontal */
	else if (sel_object == _h_zoom_in)
	{
		set_h_zoom (get_h_zoom () * 2);
		refresh ();
//		_father_object_ptr->refresh ();	/*** Pour eviter le bug du refresh () ***/
	}

	/* Zoom out horizontal */
	else if (sel_object == _h_zoom_out)
	{
		set_h_zoom (get_h_zoom () / 2);
		refresh ();
//		_father_object_ptr->refresh ();	/*** Pour eviter le bug du refresh () ***/
	}

	/* Zoom in vertical */
	else if (sel_object == _v_zoom_in)
	{
		set_v_zoom (get_v_zoom () * 2);
		refresh ();
//		_father_object_ptr->refresh ();	/*** Pour eviter le bug du refresh () ***/
	}

	/* Zoom out vertical */
	else if (sel_object == _v_zoom_out)
	{
		set_v_zoom (get_v_zoom () / 2);
		refresh ();
//		_father_object_ptr->refresh ();	/*** Pour eviter le bug du refresh () ***/
	}

	/* Ascenseur horizontal */
	else if (   sel_object == _h_slider.sbar_object
	         || sel_object == _h_slider.slider_object)
	{
		SLID_gere_slider (&_h_slider, sel_object);
		if (_h_slider.changed_pos_flag)
		{
			set_h_pos (_h_slider.virtual_pos);
			refresh ();
//			_father_object_ptr->refresh ();	/*** Pour eviter le bug du refresh () ***/
		}
	}

	/* Ascenseur vertical */
	else if (   sel_object == _v_slider.sbar_object
	         || sel_object == _v_slider.slider_object)
	{
		SLID_gere_slider (&_v_slider, sel_object);
		if (_v_slider.changed_pos_flag)
		{
			if (_inversion_flag)
			{
				set_v_pos (_v_length - _v_slider.virtual_pos - _v_slider.virtual_win);
			}
			else
			{
				set_v_pos (_v_slider.virtual_pos);
			}
			refresh ();
//			_father_object_ptr->refresh ();	/*** Pour eviter le bug du refresh () ***/
		}
	}
}



void	ICWindow::manage_main_window (int sel_object, int sel_elder)
{
	/* Rien ici */
}



int	ICWindow::get_width (void)
{
	return (_width);
}



int	ICWindow::get_height (void)
{
	return (_height);
}



void	ICWindow::set_width (int width)
{
	int		x;
	int		y;
	int		icon_width;
	int		pos_bar;
	int		window_width;
	int		h_bar_width;
	int		h_bar_pos;
	int		arrow_l_pos;
	int		arrow_r_pos;
	int		zoom_in_pos;
	int		zoom_out_pos;

	_width = width;

	icon_width = RSC_get_width (_v_slider.sbar_object);
	if (icon_width > 0)
	{
		icon_width += 2;
	}
	window_width = _width - icon_width - (4+4);
	pos_bar = window_width + (4+2);

	h_bar_width = window_width - _h_offset;
	icon_width = RSC_get_width (_arrow_left);
	arrow_l_pos = 0;
	h_bar_pos = icon_width;
	h_bar_width -= icon_width;

	icon_width = RSC_get_width (_h_zoom_out);
	zoom_out_pos = window_width - _h_offset - icon_width;
	h_bar_width -= icon_width;
	
	icon_width = RSC_get_width (_h_zoom_in);
	zoom_in_pos = zoom_out_pos - icon_width;
	h_bar_width -= icon_width;
	
	icon_width = RSC_get_width (_arrow_right);
	arrow_r_pos = zoom_in_pos - icon_width;
	h_bar_width -= icon_width;

	/* Place la fenetre */
	RSC_get_relative_object_position (_window, x, y);
	RSC_set_relative_object_position (_window, 4, y);
	RSC_set_width (_window, window_width);

	/* Place les gadgets verticaux a droite de la fenetre */
	RSC_get_relative_object_position (_v_gadgets, x, y);
	RSC_set_relative_object_position (_v_gadgets, pos_bar, y);
	RSC_get_relative_object_position (_center, x, y);
	RSC_set_relative_object_position (_center, pos_bar, y);

	/* Place les gadgets horizontaux sous la fenetre */
	RSC_get_relative_object_position (_h_gadgets, x, y);
	RSC_set_relative_object_position (_h_gadgets, _h_offset + 4, y);
	RSC_get_relative_object_position (_arrow_left, x, y);
	RSC_set_relative_object_position (_arrow_left, 0, y);
	RSC_get_relative_object_position (_h_slider.sbar_object, x, y);
	RSC_set_relative_object_position (_h_slider.sbar_object, h_bar_pos, y);
	RSC_get_relative_object_position (_arrow_right, x, y);
	RSC_set_relative_object_position (_arrow_right, arrow_r_pos, y);
	RSC_get_relative_object_position (_h_zoom_in, x, y);
	RSC_set_relative_object_position (_h_zoom_in, zoom_in_pos, y);
	RSC_get_relative_object_position (_h_zoom_out, x, y);
	RSC_set_relative_object_position (_h_zoom_out, zoom_out_pos, y);
	RSC_set_width (_h_slider.sbar_object, h_bar_width);
	SLID_check_slider (&_h_slider);

	check_pos ();
}



void	ICWindow::set_height (int height)
{
	int		x;
	int		y;
	int		icon_height;
	int		pos_bar;
	int		window_height;
	int		v_bar_height;
	int		v_bar_pos;
	int		arrow_u_pos;
	int		arrow_d_pos;
	int		zoom_in_pos;
	int		zoom_out_pos;

	_height = height;

	icon_height = RSC_get_height (_h_slider.sbar_object);
	if (icon_height > 0)
	{
		icon_height += 2;
	}
	window_height = _height - icon_height - (4+4);
	pos_bar = window_height + (4+2);

	v_bar_height = window_height;
	icon_height = RSC_get_height (_arrow_up);
	arrow_u_pos = 0;
	v_bar_pos = icon_height;
	v_bar_height -= icon_height;

	icon_height = RSC_get_height (_v_zoom_out);
	zoom_out_pos = window_height - icon_height;
	v_bar_height -= icon_height;
	
	icon_height = RSC_get_height (_v_zoom_in);
	zoom_in_pos = zoom_out_pos - icon_height;
	v_bar_height -= icon_height;
	
	icon_height = RSC_get_height (_arrow_down);
	arrow_d_pos = zoom_in_pos - icon_height;
	v_bar_height -= icon_height;

	/* Place la fenetre */
	RSC_get_relative_object_position (_window, x, y);
	RSC_set_relative_object_position (_window, x, 4);
	RSC_set_height (_window, window_height);

	/* Place les gadgets horizontaux sous la fenetre */
	RSC_get_relative_object_position (_h_gadgets, x, y);
	RSC_set_relative_object_position (_h_gadgets, x, pos_bar);
	RSC_get_relative_object_position (_center, x, y);
	RSC_set_relative_object_position (_center, x, pos_bar);

	/* Place les gadgets verticaux a droite de la fenetre */
	RSC_get_relative_object_position (_v_gadgets, x, y);
	RSC_set_relative_object_position (_v_gadgets, x, 4);
	RSC_get_relative_object_position (_arrow_up, x, y);
	RSC_set_relative_object_position (_arrow_up, x, arrow_u_pos);
	RSC_get_relative_object_position (_v_slider.sbar_object, x, y);
	RSC_set_relative_object_position (_v_slider.sbar_object, x, v_bar_pos);
	RSC_get_relative_object_position (_arrow_down, x, y);
	RSC_set_relative_object_position (_arrow_down, x, arrow_d_pos);
	RSC_get_relative_object_position (_v_zoom_in, x, y);
	RSC_set_relative_object_position (_v_zoom_in, x, zoom_in_pos);
	RSC_get_relative_object_position (_v_zoom_out, x, y);
	RSC_set_relative_object_position (_v_zoom_out, x, zoom_out_pos);
	RSC_set_height (_v_slider.sbar_object, v_bar_height);
	SLID_check_slider (&_v_slider);

	check_pos ();
}



void	ICWindow::get_coordinates (int &pix_x, int &pix_y)
{
	pix_x = RSC_absolute_object_pixxpos [_master_object];
	pix_y = RSC_absolute_object_pixypos [_master_object];
}



void	ICWindow::move_to (int pix_x, int pix_y)
{
	RSC_set_absolute_object_position (_master_object, pix_x, pix_y);
}


void	ICWindow::set_h_length (long length)
{
	_h_length = MAX (length, 0);
	check_pos ();
}



void	ICWindow::set_v_length (long length)
{
	_v_length = MAX (length, 0);
	check_pos ();
}



long	ICWindow::get_h_length (void)
{
	return (_h_length);
}



long	ICWindow::get_v_length (void)
{
	return (_v_length);
}



void	ICWindow::set_h_pos (long pos)
{
	_h_pos = MAX (pos, 0);
	check_pos ();
}



void	ICWindow::set_v_pos (long pos)
{
	_v_pos = MAX (pos, 0);
	check_pos ();
}



long	ICWindow::get_h_pos (void)
{
	return (_h_pos);
}



long	ICWindow::get_v_pos (void)
{
	return (_v_pos);
}



void	ICWindow::set_h_zoom (double zoom)
{
	_h_zoom = MIN (zoom, ICWindow_MAX_ZOOM);
	_h_zoom = MAX (_h_zoom, ICWindow_MIN_ZOOM);
	check_pos ();
}



void	ICWindow::set_v_zoom (double zoom)
{
	_v_zoom = MIN (zoom, ICWindow_MAX_ZOOM);
	_v_zoom = MAX (_v_zoom, ICWindow_MIN_ZOOM);
	check_pos ();
}



double	ICWindow::get_h_zoom (void)
{
	return (_h_zoom);
}



double	ICWindow::get_v_zoom (void)
{
	return (_v_zoom);
}



void	ICWindow::check_pos (void)
{
	_h_pos = MIN (_h_pos, _h_length - (long)ceil (RSC_get_width (_window) / _h_zoom));
	_h_pos = MAX (_h_pos, 0);
	_v_pos = MIN (_v_pos, _v_length - (long)ceil (RSC_get_height (_window) / _v_zoom));
	_v_pos = MAX (_v_pos, 0);
}



void	ICWindow::set_inversion_flag (int flag)
{
	_inversion_flag = flag;
}



void	ICWindow::get_mouse_point (long &x, long &y, int mouse_x, int mouse_y)
{
	mouse_x -= RSC_absolute_object_pixxpos [_window];
	mouse_y -= RSC_absolute_object_pixypos [_window];
	if (_inversion_flag)
	{
		mouse_y = RSC_get_height (_window) - 1 - mouse_y;
	}

	x = get_h_pos () + (long) floor (mouse_x / get_h_zoom ());
	y = get_v_pos () + (long) floor (mouse_y / get_v_zoom ());
}



/*\\\ METHODES PRIVEES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/



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



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