// 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 k3dDialog class, which provides a standard dialog implementation
		\author Tim Shead (tshead@k-3d.com)
*/

#include "gtkml.h"
#include "k3ddialog.h"
#include "keyboard.h"

#include <k3dsdk/application.h>
#include <k3dsdk/iuser_interface.h>
#include <k3dsdk/ioptions.h>
#include <k3dsdk/result.h>
#include <k3dui/keyboard.h>

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

namespace
{

void on_key_press_event(k3d::icommand_node& CommandNode, sdpGtkEvent& Event)
{
	sdpGtkEventWidgetKeyPressEvent& event = static_cast<sdpGtkEventWidgetKeyPressEvent&>(Event);
	event.SetResult(k3d::keyboard().event_signal().emit(CommandNode, k3d::convert(static_cast<GdkModifierType>(event.Event()->state)), event.Event()->keyval));
}

const std::string delete_event = "k3dDialog::delete";
const std::string configure_event = "k3dDialog::configure";
const std::string key_press_event = "k3dDialog::key_press_event";

} // namespace

k3dDialog::k3dDialog(k3d::iunknown* ParentCommandNode, const std::string& CommandNodeName, k3d::window_geometry_store* const GeometryStore) :
	base(ParentCommandNode, CommandNodeName),
	m_geometry_store(GeometryStore)
{
}

k3dDialog::~k3dDialog()
{
	// Make sure we're not modal ...
	if(IsModal())
		CancelModal();

	// No more events from this point forward ...
	DisconnectAllEvents();

	// Clean-up the GTK+ tree ...
	if(Root())
		RootWidget().Destroy();

	// Get rid of our widget pointers ...
	Clear();
}

bool k3dDialog::LoadGTKMLTemplate(std::istream& Stream, const std::string& StreamName)
{
	// Load the template ...
	return_val_if_fail(k3d::load_gtkml(Stream, StreamName, *this), false);

	// Map some default events ...
	return_val_if_fail(MapEvent("delete-event", delete_event, false, Root(), true), false);
	return_val_if_fail(MapEvent("configure-event", configure_event, false, Root(), true), false);
	return_val_if_fail(MapEvent("key-press-event", key_press_event, false, Root(), true), false);

	return true;
}

bool k3dDialog::LoadGTKMLTemplate(const boost::filesystem::path& Template)
{
	// Load the template ...
	const boost::filesystem::path template_file(k3d::preferred_language_template(k3d::dialog_template_path() / Template));
	return_val_if_fail(k3d::load_gtkml(template_file, *this), false);

	// Map some default events ...
	return_val_if_fail(MapEvent("delete-event", delete_event, false, Root(), true), false);
	return_val_if_fail(MapEvent("configure-event", configure_event, false, Root(), true), false);
	return_val_if_fail(MapEvent("key-press-event", key_press_event, false, Root(), true), false);

	return true;
}

void k3dDialog::restore_geometry()
{
	if(!m_geometry_store.get())
		return;
		
	int left = 0;
	int top = 0;
	unsigned int width = 0;
	unsigned int height = 0;
	if(!m_geometry_store->get_window_geometry(k3d::command_node_path(*this), left, top, width, height))
		return;
		
	RootWindow().SetDefaultSize(width, height);
	gdk_window_move_resize(static_cast<GtkWidget*>(RootWidget())->window, left, top, width, height);
}

void k3dDialog::Show()
{
	int left = 0;
	int top = 0;
	unsigned int width = 0;
	unsigned int height = 0;
	if(m_geometry_store.get() && m_geometry_store->get_window_geometry(k3d::command_node_path(*this), left, top, width, height))
		{	
			RootWindow().SetDefaultSize(width, height);
			RootWidget().Show();
			gdk_window_move_resize(static_cast<GtkWidget*>(RootWidget())->window, left, top, width, height);
		}
	else
		{
			RootWidget().Show();
		}
}

void k3dDialog::CloseDialog()
{
	delete this;
}

void k3dDialog::CallUpdateControls()
{
	BlockAllEvents();
	UpdateControls();
	UnblockAllEvents();
}

void k3dDialog::UpdateControls()
{
}

// Custom event handling ...
void k3dDialog::OnEvent(sdpGtkEvent* Event)
{
	// Sanity checks ...
	assert_warning(Event);

	if(Event->Name() == "ok")
		OnOK();
	else if(Event->Name() == "close")
		OnClose();
	else if(Event->Name() == delete_event)
		OnDelete(Event);
	else if(Event->Name() == configure_event)
		on_resize();
	else if(Event->Name() == key_press_event)
		on_key_press_event(*this, *Event);
	else
		base::OnEvent(Event);
}

// Called when the user hits the standard "OK" button ...
void k3dDialog::OnOK()
{
	CloseDialog();
}

// Called when the user hits the standard "Close" button ...
void k3dDialog::OnClose()
{
	CloseDialog();
}

void k3dDialog::OnDelete(sdpGtkEvent* Event)
{
	// Sanity checks ...
	assert_warning(Event);

	// Don't allow the GTK+ tree to go away just yet ...
	((sdpGtkEventWidgetDeleteEvent*)Event)->SetResult(true);

	// Turn it into a "close", instead ...
	OnClose();
}

void k3dDialog::on_resize()
{
	// Serialize our screen geometry (but not in batch mode, since it has a bad habit of trashing the user's stored settings) ...
	if(m_geometry_store.get() && k3d::application().user_interface() && (!k3d::application().user_interface()->batch_mode()))
		{
			int left = 0;
			int top = 0;
			gdk_window_get_root_origin(static_cast<GtkWidget*>(RootWidget())->window, &left, &top);

			int width = 0;
			int height = 0;
			gdk_window_get_size(static_cast<GtkWidget*>(RootWidget())->window, &width, &height);

			m_geometry_store->set_window_geometry(k3d::command_node_path(*this), left, top, width, height);
		}
}


