freehand-base.cpp revision 68f967d990ace49a3d3b08e5f1cd1b55b3b40516
/*
* Generic drawing context
*
* Author:
* Lauris Kaplinski <lauris@kaplinski.com>
* Abhishek Sharma
* Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2000 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
* Copyright (C) 2002 Lauris Kaplinski
* Copyright (C) 2012 Johan Engelen
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#define DRAW_VERBOSE
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "live_effects/lpe-patternalongpath.h"
#include "display/canvas-bpath.h"
#include "desktop.h"
#include "desktop-handles.h"
#include "desktop-style.h"
#include "document.h"
#include "draw-anchor.h"
#include "macros.h"
#include "message-stack.h"
#include "ui/tools/pen-tool.h"
#include "ui/tools/lpe-tool.h"
#include "preferences.h"
#include "selection.h"
#include "selection-chemistry.h"
#include "snap.h"
#include "sp-path.h"
#include "sp-namedview.h"
#include "live_effects/lpe-powerstroke.h"
#include "style.h"
#include "ui/control-manager.h"
#include "ui/tools/freehand-base.h"
#include <gdk/gdkkeysyms.h>
using Inkscape::DocumentUndo;
namespace Inkscape {
namespace UI {
namespace Tools {
/**
* Flushes white curve(s) and additional curve into object.
*
* No cleaning of colored curves - this has to be done by caller
* No rereading of white data, so if you cannot rely on ::modified, do it in caller
*/
, attach(false)
, red_color(0xff00007f)
, blue_color(0x0000ff7f)
, green_color(0x00ff007f)
, blue_bpath(NULL)
, blue_curve(NULL)
, blue2_bpath(NULL)
, blue2_curve(NULL)
, green_bpaths(NULL)
, green_curve(NULL)
, green_anchor(NULL)
, green_closed(false)
, white_item(NULL)
, white_curves(NULL)
, red_curve_is_valid(false)
, anchor_statusbar(false)
{
}
FreehandBase::~FreehandBase() {
if (this->grab) {
}
if (this->selection) {
}
spdc_free_colors(this);
}
void FreehandBase::setup() {
// Connect signals to track selection changes
);
);
// Create red bpath
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->red_bpath), this->red_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
// Create red curve
// Create blue bpath
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->blue_bpath), this->blue_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
// Create blue curve
this->blue_curve = new SPCurve();
// Create blue2 bpath
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(this->blue2_bpath), this->blue_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
// Create blue2 curve
this->blue2_curve = new SPCurve();
// Create green curve
this->green_curve = new SPCurve();
// No green anchor by default
this->green_anchor = NULL;
this->green_closed = FALSE;
spdc_attach_selection(this, this->selection);
}
void FreehandBase::finish() {
this->sel_changed_connection.disconnect();
this->sel_modified_connection.disconnect();
if (this->grab) {
}
if (this->selection) {
}
spdc_free_colors(this);
}
}
case GDK_KEY_PRESS:
case GDK_KEY_Up:
case GDK_KEY_Down:
case GDK_KEY_KP_Up:
case GDK_KEY_KP_Down:
// prevent the zoom field from activation
if (!MOD__CTRL_ONLY(event)) {
}
break;
default:
break;
}
break;
default:
break;
}
if (!ret) {
}
return ret;
}
{
return ( SP_IS_PEN_CONTEXT(dc)
}
{
using namespace Inkscape::LivePathEffect;
// TODO: Don't paste path if nothing is on the clipboard
}
static void spdc_apply_powerstroke_shape(const std::vector<Geom::Point> & points, FreehandBase *dc, SPItem *item)
{
using namespace Inkscape::LivePathEffect;
// write powerstroke parameters:
}
{
using namespace Inkscape::LivePathEffect;
}
//add the bspline node in the waiting effects
}
bool shape_applied = false;
#define SHAPE_LENGTH 10
#define SHAPE_HEIGHT 10
switch (shape) {
case 0:
// don't apply any shape
break;
case 1:
{
// "triangle in"
shape_applied = true;
break;
}
case 2:
{
// "triangle out"
shape_applied = true;
break;
}
case 3:
{
// "ellipse"
const double C1 = 0.552;
c->curveto((1 + C1) * SHAPE_LENGTH/2, 0, SHAPE_LENGTH, (1 - C1) * SHAPE_HEIGHT/2, SHAPE_LENGTH, SHAPE_HEIGHT/2);
c->curveto(SHAPE_LENGTH, (1 + C1) * SHAPE_HEIGHT/2, (1 + C1) * SHAPE_LENGTH/2, SHAPE_HEIGHT, SHAPE_LENGTH/2, SHAPE_HEIGHT);
c->curveto((1 - C1) * SHAPE_LENGTH/2, SHAPE_HEIGHT, 0, (1 + C1) * SHAPE_HEIGHT/2, 0, SHAPE_HEIGHT/2);
c->closepath();
c->unref();
shape_applied = true;
break;
}
case 4:
{
// take shape from clipboard; TODO: catch the case where clipboard is empty
shape_applied = true;
break;
}
default:
break;
}
if (shape_applied) {
// apply original stroke color as fill and unset stroke; then return
} else {
}
return;
}
if (SP_IS_LPETOOL_CONTEXT(dc)) {
// since a geometric LPE was applied, we switch back to "inactive" mode
}
}
if (SP_IS_PEN_CONTEXT(dc)) {
}
}
}
/*
* Selection handlers
*/
{
}
}
/* fixme: We have to ensure this is not delayed (Lauris) */
{
}
}
{
// Create new white data
// Item
// Curve list
// We keep it in desktop coordinates to eliminate calculation errors
// Anchor list
SPCurve *c;
g_return_if_fail( c->get_segment_count() > 0 );
if ( !c->is_closed() ) {
SPDrawAnchor *a;
if (a)
if (a)
}
}
// fixme: recalculate active anchor?
}
}
{
if (state & GDK_SHIFT_MASK) {
// SHIFT disables all snapping, except the angular snapping. After all, the user explicitly asked for angular
// snapping by pressing CTRL, otherwise we wouldn't have arrived here. But although we temporarily disable
// the snapping here, we must still call for a constrained snap in order to apply the constraints (i.e. round
// to the nearest angle increment)
m.snapprefs.setSnapEnabledGlobally(false);
}
Inkscape::SnappedPoint dummy = m.constrainedAngularSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_NODE_HANDLE), boost::optional<Geom::Point>(), o, snaps);
if (state & GDK_SHIFT_MASK) {
}
m.unSetup();
}
void spdc_endpoint_snap_free(ToolBase const * const ec, Geom::Point& p, boost::optional<Geom::Point> &start_of_line, guint const /*state*/)
{
// selection->singleItem() is the item that is currently being drawn. This item will not be snapped to (to avoid self-snapping)
// TODO: Allow snapping to the stationary parts of the item, and only ignore the last segment
if (start_of_line) {
}
m.unSetup();
}
{
return ret;
}
{
// Concat RBG
// Green
while (dc->green_bpaths) {
}
// Blue
// Red
if (dc->red_curve_is_valid) {
}
// Blue2
/* if c is empty, it might be that the user was trying to continue an existing curve and cancelled.
if this is the case and we are in bspline or spirolive the previous curve needs to be selected again because
we modify it when continuing through an anchor. */
if (c->is_empty()) {
if(prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 1 || prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 2){
}
c->unref();
return;
}
// Step A - test, whether we ended on green anchor
// We hit green anchor, closing Green-Blue-Red
c->closepath_current();
// Closed path, just flush
spdc_flush_white(dc, c);
c->unref();
return;
}
// Step B - both start and end anchored to same curve
{
// We hit bot start and end of single curve, closing paths
/* if we are in bspline or spirolive mode, the continuation and ending curve are updated when continuing or ending the curve in an anchor.
this causes that the original function doesn't detect if it's the same curve in case the curves have multiples parts -shift- and
close incorrectly one of the parts */
}
c->unref();
}
// if the curve has an bspline or spiro LPE, we execute
// spdc_flush_white, passing the necessary starting curve.
}else{
c = reverse_then_unref(c);
}
c->unref();
}
return;
}
// Step C - test start
s = reverse_then_unref(s);
}
s->append_continuous(c, 0.0625);
c->unref();
c = s;
e = reverse_then_unref(e);
}
c->append_continuous(e, 0.0625);
e->unref();
}
spdc_flush_white(dc, c);
c->unref();
}
{
SPCurve *c;
if (dc->white_curves) {
if (gc) {
}
} else if (gc) {
c = gc;
c->ref();
} else {
return;
}
// Now we have to go back to item coordinates at last
if ( c && !c->is_empty() ) {
// We actually have something to write
bool has_lpe = false;
if (dc->white_item) {
} else {
// Set style
}
if (has_lpe)
else
if (!dc->white_item) {
// Attach repr
// we finished the path; now apply any waiting LPEs or freehand shapes
item->updateRepr();
}
_("Draw path"));
// When quickly drawing several subpaths with Shift, the next subpath may be finished and
// flushed before the selection_modified signal is fired by the previous change, which
// results in the tool losing all of the selected path's curve except that last subpath. To
// fix this, we force the selection_modified callback now, to make sure the tool's curve is
// in sync immediately.
}
c->unref();
// Flush pending updates
doc->ensureUpToDate();
}
{
// Test green anchor
if (dc->green_anchor) {
}
}
}
/* modify the anchoring curve so it is equal to the starting curve.
this curve is modified when it's modified and we need them to be equal to the closing curve */
if(active){
}
}
return active;
}
{
if (dc->white_item) {
// We do not hold refcount
}
while (dc->white_curves) {
}
while (dc->white_anchors) {
}
}
{
// Red
}
}
// Blue
if (dc->blue_bpath) {
}
if (dc->blue_curve) {
}
// Blue2
if (dc->blue2_bpath) {
}
if (dc->blue2_curve) {
}
// Green
while (dc->green_bpaths) {
}
if (dc->green_curve) {
}
if (dc->green_anchor) {
}
// White
if (dc->white_item) {
// We do not hold refcount
}
while (dc->white_curves) {
}
while (dc->white_anchors) {
}
}
void spdc_create_single_dot(ToolBase *ec, Geom::Point const &pt, char const *tool, guint event_state) {
// apply the tool's current style
// find out stroke width (TODO: is there an easier way??)
double stroke_width = 3.0;
if (style_str) {
}
// unset stroke and set fill color to former stroke color
str = g_strdup_printf("fill:#%06x;stroke:none;", sp_desktop_get_color_tool(desktop, tool, false) >> 8);
// put the circle where the mouse click occurred and set the diameter to the
// current stroke width, multiplied by the amount specified in the preferences
if (event_state & GDK_MOD1_MASK) {
// TODO: We vary the dot size between 0.5*rad and 1.5*rad, where rad is the dot size
// as specified in prefs. Very simple, but it might be sufficient in practice. If not,
// we need to devise something more sophisticated.
rad *= (1 + s);
}
if (event_state & GDK_SHIFT_MASK) {
// double the point size
rad *= 2;
}
item->updateRepr();
}
}
}
}
/*
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:fileencoding=utf-8:textwidth=99 :