Logo Search packages:      
Sourcecode: vertex version File versions

csd.c

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

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

#include "guiutils.h"
#include "csd.h"

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


/*
 *      Color selection dialog structure:
 */
typedef struct {

      gboolean    initialized;
      gboolean    map_state;
      GtkWidget   *csd;       /* GtkColorSelectionDialog */
      csd_color_struct current_color;
      gpointer    client_data;
                  /* (gpointer data, csd_color_struct *c) */
      void        (*color_changed_cb)(gpointer, csd_color_struct *);

} csd_data_struct;
#define CSD_DATA(p)     ((csd_data_struct *)(p))

/*
 *    Color button structure:
 */
typedef struct {

      GtkWidget   *toplevel,
                  *label,
                  *button,
                  *frame,
                  *drawing_area;
      gchar       *label_text;
      csd_color_struct  color;

} csd_color_button_struct;
#define CSD_COLOR_BUTTON(p)   ((csd_color_button_struct *)(p))
#define CSD_COLOR_BUTTON_DATA_KEY   "csd_color_button_data"


static void CSDOKCB(GtkWidget *widget, gpointer data);
static void CSDCancelCB(GtkWidget *widget, gpointer data);
static gint CSDCloseCB(
      GtkWidget *widget, GdkEvent *event, gpointer data
);
static void CSDColorChangeCB(GtkWidget *widget, gpointer data);

gint CSDInit(void);
void CSDSetTransientFor(GtkWidget *w);
gboolean CSDIsQuery(void);
void CSDBreakQuery(void);
gboolean CSDGetResponse(
        const gchar *title,
        const gchar *ok_label, const gchar *cancel_label,
        csd_color_struct *start_color,
        csd_color_struct **color_rtn,
        gpointer client_data,
        void (*color_changed_cb)(gpointer, csd_color_struct *)
);
void CSDMap(void);
void CSDUnmap(void);
void CSDShutdown(void);

static void CSDColorButtonDestroyCB(GtkObject *object, gpointer data);
static void CSDColorButtonClickedCB(GtkWidget *widget, gpointer data);
GtkWidget *CSDColorButtonNew(
        const gchar *label, gint label_width,
        gpointer client_data,
        void (*func_cb)(GtkWidget *, gpointer)
);
GtkWidget *CSDColorButtonNewSimple(const gchar *label, gint label_width);
GtkWidget *CSDColorButtonGetButton(GtkWidget *w);
void CSDColorButtonGetColor(GtkWidget *w, csd_color_struct *c);
void CSDColorButtonSetColor(GtkWidget *w, const csd_color_struct *c);


static gint block_loop_level;
static csd_data_struct csd_data;
static gboolean csd_got_user_response;
static csd_color_struct response_color;


/*
 *    Ok button callback.
 */
static void CSDOKCB(GtkWidget *widget, gpointer data)
{
      csd_data_struct *csdd = (csd_data_struct *)data;
        if(csdd == NULL)
            return;

        if(!csdd->initialized)
            return;

      /* Set user response code to TRUE, indicating OK. */
      csd_got_user_response = TRUE;

      /* Copy response color. */
      memcpy(
          &response_color, &csdd->current_color,
          sizeof(csd_color_struct)
      );

      /* Unmap. */
      CSDUnmap();

      /* Break out of blocking loop. */
      gtk_main_quit();
      block_loop_level--;
}

/*
 *    Cancel callback.
 */
static void CSDCancelCB(GtkWidget *widget, gpointer data)
{
        csd_data_struct *csdd = (csd_data_struct *)data;
        if(csdd == NULL)
            return;

        if(!csdd->initialized)
            return;

        /* Set user response code to FALSE, indicating Cancel. */
        csd_got_user_response = FALSE;

      /* Unmap. */
        CSDUnmap();

        /* Break out of blocking loop. */
        gtk_main_quit();
      block_loop_level--;
}           

/*
 *      Close callback.
 */
static gint CSDCloseCB(
      GtkWidget *widget, GdkEvent *event, gpointer data
)
{
      CSDCancelCB(widget, data);
      return(TRUE);
}

/*
 *    Color changed callback.
 */
static void CSDColorChangeCB(GtkWidget *widget, gpointer data)
{
      gdouble vd[3];
      GtkColorSelectionDialog *csd;
      csd_data_struct *csdd = (csd_data_struct *)data;
      if(csdd == NULL)
          return;

      if(!csdd->initialized)
          return;

      csd = (GtkColorSelectionDialog *)csdd->csd;
      if(csd == NULL)
          return;

      /* Get current color. */
      gtk_color_selection_get_color(
          GTK_COLOR_SELECTION(csd->colorsel), vd
      );

      /* Copy current color values to csdd structure's
       * csd_color_struct.
       */
      csdd->current_color.r = (gfloat)vd[0];
      csdd->current_color.g = (gfloat)vd[1];
      csdd->current_color.b = (gfloat)vd[2];
      csdd->current_color.a = 1.0f;

      /* Call color changed callback. */
      if(csdd->color_changed_cb != NULL)
          csdd->color_changed_cb(
            csdd->client_data,
            &csdd->current_color
          );
}


/*
 *    Initializes color selection dialog..
 */
gint CSDInit(void)
{
      GdkWindow *window;
      GtkWidget *w;
      GtkColorSelectionDialog *csd;
      csd_data_struct *csdd = &csd_data;


      /* Reset local globals. */
        block_loop_level = 0;
        csd_got_user_response = FALSE;
      memset(&response_color, 0x00, sizeof(csd_color_struct));
      memset(csdd, 0x00, sizeof(csd_data_struct));

      /* Reset values. */
        csdd->initialized = TRUE;
        csdd->map_state = FALSE;

      /* Create the color selection dialog. */
      csdd->csd = w = gtk_color_selection_dialog_new("Select Color");
      csd = GTK_COLOR_SELECTION_DIALOG(w);
      if(!GTK_WIDGET_REALIZED(w))
          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
            );
        }
      gtk_signal_connect(
            GTK_OBJECT(w), "delete_event",
            GTK_SIGNAL_FUNC(CSDCloseCB), (gpointer)csdd
        );

      /* Get GtkColorSelection widget. */
      w = csd->colorsel;

      /* Connect "color_changed" signal to the GtkColorSelection
       * widget.
       */
      gtk_signal_connect(
          GTK_OBJECT(w), "color_changed",
          GTK_SIGNAL_FUNC(CSDColorChangeCB), (gpointer)csdd
      );

      /* Ok button. */
      gtk_signal_connect(
          GTK_OBJECT(csd->ok_button), "clicked",
            GTK_SIGNAL_FUNC(CSDOKCB), (gpointer)csdd
        );
      gtk_widget_show(csd->ok_button);

      /* Hide reset button. */
      if(csd->reset_button != NULL)
            gtk_widget_hide(csd->reset_button);

      /* Cancel button. */
        gtk_signal_connect(
            GTK_OBJECT(csd->cancel_button), "clicked",
            GTK_SIGNAL_FUNC(CSDCancelCB), (gpointer)csdd
        );
        gtk_widget_show(csd->cancel_button);

        /* Hide help button. */
      if(csd->help_button != NULL)
            gtk_widget_hide(csd->help_button);

      return(0);
}

/*
 *      Sets dialog to be a transient for the given toplevel window
 *      widget w. If w is NULL then no transient for will be unset.
 */
void CSDSetTransientFor(GtkWidget *w)
{
        csd_data_struct *csdd = &csd_data;

        if(!csdd->initialized)
            return;

        if(csdd->csd != 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(csdd->csd), TRUE
                );
                gtk_window_set_transient_for(
                    GTK_WINDOW(csdd->csd), GTK_WINDOW(w)
                );
            }
            else
            {
                gtk_window_set_modal(
                    GTK_WINDOW(csdd->csd), FALSE
                );
                gtk_window_set_transient_for(
                    GTK_WINDOW(csdd->csd), NULL
                );
            }
        }
}


/*
 *      Returns TRUE if currently blocking for query.
 */
gboolean CSDIsQuery(void)
{
        if(block_loop_level > 0)
            return(TRUE);
        else
            return(FALSE);
}

/*
 *    Ends query if any and returns a not available response.
 */
void CSDBreakQuery(void)
{
      csd_got_user_response = FALSE;

        /* Break out of an additional blocking loops. */
        while(block_loop_level > 0)
        {
            gtk_main_quit();
            block_loop_level--;
        }
        block_loop_level = 0;
}

/*
 *    Maps the color selection dialog and sets up the inital values.
 *
 *    Returns TRUE if a color was sselected or FALSE if user canceled.
 *
 *    For most values that are set NULL, the value is left unchanged.
 *    All given values are coppied.
 *
 *    All returned pointer values should be considered statically
 *    allocated, do not deallocate them.
 */
gboolean CSDGetResponse(
        const gchar *title,
        const gchar *ok_label, const gchar *cancel_label,
        csd_color_struct *start_color,
        csd_color_struct **color_rtn,
        gpointer client_data,
        void (*color_changed_cb)(gpointer, csd_color_struct *)
)
{
      GtkWidget *w;
      GtkColorSelectionDialog *csd;
      csd_data_struct *csdd = &csd_data;


        /* Do not handle response if already waiting for a response,
         * return with a not available response code.
         */
        if(block_loop_level > 0)
      {
            if(color_rtn != NULL)
                *color_rtn = NULL;

            return(FALSE);
      }

      /* Reset global responses values. */
      csd_got_user_response = FALSE;
      memset(&response_color, 0x00, sizeof(csd_color_struct));

      /* Reset returns. */
      if(color_rtn != NULL)
          (*color_rtn) = NULL;


      /* Color selection dialog must be initialized. */
      if(!csdd->initialized)
          return(csd_got_user_response);

      /* Get pointer to color selection dialog widget. */
      w = csdd->csd;
      if(w == NULL)
            return(csd_got_user_response);
      csd = GTK_COLOR_SELECTION_DIALOG(w);

      /* Update title if specified. */
      if(title != NULL)
          gtk_window_set_title(GTK_WINDOW(w), title);

      /* Update button labels. */
      if((ok_label != NULL) && (csd->ok_button != NULL))
      {
          GtkButton *button = (GtkButton *)csd->ok_button;
          GtkWidget *w2;

          w2 = GTK_BIN(button)->child;
          if((w2 != NULL) ? GTK_IS_LABEL(w2) : 0)
            gtk_label_set_text(GTK_LABEL(w2), ok_label);
      }
        if((cancel_label != NULL) && (csd->cancel_button != NULL))
        {
            GtkButton *button = (GtkButton *)csd->cancel_button;
            GtkWidget *w2;

            w2 = GTK_BIN(button)->child;
            if((w2 != NULL) ? GTK_IS_LABEL(w2) : 0)
                gtk_label_set_text(GTK_LABEL(w2), cancel_label);
        }


      /* Update initial start color if specified. */
      if(start_color != NULL)
      {
          gdouble vd[3];
          GtkColorSelection *colorsel;

          colorsel = GTK_COLOR_SELECTION(
            GTK_COLOR_SELECTION_DIALOG(w)->colorsel
          );

          vd[0] = start_color->r;
          vd[1] = start_color->g;
          vd[2] = start_color->b;
/*            = start_color->a; */

          gtk_color_selection_set_color(colorsel, vd);

          csdd->current_color.r = start_color->r;
            csdd->current_color.g = start_color->g;
            csdd->current_color.b = start_color->b;
            csdd->current_color.a = start_color->a;
      }

      /* Set up callbacks. */
      csdd->client_data = client_data;
      csdd->color_changed_cb = color_changed_cb;

        /* Map color selection dialog as needed. */
        CSDMap();

        /* Block GUI untill response. */
      block_loop_level++;
        gtk_main();

        /* Unmap color selection dialog just in case it was not unmapped
       * from any of the callbacks.
       */
        CSDUnmap();

        /* Break out of an additional blocking loops. */
        while(block_loop_level > 0)
        {
            gtk_main_quit();
            block_loop_level--;
        }
        block_loop_level = 0;


      /* Begin setting returns. */

      /* Color return. */
      if(color_rtn != NULL)
          *color_rtn = &response_color;

      return(csd_got_user_response);
}


/*
 *    Maps the color selection dialog as needed.
 */
void CSDMap(void)
{
      GtkWidget *w;
        csd_data_struct *csdd = &csd_data;


        if(csdd == NULL)
            return;

        if(!csdd->initialized)
            return;

      w = csdd->csd;
      gtk_widget_show_raise(w);
      csdd->map_state = TRUE;
}

/*
 *    Unmaps the color selection dialog as needed.
 */
void CSDUnmap(void)
{
        csd_data_struct *csdd = &csd_data;


      if(csdd == NULL)
          return;

      if(!csdd->initialized)
          return;

      if(csdd->map_state)
      {
          GtkWidget *w = csdd->csd;

          if(w != NULL)
            gtk_widget_hide(w);

          csdd->map_state = FALSE;
      }
}

/*
 *    Deallocates color selection dialog resources.
 */
void CSDShutdown(void)
{
      GtkWidget **w;
        csd_data_struct *csdd = &csd_data;


      /* Reset local globals. */
        csd_got_user_response = FALSE; 
        memset(&response_color, 0x00, sizeof(csd_color_struct));

        /* Break out of an additional blocking loops. */
        while(block_loop_level > 0)
        {
            gtk_main_quit();
            block_loop_level--;
        }
        block_loop_level = 0;


      /* Is color selection dialog initialized? */
      if(csdd->initialized)
      {
#define DO_DESTROY_WIDGET       \
{ if(*w != NULL) { gtk_widget_destroy(*w); *w = NULL; } }

          /* Begin destroying file browser widgets. */
          w = &csdd->csd;
          DO_DESTROY_WIDGET

#undef DO_DESTROY_WIDGET
      }

      /* Clear color selection dialog structure. */
      memset(csdd, 0x00, sizeof(csd_data_struct));
}


/*
 *    Color button "destroy" signal callback.
 */
static void CSDColorButtonDestroyCB(GtkObject *object, gpointer data)
{
      csd_color_button_struct *b = CSD_COLOR_BUTTON(data);
      if(b == NULL)
            return;
/* printf("Destroyed color button \"%s\"\n", b->label_text); */
      g_free(b->label_text);
        g_free(b);
}

/*
 *    Color button GtkButton "clicked" signal callback.
 */
static void CSDColorButtonClickedCB(GtkWidget *widget, gpointer data)
{
      gboolean status;
      GtkWidget *w;
      csd_color_struct c, *c_rtn = NULL;
      void (*color_changed_cb)(gpointer, csd_color_struct *) =
          (gpointer)CSDColorButtonSetColor;
      csd_color_button_struct *b = CSD_COLOR_BUTTON(data);
        if(b == NULL)
            return;

        if(CSDIsQuery())
            return;

      /* Get toplevel for color button. */
      w = b->toplevel;

      /* Record current color. */
      memcpy(&c, &b->color, sizeof(csd_color_struct));

        /* Get response. */
        CSDSetTransientFor(gtk_widget_get_toplevel(w));
        status = CSDGetResponse(
            "Select Color",
            "Select", "Cancel",
            &c, &c_rtn,
            w, color_changed_cb
        );
        CSDSetTransientFor(NULL);

        /* Got response? */
        if(status && (c_rtn != NULL))
        {
            CSDColorButtonSetColor(w, c_rtn);
        }
        else
        {
            CSDColorButtonSetColor(w, &c);
        }
}

/*
 *    Creates a new color button.
 */
GtkWidget *CSDColorButtonNew(
        const gchar *label, gint label_width,
        gpointer client_data,
        void (*func_cb)(GtkWidget *, gpointer)
)
{
        gint border_minor = 2;
        GtkWidget *w;
      csd_color_button_struct *b = CSD_COLOR_BUTTON(g_malloc0(
          sizeof(csd_color_button_struct)
      ));
      b->toplevel = w = gtk_hbox_new(FALSE, border_minor);
      gtk_object_set_data(GTK_OBJECT(w), CSD_COLOR_BUTTON_DATA_KEY, b);
        gtk_signal_connect(
            GTK_OBJECT(w), "destroy",
            GTK_SIGNAL_FUNC(CSDColorButtonDestroyCB), b
        );
      if(label != NULL)
      {
          b->label = w = gtk_label_new(label);
          b->label_text = g_strdup(label);
          gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_RIGHT);
          gtk_widget_set_usize(w, label_width, -1);
          gtk_box_pack_start(GTK_BOX(b->toplevel), w, FALSE, FALSE, 0);
          gtk_widget_show(w);
      }
      b->button = w = gtk_button_new();
      gtk_box_pack_start(GTK_BOX(b->toplevel), w, FALSE, FALSE, 0);
        gtk_widget_show(w);
      b->frame = w = gtk_frame_new(NULL);
        gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_IN);
        gtk_widget_set_usize(w, 20, 20);
        gtk_container_add(GTK_CONTAINER(b->button), w);
        gtk_widget_show(w);
      b->drawing_area = w = gtk_drawing_area_new();
        gtk_widget_add_events(
            w,
            GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
          GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK
        );
        gtk_container_add(GTK_CONTAINER(b->frame), w);
        GUISetWidgetTip(w, "Click to select color");
        gtk_widget_show(w);

        if(func_cb != NULL)
            gtk_signal_connect(
                GTK_OBJECT(b->button), "clicked",
                GTK_SIGNAL_FUNC(func_cb), client_data
            );

      return(b->toplevel);
}

/*
 *    Creates a new color button with "clicked" signal already
 *    connected to a default callback which prompts for a new color
 *    using the color selection dialog and sets the new color for
 *    the color button as appropriate.
 */
GtkWidget *CSDColorButtonNewSimple(const gchar *label, gint label_width)
{
      GtkWidget *w = CSDColorButtonNew(
          label, label_width, NULL, NULL
      );
        csd_color_button_struct *b = CSD_COLOR_BUTTON(
            (w != NULL) ? gtk_object_get_data(
                GTK_OBJECT(w), CSD_COLOR_BUTTON_DATA_KEY
            ) : NULL
        );
      if(b->button != NULL)
          gtk_signal_connect(
                GTK_OBJECT(b->button), "clicked",
                GTK_SIGNAL_FUNC(CSDColorButtonClickedCB), b
          );
      return(w);
}

/*
 *    Returns the GtkButton of the given color button.
 */
GtkWidget *CSDColorButtonGetButton(GtkWidget *w)
{
        csd_color_button_struct *b = CSD_COLOR_BUTTON(
            (w != NULL) ? gtk_object_get_data(
                GTK_OBJECT(w), CSD_COLOR_BUTTON_DATA_KEY
            ) : NULL
        );
      return((b != NULL) ? b->button : NULL);
}

/*
 *    Gets the color button's current color.
 */
void CSDColorButtonGetColor(GtkWidget *w, csd_color_struct *c)
{
      csd_color_button_struct *b = CSD_COLOR_BUTTON(
          (w != NULL) ? gtk_object_get_data(
            GTK_OBJECT(w), CSD_COLOR_BUTTON_DATA_KEY
          ) : NULL
      );
      if((b == NULL) || (c == NULL))
          return;

      if(c != &b->color)
          memcpy(c, &b->color, sizeof(csd_color_struct));
}

/*
 *    Sets the color button's color.
 */
void CSDColorButtonSetColor(GtkWidget *w, const csd_color_struct *c)
{
      GdkColor c2;
      GdkColormap *colormap;
      GdkWindow *window;
        csd_color_button_struct *b = CSD_COLOR_BUTTON(
            (w != NULL) ? gtk_object_get_data(
                GTK_OBJECT(w), CSD_COLOR_BUTTON_DATA_KEY
            ) : NULL
        );
        if((b == NULL) || (c == NULL))
            return;

      /* Record newly set color. */
      if(c != &b->color)
          memcpy(&b->color, c, sizeof(csd_color_struct));

      /* Get GtkDrawingArea and realize it. */
      w = b->drawing_area;
      if(w == NULL)
          return;
        if(!GTK_WIDGET_REALIZED(w))
            gtk_widget_realize(w);
      if(!GTK_WIDGET_REALIZED(w))
          return;

      /* Get the GtkDrawingArea's GdkWindow. */
      window = w->window;
      if(window == NULL)
          return;

      /* Get colormap from window and allocate a new GdkColor for the
       * setting of the GdkWindow's background color.
       */
        colormap = gdk_window_get_colormap(window);
        if(colormap == NULL)
            return;

      c2.red            = (gushort)(c->r * (gushort)-1);
      c2.green    = (gushort)(c->g * (gushort)-1);
      c2.blue           = (gushort)(c->b * (gushort)-1);
      gdk_colormap_alloc_color(colormap, &c2, TRUE, TRUE);
      gdk_window_set_background(window, &c2);
      gdk_colormap_free_colors(colormap, &c2, 1);
      gdk_window_clear(window);
}

Generated by  Doxygen 1.6.0   Back to index