item-properties.cpp revision 1160eb7a6e90b1efe44156277727f93860364743
/**
* @file
* Object properties dialog.
*/
/* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
* bulia byak <buliabyak@users.sf.net>
* Johan Engelen <goejendaagh@zonnet.nl>
* Abhishek Sharma
* Kris De Gussem <Kris.DeGussem@gmail.com>
*
* Copyright (C) 1999-2011 Authors
* Copyright (C) 2001 Ximian, Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "../desktop-handles.h"
#include "../document.h"
#include "../helper/window.h"
#include "../inkscape.h"
#include "../interface.h"
#include "../macros.h"
#include "../preferences.h"
#include "../selection.h"
#include "../sp-item.h"
#include "../verbs.h"
#include "../widgets/sp-widget.h"
#include "item-properties.h"
using Inkscape::DocumentUndo;
#define MIN_ONSCREEN_DISTANCE 50
static SPItemDialog *spid = NULL;
static void sp_item_dialog_delete( GtkObject */*object*/, GdkEvent */*event*/, gpointer /*data*/ );
static void sp_item_widget_modify_selection (SPWidget *spw, Inkscape::Selection *selection, guint flags, GtkWidget *itemw);
static void sp_item_widget_change_selection (SPWidget *spw, Inkscape::Selection *selection, GtkWidget *itemw);
/**
* \brief SPItemDialog callback for closing the dialog.
*/
static void sp_item_dialog_delete( GtkObject */*object*/, GdkEvent */*event*/, gpointer /*data*/ )
{
if (spid)
{
delete spid;
spid = NULL;
}
}
/**
* \brief SPItemDialog callback for a modification of the selected object (e.g. size, color, fill, etc.).
*/
static void sp_item_widget_modify_selection( SPWidget */*spw*/,
Inkscape::Selection */*selection*/,
guint /*flags*/,
GtkWidget */*itemw*/ )
{
if (spid)
{
spid->widget_setup();
}
}
/**
* \brief SPItemDialog callback for the selection of an other object.
*/
static void sp_item_widget_change_selection ( SPWidget */*spw*/,
Inkscape::Selection */*selection*/,
GtkWidget */*itemw*/ )
{
if (spid)
{
spid->widget_setup();
}
}
/**
* Create a new static instance of the items dialog.
*/
void sp_item_dialog(void)
{
if (spid == NULL) {
spid = new SPItemDialog();
}
}
/**
* \brief Constructor.
*/
SPItemDialog::SPItemDialog (void) :
prefs_path("/dialogs/object/"),
x(-1000),// impossible original value to make sure they are read from prefs
y(-1000),// impossible original value to make sure they are read from prefs
w(0),
h(0),
blocked (false),
closing (false),
TopTable (3, 4, false),
LabelID(_("_ID:"), 1),
LabelLabel(_("_Label:"), 1),
LabelTitle(_("_Title:"),1),
LabelDescription(_("_Description"),1),
HBoxCheck(FALSE, 0),
CheckTable(1, 2, TRUE),
CBHide(_("_Hide"), 1),
CBLock(_("L_ock"), 1),
BSet (_("_Set"), 1),
LabelInteractivity(_("_Interactivity"), 1),
attrTable(),
CurrentItem(0)
{
//intializing dialog
gchar title[500];
sp_ui_dialog_title_string (Inkscape::Verb::get(SP_VERB_DIALOG_ITEM), title);
window = Inkscape::UI::window_new (title, true);
GtkWidget *dlg;
dlg = (GtkWidget*)window->gobj();
//reading dialog position from preferences
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
if (x == -1000 || y == -1000) {
x = prefs->getInt(prefs_path + "x", -1000);
y = prefs->getInt(prefs_path + "y", -1000);
}
if (w ==0 || h == 0) {
w = prefs->getInt(prefs_path + "w", 0);
h = prefs->getInt(prefs_path + "h", 0);
}
if (w && h) {
gtk_window_resize ((GtkWindow *) dlg, w, h);
}
if (x >= 0 && y >= 0 && (x < (gdk_screen_width()-MIN_ONSCREEN_DISTANCE)) && (y < (gdk_screen_height()-MIN_ONSCREEN_DISTANCE))) {
gtk_window_move ((GtkWindow *) dlg, x, y);
} else {
gtk_window_set_position(GTK_WINDOW(dlg), GTK_WIN_POS_CENTER);
}
sp_transientize (dlg);
wd.win = dlg;
wd.stop = 0;
//set callback for the new dialog
g_signal_connect ( G_OBJECT (INKSCAPE), "activate_desktop", G_CALLBACK (sp_transientize_callback), &wd);
g_signal_connect ( G_OBJECT (dlg), "event", G_CALLBACK (sp_dialog_event_handler), dlg);
// g_signal_connect ( G_OBJECT (dlg), "destroy", G_CALLBACK (sp_item_dialog_delete), dlg);
g_signal_connect ( G_OBJECT (dlg), "delete_event", G_CALLBACK (sp_item_dialog_delete), dlg);
g_signal_connect ( G_OBJECT (INKSCAPE), "shut_down", G_CALLBACK (sp_item_dialog_delete), dlg);
g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_hide", G_CALLBACK (sp_dialog_hide), dlg);
g_signal_connect ( G_OBJECT (INKSCAPE), "dialogs_unhide", G_CALLBACK (sp_dialog_unhide), dlg);
//initialize labels for the table at the bottom of the dialog
int_labels.push_back("onclick");
int_labels.push_back("onmouseover");
int_labels.push_back("onmouseout");
int_labels.push_back("onmousedown");
int_labels.push_back("onmouseup");
int_labels.push_back("onmousemove");
int_labels.push_back("onfocusin");
int_labels.push_back("onfocusout");
int_labels.push_back("onfocusout");
int_labels.push_back("onload");
MakeWidget();
}
/**
* \brief Destructor.
*/
SPItemDialog::~SPItemDialog (void)
{
if (closing)
{
return;
}
blocked = true;
closing = true;
gtk_window_get_position ((GtkWindow *) wd.win, &x, &y);
gtk_window_get_size ((GtkWindow *) wd.win, &w, &h);
if (x<0) x=0;
if (y<0) y=0;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
prefs->setInt(prefs_path + "x", x);
prefs->setInt(prefs_path + "y", y);
prefs->setInt(prefs_path + "w", w);
prefs->setInt(prefs_path + "h", h);
sp_signal_disconnect_by_data (INKSCAPE, wd.win);
sp_signal_disconnect_by_data (INKSCAPE, &wd);
if (window)
{
//should actually always be true, but for safety check
delete window;
window = NULL;
wd.win = NULL;
}
}
/**
* \brief Constructor auxiliary function creating the child widgets.
*/
void SPItemDialog::MakeWidget(void)
{
// if (gtk_widget_get_visible (GTK_WIDGET(spw))) {
g_signal_connect (G_OBJECT (INKSCAPE), "modify_selection", G_CALLBACK (sp_item_widget_modify_selection), wd.win);
g_signal_connect (G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (sp_item_widget_change_selection), wd.win);
g_signal_connect (G_OBJECT (INKSCAPE), "set_selection", G_CALLBACK (sp_item_widget_change_selection), wd.win);
// }
window->add(vb);
TopTable.set_border_width(4);
TopTable.set_row_spacings(4);
TopTable.set_col_spacings(4);
vb.pack_start (TopTable, true, true, 0);
/* Create the label for the object id */
LabelID.set_alignment (1, 0.5);
TopTable.attach (LabelID, 0, 1, 0, 1,
Gtk::SHRINK | Gtk::FILL,
Gtk::AttachOptions(), 0, 0 );
/* Create the entry box for the object id */
EntryID.set_tooltip_text (_("The id= attribute (only letters, digits, and the characters .-_: allowed)"));
EntryID.set_max_length (64);
TopTable.attach (EntryID, 1, 2, 0, 1,
Gtk::EXPAND | Gtk::FILL,
Gtk::AttachOptions(), 0, 0 );
LabelID.set_mnemonic_widget (EntryID);
// pressing enter in the id field is the same as clicking Set:
EntryID.signal_activate().connect(sigc::mem_fun(this, &SPItemDialog::label_changed));
// focus is in the id field initially:
EntryID.grab_focus();
/* Create the label for the object label */
LabelLabel.set_alignment (1, 0.5);
TopTable.attach (LabelLabel, 0, 1, 1, 2,
Gtk::SHRINK | Gtk::FILL,
Gtk::AttachOptions(), 0, 0 );
/* Create the entry box for the object label */
EntryLabel.set_tooltip_text (_("A freeform label for the object"));
EntryLabel.set_max_length (256);
TopTable.attach (EntryLabel, 1, 2, 1, 2,
Gtk::EXPAND | Gtk::FILL,
Gtk::AttachOptions(), 0, 0 );
LabelLabel.set_mnemonic_widget (EntryLabel);
// pressing enter in the label field is the same as clicking Set:
EntryLabel.signal_activate().connect(sigc::mem_fun(this, &SPItemDialog::label_changed));
/* Create the label for the object title */
LabelTitle.set_alignment (1, 0.5);
TopTable.attach (LabelTitle, 0, 1, 2, 3,
Gtk::SHRINK | Gtk::FILL,
Gtk::AttachOptions(), 0, 0 );
/* Create the entry box for the object title */
EntryTitle.set_sensitive (FALSE);
EntryTitle.set_max_length (256);
TopTable.attach (EntryTitle, 1, 3, 2, 3,
Gtk::EXPAND | Gtk::FILL,
Gtk::AttachOptions(), 0, 0 );
LabelTitle.set_mnemonic_widget (EntryTitle);
/* Create the frame for the object description */
FrameDescription.set_label_widget (LabelDescription);
TopTable.attach (FrameDescription, 0, 3, 3, 4,
Gtk::EXPAND | Gtk::FILL,
Gtk::EXPAND | Gtk::FILL, 0, 0 );
/* Create the text view box for the object description */
FrameTextDescription.set_border_width(4);
FrameTextDescription.set_sensitive (FALSE);
FrameDescription.add (FrameTextDescription);
FrameTextDescription.set_shadow_type (Gtk::SHADOW_IN);
TextViewDescription.set_wrap_mode(Gtk::WRAP_WORD);
TextViewDescription.get_buffer()->set_text("");
FrameTextDescription.add (TextViewDescription);
TextViewDescription.add_mnemonic_label(LabelDescription);
/* Check boxes */
vb.pack_start (HBoxCheck, FALSE, FALSE, 0);
CheckTable.set_border_width(0);
HBoxCheck.pack_start (CheckTable, TRUE, TRUE, 10);
/* Hide */
CBHide.set_tooltip_text (_("Check to make the object invisible"));
CheckTable.attach (CBHide, 0, 1, 0, 1,
Gtk::EXPAND | Gtk::FILL,
Gtk::AttachOptions(), 0, 0 );
CBHide.signal_toggled().connect(sigc::mem_fun(this, &SPItemDialog::hidden_toggled));
/* Lock */
// TRANSLATORS: "Lock" is a verb here
CBLock.set_tooltip_text (_("Check to make the object insensitive (not selectable by mouse)"));
CheckTable.attach (CBLock, 1, 2, 0, 1,
Gtk::EXPAND | Gtk::FILL,
Gtk::AttachOptions(), 0, 0 );
CBLock.signal_toggled().connect(sigc::mem_fun(this, &SPItemDialog::sensitivity_toggled));
/* Button for setting the object's id, label, title and description. */
HBoxCheck.pack_start (BSet, TRUE, TRUE, 10);
BSet.signal_clicked().connect(sigc::mem_fun(this, &SPItemDialog::label_changed));
/* Create the frame for interactivity options */
EInteractivity.set_label_widget (LabelInteractivity);
vb.pack_start (EInteractivity, FALSE, FALSE, 0);
window->show_all ();
widget_setup();
}
/**
* \brief Updates entries and other child widgets on selection change, object modification, etc.
*/
void SPItemDialog::widget_setup(void)
{
if (blocked)
{
return;
}
Inkscape::Selection *selection = sp_desktop_selection (SP_ACTIVE_DESKTOP);
if (!selection->singleItem()) {
vb.set_sensitive (false);
CurrentItem = NULL;
//no selection anymore or multiple objects selected, means that we need
//to close the connections to the previously selected object
attrTable.clear();
return;
} else {
vb.set_sensitive (true);
}
SPItem *item = selection->singleItem();
if (CurrentItem == item)
{
//otherwise we would end up wasting resources through the modify selection
//callback when moving an object (endlessly setting the labels and recreating attrTable)
return;
}
blocked = true;
CBLock.set_active (item->isLocked()); /* Sensitive */
CBHide.set_active (item->isExplicitlyHidden()); /* Hidden */
if (item->cloned) {
/* ID */
EntryID.set_text ("");
EntryID.set_sensitive (FALSE);
LabelID.set_text (_("Ref"));
/* Label */
EntryLabel.set_text ("");
EntryLabel.set_sensitive (FALSE);
LabelLabel.set_text (_("Ref"));
} else {
SPObject *obj = (SPObject*)item;
/* ID */
EntryID.set_text (obj->getId());
EntryID.set_sensitive (TRUE);
LabelID.set_markup_with_mnemonic (_("_ID:"));
/* Label */
EntryLabel.set_text(obj->defaultLabel());
EntryLabel.set_sensitive (TRUE);
/* Title */
gchar *title = obj->title();
if (title) {
EntryTitle.set_text(title);
g_free(title);
}
else {
EntryTitle.set_text("");
}
EntryTitle.set_sensitive(TRUE);
/* Description */
gchar *desc = obj->desc();
if (desc) {
TextViewDescription.get_buffer()->set_text(desc);
g_free(desc);
} else {
TextViewDescription.get_buffer()->set_text("");
}
FrameTextDescription.set_sensitive(TRUE);
if (CurrentItem == NULL)
{
attrTable.set_object(obj, int_labels, int_labels, (GtkWidget*)EInteractivity.gobj());
}
else
{
attrTable.change_object(obj);
}
attrTable.show_all();
}
CurrentItem = item;
blocked = false;
}
/**
* \brief Sets object properties (ID, label, title, description) on user input.
*/
void SPItemDialog::label_changed(void)
{
if (blocked)
{
return;
}
SPItem *item = sp_desktop_selection(SP_ACTIVE_DESKTOP)->singleItem();
g_return_if_fail (item != NULL);
blocked = true;
/* Retrieve the label widget for the object's id */
gchar *id = g_strdup(EntryID.get_text().c_str());
g_strcanon (id, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.:", '_');
if (!strcmp (id, item->getId())) {
LabelID.set_markup_with_mnemonic(_("_ID:"));
} else if (!*id || !isalnum (*id)) {
LabelID.set_text (_("Id invalid! "));
} else if (SP_ACTIVE_DOCUMENT->getObjectById(id) != NULL) {
LabelID.set_text (_("Id exists! "));
} else {
SPException ex;
LabelID.set_markup_with_mnemonic(_("_ID:"));
SP_EXCEPTION_INIT (&ex);
item->setAttribute("id", id, &ex);
DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM, _("Set object ID"));
}
g_free (id);
/* Retrieve the label widget for the object's label */
Glib::ustring label = EntryLabel.get_text();
g_assert(!label.empty());
/* Give feedback on success of setting the drawing object's label
* using the widget's label text
*/
SPObject *obj = (SPObject*)item;
if (label.compare (obj->defaultLabel())) {
obj->setLabel(label.c_str());
DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
_("Set object label"));
}
/* Retrieve the title */
if (obj->setTitle(EntryTitle.get_text().c_str()))
DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
_("Set object title"));
/* Retrieve the description */
Gtk::TextBuffer::iterator start, end;
TextViewDescription.get_buffer()->get_bounds(start, end);
Glib::ustring desc = TextViewDescription.get_buffer()->get_text(start, end, TRUE);
if (obj->setDesc(desc.c_str()))
DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
_("Set object description"));
blocked = false;
}
/**
* \brief Callback for checkbox Lock.
*/
void SPItemDialog::sensitivity_toggled (void)
{
if (blocked)
{
return;
}
SPItem *item = sp_desktop_selection(SP_ACTIVE_DESKTOP)->singleItem();
g_return_if_fail (item != NULL);
blocked = true;
item->setLocked(CBLock.get_active());
DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
CBLock.get_active()? _("Lock object") : _("Unlock object"));
blocked = false;
}
/**
* \brief Callback for checkbox Hide.
*/
void SPItemDialog::hidden_toggled(void)
{
if (blocked)
{
return;
}
SPItem *item = sp_desktop_selection(SP_ACTIVE_DESKTOP)->singleItem();
g_return_if_fail (item != NULL);
blocked = true;
item->setExplicitlyHidden(CBHide.get_active());
DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_DIALOG_ITEM,
CBHide.get_active()? _("Hide object") : _("Unhide object"));
blocked = false;
}
/*
Local Variables:
mode:c++
c-file-style:"stroustrup"
c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
indent-tabs-mode:nil
fill-column:99
End:
*/
// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :