draw-context.cpp revision c13adc1aa8f34445131579baa56299b360480b5e
#define __SP_DRAW_CONTEXT_C__
/*
* Generic drawing context
*
* Author:
* Lauris Kaplinski <lauris@kaplinski.com>
*
* Copyright (C) 2000 Lauris Kaplinski
* Copyright (C) 2000-2001 Ximian, Inc.
* Copyright (C) 2002 Lauris Kaplinski
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#define DRAW_VERBOSE
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <gdk/gdkkeysyms.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 "pen-context.h"
#include "lpe-tool-context.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-patternalongpath.h"
#include "style.h"
static SPEventContextClass *draw_parent_class;
sp_draw_context_get_type(void)
{
if (!type) {
sizeof(SPDrawContextClass),
sizeof(SPDrawContext),
4,
NULL, /* value_table */
};
}
return type;
}
static void
{
}
static void
{
dc->red_curve_is_valid = false;
dc->green_closed = false;
}
static void
{
}
}
}
static void
{
}
/* Connect signals to track selection changes */
);
);
/* Create red bpath */
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(dc->red_bpath), dc->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(dc->blue_bpath), dc->blue_color, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
/* Create blue curve */
/* Create green curve */
/* No green anchor by default */
}
static void
{
}
}
}
static void
{
}
{
case GDK_KEY_PRESS:
case GDK_Up:
case GDK_Down:
case GDK_KP_Up:
case GDK_KP_Down:
// prevent the zoom field from activation
if (!MOD__CTRL_ONLY) {
}
break;
default:
break;
}
break;
default:
break;
}
if (!ret) {
}
}
return ret;
}
{
return ( SP_IS_PEN_CONTEXT(dc)
}
static void
{
using namespace Inkscape::LivePathEffect;
// TODO: Don't paste path if nothing is on the clipboard
}
/*
* If we have an item and a waiting LPE, apply the effect to the item
* (spiro spline mode is treated separately)
*/
void
{
using namespace Inkscape::LivePathEffect;
}
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"
// TODO: this is only for illustration (we create a "decrescendo"-shaped path
// manually; eventually we should read the path from a separate file)
c->moveto(0,0);
c->lineto(0, SHAPE_HEIGHT);
c->closepath();
c->unref();
shape_applied = true;
break;
}
case 2:
{
// "triangle out"
c->lineto(SHAPE_LENGTH, 0);
c->closepath();
c->unref();
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
*/
static void
{
}
}
/* fixme: We have to ensure this is not delayed (Lauris) */
static void
{
}
}
static void
{
/* 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? */
}
}
/**
* Snaps node or handle to PI/rotationsnapsperpi degree increments.
*
* \param dc draw context
* \param p cursor point (to be changed by snapping)
* \param o origin point
* \param state keyboard state to check if ctrl or shift was pressed
*/
void spdc_endpoint_snap_rotation(SPEventContext const *const ec, Geom::Point &p, Geom::Point const &o,
{
if (snaps > 0) { // 0 means no snapping
// p is at an arbitrary angle. Now we should snap this angle to specific increments.
// For this we'll calculate the closest two angles, one at each side of the current angle
// We have to angles now. The constrained snapper will try each of them and return the closest
// But first we should setup the snapper
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);
}
// Now do the snapping...
Inkscape::SnappedPoint sp = m.multipleConstrainedSnaps(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_NODE_HANDLE), constraints);
m.unSetup();
if (state & GDK_SHIFT_MASK) {
}
}
}
void spdc_endpoint_snap_free(SPEventContext const * const ec, Geom::Point& p, 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
m.unSetup();
}
static SPCurve *
{
return ret;
}
/**
* Concats red, blue and green.
* If any anchors are defined, process these, optionally removing curves from white list
* Invoke _flush_white to write result back to object.
*/
void
{
/* 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
SP_EVENT_CONTEXT_DESKTOP(dc)->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Path is closed."));
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();
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();
}
/*
* 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
*
*/
static void
{
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 */
}
/**
* Returns FIRST active anchor (the activated one).
*/
{
/* Test green anchor */
if (dc->green_anchor) {
}
}
}
return active;
}
static void
{
if (dc->white_item) {
/* We do not hold refcount */
}
while (dc->white_curves) {
}
while (dc->white_anchors) {
}
}
static void
{
/* 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) {
}
}
/* Create a single dot represented by a circle */
void spdc_create_single_dot(SPEventContext *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:encoding=utf-8:textwidth=99 :