/*
 * convert.c --
 *
 * This file implements some functions for converting Tcl_Obj to gtk types
 *
 * 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-07: Begin of developement: split from gnocl.c
 */

#include "gnocl.h"

static int getScrollbarPolicy( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkPolicyType *pol )
{
   char *txt[] = { "always", "never", "automatic", NULL };
   GtkPolicyType policies[] = { 
         GTK_POLICY_ALWAYS, GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC };
   int on;

   if( Tcl_GetBooleanFromObj( NULL, obj, &on ) == TCL_OK )
      *pol = on ? GTK_POLICY_ALWAYS : GTK_POLICY_NEVER;
   else
   {
      int idx;
      if( Tcl_GetIndexFromObj( interp, obj, txt, "scrollbar policy",
            TCL_EXACT, &idx ) != TCL_OK )
         return TCL_ERROR;
      *pol = policies[idx];
   }
   return TCL_OK;
}

int gnoclGetScrollbarPolicy( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkPolicyType *hor, GtkPolicyType *vert )
{
   int no;

   if( Tcl_ListObjLength( interp, obj, &no ) != TCL_OK  || no > 2 )
   {
      Tcl_SetResult( interp, "policy must be either a single value "
            "or a list with two elements.", TCL_STATIC );
      return TCL_ERROR;
   }

   if( no == 1 )
   {
      if( getScrollbarPolicy( interp, obj, hor ) != TCL_OK )
         return TCL_ERROR;
      *vert = *hor;
   }
   else
   {
      Tcl_Obj *tp;

      if( Tcl_ListObjIndex( interp, obj, 0, &tp ) != TCL_OK )
         return TCL_ERROR;
      if( getScrollbarPolicy( interp, tp, hor ) != TCL_OK )
         return TCL_ERROR;
      if( Tcl_ListObjIndex( interp, obj, 1, &tp ) != TCL_OK )
         return TCL_ERROR;
      if( getScrollbarPolicy( interp, tp, vert ) != TCL_OK )
         return TCL_ERROR;
   }

   return TCL_OK;
}

int gnoclGetUpdatePolicy( Tcl_Interp *interp, Tcl_Obj *obj,
      GtkUpdateType *pol )
{
   char *polTxt[] = { "continuous", "discontinuous", "delayed", NULL };
   GtkUpdateType types[] = { GTK_UPDATE_CONTINUOUS,
         GTK_UPDATE_DISCONTINUOUS, GTK_UPDATE_DELAYED };

   int idx;
   if( Tcl_GetIndexFromObj( interp, obj, polTxt, "update policies",
         TCL_EXACT, &idx ) != TCL_OK )
      return TCL_ERROR;

   *pol = types[idx];

   return TCL_OK;
}


int gnoclGetSelectionMode( Tcl_Interp *interp, Tcl_Obj *obj,
      GtkSelectionMode *selection )
{
   char *modesTxt[] = { "single", "browse", "multiple", "extended", NULL };
   GtkSelectionMode modes[] = { GTK_SELECTION_SINGLE,
         GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE,
         GTK_SELECTION_EXTENDED };

   int idx;
   if( Tcl_GetIndexFromObj( interp, obj, modesTxt, "selection modes",
         TCL_EXACT, &idx ) != TCL_OK )
      return TCL_ERROR;

   *selection = modes[idx];

   return TCL_OK;
}

int gnoclGetAnchorStyle( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkAnchorType *style )
{
   char *styles[] = { "center", 
         "N", "NW", "NE", 
         "S", "SW", "SE", 
         "W", "E", 
         NULL };
   GtkAnchorType gStyles[] = { GTK_ANCHOR_CENTER, 
         GTK_ANCHOR_NORTH, GTK_ANCHOR_NORTH_WEST, GTK_ANCHOR_NORTH_EAST,
         GTK_ANCHOR_SOUTH, GTK_ANCHOR_SOUTH_WEST, GTK_ANCHOR_SOUTH_EAST,
         GTK_ANCHOR_WEST, GTK_ANCHOR_EAST };

   int idx;
   if( Tcl_GetIndexFromObj( interp, obj, styles, "anchor style",
         TCL_EXACT, &idx ) != TCL_OK )
      return TCL_ERROR;

   *style = gStyles[idx];
   return TCL_OK;
}

int gnoclGetJustification( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkJustification *type )
{
   char *types[] = { "left", "right", "center", "fill", NULL };
   GtkAnchorType gTypes[] = {   GTK_JUSTIFY_LEFT, GTK_JUSTIFY_RIGHT,
         GTK_JUSTIFY_CENTER, GTK_JUSTIFY_FILL };

   int idx;
   if( Tcl_GetIndexFromObj( interp, obj, types, "justification",
         TCL_EXACT, &idx ) != TCL_OK )
      return TCL_ERROR;

   *type = gTypes[idx];
   return TCL_OK;
}

int gnoclGetPositionType( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkPositionType *type )
{
   char *types[] = { "left", "right", "top", "bottom", NULL };
   GtkAnchorType gTypes[] = { GTK_POS_LEFT, GTK_POS_RIGHT,
         GTK_POS_TOP, GTK_POS_BOTTOM };

   int idx;
   if( Tcl_GetIndexFromObj( interp, obj, types, "position type",
         TCL_EXACT, &idx ) != TCL_OK )
      return TCL_ERROR;

   *type = gTypes[idx];
   return TCL_OK;
}

int gnoclGetShadowType( Tcl_Interp *interp, Tcl_Obj *obj,
      GtkShadowType *shadow )
{
   char *styles[] = { "none", "in", "out", "etchedIn", "etchedOut",
         NULL };
   GtkShadowType types[] = { GTK_SHADOW_NONE, GTK_SHADOW_IN,
         GTK_SHADOW_OUT, GTK_SHADOW_ETCHED_IN, GTK_SHADOW_OUT };

   int idx;
   if( Tcl_GetIndexFromObj( interp, obj, styles, "shadow style",
         TCL_EXACT, &idx ) != TCL_OK )
      return TCL_ERROR;

   *shadow = types[idx];

   return TCL_OK;
}

int gnoclGetOrientationType( Tcl_Interp *interp, Tcl_Obj *obj,
      GtkOrientation *orient )
{
   char *styles[] = { "horizontal", "vertical", NULL };
   GtkOrientation types[] = { GTK_ORIENTATION_HORIZONTAL, 
         GTK_ORIENTATION_VERTICAL };

   int idx;
   if( Tcl_GetIndexFromObj( interp, obj, styles, "shadow style",
         TCL_EXACT, &idx ) != TCL_OK )
      return TCL_ERROR;

   *orient = types[idx];

   return TCL_OK;
}

static void saturateShort( int *i )
{
   if( *i < 0 )
      *i = 0;
   else if( *i > 65535 )
      *i = 65535;
}

int gnoclGetRGBA( Tcl_Interp *interp, Tcl_Obj *obj, 
      int *r, int *g, int *b, int *a )
{
   int no;

#define GET_INT(idx,var ) do { \
         if( Tcl_ListObjIndex( interp, obj, idx, &tp ) != TCL_OK || \
               Tcl_GetIntFromObj( interp, tp, var ) ) \
            return TCL_ERROR; } while( 0 )

   if( Tcl_ListObjLength( interp, obj, &no ) != TCL_OK  || no < 0 || no > 4 )
   {
      Tcl_SetResult( interp, "color must be either \"name\" or a list "
            "consisting of \"name alpha\", \"r g b\", or \"r g b alpha\"", 
            TCL_STATIC );
      return TCL_ERROR;
   }
   if( no == 0 )  /* transparent */
   {
      *r = *g = *b = *a = 0;
   }
   else if( no < 3 )
   {
      Tcl_Obj *tp;
      GdkColor color;

      if( Tcl_ListObjIndex( interp, obj, 0, &tp ) != TCL_OK )
         return TCL_ERROR;
      
      if( gdk_color_parse( Tcl_GetString( obj ), &color ) == 0 )
      {
         Tcl_AppendResult( interp, "unknown color \"", 
               Tcl_GetString( obj ), "\".", (char *)NULL );
         return TCL_ERROR;
      }

      *r = color.red;
      *g = color.green;
      *b = color.blue;

      if( no == 2 )
         GET_INT( 1, a );
      else
         *a = 1;
   }
   else
   {
      Tcl_Obj *tp;

      GET_INT( 0, r );
      GET_INT( 1, g );
      GET_INT( 2, b );
      if( no == 4 )
         GET_INT( 3, a );
      else
         *a = 1;
   }
#undef GET_INT

   saturateShort( r );
   saturateShort( g );
   saturateShort( b );
   saturateShort( a );

   return TCL_OK; 
}

int gnoclGetGdkColor( Tcl_Interp *interp, Tcl_Obj *obj, 
      GdkColor *color, int *pa )
{
   int r, g, b, a;

   if( gnoclGetRGBA( interp, obj, &r, &g, &b, &a ) != TCL_OK )
      return TCL_ERROR;

   color->red = r;
   color->green = g;
   color->blue = b;
   if( pa )
      *pa = a;

   return TCL_OK;
}

int gnoclGetGdkColorAlloc( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkWidget *widget, GdkColor *color, int *pa )
{
   if( gnoclGetGdkColor( interp, obj, color, pa ) != TCL_OK )
      return TCL_ERROR;

   if( *pa > 0 )
   {
      GdkColormap *cm = gtk_widget_get_colormap( widget );
      if( gdk_colormap_alloc_color( cm, color, 0, 1 ) == 0 )
      {
         Tcl_AppendResult( interp, "color \"", Tcl_GetString( obj ), 
               "\" could not be allocated.", (char *)NULL );
         return TCL_ERROR;
      }
   }

   return TCL_OK;
}

int gnoclGetFontTxt( Tcl_Interp *interp, Tcl_Obj *obj, const char **font )
{
   /* TODO: use Tk's font substitution mechanism which simplifies
      things. Font name e.g. "Courier 14" */
   *font = Tcl_GetString( obj );
   return TCL_OK;
}

int gnoclGetGdkFont( Tcl_Interp *interp, Tcl_Obj *obj, GdkFont **font )
{
   /* TODO: use Tk's font substitution mechanism which simplifies
      things. Font name e.g. "Courier 14" */

   *font = gdk_font_load( Tcl_GetString( obj ) );
   if( *font == NULL )
   {
      Tcl_AppendResult( interp, "unknown font \"", 
            Tcl_GetString( obj ), "\".", (char *)NULL );
      return TCL_ERROR;
   }

   return TCL_OK;
}

