/*  Inti: Integrated Foundation Classes
 *  Copyright (C) 2002 The Inti Development Team.
 *  Copyright (C) 2000 Red Hat, Inc.
 *
 *  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/container.h
//! @brief A GtkContainer C++ wrapper interface.
//!
//! Provides Container, an abstract base class for widgets (parents) that contain other
//! widgets (children).

#ifndef INTI_GTK_CONTAINER_H
#define INTI_GTK_CONTAINER_H

#ifndef INTI_GTK_WIDGET_H
#include <inti/gtk/widget.h>
#endif

#ifndef __GTK_CONTAINER_H__
#include <gtk/gtkcontainer.h>
#endif

#ifndef INTI_SLOT_H
#include <inti/slot.h>
#endif

#ifndef INTI_GTK_CHILD_PROPERTY_H
#include <inti/gtk/childproperty.h>
#endif

namespace Inti {

namespace Gtk {

class ContainerClass;

//! @class Container container.h inti/gtk/container.h
//! @brief A GtkContainer C++ wrapper class.
//!
//! Container is a base class for widgets (parents) that contain other widgets (children).
//! Container is responsible for managing the parent-child relationship. There are several
//! types of containers, some having only one child and others having several. Some
//! containers with only one child derive from Bin (Window, Button, Frame, HandleBox),
//! while others with several children derive from Box (HBox, VBox), MenuShell (Menu,
//! MenuBar) and Paned (HPaned, VPaned). Other containers with several children include
//! Fixed, Layout, Notebook, Table and Toolbar.

class Container : public Widget
{
	friend class G::Object;
	friend class ContainerClass;

	Container(const Container&);
	Container& operator=(const Container&);

protected:
//! @name Constructors
//! @{

	Container();
	//!< Construct a new derived container type.

	explicit Container(GtkContainer *container, bool reference = false);
	//!< Construct a new Container from an existing GtkContainer.
	//!< @param container A pointer to a GtkContainer.
	//!< @param reference Set false if the initial reference count is floating, set true if it's not.
	//!<
	//!< <BR>The <EM>container</EM> can be a newly created GtkContainer or an existing
	//!< GtkContainer. (see G::Object::Object).

//! @}
//  Override these do_ methods when you want to change the default behaviour of the GtkContainer.

	virtual void do_forall(bool include_internals, GtkCallback callback, void *callback_data);

	virtual GType do_child_type();

	virtual char* do_composite_name(GtkWidget *child);

	virtual void do_set_child_property(GtkWidget *child, unsigned int property_id, const GValue *value, GParamSpec *pspec);

	virtual void do_get_child_property(GtkWidget *child, unsigned int property_id, GValue *value, GParamSpec *pspec);

//! @name Signal Handlers
//! @{

	virtual void on_add(Widget& widget);
	//!< Called when a new child widget is added to the container.
	//!< @param widget The widget added to the container

	virtual void on_remove(Widget& widget);
	//!< Called when a child widget is removed from the container.
	//!< @param widget The widget removed from the container

	virtual void on_check_resize();
	//!< Called when a container needs to check whether it should resize or
	//!< when one of its children queues a resize request.
	//!< Only useful when writing a special custom widget.

	virtual void on_set_focus_child(Widget *widget);
	//!< Called when the container sets the focus on a child.
	//!< @param widget The widget that receives the focus.
	//!< Only useful when writing a special custom widget.

//! @}
//  Properties

	typedef G::Property<ResizeMode, int> ResizeModePropertyType;
	typedef G::PropertyProxy<G::Object, ResizeModePropertyType> ResizeModePropertyProxy;
	static const ResizeModePropertyType resize_mode_property;

	typedef G::Property<unsigned int> BorderWidthPropertyType;
	typedef G::PropertyProxy<G::Object, BorderWidthPropertyType> BorderWidthPropertyProxy;
	static const BorderWidthPropertyType border_width_property;

	typedef G::WritableProperty<Widget*, G::Object*> ChildPropertyType;
	typedef G::PropertyProxy<G::Object, ChildPropertyType> ChildPropertyProxy;
	static const ChildPropertyType child_property;

//  Signals

	typedef G::Signal1<void, GtkWidget*> AddSignalType;
	typedef G::SignalProxy<TypeInstance, AddSignalType> AddSignalProxy;
	static const AddSignalType add_signal;

	typedef G::Signal1<void, GtkWidget*> RemoveSignalType;
	typedef G::SignalProxy<TypeInstance, RemoveSignalType> RemoveSignalProxy;
	static const RemoveSignalType remove_signal;

	typedef G::Signal0<void> CheckResizeSignalType;
	typedef G::SignalProxy<TypeInstance, CheckResizeSignalType> CheckResizeSignalProxy;
	static const CheckResizeSignalType check_resize_signal;

	typedef G::Signal1<void, GtkWidget*> SetFocusChildSignalType;
	typedef G::SignalProxy<TypeInstance, SetFocusChildSignalType> SetFocusChildSignalProxy;
	static const SetFocusChildSignalType set_focus_child_signal;

public:
	typedef Slot1<void, Widget&> ForeachSlot;
	//!< Signature of the callback slot to be called for each widget in the container.
	//!<
	//!< <B>Example:</B> Method signature for ForeachSlot.
	//!< @code
	//!< void method(Widget& widget);
	//!<
	//!< // widget: The child widget.
	//!< @endcode

//! @name Constructors
//! @{
	
	virtual ~Container();
	//!< Destructor.

//! @}
//! @name Accessors
//! @{
	
	GtkContainer* gtk_container() const { return (GtkContainer*)instance; }
	//!< Get a pointer to the GtkContainer structure.

	GtkContainerClass* gtk_container_class() const;
	//!< Get a pointer to the GtkContainerClass structure.

	operator GtkContainer* () const;
	//!< Conversion operator; safely converts a Container to a GtkContainer pointer.

	bool is_resize_container() const;
	//!< Returns true if the resize request is handled by the container, and false if it's
	//!< passed to the container's parent (RESIZE_PARENT).

	GType child_type() const;
	//!< Returns the type of the children supported by the container.
	//!< @return A GType.
	//!<
	//!< <BR>Note that this may return G_TYPE_NONE to indicate that no more children can be
	//!< added, e.g. for a Gtk::Paned which already has two children.

	Widget* focus_child() const;
	//!< Returns the widget that currently has the focus set on it.
	
	bool get_children(std::vector<Widget*>& child_list) const;
	//!< Gets a list ot the container's non-internal children.
	//!< @param child_list A vector of Widget* to hold the list of the container's non-internal children.
	//!<
	//!< <BR>See foreach() for details on what constitutes an "internal" child.

	unsigned int get_border_width() const;
	//!< Retrieves the current border width of the container; see set_border_width().
	
	ResizeMode get_resize_mode() const;
	//!< Returns the resize mode for the container; see set_resize_mode().

	bool get_focus_chain(std::vector<Widget*>& focusable_widgets) const;
	//!< Retrieves the focus chain of the container, if one has been set explicitly.
	//!< @param focusable_widgets A vector of Widget* to store the focus chain of the container.
	//!< @return <EM>true</EM> if the focus chain of the container has been set explicitly.
	//!<
	//!< <BR>If no focus chain has been explicitly set, GTK+ computes the focus chain based on
	//!< the positions of the children. In that case, GTK+ stores null in focusable_widgets and
	//!< returns false. <EM>No additional reference count is added to the individual widgets in
	//!< the focus chain</EM>.

	Adjustment* get_focus_vadjustment() const;
	//!< Retrieves the vertical focus adjustment for the container; see set_focus_vadjustment().
	//!< @return The vertical focus adjustment, or null if none has been set.

	Adjustment* get_focus_hadjustment() const;
	//!< Retrieves the horizontal focus adjustment for the container; see set_focus_hadjustment().
	//!< @return The horizontal focus adjustment, or null if none has been set.

//! @}
//! @name Methods
//! @{

	void add(Widget& widget);
	//!< Adds widget to the container. 
	//!< @param widget A widget to be placed inside the container.
	//!<
	//!< <BR>Typically used for simple containers such as Window, Frame, or Button;
	//!< for more complicated layout containers such as Box or Table, this method 
	//!< will pick default packing parameters that may not be correct. So consider
	//!< methods such as Gtk::Box::pack_start() and Gtk::Table::attach() as an 
	//!< alternative to add() in those cases. A widget may be added to only one
	//!< container at a time; you can't place the same widget inside two different
	//!< containers.

	void remove(Widget& widget);
	//!< Removes widget from the container. 
	//!< @param widget A current child of the container.
	//!<
	//!< <BR>The widget must be inside container. Note that the container will own a reference
	//!< to widget, and that this may be the last reference held; so removing a widget from its
	//!< container can destroy that widget. If you want to use widget again, you need to add a
	//!< reference to it while it's not inside a container, using G::Object::ref().

	void check_resize();
	//!< Check whether the container should resize, and if so queue a resize request.
	//!< Only useful when writing a special custom widget.

	void set_focus_child(Widget& widget);
	//!< Sets the focus on a widget.
	//!< @param widget The widget that is to receive the focus.
	//!< Only useful when writing a special custom widget.

	void set_border_width(unsigned int border_width);
	//!< Sets the border width of the container.
	//!< @param border_width Amount of blank space to leave outside the container. Valid values
	//!<                     are in the range 0-65535 pixels.
	//!<
	//!< <BR>The border width of a container is the amount of space to leave around the outside
	//!< of the container. The only exception to this is Gtk::Window; because toplevel windows
	//!< can't leave space outside, they leave the space inside. The border is added on all 
	//!< sides of the container. To add space to only one side, one approach is to create an
	//!< Alignment widget, call Gtk::Widget::set_size_request() to give it a size, and place
	//!< it on the side of the container as a spacer.

	void set_resize_mode(ResizeMode resize_mode);
	//!< Sets the resize mode for the container.
	//!< @param resize_mode The new resize mode.
	//!<
	//!< <BR>The resize mode of a container determines whether a resize request will be passed
	//!< to the container's parent, queued for later execution or executed immediately.

	void foreach(const ForeachSlot *each);
	//!< Invokes the <EM>each</EM> slot on each non-internal child of the container.
	//!< @param each A ForeachSlot to call on each non-internal child of the container.
	//!<
	//!< <BR>"Internal" children generally weren't added by the user of the container, but were
	//!< added by the container implementation itself.

	void set_reallocate_redraws(bool needs_redraws);
	//!< Containers requesting reallocation redraws get automatically redrawn if any of their
	//!< children change their allocation.
	//!< @param needs_redraws The new value for the container's reallocate_redraws flag.

	void set_focus_vadjustment(Adjustment *adjustment);
	//!< Sets the vertical focus adjustment for the container.
	//!< @param adjustment The new vertical focus adjustment, or null.
	//!<
	//!< <BR>Updates the Adjustment to reflect the vertical position of the focused child,
	//!< according to the height of the container.

	void set_focus_hadjustment(Adjustment *adjustment);
	//!< Sets the horizontal focus adjustment for the container.
	//!< @param adjustment The new horizontal focus adjustment, or null.
	//!<
	//!< <BR>Updates the Adjustment to reflect the horizontal position of the focused child,
	//!< according to the width of the container.

	void resize_children();
	//!< Update the size and position of the child widgets.
	//!< Only useful when writing a special custom widget. Called after a size request to the
	//!< get the container to reallocate its size and position to reflect a change in the size
	//!< and position of its children.

	void propagate_expose(Widget& child, const Gdk::EventExpose& event);
	//!< When a container receives an expose event, it must send synthetic expose events to all
	//!< children that don't have their own Gdk::Windows.
	//!< @param child A child of the container.
	//!< @param event An expose event sent to the container.
	//!<
	//!< <BR>This method provides a convenient way of sending an expose event. A container,
	//!< when it receives an expose event, calls propagate_expose() once for each child,
	//!< passing in the event the container received. This method takes care of deciding
	//!< whether an expose event needs to be sent to the child, intersecting the event's
	//!< area with the child area, and sending the event. In most cases, a container can
	//!< simply override the inherited on_expose_event() implementation from Container.

	void set_focus_chain(const std::vector<Widget*>& focusable_widgets);
	//!< Sets a focus chain, overriding the one computed automatically by GTK+.
	//!< @param focusable_widgets A vector of Widgets to set as the new focus chain.
	//!<
	//!< <BR>In principle each widget in the chain should be a descendant of the container,
	//!< but this is not enforced by this method, since it's allowed to set the focus chain
	//!< before you pack the widgets, or have a widget in the chain that isn't always packed.
	//!< The necessary checks are done when the focus chain is actually traversed.

	void unset_focus_chain();
	//!< Removes a focus chain explicitly set with set_focus_chain().

//! @}
//! @name Property Proxies
//! @{

	const ResizeModePropertyProxy prop_resize_mode()
	{
		return ResizeModePropertyProxy(this, &resize_mode_property);
	}
	//!< Specify how resize events are handled (ResizeMode : Read / Write).

	const BorderWidthPropertyProxy prop_border_width()
	{
		return BorderWidthPropertyProxy(this, &border_width_property);
	}
	//!< The width of the empty border outside the containers children (unsigned int : Read / Write).

	const ChildPropertyProxy prop_child()
	{
		return ChildPropertyProxy(this, &child_property);
	}
	//!< Can be used to add a new child to the container (Widget* : Write).

//! @}
//! @name Signal Proxies
//! @{

	const AddSignalProxy sig_add()
	{
		return AddSignalProxy(this, &add_signal);
	}
	//!< Connect to the add_signal; emitted when a child widget is added to the container.

	const RemoveSignalProxy sig_remove()
	{
		return RemoveSignalProxy(this, &remove_signal);
	}
	//!< Connect to the remove_signal; emitted when a child widget is removed from the container.

	const CheckResizeSignalProxy sig_check_resize()
	{
		return CheckResizeSignalProxy(this, &check_resize_signal);
	}
	//!< Connect to the check_resize_signal; emitted when a container needs to check
	//!< whether it should resize or when one of its children queues a resize request.

	const SetFocusChildSignalProxy sig_set_focus_child()
	{
		return SetFocusChildSignalProxy(this, &set_focus_child_signal);
	}
	//!< Connect to the set_focus_child_signal; emitted when the container sets the focus on a child.

//! @}
};

} // namespace Gtk

} // namespace Inti

#endif // INTI_GTK_CONTAINER_H

