dyna-draw-context.cpp revision 274f6d25a9facdc5bfbe8b4df42e6173e4328775
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * Handwriting-like drawing mode
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * Mitsuru Oka <oka326@parkcity.ne.jp>
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * Lauris Kaplinski <lauris@kaplinski.com>
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * bulia byak <buliabyak@users.sf.net>
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * MenTaLguY <mental@rydia.net>
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * The original dynadraw code:
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * Paul Haeberli <paul@sgi.com>
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * Copyright (C) 1998 The Free Software Foundation
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * Copyright (C) 1999-2005 authors
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * Copyright (C) 2001-2002 Ximian, Inc.
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * Copyright (C) 2005-2007 bulia byak
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * Copyright (C) 2006 MenTaLguY
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler * Released under GNU GPL, read the file 'COPYING' for more information
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler// FIXME: move it to some shared file to be reused by both calligraphy and dropper
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andler { NR_END, 0, 0, 0, 0, 0, 0 }
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void sp_dyna_draw_context_class_init(SPDynaDrawContextClass *klass);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void sp_dyna_draw_context_init(SPDynaDrawContext *ddc);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void sp_dyna_draw_context_dispose(GObject *object);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void sp_dyna_draw_context_setup(SPEventContext *ec);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void sp_dyna_draw_context_set(SPEventContext *ec, gchar const *key, gchar const *val);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic gint sp_dyna_draw_context_root_handler(SPEventContext *ec, GdkEvent *event);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void clear_current(SPDynaDrawContext *dc);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void set_to_accumulated(SPDynaDrawContext *dc, bool unionize);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void add_cap(SPCurve *curve, NR::Point const &from, NR::Point const &to, double rounding);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void accumulate_calligraphic(SPDynaDrawContext *dc);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void fit_and_split(SPDynaDrawContext *ddc, gboolean release);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void sp_dyna_draw_reset(SPDynaDrawContext *ddc, NR::Point p);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic NR::Point sp_dyna_draw_get_npoint(SPDynaDrawContext const *ddc, NR::Point v);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic NR::Point sp_dyna_draw_get_vpoint(SPDynaDrawContext const *ddc, NR::Point n);
1b1107ddff011fb4b14c466805d0f3b75a1bae3cJosh Andlerstatic void draw_temporary_box(SPDynaDrawContext *dc);
if (!type) {
sizeof(SPDynaDrawContextClass),
sizeof(SPDynaDrawContext),
type = g_type_register_static(SP_TYPE_COMMON_CONTEXT, "SPDynaDrawContext", &info, static_cast<GTypeFlags>(0));
return type;
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(ddc->currentshape), 0x00000000, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
g_signal_connect(G_OBJECT(ddc->currentshape), "event", G_CALLBACK(sp_desktop_root_handler), ec->desktop);
c->unref();
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(ddc->hatch_area), 0x0000007f, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
static gboolean
if ( NR::L2(force) < DYNA_EPSILON || (dc->vel_max < DYNA_VEL_START && NR::L2(force) < DYNA_EPSILON_START)) {
return FALSE;
double a1;
if (length > 0) {
return FALSE;
bool flipped = false;
flipped = true;
// FIXME: when dc->vel is oscillating around the fixed angle, the new_ang flips back and forth. How to avoid this?
return FALSE;
// g_print ("force %g acc %g vel_max %g vel %g a1 %g a2 %g new_ang %g\n", NR::L2(force), NR::L2(dc->acc), dc->vel_max, NR::L2(dc->vel), a1, a2, new_ang);
return TRUE;
sp_canvas_arena_render_pixblock(SP_CANVAS_ARENA(sp_desktop_drawing(SP_EVENT_CONTEXT(dc)->desktop)), &pb);
// (2) deflection depends on width, but is upped for small widths for better visual uniformity across widths;
case GDK_BUTTON_PRESS:
return TRUE;
NULL,
case GDK_MOTION_NOTIFY:
double hatch_dist = 0;
NR::Maybe<Path::cut_position> position = get_nearest_position_on_Path(dc->hatch_livarot_path, pointer);
dc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Guide path selected</b>; start drawing along the guide with <b>Ctrl</b>"));
dc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Select a guide path</b> to track with <b>Ctrl</b>"));
double nearest_sum = std::accumulate (dc->hatch_nearest_past.begin(), dc->hatch_nearest_past.end(), 0.0);
double pointer_sum = std::accumulate (dc->hatch_pointer_past.begin(), dc->hatch_pointer_past.end(), 0.0);
//g_print ("\nlast_nearest %g %g nearest %g %g pointer %g %g pos %d %g\n", dc->last_nearest[NR::X], dc->last_nearest[NR::Y], nearest[NR::X], nearest[NR::Y], pointer[NR::X], pointer[NR::Y], position->piece, position->t);
double target;
dc->_message_context->set(Inkscape::NORMAL_MESSAGE, dc->hatch_escaped? _("Tracking: <b>connection to guide path lost!</b>") : _("<b>Tracking</b> a guide path"));
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0x7f7f7fff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0x00FF00ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0xFF0000ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0x7f7f7fff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
case GDK_BUTTON_RELEASE:
case GDK_KEY_PRESS:
case GDK_Up:
case GDK_KP_Up:
if (!MOD__CTRL_ONLY) {
case GDK_Down:
case GDK_KP_Down:
if (!MOD__CTRL_ONLY) {
case GDK_Right:
case GDK_KP_Right:
if (!MOD__CTRL_ONLY) {
sp_ddc_update_toolbox (desktop, "altx-calligraphy", dc->width * 100); // the same spinbutton is for alt+x
case GDK_Left:
case GDK_KP_Left:
if (!MOD__CTRL_ONLY) {
case GDK_Home:
case GDK_KP_Home:
case GDK_End:
case GDK_KP_End:
case GDK_x:
case GDK_X:
if (MOD__ALT_ONLY) {
case GDK_Escape:
case GDK_z:
case GDK_Z:
case GDK_KEY_RELEASE:
case GDK_Control_L:
case GDK_Control_R:
if (!ret) {
return ret;
if (unionize) {
double rounding)
Geom::CubicBezier const * dc_cal1_firstseg = dynamic_cast<Geom::CubicBezier const *>( dc->cal1->first_segment() );
Geom::CubicBezier const * rev_cal2_firstseg = dynamic_cast<Geom::CubicBezier const *>( rev_cal2->first_segment() );
Geom::CubicBezier const * dc_cal1_lastseg = dynamic_cast<Geom::CubicBezier const *>( dc->cal1->last_segment() );
Geom::CubicBezier const * rev_cal2_lastseg = dynamic_cast<Geom::CubicBezier const *>( rev_cal2->last_segment() );
static double square(double const x)
double const tolerance_sq = square( NR::expansion(SP_EVENT_CONTEXT(dc)->desktop->w2d()) * TOLERANCE_CALLIGRAPHIC );
#ifdef DYNA_DRAW_VERBOSE
#ifdef DYNA_DRAW_VERBOSE
#ifdef DYNA_DRAW_VERBOSE
if (! release) {
#ifdef DYNA_DRAW_VERBOSE
#ifdef DYNA_DRAW_VERBOSE
if (!release) {
NULL);
//guint32 strokeColor = sp_desktop_get_color_tool (SP_ACTIVE_DESKTOP, "tools.calligraphic", false);
//double strokeOpacity = sp_desktop_get_opacity_tool (SP_ACTIVE_DESKTOP, "tools.calligraphic", false);
sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(cbp), ((fillColor & 0xffffff00) | SP_COLOR_F_TO_U(opacity*fillOpacity)), SP_WIND_RULE_EVENODD);
//on second thougtht don't do stroke yet because we don't have stoke-width yet and because stoke appears between segments while drawing
//sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cbp), ((strokeColor & 0xffffff00) | SP_COLOR_F_TO_U(opacity*strokeOpacity)), 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(cbp), 0x00000000, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
g_signal_connect(G_OBJECT(cbp), "event", G_CALLBACK(sp_desktop_root_handler), SP_EVENT_CONTEXT(dc)->desktop);