summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorsu_v <suv-sf@users.sourceforge.net>2012-10-12 17:18:08 +0000
committer~suv <suv-sf@users.sourceforge.net>2012-10-12 17:18:08 +0000
commitd997c6a08a0d1184e8a4aec708033d0f548802f8 (patch)
treee644b11bedb210813006dbfe4fb6a703bb642fae /src
parentmerge from trunk (r11761) (diff)
parentFix for compiling with pre gtkmm 2.24 libraries. (diff)
downloadinkscape-d997c6a08a0d1184e8a4aec708033d0f548802f8.tar.gz
inkscape-d997c6a08a0d1184e8a4aec708033d0f548802f8.zip
merge from trunk (r11787)
(bzr r11668.1.28)
Diffstat (limited to 'src')
-rw-r--r--src/desktop.cpp55
-rw-r--r--src/desktop.h5
-rw-r--r--src/document.cpp35
-rw-r--r--src/extension/implementation/implementation.h1
-rw-r--r--src/extension/input.cpp7
-rw-r--r--src/extension/input.h4
-rw-r--r--src/extension/internal/pdfinput/pdf-input.cpp8
-rw-r--r--src/extension/internal/pdfinput/pdf-input.h4
-rw-r--r--src/extension/system.cpp1
-rw-r--r--src/file.cpp8
-rw-r--r--src/inkscape.cpp8
-rw-r--r--src/interface.cpp39
-rw-r--r--src/interface.h1
-rw-r--r--src/layer-manager.cpp81
-rw-r--r--src/layer-manager.h1
-rw-r--r--src/live_effects/lpe-powerstroke.cpp131
-rw-r--r--src/main.cpp2
-rw-r--r--src/menus-skeleton.h5
-rw-r--r--src/path-prefix.h4
-rw-r--r--src/selection-chemistry.cpp158
-rw-r--r--src/selection-chemistry.h5
-rw-r--r--src/selection-describer.cpp7
-rw-r--r--src/sp-object.cpp3
-rw-r--r--src/sp-symbol.cpp5
-rw-r--r--src/sp-use.cpp8
-rw-r--r--src/ui/clipboard.cpp50
-rw-r--r--src/ui/clipboard.h2
-rw-r--r--src/ui/dialog/Makefile_insert2
-rw-r--r--src/ui/dialog/dialog-manager.cpp3
-rw-r--r--src/ui/dialog/layer-properties.cpp7
-rw-r--r--src/ui/dialog/layers.cpp62
-rw-r--r--src/ui/dialog/symbols.cpp591
-rw-r--r--src/ui/dialog/symbols.h114
-rw-r--r--src/ui/widget/style-swatch.cpp7
-rw-r--r--src/verbs.cpp72
-rw-r--r--src/verbs.h13
-rw-r--r--src/widgets/toolbox.cpp2
-rw-r--r--src/widgets/widget-sizes.h2
-rw-r--r--src/xml/repr-css.cpp22
39 files changed, 1359 insertions, 176 deletions
diff --git a/src/desktop.cpp b/src/desktop.cpp
index ca981a458..fa0c8647f 100644
--- a/src/desktop.cpp
+++ b/src/desktop.cpp
@@ -55,6 +55,7 @@
#include "document.h"
#include "event-log.h"
#include "helper/units.h"
+#include "interface.h"
#include "inkscape-private.h"
#include "layer-fns.h"
#include "layer-manager.h"
@@ -496,13 +497,51 @@ void SPDesktop::setCurrentLayer(SPObject *object) {
_layer_hierarchy->setBottom(object);
}
-void SPDesktop::toggleAllLayers(bool hide) {
+void SPDesktop::toggleHideAllLayers(bool hide) {
- for ( SPObject* obj = currentRoot(); obj; obj = Inkscape::previous_layer(currentRoot(), obj) ) {
+ for ( SPObject* obj = Inkscape::previous_layer(currentRoot(), currentRoot()); obj; obj = Inkscape::previous_layer(currentRoot(), obj) ) {
SP_ITEM(obj)->setHidden(hide);
}
}
+void SPDesktop::toggleLockAllLayers(bool lock) {
+
+ for ( SPObject* obj = Inkscape::previous_layer(currentRoot(), currentRoot()); obj; obj = Inkscape::previous_layer(currentRoot(), obj) ) {
+ SP_ITEM(obj)->setLocked(lock);
+ }
+}
+
+void SPDesktop::toggleLockOtherLayers(SPObject *object) {
+ g_return_if_fail(SP_IS_GROUP(object));
+ g_return_if_fail( currentRoot() == object || (currentRoot() && currentRoot()->isAncestorOf(object)) );
+
+ bool othersLocked = false;
+ std::vector<SPObject*> layers;
+ for ( SPObject* obj = Inkscape::next_layer(currentRoot(), object); obj; obj = Inkscape::next_layer(currentRoot(), obj) ) {
+ // Dont lock any ancestors, since that would in turn lock the layer as well
+ if (!obj->isAncestorOf(object)) {
+ layers.push_back(obj);
+ othersLocked |= !SP_ITEM(obj)->isLocked();
+ }
+ }
+ for ( SPObject* obj = Inkscape::previous_layer(currentRoot(), object); obj; obj = Inkscape::previous_layer(currentRoot(), obj) ) {
+ if (!obj->isAncestorOf(object)) {
+ layers.push_back(obj);
+ othersLocked |= !SP_ITEM(obj)->isLocked();
+ }
+ }
+
+ SPItem *item = SP_ITEM(object);
+ if ( item->isLocked() ) {
+ item->setLocked(false);
+ }
+
+ for ( std::vector<SPObject*>::iterator it = layers.begin(); it != layers.end(); ++it ) {
+ SP_ITEM(*it)->setLocked(othersLocked);
+ }
+}
+
+
void SPDesktop::toggleLayerSolo(SPObject *object) {
g_return_if_fail(SP_IS_GROUP(object));
g_return_if_fail( currentRoot() == object || (currentRoot() && currentRoot()->isAncestorOf(object)) );
@@ -1309,6 +1348,17 @@ SPDesktop::toggleScrollbars()
_widget->toggleScrollbars();
}
+
+void SPDesktop::toggleToolbar(gchar const *toolbar_name)
+{
+ Glib::ustring pref_path = getLayoutPrefPath(this) + toolbar_name + "/state";
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean visible = prefs->getBool(pref_path, true);
+ prefs->setBool(pref_path, !visible);
+
+ layoutWidget();
+}
+
void
SPDesktop::layoutWidget()
{
@@ -1465,7 +1515,6 @@ void SPDesktop::toggleSnapGlobal()
namedview->setSnapGlobal(!v);
}
-
//----------------------------------------------------------------------
// Callback implementations. The virtual ones are connected by the view.
diff --git a/src/desktop.h b/src/desktop.h
index 919cd905e..529199692 100644
--- a/src/desktop.h
+++ b/src/desktop.h
@@ -280,7 +280,9 @@ public:
void setCurrentLayer(SPObject *object);
void toggleLayerSolo(SPObject *object);
- void toggleAllLayers(bool hidden);
+ void toggleHideAllLayers(bool hide);
+ void toggleLockAllLayers(bool lock);
+ void toggleLockOtherLayers(SPObject *object);
SPObject *layerForObject(SPObject *object);
bool isLayer(SPObject *object) const;
bool isWithinViewport(SPItem *item) const;
@@ -364,6 +366,7 @@ public:
void toggleSnapGlobal();
bool gridsEnabled() const { return grids_visible; };
void showGrids(bool show, bool dirty_document = true);
+ void toggleToolbar(gchar const *toolbar_name);
bool is_iconified();
bool is_maximized();
diff --git a/src/document.cpp b/src/document.cpp
index 9d8291db0..172037518 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -7,10 +7,12 @@
* bulia byak <buliabyak@users.sf.net>
* Jon A. Cruz <jon@joncruz.org>
* Abhishek Sharma
+ * Tavmjong Bah <tavmjong@free.fr>
*
* Copyright (C) 2004-2005 MenTaLguY
* Copyright (C) 1999-2002 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
+ * Copyright (C) 2012 Tavmjong Bah
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -59,6 +61,7 @@
#include "sp-item-group.h"
#include "sp-namedview.h"
#include "sp-object-repr.h"
+#include "sp-symbol.h"
#include "transf_mat_3x4.h"
#include "unit-constants.h"
#include "xml/repr.h"
@@ -1454,9 +1457,10 @@ void SPDocument::importDefs(SPDocument *source)
for (Inkscape::XML::Node *def = defs->firstChild() ; def ; def = def->next()) {
- // Prevent duplicates of solid swatches by checking if equivalent swatch already exists
gboolean duplicate = false;
SPObject *src = source->getObjectByRepr(def);
+
+ // Prevent duplicates of solid swatches by checking if equivalent swatch already exists
if (src && SP_IS_GRADIENT(src)) {
SPGradient *gr = SP_GRADIENT(src);
if (gr->isSolid() || gr->getVector()->isSolid()) {
@@ -1473,6 +1477,35 @@ void SPDocument::importDefs(SPDocument *source)
}
}
+ // Prevent duplication of symbols... could be more clever.
+ // The tag "_inkscape_duplicate" is added to "id" by ClipboardManagerImpl::copySymbol().
+ // We assume that symbols are in defs section (not required by SVG spec).
+ if (src && SP_IS_SYMBOL(src)) {
+
+ Glib::ustring id = src->getRepr()->attribute("id");
+ size_t pos = id.find( "_inkscape_duplicate" );
+ if( pos != Glib::ustring::npos ) {
+
+ // This is our symbol, now get rid of tag
+ id.erase( pos );
+
+ // Check that it really is a duplicate
+ for (SPObject *trg = this->getDefs()->firstChild() ; trg ; trg = trg->getNext()) {
+ if( trg && SP_IS_SYMBOL(trg) && src != trg ) {
+ std::string id2 = trg->getRepr()->attribute("id");
+
+ if( !id.compare( id2 ) ) {
+ duplicate = true;
+ break;
+ }
+ }
+ }
+ if ( !duplicate ) {
+ src->getRepr()->setAttribute("id", id.c_str() );
+ }
+ }
+ }
+
if (!duplicate) {
Inkscape::XML::Node * dup = def->duplicate(this->getReprDoc());
target_defs->appendChild(dup);
diff --git a/src/extension/implementation/implementation.h b/src/extension/implementation/implementation.h
index b0230b7c4..fb323cd78 100644
--- a/src/extension/implementation/implementation.h
+++ b/src/extension/implementation/implementation.h
@@ -104,6 +104,7 @@ public:
virtual bool check(Inkscape::Extension::Extension * /*module*/) { return true; }
virtual bool cancelProcessing () { return true; }
+ virtual bool wasCancelled () { return false; }
virtual void commitDocument () {}
// ----- Input functions -----
diff --git a/src/extension/input.cpp b/src/extension/input.cpp
index 1662ef073..5cef38009 100644
--- a/src/extension/input.cpp
+++ b/src/extension/input.cpp
@@ -152,6 +152,10 @@ Input::open (const gchar *uri)
SPDocument *const doc = imp->open(this, uri);
+ if (imp->wasCancelled()) {
+ throw Input::open_cancelled();
+ }
+
return doc;
}
@@ -227,8 +231,7 @@ Input::prefs (const gchar *uri)
delete dialog;
- if (response == Gtk::RESPONSE_OK) return true;
- return false;
+ return (response == Gtk::RESPONSE_OK);
}
} } /* namespace Inkscape, Extension */
diff --git a/src/extension/input.h b/src/extension/input.h
index 8b198495e..b01ffeb86 100644
--- a/src/extension/input.h
+++ b/src/extension/input.h
@@ -39,6 +39,10 @@ public:
virtual ~no_extension_found() throw() {}
const char *what() const throw() { return "No suitable input extension found"; }
};
+ struct open_cancelled : public std::exception {
+ virtual ~open_cancelled() throw() {}
+ const char *what() const throw() { return "Open was cancelled"; }
+ };
Input (Inkscape::XML::Node * in_repr,
Implementation::Implementation * in_imp);
diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp
index 6b6107444..d2d594017 100644
--- a/src/extension/internal/pdfinput/pdf-input.cpp
+++ b/src/extension/internal/pdfinput/pdf-input.cpp
@@ -588,12 +588,19 @@ void PdfImportDialog::_setPreviewPage(int page) {
////////////////////////////////////////////////////////////////////////////////
+bool
+PdfInput::wasCancelled () {
+ return _cancelled;
+}
+
/**
* Parses the selected page of the given PDF document using PdfParser.
*/
SPDocument *
PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
+ _cancelled = false;
+
// Initialize the globalParams variable for poppler
if (!globalParams) {
globalParams = new GlobalParams();
@@ -648,6 +655,7 @@ PdfInput::open(::Inkscape::Extension::Input * /*mod*/, const gchar * uri) {
if (inkscape_use_gui()) {
dlg = new PdfImportDialog(pdf_doc, uri);
if (!dlg->showDialog()) {
+ _cancelled = true;
delete dlg;
delete pdf_doc;
return NULL;
diff --git a/src/extension/internal/pdfinput/pdf-input.h b/src/extension/internal/pdfinput/pdf-input.h
index 75fcfa69a..e9da5b27c 100644
--- a/src/extension/internal/pdfinput/pdf-input.h
+++ b/src/extension/internal/pdfinput/pdf-input.h
@@ -135,7 +135,9 @@ public:
SPDocument *open( Inkscape::Extension::Input *mod,
const gchar *uri );
static void init( void );
-
+ virtual bool wasCancelled();
+private:
+ bool _cancelled;
};
} // namespace Implementation
diff --git a/src/extension/system.cpp b/src/extension/system.cpp
index fc20095c5..7fb6e1591 100644
--- a/src/extension/system.cpp
+++ b/src/extension/system.cpp
@@ -144,6 +144,7 @@ SPDocument *open(Extension *key, gchar const *filename)
}
SPDocument *doc = imod->open(filename);
+
if (!doc) {
throw Input::open_failed();
}
diff --git a/src/file.cpp b/src/file.cpp
index 778306d5d..a03c459da 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -235,12 +235,16 @@ bool sp_file_open(const Glib::ustring &uri,
}
SPDocument *doc = NULL;
+ bool cancelled = false;
try {
doc = Inkscape::Extension::open(key, uri.c_str());
} catch (Inkscape::Extension::Input::no_extension_found &e) {
doc = NULL;
} catch (Inkscape::Extension::Input::open_failed &e) {
doc = NULL;
+ } catch (Inkscape::Extension::Input::open_cancelled &e) {
+ doc = NULL;
+ cancelled = true;
}
if (desktop) {
@@ -287,7 +291,7 @@ bool sp_file_open(const Glib::ustring &uri,
}
return TRUE;
- } else {
+ } else if (!cancelled) {
gchar *safeUri = Inkscape::IO::sanitizeString(uri.c_str());
gchar *text = g_strdup_printf(_("Failed to load the requested file %s"), safeUri);
sp_ui_error_dialog(text);
@@ -295,6 +299,8 @@ bool sp_file_open(const Glib::ustring &uri,
g_free(safeUri);
return FALSE;
}
+
+ return FALSE;
}
/**
diff --git a/src/inkscape.cpp b/src/inkscape.cpp
index 0a94d0742..fc9a9783f 100644
--- a/src/inkscape.cpp
+++ b/src/inkscape.cpp
@@ -312,8 +312,8 @@ static gint inkscape_autosave(gpointer)
// Try to create the autosave directory if it doesn't exist
if (g_mkdir(autosave_dir.c_str(), 0755)) {
// the creation failed
- Glib::ustring msg = Glib::ustring::format(
- _("Autosave failed! Cannot create directory "), Glib::filename_to_utf8(autosave_dir));
+ Glib::ustring msg = Glib::ustring::compose(
+ _("Autosave failed! Cannot create directory %1."), Glib::filename_to_utf8(autosave_dir));
g_warning("%s", msg.c_str());
SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, msg.c_str());
return TRUE;
@@ -321,8 +321,8 @@ static gint inkscape_autosave(gpointer)
// Try to read dir again
autosave_dir_ptr = g_dir_open(autosave_dir.c_str(), 0, NULL);
if( !autosave_dir_ptr ){
- Glib::ustring msg = Glib::ustring::format(
- _("Autosave failed! Cannot open directory "), Glib::filename_to_utf8(autosave_dir));
+ Glib::ustring msg = Glib::ustring::compose(
+ _("Autosave failed! Cannot open directory %1."), Glib::filename_to_utf8(autosave_dir));
g_warning("%s", msg.c_str());
SP_ACTIVE_DESKTOP->messageStack()->flash(Inkscape::ERROR_MESSAGE, msg.c_str());
return TRUE;
diff --git a/src/interface.cpp b/src/interface.cpp
index 2ee188ef7..bad95adc6 100644
--- a/src/interface.cpp
+++ b/src/interface.cpp
@@ -527,7 +527,7 @@ static GtkWidget *sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb
} // end of sp_ui_menu_append_item_from_verb
-static Glib::ustring getLayoutPrefPath( Inkscape::UI::View::View *view )
+Glib::ustring getLayoutPrefPath( Inkscape::UI::View::View *view )
{
Glib::ustring prefPath;
@@ -554,7 +554,7 @@ checkitem_toggled(GtkCheckMenuItem *menuitem, gpointer user_data)
sp_ui_menu_activate(menuitem, action);
} else if (pref) {
- // The Show/Hide menu items without actions
+ // All check menu items should have actions now, but just in case
Glib::ustring pref_path = getLayoutPrefPath( view );
pref_path += pref;
pref_path += "/state";
@@ -596,19 +596,16 @@ static gboolean checkitem_update(GtkWidget *widget, GdkEventExpose * /*event*/,
if (!strcmp(action->id, "ToggleGrid")) {
ison = dt->gridsEnabled();
}
- if (!strcmp(action->id, "ToggleGuides")) {
+ else if (!strcmp(action->id, "ToggleGuides")) {
ison = dt->namedview->getGuides();
}
- if (!strcmp(action->id, "ToggleSnapGlobal")) {
+ else if (!strcmp(action->id, "ToggleSnapGlobal")) {
ison = dt->namedview->getSnapGlobal();
}
- if (!strcmp(action->id, "ViewCmsToggle")) {
+ else if (!strcmp(action->id, "ViewCmsToggle")) {
ison = dt->colorProfAdjustEnabled();
}
- if (!strcmp(action->id, "ToggleRulers")) {
- ison = getViewStateFromPref(view, pref);
- }
- if (!strcmp(action->id, "ToggleScrollbars")) {
+ else {
ison = getViewStateFromPref(view, pref);
}
} else if (pref) {
@@ -896,22 +893,22 @@ sp_ui_checkboxes_menus(GtkMenu *m, Inkscape::UI::View::View *view)
{
//sp_ui_menu_append_check_item_from_verb(m, view, _("_Menu"), _("Show or hide the menu bar"), "menu",
// checkitem_toggled, checkitem_update, 0);
- sp_ui_menu_append_check_item_from_verb(m, view, _("_Commands Bar"), _("Show or hide the Commands bar (under the menu)"), "commands",
- checkitem_toggled, checkitem_update, 0);
- sp_ui_menu_append_check_item_from_verb(m, view, _("Sn_ap Controls Bar"), _("Show or hide the snapping controls"), "snaptoolbox",
- checkitem_toggled, checkitem_update, 0);
- sp_ui_menu_append_check_item_from_verb(m, view, _("T_ool Controls Bar"), _("Show or hide the Tool Controls bar"), "toppanel",
- checkitem_toggled, checkitem_update, 0);
- sp_ui_menu_append_check_item_from_verb(m, view, _("_Toolbox"), _("Show or hide the main toolbox (on the left)"), "toolbox",
- checkitem_toggled, checkitem_update, 0);
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "commands",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_COMMANDS_TOOLBAR));
+ sp_ui_menu_append_check_item_from_verb(m, view,NULL, NULL, "snaptoolbox",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SNAP_TOOLBAR));
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "toppanel",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_TOOL_TOOLBAR));
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "toolbox",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_TOOLBOX));
sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "rulers",
checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_RULERS));
sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "scrollbars",
checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_SCROLLBARS));
- sp_ui_menu_append_check_item_from_verb(m, view, _("_Palette"), _("Show or hide the color palette"), "panels",
- checkitem_toggled, checkitem_update, 0);
- sp_ui_menu_append_check_item_from_verb(m, view, _("_Statusbar"), _("Show or hide the statusbar (at the bottom of the window)"), "statusbar",
- checkitem_toggled, checkitem_update, 0);
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "panels",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_PALETTE));
+ sp_ui_menu_append_check_item_from_verb(m, view, NULL, NULL, "statusbar",
+ checkitem_toggled, checkitem_update, Inkscape::Verb::get(SP_VERB_TOGGLE_STATUSBAR));
}
diff --git a/src/interface.h b/src/interface.h
index 891e39957..2e9e7fc2e 100644
--- a/src/interface.h
+++ b/src/interface.h
@@ -81,6 +81,7 @@ GtkWidget *sp_ui_main_menubar (Inkscape::UI::View::View *view);
void sp_menu_append_recent_documents (GtkWidget *menu);
void sp_ui_dialog_title_string (Inkscape::Verb * verb, gchar* c);
+Glib::ustring getLayoutPrefPath( Inkscape::UI::View::View *view );
/**
*
diff --git a/src/layer-manager.cpp b/src/layer-manager.cpp
index 894758a97..c02d75d16 100644
--- a/src/layer-manager.cpp
+++ b/src/layer-manager.cpp
@@ -159,53 +159,66 @@ void LayerManager::setCurrentLayer( SPObject* obj )
}
}
-void LayerManager::renameLayer( SPObject* obj, gchar const *label, bool uniquify )
+/*
+ * Return a unique layer name similar to param label
+ * A unique name is made by substituting or appending the label's number suffix with
+ * the next unique larger number suffix not already used for any layer name
+ */
+Glib::ustring LayerManager::getNextLayerName( SPObject* obj, gchar const *label)
{
- Glib::ustring incoming( label ? label : "" );
+ Glib::ustring incoming( label ? label : "Layer 1" );
Glib::ustring result(incoming);
Glib::ustring base(incoming);
+ Glib::ustring split(" ");
guint startNum = 1;
- if (uniquify) {
+ gint pos = base.length()-1;
+ while (pos >= 0 && g_ascii_isdigit(base[pos])) {
+ pos-- ;
+ }
- Glib::ustring::size_type pos = base.rfind('#');
- if ( pos != Glib::ustring::npos ) {
- gchar* numpart = g_strdup(base.substr(pos+1).c_str());
- if ( numpart ) {
- gchar* endPtr = NULL;
- guint64 val = g_ascii_strtoull( numpart, &endPtr, 10);
- if ( ((val > 0) || (endPtr != numpart)) && (val < 65536) ) {
- base.erase( pos );
- result = base;
- startNum = static_cast<int>(val);
- }
- g_free(numpart);
- }
+ gchar* numpart = g_strdup(base.substr(pos+1).c_str());
+ if ( numpart ) {
+ gchar* endPtr = NULL;
+ guint64 val = g_ascii_strtoull( numpart, &endPtr, 10);
+ if ( ((val > 0) || (endPtr != numpart)) && (val < 65536) ) {
+ base.erase( pos+1);
+ result = incoming;
+ startNum = static_cast<int>(val);
+ split = "";
}
+ g_free(numpart);
+ }
- std::set<Glib::ustring> currentNames;
- GSList const *layers=_document->getResourceList("layer");
- SPObject *root=_desktop->currentRoot();
- if ( root ) {
- for ( GSList const *iter=layers ; iter ; iter = iter->next ) {
- SPObject *layer=static_cast<SPObject *>(iter->data);
- if ( layer != obj ) {
- currentNames.insert( layer->label() ? Glib::ustring(layer->label()) : Glib::ustring() );
- }
+ std::set<Glib::ustring> currentNames;
+ GSList const *layers=_document->getResourceList("layer");
+ SPObject *root=_desktop->currentRoot();
+ if ( root ) {
+ for ( GSList const *iter=layers ; iter ; iter = iter->next ) {
+ SPObject *layer=static_cast<SPObject *>(iter->data);
+ if ( layer != obj ) {
+ currentNames.insert( layer->label() ? Glib::ustring(layer->label()) : Glib::ustring() );
}
}
+ }
- // Not sure if we need to cap it, but we'll just be paranoid for the moment
- // Intentionally unsigned
- guint endNum = startNum + 3000;
- for ( guint i = startNum; (i < endNum) && (currentNames.find(result) != currentNames.end()); i++ ) {
- gchar* suffix = g_strdup_printf("#%d", i);
- result = base;
- result += suffix;
+ // Not sure if we need to cap it, but we'll just be paranoid for the moment
+ // Intentionally unsigned
+ guint endNum = startNum + 3000;
+ for ( guint i = startNum; (i < endNum) && (currentNames.find(result) != currentNames.end()); i++ ) {
+ result = Glib::ustring::format(base, split, i);
+ }
- g_free(suffix);
- }
+ return result;
+}
+void LayerManager::renameLayer( SPObject* obj, gchar const *label, bool uniquify )
+{
+ Glib::ustring incoming( label ? label : "" );
+ Glib::ustring result(incoming);
+
+ if (uniquify) {
+ result = getNextLayerName(obj, label);
}
obj->setLabel( result.c_str() );
diff --git a/src/layer-manager.h b/src/layer-manager.h
index fbb22d405..1b69324d5 100644
--- a/src/layer-manager.h
+++ b/src/layer-manager.h
@@ -30,6 +30,7 @@ public:
void setCurrentLayer( SPObject* obj );
void renameLayer( SPObject* obj, gchar const *label, bool uniquify );
+ Glib::ustring getNextLayerName( SPObject* obj, gchar const *label);
sigc::connection connectCurrentLayerChanged(const sigc::slot<void, SPObject *> & slot) {
return _layer_changed_signal.connect(slot);
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp
index df94a761e..13fea76c5 100644
--- a/src/live_effects/lpe-powerstroke.cpp
+++ b/src/live_effects/lpe-powerstroke.cpp
@@ -153,6 +153,32 @@ static int circle_circle_intersection(Circle const &circle0, Circle const &circl
return 2;
}
+/**
+ * Find circle that touches inside of the curve, with radius matching the curvature, at time value \c t.
+ * Because this method internally uses unitTangentAt, t should be smaller than 1.0 (see unitTangentAt).
+ */
+Circle touching_circle( D2<SBasis> const &curve, double t, double tol=0.01 )
+{
+ //Piecewise<SBasis> k = curvature(curve, tol);
+ D2<SBasis> dM=derivative(curve);
+ if ( are_near(L2sq(dM(t)),0.) ) {
+ dM=derivative(dM);
+ }
+ if ( are_near(L2sq(dM(t)),0.) ) { // try second time
+ dM=derivative(dM);
+ }
+ Piecewise<D2<SBasis> > unitv = unitVector(dM,tol);
+ Piecewise<SBasis> dMlength = dot(Piecewise<D2<SBasis> >(dM),unitv);
+ Piecewise<SBasis> k = cross(derivative(unitv),unitv);
+ k = divide(k,dMlength,tol,3);
+ double curv = k(t); // note that this value is signed
+
+ Geom::Point normal = unitTangentAt(curve, t).cw();
+ double radius = 1/curv;
+ Geom::Point center = curve(t) + radius*normal;
+ return Geom::Circle(center, fabs(radius));
+}
+
} // namespace Geom
namespace Inkscape {
@@ -209,7 +235,7 @@ LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) :
interpolator_type(_("Interpolator type:"), _("Determines which kind of interpolator will be used to interpolate between stroke width along the path"), "interpolator_type", InterpolatorTypeConverter, &wr, this, Geom::Interpolate::INTERP_CUBICBEZIER_JOHAN),
interpolator_beta(_("Smoothness:"), _("Sets the smoothness for the CubicBezierJohan interpolator; 0 = linear interpolation, 1 = smooth"), "interpolator_beta", &wr, this, 0.2),
start_linecap_type(_("Start cap:"), _("Determines the shape of the path's start"), "start_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_ROUND),
- linejoin_type(_("Join:"), _("Specifies the shape of the path's corners"), "linejoin_type", LineJoinTypeConverter, &wr, this, LINEJOIN_ROUND),
+ linejoin_type(_("Join:"), _("Determines the shape of the path's corners"), "linejoin_type", LineJoinTypeConverter, &wr, this, LINEJOIN_ROUND),
miter_limit(_("Miter limit:"), _("Maximum length of the miter (in units of stroke width)"), "miter_limit", &wr, this, 4.),
end_linecap_type(_("End cap:"), _("Determines the shape of the path's end"), "end_linecap_type", LineCapTypeConverter, &wr, this, LINECAP_ROUND)
{
@@ -381,76 +407,26 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::
break;
}
case LINEJOIN_EXTRP_MITER_ARC: {
- Geom::Circle circle0;
- Geom::Circle circle1;
- Geom::Point tang0(0.,0.);
- {
- Geom::Point norm0(0.,0.);
- Geom::Coord curv0 = 0;
- std::vector<Geom::Point> derivs = reverse(B[prev_i]).valueAndDerivatives(0.,5);
- for (unsigned deriv_n = 1, count = 0; deriv_n < derivs.size(); deriv_n++) {
- Geom::Coord length = derivs[deriv_n].length();
- if ( ! Geom::are_near(length, 0) ) {
- if (count == 0) {
- tang0 = derivs[deriv_n] / length;
- curv0 = length; // save the length of the tangent
- count++;
- } else {
- // curv0 = need good way to calculate curvature
- // calculate direction of normal
- double angle = angle_between(tang0, derivs[deriv_n]);
- if (angle >= 0 ) {
- norm0 = tang0.ccw();
- } else {
- norm0 = tang0.cw();
- }
- break; // break out of for-loop
- }
- }
- }
- double r0 = curv0;
- Geom::Point center0 = B[prev_i].at1() - r0*norm0;
- circle0 = Geom::Circle(center0, r0);
- }
- Geom::Point tang1(0.,0.);
- {
- Geom::Point norm1(0.,0.);
- Geom::Coord curv1 = 0;
- std::vector<Geom::Point> derivs = B[i].valueAndDerivatives(0.,5);
- for (unsigned deriv_n = 1, count = 0; deriv_n < derivs.size(); deriv_n++) {
- Geom::Coord length = derivs[deriv_n].length();
- if ( ! Geom::are_near(length, 0) ) {
- if (count == 0) {
- tang1 = derivs[deriv_n] / length;
- curv1 = length; // save the length of the tangent
- count++;
- } else {
- //curv1 = length / curv1; // curvature = tangent' / tangent
- // calculate direction of normal
- double angle = angle_between(tang1, derivs[deriv_n]);
- if (angle >= 0 ) {
- norm1 = tang1.ccw();
- } else {
- norm1 = tang1.cw();
- }
- break; // break out of for-loop
- }
- }
- }
- double r1 = curv1;
- Geom::Point center1 = B[i].at0() - r1*norm1;
- circle1 = Geom::Circle(center1, r1);
- }
-
+ Geom::Circle circle1 = Geom::touching_circle(reverse(B[prev_i]),0.);
+ Geom::Circle circle2 = Geom::touching_circle(B[i],0.);
Geom::Point points[2];
- int solutions = circle_circle_intersection(circle0, circle1, points[0], points[1]);
+ int solutions = circle_circle_intersection(circle1, circle2, points[0], points[1]);
if (solutions == 2) {
- Geom::Point sol = points[0];
- if ( dot(tang0,sol-B[prev_i].at1()) > 0 ) {
+ Geom::Point sol(0.,0.);
+ if ( dot(tang2,points[0]-B[i].at0()) > 0 ) {
+ // points[0] is bad, choose points[1]
sol = points[1];
+ } else if ( dot(tang2,points[1]-B[i].at0()) > 0 ) { // points[0] could be good, now check points[1]
+ // points[1] is bad, choose points[0]
+ sol = points[0];
+ } else {
+ // both points are good, choose nearest
+ sol = ( distanceSq(B[i].at0(), points[0]) < distanceSq(B[i].at0(), points[1]) ) ?
+ points[0] : points[1];
}
- Geom::EllipticalArc *arc0 = circle0.arc(B[prev_i].at1(), 0.5*(B[prev_i].at1()+sol), sol, true);
- Geom::EllipticalArc *arc1 = circle1.arc(sol, 0.5*(sol+B[i].at0()), B[i].at0(), true);
+
+ Geom::EllipticalArc *arc0 = circle1.arc(B[prev_i].at1(), 0.5*(B[prev_i].at1()+sol), sol, true);
+ Geom::EllipticalArc *arc1 = circle2.arc(sol, 0.5*(sol+B[i].at0()), B[i].at0(), true);
if (arc0) {
build_from_sbasis(pb,arc0->toSBasis(), tol, false);
@@ -462,13 +438,30 @@ static Geom::Path path_from_piecewise_fix_cusps( Geom::Piecewise<Geom::D2<Geom::
delete arc1;
arc1 = NULL;
}
- } else if (solutions == 1) { // one circle is inside the other
+
+ break;
+ } else {
+ // fall back to miter
+ boost::optional<Geom::Point> p = intersection_point( B[prev_i].at1(), tang1,
+ B[i].at0(), tang2 );
+ if (p) {
+ // check size of miter
+ Geom::Point point_on_path = B[prev_i].at1() - rot90(tang1) * width;
+ Geom::Coord len = distance(*p, point_on_path);
+ if (len <= fabs(width) * miter_limit) {
+ // miter OK
+ pb.lineTo(*p);
+ }
+ }
+ pb.lineTo(B[i].at0());
+ }
+ /*else if (solutions == 1) { // one circle is inside the other
// don't know what to do: default to bevel
pb.lineTo(B[i].at0());
} else { // no intersections
// don't know what to do: default to bevel
pb.lineTo(B[i].at0());
- }
+ } */
break;
}
diff --git a/src/main.cpp b/src/main.cpp
index 578279929..844aded56 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -390,7 +390,7 @@ struct poptOption options[] = {
{"export-text-to-path", 'T',
POPT_ARG_NONE, &sp_export_text_to_path, SP_ARG_EXPORT_TEXT_TO_PATH,
- N_("Convert text object to paths on export (PS, EPS, PDF)"),
+ N_("Convert text object to paths on export (PS, EPS, PDF, SVG)"),
NULL},
{"export-ignore-filters", 0,
diff --git a/src/menus-skeleton.h b/src/menus-skeleton.h
index 09366a33f..fa39dbd3a 100644
--- a/src/menus-skeleton.h
+++ b/src/menus-skeleton.h
@@ -182,6 +182,7 @@ static char const menus_skeleton[] =
" <submenu name=\"" N_("_Object") "\">\n"
" <verb verb-id=\"DialogFillStroke\" />\n"
" <verb verb-id=\"DialogObjectProperties\" />\n"
+" <verb verb-id=\"DialogSymbols\" />\n"
" <separator/>\n"
" <verb verb-id=\"SelectionGroup\" />\n"
" <verb verb-id=\"SelectionUnGroup\" />\n"
@@ -198,6 +199,10 @@ static char const menus_skeleton[] =
" <verb verb-id=\"ObjectsToPattern\" />\n"
" <verb verb-id=\"ObjectsFromPattern\" />\n"
" </submenu>\n"
+" <submenu name=\"" N_("Symbo_l") "\">\n"
+" <verb verb-id=\"ObjectsToSymbol\" />\n"
+" <verb verb-id=\"ObjectsFromSymbol\" />\n"
+" </submenu>\n"
" <verb verb-id=\"ObjectsToMarker\" />\n"
" <verb verb-id=\"ObjectsToGuides\" />\n"
" <separator/>\n"
diff --git a/src/path-prefix.h b/src/path-prefix.h
index bdb6b35f7..be57ae354 100644
--- a/src/path-prefix.h
+++ b/src/path-prefix.h
@@ -34,6 +34,7 @@ extern "C" {
# define INKSCAPE_PALETTESDIR BR_DATADIR( "/inkscape/palettes" )
# define INKSCAPE_PATTERNSDIR BR_DATADIR( "/inkscape/patterns" )
# define INKSCAPE_SCREENSDIR BR_DATADIR( "/inkscape/screens" )
+# define INKSCAPE_SYMBOLSDIR BR_DATADIR( "/inkscape/symbols" )
# define INKSCAPE_TUTORIALSDIR BR_DATADIR( "/inkscape/tutorials" )
# define INKSCAPE_TEMPLATESDIR BR_DATADIR( "/inkscape/templates" )
# define INKSCAPE_UIDIR BR_DATADIR( "/inkscape/ui" )
@@ -56,6 +57,7 @@ extern "C" {
# define INKSCAPE_PALETTESDIR WIN32_DATADIR("share\\palettes")
# define INKSCAPE_PATTERNSDIR WIN32_DATADIR("share\\patterns")
# define INKSCAPE_SCREENSDIR WIN32_DATADIR("share\\screens")
+# define INKSCAPE_SYMBOLSDIR WIN32_DATADIR("share\\symbols")
# define INKSCAPE_TUTORIALSDIR WIN32_DATADIR("share\\tutorials")
# define INKSCAPE_TEMPLATESDIR WIN32_DATADIR("share\\templates")
# define INKSCAPE_UIDIR WIN32_DATADIR("share\\ui")
@@ -77,6 +79,7 @@ extern "C" {
# define INKSCAPE_PALETTESDIR "Contents/Resources/palettes"
# define INKSCAPE_PATTERNSDIR "Contents/Resources/patterns"
# define INKSCAPE_SCREENSDIR "Contents/Resources/screens"
+# define INKSCAPE_SYMBOLSDIR "Contents/Resources/symbols"
# define INKSCAPE_TUTORIALSDIR "Contents/Resources/tutorials"
# define INKSCAPE_TEMPLATESDIR "Contents/Resources/templates"
# define INKSCAPE_UIDIR "Contents/Resources/ui"
@@ -98,6 +101,7 @@ extern "C" {
# define INKSCAPE_PALETTESDIR INKSCAPE_DATADIR "/inkscape/palettes"
# define INKSCAPE_PATTERNSDIR INKSCAPE_DATADIR "/inkscape/patterns"
# define INKSCAPE_SCREENSDIR INKSCAPE_DATADIR "/inkscape/screens"
+# define INKSCAPE_SYMBOLSDIR INKSCAPE_DATADIR "/inkscape/symbols"
# define INKSCAPE_TUTORIALSDIR INKSCAPE_DATADIR "/inkscape/tutorials"
# define INKSCAPE_TEMPLATESDIR INKSCAPE_DATADIR "/inkscape/templates"
# define INKSCAPE_UIDIR INKSCAPE_DATADIR "/inkscape/ui"
diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp
index 332e9a34e..904e21960 100644
--- a/src/selection-chemistry.cpp
+++ b/src/selection-chemistry.cpp
@@ -11,6 +11,7 @@
* Martin Sucha <martin.sucha-inkscape@jts-sro.sk>
* Abhishek Sharma
* Kris De Gussem <Kris.DeGussem@gmail.com>
+ * Tavmjong Bah <tavmjong@free.fr> (Symbol additions)
*
* Copyright (C) 1999-2010,2012 authors
* Copyright (C) 2001-2002 Ximian, Inc.
@@ -71,6 +72,7 @@ SPCycleType SP_CYCLING = SP_CYCLE_FOCUS;
#include "sp-gradient-reference.h"
#include "sp-linear-gradient-fns.h"
#include "sp-pattern.h"
+#include "sp-symbol.h"
#include "sp-radial-gradient-fns.h"
#include "gradient-context.h"
#include "sp-namedview.h"
@@ -2887,6 +2889,162 @@ void sp_selection_to_guides(SPDesktop *desktop)
DocumentUndo::done(doc, SP_VERB_EDIT_SELECTION_2_GUIDES, _("Objects to guides"));
}
+/*
+ * Convert <g> to <symbol>, leaving all <use> elements referencing group unchanged.
+ */
+void sp_selection_symbol(SPDesktop *desktop, bool apply )
+{
+
+ if (desktop == NULL) {
+ return;
+ }
+
+ SPDocument *doc = sp_desktop_document(desktop);
+ Inkscape::XML::Document *xml_doc = doc->getReprDoc();
+
+ Inkscape::Selection *selection = sp_desktop_selection(desktop);
+
+ // Check if something is selected.
+ if (selection->isEmpty()) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select one <b>group</b> to convert to symbol."));
+ return;
+ }
+
+ SPObject* group = selection->single();
+
+ // Make sure we have only one object in selection.
+ if( group == NULL ) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select only one <b>group</b> to convert to symbol."));
+ return;
+ }
+
+ // Make sure we convert the original.
+ if( SP_IS_USE( group ) ) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select original (<b>Shift+D</b>) to convert to symbol."));
+ return;
+ }
+
+ // Require that we really have a group.
+ if( !SP_IS_GROUP( group ) ) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Group selection first to convert to symbol."));
+ return;
+ }
+
+ doc->ensureUpToDate();
+
+ Inkscape::XML::Node *symbol = xml_doc->createElement("svg:symbol");
+ symbol->setAttribute("style", group->getAttribute("style"));
+ symbol->setAttribute("title", group->getAttribute("title"));
+ symbol->setAttribute("transform", group->getAttribute("transform"));
+
+ Glib::ustring id = group->getAttribute("id");
+
+ // Now we need to copy all children of group
+ GSList* children = group->childList(false);
+ children = g_slist_reverse(children);
+ for (GSList* i = children; i != NULL; i = i->next ) {
+ SPObject* child = SP_OBJECT(i->data);
+ Inkscape::XML::Node *dup = child->getRepr()->duplicate(xml_doc);
+ symbol->appendChild(dup);
+ child->deleteObject(true);
+ }
+
+ // Need to delete <g>; all <use> elements that referenced <g> should
+ // auto-magically reference <symbol>.
+ doc->getDefs()->getRepr()->appendChild(symbol);
+ symbol->setAttribute("id",id.c_str()); // After we delete group with same id.
+ // Mysterious, must set symbol ID before deleting group or all <use>
+ // refering to symbol get turned into groups. (Linked to unlinking clones?)
+ group->deleteObject(true);
+
+ Inkscape::GC::release(symbol);
+ selection->clear();
+ // Group just disappears, nothing to select.
+
+ // Need to signal Symbol dialog to update
+
+ g_slist_free(children);
+
+ DocumentUndo::done(doc, SP_VERB_EDIT_SYMBOL, _("Group to symbol"));
+}
+
+/*
+ * Convert <symbol> to <g>. All <use> elements referencing symbol remain unchanged.
+ */
+void sp_selection_unsymbol(SPDesktop *desktop)
+{
+
+ if (desktop == NULL) {
+ return;
+ }
+
+ SPDocument *doc = sp_desktop_document(desktop);
+ Inkscape::XML::Document *xml_doc = doc->getReprDoc();
+
+ Inkscape::Selection *selection = sp_desktop_selection(desktop);
+
+ // Check if something is selected.
+ if (selection->isEmpty()) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select a <b>symbol</b> to extract objects from."));
+ return;
+ }
+
+ SPObject* use = selection->single();
+
+ // Make sure we have only one object in selection.
+ if( use == NULL ) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select only one <b>symbol</b> to convert to group."));
+ return;
+ }
+
+ // Require that we really have a <use> that references a <symbol>.
+ if( !SP_IS_USE( use ) && !SP_IS_SYMBOL( use->firstChild() ) ) {
+ desktop->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("Select only one <b>symbol</b> to convert to group."));
+ return;
+ }
+
+ doc->ensureUpToDate();
+
+ SPObject* symbol = use->firstChild();
+
+ Inkscape::XML::Node *group = xml_doc->createElement("svg:g");
+ group->setAttribute("style", symbol->getAttribute("style"));
+ group->setAttribute("title", symbol->getAttribute("title"));
+ group->setAttribute("transform", symbol->getAttribute("transform"));
+
+ Glib::ustring id = symbol->getAttribute("id");
+
+ // Now we need to copy all children of symbol
+ GSList* children = symbol->childList(false);
+ children = g_slist_reverse(children);
+ for (GSList* i = children; i != NULL; i = i->next ) {
+ SPObject* child = SP_OBJECT(i->data);
+ Inkscape::XML::Node *dup = child->getRepr()->duplicate(xml_doc);
+ group->appendChild(dup);
+ child->deleteObject(true);
+ }
+
+ SPObject* parent = use->parent; // So we insert <g> next to <use> (easier to find)
+
+ // Need to delete <symbol>; all other <use> elements that referenced <symbol> should
+ // auto-magically reference <g>.
+ symbol->deleteObject(true);
+ group->setAttribute("id",id.c_str()); // After we delete symbol with same id.
+ parent->getRepr()->appendChild(group);
+ //use->deleteObject(true);
+
+ SPItem *group_item = static_cast<SPItem *>(sp_desktop_document(desktop)->getObjectByRepr(group));
+ Inkscape::GC::release(group);
+ selection->clear();
+ selection->set(group_item);
+
+ // Need to signal Symbol dialog to update
+
+ g_slist_free(children);
+
+ DocumentUndo::done(doc, SP_VERB_EDIT_UNSYMBOL, _("Group from symbol"));
+}
+
void
sp_selection_tile(SPDesktop *desktop, bool apply)
{
diff --git a/src/selection-chemistry.h b/src/selection-chemistry.h
index 3c9c1aea9..5b35ded09 100644
--- a/src/selection-chemistry.h
+++ b/src/selection-chemistry.h
@@ -11,7 +11,7 @@
* Jon A. Cruz <jon@joncruz.org>
* Abhishek Sharma
*
- * Copyright (C) 1999-2010 authors
+ * Copyright (C) 1999-2012 authors
* Copyright (C) 2001-2002 Ximian, Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -67,6 +67,9 @@ void sp_selection_clone_original_path_lpe(SPDesktop *desktop);
void sp_selection_to_marker(SPDesktop *desktop, bool apply = true);
void sp_selection_to_guides(SPDesktop *desktop);
+void sp_selection_symbol(SPDesktop *desktop, bool apply = true);
+void sp_selection_unsymbol(SPDesktop *desktop);
+
void sp_selection_tile(SPDesktop *desktop, bool apply = true);
void sp_selection_untile(SPDesktop *desktop);
diff --git a/src/selection-describer.cpp b/src/selection-describer.cpp
index c141c3da5..391db8950 100644
--- a/src/selection-describer.cpp
+++ b/src/selection-describer.cpp
@@ -24,6 +24,7 @@
#include "sp-offset.h"
#include "sp-flowtext.h"
#include "sp-use.h"
+#include "sp-symbol.h"
#include "sp-rect.h"
#include "box3d.h"
#include "sp-ellipse.h"
@@ -192,7 +193,11 @@ void SelectionDescriber::_updateMessageFromSelection(Inkscape::Selection *select
if (!items->next) { // one item
char *item_desc = item->description();
- if (SP_IS_USE(item) || (SP_IS_OFFSET(item) && SP_OFFSET (item)->sourceHref)) {
+ if (SP_IS_USE(item) && SP_IS_SYMBOL(item->firstChild())) {
+ _context.setF(Inkscape::NORMAL_MESSAGE, "%s%s. %s. %s.",
+ item_desc, in_phrase,
+ _("Convert symbol to group to edit"), _when_selected);
+ } else if (SP_IS_USE(item) || (SP_IS_OFFSET(item) && SP_OFFSET (item)->sourceHref)) {
_context.setF(Inkscape::NORMAL_MESSAGE, "%s%s. %s. %s.",
item_desc, in_phrase,
_("Use <b>Shift+D</b> to look up original"), _when_selected);
diff --git a/src/sp-object.cpp b/src/sp-object.cpp
index c16dbaeef..3e18c0835 100644
--- a/src/sp-object.cpp
+++ b/src/sp-object.cpp
@@ -1409,6 +1409,9 @@ void SPObject::_requireSVGVersion(Inkscape::Version version) {
be made. The same applies to 'desc' elements. Therefore, these functions
ignore all but the first 'title' child element and first 'desc' child
element, except when deleting a title or description.
+
+ This will change in SVG 2, where multiple 'title' and 'desc' elements will
+ be allowed with different localized strings.
*/
gchar * SPObject::title() const
diff --git a/src/sp-symbol.cpp b/src/sp-symbol.cpp
index 87cd210e4..56f862bf3 100644
--- a/src/sp-symbol.cpp
+++ b/src/sp-symbol.cpp
@@ -405,6 +405,11 @@ static Geom::OptRect sp_symbol_bbox(SPItem const *item, Geom::Affine const &tran
Geom::Affine const a( symbol->c2p * transform );
bbox = ((SPItemClass *) (parent_class))->bbox(item, a, type);
}
+ } else {
+ // Need bounding box for Symbols dialog
+
+ Geom::Affine const a;
+ bbox = ((SPItemClass *) (parent_class))->bbox(item, a, type);
}
return bbox;
}
diff --git a/src/sp-use.cpp b/src/sp-use.cpp
index e39f560c3..0f45f5444 100644
--- a/src/sp-use.cpp
+++ b/src/sp-use.cpp
@@ -321,6 +321,14 @@ sp_use_description(SPItem *item)
char *ret;
if (use->child) {
+
+ if( SP_IS_SYMBOL( use->child ) ) {
+ //char *symbol_desc = SP_ITEM(use->child)->description();
+ //g_free(symbol_desc);
+ return g_strdup(_("<b>Clone of Symbol</b>"));
+ //return g_strdup_printf(_("<b>Clone of Symbol</b>: %s"), symbol_desc );
+ }
+
static unsigned recursion_depth = 0;
if (recursion_depth >= 4) {
/* TRANSLATORS: Used for statusbar description for long <use> chains:
diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp
index f1f6c4ab4..8cdb37f4f 100644
--- a/src/ui/clipboard.cpp
+++ b/src/ui/clipboard.cpp
@@ -7,9 +7,11 @@
* Jon A. Cruz <jon@joncruz.org>
* Incorporates some code from selection-chemistry.cpp, see that file for more credits.
* Abhishek Sharma
+ * Tavmjong Bah
*
* Copyright (C) 2008 authors
* Copyright (C) 2010 Jon A. Cruz
+ * Copyright (C) 2012 Tavmjong Bah (Symbol additions)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -66,6 +68,8 @@
#include "sp-mask.h"
#include "sp-textpath.h"
#include "sp-rect.h"
+#include "sp-use.h"
+#include "sp-symbol.h"
#include "live_effects/lpeobject.h"
#include "live_effects/lpeobject-reference.h"
#include "live_effects/parameter/path.h"
@@ -109,6 +113,7 @@ class ClipboardManagerImpl : public ClipboardManager {
public:
virtual void copy(SPDesktop *desktop);
virtual void copyPathParameter(Inkscape::LivePathEffect::PathParam *);
+ virtual void copySymbol(Inkscape::XML::Node* symbol, gchar const* style);
virtual bool paste(SPDesktop *desktop, bool in_place);
virtual bool pasteStyle(SPDesktop *desktop);
virtual bool pasteSize(SPDesktop *desktop, bool separately, bool apply_x, bool apply_y);
@@ -295,6 +300,43 @@ void ClipboardManagerImpl::copyPathParameter(Inkscape::LivePathEffect::PathParam
}
/**
+ * Copy a symbol from the symbol dialog.
+ * @param symbol The Inkscape::XML::Node for the symbol.
+ */
+void ClipboardManagerImpl::copySymbol(Inkscape::XML::Node* symbol, gchar const* style)
+{
+ //std::cout << "ClipboardManagerImpl::copySymbol" << std::endl;
+ if ( symbol == NULL ) {
+ return;
+ }
+
+ _discardInternalClipboard();
+ _createInternalClipboard();
+
+ // We add "_duplicate" to have a well defined symbol name that
+ // bypasses the "prevent_id_classes" routine. We'll get rid of it
+ // when we paste.
+ Inkscape::XML::Node *repr = symbol->duplicate(_doc);
+ Glib::ustring symbol_name = repr->attribute("id");
+
+ symbol_name += "_inkscape_duplicate";
+ repr->setAttribute("id", symbol_name.c_str());
+ _defs->appendChild(repr);
+
+ Glib::ustring id("#");
+ id += symbol->attribute("id");
+
+ Inkscape::XML::Node *use = _doc->createElement("svg:use");
+ use->setAttribute("xlink:href", id.c_str() );
+ // Set a default style in <use> rather than <symbol> so it can be changed.
+ use->setAttribute("style", style );
+ _root->appendChild(use);
+
+ fit_canvas_to_drawing(_clipboardSPDoc);
+ _setClipboardTargets();
+}
+
+/**
* Paste from the system clipboard into the active desktop.
* @param in_place Whether to put the contents where they were when copied.
*/
@@ -725,6 +767,14 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item)
}
}
+ // Copy symbols: We may want to be more clever...
+ // if (SP_IS_USE(item)) {
+ // SPObject *symbol = SP_USE(item)->child;
+ // if( symbol && SP_IS_SYMBOL(symbol) ) {
+ // _copyNode(symbol->getRepr(), _doc, _defs);
+ // }
+ // }
+
// recurse
for (SPObject *o = item->children ; o != NULL ; o = o->next) {
if (SP_IS_ITEM(o)) {
diff --git a/src/ui/clipboard.h b/src/ui/clipboard.h
index fb28bfc14..b565740c3 100644
--- a/src/ui/clipboard.h
+++ b/src/ui/clipboard.h
@@ -25,6 +25,7 @@
class SPDesktop;
namespace Inkscape {
class Selection;
+namespace XML { class Node; }
namespace LivePathEffect { class PathParam; }
namespace UI {
@@ -43,6 +44,7 @@ class ClipboardManager {
public:
virtual void copy(SPDesktop *desktop) = 0;
virtual void copyPathParameter(Inkscape::LivePathEffect::PathParam *) = 0;
+ virtual void copySymbol(Inkscape::XML::Node* symbol, gchar const* style) = 0;
virtual bool paste(SPDesktop *desktop, bool in_place = false) = 0;
virtual bool pasteStyle(SPDesktop *desktop) = 0;
virtual bool pasteSize(SPDesktop *desktop, bool separately, bool apply_x, bool apply_y) = 0;
diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert
index ba2f53a9e..580b47522 100644
--- a/src/ui/dialog/Makefile_insert
+++ b/src/ui/dialog/Makefile_insert
@@ -89,6 +89,8 @@ ink_common_sources += \
ui/dialog/svg-fonts-dialog.h \
ui/dialog/swatches.cpp \
ui/dialog/swatches.h \
+ ui/dialog/symbols.cpp \
+ ui/dialog/symbols.h \
ui/dialog/text-edit.cpp \
ui/dialog/text-edit.h \
ui/dialog/tile.cpp \
diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp
index 60011ca9d..faba47769 100644
--- a/src/ui/dialog/dialog-manager.cpp
+++ b/src/ui/dialog/dialog-manager.cpp
@@ -33,6 +33,7 @@
#include "ui/dialog/memory.h"
#include "ui/dialog/messages.h"
#include "ui/dialog/scriptdialog.h"
+#include "ui/dialog/symbols.h"
#include "ui/dialog/tile.h"
#include "ui/dialog/tracedialog.h"
#include "ui/dialog/transformation.h"
@@ -121,6 +122,7 @@ DialogManager::DialogManager() {
registerFactory("SvgFontsDialog", &create<SvgFontsDialog, FloatingBehavior>);
#endif
registerFactory("Swatches", &create<SwatchesPanel, FloatingBehavior>);
+ registerFactory("Symbols", &create<SymbolsDialog, FloatingBehavior>);
registerFactory("TileDialog", &create<TileDialog, FloatingBehavior>);
registerFactory("Trace", &create<TraceDialog, FloatingBehavior>);
registerFactory("Transformation", &create<Transformation, FloatingBehavior>);
@@ -156,6 +158,7 @@ DialogManager::DialogManager() {
registerFactory("SvgFontsDialog", &create<SvgFontsDialog, DockBehavior>);
#endif
registerFactory("Swatches", &create<SwatchesPanel, DockBehavior>);
+ registerFactory("Symbols", &create<SymbolsDialog, DockBehavior>);
registerFactory("TileDialog", &create<TileDialog, DockBehavior>);
registerFactory("Trace", &create<TraceDialog, DockBehavior>);
registerFactory("Transformation", &create<Transformation, DockBehavior>);
diff --git a/src/ui/dialog/layer-properties.cpp b/src/ui/dialog/layer-properties.cpp
index 35a235dbc..4f9edf774 100644
--- a/src/ui/dialog/layer-properties.cpp
+++ b/src/ui/dialog/layer-properties.cpp
@@ -331,8 +331,11 @@ void LayerPropertiesDialog::Rename::perform(LayerPropertiesDialog &dialog) {
void LayerPropertiesDialog::Create::setup(LayerPropertiesDialog &dialog) {
dialog.set_title(_("Add Layer"));
- //TODO: find an unused layer number, forming name from _("Layer ") + "%d"
- dialog._layer_name_entry.set_text(_("Layer"));
+
+ // Set the initial name to the "next available" layer name
+ LayerManager *mgr = dialog._desktop->layer_manager;
+ Glib::ustring newName = mgr->getNextLayerName(NULL, dialog._desktop->currentLayer()->label());
+ dialog._layer_name_entry.set_text(newName.c_str());
dialog._apply_button.set_label(_("_Add"));
dialog._setup_position_controls();
}
diff --git a/src/ui/dialog/layers.cpp b/src/ui/dialog/layers.cpp
index 70cf7075c..55a2f19a5 100644
--- a/src/ui/dialog/layers.cpp
+++ b/src/ui/dialog/layers.cpp
@@ -69,6 +69,9 @@ enum {
BUTTON_SOLO,
BUTTON_SHOW_ALL,
BUTTON_HIDE_ALL,
+ BUTTON_LOCK_OTHERS,
+ BUTTON_LOCK_ALL,
+ BUTTON_UNLOCK_ALL,
DRAGNDROP
};
@@ -263,6 +266,21 @@ bool LayersPanel::_executeAction()
_fireAction( SP_VERB_LAYER_HIDE_ALL );
}
break;
+ case BUTTON_LOCK_OTHERS:
+ {
+ _fireAction( SP_VERB_LAYER_LOCK_OTHERS );
+ }
+ break;
+ case BUTTON_LOCK_ALL:
+ {
+ _fireAction( SP_VERB_LAYER_LOCK_ALL );
+ }
+ break;
+ case BUTTON_UNLOCK_ALL:
+ {
+ _fireAction( SP_VERB_LAYER_UNLOCK_ALL );
+ }
+ break;
case DRAGNDROP:
{
_doTreeMove( );
@@ -544,26 +562,36 @@ void LayersPanel::_handleButtonEvent(GdkEventButton* event)
{
static unsigned doubleclick = 0;
- // TODO - fix to a better is-popup function
if ( (event->type == GDK_BUTTON_PRESS) && (event->button == 3) ) {
+ // TODO - fix to a better is-popup function
+ Gtk::TreeModel::Path path;
+ int x = static_cast<int>(event->x);
+ int y = static_cast<int>(event->y);
+ if ( _tree.get_path_at_pos( x, y, path ) ) {
+ _checkTreeSelection();
+ _popupMenu.popup(event->button, event->time);
+ }
+ }
- {
- Gtk::TreeModel::Path path;
- Gtk::TreeViewColumn* col = 0;
- int x = static_cast<int>(event->x);
- int y = static_cast<int>(event->y);
- int x2 = 0;
- int y2 = 0;
- if ( _tree.get_path_at_pos( x, y,
- path, col,
- x2, y2 ) ) {
- _checkTreeSelection();
- _popupMenu.popup(event->button, event->time);
+ if ( event->type == GDK_BUTTON_RELEASE && (event->button == 1)
+ && (event->state & GDK_SHIFT_MASK)) {
+ // Shift left click on the visible/lock columns toggles "solo" mode
+ Gtk::TreeModel::Path path;
+ Gtk::TreeViewColumn* col = 0;
+ int x = static_cast<int>(event->x);
+ int y = static_cast<int>(event->y);
+ int x2 = 0;
+ int y2 = 0;
+ if ( _tree.get_path_at_pos( x, y, path, col, x2, y2 ) ) {
+ if (col == _tree.get_column(COL_VISIBLE-1)) {
+ _takeAction(BUTTON_SOLO);
+ } else if (col == _tree.get_column(COL_LOCKED-1)) {
+ _takeAction(BUTTON_LOCK_OTHERS);
}
}
-
}
+
if ( (event->type == GDK_2BUTTON_PRESS) && (event->button == 1) ) {
doubleclick = 1;
}
@@ -876,6 +904,12 @@ LayersPanel::LayersPanel() :
_popupMenu.append(*manage(new Gtk::SeparatorMenuItem()));
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOCK_OTHERS, 0, "Lock Others", (int)BUTTON_LOCK_OTHERS ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOCK_ALL, 0, "Lock All", (int)BUTTON_LOCK_ALL ) );
+ _watching.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_UNLOCK_ALL, 0, "Unlock All", (int)BUTTON_UNLOCK_ALL ) );
+
+ _popupMenu.append(*manage(new Gtk::SeparatorMenuItem()));
+
_watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_RAISE, GTK_STOCK_GO_UP, "Up", (int)BUTTON_UP ) );
_watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_LAYER_LOWER, GTK_STOCK_GO_DOWN, "Down", (int)BUTTON_DOWN ) );
diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp
new file mode 100644
index 000000000..21a178b57
--- /dev/null
+++ b/src/ui/dialog/symbols.cpp
@@ -0,0 +1,591 @@
+/**
+ * @file
+ * Symbols dialog.
+ */
+/* Authors:
+ * Copyright (C) 2012 Tavmjong Bah
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <iostream>
+#include <algorithm>
+
+#include <gtkmm/buttonbox.h>
+#include <gtkmm/label.h>
+#include <gtkmm/table.h>
+#include <gtkmm/scrolledwindow.h>
+#include <gtkmm/comboboxtext.h>
+#include <gtkmm/iconview.h>
+#include <gtkmm/liststore.h>
+#include <gtkmm/treemodelcolumn.h>
+#include <gtkmm/clipboard.h>
+
+#include "path-prefix.h"
+#include "io/sys.h"
+
+#include "ui/cache/svg_preview_cache.h"
+#include "ui/clipboard.h"
+
+#include "symbols.h"
+
+#include "desktop.h"
+#include "desktop-handles.h"
+#include "document.h"
+#include "inkscape.h"
+#include "sp-root.h"
+#include "sp-use.h"
+#include "sp-symbol.h"
+
+#include "verbs.h"
+#include "xml/repr.h"
+
+namespace Inkscape {
+namespace UI {
+
+static Cache::SvgPreview svg_preview_cache;
+
+namespace Dialog {
+
+ // See: http://developer.gnome.org/gtkmm/stable/classGtk_1_1TreeModelColumnRecord.html
+class SymbolColumns : public Gtk::TreeModel::ColumnRecord
+{
+public:
+
+ Gtk::TreeModelColumn<Glib::ustring> symbol_id;
+ Gtk::TreeModelColumn<Glib::ustring> symbol_title;
+ Gtk::TreeModelColumn< Glib::RefPtr<Gdk::Pixbuf> > symbol_image;
+
+ SymbolColumns() {
+ add(symbol_id);
+ add(symbol_title);
+ add(symbol_image);
+ }
+};
+
+SymbolColumns* SymbolsDialog::getColumns()
+{
+ SymbolColumns* columns = new SymbolColumns();
+ return columns;
+}
+
+/**
+ * Constructor
+ */
+SymbolsDialog::SymbolsDialog( gchar const* prefsPath ) :
+ UI::Widget::Panel("", prefsPath, SP_VERB_DIALOG_SYMBOLS),
+ store(Gtk::ListStore::create(*getColumns())),
+ iconView(0),
+ previewScale(0),
+ previewSize(0),
+ currentDesktop(0),
+ deskTrack(),
+ currentDocument(0),
+ previewDocument(0),
+ instanceConns()
+{
+
+ /******************** Table *************************/
+ // Replace by Grid for GTK 3.0
+ Gtk::Table *table = new Gtk::Table(2, 4, false);
+ // panel is a cloked Gtk::VBox
+ _getContents()->pack_start(*Gtk::manage(table), Gtk::PACK_EXPAND_WIDGET);
+ guint row = 0;
+
+ /******************** Symbol Sets *************************/
+ Gtk::Label* labelSet = new Gtk::Label("Symbol set: ");
+ table->attach(*Gtk::manage(labelSet),0,1,row,row+1,Gtk::SHRINK,Gtk::SHRINK);
+
+ symbolSet = new Gtk::ComboBoxText(); // Fill in later
+#if WITH_GTKMM_2_24
+ symbolSet->append("Current Document");
+#else
+ symbolSet->append_text("Current Document");
+#endif
+ symbolSet->set_active_text("Current Document");
+ table->attach(*Gtk::manage(symbolSet),1,2,row,row+1,Gtk::FILL|Gtk::EXPAND,Gtk::SHRINK);
+
+ sigc::connection connSet =
+ symbolSet->signal_changed().connect(sigc::mem_fun(*this, &SymbolsDialog::rebuild));
+ instanceConns.push_back(connSet);
+
+ ++row;
+
+ /********************* Icon View **************************/
+ SymbolColumns* columns = getColumns();
+
+ iconView = new Gtk::IconView(static_cast<Glib::RefPtr<Gtk::TreeModel> >(store));
+ //iconView->set_text_column( columns->symbol_id );
+ iconView->set_tooltip_column( 1 );
+ iconView->set_pixbuf_column( columns->symbol_image );
+
+ sigc::connection connIconChanged;
+ connIconChanged =
+ iconView->signal_selection_changed().connect(sigc::mem_fun(*this, &SymbolsDialog::iconChanged));
+ instanceConns.push_back(connIconChanged);
+
+ Gtk::ScrolledWindow *scroller = new Gtk::ScrolledWindow();
+ scroller->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_ALWAYS);
+ scroller->add(*Gtk::manage(iconView));
+ table->attach(*Gtk::manage(scroller),0,2,row,row+1,Gtk::EXPAND|Gtk::FILL,Gtk::EXPAND|Gtk::FILL);
+
+ ++row;
+
+ /******************** Preview Scale ***********************/
+ Gtk::Label* labelScale = new Gtk::Label("Preview scale: ");
+ table->attach(*Gtk::manage(labelScale),0,1,row,row+1,Gtk::SHRINK,Gtk::SHRINK);
+
+ previewScale = new Gtk::ComboBoxText();
+ const gchar *scales[] =
+ {"Fit", "Fit to width", "Fit to height", "0.1", "0.2", "0.5", "1.0", "2.0", "5.0", NULL};
+ for( int i = 0; scales[i]; ++i ) {
+#if WITH_GTKMM_2_24
+ previewScale->append(scales[i]);
+#else
+ previewScale->append_text(scales[i]);
+#endif
+ }
+ previewScale->set_active_text(scales[0]);
+ table->attach(*Gtk::manage(previewScale),1,2,row,row+1,Gtk::FILL|Gtk::EXPAND,Gtk::SHRINK);
+
+ sigc::connection connScale =
+ previewScale->signal_changed().connect(sigc::mem_fun(*this, &SymbolsDialog::rebuild));
+ instanceConns.push_back(connScale);
+
+ ++row;
+
+ /******************** Preview Size ************************/
+ Gtk::Label* labelSize = new Gtk::Label("Preview size: ");
+ table->attach(*Gtk::manage(labelSize),0,1,row,row+1,Gtk::SHRINK,Gtk::SHRINK);
+
+ previewSize = new Gtk::ComboBoxText();
+ const gchar *sizes[] = {"16", "24", "32", "48", "64", NULL};
+ for( int i = 0; sizes[i]; ++i ) {
+#if WITH_GTKMM_2_24
+ previewSize->append(sizes[i]);
+#else
+ previewSize->append_text(sizes[i]);
+#endif
+
+ }
+ previewSize->set_active_text(sizes[2]);
+ table->attach(*Gtk::manage(previewSize),1,2,row,row+1,Gtk::FILL|Gtk::EXPAND,Gtk::SHRINK);
+
+ sigc::connection connSize =
+ previewSize->signal_changed().connect(sigc::mem_fun(*this, &SymbolsDialog::rebuild));
+ instanceConns.push_back(connSize);
+
+ ++row;
+
+ /**********************************************************/
+ currentDesktop = inkscape_active_desktop();
+ currentDocument = sp_desktop_document(currentDesktop);
+
+ previewDocument = symbols_preview_doc(); /* Template to render symbols in */
+ previewDocument->ensureUpToDate(); /* Necessary? */
+
+ key = SPItem::display_key_new(1);
+ renderDrawing.setRoot(previewDocument->getRoot()->invoke_show(renderDrawing, key, SP_ITEM_SHOW_DISPLAY ));
+
+ get_symbols();
+ draw_symbols( currentDocument ); /* Defaults to current document */
+
+ desktopChangeConn =
+ deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &SymbolsDialog::setTargetDesktop) );
+ instanceConns.push_back( desktopChangeConn );
+ deskTrack.connect(GTK_WIDGET(gobj()));
+}
+
+SymbolsDialog::~SymbolsDialog()
+{
+ for (std::vector<sigc::connection>::iterator it = instanceConns.begin(); it != instanceConns.end(); ++it) {
+ it->disconnect();
+ }
+ instanceConns.clear();
+ deskTrack.disconnect();
+}
+
+SymbolsDialog& SymbolsDialog::getInstance()
+{
+ return *new SymbolsDialog();
+}
+
+void SymbolsDialog::rebuild() {
+
+ store->clear();
+ Glib::ustring symbolSetString = symbolSet->get_active_text();
+
+ SPDocument* symbolDocument = symbolSets[symbolSetString];
+ if( !symbolDocument ) {
+ // Symbol must be from Current Document (this method of
+ // checking should be language independent).
+ symbolDocument = currentDocument;
+ }
+ draw_symbols( symbolDocument );
+}
+
+void SymbolsDialog::iconChanged() {
+#if WITH_GTKMM_3_0
+ std::vector<Gtk::TreePath> iconArray = iconView->get_selected_items();
+#else
+ Gtk::IconView::ArrayHandle_TreePaths iconArray = iconView->get_selected_items();
+#endif
+
+ if( iconArray.empty() ) {
+ //std::cout << " iconArray empty: huh? " << std::endl;
+ } else {
+ Gtk::TreeModel::Path const & path = *iconArray.begin();
+ Gtk::ListStore::iterator row = store->get_iter(path);
+ Glib::ustring symbol_id = (*row)[getColumns()->symbol_id];
+
+ /* OK, we know symbol name... now we need to copy it to clipboard, bon chance! */
+ Glib::ustring symbolSetString = symbolSet->get_active_text();
+
+ SPDocument* symbolDocument = symbolSets[symbolSetString];
+ if( !symbolDocument ) {
+ // Symbol must be from Current Document (this method of
+ // checking should be language independent).
+ symbolDocument = currentDocument;
+ }
+
+ SPObject* symbol = symbolDocument->getObjectById(symbol_id);
+ if( symbol ) {
+
+ // Find style for use in <use>
+ // First look for default style stored in <symbol>
+ gchar const* style = symbol->getAttribute("inkscape:symbol-style");
+ if( !style ) {
+ // If no default style in <symbol>, look in documents.
+ if( symbolDocument == currentDocument ) {
+ style = style_from_use( symbol_id.c_str(), currentDocument );
+ } else {
+ style = symbolDocument->getReprRoot()->attribute("style");
+ }
+ }
+
+ ClipboardManager *cm = ClipboardManager::get();
+ cm->copySymbol(symbol->getRepr(), style);
+ }
+ }
+}
+
+/* Hunts preference directories for symbol files */
+void SymbolsDialog::get_symbols() {
+
+ std::list<Glib::ustring> directories;
+
+ if( Inkscape::IO::file_test( INKSCAPE_SYMBOLSDIR, G_FILE_TEST_EXISTS ) &&
+ Inkscape::IO::file_test( INKSCAPE_SYMBOLSDIR, G_FILE_TEST_IS_DIR ) ) {
+ directories.push_back( INKSCAPE_SYMBOLSDIR );
+ }
+ if( Inkscape::IO::file_test( profile_path("symbols"), G_FILE_TEST_EXISTS ) &&
+ Inkscape::IO::file_test( profile_path("symbols"), G_FILE_TEST_IS_DIR ) ) {
+ directories.push_back( profile_path("symbols") );
+ }
+
+ std::list<Glib::ustring>::iterator it;
+ for( it = directories.begin(); it != directories.end(); ++it ) {
+
+ GError *err = 0;
+ GDir *dir = g_dir_open( (*it).c_str(), 0, &err );
+ if( dir ) {
+
+ gchar *filename = 0;
+ while( (filename = (gchar *)g_dir_read_name( dir ) ) != NULL) {
+
+ gchar *fullname = g_build_filename((*it).c_str(), filename, NULL);
+
+ if ( !Inkscape::IO::file_test( fullname, G_FILE_TEST_IS_DIR ) ) {
+
+ SPDocument* symbol_doc = SPDocument::createNewDoc( fullname, FALSE );
+ if( symbol_doc ) {
+ symbolSets[Glib::ustring(filename)]= symbol_doc;
+#if WITH_GTKMM_2_24
+ symbolSet->append(filename);
+#else
+ symbolSet->append_text(filename);
+#endif
+ }
+ }
+ g_free( fullname );
+ }
+ g_dir_close( dir );
+ }
+ }
+}
+
+GSList* SymbolsDialog::symbols_in_doc_recursive (SPObject *r, GSList *l)
+{
+
+ // Stop multiple counting of same symbol
+ if( SP_IS_USE(r) ) {
+ return l;
+ }
+
+ if( SP_IS_SYMBOL(r) ) {
+ l = g_slist_prepend (l, r);
+ }
+
+ for (SPObject *child = r->firstChild(); child; child = child->getNext()) {
+ l = symbols_in_doc_recursive( child, l );
+ }
+
+ return l;
+}
+
+GSList* SymbolsDialog::symbols_in_doc( SPDocument* symbolDocument ) {
+
+ GSList *l = NULL;
+ l = symbols_in_doc_recursive (symbolDocument->getRoot(), l );
+ return l;
+}
+
+GSList* SymbolsDialog::use_in_doc_recursive (SPObject *r, GSList *l)
+{
+
+ if( SP_IS_USE(r) ) {
+ l = g_slist_prepend (l, r);
+ }
+
+ for (SPObject *child = r->firstChild(); child; child = child->getNext()) {
+ l = use_in_doc_recursive( child, l );
+ }
+
+ return l;
+}
+
+GSList* SymbolsDialog::use_in_doc( SPDocument* useDocument ) {
+
+ GSList *l = NULL;
+ l = use_in_doc_recursive (useDocument->getRoot(), l );
+ return l;
+}
+
+// Returns style from first <use> element found that references id.
+// This is a last ditch effort to find a style.
+gchar const* SymbolsDialog::style_from_use( gchar const* id, SPDocument* document) {
+
+ gchar const* style = 0;
+ GSList* l = use_in_doc( document );
+ for( ; l != NULL; l = l->next ) {
+ SPObject* use = SP_OBJECT(l->data);
+ if( SP_IS_USE( use ) ) {
+ gchar const *href = use->getRepr()->attribute("xlink:href");
+ if( href ) {
+ Glib::ustring href2(href);
+ Glib::ustring id2(id);
+ id2 = "#" + id2;
+ if( !href2.compare(id2) ) {
+ style = use->getRepr()->attribute("style");
+ break;
+ }
+ }
+ }
+ }
+ return style;
+}
+
+void SymbolsDialog::draw_symbols( SPDocument* symbolDocument ) {
+
+
+ SymbolColumns* columns = getColumns();
+
+ GSList* l = symbols_in_doc( symbolDocument );
+ for( ; l != NULL; l = l->next ) {
+
+ SPObject* symbol = SP_OBJECT(l->data);
+ if (!SP_IS_SYMBOL(symbol)) {
+ //std::cout << " Error: not symbol" << std::endl;
+ continue;
+ }
+
+ gchar const *id = symbol->getRepr()->attribute("id");
+ gchar const *title = symbol->title(); // From title element
+ if( !title ) {
+ title = id;
+ }
+
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf = create_symbol_image(id, symbolDocument, &renderDrawing, key );
+ if( pixbuf ) {
+
+ Gtk::ListStore::iterator row = store->append();
+ (*row)[columns->symbol_id] = Glib::ustring( id );
+ (*row)[columns->symbol_title] = Glib::ustring( title );
+ (*row)[columns->symbol_image] = pixbuf;
+ }
+ }
+}
+
+/*
+ * Returns image of symbol.
+ *
+ * Symbols normally are not visible. They must be referenced by a
+ * <use> element. A temporary document is created with a dummy
+ * <symbol> element and a <use> element that references the symbol
+ * element. Each real symbol is swapped in for the dummy symbol and
+ * the temporary document is rendered.
+ */
+Glib::RefPtr<Gdk::Pixbuf>
+SymbolsDialog::create_symbol_image(gchar const *symbol_id,
+ SPDocument *source,
+ Inkscape::Drawing* drawing,
+ unsigned /*visionkey*/)
+{
+
+ // Retrieve the symbol named 'symbol_id' from the source SVG document
+ SPObject const* symbol = source->getObjectById(symbol_id);
+ if (symbol == NULL) {
+ //std::cout << " Failed to find symbol: " << symbol_id << std::endl;
+ //return 0;
+ }
+
+ // Create a copy repr of the symbol with id="the_symbol"
+ Inkscape::XML::Document *xml_doc = previewDocument->getReprDoc();
+ Inkscape::XML::Node *repr = symbol->getRepr()->duplicate(xml_doc);
+ repr->setAttribute("id", "the_symbol");
+
+ // Replace old "the_symbol" in previewDocument by new.
+ Inkscape::XML::Node *root = previewDocument->getReprRoot();
+ SPObject *symbol_old = previewDocument->getObjectById("the_symbol");
+ if (symbol_old) {
+ symbol_old->deleteObject(false);
+ }
+
+ // First look for default style stored in <symbol>
+ gchar const* style = repr->attribute("inkscape:symbol-style");
+ if( !style ) {
+ // If no default style in <symbol>, look in documents.
+ if( source == currentDocument ) {
+ style = style_from_use( symbol_id, source );
+ } else {
+ style = source->getReprRoot()->attribute("style");
+ }
+ }
+
+ // This is for display in Symbols dialog only
+ if( style ) {
+ repr->setAttribute( "style", style );
+ }
+
+ // BUG: Symbols don't work if defined outside of <defs>. Causes Inkscape
+ // crash when trying to read in such a file.
+ root->appendChild(repr);
+ //defsrepr->appendChild(repr);
+ Inkscape::GC::release(repr);
+
+ // Uncomment this to get the previewDocument documents saved (useful for debugging)
+ // FILE *fp = fopen (g_strconcat(symbol_id, ".svg", NULL), "w");
+ // sp_repr_save_stream(previewDocument->getReprDoc(), fp);
+ // fclose (fp);
+
+ // Make sure previewDocument is up-to-date.
+ previewDocument->getRoot()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ previewDocument->ensureUpToDate();
+
+ // Make sure we have symbol in previewDocument
+ SPObject *object_temp = previewDocument->getObjectById( "the_use" );
+ previewDocument->getRoot()->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ previewDocument->ensureUpToDate();
+
+ // if( object_temp == NULL || !SP_IS_ITEM(object_temp) ) {
+ // //std::cout << " previewDocument broken?" << std::endl;
+ // //return 0;
+ // }
+
+ SPItem *item = SP_ITEM(object_temp);
+
+ // Find object's bbox in document.
+ // Note symbols can have own viewport... ignore for now.
+ //Geom::OptRect dbox = item->geometricBounds();
+ Geom::OptRect dbox = item->documentVisualBounds();
+ // if (!dbox) {
+ // //std::cout << " No dbox" << std::endl;
+ // //return NULL;
+ // }
+
+ Glib::ustring previewSizeString = previewSize->get_active_text();
+ unsigned psize = atol( previewSizeString.c_str() );
+
+ Glib::ustring previewScaleString = previewScale->get_active_text();
+ int previewScaleRow = previewScale->get_active_row_number();
+
+ /* Update to renderable state */
+ Glib::ustring key = svg_preview_cache.cache_key(previewDocument->getURI(), symbol_id, psize);
+ //std::cout << " Key: " << key << std::endl;
+ // FIX ME
+ //Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::wrap(svg_preview_cache.get_preview_from_cache(key));
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf = Glib::RefPtr<Gdk::Pixbuf>(0);
+
+ if (!pixbuf) {
+
+ /* Scale symbols to fit */
+ double scale = 1.0;
+ switch (previewScaleRow) {
+ case 0:
+ /* Fit */
+ scale = psize/std::max(dbox->width(),dbox->height());
+ break;
+ case 1:
+ /* Fit width */
+ scale = psize/dbox->width();
+ break;
+ case 2:
+ /* Fit height */
+ scale = psize/dbox->height();
+ break;
+ default:
+ scale = atof( previewScaleString.c_str() );
+ }
+
+ pixbuf = Glib::wrap(render_pixbuf(*drawing, scale, *dbox, psize));
+ svg_preview_cache.set_preview_in_cache(key, pixbuf->gobj());
+ }
+
+ return pixbuf;
+}
+
+/*
+ * Return empty doc to render symbols in.
+ * Symbols are by default not rendered so a <use> element is
+ * provided.
+ */
+SPDocument* SymbolsDialog::symbols_preview_doc()
+{
+ // BUG: <symbol> must be inside <defs>
+ gchar const *buffer =
+"<svg xmlns=\"http://www.w3.org/2000/svg\""
+" xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\""
+" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\""
+" xmlns:xlink=\"http://www.w3.org/1999/xlink\""
+" style=\"fill:none;stroke:black;stroke-width:2\">"
+" <defs id=\"defs\">"
+" <symbol id=\"the_symbol\"/>"
+" </defs>"
+" <use id=\"the_use\" xlink:href=\"#the_symbol\"/>"
+"</svg>";
+
+ return SPDocument::createNewDocFromMem( buffer, strlen(buffer), FALSE );
+}
+
+void SymbolsDialog::setTargetDesktop(SPDesktop *desktop)
+{
+ if (this->currentDesktop != desktop) {
+ this->currentDesktop = desktop;
+ if( !symbolSets[symbolSet->get_active_text()] ) {
+ // Symbol set is from Current document, update
+ rebuild();
+ }
+ }
+}
+
+
+} //namespace Dialogs
+} //namespace UI
+} //namespace Inkscape
+
+
+
diff --git a/src/ui/dialog/symbols.h b/src/ui/dialog/symbols.h
new file mode 100644
index 000000000..c2bb4448e
--- /dev/null
+++ b/src/ui/dialog/symbols.h
@@ -0,0 +1,114 @@
+/** @file
+ * @brief Symbols dialog
+ */
+/* Authors:
+ * Tavmjong Bah
+ *
+ * Copyright (C) 2012 Tavmjong Bah
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef INKSCAPE_UI_DIALOG_SYMBOLS_H
+#define INKSCAPE_UI_DIALOG_SYMBOLS_H
+
+#include "ui/widget/panel.h"
+#include "ui/widget/button.h"
+
+#include "ui/dialog/desktop-tracker.h"
+
+#include "display/drawing.h"
+
+#include <glib.h>
+#include <gtkmm/treemodel.h>
+
+#include <vector>
+
+class SPObject;
+
+namespace Inkscape {
+namespace UI {
+namespace Dialog {
+
+class SymbolColumns; // For Gtk::ListStore
+
+/**
+ * A dialog that displays selectable symbols.
+ */
+class SymbolsDialog : public UI::Widget::Panel {
+
+public:
+ SymbolsDialog( gchar const* prefsPath = "/dialogs/symbols" );
+ virtual ~SymbolsDialog();
+
+ static SymbolsDialog& getInstance();
+
+protected:
+
+
+private:
+ SymbolsDialog(SymbolsDialog const &); // no copy
+ SymbolsDialog &operator=(SymbolsDialog const &); // no assign
+
+ static SymbolColumns *getColumns();
+
+ void rebuild();
+ void iconChanged();
+
+ void get_symbols();
+ void draw_symbols( SPDocument* symbol_document );
+ SPDocument* symbols_preview_doc();
+
+ GSList* symbols_in_doc_recursive(SPObject *r, GSList *l);
+ GSList* symbols_in_doc( SPDocument* document );
+ GSList* use_in_doc_recursive(SPObject *r, GSList *l);
+ GSList* use_in_doc( SPDocument* document );
+ gchar const* style_from_use( gchar const* id, SPDocument* document);
+
+ Glib::RefPtr<Gdk::Pixbuf>
+ create_symbol_image(gchar const *symbol_name,
+ SPDocument *source, Inkscape::Drawing* drawing,
+ unsigned /*visionkey*/);
+
+ /* Keep track of all symbol template documents */
+ std::map<Glib::ustring, SPDocument*> symbolSets;
+
+
+ Glib::RefPtr<Gtk::ListStore> store;
+ Gtk::ComboBoxText* symbolSet;
+ Gtk::IconView* iconView;
+ Gtk::ComboBoxText* previewScale;
+ Gtk::ComboBoxText* previewSize;
+
+ void setTargetDesktop(SPDesktop *desktop);
+ SPDesktop* currentDesktop;
+ DesktopTracker deskTrack;
+ SPDocument* currentDocument;
+ SPDocument* previewDocument; /* Document to render single symbol */
+
+ /* For rendering the template drawing */
+ unsigned key;
+ Inkscape::Drawing renderDrawing;
+
+ std::vector<sigc::connection> instanceConns;
+ sigc::connection desktopChangeConn;
+
+};
+
+} //namespace Dialogs
+} //namespace UI
+} //namespace Inkscape
+
+
+#endif // INKSCAPE_UI_DIALOG_SYMBOLS_H
+
+/*
+ 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 :
diff --git a/src/ui/widget/style-swatch.cpp b/src/ui/widget/style-swatch.cpp
index 857ae7019..60d5f6ecc 100644
--- a/src/ui/widget/style-swatch.cpp
+++ b/src/ui/widget/style-swatch.cpp
@@ -340,15 +340,12 @@ void StyleSwatch::setStyle(SPStyle *query)
if (op != 1) {
{
gchar *str;
- if (op == 0)
- str = g_strdup_printf(_("O:%.3g"), op);
- else
- str = g_strdup_printf(_("O:.%d"), (int) (op*10));
+ str = g_strdup_printf(_("O: %2.0f"), (op*100.0));
_opacity_value.set_markup (str);
g_free (str);
}
{
- gchar *str = g_strdup_printf(_("Opacity: %.3g"), op);
+ gchar *str = g_strdup_printf(_("Opacity: %2.1f %%"), (op*100.0));
_opacity_place.set_tooltip_text(str);
g_free (str);
}
diff --git a/src/verbs.cpp b/src/verbs.cpp
index edfc45f8e..8c45ce665 100644
--- a/src/verbs.cpp
+++ b/src/verbs.cpp
@@ -78,6 +78,7 @@
#include "ui/dialog/layers.h"
#include "ui/dialog/object-properties.h"
#include "ui/dialog/swatches.h"
+#include "ui/dialog/symbols.h"
#include "ui/dialog/spellcheck.h"
#include "ui/icon-names.h"
#include "ui/tool/node-tool.h"
@@ -957,6 +958,12 @@ void EditVerb::perform(SPAction *action, void *data)
case SP_VERB_EDIT_UNTILE:
sp_selection_untile(dt);
break;
+ case SP_VERB_EDIT_SYMBOL:
+ sp_selection_symbol(dt);
+ break;
+ case SP_VERB_EDIT_UNSYMBOL:
+ sp_selection_unsymbol(dt);
+ break;
case SP_VERB_EDIT_CLEAR_ALL:
sp_edit_clear_all(dt);
break;
@@ -1342,17 +1349,34 @@ void LayerVerb::perform(SPAction *action, void *data)
break;
}
case SP_VERB_LAYER_SHOW_ALL: {
- dt->toggleAllLayers( false );
+ dt->toggleHideAllLayers( false );
DocumentUndo::maybeDone(sp_desktop_document(dt), "layer:showall", SP_VERB_LAYER_SHOW_ALL, _("Show all layers"));
break;
}
-
case SP_VERB_LAYER_HIDE_ALL: {
- dt->toggleAllLayers( true );
+ dt->toggleHideAllLayers( true );
DocumentUndo::maybeDone(sp_desktop_document(dt), "layer:hideall", SP_VERB_LAYER_HIDE_ALL, _("Hide all layers"));
break;
}
-
+ case SP_VERB_LAYER_LOCK_ALL: {
+ dt->toggleLockAllLayers( true );
+ DocumentUndo::maybeDone(sp_desktop_document(dt), "layer:lockall", SP_VERB_LAYER_LOCK_ALL, _("Lock all layers"));
+ break;
+ }
+ case SP_VERB_LAYER_LOCK_OTHERS: {
+ if ( dt->currentLayer() == dt->currentRoot() ) {
+ dt->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("No current layer."));
+ } else {
+ dt->toggleLockOtherLayers( dt->currentLayer() );
+ DocumentUndo::maybeDone(sp_desktop_document(dt), "layer:lockothers", SP_VERB_LAYER_LOCK_OTHERS, _("Lock other layers"));
+ }
+ break;
+ }
+ case SP_VERB_LAYER_UNLOCK_ALL: {
+ dt->toggleLockAllLayers( false );
+ DocumentUndo::maybeDone(sp_desktop_document(dt), "layer:unlockall", SP_VERB_LAYER_UNLOCK_ALL, _("Unlock all layers"));
+ break;
+ }
case SP_VERB_LAYER_TOGGLE_LOCK:
case SP_VERB_LAYER_TOGGLE_HIDE: {
if ( dt->currentLayer() == dt->currentRoot() ) {
@@ -1775,6 +1799,24 @@ void ZoomVerb::perform(SPAction *action, void *data)
case SP_VERB_TOGGLE_SCROLLBARS:
dt->toggleScrollbars();
break;
+ case SP_VERB_TOGGLE_COMMANDS_TOOLBAR:
+ dt->toggleToolbar("commands");
+ break;
+ case SP_VERB_TOGGLE_SNAP_TOOLBAR:
+ dt->toggleToolbar("snaptoolbox");
+ break;
+ case SP_VERB_TOGGLE_TOOL_TOOLBAR:
+ dt->toggleToolbar("toppanel");
+ break;
+ case SP_VERB_TOGGLE_TOOLBOX:
+ dt->toggleToolbar("toolbox");
+ break;
+ case SP_VERB_TOGGLE_PALETTE:
+ dt->toggleToolbar("panels");
+ break;
+ case SP_VERB_TOGGLE_STATUSBAR:
+ dt->toggleToolbar("statusbar");
+ break;
case SP_VERB_TOGGLE_GUIDES:
sp_namedview_toggle_guides(doc, repr);
break;
@@ -1833,6 +1875,7 @@ void ZoomVerb::perform(SPAction *action, void *data)
inkscape_dialogs_unhide();
dt->_dlg_mgr->showDialog("IconPreviewPanel");
break;
+
default:
break;
}
@@ -1876,6 +1919,9 @@ void DialogVerb::perform(SPAction *action, void *data)
case SP_VERB_DIALOG_SWATCHES:
dt->_dlg_mgr->showDialog("Swatches");
break;
+ case SP_VERB_DIALOG_SYMBOLS:
+ dt->_dlg_mgr->showDialog("Symbols");
+ break;
case SP_VERB_DIALOG_TRANSFORM:
dt->_dlg_mgr->showDialog("Transformation");
break;
@@ -2339,6 +2385,10 @@ Verb *Verb::_base_verbs[] = {
N_("Convert selection to a rectangle with tiled pattern fill"), NULL),
new EditVerb(SP_VERB_EDIT_UNTILE, "ObjectsFromPattern", N_("Pattern to _Objects"),
N_("Extract objects from a tiled pattern fill"), NULL),
+ new EditVerb(SP_VERB_EDIT_SYMBOL, "ObjectsToSymbol", N_("Group to Symbol"),
+ N_("Convert group to a symbol"), NULL),
+ new EditVerb(SP_VERB_EDIT_UNSYMBOL, "ObjectsFromSymbol", N_("Symbol to Group"),
+ N_("Extract group from a symbol"), NULL),
new EditVerb(SP_VERB_EDIT_CLEAR_ALL, "EditClearAll", N_("Clea_r All"),
N_("Delete all objects from document"), NULL),
new EditVerb(SP_VERB_EDIT_SELECT_ALL, "EditSelectAll", N_("Select Al_l"),
@@ -2489,6 +2539,12 @@ Verb *Verb::_base_verbs[] = {
N_("Show all the layers"), NULL),
new LayerVerb(SP_VERB_LAYER_HIDE_ALL, "LayerHideAll", N_("_Hide all layers"),
N_("Hide all the layers"), NULL),
+ new LayerVerb(SP_VERB_LAYER_LOCK_ALL, "LayerLockAll", N_("_Lock all layers"),
+ N_("Lock all the layers"), NULL),
+ new LayerVerb(SP_VERB_LAYER_LOCK_OTHERS, "LayerLockOthers", N_("Lock/Unlock _other layers"),
+ N_("Lock all the other layers"), NULL),
+ new LayerVerb(SP_VERB_LAYER_UNLOCK_ALL, "LayerUnlockAll", N_("_Unlock all layers"),
+ N_("Unlock all the layers"), NULL),
new LayerVerb(SP_VERB_LAYER_TOGGLE_LOCK, "LayerToggleLock", N_("_Lock/Unlock Current Layer"),
N_("Toggle lock on current layer"), NULL),
new LayerVerb(SP_VERB_LAYER_TOGGLE_HIDE, "LayerToggleHide", N_("_Show/hide Current Layer"),
@@ -2632,6 +2688,12 @@ Verb *Verb::_base_verbs[] = {
new ZoomVerb(SP_VERB_TOGGLE_GRID, "ToggleGrid", N_("_Grid"), N_("Show or hide the grid"), INKSCAPE_ICON("show-grid")),
new ZoomVerb(SP_VERB_TOGGLE_GUIDES, "ToggleGuides", N_("G_uides"), N_("Show or hide guides (drag from a ruler to create a guide)"), INKSCAPE_ICON("show-guides")),
new ZoomVerb(SP_VERB_TOGGLE_SNAPPING, "ToggleSnapGlobal", N_("Snap"), N_("Enable snapping"), INKSCAPE_ICON("snap")),
+ new ZoomVerb(SP_VERB_TOGGLE_COMMANDS_TOOLBAR, "ToggleCommandsToolbar", N_("_Commands Bar"), N_("Show or hide the Commands bar (under the menu)"), NULL),
+ new ZoomVerb(SP_VERB_TOGGLE_SNAP_TOOLBAR, "ToggleSnapToolbar", N_("Sn_ap Controls Bar"), N_("Show or hide the snapping controls"), NULL),
+ new ZoomVerb(SP_VERB_TOGGLE_TOOL_TOOLBAR, "ToggleToolToolbar", N_("T_ool Controls Bar"), N_("Show or hide the Tool Controls bar"), NULL),
+ new ZoomVerb(SP_VERB_TOGGLE_TOOLBOX, "ToggleToolbox", N_("_Toolbox"), N_("Show or hide the main toolbox (on the left)"), NULL),
+ new ZoomVerb(SP_VERB_TOGGLE_PALETTE, "TogglePalette", N_("_Palette"), N_("Show or hide the color palette"), NULL),
+ new ZoomVerb(SP_VERB_TOGGLE_STATUSBAR, "ToggleStatusbar", N_("_Statusbar"), N_("Show or hide the statusbar (at the bottom of the window)"), NULL),
new ZoomVerb(SP_VERB_ZOOM_NEXT, "ZoomNext", N_("Nex_t Zoom"), N_("Next zoom (from the history of zooms)"),
INKSCAPE_ICON("zoom-next")),
new ZoomVerb(SP_VERB_ZOOM_PREV, "ZoomPrev", N_("Pre_vious Zoom"), N_("Previous zoom (from the history of zooms)"),
@@ -2700,6 +2762,8 @@ Verb *Verb::_base_verbs[] = {
// TRANSLATORS: "Swatches" means: color samples
new DialogVerb(SP_VERB_DIALOG_SWATCHES, "DialogSwatches", N_("S_watches..."),
N_("Select colors from a swatches palette"), GTK_STOCK_SELECT_COLOR),
+ new DialogVerb(SP_VERB_DIALOG_SYMBOLS, "DialogSymbols", N_("S_ymbols..."),
+ N_("Select symbol from a symbols palette"), GTK_STOCK_SELECT_COLOR),
new DialogVerb(SP_VERB_DIALOG_TRANSFORM, "DialogTransform", N_("Transfor_m..."),
N_("Precisely control objects' transformations"), INKSCAPE_ICON("dialog-transform")),
new DialogVerb(SP_VERB_DIALOG_ALIGN_DISTRIBUTE, "DialogAlignDistribute", N_("_Align and Distribute..."),
diff --git a/src/verbs.h b/src/verbs.h
index aa801803c..c47d3ae16 100644
--- a/src/verbs.h
+++ b/src/verbs.h
@@ -84,6 +84,8 @@ enum {
SP_VERB_EDIT_SELECTION_2_GUIDES,
SP_VERB_EDIT_TILE,
SP_VERB_EDIT_UNTILE,
+ SP_VERB_EDIT_SYMBOL,
+ SP_VERB_EDIT_UNSYMBOL,
SP_VERB_EDIT_CLEAR_ALL,
SP_VERB_EDIT_SELECT_ALL,
SP_VERB_EDIT_SELECT_ALL_IN_ALL_LAYERS,
@@ -149,6 +151,9 @@ enum {
SP_VERB_LAYER_SOLO,
SP_VERB_LAYER_SHOW_ALL,
SP_VERB_LAYER_HIDE_ALL,
+ SP_VERB_LAYER_LOCK_ALL,
+ SP_VERB_LAYER_LOCK_OTHERS,
+ SP_VERB_LAYER_UNLOCK_ALL,
SP_VERB_LAYER_TOGGLE_LOCK,
SP_VERB_LAYER_TOGGLE_HIDE,
/* Object */
@@ -222,6 +227,12 @@ enum {
SP_VERB_TOGGLE_GRID,
SP_VERB_TOGGLE_GUIDES,
SP_VERB_TOGGLE_SNAPPING,
+ SP_VERB_TOGGLE_COMMANDS_TOOLBAR,
+ SP_VERB_TOGGLE_SNAP_TOOLBAR,
+ SP_VERB_TOGGLE_TOOL_TOOLBAR,
+ SP_VERB_TOGGLE_TOOLBOX,
+ SP_VERB_TOGGLE_PALETTE,
+ SP_VERB_TOGGLE_STATUSBAR,
SP_VERB_ZOOM_NEXT,
SP_VERB_ZOOM_PREV,
SP_VERB_ZOOM_1_1,
@@ -255,6 +266,7 @@ enum {
SP_VERB_DIALOG_FILL_STROKE,
SP_VERB_DIALOG_GLYPHS,
SP_VERB_DIALOG_SWATCHES,
+ SP_VERB_DIALOG_SYMBOLS,
SP_VERB_DIALOG_TRANSFORM,
SP_VERB_DIALOG_ALIGN_DISTRIBUTE,
SP_VERB_DIALOG_SPRAY_OPTION,
@@ -328,6 +340,7 @@ enum {
SP_VERB_ALIGN_VERTICAL_BOTTOM,
SP_VERB_ALIGN_VERTICAL_TOP_TO_ANCHOR,
SP_VERB_ALIGN_VERTICAL_HORIZONTAL_CENTER,
+
/* Footer */
SP_VERB_LAST
};
diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp
index 49eb82de7..6e03c2606 100644
--- a/src/widgets/toolbox.cpp
+++ b/src/widgets/toolbox.cpp
@@ -1446,7 +1446,7 @@ void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
swatch->setClickVerb( aux_toolboxes[i].swatch_verb_id );
swatch->setWatchedTool( aux_toolboxes[i].swatch_tool, true );
GtkWidget *swatch_ = GTK_WIDGET( swatch->gobj() );
- gtk_table_attach( GTK_TABLE(holder), swatch_, 1, 2, 0, 1, (GtkAttachOptions)(GTK_SHRINK | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), AUX_BETWEEN_BUTTON_GROUPS, 0 );
+ gtk_table_attach( GTK_TABLE(holder), swatch_, 1, 2, 0, 1, (GtkAttachOptions)(GTK_SHRINK | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), AUX_BETWEEN_BUTTON_GROUPS, AUX_SPACING );
}
gtk_widget_show_all( holder );
diff --git a/src/widgets/widget-sizes.h b/src/widgets/widget-sizes.h
index c3f9e1119..fe89d4574 100644
--- a/src/widgets/widget-sizes.h
+++ b/src/widgets/widget-sizes.h
@@ -31,7 +31,7 @@
#define SELECTED_STYLE_SB_WIDTH 48
#define SELECTED_STYLE_WIDTH 190
-#define STYLE_SWATCH_WIDTH 100
+#define STYLE_SWATCH_WIDTH 135
#define STATUS_LAYER_FONT_SIZE 7700
diff --git a/src/xml/repr-css.cpp b/src/xml/repr-css.cpp
index 7fba4d7c6..f554d314d 100644
--- a/src/xml/repr-css.cpp
+++ b/src/xml/repr-css.cpp
@@ -351,7 +351,8 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con
guchar *const str_value_unsigned = cr_term_to_string(decl->value);
gchar *const str_value = reinterpret_cast<gchar *>(str_value_unsigned);
gchar *value_unquoted = attribute_unquote (str_value); // libcroco returns strings quoted in ""
- gchar *units = NULL;
+ Glib::ustring value_unquoted2 = value_unquoted ? value_unquoted : Glib::ustring();
+ Glib::ustring units;
/*
* Problem with parsing of units em and ex, like font-size "1.2em" and "3.4ex"
@@ -360,18 +361,22 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con
*
* HACK for now is to strip off em and ex units and add them back at the end
*/
- int l = strlen(value_unquoted);
- if (!strncmp(&value_unquoted[l-2], "em", 2) ||
- !strncmp(&value_unquoted[l-2], "ex", 2)) {
- units = g_strndup(&value_unquoted[l-2], 2);
- value_unquoted = g_strndup(value_unquoted, l-2);
+ int le = value_unquoted2.length();
+ if (le > 2) {
+ units = value_unquoted2.substr(le-2, 2);
+ if ((units == "em") || (units == "ex")) {
+ value_unquoted2 = value_unquoted2.substr(0, le-2);
+ }
+ else {
+ units.clear();
+ }
}
// libcroco uses %.17f for formatting... leading to trailing zeros or small rounding errors.
// CSSOStringStream is used here to write valid CSS (as in sp_style_write_string). This has
// the additional benefit of respecting the numerical precission set in the SVG Output
// preferences. We assume any numerical part comes first (if not, the whole string is copied).
- std::stringstream ss( value_unquoted );
+ std::stringstream ss( value_unquoted2 );
double number = 0;
std::string characters;
std::string temp;
@@ -385,10 +390,9 @@ static void sp_repr_css_merge_from_decl(SPCSSAttr *css, CRDeclaration const *con
Inkscape::CSSOStringStream os;
if( number_valid ) os << number;
os << characters;
- if (units) {
+ if (!units.empty()) {
os << units;
//g_message("sp_repr_css_merge_from_decl looks like em or ex units %s --> %s", str_value, os.str().c_str());
- g_free(units);
}
((Node *) css)->setAttribute(decl->property->stryng->str, os.str().c_str(), false);
g_free(value_unquoted);