/** * @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 #include #include #include #include #if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H #include #endif #include #include #if WITH_GTKMM_3_0 # include # include #else # include #endif #include #include #include #include #include #include #include #include "path-prefix.h" #include "io/sys.h" #include "ui/cache/svg_preview_cache.h" #include "ui/clipboard.h" #include "ui/icon-names.h" #include "symbols.h" #include "selection.h" #include "desktop.h" #include "desktop-handles.h" #include "document.h" #include "inkscape.h" #include "sp-root.h" #include "sp-use.h" #include "sp-defs.h" #include "sp-symbol.h" #include "widgets/icon.h" #ifdef WITH_LIBVISIO #include #include #endif #include "verbs.h" #include "helper/action.h" #include "helper/action-context.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 symbol_id; Gtk::TreeModelColumn symbol_title; Gtk::TreeModelColumn< Glib::RefPtr > 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), currentDesktop(0), deskTrack(), currentDocument(0), previewDocument(0), instanceConns() { /******************** Table *************************/ #if WITH_GTKMM_3_0 Gtk::Grid *table = new Gtk::Grid(); #else Gtk::Table *table = new Gtk::Table(2, 4, false); #endif // 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: ")); #if WITH_GTKMM_3_0 table->attach(*Gtk::manage(labelSet),0,row,1,1); #else table->attach(*Gtk::manage(labelSet),0,1,row,row+1,Gtk::SHRINK,Gtk::SHRINK); #endif symbolSet = new Gtk::ComboBoxText(); // Fill in later symbolSet->append(_("Current Document")); symbolSet->set_active_text(_("Current Document")); #if WITH_GTKMM_3_0 symbolSet->set_hexpand(); table->attach(*Gtk::manage(symbolSet),1,row,1,1); #else table->attach(*Gtk::manage(symbolSet),1,2,row,row+1,Gtk::FILL|Gtk::EXPAND,Gtk::SHRINK); #endif 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 >(store)); //iconView->set_text_column( columns->symbol_id ); iconView->set_tooltip_column( 1 ); iconView->set_pixbuf_column( columns->symbol_image ); // Giving the iconview a small minimum size will help users understand // What the dialog does. iconView->set_size_request( 100, 200 ); std::vector< Gtk::TargetEntry > targets; targets.push_back(Gtk::TargetEntry( "application/x-inkscape-paste")); iconView->enable_model_drag_source (targets, Gdk::BUTTON1_MASK, Gdk::ACTION_COPY); iconView->signal_drag_data_get().connect( sigc::mem_fun(*this, &SymbolsDialog::iconDragDataGet)); 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)); #if WITH_GTKMM_3_0 scroller->set_hexpand(); scroller->set_vexpand(); table->attach(*Gtk::manage(scroller),0,row,2,1); #else table->attach(*Gtk::manage(scroller),0,2,row,row+1,Gtk::EXPAND|Gtk::FILL,Gtk::EXPAND|Gtk::FILL); #endif ++row; /******************** Tools *******************************/ Gtk::Button* button; Gtk::HBox* tools = new Gtk::HBox(); //tools->set_layout( Gtk::BUTTONBOX_END ); #if WITH_GTKMM_3_0 scroller->set_hexpand(); table->attach(*Gtk::manage(tools),0,row,2,1); #else table->attach(*Gtk::manage(tools),0,2,row,row+1,Gtk::EXPAND|Gtk::FILL,Gtk::FILL); #endif addSymbol = Gtk::manage(new Gtk::Button()); addSymbol->add(*Gtk::manage(Glib::wrap( sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-add")))) ); addSymbol->set_tooltip_text(_("Add Symbol from the current document.")); addSymbol->set_relief( Gtk::RELIEF_NONE ); addSymbol->set_focus_on_click( false ); addSymbol->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::insertSymbol)); tools->pack_start(* addSymbol, Gtk::PACK_SHRINK); removeSymbol = Gtk::manage(new Gtk::Button()); removeSymbol->add(*Gtk::manage(Glib::wrap( sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-remove")))) ); removeSymbol->set_tooltip_text(_("Remove Symbol from the current document.")); removeSymbol->set_relief( Gtk::RELIEF_NONE ); removeSymbol->set_focus_on_click( false ); removeSymbol->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::revertSymbol)); tools->pack_start(* removeSymbol, Gtk::PACK_SHRINK); Gtk::Label* spacer = Gtk::manage(new Gtk::Label("")); tools->pack_start(* Gtk::manage(spacer)); in_sizes = 2; // Default 32px button = Gtk::manage(new Gtk::Button()); button->add(*Gtk::manage(Glib::wrap( sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-bigger")))) ); button->set_tooltip_text(_("Make Icons bigger by zooming in.")); button->set_relief( Gtk::RELIEF_NONE ); button->set_focus_on_click( false ); button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomin)); tools->pack_start(* button, Gtk::PACK_SHRINK); button = Gtk::manage(new Gtk::Button()); button->add(*Gtk::manage(Glib::wrap( sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-smaller")))) ); button->set_tooltip_text(_("Make Icons smaller by zooming out.")); button->set_relief( Gtk::RELIEF_NONE ); button->set_focus_on_click( false ); button->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::zoomout)); tools->pack_start(* button, Gtk::PACK_SHRINK); fitSymbol = Gtk::manage(new Gtk::ToggleButton()); fitSymbol->add(*Gtk::manage(Glib::wrap( sp_icon_new (Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("symbol-fit")))) ); fitSymbol->set_tooltip_text(_("Toggle 'fit' symbols in icon space.")); fitSymbol->set_relief( Gtk::RELIEF_NONE ); fitSymbol->set_focus_on_click( false ); fitSymbol->set_active( true ); fitSymbol->signal_clicked().connect(sigc::mem_fun(*this, &SymbolsDialog::rebuild)); tools->pack_start(* fitSymbol, Gtk::PACK_SHRINK); ++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 )); // This might need to be a global variable so setTargetDesktop can modify it SPDefs *defs = currentDocument->getDefs(); sigc::connection defsModifiedConn = (SP_OBJECT(defs))->connectModified( sigc::mem_fun(*this, &SymbolsDialog::defsModified)); instanceConns.push_back(defsModifiedConn); sigc::connection selectionChangedConn = currentDesktop->selection->connectChanged( sigc::mem_fun(*this, &SymbolsDialog::selectionChanged)); instanceConns.push_back(selectionChangedConn); get_symbols(); draw_symbols( currentDocument ); /* Defaults to current document */ sigc::connection desktopChangeConn = deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &SymbolsDialog::setTargetDesktop) ); instanceConns.push_back( desktopChangeConn ); deskTrack.connect(GTK_WIDGET(gobj())); } SymbolsDialog::~SymbolsDialog() { for (std::vector::iterator it = instanceConns.begin(); it != instanceConns.end(); ++it) { it->disconnect(); } instanceConns.clear(); deskTrack.disconnect(); } SymbolsDialog& SymbolsDialog::getInstance() { return *new SymbolsDialog(); } void SymbolsDialog::zoomin() { if(in_sizes < 4) { in_sizes++; rebuild(); } } void SymbolsDialog::zoomout() { if(in_sizes > 0) { in_sizes--; rebuild(); } } 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; addSymbol->set_sensitive( true ); removeSymbol->set_sensitive( true ); } else { addSymbol->set_sensitive( false ); removeSymbol->set_sensitive( false ); } draw_symbols( symbolDocument ); } void SymbolsDialog::insertSymbol() { Inkscape::Verb *verb = Inkscape::Verb::get( SP_VERB_EDIT_SYMBOL ); SPAction *action = verb->get_action(Inkscape::ActionContext( (Inkscape::UI::View::View *) this->currentDesktop) ); sp_action_perform (action, NULL); } void SymbolsDialog::revertSymbol() { Inkscape::Verb *verb = Inkscape::Verb::get( SP_VERB_EDIT_UNSYMBOL ); SPAction *action = verb->get_action(Inkscape::ActionContext( (Inkscape::UI::View::View *) this->currentDesktop ) ); sp_action_perform (action, NULL); } void SymbolsDialog::iconDragDataGet(const Glib::RefPtr& /*context*/, Gtk::SelectionData& data, guint /*info*/, guint /*time*/) { #if WITH_GTKMM_3_0 std::vector 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]; GdkAtom dataAtom = gdk_atom_intern( "application/x-inkscape-paste", FALSE ); gtk_selection_data_set( data.gobj(), dataAtom, 9, (guchar*)symbol_id.c_str(), symbol_id.length() ); } } void SymbolsDialog::defsModified(SPObject * /*object*/, guint /*flags*/) { if ( !symbolSets[symbolSet->get_active_text()] ) { rebuild(); } } void SymbolsDialog::selectionChanged(Inkscape::Selection *selection) { Glib::ustring symbol_id = selectedSymbolId(); SPDocument* symbolDocument = selectedSymbols(); SPObject* symbol = symbolDocument->getObjectById(symbol_id); if(symbol && !selection->includes(symbol)) { iconView->unselect_all(); } } SPDocument* SymbolsDialog::selectedSymbols() { /* 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). return currentDocument; } return symbolDocument; } Glib::ustring SymbolsDialog::selectedSymbolId() { #if WITH_GTKMM_3_0 std::vector iconArray = iconView->get_selected_items(); #else Gtk::IconView::ArrayHandle_TreePaths iconArray = iconView->get_selected_items(); #endif if( !iconArray.empty() ) { Gtk::TreeModel::Path const & path = *iconArray.begin(); Gtk::ListStore::iterator row = store->get_iter(path); return (*row)[getColumns()->symbol_id]; } return Glib::ustring(""); } void SymbolsDialog::iconChanged() { Glib::ustring symbol_id = selectedSymbolId(); SPDocument* symbolDocument = selectedSymbols(); SPObject* symbol = symbolDocument->getObjectById(symbol_id); if( symbol ) { if( symbolDocument == currentDocument ) { // Select the symbol on the canvas so it can be manipulated currentDesktop->selection->set( symbol, false ); } // Find style for use in // First look for default style stored in gchar const* style = symbol->getAttribute("inkscape:symbol-style"); if( !style ) { // If no default style in , 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); } } #ifdef WITH_LIBVISIO // Read Visio stencil files SPDocument* read_vss( gchar* fullname, gchar* filename ) { WPXFileStream input(fullname); if (!libvisio::VisioDocument::isSupported(&input)) { return NULL; } libvisio::VSDStringVector output; if (!libvisio::VisioDocument::generateSVGStencils(&input, output)) { return NULL; } if (output.empty()) { return NULL; } Glib::ustring tmpSVGOutput; tmpSVGOutput += "\n"; tmpSVGOutput += "\n"; tmpSVGOutput += " "; tmpSVGOutput += filename; tmpSVGOutput += "\n"; tmpSVGOutput += " \n"; // Create a string we can use for the symbol id (libvisio doesn't give us a name) std::string sanitized( filename ); sanitized.erase( sanitized.find_last_of(".vss")-3 ); sanitized.erase( std::remove_if( sanitized.begin(), sanitized.end(), ispunct ), sanitized.end() ); std::replace( sanitized.begin(), sanitized.end(), ' ', '_' ); // std::cout << filename << " |" << sanitized << "|" << std::endl; // Each "symbol" is in it's own SVG file, we wrap with and merge into one file. for (unsigned i=0; i\n"; std::istringstream iss( output[i].cstr() ); std::string line; while( std::getline( iss, line ) ) { // std::cout << line << std::endl; if( line.find( "svg:svg" ) == std::string::npos ) { tmpSVGOutput += line; tmpSVGOutput += "\n"; } } tmpSVGOutput += " \n"; } tmpSVGOutput += " \n"; tmpSVGOutput += "\n"; return SPDocument::createNewDocFromMem( tmpSVGOutput.c_str(), strlen( tmpSVGOutput.c_str()), 0 ); } #endif /* Hunts preference directories for symbol files */ void SymbolsDialog::get_symbols() { std::list 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::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 ) ) { Glib::ustring fn( filename ); Glib::ustring tag = fn.substr( fn.find_last_of(".") + 1 ); SPDocument* symbol_doc = NULL; #ifdef WITH_LIBVISIO if( tag.compare( "vss" ) == 0 ) { symbol_doc = read_vss( fullname, filename ); if( symbol_doc ) { symbolSets[Glib::ustring(filename)]= symbol_doc; symbolSet->append(filename); } } #endif // Try to read all remaining files as SVG if( !symbol_doc ) { symbol_doc = SPDocument::createNewDoc( fullname, FALSE ); if( symbol_doc ) { gchar *title = symbol_doc->getRoot()->title(); if( title == NULL ) { title = _("Unnamed Symbols"); } symbolSets[Glib::ustring(title)] = symbol_doc; symbolSet->append(title); } } } g_free( fullname ); } g_dir_close( dir ); } } } GSList* SymbolsDialog::symbols_in_doc_recursive (SPObject *r, GSList *l) { g_return_val_if_fail(r != NULL, 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 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 ) { GSList* l = symbols_in_doc( symbolDocument ); for( ; l != NULL; l = l->next ) { SPObject* symbol = SP_OBJECT(l->data); if (SP_IS_SYMBOL(symbol)) { draw_symbol( symbol ); } } } void SymbolsDialog::draw_symbol( SPObject* symbol ) { SymbolColumns* columns = getColumns(); gchar const *id = symbol->getRepr()->attribute("id"); gchar const *title = symbol->title(); // From title element if( !title ) { title = id; } Glib::RefPtr pixbuf = create_symbol_image(id, symbol ); 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; } delete columns; } /* * Returns image of symbol. * * Symbols normally are not visible. They must be referenced by a * element. A temporary document is created with a dummy * element and a element that references the symbol * element. Each real symbol is swapped in for the dummy symbol and * the temporary document is rendered. */ Glib::RefPtr SymbolsDialog::create_symbol_image(gchar const *symbol_id, SPObject *symbol) { // 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 gchar const* style = repr->attribute("inkscape:symbol-style"); if( !style ) { // If no default style in , look in documents. if( symbol->document == currentDocument ) { style = style_from_use( symbol_id, symbol->document ); } else { style = symbol->document->getReprRoot()->attribute("style"); } } // Last ditch effort to provide some default styling if( !style ) style = "fill:#bbbbbb;stroke:#808080"; // This is for display in Symbols dialog only if( style ) { repr->setAttribute( "style", style ); } // BUG: Symbols don't work if defined outside of . 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); unsigned psize = SYMBOL_ICON_SIZES[in_sizes]; /* Update to renderable state */ Glib::ustring key = svg_preview_cache.cache_key(previewDocument->getURI(), symbol_id, psize); //std::cout << " Key: " << key << std::endl; Glib::RefPtr pixbuf(NULL); GdkPixbuf *pixbuf_gobj = svg_preview_cache.get_preview_from_cache(key); if (pixbuf_gobj) { g_object_ref(pixbuf_gobj); // the reference in svg_preview_cache will get destroyed when it's freed pixbuf = Glib::wrap(pixbuf_gobj); } // 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 pixbuf; } if (!pixbuf) { /* Scale symbols to fit */ double scale = 1.0; double width = dbox->width(); double height = dbox->height(); if( width == 0.0 ) { width = 1.0; } if( height == 0.0 ) { height = 1.0; } if( fitSymbol->get_active() ) { /* Fit */ scale = psize/std::max(width,height); } pixbuf = Glib::wrap(render_pixbuf(renderDrawing, 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 element is * provided. */ SPDocument* SymbolsDialog::symbols_preview_doc() { // BUG: must be inside gchar const *buffer = "" " " " " " " " " ""; 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