// K-3D
// Copyright (c) 1995-2004, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// 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

/** \file
		\brief Implements the k3dUserInterfaceElement class, which provides a standard command-handling for GTK+ controls / dialogs / windows
		\author Tim Shead (tshead@k-3d.com)
*/

#include "bitmap_preview.h"
#include "button.h"
#include "check_button.h"
#include "chooser.h"
#include "color_chooser.h"
#include "combo_box.h"
#include "edit_control.h"
#include "orientation.h"
#include "k3duserinterfaceelement.h"
#include "menu_item.h"
#include "object_chooser.h"
#include "path_chooser.h"
#include "position.h"
#include "property_button.h"
#include "scale.h"
#include "spin_button.h"
#include "toggle_button.h"

#include <k3dsdk/application.h>
#include <k3dsdk/icommand_tree.h>
#include <k3dsdk/ioptions.h>

k3dUserInterfaceElement::k3dUserInterfaceElement(k3d::iunknown* ParentCommandNode, const std::string& CommandNodeName) :
	k3d::command_node(CommandNodeName)
{
	// Add ourselves to the command tree ...
	k3d::icommand_node* const parent = dynamic_cast<k3d::icommand_node*>(ParentCommandNode);
	return_if_fail(parent);
	k3d::application().command_tree().add_node(*this, *parent);
}

k3dUserInterfaceElement::~k3dUserInterfaceElement()
{
	// Remove ourselves from the command tree ...
	k3d::application().command_tree().remove_node(*this);
}

bool k3dUserInterfaceElement::execute_command(const std::string& Command, const std::string& Arguments)
{
	// If this is a highlight action ...
	if(Command == "highlight")
		{
			if(Arguments.size())
				{
					InteractiveHighlight(Arguments.c_str(), k3d::application().options().tutorial_speed(), true);
				}
			else
				{
					RootWidget().InteractiveShow(k3d::application().options().tutorial_speed(), true);
					RootWidget().InteractiveHighlight(k3d::application().options().tutorial_speed(), true);
				}
			return true;
		}

	return k3d::command_node::execute_command(Command, Arguments);
}

sdpGtkObject* k3dUserInterfaceElement::CreateCustomObject(sdpxml::Element& Element)
{
	// Sanity checks ...
	if(Element.Name() == "k3dbitmappreview")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);
			return new k3d::bitmap_preview::control(this, name);
		}
	else if(Element.Name() == "k3dbutton")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);
			return new k3d::button::control(this, name);
		}
	else if(Element.Name() == "k3dcheckbutton")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::check_button::control(this, name);
		}
	else if(Element.Name() == "k3dcombobox")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::combo_box::control(this, name);
		}
	else if(Element.Name() == "k3dpropertychannelbutton")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::property_button::control(this, name);
		}
	else if(Element.Name() == "k3dchooser")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::chooser::control(this, name);
		}
	else if(Element.Name() == "k3dcolorchooser")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::color_chooser::control(this, name);
		}
	else if(Element.Name() == "k3deditcontrol")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::edit_control::control(this, name);
		}
	else if(Element.Name() == "k3dmenuitem")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);
			return new k3d::menu_item::control(this, name);
		}
	else if(Element.Name() == "k3dobjectchooser")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::object_chooser::control(this, name);
		}
	else if(Element.Name() == "k3dpathchooser")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);
			return new k3d::path_chooser::control(this, name);
		}
	else if(Element.Name() == "k3dspinbutton")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::spin_button::control(this, name);
		}
	else if(Element.Name() == "k3dpositioncontrol")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::position::control(this, name);
		}
	else if(Element.Name() == "k3dorientationcontrol")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::orientation::control(this, name);
		}
	else if(Element.Name() == "k3dscalecontrol")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::scale::control(this, name);
		}
	else if(Element.Name() == "k3dtogglebutton")
		{
			std::string name;
			return_val_if_fail(sdpxml::ParseAttribute(Element, "name", name), 0);

			return new k3d::toggle_button::control(this, name);
		}

	return sdpGtkObjectContainer::CreateCustomObject(Element);
}

k3d::button::control* k3dUserInterfaceElement::get_button(const std::string& Name)
{
	return dynamic_cast<k3d::button::control*>(CustomObject(Name.c_str()));
}

k3d::bitmap_preview::control* k3dUserInterfaceElement::get_bitmap_preview(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dbitmappreview", 0);

	return static_cast<k3d::bitmap_preview::control*>(object);
}

k3d::check_button::control* k3dUserInterfaceElement::get_check_button(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dcheckbutton", 0);

	return static_cast<k3d::check_button::control*>(object);
}

k3d::property_button::control* k3dUserInterfaceElement::get_property_button(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dpropertychannelbutton", 0);

	return static_cast<k3d::property_button::control*>(object);
}

k3d::chooser::control* k3dUserInterfaceElement::get_chooser(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dchooser", 0);

	return static_cast<k3d::chooser::control*>(object);
}

k3d::combo_box::control* k3dUserInterfaceElement::get_combo_box(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dcombobox", 0);

	return static_cast<k3d::combo_box::control*>(object);
}

k3d::color_chooser::control* k3dUserInterfaceElement::get_color_chooser(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dcolorchooser", 0);

	return static_cast<k3d::color_chooser::control*>(object);
}

k3d::menu_item::control* k3dUserInterfaceElement::get_menu_item(const std::string& Name)
{
	return dynamic_cast<k3d::menu_item::control*>(CustomObject(Name.c_str()));
}

k3d::object_chooser::control* k3dUserInterfaceElement::get_object_chooser(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dobjectchooser", 0);

	return static_cast<k3d::object_chooser::control*>(object);
}

k3d::spin_button::control* k3dUserInterfaceElement::get_spin_button(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dspinbutton", 0);

	return static_cast<k3d::spin_button::control*>(object);
}

k3d::position::control* k3dUserInterfaceElement::get_position_control(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dpositioncontrol", 0);

	return static_cast<k3d::position::control*>(object);
}

k3d::orientation::control* k3dUserInterfaceElement::get_orientation_control(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dorientationcontrol", 0);

	return static_cast<k3d::orientation::control*>(object);
}

k3d::scale::control* k3dUserInterfaceElement::get_scale_control(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dscalecontrol", 0);

	return static_cast<k3d::scale::control*>(object);
}

k3d::toggle_button::control* k3dUserInterfaceElement::get_toggle_button(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dtogglebutton", 0);

	return static_cast<k3d::toggle_button::control*>(object);
}

k3d::path_chooser::control* k3dUserInterfaceElement::get_path_chooser(const std::string& Name)
{
	// Sanity checks ...
	assert_warning(Name.size());

	sdpGtkObject* object = CustomObject(Name.c_str());
	return_val_if_fail(object, 0);
	return_val_if_fail(object->CustomType() == "k3dpathchooser", 0);

	return static_cast<k3d::path_chooser::control*>(object);
}

bool k3dUserInterfaceElement::connect_check_button(const std::string& Name, std::auto_ptr<k3d::check_button::idata_proxy> Data, k3d::istate_recorder* const StateRecorder, const std::string& StateChangeName)
{
	k3d::check_button::control* const control = get_check_button(Name);
	return_val_if_fail(control, false);
	return_val_if_fail(control->attach(Data, StateRecorder, StateChangeName), false);
	return true;
}

bool k3dUserInterfaceElement::connect_color_chooser(const std::string& Name, std::auto_ptr<k3d::color_chooser::idata_proxy> Data, k3d::istate_recorder* const StateRecorder, const std::string& StateChangeName)
{
	k3d::color_chooser::control* const control = get_color_chooser(Name);
	return_val_if_fail(control, false);

	return_val_if_fail(control->attach(Data, StateRecorder, StateChangeName), false);

	return true;
}

bool k3dUserInterfaceElement::connect_property_button(const std::string& Name, std::auto_ptr<k3d::property_button::idata_proxy> Data, k3d::istate_recorder* const StateRecorder, const std::string& StateChangeName)
{
	k3d::property_button::control* const control = get_property_button(Name);
	return_val_if_fail(control, false);

	return_val_if_fail(control->attach(Data, StateRecorder, StateChangeName), false);

	return true;
}

bool k3dUserInterfaceElement::connect_spin_button(const std::string& Name, std::auto_ptr<k3d::spin_button::idata_proxy> Data, k3d::istate_recorder* const StateRecorder, const std::string& StateChangeName)
{
	k3d::spin_button::control* const control = get_spin_button(Name);
	return_val_if_fail(control, false);

	return_val_if_fail(control->attach(Data, StateRecorder, StateChangeName), false);

	return true;
}


