From 0b51e8dca51e424e491522197eb7ca55e45a38b4 Mon Sep 17 00:00:00 2001 From: Josh Andler Date: Mon, 30 Nov 2009 12:53:48 -0800 Subject: [PATCH] Spray Tool by the students at Ecole Centrale de Lyon, Lyon, France --- AUTHORS | 7 + share/icons/icons.svg | 668 ++++++++++++- src/Makefile_insert | 1 + src/pixmaps/cursor-spray-move.xpm | 38 + src/pixmaps/cursor-spray.xpm | 38 + src/preferences-skeleton.h | 1 + src/spray-context.cpp | 1199 ++++++++++++++++++++++++ src/spray-context.h | 125 +++ src/tools-switch.cpp | 8 + src/tools-switch.h | 1 + src/ui/dialog/Makefile_insert | 2 + src/ui/dialog/dialog-manager.cpp | 6 +- src/ui/dialog/inkscape-preferences.cpp | 6 + src/ui/dialog/inkscape-preferences.h | 3 +- src/ui/dialog/spray-option.cpp | 381 ++++++++ src/ui/dialog/spray-option.h | 130 +++ src/ui/icon-names.h | 10 + src/ui/view/edit-widget.cpp | 6 + src/ui/view/edit-widget.h | 1 + src/verbs.cpp | 16 + src/verbs.h | 3 + src/widgets/toolbox.cpp | 214 +++++ 22 files changed, 2856 insertions(+), 8 deletions(-) create mode 100644 src/pixmaps/cursor-spray-move.xpm create mode 100644 src/pixmaps/cursor-spray.xpm create mode 100644 src/spray-context.cpp create mode 100644 src/spray-context.h create mode 100644 src/ui/dialog/spray-option.cpp create mode 100644 src/ui/dialog/spray-option.h diff --git a/AUTHORS b/AUTHORS index fcea87043..d498ff98a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1,5 +1,6 @@ Maximilian Albert Josh Andler +Pierre Barbry-Blot Jean-François Barraud Bill Baxter John Bintz @@ -17,6 +18,7 @@ Marcus Brubaker Luca Bruno Nicu Buculei Bulia Byak +Pierre Caclin Ian Caldwell Gail Carmichael Ed Catmur @@ -76,11 +78,15 @@ Jason Kivlighn Adrian Knoth Krzysztof Kosiński Petr Kovar +Benoît Lavorata +Julien Leray Raph Levien Diederik van Lierop Nicklas Lindgren Vitaly Lipatov Ivan Louette +Pierre-Antoine Marc +Aurel-Aimé Marmion Colin Marquardt Dmitry G. Mastrukov Matiphas @@ -88,6 +94,7 @@ Michael Meeks Federico Mena MenTaLguY Aubanel Monnier +Vincent Montagne Tim Mooney Derek P. Moore Peter Moulder diff --git a/share/icons/icons.svg b/share/icons/icons.svg index dd0fe6068..baa74483a 100644 --- a/share/icons/icons.svg +++ b/share/icons/icons.svg @@ -8,7 +8,7 @@ xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" - inkscape:version="0.46+devel r21165 custom" + inkscape:version="0.47+devel" sodipodi:docname="icons.svg" height="540" width="1250" @@ -4922,6 +4922,155 @@ gradientUnits="userSpaceOnUse" id="linearGradient3740" inkscape:collect="always" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + inkscape:snap-object-midpoints="false" + inkscape:window-maximized="0"> d="m 910.68469,121.666 c 0.89363,0.12497 1.4826,1.05773 1.2925,1.92328 -0.0941,1.00279 -1.11367,1.5906 -2.04198,1.62018 -0.72256,0.0699 -1.45173,-0.0589 -2.13313,-0.29781 0,-0.27759 0,-0.55517 0,-0.83276 0.83664,0.45611 1.92451,0.60201 2.80073,0.17757 0.80169,-0.43444 0.69059,-1.81155 -0.19684,-2.08095 -0.48076,-0.18386 -1.00008,-0.10942 -1.50209,-0.12512 0,-0.2363 0,-0.47261 0,-0.70891 0.6676,-0.0288 1.50939,0.14892 1.9565,-0.47536 0.4177,-0.66094 -0.14468,-1.53437 -0.90782,-1.51097 -0.66571,-0.0681 -1.33009,0.0928 -1.95831,0.2995 0,-0.25623 0,-0.51247 0,-0.7687 1.08005,-0.28661 2.40764,-0.52909 3.35334,0.23188 0.80208,0.64443 0.62653,2.14224 -0.3992,2.46393 l -0.12785,0.0456 -0.13585,0.0387" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Makefile_insert b/src/Makefile_insert index de986ca16..18beaec37 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -222,6 +222,7 @@ ink_common_sources += \ sp-tspan.cpp sp-tspan.h \ sp-use.cpp sp-use.h \ sp-use-reference.cpp sp-use-reference.h \ + spray-context.cpp spray-context.h \ star-context.cpp star-context.h \ streq.h \ strneq.h \ diff --git a/src/pixmaps/cursor-spray-move.xpm b/src/pixmaps/cursor-spray-move.xpm new file mode 100644 index 000000000..ad898b3a5 --- /dev/null +++ b/src/pixmaps/cursor-spray-move.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static char const * cursor_spray_move_xpm[] = { +"32 32 3 1", +" c None", +". c #FFFFFF", +"+ c #000000", +" ... ", +" .+. ", +" .+. ", +"....+.... ", +".+++ +++. ", +"....+.... ", +" .+. ", +" .+. ", +" ... ", +" ... ... ... ... ", +" ..+. ..+. ..+. ..+. ", +" .+++ .+++ .+++ .+++ ", +" ..+. .+++ .+++ ..+ ", +" .... .+++ .+++ .... ", +" ..+. ..+ ..+ ..+. ", +" .+++ ..+. ..+. .+++ ", +" ..+ .+++ .+++ ..+ ", +" .... ..+ ..+ .... ", +" ..+. .... .... ..+. ", +" .+++ ..+. ..+. .+++ ", +" ..+ .+++ .+++ ..+ ", +" ..+ ..+ ", +" ... ... ", +" ..+. ..+. ", +" .+++ .+++ ", +" ..+ ..+ ", +" ", +" ", +" ", +" ", +" ", +" "}; diff --git a/src/pixmaps/cursor-spray.xpm b/src/pixmaps/cursor-spray.xpm new file mode 100644 index 000000000..9ccefee4f --- /dev/null +++ b/src/pixmaps/cursor-spray.xpm @@ -0,0 +1,38 @@ +/* XPM */ +static char const * cursor_spray_xpm[] = { +"32 32 3 1", +" c None", +". c #FFFFFF", +"+ c #000000", +" ... ", +" .+. ", +" .+. ", +"....+.... ", +".+++ +++. ", +"....+.... ", +" .+. ", +" .+. ", +" ... .+. +. ", +" .+.+.+.+. ", +" .+...+...+. ", +" +...+.....+. ", +" . . . .+.+.......+. ", +" + + + .+.........+. ", +" . . . .+...........+. ", +" + + .+.............+. ", +" . . . .+.............+. ", +" + + + .+.............+. ", +" . . .+.............+. ", +" .+.............+. ", +" .+.............+. ", +" .+...........+. ", +" .+.........+. ", +" .+.......+. ", +" .+.....+. ", +" .+...+. ", +" .+.+. ", +" .+. ", +" . ", +" ", +" ", +" "}; diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index 6185ff729..80a1bd5ea 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -114,6 +114,7 @@ static char const preferences_skeleton[] = " style=\"fill:black;fill-opacity:1;stroke:none;font-family:Bitstream Vera Sans;font-style:normal;font-weight:normal;font-size:40px;\" selcue=\"1\"/>\n" " \n" " \n" +" \n" " \n" " \n" " \n" diff --git a/src/spray-context.cpp b/src/spray-context.cpp new file mode 100644 index 000000000..71dc9648a --- /dev/null +++ b/src/spray-context.cpp @@ -0,0 +1,1199 @@ +#define __SP_SPRAY_CONTEXT_C__ + +/* + * Spray Tool + * + * Authors: + * Pierre-Antoine MARC + * Pierre CACLIN + * Aurel-Aimé MARMION + * Julien LERAY + * Benoît LAVORATA + * Vincent MONTAGNE + * Pierre BARBRY-BLOT + * + * Copyright (C) 2009 authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "config.h" + +#include +#include +#include + +#include + +#include "svg/svg.h" +#include "display/canvas-bpath.h" + +#include +#include "macros.h" +#include "document.h" +#include "selection.h" +#include "desktop.h" +#include "desktop-events.h" +#include "desktop-handles.h" +#include "unistd.h" +#include "desktop-style.h" +#include "message-context.h" +#include "pixmaps/cursor-spray.xpm" +#include "pixmaps/cursor-spray-move.xpm" +#include "pixmaps/cursor-thin.xpm" +#include "pixmaps/cursor-thicken.xpm" +#include "pixmaps/cursor-attract.xpm" +#include "pixmaps/cursor-repel.xpm" +#include "pixmaps/cursor-push.xpm" +#include "pixmaps/cursor-roughen.xpm" +#include "pixmaps/cursor-color.xpm" +#include +#include "libnr/nr-matrix-ops.h" +#include "libnr/nr-scale-translate-ops.h" +#include "xml/repr.h" +#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-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/canvas-bpath.h" +#include "display/canvas-arena.h" +#include "display/curve.h" +#include "livarot/Shape.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 "spray-context.h" +#include "ui/dialog/dialog-manager.h" +#include "helper/action.h" + +#include +using namespace std; + + +#define DDC_RED_RGBA 0xff0000ff + +#define DYNA_MIN_WIDTH 1.0e-6 + +static void sp_spray_context_class_init(SPSprayContextClass *klass); +static void sp_spray_context_init(SPSprayContext *ddc); +static void sp_spray_context_dispose(GObject *object); + +static void sp_spray_context_setup(SPEventContext *ec); +static void sp_spray_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val); +static gint sp_spray_context_root_handler(SPEventContext *ec, GdkEvent *event); + +static SPEventContextClass *parent_class; + + + +// The following code implements NormalDistribution wich is used for the density of the spray + + +/* + RAND is a macro which returns a pseudo-random numbers from a uniform + distribution on the interval [0 1] +*/ +#define RAND ((double) rand())/((double) RAND_MAX) + +/* + TWOPI = 2.0*pi +*/ +#define TWOPI 2.0*3.141592653589793238462643383279502884197169399375 + +/* + RANDN is a macro which returns a pseudo-random numbers from a normal + distribution with mean zero and standard deviation one. This macro uses Box + Muller's algorithm +*/ +#define RANDN sqrt(-2.0*log(RAND))*cos(TWOPI*RAND) + + +double NormalDistribution(double mu,double sigma) +{ +/* + This function returns a pseudo-random numbers from a normal distribution with + mean equal at mu and standard deviation equal at sigma > 0 +*/ + + return (mu+sigma*RANDN); + +} + +//Fin de la création de NormalDistribution + +GtkType +sp_spray_context_get_type(void) +{ + static GType type = 0; + if (!type) { + GTypeInfo info = { + sizeof(SPSprayContextClass), + NULL, NULL, + (GClassInitFunc) sp_spray_context_class_init, + NULL, NULL, + sizeof(SPSprayContext), + 4, + (GInstanceInitFunc) sp_spray_context_init, + NULL, /* value_table */ + }; + type = g_type_register_static(SP_TYPE_EVENT_CONTEXT, "SPSprayContext", &info, (GTypeFlags)0); + } + return type; +} + +static void +sp_spray_context_class_init(SPSprayContextClass *klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + SPEventContextClass *event_context_class = (SPEventContextClass *) klass; + + parent_class = (SPEventContextClass*)g_type_class_peek_parent(klass); + + object_class->dispose = sp_spray_context_dispose; + + event_context_class->setup = sp_spray_context_setup; + event_context_class->set = sp_spray_context_set; + event_context_class->root_handler = sp_spray_context_root_handler; +} +/*Method to rotate items*/ +void +sp_spray_rotate_rel(Geom::Point c,SPDesktop *desktop,SPItem *item, Geom::Rotate const &rotation) +{ + + Geom::Point center = c; + Geom::Translate const s(c); + Geom::Matrix affine = Geom::Matrix(s).inverse() * Geom::Matrix(rotation) * Geom::Matrix(s); + + // Rotate item. + sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * (Geom::Matrix)affine); + // Use each item's own transform writer, consistent with sp_selection_apply_affine() + sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform); + + // Restore the center position (it's changed because the bbox center changed) + if (item->isCenterSet()) { + item->setCenter(c); + item->updateRepr(); + } +} +/*Method to scale items*/ +void +sp_spray_scale_rel (Geom::Point c, SPDesktop *desktop, SPItem *item, Geom::Scale const &scale) +{ + Geom::Translate const s(c); + + + sp_item_set_i2d_affine(item, sp_item_i2d_affine(item) * s.inverse() * scale * s ); + sp_item_write_transform(item, SP_OBJECT_REPR(item), item->transform); + + +} +static void +sp_spray_context_init(SPSprayContext *tc) +{ + SPEventContext *event_context = SP_EVENT_CONTEXT(tc); + + + + event_context->cursor_shape = cursor_spray_xpm; + event_context->hot_x = 4; + event_context->hot_y = 4; + + /* attributes */ + tc->dragging = FALSE; + tc->distrib = 1; + tc->width = 0.2; + tc->force = 0.2; + tc->ratio = 0; + tc->tilt=0; + tc->mean = 0.2; + tc->rot_min=0; + tc->rot_max=0; + tc->standard_deviation=0.2; + tc->scale=1; + tc->scale_min = 1; + tc->scale_max=1; + tc->pressure = TC_DEFAULT_PRESSURE; + + tc->is_dilating = false; + tc->has_dilated = false; + + tc->do_h = true; + tc->do_s = true; + tc->do_l = true; + tc->do_o = false; + + new (&tc->style_set_connection) sigc::connection(); +} + +static void +sp_spray_context_dispose(GObject *object) +{ + SPSprayContext *tc = SP_SPRAY_CONTEXT(object); + + tc->style_set_connection.disconnect(); + tc->style_set_connection.~connection(); + + if (tc->dilate_area) { + gtk_object_destroy(GTK_OBJECT(tc->dilate_area)); + tc->dilate_area = NULL; + } + + if (tc->_message_context) { + delete tc->_message_context; + } + + G_OBJECT_CLASS(parent_class)->dispose(object); +} + +bool is_transform_modes (gint mode) +{ + return (mode == SPRAY_MODE_COPY || + mode == SPRAY_MODE_CLONE || + mode == SPRAY_MODE_SINGLE_PATH || + mode == SPRAY_OPTION); +} + +void +sp_spray_update_cursor (SPSprayContext *tc, bool with_shift) +{ + 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 SPRAY_MODE_COPY: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray copies of the initial selection"), sel_message); + break; + case SPRAY_MODE_CLONE: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray clones of the initial selection"), sel_message); + break; + case SPRAY_MODE_SINGLE_PATH: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Drag, click or scroll to spray in a single path of the initial selection"), sel_message); + break; + case SPRAY_OPTION: + tc->_message_context->setF(Inkscape::NORMAL_MESSAGE, _("%s. Modify spray options"), sel_message); + break; + } + sp_event_context_update_cursor(event_context); + g_free(sel_message); +} + +static void +sp_spray_context_setup(SPEventContext *ec) +{ + SPSprayContext *tc = SP_SPRAY_CONTEXT(ec); + + if (((SPEventContextClass *) parent_class)->setup) + ((SPEventContextClass *) parent_class)->setup(ec); + + { + /* 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); + 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, "distrib"); + sp_event_context_read(ec, "width"); + sp_event_context_read(ec, "ratio"); + sp_event_context_read(ec, "tilt"); + sp_event_context_read(ec, "rot_min"); + sp_event_context_read(ec, "rot_max"); + sp_event_context_read(ec, "scale_min"); + sp_event_context_read(ec, "scale_max"); + sp_event_context_read(ec, "mode"); + sp_event_context_read(ec, "population"); + sp_event_context_read(ec, "force"); + sp_event_context_read(ec, "mean"); + sp_event_context_read(ec, "standard_deviation"); + sp_event_context_read(ec, "usepressure"); + sp_event_context_read(ec, "Rotation min"); + sp_event_context_read(ec, "Rotation max"); + sp_event_context_read(ec, "Scale"); + sp_event_context_read(ec, "doh"); + sp_event_context_read(ec, "dol"); + sp_event_context_read(ec, "dos"); + sp_event_context_read(ec, "doo"); + + ; + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (prefs->getBool("/tools/spray/selcue")) { + ec->enableSelectionCue(); + } + + if (prefs->getBool("/tools/spray/gradientdrag")) { + ec->enableGrDrag(); + } +} + +static void +sp_spray_context_set(SPEventContext *ec, Inkscape::Preferences::Entry *val) +{ + SPSprayContext *tc = SP_SPRAY_CONTEXT(ec); + 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_spray_update_cursor(tc, false); + } else if (path == "distribution") { + tc->distrib = val->getInt(1); + } else if (path == "population") { + tc->population = CLAMP(val->getDouble(), 0.0, 1.0); + } else if (path == "tilt") { + tc->tilt = CLAMP(val->getDouble(0.1), 0, 1000.0); + } else if (path == "ratio") { + tc->ratio = CLAMP(val->getDouble(), 0.0, 0.9); + } else if (path == "force") { + tc->force = CLAMP(val->getDouble(1.0), 0, 1.0); + } else if (path == "rot_min") { + tc->rot_min = CLAMP(val->getDouble(0), 0, 10.0); + } else if (path == "rot_max") { + tc->rot_max = CLAMP(val->getDouble(0), 0, 10.0); + } else if (path == "scale_min") { + tc->scale_min = CLAMP(val->getDouble(1.0), 0, 10.0); + } else if (path == "scale_max") { + tc->scale_max = CLAMP(val->getDouble(1.0), 0, 10.0); + } else if (path == "mean") { + tc->mean = CLAMP(val->getDouble(1.0), 0, 1.0); + } else if (path == "standard_deviation") { + tc->standard_deviation = 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 +sp_spray_extinput(SPSprayContext *tc, GdkEvent *event) +{ + if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &tc->pressure)) + tc->pressure = CLAMP (tc->pressure, TC_MIN_PRESSURE, TC_MAX_PRESSURE); + else + tc->pressure = TC_DEFAULT_PRESSURE; +} + +double +get_dilate_radius (SPSprayContext *tc) +{ + + return 250 * tc->width/SP_EVENT_CONTEXT(tc)->desktop->current_zoom(); + + +} + +double +get_path_force (SPSprayContext *tc) +{ + double force = 8 * (tc->usepressure? tc->pressure : TC_DEFAULT_PRESSURE) + /sqrt(SP_EVENT_CONTEXT(tc)->desktop->current_zoom()); + if (force > 3) { + force += 4 * (force - 3); + } + return force * tc->force; +} + +double +get_path_mean (SPSprayContext *tc) +{ + return tc->mean; +} + +double +get_path_standard_deviation (SPSprayContext *tc) +{ + return tc->standard_deviation; +} + +double +get_move_force (SPSprayContext *tc) +{ + double force = (tc->usepressure? tc->pressure : TC_DEFAULT_PRESSURE); + return force * tc->force; +} + +double +get_move_mean (SPSprayContext *tc) +{ + return tc->mean; +} + +double +get_move_standard_deviation (SPSprayContext *tc) +{ + return tc->standard_deviation; +} + +/* Method to handle the distribution of the items */ + + +void random_position( double &r, double &p, double &a, double &s, int choix) +{ + if (choix == 0) // Mode 1 : uniform repartition + { + r = (1-pow(g_random_double_range(0, 1),2)); + p = g_random_double_range(0, M_PI*2); + } + if (choix == 1) //Mode 0 : gaussian repartition + { + double r_temp =-1; +while(!((r_temp>=0)&&(r_temp<=1))) +{ + r_temp = NormalDistribution(a,s/4); +} +// generates a number following a normal distribution + p = g_random_double_range(0, M_PI*2); + r=r_temp; + /* if (r_temp<=0) r=0; + else + { + if (r_temp>1) r=1; + else r = r_temp; + }*/ + } +} + + + + + +bool +sp_spray_dilate_recursive (SPDesktop *desktop, Inkscape::Selection *selection, SPItem *item, Geom::Point p, Geom::Point vector, gint mode, double radius, double force, double population, double &scale, double scale_min, double scale_max, bool reverse, double mean, double standard_deviation, double ratio,double tilt, double rot_min, double rot_max, gint _distrib ) +{ + + + + bool did = false; + + if (SP_IS_BOX3D(item) /*&& !is_transform_modes(mode)*/) { + // convert 3D boxes to ordinary groups before spraying 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)) { + for (SPObject *child = sp_object_first_child(SP_OBJECT(item)) ; child != NULL; child = SP_OBJECT_NEXT(child) ) { + if (SP_IS_ITEM(child)) { + if (sp_spray_dilate_recursive (desktop,selection, SP_ITEM(child), p, vector, mode, radius, force, population, scale, scale_min, scale_max, reverse, mean, standard_deviation,ratio,tilt, rot_min, rot_max,_distrib)) + did = true; + } + } + + } else {*/ + if (mode == SPRAY_MODE_COPY) { + + Geom::OptRect a = item->getBounds(sp_item_i2doc_affine(item)); + if (a) { + double dr; double dp; + random_position(dr,dp,mean,standard_deviation,_distrib); + dr=dr*radius; + double _fid = g_random_double_range(0,1); + SPItem *item_copied; + double angle = g_random_double_range(rot_min, rot_max); + double _scale = g_random_double_range(scale_min, scale_max); + if(_fid<=population) + { + // duplicate + SPDocument *doc = SP_OBJECT_DOCUMENT(item); + Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc); + Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item); + 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); + item_copied = (SPItem *) new_obj; //convertion object->item + Geom::Point center=item->getCenter(); + sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale)); + sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale)); + + sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle)); + Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());//Move the cursor p + sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); + + + + + + did = true; + } + } + + } else if (mode == SPRAY_MODE_SINGLE_PATH) { + + + SPItem *Pere; //Objet initial + SPItem *item_copied;//Objet projeté + SPItem *Union;//Union précédente + SPItem *fils;//Copie du père + + // GSList *items = g_slist_copy((GSList *) selection->itemList()); //Récupère la liste des objects sélectionnés +//Pere = (SPItem *) items->data;//Le premier objet est le père du spray + + int i=1; + for (GSList *items = g_slist_copy((GSList *) selection->itemList()); + items != NULL; + items = items->next) { + + SPItem *item1 = (SPItem *) items->data; + if (i==1) { + Pere=item1; + } + if (i==2) { + Union=item1; + } + i++; + } + SPDocument *doc = SP_OBJECT_DOCUMENT(Pere); + Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc); + Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(Pere); + //SPObject *old_obj = doc->getObjectByRepr(old_repr); + Inkscape::XML::Node *parent = old_repr->parent(); + + Geom::OptRect a = Pere->getBounds(sp_item_i2doc_affine(Pere)); + if (a) { + double dr; double dp; //initialisation des variables + random_position(dr,dp,mean,standard_deviation,_distrib); + dr=dr*radius; + double _fid = g_random_double_range(0,1); + double angle = (g_random_double_range(rot_min, rot_max)); + double _scale = g_random_double_range(scale_min, scale_max); + if (i==2) { + Inkscape::XML::Node *copy1 = old_repr->duplicate(xml_doc); + parent->appendChild(copy1); + SPObject *new_obj1 = doc->getObjectByRepr(copy1); + fils = (SPItem *) new_obj1; //conversion object->item + Union=fils; + Inkscape::GC::release(copy1); + } + + if (_fid<=population) { //Rules the population of objects sprayed + // duplicates the father + Inkscape::XML::Node *copy2 = old_repr->duplicate(xml_doc); + parent->appendChild(copy2); + SPObject *new_obj2 = doc->getObjectByRepr(copy2); + item_copied = (SPItem *) new_obj2; + + Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());//Move around the cursor + + Geom::Point center=Pere->getCenter(); + sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale)); + sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale)); + sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle)); + sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); + +//UNION et surduplication + selection->clear(); + selection->add(item_copied); + selection->add(Union); + sp_selected_path_union(selection->desktop()); + selection->add(Pere); + Inkscape::GC::release(copy2); + did = true; + } + + } + } else if (mode == SPRAY_MODE_CLONE) { + + Geom::OptRect a = item->getBounds(sp_item_i2doc_affine(item)); + if (a) { + double dr; double dp; + random_position(dr,dp,mean,standard_deviation,_distrib); + dr=dr*radius; + double _fid = g_random_double_range(0,1); + double angle = (g_random_double_range(rot_min, rot_max)); + double _scale = g_random_double_range(scale_min, scale_max); + + if(_fid<=population) + { + SPItem *item_copied; + SPDocument *doc = SP_OBJECT_DOCUMENT(item); + Inkscape::XML::Document* xml_doc = sp_document_repr_doc(doc); + Inkscape::XML::Node *old_repr = SP_OBJECT_REPR(item); + Inkscape::XML::Node *parent = old_repr->parent(); + + //Creation of the clone + Inkscape::XML::Node *clone = xml_doc->createElement("svg:use"); + parent->appendChild(clone); //Ajout du clone à la liste d'enfants du père (selection initiale + clone->setAttribute("xlink:href", g_strdup_printf("#%s", old_repr->attribute("id")), false); //Génère le lien entre les attributs du père et du fils + + SPObject *clone_object = doc->getObjectByRepr(clone); + item_copied = (SPItem *) clone_object;//conversion object->item + Geom::Point center=item->getCenter(); + sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(_scale,_scale)); + sp_spray_scale_rel(center,desktop,item_copied, Geom::Scale(scale,scale)); + sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle)); + Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio),-sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint()); + sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y])); + + Inkscape::GC::release(clone); + + did = true; + } }} + return did; + +} + + +bool +sp_spray_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, + 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; + + return did; +} + + +bool +sp_spray_dilate (SPSprayContext *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); + + + + bool do_fill = false, do_stroke = false, do_opacity = false; + guint32 fill_goal = sp_desktop_get_color_tool(desktop, "/tools/spray", true, &do_fill); + guint32 stroke_goal = sp_desktop_get_color_tool(desktop, "/tools/spray", false, &do_stroke); + double opacity_goal = sp_desktop_get_master_opacity_tool(desktop, "/tools/spray", &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; + } + + double path_force = get_path_force(tc); + if (radius == 0 || path_force == 0) { + return false; + } + double path_mean = get_path_mean(tc); + if (radius == 0 || path_mean == 0) { + return false; + } + double path_standard_deviation = get_path_standard_deviation(tc); + if (radius == 0 || path_standard_deviation == 0) { + return false; + } + double move_force = get_move_force(tc); + double move_mean = get_move_mean(tc); + double move_standard_deviation = get_move_standard_deviation(tc); + + + for (GSList *items = g_slist_copy((GSList *) selection->itemList()); + items != NULL; + items = items->next) { + + SPItem *item = (SPItem *) items->data; + + /*if (is_color_modes (tc->mode)) { + if (do_fill || do_stroke || do_opacity) { + if (sp_spray_color_recursive (tc->mode, item, item_at_point, + fill_goal, do_fill, + stroke_goal, do_stroke, + opacity_goal, do_opacity, + tc->mode == SPRAY_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_modes(tc->mode)) { + if (sp_spray_dilate_recursive (desktop,selection, item, p, vector, tc->mode, radius, move_force, tc->population,tc->scale, tc->scale_min, tc->scale_max, reverse, move_mean, move_standard_deviation,tc->ratio,tc->tilt, tc->rot_min, tc->rot_max, tc->distrib)) + did = true; + } else { + if (sp_spray_dilate_recursive (desktop,selection, item, p, vector, tc->mode, radius, path_force, tc->population,tc->scale, tc->scale_min, tc->scale_max, reverse, path_mean, path_standard_deviation,tc->ratio,tc->tilt, tc->rot_min, tc->rot_max, tc->distrib)) + did = true; + } + } + + return did; +} + +void +sp_spray_update_area (SPSprayContext *tc) +{ + double radius = get_dilate_radius(tc); + Geom::Matrix const sm ( Geom::Scale(radius/(1-tc->ratio), radius/(1+tc->ratio)) ); + sp_canvas_item_affine_absolute(tc->dilate_area, (sm* Geom::Rotate(tc->tilt))* Geom::Translate(SP_EVENT_CONTEXT(tc)->desktop->point())); + sp_canvas_item_show(tc->dilate_area); +} + +void +sp_spray_switch_mode (SPSprayContext *tc, gint mode, bool with_shift) +{ + SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue ("spray_tool_mode", mode); //sélectionne le bouton numéro "mode" + // need to set explicitly, because the prefs may not have changed by the previous + tc->mode = mode; + sp_spray_update_cursor (tc, with_shift); +} + +void +sp_spray_switch_mode_temporarily (SPSprayContext *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->getInt("/tools/spray/mode", 0); + SP_EVENT_CONTEXT(tc)->desktop->setToolboxSelectOneValue ("spray_tool_mode", mode); + // button has changed prefs, restore + prefs->setInt("/tools/spray/mode", now_mode); + // changing prefs changed tc->mode, restore back :) + tc->mode = mode; + sp_spray_update_cursor (tc, with_shift); +} + +gint +sp_spray_context_root_handler(SPEventContext *event_context, + GdkEvent *event) +{ + SPSprayContext *tc = SP_SPRAY_CONTEXT(event_context); + SPDesktop *desktop = event_context->desktop; + + gint ret = FALSE; + + switch (event->type) { + case GDK_ENTER_NOTIFY: + sp_canvas_item_show(tc->dilate_area); + break; + case GDK_LEAVE_NOTIFY: + sp_canvas_item_hide(tc->dilate_area); + break; + case GDK_BUTTON_PRESS: + if (event->button.button == 1 && !event_context->space_panning) { + + if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false) { + return TRUE; + } + + Geom::Point const motion_w(event->button.x, + event->button.y); + Geom::Point const motion_dt(desktop->w2d(motion_w)); + tc->last_push = desktop->dt2doc(motion_dt); + + sp_spray_extinput(tc, event); + + sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3); + tc->is_drawing = true; + tc->is_dilating = true; + tc->has_dilated = false; + + + + if(tc->is_dilating && event->button.button == 1 && !event_context->space_panning) + + sp_spray_dilate (tc, motion_w, desktop->dt2doc(motion_dt), Geom::Point(0,0), MOD__SHIFT); + + + + tc->has_dilated=true; + + ret = TRUE; + } + break; + case GDK_MOTION_NOTIFY: + { + Geom::Point const motion_w(event->motion.x, + event->motion.y); + Geom::Point motion_dt(desktop->w2d(motion_w)); + Geom::Point motion_doc(desktop->dt2doc(motion_dt)); + sp_spray_extinput(tc, event); + + // draw the dilating cursor + double radius = get_dilate_radius(tc); + Geom::Matrix const sm (Geom::Scale(radius/(1-tc->ratio), radius/(1+tc->ratio)) ); + sp_canvas_item_affine_absolute(tc->dilate_area, (sm*Geom::Rotate(tc->tilt))*Geom::Translate(desktop->w2d(motion_w))); + sp_canvas_item_show(tc->dilate_area); + + guint num = 0; + if (!desktop->selection->isEmpty()) { + num = g_slist_length((GSList *) desktop->selection->itemList()); + } + if (num == 0) { + tc->_message_context->flash(Inkscape::ERROR_MESSAGE, _("Nothing selected! Select objects to spray.")); + } + + // dilating: + if (tc->is_drawing && ( event->motion.state & GDK_BUTTON1_MASK )) { + sp_spray_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 + gobble_motion_events(GDK_BUTTON1_MASK); + return TRUE; + } + + } + break; +/*Spray with the scroll*/ + case GDK_SCROLL: + { + if (event->scroll.state & GDK_BUTTON1_MASK) + { + double temp ; + temp=tc->population; + tc->population=1.0; + desktop->setToolboxAdjustmentValue ("population", tc->population * 100); + Geom::Point const scroll_w(event->button.x,event->button.y); + Geom::Point const scroll_dt = desktop->point();; + Geom::Point motion_doc(desktop->dt2doc(scroll_dt)); + switch (event->scroll.direction) + { + case GDK_SCROLL_UP: + { + if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false) + { + return TRUE; + } + tc->last_push = desktop->dt2doc(scroll_dt); + sp_spray_extinput(tc, event); + sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3); + tc->is_drawing = true; + tc->is_dilating = true; + tc->has_dilated = false; + if(tc->is_dilating && !event_context->space_panning) + + sp_spray_dilate (tc, scroll_w, desktop->dt2doc(scroll_dt), Geom::Point(0,0),false); + + + + tc->has_dilated=true; + tc->population=temp; + + desktop->setToolboxAdjustmentValue ("population", tc->population * 100); + + ret = TRUE; + } + break; + case GDK_SCROLL_DOWN: + { + if (Inkscape::have_viable_layer(desktop, tc->_message_context) == false) + { + return TRUE; + } + tc->last_push = desktop->dt2doc(scroll_dt); + sp_spray_extinput(tc, event); + sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3); + tc->is_drawing = true; + tc->is_dilating = true; + tc->has_dilated = false; + if(tc->is_dilating && !event_context->space_panning) + sp_spray_dilate (tc, scroll_w, desktop->dt2doc(scroll_dt), Geom::Point(0,0), false); + + tc->has_dilated=true; + + ret = TRUE; + + + } + break; +case GDK_SCROLL_RIGHT: + {} break; +case GDK_SCROLL_LEFT: + {} break; + } + } + + + break; + + } + case GDK_BUTTON_RELEASE: + { + 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; + + if (tc->is_dilating && event->button.button == 1 && !event_context->space_panning) { + if (!tc->has_dilated) { + // if we did not rub, do a light tap + tc->pressure = 0.03; + sp_spray_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 SPRAY_MODE_COPY: + sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_SPRAY, _("Spray with copies")); + break; + case SPRAY_MODE_CLONE: + sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_SPRAY, _("Spray with clones")); + break; + case SPRAY_MODE_SINGLE_PATH: + sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(tc)->desktop), + SP_VERB_CONTEXT_SPRAY, _("Spray in single path")); + break; + } + } + break; + } + + case GDK_KEY_PRESS: + switch (get_group0_keyval (&event->key)) { +case GDK_j: if (MOD__SHIFT_ONLY) { + sp_spray_switch_mode(tc, SPRAY_MODE_COPY, MOD__SHIFT); + ret = TRUE; + } +case GDK_J: if (MOD__SHIFT_ONLY) { + sp_spray_switch_mode(tc, SPRAY_MODE_COPY, MOD__SHIFT); + ret = TRUE; + } + +break; + case GDK_m: + case GDK_M: + case GDK_0: + + break; + case GDK_i: + case GDK_I: + case GDK_k: if (MOD__SHIFT_ONLY) { + sp_spray_switch_mode(tc, SPRAY_MODE_SINGLE_PATH, MOD__SHIFT); + ret = TRUE; + } + case GDK_K:if (MOD__SHIFT_ONLY) { + sp_spray_switch_mode(tc, SPRAY_MODE_SINGLE_PATH, MOD__SHIFT); + ret = TRUE; + } +break; + + case GDK_l: if (MOD__SHIFT_ONLY) { + sp_spray_switch_mode(tc, SPRAY_MODE_CLONE, MOD__SHIFT); + ret = TRUE; + } + + case GDK_L: + if (MOD__SHIFT_ONLY) { + sp_spray_switch_mode(tc, SPRAY_MODE_CLONE, MOD__SHIFT); + ret = TRUE; + } + break; + case GDK_Up: + case GDK_KP_Up: + if (!MOD__CTRL_ONLY) { + tc->scale += 0.05; + + //desktop->setToolboxAdjustmentValue ("spray-force", tc->force * 100); + ret = TRUE; + } + break; + case GDK_Down: + case GDK_KP_Down: + if (!MOD__CTRL_ONLY) { + + tc->scale -= 0.05; + if (tc->scale < 0.0) + tc->scale = 0.0; + //desktop->setToolboxAdjustmentValue ("spray-force", tc->force * 100); + + ret = TRUE; + + } + break; + case GDK_Right: + case GDK_KP_Right: + if (!MOD__CTRL_ONLY) { + tc->width += 0.01; + if (tc->width > 1.0) + tc->width = 1.0; + desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100); // the same spinbutton is for alt+x + sp_spray_update_area(tc); + ret = TRUE; + } + break; + case GDK_Left: + case GDK_KP_Left: + if (!MOD__CTRL_ONLY) { + tc->width -= 0.01; + if (tc->width < 0.01) + tc->width = 0.01; + desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100); + sp_spray_update_area(tc); + ret = TRUE; + } + break; + case GDK_Home: + case GDK_KP_Home: + tc->width = 0.01; + desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100); + sp_spray_update_area(tc); + ret = TRUE; + break; + case GDK_End: + case GDK_KP_End: + tc->width = 1.0; + desktop->setToolboxAdjustmentValue ("altx-spray", tc->width * 100); + sp_spray_update_area(tc); + ret = TRUE; + break; + case GDK_x: + case GDK_X: + if (MOD__ALT_ONLY) { + desktop->setToolboxFocusTo ("altx-spray"); + ret = TRUE; + } + break; + + case GDK_Shift_L: + case GDK_Shift_R: + sp_spray_update_cursor(tc, true); + break; +/*Set the scale to 1*/ + case GDK_Control_L: + tc->scale=1; + default: + break; + } + break; + + 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_spray_update_cursor(tc, false); + break; + case GDK_Control_L: + case GDK_Control_R: + sp_spray_switch_mode (tc, prefs->getInt("/tools/spray/mode"), MOD__SHIFT); + tc->_message_context->clear(); + break; + default: + sp_spray_switch_mode (tc, prefs->getInt("/tools/spray/mode"), MOD__SHIFT); + break; + } + } + + default: + break; + } + + if (!ret) { + if (((SPEventContextClass *) parent_class)->root_handler) { + ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event); + } + } + + return ret; +} + +/* + 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:encoding=utf-8:textwidth=99 : + diff --git a/src/spray-context.h b/src/spray-context.h new file mode 100644 index 000000000..f8822ce39 --- /dev/null +++ b/src/spray-context.h @@ -0,0 +1,125 @@ +#ifndef __SP_SPRAY_CONTEXT_H__ +#define __SP_SPRAY_CONTEXT_H__ + +/* + * Spray Tool + * + * Authors: + * Pierre-Antoine MARC + * Pierre CACLIN + * Aurel-Aimé MARMION + * Julien LERAY + * Benoît LAVORATA + * Vincent MONTAGNE + * Pierre BARBRY-BLOT + * + * Copyright (C) 2009 authors + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "event-context.h" +#include +#include +//#include "ui/widget/spray-option.h" +#include "ui/dialog/dialog.h" + +#define SP_TYPE_SPRAY_CONTEXT (sp_spray_context_get_type()) +#define SP_SPRAY_CONTEXT(o) (GTK_CHECK_CAST((o), SP_TYPE_SPRAY_CONTEXT, SPSprayContext)) +#define SP_SPRAY_CONTEXT_CLASS(k) (GTK_CHECK_CLASS_CAST((k), SP_TYPE_SPRAY_CONTEXT, SPSprayContextClass)) +#define SP_IS_SPRAY_CONTEXT(o) (GTK_CHECK_TYPE((o), SP_TYPE_SPRAY_CONTEXT)) +#define SP_IS_SPRAY_CONTEXT_CLASS(k) (GTK_CHECK_CLASS_TYPE((k), SP_TYPE_SPRAY_CONTEXT)) + +class SPSprayContext; +class SPSprayContextClass; + +namespace Inkscape { + namespace UI { + namespace Dialog { + class Dialog; + } + } +} + + +#define SAMPLING_SIZE 8 /* fixme: ?? */ + +#define TC_MIN_PRESSURE 0.0 +#define TC_MAX_PRESSURE 1.0 +#define TC_DEFAULT_PRESSURE 0.35 + +enum { + SPRAY_MODE_COPY, + SPRAY_MODE_CLONE, + SPRAY_MODE_SINGLE_PATH, + SPRAY_OPTION, +}; + +struct SPSprayContext +{ + SPEventContext event_context; + //Inkscape::UI::Dialog::Dialog *dialog_option;//Attribut de type SprayOptionClass, localisé dans scr/ui/dialog + /* extended input data */ + gdouble pressure; + + /* attributes */ + guint dragging : 1; /* mouse state: mouse is dragging */ + guint usepressure : 1; + guint usetilt : 1; + bool usetext ; + + double width; + double ratio; + double tilt; + double rot_min; + double rot_max; + double force; + double population; + double scale_min; + double scale_max; + double scale; + double mean; + double standard_deviation; + + gint distrib; + + gint mode; + + Inkscape::MessageContext *_message_context; + + bool is_drawing; + + bool is_dilating; + bool has_dilated; + Geom::Point last_push; + SPCanvasItem *dilate_area; + + bool do_h; + bool do_s; + bool do_l; + bool do_o; + + sigc::connection style_set_connection; +}; + +struct SPSprayContextClass +{ + SPEventContextClass parent_class; +}; + +GtkType sp_spray_context_get_type(void); + + +#endif + +/* + 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:encoding=utf-8:textwidth=99 : + diff --git a/src/tools-switch.cpp b/src/tools-switch.cpp index 7902a7988..6c53ce61c 100644 --- a/src/tools-switch.cpp +++ b/src/tools-switch.cpp @@ -28,6 +28,7 @@ #include "select-context.h" #include "node-context.h" #include "tweak-context.h" +#include "spray-context.h" #include "sp-path.h" #include "rect-context.h" #include "sp-rect.h" @@ -62,6 +63,7 @@ static char const *const tool_names[] = { "/tools/select", "/tools/nodes", "/tools/tweak", + "/tools/spray", "/tools/shapes/rect", "/tools/shapes/3dbox", "/tools/shapes/arc", @@ -135,6 +137,12 @@ tools_switch(SPDesktop *dt, int num) inkscape_eventcontext_set(sp_desktop_event_context(dt)); dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("To tweak a path by pushing, select it and drag over it.")); break; + case TOOLS_SPRAY: + dt->set_event_context(SP_TYPE_SPRAY_CONTEXT, tool_names[num]); + dt->activate_guides(true); + inkscape_eventcontext_set(sp_desktop_event_context(dt)); + dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("To spray a path by pushing, select it and drag over it.")); + break; case TOOLS_SHAPES_RECT: dt->set_event_context(SP_TYPE_RECT_CONTEXT, tool_names[num]); dt->activate_guides(false); diff --git a/src/tools-switch.h b/src/tools-switch.h index 36dd8f80b..4cc9aa93d 100644 --- a/src/tools-switch.h +++ b/src/tools-switch.h @@ -19,6 +19,7 @@ enum { TOOLS_SELECT, TOOLS_NODES, TOOLS_TWEAK, + TOOLS_SPRAY, TOOLS_SHAPES_RECT, TOOLS_SHAPES_3DBOX, TOOLS_SHAPES_ARC, diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert index 565a24ecc..fd1b07394 100644 --- a/src/ui/dialog/Makefile_insert +++ b/src/ui/dialog/Makefile_insert @@ -73,6 +73,8 @@ ink_common_sources += \ ui/dialog/print.h \ ui/dialog/scriptdialog.cpp \ ui/dialog/scriptdialog.h \ + ui/dialog/spray-option.cpp \ + ui/dialog/spray-option.h \ ui/dialog/svg-fonts-dialog.cpp \ ui/dialog/svg-fonts-dialog.h \ ui/dialog/swatches.cpp \ diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp index d1b818d23..7f853bedc 100644 --- a/src/ui/dialog/dialog-manager.cpp +++ b/src/ui/dialog/dialog-manager.cpp @@ -40,6 +40,7 @@ #include "ui/dialog/icon-preview.h" #include "ui/dialog/floating-behavior.h" #include "ui/dialog/dock-behavior.h" +#include "ui/dialog/spray-option.h" #include "preferences.h" #ifdef ENABLE_SVG_FONTS @@ -88,7 +89,6 @@ DialogManager::DialogManager() { int dialogs_type = prefs->getIntLimited("/options/dialogtype/value", DOCK, 0, 1); if (dialogs_type == FLOATING) { - registerFactory("AlignAndDistribute", &create); registerFactory("DocumentMetadata", &create); registerFactory("DocumentProperties", &create); @@ -111,7 +111,8 @@ DialogManager::DialogManager() { registerFactory("Trace", &create); registerFactory("Transformation", &create); registerFactory("UndoHistory", &create); - registerFactory("InputDevices", &create); + registerFactory("InputDevices", &create); + registerFactory("SprayOptionClass", &create); } else { @@ -138,6 +139,7 @@ DialogManager::DialogManager() { registerFactory("Transformation", &create); registerFactory("UndoHistory", &create); registerFactory("InputDevices", &create); + registerFactory("SprayOptionClass", &create); } } diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index c7dc789ca..6e30ef61a 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -449,6 +449,12 @@ void InkscapePreferences::initPageTools() AddSelcueCheckbox(_page_tweak, "/tools/tweak", true); AddGradientCheckbox(_page_tweak, "/tools/tweak", false); + //Spray + this->AddPage(_page_spray, _("Spray"), iter_tools, PREFS_PAGE_TOOLS_SPRAY); + this->AddNewObjectsStyle(_page_spray, "/tools/spray", _("Paint objects with:")); + AddSelcueCheckbox(_page_spray, "/tools/spray", true); + AddGradientCheckbox(_page_spray, "/tools/spray", false); + //Zoom this->AddPage(_page_zoom, _("Zoom"), iter_tools, PREFS_PAGE_TOOLS_ZOOM); AddSelcueCheckbox(_page_zoom, "/tools/zoom", true); diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index 364b0eb1d..705e7a352 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -43,6 +43,7 @@ enum { PREFS_PAGE_TOOLS_SELECTOR, PREFS_PAGE_TOOLS_NODE, PREFS_PAGE_TOOLS_TWEAK, + PREFS_PAGE_TOOLS_SPRAY, PREFS_PAGE_TOOLS_ZOOM, PREFS_PAGE_TOOLS_SHAPES, PREFS_PAGE_TOOLS_SHAPES_RECT, @@ -118,7 +119,7 @@ protected: _page_clones, _page_mask, _page_transforms, _page_filters, _page_select, _page_importexport, _page_cms, _page_grids, _page_svgoutput, _page_misc, _page_ui, _page_save, _page_bitmaps, _page_spellcheck; - DialogPage _page_selector, _page_node, _page_tweak, _page_zoom, _page_shapes, _page_pencil, _page_pen, + DialogPage _page_selector, _page_node, _page_tweak, _page_spray, _page_zoom, _page_shapes, _page_pencil, _page_pen, _page_calligraphy, _page_text, _page_gradient, _page_connector, _page_dropper, _page_lpetool; DialogPage _page_rectangle, _page_3dbox, _page_ellipse, _page_star, _page_spiral, _page_paintbucket, _page_eraser; diff --git a/src/ui/dialog/spray-option.cpp b/src/ui/dialog/spray-option.cpp new file mode 100644 index 000000000..8bfe455fa --- /dev/null +++ b/src/ui/dialog/spray-option.cpp @@ -0,0 +1,381 @@ +/*Julien LERAY (julien.leray@ecl2010.ec-lyon.fr), interface for the spray tool*/ + + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include + +#include "desktop-handles.h" +#include "unclump.h" +#include "document.h" +#include "enums.h" +#include "graphlayout/graphlayout.h" +#include "inkscape.h" +#include "macros.h" +#include "node-context.h" +#include "preferences.h" +#include "removeoverlap/removeoverlap.h" +#include "selection.h" +#include "shape-editor.h" +#include "sp-flowtext.h" +#include "sp-item-transform.h" +#include "sp-text.h" +#include "text-editing.h" +#include "tools-switch.h" +#include "ui/icon-names.h" +#include "util/glib-list-iterators.h" +#include "verbs.h" +#include "widgets/icon.h" + +#include "spray-option.h" + +namespace Inkscape { +namespace UI { +namespace Dialog { + + +//Classes qui permettent de créer les environnements Gaussienne, Witdh... + + + +class Action { +public: + Action(const Glib::ustring &id, + const Glib::ustring &tiptext, + guint row, guint column, + Gtk::Table &parent, + Gtk::Tooltips &tooltips, + SprayOptionClass &dialog): + _dialog(dialog), + _id(id), + _parent(parent) {} + + virtual ~Action(){} + virtual void on_button_click(){} + SprayOptionClass &_dialog; + +private : + + Glib::ustring _id; + Gtk::Table &_parent; +}; + +class ActionE : public Action { +private: + Gtk::Label _Label; + Gtk::SpinButton _Gap; + guint _min, _max; + Glib::ustring _pref_path; + +public: + ActionE(const Glib::ustring &id, + const Glib::ustring &tiptext, + guint row, guint column, + SprayOptionClass &dialog, + guint min, guint max, + Glib::ustring const &pref_path ): + Action(id, tiptext, row, column, + dialog._Table(), dialog.tooltips(), dialog), + _min(min), + _max(max), + _pref_path(pref_path) + { + dialog._Table().set_col_spacings(3); + + double increm = ((double)_max - (double)_min)/10; + double val_ini = ((double)_max + (double)_min)/2; + _Gap.set_digits(1); + _Gap.set_size_request(60, -1); + _Gap.set_increments(increm , 0); + _Gap.set_range(_min, _max); + _Gap.set_value(val_ini); + dialog.tooltips().set_tip(_Gap, + tiptext); + _Gap.signal_changed().connect(sigc::mem_fun(*this, &ActionE::on_button_click)); //rajout douteux + _Label.set_label(id); + + dialog._Table().attach(_Label, column, column+1, row, row+1, Gtk::FILL, Gtk::FILL); + dialog._Table().attach(_Gap, column+1, column+2, row, row+1, Gtk::EXPAND, Gtk::EXPAND); + } + + virtual void on_button_click(){ + if (!_dialog.getDesktop()) return; + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + prefs->setDouble(_pref_path, SP_VERB_CONTEXT_SPRAY); + + double const Gap = _Gap.get_value(); + + + prefs->setDouble(_pref_path, Gap); + + sp_document_done(sp_desktop_document(_dialog.getDesktop()), SP_VERB_CONTEXT_SPRAY, + _("Remove overlaps")); + } + + +}; + +class ActionF : public Action { +private: + Gtk::Label _Label; + Gtk::Label _Label1; + Gtk::Label _Label2; + Gtk::SpinButton _Gap1; + Gtk::SpinButton _Gap2; + Glib::ustring _pref1_path; + Glib::ustring _pref2_path; + +public: + ActionF(const Glib::ustring &id, + const Glib::ustring &tiptext, + guint row, guint column, + SprayOptionClass &dialog, + Glib::ustring const &pref1_path, + Glib::ustring const &pref2_path ): + Action(id, tiptext, row, column, + dialog._Table(), dialog.tooltips(), dialog), + _pref1_path(pref1_path), + _pref2_path(pref2_path) + { + dialog.F_Table().set_col_spacings(3); + + _Label.set_label(id); + + _Gap1.set_digits(1); + _Gap1.set_size_request(60, -1); + _Gap1.set_increments(0.1, 0); + _Gap1.set_range(0, 10); + _Gap1.set_value(1); + dialog.tooltips().set_tip(_Gap1, + _("Minimum")); + + _Label1.set_label(Q_("Min")); + + _Gap2.set_digits(1); + _Gap2.set_size_request(60, -1); + _Gap2.set_increments(0.1, 0); + _Gap2.set_range(0, 10); + _Gap2.set_value(1); + dialog.tooltips().set_tip(_Gap2, + _("Maximum")); + + _Label2.set_label(_("Max:")); + + _Gap1.signal_changed().connect(sigc::mem_fun(*this, &ActionF::on_button_click)); + _Gap2.signal_changed().connect(sigc::mem_fun(*this, &ActionF::on_button_click)); + + dialog.F_Table().attach(_Label, column, column+1, row, row+1, Gtk::FILL, Gtk::FILL); + dialog.F_Table().attach(_Label1, column+1, column+2, row, row+1, Gtk::FILL, Gtk::FILL); + dialog.F_Table().attach(_Gap1, column+2, column+3, row, row+1, Gtk::EXPAND, Gtk::EXPAND); + dialog.F_Table().attach(_Label2, column+3, column+4, row, row+1, Gtk::FILL, Gtk::FILL); + dialog.F_Table().attach(_Gap2, column+4, column+5, row, row+1, Gtk::EXPAND, Gtk::EXPAND); + + } + + virtual void on_button_click(){ + if (!_dialog.getDesktop()) return; + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + prefs->setDouble(_pref1_path, SP_VERB_CONTEXT_SPRAY); + prefs->setDouble(_pref2_path, SP_VERB_CONTEXT_SPRAY); + + double const Gap1 = _Gap1.get_value(); + double const Gap2 = _Gap2.get_value(); + + prefs->setDouble(_pref1_path, Gap1); + prefs->setDouble(_pref2_path, Gap2); + + sp_document_done(sp_desktop_document(_dialog.getDesktop()), SP_VERB_CONTEXT_SPRAY, + _("Remove overlaps")); + } + + +}; + + + +void SprayOptionClass::combo_action() { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + cout<<"combo.get_active_row_number = "<<_combo.get_active_row_number()<setInt("/tools/spray/distribution", distrib); + + + sp_document_done(sp_desktop_document(this->getDesktop()), SP_VERB_CONTEXT_SPRAY, + _("Remove overlaps")); + +} + + + + +void SprayOptionClass::action() { + int r=1; + for (list::iterator it = _actionList.begin(); + it != _actionList.end(); + it ++) + (*it)->on_button_click(); + combo_action(); +} + + + + + + +void on_selection_changed(Inkscape::Application */*inkscape*/, Inkscape::Selection */*selection*/, SprayOptionClass *daad) +{ + daad->randomize_bbox = Geom::OptRect(); +} + +///////////////////////////////////////////////////////// +//Construction de l'interface +///////////////////////////////////////////////////////// + + +SprayOptionClass::SprayOptionClass() + : UI::Widget::Panel ("", "/dialogs/spray", SP_VERB_DIALOG_SPRAY_OPTION), + _distributionFrame(_("Distribution")), + _Frame(_("Cursor Options")), + _FFrame(_("Random Options")), + _gaussianTable(1, 5, false), + _ETable(3,2,false), + _FTable(2,5,false), + _unifLabel(_("Uniform")), + _gaussLabel(_("Gaussian ")), + _anchorLabel(_("Distribution : ")) + +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + //ComboBoxText + + _combo.append_text(_("Uniforme")); + _combo.append_text(_("Gaussienne")); + + _combo.set_active(prefs->getInt("/tools/spray/distribution", 1)); + _combo.signal_changed().connect(sigc::mem_fun(*this, &SprayOptionClass::combo_action)); + + _anchorBox.pack_start(_anchorLabel); + _anchorBox.pack_start(_combo); + + _gaussianBox.pack_start(_anchorBox); + + + _distributionBox.pack_start(_gaussianBox); + _distributionFrame.add(_distributionBox); + + + //Hbox Random + addFButton(_("Scale : ") ,_("Applique un facteur d'échelle"), 0, 0, "/tools/spray/scale_min","/tools/spray/scale_max"); + addFButton(_("Rotation : ") ,_("Fait tourner"), 1, 0, "/tools/spray/rot_min","/tools/spray/rot_max"); + _FHBox.pack_start(_FLabel); + _FHBox.pack_start(_FTable); + + //Implementation dans la Vbox Cursor + _FVBox.pack_start(_FHBox); + _FFrame.add(_FVBox); + + //Hbox Cursor + addEButton(_("Ratio : ") ,_("Excentricité de l'ellipse"), 0, 0, 0, 1,"/tools/spray/ratio"); + addEButton(_("Angle : ") ,_("Angle de l'ellipse"), 1, 0, 0, 5,"/tools/spray/tilt"); + addEButton(_("Width : ") ,_("Taille de l'ellipse"), 2, 0, 0, 1,"/tools/spray/width"); + _HBox.pack_start(_Label); + _HBox.pack_start(_ETable); + + //Implementation dans la Vbox Cursor + _VBox.pack_start(_HBox); + _Frame.add(_VBox); + + Gtk::Box *contents = _getContents(); + contents->set_spacing(4); + + + + + + + // Crée dans l'ordre suivant les différentes Frames (cadres de réglages) + + contents->pack_start(_distributionFrame, true, true); + contents->pack_start(_FFrame, true, true); + contents->pack_start(_Frame, true, true); + + + + // Connect to the global selection change, to invalidate cached randomize_bbox + g_signal_connect (G_OBJECT (INKSCAPE), "change_selection", G_CALLBACK (on_selection_changed), this); + randomize_bbox = Geom::OptRect(); + + show_all_children(); + + + +} + +SprayOptionClass::~SprayOptionClass() +{ + sp_signal_disconnect_by_data (G_OBJECT (INKSCAPE), this); + + for (std::list::iterator it = _actionList.begin(); + it != _actionList.end(); + it ++) + delete *it; +} + + + + + + + +//Fonctions qui lient la demande d'ajout d'une interface graphique à l'action correspondante + +void SprayOptionClass::addEButton(const Glib::ustring &id, + const Glib::ustring &tiptext, + guint row, guint column, + guint min, guint max, + Glib::ustring const &pref_path) +{ + _actionList.push_back( new ActionE(id, tiptext,row, column,*this,min ,max, pref_path )); +} + +void SprayOptionClass::addFButton(const Glib::ustring &id, + const Glib::ustring &tiptext, + guint row, guint column, + Glib::ustring const &pref1_path, + Glib::ustring const &pref2_path) +{ + _actionList.push_back( new ActionF(id, tiptext,row, column,*this,pref1_path, pref2_path )); +} + + + + + +SprayOptionClass &SprayOptionClass::get_SprayOptionClass() +{ + return *this; +} + +} // namespace Dialog +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/dialog/spray-option.h b/src/ui/dialog/spray-option.h new file mode 100644 index 000000000..75dfe1e35 --- /dev/null +++ b/src/ui/dialog/spray-option.h @@ -0,0 +1,130 @@ + +/*Julien LERAY (julien.leray@ecl2010.ec-lyon.fr), interface for the spray tool*/ + +#ifndef INKSCAPE_UI_DIALOG_SPRAY_OPTION_H +#define INKSCAPE_UI_DIALOG_SPRAY_OPTION_H + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "libnr/nr-dim2.h" +#include "libnr/nr-rect.h" + + +#include "ui/widget/panel.h" +#include "ui/widget/notebook-page.h" + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "desktop-handles.h" +#include "unclump.h" +#include "document.h" +#include "enums.h" +#include "graphlayout/graphlayout.h" +#include "inkscape.h" +#include "macros.h" +#include "node-context.h" +#include "preferences.h" +#include "removeoverlap/removeoverlap.h" +#include "selection.h" +#include "shape-editor.h" +#include "sp-flowtext.h" +#include "sp-item-transform.h" +#include "sp-text.h" +#include "text-editing.h" +#include "tools-switch.h" +#include "ui/icon-names.h" +#include "util/glib-list-iterators.h" +#include "verbs.h" +#include "widgets/icon.h" + +#include "spray-context.h" +#include "verbs.h" + +#include +using namespace std; + +using namespace Inkscape::UI::Widget; + +class SPItem; + + +namespace Inkscape { +namespace UI { +namespace Dialog { + +class Action; + +class SprayOptionClass : public Widget::Panel { + +private: + + SprayOptionClass(SprayOptionClass const &d); + SprayOptionClass& operator=(SprayOptionClass const &d); + +public: + SprayOptionClass(); + virtual ~SprayOptionClass(); + void test() { cout<<"appel de test !!"< _actionList; + Gtk::Frame _distributionFrame, _Frame, _FFrame ; + Gtk::Table _distributionTable, _gaussianTable, _ETable, _FTable; + Gtk::HBox _anchorBox; + Gtk::HBox _unifBox, _gaussianBox, _HBox, _FHBox, _BoutonBox; + Gtk::VBox _distributionBox, _VBox, _FVBox, _ActionBox; + Gtk::Label _anchorLabel; + Gtk::Label _unifLabel, _gaussLabel, _Label, _FLabel; + Gtk::CheckButton _unif, _gauss; + Gtk::ComboBoxText _combo; + Gtk::Tooltips _tooltips; + +}; + + +} // namespace Dialog +} // namespace UI +} // namespace Inkscape + +#endif // INKSCAPE_UI_DIALOG_ALIGN_AND_DISTRIBUTE_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:encoding=utf-8:textwidth=99 : + diff --git a/src/ui/icon-names.h b/src/ui/icon-names.h index f9a6f2a7d..0388b200f 100644 --- a/src/ui/icon-names.h +++ b/src/ui/icon-names.h @@ -456,6 +456,14 @@ "snap-nodes-smooth" #define INKSCAPE_ICON_SNAP_PAGE \ "snap-page" +#define INKSCAPE_ICON_SPRAY_COPY_MODE \ + "spray-copy-mode" +#define INKSCAPE_ICON_SPRAY_CLONE_MODE \ + "spray-clone-mode" +#define INKSCAPE_ICON_SPRAY_UNION_MODE \ + "spray-union-mode" +#define INKSCAPE_ICON_DIALOG_SPRAY_OPTIONS \ + "dialog-spray-options" #define INKSCAPE_ICON_STROKE_CAP_BUTT \ "stroke-cap-butt" #define INKSCAPE_ICON_STROKE_CAP_ROUND \ @@ -488,6 +496,8 @@ "tool-pointer" #define INKSCAPE_ICON_TOOL_TWEAK \ "tool-tweak" +#define INKSCAPE_ICON_TOOL_SPRAY \ + "tool-spray" #define INKSCAPE_ICON_TRANSFORM_AFFECT_GRADIENT \ "transform-affect-gradient" #define INKSCAPE_ICON_TRANSFORM_AFFECT_PATTERN \ diff --git a/src/ui/view/edit-widget.cpp b/src/ui/view/edit-widget.cpp index 770a9bf87..d34b18771 100644 --- a/src/ui/view/edit-widget.cpp +++ b/src/ui/view/edit-widget.cpp @@ -227,6 +227,12 @@ EditWidget::onDialogAlignAndDistribute() _dlg_mgr.showDialog("AlignAndDistribute"); } +void +EditWidget::onDialogSprayOptionClass() +{ + _dlg_mgr.showDialog("SprayOptionClass"); +} + void EditWidget::onDialogDocumentProperties() { diff --git a/src/ui/view/edit-widget.h b/src/ui/view/edit-widget.h index 2bb708305..452641e80 100644 --- a/src/ui/view/edit-widget.h +++ b/src/ui/view/edit-widget.h @@ -70,6 +70,7 @@ public: void onDialogAbout(); void onDialogAlignAndDistribute(); + void onDialogSprayOptionClass(); void onDialogInkscapePreferences(); void onDialogDialog(); void onDialogDocumentProperties(); diff --git a/src/verbs.cpp b/src/verbs.cpp index 29d24c101..56b63e95e 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -1464,6 +1464,9 @@ ContextVerb::perform(SPAction *action, void *data, void */*pdata*/) case SP_VERB_CONTEXT_TWEAK: tools_switch(dt, TOOLS_TWEAK); break; + case SP_VERB_CONTEXT_SPRAY: + tools_switch(dt, TOOLS_SPRAY); + break; case SP_VERB_CONTEXT_RECT: tools_switch(dt, TOOLS_SHAPES_RECT); break; @@ -1525,6 +1528,10 @@ ContextVerb::perform(SPAction *action, void *data, void */*pdata*/) prefs->setInt("/dialogs/preferences/page", PREFS_PAGE_TOOLS_TWEAK); dt->_dlg_mgr->showDialog("InkscapePreferences"); break; + case SP_VERB_CONTEXT_SPRAY_PREFS: + prefs->setInt("/dialogs/preferences/page", PREFS_PAGE_TOOLS_SPRAY); + dt->_dlg_mgr->showDialog("InkscapePreferences"); + break; case SP_VERB_CONTEXT_RECT_PREFS: prefs->setInt("/dialogs/preferences/page", PREFS_PAGE_TOOLS_SHAPES_RECT); dt->_dlg_mgr->showDialog("InkscapePreferences"); @@ -1797,6 +1804,9 @@ DialogVerb::perform(SPAction *action, void *data, void */*pdata*/) case SP_VERB_DIALOG_ALIGN_DISTRIBUTE: dt->_dlg_mgr->showDialog("AlignAndDistribute"); break; + case SP_VERB_DIALOG_SPRAY_OPTION: + dt->_dlg_mgr->showDialog("SprayOptionClass"); + break; case SP_VERB_DIALOG_TEXT: sp_text_edit_dialog(); break; @@ -2503,6 +2513,8 @@ Verb *Verb::_base_verbs[] = { N_("Edit paths by nodes"), INKSCAPE_ICON_TOOL_NODE_EDITOR), new ContextVerb(SP_VERB_CONTEXT_TWEAK, "ToolTweak", N_("Tweak"), N_("Tweak objects by sculpting or painting"), INKSCAPE_ICON_TOOL_TWEAK), + new ContextVerb(SP_VERB_CONTEXT_SPRAY, "ToolSpray", N_("Spray"), + N_("Spray objects by sculpting or painting"), INKSCAPE_ICON_TOOL_SPRAY), new ContextVerb(SP_VERB_CONTEXT_RECT, "ToolRect", N_("Rectangle"), N_("Create rectangles and squares"), INKSCAPE_ICON_DRAW_RECTANGLE), new ContextVerb(SP_VERB_CONTEXT_3DBOX, "Tool3DBox", N_("3D Box"), @@ -2544,6 +2556,8 @@ Verb *Verb::_base_verbs[] = { N_("Open Preferences for the Node tool"), NULL), new ContextVerb(SP_VERB_CONTEXT_TWEAK_PREFS, "TweakPrefs", N_("Tweak Tool Preferences"), N_("Open Preferences for the Tweak tool"), NULL), + new ContextVerb(SP_VERB_CONTEXT_SPRAY_PREFS, "SprayPrefs", N_("Spray Tool Preferences"), + N_("Open Preferences for the Spray tool"), NULL), new ContextVerb(SP_VERB_CONTEXT_RECT_PREFS, "RectPrefs", N_("Rectangle Preferences"), N_("Open Preferences for the Rectangle tool"), NULL), new ContextVerb(SP_VERB_CONTEXT_3DBOX_PREFS, "3DBoxPrefs", N_("3D Box Preferences"), @@ -2645,6 +2659,8 @@ Verb *Verb::_base_verbs[] = { N_("Precisely control objects' transformations"), INKSCAPE_ICON_DIALOG_TRANSFORM), new DialogVerb(SP_VERB_DIALOG_ALIGN_DISTRIBUTE, "DialogAlignDistribute", N_("_Align and Distribute..."), N_("Align and distribute objects"), INKSCAPE_ICON_DIALOG_ALIGN_AND_DISTRIBUTE), + new DialogVerb(SP_VERB_DIALOG_SPRAY_OPTION, "DialogSprayOption", N_("_Spray options..."), + N_("Some options for the spray"), INKSCAPE_ICON_DIALOG_SPRAY_OPTIONS), new DialogVerb(SP_VERB_DIALOG_UNDO_HISTORY, "DialogUndoHistory", N_("Undo _History..."), N_("Undo History"), INKSCAPE_ICON_EDIT_UNDO_HISTORY), new DialogVerb(SP_VERB_DIALOG_TEXT, "DialogText", N_("_Text and Font..."), diff --git a/src/verbs.h b/src/verbs.h index 87fe27075..3ea2fdee8 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -153,6 +153,7 @@ enum { SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_TWEAK, + SP_VERB_CONTEXT_SPRAY, SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_ARC, @@ -174,6 +175,7 @@ enum { SP_VERB_CONTEXT_SELECT_PREFS, SP_VERB_CONTEXT_NODE_PREFS, SP_VERB_CONTEXT_TWEAK_PREFS, + SP_VERB_CONTEXT_SPRAY_PREFS, SP_VERB_CONTEXT_RECT_PREFS, SP_VERB_CONTEXT_3DBOX_PREFS, SP_VERB_CONTEXT_ARC_PREFS, @@ -227,6 +229,7 @@ enum { SP_VERB_DIALOG_SWATCHES, SP_VERB_DIALOG_TRANSFORM, SP_VERB_DIALOG_ALIGN_DISTRIBUTE, + SP_VERB_DIALOG_SPRAY_OPTION, SP_VERB_DIALOG_UNDO_HISTORY, SP_VERB_DIALOG_TEXT, SP_VERB_DIALOG_XML_EDITOR, diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index e0fe9bfd1..41a70f08a 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -86,6 +86,7 @@ #include "../svg/css-ostringstream.h" #include "../tools-switch.h" #include "../tweak-context.h" +#include "../spray-context.h" #include "../ui/dialog/calligraphic-profile-rename.h" #include "../ui/icon-names.h" #include "../ui/widget/style-swatch.h" @@ -107,6 +108,7 @@ typedef void (*UpdateFunction)(SPDesktop *desktop, SPEventContext *eventcontext, static void sp_node_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); +static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); static void sp_zoom_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder); @@ -146,6 +148,7 @@ static struct { { "SPSelectContext", "select_tool", SP_VERB_CONTEXT_SELECT, SP_VERB_CONTEXT_SELECT_PREFS}, { "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS }, { "SPTweakContext", "tweak_tool", SP_VERB_CONTEXT_TWEAK, SP_VERB_CONTEXT_TWEAK_PREFS }, + { "SPSprayContext", "spray_tool", SP_VERB_CONTEXT_SPRAY, SP_VERB_CONTEXT_SPRAY_PREFS }, { "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS }, { "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS }, { "Box3DContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS }, @@ -181,6 +184,8 @@ static struct { SP_VERB_INVALID, 0, 0}, { "SPTweakContext", "tweak_toolbox", 0, sp_tweak_toolbox_prep, "TweakToolbar", SP_VERB_CONTEXT_TWEAK_PREFS, "/tools/tweak", N_("Color/opacity used for color tweaking")}, + { "SPSprayContext", "spray_toolbox", 0, sp_spray_toolbox_prep, "SprayToolbar", + SP_VERB_CONTEXT_SPRAY_PREFS, "/tools/spray", N_("Color/opacity used for color spraying")}, { "SPZoomContext", "zoom_toolbox", 0, sp_zoom_toolbox_prep, "ZoomToolbar", SP_VERB_INVALID, 0, 0}, { "SPStarContext", "star_toolbox", 0, sp_star_toolbox_prep, "StarToolbar", @@ -299,6 +304,21 @@ static gchar const * ui_descr = " " " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " " " " " @@ -718,6 +738,7 @@ Glib::RefPtr create_or_fetch_actions( SPDesktop* desktop ) //SP_VERB_EDIT_TILE, //SP_VERB_EDIT_UNTILE, SP_VERB_DIALOG_ALIGN_DISTRIBUTE, + SP_VERB_DIALOG_SPRAY_OPTION, SP_VERB_DIALOG_DISPLAY, SP_VERB_DIALOG_FILL_STROKE, SP_VERB_DIALOG_NAMEDVIEW, @@ -1627,6 +1648,7 @@ setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop) " " " " " " + " " " " " " " " @@ -4371,6 +4393,198 @@ static void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainAction } +//######################## +//## Spray ## +//######################## + +static void sp_spray_width_value_changed( GtkAdjustment *adj, GObject */*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/spray/width", adj->value ); +} + +static void sp_spray_force_value_changed( GtkAdjustment *adj, GObject */*tbl*/ ) +{ + //Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + //prefs->setDouble( "/tools/spray/force", adj->value * 0.01 ); +} + +static void sp_spray_mean_value_changed( GtkAdjustment *adj, GObject */*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/spray/mean", adj->value ); +} + +static void sp_spray_standard_deviation_value_changed( GtkAdjustment *adj, GObject */*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/spray/standard_deviation", adj->value ); +} + +static void sp_spray_pressure_state_changed( GtkToggleAction *act, gpointer /*data*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/spray/usepressure", gtk_toggle_action_get_active(act)); +} + +static void sp_spray_mode_changed( EgeSelectOneAction *act, GObject *tbl ) +{ + int mode = ege_select_one_action_get_active( act ); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setInt("/tools/spray/mode", mode); +} + +static void sp_spray_population_value_changed( GtkAdjustment *adj, GObject */*tbl*/ ) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setDouble( "/tools/spray/population", adj->value ); +} + +/*static void spray_toggle_doh (GtkToggleAction *act, gpointer ) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/spray/doh", gtk_toggle_action_get_active(act)); +} +static void spray_toggle_dos (GtkToggleAction *act, gpointer ) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/spray/dos", gtk_toggle_action_get_active(act)); +} +static void spray_toggle_dol (GtkToggleAction *act, gpointer ) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/spray/dol", gtk_toggle_action_get_active(act)); +} +static void spray_toggle_doo (GtkToggleAction *act, gpointer ) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setBool("/tools/spray/doo", gtk_toggle_action_get_active(act)); +} +*/ +static void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +{ + Inkscape::IconSize secondarySize = prefToSize("/toolbox/secondary", 1); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + { + /* Width */ + gchar const* labels[] = {_("(pinch spray)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad spray)")}; + gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "SprayWidthAction", + _("Width"), _("Width:"), _("The width of the spray area (relative to the visible canvas area)"), + "/tools/spray/width", 15, + GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "altx-spray", + 1, 100, 1.0, 0.0, + labels, values, G_N_ELEMENTS(labels), + sp_spray_width_value_changed, 0.01, 0, 100 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + { + /* Mean */ + gchar const* labels[] = {_("(minimum mean)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum mean)")}; + gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "SprayMeanAction", + _("Mean"), _("Mean:"), _("The mean of the spray action"), + "/tools/spray/mean", 20, + GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-mean", + 1, 100, 1.0, 0.0, + labels, values, G_N_ELEMENTS(labels), + sp_spray_mean_value_changed, 0.01, 0, 100 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + { + /* Standard_deviation */ + gchar const* labels[] = {_("(minimum standard_deviation)"), 0, 0, _("(default)"), 0, 0, 0, _("(maximum standard_deviation)")}; + gdouble values[] = {1, 5, 10, 20, 30, 50, 70, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "SprayStandard_deviationAction", + _("SD"), _("SD:"), _("The standard deviation of the spray action"), + "/tools/spray/standard_deviation", 20, + GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-standard_deviation", + 1, 100, 1.0, 0.0, + labels, values, G_N_ELEMENTS(labels), + sp_spray_standard_deviation_value_changed, 0.01, 0, 100 ); + ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + } + + /* Mode */ + { + GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING ); + + GtkTreeIter iter; + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Spray with copies"), + 1, _("Spray copies of the initial selection"), + 2, INKSCAPE_ICON_SPRAY_COPY_MODE, + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Spray with clones"), + 1, _("Spray clones of the initial selection"), + 2, INKSCAPE_ICON_SPRAY_CLONE_MODE, + -1 ); + + gtk_list_store_append( model, &iter ); + gtk_list_store_set( model, &iter, + 0, _("Spray single path"), + 1, _("Spray objects in a single path"), + 2, INKSCAPE_ICON_SPRAY_UNION_MODE, + -1 ); + + EgeSelectOneAction* act = ege_select_one_action_new( "SprayModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) ); + g_object_set( act, "short_label", _("Mode:"), NULL ); + gtk_action_group_add_action( mainActions, GTK_ACTION(act) ); + g_object_set_data( holder, "mode_action", act ); + + ege_select_one_action_set_appearance( act, "full" ); + ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE ); + g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL ); + ege_select_one_action_set_icon_column( act, 2 ); + ege_select_one_action_set_icon_size( act, secondarySize ); + ege_select_one_action_set_tooltip_column( act, 1 ); + + gint mode = prefs->getInt("/tools/spray/mode", 0); + ege_select_one_action_set_active( act, mode ); + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_spray_mode_changed), holder ); + + g_object_set_data( G_OBJECT(holder), "spray_tool_mode", act); + } + + { /* Population */ + gchar const* labels[] = {_("(rough, simplified)"), 0, 0, _("(default)"), 0, 0, _("(fine, but many nodes)")}; + gdouble values[] = {10, 25, 35, 50, 60, 80, 100}; + EgeAdjustmentAction *eact = create_adjustment_action( "SprayPopulationAction", + _("Population"), _("Population:"), + _("This setting adjusts the number of items sprayed"), + "/tools/spray/population", 50, + GTK_WIDGET(desktop->canvas), NULL, holder, TRUE, "spray-population", + 1, 100, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + sp_spray_population_value_changed, 0.01, 0, 100 ); + gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); + gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + g_object_set_data( holder, "spray_population", eact ); + } + + /* Use Pressure button */ + { + InkToggleAction* act = ink_toggle_action_new( "SprayPressureAction", + _("Pressure"), + _("Use the pressure of the input device to alter the force of spray action"), + "use_pressure", + Inkscape::ICON_SIZE_DECORATION ); + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_spray_pressure_state_changed), NULL); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/usepressure", true) ); + } +} + + //######################## //## Calligraphy ## //######################## -- 2.30.2