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

gEDA-cvs: pcb.git: branch: master updated (2948179e8c693f2ca8666e0ca212198254e76285)



The branch, master has been updated
       via  2948179e8c693f2ca8666e0ca212198254e76285 (commit)
       via  6d50fc7871acdddd8f319d1fd21a08d0784c9af8 (commit)
       via  12771c69eee43cd5f275a64a031f3947ab172d77 (commit)
      from  c4df558415e977e406522bfce59c63e5518f4cfa (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                                |    4 +
 src/hid/gtk/gtk-pcb-cell-renderer-visibility.c |  296 +++++++++
 src/hid/gtk/gtk-pcb-cell-renderer-visibility.h |   24 +
 src/hid/gtk/gtk-pcb-layer-selector.c           |  708 ++++++++++++++++++++++
 src/hid/gtk/gtk-pcb-layer-selector.h           |   43 ++
 src/hid/gtk/gui-top-window.c                   |  769 +++++-------------------
 src/hid/gtk/gui.h                              |    3 +-
 7 files changed, 1242 insertions(+), 605 deletions(-)
 create mode 100644 src/hid/gtk/gtk-pcb-cell-renderer-visibility.c
 create mode 100644 src/hid/gtk/gtk-pcb-cell-renderer-visibility.h
 create mode 100644 src/hid/gtk/gtk-pcb-layer-selector.c
 create mode 100644 src/hid/gtk/gtk-pcb-layer-selector.h


=================
 Commit Messages
=================

commit 2948179e8c693f2ca8666e0ca212198254e76285
Author: Andrew Poelstra <asp11@xxxxxx>
Commit: Andrew Poelstra <asp11@xxxxxx>

    Use GtkPcbLayerSelector in gtk GUI
    
    Closes-bug: lp-699482

:100644 100644 4e9ae27... 001d2ca... M	src/hid/gtk/gui-top-window.c
:100644 100644 9bed4d9... 134d2fb... M	src/hid/gtk/gui.h

commit 6d50fc7871acdddd8f319d1fd21a08d0784c9af8
Author: Andrew Poelstra <asp11@xxxxxx>
Commit: Andrew Poelstra <asp11@xxxxxx>

    Introduce GtkPcbLayerSelector widget -- not used yet
    
    This widget will replace the layer-selection buttons in the
    Gtk GUI, as well as the layer selection and visibility-toggling
    parts of the menu.
    
    This is to make layer manipulation more consistent and
    more keyboard-accessible.
    
    In future, it would be good to update this widget with context
    menus with things like "hide all but this layer".

:100644 100644 9df4a50... d4c37e0... M	src/Makefile.am
:000000 100644 0000000... 8f6d669... A	src/hid/gtk/gtk-pcb-cell-renderer-visibility.c
:000000 100644 0000000... 212c4a4... A	src/hid/gtk/gtk-pcb-cell-renderer-visibility.h
:000000 100644 0000000... 519ec50... A	src/hid/gtk/gtk-pcb-layer-selector.c
:000000 100644 0000000... 0773497... A	src/hid/gtk/gtk-pcb-layer-selector.h

commit 12771c69eee43cd5f275a64a031f3947ab172d77
Author: Andrew Poelstra <asp11@xxxxxx>
Commit: Andrew Poelstra <asp11@xxxxxx>

    Change Gtk layer_process() to use colors from Settings, not PCB
    
    Now the only code that uses the colors in the PCB struct is
    draw.c. Hopefully in a future commit we can remove this too
    and remove the duplication of color data in the Settings and
    PCB structs.

:100644 100644 aaab38e... 4e9ae27... M	src/hid/gtk/gui-top-window.c

=========
 Changes
=========

commit 2948179e8c693f2ca8666e0ca212198254e76285
Author: Andrew Poelstra <asp11@xxxxxx>
Commit: Andrew Poelstra <asp11@xxxxxx>

    Use GtkPcbLayerSelector in gtk GUI
    
    Closes-bug: lp-699482

diff --git a/src/hid/gtk/gui-top-window.c b/src/hid/gtk/gui-top-window.c
index 4e9ae27..001d2ca 100644
--- a/src/hid/gtk/gui-top-window.c
+++ b/src/hid/gtk/gui-top-window.c
@@ -82,6 +82,7 @@ a zoom in/out.
 #include <locale.h>
 #endif
 
+#include "gtk-pcb-layer-selector.h"
 #include "gtkhid.h"
 #include "gui.h"
 #include "hid.h"
@@ -157,17 +158,6 @@ typedef struct
 }
 RouteStyleButton;
 
-/* Used by the layer buttons */
-typedef struct
-{
-  GtkWidget *radio_select_button,
-    *layer_enable_button, *layer_enable_ebox, *label;
-  gchar *text;
-  gint index;
-}
-LayerButtonSet;
-
-
 /* ---------------------------------------------------------------------------
  * local macros
  */
@@ -197,22 +187,12 @@ static gint tmenuitem_cnt = 0;
 static Resource **action_resources = NULL;
 static Resource **toggle_action_resources = NULL;
 
-/* actions for the @layerview menuitems */
-static GtkToggleActionEntry layerview_toggle_entries[N_LAYER_BUTTONS];
-static Resource *layerview_resources[N_LAYER_BUTTONS];
-
-/* actions for the @layerpick menuitems */
-static GtkToggleActionEntry layerpick_toggle_entries[N_LAYER_BUTTONS];
-static Resource *layerpick_resources[N_LAYER_BUTTONS];
-
 /* actions for the @routestyles menuitems */
 static GtkToggleActionEntry routestyle_toggle_entries[N_ROUTE_STYLES];
 static Resource *routestyle_resources[N_ROUTE_STYLES];
 
 #define MENUITEM "MenuItem"
 #define TMENUITEM "TMenuItem"
-#define LAYERPICK "LayerPick"
-#define LAYERVIEW "LayerView"
 #define ROUTESTYLE "RouteStyle"
 
 
@@ -367,21 +347,6 @@ ghid_update_toggle_flags ()
 	}
     }
 
-
-  /* FIXME -- this probably needs to go somewhere else */
-#ifdef notdef
-  for (i = 0; i < N_LAYER_BUTTONS; i++)
-    {
-      sprintf (tmpnm, "%s%d", LAYERVIEW, i);
-      a = gtk_action_group_get_action (ghidgui->main_actions, tmpnm);
-      if (a != NULL)
-	{
-	  g_object_set_property (G_OBJECT (a), "visible", (i >= max_copper_layer && i < MAX_LAYER) ? &setfalse : &settrue);
-	}
-
-    }
-#endif
-
   for (i = 0; i < N_ROUTE_STYLES; i++)
     {
       sprintf (tmpnm, "%s%d", ROUTESTYLE, i);
@@ -523,24 +488,6 @@ ghid_menu_cb (GtkAction * action, gpointer data)
       else
 	node = toggle_action_resources[id];
     }
-  else if ( strncmp (name, LAYERPICK, strlen (LAYERPICK)) == 0)
-    {
-      id = atoi (name + strlen (LAYERPICK));
-
-      if (ghidgui->toggle_holdoff == TRUE) 
-	node = NULL;
-      else
-	node = layerpick_resources[id];
-    }
-  else if ( strncmp (name, LAYERVIEW, strlen (LAYERVIEW)) == 0)
-    {
-      id = atoi (name + strlen (LAYERVIEW));
-
-      if (ghidgui->toggle_holdoff == TRUE) 
-	node = NULL;
-      else
-	node = layerview_resources[id];
-    }
   else if ( strncmp (name, ROUTESTYLE, strlen (ROUTESTYLE)) == 0)
     {
       id = atoi (name + strlen (ROUTESTYLE));
@@ -730,6 +677,84 @@ layer_process (gchar **color_string, char **text, int *set, int i)
     }
 }
 
+/*! \brief Callback for GtkPcbLayerSelector layer selection */
+static void
+layer_selector_select_callback (GtkPcbLayerSelector *ls, int layer, gpointer d)
+{
+  gboolean active;
+  layer_process (NULL, NULL, &active, layer);
+
+  /* Select Layer */
+  PCB->SilkActive = (layer == LAYER_BUTTON_SILK);
+  PCB->RatDraw  = (layer == LAYER_BUTTON_RATS);
+  if (layer < max_copper_layer)
+    ChangeGroupVisibility (layer, true, true);
+
+  /* Ensure layer is turned on */
+  gtk_pcb_layer_selector_make_selected_visible (ls);
+
+  ghid_invalidate_all ();
+}
+
+/*! \brief Callback for GtkPcbLayerSelector layer toggling */
+static void
+layer_selector_toggle_callback (GtkPcbLayerSelector *ls, int layer, gpointer d)
+{
+  gboolean redraw = FALSE;
+  gboolean active;
+  layer_process (NULL, NULL, &active, layer);
+
+  active = !active;
+  switch (layer)
+    {
+    case LAYER_BUTTON_SILK:
+      PCB->ElementOn = active;
+      PCB->Data->SILKLAYER.On = PCB->ElementOn;
+      PCB->Data->BACKSILKLAYER.On = PCB->ElementOn;
+      redraw = 1;
+      break;
+    case LAYER_BUTTON_RATS:
+      PCB->RatOn = active;
+      redraw = 1;
+      break;
+    case LAYER_BUTTON_PINS:
+      PCB->PinOn = active;
+      redraw |= (PCB->Data->ElementN != 0);
+      break;
+    case LAYER_BUTTON_VIAS:
+      PCB->ViaOn = active;
+      redraw |= (PCB->Data->ViaN != 0);
+      break;
+    case LAYER_BUTTON_FARSIDE:
+      PCB->InvisibleObjectsOn = active;
+      PCB->Data->BACKSILKLAYER.On = (active && PCB->ElementOn);
+      redraw = TRUE;
+      break;
+    case LAYER_BUTTON_MASK:
+      if (active)
+        SET_FLAG (SHOWMASKFLAG, PCB);
+      else
+        CLEAR_FLAG (SHOWMASKFLAG, PCB);
+      redraw = TRUE;
+      break;
+    default:
+      /* Flip the visibility */
+      ChangeGroupVisibility (layer, active, false);
+      redraw = TRUE;
+      break;
+    }
+
+  /* Jump through hoops in case we just disabled the active layer
+   *  (or its group). In this case, select a different one if we
+   *  can. If we can't, turn the original layer back on.
+   */
+  if (!gtk_pcb_layer_selector_select_next_visible (ls))
+    gtk_pcb_layer_selector_toggle_layer (ls, layer);
+
+  if (redraw)
+    ghid_invalidate_all();
+}
+
 /*
  * The intial loading of all actions at startup.
  */
@@ -737,69 +762,10 @@ static void
 ghid_make_programmed_menu_actions ()
 {
   int i;
-  gchar * text;
-  
   Resource *ar;
   char av[64];
 
-  for (i = 0; i < N_LAYER_BUTTONS; i++)
-    {
-      layer_process (NULL, &text, NULL, i);
-#ifdef DEBUG_MENUS
-      printf ("ghid_make_programmed_menu_actions():  Added #%2d \"%s\".  max_copper_layer = %d, MAX_LAYER = %d\n", i, text, max_copper_layer, MAX_LAYER);
-#endif
-      /* name, stock_id, label, accelerator, tooltip, callback */
-      layerview_toggle_entries[i].name = g_strdup_printf ("%s%d", LAYERVIEW, i);
-      layerview_toggle_entries[i].stock_id = NULL;
-      layerview_toggle_entries[i].label = g_strdup (text);
-      layerview_toggle_entries[i].accelerator = NULL;
-      layerview_toggle_entries[i].tooltip = NULL;
-      layerview_toggle_entries[i].callback = G_CALLBACK (ghid_menu_cb);
-      layerview_toggle_entries[i].is_active = FALSE;
-      
-      ar = resource_create (0);
-      sprintf (av, "ToggleView(%d)", i + 1);
-      resource_add_val (ar, 0, strdup (av), 0);
-      resource_add_val (ar, 0, strdup (av), 0);
-      ar->flags |= FLAG_V;
-      layerview_resources[i] = ar;
-
-      /* name, stock_id, label, accelerator, tooltip, callback */
-      layerpick_toggle_entries[i].name = g_strdup_printf ("%s%d", LAYERPICK, i);
-      layerpick_toggle_entries[i].stock_id = NULL;
-      layerpick_toggle_entries[i].label = g_strdup (text);
-      layerpick_toggle_entries[i].accelerator = NULL;
-      layerpick_toggle_entries[i].tooltip = NULL;
-      layerpick_toggle_entries[i].callback = G_CALLBACK (ghid_menu_cb);
-      layerpick_toggle_entries[i].is_active = FALSE;
-
-      ar = resource_create (0);
-
-      switch (i)
-	{
-	case LAYER_BUTTON_SILK:
-	  sprintf (av, "SelectLayer(Silk) LayersChanged()");
-          if (max_copper_layer < 9)
-            layerpick_toggle_entries[i].accelerator = g_strdup_printf ("<Key>%d", max_copper_layer + 1);
-	  break; 
-	case LAYER_BUTTON_RATS:
-          if (max_copper_layer < 8)
-            layerpick_toggle_entries[i].accelerator = g_strdup_printf ("<Key>%d", max_copper_layer + 2);
-	  sprintf (av, "SelectLayer(Rats) LayersChanged()");
-	  break;
-	default:
-	  sprintf (av, "SelectLayer(%d) LayersChanged()", i + 1);
-          if (i < 9 && i < max_copper_layer)
-            layerpick_toggle_entries[i].accelerator = g_strdup_printf ("<Key>%d", i + 1);
-	  break;
-	}
-      resource_add_val (ar, 0, strdup (av), 0);
-      resource_add_val (ar, 0, strdup (av), 0);
-      ar->flags |= FLAG_V;
-      layerpick_resources[i] = ar;
-    }
-
-    for (i = 0; i < N_ROUTE_STYLES; i++)
+  for (i = 0; i < N_ROUTE_STYLES; i++)
     {
       routestyle_toggle_entries[i].name = g_strdup_printf ("%s%d", ROUTESTYLE, i);
       routestyle_toggle_entries[i].stock_id = NULL;
@@ -840,14 +806,6 @@ make_menu_actions (GtkActionGroup * actions, GHidPort * port)
 
   ghid_make_programmed_menu_actions ();
 
-  gtk_action_group_add_toggle_actions (actions, 
-				       layerpick_toggle_entries, 
-				       N_LAYER_BUTTONS, port);
-
-  gtk_action_group_add_toggle_actions (actions,
-				       layerview_toggle_entries,
-				       N_LAYER_BUTTONS, port);
-
   gtk_action_group_add_toggle_actions (actions,
 				       routestyle_toggle_entries,
 				       N_ROUTE_STYLES, port);
@@ -865,6 +823,7 @@ make_top_menubar (GtkWidget * hbox, GHidPort * port)
   GtkUIManager *ui;
   GtkWidget *frame;
   GtkActionGroup *actions;
+  GtkActionGroup *layer_actions;
   GError *error = NULL;
 
   frame = gtk_frame_new (NULL);
@@ -879,8 +838,11 @@ make_top_menubar (GtkWidget * hbox, GHidPort * port)
   ghidgui->main_actions = actions;
 
   make_menu_actions (actions, port);
-
+  layer_actions = gtk_pcb_layer_selector_get_action_group
+          (GTK_PCB_LAYER_SELECTOR (ghidgui->layer_selector));
+ 
   gtk_ui_manager_insert_action_group (ui, actions, 0);
+  gtk_ui_manager_insert_action_group (ui, layer_actions, 0);
 
   gtk_window_add_accel_group (GTK_WINDOW (gport->top_window),
 			      gtk_ui_manager_get_accel_group (ui));
@@ -1030,474 +992,80 @@ make_cursor_position_labels (GtkWidget * hbox, GHidPort * port)
 
 }
 
-
-  /* ------------------------------------------------------------------
-     |  Handle the layer buttons.
-   */
-static LayerButtonSet layer_buttons[N_LAYER_BUTTONS];
-
-static gint layer_select_button_index;
-
-static gboolean layer_enable_button_cb_hold_off,
-  layer_select_button_cb_hold_off;
-
-static void
-layer_select_button_cb (GtkWidget * widget, LayerButtonSet * lb)
-{
-  gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
-  static gboolean in_cb = FALSE;
-
-  if (!active || layer_select_button_cb_hold_off || in_cb)
-    return;
-
-  in_cb = TRUE;
-
-  PCB->SilkActive = (lb->index == LAYER_BUTTON_SILK);
-  PCB->RatDraw = (lb->index == LAYER_BUTTON_RATS);
-
-  if (lb->index < max_copper_layer)
-    ChangeGroupVisibility (lb->index, true, true);
-
-  layer_select_button_index = lb->index;
-
-  layer_select_button_cb_hold_off = TRUE;
-  layer_enable_button_cb_hold_off = TRUE;
-  ghid_layer_buttons_update ();
-  layer_select_button_cb_hold_off = FALSE;
-  layer_enable_button_cb_hold_off = FALSE;
-
-  ghid_invalidate_all ();
-  in_cb = FALSE;
-}
-
+/* \brief Add "virtual layers" to a layer selector */
 static void
-layer_enable_button_cb (GtkWidget * widget, gpointer data)
+make_virtual_layer_buttons (GtkPcbLayerSelector *layersel)
 {
-  gint i, group, layer = GPOINTER_TO_INT (data);
-  gboolean active, redraw = FALSE;
-
-  active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
-
-  if (layer_enable_button_cb_hold_off)
-    return;
-
-  switch (layer)
-    {
-    case LAYER_BUTTON_SILK:
-      PCB->ElementOn = active;
-      PCB->Data->SILKLAYER.On = PCB->ElementOn;
-      PCB->Data->BACKSILKLAYER.On = PCB->ElementOn;
-      redraw = 1;
-      break;
-
-    case LAYER_BUTTON_RATS:
-      PCB->RatOn = active;
-      redraw = 1;
-      break;
-
-    case LAYER_BUTTON_PINS:
-      PCB->PinOn = active;
-      redraw |= (PCB->Data->ElementN != 0);
-      break;
-
-    case LAYER_BUTTON_VIAS:
-      PCB->ViaOn = active;
-      redraw |= (PCB->Data->ViaN != 0);
-      break;
-
-    case LAYER_BUTTON_FARSIDE:
-      PCB->InvisibleObjectsOn = active;
-      PCB->Data->BACKSILKLAYER.On = (active && PCB->ElementOn);
-      redraw = TRUE;
-      break;
-
-    case LAYER_BUTTON_MASK:
-      if (active)
-	SET_FLAG (SHOWMASKFLAG, PCB);
-      else
-	CLEAR_FLAG (SHOWMASKFLAG, PCB);
-      redraw = TRUE;
-      break;
-
-    default:
-      /* check if active layer is in the group;
-         |  if YES, make a different one active if possible.  Logic from
-         |  Xt PCB code.
-       */
-      if ((group = GetGroupOfLayer (layer)) ==
-	  GetGroupOfLayer (MIN (max_copper_layer, INDEXOFCURRENT)))
-	{
-	  for (i = (layer + 1) % (max_copper_layer + 1); i != layer;
-	       i = (i + 1) % (max_copper_layer + 1))
-	    if (PCB->Data->Layer[i].On == true &&
-		GetGroupOfLayer (i) != group)
-	      break;
-	  if (i != layer)
-	    {
-	      ChangeGroupVisibility ((int) i, true, true);
-	    }
-	  else
-	    {
-	      /* everything else off, we can't turn this off too */
-	      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), TRUE);
-	      return;
-	    }
-	}
-      /* switch layer group on/off */
-      ChangeGroupVisibility (layer, active, false);
-      redraw = TRUE;
-      break;
-    }
-
-  layer_select_button_cb_hold_off = TRUE;
-  layer_enable_button_cb_hold_off = TRUE;
-  ghid_layer_buttons_update ();
-  layer_select_button_cb_hold_off = FALSE;
-  layer_enable_button_cb_hold_off = FALSE;
-
-  if (redraw)
-    ghid_invalidate_all();
-}
-
-static void
-layer_button_set_color (LayerButtonSet * lb, gchar * color_string,
-                        bool set_prelight)
-{
-  GdkColor color;
-
-  if (!lb->layer_enable_ebox)
-    return;
-
-  color.red = color.green = color.blue = 0;
-  ghid_map_color_string (color_string, &color);
-  gtk_widget_modify_bg (lb->layer_enable_ebox, GTK_STATE_ACTIVE, &color);
-  gtk_widget_modify_bg (lb->layer_enable_ebox, GTK_STATE_PRELIGHT,
-                        set_prelight ? &color : NULL);
-
-  gtk_widget_modify_fg (lb->label, GTK_STATE_ACTIVE, &WhitePixel);
-}
-
-void
-layer_enable_button_set_label (GtkWidget * label, gchar * text)
-{
-  gchar *s;
-
-  if (ghidgui->small_label_markup)
-    s = g_strdup_printf ("<small>%s</small>", text);
-  else
-    s = g_strdup (text);
-  gtk_label_set_markup (GTK_LABEL (label), s);
-  g_free (s);
-}
-
-static void
-ghid_show_layer_buttons(void)
-{
-	LayerButtonSet *lb;
-	gint	i;
-
-	for (i = 0; i < MAX_LAYER; ++i)
-	{
-		lb = &layer_buttons[i];
-		if (i < max_copper_layer)
-		  {
-			gtk_widget_show(lb->layer_enable_button);
-			gtk_widget_show(lb->radio_select_button);
-		  }
-		else
-		  {
-			gtk_widget_hide(lb->layer_enable_button);
-			gtk_widget_hide(lb->radio_select_button);
-		  }
-	}
-}
-
-  /* After layers comes some special cases.  Since silk and netlist (rats)
-     |  are selectable as separate drawing areas, they are more consistently
-     |  placed after the layers in the gui so the select radio buttons will
-     |  be grouped.  This is different from Xt PCB which had a different looking
-     |  select interface.
-   */
-static void
-make_layer_buttons (GtkWidget * vbox, GHidPort * port)
-{
-  LayerButtonSet *lb;
-  GtkWidget *table, *ebox, *label, *button, *hbox;
-  GSList *group = NULL;
   gchar *text;
-  gint i;
   gchar *color_string;
-  gboolean active = TRUE;
-
-  hbox = gtk_hbox_new (FALSE, 0);
-  gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 4);
-  table = gtk_table_new (N_LAYER_BUTTONS, 2, FALSE);
-  gtk_box_pack_start(GTK_BOX(hbox), table, FALSE, FALSE, 3);
-
-  for (i = 0; i < N_LAYER_BUTTONS; ++i)
-    {
-      lb = &layer_buttons[i];
-      lb->index = i;
-
-      if (i < N_SELECTABLE_LAYER_BUTTONS)
-	{
-	  button = gtk_radio_button_new (group);
-	  group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
-	  gtk_table_attach_defaults (GTK_TABLE (table), button,
-				     0, 1, i, i + 1);
-
-	  lb->radio_select_button = button;
-	  g_signal_connect (G_OBJECT (button), "toggled",
-			    G_CALLBACK (layer_select_button_cb), lb);
-	}
-
-      layer_process (&color_string, &text, &active, i);
-      
-      button = gtk_check_button_new ();
-      label = gtk_label_new ("");
-      gtk_label_set_use_markup (GTK_LABEL (label), TRUE);
-      layer_enable_button_set_label (label, text);
-
-      ebox = gtk_event_box_new ();
-      gtk_container_add (GTK_CONTAINER (ebox), label);
-      gtk_container_add (GTK_CONTAINER (button), ebox);
-      gtk_table_attach_defaults (GTK_TABLE (table), button, 1, 2, i, i + 1);
-/*		gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0); */
-      gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
-
-      lb->layer_enable_button = button;
-      lb->layer_enable_ebox = ebox;
-      lb->text = g_strdup (text);
-      lb->label = label;
-
-      layer_button_set_color (lb, color_string, active);
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), active);
-
-      g_signal_connect (G_OBJECT (button), "toggled",
-			G_CALLBACK (layer_enable_button_cb),
-			GINT_TO_POINTER (i));
-
-
-    }
-}
-
-
-  /* If new color scheme is loaded from the config or user changes a color
-     |  in the preferences, make sure our layer button colors get updated.
-   */
+  gboolean active;
+ 
+  layer_process (&color_string, &text, &active, LAYER_BUTTON_SILK);
+  gtk_pcb_layer_selector_add_layer (layersel, LAYER_BUTTON_SILK,
+                                    text, color_string, active, TRUE);
+  layer_process (&color_string, &text, &active, LAYER_BUTTON_RATS);
+  gtk_pcb_layer_selector_add_layer (layersel, LAYER_BUTTON_RATS,
+                                    text, color_string, active, TRUE);
+  layer_process (&color_string, &text, &active, LAYER_BUTTON_PINS);
+  gtk_pcb_layer_selector_add_layer (layersel, LAYER_BUTTON_PINS,
+                                    text, color_string, active, FALSE);
+  layer_process (&color_string, &text, &active, LAYER_BUTTON_VIAS);
+  gtk_pcb_layer_selector_add_layer (layersel, LAYER_BUTTON_VIAS,
+                                    text, color_string, active, FALSE);
+  layer_process (&color_string, &text, &active, LAYER_BUTTON_FARSIDE);
+  gtk_pcb_layer_selector_add_layer (layersel, LAYER_BUTTON_FARSIDE,
+                                    text, color_string, active, FALSE);
+  layer_process (&color_string, &text, &active, LAYER_BUTTON_MASK);
+  gtk_pcb_layer_selector_add_layer (layersel, LAYER_BUTTON_MASK,
+                                    text, color_string, active, FALSE);
+}
+
+/*! \brief callback for gtk_pcb_layer_selector_update_colors */
+const gchar *
+get_layer_color (gint layer)
+{
+  gchar *rv;
+  layer_process (&rv, NULL, NULL, layer);
+  return rv;
+}
+
+/*! \brief Update a layer selector's color scheme */
 void
 ghid_layer_buttons_color_update (void)
 {
-  gchar *color_string;
-  LayerButtonSet *lb;
-  gint i;
-
-  if (!gport->drawing_area)
-    return;
-
-  /* Fixme: should the color set be maintained in both the PCB and the
-     |  Settings struct?
-   */
+  printf ("UPDATE COLORS\n");
+  gtk_pcb_layer_selector_update_colors
+    (GTK_PCB_LAYER_SELECTOR (ghidgui->layer_selector), get_layer_color);
   pcb_colors_from_settings (PCB);
-
-  for (i = 0; i < N_LAYER_BUTTONS; ++i)
-    {
-      bool active;
-
-      lb = &layer_buttons[i];
-
-      layer_process (&color_string, NULL, NULL, i);
-      active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (lb));
-      layer_button_set_color (lb, color_string, active);
-    }
 }
-
-
-  /* Update layer button labels and enabled state to match current PCB.
-   */
-void
-ghid_layer_enable_buttons_update (void)
+ 
+/*! \brief Populate a layer selector with all layers Gtk is aware of */
+static void
+make_layer_buttons (GtkWidget *layersel)
 {
-  LayerButtonSet *lb;
-  gchar *s;
-  gchar *color_string;
   gint i;
+  gchar *text;
+  gchar *color_string;
+  gboolean active = TRUE;
+  ghidgui->layer_selector = layersel;
 
-#ifdef DEBUG_MENUS
-  printf ("ghid_layer_enable_buttons_update()\n");
-#endif
-
-  /* Update layer button labels and active state to state inside of PCB
-   */
-  layer_enable_button_cb_hold_off = TRUE;
   for (i = 0; i < max_copper_layer; ++i)
     {
-      lb = &layer_buttons[i];
-      s = (gchar *)UNKNOWN (PCB->Data->Layer[i].Name);
-      if (dup_string (&lb->text, s))
-	{
-	  layer_enable_button_set_label (lb->label, _(s));
-	  ghid_config_layer_name_update (_(s), i);
-	}
-      if (Settings.verbose)
-	{
-	  gboolean active, newone;
-
-	  active =
-	    gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON
-					  (lb->layer_enable_button));
-	  newone = PCB->Data->Layer[i].On;
-	  if (active != newone)
-	    printf ("ghid_layer_enable_buttons_update: active=%d new=%d\n",
-		    active, newone);
-	}
-      layer_process (&color_string, NULL, NULL, i);
-      layer_button_set_color (lb, color_string, PCB->Data->Layer[i].On);
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
-				    (lb->layer_enable_button),
-				    PCB->Data->Layer[i].On);
-    }
-  /* Buttons for elements (silk), rats, pins, vias, and far side don't
-     |  change labels.
-   */
-  lb = &layer_buttons[LAYER_BUTTON_SILK];
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lb->layer_enable_button),
-				PCB->ElementOn);
-
-  lb = &layer_buttons[LAYER_BUTTON_RATS];
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lb->layer_enable_button),
-				PCB->RatOn);
-
-  lb = &layer_buttons[LAYER_BUTTON_PINS];
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lb->layer_enable_button),
-				PCB->PinOn);
-
-  lb = &layer_buttons[LAYER_BUTTON_VIAS];
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lb->layer_enable_button),
-				PCB->ViaOn);
-
-  lb = &layer_buttons[LAYER_BUTTON_FARSIDE];
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (lb->layer_enable_button),
-				PCB->InvisibleObjectsOn);
-  layer_enable_button_cb_hold_off = FALSE;
-}
-
-void
-ghid_layer_button_select (gint layer)
-{
-  if (layer != layer_select_button_index)
-    {
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
-				    (layer_buttons[layer].
-				     radio_select_button), TRUE);
-      layer_select_button_index = layer;
+      layer_process (&color_string, &text, &active, i);
+      gtk_pcb_layer_selector_add_layer (GTK_PCB_LAYER_SELECTOR (layersel), i,
+                                        text, color_string, active, TRUE);
     }
+  make_virtual_layer_buttons (GTK_PCB_LAYER_SELECTOR (layersel));
 }
 
-  /* Main layer button synchronization with current PCB state.  Called when
-     |  user toggles layer visibility or changes drawing layer or when internal
-     |  PCB code changes layer visibility.
-   */
-
+/*! \brief Synchronize layer selector widget with current PCB state
+ *  \par Function Description
+ *  Called when user toggles layer visibility or changes drawing layer,
+ *  or when layer visibility is changed programatically.
+ */
 void
 ghid_layer_buttons_update (void)
 {
-  gint layer;
-  gboolean active = FALSE;
-  gboolean old_holdoff;
-  char tmpnm[40];
-  int i;
-  int set;
-  gchar *text;
-  GtkAction *a;
-  GValue setfalse = { 0 };
-  GValue settrue = { 0 };
-  GValue setlabel = { 0 };
-
-  g_value_init (&setfalse, G_TYPE_BOOLEAN);
-  g_value_init (&settrue, G_TYPE_BOOLEAN);
-  g_value_set_boolean (&setfalse, FALSE);
-  g_value_set_boolean (&settrue, TRUE);
-  g_value_init (&setlabel, G_TYPE_STRING);
-
-#ifdef DEBUG_MENUS
-  printf ("ghid_layer_buttons_update()\n");
-#endif
-
-  if (!ghidgui || ghidgui->creating)
-    return;
-
-  ghid_layer_enable_buttons_update ();
-
-  /* Turning off a layer that was selected will cause PCB to switch to
-     |  another layer.
-   */
-  if (PCB->RatDraw)
-    layer = LAYER_BUTTON_RATS;
-  else
-    layer = PCB->SilkActive ? LAYER_BUTTON_SILK : LayerStack[0];
-
-  if (layer < max_copper_layer)
-    active = PCB->Data->Layer[layer].On;
-  else if (layer == LAYER_BUTTON_SILK)
-    active = PCB->ElementOn;
-  else if (layer == LAYER_BUTTON_RATS)
-    active = PCB->RatOn;
-
-  if (Settings.verbose)
-    {
-      printf ("ghid_layer_buttons_update cur_index=%d update_index=%d\n",
-	      layer_select_button_index, layer);
-      if (active && layer != layer_select_button_index)
-	printf ("\tActivating button %d\n", layer);
-    }
-
-  /* mask the callbacks */
-  old_holdoff = ghidgui->toggle_holdoff;
-  ghidgui->toggle_holdoff = TRUE;
-  
-  /* update the check marks in the layer pick menu */
-  for (i = 0; i < N_LAYER_BUTTONS ; i++)
-    {
-      sprintf (tmpnm, "%s%d", LAYERPICK, i);
-      a = gtk_action_group_get_action (ghidgui->main_actions, tmpnm);
-
-      layer_process (NULL, &text, &set, i);
-      g_value_set_string (&setlabel, text);
-
-      if (a != NULL)
-	{
-	  g_object_set_property (G_OBJECT (a), "visible", (i >= max_copper_layer && i < MAX_LAYER) ? &setfalse : &settrue);
-	  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (a), (set && (i == layer) ) ? TRUE : FALSE);
-	  g_object_set_property (G_OBJECT (a), "label", &setlabel);
-	}
-
-      sprintf (tmpnm, "%s%d", LAYERVIEW, i);
-      a = gtk_action_group_get_action (ghidgui->main_actions, tmpnm);
-      if (a != NULL)
-	{
-	  g_object_set_property (G_OBJECT (a), "visible", (i >= max_copper_layer && i < MAX_LAYER) ? &setfalse : &settrue);
-	  gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (a), set ? TRUE : FALSE);
-	  g_value_set_string (&setlabel, text);
-	  g_object_set_property (G_OBJECT (a), "label", &setlabel);
-	}
-
-
-    }
-  g_value_unset (&setfalse);
-  g_value_unset (&settrue);
-  g_value_unset (&setlabel);
-  ghidgui->toggle_holdoff = old_holdoff;
-
-  if (active && layer != layer_select_button_index)
-    {
-      layer_select_button_cb_hold_off = TRUE;
-      gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON
-				    (layer_buttons[layer].
-				     radio_select_button), TRUE);
-      layer_select_button_index = layer;
-      layer_select_button_cb_hold_off = FALSE;
-    }
 }
 
 
@@ -1892,6 +1460,16 @@ ghid_build_pcb_top_window (void)
   hbox = gtk_hbox_new(FALSE, 0);
   gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
 
+  /* Build layer menus */
+  ghidgui->layer_selector = gtk_pcb_layer_selector_new ();
+  make_layer_buttons (ghidgui->layer_selector);
+  g_signal_connect (G_OBJECT (ghidgui->layer_selector), "select_layer",
+                    G_CALLBACK (layer_selector_select_callback),
+                    NULL);
+  g_signal_connect (G_OBJECT (ghidgui->layer_selector), "toggle_layer",
+                    G_CALLBACK (layer_selector_toggle_callback),
+                    NULL);
+  /* Build main menu */
   ghid_load_menus ();
   make_top_menubar(hbox, port);
 
@@ -1972,7 +1550,8 @@ ghid_build_pcb_top_window (void)
 
   vbox = ghid_scrolled_vbox(vbox_left, &scrolled,
       GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
-  make_layer_buttons(vbox, port);
+  gtk_box_pack_start (GTK_BOX(vbox), ghidgui->layer_selector,
+                      FALSE, FALSE, 0);
 
   vbox = gtk_vbox_new(FALSE, 0);
   gtk_box_pack_start(GTK_BOX(vbox_left), vbox, FALSE, FALSE, 0);
@@ -2105,7 +1684,6 @@ ghid_build_pcb_top_window (void)
   gdk_window_set_back_pixmap (gport->drawing_area->window, NULL, FALSE);
 
   ghid_route_style_temp_buttons_hide ();
-  ghid_show_layer_buttons();
 }
 
 
@@ -2429,7 +2007,6 @@ ghid_do_export (HID_Attr_Val * options)
    * are properly initialized and synchronized with the current PCB.
    */
   ghid_layer_buttons_update ();
-  ghid_show_layer_buttons();
 
   if (stdin_listen)
     ghid_create_listener ();
@@ -2449,7 +2026,6 @@ LayersChanged (int argc, char **argv, Coord x, Coord y)
 
   ghid_config_groups_changed();
   ghid_layer_buttons_update ();
-  ghid_show_layer_buttons();
 
   /* FIXME - if a layer is moved it should retain its color.  But layers
   |  currently can't do that because color info is not saved in the
@@ -2486,7 +2062,6 @@ ToggleView (int argc, char **argv, Coord x, Coord y)
 {
   int i, l;
   static gboolean in_toggle_view = 0;
-  gboolean active;
 
 #ifdef DEBUG_MENUS
   printf ("Starting ToggleView().  in_toggle_view = %d\n", in_toggle_view);
@@ -2543,10 +2118,8 @@ ToggleView (int argc, char **argv, Coord x, Coord y)
   /* Now that we've figured out which toggle button ought to control
    * this layer, simply hit the button and let the pre-existing code deal
    */
-  active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (layer_buttons[l].layer_enable_button));
-  
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (layer_buttons[l].layer_enable_button),
-				active == TRUE ? FALSE : TRUE);
+  gtk_pcb_layer_selector_toggle_layer
+    (GTK_PCB_LAYER_SELECTOR (ghidgui->layer_selector), l);
   in_toggle_view = 0;
   return 0;
 }
@@ -2585,8 +2158,8 @@ SelectLayer (int argc, char **argv, Coord x, Coord y)
   /* Now that we've figured out which radio button ought to select
    * this layer, simply hit the button and let the pre-existing code deal
    */
-  gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (layer_buttons[newl].radio_select_button),
-				TRUE);
+  gtk_pcb_layer_selector_select_layer
+    (GTK_PCB_LAYER_SELECTOR (ghidgui->layer_selector), newl);
 
   return 0;
 }
@@ -3285,27 +2858,17 @@ add_resource_to_menu (char * menu, Resource * node, void * callback, int indent)
 	  {
 	    if (strcmp (node->v[i].value, "@layerview") == 0)
 	      {
-		int i;
-		char tmpid[40];
-		for (i = 0 ; i <  N_LAYER_BUTTONS; i++)
-		  {
-		    sprintf (tmpid, "<menuitem action='%s%d' />\n", 
-			     LAYERVIEW, i);
-		    ghid_ui_info_indent (indent);
-		    ghid_ui_info_append (tmpid);
-		  }
+                gchar *tmp = gtk_pcb_layer_selector_get_view_xml
+                  (GTK_PCB_LAYER_SELECTOR (ghidgui->layer_selector));
+                ghid_ui_info_append (tmp);
+                g_free (tmp);
 	      }
 	    else if (strcmp (node->v[i].value, "@layerpick") == 0)
 	      {
-		int i;
-		char tmpid[40];
-		for (i = 0 ; i <  N_SELECTABLE_LAYER_BUTTONS; i++)
-		  {
-		    sprintf (tmpid, "<menuitem action='%s%d' />\n", 
-			     LAYERPICK, i);
-		    ghid_ui_info_indent (indent);
-		    ghid_ui_info_append (tmpid);
-		  }
+                gchar *tmp = gtk_pcb_layer_selector_get_pick_xml
+                  (GTK_PCB_LAYER_SELECTOR (ghidgui->layer_selector));
+                ghid_ui_info_append (tmp);
+                g_free (tmp);
 	      }
 	    else if (strcmp (node->v[i].value, "@routestyles") == 0)
 	      {
diff --git a/src/hid/gtk/gui.h b/src/hid/gtk/gui.h
index 9bed4d9..134d2fb 100644
--- a/src/hid/gtk/gui.h
+++ b/src/hid/gtk/gui.h
@@ -108,6 +108,7 @@ typedef struct
     *menu_hbox, *compact_vbox, *compact_hbox, *position_hbox, *label_hbox,
     *mode_buttons0_vbox, *mode_buttons1_hbox, *mode_buttons1_vbox,
     *mode_buttons0_frame, *mode_buttons1_frame, *mode_buttons0_frame_vbox;
+  GtkWidget *layer_selector;
 
   GtkWidget *h_range, *v_range;
   GtkObject *h_adjustment, *v_adjustment;
@@ -235,9 +236,7 @@ void ghid_config_files_read (gint * argc, gchar *** argv);
 
 void ghid_mode_buttons_update (void);
 void ghid_pack_mode_buttons(void);
-void ghid_layer_enable_buttons_update (void);
 void ghid_layer_buttons_update (void);
-void ghid_layer_button_select (gint layer);
 void ghid_layer_buttons_color_update (void);
 
 

commit 6d50fc7871acdddd8f319d1fd21a08d0784c9af8
Author: Andrew Poelstra <asp11@xxxxxx>
Commit: Andrew Poelstra <asp11@xxxxxx>

    Introduce GtkPcbLayerSelector widget -- not used yet
    
    This widget will replace the layer-selection buttons in the
    Gtk GUI, as well as the layer selection and visibility-toggling
    parts of the menu.
    
    This is to make layer manipulation more consistent and
    more keyboard-accessible.
    
    In future, it would be good to update this widget with context
    menus with things like "hide all but this layer".

diff --git a/src/Makefile.am b/src/Makefile.am
index 9df4a50..d4c37e0 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -272,6 +272,10 @@ 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/gtk-pcb-cell-renderer-visibility.c \
+	hid/gtk/gtk-pcb-cell-renderer-visibility.h \
 	hid/gtk/gtkhid-main.c \
 	hid/gtk/gtkhid.h \
 	hid/gtk/gui.h \
diff --git a/src/hid/gtk/gtk-pcb-cell-renderer-visibility.c b/src/hid/gtk/gtk-pcb-cell-renderer-visibility.c
new file mode 100644
index 0000000..8f6d669
--- /dev/null
+++ b/src/hid/gtk/gtk-pcb-cell-renderer-visibility.c
@@ -0,0 +1,296 @@
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gtkhid.h"
+#include "gui.h"
+
+#include "gtk-pcb-cell-renderer-visibility.h"
+
+enum {
+  TOGGLED,
+  LAST_SIGNAL
+};
+static guint toggle_cell_signals[LAST_SIGNAL] = { 0 };
+
+enum {
+  PROP_ACTIVE = 1,
+  PROP_COLOR
+};
+
+struct _GtkPcbCellRendererVisibility
+{
+  GtkCellRenderer parent;
+
+  gboolean active;
+  gchar *color;
+};
+
+struct _GtkPcbCellRendererVisibilityClass
+{
+  GtkCellRendererClass parent_class;
+
+  void (* toggled) (GtkPcbCellRendererVisibility *cell, const gchar *path);
+};
+
+/* RENDERER FUNCTIONS */
+static void
+gtk_pcb_cell_renderer_visibility_get_size (GtkCellRenderer *cell,
+                                           GtkWidget       *widget,
+                                           GdkRectangle    *cell_area,
+                                           gint            *x_offset,
+                                           gint            *y_offset,
+                                           gint            *width,
+                                           gint            *height)
+{
+  GtkStyle *style = gtk_widget_get_style (widget);
+  gint w, h;
+
+  w = VISIBILITY_TOGGLE_SIZE + 2 * (cell->xpad + style->xthickness);
+  h = VISIBILITY_TOGGLE_SIZE + 2 * (cell->ypad + style->ythickness);
+
+  if (width)
+    *width = w;
+  if (height)
+    *height = h;
+
+  if (cell_area)
+    {
+      if (x_offset)
+        {
+          gint xalign = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+                          ? 1.0 - cell->xalign
+                          : cell->xalign;
+          *x_offset = MAX (0, xalign * (cell_area->width - w));
+        }
+      if (y_offset)
+        *y_offset = MAX(0, cell->yalign * (cell_area->height - h));
+    }
+}
+
+static void
+gtk_pcb_cell_renderer_visibility_render (GtkCellRenderer      *cell,
+                                         GdkWindow            *window,
+                                         GtkWidget            *widget,
+                                         GdkRectangle         *background_area,
+                                         GdkRectangle         *cell_area,
+                                         GdkRectangle         *expose_area,
+                                         GtkCellRendererState  flags)
+{
+  GtkPcbCellRendererVisibility *pcb_cell;
+  GdkRectangle toggle_rect;
+  GdkRectangle draw_rect;
+  GtkStateType state;
+
+  pcb_cell = GTK_PCB_CELL_RENDERER_VISIBILITY (cell);
+  gtk_pcb_cell_renderer_visibility_get_size (cell, widget, cell_area,
+                                             &toggle_rect.x,
+                                             &toggle_rect.y,
+                                             &toggle_rect.width,
+                                             &toggle_rect.height);
+
+  toggle_rect.x      += cell_area->x + cell->xpad;
+  toggle_rect.y      += cell_area->y + cell->ypad;
+  toggle_rect.width  -= cell->xpad * 2;
+  toggle_rect.height -= cell->ypad * 2;
+
+  if (toggle_rect.width <= 0 || toggle_rect.height <= 0)
+    return;
+
+  if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED)
+    {
+      if (GTK_WIDGET_HAS_FOCUS (widget))
+        state = GTK_STATE_SELECTED;
+      else
+        state = GTK_STATE_ACTIVE;
+    }
+  else
+    state = GTK_STATE_NORMAL;
+
+  if (gdk_rectangle_intersect (expose_area, cell_area, &draw_rect))
+    {
+      GdkColor color;
+      cairo_t *cr = gdk_cairo_create (window);
+      if (expose_area)
+        {
+          gdk_cairo_rectangle (cr, expose_area);
+          cairo_clip (cr);
+        }
+      cairo_set_line_width (cr, 1);
+
+      cairo_rectangle (cr, toggle_rect.x + 0.5, toggle_rect.y + 0.5,
+                           toggle_rect.width - 1, toggle_rect.height - 1);
+      cairo_set_source_rgb (cr, 1, 1, 1);
+      cairo_fill_preserve (cr);
+      cairo_set_source_rgb (cr, 0, 0, 0);
+      cairo_stroke (cr);
+
+      gdk_color_parse (pcb_cell->color, &color);
+      gdk_cairo_set_source_color (cr, &color);
+      if (pcb_cell->active)
+        cairo_rectangle (cr, toggle_rect.x + 0.5, toggle_rect.y + 0.5,
+                             toggle_rect.width - 1, toggle_rect.height - 1);
+      else
+        {
+          cairo_move_to (cr, toggle_rect.x + 1, toggle_rect.y + 1);
+          cairo_rel_line_to (cr, toggle_rect.width / 2, 0);
+          cairo_rel_line_to (cr, -toggle_rect.width / 2, toggle_rect.width / 2);
+          cairo_close_path (cr);
+        }
+      cairo_fill (cr);
+
+      cairo_destroy (cr);
+    }
+}
+
+static gint
+gtk_pcb_cell_renderer_visibility_activate (GtkCellRenderer      *cell,
+                                           GdkEvent             *event,
+                                           GtkWidget            *widget,
+                                           const gchar          *path,
+                                           GdkRectangle         *background_area,
+                                           GdkRectangle         *cell_area,
+                                           GtkCellRendererState  flags)
+{
+  g_signal_emit (cell, toggle_cell_signals[TOGGLED], 0, path);
+  return TRUE;
+}
+
+/* Setter/Getter */
+static void
+gtk_pcb_cell_renderer_visibility_get_property (GObject     *object,
+                                               guint        param_id,
+                                               GValue      *value,
+                                               GParamSpec  *pspec)
+{
+  GtkPcbCellRendererVisibility *pcb_cell =
+    GTK_PCB_CELL_RENDERER_VISIBILITY (object);
+
+  switch (param_id)
+    {
+    case PROP_ACTIVE:
+      g_value_set_boolean (value, pcb_cell->active);
+      break;
+    case PROP_COLOR:
+      g_value_set_string (value, pcb_cell->color);
+      break;
+    }
+}
+
+static void
+gtk_pcb_cell_renderer_visibility_set_property (GObject      *object,
+                                               guint         param_id,
+                                               const GValue *value,
+                                               GParamSpec   *pspec)
+{
+  GtkPcbCellRendererVisibility *pcb_cell =
+    GTK_PCB_CELL_RENDERER_VISIBILITY (object);
+
+  switch (param_id)
+    {
+    case PROP_ACTIVE:
+      pcb_cell->active = g_value_get_boolean (value);
+      break;
+    case PROP_COLOR:
+      g_free (pcb_cell->color);
+      pcb_cell->color = g_value_dup_string (value);
+      break;
+    }
+}
+
+
+/* CONSTRUCTOR */
+static void
+gtk_pcb_cell_renderer_visibility_init (GtkPcbCellRendererVisibility *ls)
+{
+  g_object_set (ls, "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, NULL);
+}
+
+static void
+gtk_pcb_cell_renderer_visibility_class_init (GtkPcbCellRendererVisibilityClass *klass)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (klass);
+  GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
+
+  object_class->get_property = gtk_pcb_cell_renderer_visibility_get_property;
+  object_class->set_property = gtk_pcb_cell_renderer_visibility_set_property;
+
+  cell_class->get_size = gtk_pcb_cell_renderer_visibility_get_size;
+  cell_class->render   = gtk_pcb_cell_renderer_visibility_render;
+  cell_class->activate = gtk_pcb_cell_renderer_visibility_activate;
+
+  g_object_class_install_property (object_class, PROP_ACTIVE,
+                                   g_param_spec_boolean ("active",
+                                                         _("Visibility state"),
+                                                         _("Visibility of the layer"),
+                                                         FALSE,
+                                                         G_PARAM_READWRITE));
+  g_object_class_install_property (object_class, PROP_COLOR,
+                                   g_param_spec_string ("color",
+                                                         _("Layer color"),
+                                                         _("Layer color"),
+                                                         FALSE,
+                                                         G_PARAM_READWRITE));
+
+
+ /**
+  * GtkPcbCellRendererVisibility::toggled:
+  * @cell_renderer: the object which received the signal
+  * @path: string representation of #GtkTreePath describing the 
+  *        event location
+  *
+  * The ::toggled signal is emitted when the cell is toggled. 
+  **/
+  toggle_cell_signals[TOGGLED] =
+    g_signal_new (_("toggled"),
+                  G_OBJECT_CLASS_TYPE (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  G_STRUCT_OFFSET (GtkPcbCellRendererVisibilityClass, toggled),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__STRING,
+                  G_TYPE_NONE, 1,
+                  G_TYPE_STRING);
+}
+
+/* PUBLIC FUNCTIONS */
+GType
+gtk_pcb_cell_renderer_visibility_get_type (void)
+{
+  static GType ls_type = 0;
+
+  if (!ls_type)
+    {
+      const GTypeInfo ls_info =
+      {
+	sizeof (GtkPcbCellRendererVisibilityClass),
+	NULL, /* base_init */
+	NULL, /* base_finalize */
+	(GClassInitFunc) gtk_pcb_cell_renderer_visibility_class_init,
+	NULL, /* class_finalize */
+	NULL, /* class_data */
+	sizeof (GtkPcbCellRendererVisibility),
+	0,    /* n_preallocs */
+	(GInstanceInitFunc) gtk_pcb_cell_renderer_visibility_init,
+      };
+
+      ls_type = g_type_register_static (GTK_TYPE_CELL_RENDERER,
+                                        "GtkPcbCellRendererVisibility",
+                                        &ls_info,
+                                        0);
+    }
+
+  return ls_type;
+}
+
+GtkCellRenderer *
+gtk_pcb_cell_renderer_visibility_new (void)
+{
+  GtkPcbCellRendererVisibility *rv =
+    g_object_new (GTK_PCB_CELL_RENDERER_VISIBILITY_TYPE, NULL);
+
+  rv->active = FALSE;
+
+  return GTK_CELL_RENDERER (rv);
+}
+
diff --git a/src/hid/gtk/gtk-pcb-cell-renderer-visibility.h b/src/hid/gtk/gtk-pcb-cell-renderer-visibility.h
new file mode 100644
index 0000000..212c4a4
--- /dev/null
+++ b/src/hid/gtk/gtk-pcb-cell-renderer-visibility.h
@@ -0,0 +1,24 @@
+#ifndef GTK_PCB_CELL_RENDERER_VISIBILITY_H__
+#define GTK_PCB_CELL_RENDERER_VISIBILITY_H__
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS  /* keep c++ happy */
+
+#define VISIBILITY_TOGGLE_SIZE	16
+
+#define GTK_PCB_CELL_RENDERER_VISIBILITY_TYPE            (gtk_pcb_cell_renderer_visibility_get_type ())
+#define GTK_PCB_CELL_RENDERER_VISIBILITY(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_PCB_CELL_RENDERER_VISIBILITY_TYPE, GtkPcbCellRendererVisibility))
+#define GTK_PCB_CELL_RENDERER_VISIBILITY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_PCB_CELL_RENDERER_VISIBILITY_TYPE, GtkPcbCellRendererVisibilityClass))
+#define IS_GTK_PCB_CELL_RENDERER_VISIBILITY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_PCB_CELL_RENDERER_VISIBILITY_TYPE))
+#define IS_GTK_PCB_CELL_RENDERER_VISIBILITY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_PCB_CELL_RENDERER_VISIBILITY_TYPE))
+
+typedef struct _GtkPcbCellRendererVisibility       GtkPcbCellRendererVisibility;
+typedef struct _GtkPcbCellRendererVisibilityClass  GtkPcbCellRendererVisibilityClass;
+
+GType gtk_pcb_cell_renderer_visibility_get_type (void);
+GtkCellRenderer *gtk_pcb_cell_renderer_visibility_new (void);
+
+G_END_DECLS  /* keep c++ happy */
+#endif
diff --git a/src/hid/gtk/gtk-pcb-layer-selector.c b/src/hid/gtk/gtk-pcb-layer-selector.c
new file mode 100644
index 0000000..519ec50
--- /dev/null
+++ b/src/hid/gtk/gtk-pcb-layer-selector.c
@@ -0,0 +1,708 @@
+/*! \file <gtk-pcb-layer-selector.c>
+ *  \brief Implementation of GtkPcbLayerSelector widget
+ *  \par Description
+ *  This widget is used for
+ */
+
+#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 "gtk-pcb-layer-selector.h"
+#include "gtk-pcb-cell-renderer-visibility.h"
+
+#define INITIAL_ACTION_MAX	40
+
+/* Forward dec'ls */
+static void gtk_pcb_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 *gtk_pcb_layer_selector_parent_class;
+static guint gtk_pcb_layer_selector_signals[LAST_SIGNAL] = { 0 };
+
+struct _GtkPcbLayerSelector
+{
+  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 _GtkPcbLayerSelectorClass
+{
+  GtkTreeViewClass parent_class;
+
+  void (* select_layer) (GtkPcbLayerSelector *, gint);
+  void (* toggle_layer) (GtkPcbLayerSelector *, 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 (GtkPcbLayerSelector *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 (GtkPcbLayerSelector *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, GtkPcbLayerSelector *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)
+{
+  GtkPcbLayerSelector *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, gtk_pcb_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, GtkPcbLayerSelector *ls)
+{
+  int idx = gtk_radio_action_get_current_value (action);
+  GtkTreeRowReference *rref = ls->rows[idx];
+  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);
+  gtk_tree_selection_select_path (ls->selection, path);
+
+  g_signal_emit (ls, gtk_pcb_layer_selector_signals[SELECT_LAYER_SIGNAL],
+                 0, user_id);
+}
+
+/* CONSTRUCTOR */
+static void
+gtk_pcb_layer_selector_init (GtkPcbLayerSelector *ls)
+{
+  /* Hookup signal handlers */
+}
+
+static void
+gtk_pcb_layer_selector_class_init (GtkPcbLayerSelectorClass *klass)
+{
+  GObjectClass *object_class = (GObjectClass *) klass;
+
+  gtk_pcb_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 (GtkPcbLayerSelectorClass, select_layer),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
+                  1, G_TYPE_INT);
+  gtk_pcb_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 (GtkPcbLayerSelectorClass, toggle_layer),
+                  NULL, NULL,
+                  g_cclosure_marshal_VOID__INT, G_TYPE_NONE,
+                  1, G_TYPE_INT);
+
+  object_class->finalize = gtk_pcb_layer_selector_finalize;
+}
+
+/*! \brief Clean up object before garbage collection
+ */
+static void
+gtk_pcb_layer_selector_finalize (GObject *object)
+{
+  int i;
+  GtkPcbLayerSelector *ls = (GtkPcbLayerSelector *) 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)
+    gtk_tree_row_reference_free (ls->rows[i]);
+  g_free (ls->rows);
+
+  G_OBJECT_CLASS (gtk_pcb_layer_selector_parent_class)->finalize (object);
+}
+
+/* PUBLIC FUNCTIONS */
+GType
+gtk_pcb_layer_selector_get_type (void)
+{
+  static GType ls_type = 0;
+
+  if (!ls_type)
+    {
+      const GTypeInfo ls_info =
+      {
+	sizeof (GtkPcbLayerSelectorClass),
+	NULL, /* base_init */
+	NULL, /* base_finalize */
+	(GClassInitFunc) gtk_pcb_layer_selector_class_init,
+	NULL, /* class_finalize */
+	NULL, /* class_data */
+	sizeof (GtkPcbLayerSelector),
+	0,    /* n_preallocs */
+	(GInstanceInitFunc) gtk_pcb_layer_selector_init,
+      };
+
+      ls_type = g_type_register_static (GTK_TYPE_TREE_VIEW,
+                                        "GtkPcbLayerSelector",
+                                        &ls_info,
+                                        0);
+    }
+
+  return ls_type;
+}
+
+/*! \brief Create a new GtkPcbLayerSelector
+ *
+ *  \return a freshly-allocated GtkPcbLayerSelector.
+ */
+GtkWidget *
+gtk_pcb_layer_selector_new (void)
+{
+  GtkCellRenderer *renderer1 = gtk_pcb_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);
+
+  GtkPcbLayerSelector *ls = g_object_new (GTK_PCB_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 GtkPcbLayerSelector.
+ *  \par Function Description
+ *  This function adds an entry to a GtkPcbLayerSelector, 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.
+ *
+ *  \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
+gtk_pcb_layer_selector_add_layer (GtkPcbLayerSelector *ls,
+                                  gint user_id,
+                                  const gchar *name,
+                                  const gchar *color_string,
+                                  gboolean visible,
+                                  gboolean activatable)
+{
+  gchar *pname, *vname, *paccel, *vaccel;
+  GtkTreePath *path;
+  GtkTreeIter iter;
+
+  if (activatable != ls->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);
+    }
+
+  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);
+
+  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 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);
+    }
+  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);
+
+  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);
+
+  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->last_activatable = activatable;
+  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 *
+gtk_pcb_layer_selector_get_pick_xml (GtkPcbLayerSelector *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 *
+gtk_pcb_layer_selector_get_view_xml (GtkPcbLayerSelector *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 *
+gtk_pcb_layer_selector_get_action_group (GtkPcbLayerSelector *ls)
+{
+  return ls->action_group;
+}
+
+/*! \brief used internally */
+static gboolean
+toggle_foreach_func (GtkTreeModel *model, GtkTreePath *path,
+                     GtkTreeIter *iter, gpointer data)
+{
+  gint id;
+  GtkPcbLayerSelector *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
+gtk_pcb_layer_selector_toggle_layer (GtkPcbLayerSelector *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;
+  GtkPcbLayerSelector *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
+gtk_pcb_layer_selector_select_layer (GtkPcbLayerSelector *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
+gtk_pcb_layer_selector_select_next_visible (GtkPcbLayerSelector *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_selection_select_iter (ls->selection, &iter);
+              return TRUE;
+            }
+        }
+      while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter));
+      /* Move iter to start, and repeat. */
+      gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls->list_store), &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_selection_select_iter (ls->selection, &iter);
+              return TRUE;
+            }
+        }
+      while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter));
+      /* If we get here, nothing is selectable, so fail. */
+    }
+  return FALSE;
+}
+
+/*! \brief Makes the selected layer visible
+ *  \par Function Description
+ *  Used to ensure hidden layers are not active; un-hides the currently
+ *  selected layer.
+ *
+ *  \param [in] ls       The selector to be acted on
+ */
+void
+gtk_pcb_layer_selector_make_selected_visible (GtkPcbLayerSelector *ls)
+{
+  GtkTreeIter iter;
+  if (gtk_tree_selection_get_selected (ls->selection, NULL, &iter))
+    {
+      gboolean visible;
+      gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store),
+                          &iter, VISIBLE_COL, &visible, -1);
+      if (!visible)
+        toggle_visibility (ls, &iter);
+    }
+}
+
+/*! \brief Sets the colors of all layers in a layer-selector
+ *  \par Function Description
+ *  Updates the colors of a layer selector via a callback mechanism:
+ *  the user_id of each layer is passed to the callback function,
+ *  which returns a color string to update the layer's color, or NULL
+ *  to leave it alone.
+ *
+ *  \param [in] ls       The selector to be acted on
+ *  \param [in] callback Takes the user_id of the layer and returns a color string
+ */
+void
+gtk_pcb_layer_selector_update_colors (GtkPcbLayerSelector *ls,
+                                      const gchar *(*callback)(int user_id))
+{
+  GtkTreeIter iter;
+  gtk_tree_model_get_iter_first (GTK_TREE_MODEL (ls->list_store), &iter);
+  do
+    {
+      gint user_id;
+      const gchar *new_color;
+      gtk_tree_model_get (GTK_TREE_MODEL (ls->list_store),
+                          &iter, USER_ID_COL, &user_id, -1);
+      new_color = callback (user_id);
+      if (new_color != NULL)
+        gtk_list_store_set (ls->list_store, &iter, COLOR_COL, new_color, -1);
+    }
+  while (gtk_tree_model_iter_next (GTK_TREE_MODEL (ls->list_store), &iter));
+}
+
+
diff --git a/src/hid/gtk/gtk-pcb-layer-selector.h b/src/hid/gtk/gtk-pcb-layer-selector.h
new file mode 100644
index 0000000..0773497
--- /dev/null
+++ b/src/hid/gtk/gtk-pcb-layer-selector.h
@@ -0,0 +1,43 @@
+#ifndef GTK_PCB_LAYER_SELECTOR_H__
+#define GTK_PCB_LAYER_SELECTOR_H__
+
+#include <glib.h>
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS  /* keep c++ happy */
+
+#define GTK_PCB_LAYER_SELECTOR_TYPE            (gtk_pcb_layer_selector_get_type ())
+#define GTK_PCB_LAYER_SELECTOR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_PCB_LAYER_SELECTOR_TYPE, GtkPcbLayerSelector))
+#define GTK_PCB_LAYER_SELECTOR_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_PCB_LAYER_SELECTOR_TYPE, GtkPcbLayerSelectorClass))
+#define IS_GTK_PCB_LAYER_SELECTOR(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_PCB_LAYER_SELECTOR_TYPE))
+#define IS_GTK_PCB_LAYER_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_PCB_LAYER_SELECTOR_TYPE))
+
+typedef struct _GtkPcbLayerSelector       GtkPcbLayerSelector;
+typedef struct _GtkPcbLayerSelectorClass  GtkPcbLayerSelectorClass;
+
+GType gtk_pcb_layer_selector_get_type (void);
+GtkWidget* gtk_pcb_layer_selector_new (void);
+
+void gtk_pcb_layer_selector_add_layer (GtkPcbLayerSelector *ls,
+                                       gint user_id,
+                                       const gchar *name,
+                                       const gchar *color_string,
+                                       gboolean visible,
+                                       gboolean activatable);
+GtkAccelGroup *gtk_pcb_layer_selector_get_accel_group (GtkPcbLayerSelector *ls);
+gchar *gtk_pcb_layer_selector_get_pick_xml (GtkPcbLayerSelector *ls);
+gchar *gtk_pcb_layer_selector_get_view_xml (GtkPcbLayerSelector *ls);
+GtkActionGroup *gtk_pcb_layer_selector_get_action_group (GtkPcbLayerSelector *ls);
+
+void gtk_pcb_layer_selector_toggle_layer (GtkPcbLayerSelector *ls, 
+                                          gint user_id);
+void gtk_pcb_layer_selector_select_layer (GtkPcbLayerSelector *ls, 
+                                          gint user_id);
+gboolean gtk_pcb_layer_selector_select_next_visible (GtkPcbLayerSelector *ls);
+void gtk_pcb_layer_selector_make_selected_visible (GtkPcbLayerSelector *ls);
+void gtk_pcb_layer_selector_update_colors (GtkPcbLayerSelector *ls,
+                                           const gchar *(*callback)(int user_id));
+
+G_END_DECLS  /* keep c++ happy */
+#endif

commit 12771c69eee43cd5f275a64a031f3947ab172d77
Author: Andrew Poelstra <asp11@xxxxxx>
Commit: Andrew Poelstra <asp11@xxxxxx>

    Change Gtk layer_process() to use colors from Settings, not PCB
    
    Now the only code that uses the colors in the PCB struct is
    draw.c. Hopefully in a future commit we can remove this too
    and remove the duplication of color data in the Settings and
    PCB structs.

diff --git a/src/hid/gtk/gui-top-window.c b/src/hid/gtk/gui-top-window.c
index aaab38e..4e9ae27 100644
--- a/src/hid/gtk/gui-top-window.c
+++ b/src/hid/gtk/gui-top-window.c
@@ -693,37 +693,37 @@ layer_process (gchar **color_string, char **text, int *set, int i)
   switch (i)
     {
     case LAYER_BUTTON_SILK:
-      *color_string = PCB->ElementColor;
+      *color_string = Settings.ElementColor;
       *text = _( "silk");
       *set = PCB->ElementOn;
       break;
     case LAYER_BUTTON_RATS:
-      *color_string = PCB->RatColor;
+      *color_string = Settings.RatColor;
       *text = _( "rat lines");
       *set = PCB->RatOn;
       break;
     case LAYER_BUTTON_PINS:
-      *color_string = PCB->PinColor;
+      *color_string = Settings.PinColor;
       *text = _( "pins/pads");
       *set = PCB->PinOn;
       break;
     case LAYER_BUTTON_VIAS:
-      *color_string = PCB->ViaColor;
+      *color_string = Settings.ViaColor;
       *text = _( "vias");
       *set = PCB->ViaOn;
       break;
     case LAYER_BUTTON_FARSIDE:
-      *color_string = PCB->InvisibleObjectsColor;
+      *color_string = Settings.InvisibleObjectsColor;
       *text = _( "far side");
       *set = PCB->InvisibleObjectsOn;
       break;
     case LAYER_BUTTON_MASK:
-      *color_string = PCB->MaskColor;
+      *color_string = Settings.MaskColor;
       *text = _( "solder mask");
       *set = TEST_FLAG (SHOWMASKFLAG, PCB);
       break;
     default:		/* layers */
-      *color_string = PCB->Data->Layer[i].Color;
+      *color_string = Settings.LayerColor[i];
       *text = (char *)UNKNOWN (PCB->Data->Layer[i].Name);
       *set = PCB->Data->Layer[i].On;
       break;




_______________________________________________
geda-cvs mailing list
geda-cvs@xxxxxxxxxxxxxx
http://www.seul.org/cgi-bin/mailman/listinfo/geda-cvs