#ifndef GNOCL_H_INCLUDED
#define GNOCL_H_INCLUDED

/*
 * gnocl.h --
 *
 * This file implements a Tcl interface to gnome and gtk+
 *
 * 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.
 *
 */

#include "tcl.h"
#ifdef GNOCL_USE_GNOME
   #include <gnome.h>
#else
   #include <gtk/gtk.h>
#endif


typedef enum GnoclStringType_
{
   GNOCL_STR_EMPTY     = 0,      /* empty string */
   GNOCL_STR_STR       = 1 << 0, /* normal string */
   GNOCL_STR_STOCK     = 1 << 1, /* (potentially) the name of a stock item */
   GNOCL_STR_FILE      = 1 << 2, /* (potentially) the name of a file */
   GNOCL_STR_TRANSLATE = 1 << 3, /* to be translated via gettext */
   GNOCL_STR_UNDERLINE = 1 << 4  /* '_' marks underline und accelerator */
} GnoclStringType;

GnoclStringType gnoclGetStringType( Tcl_Obj *obj );
char *gnoclGetString( Tcl_Obj *op );
char *gnoclGetStringFromObj( Tcl_Obj *op, int *len );
char *gnoclGetStringUline( Tcl_Obj *op, char **pattern );
char *gnoclStringDup( Tcl_Obj *op );
char *gnoclGetStockButtonName( Tcl_Interp *interp, Tcl_Obj *obj );
char *gnoclGetStockMenuName( Tcl_Interp *interp, Tcl_Obj *obj, char **txt );


int gnoclMemNameAndWidget( const char *name, GtkWidget *widget );
int gnoclForgetWidgetFromName( const char *name );
char *gnoclGetAutoWidgetId( void );
GtkWidget *gnoclGetWidgetFromName( const char *name, Tcl_Interp *interp );
GtkWidget *gnoclChildNotPacked( const char *name, Tcl_Interp *interp );
int gnoclAssertNotPacked( GtkWidget *child, Tcl_Interp *interp, 
      const char *name );


enum GnoclOptionType 
{ 
   GNOCL_STRING, 
   GNOCL_DOUBLE, 
   GNOCL_INT, 
   GNOCL_BOOL,
   GNOCL_OBJ, 
   GNOCL_LIST 
};

/*
   with these types it can be determined, if parameters have changed 
   in gnoclParseAllWidgetOpts. So we can use the default parametes
   from gnome without explicitely setting them 

   !!! the struct must start with changed, so that each struct can
   be casted to Gnocl_BoolBool an changed can be read and written !!!
*/
typedef struct { int changed; char *val; } Gnocl_StringBool;
typedef struct { int changed; gboolean val; } Gnocl_BoolBool;
typedef struct { int changed; gint val; } Gnocl_IntBool;
typedef struct { int changed; gdouble val; } Gnocl_DoubleBool;
typedef struct { int changed; Tcl_Obj *val; } Gnocl_ObjBool;
typedef struct { int changed; Tcl_Obj *val; } Gnocl_ListBool;
/* this is the same as 
   #define OffsetOf(type, field) ((int) ((char *) &((type *) 0)->field))
   but one get additionaly type checking with "value"
*/
#define GNOCL_OFFSET(type, field) ((int)((char *)&((type *) 0)->field.changed))


typedef struct
{
   char c;
   enum GnoclOptionType type;
   union 
   {
      double     d;
      int        i;
      int        b;
      const char *str;
      Tcl_Obj    *obj;
   }    val;
} Gnocl_PercSubst;

const char *gnoclPercentSubstitution( Gnocl_PercSubst *p, int no, 
      const char *str );

typedef struct
{
   const char           *name;
   /*
   union
   {
      double d;
      int    n;
      char   *p;
   }                    defaultValue;
   */
   enum GnoclOptionType type;
   int                  offset;
   int                  changed;
} GnoclWidgetOptions;

int gnoclParseAllWidgetOpts( Tcl_Interp *interp, int objc, 
      Tcl_Obj * const objv[], int objcOffset, 
      const GnoclWidgetOptions *opts, char *params );
/*
int gnoclParseWidgetOpts( Tcl_Interp *interp, int objc, 
      Tcl_Obj * const objv[], const GnoclWidgetOptions *opts, char *params );
*/
int gnoclHandleStdCmds( Tcl_Interp *interp, int objc, Tcl_Obj * const objv[],
      GtkWidget *widget, const GnoclWidgetOptions *options, char *params );
int gnoclDelete( Tcl_Interp *interp, GtkWidget *widget, 
      int objc, Tcl_Obj * const objv[] );
int gnoclShow( Tcl_Interp *interp, GtkWidget *widget, 
      int objc, Tcl_Obj * const objv[] );
int gnoclHide( Tcl_Interp *interp, GtkWidget *widget, 
      int objc, Tcl_Obj * const objv[] );
int gnoclAttacheCommand( char **pold, char **pnew, GtkObject *obj,
      const char *signal, GtkSignalFunc func, gpointer data );
int gnoclAttacheVariable( char **pold, char **pnew, GtkObject *obj,
      const char *signal, GtkSignalFunc gtkFunc, 
      Tcl_Interp *interp, Tcl_VarTraceProc tclFunc, 
      gpointer data );
int gnoclAttacheCmdAndVar( int newCmdValid, char **oldCmd, char **newCmd, 
      int newVarValid, char **oldVar, char **newVar,
      const char *signal, 
      GtkObject *obj, GtkSignalFunc gtkFunc, 
      Tcl_Interp *interp, Tcl_VarTraceProc tclFunc, 
      gpointer data );
int gnoclGetScrollbarPolicy( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkPolicyType *hor, GtkPolicyType *vert );
int gnoclGetUpdatePolicy( Tcl_Interp *interp, Tcl_Obj *obj,
      GtkUpdateType *pol );
int gnoclGetSelectionMode( Tcl_Interp *interp, Tcl_Obj *obj,
      GtkSelectionMode *selection );
int gnoclGetFontTxt( Tcl_Interp *interp, Tcl_Obj *obj, const char **font );
int gnoclGetGdkFont( Tcl_Interp *interp, Tcl_Obj *obj, GdkFont **font );
int gnoclGetRGBA( Tcl_Interp *interp, Tcl_Obj *obj, 
      int *r, int *g, int *b, int *a );
int gnoclGetGdkColor( Tcl_Interp *interp, Tcl_Obj *obj, GdkColor *color, 
      int *a );
int gnoclGetGdkColorAlloc( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkWidget *widget, GdkColor *color, int *a );
int gnoclGetPositionType( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkPositionType *type );
int gnoclGetAnchorStyle( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkAnchorType *style );
int gnoclGetJustification( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkJustification *type );
int gnoclGetShadowType( Tcl_Interp *interp, Tcl_Obj *obj,
      GtkShadowType *shadow );
int gnoclGetOrientationType( Tcl_Interp *interp, Tcl_Obj *obj,
      GtkOrientation *orient );
int gnoclGetPixmap( Tcl_Interp *interp, GtkWidget *window,
      Tcl_Obj *obj, GtkWidget **widget );
int gnoclAddTooltip( GtkWidget *widget, const char *txt, 
      const char *txtPriv );
GtkAccelGroup *gnoclGetAccelGroup( );

int gnoclEditablePosToIndex( Tcl_Interp *interp, Tcl_Obj *obj, 
      GtkEditable *editable, int *pidx );
int gnoclHandleEditableCmds( int idx, Tcl_Interp *interp, int objc, 
      Tcl_Obj * const objv[], GtkEditable *editable );

int gnoclRegisterHintAppbar( GtkWidget *widget, GnomeAppBar *appBar );
GnomeAppBar *gnoclGetHintAppbar( GtkWidget *widget );

/* 
   in gnoclBind.c
*/
typedef struct Gnocl_CanvasItemInfo_ Gnocl_CanvasItemInfo;

int gnoclMemNameAndCanvasInfo( int id, Gnocl_CanvasItemInfo *widget );
int gnoclForgetCanvasItemFromName( const char *path );
Gnocl_CanvasItemInfo *gnoclGetCanvasInfoFromName( const char *path );

/* STD_CMD */
#define GNOCL_STD_CMD_NAMES "delete", "show", "hide"
#define GNOCL_STD_CMD_ENUMS DeleteIdx, ShowIdx, HideIdx 
#define GNCOL_STD_CMD_CASE(interp,objc,objv,widget) \
      case DeleteIdx: return gnoclDelete( interp, widget, objc, objv ); \
      case ShowIdx:   return gnoclShow( interp, widget, objc, objv ); \
      case HideIdx:   return gnoclHide( interp, widget, objc, objv )

/* EDITABLE_CMD */
#define GNOCL_EDITABLE_CMD_NAMES "remove", "select", \
      "cut", "copy", "paste", "getChars", "getLength"
#define GNOCL_EDITABLE_CMD_ENUMS RemoveIdx, SelectIdx, \
      CutIdx, CopyIdx, PasteIdx, GetCharsIdx, GetLengthIdx 
#define GNCOL_EDITABLE_CMD_CASE(idx,interp,objc,objv,widget) \
      case RemoveIdx: case SelectIdx: \
      case CutIdx:    case CopyIdx:   case PasteIdx: \
      case GetCharsIdx: case GetLengthIdx: \
      return gnoclHandleEditableCmds(idx-RemoveIdx, interp, objc, objv, widget )


/* STD_OPTIONS */
#define GNOCL_STD_OPTIONS_VARS \
      Gnocl_StringBool tooltip; \
      Gnocl_IntBool    width; \
      Gnocl_IntBool    height; \
      Gnocl_BoolBool   sensitive

#define GNOCL_STD_OPTIONS_NAMES( p ) \
      { "-tooltip", GNOCL_STRING, GNOCL_OFFSET( p, tooltip ) }, \
      { "-width", GNOCL_INT, GNOCL_OFFSET( p, width ) }, \
      { "-height", GNOCL_INT, GNOCL_OFFSET( p, height ) }, \
      { "-sensitive", GNOCL_BOOL, GNOCL_OFFSET( p, sensitive ) }

/* FIXME: is this correct? */
#define GNOCL_FREE_TCL_OPT(opt) \
   if( opt.changed && opt.val ) Tcl_DecrRefCount( opt.val )
#define GNOCL_FREE_MEM_OPT(opt) if( opt.changed ) g_free( opt.val )

#define GNOCL_STD_OPTIONS_FREE( p ) GNOCL_FREE_MEM_OPT( p->tooltip )

#define GNOCL_STD_OPTIONS_HANDLE( p, widget ) \
   if( p->tooltip.changed ) \
   { \
      gnoclAddTooltip( widget, p->tooltip.val, NULL ); \
   } \
   if( p->width.changed ) \
   { \
      gtk_object_set( GTK_OBJECT( widget ), "width", p->width.val, NULL ); \
   } \
   if( p->height.changed ) \
   { \
      gtk_object_set( GTK_OBJECT( widget ), "height", p->height.val, NULL ); \
   } \
   if( p->sensitive.changed ) \
   { \
      gtk_widget_set_sensitive( widget, p->sensitive.val ); \
   }

/* FIXME? or set size via
      gtk_window_set_default_size( widget, p->width.val, -1 ); \
   or
      gtk_widget_set_usize
   ???

*/

/* in helperFuncs */
const char *gnoclEventToString( GdkEventType et );
int gnoclPercentSubstAndEval( Tcl_Interp *interp, Gnocl_PercSubst *ps, 
      const char *orig_script );
GtkLabel *gnoclFindLabel( GtkWidget *widget );
guint gnoclLabelParseULine( GtkWidget *widget, char *text );
int gnoclGet2Boolean( Tcl_Interp *interp, Tcl_Obj *obj, int *b1, int *b2 );
int gnoclGet2Int( Tcl_Interp *interp, Tcl_Obj *obj, int *b1, int *b2 );
int gnoclGet2Double( Tcl_Interp *interp, Tcl_Obj *obj, double *b1, double *b2 );

/* in menu */
int gnoclMenu_registerKey( GtkWidget *widget, guint key );
guint gnoclMenu_getKey( GtkWidget *widget );

#endif
