X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Ftweak-context.cpp;h=3b93c659b664df6455948bd9ab6da916bd32eb6f;hb=0dc33d4ce43e0bb49c63aa53b826ec4a1ff68e28;hp=201af0fc57161863c820f14ad38df04ced7ec2b1;hpb=2abb884537f5d9cb8c5545b7558256f138a74d75;p=inkscape.git diff --git a/src/tweak-context.cpp b/src/tweak-context.cpp index 201af0fc5..3b93c659b 100644 --- a/src/tweak-context.cpp +++ b/src/tweak-context.cpp @@ -1,10 +1,10 @@ -#define __SP_TWEAK_CONTEXT_C__ - /* * tweaking paths without node editing * * Authors: - * bulia byak + * bulia byak + * Jon A. Cruz + * Abhishek Sharma * * Copyright (C) 2007 authors * @@ -20,8 +20,6 @@ #include #include "svg/svg.h" -#include "display/canvas-bpath.h" -#include "display/bezier-utils.h" #include #include "macros.h" @@ -30,9 +28,9 @@ #include "desktop.h" #include "desktop-events.h" #include "desktop-handles.h" -#include "desktop-affine.h" #include "desktop-style.h" #include "message-context.h" +#include "pixmaps/cursor-tweak-move.xpm" #include "pixmaps/cursor-thin.xpm" #include "pixmaps/cursor-thicken.xpm" #include "pixmaps/cursor-attract.xpm" @@ -40,9 +38,7 @@ #include "pixmaps/cursor-push.xpm" #include "pixmaps/cursor-roughen.xpm" #include "pixmaps/cursor-color.xpm" -#include "libnr/n-art-bpath.h" -#include "libnr/nr-path.h" -#include "libnr/nr-maybe.h" +#include #include "libnr/nr-matrix-ops.h" #include "libnr/nr-scale-translate-ops.h" #include "xml/repr.h" @@ -58,45 +54,41 @@ #include "path-chemistry.h" #include "sp-gradient.h" #include "sp-stop.h" -#include "sp-stop-fns.h" #include "sp-gradient-reference.h" #include "sp-linear-gradient.h" #include "sp-radial-gradient.h" #include "gradient-chemistry.h" #include "sp-text.h" #include "sp-flowtext.h" +#include "display/sp-canvas.h" #include "display/canvas-bpath.h" #include "display/canvas-arena.h" +#include "display/curve.h" #include "livarot/Shape.h" -#include "isnan.h" -#include "prefs-utils.h" +#include <2geom/isnan.h> +#include <2geom/transforms.h> +#include "preferences.h" #include "style.h" +#include "box3d.h" +#include "sp-item-transform.h" +#include "filter-chemistry.h" +#include "sp-gaussian-blur-fns.h" +#include "sp-gaussian-blur.h" #include "tweak-context.h" +using Inkscape::DocumentUndo; + #define DDC_RED_RGBA 0xff0000ff #define DYNA_MIN_WIDTH 1.0e-6 -// FIXME: move it to some shared file to be reused by both calligraphy and dropper -#define C1 0.552 -static NArtBpath const hatch_area_circle[] = { - { NR_MOVETO, 0, 0, 0, 0, -1, 0 }, - { NR_CURVETO, -1, C1, -C1, 1, 0, 1 }, - { NR_CURVETO, C1, 1, 1, C1, 1, 0 }, - { NR_CURVETO, 1, -C1, C1, -1, 0, -1 }, - { NR_CURVETO, -C1, -1, -1, -C1, -1, 0 }, - { NR_END, 0, 0, 0, 0, 0, 0 } -}; -#undef C1 - - static void sp_tweak_context_class_init(SPTweakContextClass *klass); static void sp_tweak_context_init(SPTweakContext *ddc); static void sp_tweak_context_dispose(GObject *object); static void sp_tweak_context_setup(SPEventContext *ec); -static void sp_tweak_context_set(SPEventContext *ec, gchar const *key, gchar const *val); +static void sp_tweak_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); static gint sp_tweak_context_root_handler(SPEventContext *ec, GdkEvent *event); static SPEventContextClass *parent_class; @@ -183,35 +175,101 @@ sp_tweak_context_dispose(GObject *object) G_OBJECT_CLASS(parent_class)->dispose(object); } +bool is_transform_mode (gint mode) +{ + return (mode == TWEAK_MODE_MOVE || + mode == TWEAK_MODE_MOVE_IN_OUT || + mode == TWEAK_MODE_MOVE_JITTER || + mode == TWEAK_MODE_SCALE || + mode == TWEAK_MODE_ROTATE || + mode == TWEAK_MODE_MORELESS); +} + +bool is_color_mode (gint mode) +{ + return (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER || mode == TWEAK_MODE_BLUR); +} + void -sp_tweak_update_cursor (SPTweakContext *tc, gint mode) +sp_tweak_update_cursor (SPTweakContext *tc, bool with_shift) { - SPEventContext *event_context = SP_EVENT_CONTEXT(tc); - switch (mode) { - case TWEAK_MODE_PUSH: - event_context->cursor_shape = cursor_push_xpm; + SPEventContext *event_context = SP_EVENT_CONTEXT(tc); + SPDesktop *desktop = event_context->desktop; + + guint num = 0; + gchar *sel_message = NULL; + if (!desktop->selection->isEmpty()) { + num = g_slist_length((GSList *) desktop->selection->itemList()); + sel_message = g_strdup_printf(ngettext("%i object selected","%i objects selected",num), num); + } else { + sel_message = g_strdup_printf(_("Nothing selected")); + } + + + switch (tc->mode) { + case TWEAK_MODE_MOVE: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag to move."), sel_message); + event_context->cursor_shape = cursor_tweak_move_xpm; + break; + case TWEAK_MODE_MOVE_IN_OUT: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to move in; with Shift to move out."), sel_message); + event_context->cursor_shape = cursor_tweak_move_xpm; + break; + case TWEAK_MODE_MOVE_JITTER: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to move randomly."), sel_message); + event_context->cursor_shape = cursor_tweak_move_xpm; + break; + case TWEAK_MODE_SCALE: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to scale down; with Shift to scale up."), sel_message); + event_context->cursor_shape = cursor_tweak_move_xpm; + break; + case TWEAK_MODE_ROTATE: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to rotate clockwise; with Shift, counterclockwise."), sel_message); + event_context->cursor_shape = cursor_tweak_move_xpm; break; - case TWEAK_MODE_SHRINK: - event_context->cursor_shape = cursor_thin_xpm; + case TWEAK_MODE_MORELESS: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to duplicate; with Shift, delete."), sel_message); + event_context->cursor_shape = cursor_tweak_move_xpm; break; - case TWEAK_MODE_GROW: - event_context->cursor_shape = cursor_thicken_xpm; + case TWEAK_MODE_PUSH: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag to push paths."), sel_message); + event_context->cursor_shape = cursor_push_xpm; break; - case TWEAK_MODE_ATTRACT: - event_context->cursor_shape = cursor_attract_xpm; + case TWEAK_MODE_SHRINK_GROW: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to inset paths; with Shift to outset."), sel_message); + if (with_shift) { + event_context->cursor_shape = cursor_thicken_xpm; + } else { + event_context->cursor_shape = cursor_thin_xpm; + } break; - case TWEAK_MODE_REPEL: - event_context->cursor_shape = cursor_repel_xpm; + case TWEAK_MODE_ATTRACT_REPEL: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to attract paths; with Shift to repel."), sel_message); + if (with_shift) { + event_context->cursor_shape = cursor_repel_xpm; + } else { + event_context->cursor_shape = cursor_attract_xpm; + } break; case TWEAK_MODE_ROUGHEN: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to roughen paths."), sel_message); event_context->cursor_shape = cursor_roughen_xpm; break; case TWEAK_MODE_COLORPAINT: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to paint objects with color."), sel_message); + event_context->cursor_shape = cursor_color_xpm; + break; case TWEAK_MODE_COLORJITTER: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to randomize colors."), sel_message); + event_context->cursor_shape = cursor_color_xpm; + break; + case TWEAK_MODE_BLUR: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to increase blur; with Shift to decrease."), sel_message); event_context->cursor_shape = cursor_color_xpm; break; } sp_event_context_update_cursor(event_context); + g_free(sel_message); } static bool @@ -220,9 +278,8 @@ sp_tweak_context_style_set(SPCSSAttr const *css, SPTweakContext *tc) if (tc->mode == TWEAK_MODE_COLORPAINT) { // intercept color setting only in this mode // we cannot store properties with uris css = sp_css_attr_unset_uris ((SPCSSAttr *) css); - - sp_repr_css_change (inkscape_get_repr (INKSCAPE, "tools.tweak"), (SPCSSAttr *) css, "style"); - + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setStyle("/tools/tweak/style", const_cast(css)); return true; } return false; @@ -238,14 +295,26 @@ sp_tweak_context_setup(SPEventContext *ec) ((SPEventContextClass *) parent_class)->setup(ec); { - SPCurve *c = sp_curve_new_from_foreign_bpath(hatch_area_circle); + /* TODO: have a look at sp_dyna_draw_context_setup where the same is done.. generalize? at least make it an arcto! */ + SPCurve *c = new SPCurve(); + const double C1 = 0.552; + c->moveto(-1,0); + c->curveto(-1, C1, -C1, 1, 0, 1 ); + c->curveto(C1, 1, 1, C1, 1, 0 ); + c->curveto(1, -C1, C1, -1, 0, -1 ); + c->curveto(-C1, -1, -1, -C1, -1, 0 ); + c->closepath(); tc->dilate_area = sp_canvas_bpath_new(sp_desktop_controls(ec->desktop), c); - sp_curve_unref(c); + c->unref(); sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(tc->dilate_area), 0x00000000,(SPWindRule)0); sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(tc->dilate_area), 0xff9900ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT); sp_canvas_item_hide(tc->dilate_area); } + tc->is_drawing = false; + + tc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); + sp_event_context_read(ec, "width"); sp_event_context_read(ec, "mode"); sp_event_context_read(ec, "fidelity"); @@ -256,44 +325,46 @@ sp_tweak_context_setup(SPEventContext *ec) sp_event_context_read(ec, "dos"); sp_event_context_read(ec, "doo"); - tc->is_drawing = false; - - tc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); - tc->style_set_connection = ec->desktop->connectSetStyle( // catch style-setting signal in this tool sigc::bind(sigc::ptr_fun(&sp_tweak_context_style_set), tc) ); + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/tools/tweak/selcue")) { + ec->enableSelectionCue(); + } + + if (prefs->getBool("/tools/tweak/gradientdrag")) { + ec->enableGrDrag(); + } } static void -sp_tweak_context_set(SPEventContext *ec, gchar const *key, gchar const *val) +sp_tweak_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) { SPTweakContext *tc = SP_TWEAK_CONTEXT(ec); - - if (!strcmp(key, "width")) { - double const dval = ( val ? g_ascii_strtod (val, NULL) : 0.1 ); - tc->width = CLAMP(dval, -1000.0, 1000.0); - } else if (!strcmp(key, "mode")) { - gint64 const dval = ( val ? g_ascii_strtoll (val, NULL, 10) : 0 ); - tc->mode = dval; - sp_tweak_update_cursor(tc, tc->mode); - } else if (!strcmp(key, "fidelity")) { - double const dval = ( val ? g_ascii_strtod (val, NULL) : 0.0 ); - tc->fidelity = CLAMP(dval, 0.0, 1.0); - } else if (!strcmp(key, "force")) { - double const dval = ( val ? g_ascii_strtod (val, NULL) : 1.0 ); - tc->force = CLAMP(dval, 0, 1.0); - } else if (!strcmp(key, "usepressure")) { - tc->usepressure = (val && strcmp(val, "0")); - } else if (!strcmp(key, "doh")) { - tc->do_h = (val && strcmp(val, "0")); - } else if (!strcmp(key, "dos")) { - tc->do_s = (val && strcmp(val, "0")); - } else if (!strcmp(key, "dol")) { - tc->do_l = (val && strcmp(val, "0")); - } else if (!strcmp(key, "doo")) { - tc->do_o = (val && strcmp(val, "0")); - } + Glib::ustring path = val->getEntryName(); + + if (path == "width") { + tc->width = CLAMP(val->getDouble(0.1), -1000.0, 1000.0); + } else if (path == "mode") { + tc->mode = val->getInt(); + sp_tweak_update_cursor(tc, false); + } else if (path == "fidelity") { + tc->fidelity = CLAMP(val->getDouble(), 0.0, 1.0); + } else if (path == "force") { + tc->force = CLAMP(val->getDouble(1.0), 0, 1.0); + } else if (path == "usepressure") { + tc->usepressure = val->getBool(); + } else if (path == "doh") { + tc->do_h = val->getBool(); + } else if (path == "dos") { + tc->do_s = val->getBool(); + } else if (path == "dol") { + tc->do_l = val->getBool(); + } else if (path == "doo") { + tc->do_o = val->getBool(); + } } static void @@ -309,34 +380,170 @@ double get_dilate_radius (SPTweakContext *tc) { // 10 times the pen width: - return 500 * tc->width/SP_EVENT_CONTEXT(tc)->desktop->current_zoom(); + return 500 * tc->width/SP_EVENT_CONTEXT(tc)->desktop->current_zoom(); } double -get_dilate_force (SPTweakContext *tc) +get_path_force (SPTweakContext *tc) { double force = 8 * (tc->usepressure? tc->pressure : TC_DEFAULT_PRESSURE) - /sqrt(SP_EVENT_CONTEXT(tc)->desktop->current_zoom()); + /sqrt(SP_EVENT_CONTEXT(tc)->desktop->current_zoom()); if (force > 3) { force += 4 * (force - 3); } return force * tc->force; } +double +get_move_force (SPTweakContext *tc) +{ + double force = (tc->usepressure? tc->pressure : TC_DEFAULT_PRESSURE); + return force * tc->force; +} + bool -sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, NR::Point p, NR::Point vector, gint mode, double radius, double force, double fidelity) +sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, Geom::Point p, Geom::Point vector, gint mode, double radius, double force, double fidelity, bool reverse) { bool did = false; - if (SP_IS_GROUP(item)) { - for (SPObject *child = sp_object_first_child(SP_OBJECT(item)) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + if (SP_IS_BOX3D(item) && !is_transform_mode(mode) && !is_color_mode(mode)) { + // convert 3D boxes to ordinary groups before tweaking their shapes + item = SP_ITEM(box3d_convert_to_group(SP_BOX3D(item))); + selection->add(item); + } + + if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { + GSList *items = g_slist_prepend (NULL, item); + GSList *selected = NULL; + GSList *to_select = NULL; + SPDocument *doc = SP_OBJECT_DOCUMENT(item); + sp_item_list_to_curves (items, &selected, &to_select); + g_slist_free (items); + SPObject* newObj = doc->getObjectByRepr((Inkscape::XML::Node *) to_select->data); + g_slist_free (to_select); + item = (SPItem *) newObj; + selection->add(item); + } + + if (SP_IS_GROUP(item) && !SP_IS_BOX3D(item)) { + GSList *children = NULL; + for (SPObject *child = item->firstChild() ; child; child = child->getNext() ) { if (SP_IS_ITEM(child)) { - if (sp_tweak_dilate_recursive (selection, SP_ITEM(child), p, vector, mode, radius, force, fidelity)) - did = true; + children = g_slist_prepend(children, child); } } - } else if (SP_IS_PATH(item) || SP_IS_SHAPE(item) || SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) { + for (GSList *i = children; i; i = i->next) { + SPItem *child = SP_ITEM(i->data); + if (sp_tweak_dilate_recursive (selection, SP_ITEM(child), p, vector, mode, radius, force, fidelity, reverse)) + did = true; + } + + g_slist_free(children); + + } else { + if (mode == TWEAK_MODE_MOVE) { + + Geom::OptRect a = item->getBounds(item->i2doc_affine()); + if (a) { + double x = Geom::L2(a->midpoint() - p)/radius; + if (a->contains(p)) x = 0; + if (x < 1) { + Geom::Point move = force * 0.5 * (cos(M_PI * x) + 1) * vector; + sp_item_move_rel(item, Geom::Translate(move[Geom::X], -move[Geom::Y])); + did = true; + } + } + + } else if (mode == TWEAK_MODE_MOVE_IN_OUT) { + + Geom::OptRect a = item->getBounds(item->i2doc_affine()); + if (a) { + double x = Geom::L2(a->midpoint() - p)/radius; + if (a->contains(p)) x = 0; + if (x < 1) { + Geom::Point move = force * 0.5 * (cos(M_PI * x) + 1) * + (reverse? (a->midpoint() - p) : (p - a->midpoint())); + sp_item_move_rel(item, Geom::Translate(move[Geom::X], -move[Geom::Y])); + did = true; + } + } + + } else if (mode == TWEAK_MODE_MOVE_JITTER) { + + Geom::OptRect a = item->getBounds(item->i2doc_affine()); + if (a) { + double dp = g_random_double_range(0, M_PI*2); + double dr = g_random_double_range(0, radius); + double x = Geom::L2(a->midpoint() - p)/radius; + if (a->contains(p)) x = 0; + if (x < 1) { + Geom::Point move = force * 0.5 * (cos(M_PI * x) + 1) * Geom::Point(cos(dp)*dr, sin(dp)*dr); + sp_item_move_rel(item, Geom::Translate(move[Geom::X], -move[Geom::Y])); + did = true; + } + } + + } else if (mode == TWEAK_MODE_SCALE) { + + Geom::OptRect a = item->getBounds(item->i2doc_affine()); + if (a) { + double x = Geom::L2(a->midpoint() - p)/radius; + if (a->contains(p)) x = 0; + if (x < 1) { + double scale = 1 + (reverse? force : -force) * 0.05 * (cos(M_PI * x) + 1); + sp_item_scale_rel(item, Geom::Scale(scale, scale)); + did = true; + } + } + + } else if (mode == TWEAK_MODE_ROTATE) { + + Geom::OptRect a = item->getBounds(item->i2doc_affine()); + if (a) { + double x = Geom::L2(a->midpoint() - p)/radius; + if (a->contains(p)) x = 0; + if (x < 1) { + double angle = (reverse? force : -force) * 0.05 * (cos(M_PI * x) + 1) * M_PI; + sp_item_rotate_rel(item, Geom::Rotate(angle)); + did = true; + } + } + + } else if (mode == TWEAK_MODE_MORELESS) { + + Geom::OptRect a = item->getBounds(item->i2doc_affine()); + if (a) { + double x = Geom::L2(a->midpoint() - p)/radius; + if (a->contains(p)) x = 0; + if (x < 1) { + double prob = force * 0.5 * (cos(M_PI * x) + 1); + double chance = g_random_double_range(0, 1); + if (chance <= prob) { + if (reverse) { // delete + sp_object_ref(SP_OBJECT(item), NULL); + SP_OBJECT(item)->deleteObject(true, true); + sp_object_unref(SP_OBJECT(item), NULL); + } else { // duplicate + SPDocument *doc = SP_OBJECT_DOCUMENT(item); + Inkscape::XML::Document* xml_doc = doc->getReprDoc(); + Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item); + SPObject *old_obj = doc->getObjectByRepr(old_repr); + Inkscape::XML::Node *parent = old_repr->parent(); + Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc); + parent->appendChild(copy); + SPObject *new_obj = doc->getObjectByRepr(copy); + if (selection->includes(old_obj)) { + selection->add(new_obj); + } + Inkscape::GC::release(copy); + } + did = true; + } + } + } + + } else if (SP_IS_PATH(item) || SP_IS_SHAPE(item)) { Inkscape::XML::Node *newrepr = NULL; gint pos = 0; @@ -357,9 +564,9 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, NR::Poi // skip those paths whose bboxes are entirely out of reach with our radius - NR::Maybe bbox = item->getBounds(sp_item_i2doc_affine(item)); + Geom::OptRect bbox = item->getBounds(item->i2doc_affine()); if (bbox) { - bbox->growBy(radius); + bbox->expandBy(radius); if (!bbox->contains(p)) { return false; } @@ -369,13 +576,15 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, NR::Poi if (orig == NULL) { return false; } + Path *res = new Path; res->SetBackData(false); Shape *theShape = new Shape; Shape *theRes = new Shape; + Geom::Matrix i2doc(item->i2doc_affine()); - orig->ConvertWithBackData(0.08 - (0.07 * fidelity)); // default 0.059 + orig->ConvertWithBackData((0.08 - (0.07 * fidelity)) / i2doc.descrim()); // default 0.059 orig->Fill(theShape, 0); SPCSSAttr *css = sp_repr_css_attr(SP_OBJECT_REPR(item), "style"); @@ -393,32 +602,33 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, NR::Poi theRes->ConvertToShape(theShape, fill_nonZero); } - if (NR::L2(vector) != 0) - vector = 1/NR::L2(vector) * vector; + if (Geom::L2(vector) != 0) + vector = 1/Geom::L2(vector) * vector; bool did_this = false; - NR::Matrix i2doc(sp_item_i2doc_affine(item)); - if (mode == TWEAK_MODE_SHRINK || mode == TWEAK_MODE_GROW) { - if (theShape->MakeOffset(theRes, - mode == TWEAK_MODE_GROW? force : -force, + if (mode == TWEAK_MODE_SHRINK_GROW) { + if (theShape->MakeTweak(tweak_mode_grow, theRes, + reverse? force : -force, join_straight, 4.0, - true, p[NR::X], p[NR::Y], radius, &i2doc) == 0) // 0 means the shape was actually changed + true, p, Geom::Point(0,0), radius, &i2doc) == 0) // 0 means the shape was actually changed did_this = true; - } else if (mode == TWEAK_MODE_ATTRACT || mode == TWEAK_MODE_REPEL) { - if (theShape->MakeRepel(theRes, - mode == TWEAK_MODE_REPEL? force : -force, + } else if (mode == TWEAK_MODE_ATTRACT_REPEL) { + if (theShape->MakeTweak(tweak_mode_repel, theRes, + reverse? force : -force, join_straight, 4.0, - true, p[NR::X], p[NR::Y], radius, &i2doc) == 0) + true, p, Geom::Point(0,0), radius, &i2doc) == 0) did_this = true; } else if (mode == TWEAK_MODE_PUSH) { - if (theShape->MakePush(theRes, + if (theShape->MakeTweak(tweak_mode_push, theRes, + 1.0, join_straight, 4.0, true, p, force*2*vector, radius, &i2doc) == 0) did_this = true; } else if (mode == TWEAK_MODE_ROUGHEN) { - if (theShape->MakeJitter(theRes, + if (theShape->MakeTweak(tweak_mode_roughen, theRes, + force, join_straight, 4.0, - true, p, force, radius, &i2doc) == 0) + true, p, Geom::Point(0,0), radius, &i2doc) == 0) did_this = true; } @@ -429,10 +639,10 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, NR::Poi res->Reset(); theRes->ConvertToForme(res); - double th_max = 0.6 - 0.59*sqrt(fidelity); + double th_max = (0.6 - 0.59*sqrt(fidelity)) / i2doc.descrim(); double threshold = MAX(th_max, th_max*force); res->ConvertEvenLines(threshold); - res->Simplify(threshold); + res->Simplify(threshold / (selection->desktop()->current_zoom())); if (newrepr) { // converting to path, need to replace the repr bool is_selected = selection->includes(item); @@ -453,12 +663,17 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, NR::Poi selection->add(newrepr); } - if (res->descr_cmd.size() > 1) { + if (res->descr_cmd.size() > 1) { gchar *str = res->svg_dump_path(); - if (newrepr) + if (newrepr) { newrepr->setAttribute("d", str); - else - SP_OBJECT_REPR(item)->setAttribute("d", str); + } else { + if (SP_IS_LPE_ITEM(item) && sp_lpe_item_has_path_effect_recursive(SP_LPE_ITEM(item))) { + SP_OBJECT_REPR(item)->setAttribute("inkscape:original-d", str); + } else { + SP_OBJECT_REPR(item)->setAttribute("d", str); + } + } g_free(str); } else { // TODO: if there's 0 or 1 node left, delete this path altogether @@ -475,15 +690,17 @@ sp_tweak_dilate_recursive (Inkscape::Selection *selection, SPItem *item, NR::Poi delete orig; delete res; - if (did_this) + if (did_this) did = true; } + } + return did; } -void -tweak_colorpaint (float *color, guint32 goal, double force, bool do_h, bool do_s, bool do_l) +void +tweak_colorpaint (float *color, guint32 goal, double force, bool do_h, bool do_s, bool do_l) { float rgb_g[3]; @@ -492,11 +709,11 @@ tweak_colorpaint (float *color, guint32 goal, double force, bool do_h, bool do_s sp_color_rgb_to_hsl_floatv (hsl_g, SP_RGBA32_R_F(goal), SP_RGBA32_G_F(goal), SP_RGBA32_B_F(goal)); float hsl_c[3]; sp_color_rgb_to_hsl_floatv (hsl_c, color[0], color[1], color[2]); - if (!do_h) + if (!do_h) hsl_g[0] = hsl_c[0]; - if (!do_s) + if (!do_s) hsl_g[1] = hsl_c[1]; - if (!do_l) + if (!do_l) hsl_g[2] = hsl_c[2]; sp_color_hsl_to_rgb_floatv (rgb_g, hsl_g[0], hsl_g[1], hsl_g[2]); } else { @@ -511,11 +728,9 @@ tweak_colorpaint (float *color, guint32 goal, double force, bool do_h, bool do_s } } -void -tweak_colorjitter (float *color, double force, bool do_h, bool do_s, bool do_l) +void +tweak_colorjitter (float *color, double force, bool do_h, bool do_s, bool do_l) { - force = force*force; // in [0..1], this makes finer adjustments easier - float hsl_c[3]; sp_color_rgb_to_hsl_floatv (hsl_c, color[0], color[1], color[2]); @@ -536,8 +751,8 @@ tweak_colorjitter (float *color, double force, bool do_h, bool do_s, bool do_l) sp_color_hsl_to_rgb_floatv (color, hsl_c[0], hsl_c[1], hsl_c[2]); } -void -tweak_color (guint mode, float *color, guint32 goal, double force, bool do_h, bool do_s, bool do_l) +void +tweak_color (guint mode, float *color, guint32 goal, double force, bool do_h, bool do_s, bool do_l) { if (mode == TWEAK_MODE_COLORPAINT) { tweak_colorpaint (color, goal, force, do_h, do_s, do_l); @@ -563,7 +778,7 @@ tweak_opacity (guint mode, SPIScale24 *style_opacity, double opacity_goal, doubl double -tweak_profile (double dist, double radius) +tweak_profile (double dist, double radius) { if (radius == 0) return 0; @@ -579,17 +794,17 @@ tweak_profile (double dist, double radius) } void -tweak_colors_in_gradient (SPItem *item, bool fill_or_stroke, - guint32 const rgb_goal, NR::Point p_w, double radius, double force, guint mode, - bool do_h, bool do_s, bool do_l, bool do_o) +tweak_colors_in_gradient (SPItem *item, bool fill_or_stroke, + guint32 const rgb_goal, Geom::Point p_w, double radius, double force, guint mode, + bool do_h, bool do_s, bool do_l, bool /*do_o*/) { SPGradient *gradient = sp_item_gradient (item, fill_or_stroke); if (!gradient || !SP_IS_GRADIENT(gradient)) return; - NR::Matrix i2d = sp_item_i2doc_affine (item); - NR::Point p = p_w * i2d.inverse(); + Geom::Matrix i2d (item->i2doc_affine ()); + Geom::Point p = p_w * i2d.inverse(); p *= (gradient->gradientTransform).inverse(); // now p is in gradient's original coordinates @@ -598,46 +813,50 @@ tweak_colors_in_gradient (SPItem *item, bool fill_or_stroke, if (SP_IS_LINEARGRADIENT(gradient)) { SPLinearGradient *lg = SP_LINEARGRADIENT(gradient); - NR::Point p1(lg->x1.computed, lg->y1.computed); - NR::Point p2(lg->x2.computed, lg->y2.computed); - NR::Point pdiff(p2 - p1); - double vl = NR::L2(pdiff); + Geom::Point p1(lg->x1.computed, lg->y1.computed); + Geom::Point p2(lg->x2.computed, lg->y2.computed); + Geom::Point pdiff(p2 - p1); + double vl = Geom::L2(pdiff); // This is the matrix which moves and rotates the gradient line // so it's oriented along the X axis: - NR::Matrix norm = NR::Matrix(NR::translate(-p1)) * NR::Matrix(NR::rotate(-atan2(pdiff[NR::Y], pdiff[NR::X]))); + Geom::Matrix norm = Geom::Matrix(Geom::Translate(-p1)) * Geom::Matrix(Geom::Rotate(-atan2(pdiff[Geom::Y], pdiff[Geom::X]))); // Transform the mouse point by it to find out its projection onto the gradient line: - NR::Point pnorm = p * norm; + Geom::Point pnorm = p * norm; // Scale its X coordinate to match the length of the gradient line: - pos = pnorm[NR::X] / vl; + pos = pnorm[Geom::X] / vl; // Calculate radius in lenfth-of-gradient-line units r = radius / vl; } else if (SP_IS_RADIALGRADIENT(gradient)) { SPRadialGradient *rg = SP_RADIALGRADIENT(gradient); - NR::Point c (rg->cx.computed, rg->cy.computed); - pos = NR::L2(p - c) / rg->r.computed; + Geom::Point c (rg->cx.computed, rg->cy.computed); + pos = Geom::L2(p - c) / rg->r.computed; r = radius / rg->r.computed; } // Normalize pos to 0..1, taking into accound gradient spread: double pos_e = pos; - if (gradient->spread == SP_GRADIENT_SPREAD_PAD) { - if (pos > 1) + if (gradient->getSpread() == SP_GRADIENT_SPREAD_PAD) { + if (pos > 1) { pos_e = 1; - if (pos < 0) + } + if (pos < 0) { pos_e = 0; - } else if (gradient->spread == SP_GRADIENT_SPREAD_REPEAT) { - if (pos > 1 || pos < 0) + } + } else if (gradient->getSpread() == SP_GRADIENT_SPREAD_REPEAT) { + if (pos > 1 || pos < 0) { pos_e = pos - floor(pos); - } else if (gradient->spread == SP_GRADIENT_SPREAD_REFLECT) { + } + } else if (gradient->getSpread() == SP_GRADIENT_SPREAD_REFLECT) { if (pos > 1 || pos < 0) { bool odd = ((int)(floor(pos)) % 2 == 1); pos_e = pos - floor(pos); - if (odd) + if (odd) { pos_e = 1 - pos_e; + } } } @@ -646,10 +865,10 @@ tweak_colors_in_gradient (SPItem *item, bool fill_or_stroke, double offset_l = 0; double offset_h = 0; SPObject *child_prev = NULL; - for (SPObject *child = sp_object_first_child(vector); - child != NULL; child = SP_OBJECT_NEXT(child)) { - if (!SP_IS_STOP(child)) + for (SPObject *child = vector->firstChild(); child; child = child->getNext()) { + if (!SP_IS_STOP(child)) { continue; + } SPStop *stop = SP_STOP (child); offset_h = stop->offset; @@ -661,27 +880,27 @@ tweak_colors_in_gradient (SPItem *item, bool fill_or_stroke, // so it only affects the ends of this interstop; // distribute the force between the two endstops so that they // get all the painting even if they are not touched by the brush - tweak_color (mode, stop->specified_color.v.c, rgb_goal, - force * (pos_e - offset_l) / (offset_h - offset_l), + tweak_color (mode, stop->specified_color.v.c, rgb_goal, + force * (pos_e - offset_l) / (offset_h - offset_l), do_h, do_s, do_l); - tweak_color (mode, SP_STOP(child_prev)->specified_color.v.c, rgb_goal, - force * (offset_h - pos_e) / (offset_h - offset_l), + tweak_color (mode, SP_STOP(child_prev)->specified_color.v.c, rgb_goal, + force * (offset_h - pos_e) / (offset_h - offset_l), do_h, do_s, do_l); SP_OBJECT(stop)->updateRepr(); child_prev->updateRepr(); break; } else { - // wide brush, may affect more than 2 stops, + // wide brush, may affect more than 2 stops, // paint each stop by the force from the profile curve - if (offset_l <= pos_e && offset_l > pos_e - r) { - tweak_color (mode, SP_STOP(child_prev)->specified_color.v.c, rgb_goal, + if (offset_l <= pos_e && offset_l > pos_e - r) { + tweak_color (mode, SP_STOP(child_prev)->specified_color.v.c, rgb_goal, force * tweak_profile (fabs (pos_e - offset_l), r), do_h, do_s, do_l); child_prev->updateRepr(); - } + } - if (offset_h >= pos_e && offset_h < pos_e + r) { - tweak_color (mode, stop->specified_color.v.c, rgb_goal, + if (offset_h >= pos_e && offset_h < pos_e + r) { + tweak_color (mode, stop->specified_color.v.c, rgb_goal, force * tweak_profile (fabs (pos_e - offset_h), r), do_h, do_s, do_l); SP_OBJECT(stop)->updateRepr(); @@ -695,23 +914,25 @@ tweak_colors_in_gradient (SPItem *item, bool fill_or_stroke, } bool -sp_tweak_color_recursive (guint mode, SPItem *item, SPItem *item_at_point, +sp_tweak_color_recursive (guint mode, SPItem *item, SPItem *item_at_point, guint32 fill_goal, bool do_fill, guint32 stroke_goal, bool do_stroke, float opacity_goal, bool do_opacity, - NR::Point p, double radius, double force, + bool do_blur, bool reverse, + Geom::Point p, double radius, double force, bool do_h, bool do_s, bool do_l, bool do_o) { bool did = false; if (SP_IS_GROUP(item)) { - for (SPObject *child = sp_object_first_child(SP_OBJECT(item)) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + for (SPObject *child = item->firstChild() ; child; child = child->getNext() ) { if (SP_IS_ITEM(child)) { - if (sp_tweak_color_recursive (mode, SP_ITEM(child), item_at_point, + if (sp_tweak_color_recursive (mode, SP_ITEM(child), item_at_point, fill_goal, do_fill, stroke_goal, do_stroke, opacity_goal, do_opacity, - p, radius, force, do_h, do_s, do_l, do_o)); + do_blur, reverse, + p, radius, force, do_h, do_s, do_l, do_o)) did = true; } } @@ -721,15 +942,15 @@ sp_tweak_color_recursive (guint mode, SPItem *item, SPItem *item_at_point, if (!style) { return false; } - NR::Maybe bbox = item->getBounds(sp_item_i2doc_affine(item), + Geom::OptRect bbox = item->getBounds(item->i2doc_affine(), SPItem::GEOMETRIC_BBOX); if (!bbox) { return false; } - NR::Rect brush(p - NR::Point(radius, radius), p + NR::Point(radius, radius)); + Geom::Rect brush(p - Geom::Point(radius, radius), p + Geom::Point(radius, radius)); - NR::Point center = bbox->midpoint(); + Geom::Point center = bbox->midpoint(); double this_force; // if item == item_at_point, use max force @@ -745,29 +966,77 @@ sp_tweak_color_recursive (guint mode, SPItem *item, SPItem *item_at_point, // else if object > 0.5 brush: test 4 corners of bbox and center on being in the brush, choose max // else if still smaller, then check only the object center: } else { - this_force = force * tweak_profile (NR::L2 (p - center), radius); + this_force = force * tweak_profile (Geom::L2 (p - center), radius); } - + if (this_force > 0.002) { + if (do_blur) { + Geom::OptRect bbox = item->getBounds(item->i2doc_affine(), + SPItem::GEOMETRIC_BBOX); + if (!bbox) { + return did; + } + + double blur_now = 0; + Geom::Matrix i2d = item->i2d_affine (); + if (style->filter.set && style->getFilter()) { + //cycle through filter primitives + SPObject *primitive_obj = style->getFilter()->children; + while (primitive_obj) { + if (SP_IS_FILTER_PRIMITIVE(primitive_obj)) { + SPFilterPrimitive *primitive = SP_FILTER_PRIMITIVE(primitive_obj); + //if primitive is gaussianblur + if(SP_IS_GAUSSIANBLUR(primitive)) { + SPGaussianBlur * spblur = SP_GAUSSIANBLUR(primitive); + float num = spblur->stdDeviation.getNumber(); + blur_now += num * i2d.descrim(); // sum all blurs in the filter + } + } + primitive_obj = primitive_obj->next; + } + } + double perimeter = bbox->dimensions()[Geom::X] + bbox->dimensions()[Geom::Y]; + blur_now = blur_now / perimeter; + + double blur_new; + if (reverse) + blur_new = blur_now - 0.06 * force; + else + blur_new = blur_now + 0.06 * force; + if (blur_new < 0.0005 && blur_new < blur_now) { + blur_new = 0; + } + + if (blur_new == 0) { + remove_filter(item, false); + } else { + double radius = blur_new * perimeter; + SPFilter *filter = modify_filter_gaussian_blur_from_item(SP_OBJECT_DOCUMENT(item), item, radius); + + sp_style_set_property_url(item, "filter", filter, false); + } + return true; // do not do colors, blur is a separate mode + } + if (do_fill) { - if (style->fill.type == SP_PAINT_TYPE_COLOR) { + if (style->fill.isPaintserver()) { + tweak_colors_in_gradient (item, true, fill_goal, p, radius, this_force, mode, do_h, do_s, do_l, do_o); + did = true; + } else if (style->fill.isColor()) { tweak_color (mode, style->fill.value.color.v.c, fill_goal, this_force, do_h, do_s, do_l); item->updateRepr(); did = true; - } else if (style->fill.type == SP_PAINT_TYPE_PAINTSERVER) { - tweak_colors_in_gradient (item, true, fill_goal, p, radius, this_force, mode, do_h, do_s, do_l, do_o); - did = true; } } if (do_stroke) { - if (style->stroke.type == SP_PAINT_TYPE_COLOR) { + if (style->stroke.isPaintserver()) { + tweak_colors_in_gradient (item, false, stroke_goal, p, radius, this_force, mode, do_h, do_s, do_l, do_o); + did = true; + } else if (style->stroke.isColor()) { tweak_color (mode, style->stroke.value.color.v.c, stroke_goal, this_force, do_h, do_s, do_l); item->updateRepr(); did = true; - } else if (style->stroke.type == SP_PAINT_TYPE_PAINTSERVER) { - tweak_colors_in_gradient (item, false, stroke_goal, p, radius, this_force, mode, do_h, do_s, do_l, do_o); - did = true; } } if (do_opacity && do_o) { @@ -781,47 +1050,63 @@ sp_tweak_color_recursive (guint mode, SPItem *item, SPItem *item_at_point, bool -sp_tweak_dilate (SPTweakContext *tc, NR::Point event_p, NR::Point p, NR::Point vector) +sp_tweak_dilate (SPTweakContext *tc, Geom::Point event_p, Geom::Point p, Geom::Point vector, bool reverse) { Inkscape::Selection *selection = sp_desktop_selection(SP_EVENT_CONTEXT(tc)->desktop); + SPDesktop *desktop = SP_EVENT_CONTEXT(tc)->desktop; if (selection->isEmpty()) { return false; } bool did = false; - double radius = get_dilate_radius(tc); - double force = get_dilate_force(tc); - if (radius == 0 || force == 0) { - return false; - } - double color_force = MIN(sqrt(force)/4.0, 1); + double radius = get_dilate_radius(tc); - SPItem *item_at_point = SP_EVENT_CONTEXT(tc)->desktop->item_at_point(event_p, TRUE); - Inkscape::XML::Node *tool_repr = inkscape_get_repr(INKSCAPE, "tools.tweak"); - SPCSSAttr *css = sp_repr_css_attr_inherited(tool_repr, "style"); - if (tc->mode == TWEAK_MODE_COLORPAINT && !css) - return false; + SPItem *item_at_point = SP_EVENT_CONTEXT(tc)->desktop->getItemAtPoint(event_p, TRUE); bool do_fill = false, do_stroke = false, do_opacity = false; - guint32 fill_goal = 0, stroke_goal = 0; - float opacity_goal = 1; - - const gchar *fill_prop = sp_repr_css_property(css, "fill", NULL); - if (fill_prop && strcmp(fill_prop, "none")) { - do_fill = true; - fill_goal = sp_svg_read_color(fill_prop, 0); - } - const gchar *stroke_prop = sp_repr_css_property(css, "stroke", NULL); - if (stroke_prop && strcmp(stroke_prop, "none")) { - do_stroke = true; - stroke_goal = sp_svg_read_color(stroke_prop, 0); + guint32 fill_goal = sp_desktop_get_color_tool(desktop, "/tools/tweak", true, &do_fill); + guint32 stroke_goal = sp_desktop_get_color_tool(desktop, "/tools/tweak", false, &do_stroke); + double opacity_goal = sp_desktop_get_master_opacity_tool(desktop, "/tools/tweak", &do_opacity); + if (reverse) { +#if 0 + // HSL inversion + float hsv[3]; + float rgb[3]; + sp_color_rgb_to_hsv_floatv (hsv, + SP_RGBA32_R_F(fill_goal), + SP_RGBA32_G_F(fill_goal), + SP_RGBA32_B_F(fill_goal)); + sp_color_hsv_to_rgb_floatv (rgb, hsv[0]<.5? hsv[0]+.5 : hsv[0]-.5, 1 - hsv[1], 1 - hsv[2]); + fill_goal = SP_RGBA32_F_COMPOSE(rgb[0], rgb[1], rgb[2], 1); + sp_color_rgb_to_hsv_floatv (hsv, + SP_RGBA32_R_F(stroke_goal), + SP_RGBA32_G_F(stroke_goal), + SP_RGBA32_B_F(stroke_goal)); + sp_color_hsv_to_rgb_floatv (rgb, hsv[0]<.5? hsv[0]+.5 : hsv[0]-.5, 1 - hsv[1], 1 - hsv[2]); + stroke_goal = SP_RGBA32_F_COMPOSE(rgb[0], rgb[1], rgb[2], 1); +#else + // RGB inversion + fill_goal = SP_RGBA32_U_COMPOSE( + (255 - SP_RGBA32_R_U(fill_goal)), + (255 - SP_RGBA32_G_U(fill_goal)), + (255 - SP_RGBA32_B_U(fill_goal)), + (255 - SP_RGBA32_A_U(fill_goal))); + stroke_goal = SP_RGBA32_U_COMPOSE( + (255 - SP_RGBA32_R_U(stroke_goal)), + (255 - SP_RGBA32_G_U(stroke_goal)), + (255 - SP_RGBA32_B_U(stroke_goal)), + (255 - SP_RGBA32_A_U(stroke_goal))); +#endif + opacity_goal = 1 - opacity_goal; } - const gchar *opacity_prop = sp_repr_css_property(css, "opacity", NULL); - if (opacity_prop) { - do_opacity = true; - sp_svg_number_read_f(opacity_prop, &opacity_goal); + + double path_force = get_path_force(tc); + if (radius == 0 || path_force == 0) { + return false; } + double move_force = get_move_force(tc); + double color_force = MIN(sqrt(path_force)/20.0, 1); for (GSList *items = g_slist_copy((GSList *) selection->itemList()); items != NULL; @@ -829,17 +1114,21 @@ sp_tweak_dilate (SPTweakContext *tc, NR::Point event_p, NR::Point p, NR::Point v SPItem *item = (SPItem *) items->data; - if (tc->mode == TWEAK_MODE_COLORPAINT || tc->mode == TWEAK_MODE_COLORJITTER) { + if (is_color_mode (tc->mode)) { if (do_fill || do_stroke || do_opacity) { - if (sp_tweak_color_recursive (tc->mode, item, item_at_point, + if (sp_tweak_color_recursive (tc->mode, item, item_at_point, fill_goal, do_fill, stroke_goal, do_stroke, opacity_goal, do_opacity, + tc->mode == TWEAK_MODE_BLUR, reverse, p, radius, color_force, tc->do_h, tc->do_s, tc->do_l, tc->do_o)) did = true; } + } else if (is_transform_mode(tc->mode)) { + if (sp_tweak_dilate_recursive (selection, item, p, vector, tc->mode, radius, move_force, tc->fidelity, reverse)) + did = true; } else { - if (sp_tweak_dilate_recursive (selection, item, p, vector, tc->mode, radius, force, tc->fidelity)) + if (sp_tweak_dilate_recursive (selection, item, p, vector, tc->mode, radius, path_force, tc->fidelity, reverse)) did = true; } } @@ -851,31 +1140,32 @@ void sp_tweak_update_area (SPTweakContext *tc) { double radius = get_dilate_radius(tc); - NR::Matrix const sm (NR::scale(radius, radius) * NR::translate(SP_EVENT_CONTEXT(tc)->desktop->point())); + Geom::Matrix const sm (Geom::Scale(radius, radius) * Geom::Translate(SP_EVENT_CONTEXT(tc)->desktop->point())); sp_canvas_item_affine_absolute(tc->dilate_area, sm); sp_canvas_item_show(tc->dilate_area); } void -sp_tweak_switch_mode (SPTweakContext *tc, gint mode) +sp_tweak_switch_mode (SPTweakContext *tc, gint mode, bool with_shift) { SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue ("tweak_tool_mode", mode); // need to set explicitly, because the prefs may not have changed by the previous tc->mode = mode; - sp_tweak_update_cursor (tc, mode); + sp_tweak_update_cursor (tc, with_shift); } void -sp_tweak_switch_mode_temporarily (SPTweakContext *tc, gint mode) +sp_tweak_switch_mode_temporarily (SPTweakContext *tc, gint mode, bool with_shift) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); // Juggling about so that prefs have the old value but tc->mode and the button show new mode: - gint now_mode = prefs_get_int_attribute("tools.tweak", "mode", 0); + gint now_mode = prefs->getInt("/tools/tweak/mode", 0); SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue ("tweak_tool_mode", mode); // button has changed prefs, restore - prefs_set_int_attribute("tools.tweak", "mode", now_mode); + prefs->setInt("/tools/tweak/mode", now_mode); // changing prefs changed tc->mode, restore back :) tc->mode = mode; - sp_tweak_update_cursor (tc, mode); + sp_tweak_update_cursor (tc, with_shift); } gint @@ -901,9 +1191,9 @@ sp_tweak_context_root_handler(SPEventContext *event_context, return TRUE; } - NR::Point const button_w(event->button.x, + Geom::Point const button_w(event->button.x, event->button.y); - NR::Point const button_dt(desktop->w2d(button_w)); + Geom::Point const button_dt(desktop->w2d(button_w)); tc->last_push = desktop->dt2doc(button_dt); sp_tweak_extinput(tc, event); @@ -918,15 +1208,15 @@ sp_tweak_context_root_handler(SPEventContext *event_context, break; case GDK_MOTION_NOTIFY: { - NR::Point const motion_w(event->motion.x, + Geom::Point const motion_w(event->motion.x, event->motion.y); - NR::Point motion_dt(desktop->w2d(motion_w)); - NR::Point motion_doc(desktop->dt2doc(motion_dt)); + Geom::Point motion_dt(desktop->w2d(motion_w)); + Geom::Point motion_doc(desktop->dt2doc(motion_dt)); sp_tweak_extinput(tc, event); // draw the dilating cursor double radius = get_dilate_radius(tc); - NR::Matrix const sm (NR::scale(radius, radius) * NR::translate(desktop->w2d(motion_w))); + Geom::Matrix const sm (Geom::Scale(radius, radius) * Geom::Translate(desktop->w2d(motion_w))); sp_canvas_item_affine_absolute(tc->dilate_area, sm); sp_canvas_item_show(tc->dilate_area); @@ -935,47 +1225,12 @@ sp_tweak_context_root_handler(SPEventContext *event_context, num = g_slist_length((GSList *) desktop->selection->itemList()); } if (num == 0) { - tc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("Select objects to tweak")); - } else { - switch (tc->mode) { - case TWEAK_MODE_PUSH: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, - _("Pushing %d selected object(s)"), num); - break; - case TWEAK_MODE_SHRINK: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, - _("Shrinking %d selected object(s)"), num); - break; - case TWEAK_MODE_GROW: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, - _("Growing %d selected object(s)"), num); - break; - case TWEAK_MODE_ATTRACT: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, - _("Attracting %d selected object(s)"), num); - break; - case TWEAK_MODE_REPEL: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, - _("Repelling %d selected object(s)"), num); - break; - case TWEAK_MODE_ROUGHEN: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, - _("Roughening %d selected object(s)"), num); - case TWEAK_MODE_COLORPAINT: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, - _("Painting %d selected object(s)"), num); - break; - case TWEAK_MODE_COLORJITTER: - tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, - _("Jittering colors in %d selected object(s)"), num); - break; - } + tc->_message_context->flash(Inkscape::ERROR_MESSAGE, _("Nothing selected! Select objects to tweak.")); } - // dilating: - if (tc->is_drawing && ( event->motion.state & GDK_BUTTON1_MASK )) { - sp_tweak_dilate (tc, motion_w, motion_doc, motion_doc - tc->last_push); + if (tc->is_drawing && ( event->motion.state & GDK_BUTTON1_MASK )) { + sp_tweak_dilate (tc, motion_w, motion_doc, motion_doc - tc->last_push, event->button.state & GDK_SHIFT_MASK? true : false); //tc->last_push = motion_doc; tc->has_dilated = true; // it's slow, so prevent clogging up with events @@ -989,8 +1244,8 @@ sp_tweak_context_root_handler(SPEventContext *event_context, case GDK_BUTTON_RELEASE: { - NR::Point const motion_w(event->button.x, event->button.y); - NR::Point const motion_dt(desktop->w2d(motion_w)); + Geom::Point const motion_w(event->button.x, event->button.y); + Geom::Point const motion_dt(desktop->w2d(motion_w)); sp_canvas_end_forced_full_redraws(desktop->canvas); tc->is_drawing = false; @@ -999,110 +1254,170 @@ sp_tweak_context_root_handler(SPEventContext *event_context, if (!tc->has_dilated) { // if we did not rub, do a light tap tc->pressure = 0.03; - sp_tweak_dilate (tc, motion_w, desktop->dt2doc(motion_dt), NR::Point(0,0)); + sp_tweak_dilate (tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT); } tc->is_dilating = false; tc->has_dilated = false; switch (tc->mode) { - case TWEAK_MODE_PUSH: - sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Push tweak")); + case TWEAK_MODE_MOVE: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Move tweak")); break; - case TWEAK_MODE_SHRINK: - sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Shrink tweak")); + case TWEAK_MODE_MOVE_IN_OUT: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Move in/out tweak")); break; - case TWEAK_MODE_GROW: - sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Grow tweak")); + case TWEAK_MODE_MOVE_JITTER: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Move jitter tweak")); break; - case TWEAK_MODE_ATTRACT: - sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Attract tweak")); + case TWEAK_MODE_SCALE: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Scale tweak")); break; - case TWEAK_MODE_REPEL: - sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Repel tweak")); + case TWEAK_MODE_ROTATE: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Rotate tweak")); + break; + case TWEAK_MODE_MORELESS: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Duplicate/delete tweak")); + break; + case TWEAK_MODE_PUSH: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Push path tweak")); + break; + case TWEAK_MODE_SHRINK_GROW: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Shrink/grow path tweak")); + break; + case TWEAK_MODE_ATTRACT_REPEL: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Attract/repel path tweak")); break; case TWEAK_MODE_ROUGHEN: - sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Roughen tweak")); + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Roughen path tweak")); break; case TWEAK_MODE_COLORPAINT: - sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Color paint tweak")); + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Color paint tweak")); + break; case TWEAK_MODE_COLORJITTER: - sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), - SP_VERB_CONTEXT_TWEAK, _("Color jitter tweak")); + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Color jitter tweak")); + break; + case TWEAK_MODE_BLUR: + DocumentUndo::done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_TWEAK, _("Blur tweak")); break; } - } + } break; } case GDK_KEY_PRESS: switch (get_group0_keyval (&event->key)) { - case GDK_p: - case GDK_P: + case GDK_m: + case GDK_M: + case GDK_0: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE, MOD__SHIFT); + ret = TRUE; + } + break; + case GDK_i: + case GDK_I: case GDK_1: if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_PUSH); + sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE_IN_OUT, MOD__SHIFT); ret = TRUE; } break; - case GDK_s: - case GDK_S: + case GDK_z: + case GDK_Z: case GDK_2: if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_SHRINK); + sp_tweak_switch_mode(tc, TWEAK_MODE_MOVE_JITTER, MOD__SHIFT); ret = TRUE; } break; - case GDK_g: - case GDK_G: + case GDK_less: + case GDK_comma: + case GDK_greater: + case GDK_period: case GDK_3: if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_GROW); + sp_tweak_switch_mode(tc, TWEAK_MODE_SCALE, MOD__SHIFT); ret = TRUE; } break; - case GDK_a: - case GDK_A: + case GDK_bracketright: + case GDK_bracketleft: case GDK_4: if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_ATTRACT); + sp_tweak_switch_mode(tc, TWEAK_MODE_ROTATE, MOD__SHIFT); ret = TRUE; } break; - case GDK_e: - case GDK_E: + case GDK_d: + case GDK_D: case GDK_5: if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_REPEL); + sp_tweak_switch_mode(tc, TWEAK_MODE_MORELESS, MOD__SHIFT); + ret = TRUE; + } + break; + case GDK_p: + case GDK_P: + case GDK_6: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_PUSH, MOD__SHIFT); + ret = TRUE; + } + break; + case GDK_s: + case GDK_S: + case GDK_7: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_SHRINK_GROW, MOD__SHIFT); + ret = TRUE; + } + break; + case GDK_a: + case GDK_A: + case GDK_8: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_ATTRACT_REPEL, MOD__SHIFT); ret = TRUE; } break; case GDK_r: case GDK_R: - case GDK_6: + case GDK_9: if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_ROUGHEN); + sp_tweak_switch_mode(tc, TWEAK_MODE_ROUGHEN, MOD__SHIFT); ret = TRUE; } break; case GDK_c: case GDK_C: - case GDK_7: if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_COLORPAINT); + sp_tweak_switch_mode(tc, TWEAK_MODE_COLORPAINT, MOD__SHIFT); ret = TRUE; } break; case GDK_j: case GDK_J: - case GDK_8: if (MOD__SHIFT_ONLY) { - sp_tweak_switch_mode(tc, TWEAK_MODE_COLORJITTER); + sp_tweak_switch_mode(tc, TWEAK_MODE_COLORJITTER, MOD__SHIFT); + ret = TRUE; + } + break; + case GDK_b: + case GDK_B: + if (MOD__SHIFT_ONLY) { + sp_tweak_switch_mode(tc, TWEAK_MODE_BLUR, MOD__SHIFT); ret = TRUE; } break; @@ -1171,43 +1486,37 @@ sp_tweak_context_root_handler(SPEventContext *event_context, } break; - case GDK_Control_L: - case GDK_Control_R: - if (MOD__SHIFT) { - sp_tweak_switch_mode_temporarily(tc, TWEAK_MODE_GROW); - } else { - sp_tweak_switch_mode_temporarily(tc, TWEAK_MODE_SHRINK); - } - break; case GDK_Shift_L: case GDK_Shift_R: - if (MOD__CTRL) { - sp_tweak_switch_mode_temporarily(tc, TWEAK_MODE_GROW); - } + sp_tweak_update_cursor(tc, true); + break; + + case GDK_Control_L: + case GDK_Control_R: + sp_tweak_switch_mode_temporarily(tc, TWEAK_MODE_SHRINK_GROW, MOD__SHIFT); break; default: break; } break; - case GDK_KEY_RELEASE: + case GDK_KEY_RELEASE: { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); switch (get_group0_keyval(&event->key)) { + case GDK_Shift_L: + case GDK_Shift_R: + sp_tweak_update_cursor(tc, false); + break; case GDK_Control_L: case GDK_Control_R: - sp_tweak_switch_mode (tc, prefs_get_int_attribute("tools.tweak", "mode", 0)); + sp_tweak_switch_mode (tc, prefs->getInt("/tools/tweak/mode"), MOD__SHIFT); tc->_message_context->clear(); break; - case GDK_Shift_L: - case GDK_Shift_R: - if (MOD__CTRL) { - sp_tweak_switch_mode_temporarily(tc, TWEAK_MODE_SHRINK); - } - break; - break; default: - sp_tweak_switch_mode (tc, prefs_get_int_attribute("tools.tweak", "mode", 0)); + sp_tweak_switch_mode (tc, prefs->getInt("/tools/tweak/mode"), MOD__SHIFT); break; } + } default: break; @@ -1232,4 +1541,4 @@ sp_tweak_context_root_handler(SPEventContext *event_context, fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :