tweak-tool.cpp revision f91279be939ce6c33befa6cdb5bc8a99cc5a765c
31a1996396ad24d86958f98db29aa15a74b10e6ftavmjong-free * tweaking paths without node editing
31a1996396ad24d86958f98db29aa15a74b10e6ftavmjong-free * Jon A. Cruz <jon@joncruz.org>
31a1996396ad24d86958f98db29aa15a74b10e6ftavmjong-free * Abhishek Sharma
31a1996396ad24d86958f98db29aa15a74b10e6ftavmjong-free * Copyright (C) 2007 authors
31a1996396ad24d86958f98db29aa15a74b10e6ftavmjong-free * Released under GNU GPL, read the file 'COPYING' for more information
31a1996396ad24d86958f98db29aa15a74b10e6ftavmjong-free#include "pixmaps/cursor-tweak-move-jitter.xpm"
31a1996396ad24d86958f98db29aa15a74b10e6ftavmjong-free#include "pixmaps/cursor-tweak-rotate-clockwise.xpm"
31a1996396ad24d86958f98db29aa15a74b10e6ftavmjong-free#include "pixmaps/cursor-tweak-rotate-counterclockwise.xpm"
#include "pixmaps/cursor-repel.xpm"
#include "pixmaps/cursor-push.xpm"
#include "pixmaps/cursor-roughen.xpm"
#include "pixmaps/cursor-color.xpm"
#include "context-fns.h"
#include "sp-item.h"
#include "inkscape.h"
#include "color.h"
#include "svg/svg-color.h"
#include "splivarot.h"
#include "sp-item-group.h"
#include "sp-shape.h"
#include "sp-path.h"
#include "path-chemistry.h"
#include "sp-gradient.h"
#include "sp-stop.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 "preferences.h"
#include "style.h"
#include "box3d.h"
#include "sp-item-transform.h"
#include "filter-chemistry.h"
#include "filters/gaussian-blur.h"
#include "verbs.h"
#include "ui/tools/tweak-tool.h"
#include "tool-factory.h"
namespace Inkscape {
namespace UI {
namespace Tools {
return new TweakTool();
bool tweakContextRegistered = ToolFactory::instance().registerObject("/tools/tweak", createTweakContext);
, dragging(false)
, usepressure(false)
, usetilt(false)
, fidelity(0)
, mode(0)
, is_drawing(false)
, is_dilating(false)
, has_dilated(false)
, do_h(true)
, do_s(true)
, do_l(true)
, do_o(false)
this->enableGrDrag(false);
if (this->dilate_area) {
return (mode == TWEAK_MODE_COLORPAINT || mode == TWEAK_MODE_COLORJITTER || mode == TWEAK_MODE_BLUR);
sel_message = g_strdup_printf(ngettext("<b>%i</b> object selected","<b>%i</b> objects selected",num), num);
switch (this->mode) {
case TWEAK_MODE_MOVE:
case TWEAK_MODE_MOVE_IN_OUT:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>move in</b>; with Shift to <b>move out</b>."), sel_message);
if (with_shift) {
case TWEAK_MODE_MOVE_JITTER:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>move randomly</b>."), sel_message);
case TWEAK_MODE_SCALE:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>scale down</b>; with Shift to <b>scale up</b>."), sel_message);
if (with_shift) {
case TWEAK_MODE_ROTATE:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>rotate clockwise</b>; with Shift, <b>counterclockwise</b>."), sel_message);
if (with_shift) {
case TWEAK_MODE_MORELESS:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>duplicate</b>; with Shift, <b>delete</b>."), sel_message);
if (with_shift) {
case TWEAK_MODE_PUSH:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag to <b>push paths</b>."), sel_message);
case TWEAK_MODE_SHRINK_GROW:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>inset paths</b>; with Shift to <b>outset</b>."), sel_message);
if (with_shift) {
case TWEAK_MODE_ATTRACT_REPEL:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>attract paths</b>; with Shift to <b>repel</b>."), sel_message);
if (with_shift) {
case TWEAK_MODE_ROUGHEN:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>roughen paths</b>."), sel_message);
case TWEAK_MODE_COLORPAINT:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>paint objects</b> with color."), sel_message);
case TWEAK_MODE_COLORJITTER:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>randomize colors</b>."), sel_message);
case TWEAK_MODE_BLUR:
this->message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag or click to <b>increase blur</b>; with Shift to <b>decrease</b>."), sel_message);
this->sp_event_context_update_cursor();
/* TODO: have a look at sp_dyna_draw_context_setup where the same is done.. generalize? at least make it an arcto! */
c->unref();
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->dilate_area), 0xff9900ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
this->is_drawing = false;
this->style_set_connection = this->desktop->connectSetStyle( // catch style-setting signal in this tool
this->enableSelectionCue();
this->enableGrDrag();
this->update_cursor(false);
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_tweak_dilate_recursive (selection, child, p, vector, mode, radius, force, fidelity, reverse)) {
did = true;
if (a->contains(p)) x = 0;
did = true;
if (a->contains(p)) x = 0;
did = true;
if (a->contains(p)) x = 0;
did = true;
if (a->contains(p)) x = 0;
did = true;
if (a->contains(p)) x = 0;
did = true;
if (a->contains(p)) x = 0;
did = true;
if (!newrepr) {
if (bbox) {
bool did_this = false;
did_this = true;
did_this = true;
did_this = true;
did_this = true;
if (did_this) {
if (is_selected) {
if (is_selected)
if (newrepr) {
if (newrepr) {
delete theShape;
delete theRes;
delete orig;
delete res;
if (did_this) {
did = true;
return did;
if (!do_h) {
if (!do_s) {
if (!do_l) {
if (do_h) {
if (hsl_c[0] < 0) {
if (do_s) {
if (do_l) {
if (radius == 0) {
double pos = 0;
if (lg) {
Geom::Affine norm = Geom::Affine(Geom::Translate(-p1)) * Geom::Affine(Geom::Rotate(-atan2(pdiff[Geom::Y], pdiff[Geom::X])));
if (rg) {
if (pos < 0) {
pos_e = 0;
if (odd) {
double offset_l = 0;
double offset_h = 0;
if (!stop) {
if (child_prev) {
bool did = false;
if (childItem) {
did = true;
if (!style) {
if (!bbox) {
double this_force;
if (do_blur) {
if (!bbox) {
return did;
double blur_now = 0;
while (primitive_obj) {
if (primitive) {
if (spblur) {
double blur_new;
if (reverse) {
blur_new = 0;
if (blur_new == 0) {
if (do_fill) {
tweak_colors_in_gradient(item, Inkscape::FOR_FILL, fill_goal, p, radius, this_force, mode, do_h, do_s, do_l, do_o);
did = true;
did = true;
if (do_stroke) {
tweak_colors_in_gradient(item, Inkscape::FOR_STROKE, stroke_goal, p, radius, this_force, mode, do_h, do_s, do_l, do_o);
did = true;
did = true;
return did;
sp_tweak_dilate (TweakTool *tc, Geom::Point event_p, Geom::Point p, Geom::Point vector, bool reverse)
bool did = false;
if (reverse) {
did = true;
if (sp_tweak_dilate_recursive (selection, item, p, vector, tc->mode, radius, move_force, tc->fidelity, reverse)) {
did = true;
if (sp_tweak_dilate_recursive (selection, item, p, vector, tc->mode, radius, path_force, tc->fidelity, reverse)) {
did = true;
return did;
Geom::Affine const sm (Geom::Scale(radius, radius) * Geom::Translate(SP_EVENT_CONTEXT(tc)->desktop->point()));
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
case GDK_BUTTON_PRESS:
return TRUE;
this->is_drawing = true;
this->is_dilating = true;
this->has_dilated = false;
case GDK_MOTION_NOTIFY:
if (num == 0) {
this->message_context->flash(Inkscape::ERROR_MESSAGE, _("<b>Nothing selected!</b> Select objects to tweak."));
sp_tweak_dilate (this, motion_w, motion_doc, motion_doc - this->last_push, event->button.state & GDK_SHIFT_MASK? true : false);
this->has_dilated = true;
return TRUE;
case GDK_BUTTON_RELEASE:
this->is_drawing = false;
if (!this->has_dilated) {
this->is_dilating = false;
this->has_dilated = false;
switch (this->mode) {
case TWEAK_MODE_MOVE:
case TWEAK_MODE_MOVE_IN_OUT:
case TWEAK_MODE_MOVE_JITTER:
case TWEAK_MODE_SCALE:
case TWEAK_MODE_ROTATE:
case TWEAK_MODE_MORELESS:
case TWEAK_MODE_PUSH:
case TWEAK_MODE_SHRINK_GROW:
case TWEAK_MODE_ATTRACT_REPEL:
case TWEAK_MODE_ROUGHEN:
case TWEAK_MODE_COLORPAINT:
case TWEAK_MODE_COLORJITTER:
case TWEAK_MODE_BLUR:
case GDK_KEY_PRESS:
case GDK_KEY_m:
case GDK_KEY_M:
case GDK_KEY_0:
case GDK_KEY_i:
case GDK_KEY_I:
case GDK_KEY_1:
case GDK_KEY_z:
case GDK_KEY_Z:
case GDK_KEY_2:
case GDK_KEY_less:
case GDK_KEY_comma:
case GDK_KEY_greater:
case GDK_KEY_period:
case GDK_KEY_3:
case GDK_KEY_bracketright:
case GDK_KEY_bracketleft:
case GDK_KEY_4:
case GDK_KEY_d:
case GDK_KEY_D:
case GDK_KEY_5:
case GDK_KEY_p:
case GDK_KEY_P:
case GDK_KEY_6:
case GDK_KEY_s:
case GDK_KEY_S:
case GDK_KEY_7:
case GDK_KEY_a:
case GDK_KEY_A:
case GDK_KEY_8:
case GDK_KEY_r:
case GDK_KEY_R:
case GDK_KEY_9:
case GDK_KEY_c:
case GDK_KEY_C:
case GDK_KEY_j:
case GDK_KEY_J:
case GDK_KEY_b:
case GDK_KEY_B:
case GDK_KEY_Up:
case GDK_KEY_KP_Up:
case GDK_KEY_Down:
case GDK_KEY_KP_Down:
case GDK_KEY_Right:
case GDK_KEY_KP_Right:
desktop->setToolboxAdjustmentValue ("altx-tweak", this->width * 100); // the same spinbutton is for alt+x
sp_tweak_update_area(this);
case GDK_KEY_Left:
case GDK_KEY_KP_Left:
sp_tweak_update_area(this);
case GDK_KEY_Home:
case GDK_KEY_KP_Home:
sp_tweak_update_area(this);
case GDK_KEY_End:
case GDK_KEY_KP_End:
sp_tweak_update_area(this);
case GDK_KEY_x:
case GDK_KEY_X:
case GDK_KEY_Shift_L:
case GDK_KEY_Shift_R:
this->update_cursor(true);
case GDK_KEY_Control_L:
case GDK_KEY_Control_R:
case GDK_KEY_Delete:
case GDK_KEY_KP_Delete:
case GDK_KEY_BackSpace:
case GDK_KEY_RELEASE: {
case GDK_KEY_Shift_L:
case GDK_KEY_Shift_R:
this->update_cursor(false);
case GDK_KEY_Control_L:
case GDK_KEY_Control_R:
if (!ret) {
return ret;