index d1966d248ba6c3e6af642461b6904c201483ca24..666ea4d2da0132db2bb9ea3b55df7c03be703b0b 100644 (file)
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <glibmm/i18n.h>
-
+#include <string>
+#include <cstring>
#include <numeric>
#include "svg/svg.h"
#include "desktop-affine.h"
#include "desktop-style.h"
#include "message-context.h"
+#include "prefs-utils.h"
#include "pixmaps/cursor-calligraphy.xpm"
-#include "pixmaps/cursor-thin.xpm"
-#include "pixmaps/cursor-thicken.xpm"
#include "libnr/n-art-bpath.h"
#include "libnr/nr-path.h"
#include "libnr/nr-matrix-ops.h"
#include "inkscape.h"
#include "color.h"
#include "splivarot.h"
+#include "sp-item-group.h"
#include "sp-shape.h"
#include "sp-path.h"
#include "sp-text.h"
ddc->keep_selected = true;
ddc->hatch_spacing = 0;
+ ddc->hatch_spacing_step = 0;
new (&ddc->hatch_pointer_past) std::list<double>();
new (&ddc->hatch_nearest_past) std::list<double>();
ddc->hatch_last_nearest = NR::Point(0,0);
ddc->hatch_livarot_path = NULL;
ddc->trace_bg = false;
-
- ddc->is_dilating = false;
}
static void
ddc->hatch_area = NULL;
}
- if (ddc->dilate_area) {
- gtk_object_destroy(GTK_OBJECT(ddc->dilate_area));
- ddc->dilate_area = NULL;
- }
-
if (ddc->accumulated) {
ddc->accumulated = sp_curve_unref(ddc->accumulated);
}
sp_canvas_item_hide(ddc->hatch_area);
}
- {
- SPCurve *c = sp_curve_new_from_foreign_bpath(hatch_area_circle);
- ddc->dilate_area = sp_canvas_bpath_new(sp_desktop_controls(ec->desktop), c);
- sp_curve_unref(c);
- sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(ddc->dilate_area), 0x00000000,(SPWindRule)0);
- sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(ddc->dilate_area), 0xff9900ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
- sp_canvas_item_hide(ddc->dilate_area);
- }
-
sp_event_context_read(ec, "mass");
sp_event_context_read(ec, "wiggle");
sp_event_context_read(ec, "angle");
ddc->is_drawing = false;
ddc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack());
+
+ if (prefs_get_int_attribute("tools.calligraphic", "selcue", 0) != 0) {
+ ec->enableSelectionCue();
+ }
}
static void
dc->npoints++;
}
-double
-get_dilate_radius (SPDynaDrawContext *dc)
-{
- // 10 times the pen width:
- return 500 * dc->width/SP_EVENT_CONTEXT(dc)->desktop->current_zoom();
-}
-
-double
-get_dilate_force (SPDynaDrawContext *dc)
-{
- return 8 * dc->pressure/SP_EVENT_CONTEXT(dc)->desktop->current_zoom();
-}
-
-bool
-sp_ddc_dilate (SPDynaDrawContext *dc, NR::Point p, bool expand)
-{
- Inkscape::Selection *selection = sp_desktop_selection(SP_EVENT_CONTEXT(dc)->desktop);
-
- if (selection->isEmpty()) {
- return false;
- }
-
- bool did = false;
- double radius = get_dilate_radius(dc);
- double offset = get_dilate_force(dc);
-
- for (GSList *items = g_slist_copy((GSList *) selection->itemList());
- items != NULL;
- items = items->next) {
-
- SPItem *item = (SPItem *) items->data;
-
- // only paths
- if (!SP_IS_PATH(item))
- continue;
-
- SPCurve *curve = NULL;
- curve = sp_shape_get_curve(SP_SHAPE(item));
- if (curve == NULL)
- continue;
-
- // skip those paths whose bboxes are entirely out of reach with our radius
- NR::Maybe<NR::Rect> bbox = item->getBounds(sp_item_i2doc_affine(item));
- if (bbox) {
- bbox->growBy(radius);
- if (!bbox->contains(p)) {
- continue;
- }
- }
-
- Path *orig = Path_for_item(item, false);
- if (orig == NULL) {
- sp_curve_unref(curve);
- continue;
- }
- Path *res = new Path;
- res->SetBackData(false);
-
- Shape *theShape = new Shape;
- Shape *theRes = new Shape;
-
- orig->ConvertWithBackData(0.05);
- orig->Fill(theShape, 0);
-
- SPCSSAttr *css = sp_repr_css_attr(SP_OBJECT_REPR(item), "style");
- gchar const *val = sp_repr_css_property(css, "fill-rule", NULL);
- if (val && strcmp(val, "nonzero") == 0)
- {
- theRes->ConvertToShape(theShape, fill_nonZero);
- }
- else if (val && strcmp(val, "evenodd") == 0)
- {
- theRes->ConvertToShape(theShape, fill_oddEven);
- }
- else
- {
- theRes->ConvertToShape(theShape, fill_nonZero);
- }
-
- bool did_this = false;
- if (theShape->MakeOffset(theRes,
- expand? offset : -offset,
- join_straight, butt_straight,
- true, p[NR::X], p[NR::Y], radius) == 0) // 0 means the shape was actually changed
- did_this = true;
-
- // the rest only makes sense if we actually changed the path
- if (did_this) {
- theRes->ConvertToShape(theShape, fill_positive);
-
- res->Reset();
- theRes->ConvertToForme(res);
-
- if (offset >= 0.5)
- {
- res->ConvertEvenLines(0.5);
- res->Simplify(0.5);
- }
- else
- {
- res->ConvertEvenLines(0.5*offset);
- res->Simplify(0.5 * offset);
- }
-
- sp_curve_unref(curve);
- if (res->descr_cmd.size() > 1) {
- gchar *str = res->svg_dump_path();
- SP_OBJECT_REPR(item)->setAttribute("d", str);
- g_free(str);
- } else {
- // TODO: if there's 0 or 1 node left, delete this path altogether
- }
- }
-
- delete theShape;
- delete theRes;
- delete orig;
- delete res;
-
- if (did_this)
- did = true;
- }
-
- return did;
-}
-
-void
-sp_ddc_update_cursors (SPDynaDrawContext *dc)
-{
- if (dc->is_dilating) {
- double radius = get_dilate_radius(dc);
- NR::Matrix const sm (NR::scale(radius, radius) * NR::translate(SP_EVENT_CONTEXT(dc)->desktop->point()));
- sp_canvas_item_affine_absolute(dc->dilate_area, sm);
- sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0xff9900ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
- sp_canvas_item_show(dc->dilate_area);
- }
-}
-
void
sp_ddc_update_toolbox (SPDesktop *desktop, const gchar *id, double value)
{
switch (event->type) {
case GDK_BUTTON_PRESS:
- if ( event->button.button == 1 ) {
+ if (event->button.button == 1 && !event_context->space_panning) {
SPDesktop *desktop = SP_EVENT_CONTEXT_DESKTOP(dc);
ret = TRUE;
+ sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 3);
dc->is_drawing = true;
}
break;
NR::Point const motion_w(event->motion.x,
event->motion.y);
NR::Point motion_dt(desktop->w2d(motion_w));
+ sp_dyna_draw_extinput(dc, event);
- // draw the dilating cursor
- if (event->motion.state & GDK_MOD1_MASK) {
- double radius = get_dilate_radius(dc);
- NR::Matrix const sm (NR::scale(radius, radius) * NR::translate(desktop->w2d(motion_w)));
- sp_canvas_item_affine_absolute(dc->dilate_area, sm);
- sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->hatch_area), 0xff9900ff, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
- sp_canvas_item_show(dc->dilate_area);
-
- guint num = 0;
- if (!desktop->selection->isEmpty()) {
- num = g_slist_length((GSList *) desktop->selection->itemList());
- }
- if (num == 0) {
- dc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Select paths</b> to thin or thicken"));
- } else {
- dc->_message_context->setF(Inkscape::NORMAL_MESSAGE,
- event->motion.state & GDK_SHIFT_MASK?
- _("<b>Thickening %d</b> selected paths; without <b>Shift</b> to thin") :
- _("<b>Thinning %d</b> selected paths; with <b>Shift</b> to thicken"), num);
- }
-
- } else {
- dc->_message_context->clear();
- sp_canvas_item_hide(dc->dilate_area);
- }
-
- // dilating:
- if (dc->is_drawing && ( event->motion.state & GDK_BUTTON1_MASK ) && event->motion.state & GDK_MOD1_MASK) {
- sp_ddc_dilate (dc, desktop->dt2doc(motion_dt), event->motion.state & GDK_SHIFT_MASK? true : false);
- dc->is_dilating = true;
- // it's slow, so prevent clogging up with events
- gobble_motion_events(GDK_BUTTON1_MASK);
- return TRUE;
- }
-
+ dc->_message_context->clear();
// for hatching:
double hatch_dist = 0;
}
}
- if ( dc->is_drawing && ( event->motion.state & GDK_BUTTON1_MASK ) ) {
+ if ( dc->is_drawing && (event->motion.state & GDK_BUTTON1_MASK) && !event_context->space_panning) {
dc->dragging = TRUE;
if (event->motion.state & GDK_CONTROL_MASK && dc->hatch_item) { // hatching
// We are NOT attracted to the guide!
//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);
- //g_print ("------nm %g pm %g ratio %g\n", nearest_moved, pointer_moved, ratio);
- //g_print ("------dist %g spacing %g\n", dist, dc->spacing);
- //g_print ("acting up: %s dist %g \n", position_is_ok? (dc->hatch_escaped? "escaped" : "dist") : "livarot", dist/dc->hatch_spacing);
// Remember hatch_escaped so we don't get
// attracted again until the end of this stroke
// so _gradually_ let go attraction to prevent jerks
target = (dc->hatch_spacing * speed + hatch_dist * (SPEED_NORMAL - speed))/SPEED_NORMAL;
}
- if (!isnan(dot) && dot < -0.5) {// flip
+ if (!isNaN(dot) && dot < -0.5) {// flip
target = -target;
- //g_print ("FLIP\n");
}
// This is the track pointer that we will use instead of the real one
NR::Point new_pointer = nearest + target * hatch_unit_vector;
- //g_print ("NEW %g %g\n", new_point[NR::X], new_point[NR::Y]);
// some limited feedback: allow persistent pulling to slightly change
// the spacing
dc->_message_context->set(Inkscape::NORMAL_MESSAGE, _("<b>Drawing</b> a calligraphic stroke"));
}
- sp_dyna_draw_extinput(dc, event);
if (!sp_dyna_draw_apply(dc, motion_dt)) {
ret = TRUE;
break;
case GDK_BUTTON_RELEASE:
+ {
+ NR::Point const motion_w(event->button.x, event->button.y);
+ NR::Point const motion_dt(desktop->w2d(motion_w));
+
sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate), event->button.time);
+ sp_canvas_end_forced_full_redraws(desktop->canvas);
dc->is_drawing = false;
- if ( dc->is_dilating && event->button.button == 1 ) {
- dc->is_dilating = false;
- sp_document_done(sp_desktop_document(SP_EVENT_CONTEXT(dc)->desktop),
- SP_VERB_CONTEXT_CALLIGRAPHIC,
- (event->button.state & GDK_SHIFT_MASK ? _("Thicken paths") : _("Thin paths")));
- ret = TRUE;
- } else if ( dc->dragging && event->button.button == 1 ) {
+ if (dc->dragging && event->button.button == 1 && !event_context->space_panning) {
dc->dragging = FALSE;
- NR::Point const motion_w(event->button.x, event->button.y);
- NR::Point const motion_dt(desktop->w2d(motion_w));
sp_dyna_draw_apply(dc, motion_dt);
/* Remove all temporary line segments */
dc->hatch_item = NULL;
dc->hatch_livarot_path = NULL;
+ if (dc->hatch_spacing != 0 && !dc->keep_selected) {
+ // we do not select the newly drawn path, so increase spacing by step
+ if (dc->hatch_spacing_step == 0) {
+ dc->hatch_spacing_step = dc->hatch_spacing;
+ }
+ dc->hatch_spacing += dc->hatch_spacing_step;
+ }
+
dc->_message_context->clear();
ret = TRUE;
}
break;
+ }
case GDK_KEY_PRESS:
switch (get_group0_keyval (&event->key)) {
if (dc->width > 1.0)
dc->width = 1.0;
sp_ddc_update_toolbox (desktop, "altx-calligraphy", dc->width * 100); // the same spinbutton is for alt+x
- sp_ddc_update_cursors(dc);
ret = TRUE;
}
break;
if (dc->width < 0.01)
dc->width = 0.01;
sp_ddc_update_toolbox (desktop, "altx-calligraphy", dc->width * 100);
- sp_ddc_update_cursors(dc);
ret = TRUE;
}
break;
case GDK_KP_Home:
dc->width = 0.01;
sp_ddc_update_toolbox (desktop, "altx-calligraphy", dc->width * 100);
- sp_ddc_update_cursors(dc);
ret = TRUE;
break;
case GDK_End:
case GDK_KP_End:
dc->width = 1.0;
sp_ddc_update_toolbox (desktop, "altx-calligraphy", dc->width * 100);
- sp_ddc_update_cursors(dc);
ret = TRUE;
break;
case GDK_x:
ret = TRUE;
}
break;
- case GDK_Meta_L:
- case GDK_Meta_R:
- event_context->cursor_shape = cursor_thicken_xpm;
- sp_event_context_update_cursor(event_context);
- break;
- case GDK_Alt_L:
- case GDK_Alt_R:
- if (MOD__SHIFT) {
- event_context->cursor_shape = cursor_thicken_xpm;
- sp_event_context_update_cursor(event_context);
- } else {
- event_context->cursor_shape = cursor_thin_xpm;
- sp_event_context_update_cursor(event_context);
- }
- break;
- case GDK_Shift_L:
- case GDK_Shift_R:
- if (MOD__ALT) {
- event_context->cursor_shape = cursor_thicken_xpm;
- sp_event_context_update_cursor(event_context);
- }
- break;
default:
break;
}
case GDK_Control_R:
dc->_message_context->clear();
dc->hatch_spacing = 0;
+ dc->hatch_spacing_step = 0;
break;
- case GDK_Alt_L:
- case GDK_Alt_R:
- event_context->cursor_shape = cursor_calligraphy_xpm;
- sp_event_context_update_cursor(event_context);
- break;
- case GDK_Shift_L:
- case GDK_Shift_R:
- if (MOD__ALT) {
- event_context->cursor_shape = cursor_thin_xpm;
- sp_event_context_update_cursor(event_context);
- }
- break;
- case GDK_Meta_L:
- case GDK_Meta_R:
- event_context->cursor_shape = cursor_calligraphy_xpm;
- sp_event_context_update_cursor(event_context);
- break;
default:
break;
}
} else {
if (dc->keep_selected) {
sp_desktop_selection(desktop)->set(dc->repr);
- } else {
- sp_desktop_selection(desktop)->clear();
- }
+ }
}
} else {