summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/document.cpp35
-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/symbols.cpp574
-rw-r--r--src/ui/dialog/symbols.h114
-rw-r--r--src/verbs.cpp16
-rw-r--r--src/verbs.h3
17 files changed, 991 insertions, 3 deletions
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/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/symbols.cpp b/src/ui/dialog/symbols.cpp
new file mode 100644
index 000000000..ea08c1cc8
--- /dev/null
+++ b/src/ui/dialog/symbols.cpp
@@ -0,0 +1,574 @@
+/**
+ * @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
+ symbolSet->append("Current Document");
+ 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 ) {
+ previewScale->append(scales[i]);
+ }
+ 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 ) {
+ previewSize->append(sizes[i]);
+ }
+ 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;
+ symbolSet->append(filename);
+ }
+ }
+ 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/verbs.cpp b/src/verbs.cpp
index 450b800c1..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;
@@ -1912,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;
@@ -2375,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"),
@@ -2748,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 da2adb52e..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,
@@ -264,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,