summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabiertxof <jtx@jtx>2016-12-08 22:23:58 +0000
committerJabiertxof <jtx@jtx>2016-12-08 22:23:58 +0000
commit50263b5e24cd79e510c4c09c66dc5e4cd1fe22c8 (patch)
treea0ab95ebe1882ac6e1442243eebb0e4a5e11d4ff /src
parentWorking on nested LPE (diff)
parent'upport' changes to LPE's rotate copies and mirrot symmetry (diff)
downloadinkscape-50263b5e24cd79e510c4c09c66dc5e4cd1fe22c8.tar.gz
inkscape-50263b5e24cd79e510c4c09c66dc5e4cd1fe22c8.zip
Update to trunk
(bzr r15295.1.20)
Diffstat (limited to 'src')
-rw-r--r--src/live_effects/lpe-copy_rotate.cpp155
-rw-r--r--src/live_effects/lpe-copy_rotate.h16
-rw-r--r--src/sp-mesh-array.cpp8
-rw-r--r--src/widgets/mesh-toolbar.cpp165
4 files changed, 129 insertions, 215 deletions
diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp
index 1133e083a..a21d67078 100644
--- a/src/live_effects/lpe-copy_rotate.cpp
+++ b/src/live_effects/lpe-copy_rotate.cpp
@@ -15,32 +15,12 @@
#include <2geom/path-intersection.h>
#include <2geom/sbasis-to-bezier.h>
#include "live_effects/lpe-copy_rotate.h"
-
-#include "knotholder.h"
// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
-namespace CR {
-
-class KnotHolderEntityStartingAngle : public LPEKnotHolderEntity {
-public:
- KnotHolderEntityStartingAngle(LPECopyRotate *effect) : LPEKnotHolderEntity(effect) {};
- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
- virtual Geom::Point knot_get() const;
-};
-
-class KnotHolderEntityRotationAngle : public LPEKnotHolderEntity {
-public:
- KnotHolderEntityRotationAngle(LPECopyRotate *effect) : LPEKnotHolderEntity(effect) {};
- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
- virtual Geom::Point knot_get() const;
-};
-
-} // namespace CR
-
bool
pointInTriangle(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3)
{
@@ -59,6 +39,7 @@ pointInTriangle(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &
LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this),
+ starting_point("hidden", "hidden", "starting_point", &wr, this),
starting_angle(_("Starting:"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0),
rotation_angle(_("Rotation angle:"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 60.0),
num_copies(_("Number of copies:"), _("Number of copies of the original path"), "num_copies", &wr, this, 6),
@@ -74,6 +55,7 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) :
registerParameter(&copies_to_360);
registerParameter(&fuse_paths);
registerParameter(&starting_angle);
+ registerParameter(&starting_point);
registerParameter(&rotation_angle);
registerParameter(&num_copies);
registerParameter(&origin);
@@ -87,6 +69,41 @@ LPECopyRotate::~LPECopyRotate()
}
+Gtk::Widget * LPECopyRotate::newWidget()
+{
+ // use manage here, because after deletion of Effect object, others might
+ // still be pointing to this widget.
+ Gtk::VBox *vbox = Gtk::manage(new Gtk::VBox(Effect::newWidget()));
+
+ vbox->set_border_width(5);
+ vbox->set_homogeneous(false);
+ vbox->set_spacing(2);
+
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ Parameter *param = *it;
+ Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
+ Glib::ustring *tip = param->param_getTooltip();
+ if (widg) {
+ if (param->param_key != "starting_point") {
+ vbox->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+ }
+
+ ++it;
+ }
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+
void
LPECopyRotate::doOnApply(SPLPEItem const* lpeitem)
{
@@ -104,11 +121,6 @@ LPECopyRotate::doOnApply(SPLPEItem const* lpeitem)
void
LPECopyRotate::transform_multiply(Geom::Affine const& postmul, bool set)
{
- if(fuse_paths) {
- Geom::Coord angle = Geom::deg_from_rad(atan(-postmul[1]/postmul[0]));
- angle += starting_angle;
- starting_angle.param_set_value(angle);
- }
// cycle through all parameters. Most parameters will not need transformation, but path and point params do.
for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) {
@@ -146,11 +158,25 @@ LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem)
dir = unit_vector(B - A);
// I first suspected the minus sign to be a bug in 2geom but it is
// likely due to SVG's choice of coordinate system orientation (max)
+ bool near = Geom::are_near(previous_start_point, (Geom::Point)starting_point, 0.01);
+ if (!near) {
+ starting_angle.param_set_value(deg_from_rad(-angle_between(dir, starting_point - origin)));
+ if (GDK_SHIFT_MASK) {
+ dist_angle_handle = L2(B - A);
+ } else {
+ dist_angle_handle = L2(starting_point - origin);
+ }
+ }
start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * dist_angle_handle;
rot_pos = origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle;
+ if (near) {
+ starting_point.param_setValue(start_pos);
+ }
+ previous_start_point = (Geom::Point)starting_point;
if ( fuse_paths || copies_to_360 ) {
rot_pos = origin;
}
+
SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
item->apply_to_clippath(item);
item->apply_to_mask(item);
@@ -418,85 +444,6 @@ LPECopyRotate::resetDefaults(SPItem const* item)
original_bbox(SP_LPE_ITEM(item));
}
-void
-LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
-{
- {
- KnotHolderEntity *e = new CR::KnotHolderEntityStartingAngle(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
- _("Adjust the starting angle"));
- knotholder->add(e);
- }
- {
- KnotHolderEntity *e = new CR::KnotHolderEntityRotationAngle(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
- _("Adjust the rotation angle"));
- knotholder->add(e);
- }
-};
-
-namespace CR {
-
-using namespace Geom;
-
-void
-KnotHolderEntityStartingAngle::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
-{
- LPECopyRotate* lpe = dynamic_cast<LPECopyRotate *>(_effect);
-
- Geom::Point const s = snap_knot_position(p, state);
-
- // I first suspected the minus sign to be a bug in 2geom but it is
- // likely due to SVG's choice of coordinate system orientation (max)
- lpe->starting_angle.param_set_value(deg_from_rad(-angle_between(lpe->dir, s - lpe->origin)));
- if (state & GDK_SHIFT_MASK) {
- lpe->dist_angle_handle = L2(lpe->B - lpe->A);
- } else {
- lpe->dist_angle_handle = L2(p - lpe->origin);
- }
-
- // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.
- sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
-}
-
-void
-KnotHolderEntityRotationAngle::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, guint state)
-{
- LPECopyRotate* lpe = dynamic_cast<LPECopyRotate *>(_effect);
-
- Geom::Point const s = snap_knot_position(p, state);
-
- // I first suspected the minus sign to be a bug in 2geom but it is
- // likely due to SVG's choice of coordinate system orientation (max)
- lpe->rotation_angle.param_set_value(deg_from_rad(-angle_between(lpe->dir, s - lpe->origin)) - lpe->starting_angle);
- if (state & GDK_SHIFT_MASK) {
- lpe->dist_angle_handle = L2(lpe->B - lpe->A);
- } else {
- lpe->dist_angle_handle = L2(p - lpe->origin);
- }
-
- // FIXME: this should not directly ask for updating the item. It should write to SVG, which triggers updating.
- sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
-}
-
-Geom::Point
-KnotHolderEntityStartingAngle::knot_get() const
-{
- LPECopyRotate const *lpe = dynamic_cast<LPECopyRotate const*>(_effect);
- return lpe->start_pos;
-}
-
-Geom::Point
-KnotHolderEntityRotationAngle::knot_get() const
-{
- LPECopyRotate const *lpe = dynamic_cast<LPECopyRotate const*>(_effect);
- return lpe->rot_pos;
-}
-
-} // namespace CR
-
-/* ######################## */
-
} //namespace LivePathEffect
} /* namespace Inkscape */
diff --git a/src/live_effects/lpe-copy_rotate.h b/src/live_effects/lpe-copy_rotate.h
index 87af867df..f189ffa04 100644
--- a/src/live_effects/lpe-copy_rotate.h
+++ b/src/live_effects/lpe-copy_rotate.h
@@ -13,7 +13,7 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
+#include <gtkmm.h>
#include "live_effects/effect.h"
#include "live_effects/parameter/point.h"
#include "live_effects/lpegroupbbox.h"
@@ -21,12 +21,6 @@
namespace Inkscape {
namespace LivePathEffect {
-namespace CR {
-// we need a separate namespace to avoid clashes with LPEPerpBisector
-class KnotHolderEntityStartingAngle;
-class KnotHolderEntityRotationAngle;
-}
-
class LPECopyRotate : public Effect, GroupBBoxEffect {
public:
LPECopyRotate(LivePathEffectObject *lpeobject);
@@ -38,16 +32,13 @@ public:
virtual void split(Geom::PathVector &path_in, Geom::Path const &divider);
virtual void resetDefaults(SPItem const* item);
virtual void transform_multiply(Geom::Affine const& postmul, bool set);
- /* the knotholder entity classes must be declared friends */
- friend class CR::KnotHolderEntityStartingAngle;
- friend class CR::KnotHolderEntityRotationAngle;
- void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
-
+ virtual Gtk::Widget * newWidget();
protected:
virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec);
private:
PointParam origin;
+ PointParam starting_point;
ScalarParam starting_angle;
ScalarParam rotation_angle;
ScalarParam num_copies;
@@ -58,6 +49,7 @@ private:
Geom::Point dir;
Geom::Point start_pos;
Geom::Point rot_pos;
+ Geom::Point previous_start_point;
double dist_angle_handle;
LPECopyRotate(const LPECopyRotate&);
LPECopyRotate& operator=(const LPECopyRotate&);
diff --git a/src/sp-mesh-array.cpp b/src/sp-mesh-array.cpp
index f2604976e..b522d577b 100644
--- a/src/sp-mesh-array.cpp
+++ b/src/sp-mesh-array.cpp
@@ -2026,7 +2026,7 @@ guint SPMeshNodeArray::side_arc( std::vector<guint> corners ) {
{
case 'L':
case 'l':
- std::cout << "SPMeshNodeArray::arc_sides: Can't convert straight lines to arcs.";
+ std::cerr << "SPMeshNodeArray::side_arc: Can't convert straight lines to arcs." << std::endl;
break;
case 'C':
@@ -2052,15 +2052,15 @@ guint SPMeshNodeArray::side_arc( std::vector<guint> corners ) {
++arced;
} else {
- std::cout << "SPMeshNodeArray::arc_sides: No crossing, can't turn into arc." << std::endl;
+ std::cerr << "SPMeshNodeArray::side_arc: No crossing, can't turn into arc." << std::endl;
}
} else {
- std::cout << "SPMeshNodeArray::arc_sides: Handles parallel, can't turn into arc." << std::endl;
+ std::cerr << "SPMeshNodeArray::side_arc: Handles parallel, can't turn into arc." << std::endl;
}
break;
}
default:
- std::cout << "SPMeshNodeArray::arc_sides: Invalid path type: " << n[1]->path_type << std::endl;
+ std::cerr << "SPMeshNodeArray::side_arc: Invalid path type: " << n[1]->path_type << std::endl;
}
}
}
diff --git a/src/widgets/mesh-toolbar.cpp b/src/widgets/mesh-toolbar.cpp
index f7b7a6ec9..ea0faf1df 100644
--- a/src/widgets/mesh-toolbar.cpp
+++ b/src/widgets/mesh-toolbar.cpp
@@ -67,76 +67,79 @@ static bool blocked = false;
//## Mesh ##
//########################
-/*
- * Get the current selection and dragger status from the desktop
- */
-void ms_read_selection( Inkscape::Selection *selection,
- SPMeshGradient *&ms_selected,
- bool &ms_selected_multi,
- SPMeshType &ms_type,
- bool &ms_type_multi )
+
+// Get a list of selected meshes taking into account fill/stroke toggles
+std::vector<SPMeshGradient *> ms_get_dt_selected_gradients(Inkscape::Selection *selection)
{
+ std::vector<SPMeshGradient *> ms_selected;
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool edit_fill = prefs->getBool("/tools/mesh/edit_fill", true);
+ bool edit_stroke = prefs->getBool("/tools/mesh/edit_stroke", true);
- // Read desktop selection
- bool first = true;
- ms_type = SP_MESH_TYPE_COONS;
-
auto itemlist= selection->items();
for(auto i=itemlist.begin();i!=itemlist.end();++i){
- SPItem *item = *i;
+ SPItem *item = *i;// get the items gradient, not the getVector() version
SPStyle *style = item->style;
- if (style && (style->fill.isPaintserver())) {
- SPPaintServer *server = item->style->getFillPaintServer();
- if ( SP_IS_MESHGRADIENT(server) ) {
-
- SPMeshGradient *gradient = SP_MESHGRADIENT(server); // ->getVector();
- SPMeshType type = gradient->type;
+ if (style) {
- if (gradient != ms_selected) {
- if (ms_selected) {
- ms_selected_multi = true;
- } else {
- ms_selected = gradient;
- }
+
+ if (edit_fill && style->fill.isPaintserver()) {
+ SPPaintServer *server = item->style->getFillPaintServer();
+ SPMeshGradient *mesh = dynamic_cast<SPMeshGradient *>(server);
+ if (mesh) {
+ ms_selected.push_back(mesh);
}
- if( type != ms_type ) {
- if (ms_type != SP_MESH_TYPE_COONS && !first) {
- ms_type_multi = true;
- } else {
- ms_type = type;
- }
+ }
+
+ if (edit_stroke && style->stroke.isPaintserver()) {
+ SPPaintServer *server = item->style->getStrokePaintServer();
+ SPMeshGradient *mesh = dynamic_cast<SPMeshGradient *>(server);
+ if (mesh) {
+ ms_selected.push_back(mesh);
}
- first = false;
}
}
- if (style && (style->stroke.isPaintserver())) {
- SPPaintServer *server = item->style->getStrokePaintServer();
- if ( SP_IS_MESHGRADIENT(server) ) {
+ }
+ return ms_selected;
+}
- SPMeshGradient *gradient = SP_MESHGRADIENT(server); // ->getVector();
- SPMeshType type = gradient->type;
- if (gradient != ms_selected) {
- if (ms_selected) {
- ms_selected_multi = true;
- } else {
- ms_selected = gradient;
- }
- }
- if( type != ms_type ) {
- if (ms_type != SP_MESH_TYPE_COONS && !first) {
- ms_type_multi = true;
- } else {
- ms_type = type;
- }
- }
- first = false;
+/*
+ * Get the current selection status from the desktop
+ */
+void ms_read_selection( Inkscape::Selection *selection,
+ SPMeshGradient *&ms_selected,
+ bool &ms_selected_multi,
+ SPMeshType &ms_type,
+ bool &ms_type_multi )
+{
+ ms_selected = NULL;
+ ms_selected_multi = false;
+ ms_type = SP_MESH_TYPE_COONS;
+ ms_type_multi = false;
+
+ bool first = true;
+
+ // Read desktop selection, taking into account fill/stroke toggles
+ std::vector<SPMeshGradient *> meshes = ms_get_dt_selected_gradients( selection );
+ for (auto i = meshes.begin(); i != meshes.end(); ++i) {
+ if (first) {
+ ms_selected = (*i);
+ ms_type = (*i)->type;
+ first = false;
+ } else {
+ if (ms_selected != (*i)) {
+ ms_selected_multi = true;
+ }
+ if (ms_type != (*i)->type) {
+ ms_type_multi = true;
}
}
}
- }
+}
/*
* Core function, setup all the widgets whenever something changes on the desktop
@@ -173,7 +176,7 @@ static void ms_tb_selection_changed(Inkscape::Selection * /*selection*/, gpointe
// std::cout << " type: " << ms_type << std::endl;
EgeSelectOneAction* type = (EgeSelectOneAction *) g_object_get_data(G_OBJECT(widget), "mesh_select_type_action");
- gtk_action_set_sensitive( GTK_ACTION(type), (ms_selected && !ms_selected_multi) );
+ gtk_action_set_sensitive( GTK_ACTION(type), (ms_selected && !ms_type_multi) );
if (ms_selected) {
blocked = TRUE;
ege_select_one_action_set_active( type, ms_type );
@@ -204,34 +207,6 @@ static void ms_defs_modified(SPObject * /*defs*/, guint /*flags*/, GObject *widg
ms_tb_selection_changed(NULL, widget);
}
-void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMeshGradient *&ms_selected)
-{
- SPMeshGradient *gradient = 0;
-
- auto itemlist= selection->items();
- for(auto i=itemlist.begin();i!=itemlist.end();++i){
- SPItem *item = *i;// get the items gradient, not the getVector() version
- SPStyle *style = item->style;
- SPPaintServer *server = 0;
-
- if (style && (style->fill.isPaintserver())) {
- server = item->style->getFillPaintServer();
- }
- if (style && (style->stroke.isPaintserver())) {
- server = item->style->getStrokePaintServer();
- }
-
- if ( SP_IS_MESHGRADIENT(server) ) {
- gradient = SP_MESHGRADIENT(server);
- }
- }
-
- if (gradient) {
- ms_selected = gradient;
- }
-}
-
-
/*
* Callback functions for user actions
*/
@@ -296,18 +271,17 @@ static void ms_type_changed(EgeSelectOneAction *act, GtkWidget *widget)
SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(G_OBJECT(widget), "desktop"));
Inkscape::Selection *selection = desktop->getSelection();
- SPMeshGradient *gradient = 0;
- ms_get_dt_selected_gradient(selection, gradient);
+ std::vector<SPMeshGradient *> meshes = ms_get_dt_selected_gradients(selection);
- if (gradient) {
- SPMeshType type = (SPMeshType) ege_select_one_action_get_active(act);
+ SPMeshType type = (SPMeshType) ege_select_one_action_get_active(act);
+ for (auto i = meshes.begin(); i != meshes.end(); ++i) {
// std::cout << " type: " << type << std::endl;
- gradient->type = type;
- gradient->type_set = true;
- gradient->updateRepr();
-
- DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MESH,
- _("Set mesh type"));
+ (*i)->type = type;
+ (*i)->type_set = true;
+ (*i)->updateRepr();
+ }
+ if (!meshes.empty() ) {
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MESH,_("Set mesh type"));
}
}
@@ -366,7 +340,7 @@ static void ms_toggle_handles(void)
}
}
-static void ms_toggle_fill_stroke(void)
+static void ms_toggle_fill_stroke(InkToggleAction * /*act*/, gpointer data)
{
MeshTool *mt = get_mesh_tool();
if (mt) {
@@ -374,6 +348,7 @@ static void ms_toggle_fill_stroke(void)
drag->updateDraggers();
drag->updateLines();
drag->updateLevels();
+ ms_tb_selection_changed(NULL, data); // Need to update Type widget
}
}
@@ -507,7 +482,7 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj
gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/mesh/edit_fill");
g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
- g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_toggle_fill_stroke), 0);
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_toggle_fill_stroke), holder);
}
/* Edit stroke mesh */
@@ -520,7 +495,7 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj
gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/mesh/edit_stroke");
g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
- g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_toggle_fill_stroke), 0);
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_toggle_fill_stroke), holder);
}
/* Show/hide side and tensor handles */