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 * Johan Engelen <goejendaagh@zonnet.nl>
10 *
11 * Copyright (C) 1999-2006 Authors
12 * Copyright (C) 2001 Ximian, Inc.
13 *
14 * Released under GNU GPL, read the file 'COPYING' for more information
15 */
17 #ifdef HAVE_CONFIG_H
18 # include "config.h"
19 #endif
20 #include <gtk/gtkvbox.h>
21 #include <gtk/gtkhbox.h>
22 #include <gtk/gtktable.h>
23 #include <gtk/gtkcheckbutton.h>
24 #include <gtk/gtkspinbutton.h>
25 #include <gtk/gtklabel.h>
26 #include <gtk/gtkframe.h>
27 #include <gtk/gtktextview.h>
28 #include <gtk/gtktooltips.h>
30 #include <glibmm/i18n.h>
31 #include "helper/window.h"
32 #include "../widgets/sp-widget.h"
33 #include "../inkscape.h"
34 #include "../document.h"
35 #include "../desktop-handles.h"
36 #include "../selection.h"
37 #include "../sp-item.h"
38 #include "../macros.h"
39 #include "../verbs.h"
40 #include "../interface.h"
42 #include "dialog-events.h"
43 #include "../prefs-utils.h"
45 #define MIN_ONSCREEN_DISTANCE 50
47 static GtkWidget *dlg = NULL;
48 static win_data wd;
50 // impossible original values to make sure they are read from prefs
51 static gint x = -1000, y = -1000, w = 0, h = 0;
52 static gchar *prefs_path = "dialogs.object";
54 static void sp_item_widget_modify_selection (SPWidget *spw, Inkscape::Selection *selection, guint flags, GtkWidget *itemw);
55 static void sp_item_widget_change_selection (SPWidget *spw, Inkscape::Selection *selection, GtkWidget *itemw);
56 static void sp_item_widget_setup (SPWidget *spw, Inkscape::Selection *selection);
57 static void sp_item_widget_sensitivity_toggled (GtkWidget *widget, SPWidget *spw);
58 static void sp_item_widget_hidden_toggled (GtkWidget *widget, SPWidget *spw);
59 static void sp_item_widget_label_changed (GtkWidget *widget, SPWidget *spw);
61 static void
62 sp_item_dialog_destroy (GtkObject *object, gpointer data)
63 {
64 sp_signal_disconnect_by_data (INKSCAPE, dlg);
65 wd.win = dlg = NULL;
66 wd.stop = 0;
67 }
69 static gboolean
70 sp_item_dialog_delete (GtkObject *object, GdkEvent *event, gpointer data)
71 {
72 gtk_window_get_position ((GtkWindow *) dlg, &x, &y);
73 gtk_window_get_size ((GtkWindow *) dlg, &w, &h);
75 if (x<0) x=0;
76 if (y<0) y=0;
78 prefs_set_int_attribute (prefs_path, "x", x);
79 prefs_set_int_attribute (prefs_path, "y", y);
80 prefs_set_int_attribute (prefs_path, "w", w);
81 prefs_set_int_attribute (prefs_path, "h", h);
83 return FALSE; // which means, go ahead and destroy it
85 }
87 /**
88 * \brief Creates new instance of item properties widget
89 *
90 */
91 GtkWidget *
92 sp_item_widget_new (void)
93 {
95 GtkWidget *spw, *vb, *t, *cb, *l, *f, *tf, *pb;
96 GtkTextBuffer *desc_buffer;
98 GtkTooltips *tt = gtk_tooltips_new();
100 /* Create container widget */
101 spw = sp_widget_new_global (INKSCAPE);
102 gtk_signal_connect ( GTK_OBJECT (spw), "modify_selection",
103 GTK_SIGNAL_FUNC (sp_item_widget_modify_selection),
104 spw );
105 gtk_signal_connect ( GTK_OBJECT (spw), "change_selection",
106 GTK_SIGNAL_FUNC (sp_item_widget_change_selection),
107 spw );
109 vb = gtk_vbox_new (FALSE, 0);
110 gtk_container_add (GTK_CONTAINER (spw), vb);
112 t = gtk_table_new (3, 4, FALSE);
113 gtk_container_set_border_width(GTK_CONTAINER(t), 4);
114 gtk_table_set_row_spacings (GTK_TABLE (t), 4);
115 gtk_table_set_col_spacings (GTK_TABLE (t), 4);
116 gtk_box_pack_start (GTK_BOX (vb), t, TRUE, TRUE, 0);
119 /* Create the label for the object id */
120 l = gtk_label_new_with_mnemonic (_("_Id"));
121 gtk_misc_set_alignment (GTK_MISC (l), 1, 0.5);
122 gtk_table_attach ( GTK_TABLE (t), l, 0, 1, 0, 1,
123 (GtkAttachOptions)( GTK_SHRINK | GTK_FILL ),
124 (GtkAttachOptions)0, 0, 0 );
125 gtk_object_set_data (GTK_OBJECT (spw), "id_label", l);
127 /* Create the entry box for the object id */
128 tf = gtk_entry_new ();
129 gtk_tooltips_set_tip (tt, tf, _("The id= attribute (only letters, digits, and the characters .-_: allowed)"), NULL);
130 gtk_entry_set_max_length (GTK_ENTRY (tf), 64);
131 gtk_table_attach ( GTK_TABLE (t), tf, 1, 2, 0, 1,
132 (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
133 (GtkAttachOptions)0, 0, 0 );
134 gtk_object_set_data (GTK_OBJECT (spw), "id", tf);
135 gtk_label_set_mnemonic_widget (GTK_LABEL(l), tf);
137 // pressing enter in the id field is the same as clicking Set:
138 g_signal_connect ( G_OBJECT (tf), "activate", G_CALLBACK (sp_item_widget_label_changed), spw);
139 // focus is in the id field initially:
140 gtk_widget_grab_focus (GTK_WIDGET (tf));
142 /* Button for setting the object's id, label, title and description. */
143 pb = gtk_button_new_with_mnemonic (_("_Set"));
144 gtk_table_attach ( GTK_TABLE (t), pb, 2, 3, 0, 1,
145 (GtkAttachOptions)( GTK_SHRINK | GTK_FILL ),
146 (GtkAttachOptions)0, 0, 0 );
147 gtk_signal_connect ( GTK_OBJECT (pb), "clicked",
148 GTK_SIGNAL_FUNC (sp_item_widget_label_changed),
149 spw );
151 /* Create the label for the object label */
152 l = gtk_label_new_with_mnemonic (_("_Label"));
153 gtk_misc_set_alignment (GTK_MISC (l), 1, 0.5);
154 gtk_table_attach ( GTK_TABLE (t), l, 0, 1, 1, 2,
155 (GtkAttachOptions)( GTK_SHRINK | GTK_FILL ),
156 (GtkAttachOptions)0, 0, 0 );
157 gtk_object_set_data (GTK_OBJECT (spw), "label_label", l);
159 /* Create the entry box for the object label */
160 tf = gtk_entry_new ();
161 gtk_tooltips_set_tip (tt, tf, _("A freeform label for the object"), NULL);
162 gtk_entry_set_max_length (GTK_ENTRY (tf), 256);
163 gtk_table_attach ( GTK_TABLE (t), tf, 1, 2, 1, 2,
164 (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
165 (GtkAttachOptions)0, 0, 0 );
166 gtk_object_set_data (GTK_OBJECT (spw), "label", tf);
167 gtk_label_set_mnemonic_widget (GTK_LABEL(l), tf);
169 // pressing enter in the label field is the same as clicking Set:
170 g_signal_connect ( G_OBJECT (tf), "activate", G_CALLBACK (sp_item_widget_label_changed), spw);
172 /* Create the label for the object title */
173 l = gtk_label_new (_("Title"));
174 gtk_misc_set_alignment (GTK_MISC (l), 1, 0.5);
175 gtk_table_attach ( GTK_TABLE (t), l, 0, 1, 2, 3,
176 (GtkAttachOptions)( GTK_SHRINK | GTK_FILL ),
177 (GtkAttachOptions)0, 0, 0 );
178 gtk_object_set_data (GTK_OBJECT (spw), "title_label", l);
180 /* Create the entry box for the object title */
181 tf = gtk_entry_new ();
182 gtk_widget_set_sensitive (GTK_WIDGET (tf), FALSE);
183 gtk_entry_set_max_length (GTK_ENTRY (tf), 256);
184 gtk_table_attach ( GTK_TABLE (t), tf, 1, 3, 2, 3,
185 (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
186 (GtkAttachOptions)0, 0, 0 );
187 gtk_object_set_data (GTK_OBJECT (spw), "title", tf);
189 /* Create the frame for the object description */
190 f = gtk_frame_new (_("Description"));
191 gtk_table_attach ( GTK_TABLE (t), f, 0, 3, 3, 4,
192 (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
193 (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ), 0, 0 );
194 gtk_object_set_data (GTK_OBJECT (spw), "desc_frame", l);
196 /* Create the text view box for the object description */
197 GtkWidget *textframe = gtk_frame_new(NULL);
198 gtk_container_set_border_width(GTK_CONTAINER(textframe), 4);
199 gtk_widget_set_sensitive (GTK_WIDGET (textframe), FALSE);
200 gtk_container_add (GTK_CONTAINER (f), textframe);
201 gtk_frame_set_shadow_type (GTK_FRAME (textframe), GTK_SHADOW_IN);
203 tf = gtk_text_view_new();
204 desc_buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(tf));
205 gtk_text_buffer_set_text(desc_buffer, "", -1);
206 gtk_container_add (GTK_CONTAINER (textframe), tf);
207 gtk_object_set_data (GTK_OBJECT (spw), "desc", tf);
209 /* Check boxes */
210 GtkWidget *hb_cb = gtk_hbox_new (FALSE, 0);
211 gtk_box_pack_start (GTK_BOX (vb), hb_cb, FALSE, FALSE, 0);
212 t = gtk_table_new (1, 2, TRUE);
213 gtk_container_set_border_width(GTK_CONTAINER(t), 0);
214 gtk_box_pack_start (GTK_BOX (hb_cb), t, TRUE, TRUE, 10);
216 /* Hide */
217 cb = gtk_check_button_new_with_mnemonic (_("_Hide"));
218 gtk_tooltips_set_tip (tt, cb, _("Check to make the object invisible"), NULL);
219 gtk_table_attach ( GTK_TABLE (t), cb, 0, 1, 0, 1,
220 (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
221 (GtkAttachOptions)0, 0, 0 );
222 g_signal_connect (G_OBJECT(cb), "toggled", G_CALLBACK(sp_item_widget_hidden_toggled), spw);
223 gtk_object_set_data(GTK_OBJECT(spw), "hidden", cb);
225 /* Lock */
226 // TRANSLATORS: "Lock" is a verb here
227 cb = gtk_check_button_new_with_mnemonic (_("L_ock"));
228 gtk_tooltips_set_tip (tt, cb, _("Check to make the object insensitive (not selectable by mouse)"), NULL);
229 gtk_table_attach ( GTK_TABLE (t), cb, 1, 2, 0, 1,
230 (GtkAttachOptions)( GTK_EXPAND | GTK_FILL ),
231 (GtkAttachOptions)0, 0, 0 );
232 gtk_signal_connect ( GTK_OBJECT (cb), "toggled",
233 GTK_SIGNAL_FUNC (sp_item_widget_sensitivity_toggled),
234 spw );
235 gtk_object_set_data (GTK_OBJECT (spw), "sensitive", cb);
237 gtk_widget_show_all (spw);
239 sp_item_widget_setup (SP_WIDGET (spw), sp_desktop_selection (SP_ACTIVE_DESKTOP));
241 return (GtkWidget *) spw;
243 } //end of sp_item_widget_new()
247 static void
248 sp_item_widget_modify_selection ( SPWidget *spw,
249 Inkscape::Selection *selection,
250 guint flags,
251 GtkWidget *itemw )
252 {
253 sp_item_widget_setup (spw, selection);
254 }
258 static void
259 sp_item_widget_change_selection ( SPWidget *spw,
260 Inkscape::Selection *selection,
261 GtkWidget *itemw )
262 {
263 sp_item_widget_setup (spw, selection);
264 }
267 /**
268 * \param selection Selection to use; should not be NULL.
269 */
270 static void
271 sp_item_widget_setup ( SPWidget *spw, Inkscape::Selection *selection )
272 {
273 g_assert (selection != NULL);
275 if (gtk_object_get_data (GTK_OBJECT (spw), "blocked"))
276 return;
278 if (!selection->singleItem()) {
279 gtk_widget_set_sensitive (GTK_WIDGET (spw), FALSE);
280 return;
281 } else {
282 gtk_widget_set_sensitive (GTK_WIDGET (spw), TRUE);
283 }
285 gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (TRUE));
287 SPItem *item = selection->singleItem();
289 /* Sensitive */
290 GtkWidget *w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "sensitive"));
291 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w), item->isLocked());
293 /* Hidden */
294 w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "hidden"));
295 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(w), item->isExplicitlyHidden());
297 if (SP_OBJECT_IS_CLONED (item)) {
299 /* ID */
300 w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id"));
301 gtk_entry_set_text (GTK_ENTRY (w), "");
302 gtk_widget_set_sensitive (w, FALSE);
303 w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id_label"));
304 gtk_label_set_text (GTK_LABEL (w), _("Ref"));
306 /* Label */
307 w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label"));
308 gtk_entry_set_text (GTK_ENTRY (w), "");
309 gtk_widget_set_sensitive (w, FALSE);
310 w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label_label"));
311 gtk_label_set_text (GTK_LABEL (w), _("Ref"));
313 } else {
314 SPObject *obj = (SPObject*)item;
316 /* ID */
317 w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id"));
318 gtk_entry_set_text (GTK_ENTRY (w), obj->id);
319 gtk_widget_set_sensitive (w, TRUE);
320 w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id_label"));
321 gtk_label_set_markup_with_mnemonic (GTK_LABEL (w), _("_Id"));
323 /* Label */
324 w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label"));
325 gtk_entry_set_text (GTK_ENTRY (w), obj->defaultLabel());
326 gtk_widget_set_sensitive (w, TRUE);
327 w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label_label"));
328 }
330 gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (FALSE));
333 } // end of sp_item_widget_setup()
337 static void
338 sp_item_widget_sensitivity_toggled (GtkWidget *widget, SPWidget *spw)
339 {
340 if (gtk_object_get_data (GTK_OBJECT (spw), "blocked"))
341 return;
343 SPItem *item = sp_desktop_selection(SP_ACTIVE_DESKTOP)->singleItem();
344 g_return_if_fail (item != NULL);
346 gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (TRUE));
348 item->setLocked(gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)));
350 sp_document_done (SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
351 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))? _("Lock object") : _("Unlock object"));
353 gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (FALSE));
354 }
356 void
357 sp_item_widget_hidden_toggled(GtkWidget *widget, SPWidget *spw)
358 {
359 if (gtk_object_get_data (GTK_OBJECT (spw), "blocked"))
360 return;
362 SPItem *item = sp_desktop_selection(SP_ACTIVE_DESKTOP)->singleItem();
363 g_return_if_fail (item != NULL);
365 gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (TRUE));
367 item->setExplicitlyHidden(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)));
369 sp_document_done (SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
370 gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))? _("Hide object") : _("Unhide object"));
372 gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (FALSE));
373 }
375 static void
376 sp_item_widget_label_changed (GtkWidget *widget, SPWidget *spw)
377 {
378 if (gtk_object_get_data (GTK_OBJECT (spw), "blocked"))
379 return;
381 SPItem *item = sp_desktop_selection(SP_ACTIVE_DESKTOP)->singleItem();
382 g_return_if_fail (item != NULL);
384 gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (TRUE));
386 /* Retrieve the label widget for the object's id */
387 GtkWidget *id_entry = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id"));
388 gchar *id = (gchar *) gtk_entry_get_text (GTK_ENTRY (id_entry));
389 g_strcanon (id, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.:", '_');
390 GtkWidget *id_label = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "id_label"));
391 if (!strcmp (id, SP_OBJECT_ID(item))) {
392 gtk_label_set_markup_with_mnemonic (GTK_LABEL (id_label), _("_Id"));
393 } else if (!*id || !isalnum (*id)) {
394 gtk_label_set_text (GTK_LABEL (id_label), _("Id invalid! "));
395 } else if (SP_ACTIVE_DOCUMENT->getObjectById(id) != NULL) {
396 gtk_label_set_text (GTK_LABEL (id_label), _("Id exists! "));
397 } else {
398 SPException ex;
399 gtk_label_set_markup_with_mnemonic (GTK_LABEL (id_label), _("_Id"));
400 SP_EXCEPTION_INIT (&ex);
401 sp_object_setAttribute (SP_OBJECT (item), "id", id, &ex);
402 sp_document_done (SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
403 _("Set object ID"));
404 }
406 /* Retrieve the label widget for the object's label */
407 GtkWidget *label_entry = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "label"));
408 gchar *label = (gchar *)gtk_entry_get_text (GTK_ENTRY (label_entry));
409 g_assert(label != NULL);
411 /* Give feedback on success of setting the drawing object's label
412 * using the widget's label text
413 */
414 SPObject *obj = (SPObject*)item;
415 if (strcmp (label, obj->defaultLabel())) {
416 obj->setLabel(label);
417 sp_document_done (SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
418 _("Set object label"));
419 }
421 /* Retrieve the title */
422 GtkWidget *w = GTK_WIDGET(gtk_object_get_data (GTK_OBJECT (spw), "title"));
423 gchar *title = (gchar *)gtk_entry_get_text (GTK_ENTRY (w));
424 if (title != NULL) {
425 obj->setTitle(title);
426 sp_document_done (SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
427 _("Set object title"));
428 }
430 /* Retrieve the description */
431 gchar *desc = NULL; /* TODO: get text from text buffer */
432 if (desc != NULL) {
433 obj->setDesc(desc);
434 sp_document_done (SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
435 _("Set object description"));
436 }
438 gtk_object_set_data (GTK_OBJECT (spw), "blocked", GUINT_TO_POINTER (FALSE));
440 } // end of sp_item_widget_label_changed()
443 /**
444 * \brief Dialog
445 *
446 */
447 void
448 sp_item_dialog (void)
449 {
450 if (dlg == NULL) {
452 gchar title[500];
453 sp_ui_dialog_title_string (Inkscape::Verb::get(SP_VERB_DIALOG_ITEM), title);
455 dlg = sp_window_new (title, TRUE);
456 if (x == -1000 || y == -1000) {
457 x = prefs_get_int_attribute (prefs_path, "x", -1000);
458 y = prefs_get_int_attribute (prefs_path, "y", -1000);
459 }
461 if (w ==0 || h == 0) {
462 w = prefs_get_int_attribute (prefs_path, "w", 0);
463 h = prefs_get_int_attribute (prefs_path, "h", 0);
464 }
466 // if (x<0) x=0;
467 // if (y<0) y=0;
469 if (w && h) {
470 gtk_window_resize ((GtkWindow *) dlg, w, h);
471 }
472 if (x >= 0 && y >= 0 && (x < (gdk_screen_width()-MIN_ONSCREEN_DISTANCE)) && (y < (gdk_screen_height()-MIN_ONSCREEN_DISTANCE))) {
473 gtk_window_move ((GtkWindow *) dlg, x, y);
474 } else {
475 gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
476 }
479 sp_transientize (dlg);
480 wd.win = dlg;
481 wd.stop = 0;
483 g_signal_connect ( G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (sp_transientize_callback), &wd);
484 gtk_signal_connect ( GTK_OBJECT (dlg), "event", GTK_SIGNAL_FUNC (sp_dialog_event_handler), dlg);
485 gtk_signal_connect ( GTK_OBJECT (dlg), "destroy", G_CALLBACK (sp_item_dialog_destroy), dlg);
486 gtk_signal_connect ( GTK_OBJECT (dlg), "delete_event", G_CALLBACK (sp_item_dialog_delete), dlg);
487 g_signal_connect ( G_OBJECT (INKSCAPE), "shut_down", G_CALLBACK (sp_item_dialog_delete), dlg);
488 g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide", G_CALLBACK (sp_dialog_hide), dlg);
489 g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide", G_CALLBACK (sp_dialog_unhide), dlg);
491 // Dialog-specific stuff
492 GtkWidget *itemw = sp_item_widget_new ();
493 gtk_widget_show (itemw);
494 gtk_container_add (GTK_CONTAINER (dlg), itemw);
496 }
498 gtk_window_present ((GtkWindow *) dlg);
499 }
502 /*
503 Local Variables:
504 mode:c++
505 c-file-style:"stroustrup"
506 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
507 indent-tabs-mode:nil
508 fill-column:99
509 End:
510 */
511 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :