diff options
Diffstat (limited to '')
-rw-r--r-- | src/gradient-drag.h | 254 |
1 files changed, 254 insertions, 0 deletions
diff --git a/src/gradient-drag.h b/src/gradient-drag.h new file mode 100644 index 0000000..86e1bde --- /dev/null +++ b/src/gradient-drag.h @@ -0,0 +1,254 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#ifndef SEEN_GRADIENT_DRAG_H +#define SEEN_GRADIENT_DRAG_H + +/* + * On-canvas gradient dragging + * + * Authors: + * bulia byak <bulia@users.sf.net> + * Johan Engelen <j.b.c.engelen@ewi.utwente.nl> + * Jon A. Cruz <jon@joncruz.org> + * Tavmjong Bah <tavmjong@free.fr> + * + * Copyright (C) 2012 Authors + * Copyright (C) 2007 Johan Engelen + * Copyright (C) 2005 Authors + * + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include <cstddef> +#include <sigc++/sigc++.h> +#include <vector> +#include <set> +#include <gdk/gdk.h> +#include <glib.h> +#include <glibmm/ustring.h> + +#include <2geom/point.h> + +#include "object/sp-gradient.h" // TODO refactor enums to external .h file +#include "object/sp-mesh-array.h" + +class SPKnot; + +class SPDesktop; +class SPCSSAttr; +class SPLinearGradient; +class SPMeshGradient; +class SPItem; +class SPObject; +class SPRadialGradient; +class SPStop; + +namespace Inkscape { +class Selection; +class CanvasItemCurve; +} // namespace Inkscape + +/** +This class represents a single draggable point of a gradient. It remembers the item +which has the gradient, whether it's fill or stroke, the point type (from the +GrPointType enum), and the point number (needed if more than 2 stops are present). +*/ +struct GrDraggable { + GrDraggable(SPItem *item, GrPointType point_type, guint point_i, Inkscape::PaintTarget fill_or_stroke); + virtual ~GrDraggable(); + + SPItem *item; + GrPointType point_type; + gint point_i; // the stop number of this point ( = 0 POINT_LG_BEGIN and POINT_RG_CENTER) + Inkscape::PaintTarget fill_or_stroke; + + SPObject *getServer(); + + bool mayMerge(GrDraggable *da2); + + inline int equals(GrDraggable *other) { + return ((item == other->item) && (point_type == other->point_type) && (point_i == other->point_i) && (fill_or_stroke == other->fill_or_stroke)); + } +}; + +class GrDrag; + +/** +This class holds together a visible on-canvas knot and a list of draggables that need to +be moved when the knot moves. Normally there's one draggable in the list, but there may +be more when draggers are snapped together. +*/ +struct GrDragger { + GrDragger(GrDrag *parent, Geom::Point p, GrDraggable *draggable); + virtual ~GrDragger(); + + GrDrag *parent; + + SPKnot *knot; + + // position of the knot, desktop coords + Geom::Point point; + // position of the knot before it began to drag; updated when released + Geom::Point point_original; + + std::vector<GrDraggable *> draggables; + + void addDraggable(GrDraggable *draggable); + + void updateKnotShape(); + void updateTip(); + + void select(); + void deselect(); + bool isSelected(); + + /* Given one GrDraggable, these all update other draggables belonging to same GrDragger */ + void moveThisToDraggable(SPItem *item, GrPointType point_type, gint point_i, Inkscape::PaintTarget fill_or_stroke, bool write_repr); + void moveOtherToDraggable(SPItem *item, GrPointType point_type, gint point_i, Inkscape::PaintTarget fill_or_stroke, bool write_repr); + void updateMidstopDependencies(GrDraggable *draggable, bool write_repr); + void updateDependencies(bool write_repr); + + /* Update handles/tensors when mesh corner moved */ + void moveMeshHandles( Geom::Point pc_old, MeshNodeOperation op ); + + /* Following are for highlighting mesh handles when corner node is selected. */ + GrDragger *getMgCorner(); + void highlightNode(SPMeshNode *node, bool highlight, Geom::Point corner_pos, int index); + void highlightCorner(bool highlight); + + bool mayMerge(GrDragger *other); + bool mayMerge(GrDraggable *da2); + + bool isA(GrPointType point_type); + bool isA(SPItem *item, GrPointType point_type, Inkscape::PaintTarget fill_or_stroke); + bool isA(SPItem *item, GrPointType point_type, gint point_i, Inkscape::PaintTarget fill_or_stroke); + + void fireDraggables(bool write_repr, bool scale_radial = false, bool merging_focus = false); + +protected: + void updateControlSizesOverload(SPKnot * knot); + void updateControlSizes(); + +private: + sigc::connection _moved_connection; + sigc::connection _clicked_connection; + sigc::connection _doubleclicked_connection; + sigc::connection _mousedown_connection; + sigc::connection _ungrabbed_connection; +}; + + +/** +This is the root class of the gradient dragging machinery. It holds lists of GrDraggers +and of lines (simple canvas items). It also remembers one of the draggers as selected. +*/ +class GrDrag { +public: // FIXME: make more of this private! + + GrDrag(SPDesktop *desktop); + virtual ~GrDrag(); + + bool isNonEmpty() {return !draggers.empty();} + bool hasSelection() {return !selected.empty();} + guint numSelected() {return selected.size();} + guint numDraggers() {return draggers.size();} + + guint singleSelectedDraggerNumDraggables() { + return (selected.empty()? 0 : (*(selected.begin()))->draggables.size() ); + } + + guint singleSelectedDraggerSingleDraggableType() { + return (selected.empty() ? 0 : ((*(selected.begin()))->draggables[0]->point_type)); + } + + // especially the selection must be private, fix gradient-context to remove direct access to it + std::set<GrDragger *> selected; // list of GrDragger* + void setSelected(GrDragger *dragger, bool add_to_selection = false, bool override = true); + void setDeselected(GrDragger *dragger); + void deselectAll(); + void selectAll(); + void selectByCoords(std::vector<Geom::Point> coords); + void selectByStop(SPStop *stop, bool add_to_selection = true, bool override = true); + void selectRect(Geom::Rect const &r); + + bool dropColor(SPItem *item, gchar const *c, Geom::Point p); + + SPStop *addStopNearPoint(SPItem *item, Geom::Point mouse_p, double tolerance); + + void deleteSelected(bool just_one = false); + + guint32 getColor(); + + bool keep_selection; + + GrDragger *getDraggerFor(GrDraggable *d); + GrDragger *getDraggerFor(SPItem *item, GrPointType point_type, gint point_i, Inkscape::PaintTarget fill_or_stroke); + + void grabKnot(GrDragger *dragger, gint x, gint y, guint32 etime); + void grabKnot(SPItem *item, GrPointType point_type, gint point_i, Inkscape::PaintTarget fill_or_stroke, gint x, gint y, guint32 etime); + + bool local_change; + + SPDesktop *desktop; + + // lists of edges of selection bboxes, to snap draggers to + std::vector<double> hor_levels; + std::vector<double> vert_levels; + + std::vector<GrDragger *> draggers; + std::vector<Inkscape::CanvasItemCurve *> item_curves; + + void updateDraggers(); + void refreshDraggers(); + void updateLines(); + void updateLevels(); + + bool mouseOver(); + + void selected_move_nowrite(double x, double y, bool scale_radial); + void selected_move(double x, double y, bool write_repr = true, bool scale_radial = false); + void selected_move_screen(double x, double y); + + bool key_press_handler(GdkEvent *event); + + GrDragger *select_next(); + GrDragger *select_prev(); + + void selected_reverse_vector(); + +private: + void deselect_all(); + + void addLine( SPItem *item, Geom::Point p1, Geom::Point p2, Inkscape::PaintTarget fill_or_stroke); + void addCurve(SPItem *item, Geom::Point p0, Geom::Point p1, Geom::Point p2, Geom::Point p3, + int corner0, int corner1, int handle0, int handle1, Inkscape::PaintTarget fill_or_stroke); + + GrDragger *addDragger(GrDraggable *draggable); + + void addDraggersRadial(SPRadialGradient *rg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); + void addDraggersLinear(SPLinearGradient *lg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); + void addDraggersMesh( SPMeshGradient *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); + void refreshDraggersMesh(SPMeshGradient *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke); + + bool styleSet( const SPCSSAttr *css, bool switch_style); + + Glib::ustring makeStopSafeColor( gchar const *str, bool &isNull ); + + Inkscape::Selection *selection; + sigc::connection sel_changed_connection; + sigc::connection sel_modified_connection; + + sigc::connection style_set_connection; + sigc::connection style_query_connection; +}; + +#endif // SEEN_GRADIENT_DRAG_H +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : |