/*
    GDAM - Geoff & Dave's Audio Mixer
    Copyright (C) 1999    Dave Benson, Geoff Matters.

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA

    Contact:
        daveb@ffem.org <Dave Benson>
        geoff@ugcs.caltech.edu <Geoff Matters>
*/
#ifndef __GDAM_SKIN_H_
#define __GDAM_SKIN_H_


/* 
 *                  GdamSkin
 *
 * The gtk-interface (using libglade) to GdamView's.
 *
 * Of course, this is practically the only interface
 * to gdamview that is used...
 */

typedef struct _GdamSkinClass GdamSkinClass;
typedef struct _GdamSkin GdamSkin;

#include <gtk/gtkwidget.h>
#include <gdam/component/gdamview.h>
#include <gdam/component/gdamtoplevel.h>
#include <glade/glade-xml.h>
#include <gtk/gtkstatusbar.h>

GtkType gdam_skin_get_type();
#define GDAM_TYPE_SKIN              (gdam_skin_get_type ())
#define GDAM_SKIN(obj)              (GTK_CHECK_CAST ((obj), GDAM_TYPE_SKIN, GdamSkin))
#define GDAM_SKIN_CLASS(klass)      (GTK_CHECK_CLASS_CAST ((klass), GDAM_TYPE_SKIN, GdamSkinClass))
#define GDAM_IS_SKIN(obj)           (GTK_CHECK_TYPE ((obj), GDAM_TYPE_SKIN))
#define GDAM_IS_SKIN_CLASS(klass)   (GTK_CHECK_CLASS_TYPE ((klass), GDAM_TYPE_SKIN))

#define GDAM_SKIN_GET_WIDGET(skin)  (GDAM_SKIN (skin)->main_widget)
#define GDAM_SKIN_GET_MODEL(skin)   (GDAM_SKIN (skin)->model)

#define GDAM_BUTTON23_MASK (enum GdkModifierType)(GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)

typedef struct _GdamSkinInitializer GdamSkinInitializer;
typedef gboolean (*GdamSkinInitFunc)(GdamSkin* skin, gpointer user_data);

struct _GdamSkinInitializer {
	/* Returns TRUE if successfully initialized. */
	GdamSkinInitFunc	init_func;

	/* A marshaller:  will be used to invoke the init func, unless
	 *                the marshaller is NULL. */
	gboolean              (*marshal)(GdamSkin*,
	                                 GdamSkinInitializer*);

	/* Called whether or not the init function has succeeded. */
	GDestroyNotify		destroyer;

	gpointer user_data;
};

/*
 * Connection handler for a single type of handler.
 *
 *     If you return FALSE you will be called again.
 *     Useful if you have order-dependency amoungst your
 *     handlers.
 *
 * Deprecated trick:
 *                 setting handler_names[i] to NULL prevents that string
 *                 from getting g_free'd- by doing that you may retain
 *                 a reference to whichever strings you want
 *                 (of course, you must g_free them later ...)
 */
typedef gboolean (*GdamSkinConnectHandler)(GdamSkin*          skin,
			                   GtkObject*         object,
			                   const char*        signal_name,
			                   int                num_handler_names,
			                   char**             handler_names);
struct _GdamSkinClass {
	GdamViewClass		view_class;

	GtkType			model_type;	/* or GTK_TYPE_NONE */

	gboolean              (*build_new_model)    (GdamSkin*      skin,
						     GdamChannel*   channel,
						     int            num_options,
	                                             char**         options);
        gboolean              (*initialize_main_widget)
				                    (GdamSkin*      skin,
				                     const char*    arg);

	void		      (*evaluate_options)   (GdamSkin*      skin,
						     int            num_options,
	                                             char**         options);

	/* To notice when we are connected to a component as
	 * our parent. (eg. we are notified of our toplevel in launcher). */
	void                  (*toplevel_connect)   (GdamSkin*      skin,
	                                             GdamToplevel*  toplevel);
	/* Optional handler for after skin is fully connected. */
	void                  (*post_connecting_handler)
	                                            (GdamSkin*      skin);


};

struct _GdamSkin {
	GdamView		view;

	/* The outer rendered frame usually, as named ``main_widget''
	 * in the xml file. */
	GtkWidget*		main_widget;

	/* If the skin has an underlying model,
	 * it should be stored here.
	 *
	 * XXX: this should be a member of GdamView.
	 */
	GdamModel*              model;

	/* The gladexml file we came from. */
	const char* 		filename;

	/* The channel to issue requests on.
	 * (Primarily for skins which do not have a model). */
	GdamChannel*		channel;

	/* List on GdamSkinInitializers that haven't succeeded yet. */
	GSList*			initializer_list;

	guint			finished_connecting : 1;
};



GdamSkin*       gdam_skin_new           (GtkType          skin_type,
                                         const char*      skin_filename,
					 int              num_options,
					 char**           options,
					 GdamChannel*     channel,
					 GdamModel**      model_out);
GdamSkin*       gdam_skin_new_with_model(GtkType          skin_type,
					 GdamModel*       model,
                                         const char*      skin_filename,
					 int              num_options,
					 char**           options);


/* Serialize/deserialize. */
xmlNode*        gdam_skin_to_xml        (GdamSkin*        skin,
                                         GdamXmlInfo*     xml_info);
GdamSkin*       gdam_skin_from_xml      (xmlNode*         node,
                                         GdamChannel*     channel,
					 GdamXmlInfo*     xml_info);


GdamSkin*       gdam_skin_new_by_type_name
                                        (const char*      skin_type_name,
                                         const char*      skin_filename,
				         int              num_options,
				         char**           options,
					 GdamChannel*     channel,
					 GdamModel**      model_out);


/* For use with derived classes.
 * If you want to add an action which should be tried until
 * it succeeds, in order to cope with complex dependencies,
 * use this to register it. */
void            gdam_skin_add_initializer
                                        (GdamSkin*        skin,
					 GdamSkinInitFunc initializer,
					 GDestroyNotify   destructor,
					 gpointer         user_data);

/* Registering common types of callbacks. */
typedef void (*GdamSkinFunc)(GdamSkin*);

typedef struct _GdamSkinSimpleConnect GdamSkinSimpleConnect;
struct _GdamSkinSimpleConnect {
	const char*		   name;
	GdamSkinFunc               skin_func;
};

typedef struct _GdamSkinGenericConnect GdamSkinGenericConnect;
struct _GdamSkinGenericConnect {
	const char*		   name;
	GdamSkinConnectHandler     skin_func;
};

void            gdam_skin_class_register_generic_handlers
                                        (GdamSkinClass*   skin_class,
				         int              num_types,
				         GdamSkinGenericConnect* array);

void            gdam_skin_class_register_simple_connections
                                        (GdamSkinClass*   skin_class,
				         int              num_types,
				         GdamSkinSimpleConnect* array);

void            gdam_skin_class_unregister_connection
                                        (GdamSkinClass*   skin_class,
				         const char*      name);

/*
 * detect the type of, and open an xml file.
 *
 *     if it is a glade file, open it with glade and a default GdamSkin.
 *     if it is a gdam file, make a skin out of it.  Returns the top
 *     skin or model if successful.
 */
GtkObject*       gdam_skin_open         (const char*      xml_file,
                                         GdamChannel*     channel); 

/*
 * We keep a hashtable of skins created by the ``unique''
 * methods around, hashed by type.
 *
 * try_get_unique returns the skin if it exists.
 * XXX: should implement force_get_unique.
 */
GdamSkin*       gdam_skin_try_get_unique(const char*      skin_type);



gboolean        gdam_skin_do_connect    (GdamSkin*        skin,
                                         GtkObject*       object,
			                 const char*      signal_name,
			                 int              num_handler_names,
			                 char**           handler_names);

void            gdam_skin_run_pending_initializers
                                        (GdamSkin*        skin);

GdamSkin*       gdam_skin_find_from_model(GdamModel*);


void            gdam_skin_set_whether_defined(const char* token,
                                         gboolean defined);
gboolean        gdam_skin_get_whether_defined(const char* token);

/* just find a file by filename in the skin searchpath.
 * deprecated: use gdam_search_path instead. */
const char*     gdam_skin_search_for_xml_file
                                        (const char*      skin_rel_filename);

void            gdam_skin_make_save_dialog 
                                        (GdamSkin*        skin);

void 		gdam_skin_parse_binding_file 
					(GdamSkin* 	  skin, 
    					 const char*      filename);
void 		gdam_skin_pop_up_binding_dialog 
					(GdamSkin* 	  skin);

void            gdam_skin_make_dialog   (GtkObject*       obj, 
					 gboolean         (*ok_func) 
						(GtkObject  *object, 
						 const char *filename),
					 const char*      path
					);

/* Internal use only. */

/* XXX: these should be inherited in some automatic manner... */
void            gdam_skin_add_filename_xml
                                        (GdamSkin*        skin,
					 xmlNode*         filename);
void            gdam_skin_handle_filename_xml
                                        (GdamSkin*        skin,
					 xmlNode*         node);


void            gdam_skin_connect_toplevel_notify  
                                        (GdamSkin*        skin,
                                         GdamToplevel*    toplevel);

/* connect a hotkey press/release to a skin handler */
gboolean	gdam_skin_do_key_trap   (GdamSkin* subskin, 
    		       			 GtkWidget *key_widget, 
		       			 int keycode, 
					 int is_press,
					 int num_args,
					 char **args);

GList*		gdam_skin_get_global_skin_list();
#endif
