Index: trunk/src_plugins/hid_gtk/Plug.tmpasm =================================================================== --- trunk/src_plugins/hid_gtk/Plug.tmpasm (revision 1558) +++ trunk/src_plugins/hid_gtk/Plug.tmpasm (revision 1559) @@ -23,6 +23,7 @@ $(PLUGDIR)/hid_gtk/gui-utils.o $(PLUGDIR)/hid_gtk/gtkhid-gdk.o $(PLUGDIR)/hid_gtk/menu_lht.o + $(PLUGDIR)/hid_gtk/gschem_accel_label.o @] switch /local/pcb/hid_gtk/controls Index: trunk/src_plugins/hid_gtk/ghid-main-menu.c =================================================================== --- trunk/src_plugins/hid_gtk/ghid-main-menu.c (revision 1558) +++ trunk/src_plugins/hid_gtk/ghid-main-menu.c (revision 1559) @@ -73,8 +73,11 @@ assert(node != NULL); anode = hid_cfg_menu_field(sub_res, MF_ACTION, NULL); - if (anode != NULL) + if (anode != NULL) { hid_cfg_keys_add_by_desc(&ghid_keymap, tmp_val, anode, NULL, 0); +#warning TODO: this has to be a functio that respects lists + accel = tmp_val; + } else hid_cfg_error(sub_res, "No action specified for key accel\n"); } @@ -147,12 +150,14 @@ } else { /* NORMAL ITEM */ - gchar *name = g_strdup_printf("MainMenuAction%d", action_counter++); - action = gtk_action_new(name, menu_label, tip, NULL); + GtkWidget *item = gtk_menu_item_new_gschem(menu_label, accel); + gtk_menu_shell_append(shell, item); + sub_res->user_data = item; + g_signal_connect(G_OBJECT(item), "activate", G_CALLBACK(menu->action_cb), (gpointer)n_action); } } - /* Connect accelerator, if there is one */ + /* By now this runs only for toggle items. */ if (action) { GtkWidget *item; gtk_action_set_accel_group(action, menu->accel_group); Index: trunk/src_plugins/hid_gtk/gschem_accel_label.c =================================================================== --- trunk/src_plugins/hid_gtk/gschem_accel_label.c (nonexistent) +++ trunk/src_plugins/hid_gtk/gschem_accel_label.c (revision 1559) @@ -0,0 +1,341 @@ +/* gEDA - GPL Electronic Design Automation + * gschem - gEDA Schematic Capture + * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) + * + * Code based on GTK 2.14.5 gtk/gtkaccellabel.c (LGPL) + * + * GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GschemAccelLabel: GtkLabel with accelerator monitoring facilities. + * Copyright (C) 1998 Tim Janik + * + * Modified by the GTK+ Team and others 1997-2001. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + * + * Adapted for gEDA by Peter Clifton + * + * THIS FILE IS LGPL LICENSED, pcb-rnd AS A WHOLE IS GPL LICENSED + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +/* This file has been copied from gschem sources. It seems gtk's bondage +and discipline menu item simply cna not handle arbitrary accel label text +and the default accel label widget works only if gtk takes over handling +accel key input. In pbc-rnd there's a central input key handling and support +for multi-key sequences. gschem had the same problem because of multi-key, +and came up with this solution to rewrite the accel label object. + +Modifications: + - indentation + - #includes + - helper call that creates a menu item with label and accel label +*/ + +#include +#include +#include "gschem_accel_label.h" + +#define P_(x) (x) + +enum { + PROP_0, + PROP_ACCEL_CLOSURE, + PROP_ACCEL_WIDGET, + PROP_ACCEL_STRING, +}; + +G_DEFINE_TYPE(GschemAccelLabel, gschem_accel_label, GTK_TYPE_ACCEL_LABEL) + + +gboolean gschem_accel_label_refetch(GschemAccelLabel * accel_label) +{ + gboolean enable_accels; + + g_return_val_if_fail(GSCHEM_IS_ACCEL_LABEL(accel_label), FALSE); + + g_object_get(gtk_widget_get_settings(GTK_WIDGET(accel_label)), "gtk-enable-accels", &enable_accels, NULL); + + if (!enable_accels || accel_label->accel_string == NULL) { + if (accel_label->accel_string != NULL) + g_free(accel_label->accel_string); + + accel_label->accel_string = g_strdup(""); + } + + gtk_widget_queue_resize(GTK_WIDGET(accel_label)); + + return FALSE; +} + + +static const gchar *gschem_accel_label_get_string(GschemAccelLabel * accel_label) +{ + if (!accel_label->accel_string) + gschem_accel_label_refetch(accel_label); + + return accel_label->accel_string; +} + + +static void gschem_accel_label_set_property(GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GschemAccelLabel *accel_label; + + accel_label = GSCHEM_ACCEL_LABEL(object); + + switch (prop_id) { + /* Dummy properties from GtkAccelLabel */ + case PROP_ACCEL_CLOSURE: + case PROP_ACCEL_WIDGET: + break; + + case PROP_ACCEL_STRING: + gschem_accel_label_set_accel_string(accel_label, g_value_get_string(value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void gschem_accel_label_get_property(GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) +{ + GschemAccelLabel *accel_label; + + accel_label = GSCHEM_ACCEL_LABEL(object); + + switch (prop_id) { + /* Dummy property from GtkAccelLabel */ + case PROP_ACCEL_CLOSURE: + g_value_set_boxed(value, NULL); + break; + + /* Dummy property from GtkAccelLabel */ + case PROP_ACCEL_WIDGET: + g_value_set_object(value, NULL); + break; + + case PROP_ACCEL_STRING: + g_value_set_string(value, accel_label->accel_string); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void gschem_accel_label_init(GschemAccelLabel * accel_label) +{ + accel_label->accel_padding = 3; + accel_label->accel_string = NULL; +} + +static void gschem_accel_label_finalize(GObject * object) +{ + GschemAccelLabel *accel_label = GSCHEM_ACCEL_LABEL(object); + + g_free(accel_label->accel_string); + + G_OBJECT_CLASS(gschem_accel_label_parent_class)->finalize(object); +} + +guint gschem_accel_label_get_accel_width(GschemAccelLabel * accel_label) +{ + g_return_val_if_fail(GSCHEM_IS_ACCEL_LABEL(accel_label), 0); + + return (accel_label->accel_string_width + (accel_label->accel_string_width ? accel_label->accel_padding : 0)); +} + +static void gschem_accel_label_size_request(GtkWidget * widget, GtkRequisition * requisition) +{ + GschemAccelLabel *accel_label = GSCHEM_ACCEL_LABEL(widget); + GtkAccelLabel *gtk_accel_label = GTK_ACCEL_LABEL(widget); + PangoLayout *layout; + gint width; + + GTK_WIDGET_CLASS(gschem_accel_label_parent_class)->size_request(widget, requisition); + + layout = gtk_widget_create_pango_layout(widget, gschem_accel_label_get_string(accel_label)); + pango_layout_get_pixel_size(layout, &width, NULL); + accel_label->accel_string_width = width; + gtk_accel_label->accel_string_width = width; /* HACK: This field is private to GtkAccelLabel */ + g_object_unref(layout); +} + +static gint get_first_baseline(PangoLayout * layout) +{ + PangoLayoutIter *iter; + gint result; + + iter = pango_layout_get_iter(layout); + result = pango_layout_iter_get_baseline(iter); + pango_layout_iter_free(iter); + + return PANGO_PIXELS(result); +} + +static gboolean gschem_accel_label_expose_event(GtkWidget * widget, GdkEventExpose * event) +{ + GschemAccelLabel *accel_label = GSCHEM_ACCEL_LABEL(widget); + GtkMisc *misc = GTK_MISC(accel_label); + GtkTextDirection direction; + + direction = gtk_widget_get_direction(widget); + + if (gtk_widget_is_drawable(GTK_WIDGET(accel_label))) { + guint ac_width; + + ac_width = gschem_accel_label_get_accel_width(accel_label); + + if (widget->allocation.width >= widget->requisition.width + ac_width) { + PangoLayout *label_layout; + PangoLayout *accel_layout; + GtkLabel *label = GTK_LABEL(widget); + + gint x; + gint y; + + label_layout = gtk_label_get_layout(GTK_LABEL(accel_label)); + + if (direction == GTK_TEXT_DIR_RTL) + widget->allocation.x += ac_width; + widget->allocation.width -= ac_width; + if (gtk_label_get_ellipsize(label)) + pango_layout_set_width(label_layout, pango_layout_get_width(label_layout) + - ac_width * PANGO_SCALE); + + if (GTK_WIDGET_CLASS(gschem_accel_label_parent_class)->expose_event) + GTK_WIDGET_CLASS(gschem_accel_label_parent_class)->expose_event(widget, event); + if (direction == GTK_TEXT_DIR_RTL) + widget->allocation.x -= ac_width; + widget->allocation.width += ac_width; + if (gtk_label_get_ellipsize(label)) + pango_layout_set_width(label_layout, pango_layout_get_width(label_layout) + + ac_width * PANGO_SCALE); + + if (direction == GTK_TEXT_DIR_RTL) + x = widget->allocation.x + misc->xpad; + else + x = widget->allocation.x + widget->allocation.width - misc->xpad - ac_width; + + gtk_label_get_layout_offsets(GTK_LABEL(accel_label), NULL, &y); + + accel_layout = gtk_widget_create_pango_layout(widget, gschem_accel_label_get_string(accel_label)); + + y += get_first_baseline(label_layout) - get_first_baseline(accel_layout); + + gtk_paint_layout(widget->style, + widget->window, + gtk_widget_get_state(widget), FALSE, &event->area, widget, "accellabel", x, y, accel_layout); + + g_object_unref(accel_layout); + } + else { + if (GTK_WIDGET_CLASS(gschem_accel_label_parent_class)->expose_event) + GTK_WIDGET_CLASS(gschem_accel_label_parent_class)->expose_event(widget, event); + } + } + + return FALSE; +} + +/* Underscores in key names are better displayed as spaces + * E.g., Page_Up should be "Page Up" + */ +static void substitute_underscores(char *str) +{ + char *p; + + for (p = str; *p; p++) + if (*p == '_') + *p = ' '; +} + + +/** + * gschem_accel_label_set_accel_string: + * \param accel_label a #GschemAccelLabel + * \param accel_string the accelerator string. + * + * Sets the accelerator string for this accelerator label. + **/ +void gschem_accel_label_set_accel_string(GschemAccelLabel * accel_label, const gchar * accel_string) +{ + g_return_if_fail(GSCHEM_IS_ACCEL_LABEL(accel_label)); + + if (accel_label->accel_string) + g_free(accel_label->accel_string); + + if (accel_string) { + accel_label->accel_string = g_strdup(accel_string); + substitute_underscores(accel_label->accel_string); + } + else { + accel_label->accel_string = NULL; + } + + g_object_notify(G_OBJECT(accel_label), "accel-string"); +} + +static void gschem_accel_label_class_init(GschemAccelLabelClass * class) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(class); + + gobject_class->finalize = gschem_accel_label_finalize; + gobject_class->set_property = gschem_accel_label_set_property; + gobject_class->get_property = gschem_accel_label_get_property; + + widget_class->size_request = gschem_accel_label_size_request; + widget_class->expose_event = gschem_accel_label_expose_event; + + g_object_class_install_property(gobject_class, + PROP_ACCEL_CLOSURE, + g_param_spec_boxed("accel-closure", + P_("Accelerator Closure"), + P_("The closure to be monitored for accelerator changes"), + G_TYPE_CLOSURE, G_PARAM_READWRITE)); + g_object_class_install_property(gobject_class, + PROP_ACCEL_WIDGET, + g_param_spec_object("accel-widget", + P_("Accelerator Widget"), + P_("The widget to be monitored for accelerator changes"), + GTK_TYPE_WIDGET, G_PARAM_READWRITE)); + g_object_class_install_property(gobject_class, + PROP_ACCEL_STRING, + g_param_spec_string("accel-string", + P_("Accelerator String"), + P_("The accelerator string to be displayed"), NULL, G_PARAM_READWRITE)); +} + +GtkWidget *gtk_menu_item_new_gschem(const char *label, const char *accel_label) +{ + GtkWidget *w = gtk_menu_item_new(); + GschemAccelLabel *al = g_object_new (GSCHEM_TYPE_ACCEL_LABEL, + "use-underline", TRUE, + "xalign", 0.0, + "visible", TRUE, + "label", label, + "accel-string", accel_label, + NULL); + gtk_container_add(GTK_CONTAINER(w), GTK_WIDGET(al)); + return w; +} Index: trunk/src_plugins/hid_gtk/gschem_accel_label.h =================================================================== --- trunk/src_plugins/hid_gtk/gschem_accel_label.h (nonexistent) +++ trunk/src_plugins/hid_gtk/gschem_accel_label.h (revision 1559) @@ -0,0 +1,77 @@ +/* gEDA - GPL Electronic Design Automation + * gschem - gEDA Schematic Capture + * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) + * + * Code based on GTK 2.14.5 gtk/gtkaccellabel.h (LGPL) + * + * GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * GschemAccelLabel: GtkLabel with accelerator monitoring facilities. + * Copyright (C) 1998 Tim Janik + * + * Modified by the GTK+ Team and others 1997-2001. See the AUTHORS + * file for a list of people on the GTK+ Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GTK+ at ftp://ftp.gtk.org/pub/gtk/. + * + * Adapted for gEDA by Peter Clifton + * + * THIS FILE IS LGPL LICENSED, gEDA AS A WHOLE IS GPL LICENSED + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __GSCHEM_ACCEL_LABEL_H__ +#define __GSCHEM_ACCEL_LABEL_H__ + +G_BEGIN_DECLS +#define GSCHEM_TYPE_ACCEL_LABEL (gschem_accel_label_get_type ()) +#define GSCHEM_ACCEL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GSCHEM_TYPE_ACCEL_LABEL, GschemAccelLabel)) +#define GSCHEM_ACCEL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GSCHEM_TYPE_ACCEL_LABEL, GschemAccelLabelClass)) +#define GSCHEM_IS_ACCEL_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GSCHEM_TYPE_ACCEL_LABEL)) +#define GSCHEM_IS_ACCEL_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GSCHEM_TYPE_ACCEL_LABEL)) +#define GSCHEM_ACCEL_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GSCHEM_TYPE_ACCEL_LABEL, GschemAccelLabelClass)) +typedef struct _GschemAccelLabel GschemAccelLabel; +typedef struct _GschemAccelLabelClass GschemAccelLabelClass; + +struct _GschemAccelLabel { + GtkAccelLabel label; + + guint accel_padding; + gchar *accel_string; + guint16 accel_string_width; +}; + +struct _GschemAccelLabelClass { + GtkAccelLabelClass parent_class; +}; + + +GType gschem_accel_label_get_type(void) G_GNUC_CONST; +GtkWidget *gschem_accel_label_new(const gchar * string); +guint gschem_accel_label_get_accel_width(GschemAccelLabel * accel_label); +void gschem_accel_label_set_accel_string(GschemAccelLabel * accel_label, const gchar * accel_string); +gboolean gschem_accel_label_refetch(GschemAccelLabel * accel_label); + +/* Helper: create a new menu item with label and accel label set up */ +GtkWidget *gtk_menu_item_new_gschem(const char *label, const char *accel_label); + +/* private */ +gchar *_gschem_accel_label_class_get_accelerator_label(GschemAccelLabelClass * klass, guint accelerator_key, GdkModifierType accelerator_mods); + +G_END_DECLS +#endif /* __GSCHEM_ACCEL_LABEL_H__ */