/* mguru.c - Multiway guru widget.

   Copyright (C) 1999 Perry Piplani. Idea inspired by Havoc
   Pennington's gnome-guru widget, but is a re-implemention
   from scratch.

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

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

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



#include <gnome.h>
#include "mguru.h"


enum
{
	CANCEL,
	APPLY,
	PREV,
	NEXT,
	MGURU_CLICK,
	LAST_SIGNAL
};

typedef void (*GnomeMGuruSignal2) (GtkObject *object,
					gint arg1, gint arg2, gpointer data);
typedef void (*GnomeMGuruSignal1) (GtkObject *object,
					gint arg1, gpointer data);

static void gnome_mguru_class_init     (GnomeMGuruClass *klass);
static void gnome_mguru_init           (GnomeMGuru *mguru);
static void gnome_mguru_marshal_signal1 (GtkObject *object,
					       GtkSignalFunc func,
					       gpointer func_data,
					       GtkArg *args);
static void gnome_mguru_marshal_signal2 (GtkObject *object,
					       GtkSignalFunc func,
					       gpointer func_data,
					       GtkArg *args);
static void gnome_mguru_destroy        (GtkObject *object);

static void mguru_clicked_cb (GtkWidget *widget, gpointer guru);


static void gnome_mguru_auto_state(GnomeMGuru *mguru);

static GtkVBoxClass  *parent_class = NULL;

static gint mguru_signals [LAST_SIGNAL] = { 0 };


guint gnome_mguru_get_type (void)
{
	static guint mguru_type = 0;

	if (!mguru_type){
		GtkTypeInfo mguru_info = {
			"GnomeMGuru",
			sizeof (GnomeMGuru),
			sizeof (GnomeMGuruClass),
			(GtkClassInitFunc) gnome_mguru_class_init,
			(GtkObjectInitFunc) gnome_mguru_init,
			(GtkArgSetFunc) NULL,
			(GtkArgGetFunc) NULL
		};

		mguru_type = gtk_type_unique (gtk_vbox_get_type (),
						     &mguru_info);
	}

	return mguru_type;
}

static void
gnome_mguru_class_init (GnomeMGuruClass *klass)
{
	GtkObjectClass *object_class;
	GtkWidgetClass *widget_class;

	object_class = (GtkObjectClass*) klass;
	widget_class = (GtkWidgetClass*) klass;

	object_class->destroy = gnome_mguru_destroy;

	parent_class = gtk_type_class (gtk_vbox_get_type ());


	mguru_signals[CANCEL] =
	  gtk_signal_new ("cancel",
			  GTK_RUN_LAST,
			  object_class->type,
			  GTK_SIGNAL_OFFSET (GnomeMGuruClass,
					     cancel),
			  gnome_mguru_marshal_signal1,
			  GTK_TYPE_NONE, 
			  1, GTK_TYPE_INT);
	mguru_signals[APPLY] =
	  gtk_signal_new ("apply",
			  GTK_RUN_LAST,
			  object_class->type,
			  GTK_SIGNAL_OFFSET (GnomeMGuruClass,
					     apply),
			  gnome_mguru_marshal_signal1,
			  GTK_TYPE_NONE, 
			  1, GTK_TYPE_INT);
	mguru_signals[PREV] =
	  gtk_signal_new ("prev",
			  GTK_RUN_LAST,
			  object_class->type,
			  GTK_SIGNAL_OFFSET (GnomeMGuruClass,
					     prev),
			  gnome_mguru_marshal_signal1,
			  GTK_TYPE_NONE, 
			  1, GTK_TYPE_INT);
	mguru_signals[NEXT] =
	  gtk_signal_new ("next",
			  GTK_RUN_LAST,
			  object_class->type,
			  GTK_SIGNAL_OFFSET (GnomeMGuruClass,
					     next),
			  gnome_mguru_marshal_signal1,
			  GTK_TYPE_NONE, 
			  1, GTK_TYPE_INT);
	mguru_signals[MGURU_CLICK] =
	  gtk_signal_new ("mguru_click",
			  GTK_RUN_LAST,
			  object_class->type,
			  GTK_SIGNAL_OFFSET (GnomeMGuruClass,
					     mguru_click),
			  gnome_mguru_marshal_signal2,
			  GTK_TYPE_NONE, 
			  2, GTK_TYPE_INT, GTK_TYPE_INT);
	gtk_object_class_add_signals (object_class, mguru_signals,
				      LAST_SIGNAL);

	klass->mguru_click = NULL;
	klass->cancel = NULL;
	klass->apply  = NULL;
	klass->prev  = NULL;
	klass->next  = NULL;
}

static void
gnome_mguru_marshal_signal1 (GtkObject *object,
				   GtkSignalFunc func,
				   gpointer func_data,
				   GtkArg *args)
{
	GnomeMGuruSignal1 rfunc;

	rfunc = (GnomeMGuruSignal1) func;
	(* rfunc) (object, GTK_VALUE_INT (args[0]) ,func_data);
}


static void
gnome_mguru_marshal_signal2 (GtkObject *object,
				   GtkSignalFunc func,
				   gpointer func_data,
				   GtkArg *args)
{
	GnomeMGuruSignal2 rfunc;

	rfunc = (GnomeMGuruSignal2) func;
	(* rfunc) (object, GTK_VALUE_INT (args[0]), 
		   GTK_VALUE_INT (args[1]),func_data);
}

static void
gnome_mguru_init (GnomeMGuru *mguru)
{
	mguru->notebook = gtk_notebook_new ();
	gtk_notebook_set_show_tabs(GTK_NOTEBOOK (mguru->notebook),FALSE);
	gtk_notebook_set_show_border(GTK_NOTEBOOK (mguru->notebook),FALSE);

}

static void
gnome_mguru_destroy (GtkObject *object)
{
	GnomeMGuru *mguru;

	g_return_if_fail (object != NULL);
	g_return_if_fail (GNOME_IS_MGURU (object));

	mguru = GNOME_MGURU (object);

	GTK_OBJECT_CLASS (parent_class)->destroy (object);
}


GtkWidget *gnome_mguru_new (gint multiway, 
			    GnomeDialog *dialog,
 			    GtkWidget   * graphic){
  GtkWidget *mguru;
  GList *button_list;
  gint i=0;
  GtkWidget *buttonbox;
  GtkWidget *hbox;
  
  mguru = gtk_type_new (gnome_mguru_get_type ());
  GNOME_MGURU(mguru)->multi = multiway;

  hbox=gtk_hbox_new(FALSE,0);
  gtk_box_pack_start (GTK_BOX(mguru),
		      hbox,
		      TRUE, TRUE, 0);
  if(!dialog)
    gtk_container_border_width (GTK_CONTAINER (hbox), 5);
  gtk_widget_show (hbox);

  if (graphic) {
    GtkWidget* frame;
    frame = gtk_frame_new(NULL);
    gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
    
    gtk_widget_show (frame);
    
    gtk_container_add(GTK_CONTAINER(frame),
                      graphic);
    gtk_widget_show (graphic);

    gtk_box_pack_start (GTK_BOX(hbox),
			frame,
			FALSE, FALSE, 0);

  }
    

  gtk_box_pack_start (GTK_BOX(hbox),
		      GNOME_MGURU(mguru)->notebook,
		      TRUE, TRUE, 0);
  gtk_widget_show (GNOME_MGURU(mguru)->notebook);


  if(dialog){

    GNOME_MGURU(mguru)->dialog = GTK_WIDGET(dialog);
	
    gnome_dialog_append_buttons (GNOME_DIALOG (dialog),
				 GNOME_STOCK_BUTTON_CANCEL,
				 GNOME_STOCK_BUTTON_PREV,
				 GNOME_STOCK_BUTTON_NEXT,
				 GNOME_STOCK_BUTTON_APPLY,
				 NULL);
	

    button_list = GNOME_DIALOG(dialog)->buttons;
    while(button_list){
      GNOME_MGURU(mguru)->button[i] = GTK_WIDGET(button_list->data);
      gtk_signal_connect(GTK_OBJECT(GNOME_MGURU(mguru)->button[i]),
			 "clicked",
			 GTK_SIGNAL_FUNC(mguru_clicked_cb),
			 mguru);    
      button_list = button_list->next;
      i++;
    }
    
    gtk_box_pack_start(GTK_BOX(GNOME_DIALOG(dialog)->vbox),
		       mguru, TRUE, TRUE, 0);
  }

  else{
    
    buttonbox = gtk_hbutton_box_new();
    gtk_container_set_border_width(GTK_CONTAINER(buttonbox),   
                             GNOME_PAD_SMALL); 
    gtk_box_pack_end(GTK_BOX(mguru),
                      buttonbox,
                      FALSE, FALSE, 0);
    
    GNOME_MGURU(mguru)->button[MGURU_BUTTON_CANCEL] = gnome_stock_button(GNOME_STOCK_BUTTON_CANCEL);
    GNOME_MGURU(mguru)->button[MGURU_BUTTON_PREV] = gnome_stock_button(GNOME_STOCK_BUTTON_PREV);
    GNOME_MGURU(mguru)->button[MGURU_BUTTON_NEXT] = gnome_stock_button(GNOME_STOCK_BUTTON_NEXT);
    GNOME_MGURU(mguru)->button[MGURU_BUTTON_APPLY] = gnome_stock_button(GNOME_STOCK_BUTTON_APPLY);

    for(i=0;i < MGURU_LAST_BUTTON; i++){
      gtk_box_pack_start(GTK_BOX(buttonbox),
			 GNOME_MGURU(mguru)->button[i],
			 FALSE, FALSE, 0);
      gtk_signal_connect(GTK_OBJECT(GNOME_MGURU(mguru)->button[i]),
			 "clicked",
			 GTK_SIGNAL_FUNC(mguru_clicked_cb),
			 mguru);
    }
    gtk_widget_show_all(buttonbox);
  }
  return mguru;
  
}

static void
mguru_clicked_cb(GtkWidget *widget, gpointer guru){

  gint page;
  gint butt;

  GnomeMGuru *mguru;
  mguru = GNOME_MGURU (guru);

  page=gnome_mguru_get_page(mguru);


  for(butt = 3; butt >= 0; butt--)
    if(mguru->button[butt] == widget)
      break;
  
  gtk_widget_ref(GTK_WIDGET(mguru));

  if(butt == 0)
    gtk_signal_emit (GTK_OBJECT (mguru), 
		     mguru_signals[CANCEL], 
		     page);
  if(butt == 1)
    gtk_signal_emit (GTK_OBJECT (mguru), 
		     mguru_signals[PREV], 
		     page);
  if(butt == 2)
    gtk_signal_emit (GTK_OBJECT (mguru), 
		     mguru_signals[NEXT], 
		     page);
  if(butt == 3)
    gtk_signal_emit (GTK_OBJECT (mguru), 
		     mguru_signals[APPLY], 
		     page);
  
  gtk_signal_emit (GTK_OBJECT (mguru), 
		   mguru_signals[MGURU_CLICK],
		   page,
		   butt);

  if(!mguru->multi){
    switch(butt){
    case 1:
      gnome_mguru_prev_page(mguru);
      break;
    case 2:
      gnome_mguru_next_page(mguru);
      break;
    }
  }  
  gtk_widget_unref(GTK_WIDGET(mguru));  
  return;

} 

gint  gnome_mguru_append_page (GnomeMGuru *mguru,
			       GtkWidget *child, 
			       gchar *title){

  GtkWidget *frame;
  
  g_return_val_if_fail (mguru != NULL, -1);
  g_return_val_if_fail (GNOME_IS_MGURU (mguru), -1);
  g_return_val_if_fail (child != NULL, -1);
  g_return_val_if_fail (GTK_IS_WIDGET (child), -1);
	
  frame = gtk_frame_new (title);
  gtk_container_border_width (GTK_CONTAINER (frame), 10);
  gtk_notebook_append_page (GTK_NOTEBOOK (mguru->notebook),
			    frame, NULL);
  gtk_widget_show (frame);

  gtk_container_add (GTK_CONTAINER (frame), child);

  if(!mguru->multi)
    gnome_mguru_auto_state(mguru);


	return g_list_length (
		GTK_NOTEBOOK(mguru->notebook)->children) - 1;
}

void gnome_mguru_set_page(GnomeMGuru *mguru, gint page){
  
  g_return_if_fail (mguru != NULL);
  g_return_if_fail (GNOME_IS_MGURU (mguru));

  gtk_notebook_set_page(GTK_NOTEBOOK(mguru->notebook),page);

  if(!mguru->multi)
    gnome_mguru_auto_state(mguru);


return;

}


gint gnome_mguru_get_page(GnomeMGuru *mguru){

  g_return_val_if_fail (mguru != NULL, -1);
  g_return_val_if_fail (GNOME_IS_MGURU (mguru), -1);


  return gtk_notebook_get_current_page(GTK_NOTEBOOK(mguru->notebook));

}

GtkWidget *gnome_mguru_get_page_child(GnomeMGuru *mguru, gint page){
  GtkWidget *frame;
  
  g_return_val_if_fail (mguru != NULL, NULL);
  g_return_val_if_fail (GNOME_IS_MGURU (mguru), NULL);

  frame =  gtk_notebook_get_nth_page(GTK_NOTEBOOK(mguru->notebook),page);
  return GTK_BIN(frame)->child;

}


void gnome_mguru_next_page(GnomeMGuru *mguru){
  
  g_return_if_fail (mguru != NULL);
  g_return_if_fail (GNOME_IS_MGURU (mguru));

  gtk_notebook_next_page(GTK_NOTEBOOK(mguru->notebook));

  if(!mguru->multi)
    gnome_mguru_auto_state(mguru);
  
  return;

}

void gnome_mguru_prev_page(GnomeMGuru *mguru){
  
  g_return_if_fail (mguru != NULL);
  g_return_if_fail (GNOME_IS_MGURU (mguru));

  gtk_notebook_prev_page(GTK_NOTEBOOK(mguru->notebook));

  if(!mguru->multi)
    gnome_mguru_auto_state(mguru);

  return;

}

void gnome_mguru_set_state(GnomeMGuru *mguru, GnomeMGuruState state){

  g_return_if_fail (mguru != NULL);
  g_return_if_fail (GNOME_IS_MGURU (mguru));

  switch(state){
  case GNOME_MGURU_START:
    gtk_widget_set_sensitive(mguru->button[1],FALSE);
    gtk_widget_set_sensitive(mguru->button[2],TRUE);
    gtk_widget_set_sensitive(mguru->button[3],FALSE);
    break;
  case GNOME_MGURU_MIDDLE:
    gtk_widget_set_sensitive(mguru->button[1],TRUE);
    gtk_widget_set_sensitive(mguru->button[2],TRUE);
    gtk_widget_set_sensitive(mguru->button[3],FALSE);
    break;
  case GNOME_MGURU_LAST:
    gtk_widget_set_sensitive(mguru->button[1],TRUE);
    gtk_widget_set_sensitive(mguru->button[2],FALSE);
    gtk_widget_set_sensitive(mguru->button[3],TRUE);
    break; 
  case GNOME_MGURU_ONLY:
    gtk_widget_set_sensitive(mguru->button[1],FALSE);
    gtk_widget_set_sensitive(mguru->button[2],FALSE);
    gtk_widget_set_sensitive(mguru->button[3],TRUE);
    break; 
  }

  mguru->state=state;

}

void gnome_mguru_auto_state(GnomeMGuru *mguru){
  int length;
  int current;

  length = g_list_length (GTK_NOTEBOOK(mguru->notebook)->children);
  
  if(!length)
    return;

  if(length == 1){
    gnome_mguru_set_state(mguru,GNOME_MGURU_ONLY);
    return;
  }

  current = gnome_mguru_get_page(mguru);
  if(current < 1)
    gnome_mguru_set_state(mguru,GNOME_MGURU_START);
  else if(current == length-1)
    gnome_mguru_set_state(mguru,GNOME_MGURU_LAST);
  else 
    gnome_mguru_set_state(mguru,GNOME_MGURU_MIDDLE);
  return;

}
 

    
  


syntax highlighted by Code2HTML, v. 0.9.1