diff options
| author | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-03-09 02:56:07 +0000 |
|---|---|---|
| committer | Liam P. White <inkscapebronyat-signgmaildotcom> | 2014-03-09 02:56:07 +0000 |
| commit | c515627314d3ec501dc6de928fb60b5d7895c557 (patch) | |
| tree | 8a4e5c479e8b41df87494fe555934f42aa424537 /src | |
| parent | Remove all trace of the Tags dialog (diff) | |
| parent | Remove useless r variable and warning (diff) | |
| download | inkscape-c515627314d3ec501dc6de928fb60b5d7895c557.tar.gz inkscape-c515627314d3ec501dc6de928fb60b5d7895c557.zip | |
Update to trunk
(bzr r13090.1.22)
Diffstat (limited to 'src')
| -rw-r--r-- | src/attributes-test.h | 9 | ||||
| -rw-r--r-- | src/display/drawing-image.cpp | 3 | ||||
| -rw-r--r-- | src/display/drawing-surface.cpp | 2 | ||||
| -rw-r--r-- | src/event-log.cpp | 254 | ||||
| -rw-r--r-- | src/event-log.h | 24 | ||||
| -rw-r--r-- | src/extension/internal/wmf-inout.cpp | 167 | ||||
| -rw-r--r-- | src/gradient-drag.cpp | 4 | ||||
| -rw-r--r-- | src/libvpsc/generate-constraints.cpp | 11 | ||||
| -rw-r--r-- | src/marker.cpp | 4 | ||||
| -rw-r--r-- | src/selection-chemistry.cpp | 2 | ||||
| -rw-r--r-- | src/selection.h | 8 | ||||
| -rw-r--r-- | src/sp-image.cpp | 4 | ||||
| -rw-r--r-- | src/sp-pattern.cpp | 84 | ||||
| -rw-r--r-- | src/sp-use.cpp | 3 | ||||
| -rw-r--r-- | src/style-test.h | 55 | ||||
| -rw-r--r-- | src/style.cpp | 4 | ||||
| -rw-r--r-- | src/ui/dialog/export.cpp | 502 | ||||
| -rw-r--r-- | src/ui/dialog/export.h | 48 | ||||
| -rw-r--r-- | src/ui/dialog/symbols.cpp | 4 | ||||
| -rw-r--r-- | src/ui/dialog/undo-history.cpp | 130 | ||||
| -rw-r--r-- | src/ui/dialog/undo-history.h | 11 | ||||
| -rw-r--r-- | src/ui/tools/text-tool.cpp | 217 | ||||
| -rw-r--r-- | src/ui/tools/text-tool.h | 6 | ||||
| -rw-r--r-- | src/ui/tools/tool-base.h | 5 | ||||
| -rw-r--r-- | src/util/signal-blocker.h | 70 | ||||
| -rw-r--r-- | src/verbs.cpp | 6 |
26 files changed, 970 insertions, 667 deletions
diff --git a/src/attributes-test.h b/src/attributes-test.h index eee12d3c1..ba34717ea 100644 --- a/src/attributes-test.h +++ b/src/attributes-test.h @@ -150,6 +150,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"in", true}, {"in2", true}, {"intercept", true}, + {"isolation", true}, {"k", true}, {"k1", true}, {"k2", true}, @@ -181,6 +182,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"media", false}, {"method", false}, {"min", true}, + {"mix-blend-mode", true}, {"mode", true}, {"name", true}, {"numOctaves", true}, @@ -213,6 +215,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"overflow", true}, {"overline-position", true}, {"overline-thickness", true}, + {"paint-order", true}, {"panose-1", true}, {"path", true}, {"pathLength", false}, @@ -276,9 +279,9 @@ struct {char const *attr; bool supported;} const all_attrs[] = { {"text-align", true}, {"text-anchor", true}, {"text-decoration", true}, - {"text-decoration-line", false}, - {"text-decoration-style", false}, - {"text-decoration-color", false}, + {"text-decoration-line", true}, + {"text-decoration-style", true}, + {"text-decoration-color", true}, {"text-indent", true}, {"text-rendering", true}, {"text-transform", true}, diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp index 8fd81caac..5844c8b08 100644 --- a/src/display/drawing-image.cpp +++ b/src/display/drawing-image.cpp @@ -128,7 +128,8 @@ unsigned DrawingImage::_renderItem(DrawingContext &dc, Geom::IntRect const &/*ar // Do nothing break; case SP_CSS_COLOR_RENDERING_OPTIMIZEQUALITY: - dc.patternSetFilter( CAIRO_FILTER_BEST ); + // In recent Cairo, BEST used Lanczos3, which is prohibitively slow + dc.patternSetFilter( CAIRO_FILTER_GOOD ); break; case SP_CSS_COLOR_RENDERING_OPTIMIZESPEED: default: diff --git a/src/display/drawing-surface.cpp b/src/display/drawing-surface.cpp index 94e0e1ab5..30579134b 100644 --- a/src/display/drawing-surface.cpp +++ b/src/display/drawing-surface.cpp @@ -123,7 +123,7 @@ DrawingSurface::scale() const Geom::Affine DrawingSurface::drawingTransform() const { - Geom::Affine ret = _scale * Geom::Translate(-_origin); + Geom::Affine ret = Geom::Translate(-_origin) * _scale; return ret; } diff --git a/src/event-log.cpp b/src/event-log.cpp index d0342fbe9..db680d6d2 100644 --- a/src/event-log.cpp +++ b/src/event-log.cpp @@ -1,34 +1,182 @@ /* * Author: * Gustav Broberg <broberg@kth.se> + * Jon A. Cruz <jon@joncruz.org> * - * Copyright (c) 2006, 2007 Authors + * Copyright (c) 2014 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ +#include "util/signal-blocker.h" + #include "event-log.h" #include <glibmm/i18n.h> +#include <gtkmm/treemodel.h> +#include <boost/shared_ptr.hpp> +#include <boost/make_shared.hpp> #include "desktop.h" #include "inkscape.h" +#include "util/signal-blocker.h" #include "util/ucompose.hpp" #include "document.h" #include "xml/repr.h" #include "sp-object.h" +namespace +{ + +class DialogConnection +{ +public: + DialogConnection(Gtk::TreeView *event_list_view, Inkscape::EventLog::CallbackMap *callback_connections) : + _event_list_view(event_list_view), + _callback_connections(callback_connections), + _event_list_selection(_event_list_view->get_selection()) + { + } + + Gtk::TreeView *_event_list_view; + + // Map of connections used to temporary block/unblock callbacks in a TreeView + Inkscape::EventLog::CallbackMap *_callback_connections; + + Glib::RefPtr<Gtk::TreeSelection> _event_list_selection; /// @todo remove this and use _event_list_view's call +}; + +class ConnectionMatcher +{ +public: + ConnectionMatcher(Gtk::TreeView *view, + Inkscape::EventLog::CallbackMap *callbacks) : + _view(view), + _callbacks(callbacks) + { + } + + bool operator() (DialogConnection const &dlg) + { + return (_view == dlg._event_list_view) && (_callbacks == dlg._callback_connections); + } + + Gtk::TreeView *_view; + Inkscape::EventLog::CallbackMap *_callbacks; +}; + +void addBlocker(std::vector<boost::shared_ptr<SignalBlocker> > &blockers, sigc::connection *connection) +{ + blockers.push_back(boost::make_shared<SignalBlocker>(connection)); +} + + +} // namespace + namespace Inkscape { +class EventLogPrivate +{ +public: + EventLogPrivate() : + _connections() + { + } + + bool isConnected() const + { + return !_connections.empty(); + } + + void addDialogConnection(Gtk::TreeView *event_list_view, + Inkscape::EventLog::CallbackMap *callback_connections, + Glib::RefPtr<Gtk::TreeStore> event_list_store, + Inkscape::EventLog::iterator &curr_event) + { + if (std::find_if(_connections.begin(), _connections.end(), ConnectionMatcher(event_list_view, callback_connections)) != _connections.end()) { + // skipping + } + else + { + DialogConnection dlg(event_list_view, callback_connections); + + dlg._event_list_selection->set_mode(Gtk::SELECTION_SINGLE); + + { + std::vector<boost::shared_ptr<SignalBlocker> > blockers; + addBlocker(blockers, &(*dlg._callback_connections)[Inkscape::EventLog::CALLB_SELECTION_CHANGE]); + addBlocker(blockers, &(*dlg._callback_connections)[Inkscape::EventLog::CALLB_EXPAND]); + + dlg._event_list_view->expand_to_path(event_list_store->get_path(curr_event)); + dlg._event_list_selection->select(curr_event); + } + _connections.push_back(dlg); + } + } + + void removeDialogConnection(Gtk::TreeView *event_list_view, Inkscape::EventLog::CallbackMap *callback_connections) + { + std::vector<DialogConnection>::iterator it = std::find_if(_connections.begin(), _connections.end(), ConnectionMatcher(event_list_view, callback_connections)); + if (it != _connections.end()) { + _connections.erase(it); + } + } + + void collapseRow(Gtk::TreeModel::Path const &path) + { + std::vector<boost::shared_ptr<SignalBlocker> > blockers; + for (std::vector<DialogConnection>::iterator it(_connections.begin()); it != _connections.end(); ++it) + { + addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_SELECTION_CHANGE]); + addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_COLLAPSE]); + } + + for (std::vector<DialogConnection>::iterator it(_connections.begin()); it != _connections.end(); ++it) + { + it->_event_list_view->collapse_row(path); + } + } + + void selectRow(Gtk::TreeModel::Path const &path) + { + std::vector<boost::shared_ptr<SignalBlocker> > blockers; + for (std::vector<DialogConnection>::iterator it(_connections.begin()); it != _connections.end(); ++it) + { + addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_SELECTION_CHANGE]); + addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_EXPAND]); + } + + for (std::vector<DialogConnection>::iterator it(_connections.begin()); it != _connections.end(); ++it) + { + it->_event_list_view->expand_to_path(path); + it->_event_list_selection->select(path); + it->_event_list_view->scroll_to_row(path); + } + } + + void clearEventList(Glib::RefPtr<Gtk::TreeStore> eventListStore) + { + if (eventListStore) { + std::vector<boost::shared_ptr<SignalBlocker> > blockers; + for (std::vector<DialogConnection>::iterator it(_connections.begin()); it != _connections.end(); ++it) + { + addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_SELECTION_CHANGE]); + addBlocker(blockers, &(*it->_callback_connections)[Inkscape::EventLog::CALLB_EXPAND]); + } + + eventListStore->clear(); + } + } + + std::vector<DialogConnection> _connections; +}; + EventLog::EventLog(SPDocument* document) : UndoStackObserver(), - _connected (false), + _priv(new EventLogPrivate()), _document (document), _event_list_store (Gtk::TreeStore::create(_columns)), - _event_list_selection (NULL), - _event_list_view (NULL), _curr_event_parent (NULL), - _notifications_blocked (false), - _callback_connections (NULL) + _notifications_blocked (false) { // add initial pseudo event Gtk::TreeRow curr_row = *(_event_list_store->append()); @@ -39,16 +187,11 @@ EventLog::EventLog(SPDocument* document) : } EventLog::~EventLog() { - // avoid crash by clearing entries here (see bug #1071082) - if (_connected) { - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(); - (*_callback_connections)[CALLB_EXPAND].block(); + // avoid crash by clearing entries here (see bug #1071082) + _priv->clearEventList(_event_list_store); - _event_list_store->clear(); - - (*_callback_connections)[CALLB_EXPAND].block(false); - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false); - } + delete _priv; + _priv = 0; } void @@ -70,10 +213,8 @@ EventLog::notifyUndoEvent(Event* log) } else { // if we're about to leave a branch, collapse it - if ( !_curr_event->children().empty() && _connected ) { - (*_callback_connections)[CALLB_COLLAPSE].block(); - _event_list_view->collapse_row(_event_list_store->get_path(_curr_event)); - (*_callback_connections)[CALLB_COLLAPSE].block(false); + if ( !_curr_event->children().empty() ) { + _priv->collapseRow(_event_list_store->get_path(_curr_event)); } --_curr_event; @@ -89,17 +230,9 @@ EventLog::notifyUndoEvent(Event* log) checkForVirginity(); // update the view - if (_connected) { - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(); - (*_callback_connections)[CALLB_EXPAND].block(); - + if (_priv->isConnected()) { Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event); - _event_list_view->expand_to_path(curr_path); - _event_list_selection->select(curr_path); - _event_list_view->scroll_to_row(curr_path); - - (*_callback_connections)[CALLB_EXPAND].block(false); - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false); + _priv->selectRow(curr_path); } updateUndoVerbs(); @@ -132,13 +265,7 @@ EventLog::notifyRedoEvent(Event* log) { // ...collapse it - if (_connected) { - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(); - (*_callback_connections)[CALLB_COLLAPSE].block(); - _event_list_view->collapse_row(_event_list_store->get_path(_curr_event->parent())); - (*_callback_connections)[CALLB_COLLAPSE].block(false); - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false); - } + _priv->collapseRow(_event_list_store->get_path(_curr_event->parent())); // ...and move to the next event at parent level _curr_event = _curr_event->parent(); @@ -151,18 +278,9 @@ EventLog::notifyRedoEvent(Event* log) checkForVirginity(); // update the view - if (_connected) { + if (_priv->isConnected()) { Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event); - - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(); - (*_callback_connections)[CALLB_EXPAND].block(); - - _event_list_view->expand_to_path(curr_path); - _event_list_selection->select(curr_path); - _event_list_view->scroll_to_row(curr_path); - - (*_callback_connections)[CALLB_EXPAND].block(false); - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false); + _priv->selectRow(curr_path); } updateUndoVerbs(); @@ -193,10 +311,8 @@ EventLog::notifyUndoCommitEvent(Event* log) _curr_event = _last_event = curr_row; // collapse if we're leaving a branch - if (_curr_event_parent && _connected) { - (*_callback_connections)[CALLB_COLLAPSE].block(); - _event_list_view->collapse_row(_event_list_store->get_path(_curr_event_parent)); - (*_callback_connections)[CALLB_COLLAPSE].block(false); + if (_curr_event_parent) { + _priv->collapseRow(_event_list_store->get_path(_curr_event_parent)); } _curr_event_parent = (iterator)(NULL); @@ -211,18 +327,9 @@ EventLog::notifyUndoCommitEvent(Event* log) checkForVirginity(); // update the view - if (_connected) { + if (_priv->isConnected()) { Gtk::TreePath curr_path = _event_list_store->get_path(_curr_event); - - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(); - (*_callback_connections)[CALLB_EXPAND].block(); - - _event_list_view->expand_to_path(curr_path); - _event_list_selection->select(curr_path); - _event_list_view->scroll_to_row(curr_path); - - (*_callback_connections)[CALLB_EXPAND].block(false); - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false); + _priv->selectRow(curr_path); } updateUndoVerbs(); @@ -242,25 +349,14 @@ EventLog::notifyClearRedoEvent() updateUndoVerbs(); } -void -EventLog::connectWithDialog(Gtk::TreeView *event_list_view, CallbackMap *callback_connections) +void EventLog::addDialogConnection(Gtk::TreeView *event_list_view, CallbackMap *callback_connections) { - _event_list_view = event_list_view; - _event_list_selection = event_list_view->get_selection(); - _event_list_selection->set_mode(Gtk::SELECTION_SINGLE); - - _callback_connections = callback_connections; - - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(); - (*_callback_connections)[CALLB_EXPAND].block(); - - _event_list_view->expand_to_path(_event_list_store->get_path(_curr_event)); - _event_list_selection->select(_curr_event); - - (*_callback_connections)[CALLB_EXPAND].block(false); - (*_callback_connections)[CALLB_SELECTION_CHANGE].block(false); + _priv->addDialogConnection(event_list_view, callback_connections, _event_list_store, _curr_event); +} - _connected = true; +void EventLog::removeDialogConnection(Gtk::TreeView *event_list_view, CallbackMap *callback_connections) +{ + _priv->removeDialogConnection(event_list_view, callback_connections); } void diff --git a/src/event-log.h b/src/event-log.h index 78f0ae5d1..7e3ba6817 100644 --- a/src/event-log.h +++ b/src/event-log.h @@ -1,8 +1,9 @@ /* * Author: * Gustav Broberg <broberg@kth.se> + * Jon A. Cruz <jon@joncruz.org> * - * Copyright (c) 2006, 2007 Authors + * Copyright (c) 2014 Authors * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -22,12 +23,15 @@ #include <glibmm/refptr.h> #include <gtkmm/treeselection.h> #include <gtkmm/treeview.h> +#include <sigc++/trackable.h> #include "undo-stack-observer.h" #include "event.h" namespace Inkscape { +class EventLogPrivate; + /** * A simple log for maintaining a history of commited, undone and redone events along with their * type. It implements the UndoStackObserver and should be registered with a @@ -41,7 +45,7 @@ namespace Inkscape { * expanded/collapsed state will be updated as events are commited, undone and redone. Whenever * this happens, the event log will block the TreeView's callbacks to prevent circular updates. */ -class EventLog : public UndoStackObserver +class EventLog : public UndoStackObserver, public sigc::trackable { public: @@ -104,7 +108,12 @@ public: /** * Connect with a TreeView. */ - void connectWithDialog(Gtk::TreeView *event_list_view, CallbackMap *callback_connections); + void addDialogConnection(Gtk::TreeView *event_list_view, CallbackMap *callback_connections); + + /** + * Disconnect from a TreeView. + */ + void removeDialogConnection(Gtk::TreeView *event_list_view, CallbackMap *callback_connections); /* * Updates the sensitivity and names of SP_VERB_EDIT_UNDO and SP_VERB_EDIT_REDO to reflect the @@ -113,14 +122,13 @@ public: void updateUndoVerbs(); private: - bool _connected; //< connected with dialog + EventLogPrivate *_priv; + SPDocument *_document; //< document that is logged const EventModelColumns _columns; Glib::RefPtr<Gtk::TreeStore> _event_list_store; - Glib::RefPtr<Gtk::TreeSelection> _event_list_selection; - Gtk::TreeView *_event_list_view; iterator _curr_event; //< current event in _event_list_store iterator _last_event; //< end position in _event_list_store @@ -130,9 +138,6 @@ private: bool _notifications_blocked; //< if notifications should be handled - // Map of connections used to temporary block/unblock callbacks in a TreeView - CallbackMap *_callback_connections; - // Helper functions const_iterator _getUndoEvent() const; //< returns the current undoable event or NULL if none @@ -146,7 +151,6 @@ private: // noncopyable, nonassignable EventLog(EventLog const &other); EventLog& operator=(EventLog const &other); - }; } // namespace Inkscape diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index 3c348f5c4..3a62c9c16 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -455,58 +455,45 @@ uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsa char *rgba_px = NULL; // RGBA pixels const char *px = NULL; // DIB pixels const U_RGBQUAD *ct = NULL; // DIB color table - int32_t width, height, colortype, numCt, invert; - if((iUsage != U_DIB_RGB_COLORS) || - !(dibparams = wget_DIB_params( // this returns pointers and values, but allocates no memory - dib, - &px, - &ct, - &numCt, - &width, - &height, - &colortype, - &invert - )) - ){ - - if(!DIB_to_RGBA( - px, // DIB pixel array - ct, // DIB color table - numCt, // DIB color table number of entries - &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free. - width, // Width of pixel array in record - height, // Height of pixel array in record - colortype, // DIB BitCount Enumeration - numCt, // Color table used if not 0 - invert // If DIB rows are in opposite order from RGBA rows - ) && - rgba_px - ){ - toPNG( // Get the image from the RGBA px into mempng - &mempng, - width, height, // of the SRC bitmap - rgba_px - ); - free(rgba_px); + int32_t width, height, colortype, numCt, invert; // if needed these values will be set by wget_DIB_params + if(iUsage == U_DIB_RGB_COLORS){ + // next call returns pointers and values, but allocates no memory + dibparams = wget_DIB_params(dib, &px, &ct, &numCt, &width, &height, &colortype, &invert); + if(dibparams == U_BI_RGB){ + if(!DIB_to_RGBA( + px, // DIB pixel array + ct, // DIB color table + numCt, // DIB color table number of entries + &rgba_px, // U_RGBA pixel array (32 bits), created by this routine, caller must free. + width, // Width of pixel array in record + height, // Height of pixel array in record + colortype, // DIB BitCount Enumeration + numCt, // Color table used if not 0 + invert // If DIB rows are in opposite order from RGBA rows + )){ + toPNG( // Get the image from the RGBA px into mempng + &mempng, + width, height, // of the SRC bitmap + rgba_px + ); + free(rgba_px); + } } } - gchar *base64String; - if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){ + gchar *base64String=NULL; + if(dibparams == U_BI_JPEG || dibparams==U_BI_PNG){ // image was binary png or jpg in source file base64String = g_base64_encode((guchar*) px, numCt ); - idx = in_images(d, (char *) base64String); } - else if(mempng.buffer){ + else if(mempng.buffer){ // image was DIB in source file, converted to png in this routine base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); free(mempng.buffer); - idx = in_images(d, (char *) base64String); } - else { - // insert a random 3x4 blotch otherwise + else { // failed conversion, insert the common bad image picture width = 3; height = 4; - base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="); - idx = in_images(d, (char *) base64String); + base64String = bad_image_png(); } + idx = in_images(d, (char *) base64String); if(!idx){ // add it if not already present - we looked at the actual data for comparison if(d->images.count == d->images.size){ enlarge_images(d); } idx = d->images.count; @@ -545,7 +532,7 @@ uint32_t Wmf::add_dib_image(PWMF_CALLBACK_DATA d, const char *dib, uint32_t iUsa *(d->defs) += " "; *(d->defs) += " </pattern>\n"; } - g_free(base64String); + g_free(base64String); //wait until this point to free because it might be a duplicate image return(idx-1); } @@ -563,16 +550,16 @@ uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char * mempng.buffer = NULL; char *rgba_px = NULL; // RGBA pixels - const U_RGBQUAD *ct = NULL; // color table, always NULL here + const U_RGBQUAD *ct = NULL; // color table, always NULL here int32_t width, height, colortype, numCt, invert; numCt = 0; width = Bm16.Width; // bitmap width in pixels. height = Bm16.Height; // bitmap height in scan lines. colortype = Bm16.BitsPixel; // seems to be BitCount Enumeration invert = 0; - if(colortype < 16)return(0xFFFFFFFF); // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead. + if(colortype < 16)return(U_WMR_INVALID); // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead. - if(!DIB_to_RGBA(// This is not really a dib, but close enough... + if(!DIB_to_RGBA(// This is not really a dib, but close enough so that it still works. px, // DIB pixel array ct, // DIB color table (always NULL here) numCt, // DIB color table number of entries (always 0) @@ -582,8 +569,7 @@ uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char * colortype, // DIB BitCount Enumeration numCt, // Color table used if not 0 invert // If DIB rows are in opposite order from RGBA rows - ) && rgba_px) - { + )){ toPNG( // Get the image from the RGBA px into mempng &mempng, width, height, // of the SRC bitmap @@ -591,17 +577,18 @@ uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char * ); free(rgba_px); } - gchar *base64String; - if(mempng.buffer){ + + gchar *base64String=NULL; + if(mempng.buffer){ // image was Bm16 in source file, converted to png in this routine base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); free(mempng.buffer); } - else { - // insert a random 3x4 blotch otherwise + else { // failed conversion, insert the common bad image picture width = 3; height = 4; - base64String = g_strdup("iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="); + base64String = bad_image_png(); } + idx = in_images(d, (char *) base64String); if(!idx){ // add it if not already present - we looked at the actual data for comparison if(d->images.count == d->images.size){ enlarge_images(d); } @@ -639,7 +626,7 @@ uint32_t Wmf::add_bm16_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char * *(d->defs) += "\" />\n"; *(d->defs) += " </pattern>\n"; } - g_free(base64String); + g_free(base64String); //wait until this point to free because it might be a duplicate image return(idx-1); } @@ -883,16 +870,13 @@ double Wmf::pix_to_x_point(PWMF_CALLBACK_DATA d, double px, double /*py*/) { double x = _pix_x_to_point(d, px); - return x; } double Wmf::pix_to_y_point(PWMF_CALLBACK_DATA d, double /*px*/, double py) { - double y = _pix_y_to_point(d, py); - return y; } @@ -1054,7 +1038,6 @@ Wmf::select_brush(PWMF_CALLBACK_DATA d, int index) const char *Bm16h; // Pointer to Bitmap16 header (px follows) const char *dib; // Pointer to DIB (void) U_WMRDIBCREATEPATTERNBRUSH_get(record, &Style, &cUsage, &Bm16h, &dib); - // Bm16 not handled yet if(dib || Bm16h){ if(dib){ tidx = add_dib_image(d, dib, cUsage); } else if(Bm16h){ @@ -1064,7 +1047,7 @@ Wmf::select_brush(PWMF_CALLBACK_DATA d, int index) px = Bm16h + U_SIZE_BITMAP16; tidx = add_bm16_image(d, Bm16, px); } - if(tidx == 0xFFFFFFFF){ // Problem with the image, for instance, an unsupported bitmap16 type + if(tidx == U_WMR_INVALID){ // Problem with the image, for instance, an unsupported bitmap16 type double r, g, b; r = SP_COLOR_U_TO_F( U_RGBAGetR(d->dc[d->level].textColor)); g = SP_COLOR_U_TO_F( U_RGBAGetG(d->dc[d->level].textColor)); @@ -1384,10 +1367,9 @@ void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char SVGOStringStream tmp_image; + tmp_image << "\n\t <image\n"; tmp_image << " y=\"" << dy << "\"\n x=\"" << dx <<"\"\n "; - // The image ID is filled in much later when tmp_image is converted - MEMPNG mempng; // PNG in memory comes back in this mempng.buffer = NULL; @@ -1408,7 +1390,8 @@ void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char } if(colortype < 16)return; // these would need a colortable if they were a dib, no idea what bm16 is supposed to do instead. - if(!DIB_to_RGBA( // This is not really a dib, but close enough... + + if(!DIB_to_RGBA(// This is not really a dib, but close enough so that it still works. px, // DIB pixel array ct, // DIB color table (always NULL here) numCt, // DIB color table number of entries (always 0) @@ -1418,15 +1401,13 @@ void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char colortype, // DIB BitCount Enumeration numCt, // Color table used if not 0 invert // If DIB rows are in opposite order from RGBA rows - ) && - rgba_px - ){ - sub_px = RGBA_to_RGBA( - rgba_px, // full pixel array from DIB - width, // Width of pixel array - height, // Height of pixel array - sx,sy, // starting point in pixel array - &sw,&sh // columns/rows to extract from the pixel array (output array size) + )){ + sub_px = RGBA_to_RGBA( // returns either a subset (side effect: frees rgba_px) or NULL (for subset == entire image) + rgba_px, // full pixel array from DIB + width, // Width of pixel array + height, // Height of pixel array + sx,sy, // starting point in pixel array + &sw,&sh // columns/rows to extract from the pixel array (output array size) ); if(!sub_px)sub_px=rgba_px; @@ -1437,26 +1418,26 @@ void Wmf::common_bm16_to_image(PWMF_CALLBACK_DATA d, U_BITMAP16 Bm16, const char ); free(sub_px); } - if(mempng.buffer){ + + gchar *base64String=NULL; + if(mempng.buffer){ // image was Bm16 in source file, converted to png in this routine tmp_image << " xlink:href=\"data:image/png;base64,"; - gchar *base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); + base64String = g_base64_encode((guchar*) mempng.buffer, mempng.size ); free(mempng.buffer); - tmp_image << base64String; - g_free(base64String); } - else { + else { // unknown or unsupported image type or failed conversion, insert the common bad image picture tmp_image << " xlink:href=\"data:image/png;base64,"; - // insert a random 3x4 blotch otherwise - tmp_image << "iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAIAAAA7ljmRAAAAA3NCSVQICAjb4U/gAAAALElEQVQImQXBQQ2AMAAAsUJQMSWI2H8qME1yMshojwrvGB8XcHKvR1XtOTc/8HENumHCsOMAAAAASUVORK5CYII="; + base64String = bad_image_png(); } + tmp_image << base64String; + g_free(base64String); tmp_image << "\"\n height=\"" << dh << "\"\n width=\"" << dw << "\"\n"; - tmp_image << " transform=" << current_matrix(d, 0.0, 0.0, 0); // returns an identity matrix, no offsets. - *(d->outsvg) += "\n\t <image\n"; - *(d->outsvg) += tmp_image.str().c_str(); + tmp_image << " preserveAspectRatio=\"none\"\n"; + tmp_image << "/> \n"; - *(d->outsvg) += "/> \n"; + *(d->outsvg) += tmp_image.str().c_str(); *(d->path) = ""; } @@ -1669,7 +1650,7 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK // incompatible change to text drawing detected (color or background change) forces out existing text // OR // next record is valid type and forces pending text to be drawn immediately - if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((wmr_mask != 0xFFFFFFFF) && (wmr_mask & U_DRAW_TEXT) && d->tri->dirty)){ + if ((d->dc[d->level].dirty & DIRTY_TEXT) || ((wmr_mask != U_WMR_INVALID) && (wmr_mask & U_DRAW_TEXT) && d->tri->dirty)){ TR_layout_analyze(d->tri); TR_layout_2_svg(d->tri); SVGOStringStream ts; @@ -1712,7 +1693,7 @@ std::cout << "BEFORE DRAW" */ if( - (wmr_mask != 0xFFFFFFFF) && // next record is valid type + (wmr_mask != U_WMR_INVALID) && // next record is valid type (d->mask & U_DRAW_VISIBLE) && // This record is drawable ( (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH @@ -1852,6 +1833,20 @@ std::cout << "BEFORE DRAW" d->dc[d->level].sizeWnd.y = d->PixelsOutY; } } + else { + /* There are a lot WMF files in circulation with the x,y values in the setwindowext reversed. If this is detected, swap them. + There is a remote possibility that the strange scaling this implies was intended, and those will be rendered incorrectly */ + double Ox = d->PixelsOutX; + double Oy = d->PixelsOutY; + double Wx = d->dc[d->level].sizeWnd.x; + double Wy = d->dc[d->level].sizeWnd.y; + if(Wx != Wy && Geom::are_near(Ox/Wy, Oy/Wx, 1.01/MIN(Wx,Wy)) ){ + int tmp; + tmp = d->dc[d->level].sizeWnd.x; + d->dc[d->level].sizeWnd.x = d->dc[d->level].sizeWnd.y; + d->dc[d->level].sizeWnd.y = tmp; + } + } if (!d->dc[d->level].sizeView.x || !d->dc[d->level].sizeView.y) { /* Previously it used sizeWnd, but that always resulted in scale = 1 if no viewport ever appeared, and in most files, it did not */ @@ -1984,7 +1979,7 @@ std::cout << "BEFORE DRAW" int stat = wmr_arc_points(rc, ArcStart, ArcEnd,&f1, f2, ¢er, &start, &end, &size); if(!stat){ tmp_path << "\n\tM " << pix_to_xy(d, start.x, start.y); - tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0; tmp_path << " "; tmp_path << 180.0 * current_rotation(d)/M_PI; tmp_path << " "; @@ -2036,7 +2031,7 @@ std::cout << "BEFORE DRAW" if(!wmr_arc_points(rc, ArcStart, ArcEnd, &f1, f2, ¢er, &start, &end, &size)){ tmp_path << "\n\tM " << pix_to_xy(d, center.x, center.y); tmp_path << "\n\tL " << pix_to_xy(d, start.x, start.y); - tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0 ; + tmp_path << " A " << pix_to_abs_size(d, size.x)/2.0 << "," << pix_to_abs_size(d, size.y)/2.0; tmp_path << " "; tmp_path << 180.0 * current_rotation(d)/M_PI; tmp_path << " "; diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index 0b250fe52..6773069de 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -636,13 +636,13 @@ GrDrag::GrDrag(SPDesktop *desktop) : style_set_connection(), style_query_connection() { - sel_changed_connection = selection->connectChanged( + sel_changed_connection = selection->connectChangedFirst( sigc::bind( sigc::ptr_fun(&gr_drag_sel_changed), (gpointer)this ) ); - sel_modified_connection = selection->connectModified( + sel_modified_connection = selection->connectModifiedFirst( sigc::bind( sigc::ptr_fun(&gr_drag_sel_modified), (gpointer)this ) diff --git a/src/libvpsc/generate-constraints.cpp b/src/libvpsc/generate-constraints.cpp index fabe5217f..288e7ed53 100644 --- a/src/libvpsc/generate-constraints.cpp +++ b/src/libvpsc/generate-constraints.cpp @@ -209,7 +209,6 @@ int generateXConstraints(const int n, Rectangle** rs, Variable** vars, Constrain } } else { // Close event - int r; if(useNeighbourLists) { for(NodeSet::iterator i=v->leftNeighbours->begin(); i!=v->leftNeighbours->end();i++ @@ -217,7 +216,7 @@ int generateXConstraints(const int n, Rectangle** rs, Variable** vars, Constrain Node *u=*i; double sep = (v->r->width()+u->r->width())/2.0; constraints.push_back(new Constraint(u->v,v->v,sep)); - r=u->rightNeighbours->erase(v); + u->rightNeighbours->erase(v); } for(NodeSet::iterator i=v->rightNeighbours->begin(); @@ -226,22 +225,22 @@ int generateXConstraints(const int n, Rectangle** rs, Variable** vars, Constrain Node *u=*i; double sep = (v->r->width()+u->r->width())/2.0; constraints.push_back(new Constraint(v->v,u->v,sep)); - r=u->leftNeighbours->erase(v); + u->leftNeighbours->erase(v); } } else { Node *l=v->firstAbove, *r=v->firstBelow; if(l!=NULL) { double sep = (v->r->width()+l->r->width())/2.0; constraints.push_back(new Constraint(l->v,v->v,sep)); - l->firstBelow=v->firstBelow; + l->firstBelow = v->firstBelow; } if(r!=NULL) { double sep = (v->r->width()+r->r->width())/2.0; constraints.push_back(new Constraint(v->v,r->v,sep)); - r->firstAbove=v->firstAbove; + r->firstAbove = v->firstAbove; } } - r=scanline.erase(v); + scanline.erase(v); delete v; } delete e; diff --git a/src/marker.cpp b/src/marker.cpp index fb7b0fd21..7fee16ead 100644 --- a/src/marker.cpp +++ b/src/marker.cpp @@ -206,7 +206,9 @@ void SPMarker::update(SPCtx *ctx, guint flags) { SPItemCtx rctx = get_rctx( &ictx ); // Shift according to refX, refY - this->c2p = Geom::Translate(this->viewBox.left()-this->refX.computed, this->viewBox.top()-this->refY.computed) * this->c2p; + Geom::Point ref( this->refX.computed, this->refY.computed ); + ref *= c2p; + this->c2p = this->c2p * Geom::Translate( -ref ); // And invoke parent method SPGroup::update((SPCtx *) &rctx, flags); diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 76be086a2..b3d9af910 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -1747,7 +1747,7 @@ void sp_selection_rotate_90(SPDesktop *desktop, bool ccw) DocumentUndo::done(sp_desktop_document(desktop), ccw ? SP_VERB_OBJECT_ROTATE_90_CCW : SP_VERB_OBJECT_ROTATE_90_CW, - ccw ? _("Rotate 90° CCW") : _("Rotate 90° CW")); + ccw ? _("Rotate 90\xc2\xb0 CCW") : _("Rotate 90\xc2\xb0 CW")); } void diff --git a/src/selection.h b/src/selection.h index 394ab64ff..373167a33 100644 --- a/src/selection.h +++ b/src/selection.h @@ -302,6 +302,10 @@ public: sigc::connection connectChanged(sigc::slot<void, Selection *> const &slot) { return _changed_signal.connect(slot); } + sigc::connection connectChangedFirst(sigc::slot<void, Selection *> const &slot) + { + return _changed_signal.slots().insert(_changed_signal.slots().begin(), slot); + } /** * Connects a slot to be notified of selected object modifications. @@ -319,6 +323,10 @@ public: { return _modified_signal.connect(slot); } + sigc::connection connectModifiedFirst(sigc::slot<void, Selection *, guint> const &slot) + { + return _modified_signal.slots().insert(_modified_signal.slots().begin(), slot); + } private: /** no copy. */ diff --git a/src/sp-image.cpp b/src/sp-image.cpp index 2c20331a9..cb8ede2b2 100644 --- a/src/sp-image.cpp +++ b/src/sp-image.cpp @@ -813,9 +813,7 @@ void sp_image_refresh_if_outdated( SPImage* image ) if ( !val ) { // stat call worked. Check time now if ( st.st_mtime != image->pixbuf->modificationTime() ) { - SPCtx *ctx = 0; - unsigned int flags = SP_IMAGE_HREF_MODIFIED_FLAG; - image->update(ctx, flags); + image->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG | SP_IMAGE_HREF_MODIFIED_FLAG); } } } diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 425ca9efa..e465565c4 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -542,6 +542,7 @@ static bool pattern_hasItemChildren (SPPattern const *pat) } cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &bbox, double opacity) { + bool needs_opacity = (1.0 - opacity) >= 1e-3; bool visible = opacity >= 1e-3; @@ -580,63 +581,69 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b } } - // viewBox to pattern server - Geom::Affine vb2ps = Geom::identity(); - if (this->viewBox_set) { - Geom::Rect vb = *pattern_viewBox(this); - gdouble tmp_x = pattern_width (this) / vb.width(); - gdouble tmp_y = pattern_height (this) / vb.height(); - - // FIXME: preserveAspectRatio must be taken into account here too! - vb2ps = Geom::Affine(tmp_x, 0.0, 0.0, tmp_y, pattern_x(this) - vb.left() * tmp_x, pattern_y(this) - vb.top() * tmp_y); + // ****** Geometry ****** + // + // * "width" and "height" determine tile size. + // * "viewBox" (if defined) or "patternContentUnits" determines placement of content inside + // tile. + // * "x", "y", and "patternTransform" transform tile to user space after tile is generated. + + // These functions recursively search up the tree to find the values. + double tile_x = pattern_x(this); + double tile_y = pattern_y(this); + double tile_width = pattern_width(this); + double tile_height = pattern_height(this); + if (pattern_patternUnits(this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { + tile_x *= bbox->width(); + tile_y *= bbox->height(); + tile_width *= bbox->width(); + tile_height *= bbox->height(); } - // We must determine the size and scaling of the pattern at the time it is displayed and render - // the pattern onto a surface with that size and at that resolution. + // Pattern size in pattern space + Geom::Rect pattern_tile = Geom::Rect::from_xywh(0, 0, tile_width, tile_height); + + // Content to tile (pattern space) + Geom::Affine content2ps; + if (this->viewBox_set) { + // viewBox to pattern server (using SPViewBox) + viewBox = *pattern_viewBox(this); + c2p.setIdentity(); + apply_viewbox( pattern_tile ); + content2ps = c2p; + } else { - // Pattern server to user - Geom::Affine ps2user; - ps2user = pattern_patternTransform(this); - if (!this->viewBox_set && pattern_patternContentUnits (this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { - /* BBox to user coordinate system */ - Geom::Affine bbox2user (bbox->width(), 0.0, 0.0, bbox->height(), bbox->left(), bbox->top()); - ps2user *= bbox2user; + // Content to bbox + if (pattern_patternContentUnits (this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { + content2ps = Geom::Affine(bbox->width(), 0.0, 0.0, bbox->height(), 0,0); + } } - ps2user = Geom::Translate (pattern_x (this), pattern_y (this)) * ps2user; - // Pattern size in pattern space - Geom::Rect pattern_tile = Geom::Rect::from_xywh(pattern_x(this), pattern_y(this), - pattern_width(this), pattern_height(this)); - if (pattern_patternUnits(this) == SP_PATTERN_UNITS_OBJECTBOUNDINGBOX) { - // interpret x, y, width, height in relation to bbox - Geom::Affine bbox2user(bbox->width(), 0.0, 0.0, bbox->height(), bbox->left(), bbox->top()); - pattern_tile = pattern_tile * bbox2user; - } + // Tile (pattern space) to user. + Geom::Affine ps2user = Geom::Translate(tile_x,tile_y) * pattern_patternTransform(this); + // Transform of object with pattern (includes screen scaling) cairo_matrix_t cm; cairo_get_matrix(base_ct, &cm); Geom::Affine full(cm.xx, cm.yx, cm.xy, cm.yy, 0, 0); - // The DrawingSurface class is suppose to handle the mapping from "logical space" + // The DrawingSurface class handles the mapping from "logical space" // (coordinates in the rendering) to "physical space" (surface pixels). // An oversampling is done as the pattern may not pixel align with the final surface. // The cairo surface is created when the DrawingContext is declared. - // oversample the pattern slightly + // Oversample the pattern // TODO: find optimum value // TODO: this is lame. instead of using descrim(), we should extract // the scaling component from the complete matrix and use it // to find the optimum tile size for rendering // c is number of pixels in buffer x and y. // Scale factor of 1.1 is too small... see bug #1251039 - Geom::Point c(pattern_tile.dimensions()*vb2ps.descrim()*ps2user.descrim()*full.descrim()*2.0); - - c[Geom::X] = ceil(c[Geom::X]); - c[Geom::Y] = ceil(c[Geom::Y]); + Geom::Point c(pattern_tile.dimensions()*ps2user.descrim()*full.descrim()*2.0); - // Create drawing surface with size of pattern tile (in tile space) but with number of pixels + // Create drawing surface with size of pattern tile (in pattern space) but with number of pixels // based on required resolution (c). Inkscape::DrawingSurface pattern_surface(pattern_tile, c.ceil()); Inkscape::DrawingContext dc(pattern_surface); @@ -644,14 +651,14 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b pattern_tile *= pattern_surface.drawingTransform(); Geom::IntRect one_tile = pattern_tile.roundOutwards(); - // render pattern. + // Render pattern. if (needs_opacity) { dc.pushGroup(); // this group is for pattern + opacity } // TODO: make sure there are no leaks. Inkscape::UpdateContext ctx; // UpdateContext is structure with only ctm! - ctx.ctm = vb2ps * pattern_surface.drawingTransform(); + ctx.ctm = content2ps * pattern_surface.drawingTransform(); dc.transform( pattern_surface.drawingTransform().inverse() ); drawing.update(Geom::IntRect::infinite(), ctx); @@ -670,7 +677,8 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b // << " width: " << cairo_image_surface_get_width( raw ) // << " height: " << cairo_image_surface_get_height( raw ) // << std::endl; - // cairo_surface_write_to_png( pattern_surface.raw(), "sp-pattern.png" ); + // std::string filename = "sp-pattern-" + (std::string)getId() + ".png"; + // cairo_surface_write_to_png( pattern_surface.raw(), filename.c_str() ); if (needs_opacity) { dc.popGroupToSource(); // pop raw pattern @@ -679,7 +687,7 @@ cairo_pattern_t* SPPattern::pattern_new(cairo_t *base_ct, Geom::OptRect const &b cairo_pattern_t *cp = cairo_pattern_create_for_surface(pattern_surface.raw()); // Apply transformation to user space. Also compensate for oversampling. - ink_cairo_pattern_set_matrix(cp, ps2user.inverse() * pattern_surface.drawingTransform()); + ink_cairo_pattern_set_matrix(cp, ps2user.inverse() * pattern_surface.drawingTransform() ); cairo_pattern_set_extend(cp, CAIRO_EXTEND_REPEAT); diff --git a/src/sp-use.cpp b/src/sp-use.cpp index e394e84c2..14f51159b 100644 --- a/src/sp-use.cpp +++ b/src/sp-use.cpp @@ -22,6 +22,7 @@ #include <2geom/transforms.h> #include <glibmm/i18n.h> +#include <glibmm/markup.h> #include "display/drawing-group.h" #include "attributes.h" #include "document.h" @@ -219,7 +220,7 @@ const char* SPUse::displayName() const { gchar* SPUse::description() const { if (this->child) { if( SP_IS_SYMBOL( this->child ) ) { - return g_strdup_printf(_("called %s"), this->child->title()); + return g_strdup_printf(_("called %s"), Glib::Markup::escape_text(Glib::ustring( g_dpgettext2(NULL, "Symbol", this->child->title()))).c_str()); } static unsigned recursion_depth = 0; diff --git a/src/style-test.h b/src/style-test.h index 064773d1d..8a4055cc1 100644 --- a/src/style-test.h +++ b/src/style-test.h @@ -86,6 +86,59 @@ public: // TestCase("fill:url(#painter) inherit", 0, "#painter"), TestCase("fill:inherit"), + +// General tests (in order of appearance in sp_style_read), SPIPaint tested above + TestCase("visibility:hidden"), // SPIEnum + TestCase("visibility:collapse"), + TestCase("visibility:visible"), + TestCase("display:none"), // SPIEnum + TestCase("overflow:visible"), // SPIEnum + TestCase("overflow:auto"), // SPIEnum + TestCase("font-size:12", "font-size:12px"), // SPIFontSize + TestCase("font-size:12px"), + TestCase("font-size:12pt", "font-size:15px"), + TestCase("font-size:medium"), + TestCase("font-style:italic"), // SPIEnum + TestCase("font-variant:small-caps"), // SPIEnum + TestCase("font-weight:100"), // SPIEnum + TestCase("font-weight:normal"), + TestCase("font-weight:bolder"), + TestCase("font-stretch:condensed"), // SPIEnum + TestCase("text-indent:12em"), // SPILength? + TestCase("text-align:center"), // SPIEnum + TestCase("text-decoration: underline"), // SPITextDecoration + TestCase("line-height:24px"), // SPILengthOrNormal + TestCase("letter-spacing:2px"), // SPILengthOrNormal + TestCase("word-spacing:2px"), // SPILengthOrNormal + TestCase("text-transform:lowercase"), // SPIEnum + // ... + TestCase("baseline-shift:baseline"), // SPIBaselineShift + TestCase("baseline-shift:sub"), + TestCase("baseline-shift:12.5%"), + TestCase("baseline-shift:2px"), + TestCase("opacity:0.1"), // SPIScale24 + // ... + TestCase("stroke-width:2px"), // SPILength + TestCase("stroke-linecap:round"), // SPIEnum + TestCase("stroke-linejoin:round"), // SPIEnum + TestCase("stroke-miterlimit:4"), // SPIFloat + TestCase("marker:url(#Arrow)"), // SPIString + TestCase("marker-start:url(#Arrow)"), + TestCase("marker-mid:url(#Arrow)"), + TestCase("marker-end:url(#Arrow)"), + TestCase("stroke-opacity:0.5"), // SPIScale24 + TestCase("stroke-dasharray:0, 1, 0, 1"), // NRVpathDash + TestCase("stroke-dasharray:0 1 0 1","stroke-dasharray:0, 1, 0, 1"), + TestCase("stroke-dashoffset:13"), // NRVpathDash + // ... + TestCase("font-family:sans-serif"), // SPIString, text_private + //TestCase("filter:url(#myfilter)"), // filter + + TestCase("opacity:0.1;fill:#ff0000;stroke:#0000ff;stroke-width:2px"), + +#ifdef WITH_SVG2 + TestCase("paint-order:stroke"), // SPIPaintOrder +#endif TestCase(0) }; @@ -107,8 +160,10 @@ public: gchar *str0_set = sp_style_write_string( style, SP_STYLE_FLAG_IFSET ); //printf("<<%s>>\n", str0_set); if ( cases[i].dst ) { + //std::cout << " " << std::string(str0_set) << " " << std::string(cases[i].dst) << std::endl; TS_ASSERT_EQUALS( std::string(str0_set), std::string(cases[i].dst) ); } else { + //std::cout << " " << std::string(str0_set) << " " << std::string(cases[i].src) << std::endl; TS_ASSERT_EQUALS( std::string(str0_set), std::string(cases[i].src) ); } diff --git a/src/style.cpp b/src/style.cpp index 7ad9749f0..f3a12db86 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -3731,7 +3731,7 @@ sp_style_read_ipaintorder(SPIPaintOrder *val, gchar const *str) val->layer[i] = SP_CSS_PAINT_ORDER_STROKE; val->layer_set[i] = true; used[1] = true; - } else if( !strcmp( c[i], "marker")) { + } else if( !strcmp( c[i], "markers")) { val->layer[i] = SP_CSS_PAINT_ORDER_MARKER; val->layer_set[i] = true; used[2] = true; @@ -4785,7 +4785,7 @@ sp_style_write_ifontsize(gchar *p, gint const len, gchar const *key, return g_snprintf(p, len, "%s:inherit;", key); } else if (val->type == SP_FONT_SIZE_LITERAL) { for (unsigned i = 0; enum_font_size[i].key; i++) { - if (enum_font_size[i].value == static_cast< gint > (val->value) ) { + if (enum_font_size[i].value == static_cast< gint > (val->literal) ) { return g_snprintf(p, len, "%s:%s;", key, enum_font_size[i].key); } } diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index 340a3dad0..f0a5f1bf5 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -144,11 +144,13 @@ namespace Dialog { /** A list of strings that is used both in the preferences, and in the data fields to describe the various values of \c selection_type. */ static const char * selection_names[SELECTION_NUMBER_OF] = { - "page", "drawing", "selection", "custom"}; + "page", "drawing", "selection", "custom" +}; /** The names on the buttons for the various selection types. */ static const char * selection_labels[SELECTION_NUMBER_OF] = { - N_("_Page"), N_("_Drawing"), N_("_Selection"), N_("_Custom")}; + N_("_Page"), N_("_Drawing"), N_("_Selection"), N_("_Custom") +}; Export::Export (void) : UI::Widget::Panel ("", "/dialogs/export/", SP_VERB_DIALOG_EXPORT), @@ -201,7 +203,7 @@ Export::Export (void) : /* gets added to the vbox later, but the unit selector is needed earlier than that */ unit_selector.setUnitType(Inkscape::Util::UNIT_TYPE_LINEAR); - + SPDesktop *desktop = SP_ACTIVE_DESKTOP; if (desktop) { unit_selector.setUnit(sp_desktop_namedview(desktop)->doc_units->abbr); @@ -232,28 +234,28 @@ Export::Export (void) : #endif x0_adj = createSpinbutton ( "x0", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, - t, 0, 0, _("_x0:"), "", EXPORT_COORD_PRECISION, 1, - &Export::onAreaX0Change); + t, 0, 0, _("_x0:"), "", EXPORT_COORD_PRECISION, 1, + &Export::onAreaX0Change); x1_adj = createSpinbutton ( "x1", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, - t, 0, 1, _("x_1:"), "", EXPORT_COORD_PRECISION, 1, - &Export::onAreaX1Change); + t, 0, 1, _("x_1:"), "", EXPORT_COORD_PRECISION, 1, + &Export::onAreaX1Change); width_adj = createSpinbutton ( "width", 0.0, 0.0, PNG_UINT_31_MAX, 0.1, 1.0, - t, 0, 2, _("Wid_th:"), "", EXPORT_COORD_PRECISION, 1, - &Export::onAreaWidthChange); + t, 0, 2, _("Wid_th:"), "", EXPORT_COORD_PRECISION, 1, + &Export::onAreaWidthChange); y0_adj = createSpinbutton ( "y0", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, - t, 2, 0, _("_y0:"), "", EXPORT_COORD_PRECISION, 1, - &Export::onAreaY0Change); + t, 2, 0, _("_y0:"), "", EXPORT_COORD_PRECISION, 1, + &Export::onAreaY0Change); y1_adj = createSpinbutton ( "y1", 0.0, -1000000.0, 1000000.0, 0.1, 1.0, - t, 2, 1, _("y_1:"), "", EXPORT_COORD_PRECISION, 1, - &Export::onAreaY1Change); + t, 2, 1, _("y_1:"), "", EXPORT_COORD_PRECISION, 1, + &Export::onAreaY1Change); height_adj = createSpinbutton ( "height", 0.0, 0.0, PNG_UINT_31_MAX, 0.1, 1.0, - t, 2, 2, _("Hei_ght:"), "", EXPORT_COORD_PRECISION, 1, - &Export::onAreaHeightChange); + t, 2, 2, _("Hei_ght:"), "", EXPORT_COORD_PRECISION, 1, + &Export::onAreaHeightChange); area_box.pack_start(togglebox, false, false, 3); area_box.pack_start(*t, false, false, 0); @@ -284,27 +286,27 @@ Export::Export (void) : size_box.pack_start(*t); bmwidth_adj = createSpinbutton ( "bmwidth", 16.0, 1.0, 1000000.0, 1.0, 10.0, - t, 0, 0, - _("_Width:"), _("pixels at"), 0, 1, - &Export::onBitmapWidthChange); + t, 0, 0, + _("_Width:"), _("pixels at"), 0, 1, + &Export::onBitmapWidthChange); xdpi_adj = createSpinbutton ( "xdpi", - prefs->getDouble("/dialogs/export/defaultxdpi/value", DPI_BASE), - 0.01, 100000.0, 0.1, 1.0, t, 3, 0, - "", _("dp_i"), 2, 1, - &Export::onExportXdpiChange); + prefs->getDouble("/dialogs/export/defaultxdpi/value", DPI_BASE), + 0.01, 100000.0, 0.1, 1.0, t, 3, 0, + "", _("dp_i"), 2, 1, + &Export::onExportXdpiChange); bmheight_adj = createSpinbutton ( "bmheight", 16.0, 1.0, 1000000.0, 1.0, 10.0, - t, 0, 1, - _("_Height:"), _("pixels at"), 0, 1, - &Export::onBitmapHeightChange); + t, 0, 1, + _("_Height:"), _("pixels at"), 0, 1, + &Export::onBitmapHeightChange); /** TODO * There's no way to set ydpi currently, so we use the defaultxdpi value here, too... */ ydpi_adj = createSpinbutton ( "ydpi", prefs->getDouble("/dialogs/export/defaultxdpi/value", DPI_BASE), - 0.01, 100000.0, 0.1, 1.0, t, 3, 1, - "", _("dpi"), 2, 0, NULL ); + 0.01, 100000.0, 0.1, 1.0, t, 3, 1, + "", _("dpi"), 2, 0, NULL ); singleexport_box.pack_start(size_box); } @@ -482,18 +484,18 @@ void Export::set_default_filename () { #if WITH_GTKMM_3_0 Glib::RefPtr<Gtk::Adjustment> Export::createSpinbutton( gchar const * /*key*/, float val, float min, float max, - float step, float page, - Gtk::Grid *t, int x, int y, - const Glib::ustring ll, const Glib::ustring lr, - int digits, unsigned int sensitive, - void (Export::*cb)() ) + float step, float page, + Gtk::Grid *t, int x, int y, + const Glib::ustring& ll, const Glib::ustring& lr, + int digits, unsigned int sensitive, + void (Export::*cb)() ) #else Gtk::Adjustment * Export::createSpinbutton( gchar const * /*key*/, float val, float min, float max, - float step, float page, - Gtk::Table *t, int x, int y, - const Glib::ustring ll, const Glib::ustring lr, - int digits, unsigned int sensitive, - void (Export::*cb)() ) + float step, float page, + Gtk::Table *t, int x, int y, + const Glib::ustring& ll, const Glib::ustring& lr, + int digits, unsigned int sensitive, + void (Export::*cb)() ) #endif { #if WITH_GTKMM_3_0 @@ -535,7 +537,9 @@ Gtk::Adjustment * Export::createSpinbutton( gchar const * /*key*/, float val, fl sb->set_sensitive (sensitive); pos++; - if (!ll.empty()) { l->set_mnemonic_widget(*sb);} + if (!ll.empty()) { + l->set_mnemonic_widget(*sb); + } if (!lr.empty()) { l = new Gtk::Label(lr,true); @@ -565,7 +569,7 @@ Gtk::Adjustment * Export::createSpinbutton( gchar const * /*key*/, float val, fl Glib::ustring Export::create_filepath_from_id (Glib::ustring id, const Glib::ustring &file_entry_text) { if (id.empty()) - { /* This should never happen */ + { /* This should never happen */ id = "bitmap"; } @@ -678,35 +682,35 @@ void Export::onSelectionModified ( guint /*flags*/ ) { Inkscape::Selection * Sel; switch (current_key) { - case SELECTION_DRAWING: - if ( SP_ACTIVE_DESKTOP ) { - SPDocument *doc; - doc = sp_desktop_document (SP_ACTIVE_DESKTOP); - Geom::OptRect bbox = doc->getRoot()->desktopVisualBounds(); - if (bbox) { - setArea ( bbox->left(), - bbox->top(), - bbox->right(), - bbox->bottom()); - } + case SELECTION_DRAWING: + if ( SP_ACTIVE_DESKTOP ) { + SPDocument *doc; + doc = sp_desktop_document (SP_ACTIVE_DESKTOP); + Geom::OptRect bbox = doc->getRoot()->desktopVisualBounds(); + if (bbox) { + setArea ( bbox->left(), + bbox->top(), + bbox->right(), + bbox->bottom()); } - break; - case SELECTION_SELECTION: - Sel = sp_desktop_selection(SP_ACTIVE_DESKTOP); - if (Sel->isEmpty() == false) { - Geom::OptRect bbox = Sel->visualBounds(); - if (bbox) - { - setArea ( bbox->left(), - bbox->top(), - bbox->right(), - bbox->bottom()); - } + } + break; + case SELECTION_SELECTION: + Sel = sp_desktop_selection(SP_ACTIVE_DESKTOP); + if (Sel->isEmpty() == false) { + Geom::OptRect bbox = Sel->visualBounds(); + if (bbox) + { + setArea ( bbox->left(), + bbox->top(), + bbox->right(), + bbox->bottom()); } - break; - default: - /* Do nothing for page or for custom */ - break; + } + break; + default: + /* Do nothing for page or for custom */ + break; } return; @@ -738,39 +742,39 @@ void Export::onAreaToggled () various backups. If you modify this without noticing you'll probabaly screw something up. */ switch (key) { - case SELECTION_SELECTION: - if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) - { - bbox = sp_desktop_selection (SP_ACTIVE_DESKTOP)->visualBounds(); - /* Only if there is a selection that we can set - do we break, otherwise we fall through to the - drawing */ - // std::cout << "Using selection: SELECTION" << std::endl; - key = SELECTION_SELECTION; - break; - } - case SELECTION_DRAWING: - /** \todo - * This returns wrong values if the document has a viewBox. - */ - bbox = doc->getRoot()->desktopVisualBounds(); - /* If the drawing is valid, then we'll use it and break - otherwise we drop through to the page settings */ - if (bbox) { - // std::cout << "Using selection: DRAWING" << std::endl; - key = SELECTION_DRAWING; - break; - } - case SELECTION_PAGE: - bbox = Geom::Rect(Geom::Point(0.0, 0.0), - Geom::Point(doc->getWidth().value("px"), doc->getHeight().value("px"))); - - // std::cout << "Using selection: PAGE" << std::endl; - key = SELECTION_PAGE; + case SELECTION_SELECTION: + if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) + { + bbox = sp_desktop_selection (SP_ACTIVE_DESKTOP)->visualBounds(); + /* Only if there is a selection that we can set + do we break, otherwise we fall through to the + drawing */ + // std::cout << "Using selection: SELECTION" << std::endl; + key = SELECTION_SELECTION; break; - case SELECTION_CUSTOM: - default: + } + case SELECTION_DRAWING: + /** \todo + * This returns wrong values if the document has a viewBox. + */ + bbox = doc->getRoot()->desktopVisualBounds(); + /* If the drawing is valid, then we'll use it and break + otherwise we drop through to the page settings */ + if (bbox) { + // std::cout << "Using selection: DRAWING" << std::endl; + key = SELECTION_DRAWING; break; + } + case SELECTION_PAGE: + bbox = Geom::Rect(Geom::Point(0.0, 0.0), + Geom::Point(doc->getWidth().value("px"), doc->getHeight().value("px"))); + + // std::cout << "Using selection: PAGE" << std::endl; + key = SELECTION_PAGE; + break; + case SELECTION_CUSTOM: + default: + break; } // switch current_key = key; @@ -780,9 +784,9 @@ void Export::onAreaToggled () if ( key != SELECTION_CUSTOM && bbox ) { setArea ( bbox->min()[Geom::X], - bbox->min()[Geom::Y], - bbox->max()[Geom::X], - bbox->max()[Geom::Y]); + bbox->min()[Geom::Y], + bbox->max()[Geom::X], + bbox->max()[Geom::Y]); } } // end of if ( SP_ACTIVE_DESKTOP ) @@ -793,43 +797,43 @@ void Export::onAreaToggled () float xdpi = 0.0, ydpi = 0.0; switch (key) { - case SELECTION_PAGE: - case SELECTION_DRAWING: { - SPDocument * doc = SP_ACTIVE_DOCUMENT; - sp_document_get_export_hints (doc, filename, &xdpi, &ydpi); - - if (filename.empty()) { - if (!doc_export_name.empty()) { - filename = doc_export_name; - } + case SELECTION_PAGE: + case SELECTION_DRAWING: { + SPDocument * doc = SP_ACTIVE_DOCUMENT; + sp_document_get_export_hints (doc, filename, &xdpi, &ydpi); + + if (filename.empty()) { + if (!doc_export_name.empty()) { + filename = doc_export_name; } - break; } - case SELECTION_SELECTION: - if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) { - - sp_selection_get_export_hints (sp_desktop_selection(SP_ACTIVE_DESKTOP), filename, &xdpi, &ydpi); - - /* If we still don't have a filename -- let's build - one that's nice */ - if (filename.empty()) { - const gchar * id = "object"; - const GSList * reprlst = sp_desktop_selection(SP_ACTIVE_DESKTOP)->reprList(); - for(; reprlst != NULL; reprlst = reprlst->next) { - Inkscape::XML::Node * repr = (Inkscape::XML::Node *)reprlst->data; - if (repr->attribute("id")) { - id = repr->attribute("id"); - break; - } - } + break; + } + case SELECTION_SELECTION: + if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) { - filename = create_filepath_from_id (id, filename_entry.get_text()); + sp_selection_get_export_hints (sp_desktop_selection(SP_ACTIVE_DESKTOP), filename, &xdpi, &ydpi); + + /* If we still don't have a filename -- let's build + one that's nice */ + if (filename.empty()) { + const gchar * id = "object"; + const GSList * reprlst = sp_desktop_selection(SP_ACTIVE_DESKTOP)->reprList(); + for(; reprlst != NULL; reprlst = reprlst->next) { + Inkscape::XML::Node * repr = (Inkscape::XML::Node *)reprlst->data; + if (repr->attribute("id")) { + id = repr->attribute("id"); + break; + } } + + filename = create_filepath_from_id (id, filename_entry.get_text()); } - break; - case SELECTION_CUSTOM: - default: - break; + } + break; + case SELECTION_CUSTOM: + default: + break; } if (!filename.empty()) { @@ -895,8 +899,8 @@ unsigned int Export::onProgressCallback(float value, void *dlg) int evtcount = 0; while ((evtcount < 16) && gdk_events_pending()) { - gtk_main_iteration_do(FALSE); - evtcount += 1; + gtk_main_iteration_do(FALSE); + evtcount += 1; } gtk_main_iteration_do(FALSE); @@ -960,7 +964,7 @@ Glib::ustring Export::filename_add_extension (Glib::ustring filename, Glib::ustr } else { - return filename = filename + "." + extension; + return filename = filename + "." + extension; } } } @@ -1057,9 +1061,9 @@ void Export::onExport () // Do export gchar * safeFile = Inkscape::IO::sanitizeString(path.c_str()); MessageCleaner msgCleanup(desktop->messageStack()->pushF(Inkscape::IMMEDIATE_MESSAGE, - _("Exporting file <b>%s</b>..."), safeFile), desktop); + _("Exporting file <b>%s</b>..."), safeFile), desktop); MessageCleaner msgFlashCleanup(desktop->messageStack()->flashF(Inkscape::IMMEDIATE_MESSAGE, - _("Exporting file <b>%s</b>..."), safeFile), desktop); + _("Exporting file <b>%s</b>..."), safeFile), desktop); if (!sp_export_png_file (doc, path.c_str(), *area, width, height, dpi, dpi, @@ -1067,7 +1071,7 @@ void Export::onExport () onProgressCallback, (void*)prog_dlg, TRUE, // overwrite without asking hide ? const_cast<GSList *>(sp_desktop_selection(desktop)->itemList()) : NULL - )) { + )) { gchar * error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile); desktop->messageStack()->flashF(Inkscape::ERROR_MESSAGE, @@ -1096,7 +1100,7 @@ void Export::onExport () } else { Glib::ustring filename = filename_entry.get_text(); - if (filename.empty()){ + if (filename.empty()) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("You have to enter a filename.")); sp_ui_error_dialog(_("You have to enter a filename")); return; @@ -1125,7 +1129,7 @@ void Export::onExport () Glib::ustring dirname = Glib::path_get_dirname(path); if ( dirname.empty() - || !Inkscape::IO::file_test(dirname.c_str(), (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) ) + || !Inkscape::IO::file_test(dirname.c_str(), (GFileTest)(G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) ) { gchar *safeDir = Inkscape::IO::sanitizeString(dirname.c_str()); gchar *error = g_strdup_printf(_("Directory %s does not exist or is not a directory.\n"), @@ -1151,12 +1155,12 @@ void Export::onExport () /* Do export */ ExportResult status = sp_export_png_file(sp_desktop_document(desktop), path.c_str(), - Geom::Rect(Geom::Point(x0, y0), Geom::Point(x1, y1)), width, height, xdpi, ydpi, - nv->pagecolor, - onProgressCallback, (void*)prog_dlg, - FALSE, - hide ? const_cast<GSList *>(sp_desktop_selection(desktop)->itemList()) : NULL - ); + Geom::Rect(Geom::Point(x0, y0), Geom::Point(x1, y1)), width, height, xdpi, ydpi, + nv->pagecolor, + onProgressCallback, (void*)prog_dlg, + FALSE, + hide ? const_cast<GSList *>(sp_desktop_selection(desktop)->itemList()) : NULL + ); if (status == EXPORT_ERROR) { gchar * safeFile = Inkscape::IO::sanitizeString(path.c_str()); gchar * error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile); @@ -1189,19 +1193,65 @@ void Export::onExport () /* Setup the values in the document */ switch (current_key) { - case SELECTION_PAGE: - case SELECTION_DRAWING: { - SPDocument * doc = SP_ACTIVE_DOCUMENT; - Inkscape::XML::Node * repr = doc->getReprRoot(); - bool modified = false; - - bool saved = DocumentUndo::getUndoSensitive(doc); - DocumentUndo::setUndoSensitive(doc, false); - - gchar const *temp_string = repr->attribute("inkscape:export-filename"); - if (temp_string == NULL || (filename_ext != temp_string)) { - repr->setAttribute("inkscape:export-filename", filename_ext.c_str()); - modified = true; + case SELECTION_PAGE: + case SELECTION_DRAWING: { + SPDocument * doc = SP_ACTIVE_DOCUMENT; + Inkscape::XML::Node * repr = doc->getReprRoot(); + bool modified = false; + + bool saved = DocumentUndo::getUndoSensitive(doc); + DocumentUndo::setUndoSensitive(doc, false); + + gchar const *temp_string = repr->attribute("inkscape:export-filename"); + if (temp_string == NULL || (filename_ext != temp_string)) { + repr->setAttribute("inkscape:export-filename", filename_ext.c_str()); + modified = true; + } + temp_string = repr->attribute("inkscape:export-xdpi"); + if (temp_string == NULL || xdpi != atof(temp_string)) { + sp_repr_set_svg_double(repr, "inkscape:export-xdpi", xdpi); + modified = true; + } + temp_string = repr->attribute("inkscape:export-ydpi"); + if (temp_string == NULL || ydpi != atof(temp_string)) { + sp_repr_set_svg_double(repr, "inkscape:export-ydpi", ydpi); + modified = true; + } + DocumentUndo::setUndoSensitive(doc, saved); + + if (modified) { + doc->setModifiedSinceSave(); + } + break; + } + case SELECTION_SELECTION: { + const GSList * reprlst; + SPDocument * doc = SP_ACTIVE_DOCUMENT; + bool modified = false; + + bool saved = DocumentUndo::getUndoSensitive(doc); + DocumentUndo::setUndoSensitive(doc, false); + reprlst = sp_desktop_selection(desktop)->reprList(); + + for(; reprlst != NULL; reprlst = reprlst->next) { + Inkscape::XML::Node * repr = static_cast<Inkscape::XML::Node *>(reprlst->data); + const gchar * temp_string; + Glib::ustring dir = Glib::path_get_dirname(filename.c_str()); + const gchar* docURI=SP_ACTIVE_DOCUMENT->getURI(); + Glib::ustring docdir; + if (docURI) + { + docdir = Glib::path_get_dirname(docURI); + } + if (repr->attribute("id") == NULL || + !(filename_ext.find_last_of(repr->attribute("id")) && + ( !docURI || + (dir == docdir)))) { + temp_string = repr->attribute("inkscape:export-filename"); + if (temp_string == NULL || (filename_ext != temp_string)) { + repr->setAttribute("inkscape:export-filename", filename_ext.c_str()); + modified = true; + } } temp_string = repr->attribute("inkscape:export-xdpi"); if (temp_string == NULL || xdpi != atof(temp_string)) { @@ -1213,62 +1263,16 @@ void Export::onExport () sp_repr_set_svg_double(repr, "inkscape:export-ydpi", ydpi); modified = true; } - DocumentUndo::setUndoSensitive(doc, saved); - - if (modified) { - doc->setModifiedSinceSave(); - } - break; } - case SELECTION_SELECTION: { - const GSList * reprlst; - SPDocument * doc = SP_ACTIVE_DOCUMENT; - bool modified = false; - - bool saved = DocumentUndo::getUndoSensitive(doc); - DocumentUndo::setUndoSensitive(doc, false); - reprlst = sp_desktop_selection(desktop)->reprList(); - - for(; reprlst != NULL; reprlst = reprlst->next) { - Inkscape::XML::Node * repr = static_cast<Inkscape::XML::Node *>(reprlst->data); - const gchar * temp_string; - Glib::ustring dir = Glib::path_get_dirname(filename.c_str()); - const gchar* docURI=SP_ACTIVE_DOCUMENT->getURI(); - Glib::ustring docdir; - if (docURI) - { - docdir = Glib::path_get_dirname(docURI); - } - if (repr->attribute("id") == NULL || - !(filename_ext.find_last_of(repr->attribute("id")) && - ( !docURI || - (dir == docdir)))) { - temp_string = repr->attribute("inkscape:export-filename"); - if (temp_string == NULL || (filename_ext != temp_string)) { - repr->setAttribute("inkscape:export-filename", filename_ext.c_str()); - modified = true; - } - } - temp_string = repr->attribute("inkscape:export-xdpi"); - if (temp_string == NULL || xdpi != atof(temp_string)) { - sp_repr_set_svg_double(repr, "inkscape:export-xdpi", xdpi); - modified = true; - } - temp_string = repr->attribute("inkscape:export-ydpi"); - if (temp_string == NULL || ydpi != atof(temp_string)) { - sp_repr_set_svg_double(repr, "inkscape:export-ydpi", ydpi); - modified = true; - } - } - DocumentUndo::setUndoSensitive(doc, saved); + DocumentUndo::setUndoSensitive(doc, saved); - if (modified) { - doc->setModifiedSinceSave(); - } - break; + if (modified) { + doc->setModifiedSinceSave(); } - default: - break; + break; + } + default: + break; } } @@ -1331,8 +1335,8 @@ void Export::onBrowse () // Copy the selected file name, converting from UTF-8 to UTF-16 std::string dirname = Glib::path_get_dirname(filename.raw()); if ( !Glib::file_test(dirname, Glib::FILE_TEST_EXISTS) || - Glib::file_test(filename, Glib::FILE_TEST_IS_DIR) || - dirname.empty() ) + Glib::file_test(filename, Glib::FILE_TEST_IS_DIR) || + dirname.empty() ) { Glib::ustring tmp; filename = create_filepath_from_id(tmp, tmp); @@ -1407,11 +1411,11 @@ bool Export::bbox_equal(Geom::Rect const &one, Geom::Rect const &two) { double const epsilon = pow(10.0, -EXPORT_COORD_PRECISION); return ( - (fabs(one.min()[Geom::X] - two.min()[Geom::X]) < epsilon) && - (fabs(one.min()[Geom::Y] - two.min()[Geom::Y]) < epsilon) && - (fabs(one.max()[Geom::X] - two.max()[Geom::X]) < epsilon) && - (fabs(one.max()[Geom::Y] - two.max()[Geom::Y]) < epsilon) - ); + (fabs(one.min()[Geom::X] - two.min()[Geom::X]) < epsilon) && + (fabs(one.min()[Geom::Y] - two.min()[Geom::Y]) < epsilon) && + (fabs(one.max()[Geom::X] - two.max()[Geom::X]) < epsilon) && + (fabs(one.max()[Geom::Y] - two.max()[Geom::Y]) < epsilon) + ); } /** @@ -1454,48 +1458,48 @@ void Export::detectSize() { for (int i = 0; i < SELECTION_NUMBER_OF + 1 && - key == SELECTION_NUMBER_OF && - SP_ACTIVE_DESKTOP != NULL; + key == SELECTION_NUMBER_OF && + SP_ACTIVE_DESKTOP != NULL; i++) { switch (this_test[i]) { - case SELECTION_SELECTION: - if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) { - Geom::OptRect bbox = (sp_desktop_selection (SP_ACTIVE_DESKTOP))->bounds(SPItem::VISUAL_BBOX); + case SELECTION_SELECTION: + if ((sp_desktop_selection(SP_ACTIVE_DESKTOP))->isEmpty() == false) { + Geom::OptRect bbox = (sp_desktop_selection (SP_ACTIVE_DESKTOP))->bounds(SPItem::VISUAL_BBOX); - if ( bbox && bbox_equal(*bbox,current_bbox)) { - key = SELECTION_SELECTION; - } + if ( bbox && bbox_equal(*bbox,current_bbox)) { + key = SELECTION_SELECTION; } - break; - case SELECTION_DRAWING: { - SPDocument *doc = sp_desktop_document (SP_ACTIVE_DESKTOP); + } + break; + case SELECTION_DRAWING: { + SPDocument *doc = sp_desktop_document (SP_ACTIVE_DESKTOP); - Geom::OptRect bbox = doc->getRoot()->desktopVisualBounds(); + Geom::OptRect bbox = doc->getRoot()->desktopVisualBounds(); - if ( bbox && bbox_equal(*bbox,current_bbox) ) { - key = SELECTION_DRAWING; - } - break; + if ( bbox && bbox_equal(*bbox,current_bbox) ) { + key = SELECTION_DRAWING; } + break; + } - case SELECTION_PAGE: { - SPDocument *doc; + case SELECTION_PAGE: { + SPDocument *doc; - doc = sp_desktop_document (SP_ACTIVE_DESKTOP); + doc = sp_desktop_document (SP_ACTIVE_DESKTOP); - Geom::Point x(0.0, 0.0); - Geom::Point y(doc->getWidth().value("px"), - doc->getHeight().value("px")); - Geom::Rect bbox(x, y); + Geom::Point x(0.0, 0.0); + Geom::Point y(doc->getWidth().value("px"), + doc->getHeight().value("px")); + Geom::Rect bbox(x, y); - if (bbox_equal(bbox,current_bbox)) { - key = SELECTION_PAGE; - } + if (bbox_equal(bbox,current_bbox)) { + key = SELECTION_PAGE; + } - break; - } + break; + } default: - break; + break; } } // std::cout << std::endl; @@ -1579,7 +1583,7 @@ void Export::areaYChange (Gtk::Adjustment *adj) height = SP_EXPORT_MIN_SIZE; //key = (const gchar *)g_object_get_data(G_OBJECT (adj), "key"); if (adj == y1_adj) { - //if (!strcmp (key, "y0")) { + //if (!strcmp (key, "y0")) { y1 = y0 + height * DPI_BASE / ydpi; setValuePx(y1_adj, y1); } else { diff --git a/src/ui/dialog/export.h b/src/ui/dialog/export.h index 79e597414..6f3c0dfac 100644 --- a/src/ui/dialog/export.h +++ b/src/ui/dialog/export.h @@ -56,7 +56,9 @@ public: Export (); ~Export (); - static Export &getInstance() { return *new Export(); } + static Export &getInstance() { + return *new Export(); + } private: @@ -97,7 +99,7 @@ private: float getValue (Gtk::Adjustment *adj); float getValuePx (Gtk::Adjustment *adj); #endif - + /** * Helper function to create, style and pack spinbuttons for the export dialog. * @@ -121,20 +123,20 @@ private: */ #if WITH_GTKMM_3_0 Glib::RefPtr<Gtk::Adjustment> createSpinbutton( gchar const *key, float val, float min, float max, - float step, float page, - Gtk::Grid *t, int x, int y, - const Glib::ustring ll, const Glib::ustring lr, - int digits, unsigned int sensitive, - void (Export::*cb)() ); + float step, float page, + Gtk::Grid *t, int x, int y, + const Glib::ustring& ll, const Glib::ustring& lr, + int digits, unsigned int sensitive, + void (Export::*cb)() ); #else Gtk::Adjustment * createSpinbutton( gchar const *key, float val, float min, float max, - float step, float page, - Gtk::Table *t, int x, int y, - const Glib::ustring ll, const Glib::ustring lr, - int digits, unsigned int sensitive, - void (Export::*cb)() ); + float step, float page, + Gtk::Table *t, int x, int y, + const Glib::ustring& ll, const Glib::ustring& lr, + int digits, unsigned int sensitive, + void (Export::*cb)() ); #endif - + /** * One of the area select radio buttons was pressed */ @@ -153,8 +155,12 @@ private: /** * Area X value changed callback */ - void onAreaX0Change() {areaXChange(x0_adj);} ; - void onAreaX1Change() {areaXChange(x1_adj);} ; + void onAreaX0Change() { + areaXChange(x0_adj); + } ; + void onAreaX1Change() { + areaXChange(x1_adj); + } ; #if WITH_GTKMM_3_0 void areaXChange(Glib::RefPtr<Gtk::Adjustment>& adj); #else @@ -164,8 +170,12 @@ private: /** * Area Y value changed callback */ - void onAreaY0Change() {areaYChange(y0_adj);} ; - void onAreaY1Change() {areaYChange(y1_adj);} ; + void onAreaY0Change() { + areaYChange(y0_adj); + } ; + void onAreaY1Change() { + areaYChange(y1_adj); + } ; #if WITH_GTKMM_3_0 void areaYChange(Glib::RefPtr<Gtk::Adjustment>& adj); #else @@ -235,14 +245,14 @@ private: /** * Creates progress dialog for batch exporting. - * + * * @param progress_text Text to be shown in the progress bar */ Gtk::Dialog * create_progress_dialog (Glib::ustring progress_text); /** * Callback to be used in for loop to update the progress bar. - * + * * @param value number between 0 and 1 indicating the fraction of progress (0.17 = 17 % progress) * @param dlg void pointer to the Gtk::Dialog progress dialog */ diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp index 62a2f8572..8e0d085a4 100644 --- a/src/ui/dialog/symbols.cpp +++ b/src/ui/dialog/symbols.cpp @@ -39,7 +39,7 @@ #include <gtkmm/treemodelcolumn.h> #include <gtkmm/clipboard.h> #include <glibmm/stringutils.h> - +#include <glibmm/markup.h> #include <glibmm/i18n.h> #include "path-prefix.h" #include "io/sys.h" @@ -687,7 +687,7 @@ void SymbolsDialog::add_symbol( SPObject* symbol ) { if( pixbuf ) { Gtk::ListStore::iterator row = store->append(); (*row)[columns->symbol_id] = Glib::ustring( id ); - (*row)[columns->symbol_title] = Glib::ustring( g_dpgettext2(NULL, "Symbol", title) ); + (*row)[columns->symbol_title] = Glib::Markup::escape_text(Glib::ustring( g_dpgettext2(NULL, "Symbol", title) )); (*row)[columns->symbol_image] = pixbuf; } diff --git a/src/ui/dialog/undo-history.cpp b/src/ui/dialog/undo-history.cpp index a487eb930..2412c3ec9 100644 --- a/src/ui/dialog/undo-history.cpp +++ b/src/ui/dialog/undo-history.cpp @@ -5,8 +5,9 @@ /* Author: * Gustav Broberg <broberg@kth.se> * Abhishek Sharma + * Jon A. Cruz <jon@joncruz.org> * - * Copyright (C) 2006 Authors + * Copyright (C) 2014 Authors * Released under GNU GPL. Read the file 'COPYING' for more information. */ @@ -24,6 +25,7 @@ #include "inkscape.h" #include "verbs.h" #include "desktop-handles.h" +#include "util/signal-blocker.h" #include "desktop.h" #include <gtkmm/invisible.h> @@ -131,39 +133,19 @@ UndoHistory& UndoHistory::getInstance() return *new UndoHistory(); } -void -UndoHistory::setDesktop(SPDesktop* desktop) -{ - Panel::setDesktop(desktop); - - if (!desktop) return; - - _document = sp_desktop_document(desktop); - - _event_log = desktop->event_log; - - _callback_connections[EventLog::CALLB_SELECTION_CHANGE].block(); - - _event_list_store = _event_log->getEventListStore(); - _event_list_view.set_model(_event_list_store); - _event_list_selection = _event_list_view.get_selection(); - - _event_log->connectWithDialog(&_event_list_view, &_callback_connections); - _event_list_view.scroll_to_row(_event_list_store->get_path(_event_list_selection->get_selected())); - - _callback_connections[EventLog::CALLB_SELECTION_CHANGE].block(false); -} - UndoHistory::UndoHistory() : UI::Widget::Panel ("", "/dialogs/undo-history", SP_VERB_DIALOG_UNDO_HISTORY), - _document (sp_desktop_document(getDesktop())), - _event_log (getDesktop() ? getDesktop()->event_log : NULL), - _columns (_event_log ? &_event_log->getColumns() : NULL), - _event_list_selection (_event_list_view.get_selection()), - _desktop(NULL), + _document_replaced_connection(), + _desktop(getDesktop()), + _document(_desktop ? _desktop->doc() : NULL), + _event_log(_desktop ? _desktop->event_log : NULL), + _columns(_event_log ? &_event_log->getColumns() : NULL), + _scrolled_window(), + _event_list_store(), + _event_list_selection(_event_list_view.get_selection()), _deskTrack(), - _desktopChangeConn() - + _desktopChangeConn(), + _callback_connections() { if ( !_document || !_event_log || !_columns ) return; @@ -172,9 +154,9 @@ UndoHistory::UndoHistory() _getContents()->pack_start(_scrolled_window); _scrolled_window.set_policy(Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC); - _event_list_store = _event_log->getEventListStore(); + // connect with the EventLog + _connectEventLog(); - _event_list_view.set_model(_event_list_store); _event_list_view.set_rules_hint(false); _event_list_view.set_enable_search(false); _event_list_view.set_headers_visible(false); @@ -221,12 +203,12 @@ UndoHistory::UndoHistory() _callback_connections[EventLog::CALLB_COLLAPSE] = _event_list_view.signal_row_collapsed().connect(sigc::mem_fun(*this, &Inkscape::UI::Dialog::UndoHistory::_onCollapseEvent)); - // connect with the EventLog - _event_log->connectWithDialog(&_event_list_view, &_callback_connections); - _desktopChangeConn = _deskTrack.connectDesktopChanged( sigc::mem_fun(*this, &UndoHistory::setDesktop) ); _deskTrack.connect(GTK_WIDGET(gobj())); + // connect to be informed of document changes + signalDocumentReplaced().connect(sigc::mem_fun(*this, &UndoHistory::_handleDocumentReplaced)); + show_all_children(); // scroll to the selected row @@ -239,6 +221,82 @@ UndoHistory::~UndoHistory() } +void UndoHistory::setDesktop(SPDesktop* desktop) +{ + Panel::setDesktop(desktop); + + EventLog *newEventLog = desktop ? desktop->event_log : NULL; + if ((_desktop == desktop) && (_event_log == newEventLog)) { + // same desktop set + } + else + { + _connectDocument(desktop, desktop ? desktop->doc() : NULL); + } +} + +void UndoHistory::_connectDocument(SPDesktop* desktop, SPDocument *document) +{ + // disconnect from prior + if (_event_log) { + _event_log->removeDialogConnection(&_event_list_view, &_callback_connections); + } + + SignalBlocker blocker(&_callback_connections[EventLog::CALLB_SELECTION_CHANGE]); + + _event_list_view.unset_model(); + + // connect to new EventLog/Desktop + _desktop = desktop; + _event_log = desktop ? desktop->event_log : NULL; + _document = desktop ? desktop->doc() : NULL; + _connectEventLog(); +} + +void UndoHistory::_connectEventLog() +{ + if (_event_log) { + _event_log->add_destroy_notify_callback(this, &_handleEventLogDestroyCB); + _event_list_store = _event_log->getEventListStore(); + + _event_list_view.set_model(_event_list_store); + + _event_log->addDialogConnection(&_event_list_view, &_callback_connections); + _event_list_view.scroll_to_row(_event_list_store->get_path(_event_list_selection->get_selected())); + } +} + +void UndoHistory::_handleDocumentReplaced(SPDesktop* desktop, SPDocument *document) +{ + if ((desktop != _desktop) || (document != _document)) { + _connectDocument(desktop, document); + } +} + +void *UndoHistory::_handleEventLogDestroyCB(void *data) +{ + void *result = NULL; + if (data) { + UndoHistory *self = reinterpret_cast<UndoHistory*>(data); + result = self->_handleEventLogDestroy(); + } + return result; +} + +// called *after* _event_log has been destroyed. +void *UndoHistory::_handleEventLogDestroy() +{ + if (_event_log) { + SignalBlocker blocker(&_callback_connections[EventLog::CALLB_SELECTION_CHANGE]); + + _event_list_view.unset_model(); + _event_list_store.reset(); + _event_log = NULL; + } + + return NULL; +} + void UndoHistory::_onListSelectionChange() { diff --git a/src/ui/dialog/undo-history.h b/src/ui/dialog/undo-history.h index adf4f1936..b0cc283cf 100644 --- a/src/ui/dialog/undo-history.h +++ b/src/ui/dialog/undo-history.h @@ -3,8 +3,9 @@ */ /* Author: * Gustav Broberg <broberg@kth.se> + * Jon A. Cruz <jon@joncruz.org> * - * Copyright (C) 2006 Authors + * Copyright (C) 2014 Authors * Released under GNU GPL. Read the file 'COPYING' for more information. */ @@ -134,6 +135,7 @@ public: protected: + SPDesktop *_desktop; SPDocument *_document; EventLog *_event_log; @@ -146,12 +148,17 @@ protected: Gtk::TreeView _event_list_view; Glib::RefPtr<Gtk::TreeSelection> _event_list_selection; - SPDesktop *_desktop; DesktopTracker _deskTrack; sigc::connection _desktopChangeConn; EventLog::CallbackMap _callback_connections; + static void *_handleEventLogDestroyCB(void *data); + + void _connectDocument(SPDesktop* desktop, SPDocument *document); + void _connectEventLog(); + void _handleDocumentReplaced(SPDesktop* desktop, SPDocument *document); + void *_handleEventLogDestroy(); void _onListSelectionChange(); void _onExpandEvent(const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::Path &path); void _onCollapseEvent(const Gtk::TreeModel::iterator &iter, const Gtk::TreeModel::Path &path); diff --git a/src/ui/tools/text-tool.cpp b/src/ui/tools/text-tool.cpp index 4a171d1bd..ac830fe6b 100644 --- a/src/ui/tools/text-tool.cpp +++ b/src/ui/tools/text-tool.cpp @@ -61,11 +61,6 @@ namespace Inkscape { namespace UI { namespace Tools { -static void sp_text_context_selection_changed(Inkscape::Selection *selection, TextTool *tc); -static void sp_text_context_selection_modified(Inkscape::Selection *selection, guint flags, TextTool *tc); -static bool sp_text_context_style_set(SPCSSAttr const *css, TextTool *tc); -static int sp_text_context_style_query(SPStyle *style, int property, TextTool *tc); - static void sp_text_context_validate_cursor_iterators(TextTool *tc); static void sp_text_context_update_cursor(TextTool *tc, bool scroll_to_see = true); static void sp_text_context_update_text_selection(TextTool *tc); @@ -77,15 +72,15 @@ static gint sptc_focus_out(GtkWidget *widget, GdkEventFocus *event, TextTool *tc static void sptc_commit(GtkIMContext *imc, gchar *string, TextTool *tc); namespace { - ToolBase* createTextContext() { - return new TextTool(); - } + ToolBase* createTextContext() { + return new TextTool(); + } - bool textContextRegistered = ToolFactory::instance().registerObject("/tools/text", createTextContext); + bool textContextRegistered = ToolFactory::instance().registerObject("/tools/text", createTextContext); } const std::string& TextTool::getPrefsPath() { - return TextTool::prefsPath; + return TextTool::prefsPath; } const std::string TextTool::prefsPath = "/tools/text"; @@ -165,7 +160,7 @@ void TextTool::setup() { */ gtk_im_context_set_use_preedit(this->imc, FALSE); gtk_im_context_set_client_window(this->imc, - gtk_widget_get_window (canvas)); + gtk_widget_get_window (canvas)); g_signal_connect(G_OBJECT(canvas), "focus_in_event", G_CALLBACK(sptc_focus_in), this); g_signal_connect(G_OBJECT(canvas), "focus_out_event", G_CALLBACK(sptc_focus_out), this); @@ -185,20 +180,20 @@ void TextTool::setup() { this->shape_editor->set_item(item, SH_KNOTHOLDER); } - this->sel_changed_connection = sp_desktop_selection(desktop)->connectChanged( - sigc::bind(sigc::ptr_fun(&sp_text_context_selection_changed), this) - ); - this->sel_modified_connection = sp_desktop_selection(desktop)->connectModified( - sigc::bind(sigc::ptr_fun(&sp_text_context_selection_modified), this) - ); + this->sel_changed_connection = sp_desktop_selection(desktop)->connectChangedFirst( + sigc::mem_fun(*this, &TextTool::_selectionChanged) + ); + this->sel_modified_connection = sp_desktop_selection(desktop)->connectModifiedFirst( + sigc::mem_fun(*this, &TextTool::_selectionModified) + ); this->style_set_connection = desktop->connectSetStyle( - sigc::bind(sigc::ptr_fun(&sp_text_context_style_set), this) - ); + sigc::mem_fun(*this, &TextTool::_styleSet) + ); this->style_query_connection = desktop->connectQueryStyle( - sigc::bind(sigc::ptr_fun(&sp_text_context_style_query), this) - ); + sigc::mem_fun(*this, &TextTool::_styleQueried) + ); - sp_text_context_selection_changed(sp_desktop_selection(desktop), this); + _selectionChanged(sp_desktop_selection(desktop)); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); if (prefs->getBool("/tools/text/selcue")) { @@ -396,7 +391,7 @@ bool TextTool::item_handler(SPItem* item, GdkEvent* event) { } if (!ret) { - ret = ToolBase::item_handler(item, event); + ret = ToolBase::item_handler(item, event); } return ret; @@ -437,7 +432,7 @@ static void sp_text_context_setup_text(TextTool *tc) text_item->updateRepr(); text_item->doWriteTransform(text_item->getRepr(), text_item->transform, NULL, true); DocumentUndo::done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, - _("Create text")); + _("Create text")); } /** @@ -477,7 +472,7 @@ static void insert_uni_char(TextTool *const tc) sp_text_context_update_cursor(tc); sp_text_context_update_text_selection(tc); DocumentUndo::done(sp_desktop_document(tc->desktop), SP_VERB_DIALOG_TRANSFORM, - _("Insert Unicode character")); + _("Insert Unicode character")); } } @@ -667,8 +662,7 @@ bool TextTool::root_handler(GdkEvent* event) { sp_desktop_apply_style_tool(desktop, ft->getRepr(), "/tools/text", true); sp_desktop_selection(desktop)->set(ft); desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Flowed text is created.")); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, - _("Create flowed text")); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Create flowed text")); } else { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The frame is <b>too small</b> for the current font size. Flowed text not created.")); } @@ -807,8 +801,7 @@ bool TextTool::root_handler(GdkEvent* event) { sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("No-break space")); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, - _("Insert no-break space")); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Insert no-break space")); return TRUE; } break; @@ -844,8 +837,7 @@ bool TextTool::root_handler(GdkEvent* event) { sp_repr_css_set_property(css, "font-weight", "normal"); sp_te_apply_style(this->text, this->text_sel_start, this->text_sel_end, css); sp_repr_css_attr_unref(css); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, - _("Make bold")); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Make bold")); sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); return TRUE; @@ -862,8 +854,7 @@ bool TextTool::root_handler(GdkEvent* event) { sp_repr_css_set_property(css, "font-style", "italic"); sp_te_apply_style(this->text, this->text_sel_start, this->text_sel_end, css); sp_repr_css_attr_unref(css); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, - _("Make italic")); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Make italic")); sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); return TRUE; @@ -901,8 +892,7 @@ bool TextTool::root_handler(GdkEvent* event) { sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, - _("New line")); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("New line")); return TRUE; } case GDK_KEY_BackSpace: @@ -943,8 +933,7 @@ bool TextTool::root_handler(GdkEvent* event) { sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, - _("Backspace")); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Backspace")); } return TRUE; case GDK_KEY_Delete: @@ -982,8 +971,7 @@ bool TextTool::root_handler(GdkEvent* event) { sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); - DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, - _("Delete")); + DocumentUndo::done(sp_desktop_document(desktop), SP_VERB_CONTEXT_TEXT, _("Delete")); } return TRUE; case GDK_KEY_Left: @@ -999,8 +987,7 @@ bool TextTool::root_handler(GdkEvent* event) { sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(mul*-1, 0)); sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); - DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:left", SP_VERB_CONTEXT_TEXT, - _("Kern to the left")); + DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:left", SP_VERB_CONTEXT_TEXT, _("Kern to the left")); } else { if (MOD__CTRL(event)) this->text_sel_end.cursorLeftWithControl(); @@ -1024,8 +1011,7 @@ bool TextTool::root_handler(GdkEvent* event) { sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(mul*1, 0)); sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); - DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:right", SP_VERB_CONTEXT_TEXT, - _("Kern to the right")); + DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:right", SP_VERB_CONTEXT_TEXT, _("Kern to the right")); } else { if (MOD__CTRL(event)) this->text_sel_end.cursorRightWithControl(); @@ -1049,8 +1035,7 @@ bool TextTool::root_handler(GdkEvent* event) { sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(0, mul*-1)); sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); - DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:up", SP_VERB_CONTEXT_TEXT, - _("Kern up")); + DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:up", SP_VERB_CONTEXT_TEXT, _("Kern up")); } else { if (MOD__CTRL(event)) this->text_sel_end.cursorUpWithControl(); @@ -1074,8 +1059,7 @@ bool TextTool::root_handler(GdkEvent* event) { sp_te_adjust_kerning_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, Geom::Point(0, mul*1)); sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); - DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:down", SP_VERB_CONTEXT_TEXT, - _("Kern down")); + DocumentUndo::maybeDone(sp_desktop_document(desktop), "kern:down", SP_VERB_CONTEXT_TEXT, _("Kern down")); } else { if (MOD__CTRL(event)) this->text_sel_end.cursorDownWithControl(); @@ -1150,8 +1134,7 @@ bool TextTool::root_handler(GdkEvent* event) { } else { sp_te_adjust_rotation(this->text, this->text_sel_start, this->text_sel_end, desktop, -90); } - DocumentUndo::maybeDone(sp_desktop_document(desktop), "textrot:ccw", SP_VERB_CONTEXT_TEXT, - _("Rotate counterclockwise")); + DocumentUndo::maybeDone(sp_desktop_document(desktop), "textrot:ccw", SP_VERB_CONTEXT_TEXT, _("Rotate counterclockwise")); sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); return TRUE; @@ -1171,8 +1154,7 @@ bool TextTool::root_handler(GdkEvent* event) { } else { sp_te_adjust_rotation(this->text, this->text_sel_start, this->text_sel_end, desktop, 90); } - DocumentUndo::maybeDone(sp_desktop_document(desktop), "textrot:cw", SP_VERB_CONTEXT_TEXT, - _("Rotate clockwise")); + DocumentUndo::maybeDone(sp_desktop_document(desktop), "textrot:cw", SP_VERB_CONTEXT_TEXT, _("Rotate clockwise")); sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); return TRUE; @@ -1188,15 +1170,13 @@ bool TextTool::root_handler(GdkEvent* event) { sp_te_adjust_linespacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, -10); else sp_te_adjust_linespacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, -1); - DocumentUndo::maybeDone(sp_desktop_document(desktop), "linespacing:dec", SP_VERB_CONTEXT_TEXT, - _("Contract line spacing")); + DocumentUndo::maybeDone(sp_desktop_document(desktop), "linespacing:dec", SP_VERB_CONTEXT_TEXT, _("Contract line spacing")); } else { if (MOD__SHIFT(event)) sp_te_adjust_tspan_letterspacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, -10); else sp_te_adjust_tspan_letterspacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, -1); - DocumentUndo::maybeDone(sp_desktop_document(desktop), "letterspacing:dec", SP_VERB_CONTEXT_TEXT, - _("Contract letter spacing")); + DocumentUndo::maybeDone(sp_desktop_document(desktop), "letterspacing:dec", SP_VERB_CONTEXT_TEXT, _("Contract letter spacing")); } sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); @@ -1213,15 +1193,13 @@ bool TextTool::root_handler(GdkEvent* event) { sp_te_adjust_linespacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, 10); else sp_te_adjust_linespacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, 1); - DocumentUndo::maybeDone(sp_desktop_document(desktop), "linespacing:inc", SP_VERB_CONTEXT_TEXT, - _("Expand line spacing")); + DocumentUndo::maybeDone(sp_desktop_document(desktop), "linespacing:inc", SP_VERB_CONTEXT_TEXT, _("Expand line spacing")); } else { if (MOD__SHIFT(event)) sp_te_adjust_tspan_letterspacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, 10); else sp_te_adjust_tspan_letterspacing_screen(this->text, this->text_sel_start, this->text_sel_end, desktop, 1); - DocumentUndo::maybeDone(sp_desktop_document(desktop), "letterspacing:inc", SP_VERB_CONTEXT_TEXT, - _("Expand letter spacing"));\ + DocumentUndo::maybeDone(sp_desktop_document(desktop), "letterspacing:inc", SP_VERB_CONTEXT_TEXT, _("Expand letter spacing"));\ } sp_text_context_update_cursor(this); sp_text_context_update_text_selection(this); @@ -1305,32 +1283,32 @@ bool sp_text_paste_inline(ToolBase *ec) Glib::ustring const clip_text = refClipboard->wait_for_text(); if (!clip_text.empty()) { - // Fix for 244940 - // The XML standard defines the following as valid characters - // (Extensible Markup Language (XML) 1.0 (Fourth Edition) paragraph 2.2) - // char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] - // Since what comes in off the paste buffer will go right into XML, clean - // the text here. - Glib::ustring text(clip_text); - Glib::ustring::iterator itr = text.begin(); - gunichar paste_string_uchar; - - while(itr != text.end()) - { - paste_string_uchar = *itr; - - // Make sure we don't have a control character. We should really check - // for the whole range above... Add the rest of the invalid cases from - // above if we find additional issues - if(paste_string_uchar >= 0x00000020 || - paste_string_uchar == 0x00000009 || - paste_string_uchar == 0x0000000A || - paste_string_uchar == 0x0000000D) { - ++itr; - } else { - itr = text.erase(itr); - } - } + // Fix for 244940 + // The XML standard defines the following as valid characters + // (Extensible Markup Language (XML) 1.0 (Fourth Edition) paragraph 2.2) + // char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + // Since what comes in off the paste buffer will go right into XML, clean + // the text here. + Glib::ustring text(clip_text); + Glib::ustring::iterator itr = text.begin(); + gunichar paste_string_uchar; + + while(itr != text.end()) + { + paste_string_uchar = *itr; + + // Make sure we don't have a control character. We should really check + // for the whole range above... Add the rest of the invalid cases from + // above if we find additional issues + if(paste_string_uchar >= 0x00000020 || + paste_string_uchar == 0x00000009 || + paste_string_uchar == 0x0000000A || + paste_string_uchar == 0x0000000D) { + ++itr; + } else { + itr = text.erase(itr); + } + } if (!tc->text) { // create text if none (i.e. if nascent_object) sp_text_context_setup_text(tc); @@ -1351,7 +1329,7 @@ bool sp_text_paste_inline(ToolBase *ec) begin = end + 1; } DocumentUndo::done(sp_desktop_document(ec->desktop), SP_VERB_CONTEXT_TEXT, - _("Paste text")); + _("Paste text")); return true; } @@ -1427,12 +1405,11 @@ bool sp_text_delete_selection(ToolBase *ec) /** * \param selection Should not be NULL. */ -static void -sp_text_context_selection_changed(Inkscape::Selection *selection, TextTool *tc) +void TextTool::_selectionChanged(Inkscape::Selection *selection) { g_assert(selection != NULL); - ToolBase *ec = SP_EVENT_CONTEXT(tc); + ToolBase *ec = SP_EVENT_CONTEXT(this); ec->shape_editor->unset_item(SH_KNOTHOLDER); SPItem *item = selection->singleItem(); @@ -1440,70 +1417,68 @@ sp_text_context_selection_changed(Inkscape::Selection *selection, TextTool *tc) ec->shape_editor->set_item(item, SH_KNOTHOLDER); } - if (tc->text && (item != tc->text)) { - sp_text_context_forget_text(tc); + if (this->text && (item != this->text)) { + sp_text_context_forget_text(this); } - tc->text = NULL; + this->text = NULL; if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { - tc->text = item; - Inkscape::Text::Layout const *layout = te_get_layout(tc->text); + this->text = item; + Inkscape::Text::Layout const *layout = te_get_layout(this->text); if (layout) - tc->text_sel_start = tc->text_sel_end = layout->end(); + this->text_sel_start = this->text_sel_end = layout->end(); } else { - tc->text = NULL; + this->text = NULL; } // we update cursor without scrolling, because this position may not be final; // item_handler moves cusros to the point of click immediately - sp_text_context_update_cursor(tc, false); - sp_text_context_update_text_selection(tc); + sp_text_context_update_cursor(this, false); + sp_text_context_update_text_selection(this); } -static void -sp_text_context_selection_modified(Inkscape::Selection */*selection*/, guint /*flags*/, TextTool *tc) +void TextTool::_selectionModified(Inkscape::Selection */*selection*/, guint /*flags*/) { - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); } -static bool sp_text_context_style_set(SPCSSAttr const *css, TextTool *tc) +bool TextTool::_styleSet(SPCSSAttr const *css) { - if (tc->text == NULL) + if (this->text == NULL) return false; - if (tc->text_sel_start == tc->text_sel_end) + if (this->text_sel_start == this->text_sel_end) return false; // will get picked up by the parent and applied to the whole text object - sp_te_apply_style(tc->text, tc->text_sel_start, tc->text_sel_end, css); - DocumentUndo::done(sp_desktop_document(tc->desktop), SP_VERB_CONTEXT_TEXT, - _("Set text style")); - sp_text_context_update_cursor(tc); - sp_text_context_update_text_selection(tc); + sp_te_apply_style(this->text, this->text_sel_start, this->text_sel_end, css); + DocumentUndo::done(sp_desktop_document(this->desktop), SP_VERB_CONTEXT_TEXT, + _("Set text style")); + sp_text_context_update_cursor(this); + sp_text_context_update_text_selection(this); return true; } -static int -sp_text_context_style_query(SPStyle *style, int property, TextTool *tc) +int TextTool::_styleQueried(SPStyle *style, int property) { - if (tc->text == NULL) { + if (this->text == NULL) { return QUERY_STYLE_NOTHING; } - const Inkscape::Text::Layout *layout = te_get_layout(tc->text); + const Inkscape::Text::Layout *layout = te_get_layout(this->text); if (layout == NULL) { return QUERY_STYLE_NOTHING; } - sp_text_context_validate_cursor_iterators(tc); + sp_text_context_validate_cursor_iterators(this); GSList *styles_list = NULL; Inkscape::Text::Layout::iterator begin_it, end_it; - if (tc->text_sel_start < tc->text_sel_end) { - begin_it = tc->text_sel_start; - end_it = tc->text_sel_end; + if (this->text_sel_start < this->text_sel_end) { + begin_it = this->text_sel_start; + end_it = this->text_sel_end; } else { - begin_it = tc->text_sel_end; - end_it = tc->text_sel_start; + begin_it = this->text_sel_end; + end_it = this->text_sel_start; } if (begin_it == end_it) { if (!begin_it.prevCharacter()) { @@ -1717,7 +1692,7 @@ static void sptc_commit(GtkIMContext */*imc*/, gchar *string, TextTool *tc) sp_text_context_update_text_selection(tc); DocumentUndo::done(tc->text->document, SP_VERB_CONTEXT_TEXT, - _("Type text")); + _("Type text")); } void sp_text_context_place_cursor (TextTool *tc, SPObject *text, Inkscape::Text::Layout::iterator where) diff --git a/src/ui/tools/text-tool.h b/src/ui/tools/text-tool.h index c5336d378..ca2b3d19a 100644 --- a/src/ui/tools/text-tool.h +++ b/src/ui/tools/text-tool.h @@ -84,6 +84,12 @@ public: virtual bool item_handler(SPItem* item, GdkEvent* event); virtual const std::string& getPrefsPath(); + +private: + void _selectionChanged(Inkscape::Selection *selection); + void _selectionModified(Inkscape::Selection *selection, guint flags); + bool _styleSet(SPCSSAttr const *css); + int _styleQueried(SPStyle *style, int property); }; bool sp_text_paste_inline(ToolBase *ec); diff --git a/src/ui/tools/tool-base.h b/src/ui/tools/tool-base.h index 3a536fc2c..eb8908f3e 100644 --- a/src/ui/tools/tool-base.h +++ b/src/ui/tools/tool-base.h @@ -14,6 +14,7 @@ #include <glib-object.h> #include <gdk/gdk.h> +#include <sigc++/trackable.h> #include "knot.h" #include "2geom/forward.h" @@ -104,7 +105,9 @@ void sp_event_context_snap_delay_handler(ToolBase *ec, gpointer const dse_item, * plus few abstract base classes. Writing a new tool involves * subclassing ToolBase. */ -class ToolBase { +class ToolBase + : public sigc::trackable +{ public: void enableSelectionCue (bool enable=true); void enableGrDrag (bool enable=true); diff --git a/src/util/signal-blocker.h b/src/util/signal-blocker.h new file mode 100644 index 000000000..06d9736f2 --- /dev/null +++ b/src/util/signal-blocker.h @@ -0,0 +1,70 @@ +/* + * Base RAII blocker for sgic++ signals. + * + * Authors: + * Jon A. Cruz <jon@joncruz.org> + * + * Copyright (C) 2014 Authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_INKSCAPE_UTIL_SIGNAL_BLOCKER_H +#define SEEN_INKSCAPE_UTIL_SIGNAL_BLOCKER_H + +#include <string> +#include <sigc++/connection.h> + +/** + * Base RAII blocker for sgic++ signals. + */ +class SignalBlocker +{ +public: + /** + * Creates a new instance that if the signal is currently unblocked will block + * it until this instance is destructed and then will unblock it. + */ + SignalBlocker( sigc::connection *connection ) : + _connection(connection), + _wasBlocked(_connection->blocked()) + { + if (!_wasBlocked) + { + _connection->block(); + } + } + + /** + * Destructor that will unblock the signal if it was blocked initially by this + * instance. + */ + ~SignalBlocker() + { + if (!_wasBlocked) + { + _connection->block(false); + } + } + +private: + // noncopyable, nonassignable + SignalBlocker(SignalBlocker const &other); + SignalBlocker& operator=(SignalBlocker const &other); + + sigc::connection *_connection; + bool _wasBlocked; +}; + +#endif // SEEN_INKSCAPE_UTIL_SIGNAL_BLOCKER_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 26e5ce531..d0e3a966c 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -2478,7 +2478,7 @@ Verb *Verb::_base_verbs[] = { new EditVerb(SP_VERB_EDIT_DESELECT, "EditDeselect", N_("D_eselect"), N_("Deselect any selected objects or nodes"), INKSCAPE_ICON("edit-select-none")), new EditVerb(SP_VERB_EDIT_DELETE_ALL_GUIDES, "EditRemoveAllGuides", N_("Delete All Guides"), - N_("Create four guides aligned with the page borders"), NULL), + N_("Delete all the guides in the document"), NULL), new EditVerb(SP_VERB_EDIT_GUIDES_AROUND_PAGE, "EditGuidesAroundPage", N_("Create _Guides Around the Page"), N_("Create four guides aligned with the page borders"), NULL), new EditVerb(SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER, "EditNextPathEffectParameter", N_("Next path effect parameter"), @@ -2615,11 +2615,11 @@ Verb *Verb::_base_verbs[] = { N_("Toggle visibility of current layer"), NULL), // Object - new ObjectVerb(SP_VERB_OBJECT_ROTATE_90_CW, "ObjectRotate90", N_("Rotate _90° CW"), + new ObjectVerb(SP_VERB_OBJECT_ROTATE_90_CW, "ObjectRotate90", N_("Rotate _90\xc2\xb0 CW"), // This is shared between tooltips and statusbar, so they // must use UTF-8, not HTML entities for special characters. N_("Rotate selection 90\xc2\xb0 clockwise"), INKSCAPE_ICON("object-rotate-right")), - new ObjectVerb(SP_VERB_OBJECT_ROTATE_90_CCW, "ObjectRotate90CCW", N_("Rotate 9_0° CCW"), + new ObjectVerb(SP_VERB_OBJECT_ROTATE_90_CCW, "ObjectRotate90CCW", N_("Rotate 9_0\xc2\xb0 CCW"), // This is shared between tooltips and statusbar, so they // must use UTF-8, not HTML entities for special characters. N_("Rotate selection 90\xc2\xb0 counter-clockwise"), INKSCAPE_ICON("object-rotate-left")), |
