/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/*
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
 */

/*
 * Modified by Paolo Bacchilega.
 * Modified by Gabriel de Perthuis.
 */


#include "gtkorientablebox.h"
#include "gtkhbox.h"
#include "gtkvbox.h"

#include <gdk/gdk.h>
#include "gtkintl.h"

enum {
	PROP_0,
	PROP_ORIENTATION
};

static void gtk_orientable_box_class_init    (GtkOrientableBoxClass   *klass);
static void gtk_orientable_box_init          (GtkOrientableBox        *box);
static void gtk_orientable_box_finalize      (GObject                  *box);
static void gtk_orientable_box_set_property (
	GObject *object,
	guint prop_id,
	const GValue *value,
	GParamSpec *pspec);
static void gtk_orientable_box_get_property (
	GObject *object,
	guint prop_id,
	GValue *value,
	GParamSpec *pspec);
static void gtk_orientable_box_size_request (
	GtkWidget *widget,
	GtkRequisition *requisition);
static void gtk_orientable_box_size_allocate (
	GtkWidget *widget,
	GtkAllocation *allocation);
static void gtk_orientable_box_orientation_changed (
	GtkOrientableBox* box,
	GtkOrientation orientation);

static GtkBoxClass *parent_class = NULL;
static guint orientation_changed_signal = 0;

struct _GtkOrientableBoxPrivate {
  GtkOrientation  orientation;
};


GType
gtk_orientable_box_get_type (void)
{
  static GType orientable_box_type = 0;

  if (!orientable_box_type)
    {
      static const GTypeInfo orientable_box_info =
      {
	sizeof (GtkOrientableBoxClass),
	NULL,		/* base_init */
	NULL,		/* base_finalize */
	(GClassInitFunc) gtk_orientable_box_class_init,
	NULL,		/* class_finalize */
	NULL,		/* class_data */
	sizeof (GtkOrientableBox),
	0,		/* n_preallocs */
	(GInstanceInitFunc) gtk_orientable_box_init,
      };

      orientable_box_type = g_type_register_static (GTK_TYPE_BOX, 
						     "GtkOrientableBox",
						     &orientable_box_info, 0);
    }
  
  return orientable_box_type;
}

static void
gtk_orientable_box_class_init (GtkOrientableBoxClass *klass)
{
	GObjectClass   *gobject_class;
	GtkWidgetClass *widget_class;

	parent_class = g_type_class_peek_parent (klass);

	klass->orientation_changed = gtk_orientable_box_orientation_changed;

	gobject_class = (GObjectClass*) klass;
	gobject_class->set_property = gtk_orientable_box_set_property;
	gobject_class->get_property = gtk_orientable_box_get_property;
	gobject_class->finalize = gtk_orientable_box_finalize;

	widget_class = (GtkWidgetClass*) klass;
	widget_class->size_request = gtk_orientable_box_size_request;
	widget_class->size_allocate = gtk_orientable_box_size_allocate;


	/**
	* GtkOrientableBox::orientation-changed:
	* @box: the object which emitted the signal
	* @orientation: the new #GtkOrientation of the box
	*
	* Emitted when the orientation of the box changes.
	*/
	orientation_changed_signal =
	g_signal_new ("orientation-changed",
		G_OBJECT_CLASS_TYPE (klass),
		G_SIGNAL_RUN_FIRST,
		G_STRUCT_OFFSET (GtkOrientableBoxClass, orientation_changed),
		NULL, NULL,
		g_cclosure_marshal_VOID__ENUM,
		G_TYPE_NONE, 1,
		GTK_TYPE_ORIENTATION);

	/* properties */
	g_object_class_install_property (gobject_class,
		PROP_ORIENTATION,
		g_param_spec_enum ("orientation",
			P_("Orientation"),
			P_("The orientation of the box"),
			GTK_TYPE_ORIENTATION,
			GTK_ORIENTATION_HORIZONTAL,
			G_PARAM_READWRITE));

}

static void
gtk_orientable_box_init (GtkOrientableBox *orientable_box)
{
  GtkOrientableBoxPrivate *priv;

  priv = g_new0 (GtkOrientableBoxPrivate, 1);
  orientable_box->priv = priv;
  priv->orientation = GTK_ORIENTATION_HORIZONTAL;
}

static void
gtk_orientable_box_finalize (GObject *object)
{
  GtkOrientableBox *orientable_box;

  orientable_box = GTK_ORIENTABLE_BOX (object);

  if (orientable_box->priv != NULL) {
    g_free (orientable_box->priv);
    orientable_box->priv = NULL;
  }

  G_OBJECT_CLASS (parent_class)->finalize (object);
}

GtkWidget*
gtk_orientable_box_new (gboolean homogeneous,
			 gint spacing,
			 GtkOrientation orientation)
{
  GtkOrientableBox *orientable_box;

  orientable_box = g_object_new (GTK_TYPE_ORIENTABLE_BOX, NULL);

  GTK_BOX (orientable_box)->spacing = spacing;
  GTK_BOX (orientable_box)->homogeneous = homogeneous ? TRUE : FALSE;

  orientable_box->priv->orientation = orientation;

  return GTK_WIDGET (orientable_box);
}


static void
gtk_orientable_box_set_property (
	GObject *object,
	guint prop_id,
	const GValue *value,
	GParamSpec *pspec)
{
  GtkOrientableBox *box = GTK_ORIENTABLE_BOX (object);

	if (prop_id  == PROP_ORIENTATION) {
		gtk_orientable_box_set_orientation (box, g_value_get_enum (value));
	} else {
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
	}
}

static void
gtk_orientable_box_get_property (
	GObject *object,
	guint prop_id,
	GValue *value,
	GParamSpec *pspec)
{
  GtkOrientableBox *box = GTK_ORIENTABLE_BOX (object);

	if (prop_id  == PROP_ORIENTATION) {
		g_value_set_enum (value, box->priv->orientation);
	} else {
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
	}
}

static GtkBoxClass* get_impl_class (GtkOrientableBox* box) {
	return GTK_BOX_CLASS (gtk_type_class (
		box->priv->orientation == GTK_ORIENTATION_HORIZONTAL ?
			GTK_TYPE_HBOX :
			GTK_TYPE_VBOX));
}

static void
gtk_orientable_box_size_request (GtkWidget *widget,
	GtkRequisition *requisition)
{
	GtkOrientableBox *orientable_box;
	orientable_box = GTK_ORIENTABLE_BOX (widget);
	GTK_WIDGET_CLASS (get_impl_class (orientable_box)) ->
		size_request (widget, requisition);
}

static void
gtk_orientable_box_size_allocate (GtkWidget *widget,
	GtkAllocation *allocation)
{
	GtkOrientableBox *orientable_box;
	orientable_box = GTK_ORIENTABLE_BOX (widget);
	GTK_WIDGET_CLASS (get_impl_class (orientable_box)) ->
		size_allocate (widget, allocation);
}

static void gtk_orientable_box_orientation_changed (
	GtkOrientableBox* box,
	GtkOrientation orientation) {
	if(box->priv->orientation == orientation)
		return;
	box->priv->orientation = orientation;
	gtk_widget_queue_resize (GTK_WIDGET (box));
	g_object_notify (G_OBJECT (box), "orientation");
}

GtkOrientation
gtk_orientable_box_get_orientation (GtkOrientableBox *box)
{
  g_return_val_if_fail (GTK_IS_ORIENTABLE_BOX (box), -1);
  return box->priv->orientation;
}

void
gtk_orientable_box_set_orientation (GtkOrientableBox *box,
				GtkOrientation     orientation)
{
  g_return_if_fail (GTK_IS_ORIENTABLE_BOX (box));
  g_signal_emit (box, orientation_changed_signal, 0, orientation);
}
