path-manipulator.cpp revision 8261c3f0a43f2bbfa6f25edbae152278c40d9d97
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix * Path manipulator - implementation.
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix * Krzysztof KosiĆski <tweenk.pl@gmail.com>
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix * Abhishek Sharma
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix * Copyright (C) 2009 Authors
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix * Released under GNU GPL, read the file 'COPYING' for more information
3cfad782faf34c654ec837780ed7b3fe95e82c2eJohan B. C. Engelen#include "live_effects/lpeobject-reference.h"
b320a8d186114a5122ddc3afbe95110eb6cb10cecilixnamespace UI {
79d46cc367c4181803d9a7a327b163643f23e8a7cilix/// Types of path changes that we must react to.
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix} // anonymous namespace
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix * Notifies the path manipulator when something changes the path being edited
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix * (e.g. undo / redo)
b320a8d186114a5122ddc3afbe95110eb6cb10cecilixclass PathManipulatorObserver : public Inkscape::XML::NodeObserver {
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix PathManipulatorObserver(PathManipulator *p, Inkscape::XML::Node *node)
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix virtual void notifyAttributeChanged(Inkscape::XML::Node &/*node*/, GQuark attr,
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix // do nothing if blocked
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix if (_blocked) return;
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix GQuark path_transform = g_quark_from_static_string("transform");
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix GQuark lpe_quark = _pm->_lpe_key.empty() ? 0 : g_quark_from_string(_pm->_lpe_key.data());
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix // only react to "d" (path data) and "transform" attribute changes
b320a8d186114a5122ddc3afbe95110eb6cb10cecilixvoid build_segment(Geom::PathBuilder &, Node *, Node *);
3cfad782faf34c654ec837780ed7b3fe95e82c2eJohan B. C. EngelenPathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path,
7655c8b8ffe3674dd7e7c74f450fb7194943c0deJon A. Cruz Geom::Affine const &et, guint32 outline_color, Glib::ustring lpe_key)
7655c8b8ffe3674dd7e7c74f450fb7194943c0deJon A. Cruz : PointManipulator(mpm._path_data.node_data.desktop, *mpm._path_data.node_data.selection)
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix , /* XML Tree being used here directly while it shouldn't be*/_observer(new PathManipulatorObserver(this, path->getRepr()))
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix _outline = sp_canvas_bpath_new(_multi_path_manipulator._path_data.outline_group, NULL);
3cfad782faf34c654ec837780ed7b3fe95e82c2eJohan B. C. Engelen sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(_outline), outline_color, 1.0,
624e4bb114c588505c592e405dbad6570e5704feDiederik van Lierop SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
947fb2f89245c19c5bad9dbefb9fd44c2aaed2eccilix sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(_outline), 0, SP_WIND_RULE_NONZERO);
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix sigc::bind(sigc::mem_fun(*this, &PathManipulator::update), false));
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix sigc::mem_fun(*this, &PathManipulator::_selectionChanged));
5b20351508dc029f37f23fb7add6d0b43bf47f20johanengelen sigc::hide( sigc::mem_fun(*this, &PathManipulator::_updateOutlineOnZoomChange)));
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix/** Handle motion events to update the position of the curve drag point. */
b320a8d186114a5122ddc3afbe95110eb6cb10cecilixbool PathManipulator::event(SPEventContext * /*event_context*/, GdkEvent *event)
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix if (empty()) return false;
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix default: break;
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix return false;
b320a8d186114a5122ddc3afbe95110eb6cb10cecilix/** Check whether the manipulator has any nodes. */
* \param alert_LPE if true, alerts an applied LPE to what the path is going to be changed to, so it can adjust its parameters for nicer user interfacing
if (!_live_outline)
if (!_live_objects)
_setGeometry();
if (!_path) return;
if (!empty()) {
_path = 0;
if (j->selected()) {
if (j->selected()) {
if ( !Geom::are_near(t - std::floor(t+0.5),0.) ) // std::floor(t+0.5) is another way of writing round(t)
if (_num_selected == 0) return;
if (j->selected()) {
n->sink();
(*i)->insert(k, n);
_selectionChanged(n, false);
else ++num_unselected;
if (num_unselected == 0) {
while (num_selected > 0) {
unsigned num_points = 0;
bool use_pos = false;
++num_points;
if (use_pos) {
pos_valid = false;
--num_selected;
else ++num_unselected;
while (num_selected > 0) {
unsigned num_points = 0;
++num_points;
++cur;
--end;
bool becomes_open = false;
becomes_open = true;
n->sink();
if (becomes_open) {
if (_num_selected == 0) return;
else ++num_unselected;
if (num_selected == 0) {
while (num_selected > 0) {
unsigned PathManipulator::_deleteStretch(NodeList::iterator start, NodeList::iterator end, bool keep_shape)
unsigned del_len = 0;
++del_len;
if (del_len == 0) return 0;
unsigned seg = 0;
for (unsigned s = 0; s < samples_per_segment; ++s) {
++seg;
delete[] bezier_data;
return del_len;
if (_num_selected == 0) return;
bool has_unselected = false;
unsigned num_selected = 0;
if (j->selected()) {
++num_selected;
has_unselected = true;
if (!has_unselected) {
while (num_selected > 0) {
unsigned num_points = 0;
++num_points;
if (selected_only) {
if (j->selected()) {
(*i)->reverse();
(*i)->reverse();
if (_num_selected == 0) return;
switch (type) {
case SEGMENT_STRAIGHT:
case SEGMENT_CUBIC_BEZIER:
double length_change;
if (pixel) {
if (h->isDegenerate()) {
if (dir < 0) return;
if (!nh) return;
update();
if (h->isDegenerate()) return;
double angle;
if (pixel) {
update();
if (which < 0) {
return n->front();
return n->back();
if (show) {
if (!j->selected()) continue;
j->showHandles(true);
j->showHandles(false);
j->updateHandles();
++insert_at;
return inserted;
if(j->selected()) {
if (!search_selected) continue;
if (!search_unselected) continue;
if (cond) {
match = j;
return match;
switch (type) {
case PATH_CHANGE_D: {
_getGeometry();
++curpos;
case PATH_CHANGE_TRANSFORM: {
clear();
if (i->empty()) {
if (i->empty()) continue;
if ((*i)->closed()) {
* \param alert_LPE if true, first the LPE is warned what the new path is going to be before updating it
prev = i;
++spi;
if (alert_LPE) {
LivePathEffect::LPEPowerStroke *lpe_pwr = dynamic_cast<LivePathEffect::LPEPowerStroke*>( effect_list.front()->lpeobject->get_lpe() );
if (lpe_pwr) {
if (_live_outline)
if (_live_objects)
_setGeometry();
if (!_show_outline) {
if (_show_path_direction) {
if (lpe) {
if (empty()) return;
// copied from nodepath.cpp
if (lpe) {
if (!empty()) {
update(true);
if (!n->isEndNode()) {
update();
update();
else --_num_selected;
if (!_show_handles) return;
if (!node) return;
if (selected) {
writeXML();
writeXML();
if (!pvp) return;
double fracpart;
return ret;