Code

moving trunk for module inkscape
[inkscape.git] / src / dialogs / item-properties.cpp
1 #define __SP_ITEM_PROPERTIES_C__
3 /*
4  * Object properties dialog
5  *
6  * Authors:
7  *   Lauris Kaplinski <lauris@kaplinski.com>
8  *   bulia byak <buliabyak@users.sf.net>
9  *
10  * Copyright (C) 1999-2005 Authors
11  * Copyright (C) 2001 Ximian, Inc.
12  *
13  * Released under GNU GPL, read the file 'COPYING' for more information
14  */
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
19 #include <gtk/gtkvbox.h>
20 #include <gtk/gtkhbox.h>
21 #include <gtk/gtktable.h>
22 #include <gtk/gtkcheckbutton.h>
23 #include <gtk/gtkspinbutton.h>
24 #include <gtk/gtklabel.h>
25 #include <gtk/gtkframe.h>
26 #include <gtk/gtktextview.h>
27 #include <gtk/gtktooltips.h>
29 #include <glibmm/i18n.h>
30 #include "helper/window.h"
31 #include "../widgets/sp-widget.h"
32 #include "../inkscape.h"
33 #include "../document.h"
34 #include "../desktop-handles.h"
35 #include "../selection.h"
36 #include "../sp-item.h"
37 #include "../macros.h"
38 #include "../verbs.h"
39 #include "../interface.h"
41 #include "dialog-events.h"
42 #include "../prefs-utils.h"
45 static GtkWidget *dlg = NULL;
46 static win_data wd;
48 // impossible original values to make sure they are read from prefs
49 static gint x = -1000, y = -1000, w = 0, h = 0; 
50 static gchar *prefs_path = "dialogs.object";
52 static void sp_item_widget_modify_selection (SPWidget *spw, Inkscape::Selection *selection, guint flags, GtkWidget *itemw);
53 static void sp_item_widget_change_selection (SPWidget *spw, Inkscape::Selection *selection, GtkWidget *itemw);
54 static void sp_item_widget_setup (SPWidget *spw, Inkscape::Selection *selection);
55 static void sp_item_widget_sensitivity_toggled (GtkWidget *widget, SPWidget *spw);
56 static void sp_item_widget_hidden_toggled (GtkWidget *widget, SPWidget *spw);
57 static void sp_item_widget_label_changed (GtkWidget *widget, SPWidget *spw);
59 static void
60 sp_item_dialog_destroy (GtkObject *object, gpointer data)
61 {
62     sp_signal_disconnect_by_data (INKSCAPE, dlg);
63     wd.win = dlg = NULL;
64     wd.stop = 0;
65 }
67 static gboolean
68 sp_item_dialog_delete (GtkObject *object, GdkEvent *event, gpointer data)
69 {
70     gtk_window_get_position ((GtkWindow *) dlg, &x, &y);
71     gtk_window_get_size ((GtkWindow *) dlg, &w, &h);
73     prefs_set_int_attribute (prefs_path, "x", x);
74     prefs_set_int_attribute (prefs_path, "y", y);
75     prefs_set_int_attribute (prefs_path, "w", w);
76     prefs_set_int_attribute (prefs_path, "h", h);
78     return FALSE; // which means, go ahead and destroy it
80
82 /**
83  * \brief  Creates new instance of item properties widget 
84  *
85  */
86 GtkWidget *
87 sp_item_widget_new (void)
88 {
90     GtkWidget *spw, *vb, *t, *cb, *l, *f, *tf, *pb;
91     GtkTextBuffer *desc_buffer;
93     GtkTooltips *tt = gtk_tooltips_new();
95     /* Create container widget */
96     spw = sp_widget_new_global (INKSCAPE);
97     gtk_signal_connect ( GTK_OBJECT (spw), "modify_selection", 
98                          GTK_SIGNAL_FUNC (sp_item_widget_modify_selection), 
99                          spw );
100     gtk_signal_connect ( GTK_OBJECT (spw), "change_selection", 
101                          GTK_SIGNAL_FUNC (sp_item_widget_change_selection), 
102                          spw );
104     vb = gtk_vbox_new (FALSE, 0);
105     gtk_container_add (GTK_CONTAINER (spw), vb);
107     t = gtk_table_new (3, 4, FALSE);
108     gtk_container_set_border_width(GTK_CONTAINER(t), 4);
109     gtk_table_set_row_spacings (GTK_TABLE (t), 4);
110     gtk_table_set_col_spacings (GTK_TABLE (t), 4);
111     gtk_box_pack_start (GTK_BOX (vb), t, TRUE, TRUE, 0);
114     /* Create the label for the object id */
115     l = gtk_label_new_with_mnemonic (_("_Id"));
116     gtk_misc_set_alignment (GTK_MISC (l), 1, 0.5);
117     gtk_table_attach ( GTK_TABLE (t), l, 0, 1, 0, 1, 
118                        (GtkAttachOptions)( GTK_SHRINK | GTK_FILL ), 
119                        (GtkAttachOptions)0, 0, 0 );
120     gtk_object_set_data (GTK_OBJECT (spw), "id_label", l);
122     /* Create the entry box for the object id */
123     tf = gtk_entry_new ();
124     gtk_tooltips_set_tip (tt, tf, _("The id= attribute (only letters, digits, and the characters .-_: allowed)"), NULL);
125     gtk_entry_set_max_length (GTK_ENTRY (tf), 64);
126     gtk_table_attach ( GTK_TABLE (t), tf, 1, 2, 0, 1, 
127                        (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ), 
128                        (GtkAttachOptions)0, 0, 0 );
129     gtk_object_set_data (GTK_OBJECT (spw), "id", tf);
130     gtk_label_set_mnemonic_widget (GTK_LABEL(l), tf);
132     // pressing enter in the id field is the same as clicking Set:
133     g_signal_connect ( G_OBJECT (tf), "activate", G_CALLBACK (sp_item_widget_label_changed), spw);
134     // focus is in the id field initially:
135     gtk_widget_grab_focus (GTK_WIDGET (tf));
137     /* Button for setting the object's id, label, title and description. */
138     pb = gtk_button_new_with_mnemonic (_("_Set"));
139     gtk_table_attach ( GTK_TABLE (t), pb, 2, 3, 0, 1, 
140                        (GtkAttachOptions)( GTK_SHRINK | GTK_FILL ), 
141                        (GtkAttachOptions)0, 0, 0 );
142     gtk_signal_connect ( GTK_OBJECT (pb), "clicked", 
143                          GTK_SIGNAL_FUNC (sp_item_widget_label_changed), 
144                          spw );
146     /* Create the label for the object label */
147     l = gtk_label_new_with_mnemonic (_("_Label"));
148     gtk_misc_set_alignment (GTK_MISC (l), 1, 0.5);
149     gtk_table_attach ( GTK_TABLE (t), l, 0, 1, 1, 2, 
150                        (GtkAttachOptions)( GTK_SHRINK | GTK_FILL ), 
151                        (GtkAttachOptions)0, 0, 0 );
152     gtk_object_set_data (GTK_OBJECT (spw), "label_label", l);
154     /* Create the entry box for the object label */
155     tf = gtk_entry_new ();
156     gtk_tooltips_set_tip (tt, tf, _("A freeform label for the object"), NULL);
157     gtk_entry_set_max_length (GTK_ENTRY (tf), 256);
158     gtk_table_attach ( GTK_TABLE (t), tf, 1, 2, 1, 2, 
159                        (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ), 
160                        (GtkAttachOptions)0, 0, 0 );
161     gtk_object_set_data (GTK_OBJECT (spw), "label", tf);
162     gtk_label_set_mnemonic_widget (GTK_LABEL(l), tf);
164     // pressing enter in the label field is the same as clicking Set:
165     g_signal_connect ( G_OBJECT (tf), "activate", G_CALLBACK (sp_item_widget_label_changed), spw);
167     /* Create the label for the object title */
168     l = gtk_label_new (_("Title"));
169     gtk_misc_set_alignment (GTK_MISC (l), 1, 0.5);
170     gtk_table_attach ( GTK_TABLE (t), l, 0, 1, 2, 3, 
171                        (GtkAttachOptions)( GTK_SHRINK | GTK_FILL ), 
172                        (GtkAttachOptions)0, 0, 0 );
173     gtk_object_set_data (GTK_OBJECT (spw), "title_label", l);
175     /* Create the entry box for the object title */
176     tf = gtk_entry_new ();
177     gtk_widget_set_sensitive (GTK_WIDGET (tf), FALSE);
178     gtk_entry_set_max_length (GTK_ENTRY (tf), 256);
179     gtk_table_attach ( GTK_TABLE (t), tf, 1, 3, 2, 3, 
180                        (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ), 
181                        (GtkAttachOptions)0, 0, 0 );
182     gtk_object_set_data (GTK_OBJECT (spw), "title", tf);
184     /* Create the frame for the object description */
185     f = gtk_frame_new (_("Description"));
186     gtk_table_attach ( GTK_TABLE (t), f, 0, 3, 3, 4, 
187                        (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ), 
188                        (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ), 0, 0 );
189     gtk_object_set_data (GTK_OBJECT (spw), "desc_frame", l);
191     /* Create the text view box for the object description */
192     GtkWidget *textframe = gtk_frame_new(NULL);
193     gtk_container_set_border_width(GTK_CONTAINER(textframe), 4);
194     gtk_widget_set_sensitive (GTK_WIDGET (textframe), FALSE);
195     gtk_container_add (GTK_CONTAINER (f), textframe);
196     gtk_frame_set_shadow_type (GTK_FRAME (textframe), GTK_SHADOW_IN);
198     tf = gtk_text_view_new();
199     desc_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tf));
200     gtk_text_buffer_set_text(desc_buffer, "", -1);
201     gtk_container_add (GTK_CONTAINER (textframe), tf);
202     gtk_object_set_data (GTK_OBJECT (spw), "desc", tf);
204     /* Check boxes */
205     GtkWidget *hb_cb = gtk_hbox_new (FALSE, 0);
206     gtk_box_pack_start (GTK_BOX (vb), hb_cb, FALSE, FALSE, 0);
207     t = gtk_table_new (1, 2, TRUE);
208     gtk_container_set_border_width(GTK_CONTAINER(t), 0);
209     gtk_box_pack_start (GTK_BOX (hb_cb), t, TRUE, TRUE, 10);
211     /* Hide */
212     cb = gtk_check_button_new_with_mnemonic (_("_Hide"));
213     gtk_tooltips_set_tip (tt, cb, _("Check to make the object invisible"), NULL);
214     gtk_table_attach ( GTK_TABLE (t), cb, 0, 1, 0, 1, 
215                        (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ), 
216                        (GtkAttachOptions)0, 0, 0 );
217     g_signal_connect (G_OBJECT(cb), "toggled", G_CALLBACK(sp_item_widget_hidden_toggled), spw);
218     gtk_object_set_data(GTK_OBJECT(spw), "hidden", cb);
220     /* Lock */
221     // TRANSLATORS: "Lock" is a verb here
222     cb = gtk_check_button_new_with_mnemonic (_("L_ock"));
223     gtk_tooltips_set_tip (tt, cb, _("Check to make the object insensitive (not selectable by mouse)"), NULL);
224     gtk_table_attach ( GTK_TABLE (t), cb, 1, 2, 0, 1, 
225                        (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ), 
226                        (GtkAttachOptions)0, 0, 0 );
227     gtk_signal_connect ( GTK_OBJECT (cb), "toggled", 
228                          GTK_SIGNAL_FUNC (sp_item_widget_sensitivity_toggled), 
229                          spw );
230     gtk_object_set_data (GTK_OBJECT (spw), "sensitive", cb);
232     gtk_widget_show_all (spw);
234     sp_item_widget_setup (SP_WIDGET (spw), SP_DT_SELECTION (SP_ACTIVE_DESKTOP));
236     return (GtkWidget *) spw;
237     
238 } //end of sp_item_widget_new()
242 static void
243 sp_item_widget_modify_selection ( SPWidget *spw, 
244                                   Inkscape::Selection *selection, 
245                                   guint flags, 
246                                   GtkWidget *itemw )
248     sp_item_widget_setup (spw, selection);
253 static void
254 sp_item_widget_change_selection ( SPWidget *spw, 
255                                   Inkscape::Selection *selection, 
256                                   GtkWidget *itemw )
258     sp_item_widget_setup (spw, selection);
262 /**
263 *  \param selection Selection to use; should not be NULL.
264 */
265 static void
266 sp_item_widget_setup ( SPWidget *spw, Inkscape::Selection *selection )
268     g_assert (selection != NULL);
270     if (gtk_object_get_data (GTK_OBJECT (spw), "blocked"))
271         return;
273     if (!selection->singleItem()) {
274         gtk_widget_set_sensitive (GTK_WIDGET (spw), FALSE);
275         return;
276     } else {
277         gtk_widget_set_sensitive (GTK_WIDGET (spw), TRUE);
278     }
279     
280     gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (TRUE));
282     SPItem *item = selection->singleItem();
284     /* Sensitive */
285     GtkWidget *w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "sensitive"));
286     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), item->isLocked());
288     /* Hidden */
289     w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "hidden"));
290     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), item->isExplicitlyHidden());
292     if (SP_OBJECT_IS_CLONED (item)) {
293     
294         /* ID */
295         w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id"));
296         gtk_entry_set_text (GTK_ENTRY (w), "");
297         gtk_widget_set_sensitive (w, FALSE);
298         w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id_label"));
299         gtk_label_set_text (GTK_LABEL (w), _("Ref"));
300     
301         /* Label */
302         w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label"));
303         gtk_entry_set_text (GTK_ENTRY (w), "");
304         gtk_widget_set_sensitive (w, FALSE);
305         w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label_label"));
306         gtk_label_set_text (GTK_LABEL (w), _("Ref"));
307     
308     } else {
309         SPObject *obj = (SPObject*)item;
311         /* ID */
312         w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id"));
313         gtk_entry_set_text (GTK_ENTRY (w), obj->id);
314         gtk_widget_set_sensitive (w, TRUE);
315         w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id_label"));
316         gtk_label_set_markup_with_mnemonic (GTK_LABEL (w), _("_Id"));
318         /* Label */
319         w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label"));
320         gtk_entry_set_text (GTK_ENTRY (w), obj->defaultLabel());
321         gtk_widget_set_sensitive (w, TRUE);
322         w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label_label"));
323     }
325     gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (FALSE));
326     
327     
328 } // end of sp_item_widget_setup()
332 static void
333 sp_item_widget_sensitivity_toggled (GtkWidget *widget, SPWidget *spw)
335     if (gtk_object_get_data (GTK_OBJECT (spw), "blocked"))
336         return;
338     SPItem *item = SP_DT_SELECTION(SP_ACTIVE_DESKTOP)->singleItem();
339     g_return_if_fail (item != NULL);
341     gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (TRUE));
343     item->setLocked(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
345     sp_document_maybe_done (SP_ACTIVE_DOCUMENT,  "ItemDialog:insensitive");
347     gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (FALSE));
350 void
351 sp_item_widget_hidden_toggled(GtkWidget *widget, SPWidget *spw)
353     if (gtk_object_get_data (GTK_OBJECT (spw), "blocked"))
354         return;
356     SPItem *item = SP_DT_SELECTION(SP_ACTIVE_DESKTOP)->singleItem();
357     g_return_if_fail (item != NULL);
359     gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (TRUE));
361     item->setExplicitlyHidden(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
363     sp_document_maybe_done (SP_ACTIVE_DOCUMENT,  "ItemDialog:visiblity");
365     gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (FALSE));
368 static void
369 sp_item_widget_label_changed (GtkWidget *widget, SPWidget *spw)
371     if (gtk_object_get_data (GTK_OBJECT (spw), "blocked")) 
372         return;
374     SPItem *item = SP_DT_SELECTION(SP_ACTIVE_DESKTOP)->singleItem();
375     g_return_if_fail (item != NULL);
377     gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (TRUE));
379     /* Retrieve the label widget for the object's id */
380     GtkWidget *id_entry = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id"));
381     gchar *id = (gchar *) gtk_entry_get_text (GTK_ENTRY (id_entry));
382     g_strcanon (id, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.:", '_');
383     GtkWidget *id_label = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id_label"));
384     if (!strcmp (id, SP_OBJECT_ID(item))) {
385         gtk_label_set_markup_with_mnemonic (GTK_LABEL (id_label), _("_Id"));
386     } else if (!*id || !isalnum (*id)) {
387         gtk_label_set_text (GTK_LABEL (id_label), _("Id invalid! "));
388     } else if (SP_ACTIVE_DOCUMENT->getObjectById(id) != NULL) {
389         gtk_label_set_text (GTK_LABEL (id_label), _("Id exists! "));
390     } else {
391         SPException ex;
392         gtk_label_set_markup_with_mnemonic (GTK_LABEL (id_label), _("_Id"));
393         SP_EXCEPTION_INIT (&ex);
394         sp_object_setAttribute (SP_OBJECT (item), "id", id, &ex);
395         sp_document_maybe_done (SP_ACTIVE_DOCUMENT, "ItemDialog:id");
396     }
398     /* Retrieve the label widget for the object's label */
399     GtkWidget *label_entry = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label"));
400     gchar *label = (gchar *)gtk_entry_get_text (GTK_ENTRY (label_entry));
401     g_assert(label != NULL);
403     /* Give feedback on success of setting the drawing object's label
404      * using the widget's label text 
405      */
406     SPObject *obj = (SPObject*)item;
407     if (strcmp (label, obj->defaultLabel())) {
408         obj->setLabel(label);
409         sp_document_maybe_done (SP_ACTIVE_DOCUMENT, "inkscape:label");
410     }
412     /* Retrieve the title */
413     GtkWidget *w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "title"));
414     gchar *title = (gchar *)gtk_entry_get_text (GTK_ENTRY (w));
415     if (title != NULL) {
416         obj->setTitle(title);
417         sp_document_maybe_done (SP_ACTIVE_DOCUMENT, "title");
418     }
420     /* Retrieve the description */
421     gchar *desc = NULL; /* TODO:  get text from text buffer */
422     if (desc != NULL) {
423         obj->setDesc(desc);
424         sp_document_maybe_done (SP_ACTIVE_DOCUMENT, "desc");
425     }
427     gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (FALSE));
429 } // end of sp_item_widget_label_changed()
432 /**
433  * \brief  Dialog 
434  *
435  */
436 void
437 sp_item_dialog (void)
439     if (dlg == NULL) {
441         gchar title[500];
442         sp_ui_dialog_title_string (Inkscape::Verb::get(SP_VERB_DIALOG_ITEM), title);
444         dlg = sp_window_new (title, TRUE);
445         if (x == -1000 || y == -1000) {
446             x = prefs_get_int_attribute (prefs_path, "x", 0);
447             y = prefs_get_int_attribute (prefs_path, "y", 0);
448         }
449         
450         if (w ==0 || h == 0) {
451             w = prefs_get_int_attribute (prefs_path, "w", 0);
452             h = prefs_get_int_attribute (prefs_path, "h", 0);
453         }
454         
455         if (x != 0 || y != 0) {
456             gtk_window_move ((GtkWindow *) dlg, x, y);
457         } else {
458             gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
459         }
460         
461         if (w && h) {
462             gtk_window_resize ((GtkWindow *) dlg, w, h);
463         }
464         
465         sp_transientize (dlg);
466         wd.win = dlg;
467         wd.stop = 0;
468         
469         g_signal_connect   ( G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (sp_transientize_callback), &wd);
470         gtk_signal_connect ( GTK_OBJECT (dlg), "event", GTK_SIGNAL_FUNC (sp_dialog_event_handler), dlg);
471         gtk_signal_connect ( GTK_OBJECT (dlg), "destroy", G_CALLBACK (sp_item_dialog_destroy), dlg);
472         gtk_signal_connect ( GTK_OBJECT (dlg), "delete_event", G_CALLBACK (sp_item_dialog_delete), dlg);
473         g_signal_connect   ( G_OBJECT (INKSCAPE), "shut_down", G_CALLBACK (sp_item_dialog_delete), dlg);
474         g_signal_connect   ( G_OBJECT (INKSCAPE), "dialogs_hide", G_CALLBACK (sp_dialog_hide), dlg);
475         g_signal_connect   ( G_OBJECT (INKSCAPE), "dialogs_unhide", G_CALLBACK (sp_dialog_unhide), dlg);
477         // Dialog-specific stuff
478         GtkWidget *itemw = sp_item_widget_new ();
479         gtk_widget_show (itemw);
480         gtk_container_add (GTK_CONTAINER (dlg), itemw);
481       
482     }
484     gtk_window_present ((GtkWindow *) dlg);
485
488 /*
489   Local Variables:
490   mode:c++
491   c-file-style:"stroustrup"
492   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
493   indent-tabs-mode:nil
494   fill-column:99
495   End:
496 */
497 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :