|
From: <gi...@gp...> - 2011-08-29 05:27:10
|
The branch, master has been updated
via 728f350268e134ca116a6f79577843db7b18e82c (commit)
via 73591e0e0e4c2abc764a2a8be503a44da1ca86f4 (commit)
via 352a088d8c506ef0407cb9c88844bf4033576eb0 (commit)
from acf8d00db4a90b555d768341a97453914b7b4aec (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
=========
Summary
=========
src/Makefile.am | 12 +-
...isibility.c => ghid-cell-renderer-visibility.c} | 118 ++++++++++----------
src/hid/gtk/ghid-cell-renderer-visibility.h | 24 ++++
.../{gtk-pcb-coord-entry.c => ghid-coord-entry.c} | 76 +++++++-------
src/hid/gtk/ghid-coord-entry.h | 35 ++++++
...-pcb-layer-selector.c => ghid-layer-selector.c} | 118 ++++++++++----------
src/hid/gtk/ghid-layer-selector.h | 45 ++++++++
src/hid/gtk/gtk-pcb-cell-renderer-visibility.h | 24 ----
src/hid/gtk/gtk-pcb-coord-entry.h | 35 ------
src/hid/gtk/gtk-pcb-layer-selector.h | 45 --------
src/hid/gtk/gui-config.c | 8 +-
src/hid/gtk/gui-dialog-print.c | 6 +-
src/hid/gtk/gui-dialog-size.c | 28 +++---
src/hid/gtk/gui-top-window.c | 84 +++++++-------
src/hid/gtk/gui-utils.c | 17 ++--
src/hid/gtk/gui.h | 6 +-
16 files changed, 340 insertions(+), 341 deletions(-)
rename src/hid/gtk/{gtk-pcb-cell-renderer-visibility.c => ghid-cell-renderer-visibility.c} (61%)
create mode 100644 src/hid/gtk/ghid-cell-renderer-visibility.h
rename src/hid/gtk/{gtk-pcb-coord-entry.c => ghid-coord-entry.c} (76%)
create mode 100644 src/hid/gtk/ghid-coord-entry.h
rename src/hid/gtk/{gtk-pcb-layer-selector.c => ghid-layer-selector.c} (87%)
create mode 100644 src/hid/gtk/ghid-layer-selector.h
delete mode 100644 src/hid/gtk/gtk-pcb-cell-renderer-visibility.h
delete mode 100644 src/hid/gtk/gtk-pcb-coord-entry.h
delete mode 100644 src/hid/gtk/gtk-pcb-layer-selector.h
=================
Commit Messages
=================
commit 728f350268e134ca116a6f79577843db7b18e82c
Author: Andrew Poelstra <as...@sf...>
Commit: Andrew Poelstra <as...@sf...>
Rename GtkPcbCoordEntry to GHidCoordEntry
:100644 100644 00e7453... 4b66ac7... M src/Makefile.am
:000000 100644 0000000... a49ceca... A src/hid/gtk/ghid-coord-entry.c
:000000 100644 0000000... e90c9f9... A src/hid/gtk/ghid-coord-entry.h
:100644 000000 233dc9b... 0000000... D src/hid/gtk/gtk-pcb-coord-entry.c
:100644 000000 3827ccf... 0000000... D src/hid/gtk/gtk-pcb-coord-entry.h
:100644 100644 215f16a... 88bf547... M src/hid/gtk/gui-config.c
:100644 100644 71b078f... ce98f13... M src/hid/gtk/gui-dialog-print.c
:100644 100644 27c0336... 8cc9185... M src/hid/gtk/gui-dialog-size.c
:100644 100644 a36057b... e9008c6... M src/hid/gtk/gui-utils.c
:100644 100644 ad2a112... 30ff593... M src/hid/gtk/gui.h
commit 73591e0e0e4c2abc764a2a8be503a44da1ca86f4
Author: Andrew Poelstra <as...@sf...>
Commit: Andrew Poelstra <as...@sf...>
Rename GtkPcbLayerSelector to GHidLayerSelector
:100644 100644 f4bba29... 00e7453... M src/Makefile.am
:000000 100644 0000000... 06dc8cd... A src/hid/gtk/ghid-layer-selector.c
:000000 100644 0000000... bfeffe9... A src/hid/gtk/ghid-layer-selector.h
:100644 000000 1067aeb... 0000000... D src/hid/gtk/gtk-pcb-layer-selector.c
:100644 000000 27b0de9... 0000000... D src/hid/gtk/gtk-pcb-layer-selector.h
:100644 100644 26e0030... 9d170c8... M src/hid/gtk/gui-top-window.c
commit 352a088d8c506ef0407cb9c88844bf4033576eb0
Author: Andrew Poelstra <as...@sf...>
Commit: Andrew Poelstra <as...@sf...>
Rename GtkPcbCellRendererVisibility to GHidCellRendererVisibility
:100644 100644 d4c37e0... f4bba29... M src/Makefile.am
:000000 100644 0000000... 2e07c67... A src/hid/gtk/ghid-cell-renderer-visibility.c
:000000 100644 0000000... be08fae... A src/hid/gtk/ghid-cell-renderer-visibility.h
:100644 000000 9e8593c... 0000000... D src/hid/gtk/gtk-pcb-cell-renderer-visibility.c
:100644 000000 212c4a4... 0000000... D src/hid/gtk/gtk-pcb-cell-renderer-visibility.h
:100644 100644 c8c9849... 1067aeb... M src/hid/gtk/gtk-pcb-layer-selector.c
=========
Changes
=========
commit 728f350268e134ca116a6f79577843db7b18e82c
Author: Andrew Poelstra <as...@sf...>
Commit: Andrew Poelstra <as...@sf...>
Rename GtkPcbCoordEntry to GHidCoordEntry
diff --git a/src/Makefile.am b/src/Makefile.am
index 00e7453..4b66ac7 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -270,8 +270,8 @@ libgtk_a_CPPFLAGS = -I./hid/gtk
LIBGTK_SRCS = \
dolists.h \
hid/hidint.h \
- hid/gtk/gtk-pcb-coord-entry.c \
- hid/gtk/gtk-pcb-coord-entry.h \
+ hid/gtk/ghid-coord-entry.c \
+ hid/gtk/ghid-coord-entry.h \
hid/gtk/ghid-layer-selector.c \
hid/gtk/ghid-layer-selector.h \
hid/gtk/ghid-cell-renderer-visibility.c \
diff --git a/src/hid/gtk/ghid-coord-entry.c b/src/hid/gtk/ghid-coord-entry.c
new file mode 100644
index 0000000..a49ceca
--- /dev/null
+++ b/src/hid/gtk/ghid-coord-entry.c
@@ -0,0 +1,312 @@
+/*! \file <gtk-pcb-coord-entry.c>
+ * \brief Implementation of GHidCoordEntry widget
+ * \par Description
+ * This widget is a modified spinbox for the user to enter
+ * pcb coords. It is assigned a default unit (for display),
+ * but this can be changed by the user by typing a new one
+ * or right-clicking on the box.
+ *
+ * Internally, it keeps track of its value in pcb coords.
+ * From the user's perspective, it uses natural human units.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gtkhid.h"
+#include "gui.h"
+#include "pcb-printf.h"
+
+#include "ghid-coord-entry.h"
+
+enum {
+ UNIT_CHANGE_SIGNAL,
+ LAST_SIGNAL
+};
+
+static guint ghid_coord_entry_signals[LAST_SIGNAL] = { 0 };
+
+struct _GHidCoordEntry
+{
+ GtkSpinButton parent;
+
+ Coord min_value;
+ Coord max_value;
+ Coord value;
+
+ enum ce_step_size step_size;
+ const Unit *unit;
+};
+
+struct _GHidCoordEntryClass
+{
+ GtkSpinButtonClass parent_class;
+
+ void (* change_unit) (GHidCoordEntry *, const Unit *);
+};
+
+/* SIGNAL HANDLERS */
+/*! \brief Callback for "Change Unit" menu click */
+static void
+menu_item_activate_cb (GtkMenuItem *item, GHidCoordEntry *ce)
+{
+ const char *text = gtk_menu_item_get_label (item);
+ const Unit *unit = get_unit_struct (text);
+
+ g_signal_emit (ce, ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, unit);
+}
+
+/*! \brief Callback for context menu creation */
+static void
+ghid_coord_entry_popup_cb (GHidCoordEntry *ce, GtkMenu *menu, gpointer data)
+{
+ int i, n;
+ const Unit *unit_list;
+ GtkWidget *menu_item, *submenu;
+
+ /* Build submenu */
+ n = get_n_units ();
+ unit_list = get_unit_list ();
+
+ submenu = gtk_menu_new ();
+ for (i = 0; i < n; ++i)
+ {
+ menu_item = gtk_menu_item_new_with_label (unit_list[i].suffix);
+ g_signal_connect (G_OBJECT (menu_item), "activate",
+ G_CALLBACK (menu_item_activate_cb), ce);
+ gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menu_item);
+ gtk_widget_show (menu_item);
+ }
+
+ /* Add submenu to menu */
+ menu_item = gtk_separator_menu_item_new ();
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+ gtk_widget_show (menu_item);
+
+ menu_item = gtk_menu_item_new_with_label (_("Change Units"));
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu);
+ gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
+ gtk_widget_show (menu_item);
+}
+
+/*! \brief Callback for user output */
+static gboolean
+ghid_coord_entry_output_cb (GHidCoordEntry *ce, gpointer data)
+{
+ GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
+ double value = gtk_adjustment_get_value (adj);
+ gchar *text;
+
+ text = pcb_g_strdup_printf ("%.*f %s", ce->unit->default_prec, value, ce->unit->suffix);
+ gtk_entry_set_text (GTK_ENTRY (ce), text);
+ g_free (text);
+
+ return TRUE;
+}
+
+/*! \brief Callback for user input */
+static gboolean
+ghid_coord_text_changed_cb (GHidCoordEntry *entry, gpointer data)
+{
+ const char *text;
+ char *suffix;
+ const Unit *new_unit;
+ double value;
+
+ /* Check if units have changed */
+ text = gtk_entry_get_text (GTK_ENTRY (entry));
+ value = strtod (text, &suffix);
+ new_unit = get_unit_struct (suffix);
+ if (new_unit && new_unit != entry->unit)
+ {
+ entry->value = unit_to_coord (new_unit, value);
+ g_signal_emit (entry, ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, new_unit);
+ }
+
+ return FALSE;
+}
+
+/*! \brief Callback for change in value (input or ^v clicks) */
+static gboolean
+ghid_coord_value_changed_cb (GHidCoordEntry *ce, gpointer data)
+{
+ GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
+
+ /* Re-calculate internal value */
+ double value = gtk_adjustment_get_value (adj);
+ ce->value = unit_to_coord (ce->unit, value);
+ /* Handle potential unit changes */
+ ghid_coord_text_changed_cb (ce, data);
+
+ return FALSE;
+}
+
+/*! \brief Change the unit used by a coord entry
+ *
+ * \param [in] ce The entry to be acted on
+ * \parin [in] new_unit The new unit to be used
+ */
+static void
+ghid_coord_entry_change_unit (GHidCoordEntry *ce, const Unit *new_unit)
+{
+ double climb_rate = 0.0;
+ GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
+
+ ce->unit = new_unit;
+ /* Re-calculate min/max values for spinbox */
+ gtk_adjustment_configure (adj, coord_to_unit (new_unit, ce->value),
+ coord_to_unit (new_unit, ce->min_value),
+ coord_to_unit (new_unit, ce->max_value),
+ ce->unit->step_small,
+ ce->unit->step_medium,
+ 0.0);
+
+ switch (ce->step_size)
+ {
+ case CE_TINY: climb_rate = new_unit->step_tiny; break;
+ case CE_SMALL: climb_rate = new_unit->step_small; break;
+ case CE_MEDIUM: climb_rate = new_unit->step_medium; break;
+ case CE_LARGE: climb_rate = new_unit->step_large; break;
+ }
+ gtk_spin_button_configure (GTK_SPIN_BUTTON (ce), adj, climb_rate,
+ new_unit->default_prec + strlen (new_unit->suffix));
+}
+
+/* CONSTRUCTOR */
+static void
+ghid_coord_entry_init (GHidCoordEntry *ce)
+{
+ /* Hookup signal handlers */
+ g_signal_connect (G_OBJECT (ce), "focus_out_event",
+ G_CALLBACK (ghid_coord_text_changed_cb), NULL);
+ g_signal_connect (G_OBJECT (ce), "value_changed",
+ G_CALLBACK (ghid_coord_value_changed_cb), NULL);
+ g_signal_connect (G_OBJECT (ce), "populate_popup",
+ G_CALLBACK (ghid_coord_entry_popup_cb), NULL);
+ g_signal_connect (G_OBJECT (ce), "output",
+ G_CALLBACK (ghid_coord_entry_output_cb), NULL);
+}
+
+static void
+ghid_coord_entry_class_init (GHidCoordEntryClass *klass)
+{
+ klass->change_unit = ghid_coord_entry_change_unit;
+
+ /* GtkAutoComplete *ce : the object acted on */
+ /* const Unit *new_unit: the new unit that was set */
+ ghid_coord_entry_signals[UNIT_CHANGE_SIGNAL] =
+ g_signal_new ("change-unit",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GHidCoordEntryClass, change_unit),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE,
+ 1, G_TYPE_POINTER);
+
+}
+
+/* PUBLIC FUNCTIONS */
+GType
+ghid_coord_entry_get_type (void)
+{
+ static GType ce_type = 0;
+
+ if (!ce_type)
+ {
+ const GTypeInfo ce_info =
+ {
+ sizeof (GHidCoordEntryClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ghid_coord_entry_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GHidCoordEntry),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ghid_coord_entry_init,
+ };
+
+ ce_type = g_type_register_static (GTK_TYPE_SPIN_BUTTON,
+ "GHidCoordEntry",
+ &ce_info,
+ 0);
+ }
+
+ return ce_type;
+}
+
+/*! \brief Create a new GHidCoordEntry
+ *
+ * \param [in] min_val The minimum allowed value, in pcb coords
+ * \param [in] max_val The maximum allowed value, in pcb coords
+ * \param [in] value The default value, in pcb coords
+ * \param [in] unit The default unit
+ * \param [in] step_size How large the default increments should be
+ *
+ * \return a freshly-allocated GHidCoordEntry
+ */
+GtkWidget *
+ghid_coord_entry_new (Coord min_val, Coord max_val, Coord value,
+ const Unit *unit, enum ce_step_size step_size)
+{
+ /* Setup spinbox min/max values */
+ double small_step, big_step;
+ GtkAdjustment *adj;
+ GHidCoordEntry *ce = g_object_new (GHID_COORD_ENTRY_TYPE, NULL);
+
+ ce->unit = unit;
+ ce->min_value = min_val;
+ ce->max_value = max_val;
+ ce->value = value;
+
+ ce->step_size = step_size;
+ switch (step_size)
+ {
+ case CE_TINY:
+ small_step = unit->step_tiny;
+ big_step = unit->step_small;
+ break;
+ case CE_SMALL:
+ small_step = unit->step_small;
+ big_step = unit->step_medium;
+ break;
+ case CE_MEDIUM:
+ small_step = unit->step_medium;
+ big_step = unit->step_large;
+ break;
+ case CE_LARGE:
+ small_step = unit->step_large;
+ big_step = unit->step_huge;
+ break;
+ default:
+ small_step = big_step = 0;
+ break;
+ }
+
+ adj = GTK_ADJUSTMENT (gtk_adjustment_new (coord_to_unit (unit, value),
+ coord_to_unit (unit, min_val),
+ coord_to_unit (unit, max_val),
+ small_step, big_step, 0.0));
+ gtk_spin_button_configure (GTK_SPIN_BUTTON (ce), adj, small_step,
+ unit->default_prec + strlen (unit->suffix));
+ gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (ce), FALSE);
+
+ return GTK_WIDGET (ce);
+}
+
+/*! \brief Gets a GHidCoordEntry's value, in pcb coords */
+Coord
+ghid_coord_entry_get_value (GHidCoordEntry *ce)
+{
+ return ce->value;
+}
+
+/*! \brief Sets a GHidCoordEntry's value, in pcb coords */
+void
+ghid_coord_entry_set_value (GHidCoordEntry *ce, Coord val)
+{
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (ce),
+ coord_to_unit (ce->unit, val));
+}
+
diff --git a/src/hid/gtk/ghid-coord-entry.h b/src/hid/gtk/ghid-coord-entry.h
new file mode 100644
index 0000000..e90c9f9
--- /dev/null
+++ b/src/hid/gtk/ghid-coord-entry.h
@@ -0,0 +1,35 @@
+/* This is the modified GtkSpinbox used for entering Coords.
+ * Hopefully it can be used as a template whenever we migrate the
+ * rest of the Gtk HID to use GObjects and GtkWidget subclassing.
+ */
+#ifndef GHID_COORD_ENTRY_H__
+#define GHID_COORD_ENTRY_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS /* keep c++ happy */
+
+#define GHID_COORD_ENTRY_TYPE (ghid_coord_entry_get_type ())
+#define GHID_COORD_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHID_COORD_ENTRY_TYPE, GHidCoordEntry))
+#define GHID_COORD_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GHID_COORD_ENTRY_TYPE, GHidCoordEntryClass))
+#define IS_GHID_COORD_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHID_COORD_ENTRY_TYPE))
+#define IS_GHID_COORD_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GHID_COORD_ENTRY_TYPE))
+
+typedef struct _GHidCoordEntry GHidCoordEntry;
+typedef struct _GHidCoordEntryClass GHidCoordEntryClass;
+
+/* Step sizes */
+enum ce_step_size { CE_TINY, CE_SMALL, CE_MEDIUM, CE_LARGE };
+
+GType ghid_coord_entry_get_type (void);
+GtkWidget* ghid_coord_entry_new (Coord min_val, Coord max_val, Coord value,
+ const Unit *unit, enum ce_step_size step_size);
+void ghid_coord_entry_add_entry (GHidCoordEntry *ce, const gchar *name, const gchar *desc);
+gchar *ghid_coord_entry_get_last_command (GHidCoordEntry *ce);
+
+Coord ghid_coord_entry_get_value (GHidCoordEntry *ce);
+void ghid_coord_entry_set_value (GHidCoordEntry *ce, Coord val);
+
+G_END_DECLS /* keep c++ happy */
+#endif
diff --git a/src/hid/gtk/gtk-pcb-coord-entry.c b/src/hid/gtk/gtk-pcb-coord-entry.c
deleted file mode 100644
index 233dc9b..0000000
--- a/src/hid/gtk/gtk-pcb-coord-entry.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*! \file <gtk-pcb-coord-entry.c>
- * \brief Implementation of GtkPcbCoordEntry widget
- * \par Description
- * This widget is a modified spinbox for the user to enter
- * pcb coords. It is assigned a default unit (for display),
- * but this can be changed by the user by typing a new one
- * or right-clicking on the box.
- *
- * Internally, it keeps track of its value in pcb coords.
- * From the user's perspective, it uses natural human units.
- */
-
-#include <glib.h>
-#include <glib-object.h>
-#include <gtk/gtk.h>
-
-#include "gtkhid.h"
-#include "gui.h"
-#include "pcb-printf.h"
-
-#include "gtk-pcb-coord-entry.h"
-
-enum {
- UNIT_CHANGE_SIGNAL,
- LAST_SIGNAL
-};
-
-static guint gtk_pcb_coord_entry_signals[LAST_SIGNAL] = { 0 };
-
-struct _GtkPcbCoordEntry
-{
- GtkSpinButton parent;
-
- Coord min_value;
- Coord max_value;
- Coord value;
-
- enum ce_step_size step_size;
- const Unit *unit;
-};
-
-struct _GtkPcbCoordEntryClass
-{
- GtkSpinButtonClass parent_class;
-
- void (* change_unit) (GtkPcbCoordEntry *, const Unit *);
-};
-
-/* SIGNAL HANDLERS */
-/*! \brief Callback for "Change Unit" menu click */
-static void
-menu_item_activate_cb (GtkMenuItem *item, GtkPcbCoordEntry *ce)
-{
- const char *text = gtk_menu_item_get_label (item);
- const Unit *unit = get_unit_struct (text);
-
- g_signal_emit (ce, gtk_pcb_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, unit);
-}
-
-/*! \brief Callback for context menu creation */
-static void
-gtk_pcb_coord_entry_popup_cb (GtkPcbCoordEntry *ce, GtkMenu *menu, gpointer data)
-{
- int i, n;
- const Unit *unit_list;
- GtkWidget *menu_item, *submenu;
-
- /* Build submenu */
- n = get_n_units ();
- unit_list = get_unit_list ();
-
- submenu = gtk_menu_new ();
- for (i = 0; i < n; ++i)
- {
- menu_item = gtk_menu_item_new_with_label (unit_list[i].suffix);
- g_signal_connect (G_OBJECT (menu_item), "activate",
- G_CALLBACK (menu_item_activate_cb), ce);
- gtk_menu_shell_append (GTK_MENU_SHELL (submenu), menu_item);
- gtk_widget_show (menu_item);
- }
-
- /* Add submenu to menu */
- menu_item = gtk_separator_menu_item_new ();
- gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
- gtk_widget_show (menu_item);
-
- menu_item = gtk_menu_item_new_with_label (_("Change Units"));
- gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_item), submenu);
- gtk_menu_shell_prepend (GTK_MENU_SHELL (menu), menu_item);
- gtk_widget_show (menu_item);
-}
-
-/*! \brief Callback for user output */
-static gboolean
-gtk_pcb_coord_entry_output_cb (GtkPcbCoordEntry *ce, gpointer data)
-{
- GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
- double value = gtk_adjustment_get_value (adj);
- gchar *text;
-
- text = pcb_g_strdup_printf ("%.*f %s", ce->unit->default_prec, value, ce->unit->suffix);
- gtk_entry_set_text (GTK_ENTRY (ce), text);
- g_free (text);
-
- return TRUE;
-}
-
-/*! \brief Callback for user input */
-static gboolean
-gtk_pcb_coord_text_changed_cb (GtkPcbCoordEntry *entry, gpointer data)
-{
- const char *text;
- char *suffix;
- const Unit *new_unit;
- double value;
-
- /* Check if units have changed */
- text = gtk_entry_get_text (GTK_ENTRY (entry));
- value = strtod (text, &suffix);
- new_unit = get_unit_struct (suffix);
- if (new_unit && new_unit != entry->unit)
- {
- entry->value = unit_to_coord (new_unit, value);
- g_signal_emit (entry, gtk_pcb_coord_entry_signals[UNIT_CHANGE_SIGNAL], 0, new_unit);
- }
-
- return FALSE;
-}
-
-/*! \brief Callback for change in value (input or ^v clicks) */
-static gboolean
-gtk_pcb_coord_value_changed_cb (GtkPcbCoordEntry *ce, gpointer data)
-{
- GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
-
- /* Re-calculate internal value */
- double value = gtk_adjustment_get_value (adj);
- ce->value = unit_to_coord (ce->unit, value);
- /* Handle potential unit changes */
- gtk_pcb_coord_text_changed_cb (ce, data);
-
- return FALSE;
-}
-
-/*! \brief Change the unit used by a coord entry
- *
- * \param [in] ce The entry to be acted on
- * \parin [in] new_unit The new unit to be used
- */
-static void
-gtk_pcb_coord_entry_change_unit (GtkPcbCoordEntry *ce, const Unit *new_unit)
-{
- double climb_rate = 0.0;
- GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (ce));
-
- ce->unit = new_unit;
- /* Re-calculate min/max values for spinbox */
- gtk_adjustment_configure (adj, coord_to_unit (new_unit, ce->value),
- coord_to_unit (new_unit, ce->min_value),
- coord_to_unit (new_unit, ce->max_value),
- ce->unit->step_small,
- ce->unit->step_medium,
- 0.0);
-
- switch (ce->step_size)
- {
- case CE_TINY: climb_rate = new_unit->step_tiny; break;
- case CE_SMALL: climb_rate = new_unit->step_small; break;
- case CE_MEDIUM: climb_rate = new_unit->step_medium; break;
- case CE_LARGE: climb_rate = new_unit->step_large; break;
- }
- gtk_spin_button_configure (GTK_SPIN_BUTTON (ce), adj, climb_rate,
- new_unit->default_prec + strlen (new_unit->suffix));
-}
-
-/* CONSTRUCTOR */
-static void
-gtk_pcb_coord_entry_init (GtkPcbCoordEntry *ce)
-{
- /* Hookup signal handlers */
- g_signal_connect (G_OBJECT (ce), "focus_out_event",
- G_CALLBACK (gtk_pcb_coord_text_changed_cb), NULL);
- g_signal_connect (G_OBJECT (ce), "value_changed",
- G_CALLBACK (gtk_pcb_coord_value_changed_cb), NULL);
- g_signal_connect (G_OBJECT (ce), "populate_popup",
- G_CALLBACK (gtk_pcb_coord_entry_popup_cb), NULL);
- g_signal_connect (G_OBJECT (ce), "output",
- G_CALLBACK (gtk_pcb_coord_entry_output_cb), NULL);
-}
-
-static void
-gtk_pcb_coord_entry_class_init (GtkPcbCoordEntryClass *klass)
-{
- klass->change_unit = gtk_pcb_coord_entry_change_unit;
-
- /* GtkAutoComplete *ce : the object acted on */
- /* const Unit *new_unit: the new unit that was set */
- gtk_pcb_coord_entry_signals[UNIT_CHANGE_SIGNAL] =
- g_signal_new ("change-unit",
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (GtkPcbCoordEntryClass, change_unit),
- NULL, NULL,
- g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE,
- 1, G_TYPE_POINTER);
-
-}
-
-/* PUBLIC FUNCTIONS */
-GType
-gtk_pcb_coord_entry_get_type (void)
-{
- static GType ce_type = 0;
-
- if (!ce_type)
- {
- const GTypeInfo ce_info =
- {
- sizeof (GtkPcbCoordEntryClass),
- NULL, /* base_init */
- NULL, /* base_finalize */
- (GClassInitFunc) gtk_pcb_coord_entry_class_init,
- NULL, /* class_finalize */
- NULL, /* class_data */
- sizeof (GtkPcbCoordEntry),
- 0, /* n_preallocs */
- (GInstanceInitFunc) gtk_pcb_coord_entry_init,
- };
-
- ce_type = g_type_register_static (GTK_TYPE_SPIN_BUTTON,
- "GtkPcbCoordEntry",
- &ce_info,
- 0);
- }
-
- return ce_type;
-}
-
-/*! \brief Create a new GtkPcbCoordEntry
- *
- * \param [in] min_val The minimum allowed value, in pcb coords
- * \param [in] max_val The maximum allowed value, in pcb coords
- * \param [in] value The default value, in pcb coords
- * \param [in] unit The default unit
- * \param [in] step_size How large the default increments should be
- *
- * \return a freshly-allocated GtkPcbCoordEntry
- */
-GtkWidget *
-gtk_pcb_coord_entry_new (Coord min_val, Coord max_val, Coord value,
- const Unit *unit, enum ce_step_size step_size)
-{
- /* Setup spinbox min/max values */
- double small_step, big_step;
- GtkAdjustment *adj;
- GtkPcbCoordEntry *ce = g_object_new (GTK_PCB_COORD_ENTRY_TYPE, NULL);
-
- ce->unit = unit;
- ce->min_value = min_val;
- ce->max_value = max_val;
- ce->value = value;
-
- ce->step_size = step_size;
- switch (step_size)
- {
- case CE_TINY:
- small_step = unit->step_tiny;
- big_step = unit->step_small;
- break;
- case CE_SMALL:
- small_step = unit->step_small;
- big_step = unit->step_medium;
- break;
- case CE_MEDIUM:
- small_step = unit->step_medium;
- big_step = unit->step_large;
- break;
- case CE_LARGE:
- small_step = unit->step_large;
- big_step = unit->step_huge;
- break;
- default:
- small_step = big_step = 0;
- break;
- }
-
- adj = GTK_ADJUSTMENT (gtk_adjustment_new (coord_to_unit (unit, value),
- coord_to_unit (unit, min_val),
- coord_to_unit (unit, max_val),
- small_step, big_step, 0.0));
- gtk_spin_button_configure (GTK_SPIN_BUTTON (ce), adj, small_step,
- unit->default_prec + strlen (unit->suffix));
- gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (ce), FALSE);
-
- return GTK_WIDGET (ce);
-}
-
-/*! \brief Gets a GtkPcbCoordEntry's value, in pcb coords */
-Coord
-gtk_pcb_coord_entry_get_value (GtkPcbCoordEntry *ce)
-{
- return ce->value;
-}
-
-/*! \brief Sets a GtkPcbCoordEntry's value, in pcb coords */
-void
-gtk_pcb_coord_entry_set_value (GtkPcbCoordEntry *ce, Coord val)
-{
- gtk_spin_button_set_value (GTK_SPIN_BUTTON (ce),
- coord_to_unit (ce->unit, val));
-}
-
diff --git a/src/hid/gtk/gtk-pcb-coord-entry.h b/src/hid/gtk/gtk-pcb-coord-entry.h
deleted file mode 100644
index 3827ccf..0000000
--- a/src/hid/gtk/gtk-pcb-coord-entry.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* This is the modified GtkSpinbox used for entering Coords.
- * Hopefully it can be used as a template whenever we migrate the
- * rest of the Gtk HID to use GObjects and GtkWidget subclassing.
- */
-#ifndef GTK_PCB_COORD_ENTRY_H__
-#define GTK_PCB_COORD_ENTRY_H__
-
-#include <glib.h>
-#include <glib-object.h>
-
-G_BEGIN_DECLS /* keep c++ happy */
-
-#define GTK_PCB_COORD_ENTRY_TYPE (gtk_pcb_coord_entry_get_type ())
-#define GTK_PCB_COORD_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_PCB_COORD_ENTRY_TYPE, GtkPcbCoordEntry))
-#define GTK_PCB_COORD_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_PCB_COORD_ENTRY_TYPE, GtkPcbCoordEntryClass))
-#define IS_GTK_PCB_COORD_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_PCB_COORD_ENTRY_TYPE))
-#define IS_GTK_PCB_COORD_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_PCB_COORD_ENTRY_TYPE))
-
-typedef struct _GtkPcbCoordEntry GtkPcbCoordEntry;
-typedef struct _GtkPcbCoordEntryClass GtkPcbCoordEntryClass;
-
-/* Step sizes */
-enum ce_step_size { CE_TINY, CE_SMALL, CE_MEDIUM, CE_LARGE };
-
-GType gtk_pcb_coord_entry_get_type (void);
-GtkWidget* gtk_pcb_coord_entry_new (Coord min_val, Coord max_val, Coord value,
- const Unit *unit, enum ce_step_size step_size);
-void gtk_pcb_coord_entry_add_entry (GtkPcbCoordEntry *ce, const gchar *name, const gchar *desc);
-gchar *gtk_pcb_coord_entry_get_last_command (GtkPcbCoordEntry *ce);
-
-Coord gtk_pcb_coord_entry_get_value (GtkPcbCoordEntry *ce);
-void gtk_pcb_coord_entry_set_value (GtkPcbCoordEntry *ce, Coord val);
-
-G_END_DECLS /* keep c++ happy */
-#endif
diff --git a/src/hid/gtk/gui-config.c b/src/hid/gtk/gui-config.c
index 215f16a..88bf547 100644
--- a/src/hid/gtk/gui-config.c
+++ b/src/hid/gtk/gui-config.c
@@ -1011,9 +1011,9 @@ text_spin_button_cb (GtkSpinButton * spin, void * dst)
}
static void
-coord_entry_cb (GtkPcbCoordEntry * ce, void * dst)
+coord_entry_cb (GHidCoordEntry * ce, void * dst)
{
- *(Coord *) dst = gtk_pcb_coord_entry_get_value (ce);
+ *(Coord *) dst = ghid_coord_entry_get_value (ce);
ghidgui->config_modified = TRUE;
}
@@ -1139,9 +1139,9 @@ config_sizes_tab_create (GtkWidget * tab_vbox)
static GtkWidget *config_increments_vbox, *config_increments_tab_vbox;
static void
-increment_spin_button_cb (GtkPcbCoordEntry * ce, void * dst)
+increment_spin_button_cb (GHidCoordEntry * ce, void * dst)
{
- *(Coord *)dst = gtk_pcb_coord_entry_get_value (ce);
+ *(Coord *)dst = ghid_coord_entry_get_value (ce);
ghidgui->config_modified = TRUE;
}
diff --git a/src/hid/gtk/gui-dialog-print.c b/src/hid/gtk/gui-dialog-print.c
index 71b078f..ce98f13 100644
--- a/src/hid/gtk/gui-dialog-print.c
+++ b/src/hid/gtk/gui-dialog-print.c
@@ -174,9 +174,9 @@ ghid_attribute_dialog (HID_Attribute * attrs,
hbox = gtk_hbox_new (FALSE, 4);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
- entry = gtk_pcb_coord_entry_new (attrs[j].min_val, attrs[j].max_val,
- attrs[j].default_val.coord_value,
- Settings.grid_unit, CE_SMALL);
+ entry = ghid_coord_entry_new (attrs[j].min_val, attrs[j].max_val,
+ attrs[j].default_val.coord_value,
+ Settings.grid_unit, CE_SMALL);
gtk_box_pack_start (GTK_BOX (hbox), entry, FALSE, FALSE, 0);
if(attrs[j].default_val.str_value != NULL)
gtk_entry_set_text (GTK_ENTRY (entry),
diff --git a/src/hid/gtk/gui-dialog-size.c b/src/hid/gtk/gui-dialog-size.c
index 27c0336..8cc9185 100644
--- a/src/hid/gtk/gui-dialog-size.c
+++ b/src/hid/gtk/gui-dialog-size.c
@@ -85,32 +85,32 @@ make_route_string(RouteStyleType * rs)
}
static void
-via_hole_cb (GtkPcbCoordEntry * entry, gpointer data)
+via_hole_cb (GHidCoordEntry * entry, gpointer data)
{
SizesDialog * sd = (SizesDialog *)data;
gdouble via_hole_size, via_size;
- via_hole_size = gtk_pcb_coord_entry_get_value (entry);
- via_size = gtk_pcb_coord_entry_get_value
- (GTK_PCB_COORD_ENTRY (sd->via_size_coord_entry));
+ via_hole_size = ghid_coord_entry_get_value (entry);
+ via_size = ghid_coord_entry_get_value
+ (GHID_COORD_ENTRY (sd->via_size_coord_entry));
if (via_size < via_hole_size + MIN_PINORVIACOPPER)
- gtk_pcb_coord_entry_set_value (GTK_PCB_COORD_ENTRY (sd->via_size_coord_entry),
+ ghid_coord_entry_set_value (GHID_COORD_ENTRY (sd->via_size_coord_entry),
via_hole_size + MIN_PINORVIACOPPER);
}
static void
-via_size_cb (GtkPcbCoordEntry * entry, gpointer data)
+via_size_cb (GHidCoordEntry * entry, gpointer data)
{
SizesDialog * sd = (SizesDialog *)data;
gdouble via_hole_size, via_size;
- via_size = gtk_pcb_coord_entry_get_value (entry);
- via_hole_size = gtk_pcb_coord_entry_get_value
- (GTK_PCB_COORD_ENTRY (sd->via_hole_coord_entry));
+ via_size = ghid_coord_entry_get_value (entry);
+ via_hole_size = ghid_coord_entry_get_value
+ (GHID_COORD_ENTRY (sd->via_hole_coord_entry));
if (via_hole_size > via_size - MIN_PINORVIACOPPER)
- gtk_pcb_coord_entry_set_value (GTK_PCB_COORD_ENTRY (sd->via_hole_coord_entry),
+ ghid_coord_entry_set_value (GHID_COORD_ENTRY (sd->via_hole_coord_entry),
via_size - MIN_PINORVIACOPPER);
}
@@ -261,16 +261,16 @@ ghid_route_style_dialog (gint index, RouteStyleType * temp_rst)
rst = &rst_buf;
rst->Thick =
- gtk_pcb_coord_entry_get_value (GTK_PCB_COORD_ENTRY
+ ghid_coord_entry_get_value (GHID_COORD_ENTRY
(sd->line_width_coord_entry));
rst->Hole =
- gtk_pcb_coord_entry_get_value (GTK_PCB_COORD_ENTRY
+ ghid_coord_entry_get_value (GHID_COORD_ENTRY
(sd->via_hole_coord_entry));
rst->Diameter =
- gtk_pcb_coord_entry_get_value (GTK_PCB_COORD_ENTRY
+ ghid_coord_entry_get_value (GHID_COORD_ENTRY
(sd->via_size_coord_entry));
rst->Keepaway =
- gtk_pcb_coord_entry_get_value (GTK_PCB_COORD_ENTRY
+ ghid_coord_entry_get_value (GHID_COORD_ENTRY
(sd->clearance_coord_entry));
if (index < NUM_STYLES && !set_temp1 && !set_temp2)
diff --git a/src/hid/gtk/gui-utils.c b/src/hid/gtk/gui-utils.c
index a36057b..e9008c6 100644
--- a/src/hid/gtk/gui-utils.c
+++ b/src/hid/gtk/gui-utils.c
@@ -33,7 +33,6 @@
#endif
#include "gui.h"
-#include "gtk-pcb-coord-entry.h"
#include <gdk/gdkkeysyms.h>
#ifdef HAVE_LIBDMALLOC
@@ -273,11 +272,11 @@ ghid_button_connected (GtkWidget * box, GtkWidget ** button,
void
ghid_coord_entry (GtkWidget * box, GtkWidget ** coord_entry, Coord value,
Coord low, Coord high, enum ce_step_size step_size,
- gint width, void (*cb_func) (GtkPcbCoordEntry *, gpointer),
+ gint width, void (*cb_func) (GHidCoordEntry *, gpointer),
gpointer data, gboolean right_align, gchar * string)
{
GtkWidget *hbox = NULL, *label, *entry_widget;
- GtkPcbCoordEntry *entry;
+ GHidCoordEntry *entry;
if (string && box)
{
@@ -286,12 +285,12 @@ ghid_coord_entry (GtkWidget * box, GtkWidget ** coord_entry, Coord value,
box = hbox;
}
- entry_widget = gtk_pcb_coord_entry_new (low, high, value, Settings.grid_unit, step_size);
+ entry_widget = ghid_coord_entry_new (low, high, value, Settings.grid_unit, step_size);
if (coord_entry)
*coord_entry = entry_widget;
if (width > 0)
gtk_widget_set_size_request (entry_widget, width, -1);
- entry = GTK_PCB_COORD_ENTRY (entry_widget);
+ entry = GHID_COORD_ENTRY (entry_widget);
if (data == NULL)
data = (gpointer) entry;
if (cb_func)
@@ -368,21 +367,21 @@ void
ghid_table_coord_entry (GtkWidget * table, gint row, gint column,
GtkWidget ** coord_entry, Coord value,
Coord low, Coord high, enum ce_step_size step_size,
- gint width, void (*cb_func) (GtkPcbCoordEntry *, gpointer),
+ gint width, void (*cb_func) (GHidCoordEntry *, gpointer),
gpointer data, gboolean right_align, gchar * string)
{
GtkWidget *label, *entry_widget;
- GtkPcbCoordEntry *entry;
+ GHidCoordEntry *entry;
if (!table)
return;
- entry_widget = gtk_pcb_coord_entry_new (low, high, value, Settings.grid_unit, step_size);
+ entry_widget = ghid_coord_entry_new (low, high, value, Settings.grid_unit, step_size);
if (coord_entry)
*coord_entry = entry_widget;
if (width > 0)
gtk_widget_set_size_request (entry_widget, width, -1);
- entry = GTK_PCB_COORD_ENTRY (entry_widget);
+ entry = GHID_COORD_ENTRY (entry_widget);
if (data == NULL)
data = (gpointer) entry;
if (cb_func)
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index ad2a112..30ff593 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -36,7 +36,7 @@
#include <sys/stat.h>
#include <gtk/gtk.h>
-#include "gtk-pcb-coord-entry.h"
+#include "ghid-coord-entry.h"
#include "gui-pinout-preview.h"
@@ -371,7 +371,7 @@ void ghid_button_connected (GtkWidget * box, GtkWidget ** button,
gpointer data, gchar * string);
void ghid_coord_entry (GtkWidget * box, GtkWidget ** coord_entry, Coord value,
Coord low, Coord high, enum ce_step_size step_size,
- gint width, void (*cb_func) (GtkPcbCoordEntry *, gpointer),
+ gint width, void (*cb_func) (GHidCoordEntry *, gpointer),
gpointer data, gboolean right_align, gchar * string);
void ghid_spin_button (GtkWidget * box, GtkWidget ** spin_button,
gfloat value, gfloat low, gfloat high, gfloat step0,
@@ -381,7 +381,7 @@ void ghid_spin_button (GtkWidget * box, GtkWidget ** spin_button,
void ghid_table_coord_entry (GtkWidget * table, gint row, gint column,
GtkWidget ** coord_entry, Coord value,
Coord low, Coord high, enum ce_step_size, gint width,
- void (*cb_func) (GtkPcbCoordEntry *, gpointer), gpointer data,
+ void (*cb_func) (GHidCoordEntry *, gpointer), gpointer data,
gboolean right_align, gchar * string);
void ghid_table_spin_button (GtkWidget * box, gint row, gint column,
GtkWidget ** spin_button, gfloat value,
commit 73591e0e0e4c2abc764a2a8be503a44da1ca86f4
Author: Andrew Poelstra <as...@sf...>
Commit: Andrew Poelstra <as...@sf...>
Rename GtkPcbLayerSelector to GHidLayerSelector
diff --git a/src/Makefile.am b/src/Makefile.am
index f4bba29..00e7453 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -272,8 +272,8 @@ LIBGTK_SRCS = \
hid/hidint.h \
hid/gtk/gtk-pcb-coord-entry.c \
hid/gtk/gtk-pcb-coord-entry.h \
- hid/gtk/gtk-pcb-layer-selector.c \
- hid/gtk/gtk-pcb-layer-selector.h \
+ hid/gtk/ghid-layer-selector.c \
+ hid/gtk/ghid-layer-selector.h \
hid/gtk/ghid-cell-renderer-visibility.c \
hid/gtk/ghid-cell-renderer-visibility.h \
hid/gtk/gtkhid-main.c \
diff --git a/src/hid/gtk/ghid-layer-selector.c b/src/hid/gtk/ghid-layer-selector.c
new file mode 100644
index 0000000..06dc8cd
--- /dev/null
+++ b/src/hid/gtk/ghid-layer-selector.c
@@ -0,0 +1,815 @@
+/*! \file <gtk-pcb-layer-selector.c>
+ * \brief Implementation of GHidLayerSelector widget
+ * \par Description
+ * This widget is the layer selector on the left side of the Gtk
+ * GUI. It also describes (in XML) the relevant sections of the
+ * menu for layer selection and visibility toggling, and makes
+ * sure these stay in sync.
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "gtkhid.h"
+#include "gui.h"
+#include "pcb-printf.h"
+
+#include "ghid-layer-selector.h"
+#include "ghid-cell-renderer-visibility.h"
+
+#define INITIAL_ACTION_MAX 40
+
+/* Forward dec'ls */
+static void ghid_layer_selector_finalize (GObject *object);
+
+/*! \brief Signals exposed by the widget */
+enum {
+ SELECT_LAYER_SIGNAL,
+ TOGGLE_LAYER_SIGNAL,
+ LAST_SIGNAL
+};
+
+/*! \brief Columns used for internal data store */
+enum {
+ INDEX_COL,
+ USER_ID_COL,
+ VISIBLE_COL,
+ COLOR_COL,
+ TEXT_COL,
+ FONT_COL,
+ ACTIVATABLE_COL,
+ SEPARATOR_COL,
+ N_COLS
+};
+
+static GtkTreeView *ghid_layer_selector_parent_class;
+static guint ghid_layer_selector_signals[LAST_SIGNAL] = { 0 };
+
+struct _GHidLayerSelector
+{
+ GtkTreeView parent;
+
+ GtkListStore *list_store;
+ GtkTreeSelection *selection;
+ GtkTreeViewColumn *visibility_column;
+
+ GtkActionGroup *action_group;
+
+ GtkToggleAction **view_actions;
+ GtkRadioAction **pick_actions;
+ GtkTreeRowReference **rows;
+ GSList *radio_group;
+ int max_actions;
+ int n_actions;
+
+ gboolean last_activatable;
+};
+
+struct _GHidLayerSelectorClass
+{
+ GtkTreeViewClass parent_class;
+
+ void (* select_layer) (GHidLayerSelector *, gint);
+ void (* toggle_layer) (GHidLayerSelector *, gint);
+};
+
+/*! \brief Flip the visibility state of a given layer
+ * \par Function Description
+ * Changes the internal toggle state and menu checkbox state
+ * of the layer pointed to by iter. Emits a toggle-layer signal.
+ * ALL internal visibility-flipping needs to go through this
+ * function. Otherwise a signal will not be emitted and it is
+ * likely that pcb will become inconsistent with the selector.
+ *
+ * \param [in] ls The selector to be acted on
+ * \param [in] iter A GtkTreeIter pointed at the relevant layer
+ */
+static void
+toggle_visibility (GHidLayerSelector *ls, GtkTreeIter *iter)
+{
+ gint idx;
+ gboolean toggle;
+ gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), iter,
+ VISIBLE_COL, &toggle, INDEX_COL, &idx, -1);
+ gtk_list_store_set (ls->list_store, iter, VISIBLE_COL, !toggle, -1);
+ gtk_toggle_action_set_active (ls->view_actions[idx], !toggle);
+}
+
+/*! \brief Decide if a GtkListStore entry is a layer or separator */
+static gboolean
+tree_view_separator_func (GtkTreeModel *model, GtkTreeIter *iter,
+ gpointer data)
+{
+ gboolean ret_val;
+ gtk_tree_model_get (model, iter, SEPARATOR_COL, &ret_val, -1);
+ return ret_val;
+}
+
+/*! \brief Decide if a GtkListStore entry may be selected */
+static gboolean
+tree_selection_func (GtkTreeSelection *selection, GtkTreeModel *model,
+ GtkTreePath *path, gboolean selected, gpointer data)
+{
+ GtkTreeIter iter;
+
+ if (gtk_tree_model_get_iter (model, &iter, path))
+ {
+ gboolean activatable;
+ gtk_tree_model_get (model, &iter, ACTIVATABLE_COL, &activatable, -1);
+ return activatable;
+ }
+
+ return FALSE;
+}
+
+/* SIGNAL HANDLERS */
+/*! \brief Callback for mouse-click: toggle visibility */
+static gboolean
+button_press_cb (GHidLayerSelector *ls, GdkEventButton *event)
+{
+ /* Handle visibility independently to prevent changing the active
+ * layer, which will happen if we let this event propagate. */
+ GtkTreeViewColumn *column;
+ GtkTreePath *path;
+ if (gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (ls),
+ event->x, event->y,
+ &path, &column, NULL, NULL))
+ {
+ GtkTreeIter iter;
+ gtk_tree_model_get_iter (GTK_TREE_MODEL (ls->list_store), &iter, path);
+ if (column == ls->visibility_column)
+ {
+ toggle_visibility (ls, &iter);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/*! \brief Callback for layer selection change: sync menu */
+static void
+selection_changed_cb (GtkTreeSelection *selection, GHidLayerSelector *ls)
+{
+ GtkTreeIter iter;
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+ {
+ gint idx;
+ gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store), &iter,
+ INDEX_COL, &idx, -1);
+ if (ls->pick_actions[0])
+ gtk_radio_action_set_current_value (ls->pick_actions[0], idx);
+ }
+}
+
+/*! \brief Callback for menu actions: sync layer selection list, emit signal */
+static void
+menu_view_cb (GtkToggleAction *action, GtkTreeRowReference *rref)
+{
+ GHidLayerSelector *ls;
+ GtkTreeModel *model = gtk_tree_row_reference_get_model (rref);
+ GtkTreePath *path = gtk_tree_row_reference_get_path (rref);
+ gboolean state = gtk_toggle_action_get_active (action);
+ GtkTreeIter iter;
+ gint user_id;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_list_store_set (GTK_LIST_STORE (model), &iter, VISIBLE_COL, state, -1);
+ gtk_tree_model_get (model, &iter, USER_ID_COL, &user_id, -1);
+
+ ls = g_object_get_data (G_OBJECT (model), "layer-selector");
+ g_signal_emit (ls, ghid_layer_selector_signals[TOGGLE_LAYER_SIGNAL],
+ 0, user_id);
+}
+
+/*! \brief Callback for menu actions: sync layer selection list, emit signal */
+static void
+menu_pick_cb (GtkRadioAction *action, GtkTreeRowReference *rref)
+{
+ GHidLayerSelector *ls;
+ GtkTreeModel *model = gtk_tree_row_reference_get_model (rref);
+ GtkTreePath *path = gtk_tree_row_reference_get_path (rref);
+ GtkTreeIter iter;
+ gint user_id;
+
+ gtk_tree_model_get_iter (model, &iter, path);
+ gtk_tree_model_get (model, &iter, USER_ID_COL, &user_id, -1);
+
+ ls = g_object_get_data (G_OBJECT (model), "layer-selector");
+ gtk_tree_selection_select_path (ls->selection, path);
+ g_signal_emit (ls, ghid_layer_selector_signals[SELECT_LAYER_SIGNAL],
+ 0, user_id);
+}
+
+/* CONSTRUCTOR */
+static void
+ghid_layer_selector_init (GHidLayerSelector *ls)
+{
+ /* Hookup signal handlers */
+}
+
+static void
+ghid_layer_selector_class_init (GHidLayerSelectorClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+
+ ghid_layer_selector_signals[SELECT_LAYER_SIGNAL] =
+ g_signal_new ("select-layer",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GHidLayerSelectorClass, select_layer),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
+ 1, G_TYPE_INT);
+ ghid_layer_selector_signals[TOGGLE_LAYER_SIGNAL] =
+ g_signal_new ("toggle-layer",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GHidLayerSelectorClass, toggle_layer),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
+ 1, G_TYPE_INT);
+
+ object_class->finalize = ghid_layer_selector_finalize;
+}
+
+/*! \brief Clean up object before garbage collection
+ */
+static void
+ghid_layer_selector_finalize (GObject *object)
+{
+ int i;
+ GHidLayerSelector *ls = (GHidLayerSelector *) object;
+
+ g_object_unref (ls->action_group);
+ g_free (ls->view_actions);
+ g_free (ls->pick_actions);
+ for (i = 0; i < ls->n_actions; ++i)
+ if (ls->rows[i])
+ gtk_tree_row_reference_free (ls->rows[i]);
+ g_free (ls->rows);
+
+ G_OBJECT_CLASS (ghid_layer_selector_parent_class)->finalize (object);
+}
+
+/* PUBLIC FUNCTIONS */
+GType
+ghid_layer_selector_get_type (void)
+{
+ static GType ls_type = 0;
+
+ if (!ls_type)
+ {
+ const GTypeInfo ls_info =
+ {
+ sizeof (GHidLayerSelectorClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) ghid_layer_selector_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GHidLayerSelector),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) ghid_layer_selector_init,
+ };
+
+ ls_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
+ "GHidLayerSelector",
+ &ls_info,
+ 0);
+ }
+
+ return ls_type;
+}
+
+/*! \brief Create a new GHidLayerSelector
+ *
+ * \return a freshly-allocated GHidLayerSelector.
+ */
+GtkWidget *
+ghid_layer_selector_new (void)
+{
+ GtkCellRenderer *renderer1 = ghid_cell_renderer_visibility_new ();
+ GtkCellRenderer *renderer2 = gtk_cell_renderer_text_new ();
+ GtkTreeViewColumn *opacity_col =
+ gtk_tree_view_column_new_with_attributes ("", renderer1,
+ "active", VISIBLE_COL,
+ "color", COLOR_COL, NULL);
+ GtkTreeViewColumn *name_col =
+ gtk_tree_view_column_new_with_attributes ("", renderer2,
+ "text", TEXT_COL,
+ "font", FONT_COL,
+ "sensitive", VISIBLE_COL, NULL);
+
+ GHidLayerSelector *ls = g_object_new (GHID_LAYER_SELECTOR_TYPE, NULL);
+
+ /* action index, active, color, text, font, is_separator */
+ ls->list_store = gtk_list_store_new (N_COLS, G_TYPE_INT, G_TYPE_INT,
+ G_TYPE_BOOLEAN, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_STRING,
+ G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
+ gtk_tree_view_insert_column (GTK_TREE_VIEW (ls), opacity_col, -1);
+ gtk_tree_view_insert_column (GTK_TREE_VIEW (ls), name_col, -1);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (ls), GTK_TREE_MODEL (ls->list_store));
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (ls), FALSE);
+
+ ls->last_activatable = TRUE;
+ ls->visibility_column = opacity_col;
+ ls->selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (ls));
+ ls->action_group = gtk_action_group_new ("LayerSelector");
+ ls->n_actions = 0;
+ ls->max_actions = INITIAL_ACTION_MAX;
+ ls->view_actions = g_malloc0 (ls->max_actions * sizeof (*ls->view_actions));
+ ls->pick_actions = g_malloc0 (ls->max_actions * sizeof (*ls->pick_actions));
+ ls->rows = g_malloc0 (ls->max_actions * sizeof (*ls->rows));
+
+ gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (ls),
+ tree_view_separator_func,
+ NULL, NULL);
+ gtk_tree_selection_set_select_function (ls->selection, tree_selection_func,
+ NULL, NULL);
+ gtk_tree_selection_set_mode (ls->selection, GTK_SELECTION_BROWSE);
+
+ g_object_set_data (G_OBJECT (ls->list_store), "layer-selector", ls);
+ g_signal_connect (ls, "button_press_event",
+ G_CALLBACK (button_press_cb), NULL);
+ g_signal_connect (ls->selection, "changed",
+ G_CALLBACK (selection_changed_cb), ls);
+
+ g_object_ref (ls->action_group);
+
+ return GTK_WIDGET (ls);
+}
+
+/*! \brief Add a layer to a GHidLayerSelector.
+ * \par Function Description
+ * This function adds an entry to a GHidLayerSelector, which will
+ * appear in the layer-selection list as well as visibility and selection
+ * menus (assuming this is a selectable layer). For the first 20 layers,
+ * keyboard accelerators will be added for selection/visibility toggling.
+ *
+ * If the user_id passed already exists in the layer selector, that layer
+ * will have its data overwritten with the new stuff.
+ *
+ * \param [in] ls The selector to be acted on
+ * \param [in] user_id An ID used to identify the layer; will be passed to selection/visibility callbacks
+ * \param [in] name The name of the layer; will be used on selector and menus
+ * \param [in] color_string The color of the layer on selector
+ * \param [in] visibile Whether the layer is visible
+ * \param [in] activatable Whether the layer appears in menus and can be selected
+ */
+void
+ghid_layer_selector_add_layer (GHidLayerSelector *ls,
+ gint user_id,
+ const gchar *name,
+ const gchar *color_string,
+ gboolean visible,
+ gboolean activatable)
+{
+ gchar *pname, *vname, *paccel, *vaccel;
+ gboolean new_iter = TRUE;
+ gboolean last_activatable = TRUE;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+
+ /* Look for existing layer with this ID */
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls->list_store), &iter))
+ do
+ {
+ gboolean is_sep, active;
+ gint read_id;
+ gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store),
+ &iter, USER_ID_COL, &read_id,
+ SEPARATOR_COL, &is_sep,
+ ACTIVATABLE_COL, &active, -1);
+ if (!is_sep)
+ {
+ last_activatable = active;
+ if(read_id == user_id)
+ {
+ new_iter = FALSE;
+ break;
+ }
+ }
+ }
+ while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter));
+
+ /* Handle separator addition */
+ if (new_iter)
+ {
+ if (activatable != last_activatable)
+ {
+ /* Add separator between activatable/non-activatable boundaries */
+ gtk_list_store_append (ls->list_store, &iter);
+ gtk_list_store_set (ls->list_store, &iter,
+ SEPARATOR_COL, TRUE, -1);
+ }
+ /* Create new layer */
+ gtk_list_store_append (ls->list_store, &iter);
+ gtk_list_store_set (ls->list_store, &iter,
+ INDEX_COL, ls->n_actions,
+ USER_ID_COL, user_id,
+ VISIBLE_COL, visible,
+ COLOR_COL, color_string,
+ TEXT_COL, name,
+ FONT_COL, activatable ? NULL : "Italic",
+ ACTIVATABLE_COL, activatable,
+ SEPARATOR_COL, FALSE,
+ -1);
+ }
+ else
+ gtk_list_store_set (ls->list_store, &iter,
+ VISIBLE_COL, visible,
+ COLOR_COL, color_string,
+ TEXT_COL, name,
+ FONT_COL, activatable ? NULL : "Italic",
+ ACTIVATABLE_COL, activatable,
+ -1);
+
+ /* Unless we're adding new actions, we're done now */
+ if (!new_iter)
+ return;
+
+ if (activatable && ls->n_actions == 0)
+ gtk_tree_selection_select_iter (ls->selection, &iter);
+
+ /* Allocate new actions if necessary */
+ if (ls->n_actions == ls->max_actions)
+ {
+ void *tmp[2];
+ ls->max_actions *= 2;
+ tmp[0] = g_realloc (ls->view_actions,
+ ls->max_actions * sizeof (*ls->view_actions));
+ tmp[1] = g_realloc (ls->pick_actions,
+ ls->max_actions * sizeof (*ls->pick_actions));
+ tmp[2] = g_realloc (ls->rows,
+ ls->max_actions * sizeof (*ls->rows));
+ if (tmp[0] == NULL || tmp[1] == NULL || tmp[2] == NULL)
+ g_critical ("realloc failed allocating new actions");
+ else
+ {
+ ls->view_actions = tmp[0];
+ ls->pick_actions = tmp[1];
+ ls->rows = tmp[2];
+ }
+ }
+
+ /* -- Setup new actions -- */
+ vname = g_strdup_printf ("LayerView%d", ls->n_actions);
+ pname = g_strdup_printf ("LayerPick%d", ls->n_actions);
+ vaccel = NULL;
+ paccel = NULL;
+
+ /* Determine keyboard accelerators */
+ if (ls->n_actions < 10)
+ {
+ /* Map 1-0 to actions 1-10 (with '0' meaning 10) */
+ int i = (ls->n_actions + 1) % 10;
+ vaccel = g_strdup_printf ("<Ctrl>%d", i);
+ paccel = g_strdup_printf ("%d", i);
+ }
+ else
+ {
+ /* Map 1-0 to actions 11-20 (with '0' meaning 10) */
+ int i = (ls->n_actions + 1) % 10;
+ vaccel = g_strdup_printf ("<Alt><Ctrl>%d", i);
+ paccel = g_strdup_printf ("<Alt>%d", i);
+ }
+
+ /* Create row reference for actions */
+ path = gtk_tree_model_get_path (GTK_TREE_MODEL (ls->list_store), &iter);
+ ls->rows[ls->n_actions] = gtk_tree_row_reference_new
+ (GTK_TREE_MODEL (ls->list_store), path);
+ gtk_tree_path_free (path);
+
+ /* Create selection action */
+ if (activatable)
+ {
+ ls->pick_actions[ls->n_actions]
+ = gtk_radio_action_new (pname, name, NULL, NULL, ls->n_actions);
+ gtk_radio_action_set_group (ls->pick_actions[ls->n_actions],
+ ls->radio_group);
+ ls->radio_group
+ = gtk_radio_action_get_group (ls->pick_actions[ls->n_actions]);
+ gtk_action_group_add_action_with_accel
+ (ls->action_group,
+ GTK_ACTION (ls->pick_actions[ls->n_actions]),
+ paccel);
+ g_signal_connect (ls->pick_actions[ls->n_actions], "toggled",
+ G_CALLBACK (menu_pick_cb), ls->rows[ls->n_actions]);
+ }
+ else
+ ls->pick_actions[ls->n_actions] = NULL;
+
+ /* Create visibility action */
+ ls->view_actions[ls->n_actions] = gtk_toggle_action_new (vname, name,
+ NULL, NULL);
+ gtk_toggle_action_set_active (ls->view_actions[ls->n_actions], visible);
+
+ gtk_action_group_add_action_with_accel
+ (ls->action_group,
+ GTK_ACTION (ls->view_actions[ls->n_actions]),
+ vaccel);
+ g_signal_connect (ls->view_actions[ls->n_actions], "toggled",
+ G_CALLBACK (menu_view_cb), ls->rows[ls->n_actions]);
+
+ /* cleanup */
+ if (vaccel)
+ {
+ g_free (vaccel);
+ g_free (paccel);
+ }
+ g_free (vname);
+ g_free (pname);
+
+ ls->n_actions++;
+}
+
+/*! \brief Get the "Current Layer" menu description of a layer selector
+ * \par Function Description
+ * Returns the XML content used by Gtk in building the layer-selection
+ * part of the menu. This is a radio-button list describing which layer
+ * is active.
+ *
+ * \param [in] ls The selector to be acted on
+ *
+ * \return the requested XML
+ */
+gchar *
+ghid_layer_selector_get_pick_xml (GHidLayerSelector *ls)
+{
+ int i;
+ GString *str = g_string_new ("");
+
+ for (i = 0; i < ls->n_actions; ++i)
+ if (ls->pick_actions[i])
+ g_string_append_printf (str, "<menuitem action=\"LayerPick%d\" />\n", i);
+
+ return g_string_free (str, FALSE);
+}
+
+/*! \brief Get the "Shown Layers" menu description of a layer selector
+ * \par Function Description
+ * Returns the XML content used by Gtk in building the layer-selection
+ * part of the menu. This is a toggle-button list describing which layer(s)
+ * are visible.
+ *
+ * \param [in] ls The selector to be acted on
+ *
+ * \return the requested XML
+ */
+gchar *
+ghid_layer_selector_get_view_xml (GHidLayerSelector *ls)
+{
+ int i;
+ GString *str = g_string_new ("");
+
+ for (i = 0; i < ls->n_actions; ++i)
+ if (ls->view_actions[i])
+ g_string_append_printf (str, "<menuitem action=\"LayerView%d\" />\n", i);
+
+ return g_string_free (str, FALSE);
+}
+
+/*! \brief Get the GtkActionGroup containing accelerators, etc, of a layer selector
+ * \par Function Description
+ * Returns the GtkActionGroup containing the toggle and radio buttons used
+ * in the menu. Also contains the accelerators. This action group should be
+ * added to the main UI. See Gtk docs for details.
+ *
+ * \param [in] ls The selector to be acted on
+ *
+ * \return the action group of the selector
+ */
+GtkActionGroup *
+ghid_layer_selector_get_action_group (GHidLayerSelector *ls)
+{
+ return ls->action_group;
+}
+
+/*! \brief used internally */
+static gboolean
+toggle_foreach_func (GtkTreeModel *model, GtkTreePath *path,
+ GtkTreeIter *iter, gpointer data)
+{
+ gint id;
+ GHidLayerSelector *ls = g_object_get_data (G_OBJECT (model),
+ "layer-selector");
+
+ gtk_tree_model_get (model, iter, USER_ID_COL, &id, -1);
+ if (id == *(gint *) data)
+ {
+ toggle_visibility (ls, iter);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*! \brief Toggle a layer's visibility
+ * \par Function Description
+ * Toggle the layer indicated by user_id, emitting a layer-toggle signal.
+ *
+ * \param [in] ls The selector to be acted on
+ * \param [in] user_id The ID of the layer to be affected
+ */
+void
+ghid_layer_selector_toggle_layer (GHidLayerSelector *ls, gint user_id)
+{
+ gtk_tree_model_foreach (GTK_TREE_MODEL (ls->list_store),
+ toggle_foreach_func, &user_id);
+}
+
+/*! \brief used internally */
+static gboolean
+select_foreach_func (GtkTreeModel *model, GtkTreePath *path,
+ GtkTreeIter *iter, gpointer data)
+{
+ gint id;
+ GHidLayerSelector *ls = g_object_get_data (G_OBJECT (model),
+ "layer-selector");
+
+ gtk_tree_model_get (model, iter, USER_ID_COL, &id, -1);
+ if (id == *(gint *) data)
+ {
+ gtk_tree_selection_select_path (ls->selection, path);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*! \brief Select a layer
+ * \par Function Description
+ * Select the layer indicated by user_id, emitting a layer-select signal.
+ *
+ * \param [in] ls The selector to be acted on
+ * \param [in] user_id The ID of the layer to be affected
+ */
+void
+ghid_layer_selector_select_layer (GHidLayerSelector *ls, gint user_id)
+{
+ gtk_tree_model_foreach (GTK_TREE_MODEL (ls->list_store),
+ select_foreach_func, &user_id);
+}
+
+/*! \brief Selects the next visible layer
+ * \par Function Description
+ * Used to ensure hidden layers are not active; if the active layer is
+ * visible, this function is a noop. Otherwise, it will look for the
+ * next layer that IS visible, and select that. Failing that, it will
+ * return FALSE.
+ *
+ * \param [in] ls The selector to be acted on
+ *
+ * \return TRUE on success, FALSE if all selectable layers are hidden
+ */
+gboolean
+ghid_layer_selector_select_next_visible (GHidLayerSelector *ls)
+{
+ GtkTreeIter iter;
+ if (gtk_tree_selection_get_selected (ls->selection, NULL, &iter))
+ {
+ /* Scan forward, looking for selectable iter */
+ do
+ {
+ gboolean visible, activatable;
+ gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store),
+ &iter, VISIBLE_COL, &visible,
+ ACTIVATABLE_COL, &activatable, -1);
+ if (visible && activatable)
+ {
+ gtk_tree_...
[truncated message content] |