/* -*- mia-c++ -*-
 *
 * This file is part of viewitgui - a library and program for the
 * visualization of 3D data sets. 
 *
 * Copyright (c) Leipzig, Madrid 1999-2013 Mirco Hellmann, Gert Wollny
 *
 * viewitgui 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 3 of the License, or
 * (at your option) any later version.
 *
 * viewitgui 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 viewitgui; if not, see <http://www.gnu.org/licenses/>.
 */


#include "options_mesh.hh"
#include <gtkmm/frame.h>
#include <gtkmm/label.h>
#include <gtkmm/alignment.h>
#include <gtkmm/colorselection.h>


extern CEventQueue *pending_events;

///////////////////////////////////////////////////////////////////////////////
//
// Helper Class to show a color rectangle
//
///////////////////////////////////////////////////////////////////////////////


ColorRectangle::ColorRectangle(int x_size, int y_size, Gdk::Color color)
	: DrawingArea(), m_width(x_size), m_height(y_size), m_color(color)
{
	set_size_request(m_width, m_height);
}

void ColorRectangle::set_color(Gdk::Color color)
{
	m_color = color;
	on_expose_event(NULL);
}

Gdk::Color ColorRectangle::get_color() const
{
	return m_color;
}

bool ColorRectangle::on_expose_event(GdkEventExpose*)
{
	Glib::RefPtr<Gdk::Window> win = get_window();
	Glib::RefPtr<Gdk::GC> some_gc = Gdk::GC::create(win);
	
	get_default_colormap()->alloc_color(m_color);
	some_gc->set_foreground(m_color);
	some_gc->set_background(m_color);
	
	//Fill the area
	std::vector<Gdk::Point> some_points;
	some_points.push_back(Gdk::Point(0, 0));
	some_points.push_back(Gdk::Point(0, m_width-1));
	some_points.push_back(Gdk::Point(m_height-1, m_width-1));
	some_points.push_back(Gdk::Point(m_height-1, 0));
	win->draw_polygon(some_gc, true, some_points);

	return true;
}

///////////////////////////////////////////////////////////////////////////////
//
// Class GUI_Mesh
//
///////////////////////////////////////////////////////////////////////////////


GUI_Mesh::GUI_Mesh(Gtk::VBox *box) 
	: GUI_Drawable(box)
{
	event_t event;
	event.what = event_t::ev_command; 
	PEventInfo info(new TGLMeshEventInfo(EV_GLMESH_GET_STATE));
	event.info = info;
	pending_events->push(event);
	pending_events->handle_events();
	
	add_mesh_options(info);
	add_color_options(info);
}
	
void GUI_Mesh::add_mesh_options(PEventInfo pinfo) 
{

	const TGLMeshEventInfo& info = dynamic_cast<const TGLMeshEventInfo&>(*pinfo); 

	m_culled = Gtk::manage(new class Gtk::ToggleButton("Culling"));
	m_culled->set_flags(Gtk::CAN_FOCUS);
	m_culled->set_border_width(2);
	m_culled->set_relief(Gtk::RELIEF_NORMAL);
	m_culled->set_active(info.get_culling());
   
	m_glossy = Gtk::manage(new class Gtk::ToggleButton("Glossy"));
	m_glossy->set_flags(Gtk::CAN_FOCUS);
	m_glossy->set_border_width(2);
	m_glossy->set_relief(Gtk::RELIEF_NORMAL);
	m_glossy->set_active(info.get_draw_shiny());

	m_lightmodel = Gtk::manage(new class Gtk::ToggleButton("Lightmodel"));
	m_lightmodel->set_flags(Gtk::CAN_FOCUS);
	m_lightmodel->set_border_width(2);
	m_lightmodel->set_relief(Gtk::RELIEF_NORMAL);
	m_lightmodel->set_active(info.get_light_model());

	Gtk::VBox *buttonbox = Gtk::manage(new class Gtk::VBox(false, 0));
	buttonbox->pack_start(*m_culled, Gtk::PACK_SHRINK, 0);
	buttonbox->pack_start(*m_glossy, Gtk::PACK_SHRINK, 0);
	buttonbox->pack_start(*m_lightmodel, Gtk::PACK_SHRINK, 0);
   
	Gtk::RadioButton::Group RadioGroup;
	m_culled_front = Gtk::manage(new class Gtk::RadioButton(RadioGroup, "front face"));
	m_culled_front->set_flags(Gtk::CAN_FOCUS);
	m_culled_front->set_relief(Gtk::RELIEF_NORMAL);
	m_culled_front->set_mode(true);
	m_culled_front->set_active(info.get_front_face_culling());
	m_culled_front->set_sensitive(info.get_culling());
	
	m_culled_back = Gtk::manage(new class Gtk::RadioButton(RadioGroup, "back face"));
	m_culled_back->set_flags(Gtk::CAN_FOCUS);
	m_culled_back->set_relief(Gtk::RELIEF_NORMAL);
	m_culled_back->set_mode(true);
	m_culled_back->set_active(!info.get_front_face_culling());
	m_culled_back->set_sensitive(info.get_culling());
	
	Gtk::VBox *radiobox = Gtk::manage(new class Gtk::VBox(false, 0));
	radiobox->set_border_width(9);
	radiobox->pack_start(*m_culled_front, Gtk::PACK_EXPAND_PADDING, 0);
	radiobox->pack_start(*m_culled_back, Gtk::PACK_EXPAND_PADDING, 0);

   
	Gtk::HBox *mesh_box = Gtk::manage(new class Gtk::HBox(false, 0));
	mesh_box->set_border_width(2);
	
	Gtk::Label *mesh_frame_label = Gtk::manage(new class Gtk::Label("Mesh properties"));
	mesh_frame_label->set_alignment(0.5,0.5);
	mesh_frame_label->set_padding(0,0);
	mesh_frame_label->set_justify(Gtk::JUSTIFY_LEFT);
	mesh_frame_label->set_line_wrap(false);
	mesh_frame_label->set_use_markup(false);
	mesh_frame_label->set_selectable(false);
	mesh_box->pack_start(*buttonbox, Gtk::PACK_EXPAND_PADDING, 0);
	mesh_box->pack_start(*radiobox);

	Gtk::Frame *mesh_frame = Gtk::manage(new class Gtk::Frame());
	mesh_frame->set_border_width(10);
	mesh_frame->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
	mesh_frame->set_label_align(0,0.5);
	mesh_frame->add(*mesh_box);
	mesh_frame->set_label_widget(*mesh_frame_label);
   
	m_culled->show();
	m_glossy->show();
	m_lightmodel->show();
	mesh_box->show();
	buttonbox->show();
	radiobox->show();
	mesh_frame_label->show();
	mesh_frame->show();
	
	this->pack_start(*mesh_frame);

	m_culled->signal_toggled().connect(sigc::mem_fun(*this, &GUI_Mesh::on_m_culled_toggled));
	m_glossy->signal_toggled().connect(sigc::mem_fun(*this, &GUI_Mesh::on_m_glossy_toggled));
	m_lightmodel->signal_toggled().connect(sigc::mem_fun(*this, &GUI_Mesh::on_m_lightmodel_toggled));
	m_culled_front->signal_toggled().connect(sigc::mem_fun(*this, &GUI_Mesh::on_m_culled_front_toggled));
}


void GUI_Mesh::on_m_culled_front_toggled()
{
	event_t event;
	event.what = event_t::ev_command; 
	event.info = PEventInfo(new CEventInfo(EV_GLMESH_TOGGLE_FRONTFACECULLING));
	pending_events->push(event);
}


void GUI_Mesh::on_m_culled_toggled()
{
	event_t event;
	event.what = event_t::ev_command; 
	event.info = PEventInfo(new CEventInfo(EV_GLMESH_TOGGLE_CULLING));
	pending_events->push(event);

	m_culled_front->set_sensitive(m_culled->get_active());
	m_culled_back->set_sensitive(m_culled->get_active());
}


void GUI_Mesh::on_m_glossy_toggled()
{
	event_t event;
	event.what = event_t::ev_command; 
	event.info = PEventInfo(new CEventInfo(EV_GLMESH_TOGGLE_SHINY));
	pending_events->push(event);
}


void GUI_Mesh::on_m_lightmodel_toggled()
{
	event_t event;
	event.what = event_t::ev_command; 
	event.info = PEventInfo(new CEventInfo(EV_GLMESH_TOGGLE_LIGHTMODEL));
	pending_events->push(event);
}


void GUI_Mesh::reset()
{
	GUI_Drawable::reset();
	
	if (m_culled) {
		m_culled->set_active(true);
		m_culled_back->set_active(true);
	}
	
	if (m_glossy)
		m_glossy->set_active(false);
	
	if (m_lightmodel)
		m_lightmodel->set_active(true);
}

void GUI_Mesh::add_color_options(PEventInfo pinfo) 
{
	
	const TGLMeshEventInfo& info = dynamic_cast<const TGLMeshEventInfo&>(*pinfo); 

	if (!info.get_has_color()) return;
	TColor objcolor;
	Gdk::Color color;
	
	// color 1
	objcolor = info.get_color1();
	color.set_red(int(objcolor.x * 65535));
	color.set_green(int(objcolor.y * 65535));
	color.set_blue(int(objcolor.z * 65535));
	m_color1_area = Gtk::manage(new class ColorRectangle(20,20,color));
	m_color1_area->set_size_request(20,20);
	m_color1_area->set_flags(Gtk::CAN_FOCUS);
	m_color1_area->add_events(Gdk::BUTTON_PRESS_MASK);

	// color 2
	objcolor = info.get_color2();
	color.set_red(int(objcolor.x * 65535));
	color.set_green(int(objcolor.y * 65535));
	color.set_blue(int(objcolor.z * 65535));
	m_color2_area = Gtk::manage(new class ColorRectangle(20,20,color));
	m_color2_area->set_size_request(20,20);
	m_color2_area->set_flags(Gtk::CAN_FOCUS);
	m_color2_area->add_events(Gdk::BUTTON_PRESS_MASK);
	
	// color 3
	objcolor = info.get_color3();
	color.set_red(int(objcolor.x * 65535));
	color.set_green(int(objcolor.y * 65535));
	color.set_blue(int(objcolor.z * 65535));
	m_color3_area = Gtk::manage(new class ColorRectangle(20,20,color));
	m_color3_area->set_size_request(20,20);
	m_color3_area->set_flags(Gtk::CAN_FOCUS);
	m_color3_area->add_events(Gdk::BUTTON_PRESS_MASK);
	
	Gtk::HBox *color_selection_hbox = Gtk::manage(new class Gtk::HBox(false, 0));
	color_selection_hbox->pack_start(*m_color1_area, Gtk::PACK_EXPAND_WIDGET, 2);
	color_selection_hbox->pack_start(*m_color2_area, Gtk::PACK_EXPAND_WIDGET, 2);
	color_selection_hbox->pack_start(*m_color3_area, Gtk::PACK_EXPAND_WIDGET, 2);
	
	Gtk::Frame *color_selection_frame = Gtk::manage(new class Gtk::Frame());
	color_selection_frame->set_border_width(6);
	color_selection_frame->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
	color_selection_frame->set_size_request(-1,38);
	color_selection_frame->set_label_align(0,0.5);
	color_selection_frame->add(*color_selection_hbox);

	m_color_scale = Gtk::manage(new class Gtk::Button("Color scale"));
	m_color_scale->set_flags(Gtk::CAN_FOCUS);
	m_color_scale->set_border_width(6);
	m_color_scale->set_relief(Gtk::RELIEF_NORMAL);

	m_color_legend = Gtk::manage(new class Gtk::Button("Legend"));
	m_color_legend->set_flags(Gtk::CAN_FOCUS);
	m_color_legend->set_border_width(6);
	m_color_legend->set_relief(Gtk::RELIEF_NORMAL);

	Gtk::HBox *mesh_color_hbox = Gtk::manage(new class Gtk::HBox(false, 0));
	mesh_color_hbox->pack_start(*color_selection_frame, Gtk::PACK_SHRINK, 0);
	mesh_color_hbox->pack_start(*m_color_scale, Gtk::PACK_SHRINK, 0);
	mesh_color_hbox->pack_start(*m_color_legend, Gtk::PACK_SHRINK, 0);	
   
	Gtk::Label *colormesh_frame_label = Gtk::manage(new class Gtk::Label("Color propperties"));
	colormesh_frame_label->set_alignment(0.5,0.5);
	colormesh_frame_label->set_padding(0,0);
	colormesh_frame_label->set_justify(Gtk::JUSTIFY_LEFT);
	colormesh_frame_label->set_line_wrap(false);
	colormesh_frame_label->set_use_markup(false);
	colormesh_frame_label->set_selectable(false);

	Gtk::Frame *colormesh_frame = Gtk::manage(new class Gtk::Frame());
	colormesh_frame->set_border_width(6);
	colormesh_frame->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
	colormesh_frame->set_label_align(0,0.5);
	colormesh_frame->add(*mesh_color_hbox);
	colormesh_frame->set_label_widget(*colormesh_frame_label);
	
	m_color1_area->show();
	m_color2_area->show();
	m_color3_area->show();
	color_selection_hbox->show();
	color_selection_frame->show();
	m_color_scale->show();
	m_color_legend->show();
	mesh_color_hbox->show();
	colormesh_frame_label->show();
	colormesh_frame->show();	
	
	this->pack_start(*colormesh_frame);

 	m_color1_area->signal_button_press_event().connect(sigc::mem_fun(*this, &GUI_Mesh::on_color1_button_pressed));
 	m_color2_area->signal_button_press_event().connect(sigc::mem_fun(*this, &GUI_Mesh::on_color2_button_pressed));	
 	m_color3_area->signal_button_press_event().connect(sigc::mem_fun(*this, &GUI_Mesh::on_color3_button_pressed));
	m_color_scale->signal_clicked().connect(sigc::mem_fun(*this, &GUI_Mesh::on_m_color_scale_clicked));
	m_color_legend->signal_clicked().connect(sigc::mem_fun(*this, &GUI_Mesh::on_m_color_legend_clicked));	
}

bool GUI_Mesh::on_color1_button_pressed(GdkEventButton* event)
{
	Gtk::ColorSelectionDialog dialog;
	Gdk::Color m_Color = m_color1_area->get_color();
	
	//Set the current color:
	Gtk::ColorSelection* pColorSel = dialog.get_colorsel();
	pColorSel->set_current_color(m_Color);

	if (dialog.run() == Gtk::RESPONSE_OK) {
		event_t event;
		event.what = event_t::ev_command; 
		m_Color = pColorSel->get_current_color();
		TColor newcolor(m_Color.get_red(), m_Color.get_green(), m_Color.get_blue(), 0.0);
		newcolor /= 65535.0;
		newcolor.a = get_transparency();
		
		TGLMeshEventInfo *info = new TGLMeshEventInfo(EV_GLMESH_SET_COLOR1);
		info->set_color1(newcolor);
		event.info.reset(info);
		m_color1_area->set_color(m_Color); 
		pending_events->push(event);
	}
	return true; 
}

bool GUI_Mesh::on_color2_button_pressed(GdkEventButton* event)
{
	Gtk::ColorSelectionDialog dialog;
	Gdk::Color m_Color = m_color2_area->get_color();
	
	//Set the current color:
	Gtk::ColorSelection* pColorSel = dialog.get_colorsel();
	pColorSel->set_current_color(m_Color);

	if (dialog.run() == Gtk::RESPONSE_OK) {
		event_t event;
		event.what = event_t::ev_command; 
		m_Color = pColorSel->get_current_color();
		TColor newcolor(m_Color.get_red(), m_Color.get_green(), m_Color.get_blue(), 0.0);
		newcolor /= 65535.0;
		newcolor.a = get_transparency();
		
		TGLMeshEventInfo *info = new TGLMeshEventInfo(EV_GLMESH_SET_COLOR2);
		info->set_color2(newcolor);
		event.info.reset(info);
		m_color2_area->set_color(m_Color); 
		pending_events->push(event);
	}
	return true; 
}

bool GUI_Mesh::on_color3_button_pressed(GdkEventButton* event)
{
	Gtk::ColorSelectionDialog dialog;
	Gdk::Color m_Color = m_color3_area->get_color();
	
	//Set the current color:
	Gtk::ColorSelection* pColorSel = dialog.get_colorsel();
	pColorSel->set_current_color(m_Color);

	if (dialog.run() == Gtk::RESPONSE_OK) {
		event_t event;
		event.what = event_t::ev_command; 
		m_Color = pColorSel->get_current_color();
		TColor newcolor(m_Color.get_red(), m_Color.get_green(), m_Color.get_blue(), 0.0);
		newcolor /= 65535.0;
		newcolor.a = get_transparency();
		TGLMeshEventInfo *info = new TGLMeshEventInfo(EV_GLMESH_SET_COLOR3);
		info->set_color3(newcolor);
		event.info.reset(info);
		m_color3_area->set_color(m_Color); 
		pending_events->push(event);
	}
	return true; 
}

void GUI_Mesh::on_m_color_scale_clicked()
{
	event_t event;
	event.what = event_t::ev_command; 
	event.info = PEventInfo(new CEventInfo(EV_GLMESH_TOGGLE_COLORSCALE));
	pending_events->push(event);
}


void GUI_Mesh::on_m_color_legend_clicked()
{
	event_t event;
	event.what = event_t::ev_command; 
	event.info = PEventInfo(new CEventInfo(EV_GLMESH_SHOW_DECORATION));
	pending_events->push(event);
}
	
