diff options
| author | su_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 |
| commit | d997c6a08a0d1184e8a4aec708033d0f548802f8 (patch) | |
| tree | e644b11bedb210813006dbfe4fb6a703bb642fae /src/ui | |
| parent | merge from trunk (r11761) (diff) | |
| parent | Fix for compiling with pre gtkmm 2.24 libraries. (diff) | |
| download | inkscape-d997c6a08a0d1184e8a4aec708033d0f548802f8.tar.gz inkscape-d997c6a08a0d1184e8a4aec708033d0f548802f8.zip | |
merge from trunk (r11787)
(bzr r11668.1.28)
Diffstat (limited to 'src/ui')
| -rw-r--r-- | src/ui/clipboard.cpp | 50 | ||||
| -rw-r--r-- | src/ui/clipboard.h | 2 | ||||
| -rw-r--r-- | src/ui/dialog/Makefile_insert | 2 | ||||
| -rw-r--r-- | src/ui/dialog/dialog-manager.cpp | 3 | ||||
| -rw-r--r-- | src/ui/dialog/layer-properties.cpp | 7 | ||||
| -rw-r--r-- | src/ui/dialog/layers.cpp | 62 | ||||
| -rw-r--r-- | src/ui/dialog/symbols.cpp | 591 | ||||
| -rw-r--r-- | src/ui/dialog/symbols.h | 114 | ||||
| -rw-r--r-- | src/ui/widget/style-swatch.cpp | 7 |
9 files changed, 817 insertions, 21 deletions
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); } |
