/* user_shortcuts.c
 *
 * Dialogs and infrastructure for defining and using user defined shortcuts
 */
/* GTKeyboard - A Graphical Keyboard For X
 * Copyright (C) 1999, 2000 David Allen  
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, 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
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Library 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.
 */

#include "master.h"
#define HBOXES                  SHORTCUTS
#define INSTALL_ALL_SHORTCUTS   1000  /* Make this higher than the number of 
				       * shortcuts
				       */
typedef struct{
     GtkWidget *hbox;        /* Box everything resides in */
     /* GtkWidget *chooser; */
     GtkWidget *label;
     GtkWidget *installer;
     GtkWidget *clear;
} ds_row;

/* Entry widgets for all the shortcut defines */
GtkWidget *entries[SHORTCUTS];
/* Toplevel configuration window */
GtkWidget *swindow;

/* Static Prototypes */
static void install_shortcut           (GtkWidget *emitter, gpointer data);
static void ask_define                 (GtkWidget *emitter, int data);
static void clear_shortcut_box         (GtkWidget *emitter, gpointer data);
/*************************         *******************************/

void define_shortcuts(GtkWidget *emitter, gpointer data)
{
     GtkWidget *bigbox, *toplabel, *nextlabel;
     ds_row shortcuts;
     GtkWidget *install  = gtk_button_new_with_label("Install ALL shortcuts");
     GtkWidget *okbutton, *cancel;
     GtkWidget *hbox     = gtk_hbox_new(FALSE, 0);
     GtkWidget *vbox;
     GtkWidget *align    = gtk_alignment_new(0.5, 0.5, 0, 0);
     int x;
     char buffer[512];
     char *str = "User Configurable Shortcuts:";
     char *str2= "Click on \"Define\" to commit each shortcut";

     if(data)
	  gtk_widget_destroy((GtkWidget *)data);

     /* Load the shortcuts from the file on disk */
     chocolate("Loading shortcuts from file on disk.\n");
     if(!gtkeyboard_load_shortcuts())
     {
	  gtkeyboard_error(1,"Couldn't load shortcuts from file on disk.\n");
     } /* End if */

     toplabel = gtk_label_new(str);
     nextlabel= gtk_label_new(str2);

     swindow  = gtk_dialog_new();
     okbutton =  create_ok_button(GTK_SIGNAL_FUNC(gtkeyboard_save_shortcuts), 
				  swindow);
     cancel   = create_cancel_button(swindow);

     bigbox = gtk_vbox_new(FALSE, 0);

     gtk_signal_connect(GTK_OBJECT(install), "clicked",
			GTK_SIGNAL_FUNC(install_shortcut), 
			(gpointer)INSTALL_ALL_SHORTCUTS);
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(swindow)->vbox), toplabel,
			FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(swindow)->vbox), nextlabel,
			FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(swindow)->action_area), bigbox, 
			FALSE, FALSE, 0);


     for(x=0; x<SHORTCUTS; x++)
     {
	  entries[x] = gtk_entry_new_with_max_length(SHORTCUT_MAX_LENGTH);

	  /* If a shortcut is known, add it in the box */
	  if(options.shortcuts[x]!=(char *)NULL)
	  {
	       gtk_entry_set_text(GTK_ENTRY(entries[x]),
				  options.shortcuts[x]);
	  } /* End if */
	  /* User can edit these boxes.  */
	  gtk_entry_set_editable(GTK_ENTRY(entries[x]), TRUE);
     } /* End for */

     for(x=0; x<SHORTCUTS; x++)
     {
	  sprintf(buffer,"Define Shortcut #%d:   ",(x+1));
	  shortcuts.label     = gtk_label_new(buffer);
	  shortcuts.hbox      = gtk_hbox_new(FALSE, 0);
	  shortcuts.installer = gtk_button_new_with_label("Define");
	  shortcuts.clear     = gtk_button_new_with_label(" C ");

	  gtk_signal_connect(GTK_OBJECT(shortcuts.clear), "clicked",
			     GTK_SIGNAL_FUNC(clear_shortcut_box), (gpointer)x);
	  gtk_signal_connect(GTK_OBJECT(shortcuts.installer), "clicked",
			     GTK_SIGNAL_FUNC(install_shortcut), 
			     (gpointer)x);

	  gtk_box_pack_start(GTK_BOX(shortcuts.hbox), shortcuts.label,
			     FALSE, FALSE, 0);
	  gtk_box_pack_start(GTK_BOX(shortcuts.hbox), entries[x],
			     FALSE, FALSE, 0);
	  gtk_box_pack_start(GTK_BOX(shortcuts.hbox), shortcuts.installer,
			     FALSE, FALSE, 0);
	  gtk_box_pack_start(GTK_BOX(shortcuts.hbox), shortcuts.clear,
			     FALSE, FALSE, 0);
	  gtk_box_pack_start(GTK_BOX(bigbox), shortcuts.hbox,
			     FALSE, FALSE, 0);

	  gtk_widget_show(shortcuts.hbox);
	  gtk_widget_show(shortcuts.label);
	  gtk_widget_show(entries[x]);
	  gtk_widget_show(shortcuts.installer);
	  gtk_widget_show(shortcuts.clear);
     } /* End for */

     vbox  = gtk_vbox_new(FALSE, 0);
     
     gtk_box_pack_start(GTK_BOX(vbox),  install, FALSE, FALSE, 0);

     gtk_box_pack_start(GTK_BOX(hbox), okbutton, FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(hbox),   cancel, FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(hbox),     vbox, FALSE, FALSE, 0);

     gtk_container_add(GTK_CONTAINER(align), hbox);
     gtk_box_pack_start(GTK_BOX(bigbox),  align, FALSE, FALSE, 0);

     gtkeyboard_window_common_setup(swindow);
     gtk_widget_show_all(swindow);
     gtk_main();
} /* End define_shortcuts */

static void clear_shortcut_box(GtkWidget *emitter, gpointer data)
{
     int x = (int)data;
     
     if(entries[x] && GTK_IS_WIDGET(entries[x]))
	  gtk_entry_set_text(GTK_ENTRY(entries[x]), "");
     else gtkeyboard_error(1,"Error in clear_shortcut_box:  Uninitialized.\n");
} /* End clear_shortcut_box() */

static void install_shortcut(GtkWidget *emitter, gpointer data)
{
     int x = (int) data;
     gchar *foobar;

     gtkeyboard_message(1,"Getting information from shortcut dialog...\n");

     if(x == INSTALL_ALL_SHORTCUTS)
     {
	  for(x=0; x<SHORTCUTS; x++)
	  {
	       if(!entries[x])
		    fprintf(Q,"Error:  !entries[%d]\n",x);
	       else
	       {
		    foobar = gtk_entry_get_text(GTK_ENTRY(entries[x]));

		    if(options.shortcuts[x])
		    {
			 gtkeyboard_message(3,"Eliminated old shortcut ",
					    options.shortcuts[x],"\n");
			 g_free_(options.shortcuts[x]);
			 options.shortcuts[x] = NULL;
		    } /* End else */
		    
		    options.shortcuts[x] = g_strdup_(foobar);
		    gtkeyboard_message(3,"Added new shortcut:  ",
				       options.shortcuts[x],"\n");
	       } /* End else */
	  } /* End for */

	  return;
     } /* End if */
     else
     {
	  if(x>=SHORTCUTS || x<0)  /* Out of range.  BAD */
	  {
	       fprintf(stderr,"ERROR:  install_shortcut got passed ");
	       fprintf(stderr,"passer x = %d\n",x);
	       
	       /* Let the user know what the score is */
	       chocolate("\n\n*****************\n");
	       chocolate("There was an error installing a shortcut.  ");
	       chocolate("Report this bug to bug-gtkeyboard@gnu.org ");
	       chocolate("with info on what you were doing at the time.\n");
	       chocolate("*******************\n\n");
	       return;       /* Get out or segfault */
	  } /* End if */
	  
	  if(!entries[x])
	       fprintf(Q,"Error:  !entries[%d]\n",x);
	  
	  foobar = gtk_entry_get_text(GTK_ENTRY(entries[x]));
	  
	  if(options.shortcuts[x])
	  {
	       gtkeyboard_message(3,"Eliminated old shortcut ",
				  options.shortcuts[x],"\n");
	       g_free_(options.shortcuts[x]);
	       options.shortcuts[x] = NULL;
	  } /* End else */
	  
	  options.shortcuts[x] = g_strdup_(foobar);
	  
	  gtkeyboard_message(3,"Added new shortcut:  ",options.shortcuts[x],
			     "\n");
     } /* End else */
} /* End install_shortcut */

/* Process the user shortcut referred to by x.  IT IS THE CALLERS 
 * RESPONSIBILITY TO MAKE SURE ITS WITHIN BOUNDS.  (as in, people should
 * pass 0 if they want the first shortcut, NOT 1)  The shortcut fails if
 * the reference is out of bounds.
 */
void do_shortcut(GtkWidget *emitter, gpointer data)
{
     int x = (int) data;
     int len = 0;
     long pos = 0;
     long length = 0;
     char errorbuf[1024];

     if(x<0 || x>=SHORTCUTS)
     {
	  sprintf(errorbuf,"Error: caller of do_shortcut sent %d which ",x);
	  strcat(errorbuf,"is out of bounds.  This needs to be fixed.\n");
	  gtkeyboard_error(1,errorbuf);
	  return;
     } /* End if */

     if(options.shortcuts[x] != (char *)NULL)
     {
	  if(options.VERBOSE)
	       gtkeyboard_message(1,"Processing user shortcut...\n");

	  /* Let vanilla worry about whether or not there was a redirect
	   * window 
	   */
	  len = strlen(options.shortcuts[x]);
	  pos = GET_POINT;
	 
	  vanilla(options.shortcuts[x]);

	  length = GET_LENGTH;

	  if(pos + len <= length)
	  {
	       /* Set the point to right after where we inserted the text */
	       SET_POINT((pos+len));
	  }
     } /* End if */
     else
     {
	  ask_define((GtkWidget *)NULL, x);
	  gtkeyboard_error(1,"User shortcut undefined.\n");
     } /* End else */
} /* End do_shortcut */

/* This is a popup box that asks the user if they want to define
 * some shortcuts.  It only pops up when a user tries to use an 
 * undefined shortcut
 */
static void ask_define(GtkWidget *emitter, int data)
{
     GtkWidget *popup = gtk_dialog_new();
     GtkWidget *yes = gtk_button_new_with_label("Yes");
     GtkWidget *no  = gtk_button_new_with_label("No");
     char buffer[512];
     GtkWidget *label;

     sprintf(buffer,"Shortcut #%d is not defined.  Do you want to define it?",
	     data);
     label = gtk_label_new(buffer);

     gtk_signal_connect(GTK_OBJECT(yes), "clicked",
			GTK_SIGNAL_FUNC(define_shortcuts), popup);
     gtk_signal_connect(GTK_OBJECT(no), "clicked",
			GTK_SIGNAL_FUNC(smack), popup);
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup)->vbox), label,
			FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup)->action_area), yes,
			FALSE, FALSE, 0);
     gtk_box_pack_start(GTK_BOX(GTK_DIALOG(popup)->action_area), no,
			FALSE, FALSE, 0);

     gtk_window_set_position(GTK_WINDOW(popup), GTK_WIN_POS_CENTER);

     gtkeyboard_window_common_setup(popup);
     gtk_widget_show_all(popup);
} /* End ask_define */
