#include <gtk/gtk.h>
#include "guiutils.h"
#include "tview.h"
#include "tviewcb.h"


gint TViewDeleteEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
);
void TViewRealizeCB(GtkWidget *widget, gpointer data);
void TViewChangedCB(GtkEditable *editable, gpointer data);
void TViewCutCB(GtkWidget *widget, gpointer data);
void TViewCopyCB(GtkWidget *widget, gpointer data);
void TViewPasteCB(GtkWidget *widget, gpointer data);
void TViewDeleteTextCB(GtkWidget *widget, gpointer data);
void TViewSelectAllCB(GtkWidget *widget, gpointer data);
void TViewUnselectAllCB(GtkWidget *widget, gpointer data);


#define ATOI(s)         (((s) != NULL) ? atoi(s) : 0)
#define ATOL(s)         (((s) != NULL) ? atol(s) : 0)
#define ATOF(s)         (((s) != NULL) ? atof(s) : 0.0f)
#define STRDUP(s)       (((s) != NULL) ? g_strdup(s) : NULL)

#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRLEN(s)       (((s) != NULL) ? strlen(s) : 0)
#define STRISEMPTY(s)   (((s) != NULL) ? (*(s) == '\0') : TRUE)


/*
 *	File View toplevel GtkWindow "delete_event" signal callback.
 */
gint TViewDeleteEventCB(
	GtkWidget *widget, GdkEvent *event, gpointer data
)
{
	tview_struct *tv = TVIEW(data);
	if(tv == NULL)
	    return(FALSE);

	TViewUnmap(tv);
	return(TRUE);
}

/*
 *	File View GtkText any event signal callback.
 */
gint TViewTextEventCB(GtkWidget *widget, GdkEvent *event, gpointer data)
{
	gint status = FALSE;
	gint etype;
	GdkEventConfigure *configure;
	GdkEventButton *button;
	tview_struct *tv = TVIEW(data);
	if((widget == NULL) || (event == NULL) || (tv == NULL))
	    return(status);

	etype = (gint)event->type;
	switch(etype)
	{
	  case GDK_CONFIGURE:
	    configure = (GdkEventConfigure *)event;
	    if(widget->window != NULL)
	    {
		GdkWindow *window = widget->window;
		gdk_window_set_cursor(
		    window,
		    (tv->busy_count > 0) ?
			tv->busy_cur : tv->text_cur
		);
		status = TRUE;
	    }
	    break;

	  case GDK_BUTTON_PRESS:
	    button = (GdkEventButton *)event;
	    switch(button->button)
	    {
	      case GDK_BUTTON3:
		/* Popup menu */
		if(tv->menu != NULL)
		{
		    GtkWidget *w = tv->menu;

		    gtk_menu_popup(
			GTK_MENU(w),
			NULL, NULL, NULL, tv,
			button->button, button->time
		    );
		}
		/* Need to mark the GtkText button as 0 or else it will
		 * keep marking
		 */
		GTK_TEXT(widget)->button = 0;
		gtk_grab_remove(widget);
		gtk_signal_emit_stop_by_name(
		    GTK_OBJECT(widget), "button_press_event"
		);
		status = TRUE;
		break;

	      case GDK_BUTTON4:
		/* Scroll up */
		if(tv->vadj != NULL)
		{
		    GtkAdjustment *adj = tv->vadj;
		    const gfloat inc = MAX(
			(0.25f * adj->page_size),
			adj->step_increment
		    );
		    gfloat v = adj->value - inc;
		    if(v > (adj->upper - adj->page_size))
			v = adj->upper - adj->page_size;
		    if(v < adj->lower)
			v = adj->lower;
		    gtk_adjustment_set_value(adj, v);
		}
		/* Need to mark the GtkText button as 0 or else it will
		 * keep marking
		 */
		GTK_TEXT(widget)->button = 0;
		gtk_grab_remove(widget);
                gtk_signal_emit_stop_by_name(
                    GTK_OBJECT(widget), "button_press_event"
                );
		status = TRUE;
		break;

	      case GDK_BUTTON5:
		/* Scroll down */
		if(tv->vadj != NULL)
		{
		    GtkAdjustment *adj = tv->vadj;
		    const gfloat inc = MAX(
			(0.25f * adj->page_size),
			adj->step_increment
		    );
		    gfloat v = adj->value + inc;
		    if(v > (adj->upper - adj->page_size))
			v = adj->upper - adj->page_size;
		    if(v < adj->lower)
			v = adj->lower;
		    gtk_adjustment_set_value(adj, v);
		}
		/* Need to mark the GtkText button as 0 or else it will
		 * keep marking
		 */
		GTK_TEXT(widget)->button = 0;
		gtk_grab_remove(widget);
                gtk_signal_emit_stop_by_name(
                    GTK_OBJECT(widget), "button_press_event"
                );
		status = TRUE;
		break;
	    }
	    break;

	  case GDK_BUTTON_RELEASE:
	    button = (GdkEventButton *)event;
	    /* Update so we know about selection changes */
	    TViewUpdate(tv);
	    switch(button->button)
	    {
	      case GDK_BUTTON3:
		/* Need to mark the GtkText button as 0 or else it will
		 * keep marking
		 */
		GTK_TEXT(widget)->button = 0;
		gtk_grab_remove(widget);
		gtk_signal_emit_stop_by_name(                   
		    GTK_OBJECT(widget), "button_release_event"
		);
		status = TRUE;
		break;
	      case GDK_BUTTON4:
		/* Need to mark the GtkText button as 0 or else it will
		 * keep marking
		 */
		GTK_TEXT(widget)->button = 0;
		gtk_grab_remove(widget);
		gtk_signal_emit_stop_by_name(                   
		    GTK_OBJECT(widget), "button_release_event"
		);
		status = TRUE;
		break;
	      case GDK_BUTTON5:
		/* Need to mark the GtkText button as 0 or else it will
		 * keep marking
		 */
		GTK_TEXT(widget)->button = 0;
		gtk_grab_remove(widget);
		gtk_signal_emit_stop_by_name(                   
		    GTK_OBJECT(widget), "button_release_event"
		);
		status = TRUE;
		break;
	    }
	    break;
	}

	return(status);
}

/*
 *	File View GtkText "changed" signal callback.
 */
void TViewChangedCB(GtkEditable *editable, gpointer data)
{
	tview_struct *tv = TVIEW(data);
	if((editable == NULL) || (tv == NULL))
	    return;


	/* See which widget this signal is for */

	/* Text */
	if(GTK_WIDGET(editable) == tv->text) 
	{
	    if(!tv->has_changes)
	    {
		tv->has_changes = TRUE;
		TViewUpdate(tv);
	    }

	    if(tv->changed_cb != NULL)
		tv->changed_cb(
		    tv,			/* File View */
		    tv->changed_data	/* Data */
		);
	}
}

/*
 *	File View Cut callback.
 */
void TViewCutCB(GtkWidget *widget, gpointer data)
{
	tview_struct *tv = TVIEW(data);
	if(tv == NULL)
	    return;

	TViewSetBusy(tv, TRUE);
	TViewCut(tv);
	TViewSetBusy(tv, FALSE);
}

/*
 *	File View Copy callback.
 */
void TViewCopyCB(GtkWidget *widget, gpointer data)
{
	tview_struct *tv = TVIEW(data);
	if(tv == NULL)
	    return;

	TViewSetBusy(tv, TRUE);
	TViewCopy(tv);
	TViewSetBusy(tv, FALSE);
}

/*
 *	File View Paste callback.
 */
void TViewPasteCB(GtkWidget *widget, gpointer data)
{
	tview_struct *tv = TVIEW(data);
	if(tv == NULL)
	    return;

	TViewSetBusy(tv, TRUE);
	TViewPaste(tv);
	TViewSetBusy(tv, FALSE);
}

/*
 *	File View Delete Text callback.
 */
void TViewDeleteTextCB(GtkWidget *widget, gpointer data)
{
	tview_struct *tv = TVIEW(data);
	if(tv == NULL)
	    return;

	TViewSetBusy(tv, TRUE);
	TViewDeleteText(tv);
	TViewSetBusy(tv, FALSE);
}

/*
 *	File View Select All callback.
 */
void TViewSelectAllCB(GtkWidget *widget, gpointer data)
{
	tview_struct *tv = TVIEW(data);
	if(tv == NULL)
	    return;

	TViewSetBusy(tv, TRUE);
	TViewSelectAll(tv);
	TViewSetBusy(tv, FALSE);
}

/*
 *	File View Unselect All callback.
 */
void TViewUnselectAllCB(GtkWidget *widget, gpointer data)
{
	tview_struct *tv = TVIEW(data);
	if(tv == NULL)
	    return;

	TViewSetBusy(tv, TRUE);
	TViewUnselectAll(tv);
	TViewSetBusy(tv, FALSE);
}


