From 7d0612fd5d4791988e0c0e05a2cbf1fba84fd655 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Tue, 7 Feb 2017 00:25:47 +0100 Subject: This commit fixes bug #1657874 Title Missing handles after reset of rotation center Whats the bug: In a previous commit I do, I change a event on knots from onmove to onmousedown. this seems ok but the problem were if the user click on rotation center without moving it, the onrelease event has a variable move not set and hide the current knots making the needs to switch the tools to reshow. Is in particular a big problem on little elements where the center knot have a big influence and is very easy to click on it on select. Why do this commit that broke: I want have onmousedown fired to allow meshgradient triangle knots updated on mouse down. What fixes: INstras change the place of the signal, I send back to the original position and create a new signal to fire onmousedow a knot. In the gradient code I change the previous calls from undrag to onmousedown. Fixed bugs: - https://launchpad.net/bugs/1657874 (bzr r15486) --- src/gradient-drag.cpp | 6 +++--- src/gradient-drag.h | 2 +- src/knot.cpp | 4 ++-- src/knot.h | 1 + 4 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp index a928cac0d..006e2f790 100644 --- a/src/gradient-drag.cpp +++ b/src/gradient-drag.cpp @@ -1067,7 +1067,7 @@ static void gr_knot_moved_midpoint_handler(SPKnot */*knot*/, Geom::Point const & -static void gr_knot_grabbed_handler(SPKnot */*knot*/, unsigned int /*state*/, gpointer data) +static void gr_knot_mousedown_handler(SPKnot */*knot*/, unsigned int /*state*/, gpointer data) { GrDragger *dragger = (GrDragger *) data; GrDrag *drag = dragger->parent; @@ -1688,7 +1688,7 @@ GrDragger::GrDragger(GrDrag *parent, Geom::Point p, GrDraggable *draggable) this->sizeUpdatedConn = ControlManager::getManager().connectCtrlSizeChanged(sigc::mem_fun(*this, &GrDragger::updateControlSizes)); this->_clicked_connection = this->knot->click_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_clicked_handler), this)); this->_doubleclicked_connection = this->knot->doubleclicked_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_doubleclicked_handler), this)); - this->_grabbed_connection = this->knot->grabbed_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_grabbed_handler), this)); + this->_mousedown_connection = this->knot->mousedown_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_mousedown_handler), this)); this->_ungrabbed_connection = this->knot->ungrabbed_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_ungrabbed_handler), this)); // add the initial draggable @@ -1712,7 +1712,7 @@ GrDragger::~GrDragger() this->_moved_connection.disconnect(); this->_clicked_connection.disconnect(); this->_doubleclicked_connection.disconnect(); - this->_grabbed_connection.disconnect(); + this->_mousedown_connection.disconnect(); this->_ungrabbed_connection.disconnect(); /* unref should call destroy */ diff --git a/src/gradient-drag.h b/src/gradient-drag.h index b4a64c78d..1fe2fb3f0 100644 --- a/src/gradient-drag.h +++ b/src/gradient-drag.h @@ -130,7 +130,7 @@ private: sigc::connection _moved_connection; sigc::connection _clicked_connection; sigc::connection _doubleclicked_connection; - sigc::connection _grabbed_connection; + sigc::connection _mousedown_connection; sigc::connection _ungrabbed_connection; }; diff --git a/src/knot.cpp b/src/knot.cpp index c04206dee..50fa73391 100644 --- a/src/knot.cpp +++ b/src/knot.cpp @@ -214,7 +214,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot if ((event->button.button == 1) && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) { Geom::Point const p = knot->desktop->w2d(Geom::Point(event->button.x, event->button.y)); knot->startDragging(p, (gint) event->button.x, (gint) event->button.y, event->button.time); - knot->grabbed_signal.emit(knot, event->button.state); + knot->mousedown_signal.emit(knot, event->button.state); consumed = TRUE; } break; @@ -241,7 +241,6 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot if (moved) { knot->setFlag(SP_KNOT_DRAGGING, FALSE); - knot->ungrabbed_signal.emit(knot, event->button.state); } else { knot->click_signal.emit(knot, event->button.state); @@ -277,6 +276,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot if (!moved) { knot->setFlag(SP_KNOT_DRAGGING, TRUE); + knot->grabbed_signal.emit(knot, event->button.state); } sp_event_context_snap_delay_handler(knot->desktop->event_context, NULL, knot, (GdkEventMotion *)event, Inkscape::UI::Tools::DelayedSnapEvent::KNOT_HANDLER); diff --git a/src/knot.h b/src/knot.h index 954ddd8a6..0a0ce73d2 100644 --- a/src/knot.h +++ b/src/knot.h @@ -79,6 +79,7 @@ public: // be able to figure that out sigc::signal click_signal; sigc::signal doubleclicked_signal; + sigc::signal mousedown_signal; sigc::signal grabbed_signal; sigc::signal ungrabbed_signal; sigc::signal moved_signal; -- cgit v1.2.3 From 3d6f208ab09975bbdef8e20e660227f5fbcf3a51 Mon Sep 17 00:00:00 2001 From: Alex Valavanis Date: Tue, 7 Feb 2017 12:12:46 +0000 Subject: Add new 'Strict' build type for deprecation checking (bzr r15488) --- src/2geom/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src') diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt index aa51d51bd..d2c1ea50e 100644 --- a/src/2geom/CMakeLists.txt +++ b/src/2geom/CMakeLists.txt @@ -1,3 +1,7 @@ +# Override error flag just for this folder +if (CMAKE_BUILD_TYPE MATCHES Strict) + set(CMAKE_CXX_FLAGS_STRICT "${CMAKE_CXX_FLAGS_STRICT} -Wno-error=deprecated-declarations") +endif() set(2geom_SRC affine.cpp -- cgit v1.2.3 From 026d2dcd2a7bae80241905cc32afa13fde5faa95 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 7 Feb 2017 14:34:51 +0100 Subject: Default style source to SP_STYLE_SRC_STYLE_PROP. Only set style_src on successful read. Fixed bugs: - https://launchpad.net/bugs/1662285 (bzr r15490) --- src/style-internal.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/style-internal.h b/src/style-internal.h index 69b03f503..154538833 100644 --- a/src/style-internal.h +++ b/src/style-internal.h @@ -121,7 +121,7 @@ public: inherits(inherits), set(false), inherit(false), - style_src(SP_STYLE_SRC_UNSET), + style_src(SP_STYLE_SRC_STYLE_PROP), // Default to property, see bug 1662285. style(NULL) {} @@ -132,7 +132,9 @@ public: virtual void readIfUnset( gchar const *str, SPStyleSrc const &source = SP_STYLE_SRC_STYLE_PROP ) { if ( !set ) { read( str ); - style_src = source; + if ( set ) { + style_src = source; + } } } -- cgit v1.2.3 From 58808234db8381a86518229e176f429f440ff93f Mon Sep 17 00:00:00 2001 From: Alex Valavanis Date: Tue, 7 Feb 2017 18:34:57 +0000 Subject: Fix some new Gdk deprecations (bzr r15491) --- src/debug/log-display-config.cpp | 41 ++++++++++++++++++++++++++++++---------- src/display/sp-canvas.cpp | 2 +- 2 files changed, 32 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/debug/log-display-config.cpp b/src/debug/log-display-config.cpp index ecc05b7b7..1f436a708 100644 --- a/src/debug/log-display-config.cpp +++ b/src/debug/log-display-config.cpp @@ -27,9 +27,20 @@ typedef SimpleEvent ConfigurationEvent; class Monitor : public ConfigurationEvent { public: - Monitor(GdkScreen *screen, gint monitor) : ConfigurationEvent("monitor") { +#if GTK_CHECK_VERSION(3,22,0) + Monitor(GdkMonitor *monitor) +#else + Monitor(GdkScreen *screen, gint monitor) +#endif + : ConfigurationEvent("monitor") { GdkRectangle area; + +#if GTK_CHECK_VERSION(3,22,0) + gdk_monitor_get_geometry(monitor, &area); +#else gdk_screen_get_monitor_geometry(screen, monitor, &area); +#endif + _addProperty("x", area.x); _addProperty("y", area.y); _addProperty("width", area.width); @@ -37,10 +48,13 @@ public: } }; +#if !GTK_CHECK_VERSION(3,22,0) +// We don't need this in newer Gtk+ versions as GdkMonitor information is now +// returned directly from GdkDisplay rather than needing GdkScreen first class Screen : public ConfigurationEvent { public: Screen(GdkScreen *s) : ConfigurationEvent("screen"), screen(s) { - _addProperty("width", gdk_screen_get_width(screen)); + _addProperty("width", gdk_screen_get_width(screen)); _addProperty("height", gdk_screen_get_height(screen)); } void generateChildEvents() const { @@ -53,21 +67,28 @@ public: private: GdkScreen *screen; }; +#endif class Display : public ConfigurationEvent { public: Display() : ConfigurationEvent("display") {} void generateChildEvents() const { GdkDisplay *display=gdk_display_get_default(); -#if GTK_CHECK_VERSION(3,10,0) - GdkScreen *screen = gdk_display_get_screen(display, 0); - Logger::write(screen); -#else - gint n_screens = gdk_display_get_n_screens(display); - for ( gint i = 0 ; i < n_screens ; i++ ) { - GdkScreen *screen = gdk_display_get_screen(display, i); - Logger::write(screen); + +#if GTK_CHECK_VERSION(3,22,0) + gint const n_monitors = gdk_display_get_n_monitors(display); + + // Loop through all monitors and log their details + for (gint i_monitor = 0; i_monitor < n_monitors; ++i_monitor) { + GdkMonitor *monitor = gdk_display_get_monitor(display, i_monitor); + Logger::write(monitor); } +#else + // We used to find the number of screens, and log info for + // each of them. However, the number of screens is always + // one in Gtk+ 3 + GdkScreen *screen = gdk_display_get_default_screen(display); + Logger::write(screen); #endif } }; diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 68eae0a65..41d136ee9 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -1034,7 +1034,7 @@ void SPCanvas::handle_realize(GtkWidget *widget) attributes.width = allocation.width; attributes.height = allocation.height; attributes.wclass = GDK_INPUT_OUTPUT; - attributes.visual = gdk_visual_get_system(); + attributes.visual = gdk_screen_get_system_visual(gdk_screen_get_default()); attributes.event_mask = (gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK | -- cgit v1.2.3 From 06be77e76584d2a419ce942fd3f6db891f318c7d Mon Sep 17 00:00:00 2001 From: Alex Valavanis Date: Tue, 7 Feb 2017 19:19:46 +0000 Subject: Fix Gdk deprecations (bzr r15492) --- src/display/sp-canvas.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 41d136ee9..623e417c6 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -48,6 +48,10 @@ #include #include +#if GTK_CHECK_VERSION(3,20,0) +# include +#endif + using Inkscape::Debug::GdkEventLatencyTracker; // gtk_check_version returns non-NULL on failure @@ -72,8 +76,14 @@ struct SPCanvasGroupClass { static void ungrab_default_client_pointer(guint32 const time = GDK_CURRENT_TIME) { auto const display = Gdk::Display::get_default(); + +#if GTK_CHECK_VERSION(3,20,0) + auto const seat = display->get_default_seat(); + auto const device = seat->get_pointer(); +#else auto const dm = display->get_device_manager(); auto const device = dm->get_client_pointer(); +#endif device->ungrab(time); } @@ -625,9 +635,16 @@ int sp_canvas_item_grab(SPCanvasItem *item, guint event_mask, GdkCursor *cursor, // fixme: Top hack (Lauris) // fixme: If we add key masks to event mask, Gdk will abort (Lauris) - // fixme: But Canvas actualle does get key events, so all we need is routing these here - auto dm = gdk_display_get_device_manager(gdk_display_get_default()); + // fixme: But Canvas actually does get key events, so all we need is routing these here + auto display = gdk_display_get_default(); +#if GTK_CHECK_VERSION(3,20,0) + auto seat = gdk_display_get_default_seat(display); + auto device = gdk_seat_get_pointer(seat); +#else + auto dm = gdk_display_get_device_manager(display); auto device = gdk_device_manager_get_client_pointer(dm); +#endif + gdk_device_grab(device, getWindow(item->canvas), GDK_OWNERSHIP_NONE, @@ -1694,8 +1711,14 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1) gint x, y; auto const display = Gdk::Display::get_default(); + +#if GTK_CHECK_VERSION(3,20,0) + auto const seat = display->get_default_seat(); + auto const device = seat->get_pointer(); +#else auto const dm = display->get_device_manager(); auto const device = dm->get_client_pointer(); +#endif gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(this)), device->gobj(), -- cgit v1.2.3 From a8d79dede01f2d3b38ea375bca310cd3f25796d1 Mon Sep 17 00:00:00 2001 From: peregrine Date: Wed, 8 Feb 2017 00:01:27 +0100 Subject: fix two memory leaks Fixed bugs: - https://launchpad.net/bugs/1662686 - https://launchpad.net/bugs/1662683 (bzr r15493) --- src/extension/implementation/script.cpp | 3 +++ src/extension/internal/bitmap/imagemagick.cpp | 1 + 2 files changed, 4 insertions(+) (limited to 'src') diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index d2319c2e0..b1058d415 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -963,6 +963,9 @@ void Script::checkStderr (const Glib::ustring &data, warning.run(); + delete textview; + delete scrollwindow; + return; } diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp index 472c2db91..cc5b3d1bc 100644 --- a/src/extension/internal/bitmap/imagemagick.cpp +++ b/src/extension/internal/bitmap/imagemagick.cpp @@ -213,6 +213,7 @@ ImageMagick::effect (Inkscape::Extension::Effect *module, Inkscape::UI::View::Vi dc->_nodes[i]->setAttribute("xlink:href", dc->_caches[i], true); dc->_nodes[i]->setAttribute("sodipodi:absref", NULL, true); + delete blob; } catch (Magick::Exception &error_) { printf("Caught exception: %s \n", error_.what()); -- cgit v1.2.3 From 528e1e0c53da088889b4108b1ffb6173a520c96f Mon Sep 17 00:00:00 2001 From: peregrine Date: Wed, 8 Feb 2017 06:29:21 +0100 Subject: [Bug #1658320] Color names have additional numbers. Fixed bugs: - https://launchpad.net/bugs/1658320 (bzr r15494) --- src/id-clash.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/id-clash.cpp b/src/id-clash.cpp index c284843b8..162cb9e89 100644 --- a/src/id-clash.cpp +++ b/src/id-clash.cpp @@ -373,9 +373,9 @@ void rename_id(SPObject *elem, Glib::ustring const &new_name) gchar *id = g_strdup(new_name.c_str()); //id is not empty here as new_name is check to be not empty g_strcanon (id, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.:", '_'); Glib::ustring new_name2 = id; //will not fail as id can not be NULL, see length check on new_name - g_free (id); if (!isalnum (new_name2[0])) { g_message("Invalid Id, will not change."); + g_free (id); return; } @@ -396,7 +396,7 @@ void rename_id(SPObject *elem, Glib::ustring const &new_name) break; } } - + g_free (id); // Change to the new ID elem->getRepr()->setAttribute("id", new_name2); // Make a note of this change, if we need to fix up refs to it -- cgit v1.2.3 From 4dfbde56fa77c00a76e590cca2e785343fabea59 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 8 Feb 2017 09:41:19 +0100 Subject: Fix g_warnings (typo in action name). (bzr r15495) --- src/widgets/text-toolbar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index 24665be37..37497ac01 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -2023,7 +2023,7 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje g_object_set( act, "short_label", "NotUsed", NULL ); gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); - g_object_set_data( holder, "TextDirectAction", act ); + g_object_set_data( holder, "TextDirectionAction", act ); ege_select_one_action_set_appearance( act, "full" ); ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); -- cgit v1.2.3 From ddb9f75a21c83c5979e467c5adf1b8a7cdf7b98e Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 8 Feb 2017 10:36:56 +0100 Subject: Allow dialog to be resizable. (Fixed inheritance.) Also basic housekeeping. (bzr r15496) --- src/ui/dialog/styledialog.cpp | 11 +++++++++++ src/ui/dialog/styledialog.h | 30 ++++++++++++++++++++++-------- 2 files changed, 33 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/styledialog.cpp b/src/ui/dialog/styledialog.cpp index 5246290b4..8d56e10e7 100644 --- a/src/ui/dialog/styledialog.cpp +++ b/src/ui/dialog/styledialog.cpp @@ -1114,3 +1114,14 @@ void StyleDialog::_selectRow(Selection */*sel*/) } // namespace Dialog } // namespace UI } // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/styledialog.h b/src/ui/dialog/styledialog.h index b03a1d2e1..3cc4349e6 100644 --- a/src/ui/dialog/styledialog.h +++ b/src/ui/dialog/styledialog.h @@ -30,16 +30,16 @@ namespace Dialog { /** * @brief The StyleDialog class - * A list of CSS selectors will show up in this dialog. This dialog allows to - * add and delete selectors. Objects can be added to and removed from the selectors - * in the dialog. Besides, selection of any selector row selects the matching - * objects in the drawing and vice-versa. + * A list of CSS selectors will show up in this dialog. This dialog allows one to + * add and delete selectors. Elements can be added to and removed from the selectors + * in the dialog. Selection of any selector row selects the matching objects in + * the drawing and vice-versa. */ typedef std::pair >, std::string> _selectorVecType; -class StyleDialog : public UI::Widget::Panel -{ +class StyleDialog : public Widget::Panel { + public: StyleDialog(); ~StyleDialog(); @@ -73,8 +73,11 @@ private: class ModelColumns : public Gtk::TreeModel::ColumnRecord { public: - ModelColumns() - { add(_selectorLabel); add(_colAddRemove); add(_colObj); } + ModelColumns() { + add(_selectorLabel); + add(_colAddRemove); + add(_colObj); + } Gtk::TreeModelColumn _selectorLabel; Gtk::TreeModelColumn _colAddRemove; Gtk::TreeModelColumn > _colObj; @@ -115,3 +118,14 @@ private: } // namespace Inkscape #endif // STYLEDIALOG_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 : -- cgit v1.2.3 From 116c4c4853a080ff7210de2d4e999959c0c0e0ce Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 8 Feb 2017 13:09:58 +0100 Subject: Add naive selector validation on entry in style dialog. (bzr r15497) --- src/attribute-rel-svg.cpp | 23 +++++++++++++++- src/attribute-rel-svg.h | 1 + src/ui/dialog/styledialog.cpp | 64 +++++++++++++++++++++++++++---------------- 3 files changed, 64 insertions(+), 24 deletions(-) (limited to 'src') diff --git a/src/attribute-rel-svg.cpp b/src/attribute-rel-svg.cpp index afa578061..1f4bee1b3 100644 --- a/src/attribute-rel-svg.cpp +++ b/src/attribute-rel-svg.cpp @@ -27,6 +27,27 @@ SPAttributeRelSVG * SPAttributeRelSVG::instance = NULL; bool SPAttributeRelSVG::foundFile = false; +/* + * This function returns true if element is an SVG element. + */ +bool SPAttributeRelSVG::isSVGElement(Glib::ustring element) +{ + if (SPAttributeRelSVG::instance == NULL) { + SPAttributeRelSVG::instance = new SPAttributeRelSVG(); + } + + // Always valid if data file not found! + if( !foundFile ) return true; + + // Strip off "svg:" from the element's name + Glib::ustring temp = element; + if ( temp.find("svg:") != std::string::npos ) { + temp.erase( temp.find("svg:"), 4 ); + } + + return (SPAttributeRelSVG::instance->attributesOfElements.count(temp) > 0); +} + /* * This functions checks whether an element -> attribute pair is allowed or not */ @@ -39,7 +60,7 @@ bool SPAttributeRelSVG::findIfValid(Glib::ustring attribute, Glib::ustring eleme // Always valid if data file not found! if( !foundFile ) return true; - // Strip of "svg:" from the element's name + // Strip off "svg:" from the element's name Glib::ustring temp = element; if ( temp.find("svg:") != std::string::npos ) { temp.erase( temp.find("svg:"), 4 ); diff --git a/src/attribute-rel-svg.h b/src/attribute-rel-svg.h index 74c6d3b60..c0a9cd215 100644 --- a/src/attribute-rel-svg.h +++ b/src/attribute-rel-svg.h @@ -22,6 +22,7 @@ typedef std::map > hashList; */ class SPAttributeRelSVG { public: + static bool isSVGElement(Glib::ustring element); static bool findIfValid(Glib::ustring attribute, Glib::ustring element); private: diff --git a/src/ui/dialog/styledialog.cpp b/src/ui/dialog/styledialog.cpp index 8d56e10e7..7b68cfe53 100644 --- a/src/ui/dialog/styledialog.cpp +++ b/src/ui/dialog/styledialog.cpp @@ -16,8 +16,11 @@ #include "sp-object.h" #include "selection.h" #include "xml/attribute-record.h" +#include "attribute-rel-svg.h" + +#include #include - + using Inkscape::Util::List; using Inkscape::XML::AttributeRecord; @@ -169,45 +172,60 @@ void StyleDialog::_addSelector() * is added to a new style element. */ Gtk::Dialog *textDialogPtr = new Gtk::Dialog(); - Gtk::Entry *textEditPtr = manage ( new Gtk::Entry() ); textDialogPtr->add_button("Add", Gtk::RESPONSE_OK); + + Gtk::Entry *textEditPtr = manage ( new Gtk::Entry() ); textDialogPtr->get_vbox()->pack_start(*textEditPtr, Gtk::PACK_SHRINK); + Gtk::Label *textLabelPtr = manage ( new Gtk::Label( + _("Invalid entry: Not an id (#), class (.), or element CSS selector.") + ) ); + textDialogPtr->get_vbox()->pack_start(*textLabelPtr, Gtk::PACK_SHRINK); + /** * By default, the entrybox contains 'Class1' as text. However, if object(s) * is(are) selected and user clicks '+' at the bottom of dialog, the * entrybox will have the id(s) of the selected objects as text. */ if (_desktop->getSelection()->isEmpty()) { - textEditPtr->set_text("Class1"); - } - else { + textEditPtr->set_text(".Class1"); + } else { Inkscape::Selection* selection = _desktop->getSelection(); - std::vector selected = std::vector(selection - ->objects().begin(), - selection-> - objects().end()); + std::vector selected = + std::vector(selection->objects().begin(), + selection->objects().end()); textEditPtr->set_text(_setClassAttribute(selected)); } textDialogPtr->set_size_request(200, 100); - textDialogPtr->show_all(); - int result = textDialogPtr->run(); + textEditPtr->show(); + textLabelPtr->hide(); + textDialogPtr->show(); - /** - * @brief selectorName - * This string stores selector name. The text from entrybox is saved as name - * for selector. If the entrybox is empty, the text (thus selectorName) is - * set to ".Class1" - */ - if (!textEditPtr->get_text().empty()) { + int result = -1; + bool invalid = true; + + while (invalid) { + result = textDialogPtr->run(); + + /** + * @brief selectorName + * This string stores selector name. The text from entrybox is saved as name + * for selector. If the entrybox is empty, the text (thus selectorName) is + * set to ".Class1" + */ _selectorName = textEditPtr->get_text(); - } - else { - _selectorName = ".Class1"; - } - del->set_sensitive(true); + del->set_sensitive(true); + + if (_selectorName[0] == '.' || + _selectorName[0] == '#' || + SPAttributeRelSVG::isSVGElement( _selectorName ) ) { + invalid = false; + } else { + textLabelPtr->show(); + } + } /** * The selector name objects is set to the text that the user sets in the -- cgit v1.2.3 From 646ef9c0269e7cf99f07d2a2896c35cf151a68a5 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Thu, 9 Feb 2017 14:51:53 +0100 Subject: [Bug #1662439] Instant crash when trying to move svg symbol. Fixed bugs: - https://launchpad.net/bugs/1662439 (bzr r15498) --- src/document.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/document.cpp b/src/document.cpp index b69508751..b1f16fece 100644 --- a/src/document.cpp +++ b/src/document.cpp @@ -1474,7 +1474,9 @@ static SPItem *find_group_at_point(unsigned int dkey, SPGroup *group, Geom::Poin if (SP_IS_GROUP(&o) && SP_GROUP(&o)->effectiveLayerMode(dkey) != SPGroup::LAYER ) { SPItem *child = SP_ITEM(&o); Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey); - arenaitem->drawing().update(); + if (arenaitem) { + arenaitem->drawing().update(); + } // seen remembers the last (topmost) of groups pickable at this point if (arenaitem && arenaitem->pick(p, delta, 1) != NULL) { -- cgit v1.2.3 From 52059c7c7f059a0928efd48d0ef545dabc30a3a7 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Fri, 10 Feb 2017 11:06:54 +0100 Subject: Do not delete presentation attributes. Styling source is now tracked and not automatically converted to properties in a style attribute. Fixed bugs: - https://launchpad.net/bugs/1663511 (bzr r15500) --- src/sp-object.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/sp-object.cpp b/src/sp-object.cpp index 7807703f6..9f15935ac 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -1105,7 +1105,10 @@ Inkscape::XML::Node* SPObject::write(Inkscape::XML::Document *doc, Inkscape::XML * possibly we should write property attributes instead of a style * attribute. */ - sp_style_unset_property_attrs (this); + // With the changes to preserves style source this is no longer needed + // and the above comment no longer applies. I leave it here until these + // change are well tested. + // sp_style_unset_property_attrs (this); } #ifdef OBJECT_TRACE -- cgit v1.2.3 From bd4bad24c8e2c428e07d8afc5bc1009e9809be1b Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Fri, 10 Feb 2017 22:26:04 +0100 Subject: Fix encoding/escaping issues with symbols loaded from .vss (Visio stencils) files There were three issues: - When loading a .vss file an SVG document is created internally and the file name is used to derive this document's "title". This could result in illegal characters (e.g. the ampersand "&") in the title making the document fail to load. The title is now properly escaped. - Loading of files with non-ANSI characers in filename failed on Windows. Fix is equivalent to r15421, see also bug #1416949. - The .vss file name is also used to derive symbol IDs, which were not properly sanitized before (i.e. could cause broken hrefs later or even prevent to load the .vss file). Characters that do not match [a-zA-Z0-9_-] are now laways replaced with an underscore "_") which will result in valid IDs in almost all cases Fixed bugs: - https://launchpad.net/bugs/1662465 (bzr r15501) --- src/ui/dialog/symbols.cpp | 47 ++++++++++++++++++++++++++++------------------- 1 file changed, 28 insertions(+), 19 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp index 4840b897b..c8a11b112 100644 --- a/src/ui/dialog/symbols.cpp +++ b/src/ui/dialog/symbols.cpp @@ -127,7 +127,7 @@ SymbolsDialog::SymbolsDialog( gchar const* prefsPath ) : sigc::connection connSet = symbolSet->signal_changed().connect( sigc::mem_fun(*this, &SymbolsDialog::rebuild)); instanceConns.push_back(connSet); - + ++row; /********************* Icon View **************************/ @@ -342,7 +342,7 @@ void SymbolsDialog::rebuild() { addSymbol->set_sensitive( true ); removeSymbol->set_sensitive( true ); } else { - addSymbol->set_sensitive( false ); + addSymbol->set_sensitive( false ); removeSymbol->set_sensitive( false ); } add_symbols( symbolDocument ); @@ -451,7 +451,14 @@ void SymbolsDialog::iconChanged() { #ifdef WITH_LIBVISIO // Read Visio stencil files -SPDocument* read_vss( gchar* fullname, gchar* filename ) { +SPDocument* read_vss( gchar* fullname, Glib::ustring name ) { + + #ifdef WIN32 + // RVNGFileStream uses fopen() internally which unfortunately only uses ANSI encoding on Windows + // therefore attempt to convert uri to the system codepage + // even if this is not possible the alternate short (8.3) file name will be used if available + fullname = g_win32_locale_filename_from_utf8(fullname); + #endif RVNGFileStream input(fullname); @@ -474,6 +481,12 @@ SPDocument* read_vss( gchar* fullname, gchar* filename ) { return NULL; } + // prepare a valid title for the symbol file + Glib::ustring title = Glib::Markup::escape_text(name); + // prepare a valid id prefix for the symbols (unfortunately libvisio doesn't give us a name) + Glib::RefPtr regex1 = Glib::Regex::create("[^a-zA-Z0-9_-]"); + Glib::ustring id = regex1->replace(name, 0, "_", Glib::REGEX_MATCH_PARTIAL); + Glib::ustring tmpSVGOutput; tmpSVGOutput += "\n"; tmpSVGOutput += "\n"; tmpSVGOutput += " "; - tmpSVGOutput += filename; + tmpSVGOutput += title; tmpSVGOutput += "\n"; tmpSVGOutput += " \n"; - // Create a string we can use for the symbol id (libvisio doesn't give us a name) - std::string sanitized( filename ); - sanitized.erase( sanitized.find_last_of(".vss")-3 ); - sanitized.erase( std::remove_if( sanitized.begin(), sanitized.end(), ispunct ), sanitized.end() ); - std::replace( sanitized.begin(), sanitized.end(), ' ', '_' ); - // std::cout << filename << " |" << sanitized << "|" << std::endl; - // Each "symbol" is in it's own SVG file, we wrap with and merge into one file. for (unsigned i=0; i\n"; @@ -521,12 +527,12 @@ SPDocument* read_vss( gchar* fullname, gchar* filename ) { tmpSVGOutput += " \n"; tmpSVGOutput += "\n"; - + return SPDocument::createNewDocFromMem( tmpSVGOutput.c_str(), strlen( tmpSVGOutput.c_str()), 0 ); } #endif - + /* Hunts preference directories for symbol files */ void SymbolsDialog::get_symbols() { @@ -565,11 +571,14 @@ void SymbolsDialog::get_symbols() { #ifdef WITH_LIBVISIO if( tag.compare( "vss" ) == 0 ) { + // strip extension from filename and use it as name for the symbol set + Glib::ustring name = Glib::ustring(filename); + name = name.erase(name.rfind('.')); - symbol_doc = read_vss( fullname, filename ); + symbol_doc = read_vss( fullname, name ); if( symbol_doc ) { - symbolSets[Glib::ustring(filename)]= symbol_doc; - symbolSet->append(filename); + symbolSets[name]= symbol_doc; + symbolSet->append(name); } } #endif @@ -630,7 +639,7 @@ GSList* SymbolsDialog::symbols_in_doc( SPDocument* symbolDocument ) { } GSList* SymbolsDialog::use_in_doc_recursive (SPObject *r, GSList *l) -{ +{ if ( dynamic_cast(r) ) { l = g_slist_prepend (l, r); @@ -816,7 +825,7 @@ SPDocument* SymbolsDialog::symbols_preview_doc() " xmlns:sodipodi=\"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd\"" " xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\"" " xmlns:xlink=\"http://www.w3.org/1999/xlink\">" -" " +" " " " " " " " -- cgit v1.2.3 From 9f806b86e925bc6817cb111bc50e244cfa302d4a Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Fri, 10 Feb 2017 23:04:01 +0100 Subject: Add missing "#include " for previous commit (bzr r15502) --- src/ui/dialog/symbols.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp index c8a11b112..dcfb7f242 100644 --- a/src/ui/dialog/symbols.cpp +++ b/src/ui/dialog/symbols.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3 From 7ed2fd359e5d30e850eb0ec5c84ed2e2627b017d Mon Sep 17 00:00:00 2001 From: Marc Jeanmougin Date: Fri, 10 Feb 2017 23:25:22 +0100 Subject: temporarily sets decimal separator locale to C to fix files correctly (Users with a comma decimal separator in their locale had files broken by the line update fix) Fixed bugs: - https://launchpad.net/bugs/1663075 (bzr r15503) --- src/file-update.cpp | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src') diff --git a/src/file-update.cpp b/src/file-update.cpp index 40a8bc834..2275ab1c3 100644 --- a/src/file-update.cpp +++ b/src/file-update.cpp @@ -19,6 +19,7 @@ #include "style.h" #include "document.h" #include +#include #include "text-editing.h" using namespace std; @@ -149,10 +150,12 @@ void fix_update(SPObject *o) { void sp_file_convert_text_baseline_spacing(SPDocument *doc) { + setlocale(LC_NUMERIC,"C"); sp_file_text_run_recursive(fix_blank_line, doc->getRoot()); sp_file_text_run_recursive(fix_line_spacing, doc->getRoot()); sp_file_text_run_recursive(fix_font_size, doc->getRoot()); sp_file_text_run_recursive(fix_update, doc->getRoot()); + setlocale(LC_NUMERIC,""); } void sp_file_convert_font_name(SPDocument *doc) -- cgit v1.2.3 From d2043243866f0aebfdf885ef022a1b7f628433de Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sat, 11 Feb 2017 00:21:04 +0100 Subject: Fix bug #1662812 Converting Stroke to Path messes document's structure Fixed bugs: - https://launchpad.net/bugs/1662812 (bzr r15504) --- src/splivarot.cpp | 62 +++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 40 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 531a48e44..485b4547e 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -1196,13 +1196,19 @@ sp_item_path_outline(SPItem *item, SPDesktop *desktop, bool legacy) // remember old stroke style, to be set on fill SPStyle *i_style = item->style; //Stroke - and markers + gchar const *opacity; + gchar const *filter; + SPCSSAttr *ncss = 0; { ncss = sp_css_attr_from_style(i_style, SP_STYLE_FLAG_ALWAYS); gchar const *s_val = sp_repr_css_property(ncss, "stroke", NULL); gchar const *s_opac = sp_repr_css_property(ncss, "stroke-opacity", NULL); - + opacity = sp_repr_css_property(ncss, "opacity", NULL); + filter = sp_repr_css_property(ncss, "filter", NULL); sp_repr_css_set_property(ncss, "stroke", "none"); + sp_repr_css_set_property(ncss, "filter", NULL); + sp_repr_css_set_property(ncss, "opacity", NULL); sp_repr_css_set_property(ncss, "stroke-opacity", "1.0"); sp_repr_css_set_property(ncss, "fill", s_val); if ( s_opac ) { @@ -1220,6 +1226,8 @@ sp_item_path_outline(SPItem *item, SPDesktop *desktop, bool legacy) ncsf = sp_css_attr_from_style(i_style, SP_STYLE_FLAG_ALWAYS); sp_repr_css_set_property(ncsf, "stroke", "none"); sp_repr_css_set_property(ncsf, "stroke-opacity", "1.0"); + sp_repr_css_set_property(ncsf, "filter", NULL); + sp_repr_css_set_property(ncsf, "opacity", NULL); sp_repr_css_unset_property(ncsf, "marker-start"); sp_repr_css_unset_property(ncsf, "marker-mid"); sp_repr_css_unset_property(ncsf, "marker-end"); @@ -1504,7 +1512,11 @@ sp_item_path_outline(SPItem *item, SPDesktop *desktop, bool legacy) gchar const *paint_order = sp_repr_css_property(ncss, "paint-order", NULL); SPIPaintOrder temp; temp.read( paint_order ); - if (temp.layer[0] != SP_CSS_PAINT_ORDER_NORMAL && !legacy) { + bool unique = false; + if ((!fill && !markers) || (!fill && !stroke) || (!markers && !stroke)) { + unique = true; + } + if (temp.layer[0] != SP_CSS_PAINT_ORDER_NORMAL && !legacy && !unique) { if (temp.layer[0] == SP_CSS_PAINT_ORDER_FILL) { if (temp.layer[1] == SP_CSS_PAINT_ORDER_STROKE) { @@ -1574,7 +1586,7 @@ sp_item_path_outline(SPItem *item, SPDesktop *desktop, bool legacy) } } - } else { + } else if (!unique) { if ( fill ) { g_repr->appendChild(fill); } @@ -1588,35 +1600,41 @@ sp_item_path_outline(SPItem *item, SPDesktop *desktop, bool legacy) if( fill || stroke || markers ) { did = true; } + Inkscape::XML::Node *out = NULL; - if (!fill && !markers) { + if (!fill && !markers && did) { out = stroke; - parent->mergeFrom(g_repr, ""); - parent->removeChild(g_repr); - } else if (!fill && !stroke) { + } else if (!fill && !stroke && did) { out = markers; - parent->mergeFrom(g_repr, ""); - parent->removeChild(g_repr); - } else if (!markers && !stroke) { + } else if (!markers && !stroke && did) { out = fill; - parent->mergeFrom(g_repr, ""); - parent->removeChild(g_repr); - } else { + } else if(did) { out = g_repr; } - + SPCSSAttr *r_style = sp_repr_css_attr_new(); + sp_repr_css_set_property(r_style, "opacity", opacity); + sp_repr_css_set_property(r_style, "filter", filter); + sp_repr_css_change(out, r_style, "style"); + sp_repr_css_attr_unref(r_style); + if (unique) { + out->setPosition(pos > 0 ? pos : 0); + parent->appendChild(out); + parent->removeChild(g_repr); + } + out->setAttribute("transform", item->getRepr()->attribute("transform")); //bug lp:1290573 : completely destroy the old object first curve->unref(); //Check for recursive markers to path - if( selection->includes(item) ){ - selection->remove(item); - item->deleteObject(false); - selection->add(out); - } else { - item->deleteObject(false); + if (did) { + if( selection->includes(item) ){ + selection->remove(item); + item->deleteObject(false); + selection->add(out); + } else { + item->deleteObject(false); + } + Inkscape::GC::release(g_repr); } - Inkscape::GC::release(g_repr); - } } -- cgit v1.2.3 From 9faf941d45ce7d23f5cb0d066bd23346f7e3aedf Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Sat, 11 Feb 2017 01:16:53 +0100 Subject: Fix a memory leak introduced in r15421 and r15501 respectively (bzr r15505) --- src/extension/internal/cdr-input.cpp | 8 +++++--- src/extension/internal/vsd-input.cpp | 8 +++++--- src/extension/internal/wpg-input.cpp | 7 +++++-- src/ui/dialog/symbols.cpp | 4 ++++ 4 files changed, 19 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/extension/internal/cdr-input.cpp b/src/extension/internal/cdr-input.cpp index 0435f1396..dbe88c668 100644 --- a/src/extension/internal/cdr-input.cpp +++ b/src/extension/internal/cdr-input.cpp @@ -218,11 +218,13 @@ SPDocument *CdrInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * u // RVNGFileStream uses fopen() internally which unfortunately only uses ANSI encoding on Windows // therefore attempt to convert uri to the system codepage // even if this is not possible the alternate short (8.3) file name will be used if available - uri = g_win32_locale_filename_from_utf8(uri); + gchar * converted_uri = g_win32_locale_filename_from_utf8(uri); + RVNGFileStream input(converted_uri); + g_free(converted_uri); + #else + RVNGFileStream input(uri); #endif - RVNGFileStream input(uri); - if (!libcdr::CDRDocument::isSupported(&input)) { return NULL; } diff --git a/src/extension/internal/vsd-input.cpp b/src/extension/internal/vsd-input.cpp index 78783aa2d..85698387a 100644 --- a/src/extension/internal/vsd-input.cpp +++ b/src/extension/internal/vsd-input.cpp @@ -220,11 +220,13 @@ SPDocument *VsdInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * u // RVNGFileStream uses fopen() internally which unfortunately only uses ANSI encoding on Windows // therefore attempt to convert uri to the system codepage // even if this is not possible the alternate short (8.3) file name will be used if available - uri = g_win32_locale_filename_from_utf8(uri); + gchar * converted_uri = g_win32_locale_filename_from_utf8(uri); + RVNGFileStream input(converted_uri); + g_free(converted_uri); + #else + RVNGFileStream input(uri); #endif - RVNGFileStream input(uri); - if (!libvisio::VisioDocument::isSupported(&input)) { return NULL; } diff --git a/src/extension/internal/wpg-input.cpp b/src/extension/internal/wpg-input.cpp index 12457791b..299614c94 100644 --- a/src/extension/internal/wpg-input.cpp +++ b/src/extension/internal/wpg-input.cpp @@ -85,10 +85,13 @@ SPDocument *WpgInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * u // RVNGFileStream uses fopen() internally which unfortunately only uses ANSI encoding on Windows // therefore attempt to convert uri to the system codepage // even if this is not possible the alternate short (8.3) file name will be used if available - uri = g_win32_locale_filename_from_utf8(uri); + gchar * converted_uri = g_win32_locale_filename_from_utf8(uri); + RVNGInputStream* input = new RVNGFileStream(converted_uri); + g_free(converted_uri); + #else + RVNGInputStream* input = new RVNGFileStream(uri); #endif - RVNGInputStream* input = new RVNGFileStream(uri); #if WITH_LIBWPG03 if (input->isStructured()) { RVNGInputStream* olestream = input->getSubStreamByName("PerfectOffice_MAIN"); diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp index dcfb7f242..740ff4f39 100644 --- a/src/ui/dialog/symbols.cpp +++ b/src/ui/dialog/symbols.cpp @@ -463,6 +463,10 @@ SPDocument* read_vss( gchar* fullname, Glib::ustring name ) { RVNGFileStream input(fullname); + #ifdef WIN32 + g_free(fullname); + #endif + if (!libvisio::VisioDocument::isSupported(&input)) { return NULL; } -- cgit v1.2.3 From fb35812a12b030e67223cdd003a462e22ed5d465 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Sat, 11 Feb 2017 10:50:20 +0100 Subject: Fix a critical warning on convert to paths https://bugs.launchpad.net/inkscape/+bug/1662812/comments/7 (bzr r15506) --- src/splivarot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 485b4547e..22efe38ed 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -1617,9 +1617,9 @@ sp_item_path_outline(SPItem *item, SPDesktop *desktop, bool legacy) sp_repr_css_change(out, r_style, "style"); sp_repr_css_attr_unref(r_style); if (unique) { - out->setPosition(pos > 0 ? pos : 0); parent->appendChild(out); parent->removeChild(g_repr); + out->setPosition(pos > 0 ? pos : 0); } out->setAttribute("transform", item->getRepr()->attribute("transform")); //bug lp:1290573 : completely destroy the old object first -- cgit v1.2.3 From 0dc3e9ec72db77e707135e42023bfb2d8e04bcbd Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Sat, 11 Feb 2017 21:55:19 +0100 Subject: Fix and improve window sizing and positioning behavior when opening new documents * The option "Remember and use last window's geometry" often had no effect. * When setting "Default window size" to "Large" the functions gdk_screen_width() / gdk_screen_height() were used to derive the size of the Inkscape window. However those functions return the combined screen size of all attached monitors resulting in window sizes that were too large. Now the size of the primary display is used. * In many cases the Inkscape window was moved to the top left corner of the combined screen area (which could be on a different monitor at best and outside of the visible screen area at worst). Inkscape should always spawn on the primary monitor now when not restoring the previous position. Fixed bugs: - https://launchpad.net/bugs/1190828 - https://launchpad.net/bugs/195683 - https://launchpad.net/bugs/568867 - https://launchpad.net/bugs/1654464 (bzr r15507) --- src/sp-namedview.cpp | 64 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp index d430f6321..166e90238 100644 --- a/src/sp-namedview.cpp +++ b/src/sp-namedview.cpp @@ -754,7 +754,7 @@ void SPNamedView::show(SPDesktop *desktop) namespace { -gint const MIN_ONSCREEN_DISTANCE = 50; +gint const MIN_ONSCREEN_DISTANCE = 100; gdouble const NEWDOC_X_SCALE = 0.75; gdouble const NEWDOC_Y_SCALE = NEWDOC_X_SCALE; @@ -774,12 +774,6 @@ Geom::Point calcAnchorPoint(gint const x, gint const y, } // namespace -void SPNamedView::writeNewGrid(SPDocument *document,int gridtype) -{ - g_assert(this->getRepr() != NULL); - Inkscape::CanvasGrid::writeNewGridToRepr(this->getRepr(),document,static_cast(gridtype)); -} - /* * Restores window geometry from the document settings or defaults in prefs */ @@ -788,22 +782,42 @@ void sp_namedview_window_from_document(SPDesktop *desktop) SPNamedView *nv = desktop->namedview; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); bool geometry_from_file = (1 == prefs->getInt("/options/savewindowgeometry/value", 0)); + bool geometry_from_last = (2 == prefs->getInt("/options/savewindowgeometry/value", 0)); gint default_geometry = prefs->getInt("/options/defaultwindowsize/value", 1); bool new_document = (nv->window_width <= 0) || (nv->window_height <= 0); bool show_dialogs = true; // restore window size and position stored with the document - bool sizeSet = false; - - if ((geometry_from_file && nv->window_maximized) || (new_document && (default_geometry == 2))) { + if (geometry_from_last) { + // do nothing, as we already have code for that in interface.cpp + // TODO: Probably should not do similar things in two places + } else if ((geometry_from_file && nv->window_maximized) || (new_document && (default_geometry == 2))) { Gtk::Window *win = desktop->getToplevel(); if (win) { win->maximize(); } - sizeSet = true; - } else if (geometry_from_file && !nv->window_maximized) { - gint w = MIN(gdk_screen_width(), nv->window_width); - gint h = MIN(gdk_screen_height(), nv->window_height); + } else { + // gdk_screen_width() / gdk_screen_height() return the dimensions of all displays combined + // therefore we have to get the dimensions of one monitor explicitly (currently the primary monitor) + // TODO: account for multi-monitor setups (i.e. on which monitor do we want to display Inkscape?) + gint monitor_number; + GdkRectangle monitor_geometry; + monitor_number = gdk_screen_get_primary_monitor(gdk_screen_get_default()); + gdk_screen_get_monitor_geometry(gdk_screen_get_default(), monitor_number, &monitor_geometry); + + gint w = monitor_geometry.width; + gint h = monitor_geometry.height; + bool move_to_screen = false; + if (geometry_from_file and !new_document) { + w = MIN(w, nv->window_width); + h = MIN(h, nv->window_height); + move_to_screen = true; + } else if (default_geometry == 1) { + w *= NEWDOC_X_SCALE; + h *= NEWDOC_Y_SCALE; + } else if (default_geometry == 0) { + w = h = 0; // use the smallest possible window size; could be a factor like NEWDOC_X_SCALE in future + } if ((w > 0) && (h > 0)) { #ifndef WIN32 gint dx= 0; @@ -817,22 +831,14 @@ void sp_namedview_window_from_document(SPDesktop *desktop) show_dialogs = FALSE; } #endif - Geom::Point origin = calcAnchorPoint(nv->window_x, nv->window_y, w, h, MIN_ONSCREEN_DISTANCE); desktop->setWindowSize(w, h); - desktop->setWindowPosition(origin); - sizeSet = true; + if (move_to_screen) { + Geom::Point origin = calcAnchorPoint(nv->window_x, nv->window_y, w, h, MIN_ONSCREEN_DISTANCE); + desktop->setWindowPosition(origin); + } } } - if (!sizeSet && new_document && (default_geometry == 1)) - { - gint w = gdk_screen_width() * NEWDOC_X_SCALE; - gint h = gdk_screen_height() * NEWDOC_Y_SCALE; - Geom::Point origin = calcAnchorPoint(nv->window_x, nv->window_y, w, h, MIN_ONSCREEN_DISTANCE); - desktop->setWindowSize(w, h); - desktop->setWindowPosition(origin); - } - // restore zoom and view if (nv->zoom != 0 && nv->zoom != HUGE_VAL && !IS_NAN(nv->zoom) && nv->cx != HUGE_VAL && !IS_NAN(nv->cx) @@ -850,6 +856,12 @@ void sp_namedview_window_from_document(SPDesktop *desktop) } } +void SPNamedView::writeNewGrid(SPDocument *document,int gridtype) +{ + g_assert(this->getRepr() != NULL); + Inkscape::CanvasGrid::writeNewGridToRepr(this->getRepr(),document,static_cast(gridtype)); +} + bool SPNamedView::getSnapGlobal() const { return this->snap_manager.snapprefs.getSnapEnabledGlobally(); -- cgit v1.2.3 From a65a0a21e5452ced77123a8b846ff10cc1bc74b0 Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Sun, 12 Feb 2017 15:59:14 +0100 Subject: Extensions: Make "indent" attribute a common attribute for all parameters that behaves more consistent and predictable than before. - Every "Parameter" now has an "_indent" member variable (specifying the indentation level; set in "Parameter::make()", see parameter.cpp) - Indentation is achieved by using "set_margin_left()" on the parameter's widget. This fixes bug #1662035 (comment #4 contains some more details about this patch). - Specifying "indent" on a parameter will now work consistently for all parameters. Previously the "indent" attribute often had no effect at all, e.g. for notebooks but also for parameters with 'appearance="full"' which was reasonable in most cases but made the outcome of using this attribute often unpredictable and is unnecessarily restrictive. - Most visible change: "description"s always used an indentation level of at least one (even if no indentation was specified). For the sake of consistency this discrepancy was dropped. Previous appearance can easily be restored by setting 'indent="1"'. Fixed bugs: - https://launchpad.net/bugs/1662035 (bzr r15508) --- src/extension/extension.cpp | 32 ++++++++++++++------------- src/extension/extension.h | 2 +- src/extension/param/bool.cpp | 23 +++++++++++--------- src/extension/param/bool.h | 11 ++++++++-- src/extension/param/color.cpp | 16 ++++++++++---- src/extension/param/color.h | 11 ++++++++-- src/extension/param/description.cpp | 39 +++++++++++++++------------------ src/extension/param/description.h | 5 +++-- src/extension/param/enum.cpp | 24 ++++++++++----------- src/extension/param/enum.h | 12 +++++++++-- src/extension/param/float.cpp | 35 +++++++++++++++--------------- src/extension/param/float.h | 21 +++++++++--------- src/extension/param/int.cpp | 35 +++++++++++++++--------------- src/extension/param/int.h | 20 ++++++++--------- src/extension/param/notebook.cpp | 39 +++++++++++++++++++++++++++------ src/extension/param/notebook.h | 11 +++++++++- src/extension/param/parameter.cpp | 43 ++++++++++++++++++++++++------------- src/extension/param/parameter.h | 9 +++++++- src/extension/param/radiobutton.cpp | 32 +++++++++++++-------------- src/extension/param/radiobutton.h | 3 ++- src/extension/param/string.cpp | 23 +++++++++++--------- src/extension/param/string.h | 13 ++++++++--- 22 files changed, 276 insertions(+), 183 deletions(-) (limited to 'src') diff --git a/src/extension/extension.cpp b/src/extension/extension.cpp index c6dee1b70..2d020aa0e 100644 --- a/src/extension/extension.cpp +++ b/src/extension/extension.cpp @@ -1,6 +1,6 @@ /** \file * - * Inkscape::Extension::Extension: + * Inkscape::Extension::Extension: * the ability to have features that are more modular so that they * can be added and removed easily. This is the basis for defining * those actions. @@ -144,15 +144,15 @@ Extension::~Extension (void) delete timer; timer = NULL; /** \todo Need to do parameters here */ - - // delete parameters: + + // delete parameters: for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) { Parameter * param = reinterpret_cast(list->data); delete param; } g_slist_free(parameters); - - + + for (unsigned int i = 0 ; i < _deps.size(); i++) { delete _deps[i]; } @@ -330,7 +330,7 @@ Extension::get_repr (void) } /** - \return bool + \return bool \brief Whether this extension should hide the "working, please wait" dialog */ bool @@ -444,7 +444,7 @@ Extension::get_param_enum (const gchar * name, const SPDocument * doc, const Ink /** * This is useful to find out, if a given string \c value is selectable in a ComboBox named \cname. - * + * * @param name The name of the enum parameter to get. * @param doc The document to look in for document specific parameters. * @param node The node to look in for a specific parameter. @@ -692,8 +692,9 @@ public: * @param widg Widget to add. * @param tooltip Tooltip for the widget. */ - void addWidget(Gtk::Widget *widg, gchar const *tooltip) { + void addWidget(Gtk::Widget *widg, gchar const *tooltip, int indent) { if (widg) { + widg->set_margin_left(indent*12); this->pack_start(*widg, false, false, 2); if (tooltip) { widg->set_tooltip_text(_(tooltip)); @@ -713,7 +714,7 @@ public: a Gtk::VBox, which is then returned to the calling function. If there are no visible parameters, this function just returns NULL. - If all parameters are gui_visible = false NULL is returned as well. + If all parameters are gui_visible = false NULL is returned as well. */ Gtk::Widget * Extension::autogui (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal * changeSignal) @@ -728,9 +729,10 @@ Extension::autogui (SPDocument * doc, Inkscape::XML::Node * node, sigc::signalget_gui_hidden()) continue; //Ignore hidden parameters Gtk::Widget * widg = param->get_widget(doc, node, changeSignal); gchar const * tip = param->get_tooltip(); - agui->addWidget(widg, tip); - } - + int indent = param->get_indent(); + agui->addWidget(widg, tip, indent); + } + agui->show(); return agui; }; @@ -780,7 +782,7 @@ void Extension::add_val(Glib::ustring labelstr, Glib::ustring valuestr, Gtk::Gri Gtk::Label * label; Gtk::Label * value; - (*row)++; + (*row)++; label = Gtk::manage(new Gtk::Label(labelstr)); value = Gtk::manage(new Gtk::Label(valuestr)); @@ -824,13 +826,13 @@ Extension::get_params_widget(void) return retval; } -unsigned int Extension::param_visible_count ( ) +unsigned int Extension::param_visible_count ( ) { unsigned int _visible_count = 0; for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) { Parameter * param = reinterpret_cast(list->data); if (!param->get_gui_hidden()) _visible_count++; - } + } return _visible_count; } diff --git a/src/extension/extension.h b/src/extension/extension.h index cd29e1636..bbd6d068b 100644 --- a/src/extension/extension.h +++ b/src/extension/extension.h @@ -176,7 +176,7 @@ public: private: void make_param (Inkscape::XML::Node * paramrepr); - + /** * This function looks through the linked list for a parameter * structure with the name of the passed in name. diff --git a/src/extension/param/bool.cpp b/src/extension/param/bool.cpp index ca61d8c51..833215546 100644 --- a/src/extension/param/bool.cpp +++ b/src/extension/param/bool.cpp @@ -24,9 +24,17 @@ namespace Inkscape { namespace Extension { -ParamBool::ParamBool(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), - _value(false), _indent(0) +ParamBool::ParamBool(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml) + : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + , _value(false) { const char * defaultval = NULL; if (xml->firstChild() != NULL) { @@ -39,11 +47,6 @@ ParamBool::ParamBool(const gchar * name, const gchar * guitext, const gchar * de _value = false; } - const char * indent = xml->attribute("indent"); - if (indent != NULL) { - _indent = atoi(indent) * 12; - } - gchar * pref_name = this->pref_name(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); _value = prefs->getBool(extension_pref_root + pref_name, _value); @@ -66,7 +69,7 @@ bool ParamBool::set( bool in, SPDocument * /*doc*/, Inkscape::XML::Node * /*node bool ParamBool::get(const SPDocument * /*doc*/, const Inkscape::XML::Node * /*node*/) const { - return _value; + return _value; } /** @@ -139,7 +142,7 @@ Gtk::Widget *ParamBool::get_widget(SPDocument * doc, Inkscape::XML::Node * node, ParamBoolCheckButton * checkbox = Gtk::manage(new ParamBoolCheckButton(this, doc, node, changeSignal)); checkbox->show(); - hbox->pack_start(*checkbox, false, false, _indent); + hbox->pack_start(*checkbox, false, false); hbox->show(); diff --git a/src/extension/param/bool.h b/src/extension/param/bool.h index 5d190b9d3..0af12b105 100644 --- a/src/extension/param/bool.h +++ b/src/extension/param/bool.h @@ -32,7 +32,15 @@ public: /** * Use the superclass' allocator and set the \c _value. */ - ParamBool(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); + ParamBool(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml); /** * Returns the current state/value. @@ -69,7 +77,6 @@ public: private: /** Internal value. */ bool _value; - int _indent; }; } // namespace Extension diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp index 0b58c5011..041cd5509 100644 --- a/src/extension/param/color.cpp +++ b/src/extension/param/color.cpp @@ -52,9 +52,17 @@ guint32 ParamColor::set( guint32 in, SPDocument * /*doc*/, Inkscape::XML::Node * return in; } -ParamColor::ParamColor (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), - _changeSignal(0) +ParamColor::ParamColor(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml) + : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + , _changeSignal(0) { const char * defaulthex = NULL; if (xml->firstChild() != NULL) @@ -86,7 +94,7 @@ Gtk::Widget *ParamColor::get_widget( SPDocument * /*doc*/, Inkscape::XML::Node * { using Inkscape::UI::Widget::ColorNotebook; - if (_gui_hidden) return NULL; + if (_gui_hidden) return NULL; if (changeSignal) { _changeSignal = new sigc::signal(*changeSignal); diff --git a/src/extension/param/color.h b/src/extension/param/color.h index ed2e57ceb..d6e9d1fbe 100644 --- a/src/extension/param/color.h +++ b/src/extension/param/color.h @@ -31,8 +31,15 @@ private: Inkscape::UI::SelectedColor _color; sigc::connection _color_changed; public: - ParamColor(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); - + ParamColor(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml); virtual ~ParamColor(void); /** Returns \c _value, with a \i const to protect it. */ diff --git a/src/extension/param/description.cpp b/src/extension/param/description.cpp index 07aaa07cc..7f7d2d976 100644 --- a/src/extension/param/description.cpp +++ b/src/extension/param/description.cpp @@ -26,17 +26,19 @@ namespace Extension { /** \brief Initialize the object, to do that, copy the data. */ -ParamDescription::ParamDescription (const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, - Inkscape::Extension::Extension * ext, - Inkscape::XML::Node * xml, - AppearanceMode mode) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), - _value(NULL), _mode(mode), _indent(0) +ParamDescription::ParamDescription(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode) + : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + , _value(NULL) + , _mode(mode) { // printf("Building Description\n"); const char * defaultval = NULL; @@ -50,11 +52,6 @@ ParamDescription::ParamDescription (const gchar * name, _context = xml->attribute("msgctxt"); - const char * indent = xml->attribute("indent"); - if (indent != NULL) { - _indent = atoi(indent) * 12; - } - return; } @@ -76,15 +73,13 @@ ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node } else { newguitext = _(_value); } - + Gtk::Label * label; - int padding = 12 + _indent; if (_mode == HEADER) { label = Gtk::manage(new Gtk::Label(Glib::ustring("") +newguitext + Glib::ustring(""), Gtk::ALIGN_START)); - label->set_margin_top(5); - label->set_margin_bottom(5); + label->set_margin_top(5); + label->set_margin_bottom(5); label->set_use_markup(true); - padding = _indent; } else { label = Gtk::manage(new Gtk::Label(newguitext, Gtk::ALIGN_START)); } @@ -92,7 +87,7 @@ ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node label->show(); Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4)); - hbox->pack_start(*label, true, true, padding); + hbox->pack_start(*label, true, true); hbox->show(); return hbox; diff --git a/src/extension/param/description.h b/src/extension/param/description.h index 3a72c4112..aa3c3a798 100644 --- a/src/extension/param/description.h +++ b/src/extension/param/description.h @@ -34,16 +34,17 @@ public: const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, - const gchar * gui_tip, + const gchar * gui_tip, + int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml, AppearanceMode mode); + Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal * changeSignal); private: /** \brief Internal value. */ gchar * _value; AppearanceMode _mode; - int _indent; const gchar* _context; }; diff --git a/src/extension/param/enum.cpp b/src/extension/param/enum.cpp index 8bc0fbda7..9f254041a 100644 --- a/src/extension/param/enum.cpp +++ b/src/extension/param/enum.cpp @@ -46,12 +46,17 @@ public: }; -ParamComboBox::ParamComboBox(const gchar *name, const gchar *guitext, const gchar *desc, - const Parameter::_scope_t scope, bool gui_hidden, const gchar *gui_tip, - Inkscape::Extension::Extension *ext, Inkscape::XML::Node *xml) - : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext) +ParamComboBox::ParamComboBox(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml) + : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) , _value(NULL) - , _indent(0) , choices(NULL) { const char *xmlval = NULL; // the value stored in XML @@ -94,17 +99,12 @@ ParamComboBox::ParamComboBox(const gchar *name, const gchar *guitext, const gcha } } } - + // Initialize _value with the default value from xml // for simplicity : default to the contents of the first xml-child if (xml->firstChild() && xml->firstChild()->firstChild()) { xmlval = xml->firstChild()->attribute("value"); } - - const char *indent = xml->attribute("indent"); - if (indent != NULL) { - _indent = atoi(indent) * 12; - } } gchar * pref_name = this->pref_name(); @@ -253,7 +253,7 @@ Gtk::Widget *ParamComboBox::get_widget(SPDocument * doc, Inkscape::XML::Node * n Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4)); Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START)); label->show(); - hbox->pack_start(*label, false, false, _indent); + hbox->pack_start(*label, false, false); ParamComboBoxEntry * combo = Gtk::manage(new ParamComboBoxEntry(this, doc, node, changeSignal)); // add choice strings: diff --git a/src/extension/param/enum.h b/src/extension/param/enum.h index 52e018469..f9d3d75f7 100644 --- a/src/extension/param/enum.h +++ b/src/extension/param/enum.h @@ -34,12 +34,20 @@ private: been allocated in memory. And should be free'd. It is the value of the current selected string */ gchar * _value; - int _indent; GSList * choices; /**< A table to store the choice strings */ public: - ParamComboBox(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); + ParamComboBox(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml); virtual ~ParamComboBox(void); + Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal * changeSignal); // Explicitly call superclass version to avoid method being hidden. diff --git a/src/extension/param/float.cpp b/src/extension/param/float.cpp index 23a03ea8f..fd82ab312 100644 --- a/src/extension/param/float.cpp +++ b/src/extension/param/float.cpp @@ -27,17 +27,21 @@ namespace Extension { /** Use the superclass' allocator and set the \c _value. */ -ParamFloat::ParamFloat (const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, - Inkscape::Extension::Extension * ext, - Inkscape::XML::Node * xml, - AppearanceMode mode) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), - _value(0.0), _mode(mode), _indent(0), _min(0.0), _max(10.0) +ParamFloat::ParamFloat(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode) + : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + , _value(0.0) + , _mode(mode) + , _min(0.0) + , _max(10.0) { const gchar * defaultval = NULL; if (xml->firstChild() != NULL) { @@ -69,11 +73,6 @@ ParamFloat::ParamFloat (const gchar * name, _min = 0.0; } - const char * indent = xml->attribute("indent"); - if (indent != NULL) { - _indent = atoi(indent) * 12; - } - gchar * pref_name = this->pref_name(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); _value = prefs->getDouble(extension_pref_root + pref_name, _value); @@ -179,7 +178,7 @@ Gtk::Widget * ParamFloat::get_widget(SPDocument * doc, Inkscape::XML::Node * nod auto pfa = new ParamFloatAdjustment(this, doc, node, changeSignal); Glib::RefPtr fadjust(pfa); - + if (_mode == FULL) { UI::Widget::SpinScale *scale = new UI::Widget::SpinScale(_(_text), fadjust, _precision); @@ -192,7 +191,7 @@ Gtk::Widget * ParamFloat::get_widget(SPDocument * doc, Inkscape::XML::Node * nod Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START)); label->show(); - hbox->pack_start(*label, true, true, _indent); + hbox->pack_start(*label, true, true); auto spin = Gtk::manage(new Inkscape::UI::Widget::SpinButton(fadjust, 0.1, _precision)); spin->show(); diff --git a/src/extension/param/float.h b/src/extension/param/float.h index 42b1698b1..7fd86cea7 100644 --- a/src/extension/param/float.h +++ b/src/extension/param/float.h @@ -29,15 +29,17 @@ public: enum AppearanceMode { FULL, MINIMAL }; - ParamFloat (const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, - Inkscape::Extension::Extension * ext, - Inkscape::XML::Node * xml, - AppearanceMode mode); + ParamFloat(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode); + /** Returns \c _value. */ float get(const SPDocument * /*doc*/, const Inkscape::XML::Node * /*node*/) const { return _value; } @@ -60,7 +62,6 @@ private: /** Internal value. */ float _value; AppearanceMode _mode; - int _indent; float _min; float _max; int _precision; diff --git a/src/extension/param/int.cpp b/src/extension/param/int.cpp index 222d4f243..24b1390d1 100644 --- a/src/extension/param/int.cpp +++ b/src/extension/param/int.cpp @@ -27,17 +27,21 @@ namespace Extension { /** Use the superclass' allocator and set the \c _value. */ -ParamInt::ParamInt (const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, - Inkscape::Extension::Extension * ext, - Inkscape::XML::Node * xml, - AppearanceMode mode) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), - _value(0), _mode(mode), _indent(0), _min(0), _max(10) +ParamInt::ParamInt(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode) + : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + , _value(0) + , _mode(mode) + , _min(0) + , _max(10) { const char * defaultval = NULL; if (xml->firstChild() != NULL) { @@ -62,11 +66,6 @@ ParamInt::ParamInt (const gchar * name, _min = 0; } - const char * indent = xml->attribute("indent"); - if (indent != NULL) { - _indent = atoi(indent) * 12; - } - gchar *pref_name = this->pref_name(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); _value = prefs->getInt(extension_pref_root + pref_name, _value); @@ -169,10 +168,10 @@ ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal hbox->pack_start(*scale, false, false); } else if (_mode == MINIMAL) { - + Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START)); label->show(); - hbox->pack_start(*label, true, true, _indent); + hbox->pack_start(*label, true, true); auto spin = Gtk::manage(new Inkscape::UI::Widget::SpinButton(fadjust, 1.0, 0)); spin->show(); diff --git a/src/extension/param/int.h b/src/extension/param/int.h index 3fd6cea9b..40c0395ec 100644 --- a/src/extension/param/int.h +++ b/src/extension/param/int.h @@ -29,15 +29,16 @@ public: enum AppearanceMode { FULL, MINIMAL }; - ParamInt (const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, - Inkscape::Extension::Extension * ext, - Inkscape::XML::Node * xml, - AppearanceMode mode); + ParamInt(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode); /** Returns \c _value. */ int get(const SPDocument * /*doc*/, const Inkscape::XML::Node * /*node*/) const { return _value; } @@ -59,7 +60,6 @@ private: /** Internal value. */ int _value; AppearanceMode _mode; - int _indent; int _min; int _max; }; diff --git a/src/extension/param/notebook.cpp b/src/extension/param/notebook.cpp index 957d12d06..bfdff885a 100644 --- a/src/extension/param/notebook.cpp +++ b/src/extension/param/notebook.cpp @@ -54,8 +54,16 @@ private: public: static ParamNotebookPage * makepage (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext); - ParamNotebookPage(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); + ParamNotebookPage(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml); ~ParamNotebookPage(void); + Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal * changeSignal); void paramString (std::list &list); gchar * get_guitext (void) {return _text;}; @@ -63,8 +71,15 @@ public: }; /* class ParamNotebookPage */ -ParamNotebookPage::ParamNotebookPage (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext) +ParamNotebookPage::ParamNotebookPage(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml) + : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, /*indent*/ 0, ext) { parameters = NULL; @@ -206,9 +221,11 @@ Gtk::Widget * ParamNotebookPage::get_widget(SPDocument * doc, Inkscape::XML::Nod Parameter * param = reinterpret_cast(list->data); Gtk::Widget * widg = param->get_widget(doc, node, changeSignal); if (widg) { - gchar const * tip = param->get_tooltip(); - // printf("Tip: '%s'\n", tip); + int indent = param->get_indent(); + widg->set_margin_left(indent*12); vbox->pack_start(*widg, false, false, 2); + + gchar const * tip = param->get_tooltip(); if (tip) { widg->set_tooltip_text(_(tip)); } else { @@ -224,8 +241,16 @@ Gtk::Widget * ParamNotebookPage::get_widget(SPDocument * doc, Inkscape::XML::Nod } -ParamNotebook::ParamNotebook (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext) +ParamNotebook::ParamNotebook(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml) + : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) { pages = NULL; diff --git a/src/extension/param/notebook.h b/src/extension/param/notebook.h index 3c90964fd..278c4de12 100644 --- a/src/extension/param/notebook.h +++ b/src/extension/param/notebook.h @@ -41,8 +41,17 @@ private: This only gets created if there are pages in this notebook */ public: - ParamNotebook(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); + ParamNotebook(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml); virtual ~ParamNotebook(void); + Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal * changeSignal); /** diff --git a/src/extension/param/parameter.cpp b/src/extension/param/parameter.cpp index a5632a39a..c8b30863b 100644 --- a/src/extension/param/parameter.cpp +++ b/src/extension/param/parameter.cpp @@ -78,6 +78,17 @@ Parameter *Parameter::make(Inkscape::XML::Node *in_repr, Inkscape::Extension::Ex /* else stays false */ } } + int indent = 0; + { + const char *indent_attr = in_repr->attribute("indent"); + if (indent_attr != NULL) { + if (strcmp(indent_attr, "true") == 0) { + indent = 1; + } else { + indent = atoi(indent_attr); + } + } + } const gchar* appearance = in_repr->attribute("appearance"); Parameter::_scope_t scope = Parameter::SCOPE_USER; @@ -96,21 +107,21 @@ Parameter *Parameter::make(Inkscape::XML::Node *in_repr, Inkscape::Extension::Ex Parameter * param = NULL; if (!strcmp(type, "boolean")) { - param = new ParamBool(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); + param = new ParamBool(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr); } else if (!strcmp(type, "int")) { if (appearance && !strcmp(appearance, "full")) { - param = new ParamInt(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamInt::FULL); + param = new ParamInt(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamInt::FULL); } else { - param = new ParamInt(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamInt::MINIMAL); + param = new ParamInt(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamInt::MINIMAL); } } else if (!strcmp(type, "float")) { if (appearance && !strcmp(appearance, "full")) { - param = new ParamFloat(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamFloat::FULL); + param = new ParamFloat(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamFloat::FULL); } else { - param = new ParamFloat(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamFloat::MINIMAL); + param = new ParamFloat(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamFloat::MINIMAL); } } else if (!strcmp(type, "string")) { - param = new ParamString(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); + param = new ParamString(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr); gchar const * max_length = in_repr->attribute("max_length"); if (max_length != NULL) { ParamString * ps = dynamic_cast(param); @@ -118,22 +129,22 @@ Parameter *Parameter::make(Inkscape::XML::Node *in_repr, Inkscape::Extension::Ex } } else if (!strcmp(type, "description")) { if (appearance && !strcmp(appearance, "header")) { - param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamDescription::HEADER); + param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamDescription::HEADER); } else { - param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamDescription::DESC); - } + param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamDescription::DESC); + } } else if (!strcmp(type, "enum")) { - param = new ParamComboBox(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); + param = new ParamComboBox(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr); } else if (!strcmp(type, "notebook")) { - param = new ParamNotebook(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); + param = new ParamNotebook(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr); } else if (!strcmp(type, "optiongroup")) { if (appearance && !strcmp(appearance, "minimal")) { - param = new ParamRadioButton(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamRadioButton::MINIMAL); + param = new ParamRadioButton(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamRadioButton::MINIMAL); } else { - param = new ParamRadioButton(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr, ParamRadioButton::FULL); + param = new ParamRadioButton(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamRadioButton::FULL); } } else if (!strcmp(type, "color")) { - param = new ParamColor(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); + param = new ParamColor(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr); } // Note: param could equal NULL @@ -280,12 +291,13 @@ Parameter::set_color (guint32 in, SPDocument * doc, Inkscape::XML::Node * node) /** Oop, now that we need a parameter, we need it's name. */ -Parameter::Parameter(gchar const * name, gchar const * guitext, gchar const * desc, const Parameter::_scope_t scope, bool gui_hidden, gchar const * gui_tip, Inkscape::Extension::Extension * ext) : +Parameter::Parameter(gchar const * name, gchar const * guitext, gchar const * desc, const Parameter::_scope_t scope, bool gui_hidden, gchar const * gui_tip, int indent, Inkscape::Extension::Extension * ext) : _desc(0), _scope(scope), _text(0), _gui_hidden(gui_hidden), _gui_tip(0), + _indent(indent), extension(ext), _name(0) { @@ -316,6 +328,7 @@ Parameter::Parameter (gchar const * name, gchar const * guitext, Inkscape::Exten _text(0), _gui_hidden(false), _gui_tip(0), + _indent(0), extension(ext), _name(0) { diff --git a/src/extension/param/parameter.h b/src/extension/param/parameter.h index 5e1e3897f..c787a7c97 100644 --- a/src/extension/param/parameter.h +++ b/src/extension/param/parameter.h @@ -37,7 +37,7 @@ class Extension; */ extern Glib::ustring const extension_pref_root; -/** +/** * A class to represent the parameter of an extension. * * This is really a super class that allows them to abstract all @@ -62,6 +62,7 @@ public: const Parameter::_scope_t scope, bool gui_hidden, gchar const *gui_tip, + int indent, Inkscape::Extension::Extension * ext); Parameter(gchar const *name, @@ -144,6 +145,9 @@ public: /** Indicates if the GUI for this parameter is hidden or not */ bool get_gui_hidden() const { return _gui_hidden; } + /** Indentation level of the parameter */ + int get_indent() const { return _indent; } + virtual void string(std::list &list) const; /** @@ -171,6 +175,9 @@ protected: /** A tip for the GUI if there is one. */ gchar * _gui_tip; + /** Indentation level of the parameter. */ + int _indent; + /* **** funcs **** */ diff --git a/src/extension/param/radiobutton.cpp b/src/extension/param/radiobutton.cpp index c54cc0ec3..fd1b6e04e 100644 --- a/src/extension/param/radiobutton.cpp +++ b/src/extension/param/radiobutton.cpp @@ -57,17 +57,20 @@ public: Glib::ustring * guitext; }; -ParamRadioButton::ParamRadioButton (const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, - Inkscape::Extension::Extension * ext, - Inkscape::XML::Node * xml, - AppearanceMode mode) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), - _value(0), _mode(mode), _indent(0), choices(0) +ParamRadioButton::ParamRadioButton(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml, + AppearanceMode mode) + : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + , _value(0) + , _mode(mode) + , choices(0) { // Read XML tree to add enumeration items: // printf("Extension Constructor: "); @@ -118,11 +121,6 @@ ParamRadioButton::ParamRadioButton (const gchar * name, defaultval = (static_cast (choices->data))->value->c_str(); } - const char *indent = xml ? xml->attribute("indent") : NULL; - if (indent != NULL) { - _indent = atoi(indent) * 12; - } - gchar * pref_name = this->pref_name(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); Glib::ustring paramval = prefs->getString(extension_pref_root + pref_name); @@ -310,7 +308,7 @@ Gtk::Widget * ParamRadioButton::get_widget(SPDocument * doc, Inkscape::XML::Node Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START, Gtk::ALIGN_START)); label->show(); - hbox->pack_start(*label, false, false, _indent); + hbox->pack_start(*label, false, false); Gtk::ComboBoxText* cbt = 0; bool comboSet = false; diff --git a/src/extension/param/radiobutton.h b/src/extension/param/radiobutton.h index 0e0f643c9..5e15dcb57 100644 --- a/src/extension/param/radiobutton.h +++ b/src/extension/param/radiobutton.h @@ -40,10 +40,12 @@ public: const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, + int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml, AppearanceMode mode); virtual ~ParamRadioButton(void); + Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal * changeSignal); // Explicitly call superclass version to avoid method being hidden. @@ -63,7 +65,6 @@ private: It is the value of the current selected string */ gchar * _value; AppearanceMode _mode; - int _indent; GSList * choices; /**< A table to store the choice strings */ }; /* class ParamRadioButton */ diff --git a/src/extension/param/string.cpp b/src/extension/param/string.cpp index 1d9205502..f7d3c9662 100644 --- a/src/extension/param/string.cpp +++ b/src/extension/param/string.cpp @@ -24,7 +24,7 @@ namespace Inkscape { namespace Extension { - + /** Free the allocated data. */ ParamString::~ParamString(void) @@ -76,20 +76,23 @@ void ParamString::string(std::string &string) const } /** Initialize the object, to do that, copy the data. */ -ParamString::ParamString (const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) : - Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, ext), - _value(NULL), _indent(0) +ParamString::ParamString(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml) + : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + , _value(NULL) { const char * defaultval = NULL; if (xml->firstChild() != NULL) { defaultval = xml->firstChild()->content(); } - const char * indent = xml->attribute("indent"); - if (indent != NULL) { - _indent = atoi(indent) * 12; - } - gchar * pref_name = this->pref_name(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); Glib::ustring paramval = prefs->getString(extension_pref_root + pref_name); @@ -168,7 +171,7 @@ Gtk::Widget * ParamString::get_widget(SPDocument * doc, Inkscape::XML::Node * no Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4)); Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START)); label->show(); - hbox->pack_start(*label, false, false, _indent); + hbox->pack_start(*label, false, false); ParamStringEntry * textbox = new ParamStringEntry(this, doc, node, changeSignal); textbox->show(); diff --git a/src/extension/param/string.h b/src/extension/param/string.h index 3b137aeac..f5412ebcc 100644 --- a/src/extension/param/string.h +++ b/src/extension/param/string.h @@ -19,12 +19,19 @@ private: /** \brief Internal value. This should point to a string that has been allocated in memory. And should be free'd. */ gchar * _value; - /** \brief Internal value. This indicates the maximum leght of the string. Zero meaning unlimited. + /** \brief Internal value. This indicates the maximum lenth of the string. Zero meaning unlimited. */ - int _indent; gint _max_length; public: - ParamString(const gchar * name, const gchar * guitext, const gchar * desc, const Parameter::_scope_t scope, bool gui_hidden, const gchar * gui_tip, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); + ParamString(const gchar * name, + const gchar * guitext, + const gchar * desc, + const Parameter::_scope_t scope, + bool gui_hidden, + const gchar * gui_tip, + int indent, + Inkscape::Extension::Extension * ext, + Inkscape::XML::Node * xml); virtual ~ParamString(void); /** \brief Returns \c _value, with a \i const to protect it. */ -- cgit v1.2.3 From 2295a47ec000543b6316213e54f715dc4d1e64c9 Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Sun, 12 Feb 2017 19:51:27 +0100 Subject: Extensions: Harmonize appearance and try to simplify layouting a bit (bzr r15509) --- src/extension/extension.cpp | 6 ++++-- src/extension/param/notebook.cpp | 7 ++++--- src/extension/param/parameter.h | 9 +++++++++ src/extension/prefdialog.cpp | 12 ++++++------ 4 files changed, 23 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/extension/extension.cpp b/src/extension/extension.cpp index 2d020aa0e..8b5a687ef 100644 --- a/src/extension/extension.cpp +++ b/src/extension/extension.cpp @@ -694,8 +694,8 @@ public: */ void addWidget(Gtk::Widget *widg, gchar const *tooltip, int indent) { if (widg) { - widg->set_margin_left(indent*12); - this->pack_start(*widg, false, false, 2); + widg->set_margin_left(indent * Parameter::GUI_INDENTATION); + this->pack_start(*widg, false, false, 0); if (tooltip) { widg->set_tooltip_text(_(tooltip)); } else { @@ -722,6 +722,8 @@ Extension::autogui (SPDocument * doc, Inkscape::XML::Node * node, sigc::signalset_border_width(Parameter::GUI_BOX_MARGIN); + agui->set_spacing(Parameter::GUI_BOX_SPACING); //go through the list of parameters to see if there are any non-hidden ones for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) { diff --git a/src/extension/param/notebook.cpp b/src/extension/param/notebook.cpp index bfdff885a..8ef48926e 100644 --- a/src/extension/param/notebook.cpp +++ b/src/extension/param/notebook.cpp @@ -214,7 +214,8 @@ Gtk::Widget * ParamNotebookPage::get_widget(SPDocument * doc, Inkscape::XML::Nod } Gtk::VBox * vbox = Gtk::manage(new Gtk::VBox); - vbox->set_border_width(5); + vbox->set_border_width(Parameter::GUI_BOX_MARGIN); + vbox->set_spacing(Parameter::GUI_BOX_SPACING); // add parameters onto page (if any) for (GSList * list = parameters; list != NULL; list = g_slist_next(list)) { @@ -222,8 +223,8 @@ Gtk::Widget * ParamNotebookPage::get_widget(SPDocument * doc, Inkscape::XML::Nod Gtk::Widget * widg = param->get_widget(doc, node, changeSignal); if (widg) { int indent = param->get_indent(); - widg->set_margin_left(indent*12); - vbox->pack_start(*widg, false, false, 2); + widg->set_margin_left(indent * Parameter::GUI_INDENTATION); + vbox->pack_start(*widg, false, false, 0); gchar const * tip = param->get_tooltip(); if (tip) { diff --git a/src/extension/param/parameter.h b/src/extension/param/parameter.h index c787a7c97..edbd9ce08 100644 --- a/src/extension/param/parameter.h +++ b/src/extension/param/parameter.h @@ -159,6 +159,15 @@ public: /** All the code in Notebook::get_param to get the notebook content. */ virtual Parameter *get_param(gchar const *name); + + /** Recommended margin of boxes containing parameters */ + const static int GUI_BOX_MARGIN = 10; + /** Recommended spacing between individual parameters when packing into boxes */ + const static int GUI_BOX_SPACING = 4; + /** Recommended indentation width of parameters */ + const static int GUI_INDENTATION = 12; + + protected: /** Description of the parameter. */ gchar * _desc; diff --git a/src/extension/prefdialog.cpp b/src/extension/prefdialog.cpp index fcc88853d..e98d88b2d 100644 --- a/src/extension/prefdialog.cpp +++ b/src/extension/prefdialog.cpp @@ -59,11 +59,10 @@ PrefDialog::PrefDialog (Glib::ustring name, gchar const * help, Gtk::Widget * co controls = _effect->get_imp()->prefs_effect(_effect, SP_ACTIVE_DESKTOP, &_signal_param_change, NULL); _signal_param_change.connect(sigc::mem_fun(this, &PrefDialog::param_change)); } - - hbox->pack_start(*controls, true, true, 6); + hbox->pack_start(*controls, true, true, 0); hbox->show(); - this->get_content_area()->pack_start(*hbox, true, true, 6); + this->get_content_area()->pack_start(*hbox, true, true, 0); /* Gtk::Button * help_button = add_button(Gtk::Stock::HELP, Gtk::RESPONSE_HELP); @@ -88,15 +87,16 @@ PrefDialog::PrefDialog (Glib::ustring name, gchar const * help, Gtk::Widget * co auto sep = Gtk::manage(new Gtk::Separator()); sep->show(); - this->get_content_area()->pack_start(*sep, true, true, 4); + this->get_content_area()->pack_start(*sep, false, false, Parameter::GUI_BOX_SPACING); hbox = Gtk::manage(new Gtk::HBox()); + hbox->set_border_width(Parameter::GUI_BOX_MARGIN); _button_preview = _param_preview->get_widget(NULL, NULL, &_signal_preview); _button_preview->show(); - hbox->pack_start(*_button_preview, true, true,6); + hbox->pack_start(*_button_preview, true, true, 0); hbox->show(); - this->get_content_area()->pack_start(*hbox, true, true, 6); + this->get_content_area()->pack_start(*hbox, false, false, 0); Gtk::Box * hbox = dynamic_cast(_button_preview); if (hbox != NULL) { -- cgit v1.2.3 From c85e99bd33de9d7d2129bf21cd29cca9f4c50f79 Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Mon, 13 Feb 2017 02:39:21 +0100 Subject: Extensions: Make "int" and "float" parameters specifying 'appearance="full"'expand in horizontal direction when the window is expanded (bzr r15510) --- src/extension/param/float.cpp | 2 +- src/extension/param/int.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/extension/param/float.cpp b/src/extension/param/float.cpp index fd82ab312..dd7087968 100644 --- a/src/extension/param/float.cpp +++ b/src/extension/param/float.cpp @@ -184,7 +184,7 @@ Gtk::Widget * ParamFloat::get_widget(SPDocument * doc, Inkscape::XML::Node * nod UI::Widget::SpinScale *scale = new UI::Widget::SpinScale(_(_text), fadjust, _precision); scale->set_size_request(400, -1); scale->show(); - hbox->pack_start(*scale, false, false); + hbox->pack_start(*scale, true, true); } else if (_mode == MINIMAL) { diff --git a/src/extension/param/int.cpp b/src/extension/param/int.cpp index 24b1390d1..ba51df2a3 100644 --- a/src/extension/param/int.cpp +++ b/src/extension/param/int.cpp @@ -165,7 +165,7 @@ ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal UI::Widget::SpinScale *scale = new UI::Widget::SpinScale(_(_text), fadjust, 0); scale->set_size_request(400, -1); scale->show(); - hbox->pack_start(*scale, false, false); + hbox->pack_start(*scale, true, true); } else if (_mode == MINIMAL) { -- cgit v1.2.3 From a2e57d792590665163dd07eb5e926017e40ccb90 Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Mon, 13 Feb 2017 02:46:19 +0100 Subject: Extensions: Work around gtk3 width/height calculation bug for long labels Also use constants for most dimensions so they can easily be chaned in future. (bzr r15511) --- src/extension/param/bool.cpp | 2 +- src/extension/param/color.cpp | 4 ++-- src/extension/param/description.cpp | 15 ++++++++++++++- src/extension/param/enum.cpp | 2 +- src/extension/param/float.cpp | 2 +- src/extension/param/int.cpp | 2 +- src/extension/param/parameter.h | 10 +++++++--- src/extension/param/radiobutton.cpp | 2 +- src/extension/param/string.cpp | 2 +- src/extension/prefdialog.cpp | 2 ++ 10 files changed, 31 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/extension/param/bool.cpp b/src/extension/param/bool.cpp index 833215546..9f8d3dcc0 100644 --- a/src/extension/param/bool.cpp +++ b/src/extension/param/bool.cpp @@ -133,7 +133,7 @@ Gtk::Widget *ParamBool::get_widget(SPDocument * doc, Inkscape::XML::Node * node, return NULL; } - auto hbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 4)); + auto hbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, Parameter::GUI_PARAM_WIDGETS_SPACING)); hbox->set_homogeneous(false); Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START)); diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp index 041cd5509..fd88e9adb 100644 --- a/src/extension/param/color.cpp +++ b/src/extension/param/color.cpp @@ -106,9 +106,9 @@ Gtk::Widget *ParamColor::get_widget( SPDocument * /*doc*/, Inkscape::XML::Node * _color_changed.block(false); } - Gtk::HBox *hbox = Gtk::manage(new Gtk::HBox(false, 4)); + Gtk::HBox *hbox = Gtk::manage(new Gtk::HBox(false, Parameter::GUI_PARAM_WIDGETS_SPACING)); Gtk::Widget *selector = Gtk::manage(new ColorNotebook(_color)); - hbox->pack_start (*selector, true, true, 0); + hbox->pack_start(*selector, true, true, 0); selector->show(); hbox->show(); return hbox; diff --git a/src/extension/param/description.cpp b/src/extension/param/description.cpp index 7f7d2d976..898544e94 100644 --- a/src/extension/param/description.cpp +++ b/src/extension/param/description.cpp @@ -84,9 +84,22 @@ ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node label = Gtk::manage(new Gtk::Label(newguitext, Gtk::ALIGN_START)); } label->set_line_wrap(); + label->set_xalign(0); + + // TODO: Ugly "fix" for gtk3 width/height calculation of labels. + // - If not applying any limits long labels will make the window grow horizontally until it uses up + // most of the available space (i.e. most of the screen area) which is ridicously wide + // - By using "set_default_size(0,0)" in prefidalog.cpp we tell the window to shrink as much as possible, + // however this can result in a much to narrow dialog instead and much unnecessary wrapping + // - Here we set a lower limit of GUI_MAX_LINE_LENGTH characters per line that long texts will always use + // This means texts can not shrink anymore (they can still grow, though) and it's also necessary + // to prevent https://bugzilla.gnome.org/show_bug.cgi?id=773572 + int len = newguitext.length(); + label->set_width_chars(len > Parameter::GUI_MAX_LINE_LENGTH ? Parameter::GUI_MAX_LINE_LENGTH : len); + label->show(); - Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4)); + Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox()); hbox->pack_start(*label, true, true); hbox->show(); diff --git a/src/extension/param/enum.cpp b/src/extension/param/enum.cpp index 9f254041a..a26458c35 100644 --- a/src/extension/param/enum.cpp +++ b/src/extension/param/enum.cpp @@ -250,7 +250,7 @@ Gtk::Widget *ParamComboBox::get_widget(SPDocument * doc, Inkscape::XML::Node * n return NULL; } - Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4)); + Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, Parameter::GUI_PARAM_WIDGETS_SPACING)); Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START)); label->show(); hbox->pack_start(*label, false, false); diff --git a/src/extension/param/float.cpp b/src/extension/param/float.cpp index dd7087968..e3fdba826 100644 --- a/src/extension/param/float.cpp +++ b/src/extension/param/float.cpp @@ -174,7 +174,7 @@ Gtk::Widget * ParamFloat::get_widget(SPDocument * doc, Inkscape::XML::Node * nod return NULL; } - Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4)); + Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, Parameter::GUI_PARAM_WIDGETS_SPACING)); auto pfa = new ParamFloatAdjustment(this, doc, node, changeSignal); Glib::RefPtr fadjust(pfa); diff --git a/src/extension/param/int.cpp b/src/extension/param/int.cpp index ba51df2a3..538ddc08d 100644 --- a/src/extension/param/int.cpp +++ b/src/extension/param/int.cpp @@ -155,7 +155,7 @@ ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal return NULL; } - Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4)); + Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, Parameter::GUI_PARAM_WIDGETS_SPACING)); auto pia = new ParamIntAdjustment(this, doc, node, changeSignal); Glib::RefPtr fadjust(pia); diff --git a/src/extension/param/parameter.h b/src/extension/param/parameter.h index edbd9ce08..c107f24f9 100644 --- a/src/extension/param/parameter.h +++ b/src/extension/param/parameter.h @@ -160,12 +160,16 @@ public: virtual Parameter *get_param(gchar const *name); - /** Recommended margin of boxes containing parameters */ + /** Recommended margin of boxes containing multiple Parameters (in px) */ const static int GUI_BOX_MARGIN = 10; - /** Recommended spacing between individual parameters when packing into boxes */ + /** Recommended spacing between multiple Parameters packed into a box (in px) */ const static int GUI_BOX_SPACING = 4; - /** Recommended indentation width of parameters */ + /** Recommended spacing between the widgets making up a signle Parameter (e.g. label and input) (in px) */ + const static int GUI_PARAM_WIDGETS_SPACING = 4; + /** Recommended indentation width of parameters (in px) */ const static int GUI_INDENTATION = 12; + /** Recommended maximum line lenght for wrapping textual parameters (in chars) */ + const static int GUI_MAX_LINE_LENGTH = 60; protected: diff --git a/src/extension/param/radiobutton.cpp b/src/extension/param/radiobutton.cpp index fd1b6e04e..178dc20e8 100644 --- a/src/extension/param/radiobutton.cpp +++ b/src/extension/param/radiobutton.cpp @@ -301,7 +301,7 @@ Gtk::Widget * ParamRadioButton::get_widget(SPDocument * doc, Inkscape::XML::Node return NULL; } - auto hbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, 4)); + auto hbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL, Parameter::GUI_PARAM_WIDGETS_SPACING)); hbox->set_homogeneous(false); auto vbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0)); vbox->set_homogeneous(false); diff --git a/src/extension/param/string.cpp b/src/extension/param/string.cpp index f7d3c9662..0c5238f99 100644 --- a/src/extension/param/string.cpp +++ b/src/extension/param/string.cpp @@ -168,7 +168,7 @@ Gtk::Widget * ParamString::get_widget(SPDocument * doc, Inkscape::XML::Node * no return NULL; } - Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, 4)); + Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false, Parameter::GUI_PARAM_WIDGETS_SPACING)); Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START)); label->show(); hbox->pack_start(*label, false, false); diff --git a/src/extension/prefdialog.cpp b/src/extension/prefdialog.cpp index e98d88b2d..2bdbb081e 100644 --- a/src/extension/prefdialog.cpp +++ b/src/extension/prefdialog.cpp @@ -50,6 +50,8 @@ PrefDialog::PrefDialog (Glib::ustring name, gchar const * help, Gtk::Widget * co _effect(effect), _exEnv(NULL) { + this->set_default_size(0,0); // we want the window to be as small as possible instead of clobbering up space + Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox()); if (controls == NULL) { if (_effect == NULL) { -- cgit v1.2.3 From dbb6ce3b9bd176281fba0f41b4a7aa92b6d35ff3 Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Mon, 13 Feb 2017 05:25:05 +0100 Subject: Extensions: Fix for old versions of gtkmm Use "Gtk::Misc::set_alignment()" as "Gtk::Label::set_xalign()" is only available since gtkmm 3.16 (bzr r15512) --- src/extension/param/description.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/extension/param/description.cpp b/src/extension/param/description.cpp index 898544e94..5923adea8 100644 --- a/src/extension/param/description.cpp +++ b/src/extension/param/description.cpp @@ -84,7 +84,8 @@ ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node label = Gtk::manage(new Gtk::Label(newguitext, Gtk::ALIGN_START)); } label->set_line_wrap(); - label->set_xalign(0); + //label->set_xalign(0); // requires gtkmm 3.16 + label->set_alignment(0); // TODO: Ugly "fix" for gtk3 width/height calculation of labels. // - If not applying any limits long labels will make the window grow horizontally until it uses up -- cgit v1.2.3 From 435717a3469ebb96ce8b8d30fc50d6151f9cbfbb Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Mon, 13 Feb 2017 22:35:48 +0100 Subject: Extensions: Do not require name for pure UI elements (i.e. parameters that do not store a value and therefore do not need to have a name) (bzr r15515) --- src/extension/param/parameter.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/extension/param/parameter.cpp b/src/extension/param/parameter.cpp index c8b30863b..9fbe662f7 100644 --- a/src/extension/param/parameter.cpp +++ b/src/extension/param/parameter.cpp @@ -50,10 +50,17 @@ Parameter *Parameter::make(Inkscape::XML::Node *in_repr, Inkscape::Extension::Ex const char *name = in_repr->attribute("name"); const char *type = in_repr->attribute("type"); - // In this case we just don't have enough information - if (!name || !type) { + // we can't create a parameter without type + if (!type) { return NULL; } + // also require name unless it's a pure UI element that does not store its value + if (!name) { + static std::vector ui_elements = {"description"}; + if (std::find(ui_elements.begin(), ui_elements.end(), type) == ui_elements.end()) { + return NULL; + } + } const char *guitext = in_repr->attribute("gui-text"); if (guitext == NULL) { -- cgit v1.2.3 From 38ecca9e4639b8aecc55a4becfc1ed9b2793fadc Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Mon, 13 Feb 2017 22:37:42 +0100 Subject: AboutBox: Remove superfluous space in website URL (bzr r15516) --- src/ui/dialog/aboutbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/dialog/aboutbox.cpp b/src/ui/dialog/aboutbox.cpp index 40b948a23..805bfb562 100644 --- a/src/ui/dialog/aboutbox.cpp +++ b/src/ui/dialog/aboutbox.cpp @@ -115,7 +115,7 @@ AboutBox::AboutBox() : Gtk::Dialog(_("About Inkscape")) { Gtk::Label *link = new Gtk::Label(); const gchar *website_link = - " https://www.inkscape.org"; + "https://www.inkscape.org"; link->set_markup(website_link); link->set_alignment(Gtk::ALIGN_END); -- cgit v1.2.3 From 419d9545814cb07c252422b20a77063f0f6101d1 Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Tue, 14 Feb 2017 00:01:59 +0100 Subject: Extensions: Fix potential security issue with "description" parameters. When using 'appearance="header"' arbitrary markup could be inlcuded (including URLs) (bzr r15518) --- src/extension/param/description.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/extension/param/description.cpp b/src/extension/param/description.cpp index 5923adea8..3d970b204 100644 --- a/src/extension/param/description.cpp +++ b/src/extension/param/description.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "xml/node.h" #include "extension/extension.h" @@ -74,18 +75,17 @@ ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node newguitext = _(_value); } - Gtk::Label * label; + Gtk::Label * label = Gtk::manage(new Gtk::Label()); if (_mode == HEADER) { - label = Gtk::manage(new Gtk::Label(Glib::ustring("") +newguitext + Glib::ustring(""), Gtk::ALIGN_START)); + label->set_markup(Glib::ustring("") + Glib::Markup::escape_text(newguitext) + Glib::ustring("")); label->set_margin_top(5); label->set_margin_bottom(5); - label->set_use_markup(true); } else { - label = Gtk::manage(new Gtk::Label(newguitext, Gtk::ALIGN_START)); + label->set_text(newguitext); } label->set_line_wrap(); //label->set_xalign(0); // requires gtkmm 3.16 - label->set_alignment(0); + label->set_alignment(Gtk::ALIGN_START); // TODO: Ugly "fix" for gtk3 width/height calculation of labels. // - If not applying any limits long labels will make the window grow horizontally until it uses up -- cgit v1.2.3 From 24d66b5173963dcb69545614449de91da5397db6 Mon Sep 17 00:00:00 2001 From: Eduard Braun Date: Tue, 14 Feb 2017 00:42:11 +0100 Subject: Extensions: Add 'appearance="url"' to desccription parameters. It allows to create and add a clickable plain text link to extensions The description parameter's text is escaped and converted to a URL as-is preventing potential security issues The Scour extension shows a first example implementation (bzr r15519) --- src/extension/param/description.cpp | 3 +++ src/extension/param/description.h | 2 +- src/extension/param/parameter.cpp | 12 ++++++++---- 3 files changed, 12 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/extension/param/description.cpp b/src/extension/param/description.cpp index 3d970b204..7cf818280 100644 --- a/src/extension/param/description.cpp +++ b/src/extension/param/description.cpp @@ -80,6 +80,9 @@ ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node label->set_markup(Glib::ustring("") + Glib::Markup::escape_text(newguitext) + Glib::ustring("")); label->set_margin_top(5); label->set_margin_bottom(5); + } else if (_mode == URL) { + Glib::ustring escaped_url = Glib::Markup::escape_text(newguitext); + label->set_markup(Glib::ustring::compose("%1", escaped_url)); } else { label->set_text(newguitext); } diff --git a/src/extension/param/description.h b/src/extension/param/description.h index aa3c3a798..c6c5f4013 100644 --- a/src/extension/param/description.h +++ b/src/extension/param/description.h @@ -27,7 +27,7 @@ namespace Extension { class ParamDescription : public Parameter { public: enum AppearanceMode { - DESC, HEADER + DESC, HEADER, URL }; ParamDescription(const gchar * name, const gchar * guitext, diff --git a/src/extension/param/parameter.cpp b/src/extension/param/parameter.cpp index 9fbe662f7..0eb491078 100644 --- a/src/extension/param/parameter.cpp +++ b/src/extension/param/parameter.cpp @@ -135,11 +135,15 @@ Parameter *Parameter::make(Inkscape::XML::Node *in_repr, Inkscape::Extension::Ex ps->setMaxLength(atoi(max_length)); } } else if (!strcmp(type, "description")) { - if (appearance && !strcmp(appearance, "header")) { - param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamDescription::HEADER); - } else { - param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamDescription::DESC); + ParamDescription::AppearanceMode appearance_mode = ParamDescription::DESC; + if (appearance) { + if (!strcmp(appearance, "header")) { + appearance_mode = ParamDescription::HEADER; + } else if (!strcmp(appearance, "url")) { + appearance_mode = ParamDescription::URL; + } } + param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, appearance_mode); } else if (!strcmp(type, "enum")) { param = new ParamComboBox(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr); } else if (!strcmp(type, "notebook")) { -- cgit v1.2.3 From db37e627f21d79c6968f681725c7a4dd8de21081 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Tue, 14 Feb 2017 16:39:13 +0100 Subject: Rewrite and cleanup of style dialog. Still WIP. Missing undo and document tracking. (bzr r15520) --- src/ui/dialog/cssdialog.cpp | 53 +- src/ui/dialog/cssdialog.h | 35 +- src/ui/dialog/styledialog.cpp | 1529 +++++++++++++++++++---------------------- src/ui/dialog/styledialog.h | 93 +-- 4 files changed, 791 insertions(+), 919 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/cssdialog.cpp b/src/ui/dialog/cssdialog.cpp index fa266b012..d0ae822bd 100644 --- a/src/ui/dialog/cssdialog.cpp +++ b/src/ui/dialog/cssdialog.cpp @@ -3,8 +3,10 @@ */ /* Authors: * Kamalpreet Kaur Grewal + * Tavmjong Bah * * Copyright (C) Kamalpreet Kaur Grewal 2016 + * Copyright (C) Tavmjong Bah 2017 * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -21,23 +23,6 @@ namespace Inkscape { namespace UI { namespace Dialog { -/** - * @brief CssDialog::_styleButton - * @param btn - * @param iconName - * @param tooltip - * This function sets the style of '+'button at the bottom of dialog. - */ -void CssDialog::_styleButton(Gtk::Button& btn, char const* iconName, - char const* tooltip) -{ - GtkWidget *child = sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName); - gtk_widget_show(child); - btn.add(*manage(Glib::wrap(child))); - btn.set_relief(Gtk::RELIEF_NONE); - btn.set_tooltip_text(tooltip); -} - /** * Constructor * A treeview whose each row corresponds to a CSS property of selector selected. @@ -60,8 +45,7 @@ CssDialog::CssDialog(): _store = Gtk::ListStore::create(_cssColumns); _treeView.set_model(_store); - Inkscape::UI::Widget::AddToIcon * addRenderer = manage(new Inkscape::UI:: - Widget::AddToIcon()); + Inkscape::UI::Widget::AddToIcon * addRenderer = manage(new Inkscape::UI::Widget::AddToIcon()); addRenderer->property_active() = false; int addCol = _treeView.append_column("Unset Property", *addRenderer) - 1; @@ -74,6 +58,10 @@ CssDialog::CssDialog(): int nameColNum = _treeView.append_column("Property", *_textRenderer) - 1; _propCol = _treeView.get_column(nameColNum); + if (_propCol) { + _propCol->add_attribute(_textRenderer->property_text(), + _cssColumns._propertyLabel); + } Gtk::Button* create = manage(new Gtk::Button()); _styleButton(*create, "list-add", "Add a new property"); @@ -83,12 +71,12 @@ CssDialog::CssDialog(): _getContents()->pack_start(_mainBox, Gtk::PACK_EXPAND_WIDGET); - _targetDesktop = getDesktop(); - setDesktop(_targetDesktop); + setDesktop(getDesktop()); create->signal_clicked().connect(sigc::mem_fun(*this, &CssDialog::_addProperty)); } + /** * @brief CssDialog::~CssDialog * Class destructor @@ -98,6 +86,7 @@ CssDialog::~CssDialog() setDesktop(NULL); } + /** * @brief CssDialog::setDesktop * @param desktop @@ -108,16 +97,34 @@ void CssDialog::setDesktop(SPDesktop* desktop) _desktop = desktop; } + +/** + * @brief CssDialog::_styleButton + * @param btn + * @param iconName + * @param tooltip + * This function sets the style of '+'button at the bottom of dialog. + */ +void CssDialog::_styleButton(Gtk::Button& btn, char const* iconName, + char const* tooltip) +{ + GtkWidget *child = sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName); + gtk_widget_show(child); + btn.add(*manage(Glib::wrap(child))); + btn.set_relief(Gtk::RELIEF_NONE); + btn.set_tooltip_text(tooltip); +} + + /** * @brief CssDialog::_addProperty * This function is a slot to signal_clicked for '+' button at the bottom of CSS * panel. A new row is added, double clicking which text for new property can be - * added. _newProperty is set to true in which case the value is appended. + * added. */ void CssDialog::_addProperty() { _propRow = *(_store->append()); - _newProperty = true; } } // namespace Dialog diff --git a/src/ui/dialog/cssdialog.h b/src/ui/dialog/cssdialog.h index 3bbab5031..1f8b7ca98 100644 --- a/src/ui/dialog/cssdialog.h +++ b/src/ui/dialog/cssdialog.h @@ -3,8 +3,10 @@ */ /* Authors: * Kamalpreet Kaur Grewal + * Tavmjong Bah * * Copyright (C) Kamalpreet Kaur Grewal 2016 + * Copyright (C) Tavmjong Bah 2017 * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -38,32 +40,39 @@ public: ~CssDialog(); static CssDialog &getInstance() { return *new CssDialog(); } - void setDesktop(SPDesktop* desktop); - class CssColumns : public Gtk::TreeModel::ColumnRecord - { + // Data structure + class CssColumns : public Gtk::TreeModel::ColumnRecord { public: - CssColumns() - { add(_colUnsetProp); add(_propertyLabel); } + CssColumns() { + add(_colUnsetProp); + add(_propertyLabel); + } Gtk::TreeModelColumn _colUnsetProp; Gtk::TreeModelColumn _propertyLabel; }; - - SPDesktop* _desktop; - SPDesktop* _targetDesktop; CssColumns _cssColumns; - Gtk::VBox _mainBox; - Gtk::HBox _buttonBox; + + // TreeView Gtk::TreeView _treeView; Glib::RefPtr _store; - Gtk::ScrolledWindow _scrolledWindow; Gtk::TreeModel::Row _propRow; Gtk::CellRendererText *_textRenderer; Gtk::TreeViewColumn *_propCol; - Glib::ustring _editedProp; - bool _newProperty; + // Widgets + Gtk::VBox _mainBox; + Gtk::ScrolledWindow _scrolledWindow; + Gtk::HBox _buttonBox; + + // Variables - Inkscape + SPDesktop* _desktop; + + // Helper functions + void setDesktop(SPDesktop* desktop); void _styleButton(Gtk::Button& btn, char const* iconName, char const* tooltip); + + // Signal handlers void _addProperty(); }; diff --git a/src/ui/dialog/styledialog.cpp b/src/ui/dialog/styledialog.cpp index 7b68cfe53..581911a1b 100644 --- a/src/ui/dialog/styledialog.cpp +++ b/src/ui/dialog/styledialog.cpp @@ -3,8 +3,10 @@ */ /* Authors: * Kamalpreet Kaur Grewal + * Tavmjong Bah * * Copyright (C) Kamalpreet Kaur Grewal 2016 + * Copyright (C) Tavmjong Bah 2017 * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -21,6 +23,8 @@ #include #include +//#define DEBUG_STYLEDIALOG + using Inkscape::Util::List; using Inkscape::XML::AttributeRecord; @@ -35,22 +39,6 @@ namespace Inkscape { namespace UI { namespace Dialog { -/** - * @brief StyleDialog::_styleButton - * @param btn - * @param iconName - * @param tooltip - * This function sets the style of '+' and '-' buttons at the bottom of dialog. - */ -void StyleDialog::_styleButton(Gtk::Button& btn, char const* iconName, - char const* tooltip) -{ - GtkWidget *child = sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName); - gtk_widget_show(child); - btn.add(*manage(Glib::wrap(child))); - btn.set_relief(Gtk::RELIEF_NONE); - btn.set_tooltip_text (tooltip); -} /** * Constructor @@ -60,42 +48,39 @@ void StyleDialog::_styleButton(Gtk::Button& btn, char const* iconName, */ StyleDialog::StyleDialog() : UI::Widget::Panel("", "/dialogs/style", SP_VERB_DIALOG_STYLE), - _desktop(0) + _desktop(0), + _updating(false) { - set_size_request(200, 200); - - _paned.pack1(_mainBox, Gtk::SHRINK); - _mainBox.pack_start(_scrolledWindow, Gtk::PACK_EXPAND_WIDGET); - _treeView.set_headers_visible(false); - _scrolledWindow.add(_treeView); - _scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); - - _store = Gtk::TreeStore::create(_mColumns); - _treeView.set_model(_store); + // Tree Inkscape::UI::Widget::AddToIcon * addRenderer = manage( new Inkscape::UI::Widget::AddToIcon() ); addRenderer->property_active() = true; + _store = Gtk::TreeStore::create(_mColumns); + _treeView.set_model(_store); + _treeView.set_headers_visible(false); int addCol = _treeView.append_column("type", *addRenderer) - 1; - Gtk::TreeViewColumn *col = _treeView.get_column(addCol); if ( col ) { col->add_attribute( addRenderer->property_active(), _mColumns._colAddRemove ); } - - _treeView.append_column("Selector Name", _mColumns._selectorLabel); + _treeView.append_column("Selector Name", _mColumns._colSelector); _treeView.set_expander_column(*(_treeView.get_column(1))); + + // Pack widgets + _paned.pack1(_mainBox, Gtk::SHRINK); + _mainBox.pack_start(_scrolledWindow, Gtk::PACK_EXPAND_WIDGET); + _scrolledWindow.add(_treeView); + _scrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); create = manage( new Gtk::Button() ); _styleButton(*create, "list-add", "Add a new CSS Selector"); - create->signal_clicked().connect(sigc::mem_fun(*this, - &StyleDialog::_addSelector)); + create->signal_clicked().connect(sigc::mem_fun(*this, &StyleDialog::_addSelector)); del = manage( new Gtk::Button() ); _styleButton(*del, "list-remove", "Remove a CSS Selector"); - del->signal_clicked().connect(sigc::mem_fun(*this, - &StyleDialog::_delSelector)); + del->signal_clicked().connect(sigc::mem_fun(*this, &StyleDialog::_delSelector)); del->set_sensitive(false); _mainBox.pack_end(_buttonBox, Gtk::PACK_SHRINK); @@ -105,8 +90,40 @@ StyleDialog::StyleDialog() : _getContents()->pack_start(_paned, Gtk::PACK_EXPAND_WIDGET); - _targetDesktop = getDesktop(); - setDesktop(_targetDesktop); + // Dialog size request + Gtk::Requisition sreq1, sreq2; + get_preferred_size(sreq1, sreq2); + int minWidth = 200; + int minHeight = 300; + minWidth = (sreq2.width > minWidth ? sreq2.width : minWidth ); + minHeight = (sreq2.height > minHeight ? sreq2.height : minHeight); + set_size_request(minWidth, minHeight); + + // Signal handlers + _treeView.signal_button_release_event().connect( // Needs to be release, not press. + sigc::mem_fun(*this, &StyleDialog::_handleButtonEvent), + false); + + _treeView.signal_button_release_event().connect_notify( + sigc::mem_fun(*this, &StyleDialog::_buttonEventsSelectObjs), + false); + + _treeView.get_selection()->signal_changed().connect( + sigc::mem_fun(*this, &StyleDialog::_selChanged)); + + // Add CSS dialog + _cssPane = new CssDialog; + _paned.pack2(*_cssPane, Gtk::SHRINK); + _cssPane->show_all(); + + _cssPane->_textRenderer->signal_edited().connect( + sigc::mem_fun(*this, &StyleDialog::_handleEdited)); + _cssPane->_treeView.signal_button_release_event().connect( + sigc::mem_fun(*this, &StyleDialog::_delProperty), + false); + + // Document & Desktop TO DO: Fix this brokeness + setDesktop(getDesktop()); // Adds signal handler /** * @brief document @@ -114,27 +131,17 @@ StyleDialog::StyleDialog() : * and is then used to populate the treeview with the already existing * selectors in the style element. */ - _styleExists = false; - _document = _targetDesktop->doc(); - _selectorValue = _populateTree(_getSelectorVec()); + _document = _desktop->doc(); - _treeView.signal_button_press_event().connect(sigc::mem_fun(*this, - &StyleDialog:: - _handleButtonEvent), - false); + _readStyleElement(); - _treeView.signal_button_press_event().connect_notify(sigc::mem_fun - (*this, &StyleDialog:: - _buttonEventsSelectObjs), - false); - - _cssPane = new CssDialog; + if (!_store->children().empty()) { + del->set_sensitive(true); + } - _treeView.get_selection()->signal_changed().connect(sigc::mem_fun(*this, - &StyleDialog:: - _selChanged)); } + /** * @brief StyleDialog::~StyleDialog * Class destructor @@ -144,429 +151,619 @@ StyleDialog::~StyleDialog() setDesktop(NULL); } + /** * @brief StyleDialog::setDesktop * @param desktop - * This function sets the 'desktop' for the Style Dialog. + * Set the 'desktop' for the Style Dialog. */ void StyleDialog::setDesktop( SPDesktop* desktop ) { +#ifdef DEBUG_STYLEDIALOOG + std::cout << "StyleDialog::setDesktop" << std::endl; +#endif Panel::setDesktop(desktop); _desktop = Panel::getDesktop(); - _desktop->getSelection()->connectChanged(sigc::mem_fun(*this, &StyleDialog:: - _selectRow)); + _desktop->getSelection()->connectChanged(sigc::mem_fun(*this, &StyleDialog::_selectRow)); } + /** - * @brief StyleDialog::_addSelector - * This function is the slot to the signal emitted when '+' at the bottom of - * the dialog is clicked. + * @brief StyleDialog::_styleTextNode + * @return Inkscape::XML::Node* pointing to a style element's text node. + * Returns the style element's text node. If there is no style element, one is created. + * Ditto for text node. */ -void StyleDialog::_addSelector() +Inkscape::XML::Node* StyleDialog::_getStyleTextNode() { - Gtk::TreeModel::Row row = *(_store->append()); + Inkscape::XML::Node *root = _document->getReprRoot(); + for (unsigned i = 0; i < root->childCount(); ++i) { + if (Glib::ustring(root->nthChild(i)->name()) == "svg:style") { + Inkscape::XML::Node * styleNode = root->nthChild(i); + + for (unsigned j = 0; j < styleNode->childCount(); ++j) { + if (styleNode->nthChild(j)->type() == Inkscape::XML::TEXT_NODE) { + return styleNode->nthChild(j); + } + } - /** - * On clicking '+' button, an entrybox with default text opens up. If an - * object is already selected, a selector with value in the entry - * is added to a new style element. - */ - Gtk::Dialog *textDialogPtr = new Gtk::Dialog(); - textDialogPtr->add_button("Add", Gtk::RESPONSE_OK); + // Style element found but does not contain text node! + std::cerr << "StyleDialog::_getStyleTextNode(): No text node!" << std::endl; + Inkscape::XML::Node *textNode = _document->getReprDoc()->createTextNode(""); + styleNode->appendChild(textNode); + Inkscape::GC::release(textNode); - Gtk::Entry *textEditPtr = manage ( new Gtk::Entry() ); - textDialogPtr->get_vbox()->pack_start(*textEditPtr, Gtk::PACK_SHRINK); + return textNode; + } + } - Gtk::Label *textLabelPtr = manage ( new Gtk::Label( - _("Invalid entry: Not an id (#), class (.), or element CSS selector.") - ) ); - textDialogPtr->get_vbox()->pack_start(*textLabelPtr, Gtk::PACK_SHRINK); + // Style element not found, create one + Inkscape::XML::Node *styleNode = _document->getReprDoc()->createElement("svg:style"); + Inkscape::XML::Node *textNode = _document->getReprDoc()->createTextNode(""); - /** - * By default, the entrybox contains 'Class1' as text. However, if object(s) - * is(are) selected and user clicks '+' at the bottom of dialog, the - * entrybox will have the id(s) of the selected objects as text. - */ - if (_desktop->getSelection()->isEmpty()) { - textEditPtr->set_text(".Class1"); - } else { - Inkscape::Selection* selection = _desktop->getSelection(); - std::vector selected = - std::vector(selection->objects().begin(), - selection->objects().end()); - textEditPtr->set_text(_setClassAttribute(selected)); - } + styleNode->appendChild(textNode); + Inkscape::GC::release(textNode); - textDialogPtr->set_size_request(200, 100); - textEditPtr->show(); - textLabelPtr->hide(); - textDialogPtr->show(); + root->addChild(styleNode, NULL); + Inkscape::GC::release(styleNode); - int result = -1; - bool invalid = true; + return textNode; +} + + +/** + * @brief StyleDialog::_readStyleElement + * @return selVec + * Fill the Gtk::TreeStore from the svg:style element. + */ +void StyleDialog::_readStyleElement() +{ + + Inkscape::XML::Node * textNode = _getStyleTextNode(); + if (textNode == NULL) { + std::cerr << "StyleDialog::_readStyleElement: No text node!" << std::endl; + } + + // Get content from style text node. + std::string content = (textNode->content() ? textNode->content() : ""); - while (invalid) { - result = textDialogPtr->run(); + // Remove end-of-lines (check it works on Windoze). + content.erase(std::remove(content.begin(), content.end(), '\n'), content.end()); + + // First split into selector/value chunks. + // An attempt to use Glib::Regex failed. A C++11 version worked but + // reportedly has problems on Windows. Using split_simple() is simpler + // and probably faster. + // + // Glib::RefPtr regex1 = + // Glib::Regex::create("([^\\{]+)\\{([^\\{]+)\\}"); + // + // Glib::MatchInfo minfo; + // regex1->match(content, minfo); + + // Split on curly brackets. Even tokens are selectors, odd are values. + std::vector tokens = Glib::Regex::split_simple("[}{]", content); + + // If text node is empty, return (avoids problem with negative below). + if (tokens.size() == 0) { + return; + } - /** - * @brief selectorName - * This string stores selector name. The text from entrybox is saved as name - * for selector. If the entrybox is empty, the text (thus selectorName) is - * set to ".Class1" - */ - _selectorName = textEditPtr->get_text(); + for (unsigned i = 0; i < tokens.size()-1; i += 2) { - del->set_sensitive(true); + Glib::ustring selector = tokens[i]; + REMOVE_SPACES(selector); // Remove leading/trailing spaces - if (_selectorName[0] == '.' || - _selectorName[0] == '#' || - SPAttributeRelSVG::isSVGElement( _selectorName ) ) { - invalid = false; + // Get list of objects selector matches + std::vector objVec = _getObjVec( selector ); + + Glib::ustring properties; + // Check to make sure we do have a value to match selector. + if ((i+1) < tokens.size()) { + properties = tokens[i+1]; } else { - textLabelPtr->show(); + std::cerr << "StyleDialog::_readStyleElement: Missing values " + "for last selector!" << std::endl; + } + REMOVE_SPACES(properties); + + Gtk::TreeModel::Row row = *(_store->append()); + row[_mColumns._colSelector] = selector; + row[_mColumns._colAddRemove] = true; + row[_mColumns._colObj] = objVec; + row[_mColumns._colProperties] = properties; + + // Add as children, objects that match selector. + for (auto& obj: objVec) { + Gtk::TreeModel::Row childrow = *(_store->append(row->children())); + childrow[_mColumns._colSelector] = "#" + Glib::ustring(obj->getId()); + childrow[_mColumns._colAddRemove] = false; + childrow[_mColumns._colObj] = std::vector(1, obj); + childrow[_mColumns._colProperties] = ""; // Unused } } +} - /** - * The selector name objects is set to the text that the user sets in the - * entrybox. If the attribute does not exist, it is - * created. In case the attribute already has a value, the new value entered - * is appended to the values. If a style attribute does not exist, it is - * created with an empty value. Also if a class selector is added, then - * class attribute for the selected object is set too. - */ - std::vector objVec; - bool objExists = false; - if (!_desktop->getSelection()->isEmpty()) { - for (auto& obj: _desktop->getSelection()->objects()) { - objExists = true; - if (!obj->getRepr()->attribute("style")) { - obj->getRepr()->setAttribute("style", NULL); - } +/** + * @brief StyleDialog::_writeStyleElement + * Update the content of the style element as selectors (or objects) are added/removed. + */ +void StyleDialog::_writeStyleElement() +{ + Glib::ustring styleContent; + for (auto& row: _store->children()) { + styleContent = styleContent + row[_mColumns._colSelector] + + " { " + row[_mColumns._colProperties] + " }\n"; + } + // We could test if styleContent is empty and then delete the style node here but there is no + // harm in keeping it around ... - if (obj->getAttribute("style") == NULL) { - _selectorValue = _selectorName + "{" + "}" + "\n"; - } - else { - _selectorValue = _selectorName + "{" - + obj->getAttribute("style") + "}" + "\n"; - } + Inkscape::XML::Node *textNode = _getStyleTextNode(); + textNode->setContent(styleContent.c_str()); - if (_selectorName[0] == '.') { - if (!obj->getRepr()->attribute("class")) { - obj->getRepr()->setAttribute("class", textEditPtr->get_text() - .erase(0,1)); +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_writeStyleElement(): |" << styleContent << "|" << std::endl; +#endif +} + + +/** + * @brief StyleDialog::_addToSelector + * @param row + * Add selected objects on the desktop to the selector corresponding to 'row'. + */ +void StyleDialog::_addToSelector(Gtk::TreeModel::Row row) +{ +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_addToSelector: Entrance" << std::endl; +#endif + if (*row) { + + Glib::ustring selector = row[_mColumns._colSelector]; + + if (selector[0] == '#') { + // 'id' selector... add selected object's id's to list. + Inkscape::Selection* selection = _desktop->getSelection(); + for (auto& obj: selection->objects()) { + + Glib::ustring id = (obj->getId()?obj->getId():""); + + std::vector objVec = row[_mColumns._colObj]; + bool found = false; + for (auto& obj: objVec) { + if (id == obj->getId()) { + found = true; + break; + } } - else { - obj->getRepr()->setAttribute("class", std::string(obj-> - getRepr()-> - attribute("class")) - + " " + textEditPtr->get_text() - .erase(0,1)); + + if (!found) { + // Update row + objVec.push_back(obj); // Adding to copy so need to update tree + row[_mColumns._colObj] = objVec; + row[_mColumns._colSelector] = _getIdList( objVec ); + + // Add child row + Gtk::TreeModel::Row childrow = *(_store->append(row->children())); + childrow[_mColumns._colSelector] = "#" + Glib::ustring(obj->getId()); + childrow[_mColumns._colAddRemove] = false; + childrow[_mColumns._colObj] = std::vector(1, obj); } } } - } - else { - _selectorValue = _selectorName + "{" + "}" + "\n"; - objExists = false; - } - switch (result) { - case Gtk::RESPONSE_OK: - textDialogPtr->hide(); - row[_mColumns._selectorLabel] = _selectorName; - row[_mColumns._colAddRemove] = true; - if (objExists) { + else if (selector[0] == '.') { + // 'class' selector... add value to class attribute of selected objects. + + // Get first class (split on white space or comma) + std::vector tokens = Glib::Regex::split_simple("[,\\s]+", selector); + Glib::ustring className = tokens[0]; + className.erase(0,1); + + // Get list of objects to modify Inkscape::Selection* selection = _desktop->getSelection(); - row[_mColumns._colObj] = std::vector(selection->objects() - .begin(), selection - ->objects().end()); - objVec = row[_mColumns._colObj]; + std::vector objVec( selection->objects().begin(), + selection->objects().end() ); + + _insertClass( objVec, className ); + + row[_mColumns._colObj] = _getObjVec( selector ); + + for (auto& obj: objVec) { + // Add child row + Gtk::TreeModel::Row childrow = *(_store->append(row->children())); + childrow[_mColumns._colSelector] = "#" + Glib::ustring(obj->getId()); + childrow[_mColumns._colAddRemove] = false; + childrow[_mColumns._colObj] = std::vector(1, obj); + } } - break; - default: - break; - } - /** - * A new style element is added to the document with value obtained - * from selectorValue above. If style element already exists, then - * the new selector's content is appended to its previous content. - */ - inkSelector._selector = _selectorName; - inkSelector._matchingObjs = objVec; - inkSelector._xmlContent = _selectorValue; - _selectorVec.push_back(inkSelector); - - if (_styleElementNode()) { - _styleChild = _styleElementNode(); - _updateStyleContent(); - } - else if (_styleExists && !_newDrawing) { - _updateStyleContent(); - } - else if (!_styleExists) { - Inkscape::XML::Node *root = _document->getReprDoc()->root(); - Inkscape::XML::Node *newChild = _document->getReprDoc() - ->createElement("svg:style"); - Inkscape::XML::Node *smallChildren = _document->getReprDoc() - ->createTextNode(_selectorValue.c_str()); - - newChild->appendChild(smallChildren); - Inkscape::GC::release(smallChildren); - - root->addChild(newChild, NULL); - Inkscape::GC::release(newChild); - _styleChild = newChild; + else { + // Do nothing for element selectors. + // std::cout << " Element selector... doing nothing!" << std::endl; + } } - _selAdd(row); -} -/** - * @brief StyleDialog::_updateStyleContent - * This function updates the content in style element as new selectors (or - * objects) are added/removed. - */ -void StyleDialog::_updateStyleContent() -{ - std::string styleContent = ""; - for (unsigned i = 0; i < _selectorVec.size(); ++i) { - styleContent = styleContent + _selectorVec[i]._xmlContent; - } - _styleChild->firstChild()->setContent(styleContent.c_str()); + _writeStyleElement(); } + /** - * @brief StyleDialog::_delSelector - * This function deletes selector when '-' at the bottom is clicked. The index - * of selected row is obtained and the corresponding selector and its values are - * deleted from the selector vector. If a row has no parent, it is directly - * erased from the vector along with its child rows. The style element is updated - * accordingly. + * @brief StyleDialog::_removeFromSelector + * @param row + * Remove the object corresponding to 'row' from the parent selector. */ -void StyleDialog::_delSelector() +void StyleDialog::_removeFromSelector(Gtk::TreeModel::Row row) { - Glib::RefPtr refTreeSelection = _treeView.get_selection(); - Gtk::TreeModel::iterator iter = refTreeSelection->get_selected(); - if (iter) { - Gtk::TreeModel::Row row = *iter; - std::string sel, key, value; - std::vector::iterator it; - for (it = _selectorVec.begin(); it != _selectorVec.end();) { - sel = (*it)._xmlContent; - REMOVE_SPACES(sel); - if (!sel.empty()) { - key = strtok((char*)sel.c_str(), "{"); - REMOVE_SPACES(key); - char *temp = strtok(NULL, "}"); - if (strtok(temp, "}") != NULL) { - value = strtok(temp, "}"); +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_removeFromSelector: Entrance" << std::endl; +#endif + if (*row) { + + Glib::ustring objectLabel = row[_mColumns._colSelector]; + Gtk::TreeModel::iterator iter = row->parent(); + if (iter) { + Gtk::TreeModel::Row parent = *iter; + Glib::ustring selector = parent[_mColumns._colSelector]; + + if (selector[0] == '#') { + // 'id' selector... remove selected object's id's to list. + + // Erase from selector label. + auto i = selector.find(objectLabel); + if (i != Glib::ustring::npos) { + selector.erase(i, objectLabel.length()); + } + // Erase any comma/space + if (i != Glib::ustring::npos && selector[i] == ',') { + selector.erase(i, 1); + } + if (i != Glib::ustring::npos && selector[i] == ' ') { + selector.erase(i, 1); + } + + // Update store + if (selector.empty()) { + _store->erase(parent); + } else { + // Save new selector and update object vector. + parent[_mColumns._colSelector] = selector; + parent[_mColumns._colObj] = _getObjVec( selector ); + _store->erase(row); } } - Glib::ustring selectedRowLabel = row[_mColumns._selectorLabel]; - std::string matchSelector = selectedRowLabel; - REMOVE_SPACES(matchSelector); - if (key == matchSelector) { - it = _selectorVec.erase(it); + else if (selector[0] == '.') { + // 'class' selector... remove value to class attribute of selected objects. + + std::vector objVec = row[_mColumns._colObj]; // Just one + + // Get first class (split on white space or comma) + std::vector tokens = Glib::Regex::split_simple("[,\\s]+", selector); + Glib::ustring className = tokens[0]; + className.erase(0,1); // Erase '.' + + // Erase class name from 'class' attribute. + Glib::ustring classAttr = objVec[0]->getRepr()->attribute("class"); + auto i = classAttr.find( className ); + if (i != Glib::ustring::npos) { + classAttr.erase(i, className.length()); + } + if (i != Glib::ustring::npos && classAttr[i] == ' ') { + classAttr.erase(i, 1); + } + objVec[0]->getRepr()->setAttribute("class", classAttr); + + parent[_mColumns._colObj] = _getObjVec( selector ); _store->erase(row); } - else { - ++it; - } - /** - * The _stylechild is obtained which contains the style element and - * the content in style element is updated. If _selectorVec is - * empty, the style element is removed from the XML repr else - * the content is updated simply using _updateStyleContent(). - */ - _styleChild = _styleElementNode(); - if (_store->children().empty()) { - _document->getReprRoot()->removeChild(_styleChild); - _styleExists = false; - } else { - _updateStyleContent(); + // Do nothing for element selectors. + // std::cout << " Element selector... doing nothing!" << std::endl; } } } + + _writeStyleElement(); + } + /** - * @brief StyleDialog::_styleElementNode - * @return - * This function returns the node containing style element. The document's - * children are iterated and the repr of the style element that occurs is - * obtained. + * @brief StyleDialog::_getIdList + * @param sel + * @return This function returns a comma seperated list of ids for objects in input vector. + * It is used in creating an 'id' selector. It relies on objects having 'id's. */ -Inkscape::XML::Node* StyleDialog::_styleElementNode() +Glib::ustring StyleDialog::_getIdList(std::vector sel) { - for (unsigned i = 0; i < _document->getReprRoot()->childCount(); ++i) { - if (std::string(_document->getReprRoot()->nthChild(i)->name()) - == "svg:style") { - _styleExists = true; - _newDrawing = true; - return _document->getReprRoot()->nthChild(i); - } + Glib::ustring str; + for (auto& obj: sel) { + str += "#" + Glib::ustring(obj->getId()) + ", "; + } + if (!str.empty()) { + str.erase(str.size()-1); // Remove space at end. c++11 has pop_back() but not ustring. + str.erase(str.size()-1); // Remove comma at end. } - return NULL; + return str; } /** - * @brief StyleDialog::_setClassAttribute - * @param sel - * @return This function returns the ids of objects selected which are passed - * to entrybox. + * @brief StyleDialog::_getObjVec + * @return objVec + * Return a vector of all objects that selector matches. This only handles simple id, class, and + * element selectors. Expanding this would take integrating a true CSS parser. */ -std::string StyleDialog::_setClassAttribute(std::vector sel) -{ - std::string str = ""; - for ( unsigned i = 0; i < sel.size(); ++i ) { - SPObject *obj = sel.at(i); - str = str + "#" + std::string(obj->getId()) + " "; +std::vector StyleDialog::_getObjVec(Glib::ustring selector) { + + // Split selector string into individual selectors (which are comma separated). + std::vector tokens = Glib::Regex::split_simple("\\s*,\\s*", selector ); + + std::vector objVec; + + for (auto& token: tokens) { + + // Find objects that match class selector + if (token[0] == '.') { + token.erase(0,1); + std::vector objects = _document->getObjectsByClass( token ); + objVec.insert(objVec.end(), objects.begin(), objects.end()); + } + + // Find objects that match id selector + else if (token[0] == '#') { + token.erase(0,1); + SPObject * object = _document->getObjectById( token ); + if (object) { + objVec.push_back(object); + } + } + + // Find objects that match element selector + else { + std::vector objects = _document->getObjectsByElement( token ); + objVec.insert(objVec.end(), objects.begin(), objects.end()); + } + } - return str; + +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_getObjVec: |" << selector << "|" << std::endl; + for (auto& obj: objVec) { + std::cout << " " << (obj->getId()?obj->getId():"null") << std::endl; + } +#endif + + return objVec; } + /** - * @brief StyleDialog::_getSelectorVec - * @return selVec - * This function returns a vector whose key is the style selector name and value - * is the style properties. All style selectors are extracted from svg:style - * element. _newDrawing is flag is set to false check if an existing drawing is - * opened. + * @brief StyleDialog::_insertClass + * @param objs: list of objects to insert class + * @param class: class to insert + * Insert a class name into objects' 'class' attribute. */ -std::vector StyleDialog::_getSelectorVec() -{ - for (unsigned i = 0; i < _document->getReprRoot()->childCount(); ++i) { - if (std::string(_document->getReprRoot()->nthChild(i)->name()) == "svg:style") { - _styleExists = true; - _newDrawing = false; - _styleChild = _document->getReprRoot()->nthChild(i); - - // Get content from first style element. - std::string content = _styleChild->firstChild()->content(); - - // Remove end-of-lines (check it works on Windoze). - content.erase(std::remove(content.begin(), content.end(), '\n'), content.end()); - - // First split into selector/value chunks. - // An attempt to use Glib::Regex failed. A C++11 version worked but - // reportedly has problems on Windows. Using split_simple() is simpler - // and probably faster. - // - // Glib::RefPtr regex1 = - // Glib::Regex::create("([^\\{]+)\\{([^\\{]+)\\}"); - // - // Glib::MatchInfo minfo; - // regex1->match(content, minfo); - - // Split on curly brackets. Even tokens are selectors, odd are values. - std::vector tokens = Glib::Regex::split_simple("[}{]", content); - - for (unsigned i = 0; i < tokens.size()-1; i += 2) { - std::string selectors = tokens[i]; - REMOVE_SPACES(selectors); // Remove leading/trailing spaces - - /** Make a list of all objects that selector matches. This is - * currently limited to simple id, class, and element selectors. - * Expanding this would take integrating a true CSS parser. - */ - std::vectorobjVec; - - // Split selector string into individual selectors (which are comma separated). - std::vector tokens2 = Glib::Regex::split_simple - ("\\s*,\\s*", selectors ); - - for(unsigned i = 0; i < tokens2.size(); ++i) { - std::string token2 = tokens2[i]; - - // Find objects that match class selector - if (token2[0] == '.') { - token2.erase(0,1); - std::vector objects = _document - ->getObjectsByClass(token2); - objVec.insert(objVec.end(), objects.begin(), objects.end()); - } +void StyleDialog::_insertClass(const std::vector& objVec, const Glib::ustring& className) { - // Find objects that match id selector - else if (token2[0] == '#') { - token2.erase(0,1); - SPObject * object = _document->getObjectById(token2); - if (object) { - objVec.push_back(object); - } - } + for (auto& obj: objVec) { - // Find objects that match element selector - else { - std::vector objects = _document-> - getObjectsByElement(token2); - objVec.insert(objVec.end(), objects.begin(), objects.end()); - } + if (!obj->getRepr()->attribute("class")) { + // 'class' attribute does not exist, create it. + obj->getRepr()->setAttribute("class", className); + } else { + // 'class' attribute exists, append. + Glib::ustring classAttr = obj->getRepr()->attribute("class"); + + // Split on white space. + std::vector tokens = Glib::Regex::split_simple("\\s+", classAttr); + bool add = true; + for (auto& token: tokens) { + if (token == className) { + add = false; // Might be useful to still add... + break; } + } + if (add) { + obj->getRepr()->setAttribute("class", classAttr + " " + className ); + } + } + } + } - std::string values; - // Check to make sure we do have a value to match selector. - if ((i+1) < tokens.size()) { - values = tokens[i+1]; - } else { - std::cerr << "StyleDialog::_getSelectorVec: Missing values " - "for last selector!" << std::endl; - } - _selectorValue = selectors + "{" + values + "}\n"; - inkSelector._selector = selectors; - inkSelector._matchingObjs = objVec; - inkSelector._xmlContent = _selectorValue; - _selectorVec.push_back(inkSelector); +/** + * @brief StyleDialog::_selectObjects + * @param eventX + * @param eventY + * This function selects objects in the drawing corresponding to the selector + * selected in the treeview. + */ +void StyleDialog::_selectObjects(int eventX, int eventY) +{ +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_selectObjects: " << eventX << ", " << eventY << std::endl; +#endif + + _desktop->selection->clear(); + Gtk::TreeViewColumn *col = _treeView.get_column(1); + Gtk::TreeModel::Path path; + int x2 = 0; + int y2 = 0; + // To do: We should be able to do this via passing in row. + if (_treeView.get_path_at_pos(eventX, eventY, path, col, x2, y2)) { + if (col == _treeView.get_column(1)) { + Gtk::TreeModel::iterator iter = _store->get_iter(path); + if (iter) { + Gtk::TreeModel::Row row = *iter; + Gtk::TreeModel::Children children = row.children(); + std::vector objVec = row[_mColumns._colObj]; + for (unsigned i = 0; i < objVec.size(); ++i) { + SPObject *obj = objVec[i]; + _desktop->selection->add(obj); + } } } } - return _selectorVec; } + /** - * @brief StyleDialog::_populateTree - * @param _selVec - * This function populates the treeview with selectors available in the - * stylesheet. + * @brief StyleDialog::_addSelector + * + * This function opens a dialog to add a selector. The dialog is prefilled + * with an 'id' selector containing a list of the id's of selected objects + * or with a 'class' selector if no objects are selected. */ -std::string StyleDialog::_populateTree(std::vector _selVec) +void StyleDialog::_addSelector() { - _selectorVec = _selVec; - std::string selectorValue; +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_addSelector: Entrance" << std::endl; +#endif - for(unsigned it = 0; it < _selectorVec.size(); ++it) { - Gtk::TreeModel::Row row = *(_store->append()); - row[_mColumns._selectorLabel] = _selectorVec[it]._selector; - row[_mColumns._colAddRemove] = true; - row[_mColumns._colObj] = _selectorVec[it]._matchingObjs; - std::string selValue = _selectorVec[it]._xmlContent; - selectorValue.append(selValue.c_str()); + // Store list of selected elements on desktop (not to be confused with selector). + Inkscape::Selection* selection = _desktop->getSelection(); + std::vector objVec( selection->objects().begin(), + selection->objects().end() ); + + // ==== Create popup dialog ==== + Gtk::Dialog *textDialogPtr = new Gtk::Dialog(); + textDialogPtr->add_button(_("Cancel"), Gtk::RESPONSE_CANCEL); + textDialogPtr->add_button(_("Add"), Gtk::RESPONSE_OK); + + Gtk::Entry *textEditPtr = manage ( new Gtk::Entry() ); + textDialogPtr->get_vbox()->pack_start(*textEditPtr, Gtk::PACK_SHRINK); + + Gtk::Label *textLabelPtr = manage ( new Gtk::Label( + _("Invalid entry: Not an id (#), class (.), or element CSS selector.") + ) ); + textDialogPtr->get_vbox()->pack_start(*textLabelPtr, Gtk::PACK_SHRINK); + + /** + * By default, the entrybox contains 'Class1' as text. However, if object(s) + * is(are) selected and user clicks '+' at the bottom of dialog, the + * entrybox will have the id(s) of the selected objects as text. + */ + if (_desktop->getSelection()->isEmpty()) { + textEditPtr->set_text(".Class1"); + } else { + textEditPtr->set_text(_getIdList(objVec)); } - if (_selectorVec.size() > 0) { + Gtk::Requisition sreq1, sreq2; + textDialogPtr->get_preferred_size(sreq1, sreq2); + int minWidth = 200; + int minHeight = 100; + std::cout << " preferred: " << sreq2.width << "x" << sreq2.height << std::endl; + std::cout << " minimum: " << minWidth << "x" << minHeight << std::endl; + minWidth = (sreq2.width > minWidth ? sreq2.width : minWidth ); + minHeight = (sreq2.height > minHeight ? sreq2.height : minHeight); + textDialogPtr->set_size_request(minWidth, minHeight); + textEditPtr->show(); + textLabelPtr->hide(); + textDialogPtr->show(); + + + // ==== Get response ==== + int result = -1; + bool invalid = true; + Glib::ustring selectorValue; + + while (invalid) { + result = textDialogPtr->run(); + if (result != Gtk::RESPONSE_OK) { // Cancel, close dialog, etc. + textDialogPtr->hide(); + return; + } + /** + * @brief selectorName + * This string stores selector name. The text from entrybox is saved as name + * for selector. If the entrybox is empty, the text (thus selectorName) is + * set to ".Class1" + */ + selectorValue = textEditPtr->get_text(); + del->set_sensitive(true); + + if (selectorValue[0] == '.' || + selectorValue[0] == '#' || + SPAttributeRelSVG::isSVGElement( selectorValue ) ) { + invalid = false; + } else { + textLabelPtr->show(); + } } + delete textDialogPtr; - return selectorValue; + // ==== Handle response ==== + + // If class selector, add selector name to class attribute for each object + if (selectorValue[0] == '.') { + + Glib::ustring className = selectorValue; + className.erase(0,1); + _insertClass(objVec, className); + } + + // If 'id' selector, regenerate objVec in case user modified list. + if (selectorValue[0] == '#') { + // To do + } + + // Add entry to GUI tree + Gtk::TreeModel::Row row = *(_store->append()); + row[_mColumns._colSelector] = selectorValue; + row[_mColumns._colAddRemove] = true; + row[_mColumns._colObj] = objVec; + + // Add as children objects that match selector. + for (auto& obj: objVec) { + Gtk::TreeModel::Row childrow = *(_store->append(row->children())); + childrow[_mColumns._colSelector] = "#" + Glib::ustring(obj->getId()); + childrow[_mColumns._colAddRemove] = false; + childrow[_mColumns._colObj] = std::vector(1, obj); + } + + // Add entry to style element + _writeStyleElement(); +} + +/** + * @brief StyleDialog::_delSelector + * This function deletes selector when '-' at the bottom is clicked. + * Note: If deleting a class selector, class attributes are NOT changed. + */ +void StyleDialog::_delSelector() +{ +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_delSelector" << std::endl; +#endif + Glib::RefPtr refTreeSelection = _treeView.get_selection(); + Gtk::TreeModel::iterator iter = refTreeSelection->get_selected(); + if (iter) { + Gtk::TreeModel::Row row = *iter; + _store->erase(iter); + _writeStyleElement(); + } } /** * @brief StyleDialog::_handleButtonEvent * @param event * @return - * This function handles the event when '+' button in front of a selector name - * is clicked. The selected objects (if any) is added to the selector as a child - * in the treeview. + * Handles the event when '+' button in front of a selector name is clicked or when a '-' button in + * front of a child object is clicked. In the first case, the selected objects on the desktop (if + * any) are added as children of the selector in the treeview. In the latter case, the object + * corresponding to the row is removed from the selector. */ bool StyleDialog::_handleButtonEvent(GdkEventButton *event) { - if (event->type == GDK_BUTTON_PRESS && event->button == 1) { +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_handleButtonEvent: Entrance" << std::endl; +#endif + if (event->type == GDK_BUTTON_RELEASE && event->button == 1) { Gtk::TreeViewColumn *col = 0; Gtk::TreeModel::Path path; int x = static_cast(event->x); @@ -575,119 +772,16 @@ bool StyleDialog::_handleButtonEvent(GdkEventButton *event) int y2 = 0; if (_treeView.get_path_at_pos(x, y, path, col, x2, y2)) { if (col == _treeView.get_column(0)) { - Glib::RefPtr refTreeSelection = - _treeView.get_selection(); - Gtk::TreeModel::iterator iter = refTreeSelection-> - get_selected(); + Gtk::TreeModel::iterator iter = _store->get_iter(path); Gtk::TreeModel::Row row = *iter; - /** - * This adds child rows to selected rows. If the parent row is - * a class selector, then the class attribute of object added - * to child row is appended with class in the parent row. The - * else below deletes objects from selectors when 'delete' button - * in front of child row is clicked. The class attribute is updated - * by removing the parent row's class selector name. - */ + // Add or remove objects from a if (!row.parent()) { - _selAdd(row); - } - - else { - std::string sel, key, value; - std::vector::iterator it; - Gtk::TreeModel::Row parentRow = *(row).parent(); - Glib::ustring parentKey = parentRow[_mColumns._selectorLabel]; - - for (it = _selectorVec.begin(); it != _selectorVec.end(); ++it) { - sel = (*it)._xmlContent; - REMOVE_SPACES(sel); - if (!sel.empty()) { - key = strtok((char*)sel.c_str(), "{"); - REMOVE_SPACES(key); - char *temp = strtok(NULL, "}"); - if (strtok(temp, "}") != NULL) { - value = strtok(temp, "}"); - } - } - - /** - * @brief matchSelector - * For id selectors, whenever any child row is deleted, - * the row label is updated and so is the entry for the - * selector in style element. - */ - std::string matchSelector = parentKey; - REMOVE_SPACES(matchSelector); - if (key == matchSelector) { - if (key[0] == '#') { - std::string s = parentKey; - Glib::ustring toDelRow = row[_mColumns._selectorLabel]; - std::string toDelKey = toDelRow; - std::size_t idFound = s.find(toDelKey); - if (idFound != std::string::npos) { - if (idFound == 0) { - s.erase(idFound, toDelKey.length()+1); - parentKey = s; - parentRow[_mColumns._selectorLabel] = parentKey; - (*it)._xmlContent.erase(idFound, toDelKey.length()); - } - else { - s.erase(idFound-2, toDelKey.length()+2); - parentKey = s; - parentRow[_mColumns._selectorLabel] = parentKey; - (*it)._xmlContent.erase(idFound-2, toDelKey. - length()+2); - } - } - } - } - - if (parentKey[0] == '.') { - std::vector objVec = row[_mColumns._colObj]; - for (unsigned i = 0; i < objVec.size(); ++i) { - SPObject *obj = objVec[i]; - std::string classAttr = std::string(obj->getRepr() - ->attribute("class")); - std::size_t found = classAttr.find(parentKey.erase(0,1)); - if (found != std::string::npos) { - classAttr.erase(found, parentKey.length()+1); - obj->getRepr()->setAttribute("class", classAttr); - } - } - } - - if (parentKey.empty()) { - (*it)._xmlContent = ""; - } - } - - if (_styleChild) { - _updateStyleContent(); - } - else { - _styleChild = _styleElementNode(); - _updateStyleContent(); - } - - _store->erase(row); - - /** - * On continuous deletion of objects (child rows) from the - * selector (parent row), if the parent row has no child, then - * the row is erased from the _store. Further if there is no - * row left in _store, which implies there is no content in - * XML style element, then the 'svg:style' element is also - * removed. - */ - if (parentKey.empty()) { - _store->erase(parentRow); - } - - if (parentKey.empty() && _store->children().empty()) { - _document->getReprRoot()->removeChild(_styleChild); - _styleExists = false; - } + // Add selected objects to selector. + _addToSelector(row); + } else { + // Remove object from selector + _removeFromSelector(row); } } } @@ -695,275 +789,129 @@ bool StyleDialog::_handleButtonEvent(GdkEventButton *event) return false; } -/** - * @brief StyleDialog::_selAdd - * @param row - * This routine is called when an object is added to a selector by clicking on - * '+' in front of the row with selector's label. - */ -void StyleDialog::_selAdd(Gtk::TreeModel::Row row) -{ - Glib::ustring selectorName; - Gtk::TreeModel::Row childrow; - Inkscape::Selection* selection = _desktop->getSelection(); - std::vector sel = std::vector - (selection->objects().begin(), selection->objects().end()); - for (auto& obj: selection->objects()) { - if (*row) { - if (_selectorVec.size() != 0) { - childrow = *(_store->append(row->children())); - childrow[_mColumns._selectorLabel] = "#" + - std::string(obj->getId()); - childrow[_mColumns._colAddRemove] = false; - childrow[_mColumns._colObj] = sel; - Glib::ustring key = row[_mColumns._selectorLabel]; - if (key[0] == '.') { - if (!obj->getRepr()->attribute("class")) { - obj->setAttribute("class", key.erase(0,1)); - } - else { - if (obj->getRepr()->attribute("class") != key - .erase(0,1)) { - obj->setAttribute("class", std::string - (obj->getRepr()-> - attribute("class")) - + " " + key - .erase(0,1)); - } - } - } - } - selectorName = row[_mColumns._selectorLabel]; - } - - /** - * If the object's parent row is a class selector, then - * there are no changes in style element except the class - * attribute is updated. For the id selector cases, XML - * content's style element is updated. - */ - REMOVE_SPACES(selectorName); - std::vector::iterator it; - for (it = _selectorVec.begin(); it != _selectorVec.end(); ++it) { - std::string sel, key, value; - sel = (*it)._xmlContent; - REMOVE_SPACES(sel); - if (!sel.empty()) { - key = strtok((char*)sel.c_str(), "{"); - REMOVE_SPACES(key); - char *temp = strtok(NULL, "}"); - if (strtok(temp, "}") != NULL) { - value = strtok(temp, "}"); - } - } - - Glib::ustring selectedRowLabel = row[_mColumns._selectorLabel]; - std::string matchSelector = selectedRowLabel; - REMOVE_SPACES(matchSelector); - if (key == matchSelector) { - REMOVE_SPACES((*it)._selector); - if (selectorName[0] == '#') { - if ("#" + std::string(obj->getId()) != selectorName) { - inkSelector._selector = (*it)._selector; - inkSelector._selector.append(", #" + std::string(obj->getId())); - inkSelector._xmlContent = inkSelector._selector + "{" + value + "}\n"; - row[_mColumns._selectorLabel] = selectorName + ", " + - childrow[_mColumns._selectorLabel]; - } - } - else if (selectorName[0] == '.') { - inkSelector._xmlContent = (*it)._selector + "{" + value + "}\n"; - } - - it = _selectorVec.erase(it); - it = _selectorVec.insert(it, inkSelector); - } - } - } - if (_styleElementNode()) { - _styleChild = _styleElementNode(); - _updateStyleContent(); - } - else if (_styleExists && !_newDrawing) { - _updateStyleContent(); - } -} /** - * @brief StyleDialog::_selectObjects + * @brief StyleDialog::_buttonEventsSelectObjs * @param event - * This function detects single or double click on a selector in any row. Single - * click on a selector selects the matching objects. A double click on any - * selector selects the matching objects as well as will open CSS dialog. It - * calls _selectObjects to add objects to selection. + * This function detects single or double click on a selector in any row. Clicking + * on a selector selects the matching objects on the desktop. A double click will + * in addition open the CSS dialog. */ void StyleDialog::_buttonEventsSelectObjs(GdkEventButton* event ) { - if (event->type == GDK_BUTTON_PRESS && event->button == 1) { - int x = static_cast(event->x); - int y = static_cast(event->y); - _selectObjects(x, y); - } - else if (event->type == GDK_2BUTTON_PRESS && event->button == 1) { +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_buttonEventsSelectObjs" << std::endl; +#endif + _updating = true; + + if (event->type == GDK_BUTTON_RELEASE && event->button == 1) { int x = static_cast(event->x); int y = static_cast(event->y); _selectObjects(x, y); + //} + //else if (event->type == GDK_2BUTTON_PRESS && event->button == 1) { + //int x = static_cast(event->x); + //int y = static_cast(event->y); + //_selectObjects(x, y); - //Open CSS dialog here. - if (!_cssPane->get_visible()) { - _paned.pack2(*_cssPane, Gtk::SHRINK); - _cssPane->show_all(); - } + _cssPane->_store->clear(); + // This should probably be in a member function of CSSDialog. Glib::RefPtr refTreeSelection = _treeView.get_selection(); Gtk::TreeModel::iterator iter = refTreeSelection->get_selected(); if (iter) { Gtk::TreeModel::Row row = *iter; - std::string sel, key, value; - std::vector::iterator it; - for (it = _selectorVec.begin(); it != _selectorVec.end(); ++it) { - sel = (*it)._xmlContent; - REMOVE_SPACES(sel); - if (!sel.empty()) { - key = strtok((char*)sel.c_str(), "{"); - REMOVE_SPACES(key); - char *temp = strtok(NULL, "}"); - if (strtok(temp, "}") != NULL) { - value = strtok(temp, "}"); - } + Glib::ustring properties = row[_mColumns._colProperties]; + REMOVE_SPACES(properties); // Remove leading/trailing spaces + + std::vector tokens = + Glib::Regex::split_simple("\\s*;\\s*", properties); + for (auto& token: tokens) { + if (!token.empty()) { + _cssPane->_propRow = *(_cssPane->_store->append()); + _cssPane->_propRow[_cssPane->_cssColumns._colUnsetProp] = false; + _cssPane->_propRow[_cssPane->_cssColumns._propertyLabel] = token; } + } + } + } + _updating = false; +} - Glib::ustring selectedRowLabel = row[_mColumns._selectorLabel]; - std::string matchSelector = selectedRowLabel; - REMOVE_SPACES(matchSelector); - - if (key == matchSelector) { - _cssPane->_store->clear(); - std::stringstream ss(value); - std::string token; - std::size_t found = value.find(";"); - if (found!=std::string::npos) { - while(std::getline(ss, token, ';')) { - REMOVE_SPACES(token); - if (!token.empty()) { - _cssPane->_propRow = *(_cssPane->_store->append()); - _cssPane->_propRow[_cssPane->_cssColumns._colUnsetProp] = false; - _cssPane->_propRow[_cssPane->_cssColumns._propertyLabel] = token; - _cssPane->_propCol->add_attribute(_cssPane->_textRenderer - ->property_text(), - _cssPane->_cssColumns - ._propertyLabel); - } - } - } + +/** + * @brief StyleDialog::_selectRow + * This function selects the row in treeview corresponding to an object selected + * in the drawing. If more than one row matches, the first is chosen. + */ +void StyleDialog::_selectRow(Selection */*sel*/) +{ + if (_updating) return; // Avoid updating if we have set row via dialog. + + Inkscape::Selection* selection = _desktop->getSelection(); + if (!selection->isEmpty()) { + SPObject *obj = selection->objects().back(); + + Gtk::TreeModel::Children children = _store->children(); + for(Gtk::TreeModel::Children::iterator iter = children.begin(); + iter != children.end(); ++iter) { + + Gtk::TreeModel::Row row = *iter; + std::vector objVec = row[_mColumns._colObj]; + for (unsigned i = 0; i < objVec.size(); ++i) { + if (obj->getId() == objVec[i]->getId()) { + _treeView.get_selection()->select(row); + return; } } } - else { - _cssPane->_store->clear(); - _cssPane->hide(); - } - - _cssPane->_textRenderer->signal_edited().connect(sigc::mem_fun(*this, - &StyleDialog:: - _handleEdited)); - _cssPane->_treeView.signal_button_press_event().connect(sigc::mem_fun - (*this, &StyleDialog:: - _delProperty), - false); } + + // Selection empty or no row matches. + _treeView.get_selection()->unselect_all(); } + /** * @brief StyleDialog::_selChanged - * When no row in _treeView of Style Dialog is selected, the _cssPane is hidden. */ void StyleDialog::_selChanged() { - if (_treeView.get_selection()->count_selected_rows() == 0) { - _cssPane->hide(); - } +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_selChanged" << std::endl; +#endif } /** * @brief StyleDialog::_handleEdited * @param path * @param new_text - * This function edits CSS properties of the selector chosen. new_text is used - * to update the property in XML repr. The value from selected selector is - * obtained and modified as per value of new_text. If a new property is added, - * value is appended with new_text. Later _updateStyleContent() is called to - * update XML repr and hence changes are reflected in the drawing too. + * Update trees when new text is entered into a CSS dialog row. */ void StyleDialog::_handleEdited(const Glib::ustring& path, const Glib::ustring& new_text) { +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_handleEdited: path: " << path + << " new_text: " << new_text << std::endl; +#endif + Gtk::TreeModel::iterator iterCss = _cssPane->_treeView.get_model()->get_iter(path); if (iterCss) { Gtk::TreeModel::Row row = *iterCss; row[_cssPane->_cssColumns._propertyLabel] = new_text; - _cssPane->_editedProp = new_text; } - // Selected selector row is obtained here to get corresponding key and value. + Glib::ustring properties; + for (auto& crow: _cssPane->_store->children()) { + properties = properties + crow[_cssPane->_cssColumns._propertyLabel] + "; "; + } + + // Update selector data. Glib::RefPtr refTreeSelection = _treeView.get_selection(); Gtk::TreeModel::iterator iter = refTreeSelection->get_selected(); if (iter) { Gtk::TreeModel::Row row = *iter; - std::string sel, key, value; - std::vector::iterator it; - for (it = _selectorVec.begin(); it != _selectorVec.end(); ++it) { - sel = (*it)._xmlContent; - REMOVE_SPACES(sel); - if (!sel.empty()) { - key = strtok((char*)sel.c_str(), "{"); - REMOVE_SPACES(key); - char *temp = strtok(NULL, "}"); - if (strtok(temp, "}") != NULL) { - value = strtok(temp, "}"); - } - } - - Glib::ustring selectedRowLabel = row[_mColumns._selectorLabel]; - std::string matchSelector = selectedRowLabel; - REMOVE_SPACES(matchSelector); - - if (key == matchSelector) { - /** If a new property is added, existing value is appended with new - * property, else replacements in value are done in the 'else' block. - */ - if (_cssPane->_newProperty) { - if (!new_text.empty()) { - value.append((new_text + ";").c_str()); - _cssPane->_propCol->add_attribute(_cssPane->_textRenderer - ->property_text(), - _cssPane->_cssColumns - ._propertyLabel); - _cssPane->_newProperty = false; - } - } - else { - std::stringstream ss(value); - std::string token, editedToken; - std::size_t found = value.find(";"); - if (found!=std::string::npos) { - while(std::getline(ss, token, ';')) { - REMOVE_SPACES(token); - if (!token.empty()) { - if (token.substr(0, token.find(":")) == _cssPane - ->_editedProp.substr(0, _cssPane->_editedProp - .find(":"))) { - editedToken = _cssPane->_editedProp; - size_t startPos = value.find(token); - value.replace(startPos, token.length(), editedToken); - } - } - } - } - } - value.erase(std::remove(value.begin(), value.end(), '\n'), value.end()); - (*it)._xmlContent = key + "{" + value + "}\n"; - _updateStyleContent(); - } - } + row[_mColumns._colProperties] = properties; + _writeStyleElement(); } } @@ -971,14 +919,15 @@ void StyleDialog::_handleEdited(const Glib::ustring& path, const Glib::ustring& * @brief StyleDialog::_delProperty * @param event * @return - * This function deletes property when '-' in front of property in CSS panel is - * clicked. The property row is deleted from CSS panel and XML repr is updated. - * toDelProperty is the property to be deleted which is looked in 'value' and is - * erased from 'value'. + * Delete a property from the CSS dialog and then update trees. */ bool StyleDialog::_delProperty(GdkEventButton *event) { - if (event->type == GDK_BUTTON_PRESS && event->button == 1) { +#ifdef DEBUG_STYLEDIALOG + std::cout << "StyleDialog::_delProperty" << std::endl; +#endif + + if (event->type == GDK_BUTTON_RELEASE && event->button == 1) { Gtk::TreeViewColumn *col = 0; Gtk::TreeModel::Path path; int x = static_cast(event->x); @@ -989,45 +938,23 @@ bool StyleDialog::_delProperty(GdkEventButton *event) Glib::ustring toDelProperty; if (_cssPane->_treeView.get_path_at_pos(x, y, path, col, x2, y2)) { if (col == _cssPane->_treeView.get_column(0)) { - Gtk::TreeModel::iterator cssIter = _cssPane->_treeView.get_selection() - ->get_selected(); + Gtk::TreeModel::iterator cssIter = + _cssPane->_treeView.get_selection()->get_selected(); if (cssIter) { - cssRow = *cssIter; - toDelProperty = cssRow[_cssPane->_cssColumns._propertyLabel]; - } + _cssPane->_store->erase(cssIter); + + Glib::ustring properties; + for (auto& crow: _cssPane->_store->children()) { + properties = properties + crow[_cssPane->_cssColumns._propertyLabel] + "; "; + } - Gtk::TreeModel::iterator iter = _treeView.get_selection()->get_selected(); - if (iter) { - Gtk::TreeModel::Row row = *iter; - std::string sel, key, value; - std::vector::iterator it; - for (it = _selectorVec.begin(); it != _selectorVec.end(); ++it) { - sel = (*it)._xmlContent; - REMOVE_SPACES(sel); - if (!sel.empty()) { - key = strtok((char*)sel.c_str(), "{"); - REMOVE_SPACES(key); - char *temp = strtok(NULL, "}"); - if (strtok(temp, "}") != NULL) { - value = strtok(temp, "}"); - } - } - - Glib::ustring selectedRowLabel = row[_mColumns._selectorLabel]; - std::string matchSelector = selectedRowLabel; - REMOVE_SPACES(matchSelector); - - if (key == matchSelector) { - std::size_t found = value.find(toDelProperty); - if (found!=std::string::npos) { - if (!toDelProperty.empty()) { - value.erase(found, toDelProperty.length()+1); - (*it)._xmlContent = key + "{" + value + "}\n"; - _updateStyleContent(); - _cssPane->_store->erase(cssRow); - } - } - } + // Update selector data. + Glib::RefPtr refTreeSelection = _treeView.get_selection(); + Gtk::TreeModel::iterator iter = refTreeSelection->get_selected(); + if (iter) { + Gtk::TreeModel::Row row = *iter; + row[_mColumns._colProperties] = properties; + _writeStyleElement(); } } } @@ -1036,98 +963,24 @@ bool StyleDialog::_delProperty(GdkEventButton *event) return false; } -/** - * @brief StyleDialog::_selectObjects - * @param eventX - * @param eventY - * This function selects objects in the drawing corresponding to the selector - * selected in the treeview. - */ -void StyleDialog::_selectObjects(int eventX, int eventY) -{ - _desktop->selection->clear(); - Gtk::TreeViewColumn *col = _treeView.get_column(1); - Gtk::TreeModel::Path path; - int x = eventX; - int y = eventY; - int x2 = 0; - int y2 = 0; - if (_treeView.get_path_at_pos(x, y, path, col, x2, y2)) { - if (col == _treeView.get_column(1)) { - Gtk::TreeModel::iterator iter = _store->get_iter(path); - if (iter) { - Gtk::TreeModel::Row row = *iter; - Gtk::TreeModel::Children children = row.children(); - std::vector objVec = row[_mColumns._colObj]; - for (unsigned i = 0; i < objVec.size(); ++i) { - SPObject *obj = objVec[i]; - _desktop->selection->add(obj); - } - if (children) { - _checkAllChildren(children); - } - } - } - } -} /** - * @brief StyleDialog::_checkAllChildren - * @param children - * This function iterates children of the row selected in treeview and selects - * the objects corresponding to any selector in child rows. + * @brief StyleDialog::_styleButton + * @param btn + * @param iconName + * @param tooltip + * Set the style of '+' and '-' buttons at the bottom of dialog. */ -void StyleDialog::_checkAllChildren(Gtk::TreeModel::Children& children) +void StyleDialog::_styleButton(Gtk::Button& btn, char const* iconName, + char const* tooltip) { - for (Gtk::TreeModel::Children::iterator iter = children.begin(); - iter!= children.end(); ++iter) { - Gtk::TreeModel::Row childrow = *iter; - std::vector objVec = childrow[_mColumns._colObj]; - for (unsigned i = 0; i < objVec.size(); ++i) { - SPObject *obj = objVec[i]; - _desktop->selection->add(obj); - } - } + GtkWidget *child = sp_icon_new(Inkscape::ICON_SIZE_SMALL_TOOLBAR, iconName); + gtk_widget_show(child); + btn.add(*manage(Glib::wrap(child))); + btn.set_relief(Gtk::RELIEF_NONE); + btn.set_tooltip_text (tooltip); } -/** - * @brief StyleDialog::_selectRow - * This function selects the rows in treeview corresponding to an object selected - * in the drawing. - */ -void StyleDialog::_selectRow(Selection */*sel*/) -{ - SPObject *obj = NULL; - if (!_desktop->selection->isEmpty()) { - Inkscape::Selection* selection = _desktop->getSelection(); - std::vector selected = std::vector - (selection->objects().begin(), selection->objects().end()); - obj = selected.back(); - } - - /** - * If obj has some SPObject, then it is added to desktop's selection. If a - * row in treeview has children, those rows are checked too against selected - * object's id. If an object which is not present in any selector is selected, - * the treeview's selections are unselected. - */ - if (obj != NULL) { - Gtk::TreeModel::Children children = _store->children(); - for(Gtk::TreeModel::Children::iterator iter = children.begin(); - iter != children.end(); ++iter) { - Gtk::TreeModel::Row row = *iter; - std::vector objVec = row[_mColumns._colObj]; - for (unsigned i = 0; i < objVec.size(); ++i) { - if (obj->getId() == objVec[i]->getId()) { - _treeView.get_selection()->select(row); - } - } - } - } - else { - _treeView.get_selection()->unselect_all(); - } -} } // namespace Dialog } // namespace UI diff --git a/src/ui/dialog/styledialog.h b/src/ui/dialog/styledialog.h index 3cc4349e6..37a186e40 100644 --- a/src/ui/dialog/styledialog.h +++ b/src/ui/dialog/styledialog.h @@ -3,8 +3,10 @@ */ /* Authors: * Kamalpreet Kaur Grewal + * Tavmjong Bah * * Copyright (C) Kamalpreet Kaur Grewal 2016 + * Copyright (C) Tavmjong Bah 2017 * * Released under GNU GPL, read the file 'COPYING' for more information */ @@ -33,11 +35,12 @@ namespace Dialog { * A list of CSS selectors will show up in this dialog. This dialog allows one to * add and delete selectors. Elements can be added to and removed from the selectors * in the dialog. Selection of any selector row selects the matching objects in - * the drawing and vice-versa. + * the drawing and vice-versa. (Only simple selectors supported for now.) + * + * This class must keep two things in sync: + * 1. The text node of the style element. + * 2. The Gtk::TreeModel. */ -typedef std::pair >, std::string> -_selectorVecType; - class StyleDialog : public Widget::Panel { public: @@ -45,75 +48,75 @@ public: ~StyleDialog(); static StyleDialog &getInstance() { return *new StyleDialog(); } + void setDesktop(SPDesktop* desktop); private: - void _styleButton(Gtk::Button& btn, char const* iconName, char const* tooltip); - std::string _setClassAttribute(std::vector); - class InkSelector { - public: - std::string _selector; - std::vector _matchingObjs; - std::string _xmlContent; - }; - - InkSelector inkSelector; - std::vector _selectorVec; - std::vector _getSelectorVec(); - std::string _populateTree(std::vector); - bool _handleButtonEvent(GdkEventButton *event); - void _buttonEventsSelectObjs(GdkEventButton *event); - void _selectObjects(int, int); - void _checkAllChildren(Gtk::TreeModel::Children& children); - Inkscape::XML::Node *_styleElementNode(); - void _updateStyleContent(); - void _selectRow(Selection *); - - class ModelColumns : public Gtk::TreeModel::ColumnRecord - { + // Data structure + class ModelColumns : public Gtk::TreeModel::ColumnRecord { public: ModelColumns() { - add(_selectorLabel); + add(_colSelector); add(_colAddRemove); add(_colObj); + add(_colProperties); } - Gtk::TreeModelColumn _selectorLabel; - Gtk::TreeModelColumn _colAddRemove; - Gtk::TreeModelColumn > _colObj; + Gtk::TreeModelColumn _colSelector; // Selector or matching object id. + Gtk::TreeModelColumn _colAddRemove; // Selector row or child object row. + Gtk::TreeModelColumn > _colObj; // List of matching objects. + Gtk::TreeModelColumn _colProperties; // List of properties. }; - - SPDesktop* _desktop; - SPDesktop* _targetDesktop; ModelColumns _mColumns; + + // TreeView + Gtk::TreeView _treeView; + Glib::RefPtr _store; + + // Widgets Gtk::VPaned _paned; Gtk::VBox _mainBox; Gtk::HBox _buttonBox; - Gtk::TreeView _treeView; - Glib::RefPtr _store; Gtk::ScrolledWindow _scrolledWindow; Gtk::Button* del; Gtk::Button* create; - SPDocument* _document; - bool _styleExists; - Inkscape::XML::Node *_styleChild; - std::string _selectorName; - std::string _selectorValue; - bool _newDrawing; CssDialog *_cssPane; - void _selAdd(Gtk::TreeModel::Row row); + + // Variables - Inkscape + SPDesktop* _desktop; // To do: use panel _desktop + SPDocument* _document; + bool _updating; + + // Reading and writing the style element. + Inkscape::XML::Node *_getStyleTextNode(); + void _readStyleElement(); + void _writeStyleElement(); + + // Manipulate Tree + void _addToSelector(Gtk::TreeModel::Row row); + void _removeFromSelector(Gtk::TreeModel::Row row); + Glib::ustring _getIdList(std::vector); + std::vector _getObjVec(Glib::ustring selector); + void _insertClass(const std::vector& objVec, const Glib::ustring& className); + void _selectObjects(int, int); // Signal handlers void _addSelector(); void _delSelector(); + bool _handleButtonEvent(GdkEventButton *event); + void _buttonEventsSelectObjs(GdkEventButton *event); + void _selectRow(Selection *); // Select row in tree when selection changed. void _selChanged(); - // Signal handler for CssDialog + // Signal handlers for CssDialog void _handleEdited(const Glib::ustring& path, const Glib::ustring& new_text); bool _delProperty(GdkEventButton *event); + + // GUI + void _styleButton(Gtk::Button& btn, char const* iconName, char const* tooltip); }; -} // namespace Dialog +} // namespace Dialogc } // namespace UI } // namespace Inkscape -- cgit v1.2.3 From 2d607cec2e3a62427e6c6beb4f3e3c28e3770ac6 Mon Sep 17 00:00:00 2001 From: Tavmjong Bah Date: Wed, 15 Feb 2017 07:50:11 +0100 Subject: Fix compile for Trusty. (Colliding definitions of isinf between C99 and C++11 with GCC.) (bzr r15521) --- src/libcola/gradient_projection.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/libcola/gradient_projection.cpp b/src/libcola/gradient_projection.cpp index c8488a545..c079c3149 100644 --- a/src/libcola/gradient_projection.cpp +++ b/src/libcola/gradient_projection.cpp @@ -50,7 +50,7 @@ unsigned GradientProjection::solve(double * b) { //cerr << "in gradient projection: n=" << n << endl; for (i=0;idesiredPosition=place[i]; } try { @@ -98,7 +98,7 @@ unsigned GradientProjection::solve(double * b) { for (i=0; idesiredPosition=place[i]; } for (DummyVars::iterator it=dummy_vars.begin();it!=dummy_vars.end();++it){ -- cgit v1.2.3 From f418c74c99b9621c111a8f89eae096b29255b4b2 Mon Sep 17 00:00:00 2001 From: Nicolas Dufour Date: Thu, 16 Feb 2017 18:20:39 +0100 Subject: [Bug #1426613] moving a selection of frame and text-flowed-into-frame displaces text. Fixed bugs: - https://launchpad.net/bugs/1426613 (bzr r15522) --- src/selection-chemistry.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 70307579f..f2bdeba4e 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -1618,7 +1618,7 @@ void ObjectSet::applyAffine(Geom::Affine const &affine, bool set_i2d, bool compe for (auto& itm: region.children) { SPUse *use = dynamic_cast(&itm); if ( use ) { - use->doWriteTransform(use->getRepr(), use->transform.inverse(), NULL, compensate); + use->doWriteTransform(use->getRepr(), item->transform.inverse(), NULL, compensate); } } } -- cgit v1.2.3 From a710b1017f72e57de6f48e2597f8a624a2beed46 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Thu, 16 Feb 2017 21:29:19 +0100 Subject: Fix crashes when element is not shape in rotate copies and mirror symmetry. remove std::cout uneeded (bzr r15523) --- src/live_effects/lpe-copy_rotate.cpp | 5 +---- src/live_effects/lpe-mirror_symmetry.cpp | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index 42e055062..329005878 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -168,9 +168,6 @@ LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem) processObjects(LPE_ERASE); items.clear(); } - - std::cout << previous_num_copies << "previous_num_copies\n"; - std::cout << num_copies << "num_copies\n"; } void @@ -190,7 +187,7 @@ LPECopyRotate::cloneD(SPObject *origin, SPObject *dest, bool root, bool reset) } SPShape * shape = SP_SHAPE(origin); SPPath * path = SP_PATH(dest); - if (!path && !SP_IS_GROUP(dest)) { + if (!path && !SP_IS_GROUP(dest) && shape) { Inkscape::XML::Node *dest_node = sp_selected_item_to_curved_repr(SP_ITEM(dest), 0); dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL); path = SP_PATH(dest); diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index 7f0a93c52..c4101fe79 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -196,7 +196,7 @@ LPEMirrorSymmetry::cloneD(SPObject *origin, SPObject *dest, bool live, bool root } SPShape * shape = SP_SHAPE(origin); SPPath * path = SP_PATH(dest); - if (!path && !SP_IS_GROUP(dest)) { + if (!path && !SP_IS_GROUP(dest) && shape) { Inkscape::XML::Node *dest_node = sp_selected_item_to_curved_repr(SP_ITEM(dest), 0); dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL); path = SP_PATH(dest); -- cgit v1.2.3 From b5746c69a30ebacc0e18df50b864e19309a654a1 Mon Sep 17 00:00:00 2001 From: Jabiertxof Date: Thu, 16 Feb 2017 21:39:20 +0100 Subject: Remmove unneded conditional from rotate copies and mirror symmetry (bzr r15524) --- src/live_effects/lpe-copy_rotate.cpp | 2 +- src/live_effects/lpe-mirror_symmetry.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index 329005878..15ee5eb24 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -187,7 +187,7 @@ LPECopyRotate::cloneD(SPObject *origin, SPObject *dest, bool root, bool reset) } SPShape * shape = SP_SHAPE(origin); SPPath * path = SP_PATH(dest); - if (!path && !SP_IS_GROUP(dest) && shape) { + if (shape && !path) { Inkscape::XML::Node *dest_node = sp_selected_item_to_curved_repr(SP_ITEM(dest), 0); dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL); path = SP_PATH(dest); diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index c4101fe79..ad374c5f8 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -196,7 +196,7 @@ LPEMirrorSymmetry::cloneD(SPObject *origin, SPObject *dest, bool live, bool root } SPShape * shape = SP_SHAPE(origin); SPPath * path = SP_PATH(dest); - if (!path && !SP_IS_GROUP(dest) && shape) { + if (shape && !path) { Inkscape::XML::Node *dest_node = sp_selected_item_to_curved_repr(SP_ITEM(dest), 0); dest->updateRepr(xml_doc, dest_node, SP_OBJECT_WRITE_ALL); path = SP_PATH(dest); -- cgit v1.2.3 From f4784ce3e582db53e07361f50eafc3762bf03398 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Fri, 17 Feb 2017 09:25:09 -0800 Subject: resolve bug 1665421 (bzr r15525) --- src/extension/internal/wmf-inout.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'src') diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index a79af5ec1..42ec2f2bb 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -1765,11 +1765,20 @@ std::cout << "BEFORE DRAW" << " test0 " << ( d->mask & U_DRAW_VISIBLE) << " test1 " << ( d->mask & U_DRAW_FORCE) << " test2 " << (wmr_mask & U_DRAW_ALTERS) + << " test2.5 " << ((d->mask & U_DRAW_NOFILL) != (wmr_mask & U_DRAW_NOFILL) ) << " test3 " << (wmr_mask & U_DRAW_VISIBLE) << " test4 " << !(d->mask & U_DRAW_ONLYTO) << " test5 " << ((d->mask & U_DRAW_ONLYTO) && !(wmr_mask & U_DRAW_ONLYTO) ) << std::endl; */ + /* spurious moveto records should not affect the drawing. However, they set the NOFILL + bit and that messes up the logic about when to emit a path. So prune out any + stray moveto records. That is those which were never followed by a lineto. + */ + if((d->mask & U_DRAW_NOFILL) && !(d->mask & U_DRAW_VISIBLE) && + !(wmr_mask & U_DRAW_ONLYTO) && (wmr_mask & U_DRAW_VISIBLE)){ + d->mask ^= U_DRAW_NOFILL; + } if( (wmr_mask != U_WMR_INVALID) && // next record is valid type @@ -1777,6 +1786,7 @@ std::cout << "BEFORE DRAW" ( (d->mask & U_DRAW_FORCE) || // This draw is forced by STROKE/FILL/STROKEANDFILL PATH (wmr_mask & U_DRAW_ALTERS) || // Next record would alter the drawing environment in some way + ((d->mask & U_DRAW_NOFILL) != (wmr_mask & U_DRAW_NOFILL)) || // Fill<->!Fill requires a draw between ( (wmr_mask & U_DRAW_VISIBLE) && // Next record is visible... ( ( !(d->mask & U_DRAW_ONLYTO) ) || // Non *TO records cannot be followed by any Visible -- cgit v1.2.3 From ec50243a7a1731517e2fac792d7feb67e87e8889 Mon Sep 17 00:00:00 2001 From: mathog <> Date: Fri, 17 Feb 2017 09:27:30 -0800 Subject: improve dot dash support in wmf export (bzr r15526) --- src/extension/internal/wmf-print.cpp | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp index 3d913bf1e..6dd9d895e 100644 --- a/src/extension/internal/wmf-print.cpp +++ b/src/extension/internal/wmf-print.cpp @@ -598,7 +598,28 @@ int PrintWmf::create_pen(SPStyle const *style, const Geom::Affine &transform) if (!style->stroke_dasharray.values.empty()) { if (!FixPPTDashLine) { // if this is set code elsewhere will break dots/dashes into many smaller lines. - penstyle = U_PS_DASH;// userstyle not supported apparently, for now map all Inkscape dot/dash to just dash + int n_dash = style->stroke_dasharray.values.size(); + /* options are dash, dot, dashdot and dashdotdot. Try to pick the closest one. */ + int mark_short=INT_MAX; + int mark_long =0; + int i; + for (i=0;istroke_dasharray.values[i]; + if (mark>mark_long) { mark_long = mark; } + if (mark Date: Sat, 18 Feb 2017 09:42:01 +0100 Subject: Implement Undo. Respond to external changes to