diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2017-05-05 16:52:19 +0000 |
|---|---|---|
| committer | jabiertxof <info@marker.es> | 2017-05-05 16:52:19 +0000 |
| commit | bec0359a0d5b3f7db96417f003927c282c18a9f4 (patch) | |
| tree | e45fa17927826da138e233499060e3142de86899 /src | |
| parent | Update to trunk (diff) | |
| parent | merge lpeUpdDefaultParams (diff) | |
| download | inkscape-bec0359a0d5b3f7db96417f003927c282c18a9f4.tar.gz inkscape-bec0359a0d5b3f7db96417f003927c282c18a9f4.zip | |
Update to trunk
(bzr r13645.1.174)
Diffstat (limited to 'src')
165 files changed, 3201 insertions, 2699 deletions
diff --git a/src/2geom/sbasis-to-bezier.cpp b/src/2geom/sbasis-to-bezier.cpp index 64c07f35e..583fe9ba2 100644 --- a/src/2geom/sbasis-to-bezier.cpp +++ b/src/2geom/sbasis-to-bezier.cpp @@ -188,7 +188,8 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb) double xprime[2], yprime[2]; double midx = 0; double midy = 0; - double numer; + double midx_0, midy_0; + double numer[2], numer_0[2]; double denom; double div; @@ -239,21 +240,23 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb) midx = 8*midx - 4*bz[0][X] - 4*bz[3][X]; // re-define relative to center midy = 8*midy - 4*bz[0][Y] - 4*bz[3][Y]; + midx_0 = sb[X][1][0] + sb[X][1][1]; // zeroth order estimate + midy_0 = sb[Y][1][0] + sb[Y][1][1]; if ((std::abs(xprime[0]) < EPSILON) && (std::abs(yprime[0]) < EPSILON) && ((std::abs(xprime[1]) > EPSILON) || (std::abs(yprime[1]) > EPSILON))) { // degenerate handle at 0 : use distance of closest approach - numer = midx*xprime[1] + midy*yprime[1]; + numer[0] = midx*xprime[1] + midy*yprime[1]; denom = 3.0*(xprime[1]*xprime[1] + yprime[1]*yprime[1]); delx[0] = 0; dely[0] = 0; - delx[1] = -xprime[1]*numer/denom; - dely[1] = -yprime[1]*numer/denom; + delx[1] = -xprime[1]*numer[0]/denom; + dely[1] = -yprime[1]*numer[0]/denom; } else if ((std::abs(xprime[1]) < EPSILON) && (std::abs(yprime[1]) < EPSILON) && ((std::abs(xprime[0]) > EPSILON) || (std::abs(yprime[0]) > EPSILON))) { // degenerate handle at 1 : ditto - numer = midx*xprime[0] + midy*yprime[0]; + numer[1] = midx*xprime[0] + midy*yprime[0]; denom = 3.0*(xprime[0]*xprime[0] + yprime[0]*yprime[0]); - delx[0] = xprime[0]*numer/denom; - dely[0] = yprime[0]*numer/denom; + delx[0] = xprime[0]*numer[1]/denom; + dely[0] = yprime[0]*numer[1]/denom; delx[1] = 0; dely[1] = 0; } else if (std::abs(xprime[1]*yprime[0] - yprime[1]*xprime[0]) > // general case : fit mid fxn value @@ -264,15 +267,21 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb) return; denom = 3.0*(xprime[1]*yprime[0] - yprime[1]*xprime[0]); for (int i = 0; i < 2; ++i) { - numer = xprime[1 - i]*midy - yprime[1 - i]*midx; - delx[i] = xprime[i]*numer/denom; - dely[i] = yprime[i]*numer/denom; + numer_0[i] = xprime[1 - i]*midy_0 - yprime[1 - i]*midx_0; + numer[i] = xprime[1 - i]*midy - yprime[1 - i]*midx; + delx[i] = xprime[i]*numer[i]/denom; + dely[i] = yprime[i]*numer[i]/denom; + if (numer_0[i]*numer[i] < 0) // check for reversal of direction, LP Bug 1544680 + return; } + if (std::abs((numer[0] - numer_0[0])*numer_0[1]) > 10.0*std::abs((numer[1] - numer_0[1])*numer_0[0]) // check for asymmetry + || std::abs((numer[1] - numer_0[1])*numer_0[0]) > 10.0*std::abs((numer[0] - numer_0[0])*numer_0[1])) + return; } else if ((xprime[0]*xprime[1] < 0) || (yprime[0]*yprime[1] < 0)) { // symmetric case : use distance of closest approach - numer = midx*xprime[0] + midy*yprime[0]; + numer[0] = midx*xprime[0] + midy*yprime[0]; denom = 6.0*(xprime[0]*xprime[0] + yprime[0]*yprime[0]); - delx[0] = xprime[0]*numer/denom; - dely[0] = yprime[0]*numer/denom; + delx[0] = xprime[0]*numer[0]/denom; + dely[0] = yprime[0]*numer[0]/denom; delx[1] = -delx[0]; dely[1] = -dely[0]; } else { // anti-symmetric case : fit mid slope @@ -291,10 +300,10 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb) } if (midx*yprime[0] != midy*xprime[0]) { denom = midx*yprime[0] - midy*xprime[0]; - numer = midx*(bz[3][Y] - bz[0][Y]) - midy*(bz[3][X] - bz[0][X]); + numer[0] = midx*(bz[3][Y] - bz[0][Y]) - midy*(bz[3][X] - bz[0][X]); for (int i = 0; i < 2; ++i) { - delx[i] = xprime[0]*numer/denom; - dely[i] = yprime[0]*numer/denom; + delx[i] = xprime[0]*numer[0]/denom; + dely[i] = yprime[0]*numer[0]/denom; } } else { // linear case for (int i = 0; i < 2; ++i) { diff --git a/src/attributes.cpp b/src/attributes.cpp index 5b3d35590..c375ba903 100644 --- a/src/attributes.cpp +++ b/src/attributes.cpp @@ -89,7 +89,6 @@ static SPStyleProp const props[] = { {SP_ATTR_INKSCAPE_ZOOM, "inkscape:zoom"}, {SP_ATTR_INKSCAPE_CX, "inkscape:cx"}, {SP_ATTR_INKSCAPE_CY, "inkscape:cy"}, - {SP_ATTR_INKSCAPE_DOCUMENT_ROTATION, "inkscape:document-rotation"}, {SP_ATTR_INKSCAPE_WINDOW_WIDTH, "inkscape:window-width"}, {SP_ATTR_INKSCAPE_WINDOW_HEIGHT, "inkscape:window-height"}, {SP_ATTR_INKSCAPE_WINDOW_X, "inkscape:window-x"}, diff --git a/src/attributes.h b/src/attributes.h index 6d4ac7543..c4658b85b 100644 --- a/src/attributes.h +++ b/src/attributes.h @@ -97,7 +97,6 @@ enum SPAttributeEnum { SP_ATTR_INKSCAPE_ZOOM, SP_ATTR_INKSCAPE_CX, SP_ATTR_INKSCAPE_CY, - SP_ATTR_INKSCAPE_DOCUMENT_ROTATION, SP_ATTR_INKSCAPE_WINDOW_WIDTH, SP_ATTR_INKSCAPE_WINDOW_HEIGHT, SP_ATTR_INKSCAPE_WINDOW_X, diff --git a/src/desktop-events.cpp b/src/desktop-events.cpp index 9e5f1c20b..5fef8cbfc 100644 --- a/src/desktop-events.cpp +++ b/src/desktop-events.cpp @@ -155,10 +155,6 @@ static gint sp_dt_ruler_event(GtkWidget *widget, GdkEvent *event, SPDesktopWidge } } - SPNamedView *namedview = desktop->namedview; - //if (namedview && namedview->document_rotation) { - // normal *= Geom::Rotate(Geom::rad_from_deg(namedview->document_rotation * -1)); - //} guide = sp_guideline_new(desktop->guides, NULL, event_dt, normal); sp_guideline_set_color(SP_GUIDELINE(guide), desktop->namedview->guidehicolor); diff --git a/src/desktop.cpp b/src/desktop.cpp index c46d6e2f6..c56c42267 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -40,7 +40,9 @@ #include "desktop-style.h" #include "device-manager.h" #include "display/canvas-arena.h" +#include "display/canvas-debug.h" #include "display/canvas-grid.h" +#include "display/canvas-rotate.h" #include "display/canvas-temporary-item-list.h" #include "display/drawing-group.h" #include "display/gnome-canvas-acetate.h" @@ -129,7 +131,6 @@ SPDesktop::SPDesktop() : layers->_layer_deactivated_signal.connect(sigc::bind(sigc::ptr_fun(_layer_deactivated), this)); layers->_layer_changed_signal.connect(sigc::bind(sigc::ptr_fun(_layer_hierarchy_changed), this)); selection = Inkscape::GC::release( new Inkscape::Selection(layers, this) ); - // _current_affine.setRotate(M_PI/4); // To test zooming with rotation } void @@ -221,10 +222,10 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid // being selected? or does it intercept some of the events that should have gone to the // node handler? see bug https://bugs.launchpad.net/inkscape/+bug/414142) gridgroup = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); - guides = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); - sketch = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); + guides = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); + sketch = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); tempgroup = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); - controls = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); + controls = (SPCanvasGroup *) sp_canvas_item_new (main, SP_TYPE_CANVAS_GROUP, NULL); // Set the select tool as the active tool. set_event_context2("/tools/select"); @@ -252,7 +253,8 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid _doc2dt[5] = document->getHeight().value("px"); sp_canvas_item_affine_absolute (SP_CANVAS_ITEM (drawing), _doc2dt); - _modified_connection = namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this)); + _modified_connection = + namedview->connectModified(sigc::bind<2>(sigc::ptr_fun(&_namedview_modified), this)); Inkscape::DrawingItem *ai = document->getRoot()->invoke_show( SP_CANVAS_ARENA (drawing)->drawing, @@ -314,6 +316,10 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid temporary_item_list = new Inkscape::Display::TemporaryItemList( this ); snapindicator = new Inkscape::Display::SnapIndicator ( this ); + + canvas_rotate = sp_canvas_item_new (root, SP_TYPE_CANVAS_ROTATE, NULL); + sp_canvas_item_hide( canvas_rotate ); + // canvas_debug = sp_canvas_item_new (main, SP_TYPE_CANVAS_DEBUG, NULL); } @@ -838,6 +844,7 @@ SPDesktop::set_display_area (bool log) _widget->updateRulers(); _widget->updateScrollbars(_current_affine.getZoom()); _widget->updateZoom(); + _widget->updateRotation(); signal_zoom_changed.emit(_current_affine.getZoom()); } @@ -1128,6 +1135,48 @@ SPDesktop::rotate_relative_center_point (Geom::Point const &c, double rotate) /** + * Flip keeping the point 'c' fixed in the desktop window. + */ +void +SPDesktop::flip_absolute_keep_point (Geom::Point const &c, CanvasFlip flip) +{ + Geom::Point w = d2w( c ); // Must be before flip. + _current_affine.setFlip( flip ); + set_display_area( c, w ); +} + + +void +SPDesktop::flip_relative_keep_point (Geom::Point const &c, CanvasFlip flip) +{ + Geom::Point w = d2w( c ); // Must be before flip. + _current_affine.addFlip( flip ); + set_display_area( c, w ); +} + + +/** + * Flip aligning the point 'c' to the center of desktop window. + */ +void +SPDesktop::flip_absolute_center_point (Geom::Point const &c, CanvasFlip flip) +{ + _current_affine.setFlip( flip ); + Geom::Rect viewbox = canvas->getViewbox(); + set_display_area( c, viewbox.midpoint() ); +} + + +void +SPDesktop::flip_relative_center_point (Geom::Point const &c, CanvasFlip flip) +{ + _current_affine.addFlip( flip ); + Geom::Rect viewbox = canvas->getViewbox(); + set_display_area( c, viewbox.midpoint() ); +} + + +/** * Scroll canvas by to a particular point (window coordinates). */ void @@ -1557,12 +1606,16 @@ SPDesktop::setDocument (SPDocument *doc) layers->setDocument(doc); selection->setDocument(doc); - // remove old EventLog if it exists (see also: bug #1071082) - if (event_log) { - doc->removeUndoObserver(*event_log); - delete event_log; - event_log = 0; - } + if (event_log) { + // Remove it from the replaced document. This prevents Inkscape from + // crashing since we access it in the replaced document's destructor + // which results in an undefined behavior. (See also: bug #1670688) + if (this->doc()) { + this->doc()->removeUndoObserver(*event_log); + } + delete event_log; + event_log = 0; + } /* setup EventLog */ event_log = new Inkscape::EventLog(doc); diff --git a/src/desktop.h b/src/desktop.h index 3dc11b557..330d95607 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -177,6 +177,8 @@ public: SPCanvasGroup *tempgroup; ///< contains temporary canvas items SPCanvasItem *page; ///< page background SPCanvasItem *page_border; ///< page border + SPCanvasItem *canvas_rotate; ///< quickly show canvas rotation + SPCanvasItem *canvas_debug; ///< shows tiling SPCSSAttr *current; ///< current style bool _focusMode; ///< Whether we're focused working or general working @@ -351,6 +353,18 @@ public: void rotate_absolute_center_point (Geom::Point const &c, double const rotate); void rotate_relative_center_point (Geom::Point const &c, double const rotate); + enum CanvasFlip { + FLIP_NONE = 0, + FLIP_HORIZONTAL = 1, + FLIP_VERTICAL = 2 + }; + void flip_absolute_keep_point (Geom::Point const &c, CanvasFlip flip); + void flip_relative_keep_point (Geom::Point const &c, CanvasFlip flip); + void flip_absolute_center_point (Geom::Point const &c, CanvasFlip flip); + void flip_relative_center_point (Geom::Point const &c, CanvasFlip flip); + + double current_rotation() const { return _current_affine.getRotation(); } + void scroll_absolute (Geom::Point const &point, bool is_scrolling = false); void scroll_relative (Geom::Point const &delta, bool is_scrolling = false); void scroll_relative_in_svg_coords (double dx, double dy, bool is_scrolling = false); @@ -474,10 +488,29 @@ private: _update(); } + void setFlip( CanvasFlip flip ) { + _flip = Geom::Scale(); + addFlip( flip ); + } + + void addFlip( CanvasFlip flip ) { + if (flip & FLIP_HORIZONTAL) { + _flip *= Geom::Scale(-1.0, 1.0); + } + if (flip & FLIP_VERTICAL) { + _flip *= Geom::Scale(1.0, -1.0); + } + _update(); + } + double getZoom() const { return _d2w.descrim(); } + double getRotation() const { + return _rotate.angle(); + } + void setOffset( Geom::Point offset ) { _offset = offset; } @@ -490,13 +523,14 @@ private: private: void _update() { - _d2w = _rotate * _scale; + _d2w = _rotate * _scale * _flip; _w2d = _d2w.inverse(); } Geom::Affine _w2d; // Window to desktop Geom::Affine _d2w; // Desktop to window Geom::Rotate _rotate; // Rotate part of _w2d Geom::Scale _scale; // Scale part of _w2d + Geom::Scale _flip; // Flip part of _w2d Geom::Point _offset; // Point on canvas to align to (0,0) of window }; diff --git a/src/display/CMakeLists.txt b/src/display/CMakeLists.txt index 0bf1d6e45..8eaaee99a 100644 --- a/src/display/CMakeLists.txt +++ b/src/display/CMakeLists.txt @@ -4,7 +4,9 @@ set(display_SRC canvas-arena.cpp canvas-axonomgrid.cpp canvas-bpath.cpp + canvas-debug.cpp canvas-grid.cpp + canvas-rotate.cpp canvas-temporary-item-list.cpp canvas-temporary-item.cpp canvas-text.cpp @@ -64,7 +66,9 @@ set(display_SRC canvas-arena.h canvas-axonomgrid.h canvas-bpath.h + canvas-debug.h canvas-grid.h + canvas-rotate.h canvas-temporary-item-list.h canvas-temporary-item.h canvas-text.h diff --git a/src/display/canvas-debug.cpp b/src/display/canvas-debug.cpp new file mode 100644 index 000000000..1748029e9 --- /dev/null +++ b/src/display/canvas-debug.cpp @@ -0,0 +1,100 @@ +/* + * A simple surface for debugging the canvas. Shows how tiles are drawn. + * + * Author: + * Tavmjong Bah <tavmjong@free.fr> + * + * Copyright (C) 2017 Tavmjong Bah + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "inkscape.h" +#include "desktop.h" + +#include "canvas-debug.h" +#include "sp-canvas.h" +#include "cairo-utils.h" +#include "ui/event-debug.h" + +namespace { + +static void sp_canvas_debug_destroy(SPCanvasItem *item); +static void sp_canvas_debug_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); +static void sp_canvas_debug_render (SPCanvasItem *item, SPCanvasBuf *buf); +static int sp_canvas_debug_event (SPCanvasItem *item, GdkEvent *event); + +} // namespace + +G_DEFINE_TYPE(SPCanvasDebug, sp_canvas_debug, SP_TYPE_CANVAS_ITEM); + +static void sp_canvas_debug_class_init (SPCanvasDebugClass *klass) +{ + klass->destroy = sp_canvas_debug_destroy; + klass->update = sp_canvas_debug_update; + klass->render = sp_canvas_debug_render; + klass->event = sp_canvas_debug_event; +} + +static void sp_canvas_debug_init (SPCanvasDebug *debug) +{ + debug->pickable = true; // So we can receive events. +} + +namespace { +static void sp_canvas_debug_destroy (SPCanvasItem *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (SP_IS_CANVAS_DEBUG (object)); + + if (SP_CANVAS_ITEM_CLASS(sp_canvas_debug_parent_class)->destroy) { + SP_CANVAS_ITEM_CLASS(sp_canvas_debug_parent_class)->destroy(object); + } +} + +static void sp_canvas_debug_update( SPCanvasItem *item, Geom::Affine const &/*affine*/, unsigned int /*flags*/ ) +{ + // We cover the entire canvas + item->x1 = -G_MAXINT; + item->y1 = -G_MAXINT; + item->x2 = G_MAXINT; + item->y2 = G_MAXINT; +} + +static void sp_canvas_debug_render( SPCanvasItem *item, SPCanvasBuf *buf) +{ + if (!buf->ct) { + return; + } + + cairo_set_line_width (buf->ct, 2); + + // Draw box around buffer (for debugging) + cairo_new_path (buf->ct); + cairo_move_to (buf->ct, 0, 0); + cairo_line_to (buf->ct, buf->rect.width(), 0); + cairo_line_to (buf->ct, buf->rect.width(), buf->rect.height()); + cairo_line_to (buf->ct, 0, buf->rect.height()); + cairo_close_path (buf->ct); + ink_cairo_set_source_rgba32 (buf->ct, 0xff7f7f7f); + cairo_stroke (buf->ct); +} + +static int sp_canvas_debug_event (SPCanvasItem *item, GdkEvent *event) +{ + ui_dump_event (event, Glib::ustring("sp_canvas_debug_event")); + return false; // We don't use any events... +} + +} // namespace + +/* + 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/display/canvas-debug.h b/src/display/canvas-debug.h new file mode 100644 index 000000000..d5a166da9 --- /dev/null +++ b/src/display/canvas-debug.h @@ -0,0 +1,41 @@ +#ifndef SEEN_SP_CANVAS_DEBUG_H +#define SEEN_SP_CANVAS_DEBUG_H + +/* + * A simple surface for debugging the canvas. Shows how tiles are drawn. + * + * Author: + * Tavmjong Bah <tavmjong@free.fr> + * + * Copyright (C) 2017 Tavmjong Bah + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "sp-canvas-item.h" + +class SPItem; + +#define SP_TYPE_CANVAS_DEBUG (sp_canvas_debug_get_type ()) +#define SP_CANVAS_DEBUG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_CANVAS_DEBUG, SPCanvasDebug)) +#define SP_IS_CANVAS_DEBUG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_CANVAS_DEBUG)) + +struct SPCanvasDebug : public SPCanvasItem { +}; + +GType sp_canvas_debug_get_type (void); + +struct SPCanvasDebugClass : public SPCanvasItemClass{}; + +#endif // SEEN_SP_CANVAS_DEBUG_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 : diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp index 2dadde336..4243d3365 100644 --- a/src/display/canvas-grid.cpp +++ b/src/display/canvas-grid.cpp @@ -5,6 +5,7 @@ * Copyright (C) Lauris Kaplinski 2000 * Abhishek Sharma * Jon A. Cruz <jon@joncruz.org> + * Copyright (C) Tavmong Bah 2017 <tavmjong@free.fr> */ /* As a general comment, I am not exactly proud of how things are done. @@ -841,21 +842,19 @@ void CanvasXYGrid::Update (Geom::Affine const &affine, unsigned int /*flags*/) { ow = origin * affine; - // Temp hack to insure grid doesn't collapse with rotation. - sw[0] = spacing[0] * sqrt(affine[0]*affine[0] + affine[1]*affine[1]); - sw[1] = spacing[1] * sqrt(affine[2]*affine[2] + affine[3]*affine[3]); - sw -= Geom::Point(affine[4], affine[5]); + sw[0] = Geom::Point(spacing[0], 0) * affine.withoutTranslation(); + sw[1] = Geom::Point(0, spacing[1]) * affine.withoutTranslation(); + // Find suitable grid spacing for display for(int dim = 0; dim < 2; dim++) { gint scaling_factor = empspacing; if (scaling_factor <= 1) scaling_factor = 5; - scaled[dim] = FALSE; - sw[dim] = fabs (sw[dim]); - while (sw[dim] < 8.0) { - scaled[dim] = TRUE; + scaled[dim] = false; + while (fabs(sw[dim].length()) < 8.0) { + scaled[dim] = true; sw[dim] *= scaling_factor; /* First pass, go up to the major line spacing, then keep increasing by two. */ @@ -865,49 +864,45 @@ CanvasXYGrid::Update (Geom::Affine const &affine, unsigned int /*flags*/) } -static void -grid_hline (SPCanvasBuf *buf, gint y, gint xs, gint xe, guint32 rgba) +// Find intersections of line with rectangle. There should be zero or two. +// If line is degenerate with rectangle side, two corner points are returned. +static std::vector<Geom::Point> +intersect_line_rectangle( Geom::Line const &line, Geom::Rect const &rect ) { - if ((y < buf->rect.top()) || (y >= buf->rect.bottom())) - return; - - cairo_move_to(buf->ct, 0.5 + xs, 0.5 + y); - cairo_line_to(buf->ct, 0.5 + xe, 0.5 + y); - ink_cairo_set_source_rgba32(buf->ct, rgba); - cairo_stroke(buf->ct); -} - -static void -grid_vline (SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba) -{ - if ((x < buf->rect.left()) || (x >= buf->rect.right())) - return; - - cairo_move_to(buf->ct, 0.5 + x, 0.5 + ys); - cairo_line_to(buf->ct, 0.5 + x, 0.5 + ye); - ink_cairo_set_source_rgba32(buf->ct, rgba); - cairo_stroke(buf->ct); + std::vector<Geom::Point> intersections; + for (unsigned i = 0; i < 4; ++i) { + Geom::LineSegment side( rect.corner(i), rect.corner((i+1)%4) ); + try { + Geom::OptCrossing oc = Geom::intersection(line, side); + if (oc) { + intersections.push_back( line.pointAt((*oc).ta)); + } + } catch (Geom::InfiniteSolutions) { + intersections.clear(); + intersections.push_back( side.pointAt(0) ); + intersections.push_back( side.pointAt(1) ); + return intersections; + } + } + return intersections; } -static void -grid_dot (SPCanvasBuf *buf, gint x, gint y, guint32 rgba) -{ - if ( (y < buf->rect.top()) || (y >= buf->rect.bottom()) - || (x < buf->rect.left()) || (x >= buf->rect.right()) ) - return; - - cairo_rectangle(buf->ct, x, y, 1, 1); - ink_cairo_set_source_rgba32(buf->ct, rgba); - cairo_fill(buf->ct); +// Find the signed distance of a point to a line. The distance is negative if +// the point lies to the left of the line considering the line's versor. +static double +signed_distance( Geom::Point const &point, Geom::Line const &line ) { + Geom::Coord t = line.nearestTime( point ); + Geom::Point p = line.pointAt(t); + double distance = Geom::distance( p, point ); + if ( Geom::cross( Geom::Line( p, point ).versor(), line.versor() ) < 0.0 ) { + distance = -distance; + } + return distance; } void CanvasXYGrid::Render (SPCanvasBuf *buf) { - gdouble const sxg = floor ((buf->rect.left() - ow[Geom::X]) / sw[Geom::X]) * sw[Geom::X] + ow[Geom::X]; - gint const xlinestart = round((sxg - ow[Geom::X]) / sw[Geom::X]); - gdouble const syg = floor ((buf->rect.top() - ow[Geom::Y]) / sw[Geom::Y]) * sw[Geom::Y] + ow[Geom::Y]; - gint const ylinestart = round((syg - ow[Geom::Y]) / sw[Geom::Y]); // no_emphasize_when_zoomedout determines color (minor or major) when only major grid lines/dots shown. Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -924,75 +919,128 @@ CanvasXYGrid::Render (SPCanvasBuf *buf) cairo_set_line_width(buf->ct, 1.0); cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE); - if (!render_dotted) { - // Line grid - gint ylinenum; - gdouble y; - for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) { - gint const y0 = round(y); - if (!scaled[Geom::Y] && (ylinenum % empspacing) != 0) { - grid_hline (buf, y0, buf->rect.left(), buf->rect.right() - 1, color); - } else { - grid_hline (buf, y0, buf->rect.left(), buf->rect.right() - 1, _empcolor); - } - } + for (unsigned dim = 0; dim < 2; ++dim) { - gint xlinenum; - gdouble x; - for (x = sxg, xlinenum = xlinestart; x < buf->rect.right(); x += sw[Geom::X], xlinenum++) { - gint const ix = round(x); - if (!scaled[Geom::X] && (xlinenum % empspacing) != 0) { - grid_vline (buf, ix, buf->rect.top(), buf->rect.bottom(), color); - } else { - grid_vline (buf, ix, buf->rect.top(), buf->rect.bottom(), _empcolor); + // std::cout << "\n " << (dim==0?"Horizontal":"Vertical") << " ------------" << std::endl; + + // Construct an axis line through origin with direction normal to grid spacing. + Geom::Line axis = Geom::Line::from_origin_and_vector( ow, sw[dim] ); + Geom::Line orth = Geom::Line::from_origin_and_vector( ow, sw[(dim+1)%2] ); + + double spacing = sw[(dim+1)%2].length(); // Spacing between grid lines. + double dash = sw[dim].length(); // Total length of dash pattern. + + // std::cout << " axis: " << axis.origin() << ", " << axis.vector() << std::endl; + // std::cout << " spacing: " << spacing << std::endl; + // std::cout << " dash period: " << dash << std::endl; + + // Find the minimum and maximum distances of the buffer corners from axis. + double min = 1000000; + double max = -1000000; + for (unsigned c = 0; c < 4; ++c) { + + // We need signed distance... lib2geom offers only positive distance. + double distance = signed_distance( buf->rect.corner(c), axis ); + + // Correct it for coordinate flips (inverts handedness). + if (Geom::cross( axis.vector(), orth.vector() ) > 0 ) { + distance = -distance; } + + if (distance < min) + min = distance; + if (distance > max) + max = distance; } - } else { - // Dotted grid - gint ylinenum; - gdouble y; - - // alpha needs to be larger than in the line case to maintain a similar visual impact but - // setting it to the maximal value makes the dots dominant in some cases. Solution, - // increase the alpha by a factor of 4. This then allows some user adjustment. - guint32 _empdot = (_empcolor & 0xff) << 2; - if (_empdot > 0xff) - _empdot = 0xff; - _empdot += (_empcolor & 0xffffff00); - - guint32 _colordot = (color & 0xff) << 2; - if (_colordot > 0xff) - _colordot = 0xff; - _colordot += (color & 0xffffff00); - - for (y = syg, ylinenum = ylinestart; y < buf->rect.bottom(); y += sw[Geom::Y], ylinenum++) { - gint const iy = round(y); - - gint xlinenum; - gdouble x; - for (x = sxg, xlinenum = xlinestart; x < buf->rect.right(); x += sw[Geom::X], xlinenum++) { - gint const ix = round(x); - if ( (!scaled[Geom::X] && (xlinenum % empspacing) != 0) - || (!scaled[Geom::Y] && (ylinenum % empspacing) != 0) - || ((scaled[Geom::X] || scaled[Geom::Y]) && no_emp_when_zoomed_out) ) - { - // Minor point: dot only - grid_dot (buf, ix, iy, _colordot); // | (guint32)0x000000FF); // put alpha to max value + int start = floor( min/spacing ); + int stop = floor( max/spacing ); + + // std::cout << " rect: " << buf->rect << std::endl; + // std::cout << " min: " << min << " max: " << max << std::endl; + // std::cout << " start: " << start << " stop: " << stop << std::endl; + + // Loop over grid lines that intersected buf rectangle. + for (int j = start+1; j <= stop; ++j) { + + Geom::Line grid_line = Geom::make_parallel_line( ow + j * sw[(dim+1)%2], axis ); + + std::vector<Geom::Point> x = intersect_line_rectangle( grid_line, buf->rect ); + + // If we have two intersections, grid line intersects buffer rectangle. + if (x.size() == 2 ) { + + // Make sure lines are always drawn in the same direction (or dashes misplaced). + Geom::Line vector( x[0], x[1]); + if (Geom::dot( vector.vector(), axis.vector() ) < 0.0) { + std::swap(x[0], x[1]); + } + + // Set up line. + cairo_move_to(buf->ct, x[0][Geom::X] + 0.5, x[0][Geom::Y] + 0.5); + cairo_line_to(buf->ct, x[1][Geom::X] + 0.5, x[1][Geom::Y] + 0.5); + + // Set dash pattern and color. + if (render_dotted) { + + // alpha needs to be larger than in the line case to maintain a similar + // visual impact but setting it to the maximal value makes the dots + // dominant in some cases. Solution, increase the alpha by a factor of + // 4. This then allows some user adjustment. + guint32 _empdot = (_empcolor & 0xff) << 2; + if (_empdot > 0xff) + _empdot = 0xff; + _empdot += (_empcolor & 0xffffff00); + + guint32 _colordot = (color & 0xff) << 2; + if (_colordot > 0xff) + _colordot = 0xff; + _colordot += (color & 0xffffff00); + + // Dash pattern must use spacing from orthogonal direction. + // Offset is to center dash on orthogonal lines. + double offset = fmod( signed_distance( x[0], orth ), sw[dim].length()); + if (Geom::cross( axis.vector(), orth.vector() ) > 0 ) { + offset = -offset; + } + + double dashes[2]; + if (!scaled[dim] && (j % empspacing) != 0) { + // Minor lines + dashes[0] = 1; + dashes[1] = dash -1; + offset -= 0.5; + ink_cairo_set_source_rgba32(buf->ct, _colordot); + } else { + // Major lines + dashes[0] = 3; + dashes[1] = dash - 3; + offset -= 1.5; // Center dash on intersection. + ink_cairo_set_source_rgba32(buf->ct, _empdot); + } + + cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_BUTT); + cairo_set_dash(buf->ct, dashes, 2, -offset); + } else { - // Major point: small cross - gint const pitch = 1; - grid_dot (buf, ix-pitch, iy, _empcolor); - grid_dot (buf, ix+pitch, iy, _empcolor); - grid_dot (buf, ix, iy, _empdot ); // | (guint32)0x000000FF); // put alpha to max value + // Solid lines - grid_dot (buf, ix, iy-pitch, _empcolor); - grid_dot (buf, ix, iy+pitch, _empcolor); + // Set color + if (!scaled[dim] && (j % empspacing) != 0) { + ink_cairo_set_source_rgba32(buf->ct, color ); + } else { + ink_cairo_set_source_rgba32(buf->ct, _empcolor ); + } } - } + cairo_stroke(buf->ct); + + } else { + std::cerr << "CanvasXYGrid::render: Grid line doesn't intersect!" << std::endl; + } } } + cairo_restore(buf->ct); } @@ -1031,7 +1079,7 @@ CanvasXYGridSnapper::_getSnapLines(Geom::Point const &p) const if (getSnapVisibleOnly()) { // Only snapping to visible grid lines - spacing = grid->sw[i]; // this is the spacing of the visible grid lines measured in screen pixels + spacing = grid->sw[i].length(); // this is the spacing of the visible grid lines measured in screen pixels // convert screen pixels to px // FIXME: after we switch to snapping dist in screen pixels, this will be unnecessary SPDesktop const *dt = _snapmanager->getDesktop(); diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h index bf520467a..91fa43e69 100644 --- a/src/display/canvas-grid.h +++ b/src/display/canvas-grid.h @@ -148,7 +148,7 @@ public: be different in the X or Y direction, hence two variables */ Geom::Point ow; /**< Transformed origin by the affine for the zoom */ - Geom::Point sw; /**< Transformed spacing by the affine for the zoom */ + Geom::Point sw[2]; /**< Transformed spacing by the affine for the zoom */ protected: virtual Gtk::Widget * newSpecificWidget(); diff --git a/src/display/canvas-rotate.cpp b/src/display/canvas-rotate.cpp new file mode 100644 index 000000000..aaf6b962c --- /dev/null +++ b/src/display/canvas-rotate.cpp @@ -0,0 +1,288 @@ +/* + * Temporary surface for previewing rotated canvas. + * + * Author: + * Tavmjong Bah <tavmjong@free.fr> + * + * Copyright (C) 2017 Tavmjong Bah + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "inkscape.h" +#include "desktop.h" + +#include "canvas-rotate.h" +#include "sp-canvas.h" +#include "cairo-utils.h" +#include "ui/event-debug.h" + +#include "2geom/point.h" +#include "2geom/rect.h" + +#include <gtk/gtk.h> + +namespace { + +static void sp_canvas_rotate_destroy(SPCanvasItem *item); +static void sp_canvas_rotate_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); +static void sp_canvas_rotate_render (SPCanvasItem *item, SPCanvasBuf *buf); +static int sp_canvas_rotate_event (SPCanvasItem *item, GdkEvent *event); + +} // namespace + +void sp_canvas_rotate_paint (SPCanvasRotate *canvas_rotate, cairo_surface_t *background); + +G_DEFINE_TYPE(SPCanvasRotate, sp_canvas_rotate, SP_TYPE_CANVAS_ITEM); + +static void sp_canvas_rotate_class_init (SPCanvasRotateClass *klass) +{ + klass->destroy = sp_canvas_rotate_destroy; + //klass->update = sp_canvas_rotate_update; + //klass->render = sp_canvas_rotate_render; + klass->event = sp_canvas_rotate_event; +} + +static void sp_canvas_rotate_init (SPCanvasRotate *rotate) +{ + rotate->pickable = true; // So we can receive events. + rotate->angle = 0.0; + rotate->start_angle = -1000; + rotate->surface_copy = NULL; + rotate->surface_rotated = NULL; +} + +namespace { +static void sp_canvas_rotate_destroy (SPCanvasItem *object) +{ + g_return_if_fail (object != NULL); + g_return_if_fail (SP_IS_CANVAS_ROTATE (object)); + + if (SP_CANVAS_ITEM_CLASS(sp_canvas_rotate_parent_class)->destroy) { + SP_CANVAS_ITEM_CLASS(sp_canvas_rotate_parent_class)->destroy(object); + } +} + +// NOT USED... TOO SLOW +static void sp_canvas_rotate_update( SPCanvasItem *item, Geom::Affine const &/*affine*/, unsigned int /*flags*/ ) +{ + SPCanvasRotate *cr = SP_CANVAS_ROTATE(item); + + if (cr->surface_copy == NULL) { + // std::cout << "sp_canvas_rotate_update: surface_copy is NULL" << std::endl; + return; + } + + // Destroy surface_rotated if it already exists. + if (cr->surface_rotated != NULL) { + cairo_surface_destroy (cr->surface_rotated); + cr->surface_rotated = NULL; + } + + // Create rotated surface + cr->surface_rotated = ink_cairo_surface_create_identical(cr->surface_copy); + double width = cairo_image_surface_get_width (cr->surface_rotated); + double height = cairo_image_surface_get_height (cr->surface_rotated); + cairo_t *context = cairo_create( cr->surface_rotated ); + cairo_set_operator( context, CAIRO_OPERATOR_SOURCE ); + cairo_translate( context, width/2.0, height/2.0 ); + cairo_rotate( context, Geom::rad_from_deg(-cr->angle) ); + cairo_translate( context, -width/2.0, -height/2.0 ); + cairo_set_source_surface( context, cr->surface_copy, 0, 0 ); + cairo_paint( context ); + cairo_destroy( context); + + // We cover the entire canvas + item->x1 = -G_MAXINT; + item->y1 = -G_MAXINT; + item->x2 = G_MAXINT; + item->y2 = G_MAXINT; + + item->canvas->requestRedraw(item->x1, item->y1, item->x2, item->y2); +} + +// NOT USED... TOO SLOW +static void sp_canvas_rotate_render( SPCanvasItem *item, SPCanvasBuf *buf) +{ + // std::cout << "sp_canvas_rotate_render:" << std::endl; + // std::cout << " buf->rect: " << buf->rect << std::endl; + // std::cout << " buf->canvas_rect: " << buf->canvas_rect << std::endl; + SPCanvasRotate *cr = SP_CANVAS_ROTATE(item); + + if (!buf->ct) { + return; + } + + if (cr->surface_rotated == NULL ) { + // std::cout << " surface_rotated is NULL" << std::endl; + return; + } + + // Draw rotated canvas + cairo_save (buf->ct); + cairo_translate (buf->ct, + buf->canvas_rect.left() - buf->rect.left(), + buf->canvas_rect.top() - buf->rect.top() ); + cairo_set_operator (buf->ct, CAIRO_OPERATOR_SOURCE ); + cairo_set_source_surface (buf->ct, cr->surface_rotated, 0, 0 ); + cairo_paint (buf->ct); + cairo_restore (buf->ct); + + + // Draw line from center to cursor + cairo_save (buf->ct); + cairo_translate (buf->ct, -buf->rect.left(), -buf->rect.top()); + cairo_new_path (buf->ct); + cairo_move_to (buf->ct, cr->center[Geom::X], cr->center[Geom::Y]); + cairo_rel_line_to (buf->ct, cr->cursor[Geom::X], cr->cursor[Geom::Y]); + cairo_set_line_width (buf->ct, 2); + ink_cairo_set_source_rgba32 (buf->ct, 0xff00007f); + cairo_stroke (buf->ct); + cairo_restore (buf->ct); + +} + +static int sp_canvas_rotate_event (SPCanvasItem *item, GdkEvent *event) +{ + SPCanvasRotate *cr = SP_CANVAS_ROTATE(item); + +// ui_dump_event (event, Glib::ustring("sp_canvas_rotate_event")); + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Geom::Rect viewbox = desktop->canvas->getViewbox(); // Not SVG viewbox! + cr->center = viewbox.midpoint(); + + switch (event->type) { + case GDK_MOTION_NOTIFY: + { + Geom::Point cursor( event->motion.x, event->motion.y ); + + // Both cursor and center are in window coordinates + Geom::Point rcursor( cursor - cr->center ); + double angle = Geom::deg_from_rad( Geom::atan2(rcursor) ); + + // Set start angle + if (cr->start_angle < -360) { + cr->start_angle = angle; + } + + double rotation_snap = 15; + + double delta_angle = cr->start_angle - angle; + + if (event->motion.state & GDK_SHIFT_MASK && + event->motion.state & GDK_CONTROL_MASK) { + delta_angle = 0; + } else if (event->motion.state & GDK_SHIFT_MASK) { + delta_angle = round(delta_angle/rotation_snap) * rotation_snap; + } else if (event->motion.state & GDK_CONTROL_MASK) { + // ? + } else if (event->motion.state & GDK_MOD1_MASK) { + // Decimal raw angle + } else { + delta_angle = floor(delta_angle); + } + + cr->angle = delta_angle; + + // Correct line for snapping of angle + double distance = rcursor.length(); + cr->cursor = Geom::Point::polar( Geom::rad_from_deg(angle), distance ); + + // Update screen + // sp_canvas_item_request_update( item ); + sp_canvas_rotate_paint (cr, cr->canvas->_backing_store); + break; + } + case GDK_BUTTON_RELEASE: + + // Rotate the actual canvas + desktop->rotate_relative_center_point (desktop->w2d(cr->center), + Geom::rad_from_deg(cr->angle) ); + + // We're done + sp_canvas_item_ungrab (item, event->button.time); + sp_canvas_item_hide (item); + + cr->start_angle = -1000; + if (cr->surface_copy != NULL) { + cairo_surface_destroy( cr->surface_copy ); + cr->surface_copy = NULL; + } + if (cr->surface_rotated != NULL) { + cairo_surface_destroy( cr->surface_rotated ); + cr->surface_rotated = NULL; + } + // sp_canvas_item_show (desktop->drawing); + + break; + case GDK_KEY_PRESS: + // std::cout << " Key press: " << std::endl; + break; + case GDK_KEY_RELEASE: + // std::cout << " Key release: " << std::endl; + break; + default: + // ui_dump_event (event, "sp_canvas_rotate_event: unwanted event: "); + break; + } + + if (event->type == GDK_KEY_PRESS) return false; + + return true; +} + +} // namespace + +void sp_canvas_rotate_start (SPCanvasRotate *canvas_rotate, cairo_surface_t *background) +{ + if (background == NULL) { + std::cerr << "sp_canvas_rotate_start: background is NULL!" << std::endl; + return; + } + + canvas_rotate->angle = 0.0; + + // Copy current background + canvas_rotate->surface_copy = ink_cairo_surface_copy( background ); + + // Paint canvas with background... since we are hiding drawing. + sp_canvas_item_request_update( canvas_rotate ); +} + +// Paint the canvas ourselves for speed.... +void sp_canvas_rotate_paint (SPCanvasRotate *canvas_rotate, cairo_surface_t *background) +{ + if (background == NULL) { + std::cerr << "sp_canvas_rotate_paint: background is NULL!" << std::endl; + return; + } + + double width = cairo_image_surface_get_width (background); + double height = cairo_image_surface_get_height (background); + + // Draw rotated canvas + cairo_t *context = cairo_create( background ); + + cairo_save (context); + cairo_set_operator( context, CAIRO_OPERATOR_SOURCE ); + cairo_translate( context, width/2.0, height/2.0 ); + cairo_rotate( context, Geom::rad_from_deg(-canvas_rotate->angle) ); + cairo_translate( context, -width/2.0, -height/2.0 ); + cairo_set_source_surface( context, canvas_rotate->surface_copy, 0, 0 ); + cairo_paint( context ); + cairo_restore( context ); + cairo_destroy( context ); + + gtk_widget_queue_draw (GTK_WIDGET (canvas_rotate->canvas)); +} +/* + 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/display/canvas-rotate.h b/src/display/canvas-rotate.h new file mode 100644 index 000000000..8620dcced --- /dev/null +++ b/src/display/canvas-rotate.h @@ -0,0 +1,50 @@ +#ifndef SEEN_SP_CANVAS_ROTATE_H +#define SEEN_SP_CANVAS_ROTATE_H + +/* + * Temporary surface for previewing rotated canvas. + * + * Author: + * Tavmjong Bah <tavmjong@free.fr> + * + * Copyright (C) 2017 Tavmjong Bah + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "sp-canvas-item.h" +#include "2geom/line.h" + +class SPItem; + +#define SP_TYPE_CANVAS_ROTATE (sp_canvas_rotate_get_type ()) +#define SP_CANVAS_ROTATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_CANVAS_ROTATE, SPCanvasRotate)) +#define SP_IS_CANVAS_ROTATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_CANVAS_ROTATE)) + +struct SPCanvasRotate : public SPCanvasItem { + Geom::Point center; // Center of screen + Geom::Point cursor; // Position of cursor relative to center (after angle snapping) + double angle; // Rotation angle in degrees + double start_angle; // Starting angle of cursor + cairo_surface_t *surface_copy; // Copy of original surface + cairo_surface_t *surface_rotated; // Copy of original surface, rotated +}; + +void sp_canvas_rotate_start( SPCanvasRotate *canvas_rotate, cairo_surface_t *background ); + +GType sp_canvas_rotate_get_type (void); + +struct SPCanvasRotateClass : public SPCanvasItemClass{}; + +#endif // SEEN_SP_CANVAS_ROTATE_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 : diff --git a/src/display/canvas-temporary-item-list.h b/src/display/canvas-temporary-item-list.h index 6b0e5796b..471bb99b9 100644 --- a/src/display/canvas-temporary-item-list.h +++ b/src/display/canvas-temporary-item-list.h @@ -14,7 +14,6 @@ struct SPCanvasItem; class SPDesktop; -class SPViewBox; namespace Inkscape { namespace Display { diff --git a/src/display/gnome-canvas-acetate.cpp b/src/display/gnome-canvas-acetate.cpp index 9147a1bbf..297d69068 100644 --- a/src/display/gnome-canvas-acetate.cpp +++ b/src/display/gnome-canvas-acetate.cpp @@ -14,11 +14,13 @@ */ #include "gnome-canvas-acetate.h" +#include "ui/event-debug.h" static void sp_canvas_acetate_destroy(SPCanvasItem *object); static void sp_canvas_acetate_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags); static double sp_canvas_acetate_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item); +static int sp_canvas_acetate_event( SPCanvasItem *item, GdkEvent *event); G_DEFINE_TYPE(SPCanvasAcetate, sp_canvas_acetate, SP_TYPE_CANVAS_ITEM); @@ -29,6 +31,7 @@ static void sp_canvas_acetate_class_init (SPCanvasAcetateClass *klass) item_class->destroy = sp_canvas_acetate_destroy; item_class->update = sp_canvas_acetate_update; item_class->point = sp_canvas_acetate_point; + // item_class->event = sp_canvas_acetate_event; } static void sp_canvas_acetate_init (SPCanvasAcetate */*acetate*/) @@ -60,3 +63,8 @@ static double sp_canvas_acetate_point( SPCanvasItem *item, Geom::Point /*p*/, SP return 0.0; } +// static int sp_canvas_acetate_event( SPCanvasItem *item, GdkEvent *event) +// { +// ui_dump_event (event, "sp_canvas_acetate_event"); +// return 0; // ? +// } diff --git a/src/display/sodipodi-ctrlrect.cpp b/src/display/sodipodi-ctrlrect.cpp index ecc952c48..075e04e6d 100644 --- a/src/display/sodipodi-ctrlrect.cpp +++ b/src/display/sodipodi-ctrlrect.cpp @@ -6,9 +6,11 @@ * bulia byak <buliabyak@users.sf.net> * Carl Hetherington <inkscape@carlh.net> * Jon A. Cruz <jon@joncruz.org> + * Tavmjong Bah <tavmjong@free.fr> * * Copyright (C) 1999-2001 Lauris Kaplinski * Copyright (C) 2000-2001 Ximian, Inc. + * Copyright (C) 2017 Tavmjong Bah * * Released under GNU GPL * @@ -18,6 +20,7 @@ #include "sp-canvas-util.h" #include "display/cairo-utils.h" #include "display/sp-canvas.h" +#include <2geom/transforms.h> /* * Currently we do not have point method, as it should always be painted @@ -76,14 +79,12 @@ void CtrlRect::init() _dashed = false; _checkerboard = false; - _shadow = 0; + _shadow_width = 0; _area = Geom::OptIntRect(); _rect = Geom::Rect(Geom::Point(0,0),Geom::Point(0,0)); - _shadow_size = 0; - _border_color = 0x000000ff; _fill_color = 0xffffffff; _shadow_color = 0x000000ff; @@ -98,52 +99,120 @@ void CtrlRect::render(SPCanvasBuf *buf) if (!_area) { return; } - Geom::IntRect area = *_area; - Geom::IntRect area_w_shadow (area[X].min(), area[Y].min(), - area[X].max() + _shadow_size, area[Y].max() + _shadow_size); - if ( area_w_shadow.intersects(buf->rect) ) + + Geom::IntRect area = *_area; // _area already includes space for shadow. + if ( area.intersects(buf->rect) ) { - static double const dashes[2] = {4.0, 4.0}; + cairo_save(buf->ct); cairo_translate(buf->ct, -buf->rect.left(), -buf->rect.top()); - cairo_set_line_width(buf->ct, 1); - if (_dashed) cairo_set_dash(buf->ct, dashes, 2, 0); - cairo_rectangle(buf->ct, 0.5 + area[X].min(), 0.5 + area[Y].min(), - area[X].max() - area[X].min(), area[Y].max() - area[Y].min()); + + // Get canvas rotation (scale is isotropic). + double rotation = atan2( _affine[1], _affine[0] ); + + // Are we axis aligned? + double mod_rot = fmod(rotation * M_2_PI, 1); + bool axis_aligned = Geom::are_near( mod_rot, 0 ) || Geom::are_near( mod_rot, 1.0 ); + + // Get the points we need transformed to window coordinates. + Geom::Point rect_transformed[4]; + for (unsigned i = 0; i < 4; ++i) { + rect_transformed[i] = _rect.corner(i) * _affine; + } + + // Draw shadow first. Shadow extends under rectangle to reduce aliasing effects. + if (_shadow_width > 0 && !_dashed) { + + // Offset by half stroke width (_shadow_width is in window coordinates). + // Need to handle change in handedness with flips. + Geom::Point shadow( _shadow_width/2.0, (_affine.det()>0?-1:1)*_shadow_width/2.0 ); + shadow *= Geom::Rotate( rotation ); + + if (axis_aligned) { + // Snap to pixel grid (add 0.5 to center on pixel). + cairo_move_to( buf->ct, + floor(rect_transformed[0][X]+shadow[X]+0.5) + 0.5, + floor(rect_transformed[0][Y]+shadow[Y]+0.5) + 0.5 ); + cairo_line_to( buf->ct, + floor(rect_transformed[1][X]+shadow[X]+0.5) + 0.5, + floor(rect_transformed[1][Y]+shadow[Y]+0.5) + 0.5 ); + cairo_line_to( buf->ct, + floor(rect_transformed[2][X]+shadow[X]+0.5) + 0.5, + floor(rect_transformed[2][Y]+shadow[Y]+0.5) + 0.5 ); + } else { + cairo_move_to( buf->ct, + rect_transformed[0][X]+shadow[X], + rect_transformed[0][Y]+shadow[Y] ); + cairo_line_to( buf->ct, + rect_transformed[1][X]+shadow[X], + rect_transformed[1][Y]+shadow[Y] ); + cairo_line_to( buf->ct, + rect_transformed[2][X]+shadow[X], + rect_transformed[2][Y]+shadow[Y] ); + } + + ink_cairo_set_source_rgba32( buf->ct, _shadow_color ); + cairo_set_line_width( buf->ct, _shadow_width + 1 ); + cairo_stroke( buf->ct ); + } + + // Setup rectangle path + if (axis_aligned) { + + // Snap to pixel grid + Geom::Rect outline( _rect.min() * _affine, _rect.max() * _affine); + // Check if there is a simpler way to go from 'outline' to 'int_rect'. + Geom::IntRect int_rect ( (int) floor(outline.min()[X] + 0.5), + (int) floor(outline.min()[Y] + 0.5), + (int) floor(outline.max()[X] + 0.5), + (int) floor(outline.max()[Y] + 0.5) ); + cairo_rectangle (buf->ct, + 0.5 + int_rect[X].min(), + 0.5 + int_rect[Y].min(), + int_rect[X].max() - int_rect[X].min(), + int_rect[Y].max() - int_rect[Y].min() ); + } else { + + // Angled + cairo_move_to( buf->ct, rect_transformed[0][X], rect_transformed[0][Y] ); + cairo_line_to( buf->ct, rect_transformed[1][X], rect_transformed[1][Y] ); + cairo_line_to( buf->ct, rect_transformed[2][X], rect_transformed[2][Y] ); + cairo_line_to( buf->ct, rect_transformed[3][X], rect_transformed[3][Y] ); + cairo_close_path( buf->ct ); + } + + // This doesn't seem to be used anywhere. If it is, then we should + // probably rotate the coordinate system and fill using a cairo_rectangle(). if (_checkerboard) { cairo_pattern_t *cb = ink_cairo_pattern_create_checkerboard(); cairo_set_source(buf->ct, cb); cairo_pattern_destroy(cb); cairo_fill_preserve(buf->ct); } + if (_has_fill) { ink_cairo_set_source_rgba32(buf->ct, _fill_color); cairo_fill_preserve(buf->ct); } + // Set up stroke. ink_cairo_set_source_rgba32(buf->ct, _border_color); - cairo_stroke(buf->ct); + cairo_set_line_width(buf->ct, 1); + static double const dashes[2] = {4.0, 4.0}; + if (_dashed) cairo_set_dash(buf->ct, dashes, 2, 0); - if (_shadow_size == 1) { // highlight the border by drawing it in _shadow_color - if (_dashed) { - cairo_set_dash(buf->ct, dashes, 2, 4); - cairo_rectangle(buf->ct, 0.5 + area[X].min(), 0.5 + area[Y].min(), - area[X].max() - area[X].min(), area[Y].max() - area[Y].min()); - } else { - cairo_rectangle(buf->ct, -0.5 + area[X].min(), -0.5 + area[Y].min(), - area[X].max() - area[X].min(), area[Y].max() - area[Y].min()); - } - ink_cairo_set_source_rgba32(buf->ct, _shadow_color); - cairo_stroke(buf->ct); - } else if (_shadow_size > 1) { // fill the shadow + // Stroke rectangle. + cairo_stroke_preserve(buf->ct); + + // Highlight the border by drawing it in _shadow_color. + if (_shadow_width == 1 && _dashed) { ink_cairo_set_source_rgba32(buf->ct, _shadow_color); - cairo_rectangle(buf->ct, 1 + area[X].max(), area[Y].min() + _shadow_size, - _shadow_size, area[Y].max() - area[Y].min() + 1); // right shadow - cairo_rectangle(buf->ct, area[X].min() + _shadow_size, 1 + area[Y].max(), - area[X].max() - area[X].min() - _shadow_size + 1, _shadow_size); - cairo_fill(buf->ct); + cairo_set_dash(buf->ct, dashes, 2, 4); // Dash offset by dash length. + cairo_stroke_preserve(buf->ct); } + + cairo_new_path( buf->ct ); // Clear path or get wierd artifacts. cairo_restore(buf->ct); } } @@ -158,124 +227,33 @@ void CtrlRect::update(Geom::Affine const &affine, unsigned int flags) (SP_CANVAS_ITEM_CLASS(sp_ctrlrect_parent_class))->update(this, affine, flags); } - sp_canvas_item_reset_bounds(this); + // Note: There is no harm if 'area' is too large other than a possible small slow down in + // rendering speed. - Geom::Rect bbox(_rect.min() * affine, _rect.max() * affine); + // Calculate an axis-aligned bounding box that include all of transformed _rect. + Geom::Rect bbox = _rect; + bbox *= affine; - Geom::OptIntRect _area_old = _area; - Geom::IntRect area ( (int) floor(bbox.min()[Geom::X] + 0.5), - (int) floor(bbox.min()[Geom::Y] + 0.5), - (int) floor(bbox.max()[Geom::X] + 0.5), - (int) floor(bbox.max()[Geom::Y] + 0.5) ); - _area = area; - Geom::IntRect area_old(0,0,0,0); - if (_area_old) { // this weird construction is because the code below assumes _area_old to be 'valid' - area_old = *_area_old; - } + // Enlarge bbox by twice shadow size (to allow for shadow on any side with a 45deg rotation). + bbox.expandBy( 2.0 *_shadow_width ); - gint _shadow_size_old = _shadow_size; - _shadow_size = _shadow; - - // FIXME: we don't process a possible change in _has_fill - if (_has_fill) { - if (_area_old) { - canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].min() - 1, - area_old[X].max() + _shadow_size + 1, area_old[Y].max() + _shadow_size + 1); - } - if (_area) { - canvas->requestRedraw(area[X].min() - 1, area[Y].min() - 1, - area[X].max() + _shadow_size + 1, area[Y].max() + _shadow_size + 1); - } - } else { // clear box, be smart about what part of the frame to redraw - - /* Top */ - if (area[Y].min() != area_old[Y].min()) { // different level, redraw fully old and new - if (area_old[X].min() != area_old[X].max()) - canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].min() - 1, - area_old[X].max() + 1, area_old[Y].min() + 1); - - if (area[X].min() != area[X].max()) - canvas->requestRedraw(area[X].min() - 1, area[Y].min() - 1, - area[X].max() + 1, area[Y].min() + 1); - } else { // same level, redraw only the ends - if (area[X].min() != area_old[X].min()) { - canvas->requestRedraw(MIN(area_old[X].min(),area[X].min()) - 1, area[Y].min() - 1, - MAX(area_old[X].min(),area[X].min()) + 1, area[Y].min() + 1); - } - if (area[X].max() != area_old[X].max()) { - canvas->requestRedraw(MIN(area_old[X].max(),area[X].max()) - 1, area[Y].min() - 1, - MAX(area_old[X].max(),area[X].max()) + 1, area[Y].min() + 1); - } - } - - /* Left */ - if (area[X].min() != area_old[X].min()) { // different level, redraw fully old and new - if (area_old[Y].min() != area_old[Y].max()) - canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].min() - 1, - area_old[X].min() + 1, area_old[Y].max() + 1); - - if (area[Y].min() != area[Y].max()) - canvas->requestRedraw(area[X].min() - 1, area[Y].min() - 1, - area[X].min() + 1, area[Y].max() + 1); - } else { // same level, redraw only the ends - if (area[Y].min() != area_old[Y].min()) { - canvas->requestRedraw(area[X].min() - 1, MIN(area_old[Y].min(),area[Y].min()) - 1, - area[X].min() + 1, MAX(area_old[Y].min(),area[Y].min()) + 1); - } - if (area[Y].max() != area_old[Y].max()) { - canvas->requestRedraw(area[X].min() - 1, MIN(area_old[Y].max(),area[Y].max()) - 1, - area[X].min() + 1, MAX(area_old[Y].max(),area[Y].max()) + 1); - } - } - - /* Right */ - if (area[X].max() != area_old[X].max() || _shadow_size_old != _shadow_size) { - if (area_old[Y].min() != area_old[Y].max()) - canvas->requestRedraw(area_old[X].max() - 1, area_old[Y].min() - 1, - area_old[X].max() + _shadow_size + 1, area_old[Y].max() + _shadow_size + 1); - - if (area[Y].min() != area[Y].max()) - canvas->requestRedraw(area[X].max() - 1, area[Y].min() - 1, - area[X].max() + _shadow_size + 1, area[Y].max() + _shadow_size + 1); - } else { // same level, redraw only the ends - if (area[Y].min() != area_old[Y].min()) { - canvas->requestRedraw(area[X].max() - 1, MIN(area_old[Y].min(),area[Y].min()) - 1, - area[X].max() + _shadow_size + 1, MAX(area_old[Y].min(),area[Y].min()) + _shadow_size + 1); - } - if (area[Y].max() != area_old[Y].max()) { - canvas->requestRedraw(area[X].max() - 1, MIN(area_old[Y].max(),area[Y].max()) - 1, - area[X].max() + _shadow_size + 1, MAX(area_old[Y].max(),area[Y].max()) + _shadow_size + 1); - } - } + // Generate an integer rectangle that includes bbox. + Geom::OptIntRect _area_old = _area; + _area = bbox.roundOutwards(); - /* Bottom */ - if (area[Y].max() != area_old[Y].max() || _shadow_size_old != _shadow_size) { - if (area_old[X].min() != area_old[X].max()) - canvas->requestRedraw(area_old[X].min() - 1, area_old[Y].max() - 1, - area_old[X].max() + _shadow_size + 1, area_old[Y].max() + _shadow_size + 1); - - if (area[X].min() != area[X].max()) - canvas->requestRedraw(area[X].min() - 1, area[Y].max() - 1, - area[X].max() + _shadow_size + 1, area[Y].max() + _shadow_size + 1); - } else { // same level, redraw only the ends - if (area[X].min() != area_old[X].min()) { - canvas->requestRedraw(MIN(area_old[X].min(),area[X].min()) - 1, area[Y].max() - 1, - MAX(area_old[X].min(),area[X].min()) + _shadow_size + 1, area[Y].max() + _shadow_size + 1); - } - if (area[X].max() != area_old[X].max()) { - canvas->requestRedraw(MIN(area_old[X].max(),area[X].max()) - 1, area[Y].max() - 1, - MAX(area_old[X].max(),area[X].max()) + _shadow_size + 1, area[Y].max() + _shadow_size + 1); - } - } - } + // std::cout << " _rect: " << _rect << std::endl; + // std::cout << " bbox: " << bbox << std::endl; + // std::cout << " area: " << *_area << std::endl; - // update SPCanvasItem box if (_area) { - x1 = area[X].min() - 1; - y1 = area[Y].min() - 1; - x2 = area[X].max() + _shadow_size + 1; - y2 = area[Y].max() + _shadow_size + 1; + Geom::IntRect area = *_area; + sp_canvas_update_bbox( this, area[X].min(), area[Y].min(), area[X].max(), area[Y].max() ); + } else { + std::cerr << "CtrlRect::update: No area!!" << std::endl; } + + // At rendering stage, we need to know affine: + _affine = affine; } @@ -289,7 +267,7 @@ void CtrlRect::setColor(guint32 b, bool h, guint f) void CtrlRect::setShadow(int s, guint c) { - _shadow = s; + _shadow_width = s; _shadow_color = c; _requestUpdate(); } diff --git a/src/display/sodipodi-ctrlrect.h b/src/display/sodipodi-ctrlrect.h index 08a085649..02fc85647 100644 --- a/src/display/sodipodi-ctrlrect.h +++ b/src/display/sodipodi-ctrlrect.h @@ -4,14 +4,17 @@ /** * @file * Simple non-transformed rectangle, usable for rubberband. + * Modified to work with rotated canvas. */ /* * Authors: * Lauris Kaplinski <lauris@ximian.com> * Carl Hetherington <inkscape@carlh.net> + * Tavmjong Bah <tavjong@free.fr> * * Copyright (C) 1999-2001 Lauris Kaplinski * Copyright (C) 2000-2001 Ximian, Inc. + * Copyright (C) 2017 Tavmjong Bah * * Released under GNU GPL * @@ -21,6 +24,7 @@ #include "sp-canvas-item.h" #include <2geom/rect.h> #include <2geom/int-rect.h> +#include <2geom/transforms.h> struct SPCanvasBuf; @@ -48,23 +52,24 @@ private: void _requestUpdate(); Geom::Rect _rect; + Geom::Affine _affine; + bool _has_fill; bool _dashed; bool _checkerboard; Geom::OptIntRect _area; - gint _shadow_size; + gint _shadow_width; guint32 _border_color; guint32 _fill_color; guint32 _shadow_color; - int _shadow; }; struct CtrlRectClass : public SPCanvasItemClass {}; GType sp_ctrlrect_get_type(); -#endif // SEEN_RUBBERBAND_H +#endif // SEEN_CTRLRECT_H /* Local Variables: diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index 61602e880..d04c81ecb 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -33,11 +33,6 @@ #include "display/sp-canvas-group.h" #include "display/rendermode.h" #include "display/cairo-utils.h" -#include "display/cairo-templates.h" -#include "display/drawing-context.h" -#include "display/drawing-item.h" -#include "display/nr-filter-colormatrix.h" -#include "display/canvas-arena.h" #include "preferences.h" #include "inkscape.h" #include "sodipodi-ctrlrect.h" @@ -45,8 +40,6 @@ #include "debug/gdk-event-latency-tracker.h" #include "desktop.h" #include "color.h" -#include <iomanip> -#include <glibmm/i18n.h> #if GTK_CHECK_VERSION(3,20,0) # include <gdkmm/seat.h> @@ -1514,7 +1507,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect buf.buf = NULL; buf.buf_rowstride = 0; buf.rect = paint_rect; - buf.visible_rect = canvas_rect; + buf.canvas_rect = canvas_rect; buf.is_empty = true; // create temporary surface @@ -1578,7 +1571,7 @@ void SPCanvas::paintSingleBuffer(Geom::IntRect const &paint_rect, Geom::IntRect } struct PaintRectSetup { - Geom::IntRect big_rect; + Geom::IntRect canvas_rect; GTimeVal start_time; int max_pixels; Geom::Point mouse_loc; @@ -1637,7 +1630,7 @@ int SPCanvas::paintRectInternal(PaintRectSetup const *setup, Geom::IntRect const gdk_window_begin_paint_rect(window, &r); */ - paintSingleBuffer(this_rect, setup->big_rect, bw); + paintSingleBuffer(this_rect, setup->canvas_rect, bw); //gdk_window_end_paint(window); return 1; } @@ -1702,6 +1695,7 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1) gtk_widget_get_allocation(GTK_WIDGET(this), &allocation); + // Find window rectangle in 'world coordinates'. Geom::IntRect canvas_rect = Geom::IntRect::from_xywh(_x0, _y0, allocation.width, allocation.height); Geom::IntRect paint_rect(xx0, yy0, xx1, yy1); @@ -1712,7 +1706,7 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1) paint_rect = *area; PaintRectSetup setup; - setup.big_rect = paint_rect; + setup.canvas_rect = canvas_rect; // Save the mouse location gint x, y; @@ -1733,10 +1727,16 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1) setup.mouse_loc = sp_canvas_window_to_world(this, Geom::Point(x,y)); + static unsigned tile_multiplier = 0; + if (tile_multiplier == 0) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + tile_multiplier = prefs->getIntLimited("/options/rendering/tile-multiplier", 1, 1, 64); + } + if (_rendermode != Inkscape::RENDERMODE_OUTLINE) { // use 256K as a compromise to not slow down gradients // 256K is the cached buffer and we need 4 channels - setup.max_pixels = 65536; // 256K/4 + setup.max_pixels = 65536 * tile_multiplier; // 256K/4 } else { // paths only, so 1M works faster // 1M is the cached buffer and we need 4 channels @@ -1924,19 +1924,6 @@ SPCanvasGroup *SPCanvas::getRoot() return SP_CANVAS_GROUP(_root); } -gdouble grayscale_value_matrix[20] = { - 0.21, 0.72, 0.072, 0, 0, - 0.21, 0.72, 0.072, 0, 0, - 0.21, 0.72, 0.072, 0, 0, - 0 , 0 , 0 , 1, 0 - }; -cairo_surface_t *surface_rotated; -cairo_surface_t *surface_origin; -cairo_surface_t *surface_measure; -double start_angle = 0; -bool started = false; -bool rotated = false; - /** * Scroll screen to point 'c'. 'c' is measured in screen pixels. */ @@ -1965,14 +1952,10 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); // Paint the background cairo_translate(cr, -ix, -iy); - if (rotated) { - cairo_translate(cr, dx, dy); - rotated = false; - } cairo_set_source(cr, _background); cairo_paint(cr); + // Copy the old backing store contents - cairo_set_source_surface(cr, _backing_store, _x0, _y0); cairo_rectangle(cr, _x0, _y0, allocation.width, allocation.height); cairo_clip(cr); @@ -2009,271 +1992,6 @@ void SPCanvas::scrollTo( Geom::Point const &c, unsigned int clear, bool is_scrol addIdle(); } -void SPCanvas::startRotateTo(double angle) -{ - if (!_backing_store || started) { - return; - } - start_angle = angle; - started = true; - GtkAllocation allocation; - gtk_widget_get_allocation(&_widget, &allocation); - int half_w = allocation.width/2; - int half_h = allocation.height/2; - int half_min = std::min(half_w,half_h); - - cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height); - cairo_t *cr = cairo_create(new_backing_store); - cairo_arc(cr, half_w, half_h, half_min-15, 0, 2*M_PI); - cairo_fill(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_IN); - cairo_set_source_surface(cr, _backing_store, 0, 0); - cairo_paint(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_arc(cr, half_w, half_h, half_min-16, 0, 2*M_PI); - cairo_set_source_rgba (cr, 1, 1, 1, 0.5); - cairo_stroke(cr); - cairo_destroy(cr); - surface_rotated = new_backing_store; - - cairo_surface_t *new_backing_store_measure = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height); - cr = cairo_create(new_backing_store_measure); - cairo_arc(cr, half_w, half_h, half_min-15, 0, 2*M_PI); - cairo_set_source_rgba (cr, 1, 1, 1, 0.2); - cairo_fill(cr); - cairo_translate(cr, half_w, half_h); - cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, 10.0); - for (gint x = 0; x < 360 ; x++){ - gint ang = 360 - x ;//+ 90; - if (ang > 180) { - ang -= 360; - } - double rot = (-180.0 + x)*(M_PI/180.); - double dist = half_min-9; - gint inverse = 1; - if((x) < 91 || (x) > 270) { - inverse = -1; - } - if(x%10 == 0) { - cairo_rotate(cr, -rot); - cairo_text_extents_t extents; - std::string s = std::to_string(ang) + "º"; - cairo_text_extents(cr, s.c_str(), &extents); - //std::cout << extents.width/2 << "extents.x_bearing\n"; - cairo_translate(cr, (extents.width/2) * inverse * -1, (dist + ((extents.height/2)* inverse))); - if((x) < 91 || (x) > 270) { - cairo_rotate(cr, 180*(M_PI/180.0)); - } - cairo_text_path(cr, s.c_str()); - if((x) < 91 || (x) > 270) { - cairo_rotate(cr, -180*(M_PI/180.0)); - } - cairo_translate(cr, (extents.width/2) * inverse , (dist + ((extents.height/2)* inverse)) * -1); - cairo_set_source_rgba (cr, 1, 1, 1, 1); - cairo_fill(cr); - cairo_rotate(cr, rot); - } - cairo_rotate(cr, x*(M_PI/180.)); - if(x%5 == 0) { - cairo_move_to(cr, 0, half_min-30); - cairo_line_to(cr, 0, half_min-17); - } else { - cairo_move_to(cr, 0, half_min-20); - cairo_line_to(cr, 0, half_min-15); - } - cairo_line_to(cr, 0, half_min-15); - cairo_set_source_rgba (cr, 0, 0, 0, 0.4); - cairo_set_line_width (cr,1); - cairo_stroke(cr); - cairo_rotate(cr, -x*(M_PI/180.)); - } - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_translate(cr, -half_w, -half_h); - cairo_arc(cr, half_w, half_h, half_min-30, 0, 2*M_PI); - cairo_set_source_rgba (cr, 1, 1, 1, 1); - cairo_fill(cr); - cairo_translate(cr, half_w, half_h); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_rotate(cr, start_angle*(M_PI/180.)); - cairo_move_to(cr, 0, 0); - cairo_line_to(cr, 0, (half_min-17) * -1); - cairo_set_source_rgba (cr, 1, 1, 1, 0.25); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_width (cr,5); - cairo_stroke(cr); - cairo_move_to(cr, 0, 0); - cairo_line_to(cr, 0, (half_min-17) * -1); - cairo_set_source_rgba (cr, 1, 0, 0, 0.9); - cairo_set_line_width (cr,1); - cairo_stroke(cr); - cairo_rotate(cr, -start_angle*(M_PI/180.)); - cairo_destroy(cr); - surface_measure = new_backing_store_measure; - - cairo_surface_t *new_backing_store_grey = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height); - cr = cairo_create(new_backing_store_grey); - cairo_set_operator(cr, CAIRO_OPERATOR_OVER); - cairo_set_source_surface(cr, _backing_store, 0, 0); - cairo_paint(cr); - Inkscape::Filters::FilterColorMatrix::ColorMatrixMatrix _grayscale_colormatrix = std::vector<gdouble> (grayscale_value_matrix, grayscale_value_matrix + 20); - cairo_surface_t *out = ink_cairo_surface_create_identical(new_backing_store_grey); - ink_cairo_surface_filter(new_backing_store_grey, out, _grayscale_colormatrix); - cairo_set_source_surface(cr, out, 0, 0); - cairo_surface_destroy(out); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_paint(cr); - cairo_destroy(cr); - surface_origin = new_backing_store_grey; -} - -bool SPCanvas::endRotateTo() -{ - if (!_backing_store || !started) { - return false; - } - started = false; - surface_rotated = NULL; - surface_origin = NULL; - gtk_widget_queue_draw(GTK_WIDGET(this)); - dirtyAll(); - addIdle(); - rotated = true; - return true; -} - -void SPCanvas::clearRotateTo() -{ - if (!started) { - return; - } - gtk_widget_queue_draw(GTK_WIDGET(this)); - dirtyAll(); - addIdle(); -} - -void SPCanvas::rotateTo(double angle) -{ - if (!_backing_store || !started) { - return; - } - GtkAllocation allocation; - gtk_widget_get_allocation(&_widget, &allocation); - int half_w = allocation.width/2; - int half_h = allocation.height/2; - int half_min = std::min(half_w,half_h); - cairo_surface_t *new_backing_store = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, allocation.width, allocation.height); - cairo_t *cr = cairo_create(new_backing_store); - cairo_set_source_surface(cr, surface_origin, 0, 0); - cairo_paint(cr); - cairo_set_source_rgba (cr, 0, 0, 0, 0.5); - cairo_paint(cr); - cairo_pattern_t *source_pattern; - cairo_matrix_t matrix; - source_pattern = cairo_pattern_create_for_surface (surface_rotated); - cairo_matrix_init_identity (&matrix); - cairo_matrix_translate (&matrix, allocation.width/2.0, allocation.height/2.0); - cairo_matrix_rotate (&matrix, Geom::rad_from_deg(angle - start_angle) * -1); - cairo_matrix_translate (&matrix, -allocation.width/2.0, -allocation.height/2.0); - cairo_pattern_set_matrix (source_pattern, &matrix); - cairo_set_source(cr, source_pattern); - cairo_paint(cr); - cairo_set_source_surface(cr, surface_measure, 0, 0); - cairo_paint(cr); - cairo_translate(cr, half_w, half_h); - cairo_rotate(cr, angle*(M_PI/180.)); - cairo_move_to(cr, 0, 0); - cairo_line_to(cr, 0, (half_min-17) * -1); - cairo_set_source_rgba (cr, 1, 1, 1, 0.25); - cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND); - cairo_set_line_width (cr,5); - cairo_stroke(cr); - cairo_move_to(cr, 0, 0); - cairo_line_to(cr, 0, (half_min-17) * -1); - cairo_set_source_rgba (cr, 1, 1, 1, 0.9); - cairo_set_line_width (cr,1); - cairo_stroke(cr); - cairo_move_to(cr, 0, 0); - cairo_line_to(cr, 0, (half_min-17) * -1); - cairo_set_source_rgba (cr, 1, 0, 0, 0.9); - const double dashed[] = {6.0, 3.0}; - int len = sizeof(dashed) / sizeof(dashed[0]); - cairo_set_dash(cr, dashed, len, 1); - cairo_stroke(cr); - cairo_translate(cr, -half_w, -half_h); - cairo_set_source_rgba (cr, 1, 1, 1, 0.25); - cairo_arc(cr, half_w, half_h, 7, 0, 2*M_PI); - cairo_fill(cr); - cairo_set_source_rgba (cr, 1, 0, 0, 0.7); - cairo_arc(cr, half_w, half_h, 5, 0, 2*M_PI); - cairo_fill(cr); - cairo_translate(cr, half_w, half_h); - cairo_rotate(cr, -angle*(M_PI/180.)); - cairo_select_font_face(cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL); - cairo_set_font_size(cr, 15.0); - cairo_text_extents_t extents; - std::ostringstream s; - s << _("Original angle ") << std::fixed << std::setprecision(2) << start_angle << "º"; - cairo_text_extents(cr, s.str().c_str(), &extents); - cairo_translate(cr, half_w - extents.width -15 ,-half_h + 25); - cairo_set_source_rgba (cr, 1, 1, 1, 1); - cairo_text_path(cr, s.str().c_str()); - cairo_fill(cr); - cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 25) *-1); - s.str(""); - s << _("New angle ") << std::fixed << std::setprecision(2) << angle << "º"; - cairo_text_extents(cr, s.str().c_str(), &extents); - cairo_translate(cr, half_w - extents.width -15 ,-half_h + 45); - cairo_text_path(cr, s.str().c_str()); - cairo_fill(cr); - cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 45) *-1); - s.str(""); - s << _("Gap ") << std::fixed << std::setprecision(2) << std::abs(start_angle-angle) << "º"; - cairo_text_extents(cr, s.str().c_str(), &extents); - cairo_translate(cr, half_w - extents.width -15 ,-half_h + 65); - cairo_text_path(cr, s.str().c_str()); - cairo_fill(cr); - cairo_translate(cr, (half_w - extents.width -15) *-1 ,(-half_h + 65) *-1); - cairo_translate(cr, -half_w + 10 ,-half_h + 25); - s.str(""); - cairo_set_font_size(cr, 12.0); - s << _("Normal mode, 1º round step"); - cairo_text_path(cr, s.str().c_str()); - cairo_fill(cr); - cairo_translate(cr, (-half_w +10) * -1 ,(-half_h + 25) * -1); - cairo_translate(cr, -half_w + 10 ,-half_h + 40); - s.str(""); - s << _("+ALT, Fractional degrees"); - cairo_text_path(cr, s.str().c_str()); - cairo_fill(cr); - cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 40) * -1); - cairo_translate(cr, -half_w + 10 ,-half_h + 55); - s.str(""); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - s << _("+CTRL, ") << 180.0/prefs->getInt("/options/rotationsnapsperpi/value", 12) << _("º round step"); - cairo_text_path(cr, s.str().c_str()); - cairo_fill(cr); - cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 55) * -1); - cairo_translate(cr, -half_w + 10 ,-half_h + 70); - s.str(""); - s << _("+SHIFT, Reset"); - cairo_text_path(cr, s.str().c_str()); - cairo_fill(cr); - cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 70) * -1); - cairo_translate(cr, -half_w + 10 ,-half_h + 85); - s.str(""); - s << _("+CTRL+SHIFT, 0º"); - cairo_text_path(cr, s.str().c_str()); - cairo_fill(cr); - //cairo_translate(cr, (-half_w + 10) * -1 ,(-half_h + 60) * -1); - cairo_destroy(cr); - cairo_surface_destroy(_backing_store); - _backing_store = new_backing_store; - cairo_pattern_destroy (source_pattern); - gtk_widget_queue_draw(GTK_WIDGET(this)); - addIdle(); -} - void SPCanvas::updateNow() { if (_need_update) { diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 708653bdf..a2cbe0b27 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -51,7 +51,7 @@ enum { struct SPCanvasBuf { cairo_t *ct; Geom::IntRect rect; - Geom::IntRect visible_rect; + Geom::IntRect canvas_rect; // visible window in world coordinates (i.e. offset by _x0, _y0) unsigned char *buf; int buf_rowstride; @@ -72,10 +72,7 @@ GType sp_canvas_get_type() G_GNUC_CONST; struct SPCanvas { /// Scrolls canvas to specific position (c is measured in screen pixels). void scrollTo(Geom::Point const &c, unsigned int clear, bool is_scrolling = false); - void startRotateTo(double angle); - void rotateTo(double angle); - bool endRotateTo(); - void clearRotateTo(); + /// Synchronously updates the canvas if necessary. void updateNow(); @@ -177,8 +174,8 @@ public: bool _is_dragging; double _dx0; double _dy0; - int _x0; ///< World coordinate of the leftmost pixels - int _y0; ///< World coordinate of the topmost pixels + int _x0; ///< World coordinate of the leftmost pixels of window + int _y0; ///< World coordinate of the topmost pixels of window /// Image surface storing the contents of the widget cairo_surface_t *_backing_store; diff --git a/src/document-undo.cpp b/src/document-undo.cpp index fb1f47312..f36010602 100644 --- a/src/document-undo.cpp +++ b/src/document-undo.cpp @@ -281,10 +281,6 @@ gboolean Inkscape::DocumentUndo::undo(SPDocument *doc) if (ret) INKSCAPE.external_change(); - SPObject *updated = doc->getRoot(); - if (updated && !ret) { - updated->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); - } return ret; } diff --git a/src/extension/extension.cpp b/src/extension/extension.cpp index 6c6e2d71e..497f98431 100644 --- a/src/extension/extension.cpp +++ b/src/extension/extension.cpp @@ -701,7 +701,7 @@ public: #endif this->pack_start(*widg, false, false, 0); if (tooltip) { - widg->set_tooltip_text(_(tooltip)); + widg->set_tooltip_text(tooltip); } else { widg->set_tooltip_text(""); widg->set_has_tooltip(false); @@ -718,7 +718,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_hidden = true NULL is returned as well. */ Gtk::Widget * Extension::autogui (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) @@ -732,7 +732,7 @@ Extension::autogui (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<v //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)) { Parameter * param = reinterpret_cast<Parameter *>(list->data); - if (param->get_gui_hidden()) continue; //Ignore hidden parameters + if (param->get_hidden()) continue; //Ignore hidden parameters Gtk::Widget * widg = param->get_widget(doc, node, changeSignal); gchar const * tip = param->get_tooltip(); int indent = param->get_indent(); @@ -837,7 +837,7 @@ 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<Parameter *>(list->data); - if (!param->get_gui_hidden()) _visible_count++; + if (!param->get_hidden()) _visible_count++; } return _visible_count; } diff --git a/src/extension/internal/bluredge.cpp b/src/extension/internal/bluredge.cpp index 8aa982810..d1fe357da 100644 --- a/src/extension/internal/bluredge.cpp +++ b/src/extension/internal/bluredge.cpp @@ -131,8 +131,8 @@ BlurEdge::init (void) "<inkscape-extension xmlns=\"" INKSCAPE_EXTENSION_URI "\">\n" "<name>" N_("Inset/Outset Halo") "</name>\n" "<id>org.inkscape.effect.bluredge</id>\n" - "<param name=\"blur-width\" _gui-text=\"" N_("Width:") "\" gui-description=\"" N_("Width in px of the halo") "\" scope=\"document\" type=\"float\" min=\"1.0\" max=\"50.0\">1.0</param>\n" - "<param name=\"num-steps\" _gui-text=\"" N_("Number of steps:") "\" gui-description=\"" N_("Number of inset/outset copies of the object to make") "\" scope=\"document\" type=\"int\" min=\"5\" max=\"100\">11</param>\n" + "<param name=\"blur-width\" _gui-text=\"" N_("Width:") "\" gui-description=\"" N_("Width in px of the halo") "\" type=\"float\" min=\"1.0\" max=\"50.0\">1.0</param>\n" + "<param name=\"num-steps\" _gui-text=\"" N_("Number of steps:") "\" gui-description=\"" N_("Number of inset/outset copies of the object to make") "\" type=\"int\" min=\"5\" max=\"100\">11</param>\n" "<effect>\n" "<object-type>all</object-type>\n" "<effects-menu>\n" diff --git a/src/extension/internal/cairo-png-out.cpp b/src/extension/internal/cairo-png-out.cpp index 5859a82da..956fcce9a 100644 --- a/src/extension/internal/cairo-png-out.cpp +++ b/src/extension/internal/cairo-png-out.cpp @@ -53,10 +53,11 @@ png_render_document_to_file(SPDocument *doc, gchar const *filename) { CairoRenderer *renderer; CairoRenderContext *ctx; - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; + doc->ensureUpToDate(); /* Start */ + SPItem *base = doc->getRoot(); Inkscape::Drawing drawing; unsigned dkey = SPItem::display_key_new(1); @@ -76,7 +77,6 @@ png_render_document_to_file(SPDocument *doc, gchar const *filename) renderer->destroyContext(ctx); base->invoke_hide(dkey); - doc->getRoot()->c2p *= doc->getRoot()->rotation; /* end */ delete renderer; diff --git a/src/extension/internal/cairo-ps-out.cpp b/src/extension/internal/cairo-ps-out.cpp index 809125266..e8f47e79e 100644 --- a/src/extension/internal/cairo-ps-out.cpp +++ b/src/extension/internal/cairo-ps-out.cpp @@ -68,7 +68,6 @@ static bool ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int level, bool texttopath, bool omittext, bool filtertobitmap, int resolution, const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px, bool eps = false) { - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; doc->ensureUpToDate(); SPItem *base = NULL; @@ -85,10 +84,9 @@ ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int l pageBoundingBox = !exportDrawing; } - if (!base) { - doc->getRoot()->c2p *= doc->getRoot()->rotation; + if (!base) return false; - } + Inkscape::Drawing drawing; unsigned dkey = SPItem::display_key_new(1); base->invoke_show(drawing, dkey, SP_ITEM_SHOW_DISPLAY); @@ -117,7 +115,6 @@ ps_print_document_to_file(SPDocument *doc, gchar const *filename, unsigned int l renderer->destroyContext(ctx); delete renderer; - doc->getRoot()->c2p *= doc->getRoot()->rotation; return ret; } diff --git a/src/extension/internal/cairo-renderer-pdf-out.cpp b/src/extension/internal/cairo-renderer-pdf-out.cpp index 5558fe1ad..5576676b2 100644 --- a/src/extension/internal/cairo-renderer-pdf-out.cpp +++ b/src/extension/internal/cairo-renderer-pdf-out.cpp @@ -61,7 +61,6 @@ pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int bool texttopath, bool omittext, bool filtertobitmap, int resolution, const gchar * const exportId, bool exportDrawing, bool exportCanvas, float bleedmargin_px) { - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; doc->ensureUpToDate(); /* Start */ @@ -81,7 +80,6 @@ pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int } if (!base) { - doc->getRoot()->c2p *= doc->getRoot()->rotation; return false; } @@ -114,7 +112,7 @@ pdf_render_document_to_file(SPDocument *doc, gchar const *filename, unsigned int renderer->destroyContext(ctx); delete renderer; - doc->getRoot()->c2p *= doc->getRoot()->rotation; + return ret; } diff --git a/src/extension/internal/cdr-input.cpp b/src/extension/internal/cdr-input.cpp index 70bf84ef4..b94408b36 100644 --- a/src/extension/internal/cdr-input.cpp +++ b/src/extension/internal/cdr-input.cpp @@ -210,6 +210,19 @@ void CdrImportDialog::_setPreviewPage() } SPDocument *doc = SPDocument::createNewDocFromMem(_vec[_current_page-1].cstr(), strlen(_vec[_current_page-1].cstr()), 0); + if(!doc) { + g_warning("CDR import: Could not create preview for page %d", _current_page); + gchar const *no_preview_template = + "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>" + " <path style='fill:none;stroke:#ff0000;stroke-width:2px;' d='M 82,10 18,74 m 0,-64 64,64' />" + " <rect style='fill:none;stroke:#000000;stroke-width:1.5px;' width='64' height='64' x='18' y='10' />" + " <text x='50' y='92' style='font-size:10px;text-anchor:middle;font-family:sans-serif;'>%s</text>" + "</svg>"; + gchar * no_preview = g_strdup_printf(no_preview_template, _("No preview")); + doc = SPDocument::createNewDocFromMem(no_preview, strlen(no_preview), 0); + g_free(no_preview); + } + Gtk::Widget * tmpPreviewArea = Glib::wrap(sp_svg_view_widget_new(doc)); std::swap(_previewArea, tmpPreviewArea); delete tmpPreviewArea; diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp index 198c18ff2..92deb2e19 100644 --- a/src/extension/internal/emf-inout.cpp +++ b/src/extension/internal/emf-inout.cpp @@ -94,7 +94,7 @@ Emf::print_document_to_file(SPDocument *doc, const gchar *filename) const gchar *oldconst; gchar *oldoutput; unsigned int ret; - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; + doc->ensureUpToDate(); mod = Inkscape::Extension::get_print(PRINT_EMF); @@ -114,7 +114,6 @@ Emf::print_document_to_file(SPDocument *doc, const gchar *filename) /* Print document */ ret = mod->begin(doc); if (ret) { - doc->getRoot()->c2p *= doc->getRoot()->rotation; g_free(oldoutput); throw Inkscape::Extension::Output::save_failed(); } @@ -128,7 +127,7 @@ Emf::print_document_to_file(SPDocument *doc, const gchar *filename) mod->set_param_string("destination", oldoutput); g_free(oldoutput); - doc->getRoot()->c2p *= doc->getRoot()->rotation; + return; } @@ -166,8 +165,16 @@ Emf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filena ext->set_param_bool("FixImageRot",new_FixImageRot); ext->set_param_bool("textToPath", new_val); + // ensure usage of dot as decimal separator in scanf/printf functions (indepentendly of current locale) + char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL)); + setlocale(LC_NUMERIC, "C"); + print_document_to_file(doc, filename); + // restore decimal separator used in scanf/printf functions to initial value + setlocale(LC_NUMERIC, oldlocale); + g_free(oldlocale); + return; } @@ -3525,6 +3532,10 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) return NULL; } + // ensure usage of dot as decimal separator in scanf/printf functions (indepentendly of current locale) + char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL)); + setlocale(LC_NUMERIC, "C"); + EMF_CALLBACK_DATA d; d.n_obj = 0; //these might not be set otherwise if the input file is corrupt @@ -3589,6 +3600,10 @@ Emf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) // in earlier versions no viewbox was generated and a call to setViewBoxIfMissing() was needed here. + // restore decimal separator used in scanf/printf functions to initial value + setlocale(LC_NUMERIC, oldlocale); + g_free(oldlocale); + return doc; } diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 826176bc0..147324b4f 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -251,11 +251,7 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1"); } - char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "C"); snprintf(buff, sizeof(buff) - 1, "Drawing=%.1fx%.1fpx, %.1fx%.1fmm", _width, _height, Inkscape::Util::Quantity::convert(dwInchesX, "in", "mm"), Inkscape::Util::Quantity::convert(dwInchesY, "in", "mm")); - setlocale(LC_NUMERIC, oldlocale); - g_free(oldlocale); rec = textcomment_set(buff); if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) { g_error("Fatal programming error in PrintEmf::begin at textcomment_set 1"); diff --git a/src/extension/internal/javafx-out.cpp b/src/extension/internal/javafx-out.cpp index c95434939..d7ad7e6f7 100644 --- a/src/extension/internal/javafx-out.cpp +++ b/src/extension/internal/javafx-out.cpp @@ -843,8 +843,7 @@ void JavaFXOutput::reset() bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) { reset(); - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; - doc->ensureUpToDate(); + name = Glib::path_get_basename(filename_utf8); int pos = name.find('.'); @@ -857,14 +856,12 @@ bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) //# Lets do the curves first, to get the stats if (!doTree(doc)) { - doc->getRoot()->c2p *= doc->getRoot()->rotation; return false; } String curveBuf = outbuf; outbuf.clear(); if (!doHeader()) { - doc->getRoot()->c2p *= doc->getRoot()->rotation; return false; } @@ -878,7 +875,6 @@ bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) doBody(doc, doc->getRoot()); if (!doTail()) { - doc->getRoot()->c2p *= doc->getRoot()->rotation; return false; } @@ -888,7 +884,6 @@ bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w"); if (!f) { - doc->getRoot()->c2p *= doc->getRoot()->rotation; err("Could open JavaFX file '%s' for writing", filename_utf8); return false; } @@ -899,7 +894,7 @@ bool JavaFXOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) } fclose(f); - doc->getRoot()->c2p *= doc->getRoot()->rotation; + return true; } diff --git a/src/extension/internal/latex-pstricks-out.cpp b/src/extension/internal/latex-pstricks-out.cpp index aa6ea6963..3ce2c5531 100644 --- a/src/extension/internal/latex-pstricks-out.cpp +++ b/src/extension/internal/latex-pstricks-out.cpp @@ -49,7 +49,6 @@ bool LatexOutput::check(Inkscape::Extension::Extension * /*module*/) void LatexOutput::save(Inkscape::Extension::Output * /*mod2*/, SPDocument *doc, gchar const *filename) { SPPrintContext context; - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; doc->ensureUpToDate(); Inkscape::Extension::Print *mod = Inkscape::Extension::get_print(SP_MODULE_KEY_PRINT_LATEX); @@ -77,7 +76,6 @@ void LatexOutput::save(Inkscape::Extension::Output * /*mod2*/, SPDocument *doc, mod->set_param_string("destination", oldoutput); g_free(oldoutput); - doc->getRoot()->c2p *= doc->getRoot()->rotation; } #include "clear-n_.h" diff --git a/src/extension/internal/metafile-print.cpp b/src/extension/internal/metafile-print.cpp index 11567ceb3..68a425d85 100644 --- a/src/extension/internal/metafile-print.cpp +++ b/src/extension/internal/metafile-print.cpp @@ -355,27 +355,6 @@ int PrintMetafile::hold_gradient(void *gr, int mode) return 1; } -/* behaves like snprintf() but makes sure decimal separators are formatted as dots - otherwise invalid strings can be produced depending on the set locale -*/ -int PrintMetafile::snprintf_dots(char * s, size_t n, const char * format, ...) -{ - int nChars; - - char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "C"); - - va_list argptr; - va_start(argptr, format); - nChars = vsnprintf(s, n, format, argptr); - va_end(argptr); - - setlocale(LC_NUMERIC, oldlocale); - g_free(oldlocale); - - return nChars; -} - /* convert from center ellipse to SVGEllipticalArc ellipse From: @@ -411,7 +390,7 @@ Geom::PathVector PrintMetafile::center_ellipse_as_SVG_PathV(Geom::Point ctr, dou y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); char text[256]; - snprintf_dots(text, 256, " M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", + snprintf(text, 256, " M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", x1, y1, rx, ry, F * 360. / (2.*M_PI), x2, y2, rx, ry, F * 360. / (2.*M_PI), x1, y1); Geom::PathVector outres = Geom::parse_svg_path(text); return outres; @@ -440,7 +419,7 @@ Geom::PathVector PrintMetafile::center_elliptical_ring_as_SVG_PathV(Geom::Point y22 = ctr[Y] + sin(F) * rx2 * cos(M_PI) + cos(F) * ry2 * sin(M_PI); char text[512]; - snprintf_dots(text, 512, " M %f,%f A %f %f %f 0 1 %f %f A %f %f %f 0 1 %f %f z M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", + snprintf(text, 512, " M %f,%f A %f %f %f 0 1 %f %f A %f %f %f 0 1 %f %f z M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z", x11, y11, rx1, ry1, degrot, x12, y12, rx1, ry1, degrot, x11, y11, x21, y21, rx2, ry2, degrot, x22, y22, rx2, ry2, degrot, x21, y21); Geom::PathVector outres = Geom::parse_svg_path(text); @@ -462,7 +441,7 @@ Geom::PathVector PrintMetafile::center_elliptical_hole_as_SVG_PathV(Geom::Point y2 = ctr[Y] + sin(F) * rx * cos(M_PI) + cos(F) * ry * sin(M_PI); char text[256]; - snprintf_dots(text, 256, " M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z M 50000,50000 50000,-50000 -50000,-50000 -50000,50000 z", + snprintf(text, 256, " M %f,%f A %f %f %f 0 0 %f %f A %f %f %f 0 0 %f %f z M 50000,50000 50000,-50000 -50000,-50000 -50000,50000 z", x1, y1, rx, ry, F * 360. / (2.*M_PI), x2, y2, rx, ry, F * 360. / (2.*M_PI), x1, y1); Geom::PathVector outres = Geom::parse_svg_path(text); return outres; diff --git a/src/extension/internal/odf.cpp b/src/extension/internal/odf.cpp index 66d370357..f885ef5e5 100644 --- a/src/extension/internal/odf.cpp +++ b/src/extension/internal/odf.cpp @@ -72,7 +72,6 @@ #include "sp-path.h" #include "sp-text.h" #include "sp-flowtext.h" -#include "sp-root.h" #include "svg/svg.h" #include "text-editing.h" #include "util/units.h" @@ -2096,8 +2095,7 @@ void OdfOutput::reset() void OdfOutput::save(Inkscape::Extension::Output */*mod*/, SPDocument *doc, gchar const *filename) { reset(); - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; - doc->ensureUpToDate(); + documentUri = Inkscape::URI(filename); ZipFile zf; @@ -2106,30 +2104,25 @@ void OdfOutput::save(Inkscape::Extension::Output */*mod*/, SPDocument *doc, gcha if (!writeManifest(zf)) { g_warning("Failed to write manifest"); - doc->getRoot()->c2p *= doc->getRoot()->rotation; return; } if (!writeContent(zf, doc->rroot)) { g_warning("Failed to write content"); - doc->getRoot()->c2p *= doc->getRoot()->rotation; return; } if (!writeMeta(zf)) { g_warning("Failed to write metafile"); - doc->getRoot()->c2p *= doc->getRoot()->rotation; return; } if (!zf.writeFile(filename)) { - doc->getRoot()->c2p *= doc->getRoot()->rotation; return; } - doc->getRoot()->c2p *= doc->getRoot()->rotation; } diff --git a/src/extension/internal/pov-out.cpp b/src/extension/internal/pov-out.cpp index 03a2ecd62..8df883069 100644 --- a/src/extension/internal/pov-out.cpp +++ b/src/extension/internal/pov-out.cpp @@ -616,13 +616,11 @@ void PovOutput::reset() void PovOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) { reset(); - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; - doc->ensureUpToDate(); + //###### SAVE IN POV FORMAT TO BUFFER //# Lets do the curves first, to get the stats if (!doTree(doc)) { - doc->getRoot()->c2p *= doc->getRoot()->rotation; err("Could not output curves for %s", filename_utf8); return; } @@ -632,7 +630,6 @@ void PovOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) if (!doHeader()) { - doc->getRoot()->c2p *= doc->getRoot()->rotation; err("Could not write header for %s", filename_utf8); return; } @@ -641,7 +638,6 @@ void PovOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) if (!doTail()) { - doc->getRoot()->c2p *= doc->getRoot()->rotation; err("Could not write footer for %s", filename_utf8); return; } @@ -652,11 +648,9 @@ void PovOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) //###### WRITE TO FILE Inkscape::IO::dump_fopen_call(filename_utf8, "L"); FILE *f = Inkscape::IO::fopen_utf8name(filename_utf8, "w"); - if (!f){ - doc->getRoot()->c2p *= doc->getRoot()->rotation; + if (!f) return; - } - + for (String::iterator iter = outbuf.begin() ; iter!=outbuf.end(); ++iter) { int ch = *iter; @@ -664,7 +658,6 @@ void PovOutput::saveDocument(SPDocument *doc, gchar const *filename_utf8) } fclose(f); - doc->getRoot()->c2p *= doc->getRoot()->rotation; } diff --git a/src/extension/internal/vsd-input.cpp b/src/extension/internal/vsd-input.cpp index b7277b99e..c1cfb5cc6 100644 --- a/src/extension/internal/vsd-input.cpp +++ b/src/extension/internal/vsd-input.cpp @@ -146,7 +146,7 @@ VsdImportDialog::VsdImportDialog(const std::vector<RVNGString> &vec) _page_selector_box->pack_start(*_labelTotalPages, Gtk::PACK_SHRINK); vbox1->pack_end(*_page_selector_box, Gtk::PACK_SHRINK); - + // Buttons cancelbutton = Gtk::manage(new Gtk::Button(_("_Cancel"), true)); okbutton = Gtk::manage(new Gtk::Button(_("_OK"), true)); @@ -211,6 +211,19 @@ void VsdImportDialog::_setPreviewPage() } SPDocument *doc = SPDocument::createNewDocFromMem(_vec[_current_page-1].cstr(), strlen(_vec[_current_page-1].cstr()), 0); + if(!doc) { + g_warning("VSD import: Could not create preview for page %d", _current_page); + gchar const *no_preview_template = + "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>" + " <path style='fill:none;stroke:#ff0000;stroke-width:2px;' d='M 82,10 18,74 m 0,-64 64,64' />" + " <rect style='fill:none;stroke:#000000;stroke-width:1.5px;' width='64' height='64' x='18' y='10' />" + " <text x='50' y='92' style='font-size:10px;text-anchor:middle;font-family:sans-serif;'>%s</text>" + "</svg>"; + gchar * no_preview = g_strdup_printf(no_preview_template, _("No preview")); + doc = SPDocument::createNewDocFromMem(no_preview, strlen(no_preview), 0); + g_free(no_preview); + } + Gtk::Widget * tmpPreviewArea = Glib::wrap(sp_svg_view_widget_new(doc)); std::swap(_previewArea, tmpPreviewArea); delete tmpPreviewArea; diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp index 42ec2f2bb..e2d1433e4 100644 --- a/src/extension/internal/wmf-inout.cpp +++ b/src/extension/internal/wmf-inout.cpp @@ -95,7 +95,7 @@ Wmf::print_document_to_file(SPDocument *doc, const gchar *filename) SPPrintContext context; const gchar *oldconst; gchar *oldoutput; - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; + doc->ensureUpToDate(); mod = Inkscape::Extension::get_print(PRINT_WMF); @@ -115,7 +115,6 @@ Wmf::print_document_to_file(SPDocument *doc, const gchar *filename) /* Print document */ if (mod->begin(doc)) { g_free(oldoutput); - doc->getRoot()->c2p *= doc->getRoot()->rotation; throw Inkscape::Extension::Output::save_failed(); } mod->base->invoke_print(&context); @@ -128,7 +127,7 @@ Wmf::print_document_to_file(SPDocument *doc, const gchar *filename) mod->set_param_string("destination", oldoutput); g_free(oldoutput); - doc->getRoot()->c2p *= doc->getRoot()->rotation; + return; } @@ -136,8 +135,6 @@ Wmf::print_document_to_file(SPDocument *doc, const gchar *filename) void Wmf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filename) { - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; - doc->ensureUpToDate(); Inkscape::Extension::Extension * ext; ext = Inkscape::Extension::db.get(PRINT_WMF); @@ -164,8 +161,16 @@ Wmf::save(Inkscape::Extension::Output *mod, SPDocument *doc, gchar const *filena ext->set_param_bool("FixPPTPatternAsHatch",new_FixPPTPatternAsHatch); ext->set_param_bool("textToPath", new_val); + // ensure usage of dot as decimal separator in scanf/printf functions (indepentendly of current locale) + char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL)); + setlocale(LC_NUMERIC, "C"); + print_document_to_file(doc, filename); + // restore decimal separator used in scanf/printf functions to initial value + setlocale(LC_NUMERIC, oldlocale); + g_free(oldlocale); + return; } @@ -3100,6 +3105,10 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) return NULL; } + // ensure usage of dot as decimal separator in scanf/printf functions (indepentendly of current locale) + char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL)); + setlocale(LC_NUMERIC, "C"); + WMF_CALLBACK_DATA d; d.n_obj = 0; //these might not be set otherwise if the input file is corrupt @@ -3180,6 +3189,10 @@ Wmf::open( Inkscape::Extension::Input * /*mod*/, const gchar *uri ) // in earlier versions no viewbox was generated and a call to setViewBoxIfMissing() was needed here. + // restore decimal separator used in scanf/printf functions to initial value + setlocale(LC_NUMERIC, oldlocale); + g_free(oldlocale); + return doc; } diff --git a/src/extension/param/bool.cpp b/src/extension/param/bool.cpp index 9f8d3dcc0..2c7e32480 100644 --- a/src/extension/param/bool.cpp +++ b/src/extension/param/bool.cpp @@ -14,7 +14,6 @@ #include <gtkmm/box.h> #include <gtkmm/spinbutton.h> #include <gtkmm/checkbutton.h> -#include <glib/gi18n.h> #include "xml/node.h" #include "../extension.h" @@ -25,15 +24,13 @@ 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, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) - : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + : Parameter(name, text, description, hidden, indent, ext) , _value(false) { const char * defaultval = NULL; @@ -129,14 +126,14 @@ void ParamBool::string(std::string &string) const Gtk::Widget *ParamBool::get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) { - if (_gui_hidden) { + if (_hidden) { return NULL; } 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)); + Gtk::Label * label = Gtk::manage(new Gtk::Label(_text, Gtk::ALIGN_START)); label->show(); hbox->pack_end(*label, true, true); diff --git a/src/extension/param/bool.h b/src/extension/param/bool.h index 0af12b105..826a98927 100644 --- a/src/extension/param/bool.h +++ b/src/extension/param/bool.h @@ -33,11 +33,9 @@ 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, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); diff --git a/src/extension/param/color.cpp b/src/extension/param/color.cpp index fd88e9adb..035c43ba8 100644 --- a/src/extension/param/color.cpp +++ b/src/extension/param/color.cpp @@ -53,15 +53,13 @@ guint32 ParamColor::set( guint32 in, SPDocument * /*doc*/, Inkscape::XML::Node * } ParamColor::ParamColor(const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) - : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + : Parameter(name, text, description, hidden, indent, ext) , _changeSignal(0) { const char * defaulthex = NULL; @@ -94,7 +92,7 @@ Gtk::Widget *ParamColor::get_widget( SPDocument * /*doc*/, Inkscape::XML::Node * { using Inkscape::UI::Widget::ColorNotebook; - if (_gui_hidden) return NULL; + if (_hidden) return NULL; if (changeSignal) { _changeSignal = new sigc::signal<void>(*changeSignal); diff --git a/src/extension/param/color.h b/src/extension/param/color.h index d6e9d1fbe..890f5ba5f 100644 --- a/src/extension/param/color.h +++ b/src/extension/param/color.h @@ -32,11 +32,9 @@ private: 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, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); diff --git a/src/extension/param/description.cpp b/src/extension/param/description.cpp index 3c29b7c49..cf94918f7 100644 --- a/src/extension/param/description.cpp +++ b/src/extension/param/description.cpp @@ -17,6 +17,7 @@ #include <gtkmm/label.h> #include <glibmm/i18n.h> #include <glibmm/markup.h> +#include <glibmm/regex.h> #include "xml/node.h" #include "extension/extension.h" @@ -28,30 +29,59 @@ 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, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml, AppearanceMode mode) - : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + : Parameter(name, text, description, hidden, indent, ext) , _value(NULL) , _mode(mode) { - // printf("Building Description\n"); - const char * defaultval = NULL; - if (xml->firstChild() != NULL) { - defaultval = xml->firstChild()->content(); + // construct the text content by concatenating all (non-empty) text nodes, + // removing all other nodes (e.g. comment nodes) and replacing <extension:br> elements with "<br/>" + Glib::ustring value; + Inkscape::XML::Node * cur_child = xml->firstChild(); + while (cur_child != NULL) { + if (cur_child->type() == XML::TEXT_NODE && cur_child->content() != NULL) { + value += cur_child->content(); + } else if (cur_child->type() == XML::ELEMENT_NODE && !g_strcmp0(cur_child->name(), "extension:br")) { + value += "<br/>"; + } + cur_child = cur_child->next(); } - if (defaultval != NULL) { - _value = g_strdup(defaultval); + // if there is no text content we can return immediately (the description will be invisible) + if (value == Glib::ustring("")) { + return; } - _context = xml->attribute("msgctxt"); + // do replacements in the source string to account for the attribute xml:space="preserve" + // (those should match replacements potentially performed by xgettext to allow for proper translation) + if (g_strcmp0(xml->attribute("xml:space"), "preserve") == 0) { + // xgettext copies the source string verbatim in this case, so no changes needed + } else { + // remove all whitespace from start/end of string and replace intermediate whitespace with a single space + value = Glib::Regex::create("^\\s+|\\s+$")->replace_literal(value, 0, "", (Glib::RegexMatchFlags)0); + value = Glib::Regex::create("\\s+")->replace_literal(value, 0, " ", (Glib::RegexMatchFlags)0); + } + + // translate if underscored version (_param) was used + if (g_str_has_prefix(xml->name(), "extension:_")) { + const gchar * context = xml->attribute("msgctxt"); + if (context != NULL) { + value = g_dpgettext2(NULL, context, value.c_str()); + } else { + value = _(value.c_str()); + } + } + + // finally replace all remaining <br/> with a real newline character + value = Glib::Regex::create("<br/>")->replace_literal(value, 0, "\n", (Glib::RegexMatchFlags)0); + + _value = g_strdup(value.c_str()); return; } @@ -60,31 +90,25 @@ ParamDescription::ParamDescription(const gchar * name, Gtk::Widget * ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node*/, sigc::signal<void> * /*changeSignal*/) { - if (_gui_hidden) { + if (_hidden) { return NULL; } if (_value == NULL) { return NULL; } - Glib::ustring newguitext; - - if (_context != NULL) { - newguitext = g_dpgettext2(NULL, _context, _value); - } else { - newguitext = _(_value); - } + Glib::ustring newtext = _value; Gtk::Label * label = Gtk::manage(new Gtk::Label()); if (_mode == HEADER) { - label->set_markup(Glib::ustring("<b>") + Glib::Markup::escape_text(newguitext) + Glib::ustring("</b>")); + label->set_markup(Glib::ustring("<b>") + Glib::Markup::escape_text(newtext) + Glib::ustring("</b>")); label->set_margin_top(5); label->set_margin_bottom(5); } else if (_mode == URL) { - Glib::ustring escaped_url = Glib::Markup::escape_text(newguitext); + Glib::ustring escaped_url = Glib::Markup::escape_text(newtext); label->set_markup(Glib::ustring::compose("<a href='%1'>%1</a>", escaped_url)); } else { - label->set_text(newguitext); + label->set_text(newtext); } label->set_line_wrap(); #if (GTKMM_MAJOR_VERSION == 3 && GTKMM_MINOR_VERSION >= 16) @@ -101,7 +125,7 @@ ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node // - 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(); + int len = newtext.length(); label->set_width_chars(len > Parameter::GUI_MAX_LINE_LENGTH ? Parameter::GUI_MAX_LINE_LENGTH : len); label->show(); diff --git a/src/extension/param/description.h b/src/extension/param/description.h index c6c5f4013..599c4db78 100644 --- a/src/extension/param/description.h +++ b/src/extension/param/description.h @@ -27,14 +27,12 @@ namespace Extension { class ParamDescription : public Parameter { public: enum AppearanceMode { - DESC, HEADER, URL + DESCRIPTION, HEADER, URL }; ParamDescription(const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml, @@ -45,7 +43,6 @@ private: /** \brief Internal value. */ gchar * _value; AppearanceMode _mode; - const gchar* _context; }; } /* namespace Extension */ diff --git a/src/extension/param/enum.cpp b/src/extension/param/enum.cpp index a26458c35..7cd860465 100644 --- a/src/extension/param/enum.cpp +++ b/src/extension/param/enum.cpp @@ -33,29 +33,27 @@ namespace Inkscape { namespace Extension { /* For internal use only. - Note that value and guitext MUST be non-NULL. This is ensured by newing only at one location in the code where non-NULL checks are made. */ + Note that value and text MUST be non-NULL. This is ensured by newing only at one location in the code where non-NULL checks are made. */ class enumentry { public: enumentry (Glib::ustring &val, Glib::ustring &text) : value(val), - guitext(text) + text(text) {} Glib::ustring value; - Glib::ustring guitext; + Glib::ustring text; }; ParamComboBox::ParamComboBox(const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) - : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + : Parameter(name, text, description, hidden, indent, ext) , _value(NULL) , choices(NULL) { @@ -66,7 +64,7 @@ ParamComboBox::ParamComboBox(const gchar * name, for (Inkscape::XML::Node *node = xml->firstChild(); node; node = node->next()) { char const * chname = node->name(); if (!strcmp(chname, INKSCAPE_EXTENSION_NS "item") || !strcmp(chname, INKSCAPE_EXTENSION_NS "_item")) { - Glib::ustring newguitext, newvalue; + Glib::ustring newtext, newvalue; const char * contents = NULL; if (node->firstChild()) { contents = node->firstChild()->content(); @@ -77,12 +75,12 @@ ParamComboBox::ParamComboBox(const gchar * name, // still need to include if are to be localized if (!strcmp(chname, INKSCAPE_EXTENSION_NS "_item")) { if (node->attribute("msgctxt") != NULL) { - newguitext = g_dpgettext2(NULL, node->attribute("msgctxt"), contents); + newtext = g_dpgettext2(NULL, node->attribute("msgctxt"), contents); } else { - newguitext = _(contents); + newtext = _(contents); } } else { - newguitext = contents; + newtext = contents; } } else continue; @@ -94,8 +92,8 @@ ParamComboBox::ParamComboBox(const gchar * name, newvalue = contents; } - if ( (!newguitext.empty()) && (!newvalue.empty()) ) { // logical error if this is not true here - choices = g_slist_append( choices, new enumentry(newvalue, newguitext) ); + if ( (!newtext.empty()) && (!newvalue.empty()) ) { // logical error if this is not true here + choices = g_slist_append( choices, new enumentry(newvalue, newtext) ); } } } @@ -155,7 +153,7 @@ const gchar *ParamComboBox::set(const gchar * in, SPDocument * /*doc*/, Inkscape Glib::ustring settext; for (GSList * list = choices; list != NULL; list = g_slist_next(list)) { enumentry * entr = reinterpret_cast<enumentry *>(list->data); - if ( !entr->guitext.compare(in) ) { + if ( !entr->text.compare(in) ) { settext = entr->value; break; // break out of for loop } @@ -175,20 +173,20 @@ const gchar *ParamComboBox::set(const gchar * in, SPDocument * /*doc*/, Inkscape } /** - * function to test if \c guitext is selectable + * function to test if \c text is selectable */ -bool ParamComboBox::contains(const gchar * guitext, SPDocument const * /*doc*/, Inkscape::XML::Node const * /*node*/) const +bool ParamComboBox::contains(const gchar * text, SPDocument const * /*doc*/, Inkscape::XML::Node const * /*node*/) const { - if (guitext == NULL) { + if (text == NULL) { return false; /* Can't have NULL string */ } for (GSList * list = choices; list != NULL; list = g_slist_next(list)) { enumentry * entr = reinterpret_cast<enumentry *>(list->data); - if ( !entr->guitext.compare(guitext) ) + if ( !entr->text.compare(text) ) return true; } - // if we did not find the guitext in this ParamComboBox: + // if we did not find the text in this ParamComboBox: return false; } @@ -246,12 +244,12 @@ ParamComboBoxEntry::changed (void) */ Gtk::Widget *ParamComboBox::get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) { - if (_gui_hidden) { + if (_hidden) { return NULL; } 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)); + Gtk::Label * label = Gtk::manage(new Gtk::Label(_text, Gtk::ALIGN_START)); label->show(); hbox->pack_start(*label, false, false); @@ -260,11 +258,11 @@ Gtk::Widget *ParamComboBox::get_widget(SPDocument * doc, Inkscape::XML::Node * n Glib::ustring settext; for (GSList * list = choices; list != NULL; list = g_slist_next(list)) { enumentry * entr = reinterpret_cast<enumentry *>(list->data); - Glib::ustring text = entr->guitext; + Glib::ustring text = entr->text; combo->append(text); if ( _value && !entr->value.compare(_value) ) { - settext = entr->guitext; + settext = entr->text; } } if (!settext.empty()) { diff --git a/src/extension/param/enum.h b/src/extension/param/enum.h index f9d3d75f7..143a648d7 100644 --- a/src/extension/param/enum.h +++ b/src/extension/param/enum.h @@ -38,11 +38,9 @@ private: public: ParamComboBox(const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); @@ -60,9 +58,9 @@ public: const gchar * set (const gchar * in, SPDocument * doc, Inkscape::XML::Node * node); /** - * @returns true if guitext is part of this enum + * @returns true if text is part of this enum */ - bool contains(const gchar * guitext, SPDocument const * /*doc*/, Inkscape::XML::Node const * /*node*/) const; + bool contains(const gchar * text, SPDocument const * /*doc*/, Inkscape::XML::Node const * /*node*/) const; void changed (void); }; /* class ParamComboBox */ diff --git a/src/extension/param/float.cpp b/src/extension/param/float.cpp index e3fdba826..69283a572 100644 --- a/src/extension/param/float.cpp +++ b/src/extension/param/float.cpp @@ -15,7 +15,6 @@ #include <gtkmm/scale.h> #include "ui/widget/spinbutton.h" #include "ui/widget/spin-scale.h" -#include <glib/gi18n.h> #include "xml/node.h" #include "extension/extension.h" @@ -28,16 +27,14 @@ 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, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml, AppearanceMode mode) - : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + : Parameter(name, text, description, hidden, indent, ext) , _value(0.0) , _mode(mode) , _min(0.0) @@ -170,7 +167,7 @@ void ParamFloatAdjustment::val_changed(void) */ Gtk::Widget * ParamFloat::get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) { - if (_gui_hidden) { + if (_hidden) { return NULL; } @@ -181,7 +178,7 @@ Gtk::Widget * ParamFloat::get_widget(SPDocument * doc, Inkscape::XML::Node * nod if (_mode == FULL) { - UI::Widget::SpinScale *scale = new UI::Widget::SpinScale(_(_text), fadjust, _precision); + UI::Widget::SpinScale *scale = new UI::Widget::SpinScale(_text, fadjust, _precision); scale->set_size_request(400, -1); scale->show(); hbox->pack_start(*scale, true, true); @@ -189,7 +186,7 @@ Gtk::Widget * ParamFloat::get_widget(SPDocument * doc, Inkscape::XML::Node * nod } else if (_mode == MINIMAL) { - Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START)); + Gtk::Label * label = Gtk::manage(new Gtk::Label(_text, Gtk::ALIGN_START)); label->show(); hbox->pack_start(*label, true, true); diff --git a/src/extension/param/float.h b/src/extension/param/float.h index 7fd86cea7..d58253ccb 100644 --- a/src/extension/param/float.h +++ b/src/extension/param/float.h @@ -30,11 +30,9 @@ public: FULL, MINIMAL }; ParamFloat(const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml, diff --git a/src/extension/param/int.cpp b/src/extension/param/int.cpp index 538ddc08d..357f98590 100644 --- a/src/extension/param/int.cpp +++ b/src/extension/param/int.cpp @@ -15,7 +15,6 @@ #include <gtkmm/scale.h> #include "ui/widget/spinbutton.h" #include "ui/widget/spin-scale.h" -#include <glib/gi18n.h> #include "xml/node.h" #include "extension/extension.h" @@ -28,16 +27,14 @@ 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, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml, AppearanceMode mode) - : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + : Parameter(name, text, description, hidden, indent, ext) , _value(0) , _mode(mode) , _min(0) @@ -151,7 +148,7 @@ void ParamIntAdjustment::val_changed(void) Gtk::Widget * ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) { - if (_gui_hidden) { + if (_hidden) { return NULL; } @@ -162,14 +159,13 @@ ParamInt::get_widget (SPDocument * doc, Inkscape::XML::Node * node, sigc::signal if (_mode == FULL) { - UI::Widget::SpinScale *scale = new UI::Widget::SpinScale(_(_text), fadjust, 0); + UI::Widget::SpinScale *scale = new UI::Widget::SpinScale(_text, fadjust, 0); scale->set_size_request(400, -1); scale->show(); hbox->pack_start(*scale, true, true); } else if (_mode == MINIMAL) { - - Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START)); + Gtk::Label * label = Gtk::manage(new Gtk::Label(_text, Gtk::ALIGN_START)); label->show(); hbox->pack_start(*label, true, true); diff --git a/src/extension/param/int.h b/src/extension/param/int.h index 40c0395ec..fcb1ef3f1 100644 --- a/src/extension/param/int.h +++ b/src/extension/param/int.h @@ -30,11 +30,9 @@ public: FULL, MINIMAL }; ParamInt(const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml, diff --git a/src/extension/param/notebook.cpp b/src/extension/param/notebook.cpp index de86d1005..4e94b5216 100644 --- a/src/extension/param/notebook.cpp +++ b/src/extension/param/notebook.cpp @@ -55,31 +55,27 @@ 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, + const gchar * text, + const gchar * description, + bool hidden, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); ~ParamNotebookPage(void); Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal); void paramString (std::list <std::string> &list); - gchar * get_guitext (void) {return _text;}; + gchar * get_text (void) {return _text;}; Parameter * get_param (const gchar * name); }; /* 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, + const gchar * text, + const gchar * description, + bool hidden, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) - : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, /*indent*/ 0, ext) + : Parameter(name, text, description, hidden, /*indent*/ 0, ext) { parameters = NULL; @@ -151,30 +147,23 @@ ParamNotebookPage * ParamNotebookPage::makepage (Inkscape::XML::Node * in_repr, Inkscape::Extension::Extension * in_ext) { const char * name; - const char * guitext; - const char * desc; - const char * scope_str; - Parameter::_scope_t scope = Parameter::SCOPE_USER; - bool gui_hidden = false; - const char * gui_hide; - const char * gui_tip; + const char * text; + const char * description; + bool hidden = false; + const char * hide; name = in_repr->attribute("name"); - guitext = in_repr->attribute("gui-text"); - if (guitext == NULL) - guitext = in_repr->attribute("_gui-text"); - gui_tip = in_repr->attribute("gui-tip"); - if (gui_tip == NULL) - gui_tip = in_repr->attribute("_gui-tip"); - desc = in_repr->attribute("gui-description"); - if (desc == NULL) - desc = in_repr->attribute("_gui-description"); - scope_str = in_repr->attribute("scope"); - gui_hide = in_repr->attribute("gui-hidden"); - if (gui_hide != NULL) { - if (strcmp(gui_hide, "1") == 0 || - strcmp(gui_hide, "true") == 0) { - gui_hidden = true; + text = in_repr->attribute("gui-text"); + if (text == NULL) + text = in_repr->attribute("_gui-text"); + description = in_repr->attribute("gui-description"); + if (description == NULL) + description = in_repr->attribute("_gui-description"); + hide = in_repr->attribute("gui-hidden"); + if (hide != NULL) { + if (strcmp(hide, "1") == 0 || + strcmp(hide, "true") == 0) { + hidden = true; } /* else stays false */ } @@ -184,17 +173,7 @@ ParamNotebookPage::makepage (Inkscape::XML::Node * in_repr, Inkscape::Extension: return NULL; } - if (scope_str != NULL) { - if (!strcmp(scope_str, "user")) { - scope = Parameter::SCOPE_USER; - } else if (!strcmp(scope_str, "document")) { - scope = Parameter::SCOPE_DOCUMENT; - } else if (!strcmp(scope_str, "node")) { - scope = Parameter::SCOPE_NODE; - } - } - - ParamNotebookPage * page = new ParamNotebookPage(name, guitext, desc, scope, gui_hidden, gui_tip, in_ext, in_repr); + ParamNotebookPage * page = new ParamNotebookPage(name, text, description, hidden, in_ext, in_repr); /* Note: page could equal NULL */ return page; @@ -209,7 +188,7 @@ ParamNotebookPage::makepage (Inkscape::XML::Node * in_repr, Inkscape::Extension: */ Gtk::Widget * ParamNotebookPage::get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) { - if (_gui_hidden) { + if (_hidden) { return NULL; } @@ -232,7 +211,7 @@ Gtk::Widget * ParamNotebookPage::get_widget(SPDocument * doc, Inkscape::XML::Nod gchar const * tip = param->get_tooltip(); if (tip) { - widg->set_tooltip_text(_(tip)); + widg->set_tooltip_text(tip); } else { widg->set_tooltip_text(""); widg->set_has_tooltip(false); @@ -247,15 +226,13 @@ 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, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) - : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + : Parameter(name, text, description, hidden, indent, ext) { pages = NULL; @@ -446,7 +423,7 @@ Parameter *ParamNotebookPage::get_param(const gchar * name) */ Gtk::Widget * ParamNotebook::get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) { - if (_gui_hidden) { + if (_hidden) { return NULL; } @@ -459,7 +436,7 @@ Gtk::Widget * ParamNotebook::get_widget(SPDocument * doc, Inkscape::XML::Node * i++; ParamNotebookPage * page = reinterpret_cast<ParamNotebookPage *>(list->data); Gtk::Widget * widg = page->get_widget(doc, node, changeSignal); - nb->append_page(*widg, _(page->get_guitext())); + nb->append_page(*widg, _(page->get_text())); if (!strcmp(_value, page->name())) { pagenr = i; // this is the page to be displayed? } diff --git a/src/extension/param/notebook.h b/src/extension/param/notebook.h index 278c4de12..8475de61d 100644 --- a/src/extension/param/notebook.h +++ b/src/extension/param/notebook.h @@ -42,11 +42,9 @@ private: notebook */ public: ParamNotebook(const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); diff --git a/src/extension/param/parameter.cpp b/src/extension/param/parameter.cpp index 0eb491078..5c4fe591f 100644 --- a/src/extension/param/parameter.cpp +++ b/src/extension/param/parameter.cpp @@ -62,25 +62,39 @@ Parameter *Parameter::make(Inkscape::XML::Node *in_repr, Inkscape::Extension::Ex } } - const char *guitext = in_repr->attribute("gui-text"); - if (guitext == NULL) { - guitext = in_repr->attribute("_gui-text"); - } - const char *gui_tip = in_repr->attribute("gui-tip"); - if (gui_tip == NULL) { - gui_tip = in_repr->attribute("_gui-tip"); + const char *text = in_repr->attribute("gui-text"); + if (text == NULL) { + text = in_repr->attribute("_gui-text"); + if (text == NULL) { + // text = ""; // propably better to require devs to explicitly set an empty gui-text if this is what they want + } else { + const char *context = in_repr->attribute("msgctxt"); + if (context != NULL) { + text = g_dpgettext2(NULL, context, text); + } else { + text = _(text); + } + } } - const char *desc = in_repr->attribute("gui-description"); - if (desc == NULL) { - desc = in_repr->attribute("_gui-description"); + const char *description = in_repr->attribute("gui-description"); + if (description == NULL) { + description = in_repr->attribute("_gui-description"); + if (description != NULL) { + const char *context = in_repr->attribute("msgctxt"); + if (context != NULL) { + description = g_dpgettext2(NULL, context, description); + } else { + description = _(description); + } + } } - bool gui_hidden = false; + bool hidden = false; { const char *gui_hide = in_repr->attribute("gui-hidden"); if (gui_hide != NULL) { if (strcmp(gui_hide, "1") == 0 || strcmp(gui_hide, "true") == 0) { - gui_hidden = true; + hidden = true; } /* else stays false */ } @@ -98,44 +112,30 @@ Parameter *Parameter::make(Inkscape::XML::Node *in_repr, Inkscape::Extension::Ex } const gchar* appearance = in_repr->attribute("appearance"); - Parameter::_scope_t scope = Parameter::SCOPE_USER; - { - const char *scope_str = in_repr->attribute("scope"); - if (scope_str != NULL) { - if (!strcmp(scope_str, "user")) { - scope = Parameter::SCOPE_USER; - } else if (!strcmp(scope_str, "document")) { - scope = Parameter::SCOPE_DOCUMENT; - } else if (!strcmp(scope_str, "node")) { - scope = Parameter::SCOPE_NODE; - } - } - } - Parameter * param = NULL; if (!strcmp(type, "boolean")) { - param = new ParamBool(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr); + param = new ParamBool(name, text, description, hidden, 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, indent, in_ext, in_repr, ParamInt::FULL); + param = new ParamInt(name, text, description, hidden, indent, in_ext, in_repr, ParamInt::FULL); } else { - param = new ParamInt(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamInt::MINIMAL); + param = new ParamInt(name, text, description, hidden, 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, indent, in_ext, in_repr, ParamFloat::FULL); + param = new ParamFloat(name, text, description, hidden, indent, in_ext, in_repr, ParamFloat::FULL); } else { - param = new ParamFloat(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamFloat::MINIMAL); + param = new ParamFloat(name, text, description, hidden, indent, in_ext, in_repr, ParamFloat::MINIMAL); } } else if (!strcmp(type, "string")) { - param = new ParamString(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr); + param = new ParamString(name, text, description, hidden, indent, in_ext, in_repr); gchar const * max_length = in_repr->attribute("max_length"); if (max_length != NULL) { ParamString * ps = dynamic_cast<ParamString *>(param); ps->setMaxLength(atoi(max_length)); } } else if (!strcmp(type, "description")) { - ParamDescription::AppearanceMode appearance_mode = ParamDescription::DESC; + ParamDescription::AppearanceMode appearance_mode = ParamDescription::DESCRIPTION; if (appearance) { if (!strcmp(appearance, "header")) { appearance_mode = ParamDescription::HEADER; @@ -143,19 +143,19 @@ Parameter *Parameter::make(Inkscape::XML::Node *in_repr, Inkscape::Extension::Ex appearance_mode = ParamDescription::URL; } } - param = new ParamDescription(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, appearance_mode); + param = new ParamDescription(name, text, description, hidden, 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); + param = new ParamComboBox(name, text, description, hidden, indent, in_ext, in_repr); } else if (!strcmp(type, "notebook")) { - param = new ParamNotebook(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr); + param = new ParamNotebook(name, text, description, hidden, 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, indent, in_ext, in_repr, ParamRadioButton::MINIMAL); + param = new ParamRadioButton(name, text, description, hidden, indent, in_ext, in_repr, ParamRadioButton::MINIMAL); } else { - param = new ParamRadioButton(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr, ParamRadioButton::FULL); + param = new ParamRadioButton(name, text, description, hidden, indent, in_ext, in_repr, ParamRadioButton::FULL); } } else if (!strcmp(type, "color")) { - param = new ParamColor(name, guitext, desc, scope, gui_hidden, gui_tip, indent, in_ext, in_repr); + param = new ParamColor(name, text, description, hidden, indent, in_ext, in_repr); } // Note: param could equal NULL @@ -302,29 +302,24 @@ 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, int indent, Inkscape::Extension::Extension * ext) : - _desc(0), - _scope(scope), +Parameter::Parameter(gchar const * name, gchar const * text, gchar const * description, bool hidden, int indent, Inkscape::Extension::Extension * ext) : + _description(0), _text(0), - _gui_hidden(gui_hidden), - _gui_tip(0), + _hidden(hidden), _indent(indent), - extension(ext), + _extension(ext), _name(0) { if (name != NULL) { _name = g_strdup(name); } - if (desc != NULL) { - _desc = g_strdup(desc); -// printf("Adding description: '%s' on '%s'\n", _desc, _name); - } - if (gui_tip != NULL) { - _gui_tip = g_strdup(gui_tip); + + if (description != NULL) { + _description = g_strdup(description); } - if (guitext != NULL) { - _text = g_strdup(guitext); + if (text != NULL) { + _text = g_strdup(text); } else { _text = g_strdup(name); } @@ -333,21 +328,19 @@ Parameter::Parameter(gchar const * name, gchar const * guitext, gchar const * de } /** Oop, now that we need a parameter, we need it's name. */ -Parameter::Parameter (gchar const * name, gchar const * guitext, Inkscape::Extension::Extension * ext) : - _desc(0), - _scope(Parameter::SCOPE_USER), +Parameter::Parameter (gchar const * name, gchar const * text, Inkscape::Extension::Extension * ext) : + _description(0), _text(0), - _gui_hidden(false), - _gui_tip(0), + _hidden(false), _indent(0), - extension(ext), + _extension(ext), _name(0) { if (name != NULL) { _name = g_strdup(name); } - if (guitext != NULL) { - _text = g_strdup(guitext); + if (text != NULL) { + _text = g_strdup(text); } else { _text = g_strdup(name); } @@ -363,16 +356,13 @@ Parameter::~Parameter(void) g_free(_text); _text = 0; - g_free(_gui_tip); - _gui_tip = 0; - - g_free(_desc); - _desc = 0; + g_free(_description); + _description = 0; } gchar *Parameter::pref_name(void) const { - return g_strdup_printf("%s.%s", extension->get_id(), _name); + return g_strdup_printf("%s.%s", _extension->get_id(), _name); } Inkscape::XML::Node * @@ -405,7 +395,7 @@ Inkscape::XML::Node *Parameter::document_param_node(SPDocument * doc) child != NULL; child = child->next()) { if ((GQuark)child->code() == name_quark && - !strcmp(child->attribute("extension"), extension->get_id())) { + !strcmp(child->attribute("extension"), _extension->get_id())) { params = child; break; } @@ -413,7 +403,7 @@ Inkscape::XML::Node *Parameter::document_param_node(SPDocument * doc) if (params == NULL) { params = xml_doc->createElement("inkscape:extension-param"); - params->setAttribute("extension", extension->get_id()); + params->setAttribute("extension", _extension->get_id()); defs->appendChild(params); Inkscape::GC::release(params); } diff --git a/src/extension/param/parameter.h b/src/extension/param/parameter.h index c107f24f9..96cc055d8 100644 --- a/src/extension/param/parameter.h +++ b/src/extension/param/parameter.h @@ -47,26 +47,16 @@ extern Glib::ustring const extension_pref_root; */ class Parameter { -protected: - /** List of possible scopes. */ - typedef enum { - SCOPE_USER, /**< Parameter value is saved in the user's configuration file. (default) */ - SCOPE_DOCUMENT, /**< Parameter value is saved in the document. */ - SCOPE_NODE /**< Parameter value is attached to the node. */ - } _scope_t; - public: Parameter(gchar const *name, - gchar const *guitext, - gchar const *desc, - const Parameter::_scope_t scope, - bool gui_hidden, - gchar const *gui_tip, + gchar const *text, + gchar const *description, + bool hidden, int indent, Inkscape::Extension::Extension * ext); Parameter(gchar const *name, - gchar const *guitext, + gchar const *text, Inkscape::Extension::Extension * ext); virtual ~Parameter(void); @@ -140,10 +130,10 @@ public: virtual Gtk::Widget * get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal); - gchar const * get_tooltip(void) const { return _desc; } + gchar const * get_tooltip(void) const { return _description; } /** Indicates if the GUI for this parameter is hidden or not */ - bool get_gui_hidden() const { return _gui_hidden; } + bool get_hidden() const { return _hidden; } /** Indentation level of the parameter */ int get_indent() const { return _indent; } @@ -173,20 +163,14 @@ public: protected: - /** Description of the parameter. */ - gchar * _desc; - - /** Scope of the parameter. */ - _scope_t _scope; - - /** Text for the GUI selection of this. */ - gchar * _text; + /** Parameter text to show as the GUI label. */ + gchar * _text; - /** Whether the GUI is visible. */ - bool _gui_hidden; + /** Extended description of the parameter (crrently shown as tooltip on hover). */ + gchar * _description; - /** A tip for the GUI if there is one. */ - gchar * _gui_tip; + /** Whether the parameter is visible. */ + bool _hidden; /** Indentation level of the parameter. */ int _indent; @@ -207,7 +191,7 @@ protected: private: /** Which extension is this parameter attached to. */ - Inkscape::Extension::Extension *extension; + Inkscape::Extension::Extension *_extension; /** The name of this parameter. */ gchar *_name; diff --git a/src/extension/param/radiobutton.cpp b/src/extension/param/radiobutton.cpp index 178dc20e8..a08ba6860 100644 --- a/src/extension/param/radiobutton.cpp +++ b/src/extension/param/radiobutton.cpp @@ -41,33 +41,31 @@ namespace Inkscape { namespace Extension { /* For internal use only. - Note that value and guitext MUST be non-NULL. This is ensured by newing only at one location in the code where non-NULL checks are made. */ + Note that value and text MUST be non-NULL. This is ensured by newing only at one location in the code where non-NULL checks are made. */ class optionentry { public: - optionentry (Glib::ustring * val, Glib::ustring * text) { + optionentry (Glib::ustring * val, Glib::ustring * txt) { value = val; - guitext = text; + text = txt; } ~optionentry() { delete value; - delete guitext; + delete text; } Glib::ustring * value; - Glib::ustring * guitext; + Glib::ustring * text; }; ParamRadioButton::ParamRadioButton(const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml, AppearanceMode mode) - : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + : Parameter(name, text, description, hidden, indent, ext) , _value(0) , _mode(mode) , choices(0) @@ -79,7 +77,7 @@ ParamRadioButton::ParamRadioButton(const gchar * name, while (child_repr != NULL) { char const * chname = child_repr->name(); if (!strcmp(chname, INKSCAPE_EXTENSION_NS "option") || !strcmp(chname, INKSCAPE_EXTENSION_NS "_option")) { - Glib::ustring * newguitext = NULL; + Glib::ustring * newtext = NULL; Glib::ustring * newvalue = NULL; const char * contents = child_repr->firstChild()->content(); @@ -87,12 +85,12 @@ ParamRadioButton::ParamRadioButton(const gchar * name, // don't translate when 'item' but do translate when '_option' if (!strcmp(chname, INKSCAPE_EXTENSION_NS "_option")) { if (child_repr->attribute("msgctxt") != NULL) { - newguitext = new Glib::ustring(g_dpgettext2(NULL, child_repr->attribute("msgctxt"), contents)); + newtext = new Glib::ustring(g_dpgettext2(NULL, child_repr->attribute("msgctxt"), contents)); } else { - newguitext = new Glib::ustring(_(contents)); + newtext = new Glib::ustring(_(contents)); } } else { - newguitext = new Glib::ustring(contents); + newtext = new Glib::ustring(contents); } } else { continue; @@ -106,8 +104,8 @@ ParamRadioButton::ParamRadioButton(const gchar * name, newvalue = new Glib::ustring(contents); } - if ( (newguitext) && (newvalue) ) { // logical error if this is not true here - choices = g_slist_append( choices, new optionentry(newvalue, newguitext) ); + if ( (newtext) && (newvalue) ) { // logical error if this is not true here + choices = g_slist_append( choices, new optionentry(newvalue, newtext) ); } } child_repr = child_repr->next(); @@ -282,7 +280,7 @@ Glib::ustring ParamRadioButton::value_from_label(const Glib::ustring label) for (GSList * list = choices; list != NULL; list = g_slist_next(list)) { optionentry * entr = reinterpret_cast<optionentry *>(list->data); - if ( !entr->guitext->compare(label) ) { + if ( !entr->text->compare(label) ) { value = *(entr->value); break; } @@ -297,7 +295,7 @@ Glib::ustring ParamRadioButton::value_from_label(const Glib::ustring label) */ Gtk::Widget * ParamRadioButton::get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) { - if (_gui_hidden) { + if (_hidden) { return NULL; } @@ -306,7 +304,7 @@ Gtk::Widget * ParamRadioButton::get_widget(SPDocument * doc, Inkscape::XML::Node auto vbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0)); vbox->set_homogeneous(false); - Gtk::Label * label = Gtk::manage(new Gtk::Label(_(_text), Gtk::ALIGN_START, Gtk::ALIGN_START)); + Gtk::Label * label = Gtk::manage(new Gtk::Label(_text, Gtk::ALIGN_START, Gtk::ALIGN_START)); label->show(); hbox->pack_start(*label, false, false); @@ -323,7 +321,7 @@ Gtk::Widget * ParamRadioButton::get_widget(SPDocument * doc, Inkscape::XML::Node Gtk::RadioButtonGroup group; for (GSList * list = choices; list != NULL; list = g_slist_next(list)) { optionentry * entr = reinterpret_cast<optionentry *>(list->data); - Glib::ustring * text = entr->guitext; + Glib::ustring * text = entr->text; switch ( _mode ) { case MINIMAL: { diff --git a/src/extension/param/radiobutton.h b/src/extension/param/radiobutton.h index 5e15dcb57..b91b11ea3 100644 --- a/src/extension/param/radiobutton.h +++ b/src/extension/param/radiobutton.h @@ -35,11 +35,9 @@ public: }; ParamRadioButton(const gchar * name, - const gchar * guitext, - const gchar * desc, - const Parameter::_scope_t scope, - bool gui_hidden, - const gchar * gui_tip, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml, diff --git a/src/extension/param/string.cpp b/src/extension/param/string.cpp index 0c5238f99..51b5dfdf3 100644 --- a/src/extension/param/string.cpp +++ b/src/extension/param/string.cpp @@ -77,15 +77,13 @@ 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, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml) - : Parameter(name, guitext, desc, scope, gui_hidden, gui_tip, indent, ext) + : Parameter(name, text, description, hidden, indent, ext) , _value(NULL) { const char * defaultval = NULL; @@ -164,12 +162,12 @@ void ParamStringEntry::changed_text(void) */ Gtk::Widget * ParamString::get_widget(SPDocument * doc, Inkscape::XML::Node * node, sigc::signal<void> * changeSignal) { - if (_gui_hidden) { + if (_hidden) { return NULL; } 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)); + 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/string.h b/src/extension/param/string.h index f5412ebcc..d338f83b9 100644 --- a/src/extension/param/string.h +++ b/src/extension/param/string.h @@ -24,11 +24,9 @@ private: 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, + const gchar * text, + const gchar * description, + bool hidden, int indent, Inkscape::Extension::Extension * ext, Inkscape::XML::Node * xml); diff --git a/src/extension/prefdialog.cpp b/src/extension/prefdialog.cpp index 2bdbb081e..92ddd3050 100644 --- a/src/extension/prefdialog.cpp +++ b/src/extension/prefdialog.cpp @@ -246,7 +246,7 @@ PrefDialog::on_response (int signal) { #include "internal/clear-n_.h" -const char * PrefDialog::live_param_xml = "<param name=\"__live_effect__\" type=\"boolean\" _gui-text=\"" N_("Live preview") "\" gui-description=\"" N_("Is the effect previewed live on canvas?") "\" scope=\"user\">false</param>"; +const char * PrefDialog::live_param_xml = "<param name=\"__live_effect__\" type=\"boolean\" _gui-text=\"" N_("Live preview") "\" gui-description=\"" N_("Is the effect previewed live on canvas?") "\">false</param>"; }; }; /* namespace Inkscape, Extension */ diff --git a/src/file.cpp b/src/file.cpp index fc9ce6b19..795df433d 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -293,12 +293,10 @@ bool sp_file_open(const Glib::ustring &uri, bool replace_empty) { SPDesktop *desktop = SP_ACTIVE_DESKTOP; - Inkscape::Display::TemporaryItem *page_border_rotated = NULL; if (desktop) { desktop->setWaitingCursor(); - page_border_rotated = sp_document_namedview(desktop->getDocument(), NULL)->page_border_rotated; } - + SPDocument *doc = NULL; bool cancelled = false; try { @@ -317,6 +315,7 @@ bool sp_file_open(const Glib::ustring &uri, } if (doc) { + SPDocument *existing = desktop ? desktop->getDocument() : NULL; if (existing && existing->virgin && replace_empty) { @@ -324,7 +323,6 @@ bool sp_file_open(const Glib::ustring &uri, doc->ensureUpToDate(); // TODO this will trigger broken link warnings, etc. desktop->change_document(doc); doc->emitResizedSignal(doc->getWidth().value("px"), doc->getHeight().value("px")); - desktop->remove_temporary_canvasitem(page_border_rotated); } else { // create a whole new desktop and window SPViewWidget *dtw = sp_desktop_widget_new(sp_document_namedview(doc, NULL)); // TODO this will trigger broken link warnings, etc. diff --git a/src/helper/geom-pathvectorsatellites.cpp b/src/helper/geom-pathvectorsatellites.cpp index 79055af8d..dd231d78f 100644 --- a/src/helper/geom-pathvectorsatellites.cpp +++ b/src/helper/geom-pathvectorsatellites.cpp @@ -67,7 +67,9 @@ void PathVectorSatellites::setSelected(std::vector<size_t> selected) size_t counter = 0; for (size_t i = 0; i < _satellites.size(); ++i) { for (size_t j = 0; j < _satellites[i].size(); ++j) { + std::cout << j; if (find (selected.begin(), selected.end(), counter) != selected.end()) { + _satellites[i][j].setSelected(true); } else { _satellites[i][j].setSelected(false); diff --git a/src/io/sys.cpp b/src/io/sys.cpp index 61a6a96f4..b06b550dd 100644 --- a/src/io/sys.cpp +++ b/src/io/sys.cpp @@ -37,36 +37,6 @@ void dump_ustr(Glib::ustring const &ustr); extern guint update_in_progress; -#define DEBUG_MESSAGE(key, ...) \ -{\ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); \ - gint dump = prefs->getBool("/options/bulia/" #key) ? 1 : 0;\ - gint dumpD = prefs->getBool("/options/bulia/" #key"D") ? 1 : 0;\ - gint dumpD2 = prefs->getBool("/options/bulia/" #key"D2") ? 1 : 0;\ - dumpD &= ( (update_in_progress == 0) || dumpD2 );\ - if ( dump )\ - {\ - g_message( __VA_ARGS__ );\ -\ - }\ - if ( dumpD )\ - {\ - GtkWidget *dialog = gtk_message_dialog_new(NULL,\ - GTK_DIALOG_DESTROY_WITH_PARENT, \ - GTK_MESSAGE_INFO, \ - GTK_BUTTONS_OK, \ - __VA_ARGS__ \ - );\ - g_signal_connect_swapped(dialog, "response",\ - G_CALLBACK(gtk_widget_destroy), \ - dialog); \ - gtk_widget_show_all( dialog );\ - }\ -} - - - - void Inkscape::IO::dump_fopen_call( char const *utf8name, char const *id ) { #ifdef INK_DUMP_FOPEN @@ -97,65 +67,33 @@ void Inkscape::IO::dump_fopen_call( char const *utf8name, char const *id ) FILE *Inkscape::IO::fopen_utf8name( char const *utf8name, char const *mode ) { - static gint counter = 0; FILE* fp = NULL; - - DEBUG_MESSAGE( dumpOne, "entering fopen_utf8name( '%s', '%s' )[%d]", utf8name, mode, (counter++) ); - -#ifndef WIN32 - DEBUG_MESSAGE( dumpOne, " STEP 0 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) ); gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL ); if ( filename ) { - DEBUG_MESSAGE( dumpOne, " STEP 1 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) ); - fp = std::fopen(filename, mode); - DEBUG_MESSAGE( dumpOne, " STEP 2 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) ); + Glib::ustring how( mode ); + if ( how.find("b") == Glib::ustring::npos ) + { + how.append("b"); // not needed in POSIX but doesn't hurt either + } + fp = g_fopen(filename, how.c_str()); g_free(filename); - DEBUG_MESSAGE( dumpOne, " STEP 3 ( '%s', '%s' )[%d]", utf8name, mode, (counter++) ); filename = 0; } -#else - Glib::ustring how( mode ); - how.append("b"); - DEBUG_MESSAGE( dumpOne, " calling is_os_wide() ( '%s', '%s' )[%d]", utf8name, mode, (counter++) ); - - fp = g_fopen(utf8name, how.c_str()); -#endif - - DEBUG_MESSAGE( dumpOne, "leaving fopen_utf8name( '%s', '%s' )[%d]", utf8name, mode, (counter++) ); - return fp; } int Inkscape::IO::mkdir_utf8name( char const *utf8name ) { - static gint counter = 0; int retval = -1; - - DEBUG_MESSAGE( dumpMk, "entering mkdir_utf8name( '%s' )[%d]", utf8name, (counter++) ); - -#ifndef WIN32 - DEBUG_MESSAGE( dumpMk, " STEP 0 ( '%s' )[%d]", utf8name, (counter++) ); gchar *filename = g_filename_from_utf8( utf8name, -1, NULL, NULL, NULL ); if ( filename ) { - DEBUG_MESSAGE( dumpMk, " STEP 1 ( '%s' )[%d]", utf8name, (counter++) ); - retval = ::mkdir(filename, S_IRWXU | S_IRGRP | S_IXGRP); - DEBUG_MESSAGE( dumpMk, " STEP 2 ( '%s' )[%d]", utf8name, (counter++) ); + retval = g_mkdir(filename, S_IRWXU | S_IRGRP | S_IXGRP); // The mode argument is ignored on Windows. g_free(filename); - DEBUG_MESSAGE( dumpMk, " STEP 3 ( '%s' )[%d]", utf8name, (counter++) ); filename = 0; } -#else - DEBUG_MESSAGE( dumpMk, " calling is_os_wide() ( '%s' )[%d]", utf8name, (counter++) ); - - // Mode should be ingnored inside of glib on the way in - retval = g_mkdir( utf8name, 0 ); -#endif - - DEBUG_MESSAGE( dumpMk, "leaving mkdir_utf8name( '%s' )[%d]", utf8name, (counter++) ); - return retval; } diff --git a/src/livarot/PathOutline.cpp b/src/livarot/PathOutline.cpp index 7043469d2..c1a48d41f 100644 --- a/src/livarot/PathOutline.cpp +++ b/src/livarot/PathOutline.cpp @@ -158,7 +158,8 @@ void Path::Outline(Path *dest, double width, JoinType join, ButtType butt, doubl join, butt, miter, false, false, endPos, endButt); Geom::Point endNor=endButt.ccw(); if (butt == butt_round) { - dest->ArcTo (endPos+width*endNor, 1.0001 * width, 1.0001 * width, 0.0, true, true); + dest->ArcTo (endPos+width*endButt, width, width, 0.0, false, true); + dest->ArcTo (endPos+width*endNor, width, width, 0.0, false, true); } else if (butt == butt_square) { dest->LineTo (endPos-width*endNor+width*endButt); dest->LineTo (endPos+width*endNor+width*endButt); @@ -175,7 +176,8 @@ void Path::Outline(Path *dest, double width, JoinType join, ButtType butt, doubl endNor=endButt.ccw(); if (butt == butt_round) { - dest->ArcTo (endPos+width*endNor, 1.0001 * width, 1.0001 * width, 0.0, true, true); + dest->ArcTo (endPos+width*endButt, width, width, 0.0, false, true); + dest->ArcTo (endPos+width*endNor, width, width, 0.0, false, true); } else if (butt == butt_square) { dest->LineTo (endPos-width*endNor+width*endButt); dest->LineTo (endPos+width*endNor+width*endButt); diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 5ef9487ab..467a65c7c 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -73,8 +73,10 @@ #include "path-chemistry.h" #include "xml/sp-css-attr.h" #include "live_effects/lpeobject.h" +#include <pangomm/layout.h> #include "display/curve.h" - +#include <stdio.h> +#include <string.h> namespace Inkscape { @@ -83,63 +85,63 @@ namespace LivePathEffect { const Util::EnumData<EffectType> LPETypeData[] = { // {constant defined in effect-enum.h, N_("name of your effect"), "name of your effect in SVG"} #ifdef LPE_ENABLE_TEST_EFFECTS - {DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"}, - {ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"}, + {DOEFFECTSTACK_TEST, N_("doEffect stack test"), "doeffectstacktest"}, + {ANGLE_BISECTOR, N_("Angle bisector"), "angle_bisector"}, {CIRCLE_WITH_RADIUS, N_("Circle (by center and radius)"), "circle_with_radius"}, - {CIRCLE_3PTS, N_("Circle by 3 points"), "circle_3pts"}, - {DYNASTROKE, N_("Dynamic stroke"), "dynastroke"}, - {EXTRUDE, N_("Extrude"), "extrude"}, - {LATTICE, N_("Lattice Deformation"), "lattice"}, - {LINE_SEGMENT, N_("Line Segment"), "line_segment"}, - {OFFSET, N_("Offset"), "offset"}, - {PARALLEL, N_("Parallel"), "parallel"}, - {PATH_LENGTH, N_("Path length"), "path_length"}, - {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"}, - {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"}, - {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, - {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, - {TEXT_LABEL, N_("Text label"), "text_label"}, + {CIRCLE_3PTS, N_("Circle by 3 points"), "circle_3pts"}, + {DYNASTROKE, N_("Dynamic stroke"), "dynastroke"}, + {EXTRUDE, N_("Extrude"), "extrude"}, + {LATTICE, N_("Lattice Deformation"), "lattice"}, + {LINE_SEGMENT, N_("Line Segment"), "line_segment"}, + {OFFSET, N_("Offset"), "offset"}, + {PARALLEL, N_("Parallel"), "parallel"}, + {PATH_LENGTH, N_("Path length"), "path_length"}, + {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"}, + {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"}, + {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, + {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, + {TEXT_LABEL, N_("Text label"), "text_label"}, #endif /* 0.46 */ - {BEND_PATH, N_("Bend"), "bend_path"}, - {GEARS, N_("Gears"), "gears"}, - {PATTERN_ALONG_PATH, N_("Pattern Along Path"), "skeletal"}, // for historic reasons, this effect is called skeletal(strokes) in Inkscape:SVG - {CURVE_STITCH, N_("Stitch Sub-Paths"), "curvestitching"}, + {BEND_PATH, N_("Bend"), "bend_path"}, + {GEARS, N_("Gears"), "gears"}, + {PATTERN_ALONG_PATH, N_("Pattern Along Path"), "skeletal"}, // for historic reasons, this effect is called skeletal(strokes) in Inkscape:SVG + {CURVE_STITCH, N_("Stitch Sub-Paths"), "curvestitching"}, /* 0.47 */ - {VONKOCH, N_("VonKoch"), "vonkoch"}, - {KNOT, N_("Knot"), "knot"}, - {CONSTRUCT_GRID, N_("Construct grid"), "construct_grid"}, - {SPIRO, N_("Spiro spline"), "spiro"}, - {ENVELOPE, N_("Envelope Deformation"), "envelope"}, - {INTERPOLATE, N_("Interpolate Sub-Paths"), "interpolate"}, - {ROUGH_HATCHES, N_("Hatches (rough)"), "rough_hatches"}, - {SKETCH, N_("Sketch"), "sketch"}, - {RULER, N_("Ruler"), "ruler"}, + {VONKOCH, N_("VonKoch"), "vonkoch"}, + {KNOT, N_("Knot"), "knot"}, + {CONSTRUCT_GRID, N_("Construct grid"), "construct_grid"}, + {SPIRO, N_("Spiro spline"), "spiro"}, + {ENVELOPE, N_("Envelope Deformation"), "envelope"}, + {INTERPOLATE, N_("Interpolate Sub-Paths"), "interpolate"}, + {ROUGH_HATCHES, N_("Hatches (rough)"), "rough_hatches"}, + {SKETCH, N_("Sketch"), "sketch"}, + {RULER, N_("Ruler"), "ruler"}, /* 0.91 */ - {POWERSTROKE, N_("Power stroke"), "powerstroke"}, - {CLONE_ORIGINAL, N_("Clone original"), "clone_original"}, + {POWERSTROKE, N_("Power stroke"), "powerstroke"}, + {CLONE_ORIGINAL, N_("Clone original"), "clone_original"}, /* 0.92 */ - {SIMPLIFY, N_("Simplify"), "simplify"}, - {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, - {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective_envelope"}, - {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"}, - {TRANSFORM_2PTS, N_("Transform by 2 points"), "transform_2pts"}, - {SHOW_HANDLES, N_("Show handles"), "show_handles"}, - {ROUGHEN, N_("Roughen"), "roughen"}, - {BSPLINE, N_("BSpline"), "bspline"}, - {JOIN_TYPE, N_("Join type"), "join_type"}, - {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"}, - {MIRROR_SYMMETRY, N_("Mirror symmetry"), "mirror_symmetry"}, - {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, + {SIMPLIFY, N_("Simplify"), "simplify"}, + {LATTICE2, N_("Lattice Deformation 2"), "lattice2"}, + {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"}, //TODO:Wrong name with "-" + {INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"}, + {TRANSFORM_2PTS, N_("Transform by 2 points"), "transform_2pts"}, + {SHOW_HANDLES, N_("Show handles"), "show_handles"}, + {ROUGHEN, N_("Roughen"), "roughen"}, + {BSPLINE, N_("BSpline"), "bspline"}, + {JOIN_TYPE, N_("Join type"), "join_type"}, + {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"}, + {MIRROR_SYMMETRY, N_("Mirror symmetry"), "mirror_symmetry"}, + {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, /* Ponyscape -> Inkscape 0.92*/ - {ATTACH_PATH, N_("Attach path"), "attach_path"}, - {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, - {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, - {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, - {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, + {ATTACH_PATH, N_("Attach path"), "attach_path"}, + {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, + {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, + {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, + {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, /* 9.93 */ - {MEASURE_LINE, N_("Measure Line"), "measure_line"}, - {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"}, + {MEASURE_LINE, N_("Measure Line"), "measure_line"}, + {FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet_chamfer"}, }; const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -401,58 +403,19 @@ Effect::setCurrentZoom(double cZ) } void -Effect::setSelectedNodePos(std::vector<Geom::Point> selected_nodes_pos_data) +Effect::setSelectedNodePoints(std::vector<Geom::Point> sNP) { - selected_nodes_pos = selected_nodes_pos_data; -} - -void - -Effect::setSelectedNodeIndex(Geom::PathVector pv) -{ - selected_nodes_index.clear(); - for (Geom::PathVector::const_iterator path_it = pv.begin(); - path_it != pv.end(); ++path_it) { - - if (path_it->empty()) { - continue; - } - Geom::Path::const_iterator curve_it1 = path_it->begin(); - Geom::Path::const_iterator curve_endit = path_it->end_default(); - if (path_it->closed()) { - const Geom::Curve &closingline = path_it->back_closed(); - // the closing line segment is always of type - // Geom::LineSegment. - if (are_near(closingline.initialPoint(), closingline.finalPoint())) { - // closingline.isDegenerate() did not work, because it only checks for - // *exact* zero length, which goes wrong for relative coordinates and - // rounding errors... - // the closing line segment has zero-length. So stop before that one! - curve_endit = path_it->end_open(); - } - } - size_t i = 0; - while (curve_it1 != curve_endit) { - if (isNodeSelected(curve_it1->initialPoint())) { - selected_nodes_index.push_back(i); - } - ++i; - ++curve_it1; - } - if (isNodeSelected(path_it->finalPoint())) { - selected_nodes_index.push_back(i); - } - } + selectedNodesPoints = sNP; } bool -Effect::isNodeSelected(Geom::Point const &nodePoint) const +Effect::isNodePointSelected(Geom::Point const &nodePoint) const { - if (selected_nodes_pos.size() > 0) { + if (selectedNodesPoints.size() > 0) { using Geom::X; using Geom::Y; - for (std::vector<Geom::Point>::const_iterator i = selected_nodes_pos.begin(); - i != selected_nodes_pos.end(); ++i) { + for (std::vector<Geom::Point>::const_iterator i = selectedNodesPoints.begin(); + i != selectedNodesPoints.end(); ++i) { Geom::Point p = *i; Geom::Affine transformCoordinate = sp_lpe_item->i2dt_affine(); Geom::Point p2(nodePoint[X],nodePoint[Y]); @@ -683,6 +646,7 @@ void Effect::readallParameters(Inkscape::XML::Node const* repr) { std::vector<Parameter *>::iterator it = param_vector.begin(); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); while (it != param_vector.end()) { Parameter * param = *it; const gchar * key = param->param_key.c_str(); @@ -693,10 +657,17 @@ Effect::readallParameters(Inkscape::XML::Node const* repr) g_warning("Effect::readallParameters - '%s' not accepted for %s", value, key); } } else { - // set default value - param->param_set_default(); + Glib::ustring pref_path = (Glib::ustring)"/live_effects/" + + (Glib::ustring)LPETypeConverter.get_key(effectType()).c_str() + + (Glib::ustring)"/" + + (Glib::ustring)key; + bool valid = prefs->getEntry(pref_path).isValid(); + if(valid){ + param->param_update_default(prefs->getString(pref_path).c_str()); + } else { + param->param_set_default(); + } } - ++it; } } @@ -811,10 +782,96 @@ Effect::newWidget() ++it; } - upd_params = false; return dynamic_cast<Gtk::Widget *>(vbox); } +/** + * This *creates* a new widget, with default values setter + */ +Gtk::Widget * +Effect::defaultParamSet() +{ + // use manage here, because after deletion of Effect object, others might still be pointing to this widget. + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Gtk::VBox * vbox = Gtk::manage( new Gtk::VBox() ); + Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox() ); + Glib::ustring effectname = (Glib::ustring)Inkscape::LivePathEffect::LPETypeConverter.get_label(effectType()); + Glib::ustring effectkey = (Glib::ustring)Inkscape::LivePathEffect::LPETypeConverter.get_key(effectType()); + std::vector<Parameter *>::iterator it = param_vector.begin(); + Inkscape::UI::Widget::Registry * wr; + bool has_params = false; + while (it != param_vector.end()) { + if ((*it)->widget_is_visible) { + has_params = true; + Parameter * param = *it; + Glib::ustring * tip = param->param_getTooltip(); + const gchar * key = param->param_key.c_str(); + const gchar * value = param->param_label.c_str(); + const gchar * tooltip_extra = _(". Change custom values for this parameter"); + Glib::ustring tooltip = param->param_tooltip + (Glib::ustring)tooltip_extra; + Glib::ustring pref_path = (Glib::ustring)"/live_effects/" + + effectkey + + (Glib::ustring)"/" + + (Glib::ustring)key; + bool valid = prefs->getEntry(pref_path).isValid(); + const gchar * set_or_upd; + if (valid) { + set_or_upd = _("Update"); + } else { + set_or_upd = _("Set"); + } + Gtk::HBox * vbox_param = Gtk::manage( new Gtk::HBox(true) ); + Gtk::Label *parameter_label = Gtk::manage(new Gtk::Label(value, Gtk::ALIGN_START)); + parameter_label->set_use_markup(true); + parameter_label->set_use_underline (true); + parameter_label->set_ellipsize(Pango::ELLIPSIZE_END); + vbox_param->pack_start(*parameter_label, true, true, 2); + Gtk::Button *set = Gtk::manage(new Gtk::Button((Glib::ustring)set_or_upd)); + Gtk::Button *unset = Gtk::manage(new Gtk::Button(Glib::ustring(_("Unset")))); + unset->signal_clicked().connect(sigc::bind<Glib::ustring, Gtk::Button *, Gtk::Button *>(sigc::mem_fun(*this, &Effect::unsetDefaultParam), pref_path, set, unset)); + set->signal_clicked().connect(sigc::bind<Glib::ustring, gchar *, Gtk::Button *, Gtk::Button *>(sigc::mem_fun(*this, &Effect::setDefaultParam), pref_path, param->param_getSVGValue(), set, unset)); + if (!valid) { + unset->set_sensitive(false); + } + vbox_param->pack_start(*set, true, true, 2); + vbox_param->pack_start(*unset, true, true, 2); + + vbox_expander->pack_start(*vbox_param, true, true, 2); + } + ++it; + } + Glib::ustring tip = "<b>" + effectname + (Glib::ustring)_("</b>: Set default parameters"); + Gtk::Expander * expander = Gtk::manage(new Gtk::Expander(tip)); + expander->set_use_markup(true); + expander->add(*vbox_expander); + expander->set_expanded(false); + vbox->pack_start(*dynamic_cast<Gtk::Widget *> (expander), true, true, 2); + if (has_params) { + return dynamic_cast<Gtk::Widget *>(vbox); + } else { + return NULL; + } +} + +void +Effect::setDefaultParam(Glib::ustring pref_path, gchar * value, Gtk::Button *set , Gtk::Button *unset) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString(pref_path, (Glib::ustring)value); + gchar * label = _("Update"); + set->set_label((Glib::ustring)label); + unset->set_sensitive(true); +} + +void +Effect::unsetDefaultParam(Glib::ustring pref_path, Gtk::Button *set, Gtk::Button *unset) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->remove(pref_path); + gchar * label = _("Set"); + set->set_label((Glib::ustring)label); + unset->set_sensitive(false); +} Inkscape::XML::Node *Effect::getRepr() { diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 6c11e0b67..c34c391c0 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -65,9 +65,8 @@ public: void doOnApply_impl(SPLPEItem const* lpeitem); void doBeforeEffect_impl(SPLPEItem const* lpeitem); void setCurrentZoom(double cZ); - void setSelectedNodePos(std::vector<Geom::Point> selected_nodes_pos_data); - void setSelectedNodeIndex(Geom::PathVector pv); - bool isNodeSelected(Geom::Point const &nodePoint) const; + void setSelectedNodePoints(std::vector<Geom::Point> sNP); + bool isNodePointSelected(Geom::Point const &nodePoint) const; virtual void doOnApply (SPLPEItem const* lpeitem); virtual void doBeforeEffect (SPLPEItem const* lpeitem); @@ -95,7 +94,7 @@ public: virtual void doEffect (SPCurve * curve); virtual Gtk::Widget * newWidget(); - + virtual Gtk::Widget * defaultParamSet(); /** * Sets all parameters to their default values and writes them to SVG. */ @@ -173,14 +172,15 @@ protected: // this boolean defaults to false, it concatenates the input path to one pwd2, // instead of normally 'splitting' the path into continuous pwd2 paths and calling doEffect_pwd2 for each. bool concatenate_before_pwd2; - SPLPEItem * sp_lpe_item; // these get stored in doBeforeEffect_impl, and derived classes may do as they please with them. SPShape * sp_shape; // these get stored in doBeforeEffect_impl before doEffect chain, or in performPathEffects on groups, and derived classes may do as they please with them. std::vector<const char *> items; double current_zoom; - std::vector<Geom::Point> selected_nodes_pos; - std::vector<size_t> selected_nodes_index; + std::vector<Geom::Point> selectedNodesPoints; + private: + void setDefaultParam(Glib::ustring pref_path, gchar * value, Gtk::Button *set , Gtk::Button *unset); + void unsetDefaultParam(Glib::ustring pref_path, Gtk::Button *set , Gtk::Button *unset); bool provides_own_flash_paths; // if true, the standard flash path is suppressed bool is_ready; diff --git a/src/live_effects/lpe-bendpath.cpp b/src/live_effects/lpe-bendpath.cpp index b1e133292..363356cac 100644 --- a/src/live_effects/lpe-bendpath.cpp +++ b/src/live_effects/lpe-bendpath.cpp @@ -57,10 +57,10 @@ LPEBendPath::LPEBendPath(LivePathEffectObject *lpeobject) : scale_y_rel(_("W_idth in units of length"), _("Scale the width of the path in units of its length"), "scale_y_rel", &wr, this, false), vertical_pattern(_("_Original path is vertical"), _("Rotates the original 90 degrees, before bending it along the bend path"), "vertical", &wr, this, false) { - registerParameter( dynamic_cast<Parameter *>(&bend_path) ); - registerParameter( dynamic_cast<Parameter *>(&prop_scale) ); - registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) ); - registerParameter( dynamic_cast<Parameter *>(&vertical_pattern) ); + registerParameter( &bend_path ); + registerParameter( &prop_scale); + registerParameter( &scale_y_rel); + registerParameter( &vertical_pattern); prop_scale.param_set_digits(3); prop_scale.param_set_increments(0.01, 0.10); diff --git a/src/live_effects/lpe-bounding-box.cpp b/src/live_effects/lpe-bounding-box.cpp index 11fb34e04..c83d7e3bc 100644 --- a/src/live_effects/lpe-bounding-box.cpp +++ b/src/live_effects/lpe-bounding-box.cpp @@ -20,8 +20,8 @@ LPEBoundingBox::LPEBoundingBox(LivePathEffectObject *lpeobject) : linked_path(_("Linked path:"), _("Path from which to take the original path data"), "linkedpath", &wr, this), visual_bounds(_("Visual Bounds"), _("Uses the visual bounding box"), "visualbounds", &wr, this) { - registerParameter( dynamic_cast<Parameter *>(&linked_path) ); - registerParameter( dynamic_cast<Parameter *>(&visual_bounds) ); + registerParameter(&linked_path); + registerParameter(&visual_bounds); //perceived_path = true; } diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 3fed11d5a..5c227e68a 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -86,7 +86,7 @@ Gtk::Widget *LPEBSpline::newWidget() // use manage here, because after deletion of Effect object, others might // still be pointing to this widget. Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget())); - + vbox->set_homogeneous(false); vbox->set_border_width(5); std::vector<Parameter *>::iterator it = param_vector.begin(); while (it != param_vector.end()) { @@ -398,7 +398,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weight_ammount) (apply_no_weight && Geom::are_near((*cubic)[1], point_at0)) || (apply_with_weight && !Geom::are_near((*cubic)[1], point_at0))) { - if (isNodeSelected(point_at0) || !only_selected) { + if (isNodePointSelected(point_at0) || !only_selected) { point_at1 = sbasis_in.valueAt(weight_ammount); if (weight_ammount != NO_POWER) { point_at1 = @@ -414,7 +414,7 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weight_ammount) (apply_no_weight && Geom::are_near((*cubic)[2], point_at3)) || (apply_with_weight && !Geom::are_near((*cubic)[2], point_at3))) { - if (isNodeSelected(point_at3) || !only_selected) { + if (isNodePointSelected(point_at3) || !only_selected) { point_at2 = sbasis_in.valueAt(1 - weight_ammount); if (weight_ammount != NO_POWER) { point_at2 = @@ -431,14 +431,14 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weight_ammount) (apply_no_weight && weight_ammount == NO_POWER) || (apply_with_weight && weight_ammount != NO_POWER)) { - if (isNodeSelected(point_at0) || !only_selected) { + if (isNodePointSelected(point_at0) || !only_selected) { point_at1 = sbasis_in.valueAt(weight_ammount); point_at1 = Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP); } else { point_at1 = in->first_segment()->initialPoint(); } - if (isNodeSelected(point_at3) || !only_selected) { + if (isNodePointSelected(point_at3) || !only_selected) { point_at2 = sbasis_in.valueAt(1 - weight_ammount); point_at2 = Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP); diff --git a/src/live_effects/lpe-clone-original.cpp b/src/live_effects/lpe-clone-original.cpp index c41b1ef95..d97a990af 100644 --- a/src/live_effects/lpe-clone-original.cpp +++ b/src/live_effects/lpe-clone-original.cpp @@ -20,8 +20,7 @@ namespace LivePathEffect { LPECloneOriginal::LPECloneOriginal(LivePathEffectObject *lpeobject) : Effect(lpeobject), - linked_path("LEGACY FALLBACK", "LEGACY FALLBACK", "linkedpath", &wr, this), - linked_item(_("Linked Item:"), _("Item from which to take the original data"), "linked_item", &wr, this), + linkeditem(_("Linked Item:"), _("Item from which to take the original data"), "linkeditem", &wr, this), scale(_("Scale %"), _("Scale item %"), "scale", &wr, this, 100.0), preserve_position(_("Preserve position"), _("Preserve position"), "preserve_position", &wr, this, false), inverse(_("Inverse clone"), _("Use LPE item as origin"), "inverse", &wr, this, false), @@ -37,8 +36,15 @@ LPECloneOriginal::LPECloneOriginal(LivePathEffectObject *lpeobject) : expanded(false), origin(Geom::Point(0,0)) { - registerParameter(&linked_path); - registerParameter(&linked_item); + //0.92 compatibility + const gchar * linkedpath = this->getRepr()->attribute("linkedpath"); + if (linkedpath && strcmp(linkedpath, "") != 0){ + this->getRepr()->setAttribute("linkeditem", linkedpath); + this->getRepr()->setAttribute("linkedpath", NULL); + this->getRepr()->setAttribute("transform", "false"); + }; + + registerParameter(&linkeditem); registerParameter(&scale); registerParameter(&attributes); registerParameter(&style_attributes); @@ -208,19 +214,8 @@ LPECloneOriginal::cloneAttrbutes(SPObject *origin, SPObject *dest, bool live, co void LPECloneOriginal::doBeforeEffect (SPLPEItem const* lpeitem){ - if (linked_path.linksToPath()) { //Legacy staff - Glib::ustring attributes_value("d"); - attributes.param_setValue(attributes_value); - attributes.write_to_SVG(); - Glib::ustring style_attributes_value(""); - style_attributes.param_setValue(style_attributes_value); - style_attributes.write_to_SVG(); - linked_item.param_readSVGValue(linked_path.param_getSVGValue()); - linked_path.param_readSVGValue(""); - } - - if (linked_item.linksToItem()) { - linked_item.setInverse(inverse); + if (linkeditem.linksToItem()) { + linkeditem.setInverse(inverse); if ( preserve_position_changed != preserve_position ) { if (!preserve_position) { sp_svg_transform_read(SP_ITEM(sp_lpe_item)->getAttribute("transform"), &preserve_affine); @@ -262,8 +257,8 @@ LPECloneOriginal::doBeforeEffect (SPLPEItem const* lpeitem){ } style_attr.append(Glib::ustring(style_attributes.param_getSVGValue()).append(",")); - SPItem * from = inverse ? SP_ITEM(sp_lpe_item) : SP_ITEM(linked_item.getObject()); - SPItem * to = !inverse ? SP_ITEM(sp_lpe_item) : SP_ITEM(linked_item.getObject()); + SPItem * from = inverse ? SP_ITEM(sp_lpe_item) : SP_ITEM(linkeditem.getObject()); + SPItem * to = !inverse ? SP_ITEM(sp_lpe_item) : SP_ITEM(linkeditem.getObject()); cloneAttrbutes(from, to, true, g_strdup(attr.c_str()), g_strdup(style_attr.c_str()), true); Geom::OptRect bbox = from->geometricBounds(); if (bbox && preserve_position && origin != Geom::Point(0,0)) { @@ -323,7 +318,6 @@ LPECloneOriginal::newWidget() expander->set_expanded(expanded); expander->property_expanded().signal_changed().connect(sigc::mem_fun(*this, &LPECloneOriginal::onExpanderChanged) ); vbox->pack_start(*expander, true, true, 2); - this->upd_params = false; return dynamic_cast<Gtk::Widget *>(vbox); } @@ -346,15 +340,15 @@ LPECloneOriginal::~LPECloneOriginal() void LPECloneOriginal::transform_multiply(Geom::Affine const& postmul, bool set) { - if (linked_item.linksToItem()) { - linked_item.getObject()->requestModified(SP_OBJECT_MODIFIED_FLAG); + if (linkeditem.linksToItem()) { + linkeditem.getObject()->requestModified(SP_OBJECT_MODIFIED_FLAG); } } void LPECloneOriginal::doEffect (SPCurve * curve) { - if (linked_item.linksToItem() && !inverse) { + if (linkeditem.linksToItem() && !inverse) { SPShape * shape = getCurrentShape(); if(shape){ curve->set_pathvector(shape->getCurve()->get_pathvector()); diff --git a/src/live_effects/lpe-clone-original.h b/src/live_effects/lpe-clone-original.h index e4328c169..9bab8553f 100644 --- a/src/live_effects/lpe-clone-original.h +++ b/src/live_effects/lpe-clone-original.h @@ -32,8 +32,7 @@ public: void cloneAttrbutes(SPObject *origin, SPObject *dest, bool live, const char * attributes, const char * style_attributes, bool root); private: - OriginalPathParam linked_path; - OriginalItemParam linked_item; + OriginalItemParam linkeditem; ScalarParam scale; BoolParam preserve_position; BoolParam inverse; diff --git a/src/live_effects/lpe-constructgrid.cpp b/src/live_effects/lpe-constructgrid.cpp index 8d24f9f47..db620fa95 100644 --- a/src/live_effects/lpe-constructgrid.cpp +++ b/src/live_effects/lpe-constructgrid.cpp @@ -24,8 +24,8 @@ LPEConstructGrid::LPEConstructGrid(LivePathEffectObject *lpeobject) : nr_x(_("Size _X:"), _("The size of the grid in X direction."), "nr_x", &wr, this, 5), nr_y(_("Size _Y:"), _("The size of the grid in Y direction."), "nr_y", &wr, this, 5) { - registerParameter( dynamic_cast<Parameter *>(&nr_x) ); - registerParameter( dynamic_cast<Parameter *>(&nr_y) ); + registerParameter(&nr_x); + registerParameter(&nr_y); nr_x.param_make_integer(); nr_y.param_make_integer(); diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index bf82b5deb..ffd2ef4cf 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -30,6 +30,14 @@ namespace Inkscape { namespace LivePathEffect { +static const Util::EnumData<RotateMethod> RotateMethodData[RM_END] = { + { RM_NORMAL, N_("Normal"), "normal" }, + { RM_KALEIDOSCOPE, N_("Kaleidoscope"), "kaleidoskope" }, + { RM_FUSE, N_("Fuse paths"), "fuse_paths" } +}; +static const Util::EnumDataConverter<RotateMethod> +RMConverter(RotateMethodData, RM_END); + bool pointInTriangle(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3) { @@ -52,30 +60,37 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) : starting_angle(_("Starting angle"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0), rotation_angle(_("Rotation angle"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 60.0), num_copies(_("Number of copies"), _("Number of copies of the original path"), "num_copies", &wr, this, 6), - split_gap(_("Gap on split"), _("Gap on split"), "split_gap", &wr, this, -0.001), + gap(_("Gap"), _("Gap"), "gap", &wr, this, -0.0001), copies_to_360(_("360º Copies"), _("No rotation angle, fixed to 360º"), "copies_to_360", &wr, this, true), - fuse_paths(_("Kaleidoskope"), _("Kaleidoskope by helper line, use fill-rule: evenodd for best result"), "fuse_paths", &wr, this, false), - join_paths(_("Join paths"), _("Join paths, use fill-rule: evenodd for best result"), "join_paths", &wr, this, false), + method(_("Method:"), _("Rotate methods"), "method", RMConverter, &wr, this, RM_NORMAL), + mirror_copies(_("Mirror copies"), _("Mirror between copies"), "mirror_copies", &wr, this, false), split_items(_("Split elements"), _("Split elements, this allow gradients and other paints."), "split_items", &wr, this, false), dist_angle_handle(100.0) { show_orig_path = true; _provides_knotholder_entities = true; + //0.92 compatibility + if (this->getRepr()->attribute("fuse_paths") && strcmp(this->getRepr()->attribute("fuse_paths"), "true") == 0){ + this->getRepr()->setAttribute("fuse_paths", NULL); + this->getRepr()->setAttribute("method", "kaleidoskope"); + this->getRepr()->setAttribute("mirror_copies", "true"); + }; // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter(&copies_to_360); - registerParameter(&fuse_paths); - registerParameter(&join_paths); - registerParameter(&split_items); + registerParameter(&method); + registerParameter(&num_copies); registerParameter(&starting_angle); registerParameter(&starting_point); registerParameter(&rotation_angle); - registerParameter(&num_copies); - registerParameter(&split_gap); + registerParameter(&gap); registerParameter(&origin); - split_gap.param_set_range(-999999.0, 999999.0); - split_gap.param_set_increments(0.1, 0.1); - split_gap.param_set_digits(5); - num_copies.param_set_range(0, 999999); + registerParameter(&copies_to_360); + registerParameter(&mirror_copies); + registerParameter(&split_items); + + gap.param_set_range(-99999.0, 99999.0); + gap.param_set_increments(0.1, 0.1); + gap.param_set_digits(5); + num_copies.param_set_range(1, 999999); num_copies.param_make_integer(true); apply_to_clippath_and_mask = true; previous_num_copies = num_copies; @@ -132,38 +147,21 @@ LPECopyRotate::doAfterEffect (SPLPEItem const* lpeitem) counter++; } g_free(id); - double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); - Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); - double size_divider = Geom::distance(origin,bbox) + (diagonal * 2); - Geom::Point line_start = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))) * size_divider; - Geom::Point line_end = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(rotation_angle + starting_angle))) * size_divider; Geom::Affine m = Geom::Translate(-origin) * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))); - if (fuse_paths) { - size_t rest = 0; - for (size_t i = 1; i < num_copies; ++i) { - Geom::Affine r = Geom::identity(); - Geom::Point dir = unit_vector((Geom::Point)origin - Geom::middle_point(line_start,line_end)); - if( rest%2 == 0) { - r *= Geom::Rotate(Geom::Angle(dir)).inverse(); - r *= Geom::Scale(1, -1); - r *= Geom::Rotate(Geom::Angle(dir)); - } - Geom::Rotate rot(-(Geom::rad_from_deg(rotation_angle * i))); - Geom::Affine t = m * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin); - if( rest%2 == 0) { - t = m * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)).inverse() * Geom::Translate(origin); - } - t *= sp_lpe_item->transform; - toItem(t, i-1, reset); - rest ++; + for (size_t i = 1; i < num_copies; ++i) { + Geom::Affine r = Geom::identity(); + if( i%2 != 0 && mirror_copies) { + r *= Geom::Rotate(Geom::Angle(half_dir)).inverse(); + r *= Geom::Scale(1, -1); + r *= Geom::Rotate(Geom::Angle(half_dir)); } - } else { - for (size_t i = 1; i < num_copies; ++i) { - Geom::Rotate rot(-(Geom::rad_from_deg(rotation_angle * i))); - Geom::Affine t = m * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin); - t *= sp_lpe_item->transform; - toItem(t, i - 1, reset); + Geom::Rotate rot(-(Geom::rad_from_deg(rotation_angle * i))); + Geom::Affine t = m * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin); + if( i%2 != 0 && mirror_copies) { + t = m * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)).inverse() * Geom::Translate(origin); } + t *= sp_lpe_item->transform; + toItem(t, i-1, reset); } reset = false; } else { @@ -302,15 +300,6 @@ Gtk::Widget * LPECopyRotate::newWidget() vbox->set_border_width(5); vbox->set_homogeneous(false); vbox->set_spacing(2); - Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0)); - Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox(Effect::newWidget()) ); - vbox_expander->set_border_width(0); - vbox_expander->set_spacing(2); - Gtk::Button * reset_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset styles")))); - reset_button->signal_clicked().connect(sigc::mem_fun (*this,&LPECopyRotate::resetStyles)); - reset_button->set_size_request(140,30); - vbox->pack_start(*hbox, true,true,2); - hbox->pack_start(*reset_button, false, false,2); std::vector<Parameter *>::iterator it = param_vector.begin(); while (it != param_vector.end()) { if ((*it)->widget_is_visible) { @@ -332,6 +321,12 @@ Gtk::Widget * LPECopyRotate::newWidget() ++it; } + Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0)); + Gtk::Button * reset_button = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset styles")))); + reset_button->signal_clicked().connect(sigc::mem_fun (*this,&LPECopyRotate::resetStyles)); + reset_button->set_size_request(110,20); + vbox->pack_start(*hbox, true,true,2); + hbox->pack_start(*reset_button, false, false,2); return dynamic_cast<Gtk::Widget *>(vbox); } @@ -344,7 +339,7 @@ LPECopyRotate::doOnApply(SPLPEItem const* lpeitem) A = Point(boundingbox_X.min(), boundingbox_Y.middle()); B = Point(boundingbox_X.middle(), boundingbox_Y.middle()); - origin.param_setValue(A, true); + origin.param_setValue(A); origin.param_update_default(A); dist_angle_handle = L2(B - A); dir = unit_vector(B - A); @@ -366,13 +361,14 @@ LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem) { using namespace Geom; original_bbox(lpeitem); - if (copies_to_360) { + if (copies_to_360 && num_copies > 2) { rotation_angle.param_set_value(360.0/(double)num_copies); } - if (fuse_paths && rotation_angle * num_copies > 360.1 && rotation_angle > 0) { + + if ((method == RM_KALEIDOSCOPE || method == RM_FUSE) && rotation_angle * num_copies > 360.1 && rotation_angle > 0) { num_copies.param_set_value(floor(360/rotation_angle)); } - if (fuse_paths && copies_to_360) { + if ((method == RM_KALEIDOSCOPE || method == RM_FUSE) && mirror_copies && copies_to_360) { num_copies.param_set_increments(2.0,10.0); if ((int)num_copies%2 !=0) { num_copies.param_set_value(num_copies+1); @@ -391,7 +387,7 @@ LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem) // I first suspected the minus sign to be a bug in 2geom but it is // likely due to SVG's choice of coordinate system orientation (max) bool near = Geom::are_near(previous_start_point, (Geom::Point)starting_point, 0.01); - if (!near) { + if (!near) { starting_angle.param_set_value(deg_from_rad(-angle_between(dir, starting_point - origin))); if (GDK_SHIFT_MASK) { dist_angle_handle = L2(B - A); @@ -405,11 +401,11 @@ LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem) start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * dist_angle_handle; rot_pos = origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle; near = Geom::are_near(start_pos, (Geom::Point)starting_point, 0.01); - if (!near) { - starting_point.param_setValue(start_pos, true); + if (!near) { + starting_point.param_setValue(start_pos); } previous_start_point = (Geom::Point)starting_point; - if ( fuse_paths || copies_to_360 ) { + if ( method == RM_FUSE || copies_to_360 ) { rot_pos = origin; } } @@ -486,19 +482,21 @@ LPECopyRotate::setFusion(Geom::PathVector &path_on, Geom::Path divider, double s } Geom::PathVector tmp_path_helper; Geom::Path append_path = original; - + Geom::Point previous = original.finalPoint(); for (int i = 0; i < num_copies; ++i) { Geom::Rotate rot(-Geom::rad_from_deg(rotation_angle * (i))); Geom::Affine m = pre * rot * Geom::Translate(origin); - if (i%2 != 0) { - Geom::Point A = (Geom::Point)origin; - Geom::Point B = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle*i)+starting_angle)) * size_divider; - Geom::Line ls(A,B); - m = Geom::reflection (ls.vector(), A); + if (i%2 != 0 && mirror_copies) { + Geom::Point point_a = (Geom::Point)origin; + Geom::Point point_b = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle*i)+starting_angle)) * size_divider; + Geom::Line ls(point_a, point_b); + m = Geom::reflection (ls.vector(), point_a); + append_path *= m; } else { append_path = original; + append_path *= m; } - append_path *= m; + previous = append_path.finalPoint(); if (tmp_path_helper.size() > 0) { if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(), append_path.finalPoint())) { Geom::Path tmp_append = append_path.reversed(); @@ -588,118 +586,83 @@ Geom::PathVector LPECopyRotate::doEffect_path (Geom::PathVector const & path_in) { Geom::PathVector path_out; - if (split_items && (fuse_paths || join_paths)) { + double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); + Geom::OptRect bbox = sp_lpe_item->geometricBounds(); + size_divider = Geom::distance(origin,bbox) + (diagonal * 6); + Geom::Point line_start = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))) * size_divider; + Geom::Point line_end = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(rotation_angle + starting_angle))) * size_divider; + divider = Geom::Path(line_start); + divider.appendNew<Geom::LineSegment>((Geom::Point)origin); + divider.appendNew<Geom::LineSegment>(line_end); + divider.close(); + half_dir = unit_vector(Geom::middle_point(line_start,line_end) - (Geom::Point)origin); + if (method == RM_KALEIDOSCOPE || method == RM_FUSE) { + if (method != RM_KALEIDOSCOPE) { + path_out = doEffect_path_post(path_in); + } else { + path_out = pathv_to_linear_and_cubic_beziers(path_in); + } if (num_copies == 0) { return path_out; } - path_out = pathv_to_linear_and_cubic_beziers(path_in); - double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); - Geom::OptRect bbox = sp_lpe_item->geometricBounds(); - double size_divider = Geom::distance(origin,bbox) + (diagonal * 2); - Geom::Point line_start = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(starting_angle))) * size_divider; - Geom::Point line_end = origin + dir * Geom::Rotate(-(Geom::rad_from_deg(rotation_angle + starting_angle))) * size_divider; - Geom::Path divider = Geom::Path(line_start); - divider.appendNew<Geom::LineSegment>((Geom::Point)origin); - divider.appendNew<Geom::LineSegment>(line_end); - divider.close(); Geom::PathVector triangle; triangle.push_back(divider); Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(triangle, path_out); - if (pig && ! path_out.empty() && !triangle.empty()) { - //TODO: Here can produce a crash because some knows problems in new boolops code + if (pig && !path_out.empty() && !triangle.empty()) { path_out = pig->getIntersection(); } - Geom::Affine r = Geom::identity(); - Geom::Point dir = unit_vector(Geom::middle_point(line_start,line_end) - (Geom::Point)origin); - Geom::Point gap = dir * split_gap; - path_out *= Geom::Translate(gap); - } else { - // default behavior - for (unsigned int i=0; i < path_in.size(); i++) { - Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_in = path_in[i].toPwSb(); - Geom::Piecewise<Geom::D2<Geom::SBasis> > pwd2_out = doEffect_pwd2(pwd2_in); - Geom::PathVector path = Geom::path_from_piecewise( pwd2_out, LPE_CONVERSION_TOLERANCE); - // add the output path vector to the already accumulated vector: - for (unsigned int j=0; j < path.size(); j++) { - path_out.push_back(path[j]); - } + path_out *= Geom::Translate(half_dir * gap); + if ( !split_items ) { + path_out *= Geom::Translate(half_dir * gap).inverse(); + path_out = doEffect_path_post(path_out); } + } else { + path_out = doEffect_path_post(path_in); } return pathv_to_linear_and_cubic_beziers(path_out); } -Geom::Piecewise<Geom::D2<Geom::SBasis> > -LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) +Geom::PathVector +LPECopyRotate::doEffect_path_post (Geom::PathVector const & path_in) { - using namespace Geom; - - if ((num_copies == 1 && !fuse_paths) || split_items) { - return pwd2_in; + if ((split_items || num_copies == 1) && method != RM_FUSE && method != RM_KALEIDOSCOPE) { + return path_in; } - double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); - Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); - double size_divider = Geom::distance(origin,bbox) + (diagonal * 2); - Geom::Point line_start = origin + dir * Rotate(-rad_from_deg(starting_angle)) * size_divider; - Geom::Point line_end = origin + dir * Rotate(-rad_from_deg(rotation_angle + starting_angle)) * size_divider; - //Note:: beter way to do this - //Whith AppendNew have problems whith the crossing order - Geom::Path divider = Geom::Path(line_start); - divider.appendNew<Geom::LineSegment>((Geom::Point)origin); - divider.appendNew<Geom::LineSegment>(line_end); - Piecewise<D2<SBasis> > output; - Affine pre = Translate(-origin) * Rotate(-rad_from_deg(starting_angle)); - PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001)); - if (fuse_paths) { - Geom::PathVector path_out; - Geom::PathVector tmp_path; - for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { - if (path_it->empty()) { - continue; - } - bool end_open = false; - if (path_it->closed()) { - const Geom::Curve &closingline = path_it->back_closed(); - if (!are_near(closingline.initialPoint(), closingline.finalPoint())) { - end_open = true; - } - } - Geom::Path original = (Geom::Path)(*path_it); - if (end_open && path_it->closed()) { - original.close(false); - original.appendNew<Geom::LineSegment>( original.initialPoint() ); - original.close(true); - } - tmp_path.push_back(original); - setFusion(tmp_path, divider, size_divider); - path_out.insert(path_out.end(), tmp_path.begin(), tmp_path.end()); - tmp_path.clear(); + Geom::Affine pre = Geom::Translate(-origin) * Geom::Rotate(-Geom::rad_from_deg(starting_angle)); + Geom::PathVector original_pathv = pathv_to_linear_and_cubic_beziers(path_in); + Geom::PathVector output_pv; + Geom::PathVector output; + for (int i = 0; i < num_copies; ++i) { + Geom::Rotate rot(-Geom::rad_from_deg(rotation_angle * i)); + Geom::Affine r = Geom::identity(); + if( i%2 != 0 && mirror_copies) { + r *= Geom::Rotate(Geom::Angle(half_dir)).inverse(); + r *= Geom::Scale(1, -1); + r *= Geom::Rotate(Geom::Angle(half_dir)); } - if (path_out.size()>0) { - output = paths_to_pw(path_out); + Geom::Affine t = pre * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)) * Geom::Translate(origin); + if(mirror_copies && i%2 != 0) { + t = pre * r * rot * Geom::Rotate(Geom::rad_from_deg(starting_angle)).inverse() * Geom::Translate(origin); } - } else { - Geom::PathVector output_pv; - for (int i = 0; i < num_copies; ++i) { - Rotate rot(-rad_from_deg(rotation_angle * i)); - Affine t = pre * rot * Translate(origin); - if (join_paths) { - Geom::PathVector join_pv = path_from_piecewise(pwd2_in * t , 0.01); - Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(output_pv, join_pv); - if (pig) { - if (!output_pv.empty()) { - output_pv = pig->getUnion(); - } else { - output_pv = join_pv; - } + if (method == RM_FUSE || method == RM_KALEIDOSCOPE) { + Geom::PathVector join_pv = original_pathv * t; + join_pv *= Geom::Translate(half_dir * rot * gap); + Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(output_pv, join_pv); + if (pig) { + if (!output_pv.empty()) { + output_pv = pig->getUnion(); + } else { + output_pv = join_pv; } - } else { - output.concat(pwd2_in * t); } + } else { + output_pv = path_in * t; + output.insert(output.end(), output_pv.begin(), output_pv.end()); } - if (join_paths) { - output = paths_to_pw(output_pv); - } + } + if (method == RM_FUSE || method == RM_KALEIDOSCOPE) { + output = output_pv; } return output; } diff --git a/src/live_effects/lpe-copy_rotate.h b/src/live_effects/lpe-copy_rotate.h index dbec2e1c3..542a4e36e 100644 --- a/src/live_effects/lpe-copy_rotate.h +++ b/src/live_effects/lpe-copy_rotate.h @@ -15,6 +15,7 @@ */ #include "live_effects/effect.h" +#include "live_effects/parameter/enum.h" #include "live_effects/parameter/parameter.h" #include "live_effects/parameter/text.h" #include "live_effects/parameter/point.h" @@ -23,13 +24,20 @@ namespace Inkscape { namespace LivePathEffect { +enum RotateMethod { + RM_NORMAL, + RM_KALEIDOSCOPE, + RM_FUSE, + RM_END +}; + class LPECopyRotate : public Effect, GroupBBoxEffect { public: LPECopyRotate(LivePathEffectObject *lpeobject); virtual ~LPECopyRotate(); virtual void doOnApply (SPLPEItem const* lpeitem); virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in); - virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); + Geom::PathVector doEffect_path_post (Geom::PathVector const & path_in); virtual void doBeforeEffect (SPLPEItem const* lpeitem); virtual void doAfterEffect (SPLPEItem const* lpeitem); virtual void setFusion(Geom::PathVector &path_in, Geom::Path divider, double sizeDivider); @@ -51,18 +59,21 @@ private: ScalarParam starting_angle; ScalarParam rotation_angle; ScalarParam num_copies; - ScalarParam split_gap; + ScalarParam gap; BoolParam copies_to_360; - BoolParam fuse_paths; - BoolParam join_paths; + EnumParam<RotateMethod> method; + BoolParam mirror_copies; BoolParam split_items; Geom::Point A; Geom::Point B; Geom::Point dir; + Geom::Point half_dir; Geom::Point start_pos; Geom::Point rot_pos; Geom::Point previous_start_point; double dist_angle_handle; + double size_divider; + Geom::Path divider; double previous_num_copies; bool reset; SPObject * container; diff --git a/src/live_effects/lpe-curvestitch.cpp b/src/live_effects/lpe-curvestitch.cpp index f2fc00aeb..f8d2e56ca 100644 --- a/src/live_effects/lpe-curvestitch.cpp +++ b/src/live_effects/lpe-curvestitch.cpp @@ -40,14 +40,14 @@ LPECurveStitch::LPECurveStitch(LivePathEffectObject *lpeobject) : prop_scale(_("Scale _width:"), _("Scale the width of the stitch path"), "prop_scale", &wr, this, 1), scale_y_rel(_("Scale _width relative to length"), _("Scale the width of the stitch path relative to its length"), "scale_y_rel", &wr, this, false) { - registerParameter( dynamic_cast<Parameter *>(&nrofpaths) ); - registerParameter( dynamic_cast<Parameter *>(&startpoint_edge_variation) ); - registerParameter( dynamic_cast<Parameter *>(&startpoint_spacing_variation) ); - registerParameter( dynamic_cast<Parameter *>(&endpoint_edge_variation) ); - registerParameter( dynamic_cast<Parameter *>(&endpoint_spacing_variation) ); - registerParameter( dynamic_cast<Parameter *>(&strokepath) ); - registerParameter( dynamic_cast<Parameter *>(&prop_scale) ); - registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) ); + registerParameter(&nrofpaths); + registerParameter(&startpoint_edge_variation); + registerParameter(&startpoint_spacing_variation); + registerParameter(&endpoint_edge_variation); + registerParameter(&endpoint_spacing_variation); + registerParameter(&strokepath ); + registerParameter(&prop_scale); + registerParameter(&scale_y_rel); nrofpaths.param_make_integer(); nrofpaths.param_set_range(2, Geom::infinity()); diff --git a/src/live_effects/lpe-dynastroke.cpp b/src/live_effects/lpe-dynastroke.cpp index 50bbe6451..33e754a8a 100644 --- a/src/live_effects/lpe-dynastroke.cpp +++ b/src/live_effects/lpe-dynastroke.cpp @@ -55,17 +55,17 @@ LPEDynastroke::LPEDynastroke(LivePathEffectObject *lpeobject) : capping(_("Capping:"), _("left capping"), "capping", &wr, this, "M 100,5 C 50,5 0,0 0,0 0,0 50,-5 100,-5") { - registerParameter( dynamic_cast<Parameter *>(& method) ); - registerParameter( dynamic_cast<Parameter *>(& width) ); - registerParameter( dynamic_cast<Parameter *>(& roundness) ); - registerParameter( dynamic_cast<Parameter *>(& angle) ); - //registerParameter( dynamic_cast<Parameter *>(& modulo_pi) ); - registerParameter( dynamic_cast<Parameter *>(& start_cap) ); - registerParameter( dynamic_cast<Parameter *>(& growfor) ); - registerParameter( dynamic_cast<Parameter *>(& end_cap) ); - registerParameter( dynamic_cast<Parameter *>(& fadefor) ); - registerParameter( dynamic_cast<Parameter *>(& round_ends) ); - registerParameter( dynamic_cast<Parameter *>(& capping) ); + registerParameter(&method); + registerParameter(&width); + registerParameter(&roundness); + registerParameter(&angle); + //registerParameter(&modulo_pi) ); + registerParameter(&start_cap); + registerParameter(&growfor); + registerParameter(&end_cap); + registerParameter(&fadefor); + registerParameter(&round_ends); + registerParameter(&capping); width.param_set_range(0, Geom::infinity()); roundness.param_set_range(0.01, 1); diff --git a/src/live_effects/lpe-envelope.cpp b/src/live_effects/lpe-envelope.cpp index 61a696435..8528ab14d 100644 --- a/src/live_effects/lpe-envelope.cpp +++ b/src/live_effects/lpe-envelope.cpp @@ -23,12 +23,12 @@ LPEEnvelope::LPEEnvelope(LivePathEffectObject *lpeobject) : xx(_("_Enable left & right paths"), _("Enable the left and right deformation paths"), "xx", &wr, this, true), yy(_("_Enable top & bottom paths"), _("Enable the top and bottom deformation paths"), "yy", &wr, this, true) { - registerParameter( dynamic_cast<Parameter *>(&yy) ); - registerParameter( dynamic_cast<Parameter *>(&xx) ); - registerParameter( dynamic_cast<Parameter *>(&bend_path1) ); - registerParameter( dynamic_cast<Parameter *>(&bend_path2) ); - registerParameter( dynamic_cast<Parameter *>(&bend_path3) ); - registerParameter( dynamic_cast<Parameter *>(&bend_path4) ); + registerParameter(&yy); + registerParameter(&xx); + registerParameter(&bend_path1); + registerParameter(&bend_path2); + registerParameter(&bend_path3); + registerParameter(&bend_path4); concatenate_before_pwd2 = true; apply_to_clippath_and_mask = true; } diff --git a/src/live_effects/lpe-extrude.cpp b/src/live_effects/lpe-extrude.cpp index daa30d45a..4a3ad7508 100644 --- a/src/live_effects/lpe-extrude.cpp +++ b/src/live_effects/lpe-extrude.cpp @@ -27,7 +27,7 @@ LPEExtrude::LPEExtrude(LivePathEffectObject *lpeobject) : show_orig_path = true; concatenate_before_pwd2 = false; - registerParameter( dynamic_cast<Parameter *>(&extrude_vector) ); + registerParameter(&extrude_vector); } LPEExtrude::~LPEExtrude() diff --git a/src/live_effects/lpe-fill-between-many.cpp b/src/live_effects/lpe-fill-between-many.cpp index 2e1fe0dc1..40fa91c68 100644 --- a/src/live_effects/lpe-fill-between-many.cpp +++ b/src/live_effects/lpe-fill-between-many.cpp @@ -25,11 +25,11 @@ LPEFillBetweenMany::LPEFillBetweenMany(LivePathEffectObject *lpeobject) : join(_("Join subpaths"), _("Join subpaths"), "join", &wr, this, true), close(_("Close"), _("Close path"), "close", &wr, this, true) { - registerParameter( dynamic_cast<Parameter *>(&linked_paths) ); - registerParameter( dynamic_cast<Parameter *>(&fuse) ); - registerParameter( dynamic_cast<Parameter *>(&allow_transforms) ); - registerParameter( dynamic_cast<Parameter *>(&join) ); - registerParameter( dynamic_cast<Parameter *>(&close) ); + registerParameter(&linked_paths); + registerParameter(&fuse); + registerParameter(&allow_transforms); + registerParameter(&join); + registerParameter(&close); transformmultiply = false; } diff --git a/src/live_effects/lpe-fill-between-strokes.cpp b/src/live_effects/lpe-fill-between-strokes.cpp index 43fef4288..f8d86ae99 100644 --- a/src/live_effects/lpe-fill-between-strokes.cpp +++ b/src/live_effects/lpe-fill-between-strokes.cpp @@ -25,13 +25,13 @@ LPEFillBetweenStrokes::LPEFillBetweenStrokes(LivePathEffectObject *lpeobject) : join(_("Join subpaths"), _("Join subpaths"), "join", &wr, this, true), close(_("Close"), _("Close path"), "close", &wr, this, true) { - registerParameter( dynamic_cast<Parameter *>(&linked_path) ); - registerParameter( dynamic_cast<Parameter *>(&second_path) ); - registerParameter( dynamic_cast<Parameter *>(&reverse_second) ); - registerParameter( dynamic_cast<Parameter *>(&fuse) ); - registerParameter( dynamic_cast<Parameter *>(&allow_transforms) ); - registerParameter( dynamic_cast<Parameter *>(&join) ); - registerParameter( dynamic_cast<Parameter *>(&close) ); + registerParameter(&linked_path); + registerParameter(&second_path); + registerParameter(&reverse_second); + registerParameter(&fuse); + registerParameter(&allow_transforms); + registerParameter(&join); + registerParameter(&close); transformmultiply = false; } diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp index 410d6f0fc..b9e96cb72 100644 --- a/src/live_effects/lpe-fillet-chamfer.cpp +++ b/src/live_effects/lpe-fillet-chamfer.cpp @@ -305,6 +305,8 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) } else { satellites_param.setHelperSize(helper_size); } + std::vector<size_t> selected_nodes_index; + size_t index = 0; for (size_t i = 0; i < satellites.size(); ++i) { for (size_t j = 0; j < satellites[i].size(); ++j) { if (satellites[i][j].is_time != flexible) { @@ -326,6 +328,11 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) satellites[i][j].has_mirror = mirror_knots; } satellites[i][j].hidden = hide_knots; + Geom::Curve const &curve_in = pathv[i][j]; + if (only_selected && isNodePointSelected(curve_in.initialPoint()) ){ + selected_nodes_index.push_back(index); + } + index ++; } } if (!_pathvector_satellites) { @@ -334,7 +341,6 @@ void LPEFilletChamfer::doBeforeEffect(SPLPEItem const *lpeItem) _pathvector_satellites->setPathVector(pathv); _pathvector_satellites->setSatellites(satellites); if (only_selected) { - setSelectedNodeIndex(pathv); _pathvector_satellites->setSelected(selected_nodes_index); } satellites_param.setPathVectorSatellites(_pathvector_satellites); diff --git a/src/live_effects/lpe-interpolate.cpp b/src/live_effects/lpe-interpolate.cpp index e95dc5f38..db3faa307 100644 --- a/src/live_effects/lpe-interpolate.cpp +++ b/src/live_effects/lpe-interpolate.cpp @@ -30,9 +30,9 @@ LPEInterpolate::LPEInterpolate(LivePathEffectObject *lpeobject) : { show_orig_path = true; - registerParameter( dynamic_cast<Parameter *>(&trajectory_path) ); - registerParameter( dynamic_cast<Parameter *>(&equidistant_spacing) ); - registerParameter( dynamic_cast<Parameter *>(&number_of_steps) ); + registerParameter(&trajectory_path); + registerParameter(&equidistant_spacing); + registerParameter(&number_of_steps); number_of_steps.param_make_integer(); number_of_steps.param_set_range(2, Geom::infinity()); diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 2defecb77..261612fdb 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -356,12 +356,12 @@ LPEKnot::LPEKnot(LivePathEffectObject *lpeobject) : switcher(0.,0.) { // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&interruption_width) ); - registerParameter( dynamic_cast<Parameter *>(&prop_to_stroke_width) ); - registerParameter( dynamic_cast<Parameter *>(&add_stroke_width) ); - registerParameter( dynamic_cast<Parameter *>(&add_other_stroke_width) ); - registerParameter( dynamic_cast<Parameter *>(&switcher_size) ); - registerParameter( dynamic_cast<Parameter *>(&crossing_points_vector) ); + registerParameter(&interruption_width); + registerParameter(&prop_to_stroke_width); + registerParameter(&add_stroke_width); + registerParameter(&add_other_stroke_width); + registerParameter(&switcher_size); + registerParameter(&crossing_points_vector); _provides_knotholder_entities = true; } diff --git a/src/live_effects/lpe-lattice.cpp b/src/live_effects/lpe-lattice.cpp index acffed000..124a7a9c6 100644 --- a/src/live_effects/lpe-lattice.cpp +++ b/src/live_effects/lpe-lattice.cpp @@ -50,22 +50,22 @@ LPELattice::LPELattice(LivePathEffectObject *lpeobject) : { // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&grid_point0) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point1) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point2) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point3) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point4) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point5) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point6) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point7) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point8) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point9) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point10) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point11) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point12) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point13) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point14) ); - registerParameter( dynamic_cast<Parameter *>(&grid_point15) ); + registerParameter(&grid_point0); + registerParameter(&grid_point1); + registerParameter(&grid_point2); + registerParameter(&grid_point3); + registerParameter(&grid_point4); + registerParameter(&grid_point5); + registerParameter(&grid_point6); + registerParameter(&grid_point7); + registerParameter(&grid_point8); + registerParameter(&grid_point9); + registerParameter(&grid_point10); + registerParameter(&grid_point11); + registerParameter(&grid_point12); + registerParameter(&grid_point13); + registerParameter(&grid_point14); + registerParameter(&grid_point15); apply_to_clippath_and_mask = true; } diff --git a/src/live_effects/lpe-line_segment.cpp b/src/live_effects/lpe-line_segment.cpp index cc024fb92..fd23da804 100644 --- a/src/live_effects/lpe-line_segment.cpp +++ b/src/live_effects/lpe-line_segment.cpp @@ -32,7 +32,7 @@ LPELineSegment::LPELineSegment(LivePathEffectObject *lpeobject) : end_type(_("End type:"), _("Determines on which side the line or line segment is infinite."), "end_type", EndTypeConverter, &wr, this, END_OPEN_BOTH) { /* register all your parameters here, so Inkscape knows which parameters this effect has: */ - registerParameter( dynamic_cast<Parameter *>(&end_type) ); + registerParameter(&end_type); } LPELineSegment::~LPELineSegment() diff --git a/src/live_effects/lpe-measure-line.cpp b/src/live_effects/lpe-measure-line.cpp index 86d72615c..892744462 100644 --- a/src/live_effects/lpe-measure-line.cpp +++ b/src/live_effects/lpe-measure-line.cpp @@ -49,32 +49,33 @@ static const Util::EnumDataConverter<OrientationMethod> OMConverter(OrientationM LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) : Effect(lpeobject), - unit(_("Unit*"), _("Unit"), "unit", &wr, this, "px"), - fontbutton(_("Font*"), _("Font Selector"), "fontbutton", &wr, this), + unit(_("Unit"), _("Unit"), "unit", &wr, this, "px"), + fontbutton(_("Font"), _("Font Selector"), "fontbutton", &wr, this), orientation(_("Orientation"), _("Orientation method"), "orientation", OMConverter, &wr, this, OM_PARALLEL, false), curve_linked(_("Curve on origin"), _("Curve on origin, set 0 to start/end"), "curve_linked", &wr, this, 1), - precision(_("Precision*"), _("Precision"), "precision", &wr, this, 2), - position(_("Position*"), _("Position"), "position", &wr, this, 5), - text_top_bottom(_("Text top/bottom*"), _("Text top/bottom"), "text_top_bottom", &wr, this, 0), - text_right_left(_("Text right/left*"), _("Text right/left"), "text_right_left", &wr, this, 0), - helpline_distance(_("Helpline distance*"), _("Helpline distance"), "helpline_distance", &wr, this, 0.0), - helpline_overlap(_("Helpline overlap*"), _("Helpline overlap"), "helpline_overlap", &wr, this, 2.0), - scale(_("Scale*"), _("Scaling factor"), "scale", &wr, this, 1.0), - format(_("Format*"), _("Format the number ex:{measure} {unit}, return to save"), "format", &wr, this,"{measure}{unit}"), + precision(_("Precision"), _("Precision"), "precision", &wr, this, 2), + position(_("Position"), _("Position"), "position", &wr, this, 5), + text_top_bottom(_("Text top/bottom"), _("Text top/bottom"), "text_top_bottom", &wr, this, 0), + text_right_left(_("Text right/left"), _("Text right/left"), "text_right_left", &wr, this, 0), + helpline_distance(_("Helpline distance"), _("Helpline distance"), "helpline_distance", &wr, this, 0.0), + helpline_overlap(_("Helpline overlap"), _("Helpline overlap"), "helpline_overlap", &wr, this, 2.0), + scale(_("Scale"), _("Scaling factor"), "scale", &wr, this, 1.0), + format(_("Format"), _("Format the number ex:{measure} {unit}, return to save"), "format", &wr, this,"{measure}{unit}"), id_origin("id_origin", "id_origin", "id_origin", &wr, this,""), arrows_outside(_("Arrows outside"), _("Arrows outside"), "arrows_outside", &wr, this, false), - flip_side(_("Flip side*"), _("Flip side"), "flip_side", &wr, this, false), - scale_sensitive(_("Scale sensitive*"), _("Costrained scale sensitive to transformed containers"), "scale_sensitive", &wr, this, true), - local_locale(_("Local Number Format*"), _("Local number format"), "local_locale", &wr, this, true), - line_group_05(_("Line Group 0.5*"), _("Line Group 0.5, from 0.7"), "line_group_05", &wr, this, true), - rotate_anotation(_("Rotate Anotation*"), _("Rotate Anotation"), "rotate_anotation", &wr, this, true), - hide_back(_("Hide if label over*"), _("Hide DIN line if label over"), "hide_back", &wr, this, true), - dimline_format(_("CSS DIN line*"), _("Override CSS to DIN line, return to save, empty to reset to DIM"), "dimline_format", &wr, this,""), - helperlines_format(_("CSS helpers*"), _("Override CSS to helper lines, return to save, empty to reset to DIM"), "helperlines_format", &wr, this,""), - anotation_format(_("CSS anotation*"), _("Override CSS to anotation text, return to save, empty to reset to DIM"), "anotation_format", &wr, this,""), - arrows_format(_("CSS arrows*"), _("Override CSS to arrows, return to save, empty to reset DIM"), "arrows_format", &wr, this,""), + flip_side(_("Flip side"), _("Flip side"), "flip_side", &wr, this, false), + scale_sensitive(_("Scale sensitive"), _("Costrained scale sensitive to transformed containers"), "scale_sensitive", &wr, this, true), + local_locale(_("Local Number Format"), _("Local number format"), "local_locale", &wr, this, true), + line_group_05(_("Line Group 0.5"), _("Line Group 0.5, from 0.7"), "line_group_05", &wr, this, true), + rotate_anotation(_("Rotate Anotation"), _("Rotate Anotation"), "rotate_anotation", &wr, this, true), + hide_back(_("Hide if label over"), _("Hide DIN line if label over"), "hide_back", &wr, this, true), + dimline_format(_("CSS DIN line"), _("Override CSS to DIN line, return to save, empty to reset to DIM"), "dimline_format", &wr, this,""), + helperlines_format(_("CSS helpers"), _("Override CSS to helper lines, return to save, empty to reset to DIM"), "helperlines_format", &wr, this,""), + anotation_format(_("CSS anotation"), _("Override CSS to anotation text, return to save, empty to reset to DIM"), "anotation_format", &wr, this,""), + arrows_format(_("CSS arrows"), _("Override CSS to arrows, return to save, empty to reset DIM"), "arrows_format", &wr, this,""), expanded(false) { + //set to true the parameters you want to be changed his default values registerParameter(&unit); registerParameter(&fontbutton); registerParameter(&orientation); @@ -99,39 +100,16 @@ LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) : registerParameter(&anotation_format); registerParameter(&arrows_format); registerParameter(&id_origin); + id_origin.param_hide_canvas_text(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - Glib::ustring fontbutton_value = prefs->getString("/live_effects/measure-line/fontbutton"); - if(fontbutton_value.empty()){ - fontbutton_value = "Sans 10"; - } - fontbutton.param_update_default(fontbutton_value); - scale.param_update_default(prefs->getDouble("/live_effects/measure-line/scale", 1.0)); - precision.param_update_default(prefs->getInt("/live_effects/measure-line/precision", 2)); - position.param_update_default(prefs->getDouble("/live_effects/measure-line/position", 10.0)); - text_top_bottom.param_update_default(prefs->getDouble("/live_effects/measure-line/text_top_bottom", 5.0)); - helpline_distance.param_update_default(prefs->getDouble("/live_effects/measure-line/helpline_distance", 0.0)); - helpline_overlap.param_update_default(prefs->getDouble("/live_effects/measure-line/helpline_overlap", 0.0)); - Glib::ustring unit_value = prefs->getString("/live_effects/measure-line/unit"); - if(unit_value.empty()){ - unit_value = "px"; - } - unit.param_update_default(unit_value); + Glib::ustring format_value = prefs->getString("/live_effects/measure-line/format"); if(format_value.empty()){ format_value = "{measure}{unit}"; } - format.param_update_default(format_value); - dimline_format.param_update_default(prefs->getString("/live_effects/measure-line/dimline_format")); - helperlines_format.param_update_default(prefs->getString("/live_effects/measure-line/helperlines_format")); - anotation_format.param_update_default(prefs->getString("/live_effects/measure-line/anotation_format")); - arrows_format.param_update_default(prefs->getString("/live_effects/measure-line/arrows_format")); - flip_side.param_update_default(prefs->getBool("/live_effects/measure-line/flip_side")); - scale_sensitive.param_update_default(prefs->getBool("/live_effects/measure-line/scale_sensitive")); - local_locale.param_update_default(prefs->getBool("/live_effects/measure-line/local_locale")); - line_group_05.param_update_default(prefs->getBool("/live_effects/measure-line/line_group_05")); - rotate_anotation.param_update_default(prefs->getBool("/live_effects/measure-line/rotate_anotation")); - hide_back.param_update_default(prefs->getBool("/live_effects/measure-line/hide_back")); + format.param_update_default(format_value.c_str()); + format.param_hide_canvas_text(); dimline_format.param_hide_canvas_text(); helperlines_format.param_hide_canvas_text(); @@ -375,7 +353,7 @@ LPEMeasureLine::createTextLabel(Geom::Point pos, double length, Geom::Coord angl items.push_back(id); Geom::OptRect bounds = SP_ITEM(elemref)->bounds(SPItem::GEOMETRIC_BBOX); if (bounds) { - anotation_width = bounds->width() * 1.4; + anotation_width = bounds->width() * 1.15; } } @@ -405,8 +383,14 @@ LPEMeasureLine::createLine(Geom::Point start,Geom::Point end, const char * id, b k = (Geom::distance(start,end)/2.0) - arrow_gap - (anotation_width/2.0); } if (Geom::distance(start,end) < anotation_width){ - return; + if ((elemref = document->getObjectById(id))) { + if (remove) { + elemref->deleteObject(); + } + return; + } } + //k = std::max(k , arrow_gap -1); Geom::Ray ray(end, start); Geom::Coord angle = ray.angle(); line_path.start(start); @@ -527,7 +511,6 @@ LPEMeasureLine::doBeforeEffect (SPLPEItem const* lpeitem) pathvector *= writed_transform; if ((Glib::ustring(format.param_getSVGValue()).empty())) { format.param_setValue(Glib::ustring("{measure}{unit}")); - this->upd_params = true; } size_t ncurves = pathvector.curveCount(); if (ncurves != (size_t)curve_linked.param_get_max()) { @@ -622,6 +605,9 @@ LPEMeasureLine::doBeforeEffect (SPLPEItem const* lpeitem) } bool overflow = false; const char * downline = g_strdup(Glib::ustring("downline-").append(this->getRepr()->attribute("id")).c_str()); + //delete residual lines if exist + createLine(Geom::Point(),Geom::Point(), downline, true, overflow, true, false); + //Create it if ((anotation_width/2) + std::abs(text_right_left) > Geom::distance(start,end)/2.0) { Geom::Point sstart = end - Point::polar(angle_cross, position); Geom::Point send = end - Point::polar(angle_cross, position); @@ -645,9 +631,6 @@ LPEMeasureLine::doBeforeEffect (SPLPEItem const* lpeitem) } overflow = true; createLine(sstart, prog_end, downline, true, overflow, false, false); - } else { - //erase it - createLine(Geom::Point(),Geom::Point(), downline, true, overflow, true, false); } //LINE arrow_gap = 8 * Inkscape::Util::Quantity::convert(0.35 / doc_scale, "mm", display_unit.c_str()); @@ -708,44 +691,41 @@ Gtk::Widget *LPEMeasureLine::newWidget() vbox->set_spacing(2); std::vector<Parameter *>::iterator it = param_vector.begin(); - Gtk::HBox * button1 = Gtk::manage(new Gtk::HBox(true,0)); Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox(Effect::newWidget()) ); vbox_expander->set_border_width(0); vbox_expander->set_spacing(2); while (it != param_vector.end()) { if ((*it)->widget_is_visible) { Parameter *param = *it; - Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); - Glib::ustring *tip = param->param_getTooltip(); - if (widg) { - if (param->param_key != "dimline_format" && - param->param_key != "helperlines_format" && - param->param_key != "arrows_format" && - param->param_key != "anotation_format") { - vbox->pack_start(*widg, true, true, 2); - } else { - vbox_expander->pack_start(*widg, true, true, 2); - } - if (tip) { - widg->set_tooltip_text(*tip); - } else { - widg->set_tooltip_text(""); - widg->set_has_tooltip(false); + if (param->param_key != "id_origin") { + Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget()); + Glib::ustring *tip = param->param_getTooltip(); + if (widg) { + if (param->param_key != "dimline_format" && + param->param_key != "helperlines_format" && + param->param_key != "arrows_format" && + param->param_key != "anotation_format") { + vbox->pack_start(*widg, true, true, 2); + } else { + vbox_expander->pack_start(*widg, true, true, 2); + } + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } } } } ++it; } - Gtk::Button *save_default = Gtk::manage(new Gtk::Button(Glib::ustring(_("Save '*' as default")))); - save_default->signal_clicked().connect(sigc::mem_fun(*this, &LPEMeasureLine::saveDefault)); - button1->pack_start(*save_default, true, true, 2); expander = Gtk::manage(new Gtk::Expander(Glib::ustring(_("Show DIM CSS style override")))); expander->add(*vbox_expander); expander->set_expanded(expanded); expander->property_expanded().signal_changed().connect(sigc::mem_fun(*this, &LPEMeasureLine::onExpanderChanged) ); vbox->pack_start(*expander, true, true, 2); - vbox->pack_start(*button1, true, true, 2); return dynamic_cast<Gtk::Widget *>(vbox); } @@ -766,31 +746,6 @@ LPEMeasureLine::doEffect_path(Geom::PathVector const &path_in) return path_in; } -void -LPEMeasureLine::saveDefault() -{ - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString("/live_effects/measure-line/fontbutton", Glib::ustring(fontbutton.param_getSVGValue())); - prefs->setDouble("/live_effects/measure-line/scale", scale); - prefs->setInt("/live_effects/measure-line/precision", precision); - prefs->setDouble("/live_effects/measure-line/position", position); - prefs->setDouble("/live_effects/measure-line/text_top_bottom", text_top_bottom); - prefs->setDouble("/live_effects/measure-line/helpline_distance", helpline_distance); - prefs->setDouble("/live_effects/measure-line/helpline_overlap", helpline_overlap); - prefs->setString("/live_effects/measure-line/unit", Glib::ustring(unit.get_abbreviation())); - prefs->setString("/live_effects/measure-line/format", Glib::ustring(format.param_getSVGValue())); - prefs->setString("/live_effects/measure-line/dimline_format", Glib::ustring(dimline_format.param_getSVGValue())); - prefs->setString("/live_effects/measure-line/helperlines_format", Glib::ustring(helperlines_format.param_getSVGValue())); - prefs->setString("/live_effects/measure-line/anotation_format", Glib::ustring(anotation_format.param_getSVGValue())); - prefs->setString("/live_effects/measure-line/arrows_format", Glib::ustring(arrows_format.param_getSVGValue())); - prefs->setBool("/live_effects/measure-line/flip_side", flip_side); - prefs->setBool("/live_effects/measure-line/scale_sensitive", scale_sensitive); - prefs->setBool("/live_effects/measure-line/local_locale", local_locale); - prefs->setBool("/live_effects/measure-line/line_group_05", line_group_05); - prefs->setBool("/live_effects/measure-line/rotate_anotation", rotate_anotation); - prefs->setBool("/live_effects/measure-line/hide_back", hide_back); -} - }; //namespace LivePathEffect }; /* namespace Inkscape */ diff --git a/src/live_effects/lpe-measure-line.h b/src/live_effects/lpe-measure-line.h index 724c0d924..b42f7cfd5 100644 --- a/src/live_effects/lpe-measure-line.h +++ b/src/live_effects/lpe-measure-line.h @@ -49,7 +49,6 @@ public: void createTextLabel(Geom::Point pos, double length, Geom::Coord angle, bool remove, bool valid); void onExpanderChanged(); void createArrowMarker(const char * mode); - void saveDefault(); virtual Gtk::Widget *newWidget(); private: UnitParam unit; diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index 97015c34d..4e93a2572 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -126,61 +126,61 @@ LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem) point_b = Geom::Point(center_point[X],boundingbox_Y.max()); } if ((Geom::Point)start_point == (Geom::Point)end_point) { - start_point.param_setValue(point_a, true); - end_point.param_setValue(point_b, true); + start_point.param_setValue(point_a); + end_point.param_setValue(point_b); previous_center = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); - center_point.param_setValue(previous_center, true); + center_point.param_setValue(previous_center); return; } if ( mode == MT_X || mode == MT_Y ) { if (!are_near(previous_center, (Geom::Point)center_point, 0.01)) { center_point.param_setValue(Geom::middle_point(point_a, point_b), true); - end_point.param_setValue(point_b, true); - start_point.param_setValue(point_a, true); + end_point.param_setValue(point_b); + start_point.param_setValue(point_a); } else { if ( mode == MT_X ) { if (!are_near(start_point[X], point_a[X], 0.01)) { - start_point.param_setValue(point_a, true); + start_point.param_setValue(point_a); } if (!are_near(end_point[X], point_b[X], 0.01)) { - end_point.param_setValue(point_b, true); + end_point.param_setValue(point_b); } } else { //MT_Y if (!are_near(start_point[Y], point_a[Y], 0.01)) { - start_point.param_setValue(point_a, true); + start_point.param_setValue(point_a); } if (!are_near(end_point[Y], point_b[Y], 0.01)) { - end_point.param_setValue(point_b, true); + end_point.param_setValue(point_b); } } } } else if ( mode == MT_FREE) { if (are_near(previous_center, (Geom::Point)center_point, 0.01)) { - center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point), true); + center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point)); } else { Geom::Point trans = center_point - Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point); - start_point.param_setValue(start_point * trans, true); - end_point.param_setValue(end_point * trans, true); + start_point.param_setValue(start_point * trans); + end_point.param_setValue(end_point * trans); } } else if ( mode == MT_V){ SPDocument * document = SP_ACTIVE_DOCUMENT; if (document) { Geom::Affine transform = i2anc_affine(SP_OBJECT(lpeitem), NULL).inverse(); Geom::Point sp = Geom::Point(document->getWidth().value("px")/2.0, 0) * transform; - start_point.param_setValue(sp, true); + start_point.param_setValue(sp); Geom::Point ep = Geom::Point(document->getWidth().value("px")/2.0, document->getHeight().value("px")) * transform; - end_point.param_setValue(ep, true); - center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point), true); + end_point.param_setValue(ep); + center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point)); } } else { //horizontal page SPDocument * document = SP_ACTIVE_DOCUMENT; if (document) { Geom::Affine transform = i2anc_affine(SP_OBJECT(lpeitem), NULL).inverse(); Geom::Point sp = Geom::Point(0, document->getHeight().value("px")/2.0) * transform; - start_point.param_setValue(sp, true); + start_point.param_setValue(sp); Geom::Point ep = Geom::Point(document->getWidth().value("px"), document->getHeight().value("px")/2.0) * transform; - end_point.param_setValue(ep, true); - center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point), true); + end_point.param_setValue(ep); + center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point)); } } previous_center = center_point; @@ -335,7 +335,6 @@ LPEMirrorSymmetry::newWidget() ++it; } - this->upd_params = false; return dynamic_cast<Gtk::Widget *>(vbox); } @@ -382,7 +381,7 @@ LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem) start_point.param_update_default(point_a); end_point.param_setValue(point_b); end_point.param_update_default(point_b); - center_point.param_setValue(point_c, true); + center_point.param_setValue(point_c); previous_center = center_point; SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem); if (!lpeitem->hasPathEffectOfType(this->effectType(), false) ){ //first applied not ready yet diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp index 057f404e0..a5d1d23c8 100644 --- a/src/live_effects/lpe-offset.cpp +++ b/src/live_effects/lpe-offset.cpp @@ -27,7 +27,7 @@ LPEOffset::LPEOffset(LivePathEffectObject *lpeobject) : { show_orig_path = true; apply_to_clippath_and_mask = true; - registerParameter(dynamic_cast<Parameter *>(&offset_pt)); + registerParameter(&offset_pt); } LPEOffset::~LPEOffset() @@ -39,7 +39,7 @@ LPEOffset::doOnApply(SPLPEItem const* lpeitem) { Geom::Point offset = *(SP_SHAPE(lpeitem)->_curve->first_point()); offset_pt.param_update_default(offset); - offset_pt.param_setValue(offset,true); + offset_pt.param_setValue(offset); } static void append_half_circle(Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2, diff --git a/src/live_effects/lpe-parallel.cpp b/src/live_effects/lpe-parallel.cpp index 276749c43..271442c7d 100644 --- a/src/live_effects/lpe-parallel.cpp +++ b/src/live_effects/lpe-parallel.cpp @@ -51,9 +51,9 @@ LPEParallel::LPEParallel(LivePathEffectObject *lpeobject) : show_orig_path = true; _provides_knotholder_entities = true; - registerParameter(dynamic_cast<Parameter *>(&offset_pt)); - registerParameter( dynamic_cast<Parameter *>(&length_left) ); - registerParameter( dynamic_cast<Parameter *>(&length_right) ); + registerParameter(&offset_pt); + registerParameter(&length_left); + registerParameter(&length_right); } LPEParallel::~LPEParallel() diff --git a/src/live_effects/lpe-path_length.cpp b/src/live_effects/lpe-path_length.cpp index a06dbde98..61818a73b 100644 --- a/src/live_effects/lpe-path_length.cpp +++ b/src/live_effects/lpe-path_length.cpp @@ -26,10 +26,10 @@ LPEPathLength::LPEPathLength(LivePathEffectObject *lpeobject) : unit(_("Unit:"), _("Unit"), "unit", &wr, this), display_unit(_("Display unit"), _("Print unit after path length"), "display_unit", &wr, this, true) { - registerParameter(dynamic_cast<Parameter *>(&scale)); - registerParameter(dynamic_cast<Parameter *>(&info_text)); - registerParameter(dynamic_cast<Parameter *>(&unit)); - registerParameter(dynamic_cast<Parameter *>(&display_unit)); + registerParameter(&scale); + registerParameter(&info_text); + registerParameter(&unit); + registerParameter(&display_unit); } LPEPathLength::~LPEPathLength() diff --git a/src/live_effects/lpe-patternalongpath.cpp b/src/live_effects/lpe-patternalongpath.cpp index 966e9020e..b026bbc22 100644 --- a/src/live_effects/lpe-patternalongpath.cpp +++ b/src/live_effects/lpe-patternalongpath.cpp @@ -85,16 +85,16 @@ LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) : fuse_tolerance(_("_Fuse nearby ends:"), _("Fuse ends closer than this number. 0 means don't fuse."), "fuse_tolerance", &wr, this, 0) { - registerParameter( dynamic_cast<Parameter *>(&pattern) ); - registerParameter( dynamic_cast<Parameter *>(©type) ); - registerParameter( dynamic_cast<Parameter *>(&prop_scale) ); - registerParameter( dynamic_cast<Parameter *>(&scale_y_rel) ); - registerParameter( dynamic_cast<Parameter *>(&spacing) ); - registerParameter( dynamic_cast<Parameter *>(&normal_offset) ); - registerParameter( dynamic_cast<Parameter *>(&tang_offset) ); - registerParameter( dynamic_cast<Parameter *>(&prop_units) ); - registerParameter( dynamic_cast<Parameter *>(&vertical_pattern) ); - registerParameter( dynamic_cast<Parameter *>(&fuse_tolerance) ); + registerParameter(&pattern); + registerParameter(©type); + registerParameter(&prop_scale); + registerParameter(&scale_y_rel); + registerParameter(&spacing); + registerParameter(&normal_offset); + registerParameter(&tang_offset); + registerParameter(&prop_units); + registerParameter(&vertical_pattern); + registerParameter(&fuse_tolerance); prop_scale.param_set_digits(3); prop_scale.param_set_increments(0.01, 0.10); diff --git a/src/live_effects/lpe-perp_bisector.cpp b/src/live_effects/lpe-perp_bisector.cpp index bce22250a..dab169cfe 100644 --- a/src/live_effects/lpe-perp_bisector.cpp +++ b/src/live_effects/lpe-perp_bisector.cpp @@ -99,8 +99,8 @@ LPEPerpBisector::LPEPerpBisector(LivePathEffectObject *lpeobject) : _provides_knotholder_entities = true; // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&length_left) ); - registerParameter( dynamic_cast<Parameter *>(&length_right) ); + registerParameter(&length_left); + registerParameter(&length_right); } LPEPerpBisector::~LPEPerpBisector() diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp index 365ff5389..3cff83fed 100644 --- a/src/live_effects/lpe-perspective-envelope.cpp +++ b/src/live_effects/lpe-perspective-envelope.cpp @@ -110,15 +110,15 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) int position_c = Geom::sgn(Geom::cross(handles[2] - handles[3], handles[0] - handles[3])); if (position_a != 1 && move0) { Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[0])); - down_left_point.param_setValue(point_a, true); + down_left_point.param_setValue(point_a); } if (position_b == 1 && move0) { Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[0])); - down_left_point.param_setValue(point_b, true); + down_left_point.param_setValue(point_b); } if (position_c == 1 && move0) { Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[0])); - down_left_point.param_setValue(point_c, true); + down_left_point.param_setValue(point_c); } line_a.setPoints(handles[0],handles[2]); line_b.setPoints(handles[2],handles[3]); @@ -128,15 +128,15 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) position_c = Geom::sgn(Geom::cross(handles[3] - handles[0], handles[1] - handles[0])); if (position_a != 1 && move1) { Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[1])); - up_left_point.param_setValue(point_a, true); + up_left_point.param_setValue(point_a); } if (position_b == 1 && move1) { Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[1])); - up_left_point.param_setValue(point_b, true); + up_left_point.param_setValue(point_b); } if (position_c == 1 && move1) { Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[1])); - up_left_point.param_setValue(point_c, true); + up_left_point.param_setValue(point_c); } line_a.setPoints(handles[1],handles[3]); line_b.setPoints(handles[3],handles[0]); @@ -146,15 +146,15 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) position_c = Geom::sgn(Geom::cross(handles[0] - handles[1], handles[2] - handles[1])); if (position_a != 1 && move2) { Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[2])); - up_right_point.param_setValue(point_a, true); + up_right_point.param_setValue(point_a); } if (position_b == 1 && move2) { Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[2])); - up_right_point.param_setValue(point_b, true); + up_right_point.param_setValue(point_b); } if (position_c == 1 && move2) { Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[2])); - up_right_point.param_setValue(point_c, true); + up_right_point.param_setValue(point_c); } line_a.setPoints(handles[2],handles[0]); line_b.setPoints(handles[0],handles[1]); @@ -164,15 +164,15 @@ void LPEPerspectiveEnvelope::doEffect(SPCurve *curve) position_c = Geom::sgn(Geom::cross(handles[1] - handles[2], handles[3] - handles[2])); if (position_a != 1 && move3) { Geom::Point point_a = line_a.pointAt(line_a.nearestTime(handles[3])); - down_right_point.param_setValue(point_a, true); + down_right_point.param_setValue(point_a); } if (position_b == 1 && move3) { Geom::Point point_b = line_b.pointAt(line_b.nearestTime(handles[3])); - down_right_point.param_setValue(point_b, true); + down_right_point.param_setValue(point_b); } if (position_c == 1 && move3) { Geom::Point point_c = line_c.pointAt(line_c.nearestTime(handles[3])); - down_right_point.param_setValue(point_c, true); + down_right_point.param_setValue(point_c); } } else { handles.resize(4); @@ -434,8 +434,8 @@ LPEPerspectiveEnvelope::vertical(PointParam ¶m_one, PointParam ¶m_two, G } A[Geom::X] = nearest[Geom::X] - distance_middle; B[Geom::X] = nearest[Geom::X] + distance_middle; - param_one.param_setValue(A, true); - param_two.param_setValue(B, true); + param_one.param_setValue(A); + param_two.param_setValue(B); } void @@ -455,8 +455,8 @@ LPEPerspectiveEnvelope::horizontal(PointParam ¶m_one, PointParam ¶m_two, } A[Geom::Y] = nearest[Geom::Y] - distance_middle; B[Geom::Y] = nearest[Geom::Y] + distance_middle; - param_one.param_setValue(A, true); - param_two.param_setValue(B, true); + param_one.param_setValue(A); + param_two.param_setValue(B); } void diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp index b83fb67d7..435c91c2d 100644 --- a/src/live_effects/lpe-perspective_path.cpp +++ b/src/live_effects/lpe-perspective_path.cpp @@ -51,11 +51,11 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) : uses_plane_xy(_("Uses XY plane?"), _("If true, put the path on the left side of an imaginary box, otherwise on the right side"), "uses_plane_xy", &wr, this, true) { // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter( dynamic_cast<Parameter *>(&scalex) ); - registerParameter( dynamic_cast<Parameter *>(&scaley) ); - registerParameter( dynamic_cast<Parameter *>(&offsetx) ); - registerParameter( dynamic_cast<Parameter *>(&offsety) ); - registerParameter( dynamic_cast<Parameter *>(&uses_plane_xy) ); + registerParameter( &scalex); + registerParameter( &scaley); + registerParameter( &offsetx); + registerParameter( &offsety); + registerParameter( &uses_plane_xy); concatenate_before_pwd2 = true; // don't split the path into its subpaths _provides_knotholder_entities = true; diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index e9f3975c7..d87f92fcc 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -179,14 +179,14 @@ LPEPowerStroke::LPEPowerStroke(LivePathEffectObject *lpeobject) : interpolator_beta.addSlider(true); interpolator_beta.param_set_range(0.,1.); - registerParameter( dynamic_cast<Parameter *>(&offset_points) ); - registerParameter( dynamic_cast<Parameter *>(&sort_points) ); - registerParameter( dynamic_cast<Parameter *>(&interpolator_type) ); - registerParameter( dynamic_cast<Parameter *>(&interpolator_beta) ); - registerParameter( dynamic_cast<Parameter *>(&start_linecap_type) ); - registerParameter( dynamic_cast<Parameter *>(&linejoin_type) ); - registerParameter( dynamic_cast<Parameter *>(&miter_limit) ); - registerParameter( dynamic_cast<Parameter *>(&end_linecap_type) ); + registerParameter(&offset_points); + registerParameter(&sort_points); + registerParameter(&interpolator_type); + registerParameter(&interpolator_beta); + registerParameter(&start_linecap_type); + registerParameter(&linejoin_type); + registerParameter(&miter_limit); + registerParameter(&end_linecap_type); } LPEPowerStroke::~LPEPowerStroke() diff --git a/src/live_effects/lpe-recursiveskeleton.cpp b/src/live_effects/lpe-recursiveskeleton.cpp index aa0db920b..47613f58e 100644 --- a/src/live_effects/lpe-recursiveskeleton.cpp +++ b/src/live_effects/lpe-recursiveskeleton.cpp @@ -28,7 +28,7 @@ LPERecursiveSkeleton::LPERecursiveSkeleton(LivePathEffectObject *lpeobject) : concatenate_before_pwd2 = true; iterations.param_make_integer(true); iterations.param_set_range(1, 15); - registerParameter( dynamic_cast<Parameter *>(&iterations) ); + registerParameter(&iterations); } diff --git a/src/live_effects/lpe-rough-hatches.cpp b/src/live_effects/lpe-rough-hatches.cpp index 3cc8658ea..d832b3615 100644 --- a/src/live_effects/lpe-rough-hatches.cpp +++ b/src/live_effects/lpe-rough-hatches.cpp @@ -241,26 +241,26 @@ LPERoughHatches::LPERoughHatches(LivePathEffectObject *lpeobject) : // bender(_("Global bending"), _("Relative position to a reference point defines global bending direction and amount"), "bender", &wr, this, Geom::Point(-5,0)) { - registerParameter( dynamic_cast<Parameter *>(&direction) ); - registerParameter( dynamic_cast<Parameter *>(&dist_rdm) ); - registerParameter( dynamic_cast<Parameter *>(&growth) ); - registerParameter( dynamic_cast<Parameter *>(&do_bend) ); - registerParameter( dynamic_cast<Parameter *>(&bender) ); - registerParameter( dynamic_cast<Parameter *>(&top_edge_variation) ); - registerParameter( dynamic_cast<Parameter *>(&bot_edge_variation) ); - registerParameter( dynamic_cast<Parameter *>(&top_tgt_variation) ); - registerParameter( dynamic_cast<Parameter *>(&bot_tgt_variation) ); - registerParameter( dynamic_cast<Parameter *>(&scale_tf) ); - registerParameter( dynamic_cast<Parameter *>(&scale_tb) ); - registerParameter( dynamic_cast<Parameter *>(&scale_bf) ); - registerParameter( dynamic_cast<Parameter *>(&scale_bb) ); - registerParameter( dynamic_cast<Parameter *>(&top_smth_variation) ); - registerParameter( dynamic_cast<Parameter *>(&bot_smth_variation) ); - registerParameter( dynamic_cast<Parameter *>(&fat_output) ); - registerParameter( dynamic_cast<Parameter *>(&stroke_width_top) ); - registerParameter( dynamic_cast<Parameter *>(&stroke_width_bot) ); - registerParameter( dynamic_cast<Parameter *>(&front_thickness) ); - registerParameter( dynamic_cast<Parameter *>(&back_thickness) ); + registerParameter(&direction); + registerParameter(&dist_rdm); + registerParameter(&growth); + registerParameter(&do_bend); + registerParameter(&bender); + registerParameter(&top_edge_variation); + registerParameter(&bot_edge_variation); + registerParameter(&top_tgt_variation); + registerParameter(&bot_tgt_variation); + registerParameter(&scale_tf); + registerParameter(&scale_tb); + registerParameter(&scale_bf); + registerParameter(&scale_bb); + registerParameter(&top_smth_variation); + registerParameter(&bot_smth_variation); + registerParameter(&fat_output); + registerParameter(&stroke_width_top); + registerParameter(&stroke_width_bot); + registerParameter(&front_thickness); + registerParameter(&back_thickness); //hatch_dist.param_set_range(0.1, Geom::infinity()); growth.param_set_range(0, Geom::infinity()); diff --git a/src/live_effects/lpe-ruler.cpp b/src/live_effects/lpe-ruler.cpp index 60c2a3e1c..852592219 100644 --- a/src/live_effects/lpe-ruler.cpp +++ b/src/live_effects/lpe-ruler.cpp @@ -45,15 +45,15 @@ LPERuler::LPERuler(LivePathEffectObject *lpeobject) : offset(_("_Offset:"), _("Offset of first mark"), "offset", &wr, this, 0.0), border_marks(_("Border marks:"), _("Choose whether to draw marks at the beginning and end of the path"), "border_marks", BorderMarkTypeConverter, &wr, this, BORDERMARK_BOTH) { - registerParameter(dynamic_cast<Parameter *>(&unit)); - registerParameter(dynamic_cast<Parameter *>(&mark_distance)); - registerParameter(dynamic_cast<Parameter *>(&mark_length)); - registerParameter(dynamic_cast<Parameter *>(&minor_mark_length)); - registerParameter(dynamic_cast<Parameter *>(&major_mark_steps)); - registerParameter(dynamic_cast<Parameter *>(&shift)); - registerParameter(dynamic_cast<Parameter *>(&offset)); - registerParameter(dynamic_cast<Parameter *>(&mark_dir)); - registerParameter(dynamic_cast<Parameter *>(&border_marks)); + registerParameter(&unit); + registerParameter(&mark_distance); + registerParameter(&mark_length); + registerParameter(&minor_mark_length); + registerParameter(&major_mark_steps); + registerParameter(&shift); + registerParameter(&offset); + registerParameter(&mark_dir); + registerParameter(&border_marks); major_mark_steps.param_make_integer(); major_mark_steps.param_set_range(1, 1000); diff --git a/src/live_effects/lpe-skeleton.cpp b/src/live_effects/lpe-skeleton.cpp index 4fc18cee2..d3c94269a 100644 --- a/src/live_effects/lpe-skeleton.cpp +++ b/src/live_effects/lpe-skeleton.cpp @@ -37,7 +37,7 @@ LPESkeleton::LPESkeleton(LivePathEffectObject *lpeobject) : //_provides_knotholder_entities /* register all your parameters here, so Inkscape knows which parameters this effect has: */ - registerParameter( dynamic_cast<Parameter *>(&number) ); + registerParameter(&number); } LPESkeleton::~LPESkeleton() diff --git a/src/live_effects/lpe-sketch.cpp b/src/live_effects/lpe-sketch.cpp index e01516f2e..e3376b7e5 100644 --- a/src/live_effects/lpe-sketch.cpp +++ b/src/live_effects/lpe-sketch.cpp @@ -62,25 +62,25 @@ LPESketch::LPESketch(LivePathEffectObject *lpeobject) : // register all your parameters here, so Inkscape knows which parameters this effect has: //Add some comment in the UI: *warning* the precise output of this effect might change in future releases! //convert to path if you want to keep exact output unchanged in future releases... - //registerParameter( dynamic_cast<Parameter *>(&testpointA) ); - registerParameter( dynamic_cast<Parameter *>(&nbiter_approxstrokes) ); - registerParameter( dynamic_cast<Parameter *>(&strokelength) ); - registerParameter( dynamic_cast<Parameter *>(&strokelength_rdm) ); - registerParameter( dynamic_cast<Parameter *>(&strokeoverlap) ); - registerParameter( dynamic_cast<Parameter *>(&strokeoverlap_rdm) ); - registerParameter( dynamic_cast<Parameter *>(&ends_tolerance) ); - registerParameter( dynamic_cast<Parameter *>(¶llel_offset) ); - registerParameter( dynamic_cast<Parameter *>(&tremble_size) ); - registerParameter( dynamic_cast<Parameter *>(&tremble_frequency) ); + //registerParameter(&testpointA) ); + registerParameter(&nbiter_approxstrokes); + registerParameter(&strokelength); + registerParameter(&strokelength_rdm); + registerParameter(&strokeoverlap); + registerParameter(&strokeoverlap_rdm); + registerParameter(&ends_tolerance); + registerParameter(¶llel_offset); + registerParameter(&tremble_size); + registerParameter(&tremble_frequency); #ifdef LPE_SKETCH_USE_CONSTRUCTION_LINES - registerParameter( dynamic_cast<Parameter *>(&nbtangents) ); - registerParameter( dynamic_cast<Parameter *>(&tgt_places_rdmness) ); - registerParameter( dynamic_cast<Parameter *>(&tgtscale) ); - registerParameter( dynamic_cast<Parameter *>(&tgtlength) ); - registerParameter( dynamic_cast<Parameter *>(&tgtlength_rdm) ); + registerParameter(&nbtangents); + registerParameter(&tgt_places_rdmness); + registerParameter(&tgtscale); + registerParameter(&tgtlength); + registerParameter(&tgtlength_rdm); #ifdef LPE_SKETCH_USE_CURVATURE - registerParameter( dynamic_cast<Parameter *>(&min_curvature) ); - registerParameter( dynamic_cast<Parameter *>(&max_curvature) ); + registerParameter(&min_curvature); + registerParameter(&max_curvature); #endif #endif diff --git a/src/live_effects/lpe-tangent_to_curve.cpp b/src/live_effects/lpe-tangent_to_curve.cpp index 5f63e1ee9..69a4dfad9 100644 --- a/src/live_effects/lpe-tangent_to_curve.cpp +++ b/src/live_effects/lpe-tangent_to_curve.cpp @@ -60,10 +60,10 @@ LPETangentToCurve::LPETangentToCurve(LivePathEffectObject *lpeobject) : show_orig_path = true; _provides_knotholder_entities = true; - registerParameter( dynamic_cast<Parameter *>(&angle) ); - registerParameter( dynamic_cast<Parameter *>(&t_attach) ); - registerParameter( dynamic_cast<Parameter *>(&length_left) ); - registerParameter( dynamic_cast<Parameter *>(&length_right) ); + registerParameter(&angle); + registerParameter(&t_attach); + registerParameter(&length_left); + registerParameter(&length_right); } LPETangentToCurve::~LPETangentToCurve() diff --git a/src/live_effects/lpe-test-doEffect-stack.cpp b/src/live_effects/lpe-test-doEffect-stack.cpp index 324893706..c484c88a2 100644 --- a/src/live_effects/lpe-test-doEffect-stack.cpp +++ b/src/live_effects/lpe-test-doEffect-stack.cpp @@ -21,12 +21,12 @@ LPEdoEffectStackTest::LPEdoEffectStackTest(LivePathEffectObject *lpeobject) : point(_("Point param:"), "tooltip of point parameter", "point_param", &wr, this), path(_("Path param:"), "tooltip of path parameter", "path_param", &wr, this,"M 0,100 100,0") { - registerParameter( dynamic_cast<Parameter *>(&step) ); - registerParameter( dynamic_cast<Parameter *>(&point) ); - registerParameter( dynamic_cast<Parameter *>(&path) ); + registerParameter(&step); + registerParameter(&point); + registerParameter(&path); point.set_oncanvas_looks(SP_KNOT_SHAPE_SQUARE, SP_KNOT_MODE_XOR, 0x00ff0000); - point.param_setValue(point,true); + point.param_setValue(point); } LPEdoEffectStackTest::~LPEdoEffectStackTest() diff --git a/src/live_effects/lpe-text_label.cpp b/src/live_effects/lpe-text_label.cpp index 709d05e18..0c1db2f04 100644 --- a/src/live_effects/lpe-text_label.cpp +++ b/src/live_effects/lpe-text_label.cpp @@ -23,7 +23,7 @@ LPETextLabel::LPETextLabel(LivePathEffectObject *lpeobject) : Effect(lpeobject), label(_("Label:"), _("Text label attached to the path"), "label", &wr, this, "This is a label") { - registerParameter( dynamic_cast<Parameter *>(&label) ); + registerParameter(&label); } LPETextLabel::~LPETextLabel() diff --git a/src/live_effects/lpe-transform_2pts.cpp b/src/live_effects/lpe-transform_2pts.cpp index ef2900775..f4d233d56 100644 --- a/src/live_effects/lpe-transform_2pts.cpp +++ b/src/live_effects/lpe-transform_2pts.cpp @@ -138,14 +138,22 @@ LPETransform2Pts::doBeforeEffect (SPLPEItem const* lpeitem) size_t nnodes = nodeCount(pathvector); first_knot.param_set_range(1, last_knot-1); last_knot.param_set_range(first_knot+1, nnodes); - from_original_width.param_setValue(false); + if (from_original_width){ + from_original_width.param_setValue(false); + } } else { - first_knot.param_set_value(1); - last_knot.param_set_value(2); + if (first_knot != 1){ + first_knot.param_set_value(1); + } + if (last_knot != 2){ + last_knot.param_set_value(2); + } first_knot.param_set_range(1,1); last_knot.param_set_range(2,2); - from_original_width.param_setValue(true); append_path = false; + if (!from_original_width){ + from_original_width.param_setValue(true); + } } if(lock_lenght && !lock_angle && previous_lenght != -1) { Geom::Ray transformed((Geom::Point)start,(Geom::Point)end); @@ -251,6 +259,8 @@ LPETransform2Pts::reset() first_knot.param_set_value(1); last_knot.param_set_value(2); } + offset.param_set_value(0.0); + stretch.param_set_value(1.0); Geom::Ray transformed(point_a, point_b); previous_angle = transformed.angle(); previous_lenght = Geom::distance(point_a, point_b); diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp index 47e2a1cec..b9fd8908a 100644 --- a/src/live_effects/lpe-vonkoch.cpp +++ b/src/live_effects/lpe-vonkoch.cpp @@ -53,15 +53,15 @@ LPEVonKoch::LPEVonKoch(LivePathEffectObject *lpeobject) : maxComplexity(_("_Max complexity:"), _("Disable effect if the output is too complex"), "maxComplexity", &wr, this, 1000) { //FIXME: a path is used here instead of 2 points to work around path/point param incompatibility bug. - registerParameter( dynamic_cast<Parameter *>(&ref_path) ); - //registerParameter( dynamic_cast<Parameter *>(&refA) ); - //registerParameter( dynamic_cast<Parameter *>(&refB) ); - registerParameter( dynamic_cast<Parameter *>(&generator) ); - registerParameter( dynamic_cast<Parameter *>(&similar_only) ); - registerParameter( dynamic_cast<Parameter *>(&nbgenerations) ); - registerParameter( dynamic_cast<Parameter *>(&drawall) ); - registerParameter( dynamic_cast<Parameter *>(&maxComplexity) ); - //registerParameter( dynamic_cast<Parameter *>(&draw_boxes) ); + registerParameter(&ref_path); + //registerParameter(&refA) ); + //registerParameter(&refB) ); + registerParameter(&generator); + registerParameter(&similar_only); + registerParameter(&nbgenerations); + registerParameter(&drawall); + registerParameter(&maxComplexity); + //registerParameter(&draw_boxes) ); apply_to_clippath_and_mask = true; nbgenerations.param_make_integer(); nbgenerations.param_set_range(0, Geom::infinity()); diff --git a/src/live_effects/parameter/array.h b/src/live_effects/parameter/array.h index 9204ede1f..10a3ea018 100644 --- a/src/live_effects/parameter/array.h +++ b/src/live_effects/parameter/array.h @@ -60,7 +60,7 @@ public: g_strfreev (strarray); return true; } - + virtual void param_update_default(const gchar * default_value){}; virtual gchar * param_getSVGValue() const { Inkscape::SVGOStringStream os; writesvg(os, _vector); diff --git a/src/live_effects/parameter/bool.cpp b/src/live_effects/parameter/bool.cpp index 813c06b4e..9cb91bdd6 100644 --- a/src/live_effects/parameter/bool.cpp +++ b/src/live_effects/parameter/bool.cpp @@ -42,6 +42,12 @@ BoolParam::param_update_default(bool const default_value) defvalue = default_value; } +void +BoolParam::param_update_default(const gchar * default_value) +{ + param_update_default(helperfns_read_bool(default_value, defvalue)); +} + bool BoolParam::param_readSVGValue(const gchar * strvalue) { @@ -72,7 +78,6 @@ BoolParam::param_newWidget() checkwdg->setActive(value); checkwdg->setProgrammatically = false; checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change bool parameter")); - param_effect->upd_params = false; return dynamic_cast<Gtk::Widget *> (checkwdg); } else { return NULL; diff --git a/src/live_effects/parameter/bool.h b/src/live_effects/parameter/bool.h index 7ad8a9368..39f328eaa 100644 --- a/src/live_effects/parameter/bool.h +++ b/src/live_effects/parameter/bool.h @@ -37,8 +37,8 @@ public: void param_setValue(bool newvalue); virtual void param_set_default(); void param_update_default(bool const default_value); + virtual void param_update_default(const gchar * default_value); bool get_value() const { return value; }; - inline operator bool() const { return value; }; private: diff --git a/src/live_effects/parameter/enum.h b/src/live_effects/parameter/enum.h index dbfc68623..6cadd6953 100644 --- a/src/live_effects/parameter/enum.h +++ b/src/live_effects/parameter/enum.h @@ -76,8 +76,17 @@ public: void param_set_default() { param_set_value(defvalue); } - + + void param_update_default(E default_value) { + defvalue = default_value; + } + + virtual void param_update_default(const gchar * default_value) { + param_update_default(enumdataconv->get_id_from_key(Glib::ustring(default_value))); + } + void param_set_value(E val) { + param_effect->upd_params = true; value = val; } diff --git a/src/live_effects/parameter/fontbutton.cpp b/src/live_effects/parameter/fontbutton.cpp index 64c203093..5add69c1d 100644 --- a/src/live_effects/parameter/fontbutton.cpp +++ b/src/live_effects/parameter/fontbutton.cpp @@ -33,9 +33,11 @@ FontButtonParam::param_set_default() { param_setValue(defvalue); } + void -FontButtonParam::param_update_default(const Glib::ustring default_value){ - defvalue = default_value; +FontButtonParam::param_update_default(const gchar * default_value) +{ + defvalue = (Glib::ustring)strdup(default_value); } bool @@ -66,16 +68,17 @@ FontButtonParam::param_newWidget() Glib::ustring fontspec = param_getSVGValue(); fontbuttonwdg->setValue( fontspec); fontbuttonwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change font button parameter")); - param_effect->upd_params = false; return dynamic_cast<Gtk::Widget *> (fontbuttonwdg); } void FontButtonParam::param_setValue(const Glib::ustring newvalue) { + param_effect->upd_params = true; value = newvalue; } + } /* namespace LivePathEffect */ } /* namespace Inkscape */ diff --git a/src/live_effects/parameter/fontbutton.h b/src/live_effects/parameter/fontbutton.h index df47251a2..60e1aa46e 100644 --- a/src/live_effects/parameter/fontbutton.h +++ b/src/live_effects/parameter/fontbutton.h @@ -21,15 +21,15 @@ public: const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, Effect* effect, - const Glib::ustring default_value = ""); + const Glib::ustring default_value = "Sans 10"); virtual ~FontButtonParam() {} virtual Gtk::Widget * param_newWidget(); virtual bool param_readSVGValue(const gchar * strvalue); - void param_update_default(const Glib::ustring defvalue); + void param_update_default(const gchar * default_value); virtual gchar * param_getSVGValue() const; - void param_setValue(const Glib::ustring newvalue); + void param_setValue(Glib::ustring newvalue); virtual void param_set_default(); diff --git a/src/live_effects/parameter/item.cpp b/src/live_effects/parameter/item.cpp index 93cf2b15f..7b40f4540 100644 --- a/src/live_effects/parameter/item.cpp +++ b/src/live_effects/parameter/item.cpp @@ -60,6 +60,10 @@ ItemParam::param_set_default() param_readSVGValue(defvalue); } +void +ItemParam::param_update_default(const gchar * default_value){ + defvalue = strdup(default_value); +} void ItemParam::param_set_and_write_default() diff --git a/src/live_effects/parameter/item.h b/src/live_effects/parameter/item.h index 6c719d451..89c32f9bd 100644 --- a/src/live_effects/parameter/item.h +++ b/src/live_effects/parameter/item.h @@ -36,6 +36,7 @@ public: virtual gchar * param_getSVGValue() const; virtual void param_set_default(); + virtual void param_update_default(const gchar * default_value); void param_set_and_write_default(); virtual void addCanvasIndicators(SPLPEItem const* lpeitem, std::vector<Geom::PathVector> &hp_vec); diff --git a/src/live_effects/parameter/originalpatharray.h b/src/live_effects/parameter/originalpatharray.h index 296c0f7f7..fe9371644 100644 --- a/src/live_effects/parameter/originalpatharray.h +++ b/src/live_effects/parameter/originalpatharray.h @@ -65,12 +65,11 @@ public: virtual bool param_readSVGValue(const gchar * strvalue); virtual gchar * param_getSVGValue() const; virtual void param_set_default(); - + virtual void param_update_default(const gchar * default_value){}; /** Disable the canvas indicators of parent class by overriding this method */ virtual void param_editOncanvas(SPItem * /*item*/, SPDesktop * /*dt*/) {}; /** Disable the canvas indicators of parent class by overriding this method */ virtual void addCanvasIndicators(SPLPEItem const* /*lpeitem*/, std::vector<Geom::PathVector> & /*hp_vec*/) {}; - std::vector<PathAndDirection*> _vector; protected: diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index befac4df1..1c1063960 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -39,6 +39,7 @@ Parameter::Parameter( const Glib::ustring& label, const Glib::ustring& tip, void Parameter::param_write_to_repr(const char * svgd) { + param_effect->upd_params = true; param_effect->getRepr()->setAttribute(param_key.c_str(), svgd); } @@ -107,6 +108,16 @@ ScalarParam::param_update_default(gdouble default_value) defvalue = default_value; } +void +ScalarParam::param_update_default(const gchar * default_value) +{ + double newval; + unsigned int success = sp_svg_number_read_d(default_value, &newval); + if (success == 1) { + param_update_default(newval); + } +} + void ScalarParam::param_set_value(gdouble val) { @@ -128,7 +139,6 @@ ScalarParam::param_set_range(gdouble min, gdouble max) // Once again, in gtk2, this is not a problem. But in gtk3, // widgets get allocated the amount of size they ask for, // leading to excessively long widgets. - param_effect->upd_params = true; if (min >= -SCALARPARAM_G_MAXDOUBLE) { this->min = min; } else { @@ -145,7 +155,6 @@ ScalarParam::param_set_range(gdouble min, gdouble max) void ScalarParam::param_make_integer(bool yes) { - param_effect->upd_params = true; integer = yes; digits = 0; inc_step = 1; @@ -176,7 +185,6 @@ ScalarParam::param_newWidget() if(!overwrite_widget){ rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); } - param_effect->upd_params = false; return dynamic_cast<Gtk::Widget *> (rsu); } else { return NULL; @@ -186,14 +194,12 @@ ScalarParam::param_newWidget() void ScalarParam::param_set_digits(unsigned digits) { - param_effect->upd_params = true; this->digits = digits; } void ScalarParam::param_set_increments(double step, double page) { - param_effect->upd_params = true; inc_step = step; inc_page = page; } diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index 6cf10710c..ee1d2d547 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -60,7 +60,7 @@ public: void write_to_SVG(); virtual void param_set_default() = 0; - + virtual void param_update_default(const gchar * default_value) = 0; // This creates a new widget (newed with Gtk::manage(new ...);) virtual Gtk::Widget * param_newWidget() = 0; @@ -77,6 +77,7 @@ public: virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/) {}; Glib::ustring param_key; + Glib::ustring param_tooltip; Inkscape::UI::Widget::Registry * param_wr; Glib::ustring param_label; @@ -84,7 +85,6 @@ public: bool widget_is_visible; protected: - Glib::ustring param_tooltip; Effect* param_effect; @@ -112,6 +112,7 @@ public: virtual void param_set_default(); void param_update_default(gdouble default_value); + virtual void param_update_default(const gchar * default_value); void param_set_value(gdouble val); void param_make_integer(bool yes = true); void param_set_range(gdouble min, gdouble max); @@ -120,7 +121,6 @@ public: void addSlider(bool add_slider_widget) { add_slider = add_slider_widget; }; double param_get_max() { return max; }; double param_get_min() { return min; }; - void param_overwrite_widget(bool overwrite_widget); virtual Gtk::Widget * param_newWidget(); diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index dafc6d406..aa87508ab 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -439,6 +439,10 @@ PathParam::linked_modified_callback(SPObject *linked_obj, guint /*flags*/) SP_OBJECT(param_effect->getLPEObj())->requestModified(SP_OBJECT_MODIFIED_FLAG); } +void +PathParam::param_update_default(const gchar * default_value){ + defvalue = strdup(default_value); +} /* CALLBACK FUNCTIONS FOR THE BUTTONS */ void diff --git a/src/live_effects/parameter/path.h b/src/live_effects/parameter/path.h index d2dddbe97..5381a6b36 100644 --- a/src/live_effects/parameter/path.h +++ b/src/live_effects/parameter/path.h @@ -40,6 +40,7 @@ public: virtual gchar * param_getSVGValue() const; virtual void param_set_default(); + virtual void param_update_default(const gchar * default_value); void param_set_and_write_default(); void set_new_value (Geom::PathVector const &newpath, bool write_to_svg); void set_new_value (Geom::Piecewise<Geom::D2<Geom::SBasis> > const &newpath, bool write_to_svg); diff --git a/src/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp index c87b1e299..4ca88a6b8 100644 --- a/src/live_effects/parameter/point.cpp +++ b/src/live_effects/parameter/point.cpp @@ -26,8 +26,7 @@ PointParam::PointParam( const Glib::ustring& label, const Glib::ustring& tip, : Parameter(label, tip, key, wr, effect), defvalue(default_value), liveupdate(live_update), - knoth(NULL), - _pointwdg(NULL) + knoth(NULL) { knot_shape = SP_KNOT_SHAPE_DIAMOND; knot_mode = SP_KNOT_MODE_XOR; @@ -59,12 +58,25 @@ PointParam::param_get_default() const{ } void -PointParam::param_update_default(const Geom::Point default_point) +PointParam::param_update_default(Geom::Point default_point) { defvalue = default_point; } void +PointParam::param_update_default(const gchar * default_point) +{ + gchar ** strarray = g_strsplit(default_point, ",", 2); + double newx, newy; + unsigned int success = sp_svg_number_read_d(strarray[0], &newx); + success += sp_svg_number_read_d(strarray[1], &newy); + g_strfreev (strarray); + if (success == 2) { + param_update_default( Geom::Point(newx, newy) ); + } +} + +void PointParam::param_setValue(Geom::Point newpoint, bool write) { *dynamic_cast<Geom::Point *>( this ) = newpoint; @@ -78,9 +90,6 @@ PointParam::param_setValue(Geom::Point newpoint, bool write) if(knoth && liveupdate){ knoth->update_knots(); } - if (_pointwdg) { - _pointwdg->setValue( newpoint ); - } } bool @@ -116,7 +125,7 @@ PointParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) Gtk::Widget * PointParam::param_newWidget() { - _pointwdg = Gtk::manage( + Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg = Gtk::manage( new Inkscape::UI::Widget::RegisteredTransformedPoint( param_label, param_tooltip, param_key, @@ -125,15 +134,14 @@ PointParam::param_newWidget() param_effect->getSPDoc() ) ); Geom::Affine transf = Geom::Scale(1, -1); transf[5] = SP_ACTIVE_DOCUMENT->getHeight().value("px"); - _pointwdg->setTransform(transf); - _pointwdg->setValue( *this ); - _pointwdg->clearProgrammatically(); - _pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change point parameter")); + pointwdg->setTransform(transf); + pointwdg->setValue( *this ); + pointwdg->clearProgrammatically(); + pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change point parameter")); Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() ); - static_cast<Gtk::HBox*>(hbox)->pack_start(*_pointwdg, true, true); + static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true); static_cast<Gtk::HBox*>(hbox)->show_all_children(); - param_effect->upd_params = false; return dynamic_cast<Gtk::Widget *> (hbox); } @@ -173,7 +181,7 @@ PointParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &or s = A; } } - pparam->param_setValue(s, this->pparam->liveupdate); + pparam->param_setValue(s); SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item); if(splpeitem && this->pparam->liveupdate){ sp_lpe_item_update_patheffect(splpeitem, false, false); diff --git a/src/live_effects/parameter/point.h b/src/live_effects/parameter/point.h index e8cb66225..a5153ad80 100644 --- a/src/live_effects/parameter/point.h +++ b/src/live_effects/parameter/point.h @@ -43,14 +43,15 @@ public: void param_set_default(); Geom::Point param_get_default() const; void param_set_liveupdate(bool live_update); - void param_update_default(const Geom::Point default_point); + void param_update_default(Geom::Point default_point); + + virtual void param_update_default(const gchar * default_point); virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); virtual bool providesKnotHolderEntities() const { return true; } virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); - friend class PointParamKnotHolderEntity; private: PointParam(const PointParam&); @@ -62,7 +63,6 @@ private: SPKnotModeType knot_mode; guint32 knot_color; gchar *handle_tip; - Inkscape::UI::Widget::RegisteredTransformedPoint * _pointwdg; }; diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h index 56a609fa8..a34163ca1 100644 --- a/src/live_effects/parameter/powerstrokepointarray.h +++ b/src/live_effects/parameter/powerstrokepointarray.h @@ -39,13 +39,13 @@ public: virtual bool providesKnotHolderEntities() const { return true; } virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); + virtual void param_update_default(const gchar * default_value){}; void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in, Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_normal_in); Geom::Piecewise<Geom::D2<Geom::SBasis> > const & get_pwd2() const { return last_pwd2; } Geom::Piecewise<Geom::D2<Geom::SBasis> > const & get_pwd2_normal() const { return last_pwd2_normal; } void recalculate_controlpoints_for_new_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); - friend class PowerStrokePointArrayParamKnotHolderEntity; private: diff --git a/src/live_effects/parameter/random.cpp b/src/live_effects/parameter/random.cpp index 075e85ee1..90e53ca0e 100644 --- a/src/live_effects/parameter/random.cpp +++ b/src/live_effects/parameter/random.cpp @@ -78,6 +78,20 @@ RandomParam::param_set_default() } void +RandomParam::param_update_default(gdouble default_value){ + defvalue = default_value; +} + +void +RandomParam::param_update_default(const gchar * default_value){ + double newval; + unsigned int success = sp_svg_number_read_d(default_value, &newval); + if (success == 1) { + param_update_default(newval); + } +} + +void RandomParam::param_set_value(gdouble val, long newseed) { value = val; diff --git a/src/live_effects/parameter/random.h b/src/live_effects/parameter/random.h index ca4440336..5fb6027ac 100644 --- a/src/live_effects/parameter/random.h +++ b/src/live_effects/parameter/random.h @@ -38,9 +38,9 @@ public: void param_set_value(gdouble val, long newseed); void param_make_integer(bool yes = true); void param_set_range(gdouble min, gdouble max); - + void param_update_default(gdouble default_value); + virtual void param_update_default(const gchar * default_value); void resetRandomizer(); - operator gdouble(); inline gdouble get_value() { return value; } ; diff --git a/src/live_effects/parameter/text.cpp b/src/live_effects/parameter/text.cpp index 5c4cdf4c6..4062a4dc7 100644 --- a/src/live_effects/parameter/text.cpp +++ b/src/live_effects/parameter/text.cpp @@ -50,9 +50,9 @@ TextParam::param_set_default() } void -TextParam::param_update_default(Glib::ustring default_value) +TextParam::param_update_default(const gchar * default_value) { - defvalue = default_value; + defvalue = (Glib::ustring)default_value; } void @@ -125,14 +125,12 @@ TextParam::param_newWidget() rsu->setProgrammatically = false; rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change text parameter")); - param_effect->upd_params = false; return dynamic_cast<Gtk::Widget *> (rsu); } void TextParam::param_setValue(const Glib::ustring newvalue) { - param_effect->upd_params = true; value = newvalue; if (!_hide_canvas_text) { sp_canvastext_set_text (canvas_text, newvalue.c_str()); diff --git a/src/live_effects/parameter/text.h b/src/live_effects/parameter/text.h index 553c84c0a..137f3ee02 100644 --- a/src/live_effects/parameter/text.h +++ b/src/live_effects/parameter/text.h @@ -39,16 +39,16 @@ public: virtual bool param_readSVGValue(const gchar * strvalue); virtual gchar * param_getSVGValue() const; - void param_setValue(const Glib::ustring newvalue); + void param_setValue(Glib::ustring newvalue); void param_hide_canvas_text(); virtual void param_set_default(); - void param_update_default(Glib::ustring default_value); + virtual void param_update_default(const gchar * default_value); void setPos(Geom::Point pos); void setPosAndAnchor(const Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2, const double t, const double length, bool use_curvature = false); void setAnchor(double x_value, double y_value); - const Glib::ustring get_value() const { return defvalue; }; + const Glib::ustring get_value() const { return value; }; private: TextParam(const TextParam&); diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp index b3f6442bb..9eb89fea5 100644 --- a/src/live_effects/parameter/togglebutton.cpp +++ b/src/live_effects/parameter/togglebutton.cpp @@ -60,6 +60,18 @@ ToggleButtonParam::param_getSVGValue() const return str; } +void +ToggleButtonParam::param_update_default(bool default_value) +{ + defvalue = default_value; +} + +void +ToggleButtonParam::param_update_default(const gchar * default_value) +{ + param_update_default(helperfns_read_bool(default_value, defvalue)); +} + Gtk::Widget * ToggleButtonParam::param_newWidget() { @@ -68,7 +80,7 @@ ToggleButtonParam::param_newWidget() } checkwdg = Gtk::manage( - new Inkscape::UI::Widget::RegisteredToggleButton( param_label, + new Inkscape::UI::Widget::RegisteredToggleButton(param_label, param_tooltip, param_key, *param_wr, @@ -112,7 +124,6 @@ ToggleButtonParam::param_newWidget() checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change togglebutton parameter")); _toggled_connection = checkwdg->signal_toggled().connect(sigc::mem_fun(*this, &ToggleButtonParam::toggled)); - param_effect->upd_params = false; return checkwdg; } @@ -153,14 +164,13 @@ ToggleButtonParam::refresh_button() void ToggleButtonParam::param_setValue(bool newvalue) { + param_effect->upd_params = true; value = newvalue; refresh_button(); } void ToggleButtonParam::toggled() { - //Force redraw for update widgets - param_effect->upd_params = true; if (SP_ACTIVE_DESKTOP) { Inkscape::Selection *selection = SP_ACTIVE_DESKTOP->getSelection(); selection->emitModified(); diff --git a/src/live_effects/parameter/togglebutton.h b/src/live_effects/parameter/togglebutton.h index 8390fec86..d6ca15e75 100644 --- a/src/live_effects/parameter/togglebutton.h +++ b/src/live_effects/parameter/togglebutton.h @@ -51,6 +51,8 @@ public: sigc::signal<void>& signal_toggled() { return _signal_toggled; } virtual void toggled(); + void param_update_default(bool default_value); + virtual void param_update_default(const gchar * default_value); private: ToggleButtonParam(const ToggleButtonParam&); diff --git a/src/live_effects/parameter/transformedpoint.cpp b/src/live_effects/parameter/transformedpoint.cpp index 0d03432c3..22d5ba3a4 100644 --- a/src/live_effects/parameter/transformedpoint.cpp +++ b/src/live_effects/parameter/transformedpoint.cpp @@ -82,6 +82,25 @@ TransformedPointParam::param_getSVGValue() const return str; } +void +TransformedPointParam::param_update_default(Geom::Point default_point) +{ + defvalue = default_point; +} + +void +TransformedPointParam::param_update_default(const gchar * default_point) +{ + gchar ** strarray = g_strsplit(default_point, ",", 2); + double newx, newy; + unsigned int success = sp_svg_number_read_d(strarray[0], &newx); + success += sp_svg_number_read_d(strarray[1], &newy); + g_strfreev (strarray); + if (success == 2) { + param_update_default( Geom::Point(newx, newy) ); + } +} + Gtk::Widget * TransformedPointParam::param_newWidget() { diff --git a/src/live_effects/parameter/transformedpoint.h b/src/live_effects/parameter/transformedpoint.h index c96bedb53..269cc508e 100644 --- a/src/live_effects/parameter/transformedpoint.h +++ b/src/live_effects/parameter/transformedpoint.h @@ -51,7 +51,9 @@ public: void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); void set_oncanvas_color(guint32 color); - + Geom::Point param_get_default() { return defvalue; } + void param_update_default(Geom::Point default_point); + virtual void param_update_default(const gchar * default_point); virtual bool providesKnotHolderEntities() const { return true; } virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item); diff --git a/src/live_effects/parameter/unit.cpp b/src/live_effects/parameter/unit.cpp index b6ea99bfe..b9b91c1e6 100644 --- a/src/live_effects/parameter/unit.cpp +++ b/src/live_effects/parameter/unit.cpp @@ -55,14 +55,15 @@ UnitParam::param_set_default() } void -UnitParam::param_update_default(const Glib::ustring default_unit) +UnitParam::param_update_default(const gchar * default_unit) { - defunit = unit_table.getUnit(default_unit); + defunit = unit_table.getUnit((Glib::ustring)default_unit); } void UnitParam::param_set_value(Inkscape::Util::Unit const &val) { + param_effect->upd_params = true; unit = new Inkscape::Util::Unit(val); } diff --git a/src/live_effects/parameter/unit.h b/src/live_effects/parameter/unit.h index ae58cf956..c662b6edc 100644 --- a/src/live_effects/parameter/unit.h +++ b/src/live_effects/parameter/unit.h @@ -33,11 +33,10 @@ public: virtual gchar * param_getSVGValue() const; virtual void param_set_default(); void param_set_value(Inkscape::Util::Unit const &val); - void param_update_default(const Glib::ustring default_unit); + virtual void param_update_default(const gchar * default_unit); const gchar *get_abbreviation() const; - virtual Gtk::Widget * param_newWidget(); - + operator Inkscape::Util::Unit const *() const { return unit; } private: diff --git a/src/live_effects/parameter/vector.cpp b/src/live_effects/parameter/vector.cpp index 55b4d4b32..470fa9c2d 100644 --- a/src/live_effects/parameter/vector.cpp +++ b/src/live_effects/parameter/vector.cpp @@ -48,6 +48,25 @@ VectorParam::param_set_default() setVector(defvalue); } +void +VectorParam::param_update_default(Geom::Point default_point) +{ + defvalue = default_point; +} + +void +VectorParam::param_update_default(const gchar * default_point) +{ + gchar ** strarray = g_strsplit(default_point, ",", 2); + double newx, newy; + unsigned int success = sp_svg_number_read_d(strarray[0], &newx); + success += sp_svg_number_read_d(strarray[1], &newy); + g_strfreev (strarray); + if (success == 2) { + param_update_default( Geom::Point(newx, newy) ); + } +} + bool VectorParam::param_readSVGValue(const gchar * strvalue) { diff --git a/src/live_effects/parameter/vector.h b/src/live_effects/parameter/vector.h index edee4ff4d..d270e9f43 100644 --- a/src/live_effects/parameter/vector.h +++ b/src/live_effects/parameter/vector.h @@ -51,7 +51,8 @@ public: void set_vector_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); void set_origin_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); void set_oncanvas_color(guint32 color); - + void param_update_default(Geom::Point default_point); + virtual void param_update_default(const gchar * default_point); virtual bool providesKnotHolderEntities() const { return true; } virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item); diff --git a/src/main.cpp b/src/main.cpp index 8be9e2e44..f23f9a9f7 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -146,6 +146,7 @@ enum { SP_ARG_EXPORT_BACKGROUND, SP_ARG_EXPORT_BACKGROUND_OPACITY, SP_ARG_EXPORT_SVG, + SP_ARG_EXPORT_INKSCAPE_SVG, SP_ARG_EXPORT_PS, SP_ARG_EXPORT_EPS, SP_ARG_EXPORT_PS_LEVEL, @@ -205,6 +206,7 @@ static gboolean sp_export_area_snap = FALSE; static gboolean sp_export_use_hints = FALSE; static gboolean sp_export_id_only = FALSE; static gchar *sp_export_svg = NULL; +static gchar *sp_export_inkscape_svg = NULL; static gchar *sp_export_ps = NULL; static gchar *sp_export_eps = NULL; static gint sp_export_ps_level = 3; @@ -229,6 +231,7 @@ static gchar *sp_dbus_name = NULL; #endif // WITH_DBUS static gchar *sp_export_png_utf8 = NULL; static gchar *sp_export_svg_utf8 = NULL; +static gchar *sp_export_inkscape_svg_utf8 = NULL; static gchar *sp_global_printer_utf8 = NULL; #ifdef WITH_YAML @@ -257,6 +260,7 @@ static void resetCommandlineGlobals() { sp_export_use_hints = FALSE; sp_export_id_only = FALSE; sp_export_svg = NULL; + sp_export_inkscape_svg = NULL; sp_export_ps = NULL; sp_export_eps = NULL; sp_export_ps_level = 3; @@ -282,6 +286,7 @@ static void resetCommandlineGlobals() { sp_export_png_utf8 = NULL; sp_export_svg_utf8 = NULL; + sp_export_inkscape_svg_utf8 = NULL; sp_global_printer_utf8 = NULL; } @@ -392,6 +397,10 @@ struct poptOption options[] = { N_("Background opacity of exported bitmap (either 0.0 to 1.0, or 1 to 255)"), N_("VALUE")}, + {"export-inkscape-svg", 0, + POPT_ARG_STRING, &sp_export_inkscape_svg, SP_ARG_EXPORT_INKSCAPE_SVG, + N_("Export document to an inkscape SVG file (similar to save as.)"), + N_("FILENAME")}, {"export-plain-svg", 'l', POPT_ARG_STRING, &sp_export_svg, SP_ARG_EXPORT_SVG, N_("Export document to plain SVG file (no sodipodi or inkscape namespaces)"), @@ -903,6 +912,7 @@ static int sp_common_main( int argc, char const **argv, GSList **flDest ) { fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 ); fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 ); + fixupSingleFilename( &sp_export_inkscape_svg, &sp_export_inkscape_svg_utf8 ); fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 ); #ifdef WITH_YAML fixupSingleFilename( &sp_xverbs_yaml, &sp_xverbs_yaml_utf8 ); @@ -914,6 +924,8 @@ static int sp_common_main( int argc, char const **argv, GSList **flDest ) sp_export_png_utf8 = g_strdup( sp_export_png ); if ( sp_export_svg ) sp_export_svg_utf8 = g_strdup( sp_export_svg ); + if ( sp_export_inkscape_svg ) + sp_export_inkscape_svg_utf8 = g_strdup( sp_export_inkscape_svg ); if ( sp_global_printer ) sp_global_printer_utf8 = g_strdup( sp_global_printer ); #ifdef WITH_YAML @@ -1135,20 +1147,21 @@ static int sp_process_file_list(GSList *fl) } #endif // WITH_DBUS - if (!sp_export_svg && (sp_vacuum_defs || has_performed_actions)) { + if (!sp_export_svg && !sp_export_inkscape_svg && (sp_vacuum_defs || has_performed_actions)) { // save under the name given in the command line Inkscape::Extension::save(Inkscape::Extension::db.get("org.inkscape.output.svg.inkscape"), doc, filename, false, false, false, Inkscape::Extension::FILE_SAVE_METHOD_INKSCAPE_SVG); } + if (sp_global_printer) { sp_print_document_to_file(doc, sp_global_printer); } if (sp_export_png || (sp_export_id && sp_export_use_hints)) { retVal |= sp_do_export_png(doc); } - if (sp_export_svg) { + if (sp_export_svg || sp_export_inkscape_svg) { if (sp_export_text_to_path) { - std::vector<SPItem*> items; + std::vector<SPItem*> items; SPRoot *root = doc->getRoot(); doc->ensureUpToDate(); for (auto& iter: root->children) { @@ -1180,9 +1193,15 @@ static int sp_process_file_list(GSList *fl) s.set(obj); s.fitCanvas(false); } - - Inkscape::Extension::save(Inkscape::Extension::db.get("org.inkscape.output.svg.plain"), doc, sp_export_svg, false, - false, false, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY); + if (sp_export_svg) { + Inkscape::Extension::save(Inkscape::Extension::db.get("org.inkscape.output.svg.plain"), doc, sp_export_svg, false, + false, false, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_COPY); + } + if (sp_export_inkscape_svg) { + // Export as inkscape SVG. + Inkscape::Extension::save(Inkscape::Extension::db.get("org.inkscape.output.svg.inkscape"), doc, sp_export_inkscape_svg, false, + false, false, Inkscape::Extension::FILE_SAVE_METHOD_INKSCAPE_SVG); + } } if (sp_export_ps) { retVal |= do_export_ps_pdf(doc, sp_export_ps, "image/x-postscript"); diff --git a/src/preferences.cpp b/src/preferences.cpp index 4d522a1d8..2849fe068 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -512,6 +512,35 @@ void Preferences::remove(Glib::ustring const &pref_path) Inkscape::XML::Node *node = _getNode(pref_path, false); if (node && node->parent()) { node->parent()->removeChild(node); + } else { //Handle to remove also attributes in path not only the container node + // verify path + g_assert( pref_path.at(0) == '/' ); + if (_prefs_doc == NULL){ + return; + } + node = _prefs_doc->root(); + Inkscape::XML::Node *child = NULL; + gchar **splits = g_strsplit(pref_path.c_str(), "/", 0); + if ( splits ) { + for (int part_i = 0; splits[part_i]; ++part_i) { + // skip empty path segments + if (!splits[part_i][0]) { + continue; + } + if (!node->firstChild()) { + node->setAttribute(splits[part_i], NULL); + g_strfreev(splits); + return; + } + for (child = node->firstChild(); child; child = child->next()) { + if (!strcmp(splits[part_i], child->attribute("id"))) { + break; + } + } + node = child; + } + } + g_strfreev(splits); } } diff --git a/src/print.cpp b/src/print.cpp index 479401995..7cd05ac93 100644 --- a/src/print.cpp +++ b/src/print.cpp @@ -79,7 +79,6 @@ unsigned int sp_print_text(SPPrintContext *ctx, char const *text, Geom::Point p, void sp_print_document(Gtk::Window& parentWindow, SPDocument *doc) { - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; doc->ensureUpToDate(); // Build arena @@ -89,7 +88,6 @@ sp_print_document(Gtk::Window& parentWindow, SPDocument *doc) Inkscape::UI::Dialog::Print printop(doc,base); Gtk::PrintOperationResult res = printop.run(Gtk::PRINT_OPERATION_ACTION_PRINT_DIALOG, parentWindow); (void)res; // TODO handle this - doc->getRoot()->c2p *= doc->getRoot()->rotation; } void sp_print_document_to_file(SPDocument *doc, gchar const *filename) diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index ca0f78a00..b5c89b69d 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -493,8 +493,8 @@ void SPLPEItem::removeCurrentPathEffect(bool keep_paths) } PathEffectList new_list = *this->path_effect_list; new_list.remove(lperef); //current lpe ref is always our 'own' pointer from the path_effect_list + *this->path_effect_list = new_list; this->getRepr()->setAttribute("inkscape:path-effect", patheffectlist_svg_string(new_list)); - if (!keep_paths) { // Make sure that ellipse is stored as <svg:circle> or <svg:ellipse> if possible. if( SP_IS_GENERICELLIPSE(this)) { diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp index 403b8a41b..c40006a92 100644 --- a/src/sp-namedview.cpp +++ b/src/sp-namedview.cpp @@ -19,12 +19,7 @@ #include "event-log.h" #include <2geom/transforms.h> -#include "display/sp-canvas-group.h" -#include "display/canvas-bpath.h" -#include "display/canvas-temporary-item.h" -#include "display/canvas-temporary-item-list.h" #include "display/canvas-grid.h" -#include "display/curve.h" #include "util/units.h" #include "svg/svg-color.h" #include "xml/repr.h" @@ -34,15 +29,12 @@ #include "desktop-events.h" #include "sp-guide.h" -#include "sp-root.h" #include "sp-item-group.h" #include "sp-namedview.h" #include "preferences.h" #include "desktop.h" -#include "selection.h" -#include "object-set.h" -#include "inkscape.h" #include "conn-avoid-ref.h" // for defaultConnSpacing. +#include "sp-root.h" #include <gtkmm/window.h> using Inkscape::DocumentUndo; @@ -80,7 +72,6 @@ SPNamedView::SPNamedView() : SPObjectGroup(), snap_manager(this) { this->pagecolor = 0; this->cx = 0; this->pageshadow = 0; - this->document_rotation = 0; this->window_width = 0; this->window_height = 0; this->window_maximized = 0; @@ -101,13 +92,9 @@ SPNamedView::SPNamedView() : SPObjectGroup(), snap_manager(this) { this->default_layer_id = 0; this->connector_spacing = defaultConnSpacing; - this->page_border_rotated = NULL; } SPNamedView::~SPNamedView() { - if(!this->getViewList().empty()) { // >0 Desktops - this->getViewList()[0]->remove_temporary_canvasitem(this->page_border_rotated); - } } static void sp_namedview_generate_old_grid(SPNamedView * /*nv*/, SPDocument *document, Inkscape::XML::Node *repr) { @@ -225,7 +212,6 @@ void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) { this->readAttr( "inkscape:zoom" ); this->readAttr( "inkscape:cx" ); this->readAttr( "inkscape:cy" ); - this->readAttr( "inkscape:document-rotation" ); this->readAttr( "inkscape:window-width" ); this->readAttr( "inkscape:window-height" ); this->readAttr( "inkscape:window-x" ); @@ -423,11 +409,6 @@ void SPNamedView::set(unsigned int key, const gchar* value) { this->cy = value ? g_ascii_strtod(value, NULL) : HUGE_VAL; // HUGE_VAL means not set this->requestModified(SP_OBJECT_MODIFIED_FLAG); break; - case SP_ATTR_INKSCAPE_DOCUMENT_ROTATION: - this->document_rotation = value ? g_ascii_strtod(value, NULL) : 0; - sp_namedview_set_document_rotation(this); - this->requestModified(SP_OBJECT_MODIFIED_FLAG); - break; case SP_ATTR_INKSCAPE_WINDOW_WIDTH: this->window_width = value? atoi(value) : -1; // -1 means not set this->requestModified(SP_OBJECT_MODIFIED_FLAG); @@ -970,81 +951,6 @@ static void sp_namedview_lock_guides(SPNamedView *nv) } } -//void sp_namedview_doc_rotate_guides(SPNamedView *nv) -//{ -// bool saved = DocumentUndo::getUndoSensitive(nv->document); -// DocumentUndo::setUndoSensitive(nv->document, false); -// SPRoot * root = nv->document->getRoot(); -// Geom::Point page_center = root->viewBox.midpoint() * root->vbt; -// Geom::Affine rot = Geom::identity(); -// rot *= Geom::Translate(page_center).inverse(); -// rot *= Geom::Rotate(Geom::rad_from_deg((nv->document_rotation - root->get_rotation()) * -1)); -// rot *= Geom::Translate(page_center); -// for(std::vector<SPGuide *>::iterator it=nv->guides.begin();it!=nv->guides.end();++it ) { -// Geom::Point const on_line = (*it)->getPoint() * rot ; -// (*it)->moveto(on_line, true); -// Geom::Affine rot_normal_affine = Geom::Rotate(Geom::rad_from_deg((nv->document_rotation - root->get_rotation()) * -1)); -// Geom::Point const rot_normal = (*it)->getNormal() * rot_normal_affine; -// (*it)->set_normal(rot_normal, true); -// } -// DocumentUndo::setUndoSensitive(nv->document, saved); -// nv->document->setModifiedSinceSave(); -//} - -void sp_namedview_set_document_rotation(SPNamedView *nv) -{ - if ( nv->document->getRoot()->get_rotation() == nv->document_rotation) return; - if(!nv->getViewList().empty()) { // >0 Desktops - SPDesktop *desktop = nv->getViewList()[0]; - desktop->remove_temporary_canvasitem(nv->page_border_rotated); - SPRoot * root = nv->document->getRoot(); - SPCurve *c = new SPCurve(); - c->moveto(root->viewBox.min()); - c->lineto(Geom::Point(root->viewBox.max()[Geom::X],root->viewBox.min()[Geom::Y])); - c->lineto(Geom::Point(root->viewBox.max()[Geom::X],root->viewBox.max()[Geom::Y])); - c->lineto(Geom::Point(root->viewBox.min()[Geom::X],root->viewBox.max()[Geom::Y])); - c->closepath(); - Geom::Point page_center = root->viewBox.midpoint(); - Geom::PathVector const box = c->get_pathvector(); - Geom::Affine rot = Geom::identity(); - rot *= Geom::Translate(page_center).inverse(); - rot *= Geom::Rotate(Geom::rad_from_deg(nv->document_rotation * -1)); - rot *= Geom::Translate(page_center); - if (nv->document_rotation) { - SPCanvasItem *canvas_border = sp_canvas_bpath_new(desktop->getTempGroup(), c, true); - sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(canvas_border), 0xFF00009A, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); - sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(canvas_border), 0, SP_WIND_RULE_NONZERO); - sp_canvas_item_affine_absolute(canvas_border, rot * root->vbt); - nv->page_border_rotated = desktop->add_temporary_canvasitem(canvas_border, 0); - } - //sp_namedview_doc_rotate_guides(nv); - nv->document->getRoot()->set_rotation(nv->document_rotation); - c->unref(); - } - if (nv->document_rotation) { - nv->showborder = FALSE; - } else { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - nv->showborder = prefs->getBool("/template/base/showborder", 1.0); - } - - SPDesktop * desktop = SP_ACTIVE_DESKTOP; - if (desktop) { -//TODO: Remove knots of shapes on selected items -// Inkscape::Selection * sel = desktop->getSelection(); -// std::vector<SPItem*> il(sel->items().begin(), sel->items().end()); -// for (std::vector<SPItem*>::const_iterator l = il.begin(); l != il.end(); l++){ -// SPItem *item = *l; -// sel->remove(item->getRepr()); -// sel->add(item->getRepr()); -// } - SPObject *updated = desktop->getDocument()->getRoot(); - if (updated) { - updated->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); - } - } -} - static void sp_namedview_show_single_guide(SPGuide* guide, bool show) { if (show) { @@ -1059,8 +965,6 @@ static void sp_namedview_lock_single_guide(SPGuide* guide, bool locked) guide->set_locked(locked, true); } - - void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr) { unsigned int v; diff --git a/src/sp-namedview.h b/src/sp-namedview.h index 9d11c13b7..d8ac1a77e 100644 --- a/src/sp-namedview.h +++ b/src/sp-namedview.h @@ -21,7 +21,6 @@ #include "snap.h" #include "document.h" #include "util/units.h" -#include "display/sp-canvas.h" #include <vector> namespace Inkscape { @@ -29,9 +28,6 @@ namespace Inkscape { namespace Util { class Unit; } - namespace Display { - class TemporaryItem; - } } typedef unsigned int guint32; @@ -42,7 +38,7 @@ enum { SP_BORDER_LAYER_TOP }; -class SPNamedView : public SPObjectGroup{ +class SPNamedView : public SPObjectGroup { public: SPNamedView(); virtual ~SPNamedView(); @@ -58,7 +54,6 @@ public: double zoom; double cx; double cy; - double document_rotation; int window_width; int window_height; int window_x; @@ -71,7 +66,7 @@ public: Inkscape::Util::Unit const *display_units; // Units used for the UI (*not* the same as units of SVG coordinates) Inkscape::Util::Unit const *page_size_units; // Only used in "Custom size" part of Document Properties dialog - Inkscape::Display::TemporaryItem *page_border_rotated; + GQuark default_layer_id; double connector_spacing; @@ -126,7 +121,7 @@ SPNamedView const *sp_document_namedview(SPDocument const *document, char const void sp_namedview_window_from_document(SPDesktop *desktop); void sp_namedview_document_from_window(SPDesktop *desktop); void sp_namedview_update_layers_from_document (SPDesktop *desktop); -void sp_namedview_set_document_rotation(SPNamedView *nv); + void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr); void sp_namedview_guides_toggle_lock(SPDocument *doc, Inkscape::XML::Node *repr); void sp_namedview_show_grids(SPNamedView *namedview, bool show, bool dirty_document); diff --git a/src/splivarot.cpp b/src/splivarot.cpp index 22efe38ed..c594a6426 100644 --- a/src/splivarot.cpp +++ b/src/splivarot.cpp @@ -46,6 +46,7 @@ #include "splivarot.h" #include "verbs.h" #include "2geom/svg-path-parser.h" // to get from SVG on boolean to Geom::Path +#include "util/units.h" // to get abbr for document units using Inkscape::DocumentUndo; @@ -1688,7 +1689,7 @@ void sp_selected_path_offset(SPDesktop *desktop) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - double prefOffset = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, "px"); + double prefOffset = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, desktop->getDocument()->getDisplayUnit()->abbr); sp_selected_path_do_offset(desktop, true, prefOffset); } @@ -1696,7 +1697,7 @@ void sp_selected_path_inset(SPDesktop *desktop) { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - double prefOffset = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, "px"); + double prefOffset = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, desktop->getDocument()->getDisplayUnit()->abbr); sp_selected_path_do_offset(desktop, false, prefOffset); } @@ -1782,7 +1783,7 @@ void sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool { { Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - o_width = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, "px"); + o_width = prefs->getDouble("/options/defaultoffsetwidth/value", 1.0, desktop->getDocument()->getDisplayUnit()->abbr); } if (o_width < 0.01){ @@ -2066,17 +2067,6 @@ sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset) res->Reset(); theRes->ConvertToForme(res); - if (o_width >= 1.0) - { - res->ConvertEvenLines(1.0); - res->Simplify(1.0); - } - else - { - res->ConvertEvenLines(1.0*o_width); - res->Simplify(1.0 * o_width); - } - delete theShape; delete theRes; } diff --git a/src/text-editing.cpp b/src/text-editing.cpp index 6809a4bc5..193f4b15a 100644 --- a/src/text-editing.cpp +++ b/src/text-editing.cpp @@ -942,9 +942,9 @@ sp_te_set_repr_text_multiline(SPItem *text, gchar const *str) gchar *content = g_strdup (str); repr->setContent(""); - for (auto& child: object->children) { - if (!SP_IS_FLOWREGION(&child) && !SP_IS_FLOWREGIONEXCLUDE(&child)) { - repr->removeChild(child.getRepr()); + for (auto& child: object->childList(false)) { + if (!SP_IS_FLOWREGION(child) && !SP_IS_FLOWREGIONEXCLUDE(child)) { + repr->removeChild(child->getRepr()); } } diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 259a06013..389e8902a 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -177,6 +177,7 @@ set(ui_SRC control-types.h dialog-events.h draw-anchor.h + event-debug.h icon-names.h interface.h object-edit.h diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index 734640584..3cc8ac098 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -708,7 +708,7 @@ void ClipboardManagerImpl::_copySelection(ObjectSet *selection) // (we're dealing with unattached representations, so we write to their attributes // instead of using sp_item_set_transform) SPUse *use=dynamic_cast<SPUse *>(item); - if( use && selection->includes(use->get_original()) ){//we are copying something whose parent is also copied (!) + if( use && use->get_original() && use->get_original()->parent ){//we are copying something whose parent is also copied (!) transform = ((SPItem*)(use->get_original()->parent))->i2doc_affine().inverse() * transform; } gchar *transform_str = sp_svg_transform_write(transform ); diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp index b7207fd50..1bb952de4 100644 --- a/src/ui/dialog/export.cpp +++ b/src/ui/dialog/export.cpp @@ -978,9 +978,7 @@ void Export::onExport () SPNamedView *nv = desktop->getNamedView(); SPDocument *doc = desktop->getDocument(); - Geom::Affine rot = doc->getRoot()->c2p; - doc->getRoot()->c2p = doc->getRoot()->rotation.inverse() * doc->getRoot()->c2p; - doc->ensureUpToDate(); + bool exportSuccessful = false; bool hide = hide_export.get_active (); @@ -1005,7 +1003,6 @@ void Export::onExport () if (num < 1) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("No items selected.")); - doc->getRoot()->c2p *= doc->getRoot()->rotation; return; } @@ -1097,7 +1094,6 @@ void Export::onExport () if (filename.empty()) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("You have to enter a filename.")); sp_ui_error_dialog(_("You have to enter a filename")); - doc->getRoot()->c2p *= doc->getRoot()->rotation; return; } @@ -1114,7 +1110,6 @@ void Export::onExport () if (!((x1 > x0) && (y1 > y0) && (width > 0) && (height > 0))) { desktop->messageStack()->flash(Inkscape::ERROR_MESSAGE, _("The chosen area to be exported is invalid.")); sp_ui_error_dialog(_("The chosen area to be exported is invalid")); - doc->getRoot()->c2p *= doc->getRoot()->rotation; return; } @@ -1137,7 +1132,6 @@ void Export::onExport () g_free(safeDir); g_free(error); - doc->getRoot()->c2p *= doc->getRoot()->rotation; return; } @@ -1287,7 +1281,6 @@ void Export::onExport () } } } - doc->getRoot()->c2p *= doc->getRoot()->rotation; } // end of sp_export_export_clicked() /// Called when Browse button is clicked diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index c5e8a6de6..646439613 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -1310,6 +1310,9 @@ void InkscapePreferences::initPageBehavior() _steps_zoom.init ( "/options/zoomincrement/value", 101.0, 500.0, 1.0, 1.0, M_SQRT2, true, true); _page_steps.add_line( false, _("_Zoom in/out by:"), _steps_zoom, _("%"), _("Zoom tool click, +/- keys, and middle click zoom in and out by this multiplier"), false); + _steps_rotate.init ( "/options/rotateincrement/value", 1, 90, 1.0, 5.0, 15, false, false); + _page_steps.add_line( false, _("_Rotate canvas by:"), _steps_rotate, _("degrees"), + _("Rotate canvas clockwise and counter-clockwise by this amount."), false); this->AddPage(_page_steps, _("Steps"), iter_behavior, PREFS_PAGE_BEHAVIOR_STEPS); // Clones options @@ -1408,6 +1411,10 @@ void InkscapePreferences::initPageRendering() _rendering_cache_size.init("/options/renderingcache/size", 0.0, 4096.0, 1.0, 32.0, 64.0, true, false); _page_rendering.add_line( false, _("Rendering _cache size:"), _rendering_cache_size, C_("mebibyte (2^20 bytes) abbreviation","MiB"), _("Set the amount of memory per document which can be used to store rendered parts of the drawing for later reuse; set to zero to disable caching"), false); + // rendering tile multiplier + _rendering_tile_multiplier.init("/options/rendering/tile-multiplier", 1.0, 64.0, 1.0, 4.0, 1.0, true, false); + _page_rendering.add_line( false, _("Rendering tile multiplier:"), _rendering_tile_multiplier, _("requires restart"), _("Set the relative size of tiles used to render the canvas. The larger the value, the bigger the tile size."), false); + /* blur quality */ _blur_quality_best.init ( _("Best quality (slowest)"), "/options/blurquality/value", BLUR_QUALITY_BEST, false, 0); diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index 781b5e48e..e6ba4e4b2 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -215,6 +215,7 @@ protected: UI::Widget::PrefSpinUnit _steps_scale; UI::Widget::PrefSpinUnit _steps_inset; UI::Widget::PrefSpinButton _steps_zoom; + UI::Widget::PrefSpinButton _steps_rotate; UI::Widget::PrefRadioButton _t_sel_trans_obj; UI::Widget::PrefRadioButton _t_sel_trans_outl; @@ -294,6 +295,7 @@ protected: UI::Widget::PrefCombo _switcher_style; UI::Widget::PrefCheckButton _rendering_image_outline; UI::Widget::PrefSpinButton _rendering_cache_size; + UI::Widget::PrefSpinButton _rendering_tile_multiplier; UI::Widget::PrefSpinButton _filter_multi_threaded; UI::Widget::PrefCheckButton _trans_scale_stroke; diff --git a/src/ui/dialog/livepatheffect-editor.cpp b/src/ui/dialog/livepatheffect-editor.cpp index e5becdb5c..bb9b61504 100644 --- a/src/ui/dialog/livepatheffect-editor.cpp +++ b/src/ui/dialog/livepatheffect-editor.cpp @@ -19,7 +19,7 @@ #include "livepatheffect-editor.h" #include "desktop.h" - +#include <gtkmm/expander.h> #include "document.h" #include "document-undo.h" #include "helper/action.h" @@ -47,16 +47,21 @@ namespace Dialog { /*#################### * Callback functions */ + + void lpeeditor_selection_changed (Inkscape::Selection * selection, gpointer data) { LivePathEffectEditor *lpeeditor = static_cast<LivePathEffectEditor *>(data); lpeeditor->lpe_list_locked = false; - lpeeditor->onSelectionChanged(selection, true); + lpeeditor->lpe_changed = true; + lpeeditor->onSelectionChanged(selection); } -static void lpeeditor_selection_modified (Inkscape::Selection * selection, guint /*flags*/, gpointer data) +void lpeeditor_selection_modified (Inkscape::Selection * selection, guint /*flags*/, gpointer data) { + LivePathEffectEditor *lpeeditor = static_cast<LivePathEffectEditor *>(data); + lpeeditor->lpe_list_locked = false; lpeeditor->onSelectionChanged(selection); } @@ -80,6 +85,7 @@ LivePathEffectEditor::LivePathEffectEditor() : UI::Widget::Panel("", "/dialogs/livepatheffect", SP_VERB_DIALOG_LIVE_PATH_EFFECT), deskTrack(), lpe_list_locked(false), + lpe_changed(true), effectwidget(NULL), status_label("", Gtk::ALIGN_CENTER), effectcontrol_frame(""), @@ -190,11 +196,22 @@ LivePathEffectEditor::~LivePathEffectEditor() void LivePathEffectEditor::showParams(LivePathEffect::Effect& effect) { - if ( ! effect.upd_params ) { + if (!effect.upd_params && !lpe_changed) { + lpe_changed = false; return; } + bool expanderopen = false; + Gtk::Widget * defaultswidget = effect.defaultParamSet(); if (effectwidget) { + if (defaultswidget) { + Gtk::Expander * expander = NULL; + std::vector<Gtk::Widget *> childs = dynamic_cast<Gtk::Box *> (effectwidget)->get_children(); + std::vector<Gtk::Widget *> childs_default = dynamic_cast<Gtk::Box *> (childs[childs.size()-1])->get_children(); + if ((expander = dynamic_cast<Gtk::Expander *>(childs_default[childs_default.size()-1]))){ + expanderopen = expander->get_expanded(); + } + } effectcontrol_vbox.remove(*effectwidget); delete effectwidget; effectwidget = NULL; @@ -204,6 +221,15 @@ LivePathEffectEditor::showParams(LivePathEffect::Effect& effect) effectwidget = effect.newWidget(); if (effectwidget) { + + if (defaultswidget) { + Gtk::Expander * expander = NULL; + std::vector<Gtk::Widget *> childs_default = dynamic_cast<Gtk::Box *> (defaultswidget)->get_children(); + if ((expander = dynamic_cast<Gtk::Expander *>(childs_default[childs_default.size()-1]))){ + expander->set_expanded(expanderopen); + } + dynamic_cast<Gtk::Box *> (effectwidget)->pack_start(*defaultswidget, true, true); + } effectcontrol_vbox.pack_start(*effectwidget, true, true); } button_remove.show(); @@ -212,6 +238,8 @@ LivePathEffectEditor::showParams(LivePathEffect::Effect& effect) effectcontrol_frame.show(); effectcontrol_vbox.show_all_children(); // fixme: add resizing of dialog + effect.upd_params = false; + lpe_changed = false; } void @@ -254,16 +282,15 @@ LivePathEffectEditor::set_sensitize_all(bool sensitive) } void -LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel, bool upd_params) +LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel) { if (lpe_list_locked) { // this was triggered by selecting a row in the list, so skip reloading lpe_list_locked = false; return; } - - effectlist_store->clear(); current_lpeitem = NULL; + effectlist_store->clear(); if ( sel && !sel->isEmpty() ) { SPItem *item = sel->singleItem(); @@ -278,9 +305,6 @@ LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel, bool upd_para if ( lpeitem->hasPathEffect() ) { Inkscape::LivePathEffect::Effect *lpe = lpeitem->getCurrentLPE(); if (lpe) { - if (upd_params) { - lpe->upd_params = true; - } showParams(*lpe); lpe_list_locked = true; selectInList(lpe); @@ -484,18 +508,12 @@ LivePathEffectEditor::onRemove() SPItem *item = sel->singleItem(); SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item); if ( lpeitem ) { - if (current_lperef && current_lperef->lpeobject) { - LivePathEffect::Effect * effect = current_lperef->lpeobject->get_lpe(); - if (effect) { - effect->upd_params = true; - } - } lpeitem->removeCurrentPathEffect(false); - + current_lperef = NULL; DocumentUndo::done( current_desktop->getDocument(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Remove path effect") ); - - effect_list_reload(lpeitem); + lpe_list_locked = false; + onSelectionChanged(sel); } } @@ -512,7 +530,7 @@ void LivePathEffectEditor::onUp() DocumentUndo::done( current_desktop->getDocument(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Move path effect up") ); - + effect_list_reload(lpeitem); } } @@ -529,7 +547,6 @@ void LivePathEffectEditor::onDown() DocumentUndo::done( current_desktop->getDocument(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Move path effect down") ); - effect_list_reload(lpeitem); } } @@ -554,7 +571,7 @@ void LivePathEffectEditor::on_effect_selection_changed() current_lperef = lperef; LivePathEffect::Effect * effect = lperef->lpeobject->get_lpe(); if (effect) { - effect->upd_params = true; + lpe_changed = true; showParams(*effect); } } @@ -563,6 +580,7 @@ void LivePathEffectEditor::on_effect_selection_changed() void LivePathEffectEditor::on_visibility_toggled( Glib::ustring const& str ) { + Gtk::TreeModel::Children::iterator iter = effectlist_view.get_model()->get_iter(str); Gtk::TreeModel::Row row = *iter; diff --git a/src/ui/dialog/livepatheffect-editor.h b/src/ui/dialog/livepatheffect-editor.h index a7c749ef3..7f6f56fd2 100644 --- a/src/ui/dialog/livepatheffect-editor.h +++ b/src/ui/dialog/livepatheffect-editor.h @@ -45,7 +45,7 @@ public: static LivePathEffectEditor &getInstance() { return *new LivePathEffectEditor(); } - void onSelectionChanged(Inkscape::Selection *sel, bool upd_params = false); + void onSelectionChanged(Inkscape::Selection *sel); void onSelectionModified(Inkscape::Selection *sel); virtual void on_effect_selection_changed(); void setDesktop(SPDesktop *desktop); @@ -96,7 +96,7 @@ private: }; bool lpe_list_locked; - + bool lpe_changed; //Inkscape::UI::Widget::ComboBoxEnum<LivePathEffect::EffectType> combo_effecttype; Gtk::Widget * effectwidget; @@ -126,6 +126,7 @@ private: LivePathEffect::LPEObjectReference * current_lperef; friend void lpeeditor_selection_changed (Inkscape::Selection * selection, gpointer data); + friend void lpeeditor_selection_modified (Inkscape::Selection * selection, guint /*flags*/, gpointer data); LivePathEffectEditor(LivePathEffectEditor const &d); LivePathEffectEditor& operator=(LivePathEffectEditor const &d); diff --git a/src/ui/dialog/symbols.cpp b/src/ui/dialog/symbols.cpp index 740ff4f39..e9a13620b 100644 --- a/src/ui/dialog/symbols.cpp +++ b/src/ui/dialog/symbols.cpp @@ -57,7 +57,10 @@ #include <librevenge-stream/librevenge-stream.h> using librevenge::RVNGFileStream; + using librevenge::RVNGString; using librevenge::RVNGStringVector; + using librevenge::RVNGPropertyList; + using librevenge::RVNGSVGDrawingGenerator; #else #include <libwpd-stream/libwpd-stream.h> @@ -451,6 +454,31 @@ void SymbolsDialog::iconChanged() { } #ifdef WITH_LIBVISIO + +#if WITH_LIBVISIO01 +// Extend libvisio's native RVNGSVGDrawingGenerator with support for extracting stencil names (to be used as ID/title) +class REVENGE_API RVNGSVGDrawingGenerator_WithTitle : public RVNGSVGDrawingGenerator { + public: + RVNGSVGDrawingGenerator_WithTitle(RVNGStringVector &output, RVNGStringVector &titles, const RVNGString &nmSpace) + : RVNGSVGDrawingGenerator(output, nmSpace) + , _titles(titles) + {} + + void startPage(const RVNGPropertyList &propList) + { + RVNGSVGDrawingGenerator::startPage(propList); + if (propList["draw:name"]) { + _titles.append(propList["draw:name"]->getStr()); + } else { + _titles.append(""); + } + } + + private: + RVNGStringVector &_titles; +}; +#endif + // Read Visio stencil files SPDocument* read_vss( gchar* fullname, Glib::ustring name ) { @@ -472,8 +500,9 @@ SPDocument* read_vss( gchar* fullname, Glib::ustring name ) { } RVNGStringVector output; + RVNGStringVector titles; #if WITH_LIBVISIO01 - librevenge::RVNGSVGDrawingGenerator generator(output, "svg"); + RVNGSVGDrawingGenerator_WithTitle generator(output, titles, "svg"); if (!libvisio::VisioDocument::parseStencils(&input, &generator)) { #else @@ -488,7 +517,7 @@ SPDocument* read_vss( gchar* fullname, Glib::ustring name ) { // 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) + // prepare a valid id prefix for symbols libvisio doesn't give us a name for Glib::RefPtr<Glib::Regex> regex1 = Glib::Regex::create("[^a-zA-Z0-9_-]"); Glib::ustring id = regex1->replace(name, 0, "_", Glib::REGEX_MATCH_PARTIAL); @@ -505,25 +534,30 @@ SPDocument* read_vss( gchar* fullname, Glib::ustring name ) { tmpSVGOutput += "</title>\n"; tmpSVGOutput += " <defs>\n"; - // Each "symbol" is in it's own SVG file, we wrap with <symbol> and merge into one file. + // Each "symbol" is in its own SVG file, we wrap with <symbol> and merge into one file. for (unsigned i=0; i<output.size(); ++i) { std::stringstream ss; - ss << i; + if (titles.size() == output.size() && titles[i] != "") { + // TODO: Do we need to check for duplicated titles? + ss << regex1->replace(titles[i].cstr(), 0, "_", Glib::REGEX_MATCH_PARTIAL); + } else { + ss << id << "_" << i; + } + + tmpSVGOutput += " <symbol id=\"" + ss.str() + "\">\n"; - tmpSVGOutput += " <symbol id=\""; - tmpSVGOutput += id; - tmpSVGOutput += "_"; - tmpSVGOutput += ss.str(); - tmpSVGOutput += "\">\n"; +#if WITH_LIBVISIO01 + if (titles.size() == output.size() && titles[i] != "") { + tmpSVGOutput += " <title>" + Glib::ustring(RVNGString::escapeXML(titles[i].cstr()).cstr()) + "</title>\n"; + } +#endif std::istringstream iss( output[i].cstr() ); std::string line; while( std::getline( iss, line ) ) { - // std::cout << line << std::endl; if( line.find( "svg:svg" ) == std::string::npos ) { - tmpSVGOutput += line; - tmpSVGOutput += "\n"; + tmpSVGOutput += " " + line + "\n"; } } diff --git a/src/ui/event-debug.h b/src/ui/event-debug.h new file mode 100644 index 000000000..dd33ca0e3 --- /dev/null +++ b/src/ui/event-debug.h @@ -0,0 +1,132 @@ +#ifndef SEEN_UI_EVENT_DEBUG_H +#define SEEN_UI_EVENT_DEBUG_H + +/** + * @file + * Dump event data. + */ +/* + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <gtk/gtk.h> +#include <glibmm/ustring.h> + +// See: https://developer.gnome.org/gdk3/stable/gdk3-Events.html + +inline void ui_dump_event (GdkEvent *event, Glib::ustring const &prefix, bool merge = true) { + + static GdkEventType old_type = GDK_NOTHING; + static unsigned count = 0; + + // Doesn't usually help to dump a zillion events of the same type (e.g. GDK_MOTION_NOTIFY). + ++count; + if (merge && event->type == old_type) { + if ( count == 1 ) { + std::cout << prefix << " ... ditto" << std::endl; + } + return; + } + count = 0; + old_type = event->type; + + std::cout << prefix << ": "; + + switch (event->type) { + + case GDK_KEY_PRESS: + std::cout << "GDK_KEY_PRESS: " << event->key.hardware_keycode << std::endl; + break; + case GDK_KEY_RELEASE: + std::cout << "GDK_KEY_RELEASE: " << event->key.hardware_keycode << std::endl; + break; + + case GDK_BUTTON_PRESS: + std::cout << "GDK_BUTTON_PRESS: " << event->button.button << std::endl; + break; + case GDK_2BUTTON_PRESS: + std::cout << "GDK_2BUTTON_PRESS: " << event->button.button << std::endl; + break; + case GDK_3BUTTON_PRESS: + std::cout << "GDK_3BUTTON_PRESS: " << event->button.button << std::endl; + break; + case GDK_BUTTON_RELEASE: + std::cout << "GDK_BUTTON_RELEASE: " << event->button.button << std::endl; + break; + + case GDK_SCROLL: + std::cout << "GDK_SCROLL" << std::endl; + break; + + case GDK_MOTION_NOTIFY: + std::cout << "GDK_MOTION_NOTIFY" << std::endl; + break; + case GDK_ENTER_NOTIFY: + std::cout << "GDK_ENTER_NOTIFY" << std::endl; + break; + case GDK_LEAVE_NOTIFY: + std::cout << "GDK_LEAVE_NOTIFY" << std::endl; + break; + + case GDK_TOUCH_BEGIN: + std::cout << "GDK_TOUCH_BEGIN" << std::endl; + break; + case GDK_TOUCH_UPDATE: + std::cout << "GDK_TOUCH_UPDATE" << std::endl; + break; + case GDK_TOUCH_END: + std::cout << "GDK_TOUCH_END" << std::endl; + break; + case GDK_TOUCH_CANCEL: + std::cout << "GDK_TOUCH_CANCEL" << std::endl; + break; + +#if GTK_CHECK_VERSION(3,18,0) + + case GDK_TOUCHPAD_SWIPE: + std::cout << "GDK_TOUCHPAD_SWIPE" << std::endl; + break; + case GDK_TOUCHPAD_PINCH: + std::cout << "GDK_TOUCHPAD_PINCH" << std::endl; + break; + +#endif + +#if GTK_CHECK_VERSION(3,22,0) + + case GDK_PAD_BUTTON_PRESS: + std::cout << "GDK_PAD_BUTTON_PRESS" << std::endl; + break; + case GDK_PAD_BUTTON_RELEASE: + std::cout << "GDK_PAD_BUTTON_RELEASE" << std::endl; + break; + case GDK_PAD_RING: + std::cout << "GDK_PAD_RING" << std::endl; + break; + case GDK_PAD_STRIP: + std::cout << "GDK_PAD_STRIP" << std::endl; + break; + case GDK_PAD_GROUP_MODE: + std::cout << "GDK_PAD_GROUP_MODE" << std::endl; + break; + +#endif + + default: + std::cout << "GDK event not recognized!" << std::endl; + break; + } +} + +#endif // SEEN_UI_EVENT_DEBUG_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 : diff --git a/src/ui/object-edit.cpp b/src/ui/object-edit.cpp index b11a61710..c1d85a896 100644 --- a/src/ui/object-edit.cpp +++ b/src/ui/object-edit.cpp @@ -782,6 +782,12 @@ public: virtual void knot_click(unsigned int state); }; +class ArcKnotHolderEntityCenter : public KnotHolderEntity { +public: + virtual Geom::Point knot_get() const; + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state); +}; + /* * return values: * 1 : inside @@ -983,6 +989,30 @@ ArcKnotHolderEntityRY::knot_click(unsigned int state) } } +void +ArcKnotHolderEntityCenter::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state) +{ + SPGenericEllipse *ge = dynamic_cast<SPGenericEllipse *>(item); + g_assert(ge != NULL); + + Geom::Point const s = snap_knot_position(p, state); + + ge->cx = s[Geom::X]; + ge->cy = s[Geom::Y]; + + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); +} + +Geom::Point +ArcKnotHolderEntityCenter::knot_get() const +{ + SPGenericEllipse const *ge = dynamic_cast<SPGenericEllipse *>(item); + g_assert(ge != NULL); + + return Geom::Point(ge->cx.computed, ge->cy.computed); +} + + ArcKnotHolder::ArcKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderReleasedFunc relhandler) : KnotHolder(desktop, item, relhandler) { @@ -990,6 +1020,7 @@ ArcKnotHolder::ArcKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderRelea ArcKnotHolderEntityRY *entity_ry = new ArcKnotHolderEntityRY(); ArcKnotHolderEntityStart *entity_start = new ArcKnotHolderEntityStart(); ArcKnotHolderEntityEnd *entity_end = new ArcKnotHolderEntityEnd(); + ArcKnotHolderEntityCenter *entity_center = new ArcKnotHolderEntityCenter(); entity_rx->create(desktop, item, this, Inkscape::CTRL_TYPE_SIZER, _("Adjust ellipse <b>width</b>, with <b>Ctrl</b> to make circle"), @@ -1011,10 +1042,15 @@ ArcKnotHolder::ArcKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderRelea "ellipse for arc, <b>outside</b> for segment"), SP_KNOT_SHAPE_CIRCLE, SP_KNOT_MODE_XOR); + entity_center->create(desktop, item, this, Inkscape::CTRL_TYPE_POINT, + _("Move the ellipse"), + SP_KNOT_SHAPE_CROSS); + entity.push_back(entity_rx); entity.push_back(entity_ry); entity.push_back(entity_start); entity.push_back(entity_end); + entity.push_back(entity_center); add_pattern_knotholder(); } @@ -1035,6 +1071,12 @@ public: virtual void knot_click(unsigned int state); }; +class StarKnotHolderEntityCenter : public KnotHolderEntity { +public: + virtual Geom::Point knot_get() const; + virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, unsigned int state); +}; + void StarKnotHolderEntity1::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state) { @@ -1092,6 +1134,17 @@ StarKnotHolderEntity2::knot_set(Geom::Point const &p, Geom::Point const &/*origi } } +void +StarKnotHolderEntityCenter::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state) +{ + SPStar *star = dynamic_cast<SPStar *>(item); + g_assert(star != NULL); + + star->center = snap_knot_position(p, state); + + item->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG); +} + Geom::Point StarKnotHolderEntity1::knot_get() const { @@ -1115,6 +1168,17 @@ StarKnotHolderEntity2::knot_get() const return sp_star_get_xy(star, SP_STAR_POINT_KNOT2, 0); } +Geom::Point +StarKnotHolderEntityCenter::knot_get() const +{ + g_assert(item != NULL); + + SPStar const *star = dynamic_cast<SPStar const *>(item); + g_assert(star != NULL); + + return star->center; +} + static void sp_star_knot_click(SPItem *item, unsigned int state) { @@ -1166,6 +1230,12 @@ StarKnotHolder::StarKnotHolder(SPDesktop *desktop, SPItem *item, SPKnotHolderRel entity.push_back(entity2); } + StarKnotHolderEntityCenter *entity_center = new StarKnotHolderEntityCenter(); + entity_center->create(desktop, item, this, Inkscape::CTRL_TYPE_POINT, + _("Move the star"), + SP_KNOT_SHAPE_CROSS); + entity.push_back(entity_center); + add_pattern_knotholder(); } diff --git a/src/ui/tools/calligraphic-tool.cpp b/src/ui/tools/calligraphic-tool.cpp index c2b86b538..7228a52bc 100644 --- a/src/ui/tools/calligraphic-tool.cpp +++ b/src/ui/tools/calligraphic-tool.cpp @@ -60,6 +60,7 @@ #include "verbs.h" #include "ui/tools/calligraphic-tool.h" +#include "ui/tools/freehand-base.h" using Inkscape::DocumentUndo; @@ -771,6 +772,8 @@ bool CalligraphicTool::root_handler(GdkEvent* event) { this->message_context->clear(); ret = TRUE; + } else if (!this->dragging && event->button.button == 1 && !this->space_panning){ + spdc_create_single_dot(this, this->desktop->w2d(motion_w), "/tools/calligraphic", event->button.state); } break; } diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp index 056c723ee..4af70a816 100644 --- a/src/ui/tools/freehand-base.cpp +++ b/src/ui/tools/freehand-base.cpp @@ -913,7 +913,8 @@ static void spdc_free_colors(FreehandBase *dc) } void spdc_create_single_dot(ToolBase *ec, Geom::Point const &pt, char const *tool, guint event_state) { - g_return_if_fail(!strcmp(tool, "/tools/freehand/pen") || !strcmp(tool, "/tools/freehand/pencil")); + g_return_if_fail(!strcmp(tool, "/tools/freehand/pen") || !strcmp(tool, "/tools/freehand/pencil") + || !strcmp(tool, "/tools/calligraphic") ); Glib::ustring tool_path = tool; SPDesktop *desktop = ec->desktop; @@ -937,7 +938,8 @@ void spdc_create_single_dot(ToolBase *ec, Geom::Point const &pt, char const *too // unset stroke and set fill color to former stroke color gchar * str; - str = g_strdup_printf("fill:#%06x;stroke:none;", sp_desktop_get_color_tool(desktop, tool, false) >> 8); + str = strcmp(tool, "/tools/calligraphic") ? g_strdup_printf("fill:#%06x;stroke:none;", sp_desktop_get_color_tool(desktop, tool, false) >> 8) + : g_strdup_printf("fill:#%06x;stroke:#%06x;", sp_desktop_get_color_tool(desktop, tool, true) >> 8, sp_desktop_get_color_tool(desktop, tool, false) >> 8); repr->setAttribute("style", str); g_free(str); @@ -948,6 +950,8 @@ void spdc_create_single_dot(ToolBase *ec, Geom::Point const &pt, char const *too Geom::Affine const i2d (item->i2dt_affine ()); Geom::Point pp = pt * i2d.inverse(); double rad = 0.5 * prefs->getDouble(tool_path + "/dot-size", 3.0); + if (!strcmp(tool, "/tools/calligraphic")) + rad = 0.1 * prefs->getDouble(tool_path + "/width", 3.0) / desktop->current_zoom(); if (event_state & GDK_MOD1_MASK) { // TODO: We vary the dot size between 0.5*rad and 1.5*rad, where rad is the dot size // as specified in prefs. Very simple, but it might be sufficient in practice. If not, diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index 8561e234f..0c948c91c 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -297,9 +297,8 @@ void sp_update_helperpath() { Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i); selectedNodesPositions.push_back(n->position()); } - lpe->setSelectedNodePos(selectedNodesPositions); + lpe->setSelectedNodePoints(selectedNodesPositions); lpe->setCurrentZoom(desktop->current_zoom()); - SPCurve *c = new SPCurve(); SPCurve *cc = new SPCurve(); std::vector<Geom::PathVector> cs = lpe->getCanvasIndicators(SP_LPE_ITEM(selection->singleItem())); diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp index 8c7f54d14..3d755eadc 100644 --- a/src/ui/tools/tool-base.cpp +++ b/src/ui/tools/tool-base.cpp @@ -22,12 +22,21 @@ #include "shortcuts.h" #include "file.h" + +#include "ui/interface.h" +#include "ui/event-debug.h" +#include "ui/tool/control-point.h" +#include "ui/shape-editor.h" #include "ui/tools/tool-base.h" +#include "ui/tools-switch.h" +#include "ui/tools/lpe-tool.h" #include <gdk/gdkkeysyms.h> #include <glibmm/i18n.h> #include "display/sp-canvas.h" +#include "display/sp-canvas-group.h" +#include "display/canvas-rotate.h" #include "xml/node-event-vector.h" #include "sp-cursor.h" #include "desktop.h" @@ -36,16 +45,11 @@ #include "desktop-style.h" #include "sp-namedview.h" #include "selection.h" -#include "ui/interface.h" #include "macros.h" -#include "ui/tools-switch.h" #include "message-context.h" #include "gradient-drag.h" #include "rubberband.h" #include "selcue.h" -#include "ui/tools/lpe-tool.h" -#include "ui/tool/control-point.h" -#include "ui/shape-editor.h" #include "sp-guide.h" #include "knot-ptr.h" @@ -94,7 +98,6 @@ ToolBase::ToolBase(gchar const *const *cursor_shape, gint hot_x, gint hot_y, boo , _grdrag(NULL) , shape_editor(NULL) , space_panning(false) - , rotating_mode(false) , _delayed_snap_event(NULL) , _dse_callback_in_process(false) , desktop(NULL) @@ -324,134 +327,120 @@ static gdouble accelerate_scroll(GdkEvent *event, gdouble acceleration, } bool ToolBase::root_handler(GdkEvent* event) { + + // ui_dump_event (event, "ToolBase::root_handler"); static Geom::Point button_w; static unsigned int panning = 0; static unsigned int panning_cursor = 0; static unsigned int zoom_rb = 0; - static double angle = 0; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); /// @todo REmove redundant /value in preference keys tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); bool allow_panning = prefs->getBool("/options/spacebarpans/value"); - int rotation_snap = 180.0/prefs->getInt("/options/rotationsnapsperpi/value", 12); gint ret = FALSE; switch (event->type) { - case GDK_2BUTTON_PRESS: - if (panning) { - panning = 0; - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); + case GDK_2BUTTON_PRESS: + if (panning) { + panning = 0; + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); + ret = TRUE; + } else { + /* sp_desktop_dialog(); */ + } + break; + + case GDK_BUTTON_PRESS: + // save drag origin + xp = (gint) event->button.x; + yp = (gint) event->button.y; + within_tolerance = true; + + button_w = Geom::Point(event->button.x, event->button.y); + + switch (event->button.button) { + case 1: + if (this->space_panning) { + // When starting panning, make sure there are no snap events pending because these might disable the panning again + if (_uses_snap) { + sp_event_context_discard_delayed_snap_event(this); + } + panning = 1; + + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), + GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK, NULL, + event->button.time - 1); + ret = TRUE; - } else { - /* sp_desktop_dialog(); */ } break; - case GDK_BUTTON_PRESS: - // save drag origin - xp = (gint) event->button.x; - yp = (gint) event->button.y; - within_tolerance = true; + case 2: + if (event->button.state & GDK_CONTROL_MASK) { + // On screen canvas rotation preview + + // Grab background before doing anything else + sp_canvas_rotate_start (SP_CANVAS_ROTATE(desktop->canvas_rotate), + desktop->canvas->_backing_store); + sp_canvas_item_ungrab (desktop->acetate, event->button.time); + sp_canvas_item_show (desktop->canvas_rotate); + sp_canvas_item_grab (desktop->canvas_rotate, + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK, + NULL, event->button.time ); + // sp_canvas_item_hide (desktop->drawing); + + } else if (event->button.state & GDK_SHIFT_MASK) { + zoom_rb = 2; + } else { + // When starting panning, make sure there are no snap events pending because these might disable the panning again + if (_uses_snap) { + sp_event_context_discard_delayed_snap_event(this); + } + panning = 2; - button_w = Geom::Point(event->button.x, event->button.y); - switch (event->button.button) { - case 1: - if (this->space_panning) { - // When starting panning, make sure there are no snap events pending because these might disable the panning again - if (_uses_snap) { - sp_event_context_discard_delayed_snap_event(this); - } - panning = 1; + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK, + NULL, event->button.time - 1); - sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), - GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK - | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK, NULL, - event->button.time - 1); + } - ret = TRUE; - } - desktop->canvas->clearRotateTo(); - this->rotating_mode = false; - break; + ret = TRUE; + break; - case 2: - if (event->button.state & GDK_CONTROL_MASK) { - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); - desktop->canvas->startRotateTo(desktop->namedview->document_rotation); - this->rotating_mode = true; - this->message_context->set(Inkscape::INFORMATION_MESSAGE, - _("<b>MMB + mouse move</b> to rotate canvas, use modifiers on screen to change snaps")); - } else { - if (event->button.state & GDK_SHIFT_MASK) { - zoom_rb = 2; - } else { - // When starting panning, make sure there are no snap events pending because these might disable the panning again - if (_uses_snap) { - sp_event_context_discard_delayed_snap_event(this); - } - panning = 2; - - sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), - GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK, NULL, - event->button.time - 1); - } - ret = TRUE; + case 3: + if ((event->button.state & GDK_SHIFT_MASK) || (event->button.state & GDK_CONTROL_MASK)) { + // When starting panning, make sure there are no snap events pending because these might disable the panning again + if (_uses_snap) { + sp_event_context_discard_delayed_snap_event(this); } - ret = TRUE; - break; - - case 3: - if ((event->button.state & GDK_SHIFT_MASK) || (event->button.state & GDK_CONTROL_MASK)) { - // When starting panning, make sure there are no snap events pending because these might disable the panning again - if (_uses_snap) { - sp_event_context_discard_delayed_snap_event(this); - } - panning = 3; + panning = 3; - sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), - GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK, NULL, - event->button.time); + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK, NULL, + event->button.time); - ret = TRUE; - } else if( !this->space_panning) { - sp_event_root_menu_popup(desktop, NULL, event); - } ret = TRUE; - desktop->canvas->clearRotateTo(); - this->rotating_mode = false; - break; - - default: - break; + } else { + sp_event_root_menu_popup(desktop, NULL, event); } break; - case GDK_MOTION_NOTIFY: - if (this->rotating_mode) { - button_w = Geom::Point(event->motion.x, event->motion.y); - Geom::Point const motion_dt(desktop->doc2dt(desktop->w2d(button_w))); - Geom::Rect view = desktop->get_display_area(); - Geom::Point view_center = desktop->doc2dt(view.midpoint()); - Geom::Ray center_ray(motion_dt, view_center); - angle = Geom::deg_from_rad(center_ray.angle()) - 90; - if (event->motion.state & GDK_SHIFT_MASK && event->motion.state & GDK_CONTROL_MASK) { - angle = 0; - } else if(event->motion.state & GDK_CONTROL_MASK) { - angle = floor(angle/rotation_snap) * rotation_snap; - } else if (event->motion.state & GDK_SHIFT_MASK) { - angle = desktop->namedview->document_rotation; - } else if (event->motion.state & GDK_MOD1_MASK) { - //Decimal raw angle - } else { - angle = floor(angle); - } - desktop->canvas->rotateTo(angle); - } else if (panning == 4 && !xp && !yp ) { + default: + break; + } + break; + + case GDK_MOTION_NOTIFY: + if (panning) { + if (panning == 4 && !xp && !yp ) { // <Space> + mouse panning started, save location and grab canvas xp = event->motion.x; yp = event->motion.y; @@ -463,465 +452,430 @@ bool ToolBase::root_handler(GdkEvent* event) { | GDK_POINTER_MOTION_HINT_MASK, NULL, event->motion.time - 1); } - if (panning && !this->rotating_mode) { - if ((panning == 2 && !(event->motion.state & GDK_BUTTON2_MASK)) - || (panning == 1 && !(event->motion.state & GDK_BUTTON1_MASK)) - || (panning == 3 && !(event->motion.state & GDK_BUTTON3_MASK))) { - /* Gdk seems to lose button release for us sometimes :-( */ - panning = 0; - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); - ret = TRUE; - } else { - if (within_tolerance && (abs((gint) event->motion.x - xp) - < tolerance) && (abs((gint) event->motion.y - yp) - < tolerance)) { - // do not drag if we're within tolerance from origin - break; - } - - // Once the user has moved farther than tolerance from - // the original location (indicating they intend to move - // the object, not click), then always process the motion - // notify coordinates as given (no snapping back to origin) - within_tolerance = false; - - // gobble subsequent motion events to prevent "sticking" - // when scrolling is slow - gobble_motion_events(panning == 2 ? GDK_BUTTON2_MASK : (panning - == 1 ? GDK_BUTTON1_MASK : GDK_BUTTON3_MASK)); - - if (panning_cursor == 0) { - panning_cursor = 1; - this->sp_event_context_set_cursor(GDK_FLEUR); - } - - Geom::Point const motion_w(event->motion.x, event->motion.y); - Geom::Point const moved_w(motion_w - button_w); - this->desktop->scroll_relative(moved_w, true); // we're still scrolling, do not redraw - ret = TRUE; - } - } else if (zoom_rb) { - Geom::Point const motion_w(event->motion.x, event->motion.y); - Geom::Point const motion_dt(desktop->w2d(motion_w)); + if ((panning == 2 && !(event->motion.state & GDK_BUTTON2_MASK)) + || (panning == 1 && !(event->motion.state & GDK_BUTTON1_MASK)) + || (panning == 3 && !(event->motion.state & GDK_BUTTON3_MASK))) { + /* Gdk seems to lose button release for us sometimes :-( */ + panning = 0; + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); + ret = TRUE; + } else { if (within_tolerance && (abs((gint) event->motion.x - xp) < tolerance) && (abs((gint) event->motion.y - yp) < tolerance)) { - break; // do not drag if we're within tolerance from origin + // do not drag if we're within tolerance from origin + break; } - // Once the user has moved farther than tolerance from the original location - // (indicating they intend to move the object, not click), then always process the - // motion notify coordinates as given (no snapping back to origin) + // Once the user has moved farther than tolerance from + // the original location (indicating they intend to move + // the object, not click), then always process the motion + // notify coordinates as given (no snapping back to origin) within_tolerance = false; - if (Inkscape::Rubberband::get(desktop)->is_started()) { - Inkscape::Rubberband::get(desktop)->move(motion_dt); - } else { - Inkscape::Rubberband::get(desktop)->start(desktop, motion_dt); - } + // gobble subsequent motion events to prevent "sticking" + // when scrolling is slow + gobble_motion_events(panning == 2 ? GDK_BUTTON2_MASK : (panning + == 1 ? GDK_BUTTON1_MASK : GDK_BUTTON3_MASK)); - if (zoom_rb == 2) { - gobble_motion_events(GDK_BUTTON2_MASK); + if (panning_cursor == 0) { + panning_cursor = 1; + this->sp_event_context_set_cursor(GDK_FLEUR); } - } - break; - case GDK_BUTTON_RELEASE: - if (this->rotating_mode && event->button.button == 2) { - desktop->canvas->clearRotateTo(); - this->rotating_mode = false; + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point const moved_w(motion_w - button_w); + this->desktop->scroll_relative(moved_w, true); // we're still scrolling, do not redraw ret = TRUE; - if (desktop->canvas->endRotateTo()) { - sp_repr_set_svg_double(desktop->namedview->getRepr(), "inkscape:document-rotation", angle); - } + } + } else if (zoom_rb) { + Geom::Point const motion_w(event->motion.x, event->motion.y); + Geom::Point const motion_dt(desktop->w2d(motion_w)); + + if (within_tolerance && (abs((gint) event->motion.x - xp) + < tolerance) && (abs((gint) event->motion.y - yp) + < tolerance)) { + break; // do not drag if we're within tolerance from origin + } + + // Once the user has moved farther than tolerance from the original location + // (indicating they intend to move the object, not click), then always process the + // motion notify coordinates as given (no snapping back to origin) + within_tolerance = false; + + if (Inkscape::Rubberband::get(desktop)->is_started()) { + Inkscape::Rubberband::get(desktop)->move(motion_dt); } else { - xp = yp = 0; - if (panning_cursor == 1) { - panning_cursor = 0; - GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas()); - gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor); - } + Inkscape::Rubberband::get(desktop)->start(desktop, motion_dt); + } - if (within_tolerance && (panning || zoom_rb)) { - zoom_rb = 0; + if (zoom_rb == 2) { + gobble_motion_events(GDK_BUTTON2_MASK); + } + } + break; - if (panning) { - panning = 0; - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), - event->button.time); - } + case GDK_BUTTON_RELEASE: - Geom::Point const event_w(event->button.x, event->button.y); - Geom::Point const event_dt(desktop->w2d(event_w)); + xp = yp = 0; - double const zoom_inc = prefs->getDoubleLimited( - "/options/zoomincrement/value", M_SQRT2, 1.01, 10); + if (panning_cursor == 1) { + panning_cursor = 0; + GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas()); + gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor); + } - desktop->zoom_relative_keep_point(event_dt, (event->button.state - & GDK_SHIFT_MASK) ? 1 / zoom_inc : zoom_inc); + if (within_tolerance && (panning || zoom_rb)) { + zoom_rb = 0; - desktop->updateNow(); - ret = TRUE; - } else if (panning == event->button.button) { - panning = 0; - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), - event->button.time); + if (panning) { + panning = 0; + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), + event->button.time); + } - // in slow complex drawings, some of the motion events are lost; - // to make up for this, we scroll it once again to the button-up event coordinates - // (i.e. canvas will always get scrolled all the way to the mouse release point, - // even if few intermediate steps were visible) - Geom::Point const motion_w(event->button.x, event->button.y); - Geom::Point const moved_w(motion_w - button_w); + Geom::Point const event_w(event->button.x, event->button.y); + Geom::Point const event_dt(desktop->w2d(event_w)); - this->desktop->scroll_relative(moved_w); - desktop->updateNow(); - ret = TRUE; - } else if (zoom_rb == event->button.button) { - zoom_rb = 0; + double const zoom_inc = prefs->getDoubleLimited( + "/options/zoomincrement/value", M_SQRT2, 1.01, 10); - Geom::OptRect const b = Inkscape::Rubberband::get(desktop)->getRectangle(); - Inkscape::Rubberband::get(desktop)->stop(); + desktop->zoom_relative_keep_point(event_dt, (event->button.state + & GDK_SHIFT_MASK) ? 1 / zoom_inc : zoom_inc); - if (b && !within_tolerance) { - desktop->set_display_area(*b, 10); - } + desktop->updateNow(); + ret = TRUE; + } else if (panning == event->button.button) { + panning = 0; + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), + event->button.time); + + // in slow complex drawings, some of the motion events are lost; + // to make up for this, we scroll it once again to the button-up event coordinates + // (i.e. canvas will always get scrolled all the way to the mouse release point, + // even if few intermediate steps were visible) + Geom::Point const motion_w(event->button.x, event->button.y); + Geom::Point const moved_w(motion_w - button_w); + + this->desktop->scroll_relative(moved_w); + desktop->updateNow(); + ret = TRUE; + } else if (zoom_rb == event->button.button) { + zoom_rb = 0; - ret = TRUE; - } - if (this->rotating_mode && event->button.button != 3) { - desktop->canvas->clearRotateTo(); - this->rotating_mode = false; - ret = TRUE; - desktop->canvas->endRotateTo(); - } - } - break; + Geom::OptRect const b = Inkscape::Rubberband::get(desktop)->getRectangle(); + Inkscape::Rubberband::get(desktop)->stop(); - case GDK_KEY_PRESS: { - double const acceleration = prefs->getDoubleLimited( - "/options/scrollingacceleration/value", 0, 0, 6); - int const key_scroll = prefs->getIntLimited("/options/keyscroll/value", - 10, 0, 1000); - - if (this->rotating_mode && - get_group0_keyval(&event->key) != GDK_KEY_space && - get_group0_keyval(&event->key) != GDK_KEY_Shift_L && - get_group0_keyval(&event->key) != GDK_KEY_Shift_R && - get_group0_keyval(&event->key) != GDK_KEY_Control_L && - get_group0_keyval(&event->key) != GDK_KEY_Control_R && - get_group0_keyval(&event->key) != GDK_KEY_Alt_L && - get_group0_keyval(&event->key) != GDK_KEY_Alt_R ) - { - desktop->canvas->clearRotateTo(); - this->rotating_mode = false; - ret = TRUE; - desktop->canvas->endRotateTo(); - break; + if (b && !within_tolerance) { + desktop->set_display_area(*b, 10); } - switch (get_group0_keyval(&event->key)) { - // GDK insists on stealing these keys (F1 for no idea what, tab for cycling widgets - // in the editing window). So we resteal them back and run our regular shortcut - // invoker on them. - unsigned int shortcut; - case GDK_KEY_Tab: - case GDK_KEY_ISO_Left_Tab: - case GDK_KEY_F1: - shortcut = get_group0_keyval(&event->key); - - if (event->key.state & GDK_SHIFT_MASK) { - shortcut |= SP_SHORTCUT_SHIFT_MASK; - } + ret = TRUE; + } + break; - if (event->key.state & GDK_CONTROL_MASK) { - shortcut |= SP_SHORTCUT_CONTROL_MASK; - } + case GDK_KEY_PRESS: { + double const acceleration = prefs->getDoubleLimited( + "/options/scrollingacceleration/value", 0, 0, 6); + int const key_scroll = prefs->getIntLimited("/options/keyscroll/value", + 10, 0, 1000); + + switch (get_group0_keyval(&event->key)) { + // GDK insists on stealing these keys (F1 for no idea what, tab for cycling widgets + // in the editing window). So we resteal them back and run our regular shortcut + // invoker on them. + unsigned int shortcut; + case GDK_KEY_Tab: + case GDK_KEY_ISO_Left_Tab: + case GDK_KEY_F1: + shortcut = get_group0_keyval(&event->key); + + if (event->key.state & GDK_SHIFT_MASK) { + shortcut |= SP_SHORTCUT_SHIFT_MASK; + } - if (event->key.state & GDK_MOD1_MASK) { - shortcut |= SP_SHORTCUT_ALT_MASK; - } + if (event->key.state & GDK_CONTROL_MASK) { + shortcut |= SP_SHORTCUT_CONTROL_MASK; + } - ret = sp_shortcut_invoke(shortcut, desktop); - break; + if (event->key.state & GDK_MOD1_MASK) { + shortcut |= SP_SHORTCUT_ALT_MASK; + } - case GDK_KEY_Q: - case GDK_KEY_q: - if (desktop->quick_zoomed()) { - ret = TRUE; - } - if (!MOD__SHIFT(event) && !MOD__CTRL(event) && !MOD__ALT(event)) { - desktop->zoom_quick(true); - ret = TRUE; - } - break; + ret = sp_shortcut_invoke(shortcut, desktop); + break; - case GDK_KEY_W: - case GDK_KEY_w: - case GDK_KEY_F4: - /* Close view */ - if (MOD__CTRL_ONLY(event)) { - sp_ui_close_view(NULL); - ret = TRUE; - } - break; + case GDK_KEY_Q: + case GDK_KEY_q: + if (desktop->quick_zoomed()) { + ret = TRUE; + } + if (!MOD__SHIFT(event) && !MOD__CTRL(event) && !MOD__ALT(event)) { + desktop->zoom_quick(true); + ret = TRUE; + } + break; - case GDK_KEY_Left: // Ctrl Left - case GDK_KEY_KP_Left: - case GDK_KEY_KP_4: - if (MOD__CTRL_ONLY(event)) { - int i = (int) floor(key_scroll * accelerate_scroll(event, - acceleration, desktop->getCanvas())); + case GDK_KEY_W: + case GDK_KEY_w: + case GDK_KEY_F4: + /* Close view */ + if (MOD__CTRL_ONLY(event)) { + sp_ui_close_view(NULL); + ret = TRUE; + } + break; - gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); - this->desktop->scroll_relative(Geom::Point(i, 0)); - ret = TRUE; - } - break; + case GDK_KEY_Left: // Ctrl Left + case GDK_KEY_KP_Left: + case GDK_KEY_KP_4: + if (MOD__CTRL_ONLY(event)) { + int i = (int) floor(key_scroll * accelerate_scroll(event, + acceleration, desktop->getCanvas())); - case GDK_KEY_Up: // Ctrl Up - case GDK_KEY_KP_Up: - case GDK_KEY_KP_8: - if (MOD__CTRL_ONLY(event)) { - int i = (int) floor(key_scroll * accelerate_scroll(event, - acceleration, desktop->getCanvas())); + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); + this->desktop->scroll_relative(Geom::Point(i, 0)); + ret = TRUE; + } + break; - gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); - this->desktop->scroll_relative(Geom::Point(0, i)); - ret = TRUE; - } - break; + case GDK_KEY_Up: // Ctrl Up + case GDK_KEY_KP_Up: + case GDK_KEY_KP_8: + if (MOD__CTRL_ONLY(event)) { + int i = (int) floor(key_scroll * accelerate_scroll(event, + acceleration, desktop->getCanvas())); - case GDK_KEY_Right: // Ctrl Right - case GDK_KEY_KP_Right: - case GDK_KEY_KP_6: - if (MOD__CTRL_ONLY(event)) { - int i = (int) floor(key_scroll * accelerate_scroll(event, - acceleration, desktop->getCanvas())); + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); + this->desktop->scroll_relative(Geom::Point(0, i)); + ret = TRUE; + } + break; - gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); - this->desktop->scroll_relative(Geom::Point(-i, 0)); - ret = TRUE; - } - break; + case GDK_KEY_Right: // Ctrl Right + case GDK_KEY_KP_Right: + case GDK_KEY_KP_6: + if (MOD__CTRL_ONLY(event)) { + int i = (int) floor(key_scroll * accelerate_scroll(event, + acceleration, desktop->getCanvas())); - case GDK_KEY_Down: // Ctrl Down - case GDK_KEY_KP_Down: - case GDK_KEY_KP_2: - if (MOD__CTRL_ONLY(event)) { - int i = (int) floor(key_scroll * accelerate_scroll(event, - acceleration, desktop->getCanvas())); + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); + this->desktop->scroll_relative(Geom::Point(-i, 0)); + ret = TRUE; + } + break; - gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); - this->desktop->scroll_relative(Geom::Point(0, -i)); - ret = TRUE; - } - break; + case GDK_KEY_Down: // Ctrl Down + case GDK_KEY_KP_Down: + case GDK_KEY_KP_2: + if (MOD__CTRL_ONLY(event)) { + int i = (int) floor(key_scroll * accelerate_scroll(event, + acceleration, desktop->getCanvas())); - case GDK_KEY_Menu: - sp_event_root_menu_popup(desktop, NULL, event); + gobble_key_events(get_group0_keyval(&event->key), GDK_CONTROL_MASK); + this->desktop->scroll_relative(Geom::Point(0, -i)); ret = TRUE; - break; + } + break; - case GDK_KEY_F10: - if (MOD__SHIFT_ONLY(event)) { - sp_event_root_menu_popup(desktop, NULL, event); - ret = TRUE; - } - break; + case GDK_KEY_Menu: + sp_event_root_menu_popup(desktop, NULL, event); + ret = TRUE; + break; - case GDK_KEY_space: -// if (event->key.state & GDK_CONTROL_MASK) { -// sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time); -// desktop->canvas->startRotateTo(desktop->namedview->document_rotation); -// this->rotating_mode = true; -// this->message_context->set(Inkscape::INFORMATION_MESSAGE, -// _("<b>Space+mouse move</b> to rotate canvas, use modifiers on screen to change snaps")); -// } else { - within_tolerance = true; - xp = yp = 0; - if (!allow_panning) break; - panning = 4; - this->space_panning = true; - this->message_context->set(Inkscape::INFORMATION_MESSAGE, - _("<b>Space+mouse move</b> to pan canvas")); -// } + case GDK_KEY_F10: + if (MOD__SHIFT_ONLY(event)) { + sp_event_root_menu_popup(desktop, NULL, event); ret = TRUE; - break; + } + break; - case GDK_KEY_z: - case GDK_KEY_Z: - if (MOD__ALT_ONLY(event)) { - desktop->zoom_grab_focus(); - ret = TRUE; - } - break; + case GDK_KEY_space: + within_tolerance = true; + xp = yp = 0; + if (!allow_panning) break; + panning = 4; + this->space_panning = true; + this->message_context->set(Inkscape::INFORMATION_MESSAGE, + _("<b>Space+mouse move</b> to pan canvas")); - default: - break; - } - } + ret = TRUE; break; - case GDK_KEY_RELEASE: - if (this->rotating_mode && - get_group0_keyval(&event->key) != GDK_KEY_space && - get_group0_keyval(&event->key) != GDK_KEY_Shift_L && - get_group0_keyval(&event->key) != GDK_KEY_Shift_R && - get_group0_keyval(&event->key) != GDK_KEY_Control_L && - get_group0_keyval(&event->key) != GDK_KEY_Control_R && - get_group0_keyval(&event->key) != GDK_KEY_Alt_L && - get_group0_keyval(&event->key) != GDK_KEY_Alt_R ) - { - desktop->canvas->clearRotateTo(); - this->rotating_mode = false; + case GDK_KEY_z: + case GDK_KEY_Z: + if (MOD__ALT_ONLY(event)) { + desktop->zoom_grab_focus(); ret = TRUE; - desktop->canvas->endRotateTo(); - break; } + break; - // Stop panning on any key release - if (this->space_panning) { - this->space_panning = false; - this->message_context->clear(); + default: + break; } + } + break; - if (panning) { - panning = 0; - xp = yp = 0; + case GDK_KEY_RELEASE: + // Stop panning on any key release + if (this->space_panning) { + this->space_panning = false; + this->message_context->clear(); + } - sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), - event->key.time); + if (panning) { + panning = 0; + xp = yp = 0; + + sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), + event->key.time); + + desktop->updateNow(); + } + + if (panning_cursor == 1) { + panning_cursor = 0; + GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas()); + gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor); + } + + switch (get_group0_keyval(&event->key)) { + case GDK_KEY_space: + if (within_tolerance) { + // Space was pressed, but not panned + sp_toggle_selector(desktop); - desktop->updateNow(); + // Be careful, sp_toggle_selector will delete ourselves. + // Thus, make sure we return immediately. + return true; } - if (panning_cursor == 1) { - panning_cursor = 0; - GtkWidget *w = GTK_WIDGET(this->desktop->getCanvas()); - gdk_window_set_cursor(gtk_widget_get_window (w), this->cursor); + break; + + case GDK_KEY_Q: + case GDK_KEY_q: + if (desktop->quick_zoomed()) { + desktop->zoom_quick(false); + ret = TRUE; } + break; - switch (get_group0_keyval(&event->key)) { - case GDK_KEY_space: -// if (this->rotating_mode) { -// desktop->canvas->clearRotateTo(); -// this->rotating_mode = false; -// ret = TRUE; -// if (desktop->canvas->endRotateTo()) { -// sp_repr_set_svg_double(desktop->namedview->getRepr(), "inkscape:document-rotation", angle); -// } -// } - if (within_tolerance) { - // Space was pressed, but not panned - sp_toggle_selector(desktop); - - // Be careful, sp_toggle_selector will delete ourselves. - // Thus, make sure we return immediately. - return true; - } + default: + break; + } + break; + + case GDK_SCROLL: { + bool ctrl = (event->scroll.state & GDK_CONTROL_MASK); + bool shift = (event->scroll.state & GDK_SHIFT_MASK); + bool wheelzooms = prefs->getBool("/options/wheelzooms/value"); + + int const wheel_scroll = prefs->getIntLimited( + "/options/wheelscroll/value", 40, 0, 1000); + + // Size of smooth-scrolls (only used in GTK+ 3) + gdouble delta_x = 0; + gdouble delta_y = 0; + + if (ctrl & shift) { + /* ctrl + shift, rotate */ + + double rotate_inc = prefs->getDoubleLimited( + "/options/rotateincrement/value", 15, 1, 90, "°" ); + rotate_inc *= M_PI/180.0; + + switch (event->scroll.direction) { + case GDK_SCROLL_UP: + // Do nothing break; - case GDK_KEY_Q: - case GDK_KEY_q: - if (desktop->quick_zoomed()) { - desktop->zoom_quick(false); - ret = TRUE; - } + case GDK_SCROLL_DOWN: + rotate_inc = -rotate_inc; break; default: + rotate_inc = 0.0; break; } - break; - case GDK_SCROLL: { - if (this->rotating_mode) { - desktop->canvas->clearRotateTo(); - this->rotating_mode = false; - desktop->canvas->endRotateTo(); + if (rotate_inc != 0.0) { + Geom::Point const scroll_dt = desktop->point(); + desktop->rotate_relative_keep_point(scroll_dt, rotate_inc); } - bool ctrl = (event->scroll.state & GDK_CONTROL_MASK); - bool wheelzooms = prefs->getBool("/options/wheelzooms/value"); - - int const wheel_scroll = prefs->getIntLimited( - "/options/wheelscroll/value", 40, 0, 1000); - // Size of smooth-scrolls (only used in GTK+ 3) - gdouble delta_x = 0; - gdouble delta_y = 0; + } else if (event->scroll.state & GDK_SHIFT_MASK) { + /* shift + wheel, pan left--right */ - /* shift + wheel, pan left--right */ - if (event->scroll.state & GDK_SHIFT_MASK) { - switch (event->scroll.direction) { - case GDK_SCROLL_UP: - desktop->scroll_relative(Geom::Point(wheel_scroll, 0)); - break; + switch (event->scroll.direction) { + case GDK_SCROLL_UP: + desktop->scroll_relative(Geom::Point(wheel_scroll, 0)); + break; - case GDK_SCROLL_DOWN: - desktop->scroll_relative(Geom::Point(-wheel_scroll, 0)); - break; + case GDK_SCROLL_DOWN: + desktop->scroll_relative(Geom::Point(-wheel_scroll, 0)); + break; - default: - break; - } + default: + break; + } - /* ctrl + wheel, zoom in--out */ - } else if ((ctrl && !wheelzooms) || (!ctrl && wheelzooms)) { - double rel_zoom; - double const zoom_inc = prefs->getDoubleLimited( - "/options/zoomincrement/value", M_SQRT2, 1.01, 10); + } else if ((ctrl && !wheelzooms) || (!ctrl && wheelzooms)) { + /* ctrl + wheel, zoom in--out */ + double rel_zoom; + double const zoom_inc = prefs->getDoubleLimited( + "/options/zoomincrement/value", M_SQRT2, 1.01, 10); - switch (event->scroll.direction) { - case GDK_SCROLL_UP: - rel_zoom = zoom_inc; - break; + switch (event->scroll.direction) { + case GDK_SCROLL_UP: + rel_zoom = zoom_inc; + break; - case GDK_SCROLL_DOWN: - rel_zoom = 1 / zoom_inc; - break; + case GDK_SCROLL_DOWN: + rel_zoom = 1 / zoom_inc; + break; - default: - rel_zoom = 0.0; - break; - } + default: + rel_zoom = 0.0; + break; + } - if (rel_zoom != 0.0) { - Geom::Point const scroll_dt = desktop->point(); - desktop->zoom_relative_keep_point(scroll_dt, rel_zoom); - } + if (rel_zoom != 0.0) { + Geom::Point const scroll_dt = desktop->point(); + desktop->zoom_relative_keep_point(scroll_dt, rel_zoom); + } - /* no modifier, pan up--down (left--right on multiwheel mice?) */ - } else { - switch (event->scroll.direction) { - case GDK_SCROLL_UP: - desktop->scroll_relative(Geom::Point(0, wheel_scroll)); - break; + /* no modifier, pan up--down (left--right on multiwheel mice?) */ + } else { + switch (event->scroll.direction) { + case GDK_SCROLL_UP: + desktop->scroll_relative(Geom::Point(0, wheel_scroll)); + break; - case GDK_SCROLL_DOWN: - desktop->scroll_relative(Geom::Point(0, -wheel_scroll)); - break; + case GDK_SCROLL_DOWN: + desktop->scroll_relative(Geom::Point(0, -wheel_scroll)); + break; - case GDK_SCROLL_LEFT: - desktop->scroll_relative(Geom::Point(wheel_scroll, 0)); - break; + case GDK_SCROLL_LEFT: + desktop->scroll_relative(Geom::Point(wheel_scroll, 0)); + break; - case GDK_SCROLL_RIGHT: - desktop->scroll_relative(Geom::Point(-wheel_scroll, 0)); - break; + case GDK_SCROLL_RIGHT: + desktop->scroll_relative(Geom::Point(-wheel_scroll, 0)); + break; - case GDK_SCROLL_SMOOTH: - gdk_event_get_scroll_deltas(event, &delta_x, &delta_y); - desktop->scroll_relative(Geom::Point(delta_x, delta_y)); - break; - } + case GDK_SCROLL_SMOOTH: + gdk_event_get_scroll_deltas(event, &delta_x, &delta_y); + desktop->scroll_relative(Geom::Point(delta_x, delta_y)); + break; } - break; } - default: - break; + break; } + default: + break; + } + return ret; } @@ -1255,47 +1209,6 @@ sp_event_context_get_shape_editor(ToolBase *ec) { return ec->shape_editor; } -void event_context_print_event_info(GdkEvent *event, bool print_return) { - switch (event->type) { - case GDK_BUTTON_PRESS: - g_print("GDK_BUTTON_PRESS"); - break; - case GDK_2BUTTON_PRESS: - g_print("GDK_2BUTTON_PRESS"); - break; - case GDK_3BUTTON_PRESS: - g_print("GDK_3BUTTON_PRESS"); - break; - - case GDK_MOTION_NOTIFY: - g_print("GDK_MOTION_NOTIFY"); - break; - case GDK_ENTER_NOTIFY: - g_print("GDK_ENTER_NOTIFY"); - break; - - case GDK_LEAVE_NOTIFY: - g_print("GDK_LEAVE_NOTIFY"); - break; - case GDK_BUTTON_RELEASE: - g_print("GDK_BUTTON_RELEASE"); - break; - - case GDK_KEY_PRESS: - g_print("GDK_KEY_PRESS: %d", get_group0_keyval(&event->key)); - break; - case GDK_KEY_RELEASE: - g_print("GDK_KEY_RELEASE: %d", get_group0_keyval(&event->key)); - break; - default: - //g_print ("even type not recognized"); - break; - } - - if (print_return) { - g_print("\n"); - } -} /** * Analyses the current event, calculates the mouse speed, turns snapping off (temporarily) if the diff --git a/src/ui/tools/zoom-tool.cpp b/src/ui/tools/zoom-tool.cpp index ca42d2d6f..d40d2e969 100644 --- a/src/ui/tools/zoom-tool.cpp +++ b/src/ui/tools/zoom-tool.cpp @@ -103,12 +103,14 @@ bool ZoomTool::root_handler(GdkEvent* event) { desktop->zoom_relative_keep_point(button_dt, zoom_rel); ret = true; } - - sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), - GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK, - NULL, event->button.time); - this->grabbed = SP_CANVAS_ITEM(desktop->acetate); + sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK, + NULL, event->button.time); + + this->grabbed = SP_CANVAS_ITEM(desktop->acetate); break; } @@ -156,10 +158,10 @@ bool ZoomTool::root_handler(GdkEvent* event) { Inkscape::Rubberband::get(desktop)->stop(); - if (this->grabbed) { - sp_canvas_item_ungrab(this->grabbed, event->button.time); - this->grabbed = NULL; - } + if (this->grabbed) { + sp_canvas_item_ungrab(this->grabbed, event->button.time); + this->grabbed = NULL; + } xp = yp = 0; escaped = false; diff --git a/src/ui/view/edit-widget-interface.h b/src/ui/view/edit-widget-interface.h index fcba0c6da..c93b1f0ee 100644 --- a/src/ui/view/edit-widget-interface.h +++ b/src/ui/view/edit-widget-interface.h @@ -128,6 +128,9 @@ struct EditWidgetInterface /// The zoom display will get the keyboard focus. virtual void letZoomGrabFocus() = 0; + /// Temporarily block signals and update rotation display + virtual void updateRotation() = 0; + /// In auxiliary toolbox, set focus to widget having specific id virtual void setToolboxFocusTo (const gchar *) = 0; diff --git a/src/ui/widget/color-scales.cpp b/src/ui/widget/color-scales.cpp index 89913b01b..4023d227c 100644 --- a/src/ui/widget/color-scales.cpp +++ b/src/ui/widget/color-scales.cpp @@ -48,6 +48,7 @@ ColorScales::ColorScales(SelectedColor &color, SPColorScalesMode mode) , _rangeLimit(255.0) , _updating(FALSE) , _dragging(FALSE) + , _mode(SP_COLOR_SCALES_MODE_NONE) { for (gint i = 0; i < 5; i++) { _l[i] = 0; diff --git a/src/ui/widget/rotateable.cpp b/src/ui/widget/rotateable.cpp index e0de22335..0e290730d 100644 --- a/src/ui/widget/rotateable.cpp +++ b/src/ui/widget/rotateable.cpp @@ -34,6 +34,7 @@ Rotateable::Rotateable(): signal_button_press_event().connect(sigc::mem_fun(*this, &Rotateable::on_click)); signal_motion_notify_event().connect(sigc::mem_fun(*this, &Rotateable::on_motion)); signal_button_release_event().connect(sigc::mem_fun(*this, &Rotateable::on_release)); + gtk_widget_add_events(GTK_WIDGET(gobj()), GDK_SCROLL_MASK); signal_scroll_event().connect(sigc::mem_fun(*this, &Rotateable::on_scroll)); } diff --git a/src/ui/widget/selected-style.cpp b/src/ui/widget/selected-style.cpp index 0370d55db..65d68195c 100644 --- a/src/ui/widget/selected-style.cpp +++ b/src/ui/widget/selected-style.cpp @@ -1380,13 +1380,8 @@ RotateableStrokeWidth::value_adjust(double current, double by, guint /*modifier* { double newval; // by is -1..1 - if (by < 0) { - // map negative 0..-1 to current..0 - newval = current * (1 + by); - } else { - // map positive 0..1 to current..4*current - newval = current * (1 + by) * (1 + by); - } + double max_f = 50; // maximum width is (current * max_f), minimum - zero + newval = current * (std::exp(std::log(max_f-1) * (by+1)) - 1) / (max_f-2); SPCSSAttr *css = sp_repr_css_attr_new (); if (final && newval < 1e-6) { @@ -1394,6 +1389,7 @@ RotateableStrokeWidth::value_adjust(double current, double by, guint /*modifier* // if it's not final, leave it a chance to increase again (which is not possible with "none") sp_repr_css_set_property (css, "stroke", "none"); } else { + newval = Inkscape::Util::Quantity::convert(newval, parent->_sw_unit, "px"); Inkscape::CSSOStringStream os; os << newval; sp_repr_css_set_property (css, "stroke-width", os.str().c_str()); diff --git a/src/ui/widget/selected-style.h b/src/ui/widget/selected-style.h index efac29f73..065d745f0 100644 --- a/src/ui/widget/selected-style.h +++ b/src/ui/widget/selected-style.h @@ -131,6 +131,7 @@ public: guint _mode[2]; double current_stroke_width; + Inkscape::Util::Unit const *_sw_unit; // points to object in UnitTable, do not delete protected: SPDesktop *_desktop; @@ -271,8 +272,6 @@ protected: void on_popup_preset(int i); Gtk::MenuItem _popup_sw_remove; - Inkscape::Util::Unit const *_sw_unit; /// points to object in UnitTable, do not delete - void *_drop[2]; bool _dropEnabled[2]; }; diff --git a/src/verbs.cpp b/src/verbs.cpp index 8b3d7a5a2..b7b6da340 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -41,6 +41,7 @@ #include "desktop.h" #include "display/curve.h" +#include "display/sp-canvas.h" #include "document.h" #include "ui/tools/freehand-base.h" #include "extension/effect.h" @@ -1881,8 +1882,11 @@ void ZoomVerb::perform(SPAction *action, void *data) Inkscape::XML::Node *repr = dt->namedview->getRepr(); Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - gdouble zoom_inc = - prefs->getDoubleLimited( "/options/zoomincrement/value", M_SQRT2, 1.01, 10 ); + gdouble zoom_inc = + prefs->getDoubleLimited( "/options/zoomincrement/value", M_SQRT2, 1.01, 10 ); + gdouble rotate_inc = + prefs->getDoubleLimited( "/options/rotateincrement/value", 15, 1, 90, "°" ); + rotate_inc *= M_PI/180.0; double zcorr = 1.0; Glib::ustring abbr = prefs->getString("/options/zoomcorrection/unit"); @@ -1957,6 +1961,75 @@ void ZoomVerb::perform(SPAction *action, void *data) case SP_VERB_ZOOM_PREV: dt->prev_transform(); break; + case SP_VERB_ROTATE_CW: + { + gint mul = 1 + Inkscape::UI::Tools::gobble_key_events( GDK_KEY_parenleft, 0); + // While drawing with the pen/pencil tool, rotate towards the end of the unfinished path + if (tools_isactive(dt, TOOLS_FREEHAND_PENCIL) || tools_isactive(dt, TOOLS_FREEHAND_PEN)) { + SPCurve *rc = SP_DRAW_CONTEXT(ec)->red_curve; + if (!rc->is_empty()) { + Geom::Point const rotate_to (*rc->last_point()); + dt->rotate_relative_keep_point(rotate_to, -mul*rotate_inc); + break; + } + } + + dt->rotate_relative_center_point( midpoint, -mul*rotate_inc); + break; + } + case SP_VERB_ROTATE_CCW: + { + gint mul = 1 + Inkscape::UI::Tools::gobble_key_events( GDK_KEY_parenright, 0); + // While drawing with the pen/pencil tool, rotate towards the end of the unfinished path + if (tools_isactive(dt, TOOLS_FREEHAND_PENCIL) || tools_isactive(dt, TOOLS_FREEHAND_PEN)) { + SPCurve *rc = SP_DRAW_CONTEXT(ec)->red_curve; + if (!rc->is_empty()) { + Geom::Point const rotate_to (*rc->last_point()); + dt->rotate_relative_keep_point(rotate_to, mul*rotate_inc); + break; + } + } + + dt->rotate_relative_center_point( midpoint, mul*rotate_inc); + break; + } + case SP_VERB_ROTATE_ZERO: + dt->rotate_absolute_center_point( midpoint, 0.0 ); + break; + case SP_VERB_FLIP_HORIZONTAL: + { + // While drawing with the pen/pencil tool, flip towards the end of the unfinished path + if (tools_isactive(dt, TOOLS_FREEHAND_PENCIL) || tools_isactive(dt, TOOLS_FREEHAND_PEN)) { + SPCurve *rc = SP_DRAW_CONTEXT(ec)->red_curve; + if (!rc->is_empty()) { + Geom::Point const flip_to (*rc->last_point()); + dt->flip_relative_keep_point(flip_to, SPDesktop::FLIP_HORIZONTAL); + break; + } + } + + dt->flip_relative_center_point( midpoint, SPDesktop::FLIP_HORIZONTAL); + break; + } + case SP_VERB_FLIP_VERTICAL: + { + gint mul = 1 + Inkscape::UI::Tools::gobble_key_events( GDK_KEY_parenright, 0); + // While drawing with the pen/pencil tool, flip towards the end of the unfinished path + if (tools_isactive(dt, TOOLS_FREEHAND_PENCIL) || tools_isactive(dt, TOOLS_FREEHAND_PEN)) { + SPCurve *rc = SP_DRAW_CONTEXT(ec)->red_curve; + if (!rc->is_empty()) { + Geom::Point const flip_to (*rc->last_point()); + dt->flip_relative_keep_point(flip_to, SPDesktop::FLIP_VERTICAL); + break; + } + } + + dt->flip_relative_center_point( midpoint, SPDesktop::FLIP_VERTICAL); + break; + } + case SP_VERB_FLIP_NONE: + dt->flip_absolute_center_point( midpoint, SPDesktop::FLIP_NONE); + break; case SP_VERB_TOGGLE_RULERS: dt->toggleRulers(); break; @@ -2895,10 +2968,41 @@ Verb *Verb::_base_verbs[] = { N_("Open Preferences for the Eraser tool"), NULL), new ContextVerb(SP_VERB_CONTEXT_LPETOOL_PREFS, "LPEToolPrefs", N_("LPE Tool Preferences"), N_("Open Preferences for the LPETool tool"), NULL), - // Zoom/View + + // Zoom new ZoomVerb(SP_VERB_ZOOM_IN, "ZoomIn", N_("Zoom In"), N_("Zoom in"), INKSCAPE_ICON("zoom-in")), new ZoomVerb(SP_VERB_ZOOM_OUT, "ZoomOut", N_("Zoom Out"), N_("Zoom out"), INKSCAPE_ICON("zoom-out")), - // WHY ARE THE FOLLOWING ZoomVerbs??? + new ZoomVerb(SP_VERB_ZOOM_NEXT, "ZoomNext", N_("Nex_t Zoom"), N_("Next zoom (from the history of zooms)"), + INKSCAPE_ICON("zoom-next")), + new ZoomVerb(SP_VERB_ZOOM_PREV, "ZoomPrev", N_("Pre_vious Zoom"), N_("Previous zoom (from the history of zooms)"), + INKSCAPE_ICON("zoom-previous")), + new ZoomVerb(SP_VERB_ZOOM_1_1, "Zoom1:0", N_("Zoom 1:_1"), N_("Zoom to 1:1"), + INKSCAPE_ICON("zoom-original")), + new ZoomVerb(SP_VERB_ZOOM_1_2, "Zoom1:2", N_("Zoom 1:_2"), N_("Zoom to 1:2"), + INKSCAPE_ICON("zoom-half-size")), + new ZoomVerb(SP_VERB_ZOOM_2_1, "Zoom2:1", N_("_Zoom 2:1"), N_("Zoom to 2:1"), + INKSCAPE_ICON("zoom-double-size")), + new ZoomVerb(SP_VERB_ZOOM_PAGE, "ZoomPage", N_("_Page"), + N_("Zoom to fit page in window"), INKSCAPE_ICON("zoom-fit-page")), + new ZoomVerb(SP_VERB_ZOOM_PAGE_WIDTH, "ZoomPageWidth", N_("Page _Width"), + N_("Zoom to fit page width in window"), INKSCAPE_ICON("zoom-fit-width")), + new ZoomVerb(SP_VERB_ZOOM_DRAWING, "ZoomDrawing", N_("_Drawing"), + N_("Zoom to fit drawing in window"), INKSCAPE_ICON("zoom-fit-drawing")), + new ZoomVerb(SP_VERB_ZOOM_SELECTION, "ZoomSelection", N_("_Selection"), + N_("Zoom to fit selection in window"), INKSCAPE_ICON("zoom-fit-selection")), + + new ZoomVerb(SP_VERB_ROTATE_CW, "RotateClockwise", N_("Rotate Clockwise"), N_("Rotate canvas clockwise"), NULL), + new ZoomVerb(SP_VERB_ROTATE_CCW, "RotateCounterClockwise", N_("Rotate Counter-Clockwise"), N_("Rotate canvas counter-clockwise"), NULL), + new ZoomVerb(SP_VERB_ROTATE_ZERO, "RotateZero", N_("Rotate Zero"), N_("Reset canvas rotation to zero"), NULL), + + new ZoomVerb(SP_VERB_FLIP_HORIZONTAL, "FlipHorizontal", N_("Flip Horizontal"), N_("Flip canvas horizontally"), INKSCAPE_ICON("object-flip-horizontal")), + new ZoomVerb(SP_VERB_FLIP_VERTICAL, "FlipVertical", N_("Flip Vertical"), N_("Flip canvas vertically"), INKSCAPE_ICON("object-flip-vertical")), + new ZoomVerb(SP_VERB_FLIP_NONE, "FlipNone", N_("Flip None"), N_("Undo any flip"), NULL), + + +// WHY ARE THE FOLLOWING ZoomVerbs??? + + // View new ZoomVerb(SP_VERB_TOGGLE_RULERS, "ToggleRulers", N_("_Rulers"), N_("Show or hide the canvas rulers"), NULL), new ZoomVerb(SP_VERB_TOGGLE_SCROLLBARS, "ToggleScrollbars", N_("Scroll_bars"), N_("Show or hide the canvas scrollbars"), NULL), new ZoomVerb(SP_VERB_TOGGLE_GRID, "ToggleGrid", N_("Page _Grid"), N_("Show or hide the page grid"), INKSCAPE_ICON("show-grid")), @@ -2910,16 +3014,7 @@ Verb *Verb::_base_verbs[] = { new ZoomVerb(SP_VERB_TOGGLE_TOOLBOX, "ToggleToolbox", N_("_Toolbox"), N_("Show or hide the main toolbox (on the left)"), NULL), new ZoomVerb(SP_VERB_TOGGLE_PALETTE, "TogglePalette", N_("_Palette"), N_("Show or hide the color palette"), NULL), new ZoomVerb(SP_VERB_TOGGLE_STATUSBAR, "ToggleStatusbar", N_("_Statusbar"), N_("Show or hide the statusbar (at the bottom of the window)"), NULL), - new ZoomVerb(SP_VERB_ZOOM_NEXT, "ZoomNext", N_("Nex_t Zoom"), N_("Next zoom (from the history of zooms)"), - INKSCAPE_ICON("zoom-next")), - new ZoomVerb(SP_VERB_ZOOM_PREV, "ZoomPrev", N_("Pre_vious Zoom"), N_("Previous zoom (from the history of zooms)"), - INKSCAPE_ICON("zoom-previous")), - new ZoomVerb(SP_VERB_ZOOM_1_1, "Zoom1:0", N_("Zoom 1:_1"), N_("Zoom to 1:1"), - INKSCAPE_ICON("zoom-original")), - new ZoomVerb(SP_VERB_ZOOM_1_2, "Zoom1:2", N_("Zoom 1:_2"), N_("Zoom to 1:2"), - INKSCAPE_ICON("zoom-half-size")), - new ZoomVerb(SP_VERB_ZOOM_2_1, "Zoom2:1", N_("_Zoom 2:1"), N_("Zoom to 2:1"), - INKSCAPE_ICON("zoom-double-size")), + new ZoomVerb(SP_VERB_FULLSCREEN, "FullScreen", N_("_Fullscreen"), N_("Stretch this document window to full screen"), INKSCAPE_ICON("view-fullscreen")), new ZoomVerb(SP_VERB_FULLSCREENFOCUS, "FullScreenFocus", N_("Fullscreen & Focus Mode"), N_("Stretch this document window to full screen"), @@ -2953,14 +3048,6 @@ Verb *Verb::_base_verbs[] = { new ZoomVerb(SP_VERB_VIEW_ICON_PREVIEW, "ViewIconPreview", N_("Ico_n Preview..."), N_("Open a window to preview objects at different icon resolutions"), INKSCAPE_ICON("dialog-icon-preview")), - new ZoomVerb(SP_VERB_ZOOM_PAGE, "ZoomPage", N_("_Page"), - N_("Zoom to fit page in window"), INKSCAPE_ICON("zoom-fit-page")), - new ZoomVerb(SP_VERB_ZOOM_PAGE_WIDTH, "ZoomPageWidth", N_("Page _Width"), - N_("Zoom to fit page width in window"), INKSCAPE_ICON("zoom-fit-width")), - new ZoomVerb(SP_VERB_ZOOM_DRAWING, "ZoomDrawing", N_("_Drawing"), - N_("Zoom to fit drawing in window"), INKSCAPE_ICON("zoom-fit-drawing")), - new ZoomVerb(SP_VERB_ZOOM_SELECTION, "ZoomSelection", N_("_Selection"), - N_("Zoom to fit selection in window"), INKSCAPE_ICON("zoom-fit-selection")), // Dialogs new DialogVerb(SP_VERB_DIALOG_PROTOTYPE, "DialogPrototype", N_("Prototype..."), diff --git a/src/verbs.h b/src/verbs.h index b6b7b54dc..6846f1f40 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -252,9 +252,31 @@ enum { SP_VERB_CONTEXT_ERASER_PREFS, SP_VERB_CONTEXT_LPETOOL_PREFS, - /* Zooming and desktop settings */ + + /* Zooming */ SP_VERB_ZOOM_IN, SP_VERB_ZOOM_OUT, + SP_VERB_ZOOM_NEXT, + SP_VERB_ZOOM_PREV, + SP_VERB_ZOOM_1_1, + SP_VERB_ZOOM_1_2, + SP_VERB_ZOOM_2_1, + SP_VERB_ZOOM_PAGE, + SP_VERB_ZOOM_PAGE_WIDTH, + SP_VERB_ZOOM_DRAWING, + SP_VERB_ZOOM_SELECTION, + + /* Canvas Rotation */ + SP_VERB_ROTATE_CW, + SP_VERB_ROTATE_CCW, + SP_VERB_ROTATE_ZERO, + + /* Canvas Flip */ + SP_VERB_FLIP_HORIZONTAL, + SP_VERB_FLIP_VERTICAL, + SP_VERB_FLIP_NONE, + + /* Desktop settings */ SP_VERB_TOGGLE_RULERS, SP_VERB_TOGGLE_SCROLLBARS, SP_VERB_TOGGLE_GRID, @@ -266,11 +288,6 @@ enum { SP_VERB_TOGGLE_TOOLBOX, SP_VERB_TOGGLE_PALETTE, SP_VERB_TOGGLE_STATUSBAR, - SP_VERB_ZOOM_NEXT, - SP_VERB_ZOOM_PREV, - SP_VERB_ZOOM_1_1, - SP_VERB_ZOOM_1_2, - SP_VERB_ZOOM_2_1, SP_VERB_FULLSCREEN, SP_VERB_FULLSCREENFOCUS, SP_VERB_FOCUSTOGGLE, @@ -282,14 +299,12 @@ enum { SP_VERB_VIEW_MODE_TOGGLE, SP_VERB_VIEW_COLOR_MODE_NORMAL, SP_VERB_VIEW_COLOR_MODE_GRAYSCALE, + // SP_VERB_VIEW_COLOR_MODE_PRINT_COLORS_PREVIEW, SP_VERB_VIEW_COLOR_MODE_TOGGLE, SP_VERB_VIEW_CMS_TOGGLE, SP_VERB_VIEW_ICON_PREVIEW, - SP_VERB_ZOOM_PAGE, - SP_VERB_ZOOM_PAGE_WIDTH, - SP_VERB_ZOOM_DRAWING, - SP_VERB_ZOOM_SELECTION, + /* Dialogs */ SP_VERB_DIALOG_PROTOTYPE, SP_VERB_DIALOG_DISPLAY, diff --git a/src/viewbox.cpp b/src/viewbox.cpp index 1fa33117a..1b50fe71c 100644 --- a/src/viewbox.cpp +++ b/src/viewbox.cpp @@ -17,8 +17,6 @@ #include "viewbox.h" #include "enums.h" #include "sp-item.h" -#include "inkscape.h" -#include "desktop.h" SPViewBox::SPViewBox() : viewBox_set(false) @@ -27,11 +25,6 @@ SPViewBox::SPViewBox() , aspect_align(SP_ASPECT_XMID_YMID) // Default per spec , aspect_clip(SP_ASPECT_MEET) , c2p(Geom::identity()) - , vbt(Geom::identity()) - , rotation(Geom::identity()) - , angle(0) - , previous_angle(0) - , rotated(false) { } @@ -166,16 +159,6 @@ void SPViewBox::set_preserveAspectRatio(const gchar* value) { } } -double SPViewBox::get_rotation() { - return this->angle; -} - -void SPViewBox::set_rotation(double angle_val) { - this->previous_angle = this->angle; - this->angle = angle_val; - this->rotated = true; -} - // Apply scaling from viewbox void SPViewBox::apply_viewbox(const Geom::Rect& in, double scale_none) { @@ -239,41 +222,22 @@ void SPViewBox::apply_viewbox(const Geom::Rect& in, double scale_none) { break; } } + /* Viewbox transform from scale and position */ - vbt = Geom::identity(); - vbt[0] = scale_x; - vbt[1] = 0.0; - vbt[2] = 0.0; - vbt[3] = scale_y; - vbt[4] = x - scale_x * this->viewBox.left(); - vbt[5] = y - scale_y * this->viewBox.top(); - /* Append viewbox and turn transformation */ - Geom::Point page_center = this->viewBox.midpoint(); - SPDesktop * desktop = SP_ACTIVE_DESKTOP; - if (this->angle > 0.0 || this->angle < 0.0 ) { //!0 - if (desktop) { - rotation = Geom::Translate(page_center).inverse() * Geom::Rotate(Geom::rad_from_deg(angle)) * Geom::Translate(page_center); - this->c2p = rotation * vbt * this->c2p; - } else { - this->c2p = vbt * this->c2p; - } - } else { - this->c2p = vbt * this->c2p; - } - if (desktop && this->rotated) { - Geom::Rect view = desktop->get_display_area(); - Geom::Point view_center = desktop->doc2dt(view.midpoint()); - Geom::Affine center_rotation = Geom::identity(); - center_rotation *= Geom::Translate(page_center * vbt).inverse(); - center_rotation *= Geom::Rotate(Geom::rad_from_deg(this->angle - this->previous_angle)); - center_rotation *= Geom::Translate(page_center * vbt); - view_center = desktop->dt2doc(view_center * center_rotation); - desktop->zoom_relative_center_point(view_center, 1.0); - this->rotated = false; - } + Geom::Affine q; + q[0] = scale_x; + q[1] = 0.0; + q[2] = 0.0; + q[3] = scale_y; + q[4] = x - scale_x * this->viewBox.left(); + q[5] = y - scale_y * this->viewBox.top(); + + // std::cout << " q\n" << q << std::endl; + + /* Append viewbox transformation */ + this->c2p = q * this->c2p; } - SPItemCtx SPViewBox::get_rctx(const SPItemCtx* ictx, double scale_none) { /* Create copy of item context */ diff --git a/src/viewbox.h b/src/viewbox.h index 2f107132c..c71abb610 100644 --- a/src/viewbox.h +++ b/src/viewbox.h @@ -36,14 +36,7 @@ public: /* Child to parent additional transform */ Geom::Affine c2p; - Geom::Affine vbt; - Geom::Affine rotation; - double angle; - double previous_angle; - bool rotated; - double get_rotation(); - void set_rotation(double angle_val); void set_viewBox(const gchar* value); void set_preserveAspectRatio(const gchar* value); diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp index 122b19e22..d8c27f5b7 100644 --- a/src/widgets/desktop-widget.cpp +++ b/src/widgets/desktop-widget.cpp @@ -91,20 +91,8 @@ static void sp_update_guides_lock( GtkWidget *button, gpointer data ); static void cms_adjust_toggled( GtkWidget *button, gpointer data ); #endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2) static void cms_adjust_set_sensitive( SPDesktopWidget *dtw, bool enabled ); -static void sp_desktop_widget_rotate_document(GtkSpinButton *spin, SPDesktopWidget *dtw); static void sp_desktop_widget_adjustment_value_changed (GtkAdjustment *adj, SPDesktopWidget *dtw); -static gint sp_dtw_rotation_input (GtkSpinButton *spin, gdouble *new_val, gpointer data); -static bool sp_dtw_rotation_output (GtkSpinButton *spin, gpointer data); -static void sp_dtw_rotation_populate_popup (GtkEntry *entry, GtkMenu *menu, gpointer data); -static void sp_dtw_rotate_minus_180 (GtkMenuItem *item, SPDesktopWidget * data); -static void sp_dtw_rotate_minus_135 (GtkMenuItem *item, SPDesktopWidget * data); -static void sp_dtw_rotate_minus_90 (GtkMenuItem *item, SPDesktopWidget * data); -static void sp_dtw_rotate_minus_45 (GtkMenuItem *item, SPDesktopWidget * data); -static void sp_dtw_rotate_0 (GtkMenuItem *item, SPDesktopWidget * data); -static void sp_dtw_rotate_45 (GtkMenuItem *item, SPDesktopWidget * data); -static void sp_dtw_rotate_90 (GtkMenuItem *item, SPDesktopWidget * data); -static void sp_dtw_rotate_135 (GtkMenuItem *item, SPDesktopWidget * data); static gdouble sp_dtw_zoom_value_to_display (gdouble value); static gdouble sp_dtw_zoom_display_to_value (gdouble value); static gint sp_dtw_zoom_input (GtkSpinButton *spin, gdouble *new_val, gpointer data); @@ -112,14 +100,13 @@ static bool sp_dtw_zoom_output (GtkSpinButton *spin, gpointer data); static void sp_dtw_zoom_value_changed (GtkSpinButton *spin, gpointer data); static void sp_dtw_zoom_populate_popup (GtkEntry *entry, GtkMenu *menu, gpointer data); static void sp_dtw_zoom_menu_handler (SPDesktop *dt, gdouble factor); -static void sp_dtw_zoom_50 (GtkMenuItem *item, gpointer data); -static void sp_dtw_zoom_100 (GtkMenuItem *item, gpointer data); -static void sp_dtw_zoom_200 (GtkMenuItem *item, gpointer data); -static void sp_dtw_zoom_page (GtkMenuItem *item, gpointer data); -static void sp_dtw_zoom_drawing (GtkMenuItem *item, gpointer data); -static void sp_dtw_zoom_selection (GtkMenuItem *item, gpointer data); static void sp_dtw_sticky_zoom_toggled (GtkMenuItem *item, gpointer data); +static gint sp_dtw_rotation_input (GtkSpinButton *spin, gdouble *new_val, gpointer data); +static bool sp_dtw_rotation_output (GtkSpinButton *spin, gpointer data); +static void sp_dtw_rotation_value_changed (GtkSpinButton *spin, gpointer data); +static void sp_dtw_rotation_populate_popup (GtkEntry *entry, GtkMenu *menu, gpointer data); + SPViewWidgetClass *dtw_parent_class; class CMSPrefWatcher { @@ -576,44 +563,52 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw ) gtk_box_pack_start (GTK_BOX (dtw->statusbar), dtw->select_status, TRUE, TRUE, 0); - // Zoom status spinbutton + // Zoom status spinbutton --------------- dtw->zoom_status = gtk_spin_button_new_with_range (log(SP_DESKTOP_ZOOM_MIN)/log(2), log(SP_DESKTOP_ZOOM_MAX)/log(2), 0.1); - gtk_widget_set_name(dtw->zoom_status, "ZoomStatus"); + g_object_set_data (G_OBJECT (dtw->zoom_status), "dtw", dtw->canvas); gtk_widget_set_tooltip_text (dtw->zoom_status, _("Zoom")); gtk_widget_set_size_request (dtw->zoom_status, STATUS_ZOOM_WIDTH, -1); gtk_entry_set_width_chars (GTK_ENTRY (dtw->zoom_status), 6); gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (dtw->zoom_status), FALSE); gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (dtw->zoom_status), GTK_UPDATE_ALWAYS); + + // Callbacks g_signal_connect (G_OBJECT (dtw->zoom_status), "input", G_CALLBACK (sp_dtw_zoom_input), dtw); g_signal_connect (G_OBJECT (dtw->zoom_status), "output", G_CALLBACK (sp_dtw_zoom_output), dtw); - g_object_set_data (G_OBJECT (dtw->zoom_status), "dtw", dtw->canvas); g_signal_connect (G_OBJECT (dtw->zoom_status), "focus-in-event", G_CALLBACK (spinbutton_focus_in), dtw->zoom_status); g_signal_connect (G_OBJECT (dtw->zoom_status), "key-press-event", G_CALLBACK (spinbutton_keypress), dtw->zoom_status); dtw->zoom_update = g_signal_connect (G_OBJECT (dtw->zoom_status), "value_changed", G_CALLBACK (sp_dtw_zoom_value_changed), dtw); - dtw->zoom_update = g_signal_connect (G_OBJECT (dtw->zoom_status), "populate_popup", G_CALLBACK (sp_dtw_zoom_populate_popup), dtw); + g_signal_connect (G_OBJECT (dtw->zoom_status), "populate_popup", G_CALLBACK (sp_dtw_zoom_populate_popup), dtw); + + // Style auto css_provider_spinbutton = Gtk::CssProvider::create(); - css_provider_spinbutton->load_from_data("* { padding-left: 2px; padding-right: 2px; padding-top: 0px; padding-bottom: 0px;}"); + css_provider_spinbutton->load_from_data("* { padding-left: 2px; padding-right: 2px; padding-top: 0px; padding-bottom: 0px;}"); // Shouldn't this be in a style sheet? Used also by rotate. + auto zoomstat = Glib::wrap(dtw->zoom_status); zoomstat->set_name("ZoomStatus"); auto context_zoom = zoomstat->get_style_context(); context_zoom->add_provider(css_provider_spinbutton, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); - // Rotate status spinbutton + // Rotate status spinbutton --------------- dtw->rotation_status = gtk_spin_button_new_with_range (-360.0,360.0, 1.0); - gtk_widget_set_tooltip_text (dtw->rotation_status, _("Rotation. Can be interactive with CTRL+MMB")); + g_object_set_data (G_OBJECT (dtw->rotation_status), "dtw", dtw->canvas); + gtk_widget_set_tooltip_text (dtw->rotation_status, _("Rotation. (Also Ctrl+Shift+Scroll)")); gtk_widget_set_size_request (dtw->rotation_status, STATUS_ROTATION_WIDTH, -1); gtk_entry_set_width_chars (GTK_ENTRY (dtw->rotation_status), 7); - gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (dtw->rotation_status), FALSE); - gtk_spin_button_set_digits (GTK_SPIN_BUTTON (dtw->rotation_status), 2); + gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (dtw->rotation_status), FALSE); + gtk_spin_button_set_digits (GTK_SPIN_BUTTON (dtw->rotation_status), 2); + gtk_spin_button_set_increments (GTK_SPIN_BUTTON (dtw->rotation_status), 1.0, 15.0); gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (dtw->rotation_status), GTK_UPDATE_ALWAYS); + + // Callbacks g_signal_connect (G_OBJECT (dtw->rotation_status), "input", G_CALLBACK (sp_dtw_rotation_input), dtw); g_signal_connect (G_OBJECT (dtw->rotation_status), "output", G_CALLBACK (sp_dtw_rotation_output), dtw); - g_object_set_data (G_OBJECT (dtw->rotation_status), "dtw", dtw->canvas); g_signal_connect (G_OBJECT (dtw->rotation_status), "focus-in-event", G_CALLBACK (spinbutton_focus_in), dtw->rotation_status); g_signal_connect (G_OBJECT (dtw->rotation_status), "key-press-event", G_CALLBACK (spinbutton_keypress), dtw->rotation_status); - dtw->rotation_update = g_signal_connect (G_OBJECT (dtw->rotation_status), "value_changed", G_CALLBACK (sp_desktop_widget_rotate_document), dtw); - dtw->rotation_update = g_signal_connect (G_OBJECT (dtw->rotation_status), "populate_popup", G_CALLBACK (sp_dtw_rotation_populate_popup), dtw); + dtw->rotation_update = g_signal_connect (G_OBJECT (dtw->rotation_status), "value_changed", G_CALLBACK (sp_dtw_rotation_value_changed), dtw); + g_signal_connect (G_OBJECT (dtw->rotation_status), "populate_popup", G_CALLBACK (sp_dtw_rotation_populate_popup), dtw); + // Style auto rotstat = Glib::wrap(dtw->rotation_status); rotstat->set_name("RotationStatus"); auto context_rotation = rotstat->get_style_context(); @@ -717,16 +712,22 @@ static void sp_desktop_widget_dispose(GObject *object) if ( watcher ) { watcher->remove(dtw); } + + // Zoom g_signal_handlers_disconnect_by_func(G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK(sp_dtw_zoom_input), dtw); g_signal_handlers_disconnect_by_func(G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK(sp_dtw_zoom_output), dtw); g_signal_handlers_disconnect_matched (G_OBJECT (dtw->zoom_status), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, dtw->zoom_status); g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK (sp_dtw_zoom_value_changed), dtw); g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->zoom_status), (gpointer) G_CALLBACK (sp_dtw_zoom_populate_popup), dtw); + + // Rotation g_signal_handlers_disconnect_by_func(G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK(sp_dtw_rotation_input), dtw); g_signal_handlers_disconnect_by_func(G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK(sp_dtw_rotation_output), dtw); g_signal_handlers_disconnect_matched (G_OBJECT (dtw->rotation_status), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, dtw->rotation_status); - g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK (sp_desktop_widget_rotate_document), dtw); + g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK (sp_dtw_rotation_value_changed), dtw); g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->rotation_status), (gpointer) G_CALLBACK (sp_dtw_rotation_populate_popup), dtw); + + // Canvas g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->canvas), (gpointer) G_CALLBACK (sp_desktop_widget_event), dtw); g_signal_handlers_disconnect_by_func (G_OBJECT (dtw->canvas_tbl), (gpointer) G_CALLBACK (canvas_tbl_size_allocate), dtw); @@ -1667,8 +1668,7 @@ SPDesktopWidget* SPDesktopWidget::createInstance(SPNamedView *namedview) SPNamedView *nv = dtw->desktop->namedview; gtk_box_pack_start (GTK_BOX (dtw->vbox), dtw->menubar, FALSE, FALSE, 0); dtw->layoutWidgets(); - gtk_spin_button_set_value(GTK_SPIN_BUTTON (dtw->rotation_status), namedview->document_rotation); - sp_namedview_set_document_rotation(namedview); + std::vector<GtkWidget *> toolboxes; toolboxes.push_back(dtw->tool_toolbox); toolboxes.push_back(dtw->aux_toolbox); @@ -1708,8 +1708,6 @@ sp_desktop_widget_update_rulers (SPDesktopWidget *dtw) void SPDesktopWidget::namedviewModified(SPObject *obj, guint flags) { SPNamedView *nv=SP_NAMEDVIEW(obj); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(this->rotation_status), desktop->namedview->document_rotation); - sp_namedview_set_document_rotation(nv); if (flags & SP_OBJECT_MODIFIED_FLAG) { this->dt2r = 1. / nv->display_units->factor; @@ -1768,18 +1766,6 @@ void SPDesktopWidget::namedviewModified(SPObject *obj, guint flags) } static void -sp_desktop_widget_rotate_document(GtkSpinButton *spin, SPDesktopWidget *dtw) -{ - SPNamedView *nv = dtw->desktop->namedview; - double value = gtk_spin_button_get_value (spin); - if (!dtw->desktop->getDocument()->getRoot()->rotated && value != nv->document_rotation) { - sp_repr_set_svg_double(nv->getRepr(), "inkscape:document-rotation", value); - } - spinbutton_defocus (GTK_WIDGET(spin)); -} - - -static void sp_desktop_widget_adjustment_value_changed (GtkAdjustment */*adj*/, SPDesktopWidget *dtw) { if (dtw->update) @@ -1811,6 +1797,7 @@ bool SPDesktopWidget::onFocusInEvent(GdkEventFocus*) return false; } +// ------------------------ Zoom ------------------------ static gdouble sp_dtw_zoom_value_to_display (gdouble value) { @@ -1858,38 +1845,6 @@ sp_dtw_zoom_output (GtkSpinButton *spin, gpointer /*data*/) return TRUE; } -static gint -sp_dtw_rotation_input (GtkSpinButton *spin, gdouble *new_val, gpointer /*data*/) -{ - gchar *b = g_strdup (gtk_entry_get_text (GTK_ENTRY (spin))); - - gchar *comma = g_strstr_len (b, -1, ","); - if (comma) { - *comma = '.'; - } - - char *oldlocale = g_strdup (setlocale(LC_NUMERIC, NULL)); - setlocale (LC_NUMERIC, "C"); - gdouble new_value = atof (b); - setlocale (LC_NUMERIC, oldlocale); - g_free (oldlocale); - g_free (b); - - *new_val = new_value; - return TRUE; -} - -static bool -sp_dtw_rotation_output (GtkSpinButton *spin, gpointer /*data*/) -{ - gchar b[64]; - double val = gtk_spin_button_get_value (spin); - g_snprintf (b, 64, "%7.2f°", val); - - gtk_entry_set_text (GTK_ENTRY (spin), b); - return TRUE; -} - static void sp_dtw_zoom_value_changed (GtkSpinButton *spin, gpointer data) { @@ -1908,7 +1863,14 @@ sp_dtw_zoom_value_changed (GtkSpinButton *spin, gpointer data) spinbutton_defocus (GTK_WIDGET(spin)); } +static void +sp_dtw_zoom_menu_handler (SPDesktop *dt, gdouble factor) +{ + Geom::Rect const d = dt->get_display_area(); + dt->zoom_absolute_center_point (d.midpoint(), factor); +} +// Zoom Popup Menu static void sp_dtw_zoom_10 (GtkMenuItem */*item*/, gpointer data) { @@ -1972,124 +1934,142 @@ sp_dtw_zoom_selection (GtkMenuItem */*item*/, gpointer data) static void sp_dtw_zoom_populate_popup (GtkEntry */*entry*/, GtkMenu *menu, gpointer data) { - GList *children, *iter; - GtkWidget *item; SPDesktop *dt = SP_DESKTOP_WIDGET (data)->desktop; - children = gtk_container_get_children (GTK_CONTAINER (menu)); - for ( iter = children ; iter ; iter = g_list_next (iter)) { + GList* children = gtk_container_get_children (GTK_CONTAINER (menu)); + for ( auto iter = children ; iter ; iter = g_list_next (iter)) { gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (iter->data)); } g_list_free (children); + GtkWidget *item; + item = gtk_menu_item_new_with_label ("1000%"); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_1000), dt); - gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + item = gtk_menu_item_new_with_label ("500%"); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_500), dt); - gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + item = gtk_menu_item_new_with_label ("200%"); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_200), dt); - gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + item = gtk_menu_item_new_with_label ("100%"); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_100), dt); - gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + item = gtk_menu_item_new_with_label ("50%"); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_50), dt); - gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + item = gtk_menu_item_new_with_label ("25%"); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_25), dt); - gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + item = gtk_menu_item_new_with_label ("10%"); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_10), dt); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); item = gtk_separator_menu_item_new (); - gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); item = gtk_menu_item_new_with_label (_("Page")); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_page), dt); - gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + item = gtk_menu_item_new_with_label (_("Drawing")); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_drawing), dt); - gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + item = gtk_menu_item_new_with_label (_("Selection")); g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_zoom_selection), dt); - gtk_widget_show (item); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + gtk_widget_show_all (GTK_WIDGET (menu)); } static void -sp_dtw_rotation_populate_popup (GtkEntry */*entry*/, GtkMenu *menu, gpointer data) +sp_dtw_sticky_zoom_toggled (GtkMenuItem *, gpointer data) { - GList *children, *iter; - GtkWidget *item; - SPDesktopWidget *dtw = static_cast<SPDesktopWidget*>(data); - children = gtk_container_get_children (GTK_CONTAINER (menu)); - for ( iter = children ; iter ; iter = g_list_next (iter)) { - gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (iter->data)); + SPDesktopWidget *dtw = SP_DESKTOP_WIDGET(data); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/options/stickyzoom/value", SP_BUTTON_IS_DOWN(dtw->sticky_zoom)); +} + + +void +sp_desktop_widget_update_zoom (SPDesktopWidget *dtw) +{ + GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(dtw->zoom_status)); + + g_signal_handler_block (G_OBJECT (dtw->zoom_status), dtw->zoom_update); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (dtw->zoom_status), log(dtw->desktop->current_zoom()) / log(2)); + gtk_widget_queue_draw(GTK_WIDGET(dtw->zoom_status)); + if (window) + gdk_window_process_updates(window, TRUE); + g_signal_handler_unblock (G_OBJECT (dtw->zoom_status), dtw->zoom_update); +} + + +// ---------------------- Rotation ------------------------ +static gint +sp_dtw_rotation_input (GtkSpinButton *spin, gdouble *new_val, gpointer /*data*/) +{ + gchar *b = g_strdup (gtk_entry_get_text (GTK_ENTRY (spin))); + + gchar *comma = g_strstr_len (b, -1, ","); + if (comma) { + *comma = '.'; } - g_list_free (children); - item = gtk_menu_item_new_with_label ("-180°"); - g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_180), dtw); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - - item = gtk_menu_item_new_with_label ("-135°"); - g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_135), dtw); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - - item = gtk_menu_item_new_with_label ("-90°"); - g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_90), dtw); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - - item = gtk_menu_item_new_with_label ("-45°"); - g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_45), dtw); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - - item = gtk_menu_item_new_with_label ("0°"); - g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_0), dtw); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - - item = gtk_menu_item_new_with_label ("45°"); - g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_45), dtw); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - - - item = gtk_menu_item_new_with_label ("90°"); - g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_90), dtw); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); - + char *oldlocale = g_strdup (setlocale(LC_NUMERIC, NULL)); + setlocale (LC_NUMERIC, "C"); + gdouble new_value = atof (b); + setlocale (LC_NUMERIC, oldlocale); + g_free (oldlocale); + g_free (b); - item = gtk_menu_item_new_with_label ("135°"); - g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_135), dtw); - gtk_widget_show (item); - gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + *new_val = new_value; + return TRUE; +} + +static bool +sp_dtw_rotation_output (GtkSpinButton *spin, gpointer /*data*/) +{ + gchar b[64]; + double val = gtk_spin_button_get_value (spin); + + if (val < -180) val += 360; + if (val > 180) val -= 360; + + g_snprintf (b, 64, "%7.2f°", val); + + gtk_entry_set_text (GTK_ENTRY (spin), b); + return TRUE; } static void -sp_dtw_rotate_minus_180 (GtkMenuItem */*item*/, SPDesktopWidget * data) +sp_dtw_rotation_value_changed (GtkSpinButton *spin, gpointer data) { - gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status),-180); + double const rotate_factor = M_PI / 180.0 * gtk_spin_button_get_value (spin); + // std::cout << "sp_dtw_rotation_value_changed: " + // << gtk_spin_button_get_value (spin) + // << " (" << rotate_factor << ")" <<std::endl; + + SPDesktopWidget *dtw = SP_DESKTOP_WIDGET (data); + SPDesktop *desktop = dtw->desktop; + + // Rotate around center of window + Geom::Rect const d_canvas = desktop->getCanvas()->getViewbox(); + g_signal_handler_block(spin, dtw->rotation_update); + Geom::Point midpoint = desktop->w2d(d_canvas.midpoint()); + desktop->rotate_absolute_center_point (midpoint, rotate_factor); + g_signal_handler_unblock(spin, dtw->rotation_update); + + spinbutton_defocus (GTK_WIDGET(spin)); } static void @@ -2135,35 +2115,75 @@ sp_dtw_rotate_135 (GtkMenuItem */*item*/, SPDesktopWidget * data) } static void -sp_dtw_zoom_menu_handler (SPDesktop *dt, gdouble factor) +sp_dtw_rotate_180 (GtkMenuItem */*item*/, SPDesktopWidget * data) { - Geom::Rect const d = dt->get_display_area(); - dt->zoom_absolute_center_point (d.midpoint(), factor); + gtk_spin_button_set_value (GTK_SPIN_BUTTON((data)->rotation_status),180); } - static void -sp_dtw_sticky_zoom_toggled (GtkMenuItem *, gpointer data) +sp_dtw_rotation_populate_popup (GtkEntry */*entry*/, GtkMenu *menu, gpointer data) { - SPDesktopWidget *dtw = SP_DESKTOP_WIDGET(data); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setBool("/options/stickyzoom/value", SP_BUTTON_IS_DOWN(dtw->sticky_zoom)); + SPDesktopWidget *dtw = static_cast<SPDesktopWidget*>(data); + + GList* children = gtk_container_get_children (GTK_CONTAINER (menu)); + for ( auto iter = children ; iter ; iter = g_list_next (iter)) { + gtk_container_remove (GTK_CONTAINER (menu), GTK_WIDGET (iter->data)); + } + g_list_free (children); + + GtkWidget *item; + + item = gtk_menu_item_new_with_label ("-135°"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_135), dtw); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + item = gtk_menu_item_new_with_label ("-90°"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_90), dtw); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + item = gtk_menu_item_new_with_label ("-45°"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_minus_45), dtw); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + item = gtk_menu_item_new_with_label ("0°"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_0), dtw); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + item = gtk_menu_item_new_with_label ("45°"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_45), dtw); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + item = gtk_menu_item_new_with_label ("90°"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_90), dtw); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + item = gtk_menu_item_new_with_label ("135°"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_135), dtw); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + item = gtk_menu_item_new_with_label ("180°"); + g_signal_connect (G_OBJECT (item), "activate", G_CALLBACK (sp_dtw_rotate_180), dtw); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + + gtk_widget_show_all (GTK_WIDGET (menu)); } void -sp_desktop_widget_update_zoom (SPDesktopWidget *dtw) +sp_desktop_widget_update_rotation (SPDesktopWidget *dtw) { - GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(dtw->zoom_status)); + GdkWindow *window = gtk_widget_get_window(GTK_WIDGET(dtw->rotation_status)); - g_signal_handlers_block_by_func (G_OBJECT (dtw->zoom_status), (gpointer)G_CALLBACK (sp_dtw_zoom_value_changed), dtw); - gtk_spin_button_set_value (GTK_SPIN_BUTTON (dtw->zoom_status), log(dtw->desktop->current_zoom()) / log(2)); - gtk_widget_queue_draw(GTK_WIDGET(dtw->zoom_status)); + g_signal_handler_block(G_OBJECT(dtw->rotation_status), dtw->rotation_update); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (dtw->rotation_status), dtw->desktop->current_rotation() / M_PI * 180.0); + gtk_widget_queue_draw(GTK_WIDGET(dtw->rotation_status)); if (window) gdk_window_process_updates(window, TRUE); - g_signal_handlers_unblock_by_func (G_OBJECT (dtw->zoom_status), (gpointer)G_CALLBACK (sp_dtw_zoom_value_changed), dtw); + g_signal_handler_unblock(G_OBJECT(dtw->rotation_status), dtw->rotation_update); } + +// --------------- Rulers/Scrollbars/Etc. ----------------- void sp_desktop_widget_toggle_rulers (SPDesktopWidget *dtw) { diff --git a/src/widgets/desktop-widget.h b/src/widgets/desktop-widget.h index 61c3b8b37..0d5f40987 100644 --- a/src/widgets/desktop-widget.h +++ b/src/widgets/desktop-widget.h @@ -40,6 +40,7 @@ void sp_desktop_widget_iconify(SPDesktopWidget *dtw); void sp_desktop_widget_maximize(SPDesktopWidget *dtw); void sp_desktop_widget_fullscreen(SPDesktopWidget *dtw); void sp_desktop_widget_update_zoom(SPDesktopWidget *dtw); +void sp_desktop_widget_update_rotation(SPDesktopWidget *dtw); void sp_desktop_widget_update_rulers (SPDesktopWidget *dtw); void sp_desktop_widget_update_hruler (SPDesktopWidget *dtw); void sp_desktop_widget_update_vruler (SPDesktopWidget *dtw); @@ -78,7 +79,7 @@ struct SPDesktopWidget { GtkWidget *hbox; - GtkWidget *menubar, *statusbar, *rotatebar; + GtkWidget *menubar, *statusbar; Inkscape::UI::Dialogs::SwatchesPanel *panels; @@ -193,6 +194,8 @@ struct SPDesktopWidget { { sp_desktop_widget_update_zoom (_dtw); } virtual void letZoomGrabFocus() { _dtw->letZoomGrabFocus(); } + virtual void updateRotation() + { sp_desktop_widget_update_rotation (_dtw); } virtual void setToolboxFocusTo (const gchar * id) { _dtw->setToolboxFocusTo (id); } virtual void setToolboxAdjustmentValue (const gchar *id, double val) diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp index ae6f238d4..d8e0f5418 100644 --- a/src/xml/repr-io.cpp +++ b/src/xml/repr-io.cpp @@ -404,7 +404,12 @@ Document *sp_repr_read_mem (const gchar * buffer, gint length, const gchar *defa g_return_val_if_fail (buffer != NULL, NULL); - doc = xmlParseMemory (const_cast<gchar *>(buffer), length); + int parser_options = XML_PARSE_HUGE | XML_PARSE_RECOVER; + parser_options |= XML_PARSE_NONET; // TODO: should we allow network access? + // proper solution would be to check the preference "/options/externalresources/xml/allow_net_access" + // as done in XmlSource::readXml which gets called by the analogous sp_repr_read_file() + // but sp_repr_read_mem() seems to be called in locations where Inkscape::Preferences::get() fails badly + doc = xmlReadMemory (const_cast<gchar *>(buffer), length, NULL, NULL, parser_options); rdoc = sp_repr_do_read (doc, default_ns); if (doc) { |
