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;
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 )
247 {
248 sp_item_widget_setup (spw, selection);
249 }
253 static void
254 sp_item_widget_change_selection ( SPWidget *spw,
255 Inkscape::Selection *selection,
256 GtkWidget *itemw )
257 {
258 sp_item_widget_setup (spw, selection);
259 }
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 )
267 {
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 }
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)) {
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"));
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"));
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));
328 } // end of sp_item_widget_setup()
332 static void
333 sp_item_widget_sensitivity_toggled (GtkWidget *widget, SPWidget *spw)
334 {
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));
348 }
350 void
351 sp_item_widget_hidden_toggled(GtkWidget *widget, SPWidget *spw)
352 {
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));
366 }
368 static void
369 sp_item_widget_label_changed (GtkWidget *widget, SPWidget *spw)
370 {
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)
438 {
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 }
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 }
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 }
461 if (w && h) {
462 gtk_window_resize ((GtkWindow *) dlg, w, h);
463 }
465 sp_transientize (dlg);
466 wd.win = dlg;
467 wd.stop = 0;
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);
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 :