Logo Search packages:      
Sourcecode: vertex version File versions

pstepper.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

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

#include "guiutils.h"
#include "pstepper.h"

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


static void PSDestroyCB(GtkObject *object, gpointer *data);
static gint PSCloseCB(GtkWidget *widget, GdkEvent *event, gpointer data);
static void PSButtonCB(GtkWidget *widget, gpointer data);

pstepper_struct *PStepperCreate(
        gchar *title,
        const gchar *back_text, const gchar *exit_text,
        const gchar *next_text, const gchar *finish_text,
        gint width, gint height,                /* Can be 0. */
        gpointer exit_client_data,
        void (*exit_cb)(gpointer, gint, gpointer),
        gpointer finish_client_data,
        void (*finish_cb)(gpointer, gint, gpointer)
);
gint PStepperAppend(
        pstepper_struct *ps,
        GtkWidget *page, GtkWidget *nariative,
        gpointer client_data,
        void (*page_cb)(gpointer, gint, gint, gpointer)
);
void PStepperChangePage(
        pstepper_struct *ps, gint page_num,
        gbool report_change
);
gint PStepperGetPage(pstepper_struct *ps);
void PStepperMap(pstepper_struct *ps);
void PStepperUnmap(pstepper_struct *ps);
void PStepperDestroy(pstepper_struct *ps);


#define PS_DEF_WIDTH    500
#define PS_DEF_HEIGHT   400

#define PS_BTN_WIDTH    (80 + (2 * 3))
#define PS_BTN_HEIGHT   (30 + (2 * 3))



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

/*
 *    Close callback.
 */
static gint PSCloseCB(GtkWidget *widget, GdkEvent *event, gpointer data)
{
      pstepper_struct *ps = (pstepper_struct *)data;
      if(ps == NULL)
          return(FALSE);

      if(ps->initialized)
      {
          /* Call exit callback. */
          if(ps->exit_cb != NULL)
            ps->exit_cb(
                ps,
                ps->current_page,
                ps->exit_client_data
            );
      }

      return(TRUE);
}

/*
 *    Back/next button callback.
 */
static void PSButtonCB(GtkWidget *widget, gpointer data)
{
        pstepper_struct *ps = (pstepper_struct *)data;
        if((widget == NULL) || (ps == NULL))
            return;

      /* Back? */
      if(widget == ps->back_btn)
      {
          PStepperChangePage(
            ps, ps->current_page - 1, TRUE
          );
      }
      /* Next? */
      else if(widget == ps->next_btn)
      {
            PStepperChangePage(
                ps, ps->current_page + 1, TRUE
            );
      }

      return;
}

/*
 *    Allocates a new page stepper structure and sets it up.
 *
 *    If any value is NULL or 0 then a default value will be set
 *    in its place or no value at all.
 */
pstepper_struct *PStepperCreate(
        gchar *title,
        const gchar *back_text, const gchar *exit_text,
        const gchar *next_text, const gchar *finish_text,
        gint width, gint height,                /* Can be 0. */
        gpointer exit_client_data,
        void (*exit_cb)(gpointer, gint, gpointer),
        gpointer finish_client_data,
        void (*finish_cb)(gpointer, gint, gpointer)
)
{
        GtkWidget *w, *parent, *parent2;
      GdkWindow *window;
        GtkAccelGroup *accelgrp;
      pstepper_struct *ps = (pstepper_struct *)g_malloc0(
          sizeof(pstepper_struct)
      );
      if(ps == NULL)
          return(NULL);


      /* Reset values. */
      ps->initialized = TRUE;
      ps->map_state = FALSE;
      ps->current_page = -1;
      ps->total_pages = 0;

      ps->exit_client_data = exit_client_data;
      ps->exit_cb = exit_cb;

      ps->finish_client_data = finish_client_data;
      ps->finish_cb = finish_cb;


      /* Keyboard accelerator group. */
      ps->accelgrp = accelgrp = gtk_accel_group_new();


        /* Create toplevel. */
      ps->toplevel = w = gtk_window_new(GTK_WINDOW_DIALOG);
        gtk_widget_set_usize(
            w,
            (width <= 0) ? PS_DEF_WIDTH : width,
            (height <= 0) ? PS_DEF_HEIGHT : height
        );
        gtk_widget_realize(w);
        window = w->window;
        if(window != NULL) 
        {
            gdk_window_set_decorations(
                window,
                GDK_DECOR_TITLE | GDK_DECOR_MENU | GDK_DECOR_MINIMIZE
            );
            gdk_window_set_functions(
                window,
                GDK_FUNC_MOVE | GDK_FUNC_MINIMIZE | GDK_FUNC_CLOSE
            );
        }
      if(title != NULL)
          gtk_window_set_title(GTK_WINDOW(w), title);
        gtk_signal_connect(
            GTK_OBJECT(w), "destroy",
            GTK_SIGNAL_FUNC(PSDestroyCB),
            (gpointer)ps
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "delete_event",
            GTK_SIGNAL_FUNC(PSCloseCB),
            (gpointer)ps
        );
      gtk_container_border_width(GTK_CONTAINER(w), 0);
      gtk_accel_group_attach(accelgrp, GTK_OBJECT(w));
        parent = w;


        /* Create main parents. */

        w = gtk_vbox_new(FALSE, 0);
        gtk_container_add(GTK_CONTAINER(parent), w);
        gtk_widget_show(w);
        parent = w;

        /* Main hbox which will separate the left hand naroative strip
         * from the pages and buttons on the right.
         */
        w = gtk_hbox_new(FALSE, 0);
        gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
        gtk_widget_show(w);
        parent2 = w;

        /* Nariatives strip toplevel. */
        w = gtk_vbox_new(FALSE, 0);
        ps->nariatives_toplevel = w;
        gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
        gtk_widget_show(w);

        /* Pages toplevel. */
        w = gtk_vbox_new(FALSE, 0);
        ps->pages_toplevel = w;
        gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, TRUE, 0);
        gtk_widget_show(w);

        /* Horizontal separator. */
        w = gtk_hseparator_new();
        gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 2);
        gtk_widget_show(w);
        
        /* Buttons toplevel. */
        w = gtk_hbox_new(FALSE, 0);
        ps->buttons_toplevel = w;
        gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 2);
        gtk_widget_show(w);

        /* Create buttons. */
        parent = ps->buttons_toplevel;

      if(back_text != NULL)
          ps->back_text = strdup(back_text);
      if(exit_text != NULL)
          ps->exit_text = strdup(exit_text);

      if(next_text != NULL)
          ps->next_text = strdup(next_text);
      if(finish_text != NULL)
          ps->finish_text = strdup(finish_text);

        /* Alignment widget to fill left gap. */
        w = gtk_alignment_new(0.0, 0.0, 1.0, 1.0);
        gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 2);
        gtk_widget_show(w);

        /* Back/exit button (initial label set to "Exit"). */
        w = gtk_button_new();
        ps->back_btn = w;
        gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 2);
        gtk_widget_set_usize(w, PS_BTN_WIDTH, PS_BTN_HEIGHT);
        GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
        gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(PSButtonCB),
            (gpointer)ps
        );
        gtk_accel_group_add(
            accelgrp, GDK_Escape, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_widget_show(w);
        parent2 = w;

        w = gtk_label_new(
          (exit_text == NULL) ? "Back" : exit_text
      );
        ps->back_btn_label = w;
        gtk_container_add(GTK_CONTAINER(parent2), w);
        gtk_widget_show(w);
        
        
        /* Next/finish button (initial label set to "Exit"). */
        w = gtk_button_new();
        ps->next_btn = w;
        gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 2);
        gtk_widget_set_usize(w, PS_BTN_WIDTH, PS_BTN_HEIGHT);
        GTK_WIDGET_SET_FLAGS(w, GTK_CAN_DEFAULT);
        gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(PSButtonCB),
            (gpointer)ps
        );
        gtk_accel_group_add(
            accelgrp, GDK_space, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_accel_group_add(
            accelgrp, GDK_Return, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_accel_group_add(
            accelgrp, GDK_3270_Enter, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_accel_group_add(
            accelgrp, GDK_KP_Enter, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_accel_group_add(
            accelgrp, GDK_ISO_Enter, 0, GTK_ACCEL_VISIBLE,
            GTK_OBJECT(w), "clicked"
        );
        gtk_widget_show(w);
        parent2 = w;

        w = gtk_label_new(
            (finish_text == NULL) ? "Next" : finish_text
      );
        ps->next_btn_label = w;
        gtk_container_add(GTK_CONTAINER(parent2), w);
        gtk_widget_show(w);


      return(ps);
}

/*
 *    Appends the given page and nariative widgets to the ps
 *    and assigning them the given callback function and data.
 *
 *    Returns the page number of the newly appended page and nariative
 *    or -1 on error.
 */
gint PStepperAppend(
      pstepper_struct *ps,
      GtkWidget *page, GtkWidget *nariative,
      gpointer client_data,
      void (*page_cb)(gpointer, gint, gint, gpointer)
)
{
      gint n;


      if(ps == NULL)
          return(-1);

      if(ps->total_pages < 0)
          ps->total_pages = 0;

      n = ps->total_pages;
      ps->total_pages = n + 1;


      /* Reallocate arrays. */
      ps->page = (GtkWidget **)g_realloc(
          ps->page, ps->total_pages * sizeof(GtkWidget *)
      );
      if(ps->page == NULL)
      {
          ps->total_pages = 0;
          return(-1);
      }

        ps->nariative_strip = (GtkWidget **)g_realloc(
            ps->nariative_strip, ps->total_pages * sizeof(GtkWidget *)
        );
        if(ps->nariative_strip == NULL)
        {
            ps->total_pages = 0;
            return(-1);
        }

        ps->client_data = (gpointer *)g_realloc(
            ps->client_data, ps->total_pages * sizeof(gpointer)
        );
        if(ps->client_data == NULL)
        {
            ps->total_pages = 0;
            return(-1);
        }

        ps->page_cb = (gpointer *)g_realloc(
            ps->page_cb, ps->total_pages * sizeof(gpointer)
        );
        if(ps->page_cb == NULL)
        {
            ps->total_pages = 0;
            return(-1);
        }

      /* Set new values. */
      ps->page[n] = page;
      ps->nariative_strip[n] = nariative;
      ps->client_data[n] = client_data;
      ps->page_cb[n] = page_cb;

      /* Parent widgets. */
      gtk_box_pack_start(
          GTK_BOX(ps->pages_toplevel),
          page,
          FALSE, FALSE, 0
      );
        gtk_box_pack_start(
            GTK_BOX(ps->nariatives_toplevel),
            nariative,
            FALSE, FALSE, 0
        );

      /* If this is the first page then switch to it. */
      if(n == 0)
          PStepperChangePage(ps, n, FALSE);

      return(n);
}

/*
 *    Page change procedure, this unmaps the previous page and
 *    nariative on the ps. Then maps the new specified page_num
 *    if valid and calls the appropriate page change function
 *    if report_change is TRUE.
 */
void PStepperChangePage(
        pstepper_struct *ps, gint page_num,
        gbool report_change
)
{
        GtkWidget *w;
      gint prev_page;
      void (*page_cb)(gpointer, gint, gint, gpointer);


        if(ps == NULL)
            return;

      prev_page = ps->current_page;

      /* Exit? */
      if(page_num < 0)
      {
          if((ps->exit_cb != NULL) && report_change)
            ps->exit_cb(
                ps,
                prev_page,
                ps->exit_client_data
            );
          return;
      }
        /* Finish? */
        if(page_num >= ps->total_pages)
        {
            if((ps->finish_cb != NULL) && report_change)
                ps->finish_cb(
                    ps,
                    prev_page,
                    ps->finish_client_data
                );
            return;
        }

        /* Unmap the previous nariative and page if valid. */
        if((prev_page >= 0) && (prev_page < ps->total_pages))
        {
            w = ps->nariative_strip[prev_page];
            if(w != NULL)
                gtk_widget_hide(w);

            w = ps->page[prev_page];
            if(w != NULL)
                gtk_widget_hide(w);
        }

        /* Map the new nariative and page if valid. */
        if((page_num >= 0) && (page_num < ps->total_pages))
        {
            w = ps->nariative_strip[page_num];
            if(w != NULL)
                gtk_widget_show(w);

            w = ps->page[page_num];
            if(w != NULL)
                gtk_widget_show(w);

          /* Update current page. */
          ps->current_page = page_num;

          /* Call page change. */
          if((ps->page_cb != NULL) && report_change)
          {
            page_cb = ps->page_cb[page_num];
            if(page_cb != NULL)
                page_cb(
                  ps,
                  prev_page, page_num,
                  ((ps->client_data == NULL) ?
                      NULL : ps->client_data[page_num]
                  )
                );
          }
        }   

      /* Update button labels based on current page. */
      if(ps->current_page == 0)
      {
          w = ps->back_btn_label;
          if((ps->exit_text != NULL) && (w != NULL))
            gtk_label_set_text(GTK_LABEL(w), ps->exit_text);
      }
      else
      {
            w = ps->back_btn_label;
            if((ps->back_text != NULL) && (w != NULL))
                gtk_label_set_text(GTK_LABEL(w), ps->back_text);
      }

        if(ps->current_page == (ps->total_pages - 1))
        {       
            w = ps->next_btn_label;
            if((ps->finish_text != NULL) && (w != NULL)) 
                gtk_label_set_text(GTK_LABEL(w), ps->finish_text);
        }
        else
        {
            w = ps->next_btn_label;
            if((ps->next_text != NULL) && (w != NULL))
                gtk_label_set_text(GTK_LABEL(w), ps->next_text);
        }

      return;
}

/*
 *    Gets current page number of ps. Can return -1 on error.
 */
gint PStepperGetPage(pstepper_struct *ps)
{
      if(ps == NULL)
          return(-1);

      return(ps->current_page);
}

/*
 *    Maps the page stepper ps as needed.
 */
void PStepperMap(pstepper_struct *ps)
{
        GtkWidget *w;


        if(ps == NULL)
            return;

        if(!ps->map_state)
        {
          w = ps->next_btn;
          if(w != NULL)
          {
            gtk_widget_grab_focus(w);
            gtk_widget_grab_default(w);
          }

          w = ps->toplevel;
          if(w != NULL)
            gtk_widget_show(w);

            ps->map_state = TRUE;
        }
}

/*
 *    Unmaps the page stepper ps as needed.
 */
void PStepperUnmap(pstepper_struct *ps)
{
        GtkWidget *w;


        if(ps == NULL)
            return;

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

            ps->map_state = FALSE;
        }
}

/*
 *      Dealloates all resources on the given ps and deallocates the
 *    ps structure.
 */
void PStepperDestroy(pstepper_struct *ps)
{
      gint i;
      GtkWidget **w;


      if(ps == NULL)
          return;

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

        /* Destroy each page and nariative toplevel. */
        for(i = 0; i < ps->total_pages; i++)
        {
            w = &ps->nariative_strip[i];
            DO_DESTROY_WIDGET

            w = &ps->page[i];
            DO_DESTROY_WIDGET
        }

        /* Free arrays. */
        g_free(ps->nariative_strip);
        ps->nariative_strip = NULL;
        g_free(ps->page);
        ps->page = NULL;
      g_free(ps->client_data);
      ps->client_data = NULL;
      g_free(ps->page_cb);
      ps->page_cb = NULL;

        ps->total_pages = 0;
        ps->current_page = -1;


        /* Main parents. */
        w = &ps->nariatives_toplevel;
        DO_DESTROY_WIDGET

        w = &ps->pages_toplevel;
        DO_DESTROY_WIDGET

        w = &ps->buttons_toplevel;
        DO_DESTROY_WIDGET

        /* Toplevel. */
        w = &ps->toplevel;
        DO_DESTROY_WIDGET;

#undef DO_DESTROY_WIDGET

      if(ps->accelgrp != NULL)
      {
          gtk_accel_group_unref(ps->accelgrp);
          ps->accelgrp = NULL;
      }

      /* Free other resources. */
      g_free(ps->back_text);
      ps->back_text = NULL;

      g_free(ps->exit_text);
      ps->exit_text = NULL;

      g_free(ps->next_text);
      ps->next_text = NULL;

      g_free(ps->finish_text);
      ps->finish_text = NULL;


      /* Deallocate structure itself. */
      g_free(ps);
}

Generated by  Doxygen 1.6.0   Back to index