/*  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/box.h
//! @brief A GtkBox, GtkHBox and GtkVBox C++ wrapper interface.
//!
//! Box is an abstract widget which encapsulates functionallity for a particular kind of container,
//! one that organizes a variable number of widgets into a rectangular area. Box currently has two
//! derived classes, HBox and VBox.

#ifndef INTI_GTK_BOX_H
#define INTI_GTK_BOX_H

#ifndef INTI_GTK_CONTAINER_H
#include <inti/gtk/container.h>
#endif

#ifndef __GTK_HBOX_H__
#include <gtk/gtkhbox.h>
#endif

#ifndef __GTK_VBOX_H__
#include <gtk/gtkvbox.h>
#endif

namespace Inti {

namespace Gtk {

class BoxClass;
class HBoxClass;
class VBoxClass;

//! @class BoxChild box.h inti/gtk/box.h
//! @brief A GtkBoxChild C++ wrapper class.
//!
//! The BoxChild holds a child widget of Box and describes how the child is to be packed
//! into the Box. Use query_child_packing() and set_child_packing() to query and reset
//! the padding, expand, fill, and pack fields.

class BoxChild
{
	friend class none;

	BoxChild();
	BoxChild(const BoxChild&);
	BoxChild& operator=(const BoxChild&);
	
	GtkBoxChild child_;

public:
//! @name Accessors
//! @{

	GtkBoxChild* gtk_box_child() const { return const_cast<GtkBoxChild*>(&child_); }
	//!< Get a pointer to the GtkBoxChild structure.

	Widget* widget() const;
	//!< Gets the child widget, packed into the Box.
	//!< @return The child packed into the Box.
	//!< The returned widget does not have a reference added, so you do not need to unref it.

	bool expand() const { return child_.expand; }
	//!< Get the child widget expand flag.
	//!< @return <EM>true</EM> if extra space should be given to the child widget.
	//!<
	//!< <BR>The expand flag indicates whether extra space should be given to this child.
	//!< Any extra space given to the parent Box is divided up among all children with 
	//!< this attribute set to <EM>true</EM>; set when packed, <EM>true</EM> by default.

	bool fill() const { return child_.fill; }
	//!< Get the child widget fill flag.
	//! @return <EM>true</EM> if extra space given to this child is allocated to the child.
	//!<
	//!< <BR>Indicates whether any extra space given to this child due to its expand attribute
	//!< being set is actually allocated to the child, rather than being used as padding around
	//!< the widget; set when packed, true by default.

	unsigned int padding() const { return child_.padding; }
	//!< Gets the number of extra pixels to put between the child widget and its neighbors.
	//!< @return The number of extra pixels.
	//!<
	//!< <BR>The padding is the number of extra pixels between this child and its neighbors,
	//!< set when packed, zero by default.

	PackType pack() const { return (PackType)child_.pack; }
	//!< Gets the child widget PackType.
	//!< @return The PackType.
	//!<
	//!< <BR>The PackType indicates whether the child is packed with reference to the start
	//!< (top/left) or end (bottom/right) of the Box.

//! @}
};

//! @class Box box.h inti/gtk/box.h
//! @brief A GtkBox C++ wrapper class.
//!
//! Box is an abstract widget which encapsulates functionallity for a particular kind of container,
//! one that organizes a variable number of widgets into a rectangular area. Box currently has two
//! derived classes, HBox and VBox. The rectangular area of a Box is organized into either a single
//! row or a single column of child widgets depending upon whether the box is of type HBox or VBox,
//! respectively. Thus, all children of a Box are allocated one dimension in common, which is the
//! height of a row, or the width of a column.
//!
//! Box uses a notion of packing. Packing refers to adding widgets with reference to a particular
//! position in a Container. For a Box, there are two reference positions: the start and the end
//! of the box. For a VBox, the start is defined as the top of the box and the end is defined as
//! the bottom. For a HBox the start is defined as the left side and the end is defined as the
//! right side. Use repeated calls to pack_start() to pack widgets into a Box from start to end.
//! Use pack_end() to add widgets from end to start. You may intersperse these calls and add
//! widgets from both ends of the same Box.
//! 
//! Because Box is a Container, you may also use Gtk::Container::add() to insert widgets
//! into the box, and they will be packed as if with pack_start() using the default values:
//! expand true, fill true and padding zero. Use Gtk::Container::remove() to remove widgets
//! from the Box.
//! 
//! Use set_homogeneous() to specify whether or not all children of the Box are forced to
//! get the same amount of space. Use set_spacing() to determine how much space will be 
//! minimally placed between all children in the Box. Use reorder_child() to move a Box child 
//! to a different place in the box. Use set_child_packing() to reset the expand, fill, and
//! padding attributes of any Box child. Use query_child_packing() to query these fields.

class Box : public Container
{
	friend class G::Object;
	friend class BoxClass;

	Box(const Box&);
	Box& operator=(const Box&);
	
protected:
//! @name Constructors
//! @{

	Box();
	//!< Construct a new type of Box Widget.

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

	virtual ~Box() = 0;
	//!< Destructor.
	
//! @}
//  Properties

	typedef G::Property<int> SpacingPropertyType;
	typedef G::PropertyProxy<G::Object, SpacingPropertyType> SpacingPropertyProxy;
	static const SpacingPropertyType spacing_property;

	typedef G::Property<bool> HomogeneousPropertyType;
	typedef G::PropertyProxy<G::Object, HomogeneousPropertyType> HomogeneousPropertyProxy;
	static const HomogeneousPropertyType homogeneous_property;

	typedef Gtk::ChildProperty<bool> ExpandPropertyType;
	typedef Gtk::ChildPropertyProxy<Container, ExpandPropertyType> ExpandPropertyProxy;
	static const ExpandPropertyType expand_property;

	typedef Gtk::ChildProperty<bool> FillPropertyType;
	typedef Gtk::ChildPropertyProxy<Container, FillPropertyType> FillPropertyProxy;
	static const FillPropertyType fill_property;

	typedef Gtk::ChildProperty<unsigned int> PaddingPropertyType;
	typedef Gtk::ChildPropertyProxy<Container, PaddingPropertyType> PaddingPropertyProxy;
	static const PaddingPropertyType padding_property;

	typedef Gtk::ChildProperty<PackType, int> PackTypePropertyType;
	typedef Gtk::ChildPropertyProxy<Container, PackTypePropertyType> PackTypePropertyProxy;
	static const PackTypePropertyType pack_type_property;

	typedef Gtk::ChildProperty<int> PositionPropertyType;
	typedef Gtk::ChildPropertyProxy<Container, PositionPropertyType> PositionPropertyProxy;
	static const PositionPropertyType position_property;

public:
//! @name Accessors
//! @{

	GtkBox* gtk_box() const { return (GtkBox*)instance; }
	//!< Get a pointer to the GtkBox structure.

	GtkBoxClass* gtk_box_class() const;
	//!< Get a pointer to the GtkBoxClass structure.

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

	bool children(std::vector<BoxChild*>& child_list) const;
	//!< Get a list of children belonging to the Box.
	//!< @param child_list A reference to an empty vector of BoxChild* to hold the children.
	//!< @return <EM>true</EM> if successful, <EM>false</EM> otherwise.
	//!<
	//!< <BR>The data is a vector of BoxChild pointers. The returned children do not have
	//!< a reference added, so you do not need to unref them.

	bool get_homogeneous() const;
	//!< Returns whether the box is homogeneous (all children are the same size); see set_homogeneous().
	//!< @return <EM>true</EM> if the box is homogeneous.

	int get_spacing() const;
	//!< Gets the value set by set_spacing().
	//!< @return The spacing between children.
	
//! @}
//! @name Methods
//! @{

	void pack_start(Widget& child, bool expand = true, bool fill = true, unsigned int padding = 0);
	//!< Adds child to the box, packed with reference to the start of box.
	//!< @param child   The Widget to be added to the box.
	//!< @param expand  Set <EM>true</EM> if the new child is to be given extra space allocated to the box.
	//!<	            The extra space is divided evenly between all children of box using this option.
	//!< @param fill    Set <EM>true</EM> if space given to child by the expand option is actually allocated
	//!<                to the child, rather than just padding it. This parameter has no effect if expand
	//!<                is set to false. A child is always allocated the full height of a HBox and the
	//!<                full width of a VBox. This option affects the other dimension.
	//!< @param padding The extra space in pixels to put between this child and its neighbors, over
	//!<                and above the global amount specified by spacing in Box. If child is a widget
	//!<                at one of the reference ends of the box, then padding pixels are also put
	//!<                between child and the reference edge of box.
	//!<
	//!< <BR>The child is packed after any other child packed with reference to the start of box. The default
	//!< arguments specified are those most frequently used.
	
	void pack_end(Widget& child, bool expand = true, bool fill = true, unsigned int padding = 0);
	//!< Adds child to the box, packed with reference to the end of box.
	//!< @param child   The Widget to be added to the box.
	//!< @param expand  Set <EM>true</EM> if the new child is to be given extra space allocated to the box.
	//!<	            The extra space is divided evenly between all children of box using this option.
	//!< @param fill    Set <EM>true</EM> if space given to child by the expand option is actually allocated
	//!<                to the child, rather than just padding it. This parameter has no effect if expand
	//!<                is set to false. A child is always allocated the full height of a HBox and the
	//!<                full width of a VBox. This option affects the other dimension.
	//!< @param padding The extra space in pixels to put between this child and its neighbors, over
	//!<                and above the global amount specified by spacing in Box. If child is a widget
	//!<                at one of the reference ends of the box, then padding pixels are also put
	//!<                between child and the reference edge of box.
	//!<
	//!< <BR>The child is packed after (away from end of) any other child packed with reference to the
	//!< end of box. The default arguments specified are those most frequently used.

	void insert_start(Widget& child, int position, bool expand = true, bool fill = true, unsigned int padding = 0);
	//!< Inserts child into the box at <EM>position</EM>, with reference to the start of box.
	//!< @param child    The Widget to be added to the box.
	//!< @param position The new position for child at the start, starting from 0.
	//!< @param expand   Set <EM>true</EM> if the new child is to be given extra space allocated to the box.
	//!<	             The extra space is divided evenly between all children of box using this option.
	//!< @param fill     Set <EM>true</EM> if space given to child by the expand option is actually allocated
	//!<                 to the child, rather than just padding it. This parameter has no effect if expand
	//!<                 is set to false. A child is alwaHys allocated the full height of a HBox and the
	//!<                 full width of a VBox. This option affects the other dimension.
	//!< @param padding  The extra space in pixels to put between this child and its neighbors, over
	//!<                 and above the global amount specified by spacing in Box. If child is a widget
	//!<                 at one of the reference ends of the box, then padding pixels are also put
	//!<                 between child and the reference edge of box.
	//!<
	//!< <BR>This method is equivalent to calling pack_start() followed by reorder_child(). The default
	//!< arguments specified are those most frequently used. Setting <EM>position</EM> to -1 is the same as
	//!< calling pack_start(); the position argument is ignored.

	void insert_end(Widget& child, int position, bool expand = true, bool fill = true, unsigned int padding = 0);
	//!< Inserts child into the box at <EM>position</EM>, packed with reference to the end of box.
	//!< @param child    The Widget to be added to the box.
	//!< @param position The new position for child at the end, starting from 0.
	//!< @param expand   Set <EM>true</EM> if the new child is to be given extra space allocated to the box.
	//!<	             The extra space is divided evenly between all children of box using this option.
	//!< @param fill     Set <EM>true</EM> if space given to child by the expand option is actually allocated
	//!<                 to the child, rather than just padding it. This parameter has no effect if expand
	//!<                 is set to false. A child is always allocated the full height of a HBox and the
	//!<                 full width of a VBox. This option affects the other dimension.
	//!< @param padding  The extra space in pixels to put between this child and its neighbors, over
	//!<                 and above the global amount specified by spacing in Box. If child is a widget
	//!<                 at one of the reference ends of the box, then padding pixels are also put
	//!<                 between child and the reference edge of box.
	//!<
	//!< <BR>This method is equivalent to calling pack_end() followed by reorder_child(). The default
	//!< arguments specified are those most frequently used. Setting <EM>position</EM> to -1 is the same as
	//!< calling pack_end(); the position argument is ignored.

	void set_homogeneous(bool homogeneous);
	//!< Sets the homogeneous field of the Box, controlling whether or not all children of box
	//!< are given equal space in the box.
	//!< @param homogeneous A boolean value, <EM>true</EM> to create equal allotments, <EM>false</EM>
	//!< for variable allotments.

	void set_spacing(int spacing);
	//!< Sets the spacing field of the Box, which is the number of pixels to place between children of box.
	//!< @param spacing The number of pixels to put between children.

	void reorder_child(Widget& child, int position);
	//!< Moves child to a new position in the list of box children.	
	//!< @param child The Widget to move.
	//!< @param position The new position for child in the children list, starting from 0.
	//!<
	//!< <BR>The list is the children field of GtkBox, and contains both widgets packed Gtk::PACK_START
	//!< as well as widgets packed Gtk::PACK_END, in the order that these widgets were added to box. A
	//!< negative value indicates the end of the list. 
	//!<
	//!< A widget's position in the box children list determines where the widget is packed into box.
	//!< A child widget at some position in the list will be packed just after all other widgets of the
	//!< same packing type that appear earlier in the list.

	void query_child_packing(Widget& child, bool *expand, bool *fill, unsigned int *padding, PackType *pack_type) const;
	//!< Returns information about how child is packed into the box. 
	//!< @param child The Widget of the child to query.
	//!< @param expand The returned value of the expand field in BoxChild.
	//!< @param fill The returned value of the fill field in BoxChild.
	//!< @param padding The returned value of the padding field in BoxChild.
	//!< @param pack_type The returned value of the pack field in BoxChild.

	void set_child_packing(Widget& child, bool expand, bool fill, unsigned int padding, PackType pack_type);
	//!< Sets the way child is packed into the box.
	//!< @param child The Widget of the child to set.
	//!< @param expand The new value of the expand field in BoxChild.
	//!< @param fill The new value of the fill field in BoxChild.
	//!< @param padding The new value of the padding field in BoxChild.
	//!< @param pack_type The new value of the pack field in BoxChild.

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

	const SpacingPropertyProxy prop_spacing()
	{
		return SpacingPropertyProxy(this, &spacing_property);
	}
	//!< The amount of space between children (int : Read / Write).

	const HomogeneousPropertyProxy prop_homogeneous()
	{
		return HomogeneousPropertyProxy(this, &homogeneous_property);
	}
	//!< Whether the children should all be the same size (bool : Read / Write).

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

	const ExpandPropertyProxy prop_expand()
	{
		return ExpandPropertyProxy(this, &expand_property);
	}
	//!< Whether the child should receive extra space when the parent grows (bool : Read / Write).


	const FillPropertyProxy prop_fill()
	{
		return FillPropertyProxy(this, &fill_property);
	}
	//!< Whether extra space given to the child is allocated to the child or used as padding (bool : Read / Write).

	const PaddingPropertyProxy prop_padding()
	{

		return PaddingPropertyProxy(this, &padding_property);
	}
	//!< Extra space to put between the child and its neighbors, in pixels (unsigned int : Read / Write).

	const PackTypePropertyProxy prop_pack_type()
	{
		return PackTypePropertyProxy(this, &pack_type_property);
	}
	//!< Whether the child is packed with reference to the start or end of the parent (PackType : Read / Write).

	const PositionPropertyProxy prop_position()
	{
		return PositionPropertyProxy(this, &position_property);
	}
	//!< The index of the child in the parent (int : Read / Write).

//! @}

};

//! @class HBox box.h inti/gtk/box.h
//! @brief A GtkHBox C++ wrapper class.
//!
//! HBox is a container that organizes child widgets into a single row. All children are
//! allocated the same height. Use the Box packing interface to determine the arrangement,
//! spacing, width, and alignment of HBox children.

class HBox : public Box
{
	friend class G::Object;
	friend class HBoxClass;

	HBox(const HBox&);
	HBox& operator=(const HBox&);

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

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

//! @}

public:
//! @name Constructors
//! @{

	explicit HBox(bool homogeneous = false, int spacing = 0);
	//!< Construct a new HBox with the specified homogeneous and spacing values.
	//!< @param homogeneous Set <EM>true</EM> if all children are to be given equal space allotments.
	//!< @param spacing The number of pixels to place by default between children.

	virtual ~HBox();

	//!< Destructor.
	
//! @}
//! @name Accessors
//! @{

	GtkHBox* gtk_hbox() const { return (GtkHBox*)instance; }
	//!< Get a pointer to the GtkHBox structure.

	GtkHBoxClass* gtk_hbox_class() const;
	//!< Get a pointer to the GtkHBoxClass structure.

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

//! @}
};

//! @class VBox box.h inti/gtk/box.h
//! @brief A GtkVBox C++ wrapper class.
//!
//! VBox is a container that organizes child widgets into a single column. All children are
//! allocated the same width. Use the Box packing interface to determine the arrangement,
//! spacing, width, and alignment of VBox children.

class VBox : public Box
{
	friend class G::Object;
	friend class VBoxClass;

	VBox(const VBox&);
	VBox& operator=(const VBox&);

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

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

//! @}

public:
//! @name Constructors
//! @{

	explicit VBox(bool homogeneous = false, int spacing = 0);
	//!< Construct a new VBox with the specified homogeneous and spacing values.
	//!< @param homogeneous Set <EM>true</EM> if all children are to be given equal space allotments.
	//!< @param spacing The number of pixels to place by default between children.

	virtual ~VBox();
	//!< Destructor.
	
//! @}
//! @name Accessors
//! @{
	
	GtkVBox* gtk_vbox() const { return (GtkVBox*)instance; }
	//!< Get a pointer to the GtkVBox structure.

	GtkVBoxClass* gtk_vbox_class() const;
	//!< Get a pointer to the GtkVBoxClass structure.

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

//! @}
};

} // namespace Gtk

} // namespace Inti

#endif // INTI_GTK_BOX_H


