summaryrefslogtreecommitdiffstats
path: root/src/ui
diff options
context:
space:
mode:
authorJon A. Cruz <jon@joncruz.org>2012-05-17 02:33:16 +0000
committerJon A. Cruz <jon@joncruz.org>2012-05-17 02:33:16 +0000
commite9412c187da3f62f01bc5acb6190af2d5a395ccb (patch)
tree4d6d98646a87c82dc1cc631d88875ca0d63c3fcf /src/ui
parentFixed warning with printf format. Also corrected inproper type that resulted ... (diff)
downloadinkscape-e9412c187da3f62f01bc5acb6190af2d5a395ccb.tar.gz
inkscape-e9412c187da3f62f01bc5acb6190af2d5a395ccb.zip
Corrected protected type access (comments were incorrect).
Unified color set types; fixed uninitialized member; Switched colorsets to references; Added const correctness. (bzr r11373)
Diffstat (limited to 'src/ui')
-rw-r--r--src/ui/tool/control-point-selection.cpp7
-rw-r--r--src/ui/tool/control-point.cpp234
-rw-r--r--src/ui/tool/control-point.h275
-rw-r--r--src/ui/tool/curve-drag-point.cpp27
-rw-r--r--src/ui/tool/curve-drag-point.h21
-rw-r--r--src/ui/tool/node.cpp167
-rw-r--r--src/ui/tool/node.h158
-rw-r--r--src/ui/tool/selectable-control-point.cpp72
-rw-r--r--src/ui/tool/selectable-control-point.h47
-rw-r--r--src/ui/tool/selector.cpp19
-rw-r--r--src/ui/tool/transform-handle-set.cpp121
-rw-r--r--src/ui/tool/transform-handle-set.h33
12 files changed, 729 insertions, 452 deletions
diff --git a/src/ui/tool/control-point-selection.cpp b/src/ui/tool/control-point-selection.cpp
index 1c66b91b6..58db09b56 100644
--- a/src/ui/tool/control-point-selection.cpp
+++ b/src/ui/tool/control-point-selection.cpp
@@ -268,7 +268,9 @@ void ControlPointSelection::toggleTransformHandlesMode()
{
if (_handles->mode() == TransformHandleSet::MODE_SCALE) {
_handles->setMode(TransformHandleSet::MODE_ROTATE_SKEW);
- if (size() == 1) _handles->rotationCenter().setVisible(false);
+ if (size() == 1) {
+ _handles->rotationCenter().setVisible(false);
+ }
} else {
_handles->setMode(TransformHandleSet::MODE_SCALE);
}
@@ -383,8 +385,9 @@ void ControlPointSelection::_pointChanged(SelectableControlPoint *p, bool select
{
_updateBounds();
_updateTransformHandles(false);
- if (_bounds)
+ if (_bounds) {
_handles->rotationCenter().move(_bounds->midpoint());
+ }
signal_point_changed.emit(p, selected);
}
diff --git a/src/ui/tool/control-point.cpp b/src/ui/tool/control-point.cpp
index 68749cdff..a10db03c7 100644
--- a/src/ui/tool/control-point.cpp
+++ b/src/ui/tool/control-point.cpp
@@ -1,7 +1,3 @@
-/**
- * @file
- * Desktop-bound visual control object - implementation.
- */
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
* Jon A. Cruz <jon@joncruz.org>
@@ -34,80 +30,26 @@
namespace Inkscape {
namespace UI {
-// class and member documentation goes here...
-
-/**
- * @class ControlPoint
- * Draggable point, the workhorse of on-canvas editing.
- *
- * Control points (formerly known as knots) are graphical representations of some significant
- * point in the drawing. The drawing can be changed by dragging the point and the things that are
- * attached to it with the mouse. Example things that could be edited with draggable points
- * are gradient stops, the place where text is attached to a path, text kerns, nodes and handles
- * in a path, and many more.
- *
- * @par Control point event handlers
- * @par
- * The control point has several virtual methods which allow you to react to things that
- * happen to it. The most important ones are the grabbed, dragged, ungrabbed and moved functions.
- * When a drag happens, the order of calls is as follows:
- * - <tt>grabbed()</tt>
- * - <tt>dragged()</tt>
- * - <tt>dragged()</tt>
- * - <tt>dragged()</tt>
- * - ...
- * - <tt>dragged()</tt>
- * - <tt>ungrabbed()</tt>
- *
- * The control point can also respond to clicks and double clicks. On a double click,
- * clicked() is called, followed by doubleclicked(). When deriving from SelectableControlPoint,
- * you need to manually call the superclass version at the appropriate point in your handler.
- *
- * @par Which method to override?
- * @par
- * You might wonder which hook to use when you want to do things when the point is relocated.
- * Here are some tips:
- * - If the point is used to edit an object, override the move() method.
- * - If the point can usually be dragged wherever you like but can optionally be constrained
- * to axes or the like, add a handler for <tt>signal_dragged</tt> that modifies its new
- * position argument.
- * - If the point has additional canvas items tied to it (like handle lines), override
- * the setPosition() method.
- */
-
-/**
- * @enum ControlPoint::State
- * Enumeration representing the possible states of the control point, used to determine
- * its appearance.
- * @var ControlPoint::STATE_NORMAL
- * Normal state
- * @var ControlPoint::STATE_MOUSEOVER
- * Mouse is hovering over the control point
- * @var ControlPoint::STATE_CLICKED
- * First mouse button pressed over the control point
- */
// Default colors for control points
-static ControlPoint::ColorSet default_color_set = {
+ControlPoint::ColorSet ControlPoint::_default_color_set = {
{0xffffff00, 0x01000000}, // normal fill, stroke
{0xff0000ff, 0x01000000}, // mouseover fill, stroke
- {0x0000ffff, 0x01000000} // clicked fill, stroke
+ {0x0000ffff, 0x01000000}, // clicked fill, stroke
+ //
+ {0x0000ffff, 0x000000ff}, // normal fill, stroke when selected
+ {0xff000000, 0x000000ff}, // mouseover fill, stroke when selected
+ {0xff000000, 0x000000ff} // clicked fill, stroke when selected
};
-/** Holds the currently mouseovered control point. */
ControlPoint *ControlPoint::mouseovered_point = 0;
-/** Emitted when the mouseovered point changes. The parameter is the new mouseovered point.
- * When a point ceases to be mouseovered, the parameter will be NULL. */
sigc::signal<void, ControlPoint*> ControlPoint::signal_mouseover_change;
-/** Stores the window point over which the cursor was during the last mouse button press */
Geom::Point ControlPoint::_drag_event_origin(Geom::infinity(), Geom::infinity());
-/** Stores the desktop point from which the last drag was initiated */
Geom::Point ControlPoint::_drag_origin(Geom::infinity(), Geom::infinity());
-/** Events which should be captured when a handle is being dragged. */
int const ControlPoint::_grab_event_mask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_KEY_PRESS_MASK |
GDK_KEY_RELEASE_MASK);
@@ -115,68 +57,50 @@ int const ControlPoint::_grab_event_mask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_R
bool ControlPoint::_drag_initiated = false;
bool ControlPoint::_event_grab = false;
-/** A color set which you can use to create an invisible control that can still receive events.
- * @relates ControlPoint */
-ControlPoint::ColorSet invisible_cset = {
+ControlPoint::ColorSet ControlPoint::invisible_cset = {
+ {0x00000000, 0x00000000},
+ {0x00000000, 0x00000000},
+ {0x00000000, 0x00000000},
{0x00000000, 0x00000000},
{0x00000000, 0x00000000},
{0x00000000, 0x00000000}
};
-/**
- * Create a regular control point.
- * Derive to have constructors with a reasonable number of parameters.
- *
- * @param d Desktop for this control
- * @param initial_pos Initial position of the control point in desktop coordinates
- * @param anchor Where is the control point rendered relative to its desktop coordinates
- * @param shape Shape of the control point: square, diamond, circle...
- * @param size Pixel size of the visual representation
- * @param cset Colors of the point
- * @param group The canvas group the point's canvas item should be created in
- */
-ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos,
- SPAnchorType anchor, SPCtrlShapeType shape,
- unsigned int size, ColorSet *cset, SPCanvasGroup *group)
- : _desktop (d)
- , _canvas_item (NULL)
- , _cset (cset ? cset : &default_color_set)
- , _state (STATE_NORMAL)
- , _position (initial_pos)
+ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAnchorType anchor,
+ SPCtrlShapeType shape, unsigned int size,
+ ColorSet const &cset, SPCanvasGroup *group) :
+ _desktop(d),
+ _canvas_item(NULL),
+ _cset(cset),
+ _state(STATE_NORMAL),
+ _position(initial_pos),
+ _lurking(false)
{
_canvas_item = sp_canvas_item_new(
group ? group : sp_desktop_controls (_desktop), SP_TYPE_CTRL,
"anchor", (SPAnchorType) anchor, "size", (gdouble) size, "shape", shape,
- "filled", TRUE, "fill_color", _cset->normal.fill,
- "stroked", TRUE, "stroke_color", _cset->normal.stroke,
+ "filled", TRUE, "fill_color", _cset.normal.fill,
+ "stroked", TRUE, "stroke_color", _cset.normal.stroke,
"mode", SP_CTRL_MODE_XOR, NULL);
_commonInit();
}
-/**
- * Create a control point with a pixbuf-based visual representation.
- *
- * @param d Desktop for this control
- * @param initial_pos Initial position of the control point in desktop coordinates
- * @param anchor Where is the control point rendered relative to its desktop coordinates
- * @param pixbuf Pixbuf to be used as the visual representation
- * @param cset Colors of the point
- * @param group The canvas group the point's canvas item should be created in
- */
-ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos,
- SPAnchorType anchor, Glib::RefPtr<Gdk::Pixbuf> pixbuf,
- ColorSet *cset, SPCanvasGroup *group)
- : _desktop (d)
- , _canvas_item (NULL)
- , _cset(cset ? cset : &default_color_set)
- , _position (initial_pos)
+ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAnchorType anchor,
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf,
+ ColorSet const &cset, SPCanvasGroup *group) :
+ _desktop(d),
+ _canvas_item(NULL),
+ _cset(cset),
+ _state(STATE_NORMAL),
+ _position(initial_pos),
+ _lurking(false)
{
_canvas_item = sp_canvas_item_new(
group ? group : sp_desktop_controls(_desktop), SP_TYPE_CTRL,
"anchor", (SPAnchorType) anchor, "size", (gdouble) pixbuf->get_width(),
"shape", SP_CTRL_SHAPE_BITMAP, "pixbuf", pixbuf->gobj(),
- "filled", TRUE, "fill_color", _cset->normal.fill,
- "stroked", TRUE, "stroke_color", _cset->normal.stroke,
+ "filled", TRUE, "fill_color", _cset.normal.fill,
+ "stroked", TRUE, "stroke_color", _cset.normal.stroke,
"mode", SP_CTRL_MODE_XOR, NULL);
_commonInit();
}
@@ -200,29 +124,17 @@ void ControlPoint::_commonInit()
G_CALLBACK(_event_handler), this);
}
-/** Relocate the control point without side effects.
- * Overload this method only if there is an additional graphical representation
- * that must be updated (like the lines that connect handles to nodes). If you override it,
- * you must also call the superclass implementation of the method.
- * @todo Investigate whether this method should be protected */
void ControlPoint::setPosition(Geom::Point const &pos)
{
_position = pos;
SP_CTRL(_canvas_item)->moveto(pos);
}
-/** Move the control point to new position with side effects.
- * This is called after each drag. Override this method if only some positions make sense
- * for a control point (like a point that must always be on a path and can't modify it),
- * or when moving a control point changes the positions of other points. */
void ControlPoint::move(Geom::Point const &pos)
{
setPosition(pos);
}
-/** Apply an arbitrary affine transformation to a control point. This is used
- * by ControlPointSelection, and is important for things like nodes with handles.
- * The default implementation simply moves the point according to the transform. */
void ControlPoint::transform(Geom::Affine const &m) {
move(position() * m);
}
@@ -232,9 +144,6 @@ bool ControlPoint::visible() const
return sp_canvas_item_is_visible(_canvas_item);
}
-/** Set the visibility of the control point. An invisible point is not drawn on the canvas
- * and cannot receive any events. If you want to have an invisible point that can respond
- * to events, use <tt>invisible_cset</tt> as its color set. */
void ControlPoint::setVisible(bool v)
{
if (v) sp_canvas_item_show(_canvas_item);
@@ -559,7 +468,9 @@ bool ControlPoint::_updateTip(unsigned state)
bool ControlPoint::_updateDragTip(GdkEventMotion *event)
{
- if (!_hasDragTips()) return false;
+ if (!_hasDragTips()) {
+ return false;
+ }
Glib::ustring tip = _getDragTip(event);
if (!tip.empty()) {
_desktop->event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE,
@@ -581,16 +492,6 @@ void ControlPoint::_clearMouseover()
}
}
-/** Transfer the grab to another point. This method allows one to create a draggable point
- * that should be dragged instead of the one that received the grabbed signal.
- * This is used to implement dragging out handles in the new node tool, for example.
- *
- * This method will NOT emit the ungrab signal of @c prev_point, because this would complicate
- * using it with selectable control points. If you use this method while dragging, you must emit
- * the ungrab signal yourself.
- *
- * Note that this will break horribly if you try to transfer grab between points in different
- * desktops, which doesn't make much sense anyway. */
void ControlPoint::transferGrab(ControlPoint *prev_point, GdkEventMotion *event)
{
if (!_event_grab) return;
@@ -608,42 +509,73 @@ void ControlPoint::transferGrab(ControlPoint *prev_point, GdkEventMotion *event)
_setMouseover(this, event->state);
}
-/**
- * Change the state of the knot.
- * Alters the appearance of the knot to match one of the states: normal, mouseover
- * or clicked.
- */
void ControlPoint::_setState(State state)
{
ColorEntry current = {0, 0};
+ ColorSet const &activeCset = (_isLurking()) ? invisible_cset : _cset;
switch(state) {
- case STATE_NORMAL:
- current = _cset->normal; break;
- case STATE_MOUSEOVER:
- current = _cset->mouseover; break;
- case STATE_CLICKED:
- current = _cset->clicked; break;
+ case STATE_NORMAL:
+ current = activeCset.normal;
+ break;
+ case STATE_MOUSEOVER:
+ current = activeCset.mouseover;
+ break;
+ case STATE_CLICKED:
+ current = activeCset.clicked;
+ break;
};
_setColors(current);
_state = state;
}
+
void ControlPoint::_setColors(ColorEntry colors)
{
g_object_set(_canvas_item, "fill_color", colors.fill, "stroke_color", colors.stroke, NULL);
}
+bool ControlPoint::_isLurking()
+{
+ return _lurking;
+}
+
+void ControlPoint::_setLurking(bool lurking)
+{
+ if (lurking != _lurking) {
+ _lurking = lurking;
+ _setState(_state); // TODO refactor out common part
+ }
+}
+
+
bool ControlPoint::_is_drag_cancelled(GdkEventMotion *event)
{
return !event || event->x_root == -1;
}
// dummy implementations for handlers
-// they are here to avoid unused param warnings
-bool ControlPoint::grabbed(GdkEventMotion *) { return false; }
-void ControlPoint::dragged(Geom::Point &, GdkEventMotion *) {}
-void ControlPoint::ungrabbed(GdkEventButton *) {}
-bool ControlPoint::clicked(GdkEventButton *) { return false; }
-bool ControlPoint::doubleclicked(GdkEventButton *) { return false; }
+
+bool ControlPoint::grabbed(GdkEventMotion * /*event*/)
+{
+ return false;
+}
+
+void ControlPoint::dragged(Geom::Point &/*new_pos*/, GdkEventMotion * /*event*/)
+{
+}
+
+void ControlPoint::ungrabbed(GdkEventButton * /*event*/)
+{
+}
+
+bool ControlPoint::clicked(GdkEventButton * /*event*/)
+{
+ return false;
+}
+
+bool ControlPoint::doubleclicked(GdkEventButton * /*event*/)
+{
+ return false;
+}
} // namespace UI
} // namespace Inkscape
diff --git a/src/ui/tool/control-point.h b/src/ui/tool/control-point.h
index 8d1b778a7..621c1134a 100644
--- a/src/ui/tool/control-point.h
+++ b/src/ui/tool/control-point.h
@@ -1,9 +1,8 @@
-/** @file
- * Desktop-bound visual control object
- */
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
+ * Jon A. Cruz <jon@joncruz.org>
*
+ * Copyright (C) 2012 Authors
* Copyright (C) 2009 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
*/
@@ -27,49 +26,128 @@ class SPEventContext;
namespace Inkscape {
namespace UI {
-// most of the documentation is in the .cpp file
-
+/**
+ * Draggable point, the workhorse of on-canvas editing.
+ *
+ * Control points (formerly known as knots) are graphical representations of some significant
+ * point in the drawing. The drawing can be changed by dragging the point and the things that are
+ * attached to it with the mouse. Example things that could be edited with draggable points
+ * are gradient stops, the place where text is attached to a path, text kerns, nodes and handles
+ * in a path, and many more.
+ *
+ * @par Control point event handlers
+ * @par
+ * The control point has several virtual methods which allow you to react to things that
+ * happen to it. The most important ones are the grabbed, dragged, ungrabbed and moved functions.
+ * When a drag happens, the order of calls is as follows:
+ * - <tt>grabbed()</tt>
+ * - <tt>dragged()</tt>
+ * - <tt>dragged()</tt>
+ * - <tt>dragged()</tt>
+ * - ...
+ * - <tt>dragged()</tt>
+ * - <tt>ungrabbed()</tt>
+ *
+ * The control point can also respond to clicks and double clicks. On a double click,
+ * clicked() is called, followed by doubleclicked(). When deriving from SelectableControlPoint,
+ * you need to manually call the superclass version at the appropriate point in your handler.
+ *
+ * @par Which method to override?
+ * @par
+ * You might wonder which hook to use when you want to do things when the point is relocated.
+ * Here are some tips:
+ * - If the point is used to edit an object, override the move() method.
+ * - If the point can usually be dragged wherever you like but can optionally be constrained
+ * to axes or the like, add a handler for <tt>signal_dragged</tt> that modifies its new
+ * position argument.
+ * - If the point has additional canvas items tied to it (like handle lines), override
+ * the setPosition() method.
+ */
class ControlPoint : boost::noncopyable, public sigc::trackable {
public:
typedef Inkscape::Util::ReverseInterruptible RInt;
typedef Inkscape::Util::Interruptible Int;
- // these have to be public, because GCC doesn't allow protected types in constructors,
- // even if the constructors are protected themselves.
- struct ColorEntry {
- guint32 fill;
- guint32 stroke;
- };
- struct ColorSet {
- ColorEntry normal;
- ColorEntry mouseover;
- ColorEntry clicked;
- };
+
+ /**
+ * Enumeration representing the possible states of the control point, used to determine
+ * its appearance.
+ *
+ * @todo resolve this to be in sync with the five standard GTK states.
+ */
enum State {
+ /** Normal state. */
STATE_NORMAL,
+
+ /** Mouse is hovering over the control point. */
STATE_MOUSEOVER,
+
+ /** First mouse button pressed over the control point. */
STATE_CLICKED
};
+ /**
+ * Destructor
+ */
virtual ~ControlPoint();
/// @name Adjust the position of the control point
/// @{
/** Current position of the control point. */
Geom::Point const &position() const { return _position; }
+
operator Geom::Point const &() { return _position; }
+
+ /**
+ * Move the control point to new position with side effects.
+ * This is called after each drag. Override this method if only some positions make sense
+ * for a control point (like a point that must always be on a path and can't modify it),
+ * or when moving a control point changes the positions of other points.
+ */
virtual void move(Geom::Point const &pos);
+
+ /**
+ * Relocate the control point without side effects.
+ * Overload this method only if there is an additional graphical representation
+ * that must be updated (like the lines that connect handles to nodes). If you override it,
+ * you must also call the superclass implementation of the method.
+ * @todo Investigate whether this method should be protected
+ */
virtual void setPosition(Geom::Point const &pos);
+
+ /**
+ * Apply an arbitrary affine transformation to a control point. This is used
+ * by ControlPointSelection, and is important for things like nodes with handles.
+ * The default implementation simply moves the point according to the transform.
+ */
virtual void transform(Geom::Affine const &m);
/// @}
/// @name Toggle the point's visibility
/// @{
bool visible() const;
+
+ /**
+ * Set the visibility of the control point. An invisible point is not drawn on the canvas
+ * and cannot receive any events. If you want to have an invisible point that can respond
+ * to events, use <tt>invisible_cset</tt> as its color set.
+ */
virtual void setVisible(bool v);
/// @}
/// @name Transfer grab from another event handler
/// @{
+ /**
+ * Transfer the grab to another point. This method allows one to create a draggable point
+ * that should be dragged instead of the one that received the grabbed signal.
+ * This is used to implement dragging out handles in the new node tool, for example.
+ *
+ * This method will NOT emit the ungrab signal of @c prev_point, because this would complicate
+ * using it with selectable control points. If you use this method while dragging, you must emit
+ * the ungrab signal yourself.
+ *
+ * Note that this will break horribly if you try to transfer grab between points in different
+ * desktops, which doesn't make much sense anyway.
+ */
void transferGrab(ControlPoint *from, GdkEventMotion *event);
/// @}
@@ -84,109 +162,232 @@ public:
/// @name Inspect the state of the control point
/// @{
- State state() { return _state; }
- bool mouseovered() { return this == mouseovered_point; }
+ State state() const { return _state; }
+
+ bool mouseovered() const { return this == mouseovered_point; }
/// @}
+ /** Holds the currently mouseovered control point. */
static ControlPoint *mouseovered_point;
+
+ /**
+ * Emitted when the mouseovered point changes. The parameter is the new mouseovered point.
+ * When a point ceases to be mouseovered, the parameter will be NULL.
+ */
static sigc::signal<void, ControlPoint*> signal_mouseover_change;
+
static Glib::ustring format_tip(char const *format, ...) G_GNUC_PRINTF(1,2);
// temporarily public, until snap delay is refactored a little
virtual bool _eventHandler(SPEventContext *event_context, GdkEvent *event);
protected:
+
+ struct ColorEntry {
+ guint32 fill;
+ guint32 stroke;
+ };
+
+ /**
+ * Color entries for each possible state.
+ * @todo resolve this to be in sync with the five standard GTK states.
+ */
+ struct ColorSet {
+ ColorEntry normal;
+ ColorEntry mouseover;
+ ColorEntry clicked;
+ ColorEntry selected_normal;
+ ColorEntry selected_mouseover;
+ ColorEntry selected_clicked;
+ };
+
+ /**
+ * A color set which you can use to create an invisible control that can still receive events.
+ */
+ static ColorSet invisible_cset;
+
+ /**
+ * Create a regular control point.
+ * Derive to have constructors with a reasonable number of parameters.
+ *
+ * @param d Desktop for this control
+ * @param initial_pos Initial position of the control point in desktop coordinates
+ * @param anchor Where is the control point rendered relative to its desktop coordinates
+ * @param shape Shape of the control point: square, diamond, circle...
+ * @param size Pixel size of the visual representation
+ * @param cset Colors of the point
+ * @param group The canvas group the point's canvas item should be created in
+ */
ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAnchorType anchor,
- SPCtrlShapeType shape, unsigned int size, ColorSet *cset = 0, SPCanvasGroup *group = 0);
+ SPCtrlShapeType shape, unsigned int size,
+ ColorSet const &cset = _default_color_set, SPCanvasGroup *group = 0);
+
+ /**
+ * Create a control point with a pixbuf-based visual representation.
+ *
+ * @param d Desktop for this control
+ * @param initial_pos Initial position of the control point in desktop coordinates
+ * @param anchor Where is the control point rendered relative to its desktop coordinates
+ * @param pixbuf Pixbuf to be used as the visual representation
+ * @param cset Colors of the point
+ * @param group The canvas group the point's canvas item should be created in
+ */
ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAnchorType anchor,
- Glib::RefPtr<Gdk::Pixbuf> pixbuf, ColorSet *cset = 0, SPCanvasGroup *group = 0);
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf,
+ ColorSet const &cset = _default_color_set, SPCanvasGroup *group = 0);
/// @name Handle control point events in subclasses
/// @{
/**
* Called when the user moves the point beyond the drag tolerance with the first button held
- * down. Return true if you called transferGrab() during this method.
- * @param event Motion event when drag tolerance was exceeded */
+ * down.
+ *
+ * @param event Motion event when drag tolerance was exceeded.
+ * @return true if you called transferGrab() during this method.
+ */
virtual bool grabbed(GdkEventMotion *event);
+
/**
* Called while dragging, but before moving the knot to new position.
+ *
* @param pos Old position, always equal to position()
* @param new_pos New position (after drag). This is passed as a non-const reference,
* so you can change it from the handler - that's how constrained dragging is implemented.
- * @param event Motion event */
+ * @param event Motion event.
+ */
virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event);
+
/**
- * @var ControlPoint::signal_ungrabbed
- * Emitted when the control point finishes a drag.
+ * Called when the control point finishes a drag.
+ *
* @param event Button release event
*/
virtual void ungrabbed(GdkEventButton *event);
+
/**
- * Called when the control point is clicked, at mouse button release. Your override should
- * return true if the click had some effect. If it did nothing, return false. Improperly
- * implementing this method can cause the default context menu not to appear when a control
+ * Called when the control point is clicked, at mouse button release.
+ * Improperly implementing this method can cause the default context menu not to appear when a control
* point is right-clicked.
- * @param event Button release event */
+ *
+ * @param event Button release event
+ * @return true if the click had some effect, false if it did nothing.
+ */
virtual bool clicked(GdkEventButton *event);
+
/**
* Called when the control point is doubleclicked, at mouse button release.
- * @param event Button release event */
- virtual bool doubleclicked(GdkEventButton *);
+ *
+ * @param event Button release event
+ */
+ virtual bool doubleclicked(GdkEventButton *event);
/// @}
/// @name Manipulate the control point's appearance in subclasses
/// @{
+
+ /**
+ * Change the state of the knot.
+ * Alters the appearance of the knot to match one of the states: normal, mouseover
+ * or clicked.
+ */
virtual void _setState(State state);
+
void _setColors(ColorEntry c);
unsigned int _size() const;
+
SPCtrlShapeType _shape() const;
+
SPAnchorType _anchor() const;
+
Glib::RefPtr<Gdk::Pixbuf> _pixbuf();
void _setSize(unsigned int size);
+
void _setShape(SPCtrlShapeType shape);
+
void _setAnchor(SPAnchorType anchor);
+
void _setPixbuf(Glib::RefPtr<Gdk::Pixbuf>);
+
+ /**
+ * Determins if the control point is not visible yet still reacting to events.
+ *
+ * @return true if non-visible, false otherwise.
+ */
+ bool _isLurking();
+
+ /**
+ * Sets the control point to be non-visible yet still reacting to events.
+ *
+ * @param lurking true to make non-visible, false otherwise.
+ */
+ void _setLurking(bool lurking);
+
/// @}
- virtual Glib::ustring _getTip(unsigned /*state*/) { return ""; }
- virtual Glib::ustring _getDragTip(GdkEventMotion */*event*/) { return ""; }
- virtual bool _hasDragTips() { return false; }
+ virtual Glib::ustring _getTip(unsigned /*state*/) const { return ""; }
+
+ virtual Glib::ustring _getDragTip(GdkEventMotion */*event*/) const { return ""; }
+
+ virtual bool _hasDragTips() const { return false; }
SPDesktop *const _desktop; ///< The desktop this control point resides on.
+
SPCanvasItem * _canvas_item; ///< Visual representation of the control point.
- ColorSet *_cset; ///< Colors used to represent the point
+
+ ColorSet const &_cset; ///< Colors used to represent the point
+
State _state;
static Geom::Point const &_last_click_event_point() { return _drag_event_origin; }
+
static Geom::Point const &_last_drag_origin() { return _drag_origin; }
+
static bool _is_drag_cancelled(GdkEventMotion *event);
+
+ /** Events which should be captured when a handle is being dragged. */
static int const _grab_event_mask;
private:
+
ControlPoint(ControlPoint const &other);
+
void operator=(ControlPoint const &other);
static int _event_handler(SPCanvasItem *item, GdkEvent *event, ControlPoint *point);
+
static void _setMouseover(ControlPoint *, unsigned state);
+
static void _clearMouseover();
+
bool _updateTip(unsigned state);
+
bool _updateDragTip(GdkEventMotion *event);
+
void _setDefaultColors();
+
void _commonInit();
Geom::Point _position; ///< Current position in desktop coordinates
+
gulong _event_handler_connection;
+ bool _lurking;
+
+ static ColorSet _default_color_set;
+
+ /** Stores the window point over which the cursor was during the last mouse button press. */
static Geom::Point _drag_event_origin;
+
+ /** Stores the desktop point from which the last drag was initiated. */
static Geom::Point _drag_origin;
+
static bool _event_grab;
+
static bool _drag_initiated;
};
-extern ControlPoint::ColorSet invisible_cset;
-
} // namespace UI
} // namespace Inkscape
diff --git a/src/ui/tool/curve-drag-point.cpp b/src/ui/tool/curve-drag-point.cpp
index 8754681df..19b0e3b84 100644
--- a/src/ui/tool/curve-drag-point.cpp
+++ b/src/ui/tool/curve-drag-point.cpp
@@ -1,8 +1,6 @@
-/** @file
- * Control point that is dragged during path drag
- */
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2009 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -21,26 +19,15 @@
namespace Inkscape {
namespace UI {
-/**
- * @class CurveDragPoint
- * An invisible point used to drag curves. This point is used by PathManipulator to allow editing
- * of path segments by dragging them. It is defined in a separate file so that the node tool
- * can check if the mouseovered control point is a curve drag point and update the cursor
- * accordingly, without the need to drag in the full PathManipulator header.
- */
-
-// This point should be invisible to the user - use the invisible_cset from control-point.h
-// TODO make some methods from path-manipulator.cpp public so that this point doesn't have
-// to be declared as a friend
bool CurveDragPoint::_drags_stroke = false;
bool CurveDragPoint::_segment_was_degenerate = false;
-CurveDragPoint::CurveDragPoint(PathManipulator &pm)
- : ControlPoint(pm._multi_path_manipulator._path_data.node_data.desktop, Geom::Point(),
- SP_ANCHOR_CENTER, SP_CTRL_SHAPE_CIRCLE, 1.0, &invisible_cset,
- pm._multi_path_manipulator._path_data.dragpoint_group)
- , _pm(pm)
+CurveDragPoint::CurveDragPoint(PathManipulator &pm) :
+ ControlPoint(pm._multi_path_manipulator._path_data.node_data.desktop, Geom::Point(), SP_ANCHOR_CENTER,
+ SP_CTRL_SHAPE_CIRCLE, 1.0,
+ invisible_cset, pm._multi_path_manipulator._path_data.dragpoint_group),
+ _pm(pm)
{
setVisible(false);
}
@@ -170,7 +157,7 @@ void CurveDragPoint::_insertNode(bool take_selection)
_pm._commit(_("Add node"));
}
-Glib::ustring CurveDragPoint::_getTip(unsigned state)
+Glib::ustring CurveDragPoint::_getTip(unsigned state) const
{
if (_pm.empty()) return "";
if (!first || !first.next()) return "";
diff --git a/src/ui/tool/curve-drag-point.h b/src/ui/tool/curve-drag-point.h
index 939047634..73e4cd969 100644
--- a/src/ui/tool/curve-drag-point.h
+++ b/src/ui/tool/curve-drag-point.h
@@ -1,8 +1,6 @@
-/** @file
- * Control point that is dragged during path drag
- */
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2009 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -21,15 +19,27 @@ namespace UI {
class PathManipulator;
struct PathSharedData;
+// This point should be invisible to the user - use the invisible_cset from control-point.h
+// TODO make some methods from path-manipulator.cpp public so that this point doesn't have
+// to be declared as a friend
+/**
+ * An invisible point used to drag curves. This point is used by PathManipulator to allow editing
+ * of path segments by dragging them. It is defined in a separate file so that the node tool
+ * can check if the mouseovered control point is a curve drag point and update the cursor
+ * accordingly, without the need to drag in the full PathManipulator header.
+ */
class CurveDragPoint : public ControlPoint {
public:
+
CurveDragPoint(PathManipulator &pm);
void setSize(double sz) { _setSize(sz); }
void setTimeValue(double t) { _t = t; }
void setIterator(NodeList::iterator i) { first = i; }
virtual bool _eventHandler(SPEventContext *event_context, GdkEvent *event);
+
protected:
- virtual Glib::ustring _getTip(unsigned state);
+
+ virtual Glib::ustring _getTip(unsigned state) const;
virtual void dragged(Geom::Point &, GdkEventMotion *);
virtual bool grabbed(GdkEventMotion *);
virtual void ungrabbed(GdkEventButton *);
@@ -37,10 +47,13 @@ protected:
virtual bool doubleclicked(GdkEventButton *);
private:
+
void _insertNode(bool take_selection);
+
double _t;
PathManipulator &_pm;
NodeList::iterator first;
+
static bool _drags_stroke;
static bool _segment_was_degenerate;
static Geom::Point _stroke_drag_origin;
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index ad22d95e6..1a26b5d55 100644
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
@@ -1,7 +1,3 @@
-/**
- * @file
- * Editable node - implementation.
- */
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
* Jon A. Cruz <jon@joncruz.org>
@@ -42,18 +38,21 @@
namespace Inkscape {
namespace UI {
-static SelectableControlPoint::ColorSet node_colors = {
- {
- {0xbfbfbf00, 0x000000ff}, // normal fill, stroke
- {0xff000000, 0x000000ff}, // mouseover fill, stroke
- {0xff000000, 0x000000ff} // clicked fill, stroke
- },
+ControlPoint::ColorSet Node::node_colors = {
+ {0xbfbfbf00, 0x000000ff}, // normal fill, stroke
+ {0xff000000, 0x000000ff}, // mouseover fill, stroke
+ {0xff000000, 0x000000ff}, // clicked fill, stroke
+ //
{0x0000ffff, 0x000000ff}, // normal fill, stroke when selected
{0xff000000, 0x000000ff}, // mouseover fill, stroke when selected
{0xff000000, 0x000000ff} // clicked fill, stroke when selected
};
-static ControlPoint::ColorSet handle_colors = {
+ControlPoint::ColorSet Handle::_handle_colors = {
+ {0xffffffff, 0x000000ff}, // normal fill, stroke
+ {0xff000000, 0x000000ff}, // mouseover fill, stroke
+ {0xff000000, 0x000000ff}, // clicked fill, stroke
+ //
{0xffffffff, 0x000000ff}, // normal fill, stroke
{0xff000000, 0x000000ff}, // mouseover fill, stroke
{0xff000000, 0x000000ff} // clicked fill, stroke
@@ -76,24 +75,20 @@ static Geom::Point direction(Geom::Point const &first, Geom::Point const &second
return Geom::unit_vector(second - first);
}
-/**
- * Control point of a cubic Bezier curve in a path.
- *
- * Handle keeps the node type invariant only for the opposite handle of the same node.
- * Keeping the invariant on node moves is left to the %Node class.
- */
Geom::Point Handle::_saved_other_pos(0, 0);
+
double Handle::_saved_length = 0.0;
+
bool Handle::_drag_out = false;
-Handle::Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent)
- : ControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER, SP_CTRL_SHAPE_CIRCLE, 7.0,
- &handle_colors, data.handle_group)
- , _parent(parent)
- , _degenerate(true)
+Handle::Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent) :
+ ControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER,
+ SP_CTRL_SHAPE_CIRCLE, 7.0,
+ _handle_colors, data.handle_group),
+ _parent(parent),
+ _handle_line(ControlManager::getManager().createControlLine(data.handle_line_group)),
+ _degenerate(true)
{
- _cset = &handle_colors;
- _handle_line = ControlManager::getManager().createControlLine(data.handle_line_group);
setVisible(false);
}
@@ -389,10 +384,18 @@ bool Handle::clicked(GdkEventButton *event)
return true;
}
+Handle const *Handle::other() const
+{
+ return const_cast<Handle *>(this)->other();
+}
+
Handle *Handle::other()
{
- if (this == &_parent->_front) return &_parent->_back;
- return &_parent->_front;
+ if (this == &_parent->_front) {
+ return &_parent->_back;
+ } else {
+ return &_parent->_front;
+ }
}
static double snap_increment_degrees() {
@@ -401,7 +404,7 @@ static double snap_increment_degrees() {
return 180.0 / snaps;
}
-Glib::ustring Handle::_getTip(unsigned state)
+Glib::ustring Handle::_getTip(unsigned state) const
{
char const *more;
bool can_shift_rotate = _parent->type() == NODE_CUSP && !other()->isDegenerate();
@@ -459,7 +462,7 @@ Glib::ustring Handle::_getTip(unsigned state)
}
}
-Glib::ustring Handle::_getDragTip(GdkEventMotion */*event*/)
+Glib::ustring Handle::_getDragTip(GdkEventMotion */*event*/) const
{
Geom::Point dist = position() - _last_drag_origin();
// report angle in mathematical convention
@@ -477,34 +480,48 @@ Glib::ustring Handle::_getDragTip(GdkEventMotion */*event*/)
return ret;
}
-/**
- * Curve endpoint in an editable path.
- *
- * The method move() keeps node type invariants during translations.
- */
-Node::Node(NodeSharedData const &data, Geom::Point const &initial_pos)
- : SelectableControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER,
- SP_CTRL_SHAPE_DIAMOND, 9.0, *data.selection, &node_colors, data.node_group)
- , _front(data, initial_pos, this)
- , _back(data, initial_pos, this)
- , _type(NODE_CUSP)
- , _handles_shown(false)
+Node::Node(NodeSharedData const &data, Geom::Point const &initial_pos) :
+ SelectableControlPoint(data.desktop, initial_pos, SP_ANCHOR_CENTER,
+ SP_CTRL_SHAPE_DIAMOND, 9.0,
+ *data.selection,
+ node_colors, data.node_group),
+ _front(data, initial_pos, this),
+ _back(data, initial_pos, this),
+ _type(NODE_CUSP),
+ _handles_shown(false)
{
// NOTE we do not set type here, because the handles are still degenerate
}
+Node const *Node::_next() const
+{
+ return const_cast<Node*>(this)->_next();
+}
+
// NOTE: not using iterators won't make this much quicker because iterators can be 100% inlined.
Node *Node::_next()
{
NodeList::iterator n = NodeList::get_iterator(this).next();
- if (n) return n.ptr();
- return NULL;
+ if (n) {
+ return n.ptr();
+ } else {
+ return NULL;
+ }
}
+
+Node const *Node::_prev() const
+{
+ return const_cast<Node *>(this)->_prev();
+}
+
Node *Node::_prev()
{
NodeList::iterator p = NodeList::get_iterator(this).prev();
- if (p) return p.ptr();
- return NULL;
+ if (p) {
+ return p.ptr();
+ } else {
+ return NULL;
+ }
}
void Node::move(Geom::Point const &new_pos)
@@ -533,7 +550,7 @@ void Node::transform(Geom::Affine const &m)
_fixNeighbors(old_pos, position());
}
-Geom::Rect Node::bounds()
+Geom::Rect Node::bounds() const
{
Geom::Rect b(position(), position());
b.expandTo(_front.position());
@@ -614,13 +631,6 @@ void Node::showHandles(bool v)
if (!_back.isDegenerate()) _back.setVisible(v);
}
-/** Sets the node type and optionally restores the invariants associated with the given type.
- * @param type The type to set
- * @param update_handles Whether to restore invariants associated with the given type.
- * Passing false is useful e.g. wen initially creating the path,
- * and when making cusp nodes during some node algorithms.
- * Pass true when used in response to an UI node type button.
- */
void Node::setType(NodeType type, bool update_handles)
{
if (type == NODE_PICK_BEST) {
@@ -717,8 +727,6 @@ void Node::setType(NodeType type, bool update_handles)
updateState();
}
-/** Pick the best type for this node, based on the position of its handles.
- * This is what assigns types to nodes created using the pen tool. */
void Node::pickBestType()
{
_type = NODE_CUSP;
@@ -768,13 +776,11 @@ void Node::pickBestType()
updateState();
}
-bool Node::isEndNode()
+bool Node::isEndNode() const
{
return !_prev() || !_next();
}
-/** Move the node to the bottom of its canvas group. Useful for node break, to ensure that
- * the selected nodes are above the unselected ones. */
void Node::sink()
{
sp_canvas_item_move_to_z(_canvas_item, 0);
@@ -791,7 +797,6 @@ NodeType Node::parse_nodetype(char x)
}
}
-/** Customized event handler to catch scroll events needed for selection grow/shrink. */
bool Node::_eventHandler(SPEventContext *event_context, GdkEvent *event)
{
int dir = 0;
@@ -836,8 +841,6 @@ bool Node::_eventHandler(SPEventContext *event_context, GdkEvent *event)
return ControlPoint::_eventHandler(event_context, event);
}
-/** Select or deselect a node in this node's subpath based on its path distance from this node.
- * @param dir If negative, shrink selection by one node; if positive, grow by one node */
void Node::_linearGrow(int dir)
{
// Interestingly, we do not need any help from PathManipulator when doing linear grow.
@@ -1140,13 +1143,13 @@ bool Node::clicked(GdkEventButton *event)
return SelectableControlPoint::clicked(event);
}
-Inkscape::SnapSourceType Node::_snapSourceType()
+Inkscape::SnapSourceType Node::_snapSourceType() const
{
if (_type == NODE_SMOOTH || _type == NODE_AUTO)
return SNAPSOURCE_NODE_SMOOTH;
return SNAPSOURCE_NODE_CUSP;
}
-Inkscape::SnapTargetType Node::_snapTargetType()
+Inkscape::SnapTargetType Node::_snapTargetType() const
{
if (_type == NODE_SMOOTH || _type == NODE_AUTO)
return SNAPTARGET_NODE_SMOOTH;
@@ -1158,10 +1161,6 @@ Inkscape::SnapCandidatePoint Node::snapCandidatePoint()
return SnapCandidatePoint(position(), _snapSourceType(), _snapTargetType());
}
-/**
- * Gets the handle that faces the given adjacent node.
- * Will abort with error if the given node is not adjacent.
- */
Handle *Node::handleToward(Node *to)
{
if (_next() == to) {
@@ -1173,10 +1172,6 @@ Handle *Node::handleToward(Node *to)
g_error("Node::handleToward(): second node is not adjacent!");
}
-/**
- * Gets the node in the direction of the given handle.
- * Will abort with error if the handle doesn't belong to this node.
- */
Node *Node::nodeToward(Handle *dir)
{
if (front() == dir) {
@@ -1188,10 +1183,6 @@ Node *Node::nodeToward(Handle *dir)
g_error("Node::nodeToward(): handle is not a child of this node!");
}
-/**
- * Gets the handle that goes in the direction opposite to the given adjacent node.
- * Will abort with error if the given node is not adjacent.
- */
Handle *Node::handleAwayFrom(Node *to)
{
if (_next() == to) {
@@ -1203,10 +1194,6 @@ Handle *Node::handleAwayFrom(Node *to)
g_error("Node::handleAwayFrom(): second node is not adjacent!");
}
-/**
- * Gets the node in the direction opposite to the given handle.
- * Will abort with error if the handle doesn't belong to this node.
- */
Node *Node::nodeAwayFrom(Handle *h)
{
if (front() == h) {
@@ -1218,7 +1205,7 @@ Node *Node::nodeAwayFrom(Handle *h)
g_error("Node::nodeAwayFrom(): handle is not a child of this node!");
}
-Glib::ustring Node::_getTip(unsigned state)
+Glib::ustring Node::_getTip(unsigned state) const
{
if (state_held_shift(state)) {
bool can_drag_out = (_next() && _front.isDegenerate()) || (_prev() && _back.isDegenerate());
@@ -1260,7 +1247,7 @@ Glib::ustring Node::_getTip(unsigned state)
"<b>%s</b>: drag to shape the path, click to select only this node (more: Shift, Ctrl, Alt)"), nodetype);
}
-Glib::ustring Node::_getDragTip(GdkEventMotion */*event*/)
+Glib::ustring Node::_getDragTip(GdkEventMotion */*event*/) const
{
Geom::Point dist = position() - _last_drag_origin();
GString *x = SP_PX_TO_METRIC_STRING(dist[Geom::X], _desktop->namedview->getDefaultMetric());
@@ -1283,7 +1270,6 @@ char const *Node::node_type_to_localized_string(NodeType type)
}
}
-/** Determine whether two nodes are joined by a linear segment. */
bool Node::_is_line_segment(Node *first, Node *second)
{
if (!first || !second) return false;
@@ -1306,13 +1292,6 @@ SPCtrlShapeType Node::_node_type_to_shape(NodeType type)
}
-/**
- * An editable list of nodes representing a subpath.
- *
- * It can optionally be cyclic to represent a closed path.
- * The list has iterators that act like plain node iterators, but can also be used
- * to obtain shared pointers to nodes.
- */
NodeList::NodeList(SubpathList &splist)
: _list(splist)
, _closed(false)
@@ -1344,8 +1323,6 @@ bool NodeList::closed()
return _closed;
}
-/** A subpath is degenerate if it has no segments - either one node in an open path
- * or no nodes in a closed path */
bool NodeList::degenerate()
{
return closed() ? empty() : ++begin() == end();
@@ -1362,10 +1339,9 @@ NodeList::iterator NodeList::before(double t, double *fracpart)
return ret;
}
-// insert a node before i
-NodeList::iterator NodeList::insert(iterator i, Node *x)
+NodeList::iterator NodeList::insert(iterator pos, Node *x)
{
- ListNode *ins = i._node;
+ ListNode *ins = pos._node;
x->ln_next = ins;
x->ln_prev = ins->ln_prev;
ins->ln_prev->ln_next = x;
@@ -1471,11 +1447,6 @@ NodeList &NodeList::get(iterator const &i) {
}
-/**
- * @class SubpathList
- * Editable path composed of one or more subpaths.
- */
-
} // namespace UI
} // namespace Inkscape
diff --git a/src/ui/tool/node.h b/src/ui/tool/node.h
index f2e31e018..daab19cae 100644
--- a/src/ui/tool/node.h
+++ b/src/ui/tool/node.h
@@ -3,6 +3,7 @@
*/
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2009 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -80,10 +81,11 @@ struct NodeSharedData {
class Handle : public ControlPoint {
public:
+
virtual ~Handle();
- inline Geom::Point relativePos();
- inline double length();
- bool isDegenerate() { return _degenerate; } // True if the handle is retracted, i.e. has zero length.
+ inline Geom::Point relativePos() const;
+ inline double length() const;
+ bool isDegenerate() const { return _degenerate; } // True if the handle is retracted, i.e. has zero length.
virtual void setVisible(bool);
virtual void move(Geom::Point const &p);
@@ -96,80 +98,160 @@ public:
void setDirection(Geom::Point const &dir);
Node *parent() { return _parent; }
Handle *other();
+ Handle const *other() const;
static char const *handle_type_to_localized_string(NodeType type);
+
protected:
+
Handle(NodeSharedData const &data, Geom::Point const &initial_pos, Node *parent);
virtual bool _eventHandler(SPEventContext *event_context, GdkEvent *event);
- virtual void dragged(Geom::Point &, GdkEventMotion *);
- virtual bool grabbed(GdkEventMotion *);
- virtual void ungrabbed(GdkEventButton *);
- virtual bool clicked(GdkEventButton *);
-
- virtual Glib::ustring _getTip(unsigned state);
- virtual Glib::ustring _getDragTip(GdkEventMotion *event);
- virtual bool _hasDragTips() { return true; }
+ virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event);
+ virtual bool grabbed(GdkEventMotion *event);
+ virtual void ungrabbed(GdkEventButton *event);
+ virtual bool clicked(GdkEventButton *event);
+
+ virtual Glib::ustring _getTip(unsigned state) const;
+ virtual Glib::ustring _getDragTip(GdkEventMotion *event) const;
+ virtual bool _hasDragTips() const { return true; }
+
private:
+
inline PathManipulator &_pm();
Node *_parent; // the handle's lifetime does not extend beyond that of the parent node,
// so a naked pointer is OK and allows setting it during Node's construction
SPCtrlLine *_handle_line;
bool _degenerate; // True if the handle is retracted, i.e. has zero length. This is used often internally so it makes sense to cache this
+ /**
+ * Control point of a cubic Bezier curve in a path.
+ *
+ * Handle keeps the node type invariant only for the opposite handle of the same node.
+ * Keeping the invariant on node moves is left to the %Node class.
+ */
static Geom::Point _saved_other_pos;
+
static double _saved_length;
static bool _drag_out;
+ static ColorSet _handle_colors;
friend class Node;
};
class Node : ListNode, public SelectableControlPoint {
public:
+
+ /**
+ * Curve endpoint in an editable path.
+ *
+ * The method move() keeps node type invariants during translations.
+ */
Node(NodeSharedData const &data, Geom::Point const &pos);
+
virtual void move(Geom::Point const &p);
virtual void transform(Geom::Affine const &m);
- virtual Geom::Rect bounds();
-
- NodeType type() { return _type; }
+ virtual Geom::Rect bounds() const;
+
+ NodeType type() const { return _type; }
+
+ /**
+ * Sets the node type and optionally restores the invariants associated with the given type.
+ * @param type The type to set.
+ * @param update_handles Whether to restore invariants associated with the given type.
+ * Passing false is useful e.g. wen initially creating the path,
+ * and when making cusp nodes during some node algorithms.
+ * Pass true when used in response to an UI node type button.
+ */
void setType(NodeType type, bool update_handles = true);
+
void showHandles(bool v);
+
+
+ /**
+ * Pick the best type for this node, based on the position of its handles.
+ * This is what assigns types to nodes created using the pen tool.
+ */
void pickBestType(); // automatically determine the type from handle positions
- bool isDegenerate() { return _front.isDegenerate() && _back.isDegenerate(); }
- bool isEndNode();
+
+ bool isDegenerate() const { return _front.isDegenerate() && _back.isDegenerate(); }
+ bool isEndNode() const;
Handle *front() { return &_front; }
Handle *back() { return &_back; }
+
+ /**
+ * Gets the handle that faces the given adjacent node.
+ * Will abort with error if the given node is not adjacent.
+ */
Handle *handleToward(Node *to);
+
+ /**
+ * Gets the node in the direction of the given handle.
+ * Will abort with error if the handle doesn't belong to this node.
+ */
Node *nodeToward(Handle *h);
+
+ /**
+ * Gets the handle that goes in the direction opposite to the given adjacent node.
+ * Will abort with error if the given node is not adjacent.
+ */
Handle *handleAwayFrom(Node *to);
+
+ /**
+ * Gets the node in the direction opposite to the given handle.
+ * Will abort with error if the handle doesn't belong to this node.
+ */
Node *nodeAwayFrom(Handle *h);
+
NodeList &nodeList() { return *(static_cast<ListNode*>(this)->ln_list); }
+
+ /**
+ * Move the node to the bottom of its canvas group.
+ * Useful for node break, to ensure that the selected nodes are above the unselected ones.
+ */
void sink();
static NodeType parse_nodetype(char x);
static char const *node_type_to_localized_string(NodeType type);
+
// temporarily public
+ /** Customized event handler to catch scroll events needed for selection grow/shrink. */
virtual bool _eventHandler(SPEventContext *event_context, GdkEvent *event);
+
Inkscape::SnapCandidatePoint snapCandidatePoint();
+
protected:
- virtual void dragged(Geom::Point &, GdkEventMotion *);
- virtual bool grabbed(GdkEventMotion *);
- virtual bool clicked(GdkEventButton *);
+
+ virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event);
+ virtual bool grabbed(GdkEventMotion *event);
+ virtual bool clicked(GdkEventButton *event);
virtual void _setState(State state);
- virtual Glib::ustring _getTip(unsigned state);
- virtual Glib::ustring _getDragTip(GdkEventMotion *event);
- virtual bool _hasDragTips() { return true; }
+ virtual Glib::ustring _getTip(unsigned state) const;
+ virtual Glib::ustring _getDragTip(GdkEventMotion *event) const;
+ virtual bool _hasDragTips() const { return true; }
+
private:
+
Node(Node const &);
void _fixNeighbors(Geom::Point const &old_pos, Geom::Point const &new_pos);
void _updateAutoHandles();
+
+ /**
+ * Select or deselect a node in this node's subpath based on its path distance from this node.
+ * @param dir If negative, shrink selection by one node; if positive, grow by one node.
+ */
void _linearGrow(int dir);
+
Node *_next();
+ Node const *_next() const;
Node *_prev();
- Inkscape::SnapSourceType _snapSourceType();
- Inkscape::SnapTargetType _snapTargetType();
+ Node const *_prev() const;
+ Inkscape::SnapSourceType _snapSourceType() const;
+ Inkscape::SnapTargetType _snapTargetType() const;
inline PathManipulator &_pm();
static SPCtrlShapeType _node_type_to_shape(NodeType type);
+
+ /** Determine whether two nodes are joined by a linear segment. */
static bool _is_line_segment(Node *first, Node *second);
// Handles are always present, but are not visible if they coincide with the node
@@ -179,6 +261,8 @@ private:
Handle _back; ///< Node handle in the forward direction of the path
NodeType _type; ///< Type of node - cusp, smooth...
bool _handles_shown;
+ static ColorSet node_colors;
+
friend class Handle;
friend class NodeList;
friend class NodeIterator<Node>;
@@ -271,7 +355,15 @@ public:
typedef NodeIterator<value_type const> const_iterator;
// TODO Lame. Make this private and make SubpathList a factory
+ /**
+ * An editable list of nodes representing a subpath.
+ *
+ * It can optionally be cyclic to represent a closed path.
+ * The list has iterators that act like plain node iterators, but can also be used
+ * to obtain shared pointers to nodes.
+ */
NodeList(SubpathList &_list);
+
~NodeList();
// iterators
@@ -286,7 +378,13 @@ public:
// extra node-specific methods
bool closed();
+
+ /**
+ * A subpath is degenerate if it has no segments - either one node in an open path
+ * or no nodes in a closed path.
+ */
bool degenerate();
+
void setClosed(bool c) { _closed = c; }
iterator before(double t, double *fracpart = NULL);
const_iterator before(double t, double *fracpart = NULL) const {
@@ -294,7 +392,10 @@ public:
}
// list operations
+
+ /** insert a node before pos. */
iterator insert(iterator pos, Node *x);
+
template <class InputIterator>
void insert(iterator pos, InputIterator first, InputIterator last) {
for (; first != last; ++first) insert(pos, *first);
@@ -342,7 +443,10 @@ private:
friend class NodeIterator<Node const>;
};
-/** List of node lists. Represents an editable path. */
+/**
+ * List of node lists. Represents an editable path.
+ * Editable path composed of one or more subpaths.
+ */
class SubpathList : public std::list< boost::shared_ptr<NodeList> > {
public:
typedef std::list< boost::shared_ptr<NodeList> > list_type;
@@ -361,13 +465,13 @@ private:
// define inline Handle funcs after definition of Node
-inline Geom::Point Handle::relativePos() {
+inline Geom::Point Handle::relativePos() const {
return position() - _parent->position();
}
inline void Handle::setRelativePos(Geom::Point const &p) {
setPosition(_parent->position() + p);
}
-inline double Handle::length() {
+inline double Handle::length() const {
return relativePos().length();
}
inline PathManipulator &Handle::_pm() {
diff --git a/src/ui/tool/selectable-control-point.cpp b/src/ui/tool/selectable-control-point.cpp
index cec2e7b07..f431b9d57 100644
--- a/src/ui/tool/selectable-control-point.cpp
+++ b/src/ui/tool/selectable-control-point.cpp
@@ -1,8 +1,6 @@
-/** @file
- * Desktop-bound selectable control object - implementation
- */
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2009 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -15,34 +13,32 @@
namespace Inkscape {
namespace UI {
-static SelectableControlPoint::ColorSet default_scp_color_set = {
- {
- {0xffffff00, 0x01000000}, // normal fill, stroke
- {0xff0000ff, 0x01000000}, // mouseover fill, stroke
- {0x0000ffff, 0x01000000} // clicked fill, stroke
- },
+ControlPoint::ColorSet SelectableControlPoint::_default_scp_color_set = {
+ {0xffffff00, 0x01000000}, // normal fill, stroke
+ {0xff0000ff, 0x01000000}, // mouseover fill, stroke
+ {0x0000ffff, 0x01000000}, // clicked fill, stroke
+ //
{0x0000ffff, 0x000000ff}, // normal fill, stroke when selected
{0xff000000, 0x000000ff}, // mouseover fill, stroke when selected
{0xff000000, 0x000000ff} // clicked fill, stroke when selected
};
-SelectableControlPoint::SelectableControlPoint(SPDesktop *d, Geom::Point const &initial_pos,
- SPAnchorType anchor, SPCtrlShapeType shape, unsigned int size,
- ControlPointSelection &sel, ColorSet *cset, SPCanvasGroup *group)
- : ControlPoint (d, initial_pos, anchor, shape, size,
- cset ? reinterpret_cast<ControlPoint::ColorSet*>(cset)
- : reinterpret_cast<ControlPoint::ColorSet*>(&default_scp_color_set), group)
- , _selection (sel)
+SelectableControlPoint::SelectableControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAnchorType anchor,
+ SPCtrlShapeType shape, unsigned int size,
+ ControlPointSelection &sel,
+ ColorSet const &cset, SPCanvasGroup *group) :
+ ControlPoint(d, initial_pos, anchor, shape, size, cset, group),
+ _selection(sel)
{
_selection.allPoints().insert(this);
}
-SelectableControlPoint::SelectableControlPoint(SPDesktop *d, Geom::Point const &initial_pos,
- SPAnchorType anchor, Glib::RefPtr<Gdk::Pixbuf> pixbuf,
- ControlPointSelection &sel, ColorSet *cset, SPCanvasGroup *group)
- : ControlPoint (d, initial_pos, anchor, pixbuf,
- cset ? reinterpret_cast<ControlPoint::ColorSet*>(cset)
- : reinterpret_cast<ControlPoint::ColorSet*>(&default_scp_color_set), group)
- , _selection (sel)
+
+SelectableControlPoint::SelectableControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAnchorType anchor,
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf,
+ ControlPointSelection &sel,
+ ColorSet const &cset, SPCanvasGroup *group) :
+ ControlPoint (d, initial_pos, anchor, pixbuf, cset, group),
+ _selection (sel)
{
_selection.allPoints().insert(this);
}
@@ -107,21 +103,23 @@ void SelectableControlPoint::_setState(State state)
{
if (!selected()) {
ControlPoint::_setState(state);
- return;
- }
-
- ColorSet *cset = reinterpret_cast<ColorSet*>(_cset);
- ColorEntry current = {0, 0};
- switch (state) {
- case STATE_NORMAL:
- current = cset->selected_normal; break;
- case STATE_MOUSEOVER:
- current = cset->selected_mouseover; break;
- case STATE_CLICKED:
- current = cset->selected_clicked; break;
+ } else {
+ ColorEntry current = {0, 0};
+ ColorSet const &activeCset = (_isLurking()) ? invisible_cset : _cset;
+ switch (state) {
+ case STATE_NORMAL:
+ current = activeCset.selected_normal;
+ break;
+ case STATE_MOUSEOVER:
+ current = activeCset.selected_mouseover;
+ break;
+ case STATE_CLICKED:
+ current = activeCset.selected_clicked;
+ break;
+ }
+ _setColors(current);
+ _state = state;
}
- _setColors(current);
- _state = state;
}
} // namespace UI
diff --git a/src/ui/tool/selectable-control-point.h b/src/ui/tool/selectable-control-point.h
index 8ecb39a79..45da6c2b2 100644
--- a/src/ui/tool/selectable-control-point.h
+++ b/src/ui/tool/selectable-control-point.h
@@ -1,8 +1,6 @@
-/** @file
- * Desktop-bound selectable control object
- */
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2009 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -18,40 +16,45 @@ namespace UI {
class ControlPointSelection;
+/**
+ * Desktop-bound selectable control object.
+ */
class SelectableControlPoint : public ControlPoint {
public:
- struct ColorSet {
- ControlPoint::ColorSet cpset;
- ColorEntry selected_normal;
- ColorEntry selected_mouseover;
- ColorEntry selected_clicked;
- };
~SelectableControlPoint();
bool selected() const;
- void updateState() const { const_cast<SelectableControlPoint*>(this)->_setState(_state); }
- virtual Geom::Rect bounds() {
+ void updateState() { _setState(_state); }
+ virtual Geom::Rect bounds() const {
return Geom::Rect(position(), position());
}
+
protected:
- SelectableControlPoint(SPDesktop *d, Geom::Point const &initial_pos,
- SPAnchorType anchor, SPCtrlShapeType shape,
- unsigned int size, ControlPointSelection &sel, ColorSet *cset = 0,
- SPCanvasGroup *group = 0);
- SelectableControlPoint(SPDesktop *d, Geom::Point const &initial_pos,
- SPAnchorType anchor, Glib::RefPtr<Gdk::Pixbuf> pixbuf,
- ControlPointSelection &sel, ColorSet *cset = 0, SPCanvasGroup *group = 0);
+
+ SelectableControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAnchorType anchor,
+ SPCtrlShapeType shape, unsigned int size,
+ ControlPointSelection &sel,
+ ColorSet const &cset = _default_scp_color_set, SPCanvasGroup *group = 0);
+
+ SelectableControlPoint(SPDesktop *d, Geom::Point const &initial_pos, SPAnchorType anchor,
+ Glib::RefPtr<Gdk::Pixbuf> pixbuf,
+ ControlPointSelection &sel,
+ ColorSet const &cset = _default_scp_color_set, SPCanvasGroup *group = 0);
virtual void _setState(State state);
- virtual void dragged(Geom::Point &, GdkEventMotion *);
- virtual bool grabbed(GdkEventMotion *);
- virtual void ungrabbed(GdkEventButton *);
- virtual bool clicked(GdkEventButton *);
+ virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event);
+ virtual bool grabbed(GdkEventMotion *event);
+ virtual void ungrabbed(GdkEventButton *event);
+ virtual bool clicked(GdkEventButton *event);
ControlPointSelection &_selection;
+
private:
+
void _takeSelection();
+
+ static ColorSet _default_scp_color_set;
};
} // namespace UI
diff --git a/src/ui/tool/selector.cpp b/src/ui/tool/selector.cpp
index 364776ce4..19ffd498a 100644
--- a/src/ui/tool/selector.cpp
+++ b/src/ui/tool/selector.cpp
@@ -3,6 +3,7 @@
*/
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2009 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -32,21 +33,25 @@ namespace UI {
* is pressed, it grabs events and handles drags and clicks in the usual way. */
class SelectorPoint : public ControlPoint {
public:
- SelectorPoint(SPDesktop *d, SPCanvasGroup *group, Selector *s)
- : ControlPoint(d, Geom::Point(0,0), SP_ANCHOR_CENTER, SP_CTRL_SHAPE_SQUARE,
- 1, &invisible_cset, group)
- , _selector(s)
- , _cancel(false)
+ SelectorPoint(SPDesktop *d, SPCanvasGroup *group, Selector *s) :
+ ControlPoint(d, Geom::Point(0,0), SP_ANCHOR_CENTER,
+ SP_CTRL_SHAPE_SQUARE, 1,
+ invisible_cset, group),
+ _selector(s),
+ _cancel(false)
{
setVisible(false);
_rubber = static_cast<CtrlRect*>(sp_canvas_item_new(sp_desktop_controls(_desktop),
SP_TYPE_CTRLRECT, NULL));
sp_canvas_item_hide(_rubber);
}
+
~SelectorPoint() {
gtk_object_destroy(_rubber);
}
+
SPDesktop *desktop() { return _desktop; }
+
bool event(SPEventContext *ec, GdkEvent *e) {
return _eventHandler(ec, e);
}
@@ -70,22 +75,26 @@ private:
sp_canvas_item_show(_rubber);
return false;
}
+
virtual void dragged(Geom::Point &new_pos, GdkEventMotion *) {
if (_cancel) return;
Geom::Rect sel(_start, new_pos);
_rubber->setRectangle(sel);
}
+
virtual void ungrabbed(GdkEventButton *event) {
if (_cancel) return;
sp_canvas_item_hide(_rubber);
Geom::Rect sel(_start, position());
_selector->signal_area.emit(sel, event);
}
+
virtual bool clicked(GdkEventButton *event) {
if (event->button != 1) return false;
_selector->signal_point.emit(position(), event);
return true;
}
+
CtrlRect *_rubber;
Selector *_selector;
Geom::Point _start;
diff --git a/src/ui/tool/transform-handle-set.cpp b/src/ui/tool/transform-handle-set.cpp
index b4a27170a..0e94cb25e 100644
--- a/src/ui/tool/transform-handle-set.cpp
+++ b/src/ui/tool/transform-handle-set.cpp
@@ -3,6 +3,7 @@
*/
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2009 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -38,6 +39,7 @@ namespace Inkscape {
namespace UI {
namespace {
+
SPAnchorType corner_to_anchor(unsigned c) {
switch (c % 4) {
case 0: return SP_ANCHOR_NE;
@@ -46,6 +48,7 @@ SPAnchorType corner_to_anchor(unsigned c) {
default: return SP_ANCHOR_SE;
}
}
+
SPAnchorType side_to_anchor(unsigned s) {
switch (s % 4) {
case 0: return SP_ANCHOR_N;
@@ -62,30 +65,30 @@ double snap_angle(double a) {
double unit_angle = M_PI / snaps;
return CLAMP(unit_angle * round(a / unit_angle), -M_PI, M_PI);
}
+
double snap_increment_degrees() {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
int snaps = prefs->getIntLimited("/options/rotationsnapsperpi/value", 12, 1, 1000);
return 180.0 / snaps;
}
-ControlPoint::ColorSet thandle_cset = {
+} // anonymous namespace
+
+ControlPoint::ColorSet TransformHandle::thandle_cset = {
+ {0x000000ff, 0x000000ff},
+ {0x00ff6600, 0x000000ff},
+ {0x00ff6600, 0x000000ff},
+ //
{0x000000ff, 0x000000ff},
{0x00ff6600, 0x000000ff},
{0x00ff6600, 0x000000ff}
};
-ControlPoint::ColorSet center_cset = {
- {0x00000000, 0x000000ff},
- {0x00000000, 0xff0000b0},
- {0x00000000, 0xff0000b0}
-};
-} // anonymous namespace
-
-/** Base class for node transform handles to simplify implementation */
-TransformHandle::TransformHandle(TransformHandleSet &th, SPAnchorType anchor, Glib::RefPtr<Gdk::Pixbuf> pb)
- : ControlPoint(th._desktop, Geom::Point(), anchor, pb, &thandle_cset,
- th._transform_handle_group)
- , _th(th)
+TransformHandle::TransformHandle(TransformHandleSet &th, SPAnchorType anchor, Glib::RefPtr<Gdk::Pixbuf> pb) :
+ ControlPoint(th._desktop, Geom::Point(), anchor,
+ pb,
+ thandle_cset, th._transform_handle_group),
+ _th(th)
{
setVisible(false);
}
@@ -121,7 +124,8 @@ bool TransformHandle::grabbed(GdkEventMotion *)
startTransform();
_th._setActiveHandle(this);
- _cset = &invisible_cset;
+ _setLurking(true);
+ g_message("Lurk ON for %p", this);
_setState(_state);
// Collect the snap-candidates, one for each selected node. These will be stored in the _snap_points vector.
@@ -171,7 +175,8 @@ void TransformHandle::ungrabbed(GdkEventButton *)
{
_snap_points.clear();
_th._clearActiveHandle();
- _cset = &thandle_cset;
+ _setLurking(false);
+ g_message("Lurk off for %p", this);
_setState(_state);
endTransform();
_th.signal_commit.emit(getCommitEvent());
@@ -184,7 +189,7 @@ public:
: TransformHandle(th, anchor, pb)
{}
protected:
- virtual Glib::ustring _getTip(unsigned state) {
+ virtual Glib::ustring _getTip(unsigned state) const {
if (state_held_control(state)) {
if (state_held_shift(state)) {
return C_("Transform handle tip",
@@ -205,31 +210,36 @@ protected:
return C_("Transform handle tip", "<b>Scale handle</b>: drag to scale the selection");
}
- virtual Glib::ustring _getDragTip(GdkEventMotion */*event*/) {
+ virtual Glib::ustring _getDragTip(GdkEventMotion */*event*/) const {
return format_tip(C_("Transform handle tip",
"Scale by %.2f%% x %.2f%%"), _last_scale_x * 100, _last_scale_y * 100);
}
- virtual bool _hasDragTips() { return true; }
+ virtual bool _hasDragTips() const { return true; }
static double _last_scale_x, _last_scale_y;
};
double ScaleHandle::_last_scale_x = 1.0;
double ScaleHandle::_last_scale_y = 1.0;
-/// Corner scaling handle for node transforms
+/**
+ * Corner scaling handle for node transforms.
+ */
class ScaleCornerHandle : public ScaleHandle {
public:
- ScaleCornerHandle(TransformHandleSet &th, unsigned corner)
- : ScaleHandle(th, corner_to_anchor(corner), _corner_to_pixbuf(corner))
- , _corner(corner)
+
+ ScaleCornerHandle(TransformHandleSet &th, unsigned corner) :
+ ScaleHandle(th, corner_to_anchor(corner), _corner_to_pixbuf(corner)),
+ _corner(corner)
{}
+
protected:
virtual void startTransform() {
_sc_center = _th.rotationCenter();
_sc_opposite = _th.bounds().corner(_corner + 2);
_last_scale_x = _last_scale_y = 1.0;
}
+
virtual Geom::Affine computeTransform(Geom::Point const &new_pos, GdkEventMotion *event) {
Geom::Point scc = held_shift(*event) ? _sc_center : _sc_opposite;
Geom::Point vold = _origin - scc, vnew = new_pos - scc;
@@ -275,25 +285,35 @@ protected:
* Geom::Translate(scc);
return t;
}
+
virtual CommitEvent getCommitEvent() {
return _last_transform.isUniformScale()
? COMMIT_MOUSE_SCALE_UNIFORM
: COMMIT_MOUSE_SCALE;
}
+
private:
+
static Glib::RefPtr<Gdk::Pixbuf> _corner_to_pixbuf(unsigned c) {
sp_select_context_get_type();
switch (c % 2) {
- case 0: return Glib::wrap(handles[1], true);
- default: return Glib::wrap(handles[0], true);
+ case 0:
+ return Glib::wrap(handles[1], true);
+ break;
+ default:
+ return Glib::wrap(handles[0], true);
+ break;
}
}
+
Geom::Point _sc_center;
Geom::Point _sc_opposite;
unsigned _corner;
};
-/// Side scaling handle for node transforms
+/**
+ * Side scaling handle for node transforms.
+ */
class ScaleSideHandle : public ScaleHandle {
public:
ScaleSideHandle(TransformHandleSet &th, unsigned side)
@@ -369,7 +389,9 @@ private:
unsigned _side;
};
-/// Rotation handle for node transforms
+/**
+ * Rotation handle for node transforms.
+ */
class RotateHandle : public TransformHandle {
public:
RotateHandle(TransformHandleSet &th, unsigned corner)
@@ -410,7 +432,7 @@ protected:
virtual CommitEvent getCommitEvent() { return COMMIT_MOUSE_ROTATE; }
- virtual Glib::ustring _getTip(unsigned state) {
+ virtual Glib::ustring _getTip(unsigned state) const {
if (state_held_shift(state)) {
if (state_held_control(state)) {
return format_tip(C_("Transform handle tip",
@@ -427,12 +449,12 @@ protected:
"the selection around the rotation center");
}
- virtual Glib::ustring _getDragTip(GdkEventMotion */*event*/) {
+ virtual Glib::ustring _getDragTip(GdkEventMotion */*event*/) const {
return format_tip(C_("Transform handle tip", "Rotate by %.2f°"),
_last_angle * 360.0);
}
- virtual bool _hasDragTips() { return true; }
+ virtual bool _hasDragTips() const { return true; }
private:
static Glib::RefPtr<Gdk::Pixbuf> _corner_to_pixbuf(unsigned c) {
@@ -550,7 +572,7 @@ protected:
: COMMIT_MOUSE_SKEW_X;
}
- virtual Glib::ustring _getTip(unsigned state) {
+ virtual Glib::ustring _getTip(unsigned state) const {
if (state_held_shift(state)) {
if (state_held_control(state)) {
return format_tip(C_("Transform handle tip",
@@ -568,7 +590,7 @@ protected:
"the opposite handle");
}
- virtual Glib::ustring _getDragTip(GdkEventMotion */*event*/) {
+ virtual Glib::ustring _getDragTip(GdkEventMotion */*event*/) const {
if (_last_horizontal) {
return format_tip(C_("Transform handle tip", "Skew horizontally by %.2f°"),
_last_angle * 360.0);
@@ -578,7 +600,7 @@ protected:
}
}
- virtual bool _hasDragTips() { return true; }
+ virtual bool _hasDragTips() const { return true; }
private:
@@ -601,11 +623,13 @@ bool SkewHandle::_last_horizontal = false;
double SkewHandle::_last_angle = 0;
class RotationCenter : public ControlPoint {
+
public:
- RotationCenter(TransformHandleSet &th)
- : ControlPoint(th._desktop, Geom::Point(), SP_ANCHOR_CENTER, _get_pixbuf(),
- &center_cset, th._transform_handle_group)
- , _th(th)
+ RotationCenter(TransformHandleSet &th) :
+ ControlPoint(th._desktop, Geom::Point(), SP_ANCHOR_CENTER,
+ _get_pixbuf(),
+ _center_cset, th._transform_handle_group),
+ _th(th)
{
setVisible(false);
}
@@ -628,7 +652,7 @@ protected:
}
sm.unSetup();
}
- virtual Glib::ustring _getTip(unsigned /*state*/) {
+ virtual Glib::ustring _getTip(unsigned /*state*/) const {
return C_("Transform handle tip",
"<b>Rotation center</b>: drag to change the origin of transforms");
}
@@ -640,9 +664,21 @@ private:
return Glib::wrap(handles[12], true);
}
+ static ColorSet _center_cset;
TransformHandleSet &_th;
};
+ControlPoint::ColorSet RotationCenter::_center_cset = {
+ {0x00000000, 0x000000ff},
+ {0x00000000, 0xff0000b0},
+ {0x00000000, 0xff0000b0},
+ //
+ {0x00000000, 0x000000ff},
+ {0x00000000, 0xff0000b0},
+ {0x00000000, 0xff0000b0}
+};
+
+
TransformHandleSet::TransformHandleSet(SPDesktop *d, SPCanvasGroup *th_group)
: Manipulator(d)
, _active(0)
@@ -674,18 +710,22 @@ TransformHandleSet::~TransformHandleSet()
}
}
-/** Sets the mode of transform handles (scale or rotate). */
void TransformHandleSet::setMode(Mode m)
{
_mode = m;
_updateVisibility(_visible);
}
-Geom::Rect TransformHandleSet::bounds()
+Geom::Rect TransformHandleSet::bounds() const
{
return Geom::Rect(*_scale_corners[0], *_scale_corners[2]);
}
+ControlPoint const &TransformHandleSet::rotationCenter() const
+{
+ return *_center;
+}
+
ControlPoint &TransformHandleSet::rotationCenter()
{
return *_center;
@@ -746,9 +786,6 @@ void TransformHandleSet::_clearActiveHandle()
_updateVisibility(_visible);
}
-/** Update the visibility of transformation handles according to settings and the dimensions
- * of the bounding box. It hides the handles that would have no effect or lead to
- * discontinuities. Additionally, side handles for which there is no space are not shown. */
void TransformHandleSet::_updateVisibility(bool v)
{
if (v) {
diff --git a/src/ui/tool/transform-handle-set.h b/src/ui/tool/transform-handle-set.h
index cd1a61da2..ce949cbb2 100644
--- a/src/ui/tool/transform-handle-set.h
+++ b/src/ui/tool/transform-handle-set.h
@@ -3,6 +3,7 @@
*/
/* Authors:
* Krzysztof Kosiński <tweenk.pl@gmail.com>
+ * Jon A. Cruz <jon@joncruz.org>
*
* Copyright (C) 2009 Authors
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -23,7 +24,6 @@ class CtrlRect;
namespace Inkscape {
namespace UI {
-//class TransformHandle;
class RotateHandle;
class SkewHandle;
class ScaleCornerHandle;
@@ -32,6 +32,7 @@ class RotationCenter;
class TransformHandleSet : public Manipulator {
public:
+
enum Mode {
MODE_SCALE,
MODE_ROTATE_SKEW
@@ -41,23 +42,37 @@ public:
virtual ~TransformHandleSet();
virtual bool event(SPEventContext *, GdkEvent *);
- bool visible() { return _visible; }
- Mode mode() { return _mode; }
- Geom::Rect bounds();
+ bool visible() const { return _visible; }
+ Mode mode() const { return _mode; }
+ Geom::Rect bounds() const;
void setVisible(bool v);
- void setMode(Mode);
+
+ /** Sets the mode of transform handles (scale or rotate). */
+ void setMode(Mode m);
+
void setBounds(Geom::Rect const &, bool preserve_center = false);
bool transforming() { return _in_transform; }
+
+ ControlPoint const &rotationCenter() const;
ControlPoint &rotationCenter();
sigc::signal<void, Geom::Affine const &> signal_transform;
sigc::signal<void, CommitEvent> signal_commit;
+
private:
+
void _emitTransform(Geom::Affine const &);
void _setActiveHandle(ControlPoint *h);
void _clearActiveHandle();
+
+ /** Update the visibility of transformation handles according to settings and the dimensions
+ * of the bounding box. It hides the handles that would have no effect or lead to
+ * discontinuities. Additionally, side handles for which there is no space are not shown.
+ */
void _updateVisibility(bool v);
+
+ // TODO unions must GO AWAY:
union {
ControlPoint *_handles[17];
struct {
@@ -68,6 +83,7 @@ private:
RotationCenter *_center;
};
};
+
ControlPoint *_active;
SPCanvasGroup *_transform_handle_group;
CtrlRect *_trans_outline;
@@ -79,8 +95,9 @@ private:
friend class RotationCenter;
};
-/** Base class for node transform handles to simplify implementation */
-class TransformHandle : public ControlPoint {
+/** Base class for node transform handles to simplify implementation. */
+class TransformHandle : public ControlPoint
+{
public:
TransformHandle(TransformHandleSet &th, SPAnchorType anchor, Glib::RefPtr<Gdk::Pixbuf> pb);
void getNextClosestPoint(bool reverse);
@@ -103,6 +120,8 @@ private:
virtual bool grabbed(GdkEventMotion *);
virtual void dragged(Geom::Point &new_pos, GdkEventMotion *event);
virtual void ungrabbed(GdkEventButton *);
+
+ static ColorSet thandle_cset;
};
} // namespace UI