Logo Search packages:      
Sourcecode: libjsw version File versions

fprompt.c

#include <stdio.h>
#include <stdlib.h>   
#include <string.h>
#include <sys/types.h>

#include <gdk/gdkkeysyms.h>
#include <gtk/gtk.h>

#include "guiutils.h"
#include "fprompt.h"

#ifdef MEMWATCH
# include "memwatch.h"
#endif


/* Button icons. */
#include "images/icon_ok_20x20.xpm"
#include "images/icon_cancel_20x20.xpm"
#include "images/icon_browse_20x20.xpm"


/* Floating prompt structure. */
typedef struct {

        gbool initialized;
        gbool map_state;

        gint width, height;                     /* Of toplevel. */

        GtkWidget       *toplevel,              /* Popup window. */
                        *main_hbox,
                        *label,
                        *entry,
                        *browse_btn,
                        *ok_btn,
                        *cancel_btn;

        gpointer client_data;
        gchar *(*browse_cb)(gpointer, const gchar *);
        void (*apply_cb)(gpointer, const gchar *);
        void (*cancel_cb)(gpointer);

} fprompt_struct;
static fprompt_struct fprompt;


static gint FPromptKeyEventCB(
        GtkWidget *widget, GdkEventKey *event, gpointer data
);
static void FPromptEntryActivateCB(GtkWidget *widget, gpointer data);
static void FPromptDestroyCB(GtkObject *object, gpointer data);
static void FPromptBrowseBtnCB(GtkWidget *widget, gpointer data);
static void FPromptOKBtnCB(GtkWidget *widget, gpointer data);
static void FPromptCancelBtnCB(GtkWidget *widget, gpointer data);


gint FPromptInit(void);
void FPromptSetTransientFor(GtkWidget *w);
gbool FPromptIsQuery(void);
void FPromptBreakQuery(void);
void FPromptSetPosition(gint x, gint y);
gint FPromptMapQuery(
        const gchar *label,
        const gchar *value,
        const gchar *tooltip_message,
        gint map_code,                  /* One of FPROMPT_MAP_TO_*. */
        gint width, gint height,
        guint flags,  
        gpointer client_data,
        gchar *(*browse_cb)(gpointer, const gchar *),
        void (*apply_cb)(gpointer, const gchar *),
        void (*cancel_cb)(gpointer)
);
void FPromptMap(void);
void FPromptUnmap(void);
void FPromptShutdown(void);


#define FPROMPT_BTN_WIDTH     (20 + (2 * 2))
#define FPROMPT_BTN_HEIGHT    (20 + (2 * 2))


/*
 *      Keyboard event callback.
 */
static gint FPromptKeyEventCB(
        GtkWidget *widget, GdkEventKey *key, gpointer data
)
{
        fprompt_struct *p = (fprompt_struct *)data;
        if((widget == NULL) || (key == NULL) || (p == NULL))
            return(FALSE);

        switch(key->keyval)
        {
          case GDK_Escape:
          /* Release? */
            if(!key->state)
          {
            /* Call cancel button callback. */
            FPromptCancelBtnCB(NULL, data);
          }
            return(TRUE);
            break;

        case '\n': case '\r': case GDK_KP_Enter: case GDK_ISO_Enter:
        case GDK_3270_Enter:
          /* Release? */ 
            if(!key->state)
            {
                /* Call ok button callback. */
                FPromptOKBtnCB(NULL, data);
            }
            return(TRUE);
            break;
      }

        return(FALSE);
}

/*
 *    Entry activate callback.
 */
static void FPromptEntryActivateCB(GtkWidget *widget, gpointer data)
{
      FPromptOKBtnCB(NULL, data);
      return;
}

/*
 *      Destroy callback.
 */
static void FPromptDestroyCB(GtkObject *object, gpointer data)
{
        return;
}

/*
 *    Browse button callback.
 */
static void FPromptBrowseBtnCB(GtkWidget *widget, gpointer data)
{
        fprompt_struct *p = (fprompt_struct *)data;
        if((widget == NULL) || (p == NULL))
            return;  

      if(!p->initialized)
          return;

      if(p->browse_cb != NULL)
      {
          GtkWidget *w;
          const gchar *cur_val = "";
          gchar *rtn_str;

          w = p->entry;
          if(w != NULL)
            cur_val = (const gchar *)gtk_entry_get_text(GTK_ENTRY(w));

          rtn_str = p->browse_cb(
            p->client_data,
            cur_val
          );

          w = p->entry;
          if((w != NULL) && (rtn_str != NULL))
            gtk_entry_set_text(GTK_ENTRY(w), rtn_str);
      }

        return;
}

/*
 *    OK button callback.
 */
static void FPromptOKBtnCB(GtkWidget *widget, gpointer data)
{
        fprompt_struct *p = (fprompt_struct *)data;
        if(p == NULL)
            return;

        if(!p->initialized)
            return;

        if(p->apply_cb != NULL)
      {
          GtkWidget *w;
          const gchar *cur_val = "";

          w = p->entry;
          if(w != NULL)
            cur_val = (const gchar *)gtk_entry_get_text(GTK_ENTRY(w));

            p->apply_cb(p->client_data, cur_val);
      }

        FPromptUnmap();

        return;
}

/*
 *    Close button callback.
 */
static void FPromptCancelBtnCB(GtkWidget *widget, gpointer data)
{
        fprompt_struct *p = (fprompt_struct *)data;
        if(p == NULL)
            return;

        if(!p->initialized)
            return;

      if(p->cancel_cb != NULL)
          p->cancel_cb(p->client_data);

      FPromptUnmap();

        return;
}


/*
 *    Initializes floating prompt.
 */
gint FPromptInit(void)
{
        GtkWidget *w, *parent;
        GdkWindow *window;
      fprompt_struct *p = &fprompt;

        /* Reset globals. */

        /* Reset values. */
        memset(p, 0x00, sizeof(fprompt_struct));

        p->initialized = TRUE;
        p->map_state = FALSE;


        /* Toplevel. */
        p->toplevel = w = gtk_window_new(GTK_WINDOW_DIALOG);
        gtk_widget_add_events(
            w,
            GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "key_press_event",
            GTK_SIGNAL_FUNC(FPromptKeyEventCB),
            (gpointer)p
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "key_release_event",
            GTK_SIGNAL_FUNC(FPromptKeyEventCB),
            (gpointer)p
        );
        gtk_widget_realize(w);
        window = w->window;
        if(window != NULL)
        {
            gdk_window_set_decorations(
                window, 0
            );
            gdk_window_set_functions(
                window, 0
            );
        }
      gtk_widget_set_usize(w, FPROMPT_DEF_WIDTH, FPROMPT_DEF_HEIGHT);
        gtk_signal_connect(
            GTK_OBJECT(w), "destroy",
            GTK_SIGNAL_FUNC(FPromptDestroyCB),
            (gpointer)p
        );
        gtk_container_border_width(GTK_CONTAINER(w), 0);
        parent = w;

      /* Main outer frame. */
      w = gtk_frame_new(NULL);
      gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_OUT);
      gtk_container_add(GTK_CONTAINER(parent), w);
      gtk_widget_show(w);
      parent = w;

        /* Main hbox. */
        p->main_hbox = w = gtk_hbox_new(FALSE, 0);
        gtk_container_add(GTK_CONTAINER(parent), w);
        gtk_widget_show(w);
        parent = w;

      /* Label. */
        p->label = w = gtk_label_new("Value:");
        gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_RIGHT);
      gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 2);
        gtk_widget_show(w);

      /* Entry. */
      p->entry = w = gtk_entry_new();
      GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT | GTK_CAN_FOCUS);
      gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 2);
        gtk_signal_connect(
            GTK_OBJECT(w), "activate",
            GTK_SIGNAL_FUNC(FPromptEntryActivateCB),
            (gpointer)p
        );
        gtk_widget_show(w);

      /* Browse button. */
      p->browse_btn = w = (GtkWidget *)GUIButtonPixmap(
          (u_int8_t **)icon_browse_20x20_xpm
      );
        gtk_widget_set_usize(w, FPROMPT_BTN_WIDTH, FPROMPT_BTN_HEIGHT);
        gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
        gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(FPromptBrowseBtnCB),
            (gpointer)p
        );

        /* OK button. */
        p->ok_btn = w = (GtkWidget *)GUIButtonPixmap(
            (u_int8_t **)icon_ok_20x20_xpm 
        );
        gtk_widget_set_usize(w, FPROMPT_BTN_WIDTH, FPROMPT_BTN_HEIGHT);
        gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
        gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(FPromptOKBtnCB),
            (gpointer)p 
        );

        /* Cancel button. */   
        p->cancel_btn = w = (GtkWidget *)GUIButtonPixmap(
            (u_int8_t **)icon_cancel_20x20_xpm
        );
        gtk_widget_set_usize(w, FPROMPT_BTN_WIDTH, FPROMPT_BTN_HEIGHT);
        gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
        gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(FPromptCancelBtnCB),
            (gpointer)p
        );

      /* Reset callbacks. */
      p->client_data = NULL;
      p->browse_cb = NULL;
      p->apply_cb = NULL;
      p->cancel_cb = NULL;

      return(0);
}

/*
 *      Sets prompt to be a transient for the given toplevel window
 *      widget w. If w is NULL then no transient for will be unset.
 */
void FPromptSetTransientFor(GtkWidget *w)
{
      fprompt_struct *p = &fprompt;

        if(!p->initialized)
            return;

        if(p->toplevel != NULL)
        {
            if(w != NULL)
            {
                /* Given widget if not NULL, must be a window. */
                if(!GTK_IS_WINDOW(GTK_OBJECT(w)))
                    return;

                gtk_window_set_modal(
                    GTK_WINDOW(p->toplevel), TRUE
                );
/*              gtk_grab_add(p->toplevel); */
                gtk_window_set_transient_for(
                    GTK_WINDOW(p->toplevel), GTK_WINDOW(w)
                );
            }
            else
            {
                gtk_window_set_modal(
                    GTK_WINDOW(p->toplevel), FALSE
            );
                gtk_window_set_transient_for(
                    GTK_WINDOW(p->toplevel), NULL
                );
          }
      }

      return;
}

/*
 *      Returns TRUE if currently blocking for query.
 */
gbool FPromptIsQuery(void)
{
      fprompt_struct *p = &fprompt;

        if(!p->initialized)
            return(FALSE);

      return(p->map_state);
}

/*
 *      Ends query if any and returns a not available response.
 */
void FPromptBreakQuery(void)
{
        fprompt_struct *p = &fprompt;

      /* Reset callbacks. */
        p->client_data = NULL;
        p->browse_cb = NULL;
        p->apply_cb = NULL;
        p->cancel_cb = NULL;

      /* Unmap. */
      FPromptUnmap();
      return;
}

/*
 *    Moves the floating prompt to the specified coordinates the
 *    next time it is mapped.
 */
void FPromptSetPosition(gint x, gint y)
{
      GtkWidget *w;
      fprompt_struct *p = &fprompt;

        /* Float prompt not initialized? */
        if(!p->initialized)
            return;

      w = p->toplevel;
      if(w != NULL)
          gtk_widget_set_uposition(w, x, y);

      return;
}

/*
 *    Maps the floating prompt and sets it up with the
 *    given values. Does not block execution.
 *
 *    Returns 0 on success or non-zero on error.
 */
gint FPromptMapQuery(
        const gchar *label,         /* Hides label if NULL. */
        const gchar *value,
        const gchar *tooltip_message,
      gint map_code,                /* One of FPROMPT_MAP_TO_*. */
        gint width, gint height,
        guint flags,  
        gpointer client_data,
        gchar *(*browse_cb)(gpointer, const gchar *),
        void (*apply_cb)(gpointer, const gchar *),
        void (*cancel_cb)(gpointer)
)
{
        GtkWidget *w;
      fprompt_struct *p = &fprompt;

        /* Float prompt not initialized? */
        if(!p->initialized)
            return(-1);

      /* Set new label. */
      w = p->label;
      if(w != NULL)
      {
          if(label == NULL)
          {
            gtk_widget_hide(w);
          }
          else
          {
            gtk_label_set_text(GTK_LABEL(w), label);
            gtk_widget_show(w);
          }
      }

      /* Set new entry value. */
      w = p->entry;
      if(w != NULL)
      {
          if(value != NULL)
          {
            gint len = strlen(value);

            gtk_entry_set_text(GTK_ENTRY(w), value);
            gtk_entry_select_region(GTK_ENTRY(w), 0, len);
            gtk_entry_set_position(GTK_ENTRY(w), len);
          }
          else
          {
            /* Leave value as whatever it was. */

          }

          /* Update tool tip message. */
          GUISetWidgetTip(w, tooltip_message);

          gtk_widget_grab_focus(w);
          gtk_widget_grab_default(w);
      }

      /* Show/hide buttons. */
      w = p->browse_btn;
      if(w != NULL)
      {
          if(flags & FPROMPT_FLAG_BROWSE_BTN)
            gtk_widget_show(w);
          else
            gtk_widget_hide(w);         
      }

        w = p->ok_btn;
        if(w != NULL)
        {
            if(flags & FPROMPT_FLAG_OK_BTN)
                gtk_widget_show(w);
            else
                gtk_widget_hide(w);
        }

        w = p->cancel_btn;
        if(w != NULL)
        {
            if(flags & FPROMPT_FLAG_CANCEL_BTN)
                gtk_widget_show(w);
            else
                gtk_widget_hide(w);
        }


      /* Update toplevel. */
      w = p->toplevel;
      if(w != NULL)
      {
          gint x = 0, y = 0;
          GdkWindow *window, *root;

          /* Update size of toplevel. */
          gtk_widget_set_usize(w, width, height);
          gtk_widget_queue_resize(w);

          if(width <= 0)
            p->width = w->allocation.width;
          else
            p->width = width;

            if(height <= 0)
                p->height = w->allocation.height;
            else
                p->height = height;


          /* Get parent (root) window. */
          window = w->window;
          if(window != NULL)
            root = gdk_window_get_parent(window);
          else
            root = NULL;

          /* Move toplevel, calculate x and y position relative to
           * parent window (root).
           */
          switch(map_code)
          {
            case FPROMPT_MAP_TO_POINTER_WINDOW:
            window = gdk_window_at_pointer(&x, &y);
/* This needs work. */
            gtk_widget_set_uposition(w, x, y);
            break;

            case FPROMPT_MAP_TO_POINTER:
            if(root != NULL)
            {
                gdk_window_get_pointer(root, &x, &y, 0);
                x -= (p->width / 2);
                y -= (p->height / 2);
            }
            gtk_widget_set_uposition(w, x, y);
            break;

            default:    /* FPROMPT_MAP_NO_MOVE */
            break;
          }
      }

        /* Set callbacks. */
        p->client_data = client_data;
        p->browse_cb = browse_cb;
        p->apply_cb = apply_cb;
        p->cancel_cb = cancel_cb;

      /* Map floating prompt. */
        FPromptMap();

      return(0);
}

/*
 *    Maps the floating prompt.
 */
void FPromptMap(void)
{
      fprompt_struct *p = &fprompt;
        GtkWidget *w;

        if(!p->initialized)
            return;   

        if(!p->map_state)
        {
            w = p->toplevel;
            if(w != NULL)
                gtk_widget_show(w);

            p->map_state = TRUE;
        }

        return;
}

/*
 *    Unmaps the floating prompt.
 */
void FPromptUnmap(void)
{
        fprompt_struct *p = &fprompt;
        GtkWidget *w;

        if(!p->initialized)
            return;

        if(p->map_state)
        {
            w = p->toplevel;
            if(w != NULL)   
                gtk_widget_hide(w);

            p->map_state = FALSE;
        }
            
        return;
}

/*
 *    Shuts down the floating prompt.
 */
void FPromptShutdown(void)
{
      GtkWidget **w;
        fprompt_struct *p = &fprompt;


      if(p->initialized)
      {
#define DO_DESTROY_WIDGET       \
{ \
 if((*w) != NULL) \
 { \
  GtkWidget *tmp_w = *w; \
  (*w) = NULL; \
  gtk_widget_destroy(tmp_w); \
 } \
}
          /* Begin destroying widgets. */

            w = &p->cancel_btn;
            DO_DESTROY_WIDGET

            w = &p->ok_btn;
            DO_DESTROY_WIDGET

            w = &p->browse_btn;
            DO_DESTROY_WIDGET

            w = &p->entry;
            DO_DESTROY_WIDGET

            w = &p->label;
            DO_DESTROY_WIDGET

            w = &p->main_hbox;
          DO_DESTROY_WIDGET

            w = &p->toplevel;
            DO_DESTROY_WIDGET

#undef DO_DESTROY_WIDGET
      }

      /* Clear floating prompt structure. */
        memset(p, 0x00, sizeof(fprompt_struct));
}

Generated by  Doxygen 1.6.0   Back to index