/* -*- Mode: C -*-
 * Canvas item with handles
 * Copyright (C) 1998 Free Software Foundation
 *
 * Developed by Havoc Pennington <hp@pobox.com>
 * Addtional enhancements/bugfixes Gregory McLean <gregm@comstar.net>
 *
 * 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
 */
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gnome.h>

#include "gnome-canvas-handled.h"
/****************************************************************************
 * Forward references.
 **/
static void gnome_canvas_handled_class_init (GnomeCanvasHandledClass *class);
static void gnome_canvas_handled_init       (GnomeCanvasHandled      *handled);
static void gnome_canvas_handled_destroy    (GtkObject            *object);
static void gnome_canvas_handled_set_arg    (GtkObject            *object,
					    GtkArg               *arg,
					    guint                 arg_id);
static void gnome_canvas_handled_get_arg    (GtkObject            *object,
					    GtkArg               *arg,
					    guint                 arg_id);
static void gnome_canvas_handled_realize (GnomeCanvasItem *item);

static void gnome_canvas_handled_unrealize   (GnomeCanvasItem *item);


static void gtk_marshal_NONE__DOUBLE_DOUBLE_DOUBLE_DOUBLE (GtkObject * object,
							   GtkSignalFunc func,
							   gpointer func_data,
							   GtkArg * args);

enum {
  ARG_0,
  ARG_SELECTED,
  ARG_SENSITIVE
};


enum {
  RESIZED,
  SELECTED,
  UNSELECTED,
  LAST_SIGNAL
};

static GnomeCanvasGroupClass *parent_class;

static gint handled_signals[LAST_SIGNAL] = { 0,0,0 };

GtkType
gnome_canvas_handled_get_type (void)
{
  static GtkType handled_type = 0;

  if (!handled_type) {
    GtkTypeInfo handled_info = {
      "GnomeCanvasHandled",
      sizeof (GnomeCanvasHandled),
      sizeof (GnomeCanvasHandledClass),
      (GtkClassInitFunc) gnome_canvas_handled_class_init,
      (GtkObjectInitFunc) gnome_canvas_handled_init,
      NULL, /* reserved_1 */
      NULL, /* reserved_2 */
      (GtkClassInitFunc) NULL
    };

    handled_type = gtk_type_unique (gnome_canvas_group_get_type (), &handled_info);
  }

  return handled_type;
}

static void
gnome_canvas_handled_class_init (GnomeCanvasHandledClass *klass)
{
  GtkObjectClass *object_class;
  GnomeCanvasItemClass *item_class;

  object_class = (GtkObjectClass *) klass;
  item_class = (GnomeCanvasItemClass *) klass;

  parent_class = gtk_type_class (gnome_canvas_group_get_type ());

  gtk_object_add_arg_type ("GnomeCanvasHandled::selected", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_SELECTED);
  gtk_object_add_arg_type ("GnomeCanvasHandled::sensitive", GTK_TYPE_BOOL, GTK_ARG_READWRITE, ARG_SENSITIVE);


  handled_signals[RESIZED] =
    gtk_signal_new ("resized",
		    GTK_RUN_LAST,
		    object_class->type,
		    GTK_SIGNAL_OFFSET (GnomeCanvasHandledClass, resized),
		    gtk_marshal_NONE__DOUBLE_DOUBLE_DOUBLE_DOUBLE,
		    GTK_TYPE_NONE, 4, 
		    GTK_TYPE_DOUBLE, GTK_TYPE_DOUBLE, 
		    GTK_TYPE_DOUBLE, GTK_TYPE_DOUBLE);

  handled_signals[SELECTED] =
    gtk_signal_new ("selected",
		    GTK_RUN_LAST,
		    object_class->type,
		    GTK_SIGNAL_OFFSET (GnomeCanvasHandledClass, selected),
		    gtk_marshal_NONE__NONE,
		    GTK_TYPE_NONE, 0);
  
  handled_signals[UNSELECTED] =
    gtk_signal_new ("unselected",
		    GTK_RUN_LAST,
		    object_class->type,
		    GTK_SIGNAL_OFFSET (GnomeCanvasHandledClass, unselected),
		    gtk_marshal_NONE__NONE,
		    GTK_TYPE_NONE, 0);

  gtk_object_class_add_signals (object_class, handled_signals, 
				LAST_SIGNAL);

  klass->resized          = NULL;
  klass->scale            = NULL;
  klass->size             = NULL;
  klass->selected         = NULL;
  klass->unselected       = NULL;
  klass->create           = NULL;
  klass->set_translucent  = NULL;

  item_class->realize     = gnome_canvas_handled_realize;
  item_class->unrealize   = gnome_canvas_handled_unrealize;

  object_class->destroy = gnome_canvas_handled_destroy;
  object_class->set_arg = gnome_canvas_handled_set_arg;
  object_class->get_arg = gnome_canvas_handled_get_arg;
}

static void
gnome_canvas_handled_init (GnomeCanvasHandled *handled)
{
  handled->handle_group = NULL;

  handled->selected  = FALSE;
  handled->sensitive = TRUE;
  handled->dragging  = FALSE;
}

static void
gnome_canvas_handled_destroy (GtkObject *object)
{
  GnomeCanvasHandled *handled;

  g_return_if_fail (object != NULL);
  g_return_if_fail (GNOME_IS_CANVAS_HANDLED (object));

  handled = GNOME_CANVAS_HANDLED (object);

  /* Someday useful? */

  if (GTK_OBJECT_CLASS (parent_class)->destroy)
    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
}

static void
gnome_canvas_handled_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
  GnomeCanvasItem *item;
  GnomeCanvasHandled *handled;
  gboolean need_reconf = FALSE;

  item = GNOME_CANVAS_ITEM (object);
  handled = GNOME_CANVAS_HANDLED (object);

  switch (arg_id) {
  case ARG_SELECTED:
    gnome_canvas_handled_set_selected(handled, GTK_VALUE_BOOL (*arg));
    break;
    
  case ARG_SENSITIVE:
    handled->sensitive = GTK_VALUE_BOOL (*arg);
    need_reconf = TRUE;
    break;

  default:
    g_warning("GnomeCanvasHandled got an unknown arg type.");
    break;
  }

}


static void
gnome_canvas_handled_get_arg (GtkObject *object, GtkArg *arg, guint arg_id)
{
  GnomeCanvasHandled *handled;

  handled = GNOME_CANVAS_HANDLED (object);

  switch (arg_id) {
  case ARG_SELECTED:
    GTK_VALUE_BOOL (*arg) = handled->selected;
    break;

  case ARG_SENSITIVE:
    GTK_VALUE_BOOL (*arg) = handled->sensitive;
    break;

  default:
    arg->type = GTK_TYPE_INVALID;
    break;
  }
}

static void
gnome_canvas_handled_realize (GnomeCanvasItem *item)
{
  GnomeCanvasHandled* handled = GNOME_CANVAS_HANDLED(item);

  if (GNOME_CANVAS_ITEM_CLASS(parent_class)->realize)
    (* GNOME_CANVAS_ITEM_CLASS(parent_class)->realize) (item);

}


static void 
gnome_canvas_handled_unrealize (GnomeCanvasItem *item)
{
  GnomeCanvasHandled* handled = GNOME_CANVAS_HANDLED(item);

  if (handled->selected)
    gnome_canvas_handled_set_selected(handled, FALSE);

  if (GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize)
    (* GNOME_CANVAS_ITEM_CLASS(parent_class)->unrealize) (item);
}


GnomeCanvasHandled* 
gnome_canvas_handled_create (GnomeCanvasGroup *parent, GdkEventButton* event, 
			     GtkType type, const char* first_arg_name, ...)
{
  GnomeCanvasHandled* retval;
  va_list ap;

  retval = GNOME_CANVAS_HANDLED(gtk_type_new(type));

  va_start(ap, first_arg_name);

  gnome_canvas_item_construct(GNOME_CANVAS_ITEM(retval), parent, 
			      first_arg_name, ap);

  va_end(ap);

  if (GNOME_CANVAS_HANDLED_CLASS(GTK_OBJECT(retval)->klass)->create) 
    (*GNOME_CANVAS_HANDLED_CLASS(GTK_OBJECT(retval)->klass)->create) 
      (retval, event);

  return retval;
}

void                
gnome_canvas_handled_set_selected (GnomeCanvasHandled* handled,
				   gboolean selected)
{
  gboolean changed;

  g_return_if_fail(GNOME_IS_CANVAS_HANDLED(handled));

  changed = (handled->selected != selected);

  handled->selected = selected;

  if (changed) 
    {
      gtk_signal_emit(GTK_OBJECT(handled), 
		      handled->selected ? 
		      handled_signals[SELECTED] : handled_signals[UNSELECTED]);
      
    }

}


void
gnome_canvas_handled_resized(GnomeCanvasHandled* handled,
			     double x1, double y1, double x2, double y2)
{
  gtk_signal_emit(GTK_OBJECT(handled),  
		  handled_signals[RESIZED],
		  x1, y1, x2, y2); 
}


void 
gnome_canvas_handled_scale(GnomeCanvasHandled* handled,
			   gdouble x1, gdouble y1,
			   gdouble x2, gdouble y2)

{
  g_return_if_fail(handled != NULL);

  if (GNOME_CANVAS_HANDLED_CLASS(GTK_OBJECT(handled)->klass)->scale) 
    (GNOME_CANVAS_HANDLED_CLASS(GTK_OBJECT(handled)->klass)->scale)(handled, x1, y1, x2, y2); 
  else {
    g_warning("Scaling not implemented for this item type");
  }
}


void gnome_canvas_handled_size (GnomeCanvasHandled* handled, 
				double* x1, double* y1, double* x2, double* y2)
{
  g_return_if_fail(handled != NULL);

  if (GNOME_CANVAS_HANDLED_CLASS(GTK_OBJECT(handled)->klass)->size) 
    (GNOME_CANVAS_HANDLED_CLASS(GTK_OBJECT(handled)->klass)->size)(handled, x1, y1, x2, y2); 
  else {
    g_warning("Size reporting not implemented for this item type");
  }
}

void    gnome_canvas_handled_set_translucent(GnomeCanvasHandled* handled,
					     gboolean translucency)
{
  g_return_if_fail(handled != NULL);

  if (GNOME_CANVAS_HANDLED_CLASS(GTK_OBJECT(handled)->klass)->set_translucent) 
    (GNOME_CANVAS_HANDLED_CLASS(GTK_OBJECT(handled)->klass)->set_translucent)(handled, translucency);
}


typedef void (*GtkSignal_NONE__DOUBLE_DOUBLE_DOUBLE_DOUBLE) (GtkObject * object,
							     gdouble arg1,
							     gdouble arg2,
							     gdouble arg3,
							     gdouble arg4,
							     gpointer user_data);

static void gtk_marshal_NONE__DOUBLE_DOUBLE_DOUBLE_DOUBLE (GtkObject * object,
							   GtkSignalFunc func,
							   gpointer func_data,
							   GtkArg * args)
{
  GtkSignal_NONE__DOUBLE_DOUBLE_DOUBLE_DOUBLE rfunc;
  rfunc = (GtkSignal_NONE__DOUBLE_DOUBLE_DOUBLE_DOUBLE) func;
  (*rfunc) (object,
	    GTK_VALUE_DOUBLE (args[0]),
	    GTK_VALUE_DOUBLE (args[1]),
	    GTK_VALUE_DOUBLE (args[2]),
	    GTK_VALUE_DOUBLE (args[3]),
	    func_data);
}

/* EOF */


