/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
* Copyright (C) 2001 Ximian, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Authors:
* Tristan Van Berkom <tvb@gnome.org>
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
/**
* SECTION:glade-editor-property
* @Short_Description: A generic widget to edit a #GladeProperty.
*
* The #GladeEditorProperty is a factory that will create the correct
* control for the #GladePropertyClass it was created for and provides
* a simple unified api to them.
*/
#include <stdio.h>
#include <string.h>
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "glade.h"
#include "glade-widget.h"
#include "glade-editor-property.h"
#include "glade-property.h"
#include "glade-command.h"
#include "glade-project.h"
#include "glade-builtins.h"
#include "glade-marshallers.h"
#include "glade-named-icon-chooser-dialog.h"
enum {
PROP_0,
PROP_PROPERTY_CLASS,
PROP_USE_COMMAND,
PROP_SHOW_INFO
};
enum {
GTK_DOC_SEARCH,
LAST_SIGNAL
};
static GtkTableClass *table_class;
static GladeEditorPropertyClass *editor_property_class;
static guint glade_editor_property_signals[LAST_SIGNAL] = { 0 };
#define GLADE_PROPERTY_TABLE_ROW_SPACING 2
#define FLAGS_COLUMN_SETTING 0
#define FLAGS_COLUMN_SYMBOL 1
/*******************************************************************************
Boiler plate macros (inspired from glade-command.c)
*******************************************************************************/
#define MAKE_TYPE(func, type, parent) \
GType \
func ## _get_type (void) \
{ \
static GType cmd_type = 0; \
\
if (!cmd_type) \
{ \
static const GTypeInfo info = \
{ \
sizeof (type ## Class), \
(GBaseInitFunc) NULL, \
(GBaseFinalizeFunc) NULL, \
(GClassInitFunc) func ## _class_init, \
(GClassFinalizeFunc) NULL, \
NULL, \
sizeof (type), \
0, \
(GInstanceInitFunc) NULL \
}; \
\
cmd_type = g_type_register_static (parent, #type, &info, 0); \
} \
\
return cmd_type; \
} \
#define GLADE_MAKE_EPROP(type, func) \
static void \
func ## _finalize (GObject *object); \
static void \
func ## _load (GladeEditorProperty *me, GladeProperty *property); \
static GtkWidget * \
func ## _create_input (GladeEditorProperty *me); \
static void \
func ## _class_init (gpointer parent_tmp, gpointer notused) \
{ \
GladeEditorPropertyClass *parent = parent_tmp; \
GObjectClass* object_class; \
object_class = G_OBJECT_CLASS (parent); \
parent->load = func ## _load; \
parent->create_input = func ## _create_input; \
object_class->finalize = func ## _finalize; \
} \
typedef struct { \
GladeEditorPropertyClass cmd; \
} type ## Class; \
static MAKE_TYPE(func, type, GLADE_TYPE_EDITOR_PROPERTY)
/*******************************************************************************
GladeEditorPropertyClass
*******************************************************************************/
/* declare this forwardly for the finalize routine */
static void glade_editor_property_load_common (GladeEditorProperty *eprop,
GladeProperty *property);
/* For use in editor implementations
*/
static void
glade_editor_property_commit (GladeEditorProperty *eprop,
GValue *value)
{
g_return_if_fail (GLADE_IS_EDITOR_PROPERTY (eprop));
if (eprop->use_command == FALSE)
glade_property_set_value (eprop->property, value);
else
glade_command_set_property_value (eprop->property, value);
/* If the value was denied by a verify function, we'll have to
* reload the real value.
*/
if (g_param_values_cmp (eprop->property->klass->pspec,
eprop->property->value, value) != 0)
GLADE_EDITOR_PROPERTY_GET_CLASS (eprop)->load (eprop, eprop->property);
}
static void
glade_editor_property_tooltip_cb (GladeProperty *property,
const gchar *tooltip,
GladeEditorProperty *eprop)
{
glade_util_widget_set_tooltip (eprop->input, tooltip);
glade_util_widget_set_tooltip (eprop->eventbox, tooltip);
}
static void
glade_eprop_label_style_update_cb (GtkWidget *label,
GtkStyle *prev,
GladeEditorProperty *eprop)
{
if (eprop->insensitive_colour)
gdk_color_free (eprop->insensitive_colour);
if (eprop->normal_colour)
gdk_color_free (eprop->normal_colour);
eprop->insensitive_colour =
gdk_color_copy (&(label->style->fg[GTK_STATE_INSENSITIVE]));
eprop->normal_colour =
gdk_color_copy (&(label->style->fg[GTK_STATE_NORMAL]));
}
static void
glade_editor_property_sensitivity_cb (GladeProperty *property,
GParamSpec *pspec,
GladeEditorProperty *eprop)
{
gboolean sensitive = glade_property_get_sensitive (eprop->property);
g_signal_handlers_block_by_func
(eprop->item_label, glade_eprop_label_style_update_cb, eprop);
gtk_widget_modify_fg
(GTK_WIDGET (eprop->item_label),
GTK_STATE_NORMAL,
sensitive ? eprop->normal_colour : eprop->insensitive_colour);
g_signal_handlers_unblock_by_func
(eprop->item_label, glade_eprop_label_style_update_cb, eprop);
if (sensitive == FALSE)
gtk_widget_set_sensitive (eprop->input, FALSE);
else if (glade_property_get_enabled (property) != FALSE)
gtk_widget_set_sensitive (eprop->input, TRUE);
if (eprop->check)
gtk_widget_set_sensitive (eprop->check, sensitive);
}
static void
glade_editor_property_value_changed_cb (GladeProperty *property,
GValue *old_value,
GValue *value,
GladeEditorProperty *eprop)
{
g_assert (eprop->property == property);
glade_editor_property_load (eprop, eprop->property);
}
static void
glade_editor_property_enabled_cb (GladeProperty *property,
GParamSpec *pspec,
GladeEditorProperty *eprop)
{
gboolean enabled;
g_assert (eprop->property == property);
if (eprop->klass->optional)
{
enabled = glade_property_get_enabled (property);
/* sensitive = enabled && */
if (enabled == FALSE)
gtk_widget_set_sensitive (eprop->input, FALSE);
else if (glade_property_get_sensitive (property))
gtk_widget_set_sensitive (eprop->input, TRUE);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (eprop->check), enabled);
}
}
static void
glade_editor_property_enabled_toggled_cb (GtkWidget *check,
GladeEditorProperty *eprop)
{
glade_property_set_enabled (eprop->property,
gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check)));
}
static void
glade_editor_property_info_clicked_cb (GtkWidget *info,
GladeEditorProperty *eprop)
{
GladeWidgetAdaptor *adaptor;
gchar *search, *book;
adaptor = glade_widget_adaptor_from_pspec (eprop->klass->pspec);
search = g_strdup_printf ("The %s property", eprop->klass->id);
g_object_get (adaptor, "book", &book, NULL);
g_signal_emit (G_OBJECT (eprop),
glade_editor_property_signals[GTK_DOC_SEARCH],
0, book,
g_type_name (eprop->klass->pspec->owner_type), search);
g_free (book);
g_free (search);
}
static GtkWidget *
glade_editor_property_create_info_button (GladeEditorProperty *eprop)
{
GtkWidget *image;
GtkWidget *button;
button = gtk_button_new ();
image = glade_util_get_devhelp_icon (GTK_ICON_SIZE_MENU);
gtk_widget_show (image);
gtk_container_add (GTK_CONTAINER (button), image);
glade_util_widget_set_tooltip (button, _("View GTK+ documentation for this property"));
return button;
}
static GObject *
glade_editor_property_constructor (GType type,
guint n_construct_properties,
GObjectConstructParam *construct_properties)
{
GObject *obj;
GladeEditorProperty *eprop;
gchar *text;
/* Invoke parent constructor (eprop->klass should be resolved by this point) . */
obj = G_OBJECT_CLASS (table_class)->constructor
(type, n_construct_properties, construct_properties);
eprop = GLADE_EDITOR_PROPERTY (obj);
/* Create label (make label visible but not the eventbox) */
text = g_strdup_printf ("%s:", eprop->klass->name);
eprop->item_label = gtk_label_new (text);
eprop->eventbox = gtk_event_box_new ();
g_free (text);
gtk_widget_show (eprop->item_label);
/* Deal with label colours */
glade_eprop_label_style_update_cb (eprop->item_label, NULL, eprop);
g_signal_connect (G_OBJECT (eprop->item_label), "style-set",
G_CALLBACK (glade_eprop_label_style_update_cb), eprop);
/* keep our own reference */
g_object_ref (G_OBJECT (eprop->eventbox));
gtk_misc_set_alignment (GTK_MISC (eprop->item_label), 1.0, 0.5);
gtk_container_add (GTK_CONTAINER (eprop->eventbox), eprop->item_label);
/* Create hbox and possibly check button
*/
if (eprop->klass->optional)
{
eprop->check = gtk_check_button_new ();
gtk_widget_show (eprop->check);
gtk_box_pack_start (GTK_BOX (eprop), eprop->check, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (eprop->check), "toggled",
G_CALLBACK (glade_editor_property_enabled_toggled_cb), eprop);
}
/* Create the class specific input widget and add it */
eprop->input = GLADE_EDITOR_PROPERTY_GET_CLASS (eprop)->create_input (eprop);
gtk_widget_show (eprop->input);
gtk_box_pack_start (GTK_BOX (eprop), eprop->input, TRUE, TRUE, 0);
/* Create the informational button and add it */
eprop->info = glade_editor_property_create_info_button (eprop);
g_signal_connect (G_OBJECT (eprop->info), "clicked",
G_CALLBACK (glade_editor_property_info_clicked_cb), eprop);
gtk_box_pack_start (GTK_BOX (eprop), eprop->info, FALSE, FALSE, 2);
return obj;
}
static void
glade_editor_property_finalize (GObject *object)
{
GladeEditorProperty *eprop = GLADE_EDITOR_PROPERTY (object);
/* detatch from loaded property */
glade_editor_property_load_common (eprop, NULL);
if (eprop->insensitive_colour)
gdk_color_free (eprop->insensitive_colour);
if (eprop->normal_colour)
gdk_color_free (eprop->normal_colour);
G_OBJECT_CLASS (table_class)->finalize (object);
}
static void
glade_editor_property_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GladeEditorProperty *eprop = GLADE_EDITOR_PROPERTY (object);
switch (prop_id)
{
case PROP_PROPERTY_CLASS:
eprop->klass = g_value_get_pointer (value);
break;
case PROP_USE_COMMAND:
eprop->use_command = g_value_get_boolean (value);
break;
case PROP_SHOW_INFO:
if (g_value_get_boolean (value))
glade_editor_property_show_info (eprop);
else
glade_editor_property_hide_info (eprop);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
glade_editor_property_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GladeEditorProperty *eprop = GLADE_EDITOR_PROPERTY (object);
switch (prop_id)
{
case PROP_PROPERTY_CLASS:
g_value_set_pointer (value, eprop->klass);
break;
case PROP_USE_COMMAND:
g_value_set_boolean (value, eprop->use_command);
break;
case PROP_SHOW_INFO:
g_value_set_boolean (value, eprop->show_info);
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
glade_eprop_property_finalized (GladeEditorProperty *eprop,
GladeProperty *where_property_was)
{
eprop->tooltip_id = 0;
eprop->sensitive_id = 0;
eprop->changed_id = 0;
eprop->enabled_id = 0;
eprop->property = NULL;
glade_editor_property_load (eprop, NULL);
}
static void
glade_editor_property_load_common (GladeEditorProperty *eprop,
GladeProperty *property)
{
/* Hide properties that are removed for some particular widgets.
*/
if (property)
{
gtk_widget_show (GTK_WIDGET (eprop));
gtk_widget_show (eprop->eventbox);
}
else
{
gtk_widget_hide (GTK_WIDGET (eprop));
gtk_widget_hide (eprop->eventbox);
}
/* disconnect anything from previously loaded property */
if (eprop->property != property && eprop->property != NULL)
{
if (eprop->tooltip_id > 0)
g_signal_handler_disconnect (eprop->property,
eprop->tooltip_id);
if (eprop->sensitive_id > 0)
g_signal_handler_disconnect (eprop->property,
eprop->sensitive_id);
if (eprop->changed_id > 0)
g_signal_handler_disconnect (eprop->property,
eprop->changed_id);
if (eprop->enabled_id > 0)
g_signal_handler_disconnect (eprop->property,
eprop->enabled_id);
eprop->tooltip_id = 0;
eprop->sensitive_id = 0;
eprop->changed_id = 0;
eprop->enabled_id = 0;
/* Unref it here */
g_object_weak_unref (G_OBJECT (eprop->property),
(GWeakNotify)glade_eprop_property_finalized,
eprop);
/* For a reason I cant quite tell yet, this is the only
* safe way to nullify the property member of the eprop
* without leeking signal connections to properties :-/
*/
if (property == NULL)
{
eprop->property = NULL;
}
}
/* Connect new stuff, deal with tooltip
*/
if (eprop->property != property && property != NULL)
{
eprop->property = property;
eprop->tooltip_id =
g_signal_connect (G_OBJECT (eprop->property),
"tooltip-changed",
G_CALLBACK (glade_editor_property_tooltip_cb),
eprop);
eprop->sensitive_id =
g_signal_connect (G_OBJECT (eprop->property),
"notify::sensitive",
G_CALLBACK (glade_editor_property_sensitivity_cb),
eprop);
eprop->changed_id =
g_signal_connect (G_OBJECT (eprop->property),
"value-changed",
G_CALLBACK (glade_editor_property_value_changed_cb),
eprop);
eprop->enabled_id =
g_signal_connect (G_OBJECT (eprop->property),
"notify::enabled",
G_CALLBACK (glade_editor_property_enabled_cb),
eprop);
/* In query dialogs when the user hits cancel,
* these babies go away (so better stay protected).
*/
g_object_weak_ref (G_OBJECT (eprop->property),
(GWeakNotify)glade_eprop_property_finalized,
eprop);
/* Load initial tooltips
*/
glade_editor_property_tooltip_cb
(property, glade_property_get_tooltip (property), eprop);
/* Load initial enabled state
*/
glade_editor_property_enabled_cb (property, NULL, eprop);
/* Load initial sensitive state.
*/
glade_editor_property_sensitivity_cb (property, NULL, eprop);
}
}
static void
glade_editor_property_init (GladeEditorProperty *eprop)
{
}
static void
glade_editor_property_class_init (GladeEditorPropertyClass *eprop_class)
{
GObjectClass *object_class;
g_return_if_fail (eprop_class != NULL);
/* Both parent classes assigned here.
*/
editor_property_class = eprop_class;
table_class = g_type_class_peek_parent (eprop_class);
object_class = G_OBJECT_CLASS (eprop_class);
/* GObjectClass */
object_class->constructor = glade_editor_property_constructor;
object_class->finalize = glade_editor_property_finalize;
object_class->get_property = glade_editor_property_get_property;
object_class->set_property = glade_editor_property_set_property;
/* Class methods */
eprop_class->load = glade_editor_property_load_common;
eprop_class->create_input = NULL;
/**
* GladeEditorProperty::gtk-doc-search:
* @gladeeditor: the #GladeEditorProperty which received the signal.
* @arg1: the (#gchar *) book to search or %NULL
* @arg2: the (#gchar *) page to search or %NULL
* @arg3: the (#gchar *) search string or %NULL
*
* Emitted when the editor property requests that a doc-search be performed.
*/
glade_editor_property_signals[GTK_DOC_SEARCH] =
g_signal_new ("gtk-doc-search",
G_TYPE_FROM_CLASS (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GladeEditorPropertyClass,
gtk_doc_search),
NULL, NULL,
glade_marshal_VOID__STRING_STRING_STRING,
G_TYPE_NONE, 3,
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
/* Properties */
g_object_class_install_property
(object_class, PROP_PROPERTY_CLASS,
g_param_spec_pointer
("property-class", _("Property Class"),
_("The GladePropertyClass this GladeEditorProperty was created for"),
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property
(object_class, PROP_USE_COMMAND,
g_param_spec_boolean
("use-command", _("Use Command"),
_("Whether we should use the command API for the undo/redo stack"),
FALSE, G_PARAM_READWRITE));
g_object_class_install_property
(object_class, PROP_SHOW_INFO,
g_param_spec_boolean
("show-info", _("Show Info"),
_("Whether we should show an informational button"),
FALSE, G_PARAM_READWRITE));
}
GType
glade_editor_property_get_type (void)
{
static GType property_type = 0;
if (!property_type)
{
static const GTypeInfo property_info =
{
sizeof (GladeEditorPropertyClass),
(GBaseInitFunc) NULL,
(GBaseFinalizeFunc) NULL,
(GClassInitFunc) glade_editor_property_class_init,
(GClassFinalizeFunc) NULL,
NULL, /* class_data */
sizeof (GladeEditorProperty),
0, /* n_preallocs */
(GInstanceInitFunc) glade_editor_property_init,
};
property_type =
g_type_register_static (GTK_TYPE_HBOX,
"GladeEditorProperty",
&property_info, 0);
}
return property_type;
}
/*******************************************************************************
GladeEditorPropertyNumericClass
*******************************************************************************/
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *spin;
} GladeEPropNumeric;
GLADE_MAKE_EPROP (GladeEPropNumeric, glade_eprop_numeric)
#define GLADE_TYPE_EPROP_NUMERIC (glade_eprop_numeric_get_type())
#define GLADE_EPROP_NUMERIC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_NUMERIC, GladeEPropNumeric))
#define GLADE_EPROP_NUMERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_NUMERIC, GladeEPropNumericClass))
#define GLADE_IS_EPROP_NUMERIC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_NUMERIC))
#define GLADE_IS_EPROP_NUMERIC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_NUMERIC))
#define GLADE_EPROP_NUMERIC_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_NUMERIC, GladeEPropNumericClass))
static void
glade_eprop_numeric_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static void
glade_eprop_numeric_load (GladeEditorProperty *eprop, GladeProperty *property)
{
gfloat val = 0.0F;
GladeEPropNumeric *eprop_numeric = GLADE_EPROP_NUMERIC (eprop);
/* Chain up first */
editor_property_class->load (eprop, property);
if (property)
{
if (G_IS_PARAM_SPEC_INT(eprop->klass->pspec))
val = (gfloat) g_value_get_int (property->value);
else if (G_IS_PARAM_SPEC_UINT(eprop->klass->pspec))
val = (gfloat) g_value_get_uint (property->value);
else if (G_IS_PARAM_SPEC_LONG(eprop->klass->pspec))
val = (gfloat) g_value_get_long (property->value);
else if (G_IS_PARAM_SPEC_ULONG(eprop->klass->pspec))
val = (gfloat) g_value_get_ulong (property->value);
else if (G_IS_PARAM_SPEC_INT64(eprop->klass->pspec))
val = (gfloat) g_value_get_int64 (property->value);
else if (G_IS_PARAM_SPEC_UINT64(eprop->klass->pspec))
val = (gfloat) g_value_get_uint64 (property->value);
else if (G_IS_PARAM_SPEC_DOUBLE(eprop->klass->pspec))
val = (gfloat) g_value_get_double (property->value);
else if (G_IS_PARAM_SPEC_FLOAT(eprop->klass->pspec))
val = g_value_get_float (property->value);
else
g_warning ("Unsupported type %s\n",
g_type_name(G_PARAM_SPEC_TYPE (eprop->klass->pspec)));
gtk_spin_button_set_value (GTK_SPIN_BUTTON (eprop_numeric->spin), val);
}
}
static void
glade_eprop_numeric_changed (GtkWidget *spin,
GladeEditorProperty *eprop)
{
GValue val = { 0, };
if (eprop->loading) return;
g_value_init (&val, eprop->klass->pspec->value_type);
if (G_IS_PARAM_SPEC_INT(eprop->klass->pspec))
g_value_set_int (&val, gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON (spin)));
else if (G_IS_PARAM_SPEC_UINT(eprop->klass->pspec))
g_value_set_uint (&val, gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON (spin)));
else if (G_IS_PARAM_SPEC_LONG(eprop->klass->pspec))
g_value_set_long (&val, (glong)gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON (spin)));
else if (G_IS_PARAM_SPEC_ULONG(eprop->klass->pspec))
g_value_set_ulong (&val, (gulong)gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON (spin)));
else if (G_IS_PARAM_SPEC_INT64(eprop->klass->pspec))
g_value_set_int64 (&val, (gint64)gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON (spin)));
else if (G_IS_PARAM_SPEC_UINT64(eprop->klass->pspec))
g_value_set_uint64 (&val, (guint64)gtk_spin_button_get_value_as_int
(GTK_SPIN_BUTTON (spin)));
else if (G_IS_PARAM_SPEC_FLOAT(eprop->klass->pspec))
g_value_set_float (&val, (gfloat) gtk_spin_button_get_value
(GTK_SPIN_BUTTON (spin)));
else if (G_IS_PARAM_SPEC_DOUBLE(eprop->klass->pspec))
g_value_set_double (&val, gtk_spin_button_get_value
(GTK_SPIN_BUTTON (spin)));
else
g_warning ("Unsupported type %s\n",
g_type_name(G_PARAM_SPEC_TYPE (eprop->klass->pspec)));
glade_editor_property_commit (eprop, &val);
g_value_unset (&val);
}
static GtkWidget *
glade_eprop_numeric_create_input (GladeEditorProperty *eprop)
{
GladeEPropNumeric *eprop_numeric = GLADE_EPROP_NUMERIC (eprop);
GtkAdjustment *adjustment;
adjustment = glade_property_class_make_adjustment (eprop->klass);
eprop_numeric->spin = gtk_spin_button_new (adjustment, 4,
G_IS_PARAM_SPEC_FLOAT (eprop->klass->pspec) ||
G_IS_PARAM_SPEC_DOUBLE (eprop->klass->pspec)
? 2 : 0);
gtk_widget_show (eprop_numeric->spin);
g_signal_connect (G_OBJECT (eprop_numeric->spin), "value_changed",
G_CALLBACK (glade_eprop_numeric_changed),
eprop);
return eprop_numeric->spin;
}
/*******************************************************************************
GladeEditorPropertyEnumClass
*******************************************************************************/
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *option_menu;
} GladeEPropEnum;
GLADE_MAKE_EPROP (GladeEPropEnum, glade_eprop_enum)
#define GLADE_TYPE_EPROP_ENUM (glade_eprop_enum_get_type())
#define GLADE_EPROP_ENUM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_ENUM, GladeEPropEnum))
#define GLADE_EPROP_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_ENUM, GladeEPropEnumClass))
#define GLADE_IS_EPROP_ENUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_ENUM))
#define GLADE_IS_EPROP_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_ENUM))
#define GLADE_EPROP_ENUM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_ENUM, GladeEPropEnumClass))
static void
glade_eprop_enum_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static void
glade_eprop_enum_load (GladeEditorProperty *eprop, GladeProperty *property)
{
GladeEPropEnum *eprop_enum = GLADE_EPROP_ENUM (eprop);
GEnumClass *eclass;
guint i;
gint value;
/* Chain up first */
editor_property_class->load (eprop, property);
if (property)
{
eclass = g_type_class_ref (eprop->klass->pspec->value_type);
value = g_value_get_enum (property->value);
for (i = 0; i < eclass->n_values; i++)
if (eclass->values[i].value == value)
break;
gtk_option_menu_set_history (GTK_OPTION_MENU (eprop_enum->option_menu),
i < eclass->n_values ? i : 0);
g_type_class_unref (eclass);
}
}
static void
glade_eprop_enum_changed (GtkWidget *menu_item,
GladeEditorProperty *eprop)
{
gint ival;
GValue val = { 0, };
GladeProperty *property;
if (eprop->loading) return;
ival = GPOINTER_TO_INT(g_object_get_data (G_OBJECT (menu_item), GLADE_ENUM_DATA_TAG));
property = eprop->property;
g_value_init (&val, eprop->klass->pspec->value_type);
g_value_set_enum (&val, ival);
glade_editor_property_commit (eprop, &val);
g_value_unset (&val);
}
static GtkWidget *
glade_editor_create_input_enum_item (GladeEditorProperty *eprop,
const gchar *name,
gint value)
{
GtkWidget *menu_item;
menu_item = gtk_menu_item_new_with_label (name);
g_signal_connect (G_OBJECT (menu_item), "activate",
G_CALLBACK (glade_eprop_enum_changed),
eprop);
g_object_set_data (G_OBJECT (menu_item), GLADE_ENUM_DATA_TAG, GINT_TO_POINTER(value));
return menu_item;
}
static GtkWidget *
glade_editor_create_input_stock_item (GladeEditorProperty *eprop,
const gchar *id,
gint value)
{
GtkWidget *menu_item = gtk_image_menu_item_new_from_stock (id, NULL);
g_signal_connect (G_OBJECT (menu_item), "activate",
G_CALLBACK (glade_eprop_enum_changed),
eprop);
g_object_set_data (G_OBJECT (menu_item), GLADE_ENUM_DATA_TAG, GINT_TO_POINTER(value));
return menu_item;
}
static GtkWidget *
glade_eprop_enum_create_input (GladeEditorProperty *eprop)
{
GladeEPropEnum *eprop_enum = GLADE_EPROP_ENUM (eprop);
GtkWidget *menu_item, *menu;
GladePropertyClass *klass;
GEnumClass *eclass;
gboolean stock;
guint i;
klass = eprop->klass;
eclass = g_type_class_ref (klass->pspec->value_type);
stock = (klass->pspec->value_type == GLADE_TYPE_STOCK) ||
(klass->pspec->value_type == GLADE_TYPE_STOCK_IMAGE);
menu = gtk_menu_new ();
for (i = 0; i < eclass->n_values; i++)
{
const gchar *value_name =
glade_property_class_get_displayable_value
(klass, eclass->values[i].value);
if (value_name == NULL) value_name = eclass->values[i].value_name;
if (stock && strcmp (eclass->values[i].value_nick, "glade-none"))
menu_item = glade_editor_create_input_stock_item
(eprop,
eclass->values[i].value_nick,
eclass->values[i].value);
else
menu_item = glade_editor_create_input_enum_item
(eprop, value_name, eclass->values[i].value);
gtk_widget_show (menu_item);
gtk_menu_shell_append (GTK_MENU_SHELL (menu), menu_item);
}
eprop_enum->option_menu = gtk_option_menu_new ();
gtk_option_menu_set_menu (GTK_OPTION_MENU (eprop_enum->option_menu), menu);
gtk_widget_show_all (eprop_enum->option_menu);
g_type_class_unref (eclass);
return eprop_enum->option_menu;
}
/*******************************************************************************
GladeEditorPropertyFlagsClass
*******************************************************************************/
typedef struct {
GladeEditorProperty parent_instance;
GtkTreeModel *model;
GtkWidget *entry;
} GladeEPropFlags;
GLADE_MAKE_EPROP (GladeEPropFlags, glade_eprop_flags)
#define GLADE_TYPE_EPROP_FLAGS (glade_eprop_flags_get_type())
#define GLADE_EPROP_FLAGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_FLAGS, GladeEPropFlags))
#define GLADE_EPROP_FLAGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_FLAGS, GladeEPropFlagsClass))
#define GLADE_IS_EPROP_FLAGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_FLAGS))
#define GLADE_IS_EPROP_FLAGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_FLAGS))
#define GLADE_EPROP_FLAGS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_FLAGS, GladeEPropFlagsClass))
static void
glade_eprop_flags_finalize (GObject *object)
{
GladeEPropFlags *eprop_flags = GLADE_EPROP_FLAGS(object);
g_object_unref (G_OBJECT (eprop_flags->model));
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static void
glade_eprop_flags_load (GladeEditorProperty *eprop, GladeProperty *property)
{
GladeEPropFlags *eprop_flags = GLADE_EPROP_FLAGS (eprop);
GFlagsClass *klass;
guint flag_num, value;
GString *string = g_string_new (NULL);
/* Chain up first */
editor_property_class->load (eprop, property);
gtk_list_store_clear(GTK_LIST_STORE(eprop_flags->model));
if (property)
{
/* Populate the model with the flags. */
klass = g_type_class_ref (G_VALUE_TYPE (property->value));
value = g_value_get_flags (property->value);
/* Step through each of the flags in the class. */
for (flag_num = 0; flag_num < klass->n_values; flag_num++) {
GtkTreeIter iter;
guint mask;
gboolean setting;
const gchar *value_name;
mask = klass->values[flag_num].value;
setting = ((value & mask) == mask) ? TRUE : FALSE;
value_name = glade_property_class_get_displayable_value
(eprop->klass, klass->values[flag_num].value);
if (value_name == NULL) value_name = klass->values[flag_num].value_name;
/* Setup string for property label */
if (setting)
{
if (string->len > 0)
g_string_append (string, " | ");
g_string_append (string, value_name);
}
/* Add a row to represent the flag. */
gtk_list_store_append (GTK_LIST_STORE(eprop_flags->model), &iter);
gtk_list_store_set (GTK_LIST_STORE(eprop_flags->model), &iter,
FLAGS_COLUMN_SETTING,
setting,
FLAGS_COLUMN_SYMBOL,
value_name,
-1);
}
g_type_class_unref(klass);
}
gtk_entry_set_text (GTK_ENTRY (eprop_flags->entry), string->str);
g_string_free (string, TRUE);
}
static void
flag_toggled_direct (GtkCellRendererToggle *cell,
gchar *path_string,
GladeEditorProperty *eprop)
{
GtkTreeIter iter;
guint new_value = 0;
gboolean selected;
guint value = 0;
gint flag_num = 0;
GFlagsClass *klass;
GladeEPropFlags *eprop_flags = GLADE_EPROP_FLAGS(eprop);
if (!eprop->property)
return ;
klass = g_type_class_ref (G_VALUE_TYPE (eprop->property->value));
value = g_value_get_flags (eprop->property->value);
gtk_tree_model_get_iter_from_string (eprop_flags->model, &iter, path_string);
gtk_tree_model_get (eprop_flags->model, &iter,
FLAGS_COLUMN_SETTING, &selected,
-1);
selected = selected ? FALSE : TRUE;
gtk_list_store_set (GTK_LIST_STORE (eprop_flags->model), &iter,
FLAGS_COLUMN_SETTING, selected,
-1);
gtk_tree_model_get_iter_first (GTK_TREE_MODEL (eprop_flags->model), &iter);
/* Step through each of the flags in the class, checking if
the corresponding toggle in the dialog is selected, If it
is, OR the flags' mask with the new value. */
for (flag_num = 0; flag_num < klass->n_values; flag_num++) {
gboolean setting;
gtk_tree_model_get (GTK_TREE_MODEL (eprop_flags->model), &iter,
FLAGS_COLUMN_SETTING, &setting,
-1);
if (setting)
new_value |= klass->values[flag_num].value;
gtk_tree_model_iter_next (GTK_TREE_MODEL (eprop_flags->model),
&iter);
}
/* If the new_value is different from the old value, we need
to update the property. */
if (new_value != value) {
GValue val = { 0, };
g_value_init (&val, G_VALUE_TYPE (eprop->property->value));
g_value_set_flags (&val, new_value);
glade_editor_property_commit (eprop, &val);
g_value_unset (&val);
}
}
static GtkWidget*
glade_eprop_flags_create_treeview(GladeEditorProperty *eprop)
{
GtkWidget *scrolled_window;
GtkWidget *tree_view;
GtkTreeViewColumn *column;
GtkCellRenderer *renderer;
GladeEPropFlags *eprop_flags=GLADE_EPROP_FLAGS(eprop);
if (!eprop_flags->model)
eprop_flags->model = GTK_TREE_MODEL(gtk_list_store_new (2, G_TYPE_BOOLEAN,
G_TYPE_STRING));
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_SHADOW_IN);
gtk_widget_show (scrolled_window);
tree_view = gtk_tree_view_new_with_model (GTK_TREE_MODEL (eprop_flags->model));
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
gtk_widget_show (tree_view);
gtk_container_add (GTK_CONTAINER (scrolled_window), tree_view);
column = gtk_tree_view_column_new ();
renderer = gtk_cell_renderer_toggle_new ();
gtk_tree_view_column_pack_start (column, renderer, FALSE);
gtk_tree_view_column_set_attributes (column, renderer,
"active", FLAGS_COLUMN_SETTING,
NULL);
g_signal_connect (renderer, "toggled",
G_CALLBACK (flag_toggled_direct), eprop);
renderer = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (column, renderer, TRUE);
gtk_tree_view_column_set_attributes (column, renderer,
"text", FLAGS_COLUMN_SYMBOL,
NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
return scrolled_window;
}
static void
glade_eprop_flags_show_dialog (GtkWidget *button,
GladeEditorProperty *eprop)
{
GtkWidget *dialog;
GtkWidget *view;
GtkWidget *label;
GtkWidget *vbox;
dialog = gtk_dialog_new_with_buttons (_("Select Fields"),
GTK_WINDOW (gtk_widget_get_toplevel (button)),
GTK_DIALOG_MODAL,
GTK_STOCK_CLOSE,
GTK_RESPONSE_CLOSE,
NULL);
gtk_window_set_default_size (GTK_WINDOW (dialog), 300, 400);
gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_CLOSE);
/* HIG spacings */
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2); /* 2 * 5 + 2 = 12 */
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 5);
gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->action_area), 6);
vbox = gtk_vbox_new (FALSE, 6);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
view = glade_eprop_flags_create_treeview (eprop);
label = gtk_label_new_with_mnemonic (_("_Select individual fields:"));
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), gtk_bin_get_child (GTK_BIN (view)));
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), view, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, TRUE, TRUE, 0);
gtk_widget_show (label);
gtk_widget_show (view);
gtk_widget_show (vbox);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
}
static GtkWidget *
glade_eprop_flags_create_input (GladeEditorProperty *eprop)
{
GtkWidget *vbox, *hbox, *button, *widget;
GladeEPropFlags *eprop_flags = GLADE_EPROP_FLAGS(eprop);
hbox = gtk_hbox_new (FALSE, 0);
vbox = gtk_vbox_new (FALSE, 0);
widget = glade_eprop_flags_create_treeview (eprop);
eprop_flags->entry = gtk_entry_new ();
gtk_entry_set_editable (GTK_ENTRY (eprop_flags->entry), FALSE);
gtk_box_pack_start (GTK_BOX (vbox), eprop_flags->entry, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (vbox), widget, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), vbox, TRUE, TRUE, 0);
button = gtk_button_new_with_label ("...");
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show_all (hbox);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (glade_eprop_flags_show_dialog),
eprop);
return hbox;
}
/*******************************************************************************
GladeEditorPropertyColorClass
*******************************************************************************/
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *cbutton;
GtkWidget *entry;
} GladeEPropColor;
GLADE_MAKE_EPROP (GladeEPropColor, glade_eprop_color)
#define GLADE_TYPE_EPROP_COLOR (glade_eprop_color_get_type())
#define GLADE_EPROP_COLOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_COLOR, GladeEPropColor))
#define GLADE_EPROP_COLOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_COLOR, GladeEPropColorClass))
#define GLADE_IS_EPROP_COLOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_COLOR))
#define GLADE_IS_EPROP_COLOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_COLOR))
#define GLADE_EPROP_COLOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_COLOR, GladeEPropColorClass))
static void
glade_eprop_color_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static void
glade_eprop_color_load (GladeEditorProperty *eprop, GladeProperty *property)
{
GladeEPropColor *eprop_color = GLADE_EPROP_COLOR (eprop);
GdkColor *color;
gchar *text;
/* Chain up first */
editor_property_class->load (eprop, property);
if (property)
{
if ((text = glade_property_class_make_string_from_gvalue
(eprop->klass, property->value)) != NULL)
{
gtk_entry_set_text (GTK_ENTRY (eprop_color->entry), text);
g_free (text);
}
else
gtk_entry_set_text (GTK_ENTRY (eprop_color->entry), "");
if ((color = g_value_get_boxed (property->value)) != NULL)
gtk_color_button_set_color (GTK_COLOR_BUTTON (eprop_color->cbutton),
color);
else
{
GdkColor black = { 0, };
/* Manually fill it with black for an NULL value.
*/
if (gdk_color_parse("Black", &black) &&
gdk_colormap_alloc_color(gtk_widget_get_default_colormap(),
&black, FALSE, TRUE))
gtk_color_button_set_color
(GTK_COLOR_BUTTON (eprop_color->cbutton),
&black);
}
}
}
static void
glade_eprop_color_changed (GtkWidget *button,
GladeEditorProperty *eprop)
{
GdkColor color = { 0, };
GValue value = { 0, };
if (eprop->loading) return;
gtk_color_button_get_color (GTK_COLOR_BUTTON (button), &color);
g_value_init (&value, GDK_TYPE_COLOR);
g_value_set_boxed (&value, &color);
glade_editor_property_commit (eprop, &value);
g_value_unset (&value);
}
static GtkWidget *
glade_eprop_color_create_input (GladeEditorProperty *eprop)
{
GladeEPropColor *eprop_color = GLADE_EPROP_COLOR (eprop);
GtkWidget *hbox;
hbox = gtk_hbox_new (FALSE, 0);
eprop_color->entry = gtk_entry_new ();
gtk_entry_set_editable (GTK_ENTRY (eprop_color->entry), FALSE);
gtk_widget_show (eprop_color->entry);
gtk_box_pack_start (GTK_BOX (hbox), eprop_color->entry, TRUE, TRUE, 0);
eprop_color->cbutton = gtk_color_button_new ();
gtk_widget_show (eprop_color->cbutton);
gtk_box_pack_start (GTK_BOX (hbox), eprop_color->cbutton, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (eprop_color->cbutton), "color-set",
G_CALLBACK (glade_eprop_color_changed),
eprop);
return hbox;
}
/*******************************************************************************
GladeEditorPropertyNamedIconClass
*******************************************************************************/
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *entry;
gchar *current_context;
} GladeEPropNamedIcon;
GLADE_MAKE_EPROP (GladeEPropNamedIcon, glade_eprop_named_icon)
#define GLADE_TYPE_EPROP_NAMED_ICON (glade_eprop_named_icon_get_type())
#define GLADE_EPROP_NAMED_ICON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_NAMED_ICON, GladeEPropNamedIcon))
#define GLADE_EPROP_NAMED_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_NAMED_ICON, GladeEPropNamedIconClass))
#define GLADE_IS_EPROP_NAMED_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_NAMED_ICON))
#define GLADE_IS_EPROP_NAMED_ICON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_NAMED_ICON))
#define GLADE_EPROP_NAMED_ICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_NAMED_ICON, GladeEPropNamedIconClass))
static void
glade_eprop_named_icon_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static void
glade_eprop_named_icon_load (GladeEditorProperty *eprop,
GladeProperty *property)
{
GladeEPropNamedIcon *eprop_named_icon = GLADE_EPROP_NAMED_ICON (eprop);
GtkEntry *entry;
const gchar *text;
/* Chain up first */
editor_property_class->load (eprop, property);
if (property == NULL)
return;
entry = GTK_ENTRY (eprop_named_icon->entry);
text = g_value_get_string (property->value);
gtk_entry_set_text (entry, text ? text : "");
}
static void
glade_eprop_named_icon_changed_common (GladeEditorProperty *eprop,
const gchar *text,
gboolean use_command)
{
GValue *val;
gchar *prop_text;
val = g_new0 (GValue, 1);
g_value_init (val, G_TYPE_STRING);
glade_property_get (eprop->property, &prop_text);
/* Here we try not to modify the project state by not
* modifying a null value for an unchanged property.
*/
if (prop_text == NULL &&
text && text[0] == '\0')
g_value_set_string (val, NULL);
else if (text == NULL &&
prop_text && prop_text == '\0')
g_value_set_string (val, "");
else
g_value_set_string (val, text);
glade_editor_property_commit (eprop, val);
g_value_unset (val);
g_free (val);
}
static void
glade_eprop_named_icon_changed (GtkWidget *entry,
GladeEditorProperty *eprop)
{
gchar *text;
if (eprop->loading)
return;
text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
glade_eprop_named_icon_changed_common (eprop, text, eprop->use_command);
g_free (text);
}
static gboolean
glade_eprop_named_icon_focus_out (GtkWidget *entry,
GdkEventFocus *event,
GladeEditorProperty *eprop)
{
glade_eprop_named_icon_changed (entry, eprop);
return FALSE;
}
static void
glade_eprop_named_icon_activate (GtkEntry *entry,
GladeEPropNamedIcon *eprop)
{
glade_eprop_named_icon_changed (GTK_WIDGET (entry), GLADE_EDITOR_PROPERTY (eprop));
}
static void
chooser_response (GladeNamedIconChooserDialog *dialog,
gint response_id,
GladeEPropNamedIcon *eprop)
{
gchar *icon_name;
switch (response_id) {
case GTK_RESPONSE_OK:
g_free (eprop->current_context);
eprop->current_context = glade_named_icon_chooser_dialog_get_context (dialog);
icon_name = glade_named_icon_chooser_dialog_get_icon_name (dialog);
gtk_entry_set_text (GTK_ENTRY (eprop->entry), icon_name);
gtk_widget_destroy (GTK_WIDGET (dialog));
g_free (icon_name);
glade_eprop_named_icon_changed (eprop->entry, GLADE_EDITOR_PROPERTY (eprop));
break;
case GTK_RESPONSE_CANCEL:
gtk_widget_destroy (GTK_WIDGET (dialog));
break;
case GTK_RESPONSE_HELP:
break;
case GTK_RESPONSE_DELETE_EVENT:
gtk_widget_destroy (GTK_WIDGET (dialog));
}
}
static void
glade_eprop_named_icon_show_chooser_dialog (GtkWidget *button,
GladeEditorProperty *eprop)
{
GtkWidget *dialog;
dialog = glade_named_icon_chooser_dialog_new ("Select Named Icon",
GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (eprop))),
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
glade_named_icon_chooser_dialog_set_context (GLADE_NAMED_ICON_CHOOSER_DIALOG (dialog), GLADE_EPROP_NAMED_ICON (eprop)->current_context);
glade_named_icon_chooser_dialog_set_icon_name (GLADE_NAMED_ICON_CHOOSER_DIALOG (dialog),
gtk_entry_get_text (GTK_ENTRY (GLADE_EPROP_NAMED_ICON (eprop)->entry)));
g_signal_connect (dialog, "response",
G_CALLBACK (chooser_response),
eprop);
gtk_widget_show (dialog);
}
static GtkWidget *
glade_eprop_named_icon_create_input (GladeEditorProperty *eprop)
{
GladeEPropNamedIcon *eprop_named_icon = GLADE_EPROP_NAMED_ICON (eprop);
GtkWidget *hbox;
GtkWidget *button;
hbox = gtk_hbox_new (FALSE, 0);
eprop_named_icon->entry = gtk_entry_new ();
gtk_widget_show (eprop_named_icon->entry);
eprop_named_icon->current_context = NULL;
gtk_box_pack_start (GTK_BOX (hbox), eprop_named_icon->entry, TRUE, TRUE, 0);
g_signal_connect (G_OBJECT (eprop_named_icon->entry), "activate",
G_CALLBACK (glade_eprop_named_icon_activate),
eprop);
g_signal_connect (G_OBJECT (eprop_named_icon->entry), "focus-out-event",
G_CALLBACK (glade_eprop_named_icon_focus_out),
eprop);
button = gtk_button_new_with_label ("\342\200\246");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (button, "clicked",
G_CALLBACK (glade_eprop_named_icon_show_chooser_dialog),
eprop);
return hbox;
}
/*******************************************************************************
GladeEditorPropertyTextClass
*******************************************************************************/
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *text_entry;
} GladeEPropText;
GLADE_MAKE_EPROP (GladeEPropText, glade_eprop_text)
#define GLADE_TYPE_EPROP_TEXT (glade_eprop_text_get_type())
#define GLADE_EPROP_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_TEXT, GladeEPropText))
#define GLADE_EPROP_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_TEXT, GladeEPropTextClass))
#define GLADE_IS_EPROP_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_TEXT))
#define GLADE_IS_EPROP_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_TEXT))
#define GLADE_EPROP_TEXT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_TEXT, GladeEPropTextClass))
static void
glade_eprop_text_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static void
glade_eprop_text_load (GladeEditorProperty *eprop, GladeProperty *property)
{
GladeEPropText *eprop_text = GLADE_EPROP_TEXT (eprop);
/* Chain up first */
editor_property_class->load (eprop, property);
if (property == NULL) return;
if (GTK_IS_ENTRY (eprop_text->text_entry))
{
GtkEntry *entry = GTK_ENTRY (eprop_text->text_entry);
const gchar *text = g_value_get_string (property->value);
gtk_entry_set_text (entry, text ? text : "");
}
else if (GTK_IS_TEXT_VIEW (eprop_text->text_entry))
{
GtkTextBuffer *buffer;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (eprop_text->text_entry));
if (G_VALUE_HOLDS (property->value, G_TYPE_STRV) ||
G_VALUE_HOLDS (property->value, G_TYPE_VALUE_ARRAY))
{
gchar *text = glade_property_class_make_string_from_gvalue (
property->klass, property->value);
gtk_text_buffer_set_text (buffer, text ? text : "", -1);
g_free (text);
}
else
{
const gchar *text = g_value_get_string (property->value);
gtk_text_buffer_set_text (buffer, text ? text : "", -1);
}
}
else
{
g_warning ("BUG! Invalid Text Widget type.");
}
}
static void
glade_eprop_text_changed_common (GladeEditorProperty *eprop,
const gchar *text,
gboolean use_command)
{
GValue *val;
gchar *prop_text;
if (eprop->property->klass->pspec->value_type == G_TYPE_STRV ||
eprop->property->klass->pspec->value_type == G_TYPE_VALUE_ARRAY)
{
val = glade_property_class_make_gvalue_from_string
(eprop->property->klass, text, NULL);
}
else
{
val = g_new0 (GValue, 1);
g_value_init (val, G_TYPE_STRING);
glade_property_get (eprop->property, &prop_text);
/* Here we try not to modify the project state by not
* modifying a null value for an unchanged property.
*/
if (prop_text == NULL &&
text && text[0] == '\0')
g_value_set_string (val, NULL);
else if (text == NULL &&
prop_text && prop_text == '\0')
g_value_set_string (val, "");
else
g_value_set_string (val, text);
}
glade_editor_property_commit (eprop, val);
g_value_unset (val);
g_free (val);
}
static void
glade_eprop_text_changed (GtkWidget *entry,
GladeEditorProperty *eprop)
{
gchar *text;
if (eprop->loading) return;
text = gtk_editable_get_chars (GTK_EDITABLE (entry), 0, -1);
glade_eprop_text_changed_common (eprop, text, eprop->use_command);
g_free (text);
}
static gboolean
glade_eprop_text_entry_focus_out (GtkWidget *entry,
GdkEventFocus *event,
GladeEditorProperty *eprop)
{
glade_eprop_text_changed (entry, eprop);
return FALSE;
}
static gboolean
glade_eprop_text_text_view_focus_out (GtkTextView *view,
GdkEventFocus *event,
GladeEditorProperty *eprop)
{
gchar *text;
GtkTextBuffer *buffer;
GtkTextIter start, end;
if (eprop->loading) return FALSE;
buffer = gtk_text_view_get_buffer (view);
gtk_text_buffer_get_start_iter (buffer, &start);
gtk_text_buffer_get_end_iter (buffer, &end);
text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
glade_eprop_text_changed_common (eprop, text, eprop->use_command);
g_free (text);
return FALSE;
}
static void
glade_eprop_text_show_i18n_dialog (GtkWidget *entry,
GladeEditorProperty *eprop)
{
GtkWidget *dialog;
GtkWidget *vbox, *hbox;
GtkWidget *label;
GtkWidget *sw;
GtkWidget *alignment;
GtkWidget *text_view, *comment_view;
GtkTextBuffer *text_buffer, *comment_buffer;
GtkWidget *translatable_button, *context_button;
const gchar *text;
gint res;
gchar *str;
GParamSpec *pspec;
dialog = gtk_dialog_new_with_buttons (_("Edit Text"),
GTK_WINDOW (gtk_widget_get_toplevel (entry)),
GTK_DIALOG_MODAL,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
/* HIG spacings */
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2); /* 2 * 5 + 2 = 12 */
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 5);
gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->action_area), 6);
vbox = gtk_vbox_new (FALSE, 6);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
gtk_widget_show (vbox);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, TRUE, TRUE, 0);
/* Text */
label = gtk_label_new_with_mnemonic (_("_Text:"));
gtk_widget_show (label);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_show (sw);
gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
gtk_widget_set_size_request (sw, 400, 200);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
text_view = gtk_text_view_new ();
gtk_widget_show (text_view);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), text_view);
gtk_container_add (GTK_CONTAINER (sw), text_view);
text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
text = g_value_get_string (eprop->property->value);
if (text)
{
gtk_text_buffer_set_text (text_buffer,
text,
-1);
}
/* Translatable and context prefix. */
hbox = gtk_hbox_new (FALSE, 12);
gtk_widget_show (hbox);
gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
translatable_button = gtk_check_button_new_with_mnemonic (_("T_ranslatable"));
gtk_widget_show (translatable_button);
gtk_box_pack_start (GTK_BOX (hbox), translatable_button, FALSE, FALSE, 0);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (translatable_button),
glade_property_i18n_get_translatable (eprop->property));
/* Add a cute tooltip */
if ((pspec =
g_object_class_find_property (G_OBJECT_GET_CLASS (eprop->property),
"i18n-translatable")) != NULL)
glade_util_widget_set_tooltip (translatable_button,
g_param_spec_get_blurb (pspec));
context_button = gtk_check_button_new_with_mnemonic (_("_Has context prefix"));
gtk_widget_show (context_button);
gtk_box_pack_start (GTK_BOX (hbox), context_button, FALSE, FALSE, 0);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (context_button),
glade_property_i18n_get_has_context (eprop->property));
/* Add a cute tooltip */
if ((pspec =
g_object_class_find_property (G_OBJECT_GET_CLASS (eprop->property),
"i18n-has-context")) != NULL)
glade_util_widget_set_tooltip (context_button,
g_param_spec_get_blurb (pspec));
alignment = gtk_alignment_new (0.5, 0.5, 1, 1);
gtk_alignment_set_padding (GTK_ALIGNMENT (alignment), 12, 0, 0, 0);
gtk_widget_show (alignment);
/* Comments. */
label = gtk_label_new_with_mnemonic (_("Co_mments for translators:"));
gtk_widget_show (label);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
gtk_container_add (GTK_CONTAINER (alignment), label);
gtk_box_pack_start (GTK_BOX (vbox), alignment, FALSE, FALSE, 0);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_show (sw);
gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
comment_view = gtk_text_view_new ();
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (comment_view), GTK_WRAP_WORD);
gtk_widget_show (comment_view);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), comment_view);
gtk_container_add (GTK_CONTAINER (sw), comment_view);
comment_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (comment_view));
text = glade_property_i18n_get_comment (eprop->property);
if (text)
{
gtk_text_buffer_set_text (comment_buffer,
text,
-1);
}
res = gtk_dialog_run (GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_OK) {
GtkTextIter start, end;
gboolean translatable, has_context;
/* get the new values for translatable, has_context, and comment */
translatable = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (translatable_button));
has_context = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (context_button));
gtk_text_buffer_get_bounds (comment_buffer, &start, &end);
str = gtk_text_buffer_get_text (comment_buffer, &start, &end, TRUE);
if (str[0] == '\0')
{
g_free (str);
str = NULL;
}
/* set the new i18n data via a glade command so it can be undone */
glade_command_set_i18n (eprop->property, translatable, has_context, str);
g_free (str);
/* Text */
gtk_text_buffer_get_bounds (text_buffer, &start, &end);
str = gtk_text_buffer_get_text (text_buffer, &start, &end, TRUE);
if (str[0] == '\0')
{
g_free (str);
str = NULL;
}
/* set the new text */
glade_eprop_text_changed_common (eprop, str, eprop->use_command);
g_free (str);
}
gtk_widget_destroy (dialog);
}
static GtkWidget *
glade_eprop_text_create_input (GladeEditorProperty *eprop)
{
GladeEPropText *eprop_text = GLADE_EPROP_TEXT (eprop);
GladePropertyClass *klass;
GtkWidget *hbox;
klass = eprop->klass;
hbox = gtk_hbox_new (FALSE, 0);
if (klass->visible_lines > 1 ||
klass->pspec->value_type == G_TYPE_STRV ||
klass->pspec->value_type == G_TYPE_VALUE_ARRAY)
{
GtkWidget *swindow;
swindow = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swindow),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swindow), GTK_SHADOW_IN);
eprop_text->text_entry = gtk_text_view_new ();
gtk_container_add (GTK_CONTAINER (swindow), eprop_text->text_entry);
gtk_box_pack_start (GTK_BOX (hbox), GTK_WIDGET (swindow), TRUE, TRUE, 0);
gtk_widget_show_all (swindow);
g_signal_connect (G_OBJECT (eprop_text->text_entry), "focus-out-event",
G_CALLBACK (glade_eprop_text_text_view_focus_out),
eprop);
} else {
eprop_text->text_entry = gtk_entry_new ();
gtk_widget_show (eprop_text->text_entry);
gtk_box_pack_start (GTK_BOX (hbox), eprop_text->text_entry, TRUE, TRUE, 0);
g_signal_connect (G_OBJECT (eprop_text->text_entry), "activate",
G_CALLBACK (glade_eprop_text_changed),
eprop);
g_signal_connect (G_OBJECT (eprop_text->text_entry), "focus-out-event",
G_CALLBACK (glade_eprop_text_entry_focus_out),
eprop);
}
if (klass->translatable) {
GtkWidget *button = gtk_button_new_with_label ("...");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (button, "clicked",
G_CALLBACK (glade_eprop_text_show_i18n_dialog),
eprop);
}
return hbox;
}
/*******************************************************************************
GladeEditorPropertyBoolClass
*******************************************************************************/
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *toggle;
} GladeEPropBool;
GLADE_MAKE_EPROP (GladeEPropBool, glade_eprop_bool)
#define GLADE_TYPE_EPROP_BOOL (glade_eprop_bool_get_type())
#define GLADE_EPROP_BOOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_BOOL, GladeEPropBool))
#define GLADE_EPROP_BOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_BOOL, GladeEPropBoolClass))
#define GLADE_IS_EPROP_BOOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_BOOL))
#define GLADE_IS_EPROP_BOOL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_BOOL))
#define GLADE_EPROP_BOOL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_BOOL, GladeEPropBoolClass))
static void
glade_eprop_bool_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static void
glade_eprop_bool_load (GladeEditorProperty *eprop, GladeProperty *property)
{
GladeEPropBool *eprop_bool = GLADE_EPROP_BOOL (eprop);
GtkWidget *label;
gboolean state;
/* Chain up first */
editor_property_class->load (eprop, property);
if (property)
{
state = g_value_get_boolean (property->value);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (eprop_bool->toggle), state);
label = GTK_BIN (eprop_bool->toggle)->child;
gtk_label_set_text (GTK_LABEL (label), state ? _("Yes") : _("No"));
}
}
static void
glade_eprop_bool_changed (GtkWidget *button,
GladeEditorProperty *eprop)
{
GtkWidget *label;
gboolean state;
GValue val = { 0, };
if (eprop->loading) return;
state = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
label = GTK_BIN (button)->child;
gtk_label_set_text (GTK_LABEL (label), state ? _("Yes") : _("No"));
g_value_init (&val, G_TYPE_BOOLEAN);
g_value_set_boolean (&val, state);
glade_editor_property_commit (eprop, &val);
g_value_unset (&val);
}
static GtkWidget *
glade_eprop_bool_create_input (GladeEditorProperty *eprop)
{
GladeEPropBool *eprop_bool = GLADE_EPROP_BOOL (eprop);
eprop_bool->toggle = gtk_toggle_button_new_with_label (_("No"));
g_signal_connect (G_OBJECT (eprop_bool->toggle), "toggled",
G_CALLBACK (glade_eprop_bool_changed),
eprop);
return eprop_bool->toggle;
}
/*******************************************************************************
GladeEditorPropertyUnicharClass
*******************************************************************************/
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *entry;
} GladeEPropUnichar;
GLADE_MAKE_EPROP (GladeEPropUnichar, glade_eprop_unichar)
#define GLADE_TYPE_EPROP_UNICHAR (glade_eprop_unichar_get_type())
#define GLADE_EPROP_UNICHAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_UNICHAR, GladeEPropUnichar))
#define GLADE_EPROP_UNICHAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_UNICHAR, GladeEPropUnicharClass))
#define GLADE_IS_EPROP_UNICHAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_UNICHAR))
#define GLADE_IS_EPROP_UNICHAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_UNICHAR))
#define GLADE_EPROP_UNICHAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_UNICHAR, GladeEPropUnicharClass))
static void
glade_eprop_unichar_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static void
glade_eprop_unichar_load (GladeEditorProperty *eprop, GladeProperty *property)
{
GladeEPropUnichar *eprop_unichar = GLADE_EPROP_UNICHAR (eprop);
/* Chain up first */
editor_property_class->load (eprop, property);
if (property && GTK_IS_ENTRY (eprop_unichar->entry))
{
GtkEntry *entry = GTK_ENTRY (eprop_unichar->entry);
gchar utf8st[8];
gint n;
if ((n = g_unichar_to_utf8 (g_value_get_uint (property->value), utf8st)))
{
utf8st[n] = '\0';
gtk_entry_set_text (entry, utf8st);
}
}
}
static void
glade_eprop_unichar_changed (GtkWidget *entry,
GladeEditorProperty *eprop)
{
const gchar *text;
if (eprop->loading) return;
if ((text = gtk_entry_get_text (GTK_ENTRY (entry))) != NULL)
{
gunichar unich = g_utf8_get_char (text);
GValue val = { 0, };
g_value_init (&val, G_TYPE_UINT);
g_value_set_uint (&val, unich);
glade_editor_property_commit (eprop, &val);
g_value_unset (&val);
}
}
static void
glade_eprop_unichar_delete (GtkEditable *editable,
gint start_pos,
gint end_pos,
GladeEditorProperty *eprop)
{
if (eprop->loading) return;
gtk_editable_select_region (editable, 0, -1);
g_signal_stop_emission_by_name (G_OBJECT (editable), "delete_text");
}
static void
glade_eprop_unichar_insert (GtkWidget *entry,
const gchar *text,
gint length,
gint *position,
GladeEditorProperty *eprop)
{
if (eprop->loading) return;
g_signal_handlers_block_by_func
(G_OBJECT (entry), G_CALLBACK (glade_eprop_unichar_changed), eprop);
g_signal_handlers_block_by_func
(G_OBJECT (entry), G_CALLBACK (glade_eprop_unichar_insert), eprop);
g_signal_handlers_block_by_func
(G_OBJECT (entry), G_CALLBACK (glade_eprop_unichar_delete), eprop);
gtk_editable_delete_text (GTK_EDITABLE (entry), 0, -1);
*position = 0;
gtk_editable_insert_text (GTK_EDITABLE (entry), text, 1, position);
g_signal_handlers_unblock_by_func
(G_OBJECT (entry), G_CALLBACK (glade_eprop_unichar_changed), eprop);
g_signal_handlers_unblock_by_func
(G_OBJECT (entry), G_CALLBACK (glade_eprop_unichar_insert), eprop);
g_signal_handlers_unblock_by_func
(G_OBJECT (entry), G_CALLBACK (glade_eprop_unichar_delete), eprop);
g_signal_stop_emission_by_name (G_OBJECT (entry), "insert_text");
glade_eprop_unichar_changed (entry, eprop);
}
static GtkWidget *
glade_eprop_unichar_create_input (GladeEditorProperty *eprop)
{
GladeEPropUnichar *eprop_unichar = GLADE_EPROP_UNICHAR (eprop);
eprop_unichar->entry = gtk_entry_new ();
/* it's 2 to prevent spirious beeps... */
gtk_entry_set_max_length (GTK_ENTRY (eprop_unichar->entry), 2);
g_signal_connect (G_OBJECT (eprop_unichar->entry), "changed",
G_CALLBACK (glade_eprop_unichar_changed), eprop);
g_signal_connect (G_OBJECT (eprop_unichar->entry), "insert_text",
G_CALLBACK (glade_eprop_unichar_insert), eprop);
g_signal_connect (G_OBJECT (eprop_unichar->entry), "delete_text",
G_CALLBACK (glade_eprop_unichar_delete), eprop);
return eprop_unichar->entry;
}
/*******************************************************************************
GladeEditorPropertyResourceClass
*******************************************************************************/
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *entry, *button;
} GladeEPropResource;
GLADE_MAKE_EPROP (GladeEPropResource, glade_eprop_resource)
#define GLADE_TYPE_EPROP_RESOURCE (glade_eprop_resource_get_type())
#define GLADE_EPROP_RESOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_RESOURCE, GladeEPropResource))
#define GLADE_EPROP_RESOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_RESOURCE, GladeEPropResourceClass))
#define GLADE_IS_EPROP_RESOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_RESOURCE))
#define GLADE_IS_EPROP_RESOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_RESOURCE))
#define GLADE_EPROP_RESOURCE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_RESOURCE, GladeEPropResourceClass))
static void
glade_eprop_resource_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static void
glade_eprop_resource_entry_activate (GtkEntry *entry, GladeEditorProperty *eprop)
{
GladeProject *project = glade_widget_get_project (eprop->property->widget);
GValue *value = glade_property_class_make_gvalue_from_string
(eprop->klass, gtk_entry_get_text(entry), project);
/* Set project resource here where we still have the fullpath.
*/
glade_project_set_resource (project, eprop->property,
gtk_entry_get_text(entry));
glade_editor_property_commit (eprop, value);
g_value_unset (value);
g_free (value);
}
static gboolean
glade_eprop_resource_entry_focus_out (GtkWidget *entry,
GdkEventFocus *event,
GladeEditorProperty *eprop)
{
glade_eprop_resource_entry_activate (GTK_ENTRY (entry), eprop);
return FALSE;
}
static void
glade_eprop_resource_select_file (GtkButton *button, GladeEditorProperty *eprop)
{
GladeProject *project = glade_widget_get_project (eprop->property->widget);
GtkWidget *dialog;
GtkFileFilter *filter;
GValue *value;
gchar *file, *basename;
if (eprop->loading) return;
dialog = gtk_file_chooser_dialog_new ("Select a File",
NULL,
GTK_FILE_CHOOSER_ACTION_OPEN,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (dialog), TRUE);
if (eprop->klass->pspec->value_type == GDK_TYPE_PIXBUF)
{
filter = gtk_file_filter_new ();
gtk_file_filter_add_pixbuf_formats (filter);
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
}
if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT)
{
file = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
/* Set project resource here where we still have the fullpath.
*/
glade_project_set_resource (project, eprop->property, file);
basename = g_path_get_basename (file);
value = glade_property_class_make_gvalue_from_string
(eprop->klass, basename, project);
glade_editor_property_commit (eprop, value);
g_value_unset (value);
g_free (value);
g_free (file);
g_free (basename);
}
gtk_widget_destroy (dialog);
}
static void
glade_eprop_resource_load (GladeEditorProperty *eprop, GladeProperty *property)
{
GladeEPropResource *eprop_resource = GLADE_EPROP_RESOURCE (eprop);
gchar *file;
/* Chain up first */
editor_property_class->load (eprop, property);
if (property == NULL) return;
file = glade_property_class_make_string_from_gvalue
(eprop->klass, property->value);
if (file)
{
gtk_entry_set_text (GTK_ENTRY (eprop_resource->entry), file);
g_free (file);
}
else
{
gtk_entry_set_text (GTK_ENTRY (eprop_resource->entry), "");
}
}
static GtkWidget *
glade_eprop_resource_create_input (GladeEditorProperty *eprop)
{
GladeEPropResource *eprop_resource = GLADE_EPROP_RESOURCE (eprop);
GtkWidget *hbox;
hbox = gtk_hbox_new (FALSE, 0);
eprop_resource->entry = gtk_entry_new ();
gtk_widget_show (eprop_resource->entry);
eprop_resource->button = gtk_button_new_with_label ("...");
gtk_widget_show (eprop_resource->button);
gtk_box_pack_start (GTK_BOX (hbox), eprop_resource->entry, TRUE, TRUE, 0);
gtk_box_pack_start (GTK_BOX (hbox), eprop_resource->button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (eprop_resource->entry), "activate",
G_CALLBACK (glade_eprop_resource_entry_activate),
eprop);
g_signal_connect (G_OBJECT (eprop_resource->entry), "focus-out-event",
G_CALLBACK (glade_eprop_resource_entry_focus_out),
eprop);
g_signal_connect (G_OBJECT (eprop_resource->button), "clicked",
G_CALLBACK (glade_eprop_resource_select_file),
eprop);
return hbox;
}
/*******************************************************************************
GladeEditorPropertyObjectClass
*******************************************************************************/
enum {
OBJ_COLUMN_WIDGET = 0,
OBJ_COLUMN_WIDGET_NAME,
OBJ_COLUMN_WIDGET_CLASS,
OBJ_COLUMN_SELECTED,
OBJ_COLUMN_SELECTABLE,
OBJ_NUM_COLUMNS
};
#define GLADE_RESPONSE_CLEAR 42
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *entry;
} GladeEPropObject;
GLADE_MAKE_EPROP (GladeEPropObject, glade_eprop_object)
#define GLADE_TYPE_EPROP_OBJECT (glade_eprop_object_get_type())
#define GLADE_EPROP_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_OBJECT, GladeEPropObject))
#define GLADE_EPROP_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_OBJECT, GladeEPropObjectClass))
#define GLADE_IS_EPROP_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_OBJECT))
#define GLADE_IS_EPROP_OBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_OBJECT))
#define GLADE_EPROP_OBJECT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_OBJECT, GladeEPropObjectClass))
static void
glade_eprop_object_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static gchar *
glade_eprop_object_name (const gchar *name,
GtkTreeStore *model,
GtkTreeIter *parent_iter)
{
GtkTreePath *path;
GString *string;
gint i;
string = g_string_new (name);
if (parent_iter)
{
path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), parent_iter);
for (i = 0; i < gtk_tree_path_get_depth (path); i++)
g_string_prepend (string, " ");
}
return g_string_free (string, FALSE);
}
static gboolean
glade_eprop_object_is_selected (GladeEditorProperty *eprop,
GladeWidget *widget)
{
GList *list;
if (GLADE_IS_PARAM_SPEC_OBJECTS (eprop->klass->pspec))
{
glade_property_get (eprop->property, &list);
return g_list_find (list, widget->object) != NULL;
}
return glade_property_equals (eprop->property, widget->object);
}
/*
* Note that widgets is a list of GtkWidgets, while what we store
* in the model are the associated GladeWidgets.
*/
static void
glade_eprop_object_populate_view_real (GladeEditorProperty *eprop,
GtkTreeStore *model,
GList *widgets,
GtkTreeIter *parent_iter)
{
GList *children, *list;
GtkTreeIter iter;
gboolean good_type, has_decendant;
for (list = widgets; list; list = list->next)
{
GladeWidget *widget;
if ((widget = glade_widget_get_from_gobject (list->data)) != NULL)
{
if (GLADE_IS_PARAM_SPEC_OBJECTS (eprop->klass->pspec))
{
has_decendant = glade_widget_has_decendant
(widget,
glade_param_spec_objects_get_type
(GLADE_PARAM_SPEC_OBJECTS(eprop->klass->pspec)));
good_type =
glade_util_class_implements_interface
(widget->adaptor->type,
glade_param_spec_objects_get_type
(GLADE_PARAM_SPEC_OBJECTS(eprop->klass->pspec)));
}
else
{
has_decendant = glade_widget_has_decendant
(widget, eprop->klass->pspec->value_type);
good_type = g_type_is_a (widget->adaptor->type,
eprop->klass->pspec->value_type);
}
if (good_type || has_decendant)
{
gtk_tree_store_append (model, &iter, parent_iter);
gtk_tree_store_set
(model, &iter,
OBJ_COLUMN_WIDGET, widget,
OBJ_COLUMN_WIDGET_NAME,
glade_eprop_object_name (widget->name, model, parent_iter),
OBJ_COLUMN_WIDGET_CLASS,
widget->adaptor->title,
/* Selectable if its a compatible type and
* its not itself.
*/
OBJ_COLUMN_SELECTABLE,
good_type && (widget != eprop->property->widget),
OBJ_COLUMN_SELECTED,
good_type && glade_eprop_object_is_selected
(eprop, widget), -1);
}
if (has_decendant &&
(children = glade_widget_adaptor_get_children
(widget->adaptor, widget->object)) != NULL)
{
GtkTreeIter *copy = NULL;
copy = gtk_tree_iter_copy (&iter);
glade_eprop_object_populate_view_real (eprop, model, children, copy);
gtk_tree_iter_free (copy);
g_list_free (children);
}
}
}
}
static void
glade_eprop_object_populate_view (GladeEditorProperty *eprop,
GtkTreeView *view)
{
GtkTreeStore *model = (GtkTreeStore *)gtk_tree_view_get_model (view);
GladeProject *project = glade_app_get_project ();
GList *list, *toplevels = NULL;
/* Make a list of only the toplevel widgets */
for (list = (GList *) glade_project_get_objects (project); list; list = list->next)
{
GObject *object = G_OBJECT (list->data);
GladeWidget *gwidget = glade_widget_get_from_gobject (object);
g_assert (gwidget);
if (gwidget->parent == NULL)
toplevels = g_list_append (toplevels, object);
}
/* add the widgets and recurse */
glade_eprop_object_populate_view_real (eprop, model, toplevels, NULL);
g_list_free (toplevels);
}
static gboolean
glade_eprop_object_clear_iter (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
gpointer data)
{
gtk_tree_store_set (GTK_TREE_STORE (model), iter,
OBJ_COLUMN_SELECTED, FALSE, -1);
return FALSE;
}
static gboolean
glade_eprop_object_selected_widget (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
GladeWidget **ret)
{
gboolean selected;
GladeWidget *widget;
gtk_tree_model_get (model, iter,
OBJ_COLUMN_SELECTED, &selected,
OBJ_COLUMN_WIDGET, &widget, -1);
if (selected)
{
*ret = widget;
return TRUE;
}
return FALSE;
}
static void
glade_eprop_object_selected (GtkCellRendererToggle *cell,
gchar *path_str,
GtkTreeModel *model)
{
GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
GtkTreeIter iter;
gboolean enabled, radio;
radio = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (model), "radio-list"));
gtk_tree_model_get_iter (model, &iter, path);
gtk_tree_model_get (model, &iter,
OBJ_COLUMN_SELECTED, &enabled, -1);
/* Clear the rest of the view first
*/
if (radio)
gtk_tree_model_foreach (model, glade_eprop_object_clear_iter, NULL);
gtk_tree_store_set (GTK_TREE_STORE (model), &iter,
OBJ_COLUMN_SELECTED,
radio ? TRUE : !enabled, -1);
gtk_tree_path_free (path);
}
static GtkWidget *
glade_eprop_object_view (GladeEditorProperty *eprop,
gboolean radio)
{
GtkWidget *view_widget;
GtkTreeModel *model;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
model = (GtkTreeModel *)gtk_tree_store_new
(OBJ_NUM_COLUMNS,
G_TYPE_OBJECT, /* The GladeWidget */
G_TYPE_STRING, /* The GladeWidget's name */
G_TYPE_STRING, /* The GladeWidgetClass title */
G_TYPE_BOOLEAN, /* Whether this row is selected or not */
G_TYPE_BOOLEAN); /* Whether this GladeWidget is
* of an acceptable type and
* therefore can be selected.
*/
g_object_set_data (G_OBJECT (model), "radio-list", GINT_TO_POINTER (radio));
view_widget = gtk_tree_view_new_with_model (model);
/* Pass ownership to the view */
g_object_unref (G_OBJECT (model));
g_object_set (G_OBJECT (view_widget), "enable-search", FALSE, NULL);
/********************* fake invisible column *********************/
renderer = gtk_cell_renderer_text_new ();
g_object_set (G_OBJECT (renderer), "editable", FALSE, "visible", FALSE, NULL);
column = gtk_tree_view_column_new_with_attributes (NULL, renderer, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (view_widget), column);
gtk_tree_view_column_set_visible (column, FALSE);
gtk_tree_view_set_expander_column (GTK_TREE_VIEW (view_widget), column);
/************************ selected column ************************/
renderer = gtk_cell_renderer_toggle_new ();
g_object_set (G_OBJECT (renderer),
"mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
"activatable", TRUE,
"radio", radio,
NULL);
g_signal_connect (renderer, "toggled",
G_CALLBACK (glade_eprop_object_selected), model);
gtk_tree_view_insert_column_with_attributes
(GTK_TREE_VIEW (view_widget), 0,
NULL, renderer,
"visible", OBJ_COLUMN_SELECTABLE,
"sensitive", OBJ_COLUMN_SELECTABLE,
"active", OBJ_COLUMN_SELECTED,
NULL);
/********************* widget name column *********************/
renderer = gtk_cell_renderer_text_new ();
g_object_set (G_OBJECT (renderer), "editable", FALSE, NULL);
gtk_tree_view_insert_column_with_attributes
(GTK_TREE_VIEW (view_widget), 1,
_("Name"), renderer,
"text", OBJ_COLUMN_WIDGET_NAME,
NULL);
/***************** widget class title column ******************/
renderer = gtk_cell_renderer_text_new ();
g_object_set (G_OBJECT (renderer),
"editable", FALSE,
"style", PANGO_STYLE_ITALIC,
"foreground", "Gray", NULL);
gtk_tree_view_insert_column_with_attributes
(GTK_TREE_VIEW (view_widget), 2,
_("Class"), renderer,
"text", OBJ_COLUMN_WIDGET_CLASS,
NULL);
return view_widget;
}
static gchar *
glade_eprop_object_dialog_title (GladeEditorProperty *eprop)
{
GladeWidgetAdaptor *adaptor;
const gchar *format =
GLADE_IS_PARAM_SPEC_OBJECTS (eprop->klass->pspec) ?
_("Choose %s implementors") : _("Choose a %s in this project");
if (GLADE_IS_PARAM_SPEC_OBJECTS (eprop->klass->pspec))
return g_strdup_printf (format, g_type_name
(glade_param_spec_objects_get_type
(GLADE_PARAM_SPEC_OBJECTS (eprop->klass->pspec))));
else if ((adaptor =
glade_widget_adaptor_get_by_type
(eprop->klass->pspec->value_type)) != NULL)
return g_strdup_printf (format, adaptor->title);
/* Fallback on type name (which would look like "GtkButton"
* instead of "Button" and maybe not translated).
*/
return g_strdup_printf (format, g_type_name
(eprop->klass->pspec->value_type));
}
static void
glade_eprop_object_show_dialog (GtkWidget *dialog_button,
GladeEditorProperty *eprop)
{
GtkWidget *dialog, *parent;
GtkWidget *vbox, *label, *sw;
GtkWidget *tree_view;
GladeProject *project;
gchar *title = glade_eprop_object_dialog_title (eprop);
gint res;
project = glade_widget_get_project (eprop->property->widget);
parent = gtk_widget_get_toplevel (GTK_WIDGET (eprop));
dialog = gtk_dialog_new_with_buttons (title,
GTK_WINDOW (parent),
GTK_DIALOG_MODAL,
GTK_STOCK_CLEAR, GLADE_RESPONSE_CLEAR,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
g_free (title);
gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
GLADE_RESPONSE_CLEAR,
-1);
gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
/* HIG settings */
gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2); /* 2 * 5 + 2 = 12 */
gtk_container_set_border_width (GTK_CONTAINER (GTK_DIALOG (dialog)->action_area), 5);
gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->action_area), 6);
vbox = gtk_vbox_new (FALSE, 6);
gtk_widget_show (vbox);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 5);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, TRUE, TRUE, 0);
/* Checklist */
label = gtk_label_new_with_mnemonic (_("O_bjects:"));
gtk_widget_show (label);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_show (sw);
gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
gtk_widget_set_size_request (sw, 400, 200);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
tree_view = glade_eprop_object_view (eprop, TRUE);
glade_eprop_object_populate_view (eprop, GTK_TREE_VIEW (tree_view));
gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
gtk_widget_show (tree_view);
gtk_container_add (GTK_CONTAINER (sw), tree_view);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), tree_view);
/* Run the dialog */
res = gtk_dialog_run (GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_OK)
{
GladeWidget *selected = NULL;
gtk_tree_model_foreach
(gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)),
(GtkTreeModelForeachFunc)
glade_eprop_object_selected_widget, &selected);
if (selected)
{
GValue *value = glade_property_class_make_gvalue_from_string
(eprop->klass, selected->name, project);
glade_editor_property_commit (eprop, value);
g_value_unset (value);
g_free (value);
}
}
else if (res == GLADE_RESPONSE_CLEAR)
{
GValue *value = glade_property_class_make_gvalue_from_string
(eprop->klass, NULL, project);
glade_editor_property_commit (eprop, value);
g_value_unset (value);
g_free (value);
}
gtk_widget_destroy (dialog);
}
static void
glade_eprop_object_load (GladeEditorProperty *eprop, GladeProperty *property)
{
GladeEPropObject *eprop_object = GLADE_EPROP_OBJECT (eprop);
gchar *obj_name;
/* Chain up first */
editor_property_class->load (eprop, property);
if (property == NULL) return;
if ((obj_name = glade_property_class_make_string_from_gvalue
(eprop->klass, property->value)) != NULL)
{
gtk_entry_set_text (GTK_ENTRY (eprop_object->entry), obj_name);
g_free (obj_name);
}
else
gtk_entry_set_text (GTK_ENTRY (eprop_object->entry), "");
}
static GtkWidget *
glade_eprop_object_create_input (GladeEditorProperty *eprop)
{
GladeEPropObject *eprop_object = GLADE_EPROP_OBJECT (eprop);
GtkWidget *hbox;
GtkWidget *button;
hbox = gtk_hbox_new (FALSE, 0);
eprop_object->entry = gtk_entry_new ();
gtk_entry_set_editable (GTK_ENTRY (eprop_object->entry), FALSE);
gtk_widget_show (eprop_object->entry);
gtk_box_pack_start (GTK_BOX (hbox), eprop_object->entry, TRUE, TRUE, 0);
button = gtk_button_new_with_label ("...");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (glade_eprop_object_show_dialog),
eprop);
return hbox;
}
/*******************************************************************************
GladeEditorPropertyObjectsClass
*******************************************************************************/
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *entry;
} GladeEPropObjects;
GLADE_MAKE_EPROP (GladeEPropObjects, glade_eprop_objects)
#define GLADE_TYPE_EPROP_OBJECTS (glade_eprop_objects_get_type())
#define GLADE_EPROP_OBJECTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_OBJECTS, GladeEPropObjects))
#define GLADE_EPROP_OBJECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_OBJECTS, GladeEPropObjectsClass))
#define GLADE_IS_EPROP_OBJECTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_OBJECTS))
#define GLADE_IS_EPROP_OBJECTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_OBJECTS))
#define GLADE_EPROP_OBJECTS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_OBJECTS, GladeEPropObjectsClass))
static void
glade_eprop_objects_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static void
glade_eprop_objects_load (GladeEditorProperty *eprop, GladeProperty *property)
{
GladeEPropObjects *eprop_objects = GLADE_EPROP_OBJECTS (eprop);
gchar *obj_name;
/* Chain up first */
editor_property_class->load (eprop, property);
if (property == NULL) return;
if ((obj_name = glade_property_class_make_string_from_gvalue
(eprop->klass, property->value)) != NULL)
{
gtk_entry_set_text (GTK_ENTRY (eprop_objects->entry), obj_name);
g_free (obj_name);
}
else
gtk_entry_set_text (GTK_ENTRY (eprop_objects->entry), "");
}
static gboolean
glade_eprop_objects_selected_widget (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
GList **ret)
{
gboolean selected;
GladeWidget *widget;
gtk_tree_model_get (model, iter,
OBJ_COLUMN_SELECTED, &selected,
OBJ_COLUMN_WIDGET, &widget, -1);
if (selected)
*ret = g_list_append (*ret, widget->object);
return FALSE;
}
static void
glade_eprop_objects_show_dialog (GtkWidget *dialog_button,
GladeEditorProperty *eprop)
{
GtkWidget *dialog, *parent;
GtkWidget *vbox, *label, *sw;
GtkWidget *tree_view;
GladeProject *project;
gchar *title = glade_eprop_object_dialog_title (eprop);
gint res;
project = glade_widget_get_project (eprop->property->widget);
parent = gtk_widget_get_toplevel (GTK_WIDGET (eprop));
dialog = gtk_dialog_new_with_buttons (title,
GTK_WINDOW (parent),
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CLEAR, GLADE_RESPONSE_CLEAR,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
g_free (title);
gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
vbox = gtk_vbox_new (FALSE, 6);
gtk_widget_show (vbox);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, TRUE, TRUE, 0);
/* Checklist */
label = gtk_label_new (_("Objects:"));
gtk_widget_show (label);
gtk_misc_set_alignment (GTK_MISC (label), 0, 0.5);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_show (sw);
gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
gtk_widget_set_size_request (sw, 400, 200);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
tree_view = glade_eprop_object_view (eprop, FALSE);
glade_eprop_object_populate_view (eprop, GTK_TREE_VIEW (tree_view));
gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
gtk_widget_show (tree_view);
gtk_container_add (GTK_CONTAINER (sw), tree_view);
/* Run the dialog */
res = gtk_dialog_run (GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_OK)
{
GValue *value;
GList *selected = NULL;
gtk_tree_model_foreach
(gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)),
(GtkTreeModelForeachFunc)
glade_eprop_objects_selected_widget, &selected);
value = glade_property_class_make_gvalue
(eprop->klass, selected);
glade_editor_property_commit (eprop, value);
g_value_unset (value);
g_free (value);
}
else if (res == GLADE_RESPONSE_CLEAR)
{
GValue *value = glade_property_class_make_gvalue
(eprop->klass, NULL);
glade_editor_property_commit (eprop, value);
g_value_unset (value);
g_free (value);
}
gtk_widget_destroy (dialog);
}
static GtkWidget *
glade_eprop_objects_create_input (GladeEditorProperty *eprop)
{
GladeEPropObjects *eprop_objects = GLADE_EPROP_OBJECTS (eprop);
GtkWidget *hbox;
GtkWidget *button;
hbox = gtk_hbox_new (FALSE, 0);
eprop_objects->entry = gtk_entry_new ();
gtk_entry_set_editable (GTK_ENTRY (eprop_objects->entry), FALSE);
gtk_widget_show (eprop_objects->entry);
gtk_box_pack_start (GTK_BOX (hbox), eprop_objects->entry, TRUE, TRUE, 0);
button = gtk_button_new_with_label ("...");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (glade_eprop_objects_show_dialog),
eprop);
return hbox;
}
/*******************************************************************************
GladeEditorPropertyAdjustmentClass
*******************************************************************************/
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *value, *lower, *upper, *step_increment, *page_increment, *page_size;
GtkAdjustment *value_adj;
struct
{
gulong value, lower, upper, step_increment, page_increment, page_size;
}ids;
} GladeEPropAdjustment;
GLADE_MAKE_EPROP (GladeEPropAdjustment, glade_eprop_adjustment)
#define GLADE_TYPE_EPROP_ADJUSTMENT (glade_eprop_adjustment_get_type())
#define GLADE_EPROP_ADJUSTMENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_ADJUSTMENT, GladeEPropAdjustment))
#define GLADE_EPROP_ADJUSTMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_ADJUSTMENT, GladeEPropAdjustmentClass))
#define GLADE_IS_EPROP_ADJUSTMENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_ADJUSTMENT))
#define GLADE_IS_EPROP_ADJUSTMENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_ADJUSTMENT))
#define GLADE_EPROP_ADJUSTMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_ADJUSTMENT, GladeEPropAdjustmentClass))
static void
glade_eprop_adjustment_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
typedef struct _EPropAdjIdle EPropAdjIdleData;
struct _EPropAdjIdle
{
GladeEditorProperty *eprop;
gdouble value;
};
static gboolean
glade_eprop_adj_set_value_idle (gpointer p)
{
EPropAdjIdleData *data = (EPropAdjIdleData *) p;
GladeEPropAdjustment *eprop_adj = GLADE_EPROP_ADJUSTMENT (data->eprop);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (eprop_adj->value), data->value);
g_free (p);
return FALSE;
}
static void
glade_eprop_adj_value_changed (GtkAdjustment *adj, GladeEditorProperty *eprop)
{
EPropAdjIdleData *data;
g_signal_handlers_disconnect_by_func (adj, glade_eprop_adj_value_changed, eprop);
/* Don`t do anything if the loaded property is not the same */
if (adj != g_value_get_object (eprop->property->value)) return;
data = g_new (EPropAdjIdleData, 1);
data->eprop = eprop;
data->value = adj->value;
/* Update GladeEPropAdjustment value spinbutton in an idle funtion */
g_idle_add (glade_eprop_adj_set_value_idle, data);
/* Set adjustment to the old value */
adj->value = gtk_spin_button_get_value (GTK_SPIN_BUTTON (
GLADE_EPROP_ADJUSTMENT (eprop)->value));
}
static void
glade_eprop_adjustment_load (GladeEditorProperty *eprop, GladeProperty *property)
{
GladeEPropAdjustment *eprop_adj = GLADE_EPROP_ADJUSTMENT (eprop);
GObject *object;
GtkAdjustment *adj;
/* Chain up first */
editor_property_class->load (eprop, property);
if (property == NULL) return;
object = g_value_get_object (property->value);
if (object == NULL) return;
adj = GTK_ADJUSTMENT (object);
/* Keep track of external adjustment changes */
g_signal_connect (object, "value-changed",
G_CALLBACK (glade_eprop_adj_value_changed),
eprop);
/* Update adjustment's values */
eprop_adj->value_adj->lower = adj->lower;
eprop_adj->value_adj->upper = adj->upper;
eprop_adj->value_adj->step_increment = adj->step_increment;
eprop_adj->value_adj->page_increment = adj->page_increment;
eprop_adj->value_adj->page_size = adj->page_size;
/* Block Handlers */
g_signal_handler_block (eprop_adj->value, eprop_adj->ids.value);
g_signal_handler_block (eprop_adj->lower, eprop_adj->ids.lower);
g_signal_handler_block (eprop_adj->upper, eprop_adj->ids.upper);
g_signal_handler_block (eprop_adj->step_increment, eprop_adj->ids.step_increment);
g_signal_handler_block (eprop_adj->page_increment, eprop_adj->ids.page_increment);
g_signal_handler_block (eprop_adj->page_size, eprop_adj->ids.page_size);
/* Update spinbuttons values */
gtk_spin_button_set_value (GTK_SPIN_BUTTON (eprop_adj->value), adj->value);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (eprop_adj->lower), adj->lower);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (eprop_adj->upper), adj->upper);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (eprop_adj->step_increment), adj->step_increment);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (eprop_adj->page_increment), adj->page_increment);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (eprop_adj->page_size), adj->page_size);
/* Unblock Handlers */
g_signal_handler_unblock (eprop_adj->value, eprop_adj->ids.value);
g_signal_handler_unblock (eprop_adj->lower, eprop_adj->ids.lower);
g_signal_handler_unblock (eprop_adj->upper, eprop_adj->ids.upper);
g_signal_handler_unblock (eprop_adj->step_increment, eprop_adj->ids.step_increment);
g_signal_handler_unblock (eprop_adj->page_increment, eprop_adj->ids.page_increment);
g_signal_handler_unblock (eprop_adj->page_size, eprop_adj->ids.page_size);
}
static GtkAdjustment *
glade_eprop_adjustment_dup_adj (GladeEditorProperty *eprop)
{
GtkAdjustment *adj;
GObject *object;
object = g_value_get_object (eprop->property->value);
if (object == NULL) return NULL;
adj = GTK_ADJUSTMENT (object);
return GTK_ADJUSTMENT (gtk_adjustment_new (adj->value,
adj->lower,
adj->upper,
adj->step_increment,
adj->page_increment,
adj->page_size));
}
static void
glade_eprop_adjustment_prop_changed_common (GladeEditorProperty *eprop,
GtkAdjustment *adjustment)
{
GValue value = {0, };
g_value_init (&value, GTK_TYPE_ADJUSTMENT);
g_value_set_object (&value, G_OBJECT (adjustment));
glade_editor_property_commit (eprop, &value);
g_value_unset (&value);
}
#define GLADE_EPROP_ADJUSTMENT_DEFINE_VALUE_CHANGED_FUNC(p) \
static void \
glade_eprop_adjustment_ ## p ## _changed (GtkSpinButton *spin, \
GladeEditorProperty *eprop) \
{ \
GtkAdjustment *adj = glade_eprop_adjustment_dup_adj (eprop); \
if (adj == NULL) return; \
adj->p = gtk_spin_button_get_value (spin); \
glade_eprop_adjustment_prop_changed_common (eprop, adj); \
}
GLADE_EPROP_ADJUSTMENT_DEFINE_VALUE_CHANGED_FUNC (value)
GLADE_EPROP_ADJUSTMENT_DEFINE_VALUE_CHANGED_FUNC (lower)
GLADE_EPROP_ADJUSTMENT_DEFINE_VALUE_CHANGED_FUNC (upper)
GLADE_EPROP_ADJUSTMENT_DEFINE_VALUE_CHANGED_FUNC (step_increment)
GLADE_EPROP_ADJUSTMENT_DEFINE_VALUE_CHANGED_FUNC (page_increment)
GLADE_EPROP_ADJUSTMENT_DEFINE_VALUE_CHANGED_FUNC (page_size)
#define GLADE_EPROP_ADJUSTMENT_CONNECT(object, prop) \
g_signal_connect (object, "value_changed", \
G_CALLBACK (glade_eprop_adjustment_ ## prop ## _changed), eprop);
static void
glade_eprop_adjustment_table_add_label (GtkTable *table,
gint pos,
gchar *label,
gchar *tip)
{
GtkWidget *widget, *eventbox = gtk_event_box_new ();
widget = gtk_label_new (label);
gtk_misc_set_alignment (GTK_MISC (widget), 1, 0);
gtk_container_add (GTK_CONTAINER (eventbox), widget);
glade_util_widget_set_tooltip (eventbox, tip);
gtk_table_attach_defaults (table, eventbox, 0, 1, pos, pos + 1);
}
static GtkWidget *
glade_eprop_adjustment_create_input (GladeEditorProperty *eprop)
{
GladeEPropAdjustment *eprop_adj = GLADE_EPROP_ADJUSTMENT (eprop);
GtkWidget *widget;
GtkTable *table;
eprop_adj->value = gtk_spin_button_new_with_range (-G_MAXDOUBLE, G_MAXDOUBLE, 1);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (eprop_adj->value), 2);
eprop_adj->ids.value = GLADE_EPROP_ADJUSTMENT_CONNECT (eprop_adj->value, value);
eprop_adj->value_adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (eprop_adj->value));
eprop_adj->lower = gtk_spin_button_new_with_range (-G_MAXDOUBLE, G_MAXDOUBLE, 1);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (eprop_adj->lower), 2);
eprop_adj->ids.lower = GLADE_EPROP_ADJUSTMENT_CONNECT (eprop_adj->lower, lower);
eprop_adj->upper = gtk_spin_button_new_with_range (-G_MAXDOUBLE, G_MAXDOUBLE, 1);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (eprop_adj->upper), 2);
eprop_adj->ids.upper = GLADE_EPROP_ADJUSTMENT_CONNECT (eprop_adj->upper, upper);
eprop_adj->step_increment = gtk_spin_button_new_with_range (0, G_MAXDOUBLE, 1);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (eprop_adj->step_increment), 2);
eprop_adj->ids.step_increment = GLADE_EPROP_ADJUSTMENT_CONNECT (eprop_adj->step_increment, step_increment);
eprop_adj->page_increment = gtk_spin_button_new_with_range (0, G_MAXDOUBLE, 1);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (eprop_adj->page_increment), 2);
eprop_adj->ids.page_increment = GLADE_EPROP_ADJUSTMENT_CONNECT (eprop_adj->page_increment, page_increment);
eprop_adj->page_size = gtk_spin_button_new_with_range (0, G_MAXDOUBLE, 1);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (eprop_adj->page_size), 2);
eprop_adj->ids.page_size = GLADE_EPROP_ADJUSTMENT_CONNECT (eprop_adj->page_size, page_size);
/* Eprop */
widget = gtk_table_new (6, 2, FALSE);
table = GTK_TABLE (widget);
gtk_table_set_col_spacings (table, 4);
glade_eprop_adjustment_table_add_label (table, 0, _("Value:"),
_("The current value"));
glade_eprop_adjustment_table_add_label (table, 1, _("Lower:"),
_("The minimum value"));
glade_eprop_adjustment_table_add_label (table, 2, _("Upper:"),
_("The maximum value"));
glade_eprop_adjustment_table_add_label (table, 3, _("Step inc:"),
_("The increment to use to make minor changes to the value"));
glade_eprop_adjustment_table_add_label (table, 4, _("Page inc:"),
_("The increment to use to make major changes to the value"));
glade_eprop_adjustment_table_add_label (table, 5, _("Page size:"),
_("The page size (in a GtkScrollbar this is the size of the area which is currently visible)"));
gtk_table_attach_defaults (table, eprop_adj->value, 1, 2, 0, 1);
gtk_table_attach_defaults (table, eprop_adj->lower, 1, 2, 1, 2);
gtk_table_attach_defaults (table, eprop_adj->upper, 1, 2, 2, 3);
gtk_table_attach_defaults (table, eprop_adj->step_increment, 1, 2, 3, 4);
gtk_table_attach_defaults (table, eprop_adj->page_increment, 1, 2, 4, 5);
gtk_table_attach_defaults (table, eprop_adj->page_size, 1, 2, 5, 6);
gtk_widget_show_all (widget);
return widget;
}
/*******************************************************************************
GladeEditorPropertyAccelClass
*******************************************************************************/
enum {
ACCEL_COLUMN_SIGNAL = 0,
ACCEL_COLUMN_REAL_SIGNAL,
ACCEL_COLUMN_KEY,
ACCEL_COLUMN_MOD_SHIFT,
ACCEL_COLUMN_MOD_CNTL,
ACCEL_COLUMN_MOD_ALT,
ACCEL_COLUMN_IS_CLASS,
ACCEL_COLUMN_IS_SIGNAL,
ACCEL_COLUMN_KEY_ENTERED,
ACCEL_COLUMN_KEY_SLOT,
ACCEL_NUM_COLUMNS
};
enum {
ACCEL_COMBO_COLUMN_TEXT = 0,
ACCEL_COMBO_NUM_COLUMNS,
};
typedef struct {
GladeEditorProperty parent_instance;
GtkWidget *entry;
GList *parent_iters;
GtkTreeModel *model;
} GladeEPropAccel;
typedef struct {
GtkTreeIter *iter;
gchar *name; /* <-- dont free */
} GladeEpropIterTab;
static GtkTreeModel *keysyms_model = NULL;
GLADE_MAKE_EPROP (GladeEPropAccel, glade_eprop_accel)
#define GLADE_TYPE_EPROP_ACCEL (glade_eprop_accel_get_type())
#define GLADE_EPROP_ACCEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GLADE_TYPE_EPROP_ACCEL, GladeEPropAccel))
#define GLADE_EPROP_ACCEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GLADE_TYPE_EPROP_ACCEL, GladeEPropAccelClass))
#define GLADE_IS_EPROP_ACCEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GLADE_TYPE_EPROP_ACCEL))
#define GLADE_IS_EPROP_ACCEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GLADE_TYPE_EPROP_ACCEL))
#define GLADE_EPROP_ACCEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GLADE_EPROP_ACCEL, GladeEPropAccelClass))
static GtkTreeModel *
create_keysyms_model (void)
{
GtkTreeModel *model;
GtkTreeIter iter, alphanum, fkey, keypad, other, extra;
GtkTreeIter *parent;
gint i;
model = (GtkTreeModel *)gtk_tree_store_new
(ACCEL_COMBO_NUM_COLUMNS,
G_TYPE_STRING); /* The Key charachter name */
gtk_tree_store_append (GTK_TREE_STORE (model), &alphanum, NULL);
gtk_tree_store_set
(GTK_TREE_STORE (model), &alphanum,
ACCEL_COMBO_COLUMN_TEXT, _("Alphanumerical"), -1);
gtk_tree_store_append (GTK_TREE_STORE (model), &extra, NULL);
gtk_tree_store_set
(GTK_TREE_STORE (model), &extra,
ACCEL_COMBO_COLUMN_TEXT, _("Extra"), -1);
gtk_tree_store_append (GTK_TREE_STORE (model), &keypad, NULL);
gtk_tree_store_set
(GTK_TREE_STORE (model), &keypad,
ACCEL_COMBO_COLUMN_TEXT, _("Keypad"), -1);
gtk_tree_store_append (GTK_TREE_STORE (model), &fkey, NULL);
gtk_tree_store_set
(GTK_TREE_STORE (model), &fkey,
ACCEL_COMBO_COLUMN_TEXT, _("Functions"), -1);
gtk_tree_store_append (GTK_TREE_STORE (model), &other, NULL);
gtk_tree_store_set
(GTK_TREE_STORE (model), &other,
ACCEL_COMBO_COLUMN_TEXT, _("Other"), -1);
parent = &alphanum;
for (i = 0; GladeKeys[i].name != NULL; i++)
{
gtk_tree_store_append (GTK_TREE_STORE (model), &iter, parent);
gtk_tree_store_set
(GTK_TREE_STORE (model), &iter,
ACCEL_COMBO_COLUMN_TEXT, GladeKeys[i].name, -1);
if (!strcmp (GladeKeys[i].name, GLADE_KEYS_LAST_ALPHANUM))
parent = &extra;
else if (!strcmp (GladeKeys[i].name, GLADE_KEYS_LAST_EXTRA))
parent = &keypad;
else if (!strcmp (GladeKeys[i].name, GLADE_KEYS_LAST_KP))
parent = &fkey;
else if (!strcmp (GladeKeys[i].name, GLADE_KEYS_LAST_FKEY))
parent = &other;
}
return model;
}
static void
glade_eprop_accel_finalize (GObject *object)
{
/* Chain up */
G_OBJECT_CLASS (editor_property_class)->finalize (object);
}
static void
glade_eprop_accel_load (GladeEditorProperty *eprop,
GladeProperty *property)
{
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
gchar *accels;
/* Chain up first */
editor_property_class->load (eprop, property);
if (property == NULL) return;
if ((accels = glade_property_class_make_string_from_gvalue
(eprop->klass, property->value)) != NULL)
{
gtk_entry_set_text (GTK_ENTRY (eprop_accel->entry), accels);
g_free (accels);
}
else
gtk_entry_set_text (GTK_ENTRY (eprop_accel->entry), "");
}
static gint
eprop_find_iter (GladeEpropIterTab *iter_tab,
gchar *name)
{
return strcmp (iter_tab->name, name);
}
static void
iter_tab_free (GladeEpropIterTab *iter_tab)
{
gtk_tree_iter_free (iter_tab->iter);
g_free (iter_tab);
}
static void
glade_eprop_accel_populate_view (GladeEditorProperty *eprop,
GtkTreeView *view)
{
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
GladeSignalClass *sclass;
GladeWidgetAdaptor *adaptor = glade_widget_adaptor_from_pclass (eprop->klass);
GtkTreeStore *model = (GtkTreeStore *)gtk_tree_view_get_model (view);
GtkTreeIter iter;
GladeEpropIterTab *parent_tab;
GladeAccelInfo *info;
GList *list, *l, *found, *accelerators;
gchar *name;
accelerators = g_value_get_boxed (eprop->property->value);
/* First make parent iters...
*/
for (list = adaptor->signals; list; list = list->next)
{
sclass = list->data;
/* Only action signals have accelerators. */
if ((sclass->query.signal_flags & G_SIGNAL_ACTION) == 0)
continue;
if (g_list_find_custom (eprop_accel->parent_iters,
sclass->type,
(GCompareFunc)eprop_find_iter) == NULL)
{
gtk_tree_store_append (model, &iter, NULL);
gtk_tree_store_set (model, &iter,
ACCEL_COLUMN_SIGNAL, sclass->type,
ACCEL_COLUMN_IS_CLASS, TRUE,
ACCEL_COLUMN_IS_SIGNAL, FALSE,
-1);
parent_tab = g_new0 (GladeEpropIterTab, 1);
parent_tab->name = sclass->type;
parent_tab->iter = gtk_tree_iter_copy (&iter);
eprop_accel->parent_iters =
g_list_prepend (eprop_accel->parent_iters,
parent_tab);
}
}
/* Now we populate...
*/
for (list = adaptor->signals; list; list = list->next)
{
sclass = list->data;
/* Only action signals have accelerators. */
if ((sclass->query.signal_flags & G_SIGNAL_ACTION) == 0)
continue;
if ((found = g_list_find_custom (eprop_accel->parent_iters,
sclass->type,
(GCompareFunc)eprop_find_iter)) != NULL)
{
parent_tab = found->data;
name = g_strdup_printf (" %s", sclass->name);
/* Populate from accelerator list
*/
for (l = accelerators; l; l = l->next)
{
info = l->data;
if (strcmp (info->signal, sclass->name))
continue;
gtk_tree_store_append (model, &iter, parent_tab->iter);
gtk_tree_store_set
(model, &iter,
ACCEL_COLUMN_SIGNAL, name,
ACCEL_COLUMN_REAL_SIGNAL, sclass->name,
ACCEL_COLUMN_IS_CLASS, FALSE,
ACCEL_COLUMN_IS_SIGNAL, TRUE,
ACCEL_COLUMN_MOD_SHIFT,
(info->modifiers & GDK_SHIFT_MASK) != 0,
ACCEL_COLUMN_MOD_CNTL,
(info->modifiers & GDK_CONTROL_MASK) != 0,
ACCEL_COLUMN_MOD_ALT,
(info->modifiers & GDK_MOD1_MASK) != 0,
ACCEL_COLUMN_KEY,
glade_builtin_string_from_key (info->key),
ACCEL_COLUMN_KEY_ENTERED, TRUE,
ACCEL_COLUMN_KEY_SLOT, FALSE,
-1);
}
/* Append a new empty slot at the end */
gtk_tree_store_append (model, &iter, parent_tab->iter);
gtk_tree_store_set
(model, &iter,
ACCEL_COLUMN_SIGNAL, name,
ACCEL_COLUMN_REAL_SIGNAL, sclass->name,
ACCEL_COLUMN_IS_CLASS, FALSE,
ACCEL_COLUMN_IS_SIGNAL, TRUE,
ACCEL_COLUMN_MOD_SHIFT, FALSE,
ACCEL_COLUMN_MOD_CNTL, FALSE,
ACCEL_COLUMN_MOD_ALT, FALSE,
ACCEL_COLUMN_KEY, _("<choose a key>"),
ACCEL_COLUMN_KEY_ENTERED, FALSE,
ACCEL_COLUMN_KEY_SLOT, TRUE,
-1);
g_free (name);
}
}
}
static void
key_edited (GtkCellRendererText *cell,
const gchar *path_string,
const gchar *new_text,
GladeEditorProperty *eprop)
{
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
gboolean key_was_set;
const gchar *text;
GtkTreeIter iter, parent_iter, new_iter;
if (!gtk_tree_model_get_iter_from_string (eprop_accel->model,
&iter, path_string))
return;
gtk_tree_model_get (eprop_accel->model, &iter,
ACCEL_COLUMN_KEY_ENTERED, &key_was_set,
-1);
/* If user selects "none"; remove old entry or ignore new one.
*/
if (!new_text || new_text[0] == '\0' ||
glade_builtin_string_from_key ((guint)new_text[0]) == NULL ||
g_utf8_collate (new_text, _("None")) == 0 ||
g_utf8_collate (new_text, _("<choose a key>")) == 0)
{
if (key_was_set)
gtk_tree_store_remove
(GTK_TREE_STORE (eprop_accel->model), &iter);
return;
}
if (glade_builtin_key_from_string (new_text) != 0)
text = new_text;
else
text = glade_builtin_string_from_key ((guint)new_text[0]);
gtk_tree_store_set
(GTK_TREE_STORE (eprop_accel->model), &iter,
ACCEL_COLUMN_KEY, text,
ACCEL_COLUMN_KEY_ENTERED, TRUE,
ACCEL_COLUMN_KEY_SLOT, FALSE,
-1);
/* Append a new one if needed
*/
if (key_was_set == FALSE &&
gtk_tree_model_iter_parent (eprop_accel->model,
&parent_iter, &iter))
{
gchar *signal, *real_signal;
gtk_tree_model_get (eprop_accel->model, &iter,
ACCEL_COLUMN_SIGNAL, &signal,
ACCEL_COLUMN_REAL_SIGNAL, &real_signal,
-1);
/* Append a new empty slot at the end */
gtk_tree_store_insert_after (GTK_TREE_STORE (eprop_accel->model),
&new_iter, &parent_iter, &iter);
gtk_tree_store_set (GTK_TREE_STORE (eprop_accel->model), &new_iter,
ACCEL_COLUMN_SIGNAL, signal,
ACCEL_COLUMN_REAL_SIGNAL, real_signal,
ACCEL_COLUMN_IS_CLASS, FALSE,
ACCEL_COLUMN_IS_SIGNAL, TRUE,
ACCEL_COLUMN_MOD_SHIFT, FALSE,
ACCEL_COLUMN_MOD_CNTL, FALSE,
ACCEL_COLUMN_MOD_ALT, FALSE,
ACCEL_COLUMN_KEY, _("<choose a key>"),
ACCEL_COLUMN_KEY_ENTERED, FALSE,
ACCEL_COLUMN_KEY_SLOT, TRUE,
-1);
g_free (signal);
g_free (real_signal);
}
}
static void
modifier_toggled (GtkCellRendererToggle *cell,
gchar *path_string,
GladeEditorProperty *eprop)
{
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
GtkTreeIter iter;
gint column;
gboolean active, key_entered;
if (!gtk_tree_model_get_iter_from_string (eprop_accel->model,
&iter, path_string))
return;
column = GPOINTER_TO_INT (g_object_get_data
(G_OBJECT (cell), "model-column"));
gtk_tree_model_get
(eprop_accel->model, &iter,
ACCEL_COLUMN_KEY_ENTERED, &key_entered,
column, &active, -1);
if (key_entered)
gtk_tree_store_set
(GTK_TREE_STORE (eprop_accel->model), &iter,
column, !active, -1);
}
static GtkWidget *
glade_eprop_accel_view (GladeEditorProperty *eprop)
{
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
GtkWidget *view_widget;
GtkCellRenderer *renderer;
GtkTreeViewColumn *column;
eprop_accel->model = (GtkTreeModel *)gtk_tree_store_new
(ACCEL_NUM_COLUMNS,
G_TYPE_STRING, /* The GSignal name formatted for display */
G_TYPE_STRING, /* The GSignal name */
G_TYPE_STRING, /* The Gdk keycode */
G_TYPE_BOOLEAN, /* The shift modifier */
G_TYPE_BOOLEAN, /* The cntl modifier */
G_TYPE_BOOLEAN, /* The alt modifier */
G_TYPE_BOOLEAN, /* Whether this is a class entry */
G_TYPE_BOOLEAN, /* Whether this is a signal entry (oposite of above) */
G_TYPE_BOOLEAN, /* Whether the key has been entered for this row */
G_TYPE_BOOLEAN); /* Oposite of above */
view_widget = gtk_tree_view_new_with_model (eprop_accel->model);
g_object_set (G_OBJECT (view_widget), "enable-search", FALSE, NULL);
/********************* fake invisible column *********************/
renderer = gtk_cell_renderer_text_new ();
g_object_set (G_OBJECT (renderer), "editable", FALSE, "visible", FALSE, NULL);
column = gtk_tree_view_column_new_with_attributes (NULL, renderer, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (view_widget), column);
gtk_tree_view_column_set_visible (column, FALSE);
gtk_tree_view_set_expander_column (GTK_TREE_VIEW (view_widget), column);
/********************* signal name column *********************/
renderer = gtk_cell_renderer_text_new ();
g_object_set (G_OBJECT (renderer),
"editable", FALSE,
"weight", PANGO_WEIGHT_BOLD,
NULL);
column = gtk_tree_view_column_new_with_attributes
(_("Signal"), renderer,
"text", ACCEL_COLUMN_SIGNAL,
"weight-set", ACCEL_COLUMN_IS_CLASS,
NULL);
g_object_set (G_OBJECT (column), "expand", TRUE, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (view_widget), column);
/********************* key name column *********************/
if (keysyms_model == NULL)
keysyms_model = create_keysyms_model ();
renderer = gtk_cell_renderer_combo_new ();
g_object_set (G_OBJECT (renderer),
"editable", TRUE,
"model", keysyms_model,
"text-column", ACCEL_COMBO_COLUMN_TEXT,
"has-entry", TRUE,
"style", PANGO_STYLE_ITALIC,
"foreground", "Gray",
NULL);
g_signal_connect (renderer, "edited",
G_CALLBACK (key_edited), eprop);
column = gtk_tree_view_column_new_with_attributes
(_("Key"), renderer,
"text", ACCEL_COLUMN_KEY,
"style-set", ACCEL_COLUMN_KEY_SLOT,
"foreground-set", ACCEL_COLUMN_KEY_SLOT,
"visible", ACCEL_COLUMN_IS_SIGNAL,
NULL);
g_object_set (G_OBJECT (column), "expand", TRUE, NULL);
gtk_tree_view_append_column (GTK_TREE_VIEW (view_widget), column);
/********************* shift modifier column *********************/
renderer = gtk_cell_renderer_toggle_new ();
column = gtk_tree_view_column_new_with_attributes
(_("Shift"), renderer,
"visible", ACCEL_COLUMN_IS_SIGNAL,
"sensitive", ACCEL_COLUMN_KEY_ENTERED,
"active", ACCEL_COLUMN_MOD_SHIFT,
NULL);
g_object_set_data (G_OBJECT (renderer), "model-column",
GINT_TO_POINTER (ACCEL_COLUMN_MOD_SHIFT));
g_signal_connect (G_OBJECT (renderer), "toggled",
G_CALLBACK (modifier_toggled), eprop);
gtk_tree_view_append_column (GTK_TREE_VIEW (view_widget), column);
/********************* control modifier column *********************/
renderer = gtk_cell_renderer_toggle_new ();
column = gtk_tree_view_column_new_with_attributes
(_("Control"), renderer,
"visible", ACCEL_COLUMN_IS_SIGNAL,
"sensitive", ACCEL_COLUMN_KEY_ENTERED,
"active", ACCEL_COLUMN_MOD_CNTL,
NULL);
g_object_set_data (G_OBJECT (renderer), "model-column",
GINT_TO_POINTER (ACCEL_COLUMN_MOD_CNTL));
g_signal_connect (G_OBJECT (renderer), "toggled",
G_CALLBACK (modifier_toggled), eprop);
gtk_tree_view_append_column (GTK_TREE_VIEW (view_widget), column);
/********************* alt modifier column *********************/
renderer = gtk_cell_renderer_toggle_new ();
column = gtk_tree_view_column_new_with_attributes
(_("Alt"), renderer,
"visible", ACCEL_COLUMN_IS_SIGNAL,
"sensitive", ACCEL_COLUMN_KEY_ENTERED,
"active", ACCEL_COLUMN_MOD_ALT,
NULL);
g_object_set_data (G_OBJECT (renderer), "model-column",
GINT_TO_POINTER (ACCEL_COLUMN_MOD_ALT));
g_signal_connect (G_OBJECT (renderer), "toggled",
G_CALLBACK (modifier_toggled), eprop);
gtk_tree_view_append_column (GTK_TREE_VIEW (view_widget), column);
return view_widget;
}
static gboolean
glade_eprop_accel_accum_accelerators (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter,
GList **ret)
{
GladeAccelInfo *info;
gchar *signal, *key_str;
gboolean shift, cntl, alt, entered;
gtk_tree_model_get (model, iter, ACCEL_COLUMN_KEY_ENTERED, &entered, -1);
if (entered == FALSE) return FALSE;
gtk_tree_model_get (model, iter,
ACCEL_COLUMN_REAL_SIGNAL, &signal,
ACCEL_COLUMN_KEY, &key_str,
ACCEL_COLUMN_MOD_SHIFT, &shift,
ACCEL_COLUMN_MOD_CNTL, &cntl,
ACCEL_COLUMN_MOD_ALT, &alt,
-1);
info = g_new0 (GladeAccelInfo, 1);
info->signal = signal;
info->key = glade_builtin_key_from_string (key_str);
info->modifiers = (shift ? GDK_SHIFT_MASK : 0) |
(cntl ? GDK_CONTROL_MASK : 0) |
(alt ? GDK_MOD1_MASK : 0);
*ret = g_list_prepend (*ret, info);
g_free (key_str);
return FALSE;
}
static void
glade_eprop_accel_show_dialog (GtkWidget *dialog_button,
GladeEditorProperty *eprop)
{
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
GtkWidget *dialog, *parent, *vbox, *sw, *tree_view;
GladeProject *project;
GValue *value;
GList *accelerators = NULL;
gint res;
project = glade_widget_get_project (eprop->property->widget);
parent = gtk_widget_get_toplevel (GTK_WIDGET (eprop));
dialog = gtk_dialog_new_with_buttons (_("Choose accelerator keys..."),
GTK_WINDOW (parent),
GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_STOCK_CLEAR, GLADE_RESPONSE_CLEAR,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
GTK_STOCK_OK, GTK_RESPONSE_OK,
NULL);
gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
vbox = gtk_vbox_new (FALSE, 6);
gtk_widget_show (vbox);
gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox), vbox, TRUE, TRUE, 0);
sw = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_show (sw);
gtk_box_pack_start (GTK_BOX (vbox), sw, TRUE, TRUE, 0);
gtk_widget_set_size_request (sw, 400, 200);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sw), GTK_SHADOW_IN);
tree_view = glade_eprop_accel_view (eprop);
glade_eprop_accel_populate_view (eprop, GTK_TREE_VIEW (tree_view));
gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
gtk_widget_show (tree_view);
gtk_container_add (GTK_CONTAINER (sw), tree_view);
/* Run the dialog */
res = gtk_dialog_run (GTK_DIALOG (dialog));
if (res == GTK_RESPONSE_OK)
{
gtk_tree_model_foreach
(gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)),
(GtkTreeModelForeachFunc)
glade_eprop_accel_accum_accelerators, &accelerators);
value = g_new0 (GValue, 1);
g_value_init (value, GLADE_TYPE_ACCEL_GLIST);
g_value_take_boxed (value, accelerators);
glade_editor_property_commit (eprop, value);
g_value_unset (value);
g_free (value);
}
else if (res == GLADE_RESPONSE_CLEAR)
{
value = g_new0 (GValue, 1);
g_value_init (value, GLADE_TYPE_ACCEL_GLIST);
g_value_set_boxed (value, NULL);
glade_editor_property_commit (eprop, value);
g_value_unset (value);
g_free (value);
}
/* Clean up ...
*/
gtk_widget_destroy (dialog);
g_object_unref (G_OBJECT (eprop_accel->model));
eprop_accel->model = NULL;
if (eprop_accel->parent_iters)
{
g_list_foreach (eprop_accel->parent_iters, (GFunc)iter_tab_free, NULL);
g_list_free (eprop_accel->parent_iters);
eprop_accel->parent_iters = NULL;
}
}
static GtkWidget *
glade_eprop_accel_create_input (GladeEditorProperty *eprop)
{
GladeEPropAccel *eprop_accel = GLADE_EPROP_ACCEL (eprop);
GtkWidget *hbox;
GtkWidget *button;
hbox = gtk_hbox_new (FALSE, 0);
eprop_accel->entry = gtk_entry_new ();
gtk_entry_set_editable (GTK_ENTRY (eprop_accel->entry), FALSE);
gtk_widget_show (eprop_accel->entry);
gtk_box_pack_start (GTK_BOX (hbox), eprop_accel->entry, TRUE, TRUE, 0);
button = gtk_button_new_with_label ("...");
gtk_widget_show (button);
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
g_signal_connect (G_OBJECT (button), "clicked",
G_CALLBACK (glade_eprop_accel_show_dialog),
eprop);
return hbox;
}
/*******************************************************************************
Misc static stuff
*******************************************************************************/
static GType
glade_editor_property_type (GParamSpec *pspec)
{
GType type = 0;
if (pspec->value_type == GLADE_TYPE_STOCK ||
G_IS_PARAM_SPEC_ENUM(pspec))
type = GLADE_TYPE_EPROP_ENUM;
else if (G_IS_PARAM_SPEC_FLAGS(pspec))
type = GLADE_TYPE_EPROP_FLAGS;
else if (G_IS_PARAM_SPEC_VALUE_ARRAY (pspec))
{
if (pspec->value_type == G_TYPE_VALUE_ARRAY)
type = GLADE_TYPE_EPROP_TEXT;
}
else if (G_IS_PARAM_SPEC_BOXED(pspec))
{
if (pspec->value_type == GDK_TYPE_COLOR)
type = GLADE_TYPE_EPROP_COLOR;
else if (pspec->value_type == G_TYPE_STRV)
type = GLADE_TYPE_EPROP_TEXT;
}
else if (G_IS_PARAM_SPEC_STRING(pspec))
type = GLADE_TYPE_EPROP_TEXT;
else if (G_IS_PARAM_SPEC_BOOLEAN(pspec))
type = GLADE_TYPE_EPROP_BOOL;
else if (G_IS_PARAM_SPEC_FLOAT(pspec) ||
G_IS_PARAM_SPEC_DOUBLE(pspec) ||
G_IS_PARAM_SPEC_INT(pspec) ||
G_IS_PARAM_SPEC_UINT(pspec) ||
G_IS_PARAM_SPEC_LONG(pspec) ||
G_IS_PARAM_SPEC_ULONG(pspec) ||
G_IS_PARAM_SPEC_INT64(pspec) ||
G_IS_PARAM_SPEC_UINT64(pspec))
type = GLADE_TYPE_EPROP_NUMERIC;
else if (G_IS_PARAM_SPEC_UNICHAR(pspec))
type = GLADE_TYPE_EPROP_UNICHAR;
else if (G_IS_PARAM_SPEC_OBJECT(pspec))
{
if (pspec->value_type == GDK_TYPE_PIXBUF)
type = GLADE_TYPE_EPROP_RESOURCE;
else if (pspec->value_type == GTK_TYPE_ADJUSTMENT)
type = GLADE_TYPE_EPROP_ADJUSTMENT;
else
type = GLADE_TYPE_EPROP_OBJECT;
}
else if (GLADE_IS_PARAM_SPEC_OBJECTS(pspec))
type = GLADE_TYPE_EPROP_OBJECTS;
else if (GLADE_IS_PARAM_SPEC_ACCEL(pspec))
type = GLADE_TYPE_EPROP_ACCEL;
return type;
}
/*******************************************************************************
API
*******************************************************************************/
/**
* glade_editor_property_new:
* @klass: A #GladePropertyClass
* @use_command: Whether the undo/redo stack applies here.
*
* This is a factory function to create the correct type of
* editor property that can edit the said type of #GladePropertyClass
*
* Returns: A newly created GladeEditorProperty of the correct type
*/
GladeEditorProperty *
glade_editor_property_new (GladePropertyClass *klass,
gboolean use_command)
{
GladeEditorProperty *eprop;
GType type = 0;
/* Find the right type of GladeEditorProperty for this
* GladePropertyClass.
*/
if ((type = glade_editor_property_type (klass->pspec)) == 0)
g_error ("%s : pspec '%s' type '%s' not implemented (%s)\n",
G_GNUC_PRETTY_FUNCTION,
klass->name,
g_type_name (G_PARAM_SPEC_TYPE (klass->pspec)),
g_type_name (klass->pspec->value_type));
/* special case for resource specs which are hand specified in the catalog. */
if (klass->resource)
type = GLADE_TYPE_EPROP_RESOURCE;
/* special case for string specs that denote themed application icons. */
if (klass->themed_icon)
type = GLADE_TYPE_EPROP_NAMED_ICON;
/* Create and return the correct type of GladeEditorProperty */
eprop = g_object_new (type,
"property-class", klass,
"use-command", use_command,
NULL);
return eprop;
}
/**
* glade_editor_property_new_from_widget:
* @widget: A #GladeWidget
* @property: The widget's property
* @packing: whether @property indicates a packing property or not.
* @use_command: Whether the undo/redo stack applies here.
*
* This is a convenience function to create a GladeEditorProperty corresponding
* to @property
*
* Returns: A newly created and connected GladeEditorProperty
*/
GladeEditorProperty *
glade_editor_property_new_from_widget (GladeWidget *widget,
const gchar *property,
gboolean packing,
gboolean use_command)
{
GladeEditorProperty *eprop;
GladeProperty *p;
if (packing)
p = glade_widget_get_pack_property (widget, property);
else
p = glade_widget_get_property (widget, property);
g_return_val_if_fail (GLADE_IS_PROPERTY (p), NULL);
eprop = glade_editor_property_new (p->klass, use_command);
glade_editor_property_load (eprop, p);
return eprop;
}
/**
* glade_editor_property_supported:
* @pspec: A #GParamSpec
*
* Returns: whether this pspec is supported by GladeEditorProperties.
*/
gboolean
glade_editor_property_supported (GParamSpec *pspec)
{
return glade_editor_property_type (pspec) != 0;
}
/**
* glade_editor_property_load:
* @eprop: A #GladeEditorProperty
* @property: A #GladeProperty
*
* Loads @property values into @eprop and connects.
*/
void
glade_editor_property_load (GladeEditorProperty *eprop,
GladeProperty *property)
{
g_return_if_fail (GLADE_IS_EDITOR_PROPERTY (eprop));
g_return_if_fail (property == NULL || GLADE_IS_PROPERTY (property));
eprop->loading = TRUE;
GLADE_EDITOR_PROPERTY_GET_CLASS (eprop)->load (eprop, property);
eprop->loading = FALSE;
}
/**
* glade_editor_property_load_by_widget:
* @eprop: A #GladeEditorProperty
* @widget: A #GladeWidget
*
* Convenience function to load the appropriate #GladeProperty into
* @eprop from @widget
*/
void
glade_editor_property_load_by_widget (GladeEditorProperty *eprop,
GladeWidget *widget)
{
GladeProperty *property = NULL;
g_return_if_fail (GLADE_IS_EDITOR_PROPERTY (eprop));
g_return_if_fail (widget == NULL || GLADE_IS_WIDGET (widget));
if (widget)
/* properties are allowed to be missing on some internal widgets */
property = glade_widget_get_property (widget, eprop->klass->id);
glade_editor_property_load (eprop, property);
}
/**
* glade_editor_property_show_info:
* @eprop: A #GladeEditorProperty
*
* Show the control widget to access help for @eprop
*/
void
glade_editor_property_show_info (GladeEditorProperty *eprop)
{
GladeWidgetAdaptor *adaptor;
gchar *book;
g_return_if_fail (GLADE_IS_EDITOR_PROPERTY (eprop));
adaptor = glade_widget_adaptor_from_pspec (eprop->klass->pspec);
g_object_get (adaptor, "book", &book, NULL);
if (eprop->klass->virt == FALSE &&
book != NULL)
gtk_widget_show (eprop->info);
else
{
/* Put insensitive controls to balance the UI with
* other eprops.
*/
gtk_widget_show (eprop->info);
gtk_widget_set_sensitive (eprop->info, FALSE);
}
g_free (book);
eprop->show_info = TRUE;
g_object_notify (G_OBJECT (eprop), "show-info");
}
/**
* glade_editor_property_hide_info:
* @eprop: A #GladeEditorProperty
*
* Hide the control widget to access help for @eprop
*/
void
glade_editor_property_hide_info (GladeEditorProperty *eprop)
{
g_return_if_fail (GLADE_IS_EDITOR_PROPERTY (eprop));
gtk_widget_hide (eprop->info);
eprop->show_info = FALSE;
g_object_notify (G_OBJECT (eprop), "show-info");
}
syntax highlighted by Code2HTML, v. 0.9.1