/*  Inti: Integrated Foundation Classes
 *  Copyright (C) 2002 The Inti Development Team.
 *
 *  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 Library General Public License for more details.
 *
 *  You should have received a copy of the GNU Library 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 inti/gtk/childproperty.h
//! @brief GtkContainer child properties C++ interface.
//!
//! The child property classes declared in this file are used by Inti to wrap the
//! GtkContainer child property system. Properties are object specific. For each
//! property, a class declares a protected static property that requires an object
//! pointer and a class specific public accessor function that passes the object
//! pointer for you. Most properties are readable and writable, but some one or the
//! other. You can tell if a property is readable and/or writable by its protected
//! declaration. To set a property you use its set() method. To get a property use
//! its get() method. It is unlikely you will ever need to use these property classes
//! yourself, unless your wrapping a new GTK+ C object. Usually you will use those
//! properties already implemented by Inti. Setting and getting object properties is
//! discussed in the <EM>Header Files</EM> section of the tutorial Introduction.

#ifndef INTI_GTK_CHILD_PROPERTY_H
#define INTI_GTK_CHILD_PROPERTY_H

#ifndef INTI_G_PROPERTY_H
#include <inti/glib/property.h>
#endif

#ifndef INTI_G_VALUE_H
#include <inti/glib/value.h>
#endif

namespace Inti {

namespace Gtk {

class Container;

/*  Gtk::ChildProperty (readable and writable)
 */

template<typename DataType, typename ValueType = DataType>
class ChildProperty : public G::PropertyBase
{
public:
	typedef DataType Data;

	ChildProperty(const char* name) : G::PropertyBase(name)
	{
	}

	void get(const Container *container, const Widget& child, DataType& data) const
	{
		GParamSpec *pspec = find_property(container, true);
		ValueType tmp_data = 0;
		if (pspec)
		{
			G::Value value(pspec);
			get_property(container, &child, value);
			value.get(tmp_data);
		}
		data = static_cast<DataType>(tmp_data);
	}

	void set(const Container *container, Widget& child, const DataType& data) const
	{
		GParamSpec *pspec = find_property(container, true);
		if (pspec)
		{
			G::Value value(pspec);
			value.set((ValueType)data);
			set_property(container, &child, value);
		}
	}
};

/*  Gtk::ReadableChildProperty (read only)
 */

template<typename DataType, typename ValueType = DataType>
class ReadableChildProperty : private ChildProperty<DataType, ValueType>
{
	typedef ChildProperty<DataType, ValueType> Base;

public:
	typedef DataType Data;
	
	using Base::get;

	ReadableChildProperty(const char *name) : Base(name)
	{
	}
};

/*  Gtk::WritableChildProperty (write only)
 */

template<typename DataType, typename ValueType = DataType>
class WritableChildProperty : private ChildProperty<DataType, ValueType>
{
	typedef ChildProperty<DataType, ValueType> Base;

public:
	typedef DataType Data;
	
	using Base::set;

	WritableChildProperty(const char *name) : Base(name)
	{
	}
};

/*  Gtk::ChildPropertyProxy
 */

template<typename ObjectType, typename PropertyType>
class ChildPropertyProxy : public G::PropertyProxyBase<ObjectType, PropertyType>
{
	typedef G::PropertyProxyBase<ObjectType, PropertyType> Base;

public:
	typedef typename PropertyType::Data DataType;

	ChildPropertyProxy(ObjectType *object, const PropertyType *property) : Base(object, property)
	{
	}

	void get(const Widget& child, DataType& data) const
	{
		this->property()->get(this->object(), child, data);
	}

	void set(Widget& child, const DataType& data) const
	{
		this->property()->set(this->object(), child, data);
	}
};

} // namespace Gtk

} // namespace Inti

#endif // INTI_GTK_CHILD_PROPERTY_H
