
/*
 * canvasRE.c --
 *
 * This file implements the rectangle and ellipse item of the canvas widget
 *
 * Copyright (c) 2001 - 2002 P.G. Baum
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 *
 */

/*
   History:
   2001-05: added rectangle and renamed file canvasEllipse.c to canvasRE.c 
   2001-04: Begin of developement
 */

#include "canvas.h"
#include <string.h>
#include <assert.h>


typedef struct
{
   Gnocl_ListBool   coords;
   Gnocl_BoolBool   centerRadius;  
   Gnocl_DoubleBool width;
   Gnocl_ObjBool fill;
   Gnocl_ObjBool outline;
} REParams;

static const GnoclWidgetOptions reOptions[] = 
{
   { "-coords", GNOCL_LIST, GNOCL_OFFSET( REParams, coords ) },
   { "-centerRadius", GNOCL_BOOL, GNOCL_OFFSET( REParams, centerRadius ) },
   { "-width", GNOCL_DOUBLE, GNOCL_OFFSET( REParams, width ) },
   { "-fill", GNOCL_OBJ, GNOCL_OFFSET( REParams, fill ) },
   { "-outline", GNOCL_OBJ, GNOCL_OFFSET( REParams, outline ) },
   { NULL, 0, 0 }
};

static int freeParams( REParams *params )
{
   #if 0
   /* since coords.val = obj[x] no decr necessary */
   #endif
   GNOCL_FREE_TCL_OPT( params->coords );
   GNOCL_FREE_TCL_OPT( params->fill );
   GNOCL_FREE_TCL_OPT( params->outline );

   return 0;
}

static int canvasDeleteRE( Tcl_Interp *interp, 
      Gnocl_CanvasItemInfo *info )
{
   /* no internal params, so no need to free anything */
   return 0;
}

static int setParams( Tcl_Interp *interp, REParams *params,
      Gnocl_CanvasItemInfo *info )
{
   if( params->coords.val )
   {
      double coords[4];
      int   noCoords;
      int   n;
      int ret = Tcl_ListObjLength( interp, params->coords.val, &noCoords );
      
      if( ret == TCL_OK && params->centerRadius.changed == 0 )
         params->centerRadius.val = 1;

      if( ret != TCL_OK || !( noCoords == 4  
                  || ( params->centerRadius.val && noCoords == 3 ) ) )
      {
         Tcl_SetResult( interp, 
               "list-of-coordinates must contain "
               "3 (if centerRadius) or 4 elements", TCL_STATIC );
printf( "list-of-coordinates noCoords: %d %p\n", noCoords, interp );
         return TCL_ERROR;
      }
      for( n = 0; n < noCoords; ++n )
      {
         Tcl_Obj *tp;
         if( Tcl_ListObjIndex( interp, params->coords.val, n, &tp ) != TCL_OK 
               || Tcl_GetDoubleFromObj( interp, tp, &coords[n] ) != TCL_OK )
         {
printf( "in n = %d\n", n );
            return TCL_ERROR;
         }
      }
      if( params->centerRadius.val )
      {
         double x = coords[0];
         double y = coords[1];
         double rx = coords[2];
         double ry = (noCoords == 3) ? rx : coords[3];
         coords[0] = x - rx;  /* FIXME: offset .5 ? */
         coords[1] = y - ry;
         coords[2] = x + rx;
         coords[3] = y + ry;
      }
      gnome_canvas_item_set( info->item, 
         "x1", coords[0],
         "y1", coords[1],
         "x2", coords[2],
         "y2", coords[3],
         NULL );
   }

   /*
   if( params->fill.changed )
      gnome_canvas_item_set( info->item, 
            "fill_color", params->fill.val, NULL );

   if( params->outline.changed )
      gnome_canvas_item_set( info->item, 
            "outline_color", params->outline.val, NULL );
   */
   if( params->fill.changed )
   {
      GdkColor color;
      int      alpha;
      if( gnoclGetGdkColorAlloc( interp, params->fill.val, 
            GTK_WIDGET( info->canvas ), &color, &alpha ) != TCL_OK )
         return TCL_ERROR;
      if( alpha == 0 )
         gnome_canvas_item_set( info->item, "fill_color", NULL, NULL );
      else
         gnome_canvas_item_set( info->item, "fill_color_gdk", &color, NULL );
   }

   if( params->outline.changed )
   {
      GdkColor color;
      int      alpha;
      if( gnoclGetGdkColorAlloc( interp, params->outline.val, 
            GTK_WIDGET( info->canvas ), &color, &alpha ) != TCL_OK )
         return TCL_ERROR;
      if( alpha == 0 )
         gnome_canvas_item_set( info->item, "outline_color", NULL, NULL );
      else
         gnome_canvas_item_set( info->item, "outline_color_gdk", &color, NULL );
   }

   if( params->width.changed )
      gnome_canvas_item_set( info->item, 
            "width_units", params->width.val, NULL );

   return TCL_OK;
}

static int canvasConfigRE( Tcl_Interp *interp, int objc, 
      Tcl_Obj * const objv[], Gnocl_CanvasItemInfo *info )
{
   REParams params;
   int      err;

   memset( &params, 0, sizeof( params ) );
   /* canvas itemconfigure tag params ... */
   err = gnoclParseAllWidgetOpts( interp, objc, objv, 2,
         reOptions, (char *)&params );

   if( err == TCL_OK )
      err = setParams( interp, &params, info );
   freeParams( &params );

   return err;
}


static Gnocl_CanvasItemInfo *canvasCreateRE( Tcl_Interp *interp,
      int objc, Tcl_Obj * const objv[], GnomeCanvas *widget, int isRectangle )
{
   Gnocl_CanvasItemInfo *info;
   guint    type;
   REParams params;
   int      err;

   memset( &params, 0, sizeof( params ) );
   if( gnoclParseAllWidgetOpts( interp, objc, objv, 3,
         reOptions, (char *)&params ) != TCL_OK )
   {
      freeParams( &params );
      return NULL;
   }

   if( params.coords.changed == 1 )
   {
      Tcl_SetResult( interp, 
            "in creating coordinates may not be given as option",
            TCL_STATIC );
      freeParams( &params );
      return NULL;
   }

   if( isRectangle )
      type = gnome_canvas_rect_get_type( );
   else
      type = gnome_canvas_ellipse_get_type( );

   params.coords.changed = 1;
   params.coords.val = objv[3];
   Tcl_IncrRefCount( params.coords.val );

   info = g_new( Gnocl_CanvasItemInfo, 1 );
   info->canvas = widget;
   info->deleteFunc = &canvasDeleteRE;
   info->configFunc = &canvasConfigRE;
   info->group = gnome_canvas_root( widget );
   /* default color "black" will be overwritten in setParams */
   info->item = gnome_canvas_item_new( info->group, type, 
         "fill_color", "black", NULL );
   
   err = setParams( interp, &params, info );
   freeParams( &params );

   if( err != TCL_OK )
   {
      gtk_object_destroy( GTK_OBJECT( info->item ) );
      g_free( info );
      return NULL;
   }

   return info;
}

Gnocl_CanvasItemInfo *gnoclCanvasCreateEllipse( Tcl_Interp *interp,
      int objc, Tcl_Obj * const objv[], GnomeCanvas *widget )
{
   return canvasCreateRE( interp, objc, objv, widget, 0 );
}

Gnocl_CanvasItemInfo *gnoclCanvasCreateRectangle( Tcl_Interp *interp,
      int objc, Tcl_Obj * const objv[], GnomeCanvas *widget )
{
   return canvasCreateRE( interp, objc, objv, widget, 1 );
}
