Logo Search packages:      
Sourcecode: vertex 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 gint FPromptDeleteEventCB(
        GtkWidget *widget, GdkEvent *event, 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
)
{
      static gbool reenterent = FALSE;
      gint status = FALSE;
        gint etype;
        guint keyval, state;
        gbool press;
        fprompt_struct *p = (fprompt_struct *)data;
        if((widget == NULL) || (key == NULL) || (p == NULL))
            return(status);

        if(reenterent)
            return(status);
        else
            reenterent = TRUE;

        /* Get event type. */
        etype = key->type;

        /* Get other key event values. */
        press = (etype == GDK_KEY_PRESS) ? TRUE : FALSE;
        keyval = key->keyval;
        state = key->state;

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

        case GDK_Return:
        case GDK_KP_Enter:
        case GDK_ISO_Enter:
        case GDK_3270_Enter:
          /* Release? */ 
            if(!press)
            {
                /* Call ok button callback. */
                FPromptOKBtnCB(NULL, data);
            }
          status = TRUE;
            break;
      }

      reenterent = FALSE;
        return(status);
}

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

/*
 *    Toplevel GtkWindow "delete_event" signal callback.
 */
static gint FPromptDeleteEventCB(
        GtkWidget *widget, GdkEvent *event, gpointer data
)
{
      FPromptCancelBtnCB(widget, data);
      return(TRUE);
}

/*
 *      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;

      /* Browse callback function set? */
      if(p->browse_cb != NULL)
      {
          GtkWidget *w;
          const gchar *cur_val = "";
          const gchar *rtn_str;


          /* Get current value. */
          w = p->entry;
          if(w != NULL)
            cur_val = (const gchar *)gtk_entry_get_text(GTK_ENTRY(w));

          /* Call browse callback and expect a statically allocated
           * return string.
           */
          rtn_str = p->browse_cb(
            p->client_data,
            cur_val
          );

          /* Set new value given by the browse callback function. */
          w = p->entry;
          if((w != NULL) && (rtn_str != NULL))
            gtk_entry_set_text(GTK_ENTRY(w), rtn_str);
      }
}

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

        if(!p->initialized)
            return;

      /* Apply callback function set? */
        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));

          /* Call apply callback function. */
            p->apply_cb(p->client_data, cur_val);
      }

        FPromptUnmap();
}

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

        if(!p->initialized)
            return;

      /* Cancel callback function set? */
      if(p->cancel_cb != NULL)
      {
          /* Call cancel callback function. */
          p->cancel_cb(p->client_data);
      }

      FPromptUnmap();
}


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

        /* Reset values. */
        memset(p, 0x00, sizeof(fprompt_struct));
        p->initialized = TRUE;
        p->map_state = FALSE;

        /* Toplevel. */
      p->toplevel = w = gtk_window_new(
#ifdef __MSW__
          /* On Win32 it can be a popup */
          GTK_WINDOW_POPUP
#else
          /* Got to be a dialog for key events to be received */
          GTK_WINDOW_DIALOG
#endif
      );
        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), p
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "key_release_event",
            GTK_SIGNAL_FUNC(FPromptKeyEventCB), p
        );
        gtk_widget_realize(w);
        window = w->window;
        if(window != NULL)
        {
          /* No decorations. */
            gdk_window_set_decorations(window, 0);
          /* No functions. */
          gdk_window_set_functions(window, 0);
        }
      gtk_widget_set_usize(w, FPROMPT_DEF_WIDTH, FPROMPT_DEF_HEIGHT);
        gtk_signal_connect(
            GTK_OBJECT(w), "delete_event",
            GTK_SIGNAL_FUNC(FPromptDeleteEventCB), p
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "destroy",
            GTK_SIGNAL_FUNC(FPromptDestroyCB), 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, border_minor);
        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, 0);
        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, 0);
/*
        gtk_signal_connect(
            GTK_OBJECT(w), "activate",
            GTK_SIGNAL_FUNC(FPromptEntryActivateCB), 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), 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), 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), 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;

#ifndef __MSW__
/* In Win32, this should not be set modal since it causes GDK
 * gdk_property_delete() errors.
 */
        if(p->toplevel != NULL)
        {
            if(w != NULL)
            {
                if(!GTK_IS_WINDOW(w))
                    return;

                if(GTK_WINDOW(w)->modal)
                    gtk_window_set_modal(GTK_WINDOW(w), FALSE);

                gtk_window_set_modal(
                    GTK_WINDOW(p->toplevel), TRUE
                );
                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
                );
          }
      }
#endif
}

/*
 *      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();
}

/*
 *    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);
}

/*
 *    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);

          /* This entry should be the widget in focus when things
           * are mapped.
           */
          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 = w->window,
                  *root = (window != NULL) ?
                      gdk_window_get_parent(window) : NULL;

          /* 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;

          /* Move the toplevel GdkWindow, calculate x and y position
           * relative to parent (root) GdkWindow.
           */
          switch(map_code)
          {
            case FPROMPT_MAP_TO_POINTER_WINDOW:
            window = gdk_window_at_pointer(&x, &y);
/* TODO */
            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 = p->toplevel;
      gtk_widget_show_raise(w);
      p->map_state = TRUE;
}

/*
 *    Unmaps the floating prompt.
 */
void FPromptUnmap(void)
{
        fprompt_struct *p = &fprompt;
        GtkWidget *w = p->toplevel;
      gtk_widget_hide(w);
      p->map_state = FALSE;
}

/*
 *    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