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

        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	<assert.h>
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>

#include	"base.h"
#include	"base_ct.h"
#include	"Image.h"
#include	"intrface.h"
#include	"log.h"
#include	"memory.h"
#include	"Popup.h"
#include	"PopupLine.h"
#include	"resource.h"
#include	"rsc01.h"



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




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

const int	Popup::LINE_ARRAY_GRANULARITY = 1 << 4;	/* Toujours une puissance de 2 */



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



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

/* Pointeur sur l'objet affiche s'il existe, NULL sinon. */
Popup	*Popup::displayed_popup_ptr = NULL;



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



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

/*==========================================================================*/
/*      Nom: (constructeur)                                                 */
/*      Description: initialise le popup. Il faut alors ajouter des lignes, */
/*                   avec la methode add_line.                              */
/*==========================================================================*/

Popup::Popup (void)
{
	_line_ptr = (PopupLine **) MALLOC (  Popup::LINE_ARRAY_GRANULARITY
	                                   * sizeof (*_line_ptr));
	_nbr_lines = 0;
	_nbr_columns = 0;
	_displayed_flag = false;
	_pix_x_pos = -1;
	_pix_y_pos = -1;
}



/*==========================================================================*/
/*      Nom: (destructeur)                                                  */
/*      Description: Detruit un menu pop-up.                                */
/*==========================================================================*/

Popup::~Popup (void)
{
	if (_line_ptr != NULL)
	{
		for (int line = 0; line < _nbr_lines; line ++)
		{
			delete _line_ptr [line];
			_line_ptr [line] = NULL;
		}

		FREE (_line_ptr);
		_line_ptr = NULL;
	}
}



/*==========================================================================*/
/*      Nom: check_ok                                                       */
/*      Description: Verifie l'intergrite de l'objet.                       */
/*      Retour: 0 si l'objet parait correct.                                */
/*==========================================================================*/

signed int	Popup::check_ok (void) const
{
	signed int	ret_val;

	if (_line_ptr == NULL)
	{
		LOG_printf ("Popup::check_ok: Error: line array pointer is null.\n");
		return (-1);
	}

	MCHECK (_line_ptr);

	for (int line_cnt = 0; line_cnt < _nbr_lines; line_cnt ++)
	{
		if (_line_ptr [line_cnt]->check_ok ())
		{
			LOG_printf ("Popup::check_ok: Error: line %d corrupted.\n",
			            line_cnt);
			ret_val = -1;
		}
	}

	return (ret_val);
}



/*==========================================================================*/
/*      Nom: self_display                                                   */
/*      Description: Affiche "textuellement" le contenu courant de l'objet. */
/*==========================================================================*/

void	Popup::self_display (void) const
{

	/*** A faire ***/

}



/*==========================================================================*/
/*      Nom: redraw                                                         */
/*      Description: Affiche le menu pop-up, si c'est possible.             */
/*==========================================================================*/

signed int	Popup::redraw (void)
{
	int		shadow_pix_width;

	if (! _displayed_flag)
	{
		return (0);
	}

	assert (_nbr_lines > 0);
	assert (_pix_x_pos >= 0 && _pix_y_pos >= 0);

	shadow_pix_width = _pix_width;
	if (_slider_flag)
	{
		shadow_pix_width += RSC_get_width (RSC_OBJ_PU_SBAR);
	}

	RSC_set_absolute_object_position (RSC_OBJ_PU, _pix_x_pos, _pix_y_pos);
	RSC_set_width (RSC_OBJ_PU_MENU, _pix_width);
	RSC_set_height (RSC_OBJ_PU_MENU, _pix_height);
	RSC_set_width (RSC_OBJ_PU_SHADOW, shadow_pix_width);
	RSC_set_height (RSC_OBJ_PU_SHADOW, _pix_height);

	/* Slider */
	if (_slider_flag)
	{
		RSC_clear_flag (RSC_OBJ_PU_UP, RSC_ATTR_NOTDISP);
		RSC_clear_flag (RSC_OBJ_PU_DOWN, RSC_ATTR_NOTDISP);
		RSC_clear_flag (RSC_OBJ_PU_SBAR, RSC_ATTR_NOTDISP);

		RSC_set_relative_object_position (RSC_OBJ_PU_UP, _pix_width, 0);
		RSC_set_relative_object_position (RSC_OBJ_PU_DOWN, _pix_width,
													 _pix_height - RSC_get_height (RSC_OBJ_PU_DOWN));
		RSC_set_relative_object_position (RSC_OBJ_PU_SBAR, _pix_width,
													 RSC_get_height (RSC_OBJ_PU_UP));

		RSC_set_height (RSC_OBJ_PU_SBAR, _pix_height - RSC_BOXTEXT_H * 2);
	}
	else
	{
		RSC_set_flag (RSC_OBJ_PU_UP, RSC_ATTR_NOTDISP);
		RSC_set_flag (RSC_OBJ_PU_DOWN, RSC_ATTR_NOTDISP);
		RSC_set_flag (RSC_OBJ_PU_SBAR, RSC_ATTR_NOTDISP);
	}

	INTR_graph_ptr->hide_mouse ();
	RSC_set_flag (RSC_OBJ_PU_MENU_LBKGND, RSC_ATTR_NOTDISP);
	RSC_display_object (RSC_OBJ_PU);
	RSC_clear_flag (RSC_OBJ_PU_MENU_LBKGND, RSC_ATTR_NOTDISP);

	if (_slider_flag)
	{
		SLID_display_slider (&_slider);
	}

	if (refresh ())
	{
		LOG_printf ("Popup::redraw: Error: couldn't refresh menu.\n");
		return (-1);
	}

	return (0);
}



/*==========================================================================*/
/*      Nom: refresh                                                        */
/*      Description: Rafraichit l'affichage dynamique du menu pop-up.       */
/*==========================================================================*/

signed int	Popup::refresh (void) const
{
	int		line_pix_y_pos;
	int		win_pos;
	char		*text_0;

	if (! _displayed_flag)
	{
		return (0);
	}

	RSC_set_width (RSC_OBJ_PU_MENU_LBKGND, RSC_CHAR_W * (_nbr_columns + 4));
	RSC_set_width (RSC_OBJ_PU_MENU_LBKGND_SEP, RSC_CHAR_W * (_nbr_columns + 2));
	
	text_0 = (char *) MALLOC (_nbr_columns + 4 + 1);
	if (text_0 == NULL)
	{
		LOG_printf ("Popup::refresh: Error: couldn't reserve memory for line string.\n");
		return (-1);
	}

	win_pos = 0;
	if (_slider_flag)
	{
		win_pos = _slider.virtual_pos;
	}

	RSC_set_color (RSC_OBJ_PU_MENU_LBKGND, 13);
	line_pix_y_pos = RSC_V_SPACE*2;
	for (int line = 0; line < _nbr_disp_lines; line ++)
	{
		RSC_set_relative_object_position (RSC_OBJ_PU_MENU_LBKGND,
		                                  RSC_CHAR_W, line_pix_y_pos);

		/* Ligne de separation */
		if (*(_line_ptr [line + win_pos]->get_text ()) == '\n')
		{
			RSC_clear_flag (RSC_OBJ_PU_MENU_LBKGND_SEP, RSC_ATTR_NOTDISP);
			RSC_set_flag (RSC_OBJ_PU_MENU_LBKGND_TEXT, RSC_ATTR_NOTDISP);
			RSC_display_object (RSC_OBJ_PU_MENU_LBKGND);
			RSC_set_flag (RSC_OBJ_PU_MENU_LBKGND_SEP, RSC_ATTR_NOTDISP);
			RSC_clear_flag (RSC_OBJ_PU_MENU_LBKGND_TEXT, RSC_ATTR_NOTDISP);
		}

		/* Ligne normale */
		else
		{
			if (_line_ptr [line + win_pos]->get_disable_flag ())
			{
				RSC_set_color (RSC_OBJ_PU_MENU_LBKGND_TEXT, 14);
			}

			else
			{
				RSC_set_color (RSC_OBJ_PU_MENU_LBKGND_TEXT, 12);
			}
			format_line (line + win_pos, text_0);
			RSC_set_string (RSC_OBJ_PU_MENU_LBKGND_TEXT, text_0);
			RSC_display_object (RSC_OBJ_PU_MENU_LBKGND);
		}

		line_pix_y_pos += RSC_CHAR_H + RSC_V_SPACE;
	}

	FREE (text_0);

	return (0);
}



/*==========================================================================*/
/*      Nom: add_line                                                       */
/*      Description: Ajoute une ligne au menu pop-up.                       */
/*      Parametres en entree:                                               */
/*        - text_0: pointeur sur le texte de la ligne. Si la ligne commence */
/*                  par un '\n', il s'agit d'une ligne de separation.       */
/*        - code: code renvoye par la routine de gestion du pop-up quand    */
/*                l'utilisateur a clique sur cette ligne. Ce code doit etre */
/*                superieur ou egal a 0. Si on veut utiliser les fonctions  */
/*                de recherche de ligne par le code, le code doit etre      */
/*                unique pour chaque ligne.                                 */
/*        - selected_flag: indique que la ligne apparait a l'ecran          */
/*                         accompagnee d'un symbole "check".                */
/*        - disable_flag: true indique qu'on ne peut cliquer sur la ligne.  */
/*      Retour: 0 si tout s'est bien passe.                                 */
/*==========================================================================*/

signed int	Popup::add_line (const char *text_0, signed long code, bool selected_flag, bool disable_flag, Popup *popup_ptr)
{
	int		nbr_reserved_lines;
	PopupLine	**temp_ptr;

	nbr_reserved_lines =   (_nbr_lines + Popup::LINE_ARRAY_GRANULARITY - 1)
	                     & ~(Popup::LINE_ARRAY_GRANULARITY - 1);
	nbr_reserved_lines = MAX (nbr_reserved_lines, Popup::LINE_ARRAY_GRANULARITY);
	if (nbr_reserved_lines < _nbr_lines + 1)
	{
		nbr_reserved_lines += Popup::LINE_ARRAY_GRANULARITY;
		temp_ptr = (PopupLine **) REALLOC (_line_ptr, nbr_reserved_lines * sizeof (*_line_ptr));
		if (temp_ptr == NULL)
		{
			LOG_printf ("Popup::add_line: Error: couldn't add the new line.\n");
			return (-1);
		}
		_line_ptr = temp_ptr;
	}

	_line_ptr [_nbr_lines] = new PopupLine (text_0, code, selected_flag, disable_flag, popup_ptr);
	if (_line_ptr [_nbr_lines] == NULL)
	{
		LOG_printf ("Popup::add_line: couldn't create the new line.\n");
		return (-1);
	}

	_nbr_columns = MAX (_nbr_columns,
	                    (int) strlen (_line_ptr [_nbr_lines]->get_text ()));

	_nbr_lines ++;

	return (0);
}



/*==========================================================================*/
/*      Nom: manage                                                         */
/*      Description: Gere le pop-up (affichage, choix de l'utilisateur).    */
/*      Parametres en entree:                                               */
/*        - default_line: numero de la ligne sur laquelle le curseur de la  */
/*                        souris doit se trouver au debut. -1 indique que   */
/*                        cette ligne est indeterminee (souris sur la ligne */
/*                        centrale).                                        */
/*      Retour: Le code de la ligne qui a ete selectionnee,                 */
/*              -1 si on a annule (clic a cote du menu),                    */
/*              -2 si erreur.                                               */
/*==========================================================================*/

signed long	Popup::manage (signed int default_line)
{
	int		ext_pix_width;
	int		ext_pix_height;
	signed int	win_pos;
	signed int	sel_object;
	signed int	sel_aine;
	signed int	last_object;
	signed int	temp;
	signed int	choice;
	signed int	old_choice;
	signed long	return_value;
	bool		redraw_flag;
	bool		clicked_flag;
	bool		choosen_flag;
	bool		slider_moved_flag;
	char		*text_0;
	Popup		*next_popup_ptr;
	Popup		*old_displayed_popup_ptr;
	Image		*background_ptr;

/*______________________________________________
 *
 * Preparation et affichage
 *______________________________________________
 */

	/* Recupere les dimensions internes du pop-up */
	get_dimensions (_pix_width, _pix_height, _nbr_disp_lines, _slider_flag);
	ext_pix_width = _pix_width + INTR_SHADOW_CARXDEC * RSC_CHAR_W;
	ext_pix_height = _pix_height + INTR_SHADOW_PIXYDEC;

	/* Regle la position de la fenetre en cas de slider */
	win_pos = 0;
	if (_slider_flag)
	{
		win_pos = default_line - _nbr_disp_lines / 2;	/* Centree sur la ligne par defaut */
		win_pos = MIN (win_pos, _nbr_lines - _nbr_disp_lines);
		win_pos = MAX (win_pos, 0);
		_slider.sbar_object           = RSC_OBJ_PU_SBAR;
		_slider.slider_object         = RSC_OBJ_PU_SBAR_SLIDER;
		_slider.pix_pos               = 0;
		_slider.pix_win               = 0;
		_slider.virtual_len           = _nbr_lines;
		_slider.virtual_pos           = win_pos;
		_slider.virtual_win           = _nbr_disp_lines;
		_slider.glisse_pos            = -1;
		_slider.direction             = SLID_DIRECTION_VERTICAL;
		_slider.no_graphic_limit_flag = false;
		ext_pix_width += RSC_get_width (RSC_OBJ_PU_SBAR);
	}

	/* Calcule la position d'affichage */
	if (default_line >= 0)
	{
		default_line = _nbr_disp_lines / 2;
	}
	_pix_x_pos = INTR_mouse.x - _pix_width / 2;
	_pix_x_pos = MIN (_pix_x_pos, INTR_graph_ptr->get_width () - ext_pix_width);
	_pix_x_pos = MAX (_pix_x_pos, 0);
	_pix_y_pos = INTR_mouse.y - default_line * (RSC_CHAR_H + RSC_V_SPACE)
	                         - RSC_CHAR_H/2 - RSC_V_SPACE/2 - RSC_V_SPACE*2;
	_pix_y_pos = MIN (_pix_y_pos, INTR_graph_ptr->get_height () - ext_pix_height);
	_pix_y_pos = MAX (_pix_y_pos, 0);

	/* Sauvgarde le fond */
	RSC_flush_resource ();
	background_ptr = INTR_graph_ptr->save_background (_pix_x_pos, _pix_y_pos,
	                                                 ext_pix_width, ext_pix_height);
	if (background_ptr == NULL)
	{
		LOG_printf ("Popup::manage: Error: couldn't save background.\n");
		return (-2);		/* Erreur dans la sauvegarde du fond */
	}

	/* Dessine le pop-up */
	_displayed_flag = true;
	old_displayed_popup_ptr = displayed_popup_ptr;
	displayed_popup_ptr = this;
	redraw ();

/*______________________________________________
 *
 * Gestion du pop-up
 *______________________________________________
 */

	return_value = -1;
	old_choice = -1;
	clicked_flag = false;
	choosen_flag = false;
	slider_moved_flag = false;
	last_object = -1;

	/* Reserve de la memoire pour l'affichage d'une ligne */
	text_0 = (char *) MALLOC (_nbr_columns + 4 + 1);
	if (text_0 == NULL)
	{
		LOG_printf ("Popup::manage: Error: couldn't reserve memory for line string.\n");
		return (-2);
	}

	INTR_wait_mouse (true);
	while (! choosen_flag)
	{
		INTR_graph_ptr->show_mouse ();
		INTR_graph_ptr->get_mouse (&INTR_mouse);

		/* Souris sur une des lignes du menu ? */
		choice = -1;
		sel_object = RSC_get_pointed_object_number (INTR_mouse.x, INTR_mouse.y, RSC_OBJ_PU, &sel_aine);
		if (sel_object == RSC_OBJ_PU_MENU && ! slider_moved_flag)
		{
			temp = INTR_mouse.y - (_pix_y_pos + RSC_V_SPACE*2);
			if (temp >= 0)
			{
				temp /= (RSC_CHAR_H + RSC_V_SPACE);
				if (temp < _nbr_disp_lines)
				{
					if (   ! _line_ptr [win_pos + temp]->get_disable_flag ()
					    && *(_line_ptr [win_pos + temp]->get_text ()) != '\n')
					{
						choice = temp;
					}
				}
			}
		}

		redraw_flag = false;

		RSC_gere_resource (RSC_OBJ_PU, &sel_object, &sel_aine);
		switch (sel_object)
		{
		/* Redaw si on a appuye sur le menu */
		case	RSC_OBJ_PU_MENU:
			if (! clicked_flag || slider_moved_flag)
			{
				redraw_flag = true;
			}
			break;
		/* Fleche haut */

		case	RSC_OBJ_PU_UP:
			slider_moved_flag = true;
			if (win_pos > 0)
			{
				win_pos --;
				_slider.virtual_pos = win_pos;
				SLID_display_slider (&_slider);
				RSC_display_object (RSC_OBJ_PU_MENU);
//				redraw_flag = true;
			}
			break;

		/* Fleche bas */
		case	RSC_OBJ_PU_DOWN:
			slider_moved_flag = true;
			if (win_pos < _nbr_lines - _nbr_disp_lines)
			{
				win_pos ++;
				_slider.virtual_pos = win_pos;
				SLID_display_slider (&_slider);
//				RSC_display_object (RSC_OBJ_PU_MENU);
				redraw_flag = true;
			}
			break;

		/* Slider */
		case	RSC_OBJ_PU_SBAR:
		case	RSC_OBJ_PU_SBAR_SLIDER:
			slider_moved_flag = true;
			SLID_gere_slider (&_slider, sel_object);
			if (_slider.virtual_pos != win_pos)
			{
				win_pos = _slider.virtual_pos;
//				RSC_display_object (RSC_OBJ_PU_MENU);
				redraw_flag = true;
			}
			break;
		}

		if (! slider_moved_flag && _slider.glisse_pos != -1)
		{
			_slider.glisse_pos = -1;
		}

		if (   last_object != sel_object
			 && last_object == RSC_OBJ_PU_MENU)
		{
			redraw_flag = true;
		}

		if (redraw_flag)
		{
			if (refresh ())
			{
				LOG_printf ("Popup::manage: Error: couldn't refresh menu.\n");
				FREE (text_0);
				return (-2);
			}
		}

		/* Affichage de l'inversion video */
		if (old_choice != choice || (INTR_mouse.k != 0 && ! clicked_flag))
		{
			if (old_choice >= 0)
			{
				RSC_set_color (RSC_OBJ_PU_MENU_LBKGND, 13);
				RSC_set_relative_object_position (RSC_OBJ_PU_MENU_LBKGND,
				                                  RSC_CHAR_W,
				                                    RSC_V_SPACE*2
															 + old_choice * (RSC_CHAR_H + RSC_V_SPACE));

				format_line (win_pos + old_choice, text_0);
				if (_line_ptr [win_pos + old_choice]->get_disable_flag ())
				{
					RSC_set_color (RSC_OBJ_PU_MENU_LBKGND_TEXT, 14);
				}
				else
				{
					RSC_set_color (RSC_OBJ_PU_MENU_LBKGND_TEXT, 12);
				}
				RSC_set_string (RSC_OBJ_PU_MENU_LBKGND_TEXT, text_0);

				RSC_display_object (RSC_OBJ_PU_MENU_LBKGND);
			}
			if (choice >= 0)
			{
				RSC_set_color (RSC_OBJ_PU_MENU_LBKGND, 12);
				RSC_set_relative_object_position (RSC_OBJ_PU_MENU_LBKGND,
				                                  RSC_CHAR_W,
				                                    RSC_V_SPACE*2
															 + choice * (RSC_CHAR_H + RSC_V_SPACE));

				format_line (win_pos + choice, text_0);
				RSC_set_color (RSC_OBJ_PU_MENU_LBKGND_TEXT, 14);
				RSC_set_string (RSC_OBJ_PU_MENU_LBKGND_TEXT, text_0);

				RSC_display_object (RSC_OBJ_PU_MENU_LBKGND);
			}

			INTR_graph_ptr->show_mouse ();
		}
		old_choice = choice;

		/* Clic */
		if (INTR_mouse.k != 0)
		{
			if (! slider_moved_flag)
			{
				clicked_flag = true;
			}
		}

		/* Clic relache */
		else if (slider_moved_flag)
		{
			slider_moved_flag = false;
		}
		else if (clicked_flag)
		{
			clicked_flag = false;
			if (choice >= 0 && INTR_mouse.k != 2)
			{
				if (! _line_ptr [win_pos + choice]->get_disable_flag ())
				{
					next_popup_ptr = (Popup *) (_line_ptr [win_pos + choice]->get_popup_ptr ());
					if (next_popup_ptr != NULL)
					{
						if (! next_popup_ptr->is_displayed ())
						{
							return_value = next_popup_ptr->manage ();
							redraw ();
							if (return_value >= 0)
							{
								choosen_flag = true;
							}
						}
					}
					else
					{
						return_value = _line_ptr [win_pos + choice]->manage ();
						choosen_flag = true;
					}
				}
			}
			else
			{
				return_value = -1;
				choosen_flag = true;
			}
		}

		last_object = sel_object;
	}

	FREE (text_0);

/*______________________________________________
 *
 * Restoration
 *______________________________________________
 */

	/* Remet le fond */
	RSC_flush_resource ();
	displayed_popup_ptr = old_displayed_popup_ptr;
	_displayed_flag = false;
	INTR_graph_ptr->restore_background (background_ptr);

	INTR_wait_mouse (true);

	return (return_value);
}



/*==========================================================================*/
/*      Nom: select_by_line                                                 */
/*      Description: "Check" une ligne (ou enleve la marque).               */
/*      Parametres en entree:                                               */
/*        - line: numero de la ligne concernee (numerotee a partir de 0).   */
/*        - selected_flag: true si on doit mettre le "check", false sinon.  */
/*==========================================================================*/

void	Popup::select_by_line (signed int line, bool selected_flag)
{
	assert (line < _nbr_lines);

	_line_ptr [line]->set_selected_flag (selected_flag);
}



/*==========================================================================*/
/*      Nom: select_by_code                                                 */
/*      Description: "Check" une ligne (ou enleve la marque), en se basant  */
/*                   sur le code de la ligne pour identifier celle-ci.      */
/*      Parametres en entree:                                               */
/*        - code: code de la ligne concernee.                               */
/*        - selected_flag: true si on doit mettre le "check", false sinon.  */
/*      Retour: numero de la ligne trouvee, -1 si on n'a pas trouvee de     */
/*              ligne correspondant au code.                                */
/*==========================================================================*/

signed int	Popup::select_by_code (signed long code, bool selected_flag)
{
	signed int	line;

	line = find_line_by_code (code);
	if (line < 0)
	{
		return (-1);
	}
	select_by_line (line, selected_flag);

	return (line);
}



/*==========================================================================*/
/*      Nom: select_radio_by_line                                           */
/*      Description: "Check" une ligne d'un bloc, et de-check toutes les    */
/*                   autres de ce bloc. Un bloc est limite par des lignes   */
/*                   non cliquables.                                        */
/*      Parametres en entree:                                               */
/*        - line: numero de la ligne concernee (numerotee a partir de 0).   */
/*==========================================================================*/

void	Popup::select_radio_by_line (signed int line)
{
	signed int	scan_line;

	assert (line < _nbr_lines);

	line = MAX (line, -1);

	/* Deselectionne les lignes au-dessus, dans le meme bloc */
	scan_line = line;
	while (scan_line >= 0)
	{
		if (_line_ptr [scan_line]->get_disable_flag ())
		{
			break;
		}
		_line_ptr [scan_line]->set_selected_flag (false);
		scan_line --;
	}

	/* Deselectionne les lignes en-dessous, dans le meme bloc */
	scan_line = line + 1;
	while (scan_line < _nbr_lines)
	{
		if (_line_ptr [scan_line]->get_disable_flag ())
		{
			break;
		}
		_line_ptr [scan_line]->set_selected_flag (false);
		scan_line ++;
	}

	/* Selectionne la ligne */
	if (line >= 0)
	{
		_line_ptr [line]->set_selected_flag (true);
	}
}



/*==========================================================================*/
/*      Nom: select_radio_by_code                                           */
/*      Description: "Check" une ligne d'un bloc, et de-check toutes les    */
/*                   autres de ce bloc. Un bloc est limite par des lignes   */
/*                   non cliquables. La ligne est reperee par son code.     */
/*      Parametres en entree:                                               */
/*        - code: code de la ligne concernee.                               */
/*      Retour: numero de la ligne trouvee, -1 si on n'a pas trouvee de     */
/*              ligne correspondant au code.                                */
/*==========================================================================*/


signed int	Popup::select_radio_by_code (signed long code)
{
	signed int	line;

	line = find_line_by_code (code);
	if (line < 0)
	{
		return (-1);
	}
	select_radio_by_line (line);

	return (line);
}



/*==========================================================================*/
/*      Nom: disable_by_line                                                */
/*      Description: Invalide une ligne (ou la valide).                     */
/*      Parametres en entree:                                               */
/*        - line: numero de la ligne concernee (numerotee a partir de 0).   */
/*        - disable_flag: true si on doit invalider la ligne.               */
/*==========================================================================*/

void	Popup::disable_by_line (signed int line, bool disable_flag)
{
	assert (line < _nbr_lines);

	_line_ptr [line]->set_disable_flag (disable_flag);
}



/*==========================================================================*/
/*      Nom: disable_by_code                                                */
/*      Description: Invalide une ligne (ou la valide), en se basant        */
/*                   sur le code de la ligne pour identifier celle-ci.      */
/*      Parametres en entree:                                               */
/*        - code: code de la ligne concernee.                               */
/*        - disable_flag: true si on doit invalider la ligne.               */
/*      Retour: numero de la ligne trouvee, -1 si on n'a pas trouvee de     */
/*              ligne correspondant au code.                                */
/*==========================================================================*/

signed int	Popup::disable_by_code (signed long code, bool disable_flag)
{
	signed int	line;

	line = find_line_by_code (code);
	if (line < 0)
	{
		return (-1);
	}
	disable_by_line (line, disable_flag);

	return (line);
}



bool	Popup::is_displayed (void) const
{
	return (_displayed_flag);
}



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

/*==========================================================================*/
/*      Nom: find_line_by_code                                              */
/*      Description: Trouve une ligne a partir de son code. Comme le code   */
/*                   n'est pas forcement unique, c'est la premiere ligne    */
/*                   satisfaisante qui est renvoyee.                        */
/*      Parametres en entree:                                               */
/*        - code: code de la ligne a trouver.                               */
/*      Retour: Numero de la ligne trouvee, -1 si on n'a rien trouve.       */
/*==========================================================================*/

signed int	Popup::find_line_by_code (signed long code) const
{
	for (int line = 0; line < _nbr_lines; line ++)
	{
		if (_line_ptr [line]->get_code () == code)
		{
			return (line);
		}
	}

	return (-1);
}



/*==========================================================================*/
/*      Nom: get_dimensions                                                 */
/*      Description: Renvoie les dimensions d'un pop-up, en pixels. Ces     */
/*                   dimensions ne prennent pas en compte la presence d'un  */
/*                   enventuel slider. L'ombre n'est pas non-plus comptee.  */
/*      Parametres en sortie:                                               */
/*        - pix_width: largeur en pixels.                                   */
/*        - pix_height: hauteur, en pixels.                                 */
/*        - disp_lines: nombre de lignes affichee simultanement.            */
/*        - slider_flag: true indique qu'un slider est necessaire car le    */
/*                       nombre de lignes affichees est inferieur au nombre */
/*                       de lignes total.                                   */
/*==========================================================================*/

void	Popup::get_dimensions (int &pix_width, int &pix_height, int &disp_lines, bool &slider_flag) const
{
	int		max_disp_lines;

	max_disp_lines = (  INTR_graph_ptr->get_height () - RSC_V_SPACE*2 * 2
	                  - INTR_SHADOW_PIXYDEC) / (RSC_CHAR_H + RSC_V_SPACE);

	disp_lines = MIN (_nbr_lines, max_disp_lines);
	slider_flag = (_nbr_lines > disp_lines);
	pix_height = disp_lines * (RSC_CHAR_H + RSC_V_SPACE) + RSC_V_SPACE*2 * 2;
	pix_width = (_nbr_columns + 6) * RSC_CHAR_W;
}



/*==========================================================================*/
/*      Nom: format_line                                                    */
/*      Description: Genere le texte d'une ligne tel qu'il va etre affiche  */
/*                   dans le pop-up, avec ou sans le caractere de check.    */
/*      Parametres en entree:                                               */
/*        - line: numero de la ligne a generer.                             */
/*        - text_0: pointeur sur le texte final, qui contiendra au plus     */
/*                  _nbr_columns + 4 caracteres (0 final non compris).      */
/*==========================================================================*/

void	Popup::format_line (int line, char *text_0) const
{
	assert (line < _nbr_lines);

	if (_line_ptr [line]->get_selected_flag ())
	{
		strcpy (text_0, "\x08 ");
	}
	else
	{
		strcpy (text_0, "  ");
	}

	strcat (text_0, _line_ptr [line]->get_text ());

	if (_line_ptr [line]->get_popup_ptr () != NULL)
	{
		strcat (text_0, " \xFE");
	}
}



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



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