/*
 * window.c --
 *
 * This file implements the window 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-03: Begin of developement
 */

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

typedef struct
{
   Gnocl_StringBool type;
   Gnocl_StringBool title;
   Gnocl_StringBool child;
   Gnocl_BoolBool   resizable;
   Gnocl_BoolBool   modal;

   Gnocl_IntBool    width;
   Gnocl_IntBool    height;
} WindowOptions;

static const GnoclWidgetOptions widgetOptions[] = 
{
   { "-title", GNOCL_STRING, GNOCL_OFFSET( WindowOptions, title ) },
   { "-resizable", GNOCL_BOOL, GNOCL_OFFSET( WindowOptions, resizable ) },
   { "-modal", GNOCL_BOOL, GNOCL_OFFSET( WindowOptions, modal ) },
   { "-type", GNOCL_STRING, GNOCL_OFFSET( WindowOptions, type ) },
   { "-child", GNOCL_STRING, GNOCL_OFFSET( WindowOptions, child ) },
   { "-width", GNOCL_INT, GNOCL_OFFSET( WindowOptions, width ) },
   { "-height", GNOCL_INT, GNOCL_OFFSET( WindowOptions, height ) },

   { NULL, 0, 0 }
};

/*
   This struct contains only the necessary states to remember.
   Option values can be inquired via gtk
*/
typedef struct
{
   GtkWindow  *window;
   char       *name;
   Tcl_Interp *interp;
} WindowParams;

static void freeOpts( WindowOptions *p )
{
   GNOCL_FREE_MEM_OPT( p->title );
   GNOCL_FREE_MEM_OPT( p->type );
   GNOCL_FREE_MEM_OPT( p->child );
}

static void windowDestroyFunc( GtkWidget *widget, gpointer data )
{
   WindowParams *p = (WindowParams *)data;

   gnoclForgetWidgetFromName( p->name );
   Tcl_DeleteCommand( p->interp, p->name );

   g_free( p->name );
   g_free( p );
}



/*
   test, if params are valid
   set params and show window with new settings
*/
static int windowConfigure( Tcl_Interp *interp, WindowParams *para,
      WindowOptions *popt )
{
   if( popt->width.changed ) 
   { 
      /*
      gtk_object_set( GTK_OBJECT( para->window ), "width", 
            popt->width.val, NULL ); 
      */
      gtk_window_set_default_size( para->window, popt->width.val, -1 );
   } 
   if( popt->height.changed ) 
   { 
      gtk_window_set_default_size( para->window, -1, popt->height.val );

      /*
      gtk_object_set( GTK_OBJECT( para->window ), "height", 
            popt->height.val, NULL ); 
      */
   } 
 
   if( popt->title.changed )
      gtk_window_set_title( para->window, popt->title.val );

   if( popt->resizable.changed )
   {
      if( popt->resizable.val )
         gtk_window_set_policy( para->window, 0, 1, 0 );
      else
         gtk_window_set_policy( para->window, 0, 0, 1 );
   }

   /*
      FIXME: delete old child
      if( gtk_container_children( GTK_CONTAINER( parent ) ) != NULL )
   */
   if( popt->child.changed )
   {
      GtkWidget *childWidget = gnoclChildNotPacked( popt->child.val, 
            interp );
      if( childWidget == NULL )
         return TCL_ERROR;

      gtk_container_add( GTK_CONTAINER( para->window ), childWidget );
   }

   if( popt->modal.changed )
      gtk_window_set_modal( para->window, popt->modal.val );

   /* gtk_widget_show_all( GTK_WIDGET( para->window ) ); */

   return TCL_OK;
}

static int windowFunc( ClientData data, Tcl_Interp *interp,
      int objc, Tcl_Obj * const objv[] )
{

   static char *cmds[] = { GNOCL_STD_CMD_NAMES,
         "configure", NULL };
   enum cmdIdx { GNOCL_STD_CMD_ENUMS, ConfigureIdx };
   WindowParams *para = (WindowParams *)data;
   GtkWidget *widget = GTK_WIDGET( para->window );
   int idx;

   if( Tcl_GetIndexFromObj( interp, objv[1], cmds, "command", 
         TCL_EXACT, &idx ) != TCL_OK )
      return TCL_ERROR;

   switch( idx )
   {
      GNCOL_STD_CMD_CASE( interp, objc, objv, widget );
            break;
      case ConfigureIdx:
            {
               WindowOptions opt;
               int ret = TCL_ERROR;

               memset( &opt, 0, sizeof( opt ) );
               if( gnoclParseAllWidgetOpts( interp, objc, objv, 1,
                     widgetOptions, (char *)&opt ) == TCL_OK )
                  ret = windowConfigure( interp, para, &opt );

               freeOpts( &opt );
               if( ret != TCL_OK )
                  return TCL_ERROR;
               /* gtk_widget_show_all( widget ); */
            }
            break;
   }

   return TCL_OK;
}


int gnoclWindowCmd( ClientData data, Tcl_Interp *interp,
      int objc, Tcl_Obj * const objv[] )
{
   WindowOptions opt;
   WindowParams *para;
   int ret;
   int type = 0;
  
   memset( &opt, 0, sizeof( opt ) );
   if( gnoclParseAllWidgetOpts( interp, objc, objv, 0,
         widgetOptions, (char *)&opt ) != TCL_OK )
      return TCL_ERROR;

   para = g_new( WindowParams, 1 );
   para->name = gnoclGetAutoWidgetId();
   para->interp = interp;

   if( !opt.type.val )
      type = GTK_WINDOW_TOPLEVEL;
   else
   {
      if( !strcmp( opt.type.val, "toplevel" ) )
         type = GTK_WINDOW_TOPLEVEL;
      else if( !strcmp( opt.type.val, "dialog" ) )
         type = GTK_WINDOW_DIALOG;
      else if( !strcmp( opt.type.val, "popup" ) )
         type = GTK_WINDOW_POPUP;
      else
      {
         Tcl_AppendResult( interp, "wrong parameter \"", 
               opt.type.val, "\" for option type. Must be one of "
               "toplevel, dialog, or popup", (char *)NULL );
         return TCL_ERROR;
      }
   }

   para->window = GTK_WINDOW( gtk_window_new( type ) );
   /* allow shrink, allow grow, no auto shrink */
   /*
   gtk_window_set_policy( para->window, 1, 1, 0 );
   */
   ret = windowConfigure( interp, para, &opt );
   freeOpts( &opt );
   if( ret != TCL_OK )
   {
      /* FIXME: g_free pp->name ... */
      gtk_widget_destroy( GTK_WIDGET( para->window ) );
      return TCL_ERROR;
   }

   gtk_signal_connect( GTK_OBJECT( para->window ), "destroy", 
      GTK_SIGNAL_FUNC( windowDestroyFunc ), para );

   gnoclMemNameAndWidget( para->name, GTK_WIDGET( para->window ) );
   gtk_widget_show( GTK_WIDGET( para->window ) );

   Tcl_CreateObjCommand( interp, para->name, windowFunc, para, NULL );
   Tcl_SetObjResult( interp, Tcl_NewStringObj( para->name, -1 ) );

   return TCL_OK;
}

