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

        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	"base.h"
#include	"base_ct.h"
#include	"gtracker.h"
#include	"intrface.h"
#include	"List.h"
#include	"resource.h"
#include	"rsc01.h"
#include	"SplEdMainLoop.h"



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

/* Type de l'element: sous-liste ou partie de l'ecran */
enum
{
	SplEdMainLoop_NODE_TYPE_LIST = 0,
	SplEdMainLoop_NODE_TYPE_SCREEN
};



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



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



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

int	SplEdMainLoop::edit_mode = SplEdMainLoop_MODE_NORMAL;



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



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



/*==========================================================================*/
/*      Nom: (constructeur)                                                 */
/*      Description: Initialise la liste des arrangements des elements      */
/*                   graphiques.                                            */
/*==========================================================================*/

SplEdMainLoop::SplEdMainLoop (void)
{
	SplEdMainLoop_PACK_NODE	node;

	/* Level 2 */
	node.type = SplEdMainLoop_NODE_TYPE_SCREEN;
	node.data.comp_ptr = &_icons;
	_list_array [3].add_to_end (&node);

	node.type = SplEdMainLoop_NODE_TYPE_SCREEN;
	node.data.comp_ptr = &_menubar;
	_list_array [3].add_to_end (&node);

	/* Level 1 */
	node.type = SplEdMainLoop_NODE_TYPE_SCREEN;
	node.data.comp_ptr = &_window;
	_list_array [1].add_to_end (&node);

	node.type = SplEdMainLoop_NODE_TYPE_SCREEN;
	node.data.comp_ptr = &_vumetres;
	_list_array [1].add_to_end (&node);

	node.type = SplEdMainLoop_NODE_TYPE_LIST;
	node.data.list_ptr = &_list_array [3];
	_list_array [2].add_to_end (&node);
	
	node.type = SplEdMainLoop_NODE_TYPE_SCREEN;
	node.data.comp_ptr = &_curspl;
	_list_array [2].add_to_end (&node);

	/* Level 0 */
	node.type = SplEdMainLoop_NODE_TYPE_SCREEN;
	node.data.comp_ptr = &_numdisp;
	_list_array [0].add_to_end (&node);

	node.type = SplEdMainLoop_NODE_TYPE_LIST;
	node.data.list_ptr = &_list_array [1];
	_list_array [0].add_to_end (&node);

	node.type = SplEdMainLoop_NODE_TYPE_SCREEN;
	node.data.comp_ptr = &_menus;
	_list_array [0].add_to_end (&node);

	node.type = SplEdMainLoop_NODE_TYPE_LIST;
	node.data.list_ptr = &_list_array [2];
	_list_array [0].add_to_end (&node);

	RSC_set_width (RSC_OBJ_SE, INTR_graph_ptr->get_width ());
	RSC_set_height (RSC_OBJ_SE, INTR_graph_ptr->get_height ());
}



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

void	SplEdMainLoop::redraw (void)
{
	/* Initialise la taille de l'objet */
	RSC_set_width (RSC_OBJ_SE, INTR_graph_ptr->get_width ());
	RSC_set_height (RSC_OBJ_SE, INTR_graph_ptr->get_height ());

	pack ();

	RSC_display_object (RSC_OBJ_SE, false);	// Affiche le fond

	_window.redraw ();
	_numdisp.redraw ();
	_curspl.redraw ();
	_menubar.redraw ();
	_icons.redraw ();
	_vumetres.redraw ();
	_menus.redraw ();

	refresh ();
}



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

void	SplEdMainLoop::refresh (void)
{
	_window.refresh ();
	_numdisp.refresh ();
	_curspl.refresh ();
	_menubar.refresh ();
	_icons.refresh ();
	_vumetres.refresh ();
	_menus.refresh ();
}



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

void	SplEdMainLoop::refresh_dynamic (bool force_flag)
{
	_window.refresh_dynamic (force_flag);
	_numdisp.refresh_dynamic (force_flag);
	_curspl.refresh_dynamic (force_flag);
	_menubar.refresh_dynamic (force_flag);
	_icons.refresh_dynamic (force_flag);
	_vumetres.refresh_dynamic (force_flag);
	_menus.refresh_dynamic (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	SplEdMainLoop::manage (int sel_object, int sel_elder)
{
	RSC_gere_resource (RSC_OBJ_SE_MAIN, &sel_object, &sel_elder);
	if (sel_object >= 0)
	{
		_window.manage (sel_object, sel_elder);
		return;
	}

	RSC_gere_resource (RSC_OBJ_SE_NUMDISP, &sel_object, &sel_elder);
	if (sel_object >= 0)
	{
		_numdisp.manage (sel_object, sel_elder);
		return;
	}

	RSC_gere_resource (RSC_OBJ_SE_CURSPL, &sel_object, &sel_elder);
	if (sel_object >= 0)
	{
		_curspl.manage (sel_object, sel_elder);
		return;
	}

	RSC_gere_resource (RSC_OBJ_SE_MENUBAR, &sel_object, &sel_elder);
	if (sel_object >= 0)
	{
		_menubar.manage (sel_object, sel_elder);
		return;
	}

	RSC_gere_resource (RSC_OBJ_SE_ICN, &sel_object, &sel_elder);
	if (sel_object >= 0)
	{
		_icons.manage (sel_object, sel_elder);
		return;
	}

	RSC_gere_resource (RSC_OBJ_SE_VU, &sel_object, &sel_elder);
	if (sel_object >= 0)
	{
		_vumetres.manage (sel_object, sel_elder);
		return;
	}

	RSC_gere_resource (RSC_OBJ_SE_MENUS, &sel_object, &sel_elder);
	if (sel_object >= 0)
	{
		_menus.manage (sel_object, sel_elder);
		return;
	}

	_window.refresh_dynamic (false);
	_numdisp.refresh_dynamic (false);
	_curspl.refresh_dynamic (false);
	_menubar.refresh_dynamic (false);
	_icons.refresh_dynamic (false);
	_vumetres.refresh_dynamic (false);
	_menus.refresh_dynamic (false);
}



int	SplEdMainLoop::get_width (void)
{
	return (RSC_get_width (RSC_OBJ_SE));
}



int	SplEdMainLoop::get_height (void)
{
	return (RSC_get_height (RSC_OBJ_SE));
}



void	SplEdMainLoop::set_width (int width)
{
	RSC_set_width (RSC_OBJ_SE, width);
}



void	SplEdMainLoop::set_height (int height)
{
	RSC_set_height (RSC_OBJ_SE, height);
}



void	SplEdMainLoop::pack (void)
{
	int		width;
	int		height;
	int		win_width;
	int		win_height;

	/* Fixe les dimensions de la fenetre et des vumetres */
	_window.set_width (150);
	_window.set_height (150);
	_vumetres.set_height (150);

	get_node_dimensions (&_list_array [0], width, height, 0);
	win_height = get_height () - (height - 150);

	get_node_dimensions (&_list_array [1], width, height, 1);
	win_width = get_width () - (width - 150);

	_window.set_width (win_width);
	_window.set_height (win_height);
	_vumetres.set_height (win_height);

	/* Maintenant on pack */
	pack_recursive (&_list_array [0], 0, 0, 0);
}


void	SplEdMainLoop::get_node_dimensions (List *list_ptr, int &width, int &height, int level)
{
	SplEdMainLoop_PACK_NODE	*node_ptr;
	int		cur_width;
	int		cur_height;

	width = 0;
	height = 0;

	while (! list_ptr->is_empty ())
	{
		node_ptr = (SplEdMainLoop_PACK_NODE *) list_ptr->get (0);

		if (node_ptr->type == SplEdMainLoop_NODE_TYPE_LIST)
		{
			get_node_dimensions (node_ptr->data.list_ptr, cur_width, cur_height, level + 1);
		}
		else
		{
			cur_width = node_ptr->data.comp_ptr->get_width ();
			cur_height = node_ptr->data.comp_ptr->get_height ();
		}

		if (level & 1)
		{
			width += cur_width;
			height = MAX (height, cur_height);
		}
		else
		{
			width = MAX (width, cur_width);
			height += cur_height;
		}

		list_ptr = &list_ptr->next ();
	}
}



void	SplEdMainLoop::pack_recursive (List *list_ptr, int x, int y, int level)
{
	SplEdMainLoop_PACK_NODE	*node_ptr;
	int		cur_width;
	int		cur_height;

	while (! list_ptr->is_empty ())
	{
		node_ptr = (SplEdMainLoop_PACK_NODE *) list_ptr->get (0);

		if (node_ptr->type == SplEdMainLoop_NODE_TYPE_LIST)
		{
			pack_recursive (node_ptr->data.list_ptr, x, y, level + 1);
			get_node_dimensions (node_ptr->data.list_ptr, cur_width, cur_height, level + 1);
		}
		else
		{
			node_ptr->data.comp_ptr->move_to (x, y);
			cur_width = node_ptr->data.comp_ptr->get_width ();
			cur_height = node_ptr->data.comp_ptr->get_height ();
		}

		if (level & 1)
		{
			x += cur_width;
		}
		else
		{
			y += cur_height;
		}

		list_ptr = &list_ptr->next ();
	}
}



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



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



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