[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
gEDA-dev: [PATCH 2/2] Make the multi-attribute editor non-modal
---
gschem/include/prototype.h | 2 +-
gschem/include/x_multiattrib.h | 6 +-
gschem/src/o_misc.c | 2 +-
gschem/src/x_multiattrib.c | 229 +++++++++++++++++++++++++++++++--------
gschem/src/x_pagesel.c | 8 ++-
libgeda/include/struct.h | 2 +
libgeda/src/s_toplevel.c | 2 +
7 files changed, 200 insertions(+), 51 deletions(-)
diff --git a/gschem/include/prototype.h b/gschem/include/prototype.h
index e2eb4b9..f537d7b 100644
--- a/gschem/include/prototype.h
+++ b/gschem/include/prototype.h
@@ -842,7 +842,7 @@ gboolean g_file_set_contents(const gchar *filename, const gchar *contents,
gssize length, GError **error);
#endif
/* x_multiattrib.c */
-void x_multiattrib_open (TOPLEVEL *toplevel, OBJECT *object);
+void x_multiattrib_open (TOPLEVEL *toplevel);
/* x_multimulti.c */
/* x_pagesel.c */
void x_pagesel_open (TOPLEVEL *toplevel);
diff --git a/gschem/include/x_multiattrib.h b/gschem/include/x_multiattrib.h
index e53f06e..59a21b8 100644
--- a/gschem/include/x_multiattrib.h
+++ b/gschem/include/x_multiattrib.h
@@ -44,6 +44,7 @@ struct _MultiattribClass {
struct _Multiattrib {
GschemDialog parent_instance;
+ SELECTION *selection;
OBJECT *object;
GtkTreeView *treeview;
@@ -52,7 +53,10 @@ struct _Multiattrib {
GtkTextView *textview_value;
GtkCheckButton *button_visible;
GtkOptionMenu *optionmenu_shownv;
-
+ GtkWidget *frame_attributes;
+ GtkWidget *frame_add;
+
+ gulong selection_changed_id;
};
diff --git a/gschem/src/o_misc.c b/gschem/src/o_misc.c
index 246e65b..012cf4f 100644
--- a/gschem/src/o_misc.c
+++ b/gschem/src/o_misc.c
@@ -75,7 +75,7 @@ void o_edit(TOPLEVEL *w_current, GList *list)
case(OBJ_NET):
case(OBJ_PIN):
case(OBJ_BUS):
- x_multiattrib_open (w_current, o_current);
+ x_multiattrib_open (w_current);
break;
case(OBJ_PICTURE):
diff --git a/gschem/src/x_multiattrib.c b/gschem/src/x_multiattrib.c
index f0fe51f..970ce42 100644
--- a/gschem/src/x_multiattrib.c
+++ b/gschem/src/x_multiattrib.c
@@ -41,45 +41,67 @@
#include "../include/gschem_dialog.h"
#include "../include/x_multiattrib.h"
+
+
+/*! \brief Process the response returned by the multi-attribte dialog.
+ * \par Function Description
+ * This function handles the response <B>arg1</B> of the multi-attribute
+ * editor dialog <B>dialog</B>.
+ *
+ * Parameter <B>user_data</B> is a pointer on the relevant toplevel
+ * structure.
+ *
+ * \param [in] dialog The multi-attribute editor dialog.
+ * \param [in] arg1 The response ID.
+ * \param [in] user_data A pointer on the toplevel environment.
+ */
+static void
+x_multiattrib_callback_response (GtkDialog *dialog,
+ gint arg1,
+ gpointer user_data)
+{
+ TOPLEVEL *toplevel = (TOPLEVEL*)user_data;
+
+ switch (arg1) {
+ case GTK_RESPONSE_CLOSE:
+ case GTK_RESPONSE_DELETE_EVENT:
+ g_assert (GTK_WIDGET (dialog) == toplevel->multiattribwindow);
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+ toplevel->multiattribwindow = NULL;
+ break;
+ }
+}
+
/*! \brief Open multiple attribute editor dialog.
* \par Function Description
* Opens the multiple attribute editor dialog for <B>object</B> in the
* context of <B>toplevel</B>.
*
- * The dialog is modal and this function does not return until the user
- * closes the dialog.
- *
* \param [in] toplevel The TOPLEVEL object.
- * \param [in] object OBJECT to edit attributes on.
*/
-void x_multiattrib_open (TOPLEVEL *toplevel, OBJECT *object)
+void x_multiattrib_open (TOPLEVEL *toplevel)
{
- GtkWidget *dialog;
+ if ( toplevel->multiattribwindow == NULL ) {
+ toplevel->multiattribwindow = GTK_WIDGET (g_object_new (TYPE_MULTIATTRIB,
+ "selection", toplevel->page_current->selection_list,
+ /* GschemDialog */
+ "settings-name", "multiattrib",
+ "toplevel", toplevel,
+ NULL));
- dialog = GTK_WIDGET (g_object_new (TYPE_MULTIATTRIB,
- "object", object,
- /* GschemDialog */
- "settings-name", "multiattrib",
- "toplevel", toplevel,
- NULL));
+ g_signal_connect (toplevel->multiattribwindow,
+ "response",
+ G_CALLBACK (x_multiattrib_callback_response),
+ toplevel);
- gtk_window_set_transient_for(GTK_WINDOW(dialog),
- GTK_WINDOW(toplevel->main_window));
+ gtk_window_set_transient_for (GTK_WINDOW(toplevel->multiattribwindow),
+ GTK_WINDOW(toplevel->main_window));
- multiattrib_update (MULTIATTRIB(dialog));
- gtk_widget_show (dialog);
- switch (gtk_dialog_run ((GtkDialog*)dialog)) {
- case GTK_RESPONSE_CLOSE:
- case GTK_RESPONSE_DELETE_EVENT:
- /* reset state and update message in toolbar */
- i_set_state (toplevel, SELECT);
- i_update_toolbar (toplevel);
- break;
- default:
- g_assert_not_reached ();
+ multiattrib_update (MULTIATTRIB(toplevel->multiattribwindow));
+ gtk_widget_show (toplevel->multiattribwindow);
+ } else {
+ gtk_window_present (GTK_WINDOW(toplevel->multiattribwindow));
}
- gtk_widget_destroy (dialog);
-
}
/*! \section celltextview-widget Cell TextView Widget Code.
@@ -380,7 +402,7 @@ static void cellrenderermultilinetext_init(CellRendererMultiLineText *self)
enum {
- PROP_OBJECT = 1
+ PROP_SELECTION = 1
};
enum {
@@ -388,6 +410,7 @@ enum {
NUM_COLUMNS
};
+static GObjectClass *multiattrib_parent_class = NULL;
static void multiattrib_class_init (MultiattribClass *class);
static void multiattrib_init (Multiattrib *multiattrib);
@@ -1237,6 +1260,42 @@ GType multiattrib_get_type()
return multiattrib_type;
}
+
+/*! \todo Finish function documentation
+ * \brief
+ * \par Function Description
+ *
+ */
+static void selection_died_cb( gpointer data, GObject *where_the_object_was )
+{
+ Multiattrib *multiattrib = (Multiattrib *)data;
+
+ multiattrib->selection = NULL;
+ multiattrib_update( multiattrib );
+}
+
+
+/*! \todo Finish function documentation
+ * \brief
+ * \par Function Description
+ *
+ */
+static void multiattrib_finalize( GObject *object )
+{
+ Multiattrib *multiattrib = MULTIATTRIB(object);
+
+ if ( multiattrib->selection ) {
+ g_signal_handler_disconnect( multiattrib->selection,
+ multiattrib->selection_changed_id );
+ g_object_weak_unref( G_OBJECT( multiattrib->selection ),
+ selection_died_cb,
+ multiattrib );
+ }
+
+ G_OBJECT_CLASS(multiattrib_parent_class)->finalize( object );
+}
+
+
/*! \todo Finish function documentation
* \brief
* \par Function Description
@@ -1246,16 +1305,18 @@ static void multiattrib_class_init(MultiattribClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ multiattrib_parent_class = g_type_class_peek_parent (klass);
+
gobject_class->set_property = multiattrib_set_property;
gobject_class->get_property = multiattrib_get_property;
+ gobject_class->finalize = multiattrib_finalize;
g_object_class_install_property (
- gobject_class, PROP_OBJECT,
- g_param_spec_pointer ("object",
+ gobject_class, PROP_SELECTION,
+ g_param_spec_pointer ("selection",
"",
"",
- G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE));
-
+ G_PARAM_READWRITE));
}
/*! \todo Finish function documentation
@@ -1281,7 +1342,6 @@ static void multiattrib_init(Multiattrib *multiattrib)
"title", _("Edit Attributes"),
"default-width", 320,
"default-height", 350,
- "modal", TRUE,
"window-position", GTK_WIN_POS_MOUSE,
"allow-grow", TRUE,
"allow-shrink", FALSE,
@@ -1296,6 +1356,7 @@ static void multiattrib_init(Multiattrib *multiattrib)
/* GtkFrame */
"label", _("Attributes"),
NULL));
+ multiattrib->frame_add = frame;
/* - create the model for the treeview */
store = (GtkTreeModel*)gtk_list_store_new (NUM_COLUMNS,
G_TYPE_POINTER); /* attribute */
@@ -1461,6 +1522,7 @@ static void multiattrib_init(Multiattrib *multiattrib)
frame = GTK_WIDGET (g_object_new (GTK_TYPE_FRAME,
"label", _("Add Attribute"),
NULL));
+ multiattrib->frame_attributes = frame;
table = GTK_WIDGET (g_object_new (GTK_TYPE_TABLE,
/* GtkTable */
"n-rows", 4,
@@ -1560,6 +1622,53 @@ static void multiattrib_init(Multiattrib *multiattrib)
}
+
+/*! \todo Finish function documentation
+ * \brief
+ * \par Function Description
+ *
+ */
+static void selection_changed_cb( SELECTION *selection, Multiattrib *multiattrib )
+{
+ int object_count = 0;
+ GList *selection_glist;
+ GList *iter;
+ OBJECT *object;
+
+ selection_glist = geda_list_get_glist( selection );
+
+ for ( iter = selection_glist;
+ iter != NULL;
+ iter = g_list_next( iter ) ) {
+ object = (OBJECT *)iter->data;
+ g_assert( object != NULL );
+
+ if (object->type == OBJ_COMPLEX ||
+ object->type == OBJ_PLACEHOLDER ||
+ object->type == OBJ_NET ||
+ object->type == OBJ_BUS) {
+ object_count++;
+ }
+ }
+
+ if ( object_count == 0 ) {
+ /* TODO: If the user selects a single attribute which is
+ * not floating, should we find its parent object and
+ * display the multi-attribute editor for that?
+ * Bonus marks for making it jump to the correct attrib.
+ */
+ multiattrib->object = NULL;
+ } else if ( object_count == 1 ) {
+ multiattrib->object = (OBJECT *)selection_glist->data;
+ } else {
+ /* TODO: Something clever with multiple objects selected */
+ multiattrib->object = NULL;
+ }
+
+ multiattrib_update( multiattrib );
+}
+
+
/*! \todo Finish function documentation
* \brief
* \par Function Description
@@ -1573,9 +1682,30 @@ static void multiattrib_set_property (GObject *object,
Multiattrib *multiattrib = MULTIATTRIB (object);
switch(property_id) {
- case PROP_OBJECT:
- multiattrib->object = (OBJECT*)g_value_get_pointer (value);
- multiattrib_update (multiattrib);
+ case PROP_SELECTION:
+ if ( multiattrib->selection ) {
+ g_signal_handler_disconnect( multiattrib->selection,
+ multiattrib->selection_changed_id );
+ g_object_weak_unref( G_OBJECT( multiattrib->selection ),
+ selection_died_cb,
+ multiattrib );
+ }
+ multiattrib->selection = (SELECTION*)g_value_get_pointer (value);
+ if ( multiattrib->selection ) {
+ g_object_weak_ref( G_OBJECT( multiattrib->selection ),
+ selection_died_cb,
+ multiattrib );
+ multiattrib->selection_changed_id =
+ g_signal_connect( G_OBJECT( multiattrib->selection ),
+ "changed",
+ G_CALLBACK( selection_changed_cb ),
+ multiattrib );
+ /* TODO: We might want to add a weak reference so we can ensure we are
+ * safe when a page is closed and its selection object goes away.
+ */
+ }
+ /* Synthesise a selection changed update to refresh the view */
+ selection_changed_cb( multiattrib->selection, multiattrib );
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -1596,8 +1726,8 @@ static void multiattrib_get_property (GObject *object,
Multiattrib *multiattrib = MULTIATTRIB (object);
switch(property_id) {
- case PROP_OBJECT:
- g_value_set_pointer (value, (gpointer)multiattrib->object);
+ case PROP_SELECTION:
+ g_value_set_pointer (value, (gpointer)multiattrib->selection);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -1616,18 +1746,23 @@ void multiattrib_update (Multiattrib *multiattrib)
GtkTreeIter iter;
OBJECT **object_attribs, *o_current;
gint i;
-
- if (GSCHEM_DIALOG (multiattrib)->toplevel == NULL ||
- multiattrib->object == NULL) {
- /* we can not do anything until both toplevel and object are set */
- return;
- }
+ gboolean sensitive;
- liststore = (GtkListStore*)gtk_tree_view_get_model (multiattrib->treeview);
+ g_assert( GSCHEM_DIALOG (multiattrib)->toplevel != NULL );
+
+ /* Update sensitivities */
+ sensitive = (multiattrib->object != NULL);
+ gtk_widget_set_sensitive( GTK_WIDGET( multiattrib->frame_attributes ), sensitive );
+ gtk_widget_set_sensitive( GTK_WIDGET( multiattrib->frame_add ), sensitive );
/* clear the list of attributes */
+ liststore = (GtkListStore*)gtk_tree_view_get_model (multiattrib->treeview);
gtk_list_store_clear (liststore);
-
+
+ /* If we aren't sensitive, there is nothing more to do */
+ if ( multiattrib->object == NULL )
+ return;
+
/* get list of attributes */
object_attribs = o_attrib_return_attribs (
GSCHEM_DIALOG (multiattrib)->toplevel->page_current->object_head,
@@ -1645,5 +1780,5 @@ void multiattrib_update (Multiattrib *multiattrib)
}
/* delete the list of attribute objects */
o_attrib_free_returned (object_attribs);
-
}
+
diff --git a/gschem/src/x_pagesel.c b/gschem/src/x_pagesel.c
index f13515b..5ccfc33 100644
--- a/gschem/src/x_pagesel.c
+++ b/gschem/src/x_pagesel.c
@@ -103,7 +103,13 @@ void x_pagesel_update (TOPLEVEL *toplevel)
g_assert (IS_PAGESEL (toplevel->pswindow));
pagesel_update (PAGESEL (toplevel->pswindow));
}
-
+#warning THIS BREAKES ABSTRACTION, BUT IS A USEFUL HACK FOR NOW
+ if (toplevel->multiattribwindow) {
+ g_object_set (G_OBJECT (toplevel->multiattribwindow),
+ "selection",
+ toplevel->page_current->selection_list,
+ NULL);
+ }
}
/*! \brief Callback for page manager response.
diff --git a/libgeda/include/struct.h b/libgeda/include/struct.h
index 6f0befa..f9b52ec 100644
--- a/libgeda/include/struct.h
+++ b/libgeda/include/struct.h
@@ -563,6 +563,8 @@ struct st_toplevel {
GtkWidget *clib_list;
GtkWidget *basename_list;
+ GtkWidget *multiattribwindow; /* multi-attribute editor */
+
GtkWidget *iwindow; /* image write dialog box */
GtkWidget *ifilename_entry;
diff --git a/libgeda/src/s_toplevel.c b/libgeda/src/s_toplevel.c
index 8acadd7..c94dc57 100644
--- a/libgeda/src/s_toplevel.c
+++ b/libgeda/src/s_toplevel.c
@@ -212,6 +212,8 @@ TOPLEVEL *s_toplevel_new (void)
toplevel->clib_list = NULL;
toplevel->basename_list = NULL;
+ toplevel->multiattribwindow = NULL;
+
/* toplevel->fileselect */
toplevel->iwindow = NULL;
--
1.5.2.3
_______________________________________________
geda-dev mailing list
geda-dev@moria.seul.org
http://www.seul.org/cgi-bin/mailman/listinfo/geda-dev