summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: fdb1b34)
raw | patch | inline | side by side (parent: fdb1b34)
author | Krzysztof Kosiński <tweenk.pl@gmail.com> | |
Sat, 26 Dec 2009 03:13:01 +0000 (04:13 +0100) | ||
committer | Krzysztof Kosiński <tweenk.pl@gmail.com> | |
Sat, 26 Dec 2009 03:13:01 +0000 (04:13 +0100) |
index 889e245c65570e45d707f74a7c305eaa74a4dd89..1823622596ab0e59979d91bb1d200816dcd973d9 100644 (file)
bool CurveDragPoint::_drags_stroke = false;
CurveDragPoint::CurveDragPoint(PathManipulator &pm)
- : ControlPoint(pm._path_data.node_data.desktop, Geom::Point(), Gtk::ANCHOR_CENTER,
- SP_CTRL_SHAPE_CIRCLE, 1.0, &invisible_cset, pm._path_data.dragpoint_group)
+ : ControlPoint(pm._multi_path_manipulator._path_data.node_data.desktop, Geom::Point(),
+ Gtk::ANCHOR_CENTER, SP_CTRL_SHAPE_CIRCLE, 1.0, &invisible_cset,
+ pm._multi_path_manipulator._path_data.dragpoint_group)
, _pm(pm)
{
setVisible(false);
index c441f70168b5a5046a5dbbc365bf5663e154c877..799dad0d3cb6e754390fc0129e2d4fb80c0d6e7d 100644 (file)
/**
* @brief Tool component that processes events and does something in response to them.
+ * Note: this class is probably redundant.
*/
class Manipulator {
friend class ManipulatorGroup;
/// Handle input event. Returns true if handled.
virtual bool event(GdkEvent *)=0;
- /// Commits changes to XML (repr).
- //virtual void commitToXML();
- //Manipulator *_parent;
protected:
SPDesktop *const _desktop;
};
/**
* @brief Tool component that edits something on the canvas using selectable control points.
+ * Note: this class is probably redundant.
*/
class PointManipulator : public Manipulator, public sigc::trackable {
public:
/** Manipulator that aggregates several manipulators of the same type.
* The order of invoking events on the member manipulators is undefined.
* To make this class more useful, derive from it and add actions that can be performed
- * on all manipulators in the set. */
+ * on all manipulators in the set.
+ *
+ * This is not used at the moment and is probably useless. */
template <typename T>
class MultiManipulator : public PointManipulator {
public:
MapType _mmap;
};
-/*
- * @brief Set of manipulators. Takes care of routing events to appropriate manipulators.
- */
-/*class ManipulatorGroup : private std::list<boost::shared_ptr<Manipulator> > {
-friend class Manipulator;
-public:
- ManipulatorGroup(SPDesktop *d);
- ~ManipulatorGroup();
- void add(boost::shared_ptr<Manipulator> m);
- void remove(boost::shared_ptr<Manipulator> m);
- void clear();
- bool event(GdkEvent *);
-private:
- void _grabEvents(boost::shared_ptr<Manipulator> m);
- void _ungrabEvents(boost::shared_ptr<Manipulator> m);
-
- SPDesktop *_desktop;
- boost::shared_ptr<Manipulator> _grab;
-};*/
-
} // namespace UI
} // namespace Inkscape
index aaf7e413cdfd303805a7ec4002502cbca9f6eb7d..ac0165e1a1a62882dc12059f6eed8e610def6e7d 100644 (file)
typedef std::multimap<double, IterPair> DistanceMap;
typedef std::pair<double, IterPair> DistanceMapItem;
-/** Find two selected endnodes.
- * @returns -1 if not enough endnodes selected, 1 if too many, 0 if OK */
+/** Find pairs of selected endnodes suitable for joining. */
void find_join_iterators(ControlPointSelection &sel, IterPairList &pairs)
{
IterSet join_iters;
} // anonymous namespace
-MultiPathManipulator::MultiPathManipulator(PathSharedData const &data, sigc::connection &chg)
+MultiPathManipulator::MultiPathManipulator(PathSharedData &data, sigc::connection &chg)
: PointManipulator(data.node_data.desktop, *data.node_data.selection)
, _path_data(data)
, _changed(chg)
{
- //
_selection.signal_commit.connect(
sigc::mem_fun(*this, &MultiPathManipulator::_commit));
_selection.signal_point_changed.connect(
for (std::set<ShapeRecord>::iterator i = shapes.begin(); i != shapes.end(); ++i) {
ShapeRecord const &r = *i;
if (!SP_IS_PATH(r.item) && !IS_LIVEPATHEFFECT(r.item)) continue;
- boost::shared_ptr<PathManipulator> newpm(new PathManipulator(_path_data, (SPPath*) r.item,
+ boost::shared_ptr<PathManipulator> newpm(new PathManipulator(*this, (SPPath*) r.item,
r.edit_transform, _getOutlineColor(r.role), r.lpe_key));
newpm->showHandles(_show_handles);
// always show outlines for clips and masks
{
invokeForAll(&PathManipulator::shiftSelection, dir);
}
+void MultiPathManipulator::spatialGrow(NodeList::iterator origin, int dir)
+{
+ double extr_dist = dir > 0 ? HUGE_VAL : -HUGE_VAL;
+ NodeList::iterator target;
+
+ do { // this substitutes for goto
+ if ((dir > 0 && !origin->selected())) {
+ target = origin;
+ break;
+ }
+
+ bool closest = dir > 0; // when growing, find closest node
+ bool selected = dir < 0; // when growing, consider only unselected nodes
+
+ for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) {
+ NodeList::iterator t = i->second->extremeNode(origin, selected, !selected, closest);
+ if (!t) continue;
+ double dist = Geom::distance(*t, *origin);
+ bool cond = closest ? (dist < extr_dist) : (dist > extr_dist);
+ if (cond) {
+ extr_dist = dist;
+ target = t;
+ }
+ }
+ } while (0);
+
+ if (!target) return;
+ if (dir > 0) {
+ _selection.insert(target.ptr());
+ } else {
+ _selection.erase(target.ptr());
+ }
+}
void MultiPathManipulator::invertSelection()
{
invokeForAll(&PathManipulator::invertSelection);
}
}
- _doneWithCleanup("Join segment");
+ _doneWithCleanup("Join segments");
}
void MultiPathManipulator::deleteSegments()
return false;
}
+/** Commit changes to XML and add undo stack entry based on the action that was done. Invoked
+ * by sub-manipulators, for example TransformHandleSet and ControlPointSelection. */
void MultiPathManipulator::_commit(CommitEvent cps)
{
gchar const *reason = NULL;
_changed.unblock();
}
+/** Get an outline color based on the shape's role (normal, mask, LPE parameter, etc.). */
guint32 MultiPathManipulator::_getOutlineColor(ShapeRole role)
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
index b66451ad31b293ee73646d0058780eac7c924511..4fbbf1b054415dd798f60c2616e843285b7e5c2a 100644 (file)
#include "forward.h"
#include "ui/tool/commit-events.h"
#include "ui/tool/manipulator.h"
+#include "ui/tool/node.h"
#include "ui/tool/node-types.h"
#include "ui/tool/shape-record.h"
/**
* Manipulator that manages multiple path manipulators active at the same time.
- * It functions like a boost::ptr_set - manipulators added via insert() are retained.
*/
class MultiPathManipulator : public PointManipulator {
public:
- MultiPathManipulator(PathSharedData const &data, sigc::connection &chg);
+ MultiPathManipulator(PathSharedData &data, sigc::connection &chg);
virtual ~MultiPathManipulator();
virtual bool event(GdkEvent *event);
bool empty() { return _mmap.empty(); }
unsigned size() { return _mmap.empty(); }
- // TODO fix this garbage!
void setItems(std::set<ShapeRecord> const &);
- //std::map<SPPath*, std::pair<Geom::Matrix, guint32> > const &items);
void clear() { _mmap.clear(); }
void cleanup();
void selectAll();
void selectArea(Geom::Rect const &area, bool take);
void shiftSelection(int dir);
- void linearGrow(int dir);
- void spatialGrow(int dir);
+ void spatialGrow(NodeList::iterator center, int dir);
void invertSelection();
void invertSelectionInSubpaths();
void deselect();
void showPathDirection(bool show);
void updateOutlineColors();
- sigc::signal<void> signal_coords_changed;
+ sigc::signal<void> signal_coords_changed; /// Emitted whenever the coordinates
+ /// shown in the status bar need updating
private:
typedef std::pair<ShapeRecord, boost::shared_ptr<PathManipulator> > MapPair;
typedef std::map<ShapeRecord, boost::shared_ptr<PathManipulator> > MapType;
guint32 _getOutlineColor(ShapeRole role);
MapType _mmap;
+public:
PathSharedData const &_path_data;
+private:
sigc::connection &_changed;
bool _show_handles;
bool _show_outline;
bool _show_path_direction;
+
+ friend class PathManipulator;
};
} // namespace UI
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index 5f792cfc74bb5fc8880ad5ef6d66f91c3bb1d343..4f6d0d5d7d994eeb0db82c13eb8e110c0306d5d5 100644 (file)
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
#include <glib/gi18n.h>
#include <2geom/transforms.h>
#include "ui/tool/event-utils.h"
+#include "ui/tool/multi-path-manipulator.h"
#include "ui/tool/node.h"
+#include "ui/tool/path-manipulator.h"
#include "display/sp-ctrlline.h"
#include "display/sp-canvas.h"
#include "display/sp-canvas-util.h"
@@ -409,37 +411,38 @@ void Node::_fixNeighbors(Geom::Point const &old_pos, Geom::Point const &new_pos)
if (_type == NODE_SMOOTH && !handle->isDegenerate()) {
handle->setDirection(other->position(), new_pos);
- /*Geom::Point handle_delta = handle->position() - position();
- Geom::Point new_delta = Geom::unit_vector(new_direction) * handle_delta.length();
- handle->setPosition(position() + new_delta);*/
}
// also update the handle on the other end of the segment
if (other->_type == NODE_SMOOTH && !other_handle->isDegenerate()) {
other_handle->setDirection(new_pos, other->position());
- /*
- Geom::Point handle_delta2 = other_handle->position() - other->position();
- Geom::Point new_delta2 = Geom::unit_vector(new_direction) * handle_delta2.length();
- other_handle->setPosition(other->position() + new_delta2);*/
}
}
void Node::_updateAutoHandles()
{
// Recompute the position of automatic handles.
- if (!_prev() || !_next()) {
+ // For endnodes, retract both handles. (It's only possible to create an end auto node
+ // through the XML editor.)
+ if (isEndNode()) {
_front.retract();
_back.retract();
return;
}
- // TODO describe in detail what the code below does
+
+ // Auto nodes automaticaly adjust their handles to give an appearance of smoothness,
+ // no matter what their surroundings are.
Geom::Point vec_next = _next()->position() - position();
Geom::Point vec_prev = _prev()->position() - position();
double len_next = vec_next.length(), len_prev = vec_prev.length();
if (len_next > 0 && len_prev > 0) {
+ // "dir" is an unit vector perpendicular to the bisector of the angle created
+ // by the previous node, this auto node and the next node.
Geom::Point dir = Geom::unit_vector((len_prev / len_next) * vec_next - vec_prev);
+ // Handle lengths are equal to 1/3 of the distance from the adjacent node.
_back.setRelativePos(-dir * (len_prev / 3));
_front.setRelativePos(dir * (len_next / 3));
} else {
+ // If any of the adjacent nodes coincides, retract both handles.
_front.retract();
_back.retract();
}
}
}
+bool Node::_eventHandler(GdkEvent *event)
+{
+ static NodeList::iterator origin;
+ static int dir;
+
+ switch (event->type)
+ {
+ case GDK_SCROLL:
+ if (event->scroll.direction == GDK_SCROLL_UP) {
+ dir = 1;
+ } else if (event->scroll.direction == GDK_SCROLL_DOWN) {
+ dir = -1;
+ } else break;
+ origin = NodeList::get_iterator(this);
+
+ if (held_control(event->scroll)) {
+ list()->_list._path_manipulator._multi_path_manipulator.spatialGrow(origin, dir);
+ } else {
+ list()->_list._path_manipulator.linearGrow(origin, dir);
+ }
+ return true;
+ default:
+ break;
+ }
+ return ControlPoint::_eventHandler(event);
+}
+
void Node::_setState(State state)
{
// change node size to match type and selection state
void Node::_draggedHandler(Geom::Point &new_pos, GdkEventMotion *event)
{
- if (!held_control(*event)) return;
- if (held_alt(*event)) {
- // with Ctrl+Alt, constrain to handle lines
- // project the new position onto a handle line that is closer
- Geom::Point origin = _last_drag_origin();
- Geom::Line line_front(origin, origin + _front.relativePos());
- Geom::Line line_back(origin, origin + _back.relativePos());
- double dist_front, dist_back;
- dist_front = Geom::distance(new_pos, line_front);
- dist_back = Geom::distance(new_pos, line_back);
- if (dist_front < dist_back) {
- new_pos = Geom::projection(new_pos, line_front);
+ if (held_control(*event)) {
+ if (held_alt(*event)) {
+ // with Ctrl+Alt, constrain to handle lines
+ // project the new position onto a handle line that is closer
+ Geom::Point origin = _last_drag_origin();
+ Geom::Line line_front(origin, origin + _front.relativePos());
+ Geom::Line line_back(origin, origin + _back.relativePos());
+ double dist_front, dist_back;
+ dist_front = Geom::distance(new_pos, line_front);
+ dist_back = Geom::distance(new_pos, line_back);
+ if (dist_front < dist_back) {
+ new_pos = Geom::projection(new_pos, line_front);
+ } else {
+ new_pos = Geom::projection(new_pos, line_back);
+ }
} else {
- new_pos = Geom::projection(new_pos, line_back);
+ // with Ctrl, constrain to axes
+ // TODO maybe add diagonals when the distance from origin is large enough?
+ Geom::Point origin = _last_drag_origin();
+ Geom::Point delta = new_pos - origin;
+ Geom::Dim2 d = (fabs(delta[Geom::X]) < fabs(delta[Geom::Y])) ? Geom::X : Geom::Y;
+ new_pos[d] = origin[d];
}
} else {
- // with Ctrl, constrain to axes
- // TODO this probably has to be separated into an AxisConstrainablePoint class
- // TODO maybe add diagonals when the distance from origin is large enough?
- Geom::Point origin = _last_drag_origin();
- Geom::Point delta = new_pos - origin;
- Geom::Dim2 d = (fabs(delta[Geom::X]) < fabs(delta[Geom::Y])) ? Geom::X : Geom::Y;
- new_pos[d] = origin[d];
+ // snapping?
}
}
return C_("Path node tip",
"<b>Shift:</b> drag out a handle, click to toggle selection");
}
- return C_("Path node statusbar tip", "<b>Shift:</b> click to toggle selection");
+ return C_("Path node tip", "<b>Shift:</b> click to toggle selection");
}
if (state_held_control(state)) {
Geom::Point dist = position() - _last_drag_origin();
GString *x = SP_PX_TO_METRIC_STRING(dist[Geom::X], _desktop->namedview->getDefaultMetric());
GString *y = SP_PX_TO_METRIC_STRING(dist[Geom::Y], _desktop->namedview->getDefaultMetric());
- Glib::ustring ret = format_tip(C_("Path node statusbar tip", "Move by %s, %s"),
+ Glib::ustring ret = format_tip(C_("Path node tip", "Move by %s, %s"),
x->str, y->str);
g_string_free(x, TRUE);
g_string_free(y, TRUE);
NodeList::iterator NodeList::erase(iterator i)
{
- // some acrobatics are required to ensure that the node is valid when deleted;
+ // some gymnastics are required to ensure that the node is valid when deleted;
// otherwise the code that updates handle visibility will break
Node *rm = static_cast<Node*>(i._node);
ListNode *rmnext = rm->next, *rmprev = rm->prev;
return i;
}
+// TODO this method is nasty and ugly!
+// converting SubpathList to an intrusive list might allow us to get rid of it
void NodeList::kill()
{
for (SubpathList::iterator i = _list.begin(); i != _list.end(); ++i) {
diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h
index 9a36642eb64cbadfbbe8059be4efc2ad568d55ae..68ad63ba9b831d065737f0d3405cfa2ea2f7a28a 100644 (file)
--- a/src/ui/tool/node.h
+++ b/src/ui/tool/node.h
namespace UI {
class PathManipulator;
+class MultiPathManipulator;
class Node;
class Handle;
static char const *node_type_to_localized_string(NodeType type);
protected:
+ virtual bool _eventHandler(GdkEvent *event);
virtual void _setState(State state);
virtual Glib::ustring _getTip(unsigned state);
virtual Glib::ustring _getDragTip(GdkEventMotion *event);
public:
typedef std::list< boost::shared_ptr<NodeList> > list_type;
- SubpathList() {}
+ SubpathList(PathManipulator &pm) : _path_manipulator(pm) {}
sigc::signal<void, Node *> signal_insert_node;
sigc::signal<void, Node *> signal_remove_node;
private:
list_type _nodelists;
+ PathManipulator &_path_manipulator;
friend class NodeList;
friend class Node;
friend class Handle;
index f247e553789d2378999e35d0b31534a96148189a..42db45321e82f13e9e3353d9dace1b96a2be4927 100644 (file)
void build_segment(Geom::PathBuilder &, Node *, Node *);
-PathManipulator::PathManipulator(PathSharedData const &data, SPPath *path,
+PathManipulator::PathManipulator(MultiPathManipulator &mpm, SPPath *path,
Geom::Matrix const &et, guint32 outline_color, Glib::ustring lpe_key)
- : PointManipulator(data.node_data.desktop, *data.node_data.selection)
- , _path_data(data)
+ : PointManipulator(mpm._path_data.node_data.desktop, *mpm._path_data.node_data.selection)
+ , _subpaths(*this)
+ , _multi_path_manipulator(mpm)
, _path(path)
, _spcurve(NULL)
, _dragpoint(new CurveDragPoint(*this))
_getGeometry();
- _outline = sp_canvas_bpath_new(_path_data.outline_group, NULL);
+ _outline = sp_canvas_bpath_new(_multi_path_manipulator._path_data.outline_group, NULL);
sp_canvas_item_hide(_outline);
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(_outline), outline_color, 1.0,
SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
}
}
+void PathManipulator::linearGrow(NodeList::iterator center, int dir)
+{
+ g_message("linearGrow unimplemented");
+}
+
/** Invert selection in the entire path. */
void PathManipulator::invertSelection()
{
}
/** Replace contiguous selections of nodes in each subpath with one node. */
-void PathManipulator::weldNodes(NodeList::iterator const &preserve_pos)
+void PathManipulator::weldNodes(NodeList::iterator preserve_pos)
{
if (!_num_selected) return;
_dragpoint->setVisible(false);
ins = new_sp;
}
- Node *n = new Node(_path_data.node_data, cur->position());
+ Node *n = new Node(_multi_path_manipulator._path_data.node_data, cur->position());
ins->insert(ins->end(), n);
cur->setType(NODE_CUSP, false);
n->back()->setRelativePos(cur->back()->relativePos());
@@ -747,7 +753,7 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d
NodeList::iterator inserted;
if (first->front()->isDegenerate() && second->back()->isDegenerate()) {
// for a line segment, insert a cusp node
- Node *n = new Node(_path_data.node_data,
+ Node *n = new Node(_multi_path_manipulator._path_data.node_data,
Geom::lerp(t, first->position(), second->position()));
n->setType(NODE_CUSP, false);
inserted = list.insert(insert_at, n);
@@ -759,7 +765,7 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d
std::vector<Geom::Point> seg1 = div.first.points(), seg2 = div.second.points();
// set new handle positions
- Node *n = new Node(_path_data.node_data, seg2[0]);
+ Node *n = new Node(_multi_path_manipulator._path_data.node_data, seg2[0]);
n->back()->setPosition(seg1[2]);
n->front()->setPosition(seg2[1]);
n->setType(NODE_SMOOTH, false);
@@ -771,6 +777,38 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d
return inserted;
}
+/** Find the node that is closest/farthest from the origin
+ * @param origin Point of reference
+ * @param search_selected Consider selected nodes
+ * @param search_unselected Consider unselected nodes
+ * @param closest If true, return closest node, if false, return farthest
+ * @return The matching node, or an empty iterator if none found
+ */
+NodeList::iterator PathManipulator::extremeNode(NodeList::iterator origin, bool search_selected,
+ bool search_unselected, bool closest)
+{
+ NodeList::iterator match;
+ double extr_dist = closest ? HUGE_VAL : -HUGE_VAL;
+ if (_num_selected == 0 && !search_unselected) return match;
+
+ for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) {
+ for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) {
+ if(j->selected()) {
+ if (!search_selected) continue;
+ } else {
+ if (!search_unselected) continue;
+ }
+ double dist = Geom::distance(*j, *origin);
+ bool cond = closest ? (dist < extr_dist) : (dist > extr_dist);
+ if (cond) {
+ match = j;
+ extr_dist = dist;
+ }
+ }
+ }
+ return match;
+}
+
/** Called by the XML observer when something else than us modifies the path. */
void PathManipulator::_externalChange(unsigned type)
{
SubpathPtr subpath(new NodeList(_subpaths));
_subpaths.push_back(subpath);
- Node *previous_node = new Node(_path_data.node_data, pit->initialPoint());
+ Node *previous_node = new Node(_multi_path_manipulator._path_data.node_data, pit->initialPoint());
subpath->push_back(previous_node);
Geom::Curve const &cseg = pit->back_closed();
bool fuse_ends = pit->closed()
/* regardless of segment type, create a new node at the end
* of this segment (unless this is the last segment of a closed path
* with a degenerate closing segment */
- current_node = new Node(_path_data.node_data, pos);
+ current_node = new Node(_multi_path_manipulator._path_data.node_data, pos);
subpath->push_back(current_node);
}
// if this is a bezier segment, move handles appropriately
index e0d8c68ca9490e9668f5dcf280c536f9b42b793d..82ce7fd5d3e560689936299f7634f49af49fe779 100644 (file)
namespace Inkscape {
namespace XML { class Node; }
+
namespace UI {
class PathManipulator;
class PathManipulatorObserver;
class CurveDragPoint;
class PathCanvasGroups;
+class MultiPathManipulator;
+class Node;
struct PathSharedData {
NodeSharedData node_data;
public:
typedef SPPath *ItemType;
- PathManipulator(PathSharedData const &data, SPPath *path, Geom::Matrix const &edit_trans,
+ PathManipulator(MultiPathManipulator &mpm, SPPath *path, Geom::Matrix const &edit_trans,
guint32 outline_color, Glib::ustring lpe_key);
~PathManipulator();
virtual bool event(GdkEvent *);
void selectAll();
void selectArea(Geom::Rect const &);
void shiftSelection(int dir);
- void linearGrow(int dir);
- void spatialGrow(int dir);
+ void linearGrow(NodeList::iterator center, int dir);
void invertSelection();
void invertSelectionInSubpaths();
void insertNodes();
- void weldNodes(NodeList::iterator const &preserve_pos = NodeList::iterator());
+ void weldNodes(NodeList::iterator preserve_pos = NodeList::iterator());
void weldSegments();
void breakNodes();
void deleteNodes(bool keep_shape = true);
void hideDragPoint();
NodeList::iterator subdivideSegment(NodeList::iterator after, double t);
+ NodeList::iterator extremeNode(NodeList::iterator origin, bool search_selected,
+ bool search_unselected, bool closest);
static bool is_item_type(void *item);
private:
double _getStrokeTolerance();
SubpathList _subpaths;
- PathSharedData const &_path_data;
+ MultiPathManipulator &_multi_path_manipulator;
SPPath *_path;
SPCurve *_spcurve; // in item coordinates
SPCanvasItem *_outline;
friend class PathManipulatorObserver;
friend class CurveDragPoint;
+ friend class Node;
};
} // namespace UI
index f3e2847e4be1da5a1079dee4519fe4db8bf1a62b..d6181dbf4db69b54a56efdcbb114ec343d8a627e 100644 (file)
#include "ui/tool/transform-handle-set.h"
// FIXME BRAIN DAMAGE WARNING: this is a global variable in select-context.cpp
-// Should be moved to a location where it can be accessed globally
+// It should be moved to a header
extern GdkPixbuf *handles[];
GType sp_select_context_get_type();