[gimp/soc-2011-gimpunitentry] Initial commit of GimpUnitEntry widget



commit 0a159e3d876907692a8305f5ac589455d253c50c
Author: Enrico SchroÌ?der <enni schroeder gmail com>
Date:   Tue May 31 16:03:10 2011 +0200

    Initial commit of GimpUnitEntry widget
    
    contains GimpUnitAdjustment, GimpUnitEntry and a little testapp 'test-unitentry'

 .gitignore                          |    2 +
 libgimpwidgets/Makefile.am          |   21 ++-
 libgimpwidgets/gimpunitadjustment.c |  200 ++++++++++++++++++++
 libgimpwidgets/gimpunitadjustment.h |   85 +++++++++
 libgimpwidgets/gimpunitentry.c      |  349 +++++++++++++++++++++++++++++++++++
 libgimpwidgets/gimpunitentry.h      |   71 +++++++
 libgimpwidgets/test-unitentry.c     |  103 ++++++++++
 7 files changed, 830 insertions(+), 1 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index c5269c3..28af0de 100644
--- a/.gitignore
+++ b/.gitignore
@@ -46,3 +46,5 @@
 /stamp-h
 /stamp-h.in
 /stamp-h1
+
+/libgimpwidgets/test-unitentry
\ No newline at end of file
diff --git a/libgimpwidgets/Makefile.am b/libgimpwidgets/Makefile.am
index a1aac9e..0cdc590 100644
--- a/libgimpwidgets/Makefile.am
+++ b/libgimpwidgets/Makefile.am
@@ -163,6 +163,10 @@ libgimpwidgets_2_0_la_sources = \
 	gimpstringcombobox.h		\
 	gimpunitcombobox.c		\
 	gimpunitcombobox.h		\
+	gimpunitadjustment.c		\
+	gimpunitadjustment.h		\
+	gimpunitentry.c			\
+	gimpunitentry.h			\
 	gimpunitmenu.c			\
 	gimpunitmenu.h			\
 	gimpunitstore.c			\
@@ -241,6 +245,7 @@ libgimpwidgetsinclude_HEADERS = \
 	gimpstock.h			\
 	gimpstringcombobox.h		\
 	gimpunitcombobox.h		\
+	gimpunitentry.h			\
 	gimpunitmenu.h			\
 	gimpunitstore.h			\
 	gimpwidgets-error.h		\
@@ -332,7 +337,8 @@ gimp-wilber-pixbufs.h: $(WILBER_IMAGES) Makefile.am
 
 EXTRA_PROGRAMS = \
 	test-preview-area	\
-	test-eevl
+	test-eevl		\
+	test-unitentry
 
 
 test_preview_area_SOURCES = test-preview-area.c 
@@ -356,6 +362,19 @@ test_eevl_LDADD = \
 	$(GLIB_LIBS) 		\
 	$(test_eevl_DEPENDENCIES)
 
+test_unitentry_SOURCES = \
+	test-unitentry.c \
+	$(top_builddir)/devel-docs/tools/units.c
+
+test_unitentry_DEPENDENCIES = \
+	$(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la \
+	$(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la \	
+	$(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
+
+test_unitentry_LDADD = \
+	$(GLIB_LIBS) 		\
+	$(test_unitentry_DEPENDENCIES)
+
 
 #
 # test programs, not to be built by default and never installed
diff --git a/libgimpwidgets/gimpunitadjustment.c b/libgimpwidgets/gimpunitadjustment.c
new file mode 100644
index 0000000..9457f6a
--- /dev/null
+++ b/libgimpwidgets/gimpunitadjustment.c
@@ -0,0 +1,200 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpunitadjustment.c
+ * Copyright (C) 2011 Enrico Schröder <enni schroeder gmail com>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glib-object.h>
+#include <glib/gprintf.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "gimpwidgets.h"
+#include "gimpunitadjustment.h"
+
+/* some default values */
+#define DEFAULT_UNIT        GIMP_UNIT_INCH
+#define DEFAULT_RESOLUTION  300.0
+
+G_DEFINE_TYPE (GimpUnitAdjustment, gimp_unit_adjustment, GTK_TYPE_ADJUSTMENT);
+
+/** 
+ * prototypes
+ **/
+/* converts from one current unit to another */
+void gimp_unit_adjustment_convert_unit (GimpUnitAdjustment *adj, GimpUnit unit);
+void unit_changed_handler (GimpUnitAdjustment *adj, GimpUnit unit, gpointer userData);
+
+
+static void
+gimp_unit_adjustment_init (GimpUnitAdjustment *unitAdjustment)
+{
+  /* set default values */
+  gtk_adjustment_set_upper (&unitAdjustment->parent_instance, 10000000.0);
+  gtk_adjustment_set_step_increment (&unitAdjustment->parent_instance, 1.0);
+  unitAdjustment->unitChanged = FALSE;
+
+  /* default unit, resolution */
+  unitAdjustment->unit = DEFAULT_UNIT;
+  unitAdjustment->resolution = DEFAULT_RESOLUTION;
+}
+
+static void
+gimp_unit_adjustment_class_init (GimpUnitAdjustmentClass *klass)
+{
+  klass->sig_unit_changed_id = g_signal_new ("unit-changed",
+                                              GIMP_TYPE_UNIT_ADJUSTMENT,
+                                              G_SIGNAL_RUN_LAST,
+                                              0,
+                                              NULL, 
+                                              NULL,
+                                              g_cclosure_marshal_VOID__INT,
+                                              G_TYPE_NONE, 
+                                              1, 
+                                              G_TYPE_INT);
+}
+
+GObject *
+gimp_unit_adjustment_new (void)
+{
+  return g_object_new (GIMP_TYPE_UNIT_ADJUSTMENT, NULL);
+}
+
+void
+unit_changed_handler (GimpUnitAdjustment *adj, GimpUnit unit, gpointer userData)
+{
+  GimpUnitAdjustment *adjustment = GIMP_UNIT_ADJUSTMENT (userData);
+
+  adj->unitChanged = TRUE;
+
+  gimp_unit_adjustment_convert_unit (adjustment, unit);
+}
+
+/* connects adjustment to another adjustment */
+void   
+gimp_unit_adjustment_connect (GimpUnitAdjustment *adj, GimpUnitAdjustment *target)
+{
+  g_signal_connect (target,
+                    "unit-changed",
+                    G_CALLBACK (unit_changed_handler),
+                    (gpointer*) adj); 
+}
+
+/* converts from one current unit to another */
+void
+gimp_unit_adjustment_convert_unit (GimpUnitAdjustment *adj, GimpUnit unit)
+{
+  gdouble newValue = 0;
+  if (adj->unit != unit)
+  {
+    g_debug ("GimpUnitAdjustment: changing unit from %s to %s\n",
+             gimp_unit_get_abbreviation (adj->unit),
+             gimp_unit_get_abbreviation (unit));
+
+    /* convert value to new unit */
+    newValue = gimp_units_to_pixels (gtk_adjustment_get_value (&(adj->parent_instance)),
+                                     adj->unit,
+                                     adj->resolution);
+    newValue = gimp_pixels_to_units (newValue,
+                                     unit, 
+                                     adj->resolution);
+
+    adj->unit  = unit;
+
+    gimp_unit_adjustment_set_value (adj, newValue);
+
+    /* emit "unit-changed" */
+    g_signal_emit(adj, GIMP_UNIT_ADJUSTMENT_GET_CLASS(adj)->sig_unit_changed_id, 0, unit);
+  }
+}
+
+/* sets unit of adjustment, does conversion if neccessary */
+void    
+gimp_unit_adjustment_set_unit (GimpUnitAdjustment *adj, GimpUnit unit)
+{
+  gimp_unit_adjustment_convert_unit (adj, unit);
+
+  /* emit "unit-changed" */
+  g_signal_emit(adj, GIMP_UNIT_ADJUSTMENT_GET_CLASS(adj)->sig_unit_changed_id, 0, unit);
+}
+
+/* sets/gets the value of an adjustment */
+void
+gimp_unit_adjustment_set_value (GimpUnitAdjustment *adj, gdouble value)
+{
+  g_debug ("set_value: %f", value);
+
+  gtk_adjustment_set_value (GTK_ADJUSTMENT (adj), value);
+
+  //g_debug ("new value: %f\n", gimp_unit_adjustment_get_value (adj));
+}
+gdouble 
+gimp_unit_adjustment_get_value (GimpUnitAdjustment *adj)
+{
+  gdouble value;
+
+  value = gtk_adjustment_get_value (GTK_ADJUSTMENT (adj));
+
+  return value;
+}
+gdouble 
+gimp_unit_adjustment_get_value_in_unit (GimpUnitAdjustment *adj, GimpUnit unit)
+{
+  gdouble value = gimp_unit_adjustment_get_value (adj);
+
+  value = gimp_units_to_pixels (value, adj->unit, adj->resolution);
+  value = gimp_pixels_to_units (value, unit, adj->resolution);
+
+  return value;
+}
+void    
+gimp_unit_adjustment_set_resolution (GimpUnitAdjustment *adj, gdouble res)
+{
+  adj->resolution = res;
+}
+gdouble 
+gimp_unit_adjustment_get_resolution (GimpUnitAdjustment *adj)
+{
+  return adj->resolution;
+}
+
+/* get string in format "value unit" */
+gchar* 
+gimp_unit_adjustment_to_string (GimpUnitAdjustment *adj)
+{
+  return gimp_unit_adjustment_to_string_in_unit (adj, adj->unit);
+}
+gchar*  
+gimp_unit_adjustment_to_string_in_unit (GimpUnitAdjustment *adj, GimpUnit unit)
+{
+  gdouble value;
+  gchar *text = g_malloc (sizeof (gchar) * 12);
+
+  value = gimp_unit_adjustment_get_value_in_unit (adj, unit);
+
+  g_sprintf (text, "%.2f %s", 
+             value,
+             gimp_unit_get_abbreviation (unit));
+
+  return text;
+}
+
diff --git a/libgimpwidgets/gimpunitadjustment.h b/libgimpwidgets/gimpunitadjustment.h
new file mode 100644
index 0000000..399be5f
--- /dev/null
+++ b/libgimpwidgets/gimpunitadjustment.h
@@ -0,0 +1,85 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpunitadjustment.h
+ * Copyright (C) 2011 Enrico Schröder <enni schroeder gmail com>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_UNIT_ADJUSTMENT_H__
+#define __GIMP_UNIT_ADJUSTMENT_H__
+
+#include "libgimpbase/gimpbase.h"
+
+G_BEGIN_DECLS
+
+/**
+ * boiler-plate
+ **/
+#define GIMP_TYPE_UNIT_ADJUSTMENT            (gimp_unit_adjustment_get_type ())
+#define GIMP_UNIT_ADJUSTMENT(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_UNIT_ADJUSTMENT, GimpUnitAdjustment))
+#define GIMP_UNIT_ADJUSTMENT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_UNIT_ADJUSTMENT, GimpUnitAdjustmentClass))
+#define GIMP_IS_UNIT_ADJUSTMENT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GIMP_TYPE_UNIT_ADJUSTMENT))
+#define GIMP_IS_UNIT_ADJUSTMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_UNIT_ADJUSTMENT))
+#define GIMP_UNIT_ADJUSTMENT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_UNIT_ADJUSTMENT, GimpUnitAdjustmentClass))
+
+typedef struct _GimpUnitAdjustment       GimpUnitAdjustment;
+typedef struct _GimpUnitAdjustmentClass  GimpUnitAdjustmentClass;
+
+struct _GimpUnitAdjustment
+{
+  GtkAdjustment parent_instance;
+
+  /* flag set when unit has been changed externally */
+  gboolean      unitChanged; 
+
+  /* private */
+  /* TODO move private fields into own struct? */
+  GimpUnit  unit;           /* the unit our value is in */
+  gdouble   resolution;     /* resolution in dpi */
+};
+
+struct _GimpUnitAdjustmentClass
+{
+  GtkAdjustmentClass parent_class;
+
+  /* signals */
+  guint sig_unit_changed_id;
+};
+
+/**
+ * prototypes
+ **/
+GType   gimp_unit_adjustment_get_type (void);
+GObject *gimp_unit_adjustment_new (void);
+
+/* sets unit of adjustment, does conversion if neccessary */
+void    gimp_unit_adjustment_set_unit (GimpUnitAdjustment *adj, GimpUnit unit);
+/* sets/gets the value of an adjustment */
+void    gimp_unit_adjustment_set_value (GimpUnitAdjustment *adj, gdouble value);
+gdouble gimp_unit_adjustment_get_value (GimpUnitAdjustment *adj);
+gdouble gimp_unit_adjustment_get_value_in_unit    (GimpUnitAdjustment *adj, GimpUnit unit);
+void    gimp_unit_adjustment_set_resolution (GimpUnitAdjustment *adj, gdouble res);
+gdouble gimp_unit_adjustment_get_resolution (GimpUnitAdjustment *adj);
+/* get string in format "value unit" */
+gchar*  gimp_unit_adjustment_to_string (GimpUnitAdjustment *adj);
+gchar*  gimp_unit_adjustment_to_string_in_unit (GimpUnitAdjustment *adj, GimpUnit unit);
+/* connects adjustment to another adjustment */
+void    gimp_unit_adjustment_connect (GimpUnitAdjustment *adj, GimpUnitAdjustment *target);
+
+G_END_DECLS
+
+#endif /*__GIMP_UNIT_ADJUSTMENT_H__*/
\ No newline at end of file
diff --git a/libgimpwidgets/gimpunitentry.c b/libgimpwidgets/gimpunitentry.c
new file mode 100644
index 0000000..185b33d
--- /dev/null
+++ b/libgimpwidgets/gimpunitentry.c
@@ -0,0 +1,349 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpunitentry.c
+ * Copyright (C) 2011 Enrico Schröder <enni schroeder gmail com>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <gtk/gtkadjustment.h>
+#include <gtk/gtkspinbutton.h>
+
+#include <glib/gprintf.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "gimpwidgets.h"
+
+#include "gimpeevl.h"
+#include "gimpunitentry.h"
+#include "gimpunitadjustment.h"
+
+G_DEFINE_TYPE (GimpUnitEntry, gimp_unit_entry, GTK_TYPE_SPIN_BUTTON);
+
+/* unit resolver for GimpEevl */
+static gboolean unit_resolver (const gchar      *ident,
+                               GimpEevlQuantity *result,
+                               gpointer          data);
+
+/* read and parse entered text */
+static gboolean gimp_unit_entry_parse (GimpUnitEntry *unitEntry);
+
+/**
+ * event handlers
+ **/
+static gint gimp_unit_entry_focus_out      (GtkWidget          *widget,
+                                            GdkEventFocus      *event);
+
+/**
+ *  signal handlers
+ **/
+
+/* format displayed text (signal emmitted by GtkSpinButton before text is displayed) */
+static gboolean on_output   (GtkSpinButton      *spin, 
+                             gpointer           data);
+/* parse and process entered text (signal emmited from GtkEntry) */
+static void on_text_changed (GtkEditable        *editable,
+                             gpointer           user_data);
+static void on_insert_text  (GtkEditable *editable,
+                             gchar *new_text,
+                             gint new_text_length,
+                             gint *position,
+                             gpointer user_data);
+static gint on_input        (GtkSpinButton *spinbutton,
+                             gpointer       arg1,
+                             gpointer       user_data);
+
+static void
+gimp_unit_entry_init (GimpUnitEntry *unitEntry)
+{
+  GimpUnitEntryClass *class = GIMP_UNIT_ENTRY_GET_CLASS (unitEntry);
+  
+  /* create and set our adjustment subclass */
+  GObject *adjustment = gimp_unit_adjustment_new ();
+
+  unitEntry->unitAdjustment = GIMP_UNIT_ADJUSTMENT (adjustment);
+  gtk_spin_button_set_adjustment (GTK_SPIN_BUTTON (unitEntry), 
+                                  GTK_ADJUSTMENT (adjustment));
+
+  /* some default values */
+  gtk_spin_button_set_update_policy (&unitEntry->parent_instance, GTK_UPDATE_ALWAYS);                                            
+
+  /* connect signals */
+  g_signal_connect (&unitEntry->parent_instance, 
+                    "output",
+                    G_CALLBACK(on_output), 
+                    (gpointer) adjustment);
+  g_signal_connect (&unitEntry->parent_instance.entry, 
+                    "insert-text",
+                    G_CALLBACK(on_insert_text), 
+                    (gpointer) unitEntry);
+  g_signal_connect (&unitEntry->parent_instance, 
+                    "input",
+                    G_CALLBACK(on_input), 
+                    (gpointer) unitEntry);
+  g_signal_connect (&unitEntry->parent_instance.entry,
+                    "changed",
+                    G_CALLBACK(on_text_changed), 
+                    (gpointer) unitEntry);
+
+  unitEntry->id = class->id;
+  class->id++;
+}
+
+static void
+gimp_unit_entry_class_init (GimpUnitEntryClass *class)
+{
+  //GtkWidgetClass   *widgetClass = GTK_WIDGET_CLASS (class);
+
+  /* some events we need to catch instead of our parent */
+  //widgetClass->focus_out_event = gimp_unit_entry_focus_out;
+
+  class->id = 0;
+}
+
+GtkWidget*
+gimp_unit_entry_new (void)
+{
+  return g_object_new (GIMP_TYPE_UNIT_ENTRY, NULL);
+}
+
+GimpUnitAdjustment*
+gimp_unit_entry_get_adjustment (GimpUnitEntry *entry)
+{
+  return entry->unitAdjustment;
+}
+
+/* connect to another entry */
+void 
+gimp_unit_entry_connect (GimpUnitEntry *entry, GimpUnitEntry *target)
+{
+  gimp_unit_adjustment_connect (entry->unitAdjustment, target->unitAdjustment);
+}
+
+/* read and parse entered text */
+static gboolean
+gimp_unit_entry_parse (GimpUnitEntry *entry)
+{
+  gdouble           newValue;
+  /* GimpEevl related stuff */
+  GimpEevlQuantity  result;
+  GError            *error    = NULL;
+  const gchar       *errorpos = 0;
+  /* text to parse */
+  const gchar       *str      = gtk_entry_get_text (GTK_ENTRY (entry));
+
+  if (strlen (str) <= 0)
+    return FALSE;
+  
+  /** 
+   * purpose of enteredUnit: use first unit unit_resolver will be called with  
+   * as entered unit. enteredUnit is reset now to know which unit was the first one
+   **/
+  entry->enteredUnit = -1;
+
+  g_debug ("%i parsing: %s", entry->id, str);
+
+  /* parse text via GimpEevl */
+  gimp_eevl_evaluate (str,
+                      unit_resolver,
+                      &result,
+                      (gpointer) entry,
+                      &errorpos,
+                      &error);
+
+  if (error || errorpos)
+  {
+    GdkColor color;
+    gdk_color_parse ("LightSalmon", &color);
+    gtk_widget_modify_base (GTK_WIDGET (entry), GTK_STATE_NORMAL, &color);
+
+    g_debug ("gimpeevl parsing error \n");
+    return FALSE;
+  }
+  else
+  {
+    gtk_widget_modify_base (GTK_WIDGET (entry), GTK_STATE_NORMAL, NULL);
+    g_debug ("%i gimpeevl parser result: %s = %lg (%d)", entry->id, str, result.value, result.dimension);
+    g_debug ("%i determined unit: %s\n", entry->id, gimp_unit_get_abbreviation (entry->enteredUnit));
+
+    /* set new unit */  
+    if (entry->enteredUnit != entry->unitAdjustment->unit)
+    {
+      gimp_unit_adjustment_set_unit (entry->unitAdjustment, entry->enteredUnit);
+    }
+
+    /* set new value */
+    if (gimp_unit_adjustment_get_value (entry->unitAdjustment) != result.value)
+    {
+      /* result from parser is in inch, so convert to desired unit */
+      newValue = gimp_units_to_pixels (result.value,
+                                       GIMP_UNIT_INCH,
+                                       entry->unitAdjustment->resolution);
+      newValue = gimp_pixels_to_units (newValue,
+                                       entry->unitAdjustment->unit, 
+                                       entry->unitAdjustment->resolution);
+
+      gimp_unit_adjustment_set_value (entry->unitAdjustment, newValue);
+
+      g_object_notify (G_OBJECT ( GTK_SPIN_BUTTON (entry)), "value");
+    }
+  }
+
+  return TRUE;
+}
+
+/**
+ * signal handlers
+ **/
+
+/* format displayed text, displays "[value] [unit]" (gets called by GtkSpinButton) */
+static gboolean 
+on_output (GtkSpinButton *spin, gpointer data)
+{
+  gchar *text;
+  GimpUnitAdjustment *adj = GIMP_UNIT_ADJUSTMENT (data);
+
+  /* return if widget still has focus => user input must not be overwritten */
+  if (gtk_widget_has_focus (GTK_WIDGET (spin)))
+    return TRUE;
+
+  /* parse once more to prevent value from being overwritten somewhere in GtkSpinButton or 
+     GtkEntry. If we don't do that, the entered text is truncated at the first space.
+     TODO: find out where and why
+     not very elegant, because we have do deactivate parsing in case the value was not
+     modified by user input but by changes that happened in a connected entry
+  */
+  if(adj->unitChanged)
+    adj->unitChanged = FALSE;
+  else
+    gimp_unit_entry_parse (GIMP_UNIT_ENTRY (spin));
+  
+  text = gimp_unit_adjustment_to_string (adj);
+
+  g_debug ("on_output: %s\n", text);
+
+  gtk_entry_set_text (GTK_ENTRY (spin), text);
+
+  g_free (text);
+
+  return TRUE;
+}
+
+static 
+void on_insert_text (GtkEditable *editable,
+                     gchar *new_text,
+                     gint new_text_length,
+                     gint *position,
+                     gpointer user_data)
+{
+  g_debug ("on_insert_text\n");
+}
+
+/* parse and process entered text (signal emmited from GtkEntry) */
+static 
+void on_text_changed (GtkEditable *editable, gpointer user_data)
+{
+  g_debug ("on_text_changed\n"); 
+  
+  gimp_unit_entry_parse (GIMP_UNIT_ENTRY (user_data));
+}
+
+/* unit resolver for GimpEevl */
+static gboolean
+unit_resolver (const gchar      *ident,
+               GimpEevlQuantity *result,
+               gpointer          user_data)
+{
+  GimpUnitEntry   *entry       = GIMP_UNIT_ENTRY (user_data);
+  GimpUnit        *unit        = &(entry->enteredUnit);
+  gboolean        resolved     = FALSE;
+  gboolean        default_unit = (ident == NULL);
+  gint            numUnits     = gimp_unit_get_number_of_units ();
+  const gchar     *abbr; 
+  gint            i            = 0;
+
+  result->dimension = 1;
+
+  /* if no unit is specified, use default unit */
+  if (default_unit)
+  {
+    /* if default hasn't been set before, set to inch*/
+    if (*unit == -1)
+      *unit = GIMP_UNIT_INCH;
+
+    result->dimension = 1;
+
+    if (*unit == GIMP_UNIT_PIXEL) /* handle case that unit is px */
+      result->value = gimp_unit_entry_get_adjustment (entry)->resolution;
+    else                          /* otherwise use factor */
+      result->value = gimp_unit_get_factor (*unit);
+
+    resolved          = TRUE; 
+    return resolved;
+  }
+
+  /* find matching unit */
+  for (i = 0; i < numUnits; i++)
+  {
+    abbr = gimp_unit_get_abbreviation (i);
+
+    if (strcmp (abbr, ident) == 0)
+    {
+      /* handle case that unit is px */
+      if (i == GIMP_UNIT_PIXEL)
+        result->value = gimp_unit_entry_get_adjustment (entry)->resolution;
+      else
+        result->value = gimp_unit_get_factor (i);
+
+      if (*unit == -1)
+        *unit = i;
+
+      i = numUnits;
+      resolved = TRUE;
+    }
+  }
+
+  return resolved;
+}
+
+static 
+gint on_input        (GtkSpinButton *spinButton,
+                      gpointer       arg1,
+                      gpointer       user_data)
+{
+  g_debug ("on_input\n");
+
+  //gimp_unit_entry_parse (GIMP_UNIT_ENTRY (spinButton));
+
+  return 0;
+}
+
+static gint 
+gimp_unit_entry_focus_out (GtkWidget          *widget,
+                           GdkEventFocus      *event)
+{
+  GtkEntryClass *class = GTK_ENTRY_CLASS (gimp_unit_entry_parent_class);
+
+  g_debug ("focus_out\n");
+
+  return GTK_WIDGET_CLASS (class)->focus_out_event (widget, event);
+}
diff --git a/libgimpwidgets/gimpunitentry.h b/libgimpwidgets/gimpunitentry.h
new file mode 100644
index 0000000..54ed4ff
--- /dev/null
+++ b/libgimpwidgets/gimpunitentry.h
@@ -0,0 +1,71 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpunitentry.h
+ * Copyright (C) 2011 Enrico Schröder <enni schroeder gmail com>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_UNIT_ENTRY_H__
+#define __GIMP_UNIT_ENTRY_H__
+
+#include "gimpunitadjustment.h"
+
+G_BEGIN_DECLS
+
+/**
+ * boiler-plate
+ **/
+#define GIMP_TYPE_UNIT_ENTRY            (gimp_unit_entry_get_type ())
+#define GIMP_UNIT_ENTRY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_UNIT_ENTRY, GimpUnitEntry))
+#define GIMP_UNIT_ENTRY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_UNIT_ENTRY, GimpUnitEntryClass))
+#define GIMP_IS_UNIT_ENTRY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE (obj, GIMP_TYPE_UNIT_ENTRY))
+#define GIMP_IS_UNIT_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_UNIT_ENTRY))
+#define GIMP_UNIT_ENTRY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_UNIT_ENTRY, GimpUnitEntryClass))
+
+typedef struct _GimpUnitEntry       GimpUnitEntry;
+typedef struct _GimpUnitEntryClass  GimpUnitEntryClass;
+
+struct _GimpUnitEntry
+{
+  GtkSpinButton parent_instance;
+
+  /* private */
+  GimpUnitAdjustment *unitAdjustment; /* for convinience */
+  GimpUnit           enteredUnit;     /* used to determine which unit was entered */
+
+  gint id; /* for debugging */
+};
+
+struct _GimpUnitEntryClass
+{
+  GtkSpinButtonClass parent_class;
+
+  gint id; /* for debugging */
+};
+
+/**
+ * prototypes
+ **/
+GType     gimp_unit_entry_get_type (void);
+GtkWidget *gimp_unit_entry_new (void);
+GimpUnitAdjustment *gimp_unit_entry_get_adjustment (GimpUnitEntry *entry);
+/* connect to another entry */
+void gimp_unit_entry_connect (GimpUnitEntry *entry, GimpUnitEntry *target);
+
+G_END_DECLS
+
+#endif /*__GIMP_UNIT_ENTRY_H__*/
\ No newline at end of file
diff --git a/libgimpwidgets/test-unitentry.c b/libgimpwidgets/test-unitentry.c
new file mode 100644
index 0000000..2f62317
--- /dev/null
+++ b/libgimpwidgets/test-unitentry.c
@@ -0,0 +1,103 @@
+/* small test app for the new unit entry widget developed during Google Summer of Code 2011 */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib-object.h>
+#include <glib/gprintf.h>
+#include <gtk/gtk.h>
+
+#include "devel-docs/tools/units.h"
+
+#include "gimpunitentry.h"
+
+/* global objects */
+GtkWidget *window;
+GtkWidget *vbox;
+GtkWidget *valign;
+GtkWidget *inLabel;
+GtkWidget *pxLabel;
+
+GtkWidget *entry1;
+GtkWidget *entry2;
+
+void on_value_changed (GtkAdjustment *adj, gpointer userData)
+{
+  gchar text[40];
+  gchar *val1 = gimp_unit_adjustment_to_string_in_unit (GIMP_UNIT_ENTRY (entry1)->unitAdjustment, GIMP_UNIT_INCH);
+  gchar *val2 = gimp_unit_adjustment_to_string_in_unit (GIMP_UNIT_ENTRY (entry2)->unitAdjustment, GIMP_UNIT_INCH);
+  g_sprintf (text, "%s x %s", val1, val2);
+  gtk_label_set_text (GTK_LABEL(inLabel), text); 
+
+  val1 = gimp_unit_adjustment_to_string_in_unit (GIMP_UNIT_ENTRY (entry1)->unitAdjustment, GIMP_UNIT_PIXEL);
+  val2 = gimp_unit_adjustment_to_string_in_unit (GIMP_UNIT_ENTRY (entry2)->unitAdjustment, GIMP_UNIT_PIXEL);
+  g_sprintf (text, "%s x %s", val1, val2);
+  gtk_label_set_text (GTK_LABEL(pxLabel), text); 
+
+  g_free (val1);
+  g_free (val2);
+}
+
+/* set up interface */
+void
+create_interface(void)
+{
+  /* main window */
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+  gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER);
+  gtk_window_set_default_size (GTK_WINDOW(window), 200, 100);
+
+  /* vbox (used for the entries) */
+  vbox = gtk_vbox_new (TRUE, 1);
+
+  /* valign */
+  valign = gtk_alignment_new (0, 0, 1, 0);
+  gtk_container_add (GTK_CONTAINER (valign), vbox);
+  gtk_container_add (GTK_CONTAINER (window), valign);
+
+  /* the entries */
+  entry1 = gimp_unit_entry_new ();
+  entry2 = gimp_unit_entry_new ();
+
+  gtk_box_pack_start (GTK_BOX (vbox), entry1, TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (vbox), entry2, TRUE, TRUE, 0);
+
+  gimp_unit_entry_connect (GIMP_UNIT_ENTRY (entry1), GIMP_UNIT_ENTRY (entry2));
+  gimp_unit_entry_connect (GIMP_UNIT_ENTRY (entry2), GIMP_UNIT_ENTRY (entry1));
+
+  gimp_unit_adjustment_set_value (gimp_unit_entry_get_adjustment (GIMP_UNIT_ENTRY (entry1)), 20);
+  gimp_unit_adjustment_set_value (gimp_unit_entry_get_adjustment (GIMP_UNIT_ENTRY (entry2)), 20);
+
+  /* status label */
+  inLabel = gtk_label_new ("inches");
+  pxLabel = gtk_label_new ("pixels");
+  gtk_box_pack_end (GTK_BOX (vbox), pxLabel, TRUE, TRUE, 0);
+  gtk_box_pack_end (GTK_BOX (vbox), inLabel, TRUE, TRUE, 0);
+
+  on_value_changed (NULL, NULL);
+
+  /* signals */
+  g_signal_connect_swapped (G_OBJECT(window), "destroy",
+                            G_CALLBACK(gtk_main_quit), NULL);
+  g_signal_connect (G_OBJECT (GIMP_UNIT_ENTRY (entry1)->unitAdjustment), "value-changed",
+                    G_CALLBACK (on_value_changed), NULL);
+  g_signal_connect (G_OBJECT (GIMP_UNIT_ENTRY (entry2)->unitAdjustment), "value-changed",
+                    G_CALLBACK (on_value_changed), NULL);
+
+  gtk_widget_show_all (window);
+}
+
+int main (int   argc,
+          char *argv[])
+{
+    units_init();
+
+    gtk_init (&argc, &argv);
+
+    create_interface ();
+
+    gtk_main ();
+    
+    return 0;
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]