freehand-base.cpp revision 3c15d009f1e24229c6a04a22be6fe56f4d111bf2
/*
* 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
*/
this->selection = 0;
this->grab = 0;
this->anchor_statusbar = false;
this->red_color = 0xff00007f;
this->blue_color = 0x0000ff7f;
this->green_color = 0x00ff007f;
this->red_curve_is_valid = false;
this->blue_bpath = NULL;
this->blue_curve = NULL;
this->green_bpaths = NULL;
this->green_curve = NULL;
this->green_anchor = NULL;
this->green_closed = false;
this->white_item = NULL;
this->white_curves = NULL;
this->white_anchors = NULL;
}
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 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;
}
//spanish: añadimos el modo bspline a los efectos en espera
}
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) {
}
if (c->is_empty()) {
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
c = reverse_then_unref(c);
}
c->unref();
//spanish: Si la curva tiene un LPE del tipo bspline o spiro ejecutamos spdc_flush_white
//pasándole la curva de inicio necesaria
}else
return;
}
// Step C - test start
}else{
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) {
}
}
}
//spanish: modificamos la curva de anclaje para que sea igual que la curva de inicio.
//esta curva fue modificada al continuar la curva y necesitamos que sea igual que la curva en
//la que cerramos el trazado.
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) {
}
// 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 :