diff options
| author | Jon A. Cruz <jon@joncruz.org> | 2012-05-17 02:33:16 +0000 |
|---|---|---|
| committer | Jon A. Cruz <jon@joncruz.org> | 2012-05-17 02:33:16 +0000 |
| commit | e9412c187da3f62f01bc5acb6190af2d5a395ccb (patch) | |
| tree | 4d6d98646a87c82dc1cc631d88875ca0d63c3fcf /src/ui | |
| parent | Fixed warning with printf format. Also corrected inproper type that resulted ... (diff) | |
| download | inkscape-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.cpp | 7 | ||||
| -rw-r--r-- | src/ui/tool/control-point.cpp | 234 | ||||
| -rw-r--r-- | src/ui/tool/control-point.h | 275 | ||||
| -rw-r--r-- | src/ui/tool/curve-drag-point.cpp | 27 | ||||
| -rw-r--r-- | src/ui/tool/curve-drag-point.h | 21 | ||||
| -rw-r--r-- | src/ui/tool/node.cpp | 167 | ||||
| -rw-r--r-- | src/ui/tool/node.h | 158 | ||||
| -rw-r--r-- | src/ui/tool/selectable-control-point.cpp | 72 | ||||
| -rw-r--r-- | src/ui/tool/selectable-control-point.h | 47 | ||||
| -rw-r--r-- | src/ui/tool/selector.cpp | 19 | ||||
| -rw-r--r-- | src/ui/tool/transform-handle-set.cpp | 121 | ||||
| -rw-r--r-- | src/ui/tool/transform-handle-set.h | 33 |
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(), - ¢er_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 |
