// 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 k3d::dynamic_menu, which encapsulates a dynamicly constructed menu
		\author Ed Millard (emillard@direcway.com)
		\author Tim Shead (tshead@k-3d.com)
*/

#include "dynamic_menu.h"

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

#include <sdpgtk/sdpgtkmenuitem.h>
#include <sdpgtk/sdpgtkutility.h>

namespace k3d
{

namespace dynamic_menu
{

/// For reasons not entirely clear to me, I had to reimplement this here - popup context menus seem to be "different" in some fundamental way
void InteractiveActivateMenuItem(sdpGtkMenuItem& Item, const gdouble Speed, const bool Pause)
{
	// Make our item visible ...
	Item.InteractiveShow(Speed, Pause);

	GtkMenuShell* const menu_shell = GTK_MENU_SHELL(static_cast<GtkWidget*>(Item)->parent);
	return_if_fail(menu_shell);

	// Make sure we let go of the pointer and keyboard ...
	gdk_pointer_ungrab (GDK_CURRENT_TIME);
	gdk_keyboard_ungrab (GDK_CURRENT_TIME);
				
	gtk_menu_shell_activate_item(menu_shell, Item, true);
	
	sdpGtkHandlePendingEvents();
}

class item::implementation :
	public sdpGtkMenuItem,
	public icommand_node
{
public:
	implementation() :
		parent(0),
		signal_handle(0)
	{
		Create();
		Show();
	}

	implementation(const std::string& Label, const slot_t& Slot) :
		parent(0),
		slot(Slot),
		signal_handle(0)
	{
		Create(Label.c_str());
		Show();
		
		signal_handle = gtk_signal_connect(*this, "activate", reinterpret_cast<GtkSignalFunc>(activate), reinterpret_cast<gpointer>(this));
	}
	
	implementation(icommand_node* const Parent, const std::string Name, const std::string& Label, const slot_t& Slot) :
		parent(Parent),
		name(Name),
		slot(Slot),
		signal_handle(0)
	{
		Create(Label.c_str());
		Show();
		
		signal_handle = gtk_signal_connect(*this, "activate", reinterpret_cast<GtkSignalFunc>(activate), reinterpret_cast<gpointer>(this));
	
		if(parent)
			application().command_tree().add_node(*this, *parent);
	}
	
	implementation(const std::string& Label, sdpGtkMenu& SubMenu) :
		parent(0),
		signal_handle(0)
	{
		Create(Label.c_str());
		Show();

		SetSubmenu(GTK_WIDGET(static_cast<GtkMenu*>(SubMenu)));
	}
	
	~implementation()
	{
		if(parent)
			application().command_tree().remove_node(*this);
	
#ifdef K3D_HAVE_GTK2
		if(signal_handle)
			gtk_signal_disconnect(static_cast<GtkMenuItem*>(*this), signal_handle);
#else
		if(signal_handle)
			gtk_signal_disconnect(*this, signal_handle);
#endif
		Destroy();
	}

	const std::string command_node_name()
	{
		return name;
	}
	
	const commands_t commands()
	{
		return commands_t();
	}
	
	bool execute_command(const std::string& Command, const std::string& Arguments)
	{
		if(Command == "activate")
			{
				InteractiveActivateMenuItem(*this, k3d::application().options().tutorial_speed(), true);
				return true;
			}
			
		return false;
	}

private:
	void on_activate()
	{
		if(parent)
			k3d::record_command(*this, k3d::icommand_node::command_t::USER_INTERFACE, "activate");

		slot();
	}
	
	static void activate(GtkMenuItem*, gpointer Data)
	{
		reinterpret_cast<implementation*>(Data)->on_activate();
	}

	icommand_node* const parent;
	const std::string name;
	item::slot_t slot;
	guint signal_handle;
};

//////////////////////////////////////////////////////////////////////////////////
// item

item::item() :
	m_implementation(new implementation())
{
}

item::item(const std::string& Label, const slot_t& Slot) :
	label(Label),
	m_implementation(new implementation(Label, Slot))
{
}

item::item(icommand_node* const Parent, const std::string& Name, const std::string& Label, const slot_t& Slot) :
	label(Label),
	m_implementation(new implementation(Parent, Name, Label, Slot))
{
}

item::item(const std::string& Label, sdpGtkMenu& SubMenu) :
	label(Label),
	m_implementation(new implementation(Label, SubMenu))
{
}

item::operator GtkWidget*() const
{
	return *m_implementation;
}

} // namespace dynamic_menu

} // namespace k3d

