summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabiertxof <jtx@jtx>2017-01-24 14:16:06 +0000
committerJabiertxof <jtx@jtx>2017-01-24 14:16:06 +0000
commitb25ebda10578c5d697db9716e3c2b70950d33e45 (patch)
tree4635b8b3f65600cfd54b5465b906ae42165b0674 /src
parentFix some bugs (diff)
parentfix nodes reverting back during editing (diff)
downloadinkscape-b25ebda10578c5d697db9716e3c2b70950d33e45.tar.gz
inkscape-b25ebda10578c5d697db9716e3c2b70950d33e45.zip
fixing to new trunk
(bzr r15142.1.38)
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/color-profile.cpp4
-rw-r--r--src/desktop-style.cpp11
-rw-r--r--src/display/cairo-utils.cpp3
-rw-r--r--src/display/canvas-axonomgrid.cpp5
-rw-r--r--src/display/canvas-grid.cpp39
-rw-r--r--src/display/canvas-grid.h10
-rw-r--r--src/display/curve.cpp14
-rw-r--r--src/display/curve.h1
-rw-r--r--src/display/drawing-group.cpp3
-rw-r--r--src/display/drawing-item.cpp23
-rw-r--r--src/display/drawing-item.h4
-rw-r--r--src/display/drawing-text.cpp2
-rw-r--r--src/display/drawing.cpp6
-rw-r--r--src/display/drawing.h2
-rw-r--r--src/display/snap-indicator.cpp4
-rw-r--r--src/display/sodipodi-ctrl.cpp74
-rw-r--r--src/display/sodipodi-ctrl.h2
-rw-r--r--src/display/sp-canvas.cpp31
-rw-r--r--src/display/sp-ctrlcurve.cpp2
-rw-r--r--src/display/sp-ctrlcurve.h3
-rw-r--r--src/display/sp-ctrlline.cpp1
-rw-r--r--src/display/sp-ctrlline.h2
-rw-r--r--src/document.cpp1
-rw-r--r--src/extension/internal/cdr-input.cpp11
-rw-r--r--src/extension/internal/emf-print.cpp4
-rw-r--r--src/extension/internal/filter/filter.cpp1
-rw-r--r--src/extension/internal/pdfinput/pdf-input.cpp71
-rw-r--r--src/extension/internal/pdfinput/pdf-input.h1
-rw-r--r--src/extension/internal/vsd-input.cpp11
-rw-r--r--src/extension/internal/wpg-input.cpp7
-rw-r--r--src/extension/param/description.cpp3
-rw-r--r--src/extension/prefdialog.cpp8
-rw-r--r--src/file.cpp570
-rw-r--r--src/gradient-chemistry.cpp2
-rw-r--r--src/gradient-drag.cpp567
-rw-r--r--src/gradient-drag.h18
-rw-r--r--src/helper/geom-pathstroke.cpp226
-rw-r--r--src/helper/geom-pathstroke.h17
-rw-r--r--src/helper/png-write.cpp18
-rw-r--r--src/helper/png-write.h4
-rw-r--r--src/inkscape.cpp2
-rw-r--r--src/io/sys.cpp2
-rw-r--r--src/knot-enums.h1
-rw-r--r--src/knot-holder-entity.cpp4
-rw-r--r--src/knot.cpp23
-rw-r--r--src/knot.h2
-rw-r--r--src/libnrtype/Layout-TNG-Compute.cpp30
-rw-r--r--src/libnrtype/Layout-TNG-Output.cpp17
-rw-r--r--src/libnrtype/Layout-TNG.h8
-rw-r--r--src/libuemf/uemf.h24
-rw-r--r--src/livarot/LivarotDefs.h12
-rw-r--r--src/livarot/Shape.h1
-rw-r--r--src/livarot/int-line.h1
-rw-r--r--src/live_effects/effect.cpp16
-rw-r--r--src/live_effects/effect.h5
-rw-r--r--src/live_effects/lpe-angle_bisector.cpp8
-rw-r--r--src/live_effects/lpe-attach-path.cpp5
-rw-r--r--src/live_effects/lpe-bendpath.cpp3
-rw-r--r--src/live_effects/lpe-bounding-box.cpp6
-rw-r--r--src/live_effects/lpe-bspline.h2
-rw-r--r--src/live_effects/lpe-circle_3pts.cpp2
-rw-r--r--src/live_effects/lpe-circle_with_radius.cpp2
-rw-r--r--src/live_effects/lpe-clone-original.cpp5
-rw-r--r--src/live_effects/lpe-constructgrid.cpp4
-rw-r--r--src/live_effects/lpe-copy_rotate.cpp210
-rw-r--r--src/live_effects/lpe-copy_rotate.h15
-rw-r--r--src/live_effects/lpe-curvestitch.cpp5
-rw-r--r--src/live_effects/lpe-dynastroke.cpp2
-rw-r--r--src/live_effects/lpe-ellipse_5pts.cpp5
-rw-r--r--src/live_effects/lpe-envelope.cpp2
-rw-r--r--src/live_effects/lpe-extrude.cpp4
-rw-r--r--src/live_effects/lpe-fill-between-many.cpp2
-rw-r--r--src/live_effects/lpe-fill-between-strokes.cpp5
-rw-r--r--src/live_effects/lpe-fillet-chamfer.cpp2
-rw-r--r--src/live_effects/lpe-gears.cpp7
-rw-r--r--src/live_effects/lpe-interpolate.cpp6
-rw-r--r--src/live_effects/lpe-interpolate_points.cpp3
-rw-r--r--src/live_effects/lpe-jointype.cpp2
-rw-r--r--src/live_effects/lpe-knot.cpp17
-rw-r--r--src/live_effects/lpe-knot.h2
-rw-r--r--src/live_effects/lpe-lattice.cpp3
-rw-r--r--src/live_effects/lpe-lattice2.cpp3
-rw-r--r--src/live_effects/lpe-lattice2.h2
-rw-r--r--src/live_effects/lpe-line_segment.cpp2
-rw-r--r--src/live_effects/lpe-measure-line.cpp1087
-rw-r--r--src/live_effects/lpe-measure-line.h27
-rw-r--r--src/live_effects/lpe-mirror_symmetry.cpp225
-rw-r--r--src/live_effects/lpe-mirror_symmetry.h14
-rw-r--r--src/live_effects/lpe-offset.cpp5
-rw-r--r--src/live_effects/lpe-parallel.cpp5
-rw-r--r--src/live_effects/lpe-path_length.cpp14
-rw-r--r--src/live_effects/lpe-path_length.h2
-rw-r--r--src/live_effects/lpe-patternalongpath.cpp45
-rw-r--r--src/live_effects/lpe-patternalongpath.h2
-rw-r--r--src/live_effects/lpe-perp_bisector.cpp6
-rw-r--r--src/live_effects/lpe-perspective-envelope.cpp10
-rw-r--r--src/live_effects/lpe-perspective_path.cpp10
-rw-r--r--src/live_effects/lpe-perspective_path.h2
-rw-r--r--src/live_effects/lpe-powerstroke.cpp3
-rw-r--r--src/live_effects/lpe-recursiveskeleton.cpp5
-rw-r--r--src/live_effects/lpe-rough-hatches.cpp3
-rw-r--r--src/live_effects/lpe-roughen.cpp3
-rw-r--r--src/live_effects/lpe-roughen.h1
-rw-r--r--src/live_effects/lpe-ruler.cpp3
-rw-r--r--src/live_effects/lpe-show_handles.cpp40
-rw-r--r--src/live_effects/lpe-show_handles.h6
-rw-r--r--src/live_effects/lpe-simplify.cpp8
-rw-r--r--src/live_effects/lpe-simplify.h1
-rw-r--r--src/live_effects/lpe-skeleton.cpp7
-rw-r--r--src/live_effects/lpe-skeleton.h2
-rw-r--r--src/live_effects/lpe-sketch.cpp5
-rw-r--r--src/live_effects/lpe-spiro.cpp2
-rw-r--r--src/live_effects/lpe-tangent_to_curve.cpp12
-rw-r--r--src/live_effects/lpe-tangent_to_curve.h2
-rw-r--r--src/live_effects/lpe-taperstroke.cpp8
-rw-r--r--src/live_effects/lpe-taperstroke.h2
-rw-r--r--src/live_effects/lpe-test-doEffect-stack.cpp5
-rw-r--r--src/live_effects/lpe-text_label.cpp5
-rw-r--r--src/live_effects/lpe-transform_2pts.cpp15
-rw-r--r--src/live_effects/lpe-transform_2pts.h2
-rw-r--r--src/live_effects/lpe-vonkoch.cpp2
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.cpp8
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.h3
-rw-r--r--src/live_effects/parameter/fontbutton.cpp2
-rw-r--r--src/live_effects/parameter/fontbutton.h1
-rw-r--r--src/live_effects/parameter/originalpath.cpp2
-rw-r--r--src/live_effects/parameter/originalpatharray.cpp2
-rw-r--r--src/live_effects/parameter/parameter.h4
-rw-r--r--src/live_effects/parameter/point.cpp12
-rw-r--r--src/live_effects/parameter/point.h2
-rw-r--r--src/live_effects/parameter/powerstrokepointarray.cpp4
-rw-r--r--src/live_effects/parameter/powerstrokepointarray.h2
-rw-r--r--src/live_effects/parameter/text.cpp5
-rw-r--r--src/live_effects/parameter/vector.cpp9
-rw-r--r--src/live_effects/parameter/vector.h2
-rw-r--r--src/main.cpp4
-rw-r--r--src/object-set.h39
-rw-r--r--src/path-chemistry.cpp3
-rw-r--r--src/preferences-skeleton.h6
-rw-r--r--src/selection-chemistry.cpp71
-rw-r--r--src/sp-ellipse.cpp7
-rw-r--r--src/sp-gradient.cpp10
-rw-r--r--src/sp-image.cpp2
-rw-r--r--src/sp-item-group.cpp5
-rw-r--r--src/sp-item.cpp3
-rw-r--r--src/sp-lpe-item.cpp34
-rw-r--r--src/sp-mesh-array.cpp153
-rw-r--r--src/sp-mesh-array.h7
-rw-r--r--src/sp-object.cpp4
-rw-r--r--src/sp-path.cpp62
-rw-r--r--src/splivarot.cpp163
-rw-r--r--src/splivarot.h21
-rw-r--r--src/ui/clipboard.cpp40
-rw-r--r--src/ui/dialog/aboutbox.cpp5
-rw-r--r--src/ui/dialog/align-and-distribute.cpp4
-rw-r--r--src/ui/dialog/calligraphic-profile-rename.cpp9
-rw-r--r--src/ui/dialog/clonetiler.cpp2
-rw-r--r--src/ui/dialog/dialog.cpp1
-rw-r--r--src/ui/dialog/dock-behavior.cpp3
-rw-r--r--src/ui/dialog/document-properties.cpp9
-rw-r--r--src/ui/dialog/export.cpp30
-rw-r--r--src/ui/dialog/export.h4
-rw-r--r--src/ui/dialog/filedialogimpl-gtkmm.cpp15
-rw-r--r--src/ui/dialog/filter-effects-dialog.cpp5
-rw-r--r--src/ui/dialog/floating-behavior.cpp1
-rw-r--r--src/ui/dialog/grid-arrange-tab.cpp321
-rw-r--r--src/ui/dialog/guides.cpp8
-rw-r--r--src/ui/dialog/icon-preview.cpp1
-rw-r--r--src/ui/dialog/inkscape-preferences.cpp2
-rw-r--r--src/ui/dialog/knot-properties.cpp12
-rw-r--r--src/ui/dialog/knot-properties.h11
-rw-r--r--src/ui/dialog/layer-properties.cpp9
-rw-r--r--src/ui/dialog/livepatheffect-add.cpp6
-rw-r--r--src/ui/dialog/livepatheffect-editor.cpp7
-rw-r--r--src/ui/dialog/lpe-fillet-chamfer-properties.cpp11
-rw-r--r--src/ui/dialog/lpe-powerstroke-properties.cpp7
-rw-r--r--src/ui/dialog/objects.cpp1
-rw-r--r--src/ui/dialog/ocaldialogs.cpp10
-rw-r--r--src/ui/dialog/panel-dialog.h6
-rw-r--r--src/ui/dialog/pixelartdialog.cpp5
-rw-r--r--src/ui/dialog/svg-fonts-dialog.cpp10
-rw-r--r--src/ui/dialog/text-edit.cpp5
-rw-r--r--src/ui/dialog/text-edit.h1
-rw-r--r--src/ui/dialog/tracedialog.cpp5
-rw-r--r--src/ui/dialog/transformation.cpp5
-rw-r--r--src/ui/dialog/undo-history.cpp10
-rw-r--r--src/ui/dialog/xml-tree.cpp1
-rw-r--r--src/ui/interface.cpp6
-rw-r--r--src/ui/object-edit.cpp2
-rw-r--r--src/ui/tool/node.cpp10
-rw-r--r--src/ui/tool/path-manipulator.cpp11
-rw-r--r--src/ui/tool/transform-handle-set.cpp5
-rw-r--r--src/ui/tools/calligraphic-tool.cpp4
-rw-r--r--src/ui/tools/eraser-tool.cpp12
-rw-r--r--src/ui/tools/flood-tool.cpp10
-rw-r--r--src/ui/tools/gradient-tool.cpp18
-rw-r--r--src/ui/tools/mesh-tool.cpp412
-rw-r--r--src/ui/tools/mesh-tool.h27
-rw-r--r--src/ui/tools/node-tool.cpp34
-rw-r--r--src/ui/tools/node-tool.h9
-rw-r--r--src/ui/tools/spray-tool.cpp4
-rw-r--r--src/ui/tools/tweak-tool.cpp185
-rw-r--r--src/ui/widget/dock-item.cpp10
-rw-r--r--src/ui/widget/dock.cpp2
-rw-r--r--src/ui/widget/font-button.cpp3
-rw-r--r--src/ui/widget/font-button.h1
-rw-r--r--src/ui/widget/frame.cpp30
-rw-r--r--src/ui/widget/frame.h3
-rw-r--r--src/ui/widget/panel.cpp20
-rw-r--r--src/ui/widget/panel.h5
-rw-r--r--src/ui/widget/preferences-widget.cpp6
-rw-r--r--src/ui/widget/registered-widget.h2
-rw-r--r--src/ui/widget/selected-style.cpp51
-rw-r--r--src/verbs.cpp18
-rw-r--r--src/verbs.h1
-rw-r--r--src/widgets/CMakeLists.txt2
-rw-r--r--src/widgets/dash-selector.cpp4
-rw-r--r--src/widgets/desktop-widget.cpp7
-rw-r--r--src/widgets/eraser-toolbar.cpp2
-rw-r--r--src/widgets/fill-style.cpp155
-rw-r--r--src/widgets/font-selector.cpp7
-rw-r--r--src/widgets/gimp/ruler.cpp43
-rw-r--r--src/widgets/gradient-selector.h3
-rw-r--r--src/widgets/image-menu-item.c1071
-rw-r--r--src/widgets/image-menu-item.h81
-rw-r--r--src/widgets/ink-action.cpp6
-rw-r--r--src/widgets/lpe-toolbar.cpp2
-rw-r--r--src/widgets/measure-toolbar.cpp2
-rw-r--r--src/widgets/mesh-toolbar.cpp210
-rw-r--r--src/widgets/paint-selector.cpp324
-rw-r--r--src/widgets/paint-selector.h24
-rw-r--r--src/widgets/paintbucket-toolbar.cpp2
-rw-r--r--src/widgets/select-toolbar.cpp18
-rw-r--r--src/widgets/stroke-style.cpp10
-rw-r--r--src/widgets/stroke-style.h2
-rw-r--r--src/widgets/text-toolbar.cpp174
-rw-r--r--src/widgets/toolbox.cpp25
238 files changed, 4574 insertions, 3604 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1102bf4bf..47aa02ef1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -521,7 +521,6 @@ set(INKSCAPE_TARGET_LIBS
depixelize_LIB
util_LIB
gc_LIB
- ${INKSCAPE_LIBS}
)
# Build everything except main and inkview.c in a shared library.
@@ -534,7 +533,7 @@ if(WITH_DBUS)
endif()
# Link the inkscape_base library against all external dependencies
-target_link_libraries(inkscape_base ${INKSCAPE_TARGET_LIBS})
+target_link_libraries(inkscape_base PRIVATE ${INKSCAPE_TARGET_LIBS} PUBLIC ${INKSCAPE_LIBS})
# Link inkscape and inkview against inkscape_base
target_link_libraries(inkscape inkscape_base)
diff --git a/src/color-profile.cpp b/src/color-profile.cpp
index 6ebf40f2c..cbd3475b4 100644
--- a/src/color-profile.cpp
+++ b/src/color-profile.cpp
@@ -307,7 +307,7 @@ void ColorProfile::set(unsigned key, gchar const *value) {
//# 1. Get complete URI of document
gchar const *docbase = doc->getURI();
- gchar* escaped = g_uri_escape_string(this->href, "!*'();:@=+$,/?#", TRUE);
+ gchar* escaped = g_uri_escape_string(this->href, "!*'();@=+$,/?#", TRUE);
//g_message("docbase:%s\n", docbase);
//org::w3c::dom::URI docUri(docbase);
@@ -781,7 +781,7 @@ std::vector<std::pair<Glib::ustring, bool> > ColorProfile::getBaseProfileDirs()
static bool isIccFile( gchar const *filepath )
{
bool isIccFile = false;
- struct stat st;
+ GStatBuf st;
if ( g_stat(filepath, &st) == 0 && (st.st_size > 128) ) {
//0-3 == size
//36-39 == 'acsp' 0x61637370
diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp
index 65e511245..4c07c76ea 100644
--- a/src/desktop-style.cpp
+++ b/src/desktop-style.cpp
@@ -209,7 +209,7 @@ sp_desktop_set_style(Inkscape::ObjectSet *set, SPDesktop *desktop, SPCSSAttr *cs
if (!change)
return;
-// 2. Emit signal
+// 2. Emit signal... See desktop->connectSetStyle in text-tool, tweak-tool, and gradient-drag.
bool intercepted = desktop->_set_style_signal.emit(css);
/** \todo
@@ -1045,6 +1045,7 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r
bool lineheight_normal = false;
bool lineheight_unit_proportional = false;
bool lineheight_unit_absolute = false;
+ bool lineheight_set = false; // Set true if any object has lineheight set.
double size_prev = 0;
double letterspacing_prev = 0;
@@ -1130,6 +1131,9 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r
lineheight_normal = false;
lineheight += lineheight_current * doc_scale;
}
+ if (style->line_height.set) {
+ lineheight_set = true;
+ }
if ((size_prev != 0 && style->font_size.computed != size_prev) ||
(letterspacing_prev != 0 && style->letter_spacing.computed != letterspacing_prev) ||
@@ -1205,6 +1209,9 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r
}
}
+ // Used by text toolbar unset 'line-height'
+ style_res->line_height.set = lineheight_set;
+
if (texts > 1) {
if (different || different_lineheight) {
return QUERY_STYLE_MULTIPLE_AVERAGED;
@@ -1907,7 +1914,7 @@ sp_desktop_query_style_from_list (const std::vector<SPItem*> &list, SPStyle *sty
int
sp_desktop_query_style(SPDesktop *desktop, SPStyle *style, int property)
{
- // Used by text tool and in gradient dragging
+ // Used by text tool and in gradient dragging. See connectQueryStyle.
int ret = desktop->_query_style_signal.emit(style, property);
if (ret != QUERY_STYLE_NOTHING)
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp
index a7625f4a1..8045007e7 100644
--- a/src/display/cairo-utils.cpp
+++ b/src/display/cairo-utils.cpp
@@ -13,7 +13,6 @@
#endif
#include "display/cairo-utils.h"
-#include <arpa/inet.h>
#include <stdexcept>
#include <glib/gstdio.h>
@@ -291,7 +290,7 @@ Pixbuf *Pixbuf::create_from_file(std::string const &fn)
if (!g_file_test(fn.c_str(), G_FILE_TEST_EXISTS)) {
return NULL;
}
- struct stat stdir;
+ GStatBuf stdir;
int val = g_stat(fn.c_str(), &stdir);
if (val == 0 && stdir.st_mode & S_IFDIR){
return NULL;
diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp
index 421a39fbd..94ee4ccfd 100644
--- a/src/display/canvas-axonomgrid.cpp
+++ b/src/display/canvas-axonomgrid.cpp
@@ -107,7 +107,12 @@ attach_all(Gtk::Grid &table, Gtk::Widget const *const arr[], unsigned size, int
table.attach(const_cast<Gtk::Widget&>(*arr[i+1]), 1, r, 2, 1);
} else if (arr[i]) {
Gtk::Label& label = reinterpret_cast<Gtk::Label&> (const_cast<Gtk::Widget&>(*arr[i]));
+#if GTK_CHECK_VERSION(3,16,0)
+ label.set_xalign(0.0);
+ label.set_yalign(0.5);
+#else
label.set_alignment (0.0);
+#endif
label.set_hexpand();
label.set_valign(Gtk::ALIGN_CENTER);
table.attach(label, 0, r, 3, 1);
diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp
index fa45fe02c..cf7d04555 100644
--- a/src/display/canvas-grid.cpp
+++ b/src/display/canvas-grid.cpp
@@ -139,7 +139,7 @@ grid_canvasitem_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned
};
CanvasGrid::CanvasGrid(SPNamedView * nv, Inkscape::XML::Node * in_repr, SPDocument *in_doc, GridType type)
- : visible(true), gridtype(type)
+ : visible(true), gridtype(type), legacy(false), pixel(false)
{
repr = in_repr;
doc = in_doc;
@@ -413,7 +413,12 @@ static inline void attach_all(Gtk::Grid &table, Gtk::Widget const *const arr[],
table.attach(const_cast<Gtk::Widget&>(*arr[i+1]), 1, r, 2, 1);
} else if (arr[i]) {
Gtk::Label& label = reinterpret_cast<Gtk::Label&> (const_cast<Gtk::Widget&>(*arr[i]));
+#if GTK_CHECK_VERSION(3,16,0)
+ label.set_xalign(0.0);
+ label.set_yalign(0.5);
+#else
label.set_alignment (0.0);
+#endif
label.set_hexpand();
label.set_valign(Gtk::ALIGN_CENTER);
table.attach(label, 0, r, 3, 1);
@@ -528,6 +533,10 @@ CanvasXYGrid::readRepr()
if( q.unit->type == UNIT_TYPE_LINEAR ) {
// Legacy grid not in 'user units'
origin[Geom::X] = q.value("px");
+ legacy = true;
+ if (q.unit->abbr == "px" ) {
+ pixel = true;
+ }
} else {
// Grid in 'user units'
origin[Geom::X] = q.quantity * scale_x;
@@ -541,6 +550,10 @@ CanvasXYGrid::readRepr()
if( q.unit->type == UNIT_TYPE_LINEAR ) {
// Legacy grid not in 'user units'
origin[Geom::Y] = q.value("px");
+ legacy = true;
+ if (q.unit->abbr == "px" ) {
+ pixel = true;
+ }
} else {
// Grid in 'user units'
origin[Geom::Y] = q.quantity * scale_y;
@@ -559,6 +572,10 @@ CanvasXYGrid::readRepr()
if( q.unit->type == UNIT_TYPE_LINEAR ) {
// Legacy grid not in 'user units'
spacing[Geom::X] = q.value("px");
+ legacy = true;
+ if (q.unit->abbr == "px" ) {
+ pixel = true;
+ }
} else {
// Grid in 'user units'
spacing[Geom::X] = q.quantity * scale_x;
@@ -578,6 +595,10 @@ CanvasXYGrid::readRepr()
if( q.unit->type == UNIT_TYPE_LINEAR ) {
// Legacy grid not in 'user units'
spacing[Geom::Y] = q.value("px");
+ legacy = true;
+ if (q.unit->abbr == "px" ) {
+ pixel = true;
+ }
} else {
// Grid in 'user units'
spacing[Geom::Y] = q.quantity * scale_y;
@@ -798,7 +819,23 @@ CanvasXYGrid::updateWidgets()
*/
}
+// For correcting old SVG Inkscape files
+void
+CanvasXYGrid::Scale (Geom::Scale const &scale ) {
+ origin *= scale;
+ spacing *= scale;
+ // Write out in 'user-units'
+ Inkscape::SVGOStringStream os_x, os_y, ss_x, ss_y;
+ os_x << origin[Geom::X];
+ os_y << origin[Geom::Y];
+ ss_x << spacing[Geom::X];
+ ss_y << spacing[Geom::Y];
+ repr->setAttribute("originx", os_x.str().c_str());
+ repr->setAttribute("originy", os_y.str().c_str());
+ repr->setAttribute("spacingx", ss_x.str().c_str());
+ repr->setAttribute("spacingy", ss_y.str().c_str());
+}
void
CanvasXYGrid::Update (Geom::Affine const &affine, unsigned int /*flags*/)
diff --git a/src/display/canvas-grid.h b/src/display/canvas-grid.h
index 557bd6dab..bf520467a 100644
--- a/src/display/canvas-grid.h
+++ b/src/display/canvas-grid.h
@@ -101,6 +101,9 @@ public:
static void on_repr_attr_changed (Inkscape::XML::Node * repr, const gchar *key, const gchar *oldval, const gchar *newval, bool is_interactive, void * data);
+ bool isLegacy() const { return legacy; }
+ bool isPixel() const { return pixel; }
+
bool isVisible() const { return (isEnabled() &&visible); };
bool isEnabled() const;
@@ -118,7 +121,11 @@ protected:
GridType gridtype;
-private:
+ // For dealing with old Inkscape SVG files (pre 0.92)
+ bool legacy;
+ bool pixel;
+
+ private:
CanvasGrid(const CanvasGrid&);
CanvasGrid& operator=(const CanvasGrid&);
};
@@ -129,6 +136,7 @@ public:
CanvasXYGrid(SPNamedView * nv, Inkscape::XML::Node * in_repr, SPDocument * in_doc);
virtual ~CanvasXYGrid();
+ virtual void Scale (Geom::Scale const &scale);
virtual void Update (Geom::Affine const &affine, unsigned int flags);
virtual void Render (SPCanvasBuf *buf);
diff --git a/src/display/curve.cpp b/src/display/curve.cpp
index 1998e9bec..6e662b17b 100644
--- a/src/display/curve.cpp
+++ b/src/display/curve.cpp
@@ -335,6 +335,20 @@ SPCurve::is_closed() const
}
/**
+ * True if both curves are equal
+ */
+bool
+SPCurve::is_equal(SPCurve * other) const
+{
+ if(other == NULL) {
+ return false;
+ } else if(_pathv == other->get_pathvector()){
+ return true;
+ }
+ return false;
+}
+
+/**
* Return last pathsegment (possibly the closing path segment) of the last path in PathVector or NULL.
* If the last path is empty (contains only a moveto), the function returns NULL
*/
diff --git a/src/display/curve.h b/src/display/curve.h
index 72e6df95c..8375e1105 100644
--- a/src/display/curve.h
+++ b/src/display/curve.h
@@ -45,6 +45,7 @@ public:
bool is_empty() const;
bool is_unset() const;
bool is_closed() const;
+ bool is_equal(SPCurve * other) const;
Geom::Curve const * last_segment() const;
Geom::Path const * last_path() const;
Geom::Curve const * first_segment() const;
diff --git a/src/display/drawing-group.cpp b/src/display/drawing-group.cpp
index 1a9cbfdcc..018f23e74 100644
--- a/src/display/drawing-group.cpp
+++ b/src/display/drawing-group.cpp
@@ -95,6 +95,7 @@ DrawingGroup::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigne
if (stop_at == NULL) {
// normal rendering
for (ChildrenList::iterator i = _children.begin(); i != _children.end(); ++i) {
+ i->setAntialiasing(_antialias);
i->render(dc, area, flags, stop_at);
}
} else {
@@ -103,10 +104,12 @@ DrawingGroup::_renderItem(DrawingContext &dc, Geom::IntRect const &area, unsigne
if (&*i == stop_at) return RENDER_OK; // do not render the stop_at item at all
if (i->isAncestorOf(stop_at)) {
// render its ancestors without masks, opacity or filters
+ i->setAntialiasing(_antialias);
i->render(dc, area, flags | RENDER_FILTER_BACKGROUND, stop_at);
// stop further rendering
return RENDER_OK;
} else {
+ i->setAntialiasing(_antialias);
i->render(dc, area, flags, stop_at);
}
}
diff --git a/src/display/drawing-item.cpp b/src/display/drawing-item.cpp
index 89ca66dc4..c4af81efc 100644
--- a/src/display/drawing-item.cpp
+++ b/src/display/drawing-item.cpp
@@ -132,7 +132,7 @@ DrawingItem::DrawingItem(Drawing &drawing)
, _propagate(0)
// , _renders_opacity(0)
, _pick_children(0)
- , _antialias(1)
+ , _antialias(2)
, _isolation(SP_CSS_ISOLATION_AUTO)
, _mix_blend_mode(SP_CSS_BLEND_NORMAL)
{}
@@ -291,7 +291,7 @@ DrawingItem::setOpacity(float opacity)
}
void
-DrawingItem::setAntialiasing(bool a)
+DrawingItem::setAntialiasing(unsigned a)
{
if (_antialias != a) {
_antialias = a;
@@ -699,10 +699,21 @@ DrawingItem::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flag
Geom::OptIntRect carea = Geom::intersect(area, _drawbox);
if (!carea) return RENDER_OK;
- if (_antialias) {
- cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_DEFAULT);
- } else {
- cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_NONE);
+ switch(_antialias){
+ case 0:
+ cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_NONE);
+ break;
+ case 1:
+ cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_FAST);
+ break;
+ case 2:
+ cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_GOOD);
+ break;
+ case 3:
+ cairo_set_antialias(dc.raw(), CAIRO_ANTIALIAS_BEST);
+ break;
+ default: // should not happen
+ g_assert_not_reached();
}
// render from cache if possible
diff --git a/src/display/drawing-item.h b/src/display/drawing-item.h
index 3c593ceaa..21f6ffacc 100644
--- a/src/display/drawing-item.h
+++ b/src/display/drawing-item.h
@@ -115,7 +115,7 @@ public:
virtual void setStyle(SPStyle *style, SPStyle *context_style = NULL);
virtual void setChildrenStyle(SPStyle *context_style);
void setOpacity(float opacity);
- void setAntialiasing(bool a);
+ void setAntialiasing(unsigned a);
void setIsolation(unsigned isolation); // CSS Compositing and Blending
void setBlendMode(unsigned blend_mode);
void setTransform(Geom::Affine const &trans);
@@ -222,7 +222,7 @@ protected:
//unsigned _renders_opacity : 1; ///< Whether object needs temporary surface for opacity
unsigned _pick_children : 1; ///< For groups: if true, children are returned from pick(),
/// otherwise the group is returned
- unsigned _antialias : 1; ///< Whether to use antialiasing
+ unsigned _antialias : 2; ///< antialiasing level (NONE/FAST/GOOD(DEFAULT)/BEST)
unsigned _isolation : 1;
unsigned _mix_blend_mode : 4;
diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp
index 1280a2db9..21af7b200 100644
--- a/src/display/drawing-text.cpp
+++ b/src/display/drawing-text.cpp
@@ -599,7 +599,7 @@ unsigned DrawingText::_renderItem(DrawingContext &dc, Geom::IntRect const &/*are
}
{
Inkscape::DrawingContext::Save save(dc);
- if (!_style || ! _style->vector_effect.computed == SP_VECTOR_EFFECT_NON_SCALING_STROKE) {
+ if (!_style || !(_style->vector_effect.computed == SP_VECTOR_EFFECT_NON_SCALING_STROKE)) {
dc.transform(_ctm);
}
if (has_stroke) {
diff --git a/src/display/drawing.cpp b/src/display/drawing.cpp
index eadd7e528..71fb94be0 100644
--- a/src/display/drawing.cpp
+++ b/src/display/drawing.cpp
@@ -167,10 +167,14 @@ Drawing::update(Geom::IntRect const &area, UpdateContext const &ctx, unsigned fl
}
void
-Drawing::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags)
+Drawing::render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags, int antialiasing)
{
if (_root) {
+ int prev_a = _root->_antialias;
+ if(antialiasing >= 0)
+ _root->setAntialiasing(antialiasing);
_root->render(dc, area, flags);
+ _root->setAntialiasing(prev_a);
}
if (colorMode() == COLORMODE_GRAYSCALE) {
diff --git a/src/display/drawing.h b/src/display/drawing.h
index 0c12b1510..e472c8f5b 100644
--- a/src/display/drawing.h
+++ b/src/display/drawing.h
@@ -68,7 +68,7 @@ public:
void setGrayscaleMatrix(double value_matrix[20]);
void update(Geom::IntRect const &area = Geom::IntRect::infinite(), UpdateContext const &ctx = UpdateContext(), unsigned flags = DrawingItem::STATE_ALL, unsigned reset = 0);
- void render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags = 0);
+ void render(DrawingContext &dc, Geom::IntRect const &area, unsigned flags = 0, int antialiasing = -1);
DrawingItem *pick(Geom::Point const &p, double delta, unsigned flags);
sigc::signal<void, DrawingItem *> signal_request_update;
diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp
index 17deea16d..f2271e0c6 100644
--- a/src/display/snap-indicator.cpp
+++ b/src/display/snap-indicator.cpp
@@ -287,7 +287,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap
} else if (p.getSource() != SNAPSOURCE_UNDEFINED) {
tooltip_str = g_strdup(source_name);
}
- double fontsize = prefs->getInt("/tools/measure/fontsize");
+ double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0);
if (tooltip_str) {
Geom::Point tooltip_pos = p.getPoint();
@@ -327,7 +327,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap
SP_CTRLRECT(box)->setDashed(true);
SP_CTRLRECT(box)->pickable = false; // See the extensive comment above
sp_canvas_item_move_to_z(box, 0);
- _snaptarget_bbox = _desktop->add_temporary_canvasitem(box, timeout_val);
+ _snaptarget_bbox = _desktop->add_temporary_canvasitem(box, timeout_val*1000.0);
}
}
}
diff --git a/src/display/sodipodi-ctrl.cpp b/src/display/sodipodi-ctrl.cpp
index 327fbce1f..27b6988c5 100644
--- a/src/display/sodipodi-ctrl.cpp
+++ b/src/display/sodipodi-ctrl.cpp
@@ -18,6 +18,7 @@ enum {
ARG_MODE,
ARG_ANCHOR,
ARG_SIZE,
+ ARG_ANGLE,
ARG_FILLED,
ARG_FILL_COLOR,
ARG_STROKED,
@@ -53,7 +54,7 @@ sp_ctrl_class_init (SPCtrlClass *klass)
g_object_class_install_property (g_object_class,
ARG_SIZE, g_param_spec_double ("size", "size", "Size", 0.0, G_MAXDOUBLE, 8.0, (GParamFlags) G_PARAM_READWRITE));
g_object_class_install_property (g_object_class,
- ARG_PIXBUF, g_param_spec_pointer ("pixbuf", "pixbuf", "Pixbuf", (GParamFlags) G_PARAM_READWRITE));
+ ARG_ANGLE, g_param_spec_double ("angle", "angle", "Angle", -G_MAXDOUBLE, G_MAXDOUBLE, 0.0, (GParamFlags) G_PARAM_READWRITE));
g_object_class_install_property (g_object_class,
ARG_FILLED, g_param_spec_boolean ("filled", "filled", "Filled", TRUE, (GParamFlags) G_PARAM_READWRITE));
g_object_class_install_property (g_object_class,
@@ -62,6 +63,8 @@ sp_ctrl_class_init (SPCtrlClass *klass)
ARG_STROKED, g_param_spec_boolean ("stroked", "stroked", "Stroked", FALSE, (GParamFlags) G_PARAM_READWRITE));
g_object_class_install_property (g_object_class,
ARG_STROKE_COLOR, g_param_spec_int ("stroke_color", "stroke_color", "Stroke Color", G_MININT, G_MAXINT, 0x000000ff, (GParamFlags) G_PARAM_READWRITE));
+ g_object_class_install_property (g_object_class,
+ ARG_PIXBUF, g_param_spec_pointer ("pixbuf", "pixbuf", "Pixbuf", (GParamFlags) G_PARAM_READWRITE));
item_class->destroy = sp_ctrl_destroy;
item_class->update = sp_ctrl_update;
@@ -95,6 +98,9 @@ sp_ctrl_set_property(GObject *object, guint prop_id, const GValue *value, GParam
ctrl->height = ctrl->width;
ctrl->defined = (ctrl->width > 0);
break;
+ case ARG_ANGLE:
+ ctrl->angle = (double)g_value_get_double(value);
+ break;
case ARG_FILLED:
ctrl->filled = g_value_get_boolean(value);
break;
@@ -151,6 +157,10 @@ sp_ctrl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec
g_value_set_double(value, ctrl->width);
break;
+ case ARG_ANGLE:
+ g_value_set_double(value, ctrl->angle);
+ break;
+
case ARG_FILLED:
g_value_set_boolean(value, ctrl->filled);
break;
@@ -192,6 +202,7 @@ sp_ctrl_init (SPCtrl *ctrl)
ctrl->stroked = 0;
ctrl->fill_color = 0x000000ff;
ctrl->stroke_color = 0x000000ff;
+ ctrl->angle = 0.0;
new (&ctrl->box) Geom::IntRect(0,0,0,0);
ctrl->cache = NULL;
@@ -291,6 +302,23 @@ sp_ctrl_point (SPCanvasItem *item, Geom::Point p, SPCanvasItem **actual_item)
return 1e18;
}
+bool
+sp_point_inside_line(Geom::Point a, Geom::Point b, Geom::Point c, double tolerance = 0.1){
+ //http://stackoverflow.com/questions/328107/how-can-you-determine-a-point-is-between-two-other-points-on-a-line-segment
+ return Geom::are_near(Geom::distance(a,c) + Geom::distance(c,b) , Geom::distance(a,b), tolerance);
+}
+
+bool
+sp_point_inside_triangle(Geom::Point p1,Geom::Point p2,Geom::Point p3, Geom::Point point){
+ using Geom::X;
+ using Geom::Y;
+ double denominator = (p1[X]*(p2[Y] - p3[Y]) + p1[Y]*(p3[X] - p2[X]) + p2[X]*p3[Y] - p2[Y]*p3[X]);
+ double t1 = (point[X]*(p3[Y] - p1[Y]) + point[Y]*(p1[X] - p3[X]) - p1[X]*p3[Y] + p1[Y]*p3[X]) / denominator;
+ double t2 = (point[X]*(p2[Y] - p1[Y]) + point[Y]*(p1[X] - p2[X]) - p1[X]*p2[Y] + p1[Y]*p2[X]) / -denominator;
+ double see = t1 + t2;
+ return 0 <= t1 && t1 <= 1 && 0 <= t2 && t2 <= 1 && see <= 1;
+}
+
static void
sp_ctrl_build_cache (SPCtrl *ctrl)
{
@@ -316,7 +344,7 @@ sp_ctrl_build_cache (SPCtrl *ctrl)
} else {
stroke_color = fill_color;
}
-
+ gint32 stroke_color_smooth = SP_RGBA32_F_COMPOSE(SP_RGBA32_R_F(stroke_color), SP_RGBA32_G_F(stroke_color), SP_RGBA32_B_F(stroke_color), 0.15);
width = (ctrl->width * 2 +1);
height = (ctrl->height * 2 +1);
c = ctrl->width; // Only used for pre-set square drawing
@@ -325,7 +353,24 @@ sp_ctrl_build_cache (SPCtrl *ctrl)
if (ctrl->cache) delete[] ctrl->cache;
ctrl->cache = new guint32[size];
-
+ Geom::Point point;
+ Geom::Point p1;
+ Geom::Point p2;
+ Geom::Point p3;
+ if(ctrl->shape == SP_CTRL_SHAPE_TRIANGLE){
+ Geom::Affine m = Geom::Translate(Geom::Point(-width/2.0,-height/2.0));
+ m *= Geom::Rotate(-ctrl->angle);
+ m *= Geom::Translate(Geom::Point(width/2.0, height/2.0));
+ p1 = Geom::Point(0,height/2);
+ p2 = Geom::Point(width - (width/M_PI), height/M_PI);
+ p3 = Geom::Point(width - (width/M_PI), height-(height/M_PI));
+ p1 *= m;
+ p2 *= m;
+ p3 *= m;
+ p1 = p1.floor();
+ p2 = p2.floor();
+ p3 = p3.floor();
+ }
switch (ctrl->shape) {
case SP_CTRL_SHAPE_SQUARE:
p = ctrl->cache;
@@ -407,6 +452,29 @@ sp_ctrl_build_cache (SPCtrl *ctrl)
ctrl->build = TRUE;
break;
+ case SP_CTRL_SHAPE_TRIANGLE:
+ p = ctrl->cache;
+ for(y = 0; y < height; y++) {
+ for(x = 0; x < width; x++) {
+ point = Geom::Point(x,y);
+ if (sp_point_inside_triangle(p1, p2, p3, point)) {
+ p[(y*width)+x] = fill_color;
+ } else if (point == p1 || point == p2 || point == p3 || sp_point_inside_line(p1, p2, point, 0.2) ||
+ sp_point_inside_line(p3, p1, point, 0.2))
+ {
+ p[(y*width)+x] = stroke_color;
+ } else if (sp_point_inside_line(p1, p2, point, 0.5) ||
+ sp_point_inside_line(p3, p1, point, 0.5))
+ {
+ p[(y*width)+x] = stroke_color_smooth;
+ } else {
+ p[(y*width)+x] = 0;
+ }
+ }
+ }
+ ctrl->build = TRUE;
+ break;
+
case SP_CTRL_SHAPE_CROSS:
p = ctrl->cache;
for (y = 0; y < height; y++) {
diff --git a/src/display/sodipodi-ctrl.h b/src/display/sodipodi-ctrl.h
index ecdb896a7..ac5ac9442 100644
--- a/src/display/sodipodi-ctrl.h
+++ b/src/display/sodipodi-ctrl.h
@@ -22,6 +22,7 @@ typedef enum {
SP_CTRL_SHAPE_SQUARE,
SP_CTRL_SHAPE_DIAMOND,
SP_CTRL_SHAPE_CIRCLE,
+ SP_CTRL_SHAPE_TRIANGLE,
SP_CTRL_SHAPE_CROSS,
SP_CTRL_SHAPE_BITMAP,
SP_CTRL_SHAPE_IMAGE
@@ -46,6 +47,7 @@ struct SPCtrl : public SPCanvasItem {
guint stroked : 1;
guint32 fill_color;
guint32 stroke_color;
+ gdouble angle;
Geom::IntRect box; /* NB! x1 & y1 are included */
guint32 *cache;
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 427cec20a..68eae0a65 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -21,6 +21,8 @@
# include <config.h>
#endif
+#include <gdkmm/devicemanager.h>
+#include <gdkmm/display.h>
#include <gdkmm/rectangle.h>
#include <cairomm/region.h>
@@ -67,6 +69,14 @@ struct SPCanvasGroupClass {
SPCanvasItemClass parent_class;
};
+static void ungrab_default_client_pointer(guint32 const time = GDK_CURRENT_TIME)
+{
+ auto const display = Gdk::Display::get_default();
+ auto const dm = display->get_device_manager();
+ auto const device = dm->get_client_pointer();
+ device->ungrab(time);
+}
+
/**
* A group of items.
*/
@@ -327,10 +337,7 @@ void sp_canvas_item_dispose(GObject *object)
if (item == item->canvas->_grabbed_item) {
item->canvas->_grabbed_item = NULL;
-
- auto dm = gdk_display_get_device_manager(gdk_display_get_default());
- auto device = gdk_device_manager_get_client_pointer(dm);
- gdk_device_ungrab(device, GDK_CURRENT_TIME);
+ ungrab_default_client_pointer();
}
if (item == item->canvas->_focused_item) {
@@ -653,10 +660,7 @@ void sp_canvas_item_ungrab(SPCanvasItem *item, guint32 etime)
}
item->canvas->_grabbed_item = NULL;
-
- auto dm = gdk_display_get_device_manager(gdk_display_get_default());
- auto device = gdk_device_manager_get_client_pointer(dm);
- gdk_device_ungrab(device, etime);
+ ungrab_default_client_pointer(etime);
}
/**
@@ -965,9 +969,7 @@ void SPCanvas::shutdownTransients()
if (_grabbed_item) {
_grabbed_item = NULL;
- auto dm = gdk_display_get_device_manager(gdk_display_get_default());
- auto device = gdk_device_manager_get_client_pointer(dm);
- gdk_device_ungrab(device, GDK_CURRENT_TIME);
+ ungrab_default_client_pointer();
}
removeIdle();
}
@@ -1691,11 +1693,12 @@ bool SPCanvas::paintRect(int xx0, int yy0, int xx1, int yy1)
// Save the mouse location
gint x, y;
- auto dm = gdk_display_get_device_manager(gdk_display_get_default());
- auto device = gdk_device_manager_get_client_pointer(dm);
+ auto const display = Gdk::Display::get_default();
+ auto const dm = display->get_device_manager();
+ auto const device = dm->get_client_pointer();
gdk_window_get_device_position(gtk_widget_get_window(GTK_WIDGET(this)),
- device,
+ device->gobj(),
&x, &y, NULL);
setup.mouse_loc = sp_canvas_window_to_world(this, Geom::Point(x,y));
diff --git a/src/display/sp-ctrlcurve.cpp b/src/display/sp-ctrlcurve.cpp
index 2e0e8105b..79ef20d6c 100644
--- a/src/display/sp-ctrlcurve.cpp
+++ b/src/display/sp-ctrlcurve.cpp
@@ -47,6 +47,8 @@ sp_ctrlcurve_init(SPCtrlCurve *ctrlcurve)
// Points are initialized to 0,0
ctrlcurve->rgba = 0x0000ff7f;
ctrlcurve->item=NULL;
+ ctrlcurve->corner0 = -1;
+ ctrlcurve->corner1 = -1;
}
namespace {
diff --git a/src/display/sp-ctrlcurve.h b/src/display/sp-ctrlcurve.h
index 847944f38..56b3089d9 100644
--- a/src/display/sp-ctrlcurve.h
+++ b/src/display/sp-ctrlcurve.h
@@ -31,6 +31,9 @@ struct SPCtrlCurve : public SPCtrlLine {
Geom::Point const &q2, Geom::Point const &q3);
Geom::Point p0, p1, p2, p3;
+
+ int corner0; // Used to store index of corner for finding dragger.
+ int corner1;
};
GType sp_ctrlcurve_get_type();
diff --git a/src/display/sp-ctrlline.cpp b/src/display/sp-ctrlline.cpp
index 6c5674935..c4ced2a33 100644
--- a/src/display/sp-ctrlline.cpp
+++ b/src/display/sp-ctrlline.cpp
@@ -52,6 +52,7 @@ static void sp_ctrlline_init(SPCtrlLine *ctrlline)
ctrlline->rgba = 0x0000ff7f;
ctrlline->s[Geom::X] = ctrlline->s[Geom::Y] = ctrlline->e[Geom::X] = ctrlline->e[Geom::Y] = 0.0;
ctrlline->item=NULL;
+ ctrlline->is_fill = true;
}
namespace {
diff --git a/src/display/sp-ctrlline.h b/src/display/sp-ctrlline.h
index b2e222437..bac0cfa54 100644
--- a/src/display/sp-ctrlline.h
+++ b/src/display/sp-ctrlline.h
@@ -33,6 +33,8 @@ struct SPCtrlLine : public SPCanvasItem {
SPItem *item; // the item to which this line belongs in some sense; may be NULL for some users
+ bool is_fill; // fill or stroke... used with meshes.
+
guint32 rgba;
Geom::Point s;
Geom::Point e;
diff --git a/src/document.cpp b/src/document.cpp
index a371fe1e5..8072ec53d 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -956,6 +956,7 @@ SPDocument::emitReconstructionFinish(void)
priv->_reconstruction_finish_signal.emit();
// indicates that gradients are reloaded (to rebuild the Auto palette)
priv->resources_changed_signals[g_quark_from_string("gradient")].emit();
+ priv->resources_changed_signals[g_quark_from_string("filter")].emit();
/**
diff --git a/src/extension/internal/cdr-input.cpp b/src/extension/internal/cdr-input.cpp
index b94b6d019..0435f1396 100644
--- a/src/extension/internal/cdr-input.cpp
+++ b/src/extension/internal/cdr-input.cpp
@@ -116,8 +116,8 @@ CdrImportDialog::CdrImportDialog(const std::vector<RVNGString> &vec)
// CONTROLS
// Buttons
- cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel")));
- okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok")));
+ cancelbutton = Gtk::manage(new Gtk::Button(_("_Cancel"), true));
+ okbutton = Gtk::manage(new Gtk::Button(_("_OK"), true));
// Labels
_labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:")));
@@ -214,6 +214,13 @@ void CdrImportDialog::_setPreviewPage()
SPDocument *CdrInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri)
{
+ #ifdef WIN32
+ // RVNGFileStream uses fopen() internally which unfortunately only uses ANSI encoding on Windows
+ // therefore attempt to convert uri to the system codepage
+ // even if this is not possible the alternate short (8.3) file name will be used if available
+ uri = g_win32_locale_filename_from_utf8(uri);
+ #endif
+
RVNGFileStream input(uri);
if (!libcdr::CDRDocument::isSupported(&input)) {
diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp
index d4c5d95a3..826176bc0 100644
--- a/src/extension/internal/emf-print.cpp
+++ b/src/extension/internal/emf-print.cpp
@@ -205,7 +205,7 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
} else {
p = ansi_uri;
}
- snprintf(buff, sizeof(buff) - 1, "Inkscape %s (%s)\1%s\1", Inkscape::version_string, __DATE__, p);
+ snprintf(buff, sizeof(buff) - 1, "Inkscape %s \1%s\1", Inkscape::version_string, p);
uint16_t *Description = U_Utf8ToUtf16le(buff, 0, NULL);
int cbDesc = 2 + wchar16len(Description); // also count the final terminator
(void) U_Utf16leEdit(Description, '\1', '\0'); // swap the temporary \1 characters for nulls
@@ -1064,7 +1064,7 @@ void PrintEmf::do_clip_if_present(SPStyle const *style){
g_error("Fatal programming error in PrintEmf::image at U_EMRSAVEDC_set");
}
(void) draw_pathv_to_EMF(combined_pathvector, tf);
- rec = U_EMRSELECTCLIPPATH_set(U_RGN_OR);
+ rec = U_EMRSELECTCLIPPATH_set(U_RGN_COPY);
if (!rec || emf_append((PU_ENHMETARECORD)rec, et, U_REC_FREE)) {
g_error("Fatal programming error in PrintEmf::do_clip_if_present at U_EMRSELECTCLIPPATH_set");
}
diff --git a/src/extension/internal/filter/filter.cpp b/src/extension/internal/filter/filter.cpp
index 0907845f8..0408d516e 100644
--- a/src/extension/internal/filter/filter.cpp
+++ b/src/extension/internal/filter/filter.cpp
@@ -143,6 +143,7 @@ void Filter::effect(Inkscape::Extension::Effect *module, Inkscape::UI::View::Vie
Inkscape::XML::Node * newfilterroot = xmldoc->createElement("svg:filter");
merge_filters(newfilterroot, filterdoc->root(), xmldoc);
defsrepr->appendChild(newfilterroot);
+ document->doc()->priv->resources_changed_signals[g_quark_from_string("filter")].emit();
Glib::ustring url = "url(#"; url += newfilterroot->attribute("id"); url += ")";
diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp
index 0c22fa399..a57396b17 100644
--- a/src/extension/internal/pdfinput/pdf-input.cpp
+++ b/src/extension/internal/pdfinput/pdf-input.cpp
@@ -85,8 +85,8 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
_poppler_doc = NULL;
#endif // HAVE_POPPLER_CAIRO
_pdf_doc = doc;
- cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel")));
- okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok")));
+ cancelbutton = Gtk::manage(new Gtk::Button(_("_Cancel"), true));
+ okbutton = Gtk::manage(new Gtk::Button(_("_OK"), true));
_labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:")));
// Page number
@@ -157,9 +157,50 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
okbutton->set_can_focus();
okbutton->set_can_default();
okbutton->set_relief(Gtk::RELIEF_NORMAL);
- this->get_action_area()->property_layout_style().set_value(Gtk::BUTTONBOX_END);
+
+#if GTK_CHECK_VERSION(3,16,0)
+ _labelSelect->set_xalign(0.5);
+ _labelSelect->set_yalign(0.5);
+ _labelTotalPages->set_xalign(0.5);
+ _labelTotalPages->set_yalign(0.5);
+ _labelPrecision->set_xalign(0.0);
+ _labelPrecision->set_yalign(0.5);
+ _labelPrecisionWarning->set_xalign(0.0);
+ _labelPrecisionWarning->set_yalign(0.5);
+ _labelPrecisionComment->set_xalign(0.5);
+ _labelPrecisionComment->set_yalign(0.5);
+#else
_labelSelect->set_alignment(0.5,0.5);
- _labelSelect->set_padding(4,0);
+ _labelTotalPages->set_alignment(0.5,0.5);
+ _labelPrecision->set_alignment(0,0.5);
+ _labelPrecisionWarning->set_alignment(0,0.5);
+ _labelPrecisionComment->set_alignment(0.5,0.5);
+#endif
+
+#if GTK_CHECK_VERSION(3,12,0)
+ _labelSelect->set_margin_start(4);
+ _labelSelect->set_margin_end(4);
+ _labelTotalPages->set_margin_start(4);
+ _labelTotalPages->set_margin_end(4);
+ _labelPrecision->set_margin_start(4);
+ _labelPrecision->set_margin_end(4);
+ _labelPrecisionWarning->set_margin_start(4);
+ _labelPrecisionWarning->set_margin_end(4);
+ _labelPrecisionComment->set_margin_start(4);
+ _labelPrecisionComment->set_margin_end(4);
+#else
+ _labelSelect->set_margin_left(4);
+ _labelSelect->set_margin_right(4);
+ _labelTotalPages->set_margin_left(4);
+ _labelTotalPages->set_margin_right(4);
+ _labelPrecision->set_margin_left(4);
+ _labelPrecision->set_margin_right(4);
+ _labelPrecisionWarning->set_margin_left(4);
+ _labelPrecisionWarning->set_margin_right(4);
+ _labelPrecisionComment->set_margin_left(4);
+ _labelPrecisionComment->set_margin_right(4);
+#endif
+
_labelSelect->set_justify(Gtk::JUSTIFY_LEFT);
_labelSelect->set_line_wrap(false);
_labelSelect->set_use_markup(false);
@@ -169,8 +210,6 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
_pageNumberSpin->set_numeric(true);
_pageNumberSpin->set_digits(0);
_pageNumberSpin->set_wrap(false);
- _labelTotalPages->set_alignment(0.5,0.5);
- _labelTotalPages->set_padding(4,0);
_labelTotalPages->set_justify(Gtk::JUSTIFY_LEFT);
_labelTotalPages->set_line_wrap(false);
_labelTotalPages->set_use_markup(false);
@@ -189,14 +228,10 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
vbox2->pack_start(*hbox3);
_pageSettingsFrame->add(*vbox2);
_pageSettingsFrame->set_border_width(4);
- _labelPrecision->set_alignment(0,0.5);
- _labelPrecision->set_padding(4,0);
_labelPrecision->set_justify(Gtk::JUSTIFY_LEFT);
_labelPrecision->set_line_wrap(true);
_labelPrecision->set_use_markup(false);
_labelPrecision->set_selectable(false);
- _labelPrecisionWarning->set_alignment(0,0.5);
- _labelPrecisionWarning->set_padding(4,0);
_labelPrecisionWarning->set_justify(Gtk::JUSTIFY_LEFT);
_labelPrecisionWarning->set_line_wrap(true);
_labelPrecisionWarning->set_use_markup(true);
@@ -213,6 +248,14 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
_importViaInternal->set_active(true);
_labelViaPoppler->set_line_wrap(true);
_labelViaInternal->set_line_wrap(true);
+
+# if GTK_CHECK_VERSION(3,16,0)
+ _labelViaPoppler->set_xalign(0);
+ _labelViaInternal->set_xalign(0);
+# else
+ _labelViaPoppler->set_alignment(0, 0.5);
+ _labelViaInternal->set_alignment(0, 0.5);
+# endif
#endif
_fallbackPrecisionSlider->set_size_request(180,-1);
@@ -222,8 +265,6 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
_fallbackPrecisionSlider->set_draw_value(true);
_fallbackPrecisionSlider->set_value_pos(Gtk::POS_TOP);
_labelPrecisionComment->set_size_request(90,-1);
- _labelPrecisionComment->set_alignment(0.5,0.5);
- _labelPrecisionComment->set_padding(4,0);
_labelPrecisionComment->set_justify(Gtk::JUSTIFY_LEFT);
_labelPrecisionComment->set_line_wrap(false);
_labelPrecisionComment->set_use_markup(false);
@@ -260,10 +301,10 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
// vbox3->pack_start(*hbox5, Gtk::PACK_SHRINK, 4);
_importSettingsFrame->add(*vbox3);
_importSettingsFrame->set_border_width(4);
- vbox1->pack_start(*_pageSettingsFrame, Gtk::PACK_EXPAND_PADDING, 0);
- vbox1->pack_start(*_importSettingsFrame, Gtk::PACK_EXPAND_PADDING, 0);
+ vbox1->pack_start(*_pageSettingsFrame, Gtk::PACK_SHRINK, 0);
+ vbox1->pack_start(*_importSettingsFrame, Gtk::PACK_SHRINK, 0);
hbox1->pack_start(*vbox1);
- hbox1->pack_start(*_previewArea, Gtk::PACK_EXPAND_WIDGET, 4);
+ hbox1->pack_start(*_previewArea, Gtk::PACK_SHRINK, 4);
get_content_area()->set_homogeneous(false);
get_content_area()->set_spacing(0);
diff --git a/src/extension/internal/pdfinput/pdf-input.h b/src/extension/internal/pdfinput/pdf-input.h
index c338207c1..a70d40a23 100644
--- a/src/extension/internal/pdfinput/pdf-input.h
+++ b/src/extension/internal/pdfinput/pdf-input.h
@@ -32,7 +32,6 @@ class Page;
class PDFDoc;
namespace Gtk {
- class Alignment;
class Button;
class CheckButton;
class ComboBoxText;
diff --git a/src/extension/internal/vsd-input.cpp b/src/extension/internal/vsd-input.cpp
index 2de2d0ec6..78783aa2d 100644
--- a/src/extension/internal/vsd-input.cpp
+++ b/src/extension/internal/vsd-input.cpp
@@ -118,8 +118,8 @@ VsdImportDialog::VsdImportDialog(const std::vector<RVNGString> &vec)
// CONTROLS
// Buttons
- cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel")));
- okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok")));
+ cancelbutton = Gtk::manage(new Gtk::Button(_("_Cancel"), true));
+ okbutton = Gtk::manage(new Gtk::Button(_("_OK"), true));
// Labels
_labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:")));
@@ -216,6 +216,13 @@ void VsdImportDialog::_setPreviewPage()
SPDocument *VsdInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri)
{
+ #ifdef WIN32
+ // RVNGFileStream uses fopen() internally which unfortunately only uses ANSI encoding on Windows
+ // therefore attempt to convert uri to the system codepage
+ // even if this is not possible the alternate short (8.3) file name will be used if available
+ uri = g_win32_locale_filename_from_utf8(uri);
+ #endif
+
RVNGFileStream input(uri);
if (!libvisio::VisioDocument::isSupported(&input)) {
diff --git a/src/extension/internal/wpg-input.cpp b/src/extension/internal/wpg-input.cpp
index 54a14fc72..12457791b 100644
--- a/src/extension/internal/wpg-input.cpp
+++ b/src/extension/internal/wpg-input.cpp
@@ -81,6 +81,13 @@ namespace Internal {
SPDocument *WpgInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * uri)
{
+ #ifdef WIN32
+ // RVNGFileStream uses fopen() internally which unfortunately only uses ANSI encoding on Windows
+ // therefore attempt to convert uri to the system codepage
+ // even if this is not possible the alternate short (8.3) file name will be used if available
+ uri = g_win32_locale_filename_from_utf8(uri);
+ #endif
+
RVNGInputStream* input = new RVNGFileStream(uri);
#if WITH_LIBWPG03
if (input->isStructured()) {
diff --git a/src/extension/param/description.cpp b/src/extension/param/description.cpp
index 326e75e4a..07aaa07cc 100644
--- a/src/extension/param/description.cpp
+++ b/src/extension/param/description.cpp
@@ -81,7 +81,8 @@ ParamDescription::get_widget (SPDocument * /*doc*/, Inkscape::XML::Node * /*node
int padding = 12 + _indent;
if (_mode == HEADER) {
label = Gtk::manage(new Gtk::Label(Glib::ustring("<b>") +newguitext + Glib::ustring("</b>"), Gtk::ALIGN_START));
- label->set_padding(0,5);
+ label->set_margin_top(5);
+ label->set_margin_bottom(5);
label->set_use_markup(true);
padding = _indent;
} else {
diff --git a/src/extension/prefdialog.cpp b/src/extension/prefdialog.cpp
index 1ca590e85..fcc88853d 100644
--- a/src/extension/prefdialog.cpp
+++ b/src/extension/prefdialog.cpp
@@ -8,7 +8,6 @@
*/
#include "prefdialog.h"
-#include <gtkmm/stock.h>
#include <gtkmm/checkbutton.h>
#include <gtkmm/separator.h>
#include <glibmm/i18n.h>
@@ -71,11 +70,8 @@ PrefDialog::PrefDialog (Glib::ustring name, gchar const * help, Gtk::Widget * co
if (_help == NULL)
help_button->set_sensitive(false);
*/
- _button_cancel = add_button(_effect == NULL ? Gtk::Stock::CANCEL : Gtk::Stock::CLOSE, Gtk::RESPONSE_CANCEL);
- _button_cancel->set_use_stock(true);
-
- _button_ok = add_button(_effect == NULL ? Gtk::Stock::OK : Gtk::Stock::APPLY, Gtk::RESPONSE_OK);
- _button_ok->set_use_stock(true);
+ _button_cancel = add_button(_effect == NULL ? _("_Cancel") : _("_Close"), Gtk::RESPONSE_CANCEL);
+ _button_ok = add_button(_effect == NULL ? _("_OK") : _("_Apply"), Gtk::RESPONSE_OK);
set_default_response(Gtk::RESPONSE_OK);
_button_ok->grab_focus();
diff --git a/src/file.cpp b/src/file.cpp
index 49d7fece5..6613b1e65 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -11,9 +11,10 @@
* Jon A. Cruz <jon@joncruz.org>
* Abhishek Sharma
* David Xiong
+ * Tavmjong Bah
*
* Copyright (C) 2006 Johan Engelen <johan@shouraizou.nl>
- * Copyright (C) 1999-2012 Authors
+ * Copyright (C) 1999-2016 Authors
* Copyright (C) 2004 David Turner
* Copyright (C) 2001-2002 Ximian, Inc.
*
@@ -30,9 +31,12 @@
# include "config.h"
#endif
+#include <gtkmm.h>
+
#include "ui/dialog/ocaldialogs.h"
#include "desktop.h"
+#include "extension/effect.h"
#include "document-private.h"
#include "document-undo.h"
#include "ui/tools/tool-base.h"
@@ -61,9 +65,13 @@
#include "event-log.h"
#include "ui/dialog/font-substitution.h"
-#include <gtkmm/main.h>
-#include <glibmm/miscutils.h>
-#include <glibmm/convert.h>
+// For updating old Inkscape SVG files
+#include "display/canvas-grid.h"
+#include "sp-guide.h"
+#include "selection-chemistry.h"
+#include "persp3d.h"
+#include "proj_pt.h"
+#include "ui/shape-editor.h"
using Inkscape::DocumentUndo;
@@ -130,15 +138,6 @@ SPDesktop *sp_file_new(const std::string &templ)
DocumentUndo::setUndoSensitive(doc, true);
}
- // Set viewBox if it doesn't exist
- if (!doc->getRoot()->viewBox_set
- && (doc->getRoot()->width.unit != SVGLength::PERCENT)
- && (doc->getRoot()->height.unit != SVGLength::PERCENT)) {
- DocumentUndo::setUndoSensitive(doc, false);
- doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDisplayUnit()), doc->getHeight().value(doc->getDisplayUnit())));
- DocumentUndo::setUndoSensitive(doc, true);
- }
-
SPDesktop *olddesktop = SP_ACTIVE_DESKTOP;
if (olddesktop)
olddesktop->setWaitingCursor();
@@ -241,6 +240,43 @@ sp_file_exit()
}
+// Quick and dirty internal backup function
+bool sp_file_save_backup( Glib::ustring uri ) {
+
+ Glib::ustring out = uri;
+ out.insert(out.find(".svg"),"_backup");
+
+ FILE *filein = Inkscape::IO::fopen_utf8name(uri.c_str(), "rb");
+ if (!filein) {
+ std::cerr << "sp_file_save_backup: failed to open: " << uri << std::endl;
+ return false;
+ }
+
+ FILE *fileout = Inkscape::IO::fopen_utf8name(out.c_str(), "wb");
+ if (!fileout) {
+ std::cerr << "sp_file_save_backup: failed to open: " << out << std::endl;
+ fclose( filein );
+ return false;
+ }
+
+ int ch;
+ while ((ch = fgetc(filein)) != EOF) {
+ fputc(ch, fileout);
+ }
+ fflush(fileout);
+
+ bool return_value = true;
+ if (ferror(fileout)) {
+ std::cerr << "sp_file_save_backup: error when writing to: " << out << std::endl;
+ return_value = false;
+ }
+
+ fclose(filein);
+ fclose(fileout);
+
+ return return_value;
+}
+
/*######################
## O P E N
######################*/
@@ -281,14 +317,6 @@ bool sp_file_open(const Glib::ustring &uri,
}
if (doc) {
- // Set viewBox if it doesn't exist
- if (!doc->getRoot()->viewBox_set
- && (doc->getRoot()->width.unit != SVGLength::PERCENT)
- && (doc->getRoot()->height.unit != SVGLength::PERCENT)) {
- DocumentUndo::setUndoSensitive(doc, false);
- doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDisplayUnit()), doc->getHeight().value(doc->getDisplayUnit())));
- DocumentUndo::setUndoSensitive(doc, true);
- }
SPDocument *existing = desktop ? desktop->getDocument() : NULL;
if (existing && existing->virgin && replace_empty) {
@@ -315,6 +343,498 @@ bool sp_file_open(const Glib::ustring &uri,
root->original.inkscape = root->version.inkscape;
root->original.svg = root->version.svg;
+ if (INKSCAPE.use_gui()) {
+
+ // See if we need to offer the user a fix for the 90->96 px per inch change.
+ // std::cout << "SPFileOpen:" << std::endl;
+ // std::cout << " Version: " << sp_version_to_string(root->version.inkscape) << std::endl;
+
+ if ( sp_version_inside_range( root->version.inkscape, 0, 1, 0, 92 ) ) {
+
+ // std::cout << " SVG file from old Inkscape version detected: "
+ // << sp_version_to_string(root->version.inkscape) << std::endl;
+ static const double ratio = 90.0/96.0;
+
+ bool need_fix_viewbox = false;
+ bool need_fix_units = false;
+ bool need_fix_guides = false;
+ bool need_fix_grid_mm = false;
+ bool need_fix_box3d = false;
+ bool did_scaling = false;
+
+ // Check if potentially need viewbox or unit fix
+ switch (root->width.unit) {
+ case SP_CSS_UNIT_PC:
+ case SP_CSS_UNIT_PT:
+ case SP_CSS_UNIT_MM:
+ case SP_CSS_UNIT_CM:
+ case SP_CSS_UNIT_IN:
+ need_fix_viewbox = true;
+ break;
+ case SP_CSS_UNIT_NONE:
+ case SP_CSS_UNIT_PX:
+ need_fix_units = true;
+ break;
+ case SP_CSS_UNIT_EM:
+ case SP_CSS_UNIT_EX:
+ case SP_CSS_UNIT_PERCENT:
+ // OK
+ break;
+ default:
+ std::cerr << "sp_file_open: Unhandled width unit!" << std::endl;
+ }
+
+ switch (root->height.unit) {
+ case SP_CSS_UNIT_PC:
+ case SP_CSS_UNIT_PT:
+ case SP_CSS_UNIT_MM:
+ case SP_CSS_UNIT_CM:
+ case SP_CSS_UNIT_IN:
+ need_fix_viewbox = true;
+ break;
+ case SP_CSS_UNIT_NONE:
+ case SP_CSS_UNIT_PX:
+ need_fix_units = true;
+ break;
+ case SP_CSS_UNIT_EM:
+ case SP_CSS_UNIT_EX:
+ case SP_CSS_UNIT_PERCENT:
+ // OK
+ break;
+ default:
+ std::cerr << "sp_file_open: Unhandled height unit!" << std::endl;
+ }
+
+ // std::cout << "Absolute SVG units in root? " << (need_fix_viewbox?"true":"false") << std::endl;
+ // std::cout << "User units in root? " << (need_fix_units ?"true":"false") << std::endl;
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ if (!root->viewBox_set && need_fix_viewbox) {
+
+ Glib::ustring msg = _(
+ "Old Inkscape files use 1in == 90px. CSS requires 1in == 96px.\n"
+ "Drawing elements may be too small. This can be corrected by\n"
+ "either setting the SVG 'viewBox' to compensate or by scaling\n"
+ "all the elements in the drawing.");
+ Gtk::Dialog scaleDialog( _("Old Inkscape file detected (90 DPI)"), false);
+
+ Gtk::Label info;
+ info.set_markup(msg.c_str());
+ info.show();
+ scaleDialog.get_content_area()->pack_start(info, false, false, 20);
+
+ Gtk::CheckButton backupButton( _("Create backup file (in same directory).") );
+ bool backup = prefs->getBool("/options/dpifixbackup", true);
+ backupButton.set_active( backup );
+ backupButton.show();
+ scaleDialog.get_content_area()->pack_start(backupButton, false, false, 20);
+
+ scaleDialog.add_button(_("Set 'viewBox'"), 1);
+ scaleDialog.add_button(_("Scale elements"), 2);
+ scaleDialog.add_button(_("Ignore"), 3);
+ scaleDialog.add_button("Scale test - group", 4);
+ scaleDialog.add_button("Scale test - children", 5);
+ scaleDialog.add_button("Scale test - all", 6);
+
+ gint response = scaleDialog.run();
+ backup = backupButton.get_active();
+ prefs->setBool("/options/dpifixbackup", backup);
+
+ if ( backup && response != 3) {
+ sp_file_save_backup( uri );
+ }
+
+ if (response == 1) {
+
+ doc->setViewBox(Geom::Rect::from_xywh(
+ 0, 0,
+ doc->getWidth().value("px") * ratio,
+ doc->getHeight().value("px") * ratio));
+
+ } else if (response == 2 ) {
+
+ std::list<Inkscape::Extension::Effect *> effects;
+ Inkscape::Extension::db.get_effect_list(effects);
+ std::list<Inkscape::Extension::Effect *>::iterator it = effects.begin();
+ bool did = false;
+ while (it != effects.end()) {
+ if (strcmp((*it)->get_id(), "org.inkscape.dpi90to96") == 0) {
+ Inkscape::UI::View::View *view = desktop;
+ (*it)->effect(view);
+ did = true;
+ break;
+ }
+ ++it;
+ }
+ if (!did) {
+ std::cerr << "sp_file_open: Failed to find dpi90to96 extension." << std::endl;
+ }
+ did_scaling = true;
+
+ } else if (response == 4) {
+
+ // Save preferences
+ bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive",true);
+ bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);
+
+ prefs->setBool("/options/kbselection/onlysensitive", false);
+ prefs->setBool("/options/kbselection/onlyvisible", false);
+
+ Inkscape::Selection *selection = desktop->getSelection();
+ Inkscape::SelectionHelper::selectAllInAll( desktop );
+ selection->group();
+ SPItem * group = selection->singleItem();
+ if (group) {
+ group->setAttribute("transform","scale(1.06666667,1.06666667)");
+ } else {
+ std::cerr << "sp_file_open: Failed to get group!" << std::endl;
+ }
+ selection->clear();
+ selection->add( group );
+ selection->ungroup();
+ selection->clear();
+
+ prefs->setBool("/options/kbselection/onlysensitive", onlysensitive);
+ prefs->setBool("/options/kbselection/onlyvisible", onlyvisible );
+
+ did_scaling = true;
+
+ } else if (response == 5) {
+
+ // Save preferences
+ bool transform_stroke = prefs->getBool("/options/transform/stroke", true);
+ bool transform_rectcorners = prefs->getBool("/options/transform/rectcorners", true);
+ bool transform_pattern = prefs->getBool("/options/transform/pattern", true);
+ bool transform_gradient = prefs->getBool("/options/transform/gradient", true);
+
+ prefs->setBool("/options/transform/stroke", true);
+ prefs->setBool("/options/transform/rectcorners", true);
+ prefs->setBool("/options/transform/pattern", true);
+ prefs->setBool("/options/transform/gradient", true);
+
+ Inkscape::UI::ShapeEditor::blockSetItem(true);
+ doc->getRoot()->scaleChildItemsRec(Geom::Scale(1/ratio),Geom::Point(0, 0), false);
+ Inkscape::UI::ShapeEditor::blockSetItem(false);
+
+ // Restore preferences
+ prefs->setBool("/options/transform/stroke", transform_stroke);
+ prefs->setBool("/options/transform/rectcorners", transform_rectcorners);
+ prefs->setBool("/options/transform/pattern", transform_pattern);
+ prefs->setBool("/options/transform/gradient", transform_gradient);
+
+ } else if (response == 6) {
+
+ // Save preferences
+ bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive",true);
+ bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);
+
+ prefs->setBool("/options/kbselection/onlysensitive", false);
+ prefs->setBool("/options/kbselection/onlyvisible", false);
+
+ Inkscape::Selection *selection = desktop->getSelection();
+ Inkscape::SelectionHelper::selectAllInAll( desktop );
+
+ double height = root->height.computed;
+ selection->setScaleRelative( Geom::Point(0,height), Geom::Scale(96.0/90.0,96.0/90.0) );
+ selection->clear();
+
+ prefs->setBool("/options/kbselection/onlysensitive", onlysensitive);
+ prefs->setBool("/options/kbselection/onlyvisible", onlyvisible );
+
+ did_scaling = true;
+
+ }
+
+ need_fix_box3d = false; // setScaleRelative() handles box3d
+ need_fix_guides = true; // Always fix guides
+ }
+
+ else if (need_fix_units) {
+ Glib::ustring msg = _(
+ "Old Inkscape files use 1in == 90px. CSS requires 1in == 96px.\n"
+ "Drawings meant to match a physical size (e.g. Letter or A4)\n"
+ "will be too small. Scaling the drawing can correct for this.\n"
+ "Internal scaling can be handled either by setting the SVG 'viewBox'\n"
+ "attribute to compensate or by scaling all objects in the drawing.");
+ Gtk::Dialog scaleDialog( _("Old Inkscape file detected (90 DPI)"), false);
+
+ Gtk::Label info;
+ info.set_markup(msg.c_str());
+ info.show();
+ scaleDialog.get_content_area()->pack_start(info, false, false, 20);
+
+ Gtk::CheckButton backupButton( _("Create backup file (in same directory).") );
+ bool backup = prefs->getBool("/options/dpifixbackup", true);
+ backupButton.set_active( backup );
+ backupButton.show();
+ scaleDialog.get_content_area()->pack_start(backupButton, false, false, 20);
+
+ scaleDialog.add_button(_("Set 'viewBox'"), 1);
+ scaleDialog.add_button(_("Scale elements"), 2);
+ scaleDialog.add_button(_("Ignore"), 3);
+ scaleDialog.add_button("Scale test - group", 4);
+ scaleDialog.add_button("Scale test - children", 5);
+ scaleDialog.add_button("Scale test - all", 6);
+
+ gint response = scaleDialog.run();
+ backup = backupButton.get_active();
+ prefs->setBool("/options/dpifixbackup", backup);
+
+ if ( backup && response != 3) {
+ sp_file_save_backup( uri );
+ }
+
+ if (response == 1) {
+
+ if (!root->viewBox_set) {
+ doc->setViewBox(Geom::Rect::from_xywh(
+ 0, 0,
+ doc->getWidth().value("px"),
+ doc->getHeight().value("px")));
+ }
+ Inkscape::Util::Quantity width =
+ Inkscape::Util::Quantity(doc->getWidth().value("px")/ratio, "px" );
+ Inkscape::Util::Quantity height =
+ Inkscape::Util::Quantity(doc->getHeight().value("px")/ratio,"px" );
+ doc->setWidthAndHeight( width, height, false );
+
+ need_fix_guides = true; // Only fix guides if drawing scaled
+ need_fix_box3d = true;
+
+ } else if (response == 2) {
+
+ std::list<Inkscape::Extension::Effect *> effects;
+ Inkscape::Extension::db.get_effect_list(effects);
+ std::list<Inkscape::Extension::Effect *>::iterator it = effects.begin();
+ bool did = false;
+ while (it != effects.end()){
+ if (strcmp((*it)->get_id(), "org.inkscape.dpi90to96") == 0) {
+ Inkscape::UI::View::View *view = desktop;
+ (*it)->effect(view);
+ did = true;
+ break;
+ }
+ ++it;
+ }
+ if (!did) {
+ std::cerr << "sp_file_open: Failed to find dpi90to96 extension." << std::endl;
+ }
+ need_fix_guides = true; // Only fix guides if drawing scaled
+ did_scaling = true;
+
+ } else if (response == 4) {
+
+ Inkscape::Util::Quantity width =
+ Inkscape::Util::Quantity(doc->getWidth().value("px")/ratio, "px" );
+ Inkscape::Util::Quantity height =
+ Inkscape::Util::Quantity(doc->getHeight().value("px")/ratio,"px" );
+ doc->setWidthAndHeight( width, height, false );
+
+ if (!root->viewBox_set) {
+
+ // Save preferences
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive",true);
+ bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);
+
+ prefs->setBool("/options/kbselection/onlysensitive", false);
+ prefs->setBool("/options/kbselection/onlyvisible", false);
+
+ Inkscape::Selection *selection = desktop->getSelection();
+ Inkscape::SelectionHelper::selectAllInAll( desktop );
+ selection->group();
+ SPItem * group = selection->singleItem();
+ if (group) {
+ group->setAttribute("transform","scale(1.06666667,1.06666667)");
+ } else {
+ std::cerr << "sp_file_open: Failed to get group!" << std::endl;
+ }
+ selection->clear();
+ selection->add( group );
+ selection->ungroup();
+ selection->clear();
+
+ prefs->setBool("/options/kbselection/onlysensitive", onlysensitive);
+ prefs->setBool("/options/kbselection/onlyvisible", onlyvisible );
+
+ did_scaling = true;
+ }
+
+ need_fix_box3d = true;
+ need_fix_guides = true; // Only fix guides if drawing scaled
+
+ } else if (response == 5) {
+
+ Inkscape::Util::Quantity width =
+ Inkscape::Util::Quantity(doc->getWidth().value("px")/ratio, "px" );
+ Inkscape::Util::Quantity height =
+ Inkscape::Util::Quantity(doc->getHeight().value("px")/ratio,"px" );
+ doc->setWidthAndHeight( width, height, false );
+
+ if (!root->viewBox_set) {
+
+ // Save preferences
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool transform_stroke = prefs->getBool("/options/transform/stroke", true);
+ bool transform_rectcorners = prefs->getBool("/options/transform/rectcorners", true);
+ bool transform_pattern = prefs->getBool("/options/transform/pattern", true);
+ bool transform_gradient = prefs->getBool("/options/transform/gradient", true);
+
+ prefs->setBool("/options/transform/stroke", true);
+ prefs->setBool("/options/transform/rectcorners", true);
+ prefs->setBool("/options/transform/pattern", true);
+ prefs->setBool("/options/transform/gradient", true);
+
+ Inkscape::UI::ShapeEditor::blockSetItem(true);
+ doc->getRoot()->scaleChildItemsRec(Geom::Scale(1/ratio),Geom::Point(0, 0), false);
+ Inkscape::UI::ShapeEditor::blockSetItem(false);
+
+ // Restore preferences
+ prefs->setBool("/options/transform/stroke", transform_stroke);
+ prefs->setBool("/options/transform/rectcorners", transform_rectcorners);
+ prefs->setBool("/options/transform/pattern", transform_pattern);
+ prefs->setBool("/options/transform/gradient", transform_gradient);
+
+ did_scaling = true;
+
+ }
+
+ } else if (response == 6) {
+
+ double old_height = root->height.computed;
+ Inkscape::Util::Quantity width =
+ Inkscape::Util::Quantity(doc->getWidth().value("px")/ratio, "px" );
+ Inkscape::Util::Quantity height =
+ Inkscape::Util::Quantity(doc->getHeight().value("px")/ratio,"px" );
+ doc->setWidthAndHeight( width, height, false );
+
+ if (!root->viewBox_set) {
+
+ // Save preferences
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive",true);
+ bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true);
+
+ prefs->setBool("/options/kbselection/onlysensitive", false);
+ prefs->setBool("/options/kbselection/onlyvisible", false);
+
+ Inkscape::Selection *selection = desktop->getSelection();
+ Inkscape::SelectionHelper::selectAllInAll( desktop );
+ double height = root->height.computed;
+
+ // So far we have just enlarged the drawing but due to the
+ // inverted coordinate system we must scale around the old
+ // height position.
+ selection->setScaleRelative( Geom::Point(0,old_height), Geom::Scale(96.0/90.0,96.0/90.0) );
+ selection->clear();
+
+ prefs->setBool("/options/kbselection/onlysensitive", onlysensitive);
+ prefs->setBool("/options/kbselection/onlyvisible", onlyvisible );
+
+ did_scaling = true;
+ }
+
+ need_fix_box3d = false; // setScaleRelative() handls box3s
+ need_fix_guides = true; // Only fix guides if drawing scaled
+
+ } else {
+ // Ignore
+ need_fix_grid_mm = true;
+ }
+ }
+
+ // Fix guides and grids and perspective
+ for (SPObject *child = root->firstChild() ; child; child = child->getNext() ) {
+ SPNamedView *nv = dynamic_cast<SPNamedView *>(child);
+ if (nv) {
+ if (need_fix_guides) {
+ // std::cout << "Fixing guides" << std::endl;
+ for (SPObject *child2 = nv->firstChild() ; child2; child2 = child2->getNext() ) {
+ SPGuide *gd = dynamic_cast<SPGuide *>(child2);
+ if (gd) {
+ gd->moveto( gd->getPoint() / ratio, true );
+ }
+ }
+ }
+
+ for(std::vector<Inkscape::CanvasGrid *>::const_iterator it=nv->grids.begin();it!=nv->grids.end();++it ) {
+ Inkscape::CanvasXYGrid *xy = dynamic_cast<Inkscape::CanvasXYGrid *>(*it);
+ if (xy) {
+ // std::cout << "A grid: " << xy->getSVGName() << std::endl;
+ // std::cout << " Origin: " << xy->origin
+ // << " Spacing: " << xy->spacing << std::endl;
+ // std::cout << (xy->isLegacy()?" Legacy":" Not Legacy") << std::endl;
+ Geom::Scale scale = doc->getDocumentScale();
+ if (xy->isLegacy()) {
+ if (xy->isPixel()) {
+ if (need_fix_grid_mm) {
+ xy->Scale( Geom::Scale(1,1) ); // See note below
+ } else {
+ scale *= Geom::Scale(ratio,ratio);
+ xy->Scale( scale.inverse() ); /* *** */
+ }
+ } else {
+ if (need_fix_grid_mm) {
+ xy->Scale( Geom::Scale(ratio,ratio) );
+ } else {
+ xy->Scale( scale.inverse() ); /* *** */
+ }
+ }
+ } else {
+ if (need_fix_guides) {
+ if(did_scaling){
+ xy->Scale( Geom::Scale(ratio,ratio).inverse() );
+ } else {
+ // HACK: Scaling the document does not seem to cause
+ // grids defined in document units to be updated.
+ // This forces an update.
+ xy->Scale( Geom::Scale(1,1) );
+ }
+ }
+ }
+ }
+ }
+ } // If SPNamedView
+
+ SPDefs *defs = dynamic_cast<SPDefs *>(child);
+ if (defs && need_fix_box3d) {
+ for (SPObject *child = defs->firstChild() ; child; child = child->getNext() ) {
+ Persp3D* persp3d = dynamic_cast<Persp3D *>(child);
+ if (persp3d) {
+ std::vector<Glib::ustring> tokens;
+
+ const gchar* vp_x = persp3d->getAttribute("inkscape:vp_x");
+ const gchar* vp_y = persp3d->getAttribute("inkscape:vp_y");
+ const gchar* vp_z = persp3d->getAttribute("inkscape:vp_z");
+ const gchar* vp_o = persp3d->getAttribute("inkscape:persp3d-origin");
+ // std::cout << "Found Persp3d: "
+ // << " vp_x: " << vp_x
+ // << " vp_y: " << vp_y
+ // << " vp_z: " << vp_z << std::endl;
+ Proj::Pt2 pt_x (vp_x);
+ Proj::Pt2 pt_y (vp_y);
+ Proj::Pt2 pt_z (vp_z);
+ Proj::Pt2 pt_o (vp_o);
+ pt_x = pt_x * (1.0/ratio);
+ pt_y = pt_y * (1.0/ratio);
+ pt_z = pt_z * (1.0/ratio);
+ pt_o = pt_o * (1.0/ratio);
+ persp3d->setAttribute("inkscape:vp_x",pt_x.coord_string());
+ persp3d->setAttribute("inkscape:vp_y",pt_y.coord_string());
+ persp3d->setAttribute("inkscape:vp_z",pt_z.coord_string());
+ persp3d->setAttribute("inkscape:persp3d-origin",pt_o.coord_string());
+ }
+ }
+ }
+ } // Look for SPNamedView and SPDefs loop
+
+ // desktop->getDocument()->ensureUpToDate(); // Does not update box3d!
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_NONE, _("Update Document"));
+
+ } // If old Inkscape version
+ } // If use_gui
+
// resize the window to match the document properties
sp_namedview_window_from_document(desktop);
sp_namedview_update_layers_from_document(desktop);
@@ -1113,8 +1633,12 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place)
for (Inkscape::XML::Node *obj = clipboard->firstChild() ; obj ; obj = obj->next()) {
if(target_document->getObjectById(obj->attribute("id"))) continue;
Inkscape::XML::Node *obj_copy = obj->duplicate(target_document->getReprDoc());
- target_parent->appendChild(obj_copy);
+ SPObject * pasted = desktop->currentLayer()->appendChildRepr(obj_copy);
Inkscape::GC::release(obj_copy);
+ SPLPEItem * pasted_lpe_item = dynamic_cast<SPLPEItem *>(pasted);
+ if (pasted_lpe_item){
+ pasted_lpe_item->forkPathEffectsIfNecessary(1);
+ }
pasted_objects_not.push_back(obj_copy);
}
Inkscape::Selection *selection = desktop->getSelection();
@@ -1159,6 +1683,7 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place)
selection->moveRelative(offset);
}
+ target_document->emitReconstructionFinish();
}
@@ -1258,6 +1783,7 @@ file_import(SPDocument *in_doc, const Glib::ustring &uri,
}
}
}
+ in_doc->emitReconstructionFinish();
if (newgroup) new_obj = place_to_insert->appendChildRepr(newgroup);
// release some stuff
diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp
index c133bfa7c..05f594f86 100644
--- a/src/gradient-chemistry.cpp
+++ b/src/gradient-chemistry.cpp
@@ -1583,7 +1583,7 @@ SPGradient *sp_gradient_vector_for_object( SPDocument *const doc, SPDesktop *con
SPIPaint const &paint = ( (fill_or_stroke == Inkscape::FOR_FILL) ? style.fill : style.stroke );
if (paint.isPaintserver()) {
SPObject *server = (fill_or_stroke == Inkscape::FOR_FILL) ? o->style->getFillPaintServer() : o->style->getStrokePaintServer();
- if ( SP_IS_GRADIENT(server) ) {
+ if ( SP_IS_LINEARGRADIENT(server) || SP_IS_RADIALGRADIENT(server) ) {
return SP_GRADIENT(server)->getVector(true);
} else {
color = sp_desktop_get_color(desktop, (fill_or_stroke == Inkscape::FOR_FILL));
diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp
index fc75054a0..a928cac0d 100644
--- a/src/gradient-drag.cpp
+++ b/src/gradient-drag.cpp
@@ -59,12 +59,14 @@ using Inkscape::allPaintTargets;
using Inkscape::CTLINE_PRIMARY;
using Inkscape::CTLINE_SECONDARY;
-#define GR_KNOT_COLOR_NORMAL 0xffffff00
-#define GR_KNOT_COLOR_MOUSEOVER 0xff000000
-#define GR_KNOT_COLOR_SELECTED 0x0000ff00
+guint32 const GR_KNOT_COLOR_NORMAL = 0xffffff00;
+guint32 const GR_KNOT_COLOR_MOUSEOVER = 0xff000000;
+guint32 const GR_KNOT_COLOR_SELECTED = 0x0000ff00;
+guint32 const GR_KNOT_COLOR_HIGHLIGHT = 0xffffff00;
+guint32 const GR_KNOT_COLOR_MESHCORNER = 0xbfbfbf00;
-#define GR_LINE_COLOR_FILL 0x0000ff7f
-#define GR_LINE_COLOR_STROKE 0x9999007f
+guint32 const GR_LINE_COLOR_FILL = 0x0000ff7f;
+guint32 const GR_LINE_COLOR_STROKE = 0x9999007f;
// screen pixels between knots when they snap:
#define SNAP_DIST 5
@@ -116,6 +118,7 @@ static void gr_drag_sel_modified(Inkscape::Selection */*selection*/, guint /*fla
{
GrDrag *drag = (GrDrag *) data;
if (drag->local_change) {
+ drag->refreshDraggers (); // Needed to move mesh handles and toggle visibility
drag->local_change = false;
} else {
drag->updateDraggers ();
@@ -731,14 +734,24 @@ SPObject *GrDraggable::getServer()
static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, guint state, gpointer data)
{
GrDragger *dragger = (GrDragger *) data;
- GrDrag *drag = dragger->parent;
- Geom::Point p = ppointer;
+ // Dragger must have at least one draggable
+ GrDraggable *draggable = (GrDraggable *) dragger->draggables[0];
+ if (!draggable) return;
+ // Find mesh corner that corresponds to dragger (only checks first draggable) and highlight it.
+ GrDragger *dragger_corner = dragger->getMgCorner();
+ if (dragger_corner) {
+ dragger_corner->highlightCorner(true);
+ }
+
+ // Set-up snapping
SPDesktop *desktop = dragger->parent->desktop;
SnapManager &m = desktop->namedview->snap_manager;
double snap_dist = m.snapprefs.getObjectTolerance() / dragger->parent->desktop->current_zoom();
+ Geom::Point p = ppointer;
+
if (state & GDK_SHIFT_MASK) {
// with Shift; unsnap if we carry more than one draggable
if (dragger->draggables.size()>1) {
@@ -890,6 +903,7 @@ static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, gui
knot->moveto(p);
}
+ GrDrag *drag = dragger->parent; // There is just one GrDrag.
drag->keep_selection = (drag->selected.find(dragger)!=drag->selected.end());
bool scale_radial = (state & GDK_CONTROL_MASK) && (state & GDK_SHIFT_MASK);
@@ -1056,6 +1070,19 @@ static void gr_knot_moved_midpoint_handler(SPKnot */*knot*/, Geom::Point const &
static void gr_knot_grabbed_handler(SPKnot */*knot*/, unsigned int /*state*/, gpointer data)
{
GrDragger *dragger = (GrDragger *) data;
+ GrDrag *drag = dragger->parent;
+
+ // Turn off all mesh handle highlighting
+ for(std::vector<GrDragger *>::const_iterator it = drag->draggers.begin(); it != drag->draggers.end(); ++it) { //for all selected draggers
+ GrDragger *d = *it;
+ d->highlightCorner(false);
+ }
+
+ // Highlight only mesh corner corresponding to grabbed corner or handle
+ GrDragger *dragger_corner = dragger->getMgCorner();
+ if (dragger_corner) {
+ dragger_corner->highlightCorner(true);
+ }
dragger->parent->desktop->canvas->forceFullRedrawAfterInterruptions(5);
}
@@ -1207,6 +1234,30 @@ void GrDragger::fireDraggables(bool write_repr, bool scale_radial, bool merging_
}
}
+void GrDragger::updateControlSizesOverload(SPKnot * knot)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int sizes[] = {4, 6, 8, 10, 12, 14, 16};
+ std::vector<int> sizeTable = std::vector<int>(sizes, sizes + (sizeof(sizes) / sizeof(sizes[0])));
+ int size = prefs->getIntLimited("/options/grabsize/value", 3, 1, 7);
+ int knot_size = sizeTable[size - 1];
+ if(knot->shape == SP_KNOT_SHAPE_TRIANGLE){
+ knot_size *= 2.2;
+ knot_size = floor(knot_size);
+ if ( knot_size % 2 == 0 ){
+ knot_size += 1;
+ }
+ }
+ knot->setSize(knot_size);
+}
+
+void GrDragger::updateControlSizes()
+{
+ updateControlSizesOverload(this->knot);
+ this->knot->updateCtrl();
+ this->updateKnotShape();
+}
+
/**
* Checks if the dragger has a draggable with this point_type.
*/
@@ -1377,10 +1428,11 @@ GrDragger::moveMeshHandles ( Geom::Point pc_old, MeshNodeOperation op )
pcg_old *= (gradient->gradientTransform).inverse();
mg->array.update_handles( point_i, selected_corners[ gradient ], pcg_old, op );
+ mg->array.write( mg );
// Move on-screen knots
for( guint i = 0; i < mg->array.handles.size(); ++i ) {
- GrDragger *handle = drag->getDraggerFor( item, POINT_MG_HANDLE, i, fill_or_stroke );
+ GrDragger *handle = drag->getDraggerFor( item, POINT_MG_HANDLE, i, fill_or_stroke );
SPKnot *knot = handle->knot;
Geom::Point pk = getGradientCoords( item, POINT_MG_HANDLE, i, fill_or_stroke );
knot->moveto(pk);
@@ -1424,6 +1476,15 @@ void GrDragger::updateTip()
(draggable->fill_or_stroke == Inkscape::FOR_STROKE) ? _(" (stroke)") : "");
break;
+ case POINT_MG_CORNER:
+ case POINT_MG_HANDLE:
+ case POINT_MG_TENSOR:
+ this->knot->tip = g_strdup_printf (_("%s for: %s%s"),
+ _(gr_knot_descr[draggable->point_type]),
+ item_desc,
+ (draggable->fill_or_stroke == Inkscape::FOR_STROKE) ? _(" (stroke)") : "");
+ break;
+
default:
this->knot->tip = g_strdup_printf (_("%s for: %s%s; drag with <b>Ctrl</b> to snap angle, with <b>Ctrl+Alt</b> to preserve angle, with <b>Ctrl+Shift</b> to scale around center"),
_(gr_knot_descr[draggable->point_type]),
@@ -1451,7 +1512,16 @@ void GrDragger::updateKnotShape()
if (draggables.empty())
return;
GrDraggable *last = draggables.back();
+
g_object_set (G_OBJECT (this->knot->item), "shape", gr_knot_shapes[last->point_type], NULL);
+
+ // For highlighting mesh handles corresponding to selected corner
+ if (this->knot->shape == SP_KNOT_SHAPE_TRIANGLE) {
+ this->knot->setFill(GR_KNOT_COLOR_HIGHLIGHT, GR_KNOT_COLOR_MOUSEOVER, GR_KNOT_COLOR_MOUSEOVER);
+ if (gr_knot_shapes[last->point_type] == SP_KNOT_SHAPE_CIRCLE) {
+ g_object_set (G_OBJECT (this->knot->item), "shape", SP_KNOT_SHAPE_TRIANGLE, NULL);
+ }
+ }
}
/**
@@ -1590,8 +1660,13 @@ GrDragger::GrDragger(GrDrag *parent, Geom::Point p, GrDraggable *draggable)
// create the knot
this->knot = new SPKnot(parent->desktop, NULL);
this->knot->setMode(SP_KNOT_MODE_XOR);
- this->knot->setFill(GR_KNOT_COLOR_NORMAL, GR_KNOT_COLOR_MOUSEOVER, GR_KNOT_COLOR_MOUSEOVER);
+ guint32 fill_color = GR_KNOT_COLOR_NORMAL;
+ if (draggable && draggable->point_type == POINT_MG_CORNER) {
+ fill_color = GR_KNOT_COLOR_MESHCORNER;
+ }
+ this->knot->setFill(fill_color, GR_KNOT_COLOR_MOUSEOVER, GR_KNOT_COLOR_MOUSEOVER);
this->knot->setStroke(0x0000007f, 0x0000007f, 0x0000007f);
+ this->updateControlSizesOverload(this->knot);
this->knot->updateCtrl();
// move knot to the given point
@@ -1610,6 +1685,7 @@ GrDragger::GrDragger(GrDrag *parent, Geom::Point p, GrDraggable *draggable)
this->_moved_connection = this->knot->moved_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_moved_handler), this));
}
+ this->sizeUpdatedConn = ControlManager::getManager().connectCtrlSizeChanged(sigc::mem_fun(*this, &GrDragger::updateControlSizes));
this->_clicked_connection = this->knot->click_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_clicked_handler), this));
this->_doubleclicked_connection = this->knot->doubleclicked_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_doubleclicked_handler), this));
this->_grabbed_connection = this->knot->grabbed_signal.connect(sigc::bind(sigc::ptr_fun(gr_knot_grabbed_handler), this));
@@ -1632,6 +1708,7 @@ GrDragger::~GrDragger()
//this->parent->setDeselected(this);
// disconnect signals
+ this->sizeUpdatedConn.disconnect();
this->_moved_connection.disconnect();
this->_clicked_connection.disconnect();
this->_doubleclicked_connection.disconnect();
@@ -1651,6 +1728,21 @@ GrDragger::~GrDragger()
/**
* Select the dragger which has the given draggable.
*/
+GrDragger *GrDrag::getDraggerFor(GrDraggable *d) {
+ for (std::vector<GrDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i ) {
+ GrDragger *dragger = *i;
+ for (std::vector<GrDraggable *>::const_iterator j = dragger->draggables.begin(); j != dragger->draggables.end(); ++j ) {
+ if (d == *j) {
+ return dragger;
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Select the dragger which has the given draggable.
+ */
GrDragger *GrDrag::getDraggerFor(SPItem *item, GrPointType point_type, gint point_i, Inkscape::PaintTarget fill_or_stroke)
{
for (std::vector<GrDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i ) {
@@ -1677,6 +1769,152 @@ void GrDragger::moveOtherToDraggable(SPItem *item, GrPointType point_type, gint
}
}
+/**
+ * Find mesh corner corresponding to given dragger.
+ */
+GrDragger* GrDragger::getMgCorner(){
+ GrDraggable *draggable = (GrDraggable *) this->draggables[0];
+ if (draggable) {
+
+ // If corner, we already found it!
+ if (draggable->point_type == POINT_MG_CORNER) {
+ return this;
+ }
+
+ // The mapping between handles and corners is complex... so find corner by bruit force.
+ SPGradient *gradient = getGradient(draggable->item, draggable->fill_or_stroke);
+ SPMeshGradient *mg = dynamic_cast<SPMeshGradient *>(gradient);
+ if (mg) {
+ std::vector< std::vector< SPMeshNode* > > nodes = mg->array.nodes;
+ for (guint i = 0; i < nodes.size(); ++i) {
+ for (guint j = 0; j < nodes[i].size(); ++j) {
+ if (nodes[i][j]->set && nodes[i][j]->node_type == MG_NODE_TYPE_HANDLE) {
+ if (draggable->point_i == (gint)nodes[i][j]->draggable) {
+
+ if (nodes.size() > i+1 && nodes[i+1].size() > j && nodes[i+1][j]->node_type == MG_NODE_TYPE_CORNER) {
+ return this->parent->getDraggerFor(draggable->item, POINT_MG_CORNER, nodes[i+1][j]->draggable, draggable->fill_or_stroke);
+ }
+
+ if (j != 0 && nodes.size() > i && nodes[i].size() > j-1 && nodes[i][j-1]->node_type == MG_NODE_TYPE_CORNER) {
+ return this->parent->getDraggerFor(draggable->item, POINT_MG_CORNER, nodes[i][j-1]->draggable, draggable->fill_or_stroke);
+ }
+
+ if (i != 0 && nodes.size() > i-1 && nodes[i-1].size() > j && nodes[i-1][j]->node_type == MG_NODE_TYPE_CORNER) {
+ return this->parent->getDraggerFor(draggable->item, POINT_MG_CORNER, nodes[i-1][j]->draggable, draggable->fill_or_stroke);
+ }
+
+ if (nodes.size() > i && nodes[i].size() > j+1 && nodes[i][j+1]->node_type == MG_NODE_TYPE_CORNER) {
+ return this->parent->getDraggerFor(draggable->item, POINT_MG_CORNER, nodes[i][j+1]->draggable, draggable->fill_or_stroke);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Highlight mesh node
+ */
+void GrDragger::highlightNode(SPMeshNode* node, bool highlight, Geom::Point corner_pos)
+{
+ GrPointType type = POINT_MG_TENSOR;
+ if (node->node_type == MG_NODE_TYPE_HANDLE) {
+ type = POINT_MG_HANDLE;
+ }
+
+ GrDraggable *draggable = (GrDraggable *) this->draggables[0];
+ GrDragger *d = this->parent->getDraggerFor(draggable->item, type, node->draggable, draggable->fill_or_stroke);
+ if (d && node->draggable < G_MAXUINT) {
+ Geom::Point end = d->knot->pos;
+ double angl = Geom::Ray(corner_pos, end).angle();
+
+ if (highlight && knot->fill[SP_KNOT_VISIBLE] == GR_KNOT_COLOR_HIGHLIGHT && abs(angl - knot->angle) > Geom::rad_from_deg(10.0)){
+ return;
+ }
+
+ SPKnot *knot = d->knot;
+ if (highlight) {
+ knot->setFill(GR_KNOT_COLOR_HIGHLIGHT, GR_KNOT_COLOR_MOUSEOVER, GR_KNOT_COLOR_MOUSEOVER);
+ } else {
+ knot->setFill(GR_KNOT_COLOR_NORMAL, GR_KNOT_COLOR_MOUSEOVER, GR_KNOT_COLOR_MOUSEOVER);
+ }
+
+ if (type == POINT_MG_HANDLE) {
+ if (highlight) {
+ knot->setShape(SP_KNOT_SHAPE_TRIANGLE);
+ } else {
+ knot->setShape(SP_KNOT_SHAPE_CIRCLE);
+ }
+ } else {
+ //Code for tensors
+ return;
+ }
+
+ this->updateControlSizesOverload(knot);
+ knot->setAngle(angl);
+ knot->updateCtrl();
+ d->updateKnotShape();
+ }
+}
+
+/**
+ * Highlight handles for mesh corner corresponding to this dragger.
+ */
+void GrDragger::highlightCorner(bool highlight)
+{
+ // Must be a mesh gradient
+ GrDraggable *draggable = (GrDraggable *) this->draggables[0];
+ if (draggable && draggable->point_type == POINT_MG_CORNER) {
+ SPGradient *gradient = getGradient(draggable->item, draggable->fill_or_stroke);
+ if (SP_IS_MESHGRADIENT( gradient )) {
+ Geom::Point corner_point = this->point;
+ gint corner = draggable->point_i;
+ SPMeshGradient *mg = SP_MESHGRADIENT( gradient );
+ SPMeshNodeArray mg_arr = mg->array;
+ std::vector< std::vector< SPMeshNode* > > nodes = mg_arr.nodes;
+ // Find number of patch rows and columns
+ guint mrow = mg_arr.patch_rows();
+ guint mcol = mg_arr.patch_columns();
+ // Number of corners in a row of patches.
+ guint ncorners = mcol + 1;
+ // Find corner row/column
+ guint crow = corner / ncorners;
+ guint ccol = corner % ncorners;
+ // Find node row/column
+ guint nrow = crow * 3;
+ guint ncol = ccol * 3;
+
+ bool patch[4];
+ patch[0] = patch[1] = patch[2] = patch[3] = false;
+ if (ccol > 0 && crow > 0 ) patch[0] = true;
+ if (ccol < mcol && crow > 0 ) patch[1] = true;
+ if (ccol < mcol && crow < mrow ) patch[2] = true;
+ if (ccol > 0 && crow < mrow ) patch[3] = true;
+ if (patch[0] || patch[1]) {
+ highlightNode(nodes[nrow-1][ncol ], highlight, corner_point);
+ }
+ if (patch[1] || patch[2]) {
+ highlightNode(nodes[nrow ][ncol+1], highlight, corner_point);
+ }
+ if (patch[2] || patch[3]) {
+ highlightNode(nodes[nrow+1][ncol ], highlight, corner_point);
+ }
+ if (patch[3] || patch[0]) {
+ highlightNode(nodes[nrow ][ncol-1], highlight, corner_point);
+ }
+ // Highlight tensors
+ /*
+ if( patch[0] ) highlightNode(nodes[nrow-1][ncol-1], highlight, corner_point, point_i);
+ if( patch[1] ) highlightNode(nodes[nrow-1][ncol+1], highlight, corner_point, point_i);
+ if( patch[2] ) highlightNode(nodes[nrow+1][ncol+1], highlight, corner_point, point_i);
+ if( patch[3] ) highlightNode(nodes[nrow+1][ncol-1], highlight, corner_point, point_i);
+ */
+ }
+ }
+}
/**
* Draw this dragger as selected.
@@ -1685,13 +1923,7 @@ void GrDragger::select()
{
this->knot->fill [SP_KNOT_STATE_NORMAL] = GR_KNOT_COLOR_SELECTED;
g_object_set (G_OBJECT (this->knot->item), "fill_color", GR_KNOT_COLOR_SELECTED, NULL);
- //if( isA(POINT_MG_CORNER) ) {
- // for (GSList * drgble = this->draggables; drgble != NULL; drgble = drgble->next) {
- // GrDraggable *draggable = (GrDraggable*) drgble->data;
- // //if( draggable != NULL ) std::cout << " draggable" << std::endl;
- // // MESH FIXME: TURN ON CORRESPONDING SIDE/TENSOR NODE VISIBILITY
- // }
- //}
+ highlightCorner(true);
}
/**
@@ -1699,9 +1931,10 @@ void GrDragger::select()
*/
void GrDragger::deselect()
{
- this->knot->fill [SP_KNOT_STATE_NORMAL] = GR_KNOT_COLOR_NORMAL;
- g_object_set (G_OBJECT (this->knot->item), "fill_color", GR_KNOT_COLOR_NORMAL, NULL);
- // MESH FIXME: TURN OFF CORRESPONDING SIDE/TENSOR NODE VISIBILITY
+ guint32 fill_color = isA(POINT_MG_CORNER) ? GR_KNOT_COLOR_MESHCORNER : GR_KNOT_COLOR_NORMAL;
+ this->knot->fill [SP_KNOT_STATE_NORMAL] = fill_color;
+ g_object_set (G_OBJECT (this->knot->item), "fill_color", fill_color, NULL);
+ highlightCorner(false);
}
bool
@@ -1860,6 +2093,7 @@ void GrDrag::addLine(SPItem *item, Geom::Point p1, Geom::Point p2, Inkscape::Pai
sp_canvas_item_move_to_z(line, 0);
line->item = item;
+ line->is_fill = (fill_or_stroke == Inkscape::FOR_FILL);
sp_canvas_item_show(line);
this->lines.push_back(line);
}
@@ -1869,13 +2103,35 @@ void GrDrag::addLine(SPItem *item, Geom::Point p1, Geom::Point p2, Inkscape::Pai
/**
* Create a curve from p0 to p3 and add it to the lines list. Used for mesh sides.
*/
-void GrDrag::addCurve(SPItem *item, Geom::Point p0, Geom::Point p1, Geom::Point p2, Geom::Point p3, Inkscape::PaintTarget fill_or_stroke)
+void GrDrag::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)
+
{
+ // Highlight curve if one of its draggers has a mouse over it.
+ bool highlight = false;
+ GrDragger* dragger0 = getDraggerFor(item, POINT_MG_CORNER, corner0, fill_or_stroke);
+ GrDragger* dragger1 = getDraggerFor(item, POINT_MG_CORNER, corner1, fill_or_stroke);
+ GrDragger* dragger2 = getDraggerFor(item, POINT_MG_HANDLE, handle0, fill_or_stroke);
+ GrDragger* dragger3 = getDraggerFor(item, POINT_MG_HANDLE, handle1, fill_or_stroke);
+ if (dragger0->knot && (dragger0->knot->flags & SP_KNOT_MOUSEOVER) ||
+ dragger1->knot && (dragger1->knot->flags & SP_KNOT_MOUSEOVER) ||
+ dragger2->knot && (dragger2->knot->flags & SP_KNOT_MOUSEOVER) ||
+ dragger3->knot && (dragger3->knot->flags & SP_KNOT_MOUSEOVER) ) {
+ highlight = true;
+ }
+
+ // CtrlLineType only sets color
CtrlLineType type = (fill_or_stroke == Inkscape::FOR_FILL) ? CTLINE_PRIMARY : CTLINE_SECONDARY;
+ if (highlight) {
+ type = (fill_or_stroke == Inkscape::FOR_FILL) ? CTLINE_SECONDARY : CTLINE_PRIMARY;
+ }
SPCtrlCurve *line = ControlManager::getManager().createControlCurve(this->desktop->getControls(), p0, p1, p2, p3, type);
+ line->corner0 = corner0;
+ line->corner1 = corner1;
sp_canvas_item_move_to_z(line, 0);
line->item = item;
+ line->is_fill = (fill_or_stroke == Inkscape::FOR_FILL);
sp_canvas_item_show (line);
this->lines.push_back(line);
}
@@ -1885,7 +2141,7 @@ void GrDrag::addCurve(SPItem *item, Geom::Point p0, Geom::Point p1, Geom::Point
* If there already exists a dragger within MERGE_DIST of p, add the draggable to it; otherwise create
* new dragger and add it to draggers list.
*/
-void GrDrag::addDragger(GrDraggable *draggable)
+GrDragger* GrDrag::addDragger(GrDraggable *draggable)
{
Geom::Point p = getGradientCoords(draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke);
@@ -1895,13 +2151,14 @@ void GrDrag::addDragger(GrDraggable *draggable)
// distance is small, merge this draggable into dragger, no need to create new dragger
dragger->addDraggable (draggable);
dragger->updateKnotShape();
- return;
+ return dragger;
}
}
GrDragger *new_dragger = new GrDragger(this, p, draggable);
// fixme: draggers should be added AFTER the last one: this way tabbing through them will be from begin to end.
this->draggers.push_back(new_dragger);
+ return new_dragger;
}
/**
@@ -1953,15 +2210,10 @@ void GrDrag::addDraggersMesh(SPMeshGradient *mg, SPItem *item, Inkscape::PaintTa
// Show/hide mesh on fill/stroke. This doesn't work at the moment... and prevents node color updating.
- //Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- bool edit_fill = true; //abs(prefs->getBool("/tools/mesh/edit_fill", true));
- bool edit_stroke = true; //abs(prefs->getBool("/tools/mesh/edit_stroke", true));
- bool show_handles = true; //abs(prefs->getBool("/tools/mesh/show_handles", true));
-
- if( (fill_or_stroke == Inkscape::FOR_FILL && !edit_fill) ||
- (fill_or_stroke == Inkscape::FOR_STROKE && !edit_stroke) ) {
- return;
- }
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool show_handles = abs(prefs->getBool("/tools/mesh/show_handles", true));
+ bool edit_fill = abs(prefs->getBool("/tools/mesh/edit_fill", true));
+ bool edit_stroke = abs(prefs->getBool("/tools/mesh/edit_stroke", true));
// Make sure we have at least one patch defined.
if( mg->array.patch_rows() == 0 || mg->array.patch_columns() == 0 ) {
@@ -1977,58 +2229,141 @@ void GrDrag::addDraggersMesh(SPMeshGradient *mg, SPItem *item, Inkscape::PaintTa
mg->array.handles.clear();
mg->array.tensors.clear();
+ if( (fill_or_stroke == Inkscape::FOR_FILL && !edit_fill) ||
+ (fill_or_stroke == Inkscape::FOR_STROKE && !edit_stroke) ) {
+ return;
+ }
for( guint i = 0; i < nodes.size(); ++i ) {
for( guint j = 0; j < nodes[i].size(); ++j ) {
// std::cout << " Draggers: " << i << " " << j << " " << nodes[i][j]->node_type << std::endl;
+ switch ( nodes[i][j]->node_type ) {
- if( nodes[i][j]->set ) {
- switch ( nodes[i][j]->node_type ) {
+ case MG_NODE_TYPE_CORNER:
+ {
+ mg->array.corners.push_back( nodes[i][j] );
+ GrDraggable *corner = new GrDraggable (item, POINT_MG_CORNER, icorner, fill_or_stroke);
+ addDragger ( corner );
+ nodes[i][j]->draggable = icorner;
+ ++icorner;
+ break;
+ }
- case MG_NODE_TYPE_CORNER:
- {
- mg->array.corners.push_back( nodes[i][j] );
- GrDraggable *corner = new GrDraggable (item, POINT_MG_CORNER, icorner, fill_or_stroke);
- addDragger ( corner );
- nodes[i][j]->draggable = icorner;
- ++icorner;
- break;
+ case MG_NODE_TYPE_HANDLE:
+ {
+ mg->array.handles.push_back( nodes[i][j] );
+ GrDraggable *handle = new GrDraggable (item, POINT_MG_HANDLE, ihandle, fill_or_stroke);
+ GrDragger* dragger = addDragger ( handle );
+
+ if( !show_handles || !nodes[i][j]->set ) {
+ dragger->knot->hide();
}
+ nodes[i][j]->draggable = ihandle;
+ ++ihandle;
+ break;
+ }
- case MG_NODE_TYPE_HANDLE:
- {
- if( show_handles ) {
- mg->array.handles.push_back( nodes[i][j] );
- GrDraggable *handle = new GrDraggable (item, POINT_MG_HANDLE, ihandle, fill_or_stroke);
- addDragger ( handle );
- nodes[i][j]->draggable = ihandle;
- ++ihandle;
- break;
- }
+ case MG_NODE_TYPE_TENSOR:
+ {
+ mg->array.tensors.push_back( nodes[i][j] );
+ GrDraggable *tensor = new GrDraggable (item, POINT_MG_TENSOR, itensor, fill_or_stroke);
+ GrDragger* dragger = addDragger ( tensor );
+ if( !show_handles || !nodes[i][j]->set ) {
+ dragger->knot->hide();
}
+ nodes[i][j]->draggable = itensor;
+ ++itensor;
+ break;
+ }
- case MG_NODE_TYPE_TENSOR:
- {
- if( show_handles ) {
- mg->array.tensors.push_back( nodes[i][j] );
- GrDraggable *tensor = new GrDraggable (item, POINT_MG_TENSOR, itensor, fill_or_stroke);
- addDragger ( tensor );
- nodes[i][j]->draggable = itensor;
- ++itensor;
- break;
+ default:
+ std::cerr << "Bad Mesh draggable type" << std::endl;
+ break;
+ }
+ }
+ }
+
+ mg->array.draggers_valid = true;
+}
+
+/**
+ * Refresh draggers, moving and toggling visibility as necessary.
+ * Does not regenerate draggers (as does updateDraggersMesh()).
+ */
+void GrDrag::refreshDraggersMesh(SPMeshGradient *mg, SPItem *item, Inkscape::PaintTarget fill_or_stroke)
+{
+ mg->ensureArray();
+ std::vector< std::vector< SPMeshNode* > > nodes = mg->array.nodes;
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool show_handles = abs(prefs->getBool("/tools/mesh/show_handles", true));
+
+ // Make sure we have at least one patch defined.
+ if( mg->array.patch_rows() == 0 || mg->array.patch_columns() == 0 ) {
+
+ std::cerr << "GrDrag::refreshDraggersMesh: Empty Mesh, No Draggers to refresh!" << std::endl;
+ return;
+ }
+
+ guint ihandle = 0;
+ guint itensor = 0;
+
+ for( guint i = 0; i < nodes.size(); ++i ) {
+ for( guint j = 0; j < nodes[i].size(); ++j ) {
+
+ // std::cout << " Draggers: " << i << " " << j << " " << nodes[i][j]->node_type << std::endl;
+
+ switch ( nodes[i][j]->node_type ) {
+
+ case MG_NODE_TYPE_CORNER:
+ // Do nothing, corners are always shown.
+ break;
+
+ case MG_NODE_TYPE_HANDLE:
+ {
+ GrDragger* dragger = getDraggerFor(item, POINT_MG_HANDLE, ihandle, fill_or_stroke);
+ if (dragger) {
+ Geom::Point pk = getGradientCoords( item, POINT_MG_HANDLE, ihandle, fill_or_stroke);
+ dragger->knot->moveto(pk);
+ if( !show_handles || !nodes[i][j]->set ) {
+ dragger->knot->hide();
+ } else {
+ dragger->knot->show();
}
+ } else {
+ // This can happen if a draggable is not visible.
+ // std::cerr << "GrDrag::refreshDraggersMesh: No dragger!" << std::endl;
}
+ ++ihandle;
+ break;
+ }
- default:
- std::cerr << "Bad Mesh draggable type" << std::endl;
- break;
+ case MG_NODE_TYPE_TENSOR:
+ {
+ GrDragger* dragger = getDraggerFor(item, POINT_MG_TENSOR, itensor, fill_or_stroke);
+ if (dragger) {
+ Geom::Point pk = getGradientCoords( item, POINT_MG_TENSOR, itensor, fill_or_stroke);
+ dragger->knot->moveto(pk);
+ if( !show_handles || !nodes[i][j]->set ) {
+ dragger->knot->hide();
+ } else {
+ dragger->knot->show();
+ }
+ } else {
+ // This can happen if a draggable is not visible.
+ // std::cerr << "GrDrag::refreshDraggersMesh: No dragger!" << std::endl;
+ }
+ ++itensor;
+ break;
}
+
+ default:
+ std::cerr << "Bad Mesh draggable type" << std::endl;
+ break;
}
}
}
-
- mg->array.draggers_valid = true;
}
/**
@@ -2109,16 +2444,59 @@ void GrDrag::updateDraggers()
/**
+ * Refresh draggers, moving and toggling visibility as necessary.
+ * Does not regenerate draggers (as does updateDraggers()).
+ * Only applies to mesh gradients.
+ */
+void GrDrag::refreshDraggers()
+{
+
+ g_return_if_fail(this->selection != NULL);
+ auto list = this->selection->items();
+ for (auto i = list.begin(); i != list.end(); ++i) {
+ SPItem *item = *i;
+ SPStyle *style = item->style;
+
+ if (style && (style->fill.isPaintserver())) {
+ SPPaintServer *server = style->getFillPaintServer();
+ if ( server && SP_IS_GRADIENT( server ) ) {
+ if ( SP_IS_MESHGRADIENT(server) ) {
+ refreshDraggersMesh( SP_MESHGRADIENT(server), item, Inkscape::FOR_FILL );
+ }
+ }
+ }
+
+ if (style && (style->stroke.isPaintserver())) {
+ SPPaintServer *server = style->getStrokePaintServer();
+ if ( server && SP_IS_GRADIENT( server ) ) {
+ if ( SP_IS_MESHGRADIENT(server) ) {
+ refreshDraggersMesh( SP_MESHGRADIENT(server), item, Inkscape::FOR_STROKE );
+ }
+ }
+ }
+ }
+}
+
+
+/**
* Returns true if at least one of the draggers' knots has the mouse hovering above it.
*/
bool GrDrag::mouseOver()
{
+ static bool mouse_out = false;
+ // added knot mouse out for future use
for (std::vector<GrDragger *>::const_iterator l = this->draggers.begin(); l != this->draggers.end(); ++l) {
GrDragger *d = *l;
if (d->knot && (d->knot->flags & SP_KNOT_MOUSEOVER)) {
+ mouse_out = true;
+ updateLines();
return true;
}
}
+ if(mouse_out == true){
+ updateLines();
+ mouse_out = false;
+ }
return false;
}
@@ -2156,8 +2534,12 @@ void GrDrag::updateLines()
addLine(item, center, getGradientCoords(item, POINT_RG_R2, 0, Inkscape::FOR_FILL), Inkscape::FOR_FILL);
} else if ( SP_IS_MESHGRADIENT(server) ) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool edit_fill = abs(prefs->getBool("/tools/mesh/edit_fill", true));
+
SPMeshGradient *mg = SP_MESHGRADIENT(server);
+ if (edit_fill) {
guint rows = mg->array.patch_rows();
guint columns = mg->array.patch_columns();
for ( guint i = 0; i < rows; ++i ) {
@@ -2167,12 +2549,27 @@ void GrDrag::updateLines()
SPMeshPatchI patch( &(mg->array.nodes), i, j );
+ // clockwise around patch, used to find corner dragger
+ int corner0 = i * (columns + 1) + j;
+ int corner1 = corner0 + 1;
+ int corner2 = corner1 + columns + 1;
+ int corner3 = corner2 - 1;
+ // clockwise around patch, used to find handle dragger
+ int handle0 = 2*j + i*(2+4*columns);
+ int handle1 = handle0 + 1;
+ int handle2 = j + i*(2+4*columns) + 2*columns + 1;
+ int handle3 = j + i*(2+4*columns) + 3*columns + 2;
+ int handle4 = handle1 + (2+4*columns);
+ int handle5 = handle0 + (2+4*columns);
+ int handle6 = handle3 - 1;
+ int handle7 = handle2 - 1;
+
// Top line
h = patch.getPointsForSide( 0 );
for( guint p = 0; p < 4; ++p ) {
h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
}
- addCurve (item, h[0], h[1], h[2], h[3], Inkscape::FOR_FILL );
+ addCurve (item, h[0], h[1], h[2], h[3], corner0, corner1, handle0, handle1, Inkscape::FOR_FILL );
// Right line
if( j == columns - 1 ) {
@@ -2180,7 +2577,7 @@ void GrDrag::updateLines()
for( guint p = 0; p < 4; ++p ) {
h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
}
- addCurve (item, h[0], h[1], h[2], h[3], Inkscape::FOR_FILL );
+ addCurve (item, h[0], h[1], h[2], h[3], corner1, corner2, handle2, handle3, Inkscape::FOR_FILL );
}
// Bottom line
@@ -2189,7 +2586,7 @@ void GrDrag::updateLines()
for( guint p = 0; p < 4; ++p ) {
h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
}
- addCurve (item, h[0], h[1], h[2], h[3], Inkscape::FOR_FILL );
+ addCurve (item, h[0], h[1], h[2], h[3], corner2, corner3, handle4, handle5, Inkscape::FOR_FILL );
}
// Left line
@@ -2197,9 +2594,10 @@ void GrDrag::updateLines()
for( guint p = 0; p < 4; ++p ) {
h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
}
- addCurve (item, h[0], h[1], h[2], h[3], Inkscape::FOR_FILL );
+ addCurve (item, h[0], h[1], h[2], h[3], corner3, corner0, handle6, handle7, Inkscape::FOR_FILL );
}
}
+ }
}
}
}
@@ -2218,6 +2616,11 @@ void GrDrag::updateLines()
addLine(item, center, getGradientCoords(item, POINT_RG_R2, 0, Inkscape::FOR_STROKE), Inkscape::FOR_STROKE);
} else if ( SP_IS_MESHGRADIENT(server) ) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool edit_stroke = abs(prefs->getBool("/tools/mesh/edit_stroke", true));
+
+ if (edit_stroke) {
+
// MESH FIXME: TURN ROUTINE INTO FUNCTION AND CALL FOR BOTH FILL AND STROKE.
SPMeshGradient *mg = SP_MESHGRADIENT(server);
@@ -2230,12 +2633,27 @@ void GrDrag::updateLines()
SPMeshPatchI patch( &(mg->array.nodes), i, j );
+ // clockwise around patch, used to find corner dragger
+ int corner0 = i * (columns + 1) + j;
+ int corner1 = corner0 + 1;
+ int corner2 = corner1 + columns + 1;
+ int corner3 = corner2 - 1;
+ // clockwise around patch, used to find handle dragger
+ int handle0 = 2*j + i*(2+4*columns);
+ int handle1 = handle0 + 1;
+ int handle2 = j + i*(2+4*columns) + 2*columns + 1;
+ int handle3 = j + i*(2+4*columns) + 3*columns + 2;
+ int handle4 = handle1 + (2+4*columns);
+ int handle5 = handle0 + (2+4*columns);
+ int handle6 = handle3 - 1;
+ int handle7 = handle2 - 1;
+
// Top line
h = patch.getPointsForSide( 0 );
for( guint p = 0; p < 4; ++p ) {
h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
}
- addCurve (item, h[0], h[1], h[2], h[3], Inkscape::FOR_STROKE );
+ addCurve (item, h[0], h[1], h[2], h[3], corner0, corner1, handle0, handle1, Inkscape::FOR_STROKE);
// Right line
if( j == columns - 1 ) {
@@ -2243,7 +2661,7 @@ void GrDrag::updateLines()
for( guint p = 0; p < 4; ++p ) {
h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
}
- addCurve (item, h[0], h[1], h[2], h[3], Inkscape::FOR_STROKE );
+ addCurve (item, h[0], h[1], h[2], h[3], corner1, corner2, handle2, handle3, Inkscape::FOR_STROKE);
}
// Bottom line
@@ -2252,7 +2670,7 @@ void GrDrag::updateLines()
for( guint p = 0; p < 4; ++p ) {
h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
}
- addCurve (item, h[0], h[1], h[2], h[3], Inkscape::FOR_STROKE );
+ addCurve (item, h[0], h[1], h[2], h[3], corner2, corner3, handle4, handle5, Inkscape::FOR_STROKE);
}
// Left line
@@ -2260,9 +2678,10 @@ void GrDrag::updateLines()
for( guint p = 0; p < 4; ++p ) {
h[p] *= Geom::Affine(mg->gradientTransform) * (Geom::Affine)item->i2dt_affine();
}
- addCurve (item, h[0], h[1], h[2], h[3], Inkscape::FOR_STROKE );
+ addCurve (item, h[0], h[1], h[2], h[3], corner3, corner0, handle6, handle7,Inkscape::FOR_STROKE);
}
- }
+ }
+ }
}
}
}
diff --git a/src/gradient-drag.h b/src/gradient-drag.h
index cf0a35c89..b4a64c78d 100644
--- a/src/gradient-drag.h
+++ b/src/gradient-drag.h
@@ -107,6 +107,11 @@ struct GrDragger {
/* 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);
+ void highlightCorner(bool highlight);
+
bool mayMerge(GrDragger *other);
bool mayMerge(GrDraggable *da2);
@@ -116,6 +121,11 @@ struct GrDragger {
void fireDraggables(bool write_repr, bool scale_radial = false, bool merging_focus = false);
+protected:
+ void updateControlSizesOverload(SPKnot * knot);
+ void updateControlSizes();
+ sigc::connection sizeUpdatedConn;
+
private:
sigc::connection _moved_connection;
sigc::connection _clicked_connection;
@@ -168,6 +178,7 @@ public: // FIXME: make more of this private!
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);
@@ -185,6 +196,7 @@ public: // FIXME: make more of this private!
std::vector<SPCtrlLine *> lines;
void updateDraggers();
+ void refreshDraggers();
void updateLines();
void updateLevels();
@@ -203,13 +215,15 @@ 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, 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);
- void addDragger(GrDraggable *draggable);
+ 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 );
diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp
index 10641692d..50627fd0b 100644
--- a/src/helper/geom-pathstroke.cpp
+++ b/src/helper/geom-pathstroke.cpp
@@ -1,6 +1,7 @@
/* Authors:
* Liam P. White
* Tavmjong Bah
+ * Alexander Brock
*
* Copyright (C) 2014-2015 Authors
*
@@ -746,33 +747,36 @@ void get_cubic_data(Geom::CubicBezier const& bez, double time, double& len, doub
len = l;
}
-void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, double tol, size_t levels)
-{
+double _offset_cubic_stable_sub(
+ Geom::CubicBezier const& bez,
+ Geom::CubicBezier& c,
+ const Geom::Point& start_normal,
+ const Geom::Point& end_normal,
+ const Geom::Point& start_new,
+ const Geom::Point& end_new,
+ const double start_rad,
+ const double end_rad,
+ const double start_len,
+ const double end_len,
+ const double width,
+ const double width_correction) {
using Geom::X;
using Geom::Y;
- Geom::Point start_pos = bez.initialPoint();
- Geom::Point end_pos = bez.finalPoint();
-
- Geom::Point start_normal = Geom::rot90(bez.unitTangentAt(0));
- Geom::Point end_normal = -Geom::rot90(Geom::unitTangentAt(Geom::reverse(bez.toSBasis()), 0.));
-
- // offset the start and end control points out by the width
- Geom::Point start_new = start_pos + start_normal*width;
- Geom::Point end_new = end_pos + end_normal*width;
-
- // --------
- double start_rad, end_rad;
- double start_len, end_len; // tangent lengths
- get_cubic_data(bez, 0, start_len, start_rad);
- get_cubic_data(bez, 1, end_len, end_rad);
-
double start_off = 1, end_off = 1;
// correction of the lengths of the tangent to the offset
if (!Geom::are_near(start_rad, 0))
- start_off += width / start_rad;
+ start_off += (width + width_correction) / start_rad;
if (!Geom::are_near(end_rad, 0))
- end_off += width / end_rad;
+ end_off += (width + width_correction) / end_rad;
+
+ // We don't change the direction of the control points
+ if (start_off < 0) {
+ start_off = 0;
+ }
+ if (end_off < 0) {
+ end_off = 0;
+ }
start_off *= start_len;
end_off *= end_len;
// --------
@@ -783,23 +787,137 @@ void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, dou
mid2_new = Geom::Point(end_new[X] - mid2_new[X]/3., end_new[Y] - mid2_new[Y]/3.);
// create the estimate curve
- Geom::CubicBezier c = Geom::CubicBezier(start_new, mid1_new, mid2_new, end_new);
+ c = Geom::CubicBezier(start_new, mid1_new, mid2_new, end_new);
+
+ // check the tolerance for our estimate to be a parallel curve
+
+ double worst_residual = 0;
+ for (size_t ii = 3; ii <= 7; ii+=2) {
+ const double t = static_cast<double>(ii) / 10;
+ const Geom::Point req = bez.pointAt(t);
+ const Geom::Point chk = c.pointAt(c.nearestTime(req));
+ const double current_residual = (chk-req).length() - std::abs(width);
+ if (std::abs(current_residual) > std::abs(worst_residual)) {
+ worst_residual = current_residual;
+ }
+ }
+ return worst_residual;
+}
+
+void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, double tol, size_t levels)
+{
+ using Geom::X;
+ using Geom::Y;
+
+ const Geom::Point start_pos = bez.initialPoint();
+ const Geom::Point end_pos = bez.finalPoint();
+
+ const Geom::Point start_normal = Geom::rot90(bez.unitTangentAt(0));
+ const Geom::Point end_normal = -Geom::rot90(Geom::unitTangentAt(Geom::reverse(bez.toSBasis()), 0.));
+
+ // offset the start and end control points out by the width
+ const Geom::Point start_new = start_pos + start_normal*width;
+ const Geom::Point end_new = end_pos + end_normal*width;
+
+ // --------
+ double start_rad, end_rad;
+ double start_len, end_len; // tangent lengths
+ get_cubic_data(bez, 0, start_len, start_rad);
+ get_cubic_data(bez, 1, end_len, end_rad);
+
+
+ Geom::CubicBezier c;
+
+ double best_width_correction = 0;
+ double best_residual = _offset_cubic_stable_sub(
+ bez, c,
+ start_normal, end_normal,
+ start_new, end_new,
+ start_rad, end_rad,
+ start_len, end_len,
+ width, best_width_correction);
+ double stepsize = std::abs(width)/2;
+ bool seen_success = false;
+ double stepsize_threshold = 0;
+ // std::cout << "Residual from " << best_residual << " ";
+ size_t ii = 0;
+ for (; ii < 100 && stepsize > stepsize_threshold; ++ii) {
+ bool success = false;
+ const double width_correction = best_width_correction - (best_residual > 0 ? 1 : -1) * stepsize;
+ Geom::CubicBezier current_curve;
+ const double residual = _offset_cubic_stable_sub(
+ bez, current_curve,
+ start_normal, end_normal,
+ start_new, end_new,
+ start_rad, end_rad,
+ start_len, end_len,
+ width, width_correction);
+ if (std::abs(residual) < std::abs(best_residual)) {
+ best_residual = residual;
+ best_width_correction = width_correction;
+ c = current_curve;
+ success = true;
+ if (std::abs(best_residual) < tol/4) {
+ break;
+ }
+ }
+
+ if (success) {
+ if (!seen_success) {
+ seen_success = true;
+ //std::cout << "Stepsize factor: " << std::abs(width) / stepsize << std::endl;
+ stepsize_threshold = stepsize / 1000;
+ }
+ }
+ else {
+ stepsize /= 2;
+ }
+ if (std::abs(best_width_correction) >= std::abs(width)/2) {
+ //break; // Seems to prevent some numerical instabilities, not clear if useful
+ }
+ }
// reached maximum recursive depth
// don't bother with any more correction
if (levels == 0) {
- p.append(c);
+ try {
+ p.append(c);
+ }
+ catch (...) {
+ if ((p.finalPoint() - c.initialPoint()).length() < 1e-6) {
+ c.setInitial(p.finalPoint());
+ }
+ else {
+ auto line = Geom::LineSegment(p.finalPoint(), c.initialPoint());
+ p.append(line);
+ }
+ p.append(c);
+ }
+
return;
}
- // check the tolerance for our estimate to be a parallel curve
- Geom::Point chk = c.pointAt(.5);
- Geom::Point req = bez.pointAt(.5) + Geom::rot90(bez.unitTangentAt(.5))*width; // required accuracy
-
- Geom::Point const diff = req - chk;
- double const err = Geom::dot(diff, diff);
+ // We find the point on our new curve (c) for which the distance between
+ // (c) and (bez) differs the most from the desired distance (width).
+ double worst_err = std::abs(best_residual);
+ double worst_time = .5;
+ for (size_t ii = 1; ii <= 9; ++ii) {
+ const double t = static_cast<double>(ii) / 10;
+ const Geom::Point req = bez.pointAt(t);
+ // We use the exact solution with nearestTime because it is numerically
+ // much more stable than simply assuming that the point on (c) closest
+ // to bez.pointAt(t) is given by c.pointAt(t)
+ const Geom::Point chk = c.pointAt(c.nearestTime(req));
+
+ Geom::Point const diff = req - chk;
+ const double err = std::abs(diff.length() - std::abs(width));
+ if (err > worst_err) {
+ worst_err = err;
+ worst_time = t;
+ }
+ }
- if (err < tol) {
+ if (worst_err < tol) {
if (Geom::are_near(start_new, p.finalPoint())) {
p.setFinal(start_new); // if it isn't near, we throw
}
@@ -809,7 +927,7 @@ void offset_cubic(Geom::Path& p, Geom::CubicBezier const& bez, double width, dou
return;
} else {
// split the curve in two
- std::pair<Geom::CubicBezier, Geom::CubicBezier> s = bez.subdivide(.5);
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> s = bez.subdivide(worst_time);
offset_cubic(p, s.first, width, tol, levels - 1);
offset_cubic(p, s.second, width, tol, levels - 1);
}
@@ -827,9 +945,8 @@ void offset_quadratic(Geom::Path& p, Geom::QuadraticBezier const& bez, double wi
offset_cubic(p, cub, width, tol, levels);
}
-void offset_curve(Geom::Path& res, Geom::Curve const* current, double width)
+void offset_curve(Geom::Path& res, Geom::Curve const* current, double width, double tolerance)
{
- double const tolerance = 0.0025;
size_t levels = 8;
if (current->isDegenerate()) return; // don't do anything
@@ -855,14 +972,14 @@ void offset_curve(Geom::Path& res, Geom::Curve const* current, double width)
default: {
Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(current->toSBasis(), tolerance);
for (size_t i = 0; i < sbasis_path.size(); ++i)
- offset_curve(res, &sbasis_path[i], width);
+ offset_curve(res, &sbasis_path[i], width, tolerance);
break;
}
}
} else {
Geom::Path sbasis_path = Geom::cubicbezierpath_from_sbasis(current->toSBasis(), 0.1);
for (size_t i = 0; i < sbasis_path.size(); ++i)
- offset_curve(res, &sbasis_path[i], width);
+ offset_curve(res, &sbasis_path[i], width, tolerance);
}
}
@@ -902,13 +1019,19 @@ void peak_cap(Geom::PathBuilder& res, Geom::Path const& with_dir, Geom::Path con
namespace Inkscape {
-Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join, LineCapType butt)
+Geom::PathVector outline(
+ Geom::Path const& input,
+ double width,
+ double miter,
+ LineJoinType join,
+ LineCapType butt,
+ double tolerance)
{
if (input.size() == 0) return Geom::PathVector(); // nope, don't even try
Geom::PathBuilder res;
- Geom::Path with_dir = half_outline(input, width/2., miter, join);
- Geom::Path against_dir = half_outline(input.reversed(), width/2., miter, join);
+ Geom::Path with_dir = half_outline(input, width/2., miter, join, tolerance);
+ Geom::Path against_dir = half_outline(input.reversed(), width/2., miter, join, tolerance);
res.moveTo(with_dir[0].initialPoint());
res.append(with_dir);
@@ -947,8 +1070,21 @@ Geom::PathVector outline(Geom::Path const& input, double width, double miter, Li
return res.peek();
}
-Geom::Path half_outline(Geom::Path const& input, double width, double miter, LineJoinType join)
+Geom::Path half_outline(
+ Geom::Path const& input,
+ double width,
+ double miter,
+ LineJoinType join,
+ double tolerance)
{
+ if (tolerance <= 0) {
+ if (std::abs(width) > 0) {
+ tolerance = 5.0 * (std::abs(width)/100);
+ }
+ else {
+ tolerance = 1e-4;
+ }
+ }
Geom::Path res;
if (input.size() == 0) return res;
@@ -963,12 +1099,13 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin
res.start(start);
// Do two curves at a time for efficiency, since the join function needs to know the outgoing curve as well
- const size_t k = (input.back_closed().isDegenerate() && input.closed())
- ?input.size_default()-1:input.size_default();
+ const Geom::Curve &closingline = input.back_closed();
+ const size_t k = (are_near(closingline.initialPoint(), closingline.finalPoint()) && input.closed() )
+ ?input.size_open():input.size_default();
for (size_t u = 0; u < k; u += 2) {
temp.clear();
- offset_curve(temp, &input[u], width);
+ offset_curve(temp, &input[u], width, tolerance);
// on the first run through, there isn't a join
if (u == 0) {
@@ -981,12 +1118,11 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin
// odd number of paths
if (u < k - 1) {
temp.clear();
- offset_curve(temp, &input[u+1], width);
+ offset_curve(temp, &input[u+1], width, tolerance);
tangents(tang, input[u], input[u+1]);
outline_join(res, temp, tang[0], tang[1], width, miter, join);
}
}
-
if (input.closed()) {
Geom::Curve const &c1 = res.back();
Geom::Curve const &c2 = res.front();
@@ -998,7 +1134,6 @@ Geom::Path half_outline(Geom::Path const& input, double width, double miter, Lin
outline_join(temp, temp2, tang[0], tang[1], width, miter, join);
res.erase(res.begin());
res.erase_last();
- //
res.append(temp);
res.close();
}
@@ -1010,9 +1145,8 @@ void outline_join(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang,
{
if (res.size() == 0 || temp.size() == 0)
return;
-
Geom::Curve const& outgoing = temp.front();
- if (Geom::are_near(res.finalPoint(), outgoing.initialPoint())) {
+ if (Geom::are_near(res.finalPoint(), outgoing.initialPoint(), 0.01)) {
// if the points are /that/ close, just ignore this one
res.setFinal(temp.initialPoint());
res.append(temp);
diff --git a/src/helper/geom-pathstroke.h b/src/helper/geom-pathstroke.h
index 6a753a6fd..4e4b8b91e 100644
--- a/src/helper/geom-pathstroke.h
+++ b/src/helper/geom-pathstroke.h
@@ -42,12 +42,19 @@ enum LineCapType {
* @param[in] miter Miter limit. Only used when @a join is one of JOIN_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE.
* @param[in] join Line join type used during offset. Member of LineJoinType enum.
* @param[in] cap Line cap type used during stroking. Member of LineCapType enum.
+ * @param[in] tolerance Tolerance, values smaller than 0 lead to automatic tolerance depending on width.
*
* @return Stroked path.
* If the input path is closed, the resultant vector will contain two paths.
* Otherwise, there should be only one in the output.
*/
-Geom::PathVector outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL, LineCapType cap = BUTT_FLAT);
+Geom::PathVector outline(
+ Geom::Path const& input,
+ double width,
+ double miter,
+ LineJoinType join = JOIN_BEVEL,
+ LineCapType cap = BUTT_FLAT,
+ double tolerance = -1);
/**
* Offset the input path by @a width.
@@ -57,10 +64,16 @@ Geom::PathVector outline(Geom::Path const& input, double width, double miter, Li
* @param[in] width Amount to offset.
* @param[in] miter Miter limit. Only used when @a join is one of JOIN_MITER, JOIN_MITER_CLIP, and JOIN_EXTRAPOLATE.
* @param[in] join Line join type used during offset. Member of LineJoinType enum.
+ * @param[in] tolerance Tolerance, values smaller than 0 lead to automatic tolerance depending on width.
*
* @return Offsetted output.
*/
-Geom::Path half_outline(Geom::Path const& input, double width, double miter, LineJoinType join = JOIN_BEVEL);
+Geom::Path half_outline(
+ Geom::Path const& input,
+ double width,
+ double miter,
+ LineJoinType join = JOIN_BEVEL,
+ double tolerance = -1);
/**
* Builds a join on the provided path.
diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp
index 2433e2777..e06c539d3 100644
--- a/src/helper/png-write.cpp
+++ b/src/helper/png-write.cpp
@@ -123,8 +123,8 @@ void PngTextList::add(gchar const* key, gchar const* text)
static bool
sp_png_write_rgba_striped(SPDocument *doc,
gchar const *filename, unsigned long int width, unsigned long int height, double xdpi, double ydpi,
- int (* get_rows)(guchar const **rows, void **to_free, int row, int num_rows, void *data, int color_type, int bit_depth),
- void *data, bool interlace, int color_type, int bit_depth, int zlib)
+ int (* get_rows)(guchar const **rows, void **to_free, int row, int num_rows, void *data, int color_type, int bit_depth, int antialias),
+ void *data, bool interlace, int color_type, int bit_depth, int zlib, int antialiasing)
{
g_return_val_if_fail(filename != NULL, false);
g_return_val_if_fail(data != NULL, false);
@@ -286,7 +286,7 @@ sp_png_write_rgba_striped(SPDocument *doc,
r = 0;
while (r < static_cast<png_uint_32>(height)) {
void *to_free;
- int n = get_rows((unsigned char const **) row_pointers, &to_free, r, height-r, data, color_type, bit_depth);
+ int n = get_rows((unsigned char const **) row_pointers, &to_free, r, height-r, data, color_type, bit_depth, antialiasing);
if (!n) break;
png_write_rows(png_ptr, row_pointers, n);
g_free(to_free);
@@ -320,7 +320,7 @@ sp_png_write_rgba_striped(SPDocument *doc,
*
*/
static int
-sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, void *data, int color_type, int bit_depth)
+sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, void *data, int color_type, int bit_depth, int antialiasing)
{
struct SPEBP *ebp = (struct SPEBP *) data;
@@ -352,7 +352,7 @@ sp_export_get_rows(guchar const **rows, void **to_free, int row, int num_rows, v
dc.setOperator(CAIRO_OPERATOR_OVER);
/* Render */
- ebp->drawing->render(dc, bbox);
+ ebp->drawing->render(dc, bbox, 0, antialiasing);
cairo_surface_destroy(s);
// PNG stores data as unpremultiplied big-endian RGBA, which means
@@ -396,10 +396,10 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
unsigned long bgcolor,
unsigned int (*status) (float, void *),
void *data, bool force_overwrite,
- const std::vector<SPItem*> &items_only, bool interlace, int color_type, int bit_depth, int zlib)
+ const std::vector<SPItem*> &items_only, bool interlace, int color_type, int bit_depth, int zlib, int antialiasing)
{
return sp_export_png_file(doc, filename, Geom::Rect(Geom::Point(x0,y0),Geom::Point(x1,y1)),
- width, height, xdpi, ydpi, bgcolor, status, data, force_overwrite, items_only, interlace, color_type, bit_depth, zlib);
+ width, height, xdpi, ydpi, bgcolor, status, data, force_overwrite, items_only, interlace, color_type, bit_depth, zlib, antialiasing);
}
ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
@@ -408,7 +408,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
unsigned long bgcolor,
unsigned (*status)(float, void *),
void *data, bool force_overwrite,
- const std::vector<SPItem*> &items_only, bool interlace, int color_type, int bit_depth, int zlib)
+ const std::vector<SPItem*> &items_only, bool interlace, int color_type, int bit_depth, int zlib, int antialiasing)
{
g_return_val_if_fail(doc != NULL, EXPORT_ERROR);
g_return_val_if_fail(filename != NULL, EXPORT_ERROR);
@@ -479,7 +479,7 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
ebp.px = g_try_new(guchar, 4 * ebp.sheight * width);
if (ebp.px) {
- write_status = sp_png_write_rgba_striped(doc, filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp, interlace, color_type, bit_depth, zlib);
+ write_status = sp_png_write_rgba_striped(doc, filename, width, height, xdpi, ydpi, sp_export_get_rows, &ebp, interlace, color_type, bit_depth, zlib, antialiasing);
g_free(ebp.px);
}
diff --git a/src/helper/png-write.h b/src/helper/png-write.h
index e47f01743..06498f46e 100644
--- a/src/helper/png-write.h
+++ b/src/helper/png-write.h
@@ -35,13 +35,13 @@ ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
unsigned long int width, unsigned long int height, double xdpi, double ydpi,
unsigned long bgcolor,
unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector<SPItem*> &items_only = std::vector<SPItem*>(),
- bool interlace = false, int color_type = 6, int bit_depth = 8, int zlib = 6);
+ bool interlace = false, int color_type = 6, int bit_depth = 8, int zlib = 6, int antialiasing = 2);
ExportResult sp_export_png_file(SPDocument *doc, gchar const *filename,
Geom::Rect const &area,
unsigned long int width, unsigned long int height, double xdpi, double ydpi,
unsigned long bgcolor,
unsigned int (*status) (float, void *), void *data, bool force_overwrite = false, const std::vector<SPItem*> &items_only = std::vector<SPItem*>(),
- bool interlace = false, int color_type = 6, int bit_depth = 8, int zlib = 6);
+ bool interlace = false, int color_type = 6, int bit_depth = 8, int zlib = 6, int antialiasing = 2);
#endif // SEEN_SP_PNG_WRITE_H
diff --git a/src/inkscape.cpp b/src/inkscape.cpp
index 2ba85026f..bf694ada7 100644
--- a/src/inkscape.cpp
+++ b/src/inkscape.cpp
@@ -274,7 +274,7 @@ int Application::autosave()
if (doc->isModifiedSinceSave()) {
gchar *oldest_autosave = 0;
const gchar *filename = 0;
- struct stat sb;
+ GStatBuf sb;
time_t min_time = 0;
gint count = 0;
diff --git a/src/io/sys.cpp b/src/io/sys.cpp
index 94175176a..61a6a96f4 100644
--- a/src/io/sys.cpp
+++ b/src/io/sys.cpp
@@ -226,7 +226,7 @@ bool Inkscape::IO::file_is_writable( char const *utf8name)
filename = g_filename_from_utf8 ( utf8name, -1, NULL, NULL, NULL );
}
if ( filename ) {
- struct stat st;
+ GStatBuf st;
if (g_file_test (filename, G_FILE_TEST_EXISTS)){
if (g_lstat (filename, &st) == 0) {
success = ((st.st_mode & S_IWRITE) != 0);
diff --git a/src/knot-enums.h b/src/knot-enums.h
index 1045e0433..ea23a5a2c 100644
--- a/src/knot-enums.h
+++ b/src/knot-enums.h
@@ -19,6 +19,7 @@ typedef enum {
SP_KNOT_SHAPE_SQUARE,
SP_KNOT_SHAPE_DIAMOND,
SP_KNOT_SHAPE_CIRCLE,
+ SP_KNOT_SHAPE_TRIANGLE,
SP_KNOT_SHAPE_CROSS,
SP_KNOT_SHAPE_BITMAP,
SP_KNOT_SHAPE_IMAGE
diff --git a/src/knot-holder-entity.cpp b/src/knot-holder-entity.cpp
index 95b135be0..8add35d46 100644
--- a/src/knot-holder-entity.cpp
+++ b/src/knot-holder-entity.cpp
@@ -24,6 +24,7 @@
#include "sp-pattern.h"
#include "snap.h"
#include "desktop.h"
+#include "inkscape.h"
#include "sp-namedview.h"
int KnotHolderEntity::counter = 0;
@@ -32,6 +33,9 @@ void KnotHolderEntity::create(SPDesktop *desktop, SPItem *item, KnotHolder *pare
const gchar *tip,
SPKnotShapeType shape, SPKnotModeType mode, guint32 color)
{
+ if (!desktop) {
+ desktop = SP_ACTIVE_DESKTOP;
+ }
knot = new SPKnot(desktop, tip);
this->parent_holder = parent;
diff --git a/src/knot.cpp b/src/knot.cpp
index b57c938c3..c04206dee 100644
--- a/src/knot.cpp
+++ b/src/knot.cpp
@@ -25,8 +25,6 @@
#include "document-undo.h"
#include "message-stack.h"
#include "message-context.h"
-#include "ui/tools-switch.h"
-#include "ui/tools/tool-base.h"
#include "ui/tools/node-tool.h"
#include <gtk/gtk.h>
@@ -71,6 +69,7 @@ SPKnot::SPKnot(SPDesktop *desktop, gchar const *tip)
this->flags = 0;
this->size = 8;
+ this->angle = 0;
this->pos = Geom::Point(0, 0);
this->grabbed_rel_pos = Geom::Point(0, 0);
this->anchor = SP_ANCHOR_CENTER;
@@ -111,6 +110,7 @@ SPKnot::SPKnot(SPDesktop *desktop, gchar const *tip)
SP_TYPE_CTRL,
"anchor", SP_ANCHOR_CENTER,
"size", 8.0,
+ "angle", 0.0,
"filled", TRUE,
"fill_color", 0xffffff00,
"stroked", TRUE,
@@ -214,7 +214,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
if ((event->button.button == 1) && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) {
Geom::Point const p = knot->desktop->w2d(Geom::Point(event->button.x, event->button.y));
knot->startDragging(p, (gint) event->button.x, (gint) event->button.y, event->button.time);
-
+ knot->grabbed_signal.emit(knot, event->button.state);
consumed = TRUE;
}
break;
@@ -252,10 +252,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
consumed = TRUE;
}
}
- if (tools_isactive(knot->desktop, TOOLS_NODES)) {
- Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(knot->desktop->event_context);
- nt->update_helperpath();
- }
+ Inkscape::UI::Tools::sp_update_helperpath();
break;
case GDK_MOTION_NOTIFY:
if (grabbed && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) {
@@ -279,8 +276,6 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
}
if (!moved) {
- knot->grabbed_signal.emit(knot, event->motion.state);
-
knot->setFlag(SP_KNOT_DRAGGING, TRUE);
}
@@ -288,10 +283,7 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
sp_knot_handler_request_position(event, knot);
moved = TRUE;
}
- if (tools_isactive(knot->desktop, TOOLS_NODES)) {
- Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(knot->desktop->event_context);
- nt->update_helperpath();
- }
+ Inkscape::UI::Tools::sp_update_helperpath();
break;
case GDK_ENTER_NOTIFY:
knot->setFlag(SP_KNOT_MOUSEOVER, TRUE);
@@ -449,6 +441,7 @@ void SPKnot::updateCtrl() {
g_object_set(this->item, "shape", this->shape, NULL);
g_object_set(this->item, "mode", this->mode, NULL);
g_object_set(this->item, "size", (gdouble) this->size, NULL);
+ g_object_set(this->item, "angle", this->angle, NULL);
g_object_set(this->item, "anchor", this->anchor, NULL);
if (this->pixbuf) {
@@ -492,6 +485,10 @@ void SPKnot::setPixbuf(gpointer p) {
pixbuf = p;
}
+void SPKnot::setAngle(double i) {
+ angle = i;
+}
+
void SPKnot::setFill(guint32 normal, guint32 mouseover, guint32 dragging) {
fill[SP_KNOT_STATE_NORMAL] = normal;
fill[SP_KNOT_STATE_MOUSEOVER] = mouseover;
diff --git a/src/knot.h b/src/knot.h
index e3ad98e66..954ddd8a6 100644
--- a/src/knot.h
+++ b/src/knot.h
@@ -51,6 +51,7 @@ public:
unsigned int flags;
unsigned int size; /**< Always square. */
+ double angle; /**< Angle of mesh handle. */
Geom::Point pos; /**< Our desktop coordinates. */
Geom::Point grabbed_rel_pos; /**< Grabbed relative position. */
Geom::Point drag_origin; /**< Origin of drag. */
@@ -92,6 +93,7 @@ public:
void setAnchor(unsigned int i);
void setMode(unsigned int i);
void setPixbuf(void* p);
+ void setAngle(double i);
void setFill(guint32 normal, guint32 mouseover, guint32 dragging);
void setStroke(guint32 normal, guint32 mouseover, guint32 dragging);
diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp
index 6b1aba53f..e6da9ba63 100644
--- a/src/libnrtype/Layout-TNG-Compute.cpp
+++ b/src/libnrtype/Layout-TNG-Compute.cpp
@@ -1182,10 +1182,34 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
for(input_index = para->first_input_index ; input_index < _flow._input_stream.size() ; input_index++) {
if (_flow._input_stream[input_index]->Type() == CONTROL_CODE) {
Layout::InputStreamControlCode const *control_code = static_cast<Layout::InputStreamControlCode const *>(_flow._input_stream[input_index]);
+
if ( control_code->code == SHAPE_BREAK
- || control_code->code == PARAGRAPH_BREAK)
+ || control_code->code == PARAGRAPH_BREAK) {
+
+ // Add span to be used to calculate line spacing of blank lines.
+ UnbrokenSpan new_span;
+ new_span.pango_item_index = -1;
+ new_span.input_index = input_index;
+
+ // No pango object, so find font and line height ourselves.
+ SPObject * object = static_cast<SPObject *>(control_code->source_cookie);
+ if (object) {
+ SPStyle * style = object->style;
+ if (style) {
+ new_span.font_size = style->font_size.computed * _flow.getTextLengthMultiplierDue();
+ font_factory * factory = font_factory::Default();
+ font_instance * font = factory->FaceFromStyle( style );
+ new_span.line_height_multiplier = _computeFontLineHeight( object->style );
+ new_span.line_height.set( font );
+ new_span.line_height *= new_span.font_size;
+ }
+ }
+ new_span.text_bytes = 0;
+ new_span.char_index_in_para = char_index_in_para;
+ para->unbroken_spans.push_back(new_span);
+ TRACE(("add empty span for break %lu\n", para->unbroken_spans.size() - 1));
break; // stop at the end of the paragraph
- else if (control_code->code == ARBITRARY_GAP) {
+ } else if (control_code->code == ARBITRARY_GAP) {
UnbrokenSpan new_span;
new_span.pango_item_index = -1;
new_span.input_index = input_index;
@@ -1619,8 +1643,8 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const &para,
*line_height = *strut_height;
for (std::vector<ChunkInfo>::const_iterator it_chunk = chunk_info->begin() ; it_chunk != chunk_info->end() ; it_chunk++) {
for (std::vector<BrokenSpan>::const_iterator it_span = it_chunk->broken_spans.begin() ; it_span != it_chunk->broken_spans.end() ; it_span++) {
- TRACE((" brokenspan line_height: %f\n", it_span->start.iter_span->line_height.emSize() ));
FontMetrics span_height = it_span->start.iter_span->line_height;
+ TRACE((" brokenspan line_height: %f\n", span_height.emSize() ));
span_height.computeEffective( it_span->start.iter_span->line_height_multiplier );
line_height->max( span_height );
}
diff --git a/src/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp
index df7adf5b4..a1a19f2b3 100644
--- a/src/libnrtype/Layout-TNG-Output.cpp
+++ b/src/libnrtype/Layout-TNG-Output.cpp
@@ -867,6 +867,23 @@ double Layout::getActualLength() const
}//namespace Text
}//namespace Inkscape
+std::ostream &operator<<(std::ostream &out, const Inkscape::Text::Layout::FontMetrics &f) {
+ out << " emSize: " << f.emSize()
+ << " ascent: " << f.ascent
+ << " descent: " << f.descent
+ << " xheight: " << f.xheight;
+ return out;
+}
+
+std::ostream &operator<<(std::ostream &out, const Inkscape::Text::Layout::FontMetrics *f) {
+ out << " emSize: " << f->emSize()
+ << " ascent: " << f->ascent
+ << " descent: " << f->descent
+ << " xheight: " << f->xheight;
+ return out;
+}
+
+
/*
Local Variables:
diff --git a/src/libnrtype/Layout-TNG.h b/src/libnrtype/Layout-TNG.h
index 8b46758f0..e06b8392f 100644
--- a/src/libnrtype/Layout-TNG.h
+++ b/src/libnrtype/Layout-TNG.h
@@ -629,7 +629,7 @@ public:
void reset() {
ascent = 0.8;
- descent = -0.2;
+ descent = 0.2;
xheight = 0.5;
ascent_max = 0.8;
descent_max = 0.2;
@@ -664,7 +664,7 @@ public:
// private:
double ascent; // Typographic ascent.
- double descent; // Typographic descent.
+ double descent; // Typographic descent. (Normally positive).
double xheight; // Height of 'x' measured from alphabetic baseline.
double ascent_max; // Maximum ascent of all glyphs in font.
double descent_max; // Maximum descent of all glyphs in font.
@@ -1189,6 +1189,10 @@ inline bool Layout::iterator::prevCharacter()
}//namespace Text
}//namespace Inkscape
+std::ostream &operator<<(std::ostream &out, const Inkscape::Text::Layout::FontMetrics &f);
+std::ostream &operator<<(std::ostream &out, const Inkscape::Text::Layout::FontMetrics *f);
+
+
#endif
diff --git a/src/libuemf/uemf.h b/src/libuemf/uemf.h
index 82fd0990c..05566af06 100644
--- a/src/libuemf/uemf.h
+++ b/src/libuemf/uemf.h
@@ -168,12 +168,24 @@ extern "C" {
#define U_ROUND(A) ( (A) > 0 ? floor((A)+0.5) : ( (A) < 0 ? -floor(-(A)+0.5) : (A) ) )
#define MAKE_MIN_PTR(A,B) ( A < B ? A : B)
-/* This is tricky. The next one can be called with a size which is either an int or an unsigned int.
- The former can be negative, which is obviously wrong, but testing for that means that the size cannot
- be more than INT_MAX/2. Accept that limitation since no reasonable EMF record or file should ever be that large.
- B must be an INT or size_t.
- If a uint16_t is used gcc complains about the first test. Force B to be at least as big as int (at run time) */
-#define IS_MEM_UNSAFE(A,B,C) ( (sizeof(B) < sizeof(int) || (int)(B)) < 0 ? 1 : ((int8_t *)(A) > (int8_t *)(C) ? 1 : ((int8_t *)(C) - (int8_t *)(A) >= (int)(B) ? 0 : 1 ))) //!< Return 1 when a region of memory starting at A of B bytes extends beyond pointer C
+
+/* IS_MEM_UNSAFE takes 3 parameters:
+ A start address of a block of allocated memory
+ B offset into this block starting at A
+ C address of final byte of a block of allocated memory.
+ Returns
+ 1 if B cannot be an int or size_t
+ 1 if C > A
+ 1 if A+B is not in the range A to C, inclusive
+ 0 otherwise.
+ B may be an int, an unsigned int, or a size_t. An int can be negative,
+ which is obviously wrong, but testing for that means that the size
+ of B cannot be more than INT_MAX/2. Accept that limitation since
+ no reasonable EMF record or file should ever be that large.
+ If B is a uint16_t gcc complains about the first test.
+ This Macro must not be used where B needs more than 32 bits!
+*/
+#define IS_MEM_UNSAFE(A,B,C) ( (sizeof(B) < sizeof(int) || (int)(B) < 0) ? 1 : ((int8_t *)(A) > (int8_t *)(C) ? 1 : ((int8_t *)(C) - (int8_t *)(A) >= (int)(B) ? 0 : 1 )))
/** @} */
diff --git a/src/livarot/LivarotDefs.h b/src/livarot/LivarotDefs.h
index abeff3861..d020841b0 100644
--- a/src/livarot/LivarotDefs.h
+++ b/src/livarot/LivarotDefs.h
@@ -40,18 +40,6 @@ enum
found_between = 4
};
-// boolean operation
-enum bool_op
-{
- bool_op_union, // A OR B
- bool_op_inters, // A AND B
- bool_op_diff, // A \ B
- bool_op_symdiff, // A XOR B
- bool_op_cut, // coupure (pleines)
- bool_op_slice // coupure (contour)
-};
-typedef enum bool_op BooleanOp;
-
// types of cap for stroking polylines
enum butt_typ
{
diff --git a/src/livarot/Shape.h b/src/livarot/Shape.h
index 98fc2d7bf..da1edc6b3 100644
--- a/src/livarot/Shape.h
+++ b/src/livarot/Shape.h
@@ -17,6 +17,7 @@
#include <2geom/point.h>
#include "livarot/LivarotDefs.h"
+#include "object-set.h"
class Path;
class FloatLigne;
diff --git a/src/livarot/int-line.h b/src/livarot/int-line.h
index 1d3bbd9d2..ed3ccfb96 100644
--- a/src/livarot/int-line.h
+++ b/src/livarot/int-line.h
@@ -2,6 +2,7 @@
#define INKSCAPE_LIVAROT_INT_LINE_H
#include "livarot/LivarotDefs.h"
+#include "object-set.h"
/** \file
* Coverage with integer boundaries.
diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp
index 792bb5d7a..5cc0d6f20 100644
--- a/src/live_effects/effect.cpp
+++ b/src/live_effects/effect.cpp
@@ -350,6 +350,7 @@ Effect::Effect(LivePathEffectObject *lpeobject)
oncanvasedit_it(0),
is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true),
show_orig_path(false),
+ erase_extra_objects(true),
lpeobj(lpeobject),
concatenate_before_pwd2(false),
sp_lpe_item(NULL),
@@ -611,15 +612,15 @@ Effect::registerParameter(Parameter * param)
* Add all registered LPE knotholder handles to the knotholder
*/
void
-Effect::addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
+Effect::addHandles(KnotHolder *knotholder, SPItem *item) {
using namespace Inkscape::LivePathEffect;
// add handles provided by the effect itself
- addKnotHolderEntities(knotholder, desktop, item);
+ addKnotHolderEntities(knotholder, item);
// add handles provided by the effect's parameters (if any)
for (std::vector<Parameter *>::iterator p = param_vector.begin(); p != param_vector.end(); ++p) {
- (*p)->addKnotHolderEntities(knotholder, desktop, item);
+ (*p)->addKnotHolderEntities(knotholder, item);
}
}
@@ -659,14 +660,7 @@ Effect::addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathV
*/
void
Effect::update_helperpath() {
- using namespace Inkscape::UI;
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
- if (desktop) {
- if (tools_isactive(desktop, TOOLS_NODES)) {
- Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(desktop->event_context);
- nt->update_helperpath();
- }
- }
+ Inkscape::UI::Tools::sp_update_helperpath();
}
/**
diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h
index 5ca53486c..1997ff0ca 100644
--- a/src/live_effects/effect.h
+++ b/src/live_effects/effect.h
@@ -100,7 +100,7 @@ public:
// /TODO: in view of providesOwnFlashPaths() below, this is somewhat redundant
// (but spiro lpe still needs it!)
virtual LPEPathFlashType pathFlashType() const { return DEFAULT; }
- void addHandles(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ void addHandles(KnotHolder *knotholder, SPItem *item);
std::vector<Geom::PathVector> getCanvasIndicators(SPLPEItem const* lpeitem);
void update_helperpath();
@@ -123,6 +123,7 @@ public:
void editNextParamOncanvas(SPItem * item, SPDesktop * desktop);
bool apply_to_clippath_and_mask;
+ bool erase_extra_objects; // set this to false allow retain extra generated objects, see measure line LPE
bool upd_params;
protected:
@@ -141,7 +142,7 @@ protected:
void registerParameter(Parameter * param);
Parameter * getNextOncanvasEditableParam();
- virtual void addKnotHolderEntities(KnotHolder * /*knotholder*/, SPDesktop * /*desktop*/, SPItem * /*item*/) {};
+ virtual void addKnotHolderEntities(KnotHolder * /*knotholder*/, SPItem * /*item*/) {};
virtual void addCanvasIndicators(SPLPEItem const* lpeitem, std::vector<Geom::PathVector> &hp_vec);
diff --git a/src/live_effects/lpe-angle_bisector.cpp b/src/live_effects/lpe-angle_bisector.cpp
index 9bfbf4ca8..56d33eb4b 100644
--- a/src/live_effects/lpe-angle_bisector.cpp
+++ b/src/live_effects/lpe-angle_bisector.cpp
@@ -8,15 +8,13 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-angle_bisector.h"
-
-#include <2geom/sbasis-to-bezier.h>
-
+#include "2geom/sbasis-to-bezier.h"
#include "sp-lpe-item.h"
#include "knot-holder-entity.h"
#include "knotholder.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-attach-path.cpp b/src/live_effects/lpe-attach-path.cpp
index d2b44dd4e..302165719 100644
--- a/src/live_effects/lpe-attach-path.cpp
+++ b/src/live_effects/lpe-attach-path.cpp
@@ -4,15 +4,14 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
#include <math.h>
-
#include "live_effects/lpe-attach-path.h"
-
#include "display/curve.h"
#include "sp-shape.h"
#include "sp-text.h"
#include "2geom/path-sink.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-bendpath.cpp b/src/live_effects/lpe-bendpath.cpp
index c24d38d7b..b1e133292 100644
--- a/src/live_effects/lpe-bendpath.cpp
+++ b/src/live_effects/lpe-bendpath.cpp
@@ -7,9 +7,10 @@
#include "live_effects/lpe-bendpath.h"
#include "sp-item-group.h"
-
#include "knot-holder-entity.h"
#include "knotholder.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using std::vector;
diff --git a/src/live_effects/lpe-bounding-box.cpp b/src/live_effects/lpe-bounding-box.cpp
index 2de768c3a..11fb34e04 100644
--- a/src/live_effects/lpe-bounding-box.cpp
+++ b/src/live_effects/lpe-bounding-box.cpp
@@ -3,14 +3,14 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-bounding-box.h"
#include "display/curve.h"
#include "sp-shape.h"
#include "sp-text.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h
index 7823f00f0..90cf82c19 100644
--- a/src/live_effects/lpe-bspline.h
+++ b/src/live_effects/lpe-bspline.h
@@ -6,8 +6,8 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include "live_effects/effect.h"
+#include "live_effects/effect.h"
#include <vector>
namespace Inkscape {
diff --git a/src/live_effects/lpe-circle_3pts.cpp b/src/live_effects/lpe-circle_3pts.cpp
index 18252f6a0..3410b13f2 100644
--- a/src/live_effects/lpe-circle_3pts.cpp
+++ b/src/live_effects/lpe-circle_3pts.cpp
@@ -17,6 +17,8 @@
// You might need to include other 2geom files. You can add them here:
#include <2geom/circle.h>
#include <2geom/path-sink.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-circle_with_radius.cpp b/src/live_effects/lpe-circle_with_radius.cpp
index 6e03cb1ce..fcefc4ec6 100644
--- a/src/live_effects/lpe-circle_with_radius.cpp
+++ b/src/live_effects/lpe-circle_with_radius.cpp
@@ -17,6 +17,8 @@
// You might need to include other 2geom files. You can add them here:
#include <2geom/circle.h>
#include <2geom/path-sink.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using namespace Geom;
diff --git a/src/live_effects/lpe-clone-original.cpp b/src/live_effects/lpe-clone-original.cpp
index 7541c0be2..10418a02d 100644
--- a/src/live_effects/lpe-clone-original.cpp
+++ b/src/live_effects/lpe-clone-original.cpp
@@ -4,11 +4,10 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-clone-original.h"
-
#include "display/curve.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-constructgrid.cpp b/src/live_effects/lpe-constructgrid.cpp
index 4af8891e8..8d24f9f47 100644
--- a/src/live_effects/lpe-constructgrid.cpp
+++ b/src/live_effects/lpe-constructgrid.cpp
@@ -10,9 +10,9 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-constructgrid.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp
index 1133e083a..813f25d3d 100644
--- a/src/live_effects/lpe-copy_rotate.cpp
+++ b/src/live_effects/lpe-copy_rotate.cpp
@@ -11,36 +11,18 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <gtkmm.h>
#include <gdk/gdk.h>
#include <2geom/path-intersection.h>
#include <2geom/sbasis-to-bezier.h>
+#include <2geom/intersection-graph.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)
{
@@ -58,28 +40,31 @@ 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_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),
+ origin(_("Origin"), _("Adjust origin of the rotation"), "origin", &wr, this, _("Adjust origin of the rotation")),
+ starting_point(_("Start point"), _("Starting point to define start angle"), "starting_point", &wr, this, _("Adjust starting point to define start angle")),
+ starting_angle(_("Starting angle"), _("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),
copies_to_360(_("360º Copies"), _("No rotation angle, fixed to 360º"), "copies_to_360", &wr, this, true),
- fuse_paths(_("Fuse paths"), _("Fuse paths by helper line, use fill-rule: evenodd for best result"), "fuse_paths", &wr, this, false),
+ fuse_paths(_("Kaleidoskope"), _("Kaleidoskope by helper line, use fill-rule: evenodd for best result"), "fuse_paths", &wr, this, false),
+ join_paths(_("Join paths"), _("Join paths, use fill-rule: evenodd for best result"), "join_paths", &wr, this, false),
dist_angle_handle(100.0)
{
show_orig_path = true;
_provides_knotholder_entities = true;
- apply_to_clippath_and_mask = true;
-
// register all your parameters here, so Inkscape knows which parameters this effect has:
registerParameter(&copies_to_360);
registerParameter(&fuse_paths);
+ registerParameter(&join_paths);
registerParameter(&starting_angle);
+ registerParameter(&starting_point);
registerParameter(&rotation_angle);
registerParameter(&num_copies);
registerParameter(&origin);
num_copies.param_make_integer(true);
num_copies.param_set_range(0, 1000);
+ apply_to_clippath_and_mask = true;
}
LPECopyRotate::~LPECopyRotate()
@@ -87,6 +72,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)
{
@@ -95,7 +115,7 @@ LPECopyRotate::doOnApply(SPLPEItem const* lpeitem)
A = Point(boundingbox_X.min(), boundingbox_Y.middle());
B = Point(boundingbox_X.middle(), boundingbox_Y.middle());
- origin.param_setValue(A);
+ origin.param_setValue(A, true);
origin.param_update_default(A);
dist_angle_handle = L2(B - A);
dir = unit_vector(B - A);
@@ -104,11 +124,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,14 +161,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;
+ near = Geom::are_near(start_pos, (Geom::Point)starting_point, 0.01);
+ if (!near) {
+ starting_point.param_setValue(start_pos, true);
+ }
+ 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);
}
void
@@ -235,19 +261,8 @@ LPECopyRotate::setFusion(Geom::PathVector &path_on, Geom::Path divider, double s
if (i%2 != 0) {
Geom::Point A = (Geom::Point)origin;
Geom::Point B = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle*i)+starting_angle)) * size_divider;
- Geom::Translate m1(A[0], A[1]);
- double hyp = Geom::distance(A, B);
- double c = (B[0] - A[0]) / hyp; // cos(alpha)
- double s = (B[1] - A[1]) / hyp; // sin(alpha)
-
- Geom::Affine m2(c, -s, s, c, 0.0, 0.0);
- Geom::Scale sca(1.0, -1.0);
-
- Geom::Affine tmp_m = m1.inverse() * m2;
- m = tmp_m;
- m = m * sca;
- m = m * m2.inverse();
- m = m * m1;
+ Geom::Line ls(A,B);
+ m = Geom::reflection (ls.vector(), A);
} else {
append_path = original;
}
@@ -388,10 +403,26 @@ LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & p
output = paths_to_pw(path_out);
}
} else {
+ Geom::PathVector output_pv = path_from_piecewise(output , 0.01);
for (int i = 0; i < num_copies; ++i) {
Rotate rot(-rad_from_deg(rotation_angle * i));
Affine t = pre * rot * Translate(origin);
- output.concat(pwd2_in * t);
+ if (join_paths) {
+ Geom::PathVector join_pv = path_from_piecewise(pwd2_in * t , 0.01);
+ Geom::PathIntersectionGraph *pig = new Geom::PathIntersectionGraph(output_pv, join_pv);
+ if (pig) {
+ if (!output_pv.empty()) {
+ output_pv = pig->getUnion();
+ } else {
+ output_pv = join_pv;
+ }
+ }
+ } else {
+ output.concat(pwd2_in * t);
+ }
+ }
+ if (join_paths) {
+ output = paths_to_pw(output_pv);
}
}
return output;
@@ -418,85 +449,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..c2ae2daf1 100644
--- a/src/live_effects/lpe-copy_rotate.h
+++ b/src/live_effects/lpe-copy_rotate.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,26 +32,25 @@ 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;
BoolParam copies_to_360;
BoolParam fuse_paths;
+ BoolParam join_paths;
Geom::Point A;
Geom::Point B;
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/live_effects/lpe-curvestitch.cpp b/src/live_effects/lpe-curvestitch.cpp
index 3beedaf57..38cbeaac0 100644
--- a/src/live_effects/lpe-curvestitch.cpp
+++ b/src/live_effects/lpe-curvestitch.cpp
@@ -13,8 +13,6 @@
*/
#include "ui/widget/scalar.h"
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-curvestitch.h"
#include "sp-path.h"
@@ -22,6 +20,9 @@
#include "xml/repr.h"
#include <2geom/bezier-to-sbasis.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-dynastroke.cpp b/src/live_effects/lpe-dynastroke.cpp
index 7e22f6e51..50bbe6451 100644
--- a/src/live_effects/lpe-dynastroke.cpp
+++ b/src/live_effects/lpe-dynastroke.cpp
@@ -16,6 +16,8 @@
#include <2geom/bezier-to-sbasis.h>
#include <2geom/sbasis-math.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-ellipse_5pts.cpp b/src/live_effects/lpe-ellipse_5pts.cpp
index 0371fc313..28e7058d7 100644
--- a/src/live_effects/lpe-ellipse_5pts.cpp
+++ b/src/live_effects/lpe-ellipse_5pts.cpp
@@ -12,15 +12,14 @@
*/
#include "live_effects/lpe-ellipse_5pts.h"
-
-// You might need to include other 2geom files. You can add them here:
-#include <glibmm/i18n.h>
#include <2geom/circle.h>
#include <2geom/ellipse.h>
#include <2geom/path-sink.h>
#include "inkscape.h"
#include "desktop.h"
#include "message-stack.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-envelope.cpp b/src/live_effects/lpe-envelope.cpp
index c3b0a7c10..61a696435 100644
--- a/src/live_effects/lpe-envelope.cpp
+++ b/src/live_effects/lpe-envelope.cpp
@@ -6,6 +6,8 @@
#include "live_effects/lpe-envelope.h"
#include "display/curve.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using std::vector;
diff --git a/src/live_effects/lpe-extrude.cpp b/src/live_effects/lpe-extrude.cpp
index d22007f76..daa30d45a 100644
--- a/src/live_effects/lpe-extrude.cpp
+++ b/src/live_effects/lpe-extrude.cpp
@@ -12,10 +12,10 @@
*/
#include "live_effects/lpe-extrude.h"
-
+#include "sp-item.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
-#include "sp-item.h"
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-fill-between-many.cpp b/src/live_effects/lpe-fill-between-many.cpp
index 2087925fa..1e2eadfdb 100644
--- a/src/live_effects/lpe-fill-between-many.cpp
+++ b/src/live_effects/lpe-fill-between-many.cpp
@@ -11,7 +11,7 @@
#include "display/curve.h"
#include "sp-shape.h"
#include "sp-text.h"
-
+// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
namespace Inkscape {
diff --git a/src/live_effects/lpe-fill-between-strokes.cpp b/src/live_effects/lpe-fill-between-strokes.cpp
index b1e328d18..0dbebdf26 100644
--- a/src/live_effects/lpe-fill-between-strokes.cpp
+++ b/src/live_effects/lpe-fill-between-strokes.cpp
@@ -3,14 +3,13 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-fill-between-strokes.h"
#include "display/curve.h"
#include "sp-shape.h"
#include "sp-text.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp
index 24ee2ccc3..1e2df7dc8 100644
--- a/src/live_effects/lpe-fillet-chamfer.cpp
+++ b/src/live_effects/lpe-fillet-chamfer.cpp
@@ -25,8 +25,8 @@
// for programmatically updating knots
#include "ui/tools-switch.h"
-
// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using namespace Geom;
namespace Inkscape {
diff --git a/src/live_effects/lpe-gears.cpp b/src/live_effects/lpe-gears.cpp
index 1d5398aa5..dad520041 100644
--- a/src/live_effects/lpe-gears.cpp
+++ b/src/live_effects/lpe-gears.cpp
@@ -7,10 +7,9 @@
*/
#include "live_effects/lpe-gears.h"
-
-#include <glibmm/i18n.h>
-
#include <2geom/bezier-to-sbasis.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using std::vector;
using namespace Geom;
@@ -208,7 +207,7 @@ LPEGears::LPEGears(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
teeth(_("_Teeth:"), _("The number of teeth"), "teeth", &wr, this, 10),
phi(_("_Phi:"), _("Tooth pressure angle (typically 20-25 deg). The ratio of teeth not in contact."), "phi", &wr, this, 5),
- min_radius(_("Min Radius:"), _("Minimun radius, low balues can slow"), "min_radius", &wr, this, 5.0)
+ min_radius(_("Min Radius:"), _("Minimum radius, low values can be slow"), "min_radius", &wr, this, 5.0)
{
/* Tooth pressure angle: The angle between the tooth profile and a perpendicular to the pitch
* circle, usually at the point where the pitch circle meets the tooth profile. Standard angles
diff --git a/src/live_effects/lpe-interpolate.cpp b/src/live_effects/lpe-interpolate.cpp
index 43da4d105..e95dc5f38 100644
--- a/src/live_effects/lpe-interpolate.cpp
+++ b/src/live_effects/lpe-interpolate.cpp
@@ -9,15 +9,15 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-interpolate.h"
#include <2geom/sbasis-to-bezier.h>
#include "sp-path.h"
#include "display/curve.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-interpolate_points.cpp b/src/live_effects/lpe-interpolate_points.cpp
index ab0576174..0a0bcea14 100644
--- a/src/live_effects/lpe-interpolate_points.cpp
+++ b/src/live_effects/lpe-interpolate_points.cpp
@@ -12,8 +12,9 @@
*/
#include "live_effects/lpe-interpolate_points.h"
-
#include "live_effects/lpe-powerstroke-interpolators.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp
index 3bfbd6288..dacb87dd9 100644
--- a/src/live_effects/lpe-jointype.cpp
+++ b/src/live_effects/lpe-jointype.cpp
@@ -19,6 +19,8 @@
#include <2geom/elliptical-arc.h>
#include "lpe-jointype.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp
index fbc32cf3e..2defecb77 100644
--- a/src/live_effects/lpe-knot.cpp
+++ b/src/live_effects/lpe-knot.cpp
@@ -20,18 +20,21 @@
#include "knot-holder-entity.h"
#include "knotholder.h"
-#include <glibmm/i18n.h>
#include <gdk/gdk.h>
#include <2geom/sbasis-to-bezier.h>
#include <2geom/bezier-to-sbasis.h>
#include <2geom/basic-intersection.h>
+#include "helper/geom.h"
// for change crossing undo
#include "verbs.h"
#include "document.h"
#include "document-undo.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -392,14 +395,14 @@ LPEKnot::doEffect_path (Geom::PathVector const &path_in)
if (gpaths.size()==0){
return path_in;
}
-
- for (unsigned comp=0; comp<path_in.size(); comp++){
+ Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(path_in);
+ for (unsigned comp=0; comp<original_pathv.size(); comp++){
//find the relevant path component in gpaths (required to allow groups!)
//Q: do we always receive the group members in the same order? can we rest on that?
unsigned i0 = 0;
for (i0=0; i0<gpaths.size(); i0++){
- if (path_in[comp]==gpaths[i0]) break;
+ if (original_pathv[comp]==gpaths[i0]) break;
}
if (i0 == gpaths.size() ) {THROW_EXCEPTION("lpe-knot error: group member not recognized");}// this should not happen...
@@ -514,7 +517,7 @@ collectPathsAndWidths (SPLPEItem const *lpeitem, Geom::PathVector &paths, std::v
c = SP_SHAPE(lpeitem)->getCurve();
}
if (c) {
- Geom::PathVector subpaths = c->get_pathvector();
+ Geom::PathVector subpaths = pathv_to_linear_and_cubic_beziers(c->get_pathvector());
for (unsigned i=0; i<subpaths.size(); i++){
paths.push_back(subpaths[i]);
//FIXME: do we have to be more carefull when trying to access stroke width?
@@ -612,10 +615,10 @@ LPEKnot::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::Pat
hp_vec.push_back(pathv);
}
-void LPEKnot::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+void LPEKnot::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
KnotHolderEntity *e = new KnotHolderEntityCrossingSwitcher(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("Drag to select a crossing, click to flip it") );
knotholder->add(e);
};
diff --git a/src/live_effects/lpe-knot.h b/src/live_effects/lpe-knot.h
index 95bfaf6e1..ac518b97c 100644
--- a/src/live_effects/lpe-knot.h
+++ b/src/live_effects/lpe-knot.h
@@ -61,7 +61,7 @@ public:
/* the knotholder entity classes must be declared friends */
friend class KnotHolderEntityCrossingSwitcher;
- void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
protected:
virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec);
diff --git a/src/live_effects/lpe-lattice.cpp b/src/live_effects/lpe-lattice.cpp
index 091b6ddca..acffed000 100644
--- a/src/live_effects/lpe-lattice.cpp
+++ b/src/live_effects/lpe-lattice.cpp
@@ -20,7 +20,8 @@
#include <2geom/sbasis-2d.h>
#include <2geom/bezier-to-sbasis.h>
-
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using namespace Geom;
namespace Inkscape {
diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp
index 9e9fc153a..e827491c0 100644
--- a/src/live_effects/lpe-lattice2.cpp
+++ b/src/live_effects/lpe-lattice2.cpp
@@ -16,12 +16,15 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <gtkmm.h>
#include "live_effects/lpe-lattice2.h"
#include "display/curve.h"
#include "helper/geom.h"
#include <2geom/sbasis-2d.h>
#include <2geom/bezier-to-sbasis.h>
+
// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using namespace Geom;
diff --git a/src/live_effects/lpe-lattice2.h b/src/live_effects/lpe-lattice2.h
index 4a025d182..59a0350d3 100644
--- a/src/live_effects/lpe-lattice2.h
+++ b/src/live_effects/lpe-lattice2.h
@@ -18,7 +18,7 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <gtkmm.h>
+
#include "live_effects/effect.h"
#include "live_effects/parameter/enum.h"
#include "live_effects/parameter/point.h"
diff --git a/src/live_effects/lpe-line_segment.cpp b/src/live_effects/lpe-line_segment.cpp
index 4c9edabd4..cc024fb92 100644
--- a/src/live_effects/lpe-line_segment.cpp
+++ b/src/live_effects/lpe-line_segment.cpp
@@ -13,6 +13,8 @@
#include "live_effects/lpe-line_segment.h"
#include "ui/tools/lpe-tool.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-measure-line.cpp b/src/live_effects/lpe-measure-line.cpp
index e8ceb7e51..af2a8e919 100644
--- a/src/live_effects/lpe-measure-line.cpp
+++ b/src/live_effects/lpe-measure-line.cpp
@@ -14,8 +14,7 @@
#include <libnrtype/font-lister.h>
#include "inkscape.h"
#include "xml/node.h"
-#include "uri.h"
-#include "uri-references.h"
+#include "xml/sp-css-attr.h"
#include "preferences.h"
#include "util/units.h"
#include "svg/svg-length.h"
@@ -29,7 +28,6 @@
#include "sp-item.h"
#include "sp-shape.h"
#include "sp-path.h"
-#include "desktop.h"
#include "document.h"
#include <iomanip>
@@ -54,16 +52,17 @@ LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) :
orientation(_("Orientation"), _("Orientation method"), "orientation", OMConverter, &wr, this, OM_PARALLEL, false),
curve_linked(_("Curve on origin"), _("Curve on origin, set 0 to start/end"), "curve_linked", &wr, this, 1),
precision(_("Precision*"), _("Precision"), "precision", &wr, this, 2),
- position(_("Positon*"), _("Positon"), "position", &wr, this, 5),
+ position(_("Position*"), _("Position"), "position", &wr, this, 5),
text_top_bottom(_("Text top/bottom*"), _("Text top/bottom"), "text_top_bottom", &wr, this, 0),
text_right_left(_("Text right/left*"), _("Text right/left"), "text_right_left", &wr, this, 0),
helpline_distance(_("Helpline distance*"), _("Helpline distance"), "helpline_distance", &wr, this, 0.0),
helpline_overlap(_("Helpline overlap*"), _("Helpline overlap"), "helpline_overlap", &wr, this, 2.0),
scale(_("Scale*"), _("Scaling factor"), "scale", &wr, this, 1.0),
- format(_("Format*"), _("Format the number ex:{measure} {unit}, return to save"), "format", &wr, this,"measure unit"),
+ format(_("Format*"), _("Format the number ex:{measure} {unit}, return to save"), "format", &wr, this,"{measure}{unit}"),
+ id_origin("id_origin", "id_origin", "id_origin", &wr, this,""),
arrows_outside(_("Arrows outside"), _("Arrows outside"), "arrows_outside", &wr, this, false),
flip_side(_("Flip side*"), _("Flip side"), "flip_side", &wr, this, false),
- scale_insensitive(_("Scale insensitive*"), _("Scale insensitive to transforms in element, parents..."), "scale_insensitive", &wr, this, true),
+ scale_sensitive(_("Scale sensitive*"), _("Costrained scale sensitive to transformed containers"), "scale_sensitive", &wr, this, true),
local_locale(_("Local Number Format*"), _("Local number format"), "local_locale", &wr, this, true),
line_group_05(_("Line Group 0.5*"), _("Line Group 0.5, from 0.7"), "line_group_05", &wr, this, true),
rotate_anotation(_("Rotate Anotation*"), _("Rotate Anotation"), "rotate_anotation", &wr, this, true),
@@ -88,7 +87,7 @@ LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) :
registerParameter(&format);
registerParameter(&arrows_outside);
registerParameter(&flip_side);
- registerParameter(&scale_insensitive);
+ registerParameter(&scale_sensitive);
registerParameter(&local_locale);
registerParameter(&line_group_05);
registerParameter(&rotate_anotation);
@@ -97,6 +96,8 @@ LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) :
registerParameter(&helperlines_format);
registerParameter(&anotation_format);
registerParameter(&arrows_format);
+ registerParameter(&id_origin);
+ id_origin.param_hide_canvas_text();
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
Glib::ustring fontbutton_value = prefs->getString("/live_effects/measure-line/fontbutton");
if(fontbutton_value.empty()){
@@ -124,7 +125,7 @@ LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) :
anotation_format.param_update_default(prefs->getString("/live_effects/measure-line/anotation_format"));
arrows_format.param_update_default(prefs->getString("/live_effects/measure-line/arrows_format"));
flip_side.param_update_default(prefs->getBool("/live_effects/measure-line/flip_side"));
- scale_insensitive.param_update_default(prefs->getBool("/live_effects/measure-line/scale_insensitive"));
+ scale_sensitive.param_update_default(prefs->getBool("/live_effects/measure-line/scale_sensitive"));
local_locale.param_update_default(prefs->getBool("/live_effects/measure-line/local_locale"));
line_group_05.param_update_default(prefs->getBool("/live_effects/measure-line/line_group_05"));
rotate_anotation.param_update_default(prefs->getBool("/live_effects/measure-line/rotate_anotation"));
@@ -158,7 +159,8 @@ LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) :
helpline_overlap.param_set_range(-999999.0, 999999.0);
helpline_overlap.param_set_increments(1, 1);
helpline_overlap.param_set_digits(2);
- erase = true;
+ start_stored = Geom::Point(0,0);
+ end_stored = Geom::Point(0,0);
}
LPEMeasureLine::~LPEMeasureLine() {}
@@ -168,614 +170,568 @@ void swap(Geom::Point &A, Geom::Point &B){
A = B;
B = tmp;
}
-void
-LPEMeasureLine::doOnApply(SPLPEItem const* lpeitem)
-{
- if (!SP_IS_SHAPE(lpeitem)) {
- g_warning("LPE measure line can only be applied to shapes (not groups).");
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->removeCurrentPathEffect(false);
- }
-}
void
-LPEMeasureLine::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/)
+LPEMeasureLine::createArrowMarker(const char * mode)
{
- if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) {
- Inkscape::URI SVGElem_uri(((Glib::ustring)"#" + (Glib::ustring)"text-on-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- Inkscape::URIReference* SVGElemRef = new Inkscape::URIReference(desktop->doc());
- SVGElemRef->attach(SVGElem_uri);
- SPObject *elemref = NULL;
- Inkscape::XML::Node *node = NULL;
- if (elemref = SVGElemRef->getObject()) {
- node = elemref->getRepr();
- if (!this->isVisible()) {
- node->setAttribute("style", "display:none");
- } else {
- node->setAttribute("style", NULL);
- }
- }
- Inkscape::URI SVGElem_uri2(((Glib::ustring)"#" + (Glib::ustring)"infoline-on-start-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri2);
- if (elemref = SVGElemRef->getObject()) {
- node = elemref->getRepr();
- if (!this->isVisible()) {
- node->setAttribute("style", "display:none");
- } else {
- node->setAttribute("style", NULL);
- }
- }
- Inkscape::URI SVGElem_uri3(((Glib::ustring)"#" + (Glib::ustring)"infoline-on-end-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri3);
- if (elemref = SVGElemRef->getObject()) {
- node = elemref->getRepr();
- if (!this->isVisible()) {
- node->setAttribute("style", "display:none");
- } else {
- node->setAttribute("style", NULL);
- }
- }
- Inkscape::URI SVGElem_uri4(((Glib::ustring)"#" + (Glib::ustring)"infoline-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri4);
- if (elemref = SVGElemRef->getObject()) {
- node = elemref->getRepr();
- if (!this->isVisible()) {
- node->setAttribute("style", "display:none");
- } else {
- node->setAttribute("style", NULL);
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ SPObject *elemref = NULL;
+ Inkscape::XML::Node *arrow = NULL;
+ if (elemref = document->getObjectById(mode)) {
+ Inkscape::XML::Node *arrow= elemref->getRepr();
+ if (arrow) {
+ arrow->setAttribute("sodipodi:insensitive", "true");
+ arrow->setAttribute("transform", NULL);
+ Inkscape::XML::Node *arrow_data = arrow->firstChild();
+ if (arrow_data) {
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property (css, "fill","#000000");
+ sp_repr_css_set_property (css, "stroke","none");
+ arrow_data->setAttribute("transform", NULL);
+ sp_repr_css_attr_add_from_string(css, arrows_format.param_getSVGValue());
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ arrow_data->setAttribute("style", css_str.c_str());
}
}
- Inkscape::URI SVGElem_uri5(((Glib::ustring)"#" + (Glib::ustring)"downline-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri5);
- if (elemref = SVGElemRef->getObject()) {
- node = elemref->getRepr();
- if (!this->isVisible()) {
- node->setAttribute("style", "display:none");
- } else {
- node->setAttribute("style", NULL);
- }
+ } else {
+ arrow = xml_doc->createElement("svg:marker");
+ arrow->setAttribute("id", mode);
+ arrow->setAttribute("inkscape:stockid", mode);
+ arrow->setAttribute("orient", "auto");
+ arrow->setAttribute("refX", "0.0");
+ arrow->setAttribute("refY", "0.0");
+ arrow->setAttribute("style", "overflow:visible");
+ arrow->setAttribute("sodipodi:insensitive", "true");
+ /* Create <path> */
+ Inkscape::XML::Node *arrow_path = xml_doc->createElement("svg:path");
+ if (std::strcmp(mode, "ArrowDIN-start") == 0) {
+ arrow_path->setAttribute("d", "M -8,0 8,-2.11 8,2.11 z");
+ } else if (std::strcmp(mode, "ArrowDIN-end") == 0) {
+ arrow_path->setAttribute("d", "M 8,0 -8,2.11 -8,-2.11 z");
+ } else if (std::strcmp(mode, "ArrowDINout-start") == 0) {
+ arrow_path->setAttribute("d", "M 0,0 -16,2.11 -16,0.5 -26,0.5 -26,-0.5 -16,-0.5 -16,-2.11 z");
+ } else {
+ arrow_path->setAttribute("d", "M 0,0 16,2.11 16,0.5 26,0.5 26,-0.5 16,-0.5 16,-2.11 z");
}
+
+ arrow_path->setAttribute("id", Glib::ustring(mode).append("_path").c_str());
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property (css, "fill","#000000");
+ sp_repr_css_set_property (css, "stroke","none");
+ sp_repr_css_attr_add_from_string(css, arrows_format.param_getSVGValue());
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ arrow_path->setAttribute("style", css_str.c_str());
+ arrow->addChild(arrow_path, NULL);
+ Inkscape::GC::release(arrow_path);
+ elemref = SP_OBJECT(document->getDefs()->appendChildRepr(arrow));
+ Inkscape::GC::release(arrow);
}
+ elements.push_back(mode);
}
void
-LPEMeasureLine::createArrowMarker(Glib::ustring mode)
+LPEMeasureLine::createTextLabel(Geom::Point pos, double length, Geom::Coord angle, bool remove, bool valid)
{
- if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) {
- Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
- Inkscape::URI SVGElem_uri(((Glib::ustring)"#" + mode).c_str());
- Inkscape::URIReference* SVGElemRef = new Inkscape::URIReference(desktop->doc());
- SVGElemRef->attach(SVGElem_uri);
- SPObject *elemref = NULL;
- Inkscape::XML::Node *arrow = NULL;
- if (!(elemref = SVGElemRef->getObject())) {
- arrow = xml_doc->createElement("svg:marker");
- arrow->setAttribute("id", mode.c_str());
- arrow->setAttribute("inkscape:stockid", mode.c_str());
- arrow->setAttribute("orient", "auto");
- arrow->setAttribute("refX", "0.0");
- arrow->setAttribute("refY", "0.0");
- arrow->setAttribute("style", "overflow:visible");
- arrow->setAttribute("sodipodi:insensitive", "true");
- /* Create <path> */
- Inkscape::XML::Node *arrow_path = xml_doc->createElement("svg:path");
- if (mode == (Glib::ustring)"ArrowDIN-start") {
- arrow_path->setAttribute("d", "M -8,0 8,-2.11 8,2.11 z");
- } else if (mode == (Glib::ustring)"ArrowDIN-end") {
- arrow_path->setAttribute("d", "M 8,0 -8,2.11 -8,-2.11 z");
- } else if (mode == (Glib::ustring)"ArrowDINout-start") {
- arrow_path->setAttribute("d", "M 0,0 -16,2.11 -16,0.5 -26,0.5 -26,-0.5 -16,-0.5 -16,-2.11 z");
- } else {
- arrow_path->setAttribute("d", "M 0,0 16,2.11 16,0.5 26,0.5 26,-0.5 16,-0.5 16,-2.11 z");
- }
-
- arrow_path->setAttribute("id", (mode + (Glib::ustring)"_path").c_str());
- SPCSSAttr *css = sp_repr_css_attr_new();
- sp_repr_css_set_property (css, "fill","#000000");
- sp_repr_css_set_property (css, "stroke","none" );
- sp_repr_css_attr_add_from_string(css, arrows_format.param_getSVGValue());
- Glib::ustring css_str;
- sp_repr_css_write_string(css,css_str);
- arrow_path->setAttribute("style", css_str.c_str());
- arrow->addChild(arrow_path, NULL);
- Inkscape::GC::release(arrow_path);
- elemref = SP_OBJECT(desktop->getDocument()->getDefs()->appendChildRepr(arrow));
- Inkscape::GC::release(arrow);
- } else {
- Inkscape::XML::Node *arrow= elemref->getRepr();
- if (arrow) {
- arrow->setAttribute("sodipodi:insensitive", "true");
- Inkscape::XML::Node *arrow_data = arrow->firstChild();
- if (arrow_data) {
- SPCSSAttr *css = sp_repr_css_attr_new();
- sp_repr_css_set_property (css, "fill","#000000");
- sp_repr_css_set_property (css, "stroke","none" );
- sp_repr_css_attr_add_from_string(css, arrows_format.param_getSVGValue());
- Glib::ustring css_str;
- sp_repr_css_write_string(css,css_str);
- arrow_data->setAttribute("style", css_str.c_str());
- }
- }
- }
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ Inkscape::XML::Node *rtext = NULL;
+ double doc_w = document->getRoot()->width.value;
+ Geom::Scale scale = document->getDocumentScale();
+ SPNamedView *nv = sp_document_namedview(document, NULL);
+ Glib::ustring display_unit = nv->display_units->abbr;
+ if (display_unit.empty()) {
+ display_unit = "px";
+ }
+ //only check constrain viewbox on X
+ doc_scale = Inkscape::Util::Quantity::convert( scale[Geom::X], "px", nv->display_units );
+ if( doc_scale > 0 ) {
+ doc_scale= 1.0/doc_scale;
+ } else {
+ doc_scale = 1.0;
+ }
+ const char * id = g_strdup(Glib::ustring("text-on-").append(this->getRepr()->attribute("id")).c_str());
+ SPObject *elemref = NULL;
+ Inkscape::XML::Node *rtspan = NULL;
+ if (elemref = document->getObjectById(id)) {
+ if (remove) {
+ elemref->deleteObject();
+ return;
+ }
+ pos = pos - Point::polar(angle, text_right_left);
+ rtext = elemref->getRepr();
+ sp_repr_set_svg_double(rtext, "x", pos[Geom::X]);
+ sp_repr_set_svg_double(rtext, "y", pos[Geom::Y]);
+ rtext->setAttribute("sodipodi:insensitive", "true");
+ rtext->setAttribute("transform", NULL);
+ } else {
+ if (remove) {
+ return;
+ }
+ rtext = xml_doc->createElement("svg:text");
+ rtext->setAttribute("xml:space", "preserve");
+ rtext->setAttribute("id", id);
+ rtext->setAttribute("sodipodi:insensitive", "true");
+ pos = pos - Point::polar(angle, text_right_left);
+ sp_repr_set_svg_double(rtext, "x", pos[Geom::X]);
+ sp_repr_set_svg_double(rtext, "y", pos[Geom::Y]);
+ rtspan = xml_doc->createElement("svg:tspan");
+ rtspan->setAttribute("sodipodi:role", "line");
+ }
+ const char * transform;
+ Geom::Affine affine = Geom::Affine(Geom::Translate(pos).inverse());
+ angle = std::fmod(angle, 2*M_PI);
+ if (angle < 0) angle += 2*M_PI;
+ if (angle >= rad_from_deg(90) && angle < rad_from_deg(270)) {
+ angle = std::fmod(angle + rad_from_deg(180), 2*M_PI);
+ if (angle < 0) angle += 2*M_PI;
+ }
+ affine *= Geom::Rotate(angle);
+ affine *= Geom::Translate(pos);
+ if (rotate_anotation) {
+ transform = sp_svg_transform_write(affine);
+ } else {
+ transform = NULL;
+ }
+ rtext->setAttribute("transform", transform);
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_attr_add_from_string(css, anotation_format.param_getSVGValue());
+ Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance();
+ fontlister->fill_css(css, Glib::ustring(fontbutton.param_getSVGValue()));
+ std::stringstream font_size;
+ font_size.imbue(std::locale::classic());
+ font_size << fontsize << "pt";
+ sp_repr_css_set_property (css, "font-size",font_size.str().c_str());
+ sp_repr_css_set_property (css, "line-height","125%");
+ sp_repr_css_set_property (css, "letter-spacing","0");
+ sp_repr_css_set_property (css, "word-spacing", "0");
+ sp_repr_css_set_property (css, "text-align", "center");
+ sp_repr_css_set_property (css, "text-anchor", "middle");
+ sp_repr_css_set_property (css, "fill", "#000000");
+ sp_repr_css_set_property (css, "fill-opacity", "1");
+ sp_repr_css_set_property (css, "stroke", "none");
+ sp_repr_css_attr_add_from_string(css, anotation_format.param_getSVGValue());
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ if (!rtspan) {
+ rtspan = rtext->firstChild();
+ }
+ rtext->setAttribute("style", css_str.c_str());
+ rtspan->setAttribute("style", NULL);
+ rtspan->setAttribute("transform", NULL);
+ sp_repr_css_attr_unref (css);
+ if (!elemref) {
+ rtext->addChild(rtspan, NULL);
+ Inkscape::GC::release(rtspan);
+ }
+ length = Inkscape::Util::Quantity::convert(length / doc_scale, display_unit.c_str(), unit.get_abbreviation());
+ std::stringstream length_str;
+ length_str.precision(precision);
+ length_str.setf(std::ios::fixed, std::ios::floatfield);
+ if (local_locale) {
+ length_str.imbue(std::locale(""));
+ } else {
+ length_str.imbue(std::locale::classic());
+ }
+ length_str << std::fixed << length;
+ Glib::ustring label_value = Glib::ustring(format.param_getSVGValue());
+ size_t s = label_value.find(Glib::ustring("{measure}"),0);
+ if(s < label_value.length()) {
+ label_value.replace(s,s+9,length_str.str());
+ }
+ s = label_value.find(Glib::ustring("{unit}"),0);
+ if(s < label_value.length()) {
+ label_value.replace(s,s+6,unit.get_abbreviation());
+ }
+ if ( !valid ) {
+ label_value = Glib::ustring(_("Non Uniform Scale"));
+ }
+ Inkscape::XML::Node *rstring = NULL;
+ if (!elemref) {
+ rstring = xml_doc->createTextNode(label_value.c_str());
+ rtspan->addChild(rstring, NULL);
+ Inkscape::GC::release(rstring);
+ } else {
+ rstring = rtspan->firstChild();
+ rstring->setContent(label_value.c_str());
+ }
+ if (!elemref) {
+ elemref = sp_lpe_item->parent->appendChildRepr(rtext);
+ Inkscape::GC::release(rtext);
+ } else if (elemref->parent != sp_lpe_item->parent) {
+ Inkscape::XML::Node *old_repr = elemref->getRepr();
+ Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
+ SPObject * elemref_copy = sp_lpe_item->parent->appendChildRepr(copy);
+ Inkscape::GC::release(copy);
+ elemref->deleteObject();
+ copy->setAttribute("id", id);
+ elemref = elemref_copy;
+ }
+ elements.push_back(id);
+ Geom::OptRect bounds = SP_ITEM(elemref)->bounds(SPItem::GEOMETRIC_BBOX);
+ if (bounds) {
+ anotation_width = bounds->width() * 1.4;
}
}
void
-LPEMeasureLine::createTextLabel(Geom::Point pos, double length, Geom::Coord angle, bool remove)
+LPEMeasureLine::createLine(Geom::Point start,Geom::Point end, const char * id, bool main, bool overflow, bool remove, bool arrows)
{
- if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) {
- Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
- Inkscape::XML::Node *rtext = NULL;
- double doc_w = desktop->getDocument()->getRoot()->width.value;
- Geom::Scale scale = desktop->getDocument()->getDocumentScale();
- SPNamedView *nv = desktop->getNamedView();
- Glib::ustring display_unit = nv->display_units->abbr;
- if (display_unit.empty()) {
- display_unit = "px";
- }
- //only check constrain viewbox on X
- doc_scale = Inkscape::Util::Quantity::convert( scale[Geom::X], "px", nv->display_units );
- if( doc_scale > 0 ) {
- doc_scale= 1.0/doc_scale;
- } else {
- doc_scale = 1.0;
- }
- Inkscape::URI SVGElem_uri(((Glib::ustring)"#" + (Glib::ustring)"text-on-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- Inkscape::URIReference* SVGElemRef = new Inkscape::URIReference(desktop->doc());
- SVGElemRef->attach(SVGElem_uri);
- SPObject *elemref = NULL;
- Inkscape::XML::Node *rtspan = NULL;
-
- if (elemref = SVGElemRef->getObject()) {
- if (remove) {
- elemref->deleteObject();
- return;
- }
- pos = pos - Point::polar(angle, text_right_left);
- rtext = elemref->getRepr();
- sp_repr_set_svg_double(rtext, "x", pos[Geom::X]);
- sp_repr_set_svg_double(rtext, "y", pos[Geom::Y]);
- rtext->setAttribute("sodipodi:insensitive", "true");
- } else {
- if (remove) {
- return;
- }
- rtext = xml_doc->createElement("svg:text");
- rtext->setAttribute("xml:space", "preserve");
- rtext->setAttribute("id", ( (Glib::ustring)"text-on-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- rtext->setAttribute("sodipodi:insensitive", "true");
- pos = pos - Point::polar(angle, text_right_left);
- sp_repr_set_svg_double(rtext, "x", pos[Geom::X]);
- sp_repr_set_svg_double(rtext, "y", pos[Geom::Y]);
- rtspan = xml_doc->createElement("svg:tspan");
- rtspan->setAttribute("sodipodi:role", "line");
- }
- gchar * transform;
- Geom::Affine affine = Geom::Affine(Geom::Translate(pos).inverse());
- angle = std::fmod(angle, 2*M_PI);
- if (angle < 0) angle += 2*M_PI;
- if (angle >= rad_from_deg(90) && angle < rad_from_deg(270)) {
- angle = std::fmod(angle + rad_from_deg(180), 2*M_PI);
- if (angle < 0) angle += 2*M_PI;
- }
- affine *= Geom::Rotate(angle);
- affine *= Geom::Translate(pos);
- if (rotate_anotation) {
- transform = sp_svg_transform_write(affine);
- } else {
- transform = NULL;
- }
- rtext->setAttribute("transform", transform);
- SPCSSAttr *css = sp_repr_css_attr_new();
- sp_repr_css_attr_add_from_string(css, anotation_format.param_getSVGValue());
- Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance();
- fontlister->fill_css( css, (Glib::ustring)fontbutton.param_getSVGValue() );
- std::stringstream font_size;
- font_size.imbue(std::locale::classic());
- font_size << fontsize << "pt";
-
- sp_repr_css_set_property (css, "font-size",font_size.str().c_str());
- sp_repr_css_set_property (css, "line-height","125%");
- sp_repr_css_set_property (css, "letter-spacing","0");
- sp_repr_css_set_property (css, "word-spacing", "0");
- sp_repr_css_set_property (css, "text-align", "center");
- sp_repr_css_set_property (css, "text-anchor", "middle");
- sp_repr_css_set_property (css, "fill", "#000000");
- sp_repr_css_set_property (css, "fill-opacity", "1");
- sp_repr_css_set_property (css, "stroke", "none");
- sp_repr_css_attr_add_from_string(css, anotation_format.param_getSVGValue());
- Glib::ustring css_str;
- sp_repr_css_write_string(css,css_str);
- if (!rtspan) {
- rtspan = rtext->firstChild();
- }
- rtext->setAttribute("style", css_str.c_str());
- rtspan->setAttribute("style", NULL);
- sp_repr_css_attr_unref (css);
- if (!elemref) {
- rtext->addChild(rtspan, NULL);
- Inkscape::GC::release(rtspan);
- }
- length = Inkscape::Util::Quantity::convert(length / doc_scale, display_unit.c_str(), unit.get_abbreviation());
- std::stringstream length_str;
- length_str.precision(precision);
- length_str.setf(std::ios::fixed, std::ios::floatfield);
- if (local_locale) {
- length_str.imbue(std::locale(""));
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ SPObject *elemref = NULL;
+ Inkscape::XML::Node *line = NULL;
+ if (!main) {
+ Geom::Ray ray(start, end);
+ Geom::Coord angle = ray.angle();
+ start = start + Point::polar(angle, helpline_distance );
+ end = end + Point::polar(angle, helpline_overlap );
+ }
+ Geom::PathVector line_pathv;
+ if (main && std::abs(text_top_bottom) < fontsize/1.5 && hide_back && !overflow){
+ Geom::Path line_path;
+ double k = 0;
+ if (flip_side) {
+ k = (Geom::distance(start,end)/2.0) + arrow_gap - (anotation_width/2.0);
} else {
- length_str.imbue(std::locale::classic());
- }
- length_str << std::fixed << length;
- Glib::ustring label_value = Glib::ustring(format.param_getSVGValue());
- size_t s = label_value.find((Glib::ustring)"{measure}",0);
- if(s < label_value.length()) {
- label_value.replace(s,s+9,length_str.str());
+ k = (Geom::distance(start,end)/2.0) - arrow_gap - (anotation_width/2.0);
+ }
+ if (Geom::distance(start,end) < anotation_width){
+ return;
+ }
+ Geom::Ray ray(end, start);
+ Geom::Coord angle = ray.angle();
+ line_path.start(start);
+ line_path.appendNew<Geom::LineSegment>(start - Point::polar(angle, k));
+ line_pathv.push_back(line_path);
+ line_path.clear();
+ line_path.start(end + Point::polar(angle, k));
+ line_path.appendNew<Geom::LineSegment>(end);
+ line_pathv.push_back(line_path);
+ } else {
+ Geom::Path line_path;
+ line_path.start(start);
+ line_path.appendNew<Geom::LineSegment>(end);
+ line_pathv.push_back(line_path);
+ }
+ if (elemref = document->getObjectById(id)) {
+ if (remove) {
+ elemref->deleteObject();
+ return;
}
- s = label_value.find((Glib::ustring)"{unit}",0);
- if(s < label_value.length()) {
- label_value.replace(s,s+6,unit.get_abbreviation());
+ line = elemref->getRepr();
+
+ const char * line_str = sp_svg_write_path( line_pathv );
+ line->setAttribute("d" , line_str);
+ line->setAttribute("transform", NULL);
+ } else {
+ if (remove) {
+ return;
}
- Inkscape::XML::Node *rstring = NULL;
- if (!elemref) {
- rstring = xml_doc->createTextNode(label_value.c_str());
- rtspan->addChild(rstring, NULL);
- Inkscape::GC::release(rstring);
+ line = xml_doc->createElement("svg:path");
+ line->setAttribute("id", id);
+ const char * line_str = sp_svg_write_path( line_pathv );
+ line->setAttribute("d" , line_str);
+ }
+ line->setAttribute("sodipodi:insensitive", "true");
+ line_pathv.clear();
+
+ Glib::ustring style = Glib::ustring("stroke:#000000;fill:none;");
+ if (overflow && !arrows) {
+ line->setAttribute("inkscape:label", "downline");
+ } else if (main) {
+ line->setAttribute("inkscape:label", "dinline");
+ if (arrows_outside) {
+ style = style + Glib::ustring("marker-start:url(#ArrowDINout-start);marker-end:url(#ArrowDINout-end);");
} else {
- rstring = rtspan->firstChild();
- rstring->setContent(label_value.c_str());
+ style = style + Glib::ustring("marker-start:url(#ArrowDIN-start);marker-end:url(#ArrowDIN-end);");
}
- if (!elemref) {
- elemref = SP_OBJECT(desktop->currentLayer()->appendChildRepr(rtext));
- Inkscape::GC::release(rtext);
- }
- Inkscape::XML::Node *tmp_node = rtext->duplicate(xml_doc);
- affine = Geom::Affine(Geom::Scale(1.4));
- tmp_node->setAttribute("transform", sp_svg_transform_write(affine));
- SPObject * tmp_obj = SP_OBJECT(desktop->currentLayer()->appendChildRepr(tmp_node));
- Inkscape::GC::release(tmp_node);
- tmp_obj->updateRepr();
- Geom::OptRect bounds = SP_ITEM(tmp_obj)->bounds(SPItem::GEOMETRIC_BBOX);
- if (bounds) {
- anotation_width = bounds->width();
- }
- tmp_obj->deleteObject();
+ } else {
+ line->setAttribute("inkscape:label", "dinhelpline");
+ }
+ std::stringstream stroke_w;
+ stroke_w.imbue(std::locale::classic());
+ if (line_group_05) {
+ double stroke_width = Inkscape::Util::Quantity::convert(0.25 / doc_scale, "mm", display_unit.c_str());
+ stroke_w << stroke_width;
+ style = style + Glib::ustring("stroke-width:" + stroke_w.str());
+ } else {
+ double stroke_width = Inkscape::Util::Quantity::convert(0.35 / doc_scale, "mm", display_unit.c_str());
+ stroke_w << stroke_width;
+ style = style + Glib::ustring("stroke-width:" + stroke_w.str());
+ }
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_attr_add_from_string(css, style.c_str());
+ if (main) {
+ sp_repr_css_attr_add_from_string(css, dimline_format.param_getSVGValue());
+ } else {
+ sp_repr_css_attr_add_from_string(css, helperlines_format.param_getSVGValue());
+ }
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ line->setAttribute("style", css_str.c_str());
+ if (!elemref) {
+ elemref = sp_lpe_item->parent->appendChildRepr(line);
+ Inkscape::GC::release(line);
+ } else if (elemref->parent != sp_lpe_item->parent) {
+ Inkscape::XML::Node *old_repr = elemref->getRepr();
+ Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
+ SPObject * elemref_copy = sp_lpe_item->parent->appendChildRepr(copy);
+ Inkscape::GC::release(copy);
+ elemref->deleteObject();
+ copy->setAttribute("id", id);
}
+ elements.push_back(id);
}
void
-LPEMeasureLine::createLine(Geom::Point start,Geom::Point end, Glib::ustring id, bool main, bool overflow, bool remove, bool arrows)
+LPEMeasureLine::doOnApply(SPLPEItem const* lpeitem)
{
- if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) {
- Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
- Inkscape::URI SVGElem_uri(((Glib::ustring)"#" + id).c_str());
- Inkscape::URIReference* SVGElemRef = new Inkscape::URIReference(desktop->doc());
- SVGElemRef->attach(SVGElem_uri);
- SPObject *elemref = NULL;
- Inkscape::XML::Node *line = NULL;
- if (!main) {
- Geom::Ray ray(start, end);
- Geom::Coord angle = ray.angle();
- start = start + Point::polar(angle, helpline_distance );
- end = end + Point::polar(angle, helpline_overlap );
- }
- Geom::PathVector line_pathv;
- if (main && std::abs(text_top_bottom) < fontsize/1.5 && hide_back && !overflow){
- Geom::Path line_path;
- double k = 0;
- if (flip_side) {
- k = (Geom::distance(start,end)/2.0) + arrow_gap - (anotation_width/2.0);
- } else {
- k = (Geom::distance(start,end)/2.0) - arrow_gap - (anotation_width/2.0);
- }
- if (Geom::distance(start,end) < anotation_width){
- return;
- }
- Geom::Ray ray(end, start);
- Geom::Coord angle = ray.angle();
- line_path.start(start);
- line_path.appendNew<Geom::LineSegment>(start - Point::polar(angle, k));
- line_pathv.push_back(line_path);
- line_path.clear();
- line_path.start(end + Point::polar(angle, k));
- line_path.appendNew<Geom::LineSegment>(end);
- line_pathv.push_back(line_path);
- } else {
- Geom::Path line_path;
- line_path.start(start);
- line_path.appendNew<Geom::LineSegment>(end);
- line_pathv.push_back(line_path);
- }
-
- if (elemref = SVGElemRef->getObject()) {
- if (remove) {
- elemref->deleteObject();
- return;
- }
- line = elemref->getRepr();
-
- gchar * line_str = sp_svg_write_path( line_pathv );
- line->setAttribute("d" , line_str);
- } else {
- if (remove) {
- return;
- }
- line = xml_doc->createElement("svg:path");
- line->setAttribute("id", id.c_str());
- gchar * line_str = sp_svg_write_path( line_pathv );
- line->setAttribute("d" , line_str);
- }
- line->setAttribute("sodipodi:insensitive", "true");
- line_pathv.clear();
-
- Glib::ustring style = (Glib::ustring)"stroke:#000000;fill:none;";
- if (overflow && !arrows) {
- line->setAttribute("inkscape:label", "downline");
- } else if (main) {
- line->setAttribute("inkscape:label", "dinline");
- if (arrows_outside) {
- style = style + (Glib::ustring)"marker-start:url(#ArrowDINout-start);marker-end:url(#ArrowDINout-end);";
- } else {
- style = style + (Glib::ustring)"marker-start:url(#ArrowDIN-start);marker-end:url(#ArrowDIN-end);";
- }
- } else {
- line->setAttribute("inkscape:label", "dinhelpline");
- }
- std::stringstream stroke_w;
- stroke_w.imbue(std::locale::classic());
- if (line_group_05) {
- double stroke_width = Inkscape::Util::Quantity::convert(0.25 / doc_scale, "mm", display_unit.c_str());
- stroke_w << stroke_width;
- style = style + (Glib::ustring)"stroke-width:" + (Glib::ustring)stroke_w.str();
- } else {
- double stroke_width = Inkscape::Util::Quantity::convert(0.35 / doc_scale, "mm", display_unit.c_str());
- stroke_w << stroke_width;
- style = style + (Glib::ustring)"stroke-width:" + (Glib::ustring)stroke_w.str();
- }
- SPCSSAttr *css = sp_repr_css_attr_new();
- sp_repr_css_attr_add_from_string(css, style.c_str());
- if (main) {
- sp_repr_css_attr_add_from_string(css, dimline_format.param_getSVGValue());
- } else {
- sp_repr_css_attr_add_from_string(css, helperlines_format.param_getSVGValue());
- }
- Glib::ustring css_str;
- sp_repr_css_write_string(css,css_str);
- line->setAttribute("style", css_str.c_str());
- if (!elemref) {
- elemref = SP_OBJECT(desktop->currentLayer()->appendChildRepr(line));
- Inkscape::GC::release(line);
- }
+ if (!SP_IS_SHAPE(lpeitem)) {
+ g_warning("LPE measure line can only be applied to shapes (not groups).");
+ SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
+ item->removeCurrentPathEffect(false);
}
+ id_origin.param_setValue(Glib::ustring(lpeitem->getId()));
+ id_origin.write_to_SVG();
}
void
LPEMeasureLine::doBeforeEffect (SPLPEItem const* lpeitem)
{
SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem);
+ sp_lpe_item->parent = dynamic_cast<SPObject *>(splpeitem->parent);
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ Inkscape::XML::Node *root = splpeitem->document->getReprRoot();
+ Inkscape::XML::Node *root_origin = document->getReprRoot();
+ if (root_origin != root) {
+ return;
+ }
SPPath *sp_path = dynamic_cast<SPPath *>(splpeitem);
if (sp_path) {
- SPDocument * doc = SP_ACTIVE_DOCUMENT;
- Geom::Affine affinetransform = i2anc_affine(SP_OBJECT(lpeitem)->parent, SP_OBJECT(doc->getRoot()));
- double parents_scale = (affinetransform.inverse().expansionX() + affinetransform.inverse().expansionY()) / 2.0;
-
+ Geom::Affine affinetransform = i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(document->getRoot()));
Geom::PathVector pathvector = sp_path->get_original_curve()->get_pathvector();
- pathvector *= affinetransform;
- if (arrows_outside) {
- createArrowMarker((Glib::ustring)"ArrowDINout-start");
- createArrowMarker((Glib::ustring)"ArrowDINout-end");
- } else {
- createArrowMarker((Glib::ustring)"ArrowDIN-start");
- createArrowMarker((Glib::ustring)"ArrowDIN-end");
+ Geom::Affine writed_transform = Geom::identity();
+ sp_svg_transform_read(splpeitem->getAttribute("transform"), &writed_transform );
+ pathvector *= writed_transform;
+ if ((Glib::ustring(format.param_getSVGValue()).empty())) {
+ format.param_setValue(Glib::ustring("{measure}{unit}"));
+ this->upd_params = true;
+ }
+ size_t ncurves = pathvector.curveCount();
+ if (ncurves != (size_t)curve_linked.param_get_max()) {
+ curve_linked.param_set_range(0, ncurves);
}
- if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) {
- if (((Glib::ustring)format.param_getSVGValue()).empty()) {
- format.param_setValue((Glib::ustring)"{measure}{unit}");
- this->upd_params = true;
+ Geom::Point start = pathvector.initialPoint();
+ Geom::Point end = pathvector.finalPoint();
+ if (curve_linked) { //!0
+ start = pathvector.pointAt(curve_linked -1);
+ end = pathvector.pointAt(curve_linked);
+ }
+ if (Geom::are_near(start, start_stored, 0.01) &&
+ Geom::are_near(end, end_stored, 0.01) &&
+ sp_lpe_item->getCurrentLPE() != this){
+ return;
+ }
+ elements.clear();
+ start_stored = start;
+ end_stored = end;
+ Geom::Point hstart = start;
+ Geom::Point hend = end;
+ bool remove = false;
+ if (Geom::are_near(hstart, hend)) {
+ remove = true;
+ }
+ if (orientation == OM_VERTICAL) {
+ Coord xpos = std::max(hstart[Geom::X],hend[Geom::X]);
+ if (flip_side) {
+ xpos = std::min(hstart[Geom::X],hend[Geom::X]);
}
- size_t ncurves = pathvector.curveCount();
- curve_linked.param_set_range(0, ncurves);
- Geom::Point start = pathvector.initialPoint();
- Geom::Point end = pathvector.finalPoint();
- if (curve_linked) { //!0
- start = pathvector.pointAt(curve_linked -1);
- end = pathvector.pointAt(curve_linked);
+ hstart[Geom::X] = xpos;
+ hend[Geom::X] = xpos;
+ if (hstart[Geom::Y] > hend[Geom::Y]) {
+ swap(hstart,hend);
+ swap(start,end);
}
- Geom::Point hstart = start;
- Geom::Point hend = end;
- bool remove = false;
- if (Geom::are_near(hstart, hend)) {
+ if (Geom::are_near(hstart[Geom::Y], hend[Geom::Y])) {
remove = true;
}
- if (orientation == OM_VERTICAL) {
- Coord xpos = std::max(hstart[Geom::X],hend[Geom::X]);
- if (flip_side) {
- xpos = std::min(hstart[Geom::X],hend[Geom::X]);
- }
- hstart[Geom::X] = xpos;
- hend[Geom::X] = xpos;
- if (hstart[Geom::Y] > hend[Geom::Y]) {
- swap(hstart,hend);
- swap(start,end);
- }
- if (Geom::are_near(hstart[Geom::Y], hend[Geom::Y])) {
- remove = true;
- }
+ }
+ if (orientation == OM_HORIZONTAL) {
+ Coord ypos = std::max(hstart[Geom::Y],hend[Geom::Y]);
+ if (flip_side) {
+ ypos = std::min(hstart[Geom::Y],hend[Geom::Y]);
}
- if (orientation == OM_HORIZONTAL) {
- Coord ypos = std::max(hstart[Geom::Y],hend[Geom::Y]);
- if (flip_side) {
- ypos = std::min(hstart[Geom::Y],hend[Geom::Y]);
- }
- hstart[Geom::Y] = ypos;
- hend[Geom::Y] = ypos;
- if (hstart[Geom::X] < hend[Geom::X]) {
- swap(hstart,hend);
- swap(start,end);
- }
- if (Geom::are_near(hstart[Geom::X], hend[Geom::X])) {
- remove = true;
- }
+ hstart[Geom::Y] = ypos;
+ hend[Geom::Y] = ypos;
+ if (hstart[Geom::X] < hend[Geom::X]) {
+ swap(hstart,hend);
+ swap(start,end);
}
- double length = Geom::distance(hstart,hend) * scale;
- Geom::Point pos = Geom::middle_point(hstart,hend);
- Geom::Ray ray(hstart,hend);
- Geom::Coord angle = ray.angle();
- if (flip_side) {
- angle = std::fmod(angle + rad_from_deg(180), 2*M_PI);
- if (angle < 0) angle += 2*M_PI;
+ if (Geom::are_near(hstart[Geom::X], hend[Geom::X])) {
+ remove = true;
}
- //We get the font size to offset the text to the middle
- Pango::FontDescription fontdesc((Glib::ustring)fontbutton.param_getSVGValue());
- fontsize = fontdesc.get_size()/(double)Pango::SCALE;
- fontsize *= desktop->doc()->getRoot()->c2p.inverse().expansionX();
- Geom::Coord angle_cross = std::fmod(angle + rad_from_deg(90), 2*M_PI);
- if (angle_cross < 0) angle_cross += 2*M_PI;
- angle = std::fmod(angle, 2*M_PI);
+ }
+ double length = Geom::distance(hstart,hend) * scale;
+ Geom::Point pos = Geom::middle_point(hstart,hend);
+ Geom::Ray ray(hstart,hend);
+ Geom::Coord angle = ray.angle();
+ if (flip_side) {
+ angle = std::fmod(angle + rad_from_deg(180), 2*M_PI);
if (angle < 0) angle += 2*M_PI;
- if (angle >= rad_from_deg(90) && angle < rad_from_deg(270)) {
- pos = pos - Point::polar(angle_cross, (position - text_top_bottom) + fontsize/2.5);
- } else {
- pos = pos - Point::polar(angle_cross, (position + text_top_bottom) - fontsize/2.5);
- }
- if (scale_insensitive) {
- length *= parents_scale;
+ }
+ if (arrows_outside) {
+ createArrowMarker("ArrowDINout-start");
+ createArrowMarker("ArrowDINout-end");
+ } else {
+ createArrowMarker("ArrowDIN-start");
+ createArrowMarker("ArrowDIN-end");
+ }
+ //We get the font size to offset the text to the middle
+ Pango::FontDescription fontdesc(Glib::ustring(fontbutton.param_getSVGValue()));
+ fontsize = fontdesc.get_size()/(double)Pango::SCALE;
+ fontsize *= document->getRoot()->c2p.inverse().expansionX();
+ Geom::Coord angle_cross = std::fmod(angle + rad_from_deg(90), 2*M_PI);
+ if (angle_cross < 0) angle_cross += 2*M_PI;
+ angle = std::fmod(angle, 2*M_PI);
+ if (angle < 0) angle += 2*M_PI;
+ if (angle >= rad_from_deg(90) && angle < rad_from_deg(270)) {
+ pos = pos - Point::polar(angle_cross, (position - text_top_bottom) + fontsize/2.5);
+ } else {
+ pos = pos - Point::polar(angle_cross, (position + text_top_bottom) - fontsize/2.5);
+ }
+ double parents_scale = (affinetransform.expansionX() + affinetransform.expansionY()) / 2.0;
+ if (scale_sensitive) {
+ length *= parents_scale;
+ }
+ if (scale_sensitive && !affinetransform.preservesAngles()) {
+ createTextLabel(pos, length, angle, remove, false);
+ } else {
+ createTextLabel(pos, length, angle, remove, true);
+ }
+ bool overflow = false;
+ const char * downline = g_strdup(Glib::ustring("downline-").append(this->getRepr()->attribute("id")).c_str());
+ if ((anotation_width/2) + std::abs(text_right_left) > Geom::distance(start,end)/2.0) {
+ Geom::Point sstart = end - Point::polar(angle_cross, position);
+ Geom::Point send = end - Point::polar(angle_cross, position);
+ if (text_right_left < 0 && flip_side || text_right_left > 0 && !flip_side) {
+ sstart = start - Point::polar(angle_cross, position);
+ send = start - Point::polar(angle_cross, position);
}
- createTextLabel(pos, length, angle, remove);
- bool overflow = false;
- if ((anotation_width/2) + std::abs(text_right_left) > Geom::distance(start,end)/2.0) {
- Geom::Point sstart = end - Point::polar(angle_cross, position);
- Geom::Point send = end - Point::polar(angle_cross, position);
- if (text_right_left < 0 && flip_side || text_right_left > 0 && !flip_side) {
- sstart = start - Point::polar(angle_cross, position);
- send = start - Point::polar(angle_cross, position);
- }
- Geom::Point prog_end = Geom::Point();
- if (std::abs(text_top_bottom) < fontsize/1.5 && hide_back) {
- if (text_right_left > 0 ) {
- prog_end = sstart - Point::polar(angle, std::abs(text_right_left) - (anotation_width/1.9) - (Geom::distance(start,end)/2.0));
- } else {
- prog_end = sstart + Point::polar(angle, std::abs(text_right_left) - (anotation_width/1.9) - (Geom::distance(start,end)/2.0));
- }
+ Geom::Point prog_end = Geom::Point();
+ if (std::abs(text_top_bottom) < fontsize/1.5 && hide_back) {
+ if (text_right_left > 0 ) {
+ prog_end = sstart - Point::polar(angle, std::abs(text_right_left) - (anotation_width/1.9) - (Geom::distance(start,end)/2.0));
} else {
- if (text_right_left > 0 ) {
- prog_end = sstart - Point::polar(angle,(anotation_width/2) + std::abs(text_right_left) - (Geom::distance(start,end)/2.0));
- } else {
- prog_end = sstart + Point::polar(angle,(anotation_width/2) + std::abs(text_right_left) - (Geom::distance(start,end)/2.0));
- }
+ prog_end = sstart + Point::polar(angle, std::abs(text_right_left) - (anotation_width/1.9) - (Geom::distance(start,end)/2.0));
}
- overflow = true;
- createLine(sstart, prog_end, (Glib::ustring)"downline-" + (Glib::ustring)this->getRepr()->attribute("id"), true, overflow, false, false);
} else {
- //erase it
- createLine(Geom::Point(),Geom::Point(), (Glib::ustring)"downline-" + (Glib::ustring)this->getRepr()->attribute("id"), true, overflow, true, false);
- }
- //LINE
- arrow_gap = 8 * Inkscape::Util::Quantity::convert(0.35 / doc_scale, "mm", display_unit.c_str());
- if (line_group_05) {
- arrow_gap = 8 * Inkscape::Util::Quantity::convert(0.25 / doc_scale, "mm", display_unit.c_str());
- }
- SPCSSAttr *css = sp_repr_css_attr_new();
- sp_repr_css_attr_add_from_string(css, dimline_format.param_getSVGValue());
- setlocale(LC_NUMERIC, std::locale::classic().name().c_str());
- double width_line = atof(sp_repr_css_property(css,"stroke-width","-1"));
- setlocale(LC_NUMERIC, std::locale("").name().c_str());
- if (width_line > -0.0001) {
- arrow_gap = 8 * Inkscape::Util::Quantity::convert(width_line/ doc_scale, "mm", display_unit.c_str());
- }
- if (flip_side) {
- arrow_gap *= -1;
- }
- hstart = hstart - Point::polar(angle_cross, position);
- Glib::ustring id = (Glib::ustring)"infoline-on-start-" + (Glib::ustring)this->getRepr()->attribute("id");
- createLine(start, hstart, id, false, false, remove);
- hend = hend - Point::polar(angle_cross, position);
- id = (Glib::ustring)"infoline-on-end-" + (Glib::ustring)this->getRepr()->attribute("id");
- createLine(end, hend, id, false, false, remove);
- if (!arrows_outside) {
- hstart = hstart + Point::polar(angle, arrow_gap);
- hend = hend - Point::polar(angle, arrow_gap );
+ if (text_right_left > 0 ) {
+ prog_end = sstart - Point::polar(angle,(anotation_width/2) + std::abs(text_right_left) - (Geom::distance(start,end)/2.0));
+ } else {
+ prog_end = sstart + Point::polar(angle,(anotation_width/2) + std::abs(text_right_left) - (Geom::distance(start,end)/2.0));
+ }
}
- id = (Glib::ustring)"infoline-" + (Glib::ustring)this->getRepr()->attribute("id");
- createLine(hstart, hend, id, true, overflow, remove, true);
+ overflow = true;
+ createLine(sstart, prog_end, downline, true, overflow, false, false);
+ } else {
+ //erase it
+ createLine(Geom::Point(),Geom::Point(), downline, true, overflow, true, false);
}
+ //LINE
+ arrow_gap = 8 * Inkscape::Util::Quantity::convert(0.35 / doc_scale, "mm", display_unit.c_str());
+ if (line_group_05) {
+ arrow_gap = 8 * Inkscape::Util::Quantity::convert(0.25 / doc_scale, "mm", display_unit.c_str());
+ }
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_attr_add_from_string(css, dimline_format.param_getSVGValue());
+ setlocale(LC_NUMERIC, std::locale::classic().name().c_str());
+ double width_line = atof(sp_repr_css_property(css,"stroke-width","-1"));
+ setlocale(LC_NUMERIC, std::locale("").name().c_str());
+ if (width_line > -0.0001) {
+ arrow_gap = 8 * Inkscape::Util::Quantity::convert(width_line/ doc_scale, "mm", display_unit.c_str());
+ }
+ if (flip_side) {
+ arrow_gap *= -1;
+ }
+ hstart = hstart - Point::polar(angle_cross, position);
+ createLine(start, hstart, g_strdup(Glib::ustring("infoline-on-start-").append(this->getRepr()->attribute("id")).c_str()), false, false, remove);
+ hend = hend - Point::polar(angle_cross, position);
+ createLine(end, hend, g_strdup(Glib::ustring("infoline-on-end-").append(this->getRepr()->attribute("id")).c_str()), false, false, remove);
+ if (!arrows_outside) {
+ hstart = hstart + Point::polar(angle, arrow_gap);
+ hend = hend - Point::polar(angle, arrow_gap );
+ }
+ createLine(hstart, hend, g_strdup(Glib::ustring("infoline-").append(this->getRepr()->attribute("id")).c_str()), true, overflow, remove, true);
}
}
-void LPEMeasureLine::doOnRemove (SPLPEItem const* lpeitem)
+void
+LPEMeasureLine::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/)
{
- if (!erase) return;
-
- if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) {
- Inkscape::URI SVGElem_uri(((Glib::ustring)"#" + (Glib::ustring)"text-on-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- Inkscape::URIReference* SVGElemRef = new Inkscape::URIReference(desktop->doc());
- SVGElemRef->attach(SVGElem_uri);
- SPObject *elemref = NULL;
- if (elemref = SVGElemRef->getObject()) {
- elemref->deleteObject();
- }
- Inkscape::URI SVGElem_uri2(((Glib::ustring)"#" + (Glib::ustring)"infoline-on-end-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri2);
- if (elemref = SVGElemRef->getObject()) {
- elemref->deleteObject();
- }
- Inkscape::URI SVGElem_uri3(((Glib::ustring)"#" + (Glib::ustring)"infoline-on-start-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri3);
- if (elemref = SVGElemRef->getObject()) {
- elemref->deleteObject();
- }
- Inkscape::URI SVGElem_uri4(((Glib::ustring)"#" + (Glib::ustring)"infoline-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri4);
- if (elemref = SVGElemRef->getObject()) {
- elemref->deleteObject();
- }
- Inkscape::URI SVGElem_uri5(((Glib::ustring)"#" + (Glib::ustring)"downline-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri5);
- if (elemref = SVGElemRef->getObject()) {
- elemref->deleteObject();
- }
+ processObjects(LPE_VISIBILITY);
+}
+
+void
+LPEMeasureLine::doOnRemove (SPLPEItem const* /*lpeitem*/)
+{
+ //unset "erase_extra_objects" hook on sp-lpe-item.cpp
+ if (!erase_extra_objects) {
+ processObjects(LPE_TO_OBJECTS);
+ elements.clear();
+ return;
}
+ processObjects(LPE_ERASE);
}
-void LPEMeasureLine::toObjects()
+void
+LPEMeasureLine::processObjects(LpeAction lpe_action)
{
- if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) {
-
- Inkscape::URI SVGElem_uri(((Glib::ustring)"#" + (Glib::ustring)"text-on-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- Inkscape::URIReference* SVGElemRef = new Inkscape::URIReference(desktop->doc());
- SVGElemRef->attach(SVGElem_uri);
- SPObject *elemref = NULL;
- if (elemref = SVGElemRef->getObject()) {
- elemref->getRepr()->setAttribute("sodipodi:insensitive", NULL);
- }
- Inkscape::URI SVGElem_uri2(((Glib::ustring)"#" + (Glib::ustring)"infoline-on-end-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri2);
- if (elemref = SVGElemRef->getObject()) {
- elemref->getRepr()->setAttribute("sodipodi:insensitive", NULL);
- }
- Inkscape::URI SVGElem_uri3(((Glib::ustring)"#" + (Glib::ustring)"infoline-on-start-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri3);
- if (elemref = SVGElemRef->getObject()) {
- elemref->getRepr()->setAttribute("sodipodi:insensitive", NULL);
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ for (std::vector<const char *>::iterator el_it = elements.begin();
+ el_it != elements.end(); ++el_it) {
+ const char * id = *el_it;
+ if (!id || strlen(id) == 0) {
+ return;
}
- Inkscape::URI SVGElem_uri4(((Glib::ustring)"#" + (Glib::ustring)"infoline-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri4);
- if (elemref = SVGElemRef->getObject()) {
- elemref->getRepr()->setAttribute("sodipodi:insensitive", NULL);
- }
- Inkscape::URI SVGElem_uri5(((Glib::ustring)"#" + (Glib::ustring)"downline-" + (Glib::ustring)this->getRepr()->attribute("id")).c_str());
- SVGElemRef->attach(SVGElem_uri5);
- if (elemref = SVGElemRef->getObject()) {
- elemref->getRepr()->setAttribute("sodipodi:insensitive", NULL);
- }
- erase = false;
- sp_lpe_item->removeCurrentPathEffect(true);
- //TODO: find better way to refresh effect list
- if (SP_IS_OBJECT(sp_lpe_item)){
- Inkscape::Selection *selection = SP_ACTIVE_DESKTOP->getSelection();
- selection->remove(SP_OBJECT(sp_lpe_item));
- selection->add(SP_OBJECT(sp_lpe_item));
+ SPObject *elemref = NULL;
+ if (elemref = document->getObjectById(id)) {
+ SPCSSAttr *css;
+ Glib::ustring css_str;
+ switch (lpe_action){
+ case LPE_TO_OBJECTS:
+ elemref->getRepr()->setAttribute("inkscape:path-effect", NULL);
+ elemref->getRepr()->setAttribute("sodipodi:insensitive", NULL);
+ break;
+
+ case LPE_ERASE:
+ if (std::strcmp(elemref->getId(),id_origin.param_getSVGValue()) != 0) {
+ elemref->deleteObject();
+ }
+ break;
+
+ case LPE_VISIBILITY:
+ css = sp_repr_css_attr_new();
+ sp_repr_css_attr_add_from_string(css, elemref->getRepr()->attribute("style"));
+ if (!this->isVisible() && std::strcmp(elemref->getId(),id_origin.param_getSVGValue()) != 0) {
+ css->setAttribute("display", "none");
+ } else {
+ css->setAttribute("display", NULL);
+ }
+ sp_repr_css_write_string(css,css_str);
+ elemref->getRepr()->setAttribute("style", css_str.c_str());
+ break;
+
+ default:
+ break;
+ }
}
}
+ if (lpe_action == LPE_ERASE) {
+ elements.clear();
+ }
}
Gtk::Widget *LPEMeasureLine::newWidget()
@@ -790,7 +746,6 @@ Gtk::Widget *LPEMeasureLine::newWidget()
std::vector<Parameter *>::iterator it = param_vector.begin();
Gtk::HBox * button1 = Gtk::manage(new Gtk::HBox(true,0));
- Gtk::HBox * button2 = Gtk::manage(new Gtk::HBox(true,0));
Gtk::VBox * vbox_expander = Gtk::manage( new Gtk::VBox(Effect::newWidget()) );
vbox_expander->set_border_width(0);
vbox_expander->set_spacing(2);
@@ -822,16 +777,12 @@ Gtk::Widget *LPEMeasureLine::newWidget()
Gtk::Button *save_default = Gtk::manage(new Gtk::Button(Glib::ustring(_("Save '*' as default"))));
save_default->signal_clicked().connect(sigc::mem_fun(*this, &LPEMeasureLine::saveDefault));
button1->pack_start(*save_default, true, true, 2);
- Gtk::Button *remove = Gtk::manage(new Gtk::Button(Glib::ustring(_("Convert to objects"))));
- remove->signal_clicked().connect(sigc::mem_fun(*this, &LPEMeasureLine::toObjects));
- button2->pack_start(*remove, true, true, 2);
expander = Gtk::manage(new Gtk::Expander(Glib::ustring(_("Show DIM CSS style override"))));
expander->add(*vbox_expander);
expander->set_expanded(expanded);
expander->property_expanded().signal_changed().connect(sigc::mem_fun(*this, &LPEMeasureLine::onExpanderChanged) );
vbox->pack_start(*expander, true, true, 2);
vbox->pack_start(*button1, true, true, 2);
- vbox->pack_start(*button2, true, true, 2);
return dynamic_cast<Gtk::Widget *>(vbox);
}
@@ -856,21 +807,21 @@ void
LPEMeasureLine::saveDefault()
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- prefs->setString("/live_effects/measure-line/fontbutton", (Glib::ustring)fontbutton.param_getSVGValue());
+ prefs->setString("/live_effects/measure-line/fontbutton", Glib::ustring(fontbutton.param_getSVGValue()));
prefs->setDouble("/live_effects/measure-line/scale", scale);
prefs->setInt("/live_effects/measure-line/precision", precision);
prefs->setDouble("/live_effects/measure-line/position", position);
prefs->setDouble("/live_effects/measure-line/text_top_bottom", text_top_bottom);
prefs->setDouble("/live_effects/measure-line/helpline_distance", helpline_distance);
prefs->setDouble("/live_effects/measure-line/helpline_overlap", helpline_overlap);
- prefs->setString("/live_effects/measure-line/unit", (Glib::ustring)unit.get_abbreviation());
- prefs->setString("/live_effects/measure-line/format", (Glib::ustring)format.param_getSVGValue());
- prefs->setString("/live_effects/measure-line/dimline_format", (Glib::ustring)dimline_format.param_getSVGValue());
- prefs->setString("/live_effects/measure-line/helperlines_format", (Glib::ustring)helperlines_format.param_getSVGValue());
- prefs->setString("/live_effects/measure-line/anotation_format", (Glib::ustring)anotation_format.param_getSVGValue());
- prefs->setString("/live_effects/measure-line/arrows_format", (Glib::ustring)arrows_format.param_getSVGValue());
+ prefs->setString("/live_effects/measure-line/unit", Glib::ustring(unit.get_abbreviation()));
+ prefs->setString("/live_effects/measure-line/format", Glib::ustring(format.param_getSVGValue()));
+ prefs->setString("/live_effects/measure-line/dimline_format", Glib::ustring(dimline_format.param_getSVGValue()));
+ prefs->setString("/live_effects/measure-line/helperlines_format", Glib::ustring(helperlines_format.param_getSVGValue()));
+ prefs->setString("/live_effects/measure-line/anotation_format", Glib::ustring(anotation_format.param_getSVGValue()));
+ prefs->setString("/live_effects/measure-line/arrows_format", Glib::ustring(arrows_format.param_getSVGValue()));
prefs->setBool("/live_effects/measure-line/flip_side", flip_side);
- prefs->setBool("/live_effects/measure-line/scale_insensitive", scale_insensitive);
+ prefs->setBool("/live_effects/measure-line/scale_sensitive", scale_sensitive);
prefs->setBool("/live_effects/measure-line/local_locale", local_locale);
prefs->setBool("/live_effects/measure-line/line_group_05", line_group_05);
prefs->setBool("/live_effects/measure-line/rotate_anotation", rotate_anotation);
diff --git a/src/live_effects/lpe-measure-line.h b/src/live_effects/lpe-measure-line.h
index 2fab9dbb9..c69921a4d 100644
--- a/src/live_effects/lpe-measure-line.h
+++ b/src/live_effects/lpe-measure-line.h
@@ -11,6 +11,9 @@
*/
#include "live_effects/effect.h"
+
+#include <gtkmm/expander.h>
+
#include "live_effects/parameter/enum.h"
#include "live_effects/parameter/fontbutton.h"
#include "live_effects/parameter/text.h"
@@ -32,20 +35,27 @@ enum OrientationMethod {
OM_END
};
+enum LpeAction {
+ LPE_ERASE = 0,
+ LPE_TO_OBJECTS,
+ LPE_VISIBILITY
+};
+
class LPEMeasureLine : public Effect {
public:
LPEMeasureLine(LivePathEffectObject *lpeobject);
virtual ~LPEMeasureLine();
virtual void doBeforeEffect (SPLPEItem const* lpeitem);
virtual void doOnApply(SPLPEItem const* lpeitem);
- virtual void doOnRemove (SPLPEItem const* lpeitem);
+ virtual void doOnRemove (SPLPEItem const* /*lpeitem*/);
+ virtual void doEffect (SPCurve * curve){}; //stop the chain
virtual void doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/);
virtual Geom::PathVector doEffect_path(Geom::PathVector const &path_in);
- void createLine(Geom::Point start,Geom::Point end,Glib::ustring id, bool main, bool overflow, bool remove, bool arrows = false);
- void createTextLabel(Geom::Point pos, double length, Geom::Coord angle, bool remove);
+ void processObjects(LpeAction lpe_action);
+ void createLine(Geom::Point start,Geom::Point end, const char * id, bool main, bool overflow, bool remove, bool arrows = false);
+ void createTextLabel(Geom::Point pos, double length, Geom::Coord angle, bool remove, bool valid);
void onExpanderChanged();
- void toObjects();
- void createArrowMarker(Glib::ustring mode);
+ void createArrowMarker(const char * mode);
void saveDefault();
virtual Gtk::Widget *newWidget();
private:
@@ -61,9 +71,10 @@ private:
ScalarParam helpline_overlap;
ScalarParam scale;
TextParam format;
+ TextParam id_origin;
BoolParam arrows_outside;
BoolParam flip_side;
- BoolParam scale_insensitive;
+ BoolParam scale_sensitive;
BoolParam local_locale;
BoolParam line_group_05;
BoolParam rotate_anotation;
@@ -79,7 +90,9 @@ private:
double fontsize;
double anotation_width;
double arrow_gap;
- bool erase;
+ Geom::Point start_stored;
+ Geom::Point end_stored;
+ std::vector<const char *> elements;
/* Geom::Affine affine_over;*/
LPEMeasureLine(const LPEMeasureLine &);
LPEMeasureLine &operator=(const LPEMeasureLine &);
diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp
index 4deb29d8f..61b2b8b5c 100644
--- a/src/live_effects/lpe-mirror_symmetry.cpp
+++ b/src/live_effects/lpe-mirror_symmetry.cpp
@@ -13,13 +13,16 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+
+#include <gtkmm.h>
#include "live_effects/lpe-mirror_symmetry.h"
#include <display/curve.h>
#include <svg/path-string.h>
#include "helper/geom.h"
#include <2geom/path-intersection.h>
-#include "knotholder.h"
+
// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -34,39 +37,15 @@ static const Util::EnumData<ModeType> ModeTypeData[MT_END] = {
static const Util::EnumDataConverter<ModeType>
MTConverter(ModeTypeData, MT_END);
-namespace MS {
-
-class KnotHolderEntityCenterMirrorSymmetry : public LPEKnotHolderEntity {
-public:
- KnotHolderEntityCenterMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){};
- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
- virtual Geom::Point knot_get() const;
-};
-
-class KnotHolderEntityStartMirrorSymmetry : public LPEKnotHolderEntity {
-public:
- KnotHolderEntityStartMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){};
- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
- virtual Geom::Point knot_get() const;
-};
-
-class KnotHolderEntityEndMirrorSymmetry : public LPEKnotHolderEntity {
-public:
- KnotHolderEntityEndMirrorSymmetry(LPEMirrorSymmetry *effect) : LPEKnotHolderEntity(effect){};
- virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
- virtual Geom::Point knot_get() const;
-};
-
-} // namespace MS
-
LPEMirrorSymmetry::LPEMirrorSymmetry(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
mode(_("Mode"), _("Symmetry move mode"), "mode", MTConverter, &wr, this, MT_FREE),
- discard_orig_path(_("Discard original path?"), _("Check this to only keep the mirrored part of the path"), "discard_orig_path", &wr, this, false),
+ discard_orig_path(_("Discard original path"), _("Check this to only keep the mirrored part of the path"), "discard_orig_path", &wr, this, false),
fuse_paths(_("Fuse paths"), _("Fuse original and the reflection into a single path"), "fuse_paths", &wr, this, false),
oposite_fuse(_("Opposite fuse"), _("Picks the other side of the mirror as the original"), "oposite_fuse", &wr, this, false),
- start_point(_("Start mirror line"), _("Start mirror line"), "start_point", &wr, this, "Adjust the start of mirroring"),
- end_point(_("End mirror line"), _("End mirror line"), "end_point", &wr, this, "Adjust end of mirroring")
+ start_point(_("Start mirror line"), _("Start mirror line"), "start_point", &wr, this, _("Adjust start of mirroring")),
+ end_point(_("End mirror line"), _("End mirror line"), "end_point", &wr, this, _("Adjust end of mirroring")),
+ center_point(_("Center mirror line"), _("Center mirror line"), "center_point", &wr, this, _("Adjust center of mirroring"))
{
show_orig_path = true;
registerParameter(&mode);
@@ -75,6 +54,8 @@ LPEMirrorSymmetry::LPEMirrorSymmetry(LivePathEffectObject *lpeobject) :
registerParameter( &oposite_fuse);
registerParameter( &start_point);
registerParameter( &end_point);
+ registerParameter( &center_point);
+ previous_center = Geom::Point(0,0);
apply_to_clippath_and_mask = true;
}
@@ -82,12 +63,47 @@ LPEMirrorSymmetry::~LPEMirrorSymmetry()
{
}
-void
+Gtk::Widget * LPEMirrorSymmetry::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 != "center_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
LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem)
{
using namespace Geom;
original_bbox(lpeitem);
+ //center_point->param_set_liveupdate(false);
Point point_a(boundingbox_X.max(), boundingbox_Y.min());
Point point_b(boundingbox_X.max(), boundingbox_Y.max());
Point point_c(boundingbox_X.max(), boundingbox_Y.middle());
@@ -99,47 +115,59 @@ LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem)
point_a = Geom::Point(center_point[X],boundingbox_Y.min());
point_b = Geom::Point(center_point[X],boundingbox_Y.max());
}
- line_separation.setPoints(point_a, point_b);
+ if ((Geom::Point)start_point == (Geom::Point)end_point) {
+ start_point.param_setValue(point_a, true);
+ end_point.param_setValue(point_b, true);
+ previous_center = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
+ center_point.param_setValue(previous_center, true);
+ return;
+ }
if ( mode == MT_X || mode == MT_Y ) {
- start_point.param_setValue(point_a);
- end_point.param_setValue(point_b);
- center_point = Geom::middle_point(point_a, point_b);
+ if (!are_near(previous_center, (Geom::Point)center_point, 0.01)) {
+ center_point.param_setValue(Geom::middle_point(point_a, point_b), true);
+ end_point.param_setValue(point_b, true);
+ start_point.param_setValue(point_a, true);
+ } else {
+ if ( mode == MT_X ) {
+ if (!are_near(start_point[X], point_a[X], 0.01)) {
+ start_point.param_setValue(point_a, true);
+ }
+ if (!are_near(end_point[X], point_b[X], 0.01)) {
+ end_point.param_setValue(point_b, true);
+ }
+ } else { //MT_Y
+ if (!are_near(start_point[Y], point_a[Y], 0.01)) {
+ start_point.param_setValue(point_a, true);
+ }
+ if (!are_near(end_point[Y], point_b[Y], 0.01)) {
+ end_point.param_setValue(point_b, true);
+ }
+ }
+ }
} else if ( mode == MT_FREE) {
- if(!are_near(previous_center,center_point, 0.01)) {
- Geom::Point trans = center_point - previous_center;
- start_point.param_setValue(start_point * trans);
- end_point.param_setValue(end_point * trans);
- line_separation.setPoints(start_point, end_point);
+ if (are_near(previous_center, (Geom::Point)center_point, 0.01)) {
+ center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point), true);
} else {
- center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
- line_separation.setPoints(start_point, end_point);
+ Geom::Point trans = center_point - Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
+ start_point.param_setValue(start_point * trans, true);
+ end_point.param_setValue(end_point * trans, true);
}
} else if ( mode == MT_V){
- if(SP_ACTIVE_DESKTOP){
- SPDocument * doc = SP_ACTIVE_DESKTOP->getDocument();
- Geom::Rect view_box_rect = doc->getViewBox();
- Geom::Point sp = Geom::Point(view_box_rect.width()/2.0, 0);
- sp *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse();
- start_point.param_setValue(sp);
- Geom::Point ep = Geom::Point(view_box_rect.width()/2.0, view_box_rect.height());
- ep *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse();
- end_point.param_setValue(ep);
- center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
- line_separation.setPoints(start_point, end_point);
- }
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ Geom::Affine transform = i2anc_affine(SP_OBJECT(lpeitem), NULL).inverse();
+ Geom::Point sp = Geom::Point(document->getWidth().value("px")/2.0, 0) * transform;
+ start_point.param_setValue(sp, true);
+ Geom::Point ep = Geom::Point(document->getWidth().value("px")/2.0, document->getHeight().value("px")) * transform;
+ end_point.param_setValue(ep, true);
+ center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point), true);
} else { //horizontal page
- if(SP_ACTIVE_DESKTOP){
- SPDocument * doc = SP_ACTIVE_DESKTOP->getDocument();
- Geom::Rect view_box_rect = doc->getViewBox();
- Geom::Point sp = Geom::Point(0, view_box_rect.height()/2.0);
- sp *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse();
- start_point.param_setValue(sp);
- Geom::Point ep = Geom::Point(view_box_rect.width(), view_box_rect.height()/2.0);
- ep *= i2anc_affine(SP_OBJECT(lpeitem), SP_OBJECT(SP_ACTIVE_DESKTOP->currentLayer()->parent)) .inverse();
- end_point.param_setValue(ep);
- center_point = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
- line_separation.setPoints(start_point, end_point);
- }
+ SPDocument * document = SP_ACTIVE_DOCUMENT;
+ Geom::Affine transform = i2anc_affine(SP_OBJECT(lpeitem), NULL).inverse();
+ Geom::Point sp = Geom::Point(0, document->getHeight().value("px")/2.0) * transform;
+ start_point.param_setValue(sp, true);
+ Geom::Point ep = Geom::Point(document->getWidth().value("px"), document->getHeight().value("px")/2.0) * transform;
+ end_point.param_setValue(ep, true);
+ center_point.param_setValue(Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point), true);
}
previous_center = center_point;
}
@@ -147,13 +175,12 @@ LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem)
void
LPEMirrorSymmetry::transform_multiply(Geom::Affine const& postmul, bool set)
{
- center_point *= postmul;
- previous_center = center_point;
// 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) {
Parameter * param = *it;
param->param_transform_multiply(postmul, set);
}
+ previous_center = Geom::middle_point((Geom::Point)start_point, (Geom::Point)end_point);
}
void
@@ -166,11 +193,11 @@ LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem)
Point point_a(boundingbox_X.max(), boundingbox_Y.min());
Point point_b(boundingbox_X.max(), boundingbox_Y.max());
Point point_c(boundingbox_X.max(), boundingbox_Y.middle());
- start_point.param_setValue(point_a);
+ start_point.param_setValue(point_a, true);
start_point.param_update_default(point_a);
- end_point.param_setValue(point_b);
+ end_point.param_setValue(point_b, true);
end_point.param_update_default(point_b);
- center_point = point_c;
+ center_point.param_setValue(point_c, true);
previous_center = center_point;
}
@@ -185,24 +212,8 @@ LPEMirrorSymmetry::doEffect_path (Geom::PathVector const & path_in)
path_out = pathv_to_linear_and_cubic_beziers(path_in);
}
- Geom::Point point_a(line_separation.initialPoint());
- Geom::Point point_b(line_separation.finalPoint());
-
- Geom::Translate m1(point_a[0], point_a[1]);
- double hyp = Geom::distance(point_a, point_b);
- double cos = 0;
- double sin = 0;
- if (hyp > 0) {
- cos = (point_b[0] - point_a[0]) / hyp;
- sin = (point_b[1] - point_a[1]) / hyp;
- }
- Geom::Affine m2(cos, -sin, sin, cos, 0.0, 0.0);
- Geom::Scale sca(1.0, -1.0);
-
- Geom::Affine m = m1.inverse() * m2;
- m = m * sca;
- m = m * m2.inverse();
- m = m * m1;
+ Geom::Line line_separation((Geom::Point)start_point, (Geom::Point)end_point);
+ Geom::Affine m = Geom::reflection (line_separation.vector(), (Geom::Point)start_point);
if (fuse_paths && !discard_orig_path) {
for (Geom::PathVector::const_iterator path_it = original_pathv.begin();
@@ -330,44 +341,6 @@ LPEMirrorSymmetry::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector
hp_vec.push_back(helper);
}
-void
-LPEMirrorSymmetry::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
-{
- SPKnotShapeType knot_shape = SP_KNOT_SHAPE_CIRCLE;
- SPKnotModeType knot_mode = SP_KNOT_MODE_XOR;
- guint32 knot_color = 0x0000ff00;
- {
- KnotHolderEntity *c = new MS::KnotHolderEntityCenterMirrorSymmetry(this);
- c->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
- _("Adjust the center"), knot_shape, knot_mode, knot_color );
- knotholder->add(c);
- }
-};
-
-namespace MS {
-
-using namespace Geom;
-
-void
-KnotHolderEntityCenterMirrorSymmetry::knot_set(Geom::Point const &p, Geom::Point const &origin, guint state)
-{
- LPEMirrorSymmetry* lpe = dynamic_cast<LPEMirrorSymmetry *>(_effect);
- Geom::Point const s = snap_knot_position(p, state);
- lpe->center_point = s;
-
- // 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
-KnotHolderEntityCenterMirrorSymmetry::knot_get() const
-{
- LPEMirrorSymmetry const *lpe = dynamic_cast<LPEMirrorSymmetry const*>(_effect);
- return lpe->center_point;
-}
-
-} // namespace CR
-
} //namespace LivePathEffect
} /* namespace Inkscape */
diff --git a/src/live_effects/lpe-mirror_symmetry.h b/src/live_effects/lpe-mirror_symmetry.h
index 7ec4029e0..b4967173a 100644
--- a/src/live_effects/lpe-mirror_symmetry.h
+++ b/src/live_effects/lpe-mirror_symmetry.h
@@ -15,7 +15,7 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <gtkmm.h>
+
#include "live_effects/effect.h"
#include "live_effects/parameter/parameter.h"
#include "live_effects/parameter/point.h"
@@ -26,11 +26,6 @@
namespace Inkscape {
namespace LivePathEffect {
-namespace MS {
-// we need a separate namespace to avoid clashes with LPEPerpBisector
-class KnotHolderEntityCenterMirrorSymmetry;
-}
-
enum ModeType {
MT_V,
MT_H,
@@ -48,9 +43,7 @@ public:
virtual void doBeforeEffect (SPLPEItem const* lpeitem);
virtual void transform_multiply(Geom::Affine const& postmul, bool set);
virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in);
- /* the knotholder entity classes must be declared friends */
- friend class MS::KnotHolderEntityCenterMirrorSymmetry;
- 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);
@@ -62,9 +55,8 @@ private:
BoolParam oposite_fuse;
PointParam start_point;
PointParam end_point;
- Geom::Line line_separation;
+ PointParam center_point;
Geom::Point previous_center;
- Geom::Point center_point;
LPEMirrorSymmetry(const LPEMirrorSymmetry&);
LPEMirrorSymmetry& operator=(const LPEMirrorSymmetry&);
diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp
index a0fa46c3f..057f404e0 100644
--- a/src/live_effects/lpe-offset.cpp
+++ b/src/live_effects/lpe-offset.cpp
@@ -11,13 +11,12 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-offset.h"
#include "sp-shape.h"
#include "display/curve.h"
-
#include <2geom/elliptical-arc.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-parallel.cpp b/src/live_effects/lpe-parallel.cpp
index 9cd8ecf46..276749c43 100644
--- a/src/live_effects/lpe-parallel.cpp
+++ b/src/live_effects/lpe-parallel.cpp
@@ -11,14 +11,15 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-parallel.h"
#include "sp-shape.h"
#include "display/curve.h"
#include "knotholder.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-path_length.cpp b/src/live_effects/lpe-path_length.cpp
index 8fbf9d420..a06dbde98 100644
--- a/src/live_effects/lpe-path_length.cpp
+++ b/src/live_effects/lpe-path_length.cpp
@@ -11,10 +11,10 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-path_length.h"
#include "util/units.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -37,12 +37,6 @@ LPEPathLength::~LPEPathLength()
}
-void
-LPEPathLength::hideCanvasText() {
- // this is only used in sp-lpe-item.cpp to hide the canvas text when the effect is invisible
- info_text.param_setValue("");
-}
-
Geom::Piecewise<Geom::D2<Geom::SBasis> >
LPEPathLength::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
{
@@ -69,7 +63,9 @@ LPEPathLength::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & p
//g_print ("Area is zero\n");
}
//g_print ("Area: %f\n", area);
-
+ if (!this->isVisible()) {
+ info_text.param_setValue("");
+ }
return pwd2_in;
}
diff --git a/src/live_effects/lpe-path_length.h b/src/live_effects/lpe-path_length.h
index e108e770a..14d093c09 100644
--- a/src/live_effects/lpe-path_length.h
+++ b/src/live_effects/lpe-path_length.h
@@ -29,8 +29,6 @@ public:
virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);
- void hideCanvasText();
-
private:
LPEPathLength(const LPEPathLength&);
LPEPathLength& operator=(const LPEPathLength&);
diff --git a/src/live_effects/lpe-patternalongpath.cpp b/src/live_effects/lpe-patternalongpath.cpp
index 0785da235..966e9020e 100644
--- a/src/live_effects/lpe-patternalongpath.cpp
+++ b/src/live_effects/lpe-patternalongpath.cpp
@@ -11,7 +11,10 @@
#include <2geom/bezier-to-sbasis.h>
#include "knotholder.h"
+#include <cmath>
#include <algorithm>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
using std::vector;
@@ -61,7 +64,7 @@ static const Util::EnumDataConverter<PAPCopyType> PAPCopyTypeConverter(PAPCopyTy
LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
pattern(_("Pattern source:"), _("Path to put along the skeleton path"), "pattern", &wr, this, "M0,0 L1,0"),
- original_height(0),
+ original_height(0.0),
prop_scale(_("_Width:"), _("Width of the pattern"), "prop_scale", &wr, this, 1.0),
copytype(_("Pattern copies:"), _("How many pattern copies to place along the skeleton path"),
"copytype", PAPCopyTypeConverter, &wr, this, PAPCT_SINGLE_STRETCHED),
@@ -142,15 +145,15 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
double xspace = spacing;
double noffset = normal_offset;
double toffset = tang_offset;
- if (prop_units.get_value() && pattBndsY){
+ if (prop_units.get_value()){
xspace *= pattBndsX->extent();
noffset *= pattBndsY->extent();
toffset *= pattBndsX->extent();
}
//Prevent more than 90% overlap...
- if (xspace < -pattBndsX->extent()*.9) {
- xspace = -pattBndsX->extent()*.9;
+ if (xspace < -pattBndsX->extent() * 0.9) {
+ xspace = -pattBndsX->extent() * 0.9;
}
//TODO: dynamical update of parameter ranges?
//if (prop_units.get_value()){
@@ -159,7 +162,7 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
// spacing.param_set_range(-pattBndsX.extent()*.9, Geom::infinity());
// }
- y0+=noffset;
+ y0 += noffset;
std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > paths_in;
paths_in = split_at_discontinuities(pwd2_in);
@@ -168,11 +171,14 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
Geom::Piecewise<Geom::D2<Geom::SBasis> > path_i = paths_in[idx];
Piecewise<SBasis> x = x0;
Piecewise<SBasis> y = y0;
- Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(path_i,2,.1);
- uskeleton = remove_short_cuts(uskeleton,.01);
+ Piecewise<D2<SBasis> > uskeleton = arc_length_parametrization(path_i,2, 0.1);
+ uskeleton = remove_short_cuts(uskeleton, 0.01);
Piecewise<D2<SBasis> > n = rot90(derivative(uskeleton));
- n = force_continuity(remove_short_cuts(n,.1));
-
+ if (Geom::are_near(pwd2_in[0].at0(),pwd2_in[pwd2_in.size()-1].at1(), 0.01)) {
+ n = force_continuity(remove_short_cuts(n, 0.1), 0.01);
+ } else {
+ n = force_continuity(remove_short_cuts(n, 0.1));
+ }
int nbCopies = 0;
double scaling = 1;
switch(type) {
@@ -192,7 +198,7 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
case PAPCT_REPEATED_STRETCHED:
// if uskeleton is closed:
- if(path_i.segs.front().at0() == path_i.segs.back().at1()){
+ if (are_near(path_i.segs.front().at0(), path_i.segs.back().at1())){
nbCopies = std::max(1, static_cast<int>(std::floor((uskeleton.domain().extent() - toffset)/(pattBndsX->extent()+xspace))));
pattBndsX = Interval(pattBndsX->min(),pattBndsX->max()+xspace);
scaling = (uskeleton.domain().extent() - toffset)/(((double)nbCopies)*pattBndsX->extent());
@@ -208,18 +214,18 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
return pwd2_in;
};
+ //Ceil to 6 decimals
+ scaling = ceil(scaling * 1000000) / 1000000;
double pattWidth = pattBndsX->extent() * scaling;
- if (scaling != 1.0) {
- x*=scaling;
- }
+ x *= scaling;
if ( scale_y_rel.get_value() ) {
- y*=(scaling*prop_scale);
+ y *= prop_scale * scaling;
} else {
- if (prop_scale != 1.0) y *= prop_scale;
+ y *= prop_scale;
}
x += toffset;
-
+
double offs = 0;
for (int i=0; i<nbCopies; i++){
if (fuse_tolerance > 0){
@@ -232,7 +238,7 @@ LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > con
offs+=pattWidth;
}
}
- if (fuse_tolerance > 0){
+ if (fuse_tolerance > 0){
pre_output = fuse_nearby_ends(pre_output, fuse_tolerance);
for (unsigned i=0; i<pre_output.size(); i++){
output.concat(pre_output[i]);
@@ -261,7 +267,6 @@ LPEPatternAlongPath::transform_multiply(Geom::Affine const& postmul, bool set)
pattern.param_transform_multiply(postmul, set);
pattern.write_to_SVG();
}
- sp_lpe_item_update_patheffect (sp_lpe_item, false, true);
}
void
@@ -272,10 +277,10 @@ LPEPatternAlongPath::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vect
void
-LPEPatternAlongPath::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+LPEPatternAlongPath::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
KnotHolderEntity *e = new WPAP::KnotHolderEntityWidthPatternAlongPath(this);
- e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Change the width"), SP_KNOT_SHAPE_CIRCLE);
+ e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Change the width"), SP_KNOT_SHAPE_CIRCLE);
knotholder->add(e);
}
diff --git a/src/live_effects/lpe-patternalongpath.h b/src/live_effects/lpe-patternalongpath.h
index 3d7fc02bc..c34a9a15d 100644
--- a/src/live_effects/lpe-patternalongpath.h
+++ b/src/live_effects/lpe-patternalongpath.h
@@ -43,7 +43,7 @@ public:
void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec);
- virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item);
+ virtual void addKnotHolderEntities(KnotHolder * knotholder, SPItem * item);
PathParam pattern;
diff --git a/src/live_effects/lpe-perp_bisector.cpp b/src/live_effects/lpe-perp_bisector.cpp
index f69dae6a1..bce22250a 100644
--- a/src/live_effects/lpe-perp_bisector.cpp
+++ b/src/live_effects/lpe-perp_bisector.cpp
@@ -11,9 +11,6 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-perp_bisector.h"
#include "display/curve.h"
#include "sp-path.h"
@@ -21,6 +18,9 @@
#include "knotholder.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
namespace PB {
diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp
index 6a6b59519..18b5b724d 100644
--- a/src/live_effects/lpe-perspective-envelope.cpp
+++ b/src/live_effects/lpe-perspective-envelope.cpp
@@ -20,6 +20,9 @@
#include "display/curve.h"
#include <gsl/gsl_linalg.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
using namespace Geom;
namespace Inkscape {
@@ -376,7 +379,7 @@ LPEPerspectiveEnvelope::newWidget()
hbox_down_handles->pack_start(*widg, true, true, 2);
}
if (tip) {
- widg->set_tooltip_text(*tip);
+ widg->set_tooltip_markup(*tip);
} else {
widg->set_tooltip_text("");
widg->set_has_tooltip(false);
@@ -405,7 +408,8 @@ LPEPerspectiveEnvelope::newWidget()
vbox->pack_start(*hbox_middle, false, true, 2);
vbox->pack_start(*hbox_down_handles, true, true, 2);
Gtk::HBox * hbox = Gtk::manage(new Gtk::HBox(false,0));
- Gtk::Button* reset_button = Gtk::manage(new Gtk::Button(Gtk::Stock::CLEAR));
+ Gtk::Button* reset_button = Gtk::manage(new Gtk::Button(_("_Clear"), true));
+ reset_button->set_image_from_icon_name("edit-clear");
reset_button->signal_clicked().connect(sigc::mem_fun (*this,&LPEPerspectiveEnvelope::resetGrid));
reset_button->set_size_request(140,30);
vbox->pack_start(*hbox, true,true,2);
@@ -537,4 +541,4 @@ LPEPerspectiveEnvelope::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::v
fill-column:99
End:
*/
-// vim: file_type=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp
index cb4e43d87..979b6dea5 100644
--- a/src/live_effects/lpe-perspective_path.cpp
+++ b/src/live_effects/lpe-perspective_path.cpp
@@ -11,8 +11,6 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <gtkmm.h>
-#include <glibmm/i18n.h>
-
#include "persp3d.h"
//#include "transf_mat_3x4.h"
#include "document-private.h"
@@ -20,9 +18,11 @@
#include "live_effects/lpeobject.h"
#include "knot-holder-entity.h"
#include "knotholder.h"
-#include "desktop.h"
#include <util/units.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -242,9 +242,9 @@ LPEPerspectivePath::newWidget()
return dynamic_cast<Gtk::Widget *>(vbox);
}
-void LPEPerspectivePath::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
+void LPEPerspectivePath::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) {
KnotHolderEntity *e = new PP::KnotHolderEntityOffset(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("Adjust the origin") );
knotholder->add(e);
};
diff --git a/src/live_effects/lpe-perspective_path.h b/src/live_effects/lpe-perspective_path.h
index c4ddf1853..87ee453ff 100644
--- a/src/live_effects/lpe-perspective_path.h
+++ b/src/live_effects/lpe-perspective_path.h
@@ -41,7 +41,7 @@ public:
virtual Gtk::Widget * newWidget();
/* the knotholder entity classes must be declared friends */
friend class PP::KnotHolderEntityOffset;
- void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
private:
// add the parameters for your effect here:
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp
index 329a00756..e9f3975c7 100644
--- a/src/live_effects/lpe-powerstroke.cpp
+++ b/src/live_effects/lpe-powerstroke.cpp
@@ -25,6 +25,9 @@
#include <2geom/circle.h>
#include "helper/geom.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Geom {
// should all be moved to 2geom at some point
diff --git a/src/live_effects/lpe-recursiveskeleton.cpp b/src/live_effects/lpe-recursiveskeleton.cpp
index ed0c915ce..aa0db920b 100644
--- a/src/live_effects/lpe-recursiveskeleton.cpp
+++ b/src/live_effects/lpe-recursiveskeleton.cpp
@@ -10,12 +10,13 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-recursiveskeleton.h"
#include <2geom/bezier-to-sbasis.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-rough-hatches.cpp b/src/live_effects/lpe-rough-hatches.cpp
index 2fb65b349..3cc8658ea 100644
--- a/src/live_effects/lpe-rough-hatches.cpp
+++ b/src/live_effects/lpe-rough-hatches.cpp
@@ -13,7 +13,6 @@
*/
#include "ui/widget/scalar.h"
-#include <glibmm/i18n.h>
#include "live_effects/lpe-rough-hatches.h"
#include "sp-item.h"
@@ -23,6 +22,8 @@
#include <2geom/sbasis-math.h>
#include <2geom/bezier-to-sbasis.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp
index 3a486ff10..c6edffd9b 100644
--- a/src/live_effects/lpe-roughen.cpp
+++ b/src/live_effects/lpe-roughen.cpp
@@ -13,11 +13,14 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <gtkmm.h>
#include "live_effects/lpe-roughen.h"
#include "display/curve.h"
#include <boost/functional/hash.hpp>
#include "helper/geom.h"
+
// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-roughen.h b/src/live_effects/lpe-roughen.h
index dbdb91e62..bab06022f 100644
--- a/src/live_effects/lpe-roughen.h
+++ b/src/live_effects/lpe-roughen.h
@@ -12,7 +12,6 @@
#ifndef INKSCAPE_LPE_ROUGHEN_H
#define INKSCAPE_LPE_ROUGHEN_H
-#include <gtkmm.h>
#include "live_effects/effect.h"
#include "live_effects/parameter/enum.h"
#include "live_effects/parameter/parameter.h"
diff --git a/src/live_effects/lpe-ruler.cpp b/src/live_effects/lpe-ruler.cpp
index 3a2d78b2c..60c2a3e1c 100644
--- a/src/live_effects/lpe-ruler.cpp
+++ b/src/live_effects/lpe-ruler.cpp
@@ -12,7 +12,8 @@
*/
#include "live_effects/lpe-ruler.h"
-
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-show_handles.cpp b/src/live_effects/lpe-show_handles.cpp
index 388ea176f..7c298d0e7 100644
--- a/src/live_effects/lpe-show_handles.cpp
+++ b/src/live_effects/lpe-show_handles.cpp
@@ -6,6 +6,7 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <gtkmm.h>
#include "live_effects/lpe-show_handles.h"
#include <2geom/sbasis-to-bezier.h>
#include <2geom/svg-path-parser.h>
@@ -13,6 +14,7 @@
#include "desktop-style.h"
#include "style.h"
#include "svg/svg.h"
+
// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
@@ -24,20 +26,17 @@ LPEShowHandles::LPEShowHandles(LivePathEffectObject *lpeobject)
nodes(_("Show nodes"), _("Show nodes"), "nodes", &wr, this, true),
handles(_("Show handles"), _("Show handles"), "handles", &wr, this, true),
original_path(_("Show path"), _("Show path"), "original_path", &wr, this, true),
- scale_nodes_and_handles(_("Scale nodes and handles"), _("Scale nodes and handles"), "scale_nodes_and_handles", &wr, this, 10),
- rotate_nodes(_("Rotate nodes"), _("Rotate nodes"), "rotate_nodes", &wr, this, 0)
+ show_center_node(_("Show center of node"), _("Show center of node"), "show_center_node", &wr, this, false),
+ scale_nodes_and_handles(_("Scale nodes and handles"), _("Scale nodes and handles"), "scale_nodes_and_handles", &wr, this, 10)
{
registerParameter(&nodes);
registerParameter(&handles);
registerParameter(&original_path);
+ registerParameter(&show_center_node);
registerParameter(&scale_nodes_and_handles);
- registerParameter(&rotate_nodes);
scale_nodes_and_handles.param_set_range(0, 500.);
scale_nodes_and_handles.param_set_increments(1, 1);
scale_nodes_and_handles.param_set_digits(2);
- rotate_nodes.param_set_range(0, 365);
- rotate_nodes.param_set_increments(1, 1);
- rotate_nodes.param_set_digits(0);
stroke_width = 1.0;
}
@@ -129,7 +128,11 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result)
}
}
if(nodes) {
- drawNode(curve_it1->initialPoint());
+ Geom::NodeType nodetype = Geom::NODE_CUSP;
+ if(path_it->closed()) {
+ nodetype = Geom::get_nodetype(path_it->finalCurve(), *curve_it1);
+ }
+ drawNode(curve_it1->initialPoint(), nodetype);
}
while (curve_it1 != curve_endit) {
cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
@@ -145,8 +148,9 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result)
}
}
}
- if(nodes) {
- drawNode(curve_it1->finalPoint());
+ if(nodes && (curve_it2 != curve_endit || !path_it->closed())) {
+ Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
+ drawNode(curve_it1->finalPoint(), nodetype);
}
++curve_it1;
if(curve_it2 != curve_endit) {
@@ -157,16 +161,26 @@ LPEShowHandles::generateHelperPath(Geom::PathVector result)
}
void
-LPEShowHandles::drawNode(Geom::Point p)
+LPEShowHandles::drawNode(Geom::Point p, Geom::NodeType nodetype)
{
if(stroke_width * scale_nodes_and_handles > 0.0) {
+ Geom::Rotate rotate = Geom::Rotate(0);
+ if ( nodetype == Geom::NODE_CUSP) {
+ rotate = Geom::Rotate::from_degrees(45);
+ }
double diameter = stroke_width * scale_nodes_and_handles;
char const * svgd;
- svgd = "M 0.05,0 A 0.05,0.05 0 0 1 0,0.05 0.05,0.05 0 0 1 -0.05,0 0.05,0.05 0 0 1 0,-0.05 0.05,0.05 0 0 1 0.05,0 Z M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z";
+ if (show_center_node) {
+ svgd = "M 0.05,0 A 0.05,0.05 0 0 1 0,0.05 0.05,0.05 0 0 1 -0.05,0 0.05,0.05 0 0 1 0,-0.05 0.05,0.05 0 0 1 0.05,0 Z M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z";
+ } else {
+ svgd = "M -0.5,-0.5 0.5,-0.5 0.5,0.5 -0.5,0.5 Z";
+ }
Geom::PathVector pathv = sp_svg_read_pathv(svgd);
- pathv *= Geom::Rotate::from_degrees(rotate_nodes) * Geom::Scale(diameter) * Geom::Translate(p);
+ pathv *= rotate * Geom::Scale(diameter) * Geom::Translate(p);
outline_path.push_back(pathv[0]);
- outline_path.push_back(pathv[1]);
+ if (show_center_node) {
+ outline_path.push_back(pathv[1]);
+ }
}
}
diff --git a/src/live_effects/lpe-show_handles.h b/src/live_effects/lpe-show_handles.h
index 8bff3c1a8..c46abd2c2 100644
--- a/src/live_effects/lpe-show_handles.h
+++ b/src/live_effects/lpe-show_handles.h
@@ -8,7 +8,7 @@
* Copyright (C) Jabier Arraiza Cenoz 2014 <jabier.arraiza@marker.es>
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <gtkmm.h>
+#include "helper/geom-nodetype.h"
#include "live_effects/effect.h"
#include "live_effects/lpegroupbbox.h"
#include "live_effects/parameter/bool.h"
@@ -28,7 +28,7 @@ public:
virtual void generateHelperPath(Geom::PathVector result);
- virtual void drawNode(Geom::Point p);
+ virtual void drawNode(Geom::Point p, Geom::NodeType nodetype);
virtual void drawHandle(Geom::Point p);
@@ -43,8 +43,8 @@ private:
BoolParam nodes;
BoolParam handles;
BoolParam original_path;
+ BoolParam show_center_node;
ScalarParam scale_nodes_and_handles;
- ScalarParam rotate_nodes;
double stroke_width;
static bool alerts_off;
diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp
index ec21e10d2..5de9816bb 100644
--- a/src/live_effects/lpe-simplify.cpp
+++ b/src/live_effects/lpe-simplify.cpp
@@ -2,6 +2,7 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include <gtkmm.h>
#include "live_effects/lpe-simplify.h"
#include "display/curve.h"
#include "helper/geom.h"
@@ -9,6 +10,7 @@
#include "svg/svg.h"
#include "ui/tools/node-tool.h"
#include "ui/icon-names.h"
+
// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
@@ -138,11 +140,7 @@ LPESimplify::doEffect(SPCurve *curve)
Geom::PathVector result = Geom::parse_svg_path(pathliv->svg_dump_path());
generateHelperPathAndSmooth(result);
curve->set_pathvector(result);
- SPDesktop* desktop = SP_ACTIVE_DESKTOP;
- if(desktop && INK_IS_NODE_TOOL(desktop->event_context)) {
- Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(desktop->event_context);
- nt->update_helperpath();
- }
+ Inkscape::UI::Tools::sp_update_helperpath();
}
void
diff --git a/src/live_effects/lpe-simplify.h b/src/live_effects/lpe-simplify.h
index 8135561af..6c407f572 100644
--- a/src/live_effects/lpe-simplify.h
+++ b/src/live_effects/lpe-simplify.h
@@ -6,7 +6,6 @@
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <gtkmm.h>
#include "live_effects/effect.h"
#include "live_effects/parameter/togglebutton.h"
#include "live_effects/lpegroupbbox.h"
diff --git a/src/live_effects/lpe-skeleton.cpp b/src/live_effects/lpe-skeleton.cpp
index 7d34db699..4fc18cee2 100644
--- a/src/live_effects/lpe-skeleton.cpp
+++ b/src/live_effects/lpe-skeleton.cpp
@@ -20,8 +20,7 @@
#include "live_effects/lpe-skeleton.h"
-// You might need to include other 2geom files. You can add them here:
-
+// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
namespace Inkscape {
@@ -98,10 +97,10 @@ public:
} // namespace Skeleton
void
-LPESkeleton::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
+LPESkeleton::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) {
{
KnotHolderEntityMyHandle *e = new KnotHolderEntityMyHandle(this);
- e->create( desktop, item, knotholder,
+ e->create( NULL, item, knotholder,
_("Text describing what this handle does"),
//optional: knot_shape, knot_mode, knot_color);
knotholder->add(e);
diff --git a/src/live_effects/lpe-skeleton.h b/src/live_effects/lpe-skeleton.h
index 3b45b6978..e633ba5ab 100644
--- a/src/live_effects/lpe-skeleton.h
+++ b/src/live_effects/lpe-skeleton.h
@@ -41,7 +41,7 @@ public:
/* the knotholder entity classes (if any) can be declared friends */
//friend class Skeleton::KnotHolderEntityMyHandle;
- //virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ //virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
private:
// add the parameters for your effect here:
diff --git a/src/live_effects/lpe-sketch.cpp b/src/live_effects/lpe-sketch.cpp
index 95e2f6f0d..e01516f2e 100644
--- a/src/live_effects/lpe-sketch.cpp
+++ b/src/live_effects/lpe-sketch.cpp
@@ -13,13 +13,14 @@
#include "live_effects/lpe-sketch.h"
-#include <glibmm/i18n.h>
-
// You might need to include other 2geom files. You can add them here:
#include <2geom/sbasis-math.h>
#include <2geom/bezier-to-sbasis.h>
#include <2geom/path-intersection.h>
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-spiro.cpp b/src/live_effects/lpe-spiro.cpp
index 4a41dc5a0..8ea57bee4 100644
--- a/src/live_effects/lpe-spiro.cpp
+++ b/src/live_effects/lpe-spiro.cpp
@@ -16,8 +16,6 @@
// For handling un-continuous paths:
#include "message-stack.h"
#include "inkscape.h"
-#include "desktop.h"
-
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-tangent_to_curve.cpp b/src/live_effects/lpe-tangent_to_curve.cpp
index b308ef8d7..5f63e1ee9 100644
--- a/src/live_effects/lpe-tangent_to_curve.cpp
+++ b/src/live_effects/lpe-tangent_to_curve.cpp
@@ -13,13 +13,13 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-tangent_to_curve.h"
#include "sp-path.h"
#include "display/curve.h"
#include "knotholder.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
@@ -92,22 +92,22 @@ LPETangentToCurve::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const
}
void
-LPETangentToCurve::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) {
+LPETangentToCurve::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) {
{
KnotHolderEntity *e = new TtC::KnotHolderEntityAttachPt(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("Adjust the point of attachment of the tangent") );
knotholder->add(e);
}
{
KnotHolderEntity *e = new TtC::KnotHolderEntityLeftEnd(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("Adjust the <b>left</b> end of the tangent") );
knotholder->add(e);
}
{
KnotHolderEntity *e = new TtC::KnotHolderEntityRightEnd(this);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create( NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("Adjust the <b>right</b> end of the tangent") );
knotholder->add(e);
}
diff --git a/src/live_effects/lpe-tangent_to_curve.h b/src/live_effects/lpe-tangent_to_curve.h
index 8e44c01d1..a6a3c17ca 100644
--- a/src/live_effects/lpe-tangent_to_curve.h
+++ b/src/live_effects/lpe-tangent_to_curve.h
@@ -41,7 +41,7 @@ public:
friend class TtC::KnotHolderEntityLeftEnd;
friend class TtC::KnotHolderEntityRightEnd;
friend class TtC::KnotHolderEntityAttachPt;
- virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item);
+ virtual void addKnotHolderEntities(KnotHolder * knotholder, SPItem * item);
private:
ScalarParam angle;
diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp
index f6f6b33dc..f4a81aa90 100644
--- a/src/live_effects/lpe-taperstroke.cpp
+++ b/src/live_effects/lpe-taperstroke.cpp
@@ -26,6 +26,8 @@
#include "svg/svg.h"
#include "knotholder.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
template<typename T>
inline bool withinRange(T value, T low, T high) {
@@ -433,14 +435,14 @@ Piecewise<D2<SBasis> > stretch_along(Piecewise<D2<SBasis> > pwd2_in, Geom::Path
}
}
-void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+void LPETaperStroke::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
KnotHolderEntity *e = new TpS::KnotHolderEntityAttachBegin(this);
- e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE);
+ e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Start point of the taper"), SP_KNOT_SHAPE_CIRCLE);
knotholder->add(e);
KnotHolderEntity *f = new TpS::KnotHolderEntityAttachEnd(this);
- f->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE);
+ f->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("End point of the taper"), SP_KNOT_SHAPE_CIRCLE);
knotholder->add(f);
}
diff --git a/src/live_effects/lpe-taperstroke.h b/src/live_effects/lpe-taperstroke.h
index 88604486e..e3ecbb56c 100644
--- a/src/live_effects/lpe-taperstroke.h
+++ b/src/live_effects/lpe-taperstroke.h
@@ -36,7 +36,7 @@ public:
virtual Geom::PathVector doEffect_path (Geom::PathVector const& path_in);
Geom::PathVector doEffect_simplePath(Geom::PathVector const& path_in);
- virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item);
+ virtual void addKnotHolderEntities(KnotHolder * knotholder, SPItem * item);
friend class TpS::KnotHolderEntityAttachBegin;
friend class TpS::KnotHolderEntityAttachEnd;
diff --git a/src/live_effects/lpe-test-doEffect-stack.cpp b/src/live_effects/lpe-test-doEffect-stack.cpp
index c7ecf6481..324893706 100644
--- a/src/live_effects/lpe-test-doEffect-stack.cpp
+++ b/src/live_effects/lpe-test-doEffect-stack.cpp
@@ -4,10 +4,11 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-test-doEffect-stack.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
using std::memcpy;
namespace Inkscape {
diff --git a/src/live_effects/lpe-text_label.cpp b/src/live_effects/lpe-text_label.cpp
index 602a6897c..709d05e18 100644
--- a/src/live_effects/lpe-text_label.cpp
+++ b/src/live_effects/lpe-text_label.cpp
@@ -11,10 +11,11 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-#include <glibmm/i18n.h>
-
#include "live_effects/lpe-text_label.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
diff --git a/src/live_effects/lpe-transform_2pts.cpp b/src/live_effects/lpe-transform_2pts.cpp
index 78db622f2..ef2900775 100644
--- a/src/live_effects/lpe-transform_2pts.cpp
+++ b/src/live_effects/lpe-transform_2pts.cpp
@@ -20,6 +20,7 @@
// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
+
namespace Inkscape {
namespace LivePathEffect {
@@ -33,7 +34,7 @@ LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) :
flip_vertical(_("Flip vertical"), _("Flip vertical"), "flip_vertical", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")),
start(_("Start"), _("Start point"), "start", &wr, this, "Start point"),
end(_("End"), _("End point"), "end", &wr, this, "End point"),
- strech(_("Stretch"), _("Stretch the result"), "strech", &wr, this, 1),
+ stretch(_("Stretch"), _("Stretch the result"), "stretch", &wr, this, 1),
offset(_("Offset"), _("Offset from knots"), "offset", &wr, this, 0),
first_knot(_("First Knot"), _("First Knot"), "first_knot", &wr, this, 1),
last_knot(_("Last Knot"), _("Last Knot"), "last_knot", &wr, this, 1),
@@ -51,7 +52,7 @@ LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) :
registerParameter(&first_knot);
registerParameter(&last_knot);
registerParameter(&helper_size);
- registerParameter(&strech);
+ registerParameter(&stretch);
registerParameter(&offset);
registerParameter(&start);
registerParameter(&end);
@@ -72,9 +73,9 @@ LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) :
offset.param_set_range(-999999.0, 999999.0);
offset.param_set_increments(1, 1);
offset.param_set_digits(2);
- strech.param_set_range(0, 999.0);
- strech.param_set_increments(0.01, 0.01);
- strech.param_set_digits(4);
+ stretch.param_set_range(0, 999.0);
+ stretch.param_set_increments(0.01, 0.01);
+ stretch.param_set_digits(4);
apply_to_clippath_and_mask = true;
}
@@ -378,9 +379,9 @@ LPETransform2Pts::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const
m *= Geom::Scale(-1,1);
m *= Geom::Rotate(original_angle);
}
- if(strech != 1){
+ if(stretch != 1){
m *= Geom::Rotate(-original_angle);
- m *= Geom::Scale(1,strech);
+ m *= Geom::Scale(1,stretch);
m *= Geom::Rotate(original_angle);
}
if(elastic) {
diff --git a/src/live_effects/lpe-transform_2pts.h b/src/live_effects/lpe-transform_2pts.h
index c20d56206..0f88e6b00 100644
--- a/src/live_effects/lpe-transform_2pts.h
+++ b/src/live_effects/lpe-transform_2pts.h
@@ -57,7 +57,7 @@ private:
ToggleButtonParam flip_vertical;
PointParam start;
PointParam end;
- ScalarParam strech;
+ ScalarParam stretch;
ScalarParam offset;
ScalarParam first_knot;
ScalarParam last_knot;
diff --git a/src/live_effects/lpe-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp
index 2486f3366..47e2a1cec 100644
--- a/src/live_effects/lpe-vonkoch.cpp
+++ b/src/live_effects/lpe-vonkoch.cpp
@@ -5,7 +5,7 @@
*/
#include "live_effects/lpe-vonkoch.h"
-
+// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
//using std::vector;
diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp
index b321a5831..7696288b0 100644
--- a/src/live_effects/parameter/filletchamferpointarray.cpp
+++ b/src/live_effects/parameter/filletchamferpointarray.cpp
@@ -24,7 +24,6 @@
#include "selection.h"
// needed for on-canvas editting:
-#include "desktop.h"
#include "live_effects/lpeobject.h"
#include "helper/geom-nodetype.h"
#include "helper/geom-curves.h"
@@ -825,10 +824,7 @@ void FilletChamferPointArrayParamKnotHolderEntity::knot_set_offset(
this->parent_holder->knot_ungrabbed_handler(this->knot, 0);
}
-void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder,
- SPDesktop *desktop,
- SPItem *item)
-{
+void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item) {
recalculate_knots(get_pwd2());
for (unsigned int i = 0; i < _vector.size(); ++i) {
if (_vector[i][Y] <= 0) {
@@ -854,7 +850,7 @@ void FilletChamferPointArrayParam::addKnotHolderEntities(KnotHolder *knotholder,
}
FilletChamferPointArrayParamKnotHolderEntity *e =
new FilletChamferPointArrayParamKnotHolderEntity(this, i);
- e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),
+ e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _(tip),
knot_shape, knot_mode, knot_color);
knotholder->add(e);
}
diff --git a/src/live_effects/parameter/filletchamferpointarray.h b/src/live_effects/parameter/filletchamferpointarray.h
index 48cd26d2d..b81339a69 100644
--- a/src/live_effects/parameter/filletchamferpointarray.h
+++ b/src/live_effects/parameter/filletchamferpointarray.h
@@ -59,8 +59,7 @@ public:
return true;
}
virtual void updateCanvasIndicators();
- virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop,
- SPItem *item);
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_in,
Geom::Piecewise<Geom::D2<Geom::SBasis> > const &pwd2_normal_in);
diff --git a/src/live_effects/parameter/fontbutton.cpp b/src/live_effects/parameter/fontbutton.cpp
index ff8ab76a0..64c203093 100644
--- a/src/live_effects/parameter/fontbutton.cpp
+++ b/src/live_effects/parameter/fontbutton.cpp
@@ -4,7 +4,7 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
-
+#include <gtkmm.h>
#include "ui/widget/registered-widget.h"
#include "live_effects/parameter/fontbutton.h"
#include "live_effects/effect.h"
diff --git a/src/live_effects/parameter/fontbutton.h b/src/live_effects/parameter/fontbutton.h
index 387ad130b..df47251a2 100644
--- a/src/live_effects/parameter/fontbutton.h
+++ b/src/live_effects/parameter/fontbutton.h
@@ -8,7 +8,6 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
#include <glib.h>
-#include <gtkmm.h>
#include "live_effects/parameter/parameter.h"
namespace Inkscape {
diff --git a/src/live_effects/parameter/originalpath.cpp b/src/live_effects/parameter/originalpath.cpp
index 2741461be..f7eb48b7a 100644
--- a/src/live_effects/parameter/originalpath.cpp
+++ b/src/live_effects/parameter/originalpath.cpp
@@ -56,7 +56,7 @@ OriginalPathParam::param_newWidget()
}
{ // Paste path to link button
- Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-paste"), Inkscape::ICON_SIZE_BUTTON) );
+ Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon( INKSCAPE_ICON("edit-clone"), Inkscape::ICON_SIZE_BUTTON) );
Gtk::Button *pButton = Gtk::manage(new Gtk::Button());
pButton->set_relief(Gtk::RELIEF_NONE);
pIcon->show();
diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp
index 4ee068ebf..083abc94c 100644
--- a/src/live_effects/parameter/originalpatharray.cpp
+++ b/src/live_effects/parameter/originalpatharray.cpp
@@ -144,7 +144,7 @@ Gtk::Widget* OriginalPathArrayParam::param_newWidget()
{ // Paste path to link button
- Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon("gtk-stock", Inkscape::ICON_SIZE_BUTTON) );
+ Gtk::Widget *pIcon = Gtk::manage( sp_icon_get_icon("edit-clone", Inkscape::ICON_SIZE_BUTTON) );
Gtk::Button *pButton = Gtk::manage(new Gtk::Button());
pButton->set_relief(Gtk::RELIEF_NONE);
pIcon->show();
diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h
index 3658bded8..6cf10710c 100644
--- a/src/live_effects/parameter/parameter.h
+++ b/src/live_effects/parameter/parameter.h
@@ -68,7 +68,7 @@ public:
// overload these for your particular parameter to make it provide knotholder handles or canvas helperpaths
virtual bool providesKnotHolderEntities() const { return false; }
- virtual void addKnotHolderEntities(KnotHolder */*knotholder*/, SPDesktop */*desktop*/, SPItem */*item*/) {};
+ virtual void addKnotHolderEntities(KnotHolder */*knotholder*/, SPItem */*item*/) {};
virtual void addCanvasIndicators(SPLPEItem const*/*lpeitem*/, std::vector<Geom::PathVector> &/*hp_vec*/) {};
virtual void param_editOncanvas(SPItem * /*item*/, SPDesktop * /*dt*/) {};
@@ -118,6 +118,8 @@ public:
void param_set_digits(unsigned digits);
void param_set_increments(double step, double page);
void addSlider(bool add_slider_widget) { add_slider = add_slider_widget; };
+ double param_get_max() { return max; };
+ double param_get_min() { return min; };
void param_overwrite_widget(bool overwrite_widget);
virtual Gtk::Widget * param_newWidget();
diff --git a/src/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp
index 3442fd851..c87b1e299 100644
--- a/src/live_effects/parameter/point.cpp
+++ b/src/live_effects/parameter/point.cpp
@@ -15,9 +15,6 @@
#include "knotholder.h"
#include <glibmm/i18n.h>
-// needed for on-canvas editting:
-#include "desktop.h"
-
namespace Inkscape {
namespace LivePathEffect {
@@ -126,9 +123,8 @@ PointParam::param_newWidget()
*param_wr,
param_effect->getRepr(),
param_effect->getSPDoc() ) );
- // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP)
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
- Geom::Affine transf = desktop->doc2dt();
+ Geom::Affine transf = Geom::Scale(1, -1);
+ transf[5] = SP_ACTIVE_DOCUMENT->getHeight().value("px");
_pointwdg->setTransform(transf);
_pointwdg->setValue( *this );
_pointwdg->clearProgrammatically();
@@ -205,12 +201,12 @@ PointParamKnotHolderEntity::knot_click(guint state)
}
void
-PointParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+PointParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
knoth = knotholder;
PointParamKnotHolderEntity *e = new PointParamKnotHolderEntity(this);
// TODO: can we ditch handleTip() etc. because we have access to handle_tip etc. itself???
- e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color);
+ e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), knot_shape, knot_mode, knot_color);
knotholder->add(e);
}
diff --git a/src/live_effects/parameter/point.h b/src/live_effects/parameter/point.h
index 62c6fb83d..e8cb66225 100644
--- a/src/live_effects/parameter/point.h
+++ b/src/live_effects/parameter/point.h
@@ -49,7 +49,7 @@ public:
void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color);
virtual bool providesKnotHolderEntities() const { return true; }
- virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
friend class PointParamKnotHolderEntity;
private:
diff --git a/src/live_effects/parameter/powerstrokepointarray.cpp b/src/live_effects/parameter/powerstrokepointarray.cpp
index c61e8f9cb..7753d819d 100644
--- a/src/live_effects/parameter/powerstrokepointarray.cpp
+++ b/src/live_effects/parameter/powerstrokepointarray.cpp
@@ -248,11 +248,11 @@ PowerStrokePointArrayParamKnotHolderEntity::knot_click(guint state)
}
}
-void PowerStrokePointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+void PowerStrokePointArrayParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
for (unsigned int i = 0; i < _vector.size(); ++i) {
PowerStrokePointArrayParamKnotHolderEntity *e = new PowerStrokePointArrayParamKnotHolderEntity(this, i);
- e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
+ e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN,
_("<b>Stroke width control point</b>: drag to alter the stroke width. <b>Ctrl+click</b> adds a control point, <b>Ctrl+Alt+click</b> deletes it, <b>Shift+click</b> launches width dialog."),
knot_shape, knot_mode, knot_color);
knotholder->add(e);
diff --git a/src/live_effects/parameter/powerstrokepointarray.h b/src/live_effects/parameter/powerstrokepointarray.h
index 70b22e27e..56a609fa8 100644
--- a/src/live_effects/parameter/powerstrokepointarray.h
+++ b/src/live_effects/parameter/powerstrokepointarray.h
@@ -38,7 +38,7 @@ public:
float median_width();
virtual bool providesKnotHolderEntities() const { return true; }
- virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
void set_pwd2(Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in, Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_normal_in);
Geom::Piecewise<Geom::D2<Geom::SBasis> > const & get_pwd2() const { return last_pwd2; }
diff --git a/src/live_effects/parameter/text.cpp b/src/live_effects/parameter/text.cpp
index 0650b7e66..8cab68ad0 100644
--- a/src/live_effects/parameter/text.cpp
+++ b/src/live_effects/parameter/text.cpp
@@ -110,7 +110,10 @@ TextParam::param_readSVGValue(const gchar * strvalue)
gchar *
TextParam::param_getSVGValue() const
{
- return g_strdup(value.c_str());
+ Inkscape::SVGOStringStream os;
+ os << value;
+ gchar * str = g_strdup(os.str().c_str());
+ return str;
}
Gtk::Widget *
diff --git a/src/live_effects/parameter/vector.cpp b/src/live_effects/parameter/vector.cpp
index cfaa9e7e7..55b4d4b32 100644
--- a/src/live_effects/parameter/vector.cpp
+++ b/src/live_effects/parameter/vector.cpp
@@ -14,7 +14,6 @@
#include "svg/stringstream.h"
#include "live_effects/effect.h"
-#include "desktop.h"
#include "verbs.h"
namespace Inkscape {
@@ -117,7 +116,7 @@ VectorParam::set_and_write_new_values(Geom::Point const &new_origin, Geom::Point
void
VectorParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/)
{
- set_and_write_new_values( origin * postmul, vector * postmul.withoutTranslation() );
+ set_and_write_new_values( origin * postmul, vector * postmul.withoutTranslation() );
}
@@ -188,14 +187,14 @@ private:
};
void
-VectorParam::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+VectorParam::addKnotHolderEntities(KnotHolder *knotholder, SPItem *item)
{
VectorParamKnotHolderEntity_Origin *origin_e = new VectorParamKnotHolderEntity_Origin(this);
- origin_e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), ori_knot_shape, ori_knot_mode, ori_knot_color);
+ origin_e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), ori_knot_shape, ori_knot_mode, ori_knot_color);
knotholder->add(origin_e);
VectorParamKnotHolderEntity_Vector *vector_e = new VectorParamKnotHolderEntity_Vector(this);
- vector_e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), vec_knot_shape, vec_knot_mode, vec_knot_color);
+ vector_e->create(NULL, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, handleTip(), vec_knot_shape, vec_knot_mode, vec_knot_color);
knotholder->add(vector_e);
}
diff --git a/src/live_effects/parameter/vector.h b/src/live_effects/parameter/vector.h
index 35ca04437..edee4ff4d 100644
--- a/src/live_effects/parameter/vector.h
+++ b/src/live_effects/parameter/vector.h
@@ -53,7 +53,7 @@ public:
void set_oncanvas_color(guint32 color);
virtual bool providesKnotHolderEntities() const { return true; }
- virtual void addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item);
+ virtual void addKnotHolderEntities(KnotHolder *knotholder, SPItem *item);
private:
VectorParam(const VectorParam&);
diff --git a/src/main.cpp b/src/main.cpp
index 95764aea9..605c1207e 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -420,7 +420,7 @@ struct poptOption options[] = {
{"export-pdf-version", 0,
POPT_ARG_STRING, &sp_export_pdf_version, SP_ARG_EXPORT_PDF_VERSION,
// TRANSLATORS: "--export-pdf-version" is an Inkscape command line option; see "inkscape --help"
- N_("Export PDF to given version. (hint: make sure to input the exact string found in the PDF export dialog, e.g. \"PDF 1.4\" which is PDF-a conformant)"),
+ N_("Export PDF to given version. (hint: make sure to input a version found in the PDF export dialog, e.g. \"1.4\" which is PDF-a conformant)"),
N_("PDF_VERSION")},
{"export-latex", 0,
@@ -2159,7 +2159,7 @@ sp_process_args(poptContext ctx)
}
#endif // WITH_YAML
case SP_ARG_VERSION: {
- printf("Inkscape %s (%s)\n", Inkscape::version_string, __DATE__);
+ printf("Inkscape %s\n", Inkscape::version_string);
exit(0);
break;
}
diff --git a/src/object-set.h b/src/object-set.h
index 12f2cb101..7c224f640 100644
--- a/src/object-set.h
+++ b/src/object-set.h
@@ -33,6 +33,29 @@
#include "sp-item-group.h"
#include "desktop.h"
#include "document.h"
+#include "verbs.h"
+
+enum BoolOpErrors {
+ DONE,
+ DONE_NO_PATH,
+ DONE_NO_ACTION,
+ ERR_TOO_LESS_PATHS_1,
+ ERR_TOO_LESS_PATHS_2,
+ ERR_NO_PATHS,
+ ERR_Z_ORDER
+};
+
+// boolean operation
+enum bool_op
+{
+ bool_op_union, // A OR B
+ bool_op_inters, // A AND B
+ bool_op_diff, // A \ B
+ bool_op_symdiff, // A XOR B
+ bool_op_cut, // coupure (pleines)
+ bool_op_slice // coupure (contour)
+};
+typedef enum bool_op BooleanOp;
class SPBox3D;
class Persp3D;
@@ -376,7 +399,16 @@ public:
void toCurves(bool skip_undo = false);
void toLPEItems();
void pathReverse();
-
+
+ // Boolean operations
+ // in splivarot.cpp
+ bool pathUnion(const bool skip_undo = false);
+ bool pathIntersect(const bool skip_undo = false);
+ bool pathDiff(const bool skip_undo = false);
+ bool pathSymDiff(const bool skip_undo = false);
+ bool pathCut(const bool skip_undo = false);
+ bool pathSlice(const bool skip_undo = false);
+
//Other path operations
//in selection-chemistry.cpp
void toMarker(bool apply = true);
@@ -415,7 +447,7 @@ public:
// various
void getExportHints(Glib::ustring &filename, float *xdpi, float *ydpi);
bool fitCanvas(bool with_margins, bool skip_undo = false);
-
+ void swapFillStroke();
protected:
virtual void _connectSignals(SPObject* object) {};
@@ -438,6 +470,9 @@ protected:
std::list<SPBox3D *> _3dboxes;
std::unordered_map<SPObject*, sigc::connection> _releaseConnections;
+private:
+ BoolOpErrors pathBoolOp(bool_op bop, const bool skip_undo, const unsigned int verb = SP_VERB_NONE, const Glib::ustring description = "");
+
};
typedef ObjectSet::SPItemRange SPItemRange;
diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp
index a19ca9524..741f433f2 100644
--- a/src/path-chemistry.cpp
+++ b/src/path-chemistry.cpp
@@ -552,7 +552,8 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/)
return g_repr;
}
-
+
+ SP_LPE_ITEM(item)->removeAllPathEffects(true);
SPCurve *curve = NULL;
{
SPShape *shape = dynamic_cast<SPShape *>(item);
diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h
index 38196a58e..ed00092b2 100644
--- a/src/preferences-skeleton.h
+++ b/src/preferences-skeleton.h
@@ -74,8 +74,7 @@ static char const preferences_skeleton[] =
" </group>\n"
"\n"
" <group id=\"tools\"\n"
-" bounding_box=\"0\"\n"
-" style=\"fill:none;stroke:black;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;\">\n"
+" bounding_box=\"0\">\n"
" <group id=\"shapes\" style=\"fill-rule:evenodd;\" selcue=\"1\" gradientdrag=\"1\">\n"
" <eventcontext id=\"rect\" style=\"fill:blue;\" usecurrent=\"1\"/>\n"
" <eventcontext id=\"3dbox\" style=\"stroke:none;stroke-linejoin:round;\" usecurrent=\"1\">\n"
@@ -88,7 +87,7 @@ static char const preferences_skeleton[] =
" </eventcontext>\n"
" <eventcontext id=\"arc\" style=\"fill:red;\" end=\"0\" start=\"0\" usecurrent=\"1\"/>\n"
" <eventcontext id=\"star\" magnitude=\"5\" style=\"fill:yellow;\" usecurrent=\"1\"/>\n"
-" <eventcontext id=\"spiral\" style=\"fill:none;\" usecurrent=\"0\"/>\n"
+" <eventcontext id=\"spiral\" style=\"fill:none;stroke:black\" expansion=\"1\" usecurrent=\"0\"/>\n"
" </group>\n"
" <group id=\"freehand\"\n"
" style=\"fill:none;stroke:black;stroke-opacity:1;stroke-linejoin:miter;stroke-linecap:butt;\">\n"
@@ -140,6 +139,7 @@ static char const preferences_skeleton[] =
" <dash id=\"dash-1-12\" style=\"stroke-dasharray:1,12\"/>\n"
" <dash id=\"dash-1-24\" style=\"stroke-dasharray:1,24\"/>\n"
" <dash id=\"dash-1-48\" style=\"stroke-dasharray:1,48\"/>\n"
+" <dash id=\"dash-empty\" style=\"stroke-dasharray:0 11\"/>\n"
" <dash id=\"dash-2-1\" style=\"stroke-dasharray:2,1\"/>\n"
" <dash id=\"dash-3-1\" style=\"stroke-dasharray:3,1\"/>\n"
" <dash id=\"dash-4-1\" style=\"stroke-dasharray:4,1\"/>\n"
diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp
index f8ab33ac4..67972cabb 100644
--- a/src/selection-chemistry.cpp
+++ b/src/selection-chemistry.cpp
@@ -97,6 +97,7 @@ SPCycleType SP_CYCLING = SP_CYCLE_FOCUS;
#include "live_effects/parameter/originalpath.h"
#include "layer-manager.h"
#include "object-set.h"
+#include "svg/svg-color.h"
// For clippath editing
#include "ui/tools/node-tool.h"
@@ -1242,7 +1243,6 @@ void ObjectSet::pasteStyle()
}
}
-
void ObjectSet::pastePathEffect()
{
Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
@@ -4169,6 +4169,75 @@ bool ObjectSet::fitCanvas(bool with_margins, bool skip_undo)
}
}
+void ObjectSet::swapFillStroke()
+{
+ if (desktop() == NULL) {
+ return;
+ }
+
+ SPIPaint *paint;
+ SPPaintServer *server;
+ Glib::ustring _paintserver_id;
+
+ auto list= items();
+ for (auto itemlist=list.begin();itemlist!=list.end();++itemlist) {
+ SPItem *item = *itemlist;
+
+ SPCSSAttr *css = sp_repr_css_attr_new ();
+
+ _paintserver_id.clear();
+ paint = &(item->style->fill);
+ if (paint->set && paint->isNone())
+ sp_repr_css_set_property (css, "stroke", "none");
+ else if (paint->set && paint->isColor()) {
+ guint32 color = paint->value.color.toRGBA32(SP_SCALE24_TO_FLOAT (item->style->fill_opacity.value));
+ gchar c[64];
+ sp_svg_write_color (c, sizeof(c), color);
+ sp_repr_css_set_property (css, "stroke", c);
+ }
+ else if (!paint->set)
+ sp_repr_css_unset_property (css, "stroke");
+ else if (paint->set && paint->isPaintserver()) {
+ server = SP_STYLE_FILL_SERVER(item->style);
+ if (server) {
+ Inkscape::XML::Node *srepr = server->getRepr();
+ _paintserver_id += "url(#";
+ _paintserver_id += srepr->attribute("id");
+ _paintserver_id += ")";
+ sp_repr_css_set_property (css, "stroke", _paintserver_id.c_str());
+ }
+ }
+
+ _paintserver_id.clear();
+ paint = &(item->style->stroke);
+ if (paint->set && paint->isNone())
+ sp_repr_css_set_property (css, "fill", "none");
+ else if (paint->set && paint->isColor()) {
+ guint32 color = paint->value.color.toRGBA32(SP_SCALE24_TO_FLOAT (item->style->stroke_opacity.value));
+ gchar c[64];
+ sp_svg_write_color (c, sizeof(c), color);
+ sp_repr_css_set_property (css, "fill", c);
+ }
+ else if (!paint->set)
+ sp_repr_css_unset_property (css, "fill");
+ else if (paint->set && paint->isPaintserver()) {
+ server = SP_STYLE_STROKE_SERVER(item->style);
+ if (server) {
+ Inkscape::XML::Node *srepr = server->getRepr();
+ _paintserver_id += "url(#";
+ _paintserver_id += srepr->attribute("id");
+ _paintserver_id += ")";
+ sp_repr_css_set_property (css, "fill", _paintserver_id.c_str());
+ }
+ }
+
+ sp_desktop_apply_css_recursive(item, css, true);
+ sp_repr_css_attr_unref (css);
+ }
+
+ DocumentUndo::done(document(), SP_VERB_EDIT_SWAP_FILL_STROKE,
+ _("Swap fill and stroke of an object"));
+}
/**
* \param with_margins margins defined in the xml under <sodipodi:namedview>
diff --git a/src/sp-ellipse.cpp b/src/sp-ellipse.cpp
index 0d60aa5d8..ed1e2b504 100644
--- a/src/sp-ellipse.cpp
+++ b/src/sp-ellipse.cpp
@@ -32,11 +32,12 @@
#include "svg/svg.h"
#include "svg/path-string.h"
+#define SP_2PI (2 * M_PI)
SPGenericEllipse::SPGenericEllipse()
: SPShape()
, start(0)
- , end(M_2_PI)
+ , end(SP_2PI)
, type(SP_GENERIC_ELLIPSE_UNDEFINED)
, _closed(true)
{
@@ -527,7 +528,7 @@ void SPGenericEllipse::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p,
// Snap to the 4 quadrant points of the ellipse, but only if the arc
// spans far enough to include them
if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_ELLIPSE_QUADRANT_POINT)) {
- for (double angle = 0; angle < M_2_PI; angle += M_PI_2) {
+ for (double angle = 0; angle < SP_2PI; angle += M_PI_2) {
if (Geom::AngleInterval(this->start, this->end, true).contains(angle)) {
Geom::Point pt = this->getPointAtAngle(angle) * i2dt;
p.push_back(Inkscape::SnapCandidatePoint(pt, Inkscape::SNAPSOURCE_ELLIPSE_QUADRANT_POINT, Inkscape::SNAPTARGET_ELLIPSE_QUADRANT_POINT));
@@ -662,7 +663,7 @@ bool SPGenericEllipse::_isSlice() const
{
Geom::AngleInterval a(this->start, this->end, true);
- return !(Geom::are_near(a.extent(), 0) || Geom::are_near(a.extent(), M_2_PI));
+ return !(Geom::are_near(a.extent(), 0) || Geom::are_near(a.extent(), SP_2PI));
}
/*
diff --git a/src/sp-gradient.cpp b/src/sp-gradient.cpp
index 746c7fa41..f02149cbb 100644
--- a/src/sp-gradient.cpp
+++ b/src/sp-gradient.cpp
@@ -820,6 +820,9 @@ has_units_set(SPGradient const *gr)
SPGradient *SPGradient::getVector(bool force_vector)
{
SPGradient * src = chase_hrefs(this, has_stopsFN);
+ if (src == NULL) {
+ src = this;
+ }
if (force_vector) {
src = sp_gradient_ensure_vector_normalized(src);
@@ -830,10 +833,9 @@ SPGradient *SPGradient::getVector(bool force_vector)
SPGradient *SPGradient::getArray(bool force_vector)
{
SPGradient * src = chase_hrefs(this, has_patchesFN);
-
- // if (force_vector) {
- // src = sp_gradient_ensure_vector_normalized(src);
- // }
+ if (src == NULL) {
+ src = this;
+ }
return src;
}
diff --git a/src/sp-image.cpp b/src/sp-image.cpp
index aa1dbfe20..1961971cb 100644
--- a/src/sp-image.cpp
+++ b/src/sp-image.cpp
@@ -793,7 +793,7 @@ void sp_image_refresh_if_outdated( SPImage* image )
if ( image->href && image->pixbuf && image->pixbuf->modificationTime()) {
// It *might* change
- struct stat st;
+ GStatBuf st;
memset(&st, 0, sizeof(st));
int val = 0;
if (g_file_test (image->pixbuf->originalPath().c_str(), G_FILE_TEST_EXISTS)){
diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp
index 96dcdbe30..7b2507b5e 100644
--- a/src/sp-item-group.cpp
+++ b/src/sp-item-group.cpp
@@ -584,12 +584,13 @@ sp_item_group_ungroup (SPGroup *group, std::vector<SPItem*> &children, bool do_d
SPText * text = dynamic_cast<SPText *>(citem);
if (text) {
//this causes a change in text-on-path appearance when there is a non-conformal transform, see bug #1594565
- double scale = (ctrans.expansionX() + ctrans.expansionY()) / 2.0;
SPTextPath * text_path = dynamic_cast<SPTextPath *>(text->firstChild());
if (!text_path) {
nrepr->setAttribute("transform", affinestr);
} else {
- sp_recursive_scale_text_size(nrepr, scale);
+ // The following breaks roundtripping group -> ungroup
+ // double scale = (ctrans.expansionX() + ctrans.expansionY()) / 2.0;
+ // sp_recursive_scale_text_size(nrepr, scale);
Geom::Affine ttrans = ctrans.inverse() * SP_ITEM(text)->transform * ctrans;
gchar *affinestr = sp_svg_transform_write(ttrans);
nrepr->setAttribute("transform", affinestr);
diff --git a/src/sp-item.cpp b/src/sp-item.cpp
index 36a9c3c9d..5d02020c6 100644
--- a/src/sp-item.cpp
+++ b/src/sp-item.cpp
@@ -121,6 +121,7 @@ void SPItem::setLocked(bool locked) {
setAttribute("sodipodi:insensitive",
( locked ? "1" : NULL ));
updateRepr();
+ document->_emitModified();
}
bool SPItem::isHidden() const {
@@ -667,7 +668,7 @@ void SPItem::update(SPCtx* ctx, guint flags) {
if (flags & SP_OBJECT_STYLE_MODIFIED_FLAG) {
for (SPItemView *v = display; v != NULL; v = v->next) {
v->arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(style->opacity.value));
- v->arenaitem->setAntialiasing(style->shape_rendering.computed != SP_CSS_SHAPE_RENDERING_CRISPEDGES);
+ v->arenaitem->setAntialiasing(style->shape_rendering.computed == SP_CSS_SHAPE_RENDERING_CRISPEDGES ? 0 : 2);
v->arenaitem->setIsolation( style->isolation.value );
v->arenaitem->setBlendMode( style->mix_blend_mode.value );
v->arenaitem->setVisible(!isHidden());
diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp
index 8f0713652..e2f61bfb5 100644
--- a/src/sp-lpe-item.cpp
+++ b/src/sp-lpe-item.cpp
@@ -125,7 +125,8 @@ void SPLPEItem::set(unsigned int key, gchar const* value) {
{
if (!value) {
LivePathEffectObject *lpeobj = (*it)->lpeobject;
- if (Inkscape::LivePathEffect::LPEMeasureLine * lpe = dynamic_cast<Inkscape::LivePathEffect::LPEMeasureLine *>(lpeobj->get_lpe())) {
+ Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe();
+ if (dynamic_cast<Inkscape::LivePathEffect::LPEMeasureLine *>(lpe)){
lpe->doOnRemove(this);
}
}
@@ -289,22 +290,6 @@ sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write)
if (!lpeitem->pathEffectsEnabled())
return;
- // TODO: hack! this will be removed when path length measuring is reimplemented in a better way
- PathEffectList lpelist = lpeitem->getEffectList();
- std::list<Inkscape::LivePathEffect::LPEObjectReference *>::iterator i;
- for (i = lpelist.begin(); i != lpelist.end(); ++i) {
- if ((*i)->lpeobject) {
- Inkscape::LivePathEffect::Effect *lpe = (*i)->lpeobject->get_lpe();
- if (dynamic_cast<Inkscape::LivePathEffect::LPEPathLength *>(lpe)) {
- if (!lpe->isVisible()) {
- // we manually disable text for LPEPathLength
- // use static_cast, because we already checked for the right type above
- static_cast<Inkscape::LivePathEffect::LPEPathLength *>(lpe)->hideCanvasText();
- }
- }
- }
- }
-
SPLPEItem *top = NULL;
if (wholetree) {
@@ -514,6 +499,21 @@ void SPLPEItem::removeCurrentPathEffect(bool keep_paths)
*/
void SPLPEItem::removeAllPathEffects(bool keep_paths)
{
+ if (keep_paths) {
+ if (path_effect_list->empty()) {
+ return;
+ }
+
+ for (PathEffectList::const_iterator it = path_effect_list->begin(); it != path_effect_list->end(); ++it)
+ {
+ LivePathEffectObject *lpeobj = (*it)->lpeobject;
+ if (lpeobj) {
+ Inkscape::LivePathEffect::Effect * lpe = lpeobj->get_lpe();
+ lpe->erase_extra_objects = false;
+ }
+ }
+ }
+
this->getRepr()->setAttribute("inkscape:path-effect", NULL);
if (!keep_paths) {
diff --git a/src/sp-mesh-array.cpp b/src/sp-mesh-array.cpp
index 208dac2bc..f192d0e44 100644
--- a/src/sp-mesh-array.cpp
+++ b/src/sp-mesh-array.cpp
@@ -38,6 +38,7 @@
*/
#include <glibmm.h>
+#include <set>
// For color picking
#include "display/drawing.h"
@@ -1057,10 +1058,10 @@ void SPMeshNodeArray::write( SPMeshGradient *mg ) {
break;
case 'z':
case 'Z':
- std::cout << "SPMeshNodeArray::write(): bad path type" << path_type << std::endl;
+ std::cerr << "SPMeshNodeArray::write(): bad path type" << path_type << std::endl;
break;
default:
- std::cout << "SPMeshNodeArray::write(): unhandled path type" << path_type << std::endl;
+ std::cerr << "SPMeshNodeArray::write(): unhandled path type" << path_type << std::endl;
}
stop->setAttribute("path", is.str().c_str());
// std::cout << "SPMeshNodeArray::write: path: " << is.str().c_str() << std::endl;
@@ -1120,11 +1121,11 @@ void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bb
if( !bbox ) {
// Set default size to bounding box if size not given.
- std::cout << "SPMeshNodeArray::create(): bbox empty" << std::endl;
+ std::cerr << "SPMeshNodeArray::create(): bbox empty" << std::endl;
bbox = item->geometricBounds();
if( !bbox ) {
- std::cout << "SPMeshNodeArray::create: ERROR: No bounding box!" << std::endl;
+ std::cerr << "SPMeshNodeArray::create: ERROR: No bounding box!" << std::endl;
return;
}
}
@@ -1151,7 +1152,14 @@ void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bb
// Get default color
SPColor color = default_color( item );
-
+
+ // Set some corners to white so we can see the mesh.
+ SPColor white( 1.0, 1.0, 1.0 );
+ if (color == white) {
+ // If default color is white, set other color to black.
+ white = SPColor( 0.0, 0.0, 0.0 );
+ }
+
// Get preferences
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
guint prows = prefs->getInt("/tools/mesh/mesh_rows", 1);
@@ -1190,6 +1198,9 @@ void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bb
ry = arc->ry.computed;
start = arc->start;
end = arc->end;
+ if( end <= start ) {
+ end += 2.0 * M_PI;
+ }
}
// std::cout << " start: " << start << " end: " << end << std::endl;
@@ -1236,7 +1247,7 @@ void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bb
for( guint k = 0; k < 4; ++k ) {
patch.setPathType( k, 'l' );
- patch.setColor( k, color );
+ patch.setColor( k, (i+k)%2 ? color : white );
patch.setOpacity( k, 1.0 );
}
patch.setPathType( 0, 'c' );
@@ -1293,7 +1304,7 @@ void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bb
patch.setPathType( i, 'c' );
- patch.setColor( i, color );
+ patch.setColor( i, i%2 ? color : white );
patch.setOpacity( i, 1.0 );
}
@@ -1334,7 +1345,7 @@ void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bb
for( guint s = 0; s < 4; ++s ) {
patch.setPathType( s, 'l' );
- patch.setColor( s, color );
+ patch.setColor( s, (i+s)%2 ? color : white );
patch.setOpacity( s, 1.0 );
}
@@ -1362,10 +1373,10 @@ void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bb
for( guint s = 0; s < 4; ++s ) {
patch0.setPathType( s, 'l' );
- patch0.setColor( s, color );
+ patch0.setColor( s, s%2 ? color : white );
patch0.setOpacity( s, 1.0 );
patch1.setPathType( s, 'l' );
- patch1.setColor( s, color );
+ patch1.setColor( s, s%2 ? white : color );
patch1.setOpacity( s, 1.0 );
}
@@ -1415,7 +1426,7 @@ void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bb
// Corner
node->node_type = MG_NODE_TYPE_CORNER;
node->set = true;
- node->color = color;
+ node->color = (i+j)%2 ? color : white;
node->opacity = 1.0;
} else {
@@ -1467,11 +1478,8 @@ void SPMeshNodeArray::clear() {
delete nodes[i][j];
}
}
- for( guint i = 0; i < nodes.size(); ++i ) {
- nodes[i].clear();
- }
- nodes.clear();
}
+ nodes.clear();
};
@@ -2018,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':
@@ -2044,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;
}
}
}
@@ -2415,11 +2423,74 @@ guint SPMeshNodeArray::color_pick( std::vector<guint> icorners, SPItem* item ) {
}
/**
+ Splits selected rows and/or columns in half (according to the path 't' parameter).
+ Input is a list of selected corner draggable indices.
+*/
+guint SPMeshNodeArray::insert( std::vector<guint> corners ) {
+
+ guint inserted = 0;
+
+ if( corners.size() < 2 ) return 0;
+
+ std::set<guint> columns;
+ std::set<guint> rows;
+
+ for( guint i = 0; i < corners.size()-1; ++i ) {
+ for( guint j = i+1; j < corners.size(); ++j ) {
+
+ // This works as all corners have indices and they
+ // are numbered in order by row and column (and
+ // the node array is rectangular).
+
+ guint c1 = corners[i];
+ guint c2 = corners[j];
+ if (c2 < c1) {
+ c1 = corners[j];
+ c2 = corners[i];
+ }
+
+ // Number of corners in a row of patches.
+ guint ncorners = patch_columns() + 1;
+
+ guint crow1 = c1 / ncorners;
+ guint crow2 = c2 / ncorners;
+ guint ccol1 = c1 % ncorners;
+ guint ccol2 = c2 % ncorners;
+
+ // Check for horizontal neighbors
+ if ( crow1 == crow2 && (ccol2 - ccol1) == 1 ) {
+ columns.insert( ccol1 );
+ }
+
+ // Check for vertical neighbors
+ if ( ccol1 == ccol2 && (crow2 - crow1) == 1 ) {
+ rows.insert( crow1 );
+ }
+ }
+ }
+
+ // Iterate backwards so column/row numbers are not invalidated.
+ std::set<guint>::reverse_iterator rit;
+ for (rit=columns.rbegin(); rit != columns.rend(); ++rit) {
+ split_column( *rit, 0.5);
+ ++inserted;
+ }
+ for (rit=rows.rbegin(); rit != rows.rend(); ++rit) {
+ split_row( *rit, 0.5);
+ ++inserted;
+ }
+
+ if( inserted > 0 ) built = false;
+ return inserted;
+}
+
+/**
Moves handles in response to a corner node move.
p_old: orignal position of moved corner node.
corner: the corner node moved (draggable index, i.e. point_i).
selected: list of all corners selected (draggable indices).
op: how other corners should be moved.
+ Corner node must already have been moved!
*/
void SPMeshNodeArray::update_handles( guint corner, std::vector< guint > /*selected*/, Geom::Point p_old, MeshNodeOperation /*op*/ )
{
@@ -2704,6 +2775,11 @@ SPCurve * SPMeshNodeArray::outline_path() {
SPCurve *outline = new SPCurve();
+ if (nodes.empty() ) {
+ std::cerr << "SPMeshNodeArray::outline_path: empty array!" << std::endl;
+ return outline;
+ }
+
outline->moveto( nodes[0][0]->p );
int ncol = nodes[0].size();
@@ -2720,7 +2796,7 @@ SPCurve * SPMeshNodeArray::outline_path() {
}
// Bottom (right to left)
- for (int i = 1; i < nrow; i += 3 ) {
+ for (int i = 1; i < ncol; i += 3 ) {
outline->curveto( nodes[nrow-1][ncol-i-1]->p, nodes[nrow-1][ncol-i-2]->p, nodes[nrow-1][ncol-i-3]->p);
}
@@ -2743,6 +2819,43 @@ void SPMeshNodeArray::transform(Geom::Affine const &m) {
}
}
+// Transform mesh to fill box. Return true if mesh transformed.
+bool SPMeshNodeArray::fill_box(Geom::OptRect &box) {
+
+ // If gradientTransfor is set (as happens when an object is transformed
+ // with the "optimized" preferences set true), we need to remove it.
+ if (mg->gradientTransform_set) {
+ Geom::Affine gt = mg->gradientTransform;
+ transform( gt );
+ mg->gradientTransform_set = false;
+ mg->gradientTransform.setIdentity();
+ }
+
+ SPCurve *outline = outline_path();
+ Geom::OptRect mesh_bbox = outline->get_pathvector().boundsExact();
+ outline->unref();
+
+ if ((*mesh_bbox).width() == 0 || (*mesh_bbox).height() == 0) {
+ return false;
+ }
+
+ double scale_x = (*box).width() /(*mesh_bbox).width() ;
+ double scale_y = (*box).height()/(*mesh_bbox).height();
+
+ Geom::Translate t1(-(*mesh_bbox).min());
+ Geom::Scale scale(scale_x,scale_y);
+ Geom::Translate t2((*box).min());
+ Geom::Affine trans = t1 * scale * t2;
+ if (!trans.isIdentity() ) {
+ transform(trans);
+ write( mg );
+ mg->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ return true;
+ }
+
+ return false;
+}
+
// Defined in gradient-chemistry.cpp
guint32 average_color(guint32 c1, guint32 c2, gdouble p);
diff --git a/src/sp-mesh-array.h b/src/sp-mesh-array.h
index 2ba1bfd5d..df43638db 100644
--- a/src/sp-mesh-array.h
+++ b/src/sp-mesh-array.h
@@ -76,7 +76,8 @@ enum MeshCornerOperation {
MG_CORNER_SIDE_ARC,
MG_CORNER_TENSOR_TOGGLE,
MG_CORNER_COLOR_SMOOTH,
- MG_CORNER_COLOR_PICK
+ MG_CORNER_COLOR_PICK,
+ MG_CORNER_INSERT
};
enum MeshNodeOperation {
@@ -192,6 +193,7 @@ public:
unsigned int tensor_toggle( std::vector< unsigned int > );
unsigned int color_smooth( std::vector< unsigned int > );
unsigned int color_pick( std::vector< unsigned int >, SPItem* );
+ unsigned int insert( std::vector< unsigned int > );
// Update other nodes in response to a node move.
void update_handles( unsigned int corner, std::vector< unsigned int > selected_corners, Geom::Point old_p, MeshNodeOperation op );
@@ -202,6 +204,9 @@ public:
// Transform array
void transform(Geom::Affine const &m);
+ // Transform mesh to fill box. Return true if not identity transform.
+ bool fill_box(Geom::OptRect &box);
+
// Find bounding box
// Geom::OptRect findBoundingBox();
diff --git a/src/sp-object.cpp b/src/sp-object.cpp
index e9c60fc7d..75f4657ef 100644
--- a/src/sp-object.cpp
+++ b/src/sp-object.cpp
@@ -660,7 +660,9 @@ void SPObject::build(SPDocument *document, Inkscape::XML::Node *repr) {
object->readAttr("xml:space");
object->readAttr("inkscape:label");
object->readAttr("inkscape:collect");
- if(object->cloned)
+ if(object->cloned && (repr->attribute("id")) ) // The cases where this happens are when the "original" has no id. This happens
+ // if it is a SPString (a TextNode, e.g. in a <title>), or when importing
+ // stuff externally modified to have no id.
object->clone_original = document->getObjectById(repr->attribute("id"));
for (Inkscape::XML::Node *rchild = repr->firstChild() ; rchild != NULL; rchild = rchild->next()) {
diff --git a/src/sp-path.cpp b/src/sp-path.cpp
index a7119dd31..b593b7937 100644
--- a/src/sp-path.cpp
+++ b/src/sp-path.cpp
@@ -187,35 +187,35 @@ void SPPath::release() {
void SPPath::set(unsigned int key, const gchar* value) {
switch (key) {
case SP_ATTR_INKSCAPE_ORIGINAL_D:
- if (value) {
- Geom::PathVector pv = sp_svg_read_pathv(value);
- SPCurve *curve = new SPCurve(pv);
-
- if (curve) {
- this->set_original_curve(curve, TRUE, true);
- curve->unref();
- }
- } else {
- this->set_original_curve(NULL, TRUE, true);
- }
-
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ if (value) {
+ Geom::PathVector pv = sp_svg_read_pathv(value);
+ SPCurve *curve = new SPCurve(pv);
+
+ if (curve) {
+ this->set_original_curve(curve, TRUE, true);
+ curve->unref();
+ }
+ } else {
+ this->set_original_curve(NULL, TRUE, true);
+ }
+
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_ATTR_D:
- if (value) {
- Geom::PathVector pv = sp_svg_read_pathv(value);
- SPCurve *curve = new SPCurve(pv);
-
- if (curve) {
- this->setCurve(curve, TRUE);
- curve->unref();
- }
- } else {
- this->setCurve(NULL, TRUE);
- }
-
- this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ if (value) {
+ Geom::PathVector pv = sp_svg_read_pathv(value);
+ SPCurve *curve = new SPCurve(pv);
+
+ if (curve) {
+ this->setCurve(curve, TRUE);
+ curve->unref();
+ }
+ } else {
+ this->setCurve(NULL, TRUE);
+ }
+
+ this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_PROP_MARKER:
@@ -276,13 +276,13 @@ g_message("sp_path_write writes 'd' attribute");
}
void SPPath::update(SPCtx *ctx, guint flags) {
- if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
- flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore
- }
+ if (flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) {
+ flags &= ~SP_OBJECT_USER_MODIFIED_FLAG_B; // since we change the description, it's not a "just translation" anymore
+ }
- SPShape::update(ctx, flags);
+ SPShape::update(ctx, flags);
- this->connEndPair.update();
+ this->connEndPair.update();
}
Geom::Affine SPPath::set_transform(Geom::Affine const &transform) {
diff --git a/src/splivarot.cpp b/src/splivarot.cpp
index 6b9fd5f83..531a48e44 100644
--- a/src/splivarot.cpp
+++ b/src/splivarot.cpp
@@ -47,96 +47,51 @@
#include "verbs.h"
#include "2geom/svg-path-parser.h" // to get from SVG on boolean to Geom::Path
-enum BoolOpErrors {
- DONE,
- DONE_NO_PATH,
- DONE_NO_ACTION,
- ERR_TOO_LESS_PATHS_1,
- ERR_TOO_LESS_PATHS_2,
- ERR_NO_PATHS,
- ERR_Z_ORDER
-};
-
using Inkscape::DocumentUndo;
bool Ancetre(Inkscape::XML::Node *a, Inkscape::XML::Node *who);
-void sp_selected_path_boolop_ui(Inkscape::Selection *selection, SPDesktop *desktop, bool_op bop,
- const unsigned int verb = SP_VERB_NONE, const Glib::ustring description = "");
-BoolOpErrors sp_selected_path_boolop(Inkscape::ObjectSet *set, bool_op bop);
void sp_selected_path_do_offset(SPDesktop *desktop, bool expand, double prefOffset);
void sp_selected_path_create_offset_object(SPDesktop *desktop, int expand, bool updating);
-void
-sp_selected_path_union(Inkscape::Selection *selection, SPDesktop *desktop)
-{
- sp_selected_path_boolop_ui(selection, desktop, bool_op_union, SP_VERB_SELECTION_UNION, _("Union"));
-}
-
-void
-sp_selected_path_union_skip_undo(Inkscape::ObjectSet *set)
-{
- sp_selected_path_boolop(set, bool_op_union);
-}
-
-void
-sp_selected_path_intersect(Inkscape::Selection *selection, SPDesktop *desktop)
-{
- sp_selected_path_boolop_ui(selection, desktop, bool_op_inters, SP_VERB_SELECTION_INTERSECT, _("Intersection"));
-}
-
-void
-sp_selected_path_intersect_skip_undo(Inkscape::ObjectSet *set)
-{
- sp_selected_path_boolop(set, bool_op_inters);
-}
-
-void
-sp_selected_path_diff(Inkscape::Selection *selection, SPDesktop *desktop)
-{
- sp_selected_path_boolop_ui(selection, desktop, bool_op_diff, SP_VERB_SELECTION_DIFF, _("Difference"));
-}
-
-void
-sp_selected_path_diff_skip_undo(Inkscape::ObjectSet *set)
-{
- sp_selected_path_boolop(set, bool_op_diff);
+bool Inkscape::ObjectSet::pathUnion(const bool skip_undo) {
+ BoolOpErrors result = pathBoolOp(bool_op_union, skip_undo, SP_VERB_SELECTION_UNION, _("Union"));
+ return DONE == result;
}
-void
-sp_selected_path_symdiff(Inkscape::Selection *selection, SPDesktop *desktop)
-{
- sp_selected_path_boolop_ui(selection, desktop, bool_op_symdiff, SP_VERB_SELECTION_SYMDIFF, _("Exclusion"));
-}
-
-void
-sp_selected_path_symdiff_skip_undo(Inkscape::ObjectSet *set)
+bool
+Inkscape::ObjectSet::pathIntersect(const bool skip_undo)
{
- sp_selected_path_boolop(set, bool_op_symdiff);
+ BoolOpErrors result = pathBoolOp(bool_op_inters, skip_undo, SP_VERB_SELECTION_INTERSECT, _("Intersection"));
+ return DONE == result;
}
-void
-sp_selected_path_cut(Inkscape::Selection *selection, SPDesktop *desktop)
+bool
+Inkscape::ObjectSet::pathDiff(const bool skip_undo)
{
- sp_selected_path_boolop_ui(selection, desktop, bool_op_cut, SP_VERB_SELECTION_CUT, _("Division"));
+ BoolOpErrors result = pathBoolOp(bool_op_diff, skip_undo, SP_VERB_SELECTION_DIFF, _("Difference"));
+ return DONE == result;
}
-void
-sp_selected_path_cut_skip_undo(Inkscape::ObjectSet *set)
+bool
+Inkscape::ObjectSet::pathSymDiff(const bool skip_undo)
{
- sp_selected_path_boolop(set, bool_op_cut);
+ BoolOpErrors result = pathBoolOp(bool_op_symdiff, skip_undo, SP_VERB_SELECTION_SYMDIFF, _("Exclusion"));
+ return DONE == result;
}
-void
-sp_selected_path_slice(Inkscape::Selection *selection, SPDesktop *desktop)
+bool
+Inkscape::ObjectSet::pathCut(const bool skip_undo)
{
- sp_selected_path_boolop_ui(selection, desktop, bool_op_slice, SP_VERB_SELECTION_SLICE, _("Cut path"));
+ BoolOpErrors result = pathBoolOp(bool_op_cut, skip_undo, SP_VERB_SELECTION_CUT, _("Division"));
+ return DONE == result;
}
-void
-sp_selected_path_slice_skip_undo(Inkscape::ObjectSet *set)
+bool
+Inkscape::ObjectSet::pathSlice(const bool skip_undo)
{
- sp_selected_path_boolop(set, bool_op_slice);
+ BoolOpErrors result = pathBoolOp(bool_op_slice, skip_undo, SP_VERB_SELECTION_SLICE, _("Cut path"));
+ return DONE == result;
}
// helper for printing error messages, regardless of whether we have a GUI or not
@@ -352,10 +307,36 @@ Geom::PathVector pathliv_to_pathvector(Path *pathliv){
// boolean operations on the desktop
// take the source paths from the file, do the operation, delete the originals and add the results
-BoolOpErrors sp_selected_path_boolop(Inkscape::ObjectSet * set, bool_op bop)
+BoolOpErrors Inkscape::ObjectSet::pathBoolOp(bool_op bop, const bool skip_undo, const unsigned int verb, const Glib::ustring description)
{
- SPDocument *doc = set->desktop()->getDocument();
- std::vector<SPItem*> il(set->items().begin(), set->items().end());
+ if (nullptr != desktop() && !skip_undo) {
+ SPDocument *doc = desktop()->getDocument();
+ BoolOpErrors returnCode = ObjectSet::pathBoolOp(bop, true);
+ switch(returnCode) {
+ case ERR_TOO_LESS_PATHS_1:
+ boolop_display_error_message(desktop(), _("Select <b>at least 1 path</b> to perform a boolean union."));
+ break;
+ case ERR_TOO_LESS_PATHS_2:
+ boolop_display_error_message(desktop(), _("Select <b>at least 2 paths</b> to perform a boolean operation."));
+ break;
+ case ERR_NO_PATHS:
+ boolop_display_error_message(desktop(), _("One of the objects is <b>not a path</b>, cannot perform boolean operation."));
+ break;
+ case ERR_Z_ORDER:
+ boolop_display_error_message(desktop(), _("Unable to determine the <b>z-order</b> of the objects selected for difference, XOR, division, or path cut."));
+ break;
+ case DONE_NO_PATH:
+ DocumentUndo::done(doc, SP_VERB_NONE, description);
+ break;
+ case DONE:
+ DocumentUndo::done(doc, verb, description);
+ break;
+ }
+ return returnCode;
+ }
+
+ SPDocument *doc = document();
+ std::vector<SPItem*> il(items().begin(), items().end());
// allow union on a single object for the purpose of removing self overlapse (svn log, revision 13334)
if (il.size() < 2 && bop != bool_op_union) {
@@ -687,7 +668,7 @@ BoolOpErrors sp_selected_path_boolop(Inkscape::ObjectSet * set, bool_op bop)
for (std::vector<SPItem*>::const_iterator l = il.begin(); l != il.end(); l++){
(*l)->deleteObject();
}
- set->clear();
+ clear();
delete res;
return DONE_NO_PATH;
@@ -703,7 +684,7 @@ BoolOpErrors sp_selected_path_boolop(Inkscape::ObjectSet * set, bool_op bop)
}
} else {
// find out the bottom object
- std::vector<Inkscape::XML::Node*> sorted(set->xmlNodes().begin(), set->xmlNodes().end());
+ std::vector<Inkscape::XML::Node*> sorted(xmlNodes().begin(), xmlNodes().end());
sort(sorted.begin(),sorted.end(),sp_repr_compare_position_bool);
@@ -731,7 +712,7 @@ BoolOpErrors sp_selected_path_boolop(Inkscape::ObjectSet * set, bool_op bop)
gchar *title = source->title();
gchar *desc = source->desc();
// remove source paths
- set->clear();
+ clear();
for (std::vector<SPItem*>::const_iterator l = il.begin(); l != il.end(); l++){
// if this is the bottommost object,
if (!strcmp(reinterpret_cast<SPObject *>(*l)->getRepr()->attribute("id"), id)) {
@@ -810,7 +791,7 @@ BoolOpErrors sp_selected_path_boolop(Inkscape::ObjectSet * set, bool_op bop)
// move to the saved position
repr->setPosition(pos > 0 ? pos : 0);
- set->add(doc->getObjectByRepr(repr));
+ add(doc->getObjectByRepr(repr));
Inkscape::GC::release(repr);
delete resPath[i];
@@ -845,7 +826,7 @@ BoolOpErrors sp_selected_path_boolop(Inkscape::ObjectSet * set, bool_op bop)
}
repr->setPosition(pos > 0 ? pos : 0);
- set->add(doc->getObjectByRepr(repr));
+ add(doc->getObjectByRepr(repr));
Inkscape::GC::release(repr);
}
@@ -858,36 +839,6 @@ BoolOpErrors sp_selected_path_boolop(Inkscape::ObjectSet * set, bool_op bop)
return DONE;
}
-void sp_selected_path_boolop_ui(Inkscape::Selection *selection, SPDesktop *desktop, bool_op bop, const unsigned int verb,
- const Glib::ustring description)
-{
- SPDocument *doc = selection->desktop()->getDocument();
- BoolOpErrors returnCode = sp_selected_path_boolop(selection, bop);
- switch(returnCode) {
- case ERR_TOO_LESS_PATHS_1:
- boolop_display_error_message(desktop, _("Select <b>at least 1 path</b> to perform a boolean union."));
- return;
- case ERR_TOO_LESS_PATHS_2:
- boolop_display_error_message(desktop, _("Select <b>at least 2 paths</b> to perform a boolean operation."));
- return;
- case ERR_NO_PATHS:
- boolop_display_error_message(desktop, _("One of the objects is <b>not a path</b>, cannot perform boolean operation."));
- return;
- case ERR_Z_ORDER:
- boolop_display_error_message(desktop, _("Unable to determine the <b>z-order</b> of the objects selected for difference, XOR, division, or path cut."));
- return;
- case DONE_NO_PATH:
- DocumentUndo::done(doc, SP_VERB_NONE, description);
- return;
- case DONE:
- DocumentUndo::done(doc, verb, description);
- return;
- case DONE_NO_ACTION:
- default:
- return;
- }
-}
-
static
void sp_selected_path_outline_add_marker( SPObject *marker_object, Geom::Affine marker_transform,
Geom::Scale stroke_scale, Geom::Affine transform,
diff --git a/src/splivarot.h b/src/splivarot.h
index 6adc05946..17dd4f66b 100644
--- a/src/splivarot.h
+++ b/src/splivarot.h
@@ -10,6 +10,7 @@
#include <2geom/forward.h>
#include <2geom/path.h>
#include "livarot/Path.h"
+#include "object-set.h"
class SPCurve;
class SPDesktop;
@@ -20,26 +21,6 @@ namespace Inkscape {
class ObjectSet;
}
-// boolean operations
-// work on the current selection
-// selection has 2 contain exactly 2 items
-
-// UPDATE: these signatures have been modified so they may work in
-// command-line mode, i.e. without a desktop. If a desktop is not
-// provided (desktop == NULL), error messages will be shown on stderr.
-void sp_selected_path_union (Inkscape::Selection *selection, SPDesktop *desktop);
-void sp_selected_path_union_skip_undo (Inkscape::ObjectSet *set);
-void sp_selected_path_intersect (Inkscape::Selection *selection, SPDesktop *desktop);
-void sp_selected_path_intersect_skip_undo (Inkscape::ObjectSet *set);
-void sp_selected_path_diff (Inkscape::Selection *selection, SPDesktop *desktop);
-void sp_selected_path_diff_skip_undo (Inkscape::ObjectSet *set);
-void sp_selected_path_symdiff (Inkscape::Selection *selection, SPDesktop *desktop);
-void sp_selected_path_symdiff_skip_undo (Inkscape::ObjectSet *set);
-void sp_selected_path_cut (Inkscape::Selection *selection, SPDesktop *desktop);
-void sp_selected_path_cut_skip_undo (Inkscape::ObjectSet *set);
-void sp_selected_path_slice (Inkscape::Selection *selection, SPDesktop *desktop);
-void sp_selected_path_slice_skip_undo (Inkscape::ObjectSet *set);
-
// offset/inset of a curve
// takes the fill-rule in consideration
// offset amount is the stroke-width of the curve
diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp
index a8e708597..c1e824c1e 100644
--- a/src/ui/clipboard.cpp
+++ b/src/ui/clipboard.cpp
@@ -643,7 +643,6 @@ Glib::ustring ClipboardManagerImpl::getShapeOrTextObjectId(SPDesktop *desktop)
return svgd;
}
-
/**
* Iterate over a list of items and copy them to the clipboard.
*/
@@ -689,25 +688,6 @@ void ClipboardManagerImpl::_copySelection(ObjectSet *selection)
else
obj_copy = _copyNode(obj, _doc, _clipnode);
- // For lpe items, copy lpe stack if applicable
- SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item);
- if (lpeitem) {
- Inkscape::SVGOStringStream os;
- if (lpeitem->hasPathEffect()) {
- for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it)
- {
- LivePathEffectObject *lpeobj = (*it)->lpeobject;
- if (lpeobj) {
- Inkscape::XML::Node * lpeobjcopy = _copyNode(lpeobj->getRepr(), _doc, _defs);
- gchar *new_conflict_id = sp_object_get_unique_id(lpeobj, lpeobj->getAttribute("id"));
- lpeobjcopy->setAttribute("id", new_conflict_id);
- g_free(new_conflict_id);
- os << "#" << lpeobjcopy->attribute("id") << ";";
- }
- }
- }
- obj_copy->setAttribute("inkscape:path-effect", os.str().c_str());
- }
// copy complete inherited style
SPCSSAttr *css = sp_repr_css_attr_inherited(obj, "style");
sp_repr_css_set(obj_copy, css, "style");
@@ -739,6 +719,13 @@ void ClipboardManagerImpl::_copySelection(ObjectSet *selection)
sp_repr_css_set(_clipnode, style, "style");
sp_repr_css_attr_unref(style);
}
+ // copy path effect from the first path
+ if (object) {
+ gchar const *effect =object->getRepr()->attribute("inkscape:path-effect");
+ if (effect) {
+ _clipnode->setAttribute("inkscape:path-effect", effect);
+ }
+ }
}
Geom::OptRect size = selection->visualBounds();
@@ -841,6 +828,19 @@ void ClipboardManagerImpl::_copyUsedDefs(SPItem *item)
}
}
+ // For lpe items, copy lpe stack if applicable
+ SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item);
+ if (lpeitem) {
+ if (lpeitem->hasPathEffect()) {
+ for (PathEffectList::iterator it = lpeitem->path_effect_list->begin(); it != lpeitem->path_effect_list->end(); ++it){
+ LivePathEffectObject *lpeobj = (*it)->lpeobject;
+ if (lpeobj) {
+ _copyNode(lpeobj->getRepr(), _doc, _defs);
+ }
+ }
+ }
+ }
+
// recurse
for(auto& o: item->children) {
SPItem *childItem = dynamic_cast<SPItem *>(&o);
diff --git a/src/ui/dialog/aboutbox.cpp b/src/ui/dialog/aboutbox.cpp
index 552500fe8..8f0545e96 100644
--- a/src/ui/dialog/aboutbox.cpp
+++ b/src/ui/dialog/aboutbox.cpp
@@ -27,7 +27,6 @@
#include <gtkmm/scrolledwindow.h>
#include <gtkmm/aspectframe.h>
#include <gtkmm/textview.h>
-#include <gtkmm/stock.h>
#include "path-prefix.h"
#include "document.h"
@@ -39,8 +38,6 @@
#include "inkscape-version.h"
-
-
namespace Inkscape {
namespace UI {
namespace Dialog {
@@ -102,7 +99,7 @@ AboutBox::AboutBox() : Gtk::Dialog(_("About Inkscape")) {
tabs->show_all();
- add_button(Gtk::Stock::CLOSE, Gtk::RESPONSE_CLOSE);
+ add_button(_("_Close"), Gtk::RESPONSE_CLOSE);
set_default_response(Gtk::RESPONSE_CLOSE);
Gtk::Label *label=new Gtk::Label();
diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp
index 236832beb..1c88fc849 100644
--- a/src/ui/dialog/align-and-distribute.cpp
+++ b/src/ui/dialog/align-and-distribute.cpp
@@ -614,7 +614,7 @@ private :
}
};
-// instantiae the private static member
+// instantiate the private static member
boost::optional<Geom::Point> ActionExchangePositions::center;
class ActionUnclump : public Action {
@@ -928,7 +928,7 @@ AlignAndDistribute::AlignAndDistribute()
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- //Instanciate the align buttons
+ //Instantiate the align buttons
addAlignButton(INKSCAPE_ICON("align-horizontal-right-to-anchor"),
_("Align right edges of objects to the left edge of the anchor"),
0, 0);
diff --git a/src/ui/dialog/calligraphic-profile-rename.cpp b/src/ui/dialog/calligraphic-profile-rename.cpp
index 50dae0fd8..36570e769 100644
--- a/src/ui/dialog/calligraphic-profile-rename.cpp
+++ b/src/ui/dialog/calligraphic-profile-rename.cpp
@@ -15,7 +15,6 @@
#include "calligraphic-profile-rename.h"
#include <glibmm/i18n.h>
-#include <gtkmm/stock.h>
#include <gtkmm/grid.h>
#include "desktop.h"
@@ -46,17 +45,17 @@ CalligraphicProfileRename::CalligraphicProfileRename() :
mainVBox->pack_start(*_layout_table, false, false, 4);
// Buttons
- _close_button.set_use_stock(true);
- _close_button.set_label(Gtk::Stock::CANCEL.id);
+ _close_button.set_use_underline();
+ _close_button.set_label(_("_Cancel"));
_close_button.set_can_default();
_delete_button.set_use_underline(true);
- _delete_button.set_label(_("Delete"));
+ _delete_button.set_label(_("_Delete"));
_delete_button.set_can_default();
_delete_button.set_visible(false);
_apply_button.set_use_underline(true);
- _apply_button.set_label(_("Save"));
+ _apply_button.set_label(_("_Save"));
_apply_button.set_can_default();
_close_button.signal_clicked()
diff --git a/src/ui/dialog/clonetiler.cpp b/src/ui/dialog/clonetiler.cpp
index 8e9d3dbbf..3cdcf594a 100644
--- a/src/ui/dialog/clonetiler.cpp
+++ b/src/ui/dialog/clonetiler.cpp
@@ -936,7 +936,7 @@ CloneTiler::CloneTiler () :
auto hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, VB_MARGIN);
gtk_box_set_homogeneous(GTK_BOX(hb), FALSE);
gtk_box_pack_start (GTK_BOX (mainbox), hb, FALSE, FALSE, 0);
- GtkWidget *l = gtk_label_new(_(""));
+ GtkWidget *l = gtk_label_new("");
gtk_label_set_markup (GTK_LABEL(l), _("Apply to tiled clones:"));
gtk_box_pack_start (GTK_BOX (hb), l, FALSE, FALSE, 0);
}
diff --git a/src/ui/dialog/dialog.cpp b/src/ui/dialog/dialog.cpp
index d0b618c65..27a6e55d9 100644
--- a/src/ui/dialog/dialog.cpp
+++ b/src/ui/dialog/dialog.cpp
@@ -19,7 +19,6 @@
#include "dialog-manager.h"
#include <gtkmm/dialog.h>
-#include <gtkmm/stock.h>
#include <gdk/gdkkeysyms.h>
#include "inkscape.h"
diff --git a/src/ui/dialog/dock-behavior.cpp b/src/ui/dialog/dock-behavior.cpp
index ec630c08f..02955b9a8 100644
--- a/src/ui/dialog/dock-behavior.cpp
+++ b/src/ui/dialog/dock-behavior.cpp
@@ -25,9 +25,6 @@
#include "dialog.h"
#include "ui/dialog-events.h"
-#include <gtkmm/invisible.h>
-#include <gtkmm/stock.h>
-
namespace Inkscape {
namespace UI {
namespace Dialog {
diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp
index 053549b73..8593223c1 100644
--- a/src/ui/dialog/document-properties.cpp
+++ b/src/ui/dialog/document-properties.cpp
@@ -44,9 +44,6 @@
#include "color-profile.h"
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
-#include <gtkmm/stock.h>
-#include <gtkmm/imagemenuitem.h>
-
#include "ui/icon-names.h"
using std::pair;
@@ -558,7 +555,7 @@ void DocumentProperties::linked_profiles_list_button_release(GdkEventButton* eve
void DocumentProperties::cms_create_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
{
- Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
+ Gtk::MenuItem* mi = Gtk::manage(new Gtk::MenuItem(_("_Remove"), true));
_EmbProfContextMenu.append(*mi);
mi->signal_activate().connect(rem);
mi->show();
@@ -568,7 +565,7 @@ void DocumentProperties::cms_create_popup_menu(Gtk::Widget& parent, sigc::slot<v
void DocumentProperties::external_create_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
{
- Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
+ Gtk::MenuItem* mi = Gtk::manage(new Gtk::MenuItem(_("_Remove"), true));
_ExternalScriptsContextMenu.append(*mi);
mi->signal_activate().connect(rem);
mi->show();
@@ -577,7 +574,7 @@ void DocumentProperties::external_create_popup_menu(Gtk::Widget& parent, sigc::s
void DocumentProperties::embedded_create_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
{
- Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
+ Gtk::MenuItem* mi = Gtk::manage(new Gtk::MenuItem(_("_Remove"), true));
_EmbeddedScriptsContextMenu.append(*mi);
mi->signal_activate().connect(rem);
mi->show();
diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp
index c38e798ec..b7207fd50 100644
--- a/src/ui/dialog/export.cpp
+++ b/src/ui/dialog/export.cpp
@@ -26,7 +26,6 @@
#include <gtkmm/entry.h>
#include <gtkmm/grid.h>
#include <gtkmm/spinbutton.h>
-#include <gtkmm/stock.h>
#ifdef WITH_GNOME_VFS
# include <libgnomevfs/gnome-vfs-init.h> // gnome_vfs_initialized
@@ -142,7 +141,7 @@ Export::Export (void) :
units_label(_("Units:")),
filename_box(false, 5),
browse_label(_("_Export As..."), 1),
- browse_image(Gtk::StockID(Gtk::Stock::INDEX), Gtk::ICON_SIZE_BUTTON),
+ browse_image(),
batch_box(false, 5),
batch_export(_("B_atch export all selected objects"), _("Export each selected object into its own PNG file, using export hints if any (caution, overwrites without asking!)")),
interlacing(_("Use interlacing"),_("Enables ADAM7 interlacing for PNG output. This results in slightly heavier images, but big images will look better sooner when loading the file")),
@@ -152,12 +151,12 @@ Export::Export (void) :
zlib_compression(),
pHYs_label(_("pHYs dpi")),
pHYs_sb(pHYs_adj, 1.0, 2),
+ antialiasing_label(_("Antialiasing")),
+ antialiasing_cb(),
hide_box(false, 5),
- hide_export(_("Hide a_ll except selected"), _("In the exported image, hide all objects except those that are selected")),
+ hide_export(_("Hide all except selected"), _("In the exported image, hide all objects except those that are selected")),
closeWhenDone(_("Close when complete"), _("Once the export completes, close this dialog")),
button_box(false, 3),
- export_label(_("_Export"), 1),
- export_image(Gtk::StockID(Gtk::Stock::APPLY), Gtk::ICON_SIZE_BUTTON),
_prog(),
prog_dlg(NULL),
interrupted(false),
@@ -290,6 +289,7 @@ Export::Export (void) :
filename_box.pack_start (filename_entry, true, true, 0);
Gtk::HBox* browser_im_label = new Gtk::HBox(false, 3);
+ browse_image.set_from_icon_name("folder", Gtk::ICON_SIZE_BUTTON);
browser_im_label->pack_start(browse_image);
browser_im_label->pack_start(browse_label);
browse_button.add(*browser_im_label);
@@ -318,11 +318,8 @@ Export::Export (void) :
/* Export Button row */
button_box.set_border_width(3);
- Gtk::HBox* export_image_label = new Gtk::HBox(false, 3);
- export_image_label->pack_start(export_image);
- export_image_label->pack_start(export_label);
-
- export_button.add(*export_image_label);
+ export_button.set_label(_("_Export"));
+ export_button.set_use_underline();
export_button.set_tooltip_text (_("Export the bitmap file with these settings"));
button_box.pack_start(closeWhenDone, true, true, 0 );
@@ -345,6 +342,10 @@ Export::Export (void) :
pHYs_sb.set_width_chars(7);
pHYs_sb.set_tooltip_text( _("Will force-set the physical dpi for the png file. Set this to 72 if you're planning to work on your png with Photoshop") );
zlib_compression.set_hexpand();
+ const char* const antialising_list[] = {"CAIRO_ANTIALIAS_NONE","CAIRO_ANTIALIAS_FAST","CAIRO_ANTIALIAS_GOOD (default)","CAIRO_ANTIALIAS_BEST"};
+ for(int i=0; i<4; ++i)
+ antialiasing_cb.append(antialising_list[i]);
+ antialiasing_cb.set_active_text(antialising_list[2]);
auto table = new Gtk::Grid();
gtk_container_add(GTK_CONTAINER(expander.gobj()), (GtkWidget*)(table->gobj()));
table->attach(interlacing,0,0,1,1);
@@ -354,6 +355,8 @@ Export::Export (void) :
table->attach(zlib_compression,1,2,1,1);
table->attach(pHYs_label,0,3,1,1);
table->attach(pHYs_sb,1,3,1,1);
+ table->attach(antialiasing_label,0,4,1,1);
+ table->attach(antialiasing_cb,1,4,1,1);
table->show();
/* Main dialog */
@@ -906,7 +909,7 @@ Gtk::Dialog * Export::create_progress_dialog (Glib::ustring progress_text) {
auto CA = dlg->get_content_area();
CA->pack_start(*prg, FALSE, FALSE, 4);
- Gtk::Button* btn = dlg->add_button (Gtk::Stock::CANCEL,Gtk::RESPONSE_CANCEL );
+ Gtk::Button* btn = dlg->add_button (_("_Cancel"),Gtk::RESPONSE_CANCEL );
btn->signal_clicked().connect( sigc::mem_fun(*this, &Export::onProgressCancel) );
dlg->signal_delete_event().connect( sigc::mem_fun(*this, &Export::onProgressDelete) );
@@ -991,6 +994,7 @@ void Export::onExport ()
int bitdepths[] = {1,2,4,8,16,8,16,8,16,8,16};
int color_type = colortypes[bitdepth_cb.get_active_row_number()] ;
int bit_depth = bitdepths[bitdepth_cb.get_active_row_number()] ;
+ int antialiasing = antialiasing_cb.get_active_row_number();
if (batch_export.get_active ()) {
@@ -1060,7 +1064,7 @@ void Export::onExport ()
onProgressCallback, (void*)prog_dlg,
TRUE, // overwrite without asking
hide ? selected : x,
- do_interlace, color_type, bit_depth, zlib
+ do_interlace, color_type, bit_depth, zlib, antialiasing
)) {
gchar * error = g_strdup_printf(_("Could not export to filename %s.\n"), safeFile);
@@ -1156,7 +1160,7 @@ void Export::onExport ()
onProgressCallback, (void*)prog_dlg,
FALSE,
hide ? selected : x,
- do_interlace, color_type, bit_depth, zlib
+ do_interlace, color_type, bit_depth, zlib, antialiasing
);
if (status == EXPORT_ERROR) {
gchar * safeFile = Inkscape::IO::sanitizeString(path.c_str());
diff --git a/src/ui/dialog/export.h b/src/ui/dialog/export.h
index 112f42312..1f8e87dbc 100644
--- a/src/ui/dialog/export.h
+++ b/src/ui/dialog/export.h
@@ -327,12 +327,12 @@ private:
Gtk::Label pHYs_label;
Glib::RefPtr<Gtk::Adjustment> pHYs_adj;
Gtk::SpinButton pHYs_sb;
+ Gtk::Label antialiasing_label;
+ Gtk::ComboBoxText antialiasing_cb;
/* Export Button widgets */
Gtk::HBox button_box;
Gtk::Button export_button;
- Gtk::Label export_label;
- Gtk::Image export_image;
Gtk::ProgressBar _prog;
diff --git a/src/ui/dialog/filedialogimpl-gtkmm.cpp b/src/ui/dialog/filedialogimpl-gtkmm.cpp
index e8c1bf723..92e9ce834 100644
--- a/src/ui/dialog/filedialogimpl-gtkmm.cpp
+++ b/src/ui/dialog/filedialogimpl-gtkmm.cpp
@@ -35,7 +35,6 @@
#endif
#include <gtkmm/expander.h>
-#include <gtkmm/stock.h>
#include <glibmm/convert.h>
#include <glibmm/fileutils.h>
@@ -555,7 +554,7 @@ bool SVGPreview::set(Glib::ustring &fileName, int dialogType)
Glib::ustring fileNameUtf8 = Glib::filename_to_utf8(fileName);
gchar *fName = const_cast<gchar *>(
fileNameUtf8.c_str()); // const-cast probably not necessary? (not necessary on Windows version of stat())
- struct stat info;
+ GStatBuf info;
if (g_stat(fName, &info)) // stat returns 0 upon success
{
g_warning("SVGPreview::set() : %s : %s", fName, strerror(errno));
@@ -735,8 +734,8 @@ FileOpenDialogImplGtk::FileOpenDialogImplGtk(Gtk::Window &parentWindow, const Gl
//###### Add the file types menu
createFilterMenu();
- add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
- set_default(*add_button(Gtk::Stock::OPEN, Gtk::RESPONSE_OK));
+ add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
+ set_default(*add_button(_("_Open"), Gtk::RESPONSE_OK));
//###### Allow easy access to our examples folder
if (Inkscape::IO::file_test(INKSCAPE_EXAMPLESDIR, G_FILE_TEST_EXISTS) &&
@@ -1050,8 +1049,8 @@ FileSaveDialogImplGtk::FileSaveDialogImplGtk(Gtk::Window &parentWindow, const Gl
// if (extension == NULL)
// checkbox.set_sensitive(FALSE);
- add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
- set_default(*add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK));
+ add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
+ set_default(*add_button(_("_Save"), Gtk::RESPONSE_OK));
show_all_children();
}
@@ -1597,8 +1596,8 @@ FileExportDialogImpl::FileExportDialogImpl(Gtk::Window &parentWindow, const Glib
// if (extension == NULL)
// checkbox.set_sensitive(FALSE);
- add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
- set_default(*add_button(Gtk::Stock::SAVE, Gtk::RESPONSE_OK));
+ add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
+ set_default(*add_button(_("_Save"), Gtk::RESPONSE_OK));
show_all_children();
}
diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp
index f657e1b76..80dc08ccf 100644
--- a/src/ui/dialog/filter-effects-dialog.cpp
+++ b/src/ui/dialog/filter-effects-dialog.cpp
@@ -64,7 +64,6 @@
#include "selection-chemistry.h"
#include <gtkmm/colorbutton.h>
-#include <gtkmm/stock.h>
#include <gdkmm/general.h>
#include <gtkmm/checkbutton.h>
@@ -1305,7 +1304,7 @@ static Glib::RefPtr<Gtk::Menu> create_popup_menu(Gtk::Widget& parent, sigc::slot
mi->show();
menu->append(*mi);
- mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
+ mi = Gtk::manage(new Gtk::MenuItem(_("_Remove"), true));
menu->append(*mi);
mi->signal_activate().connect(rem);
mi->show();
@@ -1319,7 +1318,7 @@ FilterEffectsDialog::FilterModifier::FilterModifier(FilterEffectsDialog& d)
: _desktop(NULL),
_deskTrack(),
_dialog(d),
- _add(Gtk::Stock::NEW),
+ _add(_("_New"), true),
_observer(new Inkscape::XML::SignalObserver)
{
Gtk::ScrolledWindow* sw = Gtk::manage(new Gtk::ScrolledWindow);
diff --git a/src/ui/dialog/floating-behavior.cpp b/src/ui/dialog/floating-behavior.cpp
index fa8e11dfd..9abad3e7b 100644
--- a/src/ui/dialog/floating-behavior.cpp
+++ b/src/ui/dialog/floating-behavior.cpp
@@ -15,7 +15,6 @@
#endif
#include <gtkmm/dialog.h>
-#include <gtkmm/stock.h>
#include <glibmm/main.h>
#include "floating-behavior.h"
diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp
index 5872393ae..9ec8d3148 100644
--- a/src/ui/dialog/grid-arrange-tab.cpp
+++ b/src/ui/dialog/grid-arrange-tab.cpp
@@ -1,25 +1,24 @@
-/*
- * A simple dialog for creating grid type arrangements of selected objects
- *
- * Authors:
- * Bob Jamison ( based off trace dialog)
- * John Cliff
- * Other dudes from The Inkscape Organization
- * Abhishek Sharma
- * Declara Denis
- *
- * Copyright (C) 2004 Bob Jamison
- * Copyright (C) 2004 John Cliff
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-//#define DEBUG_GRID_ARRANGE 1
+ /*
+ * A simple dialog for creating grid type arrangements of selected objects
+ *
+ * Authors:
+ * Bob Jamison ( based off trace dialog)
+ * John Cliff
+ * Other dudes from The Inkscape Organization
+ * Abhishek Sharma
+ * Declara Denis
+ *
+ * Copyright (C) 2004 Bob Jamison
+ * Copyright (C) 2004 John Cliff
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+ //#define DEBUG_GRID_ARRANGE 1
#include "ui/dialog/grid-arrange-tab.h"
#include <glibmm/i18n.h>
#include <gtkmm/grid.h>
-#include <gtkmm/stock.h>
#include <2geom/transforms.h>
@@ -31,193 +30,193 @@
#include "document-undo.h"
#include "widgets/icon.h"
#include "desktop.h"
-//#include "sp-item-transform.h" FIXME
+ //#include "sp-item-transform.h" FIXME
#include "ui/dialog/tile.h" // for Inkscape::UI::Dialog::ArrangeDialog
-/*
- * Sort items by their x co-ordinates, taking account of y (keeps rows intact)
- *
- * <0 *elem1 goes before *elem2
- * 0 *elem1 == *elem2
- * >0 *elem1 goes after *elem2
- */
-static bool sp_compare_x_position(SPItem *first, SPItem *second)
-{
- using Geom::X;
- using Geom::Y;
+ /*
+ * Sort items by their x co-ordinates, taking account of y (keeps rows intact)
+ *
+ * <0 *elem1 goes before *elem2
+ * 0 *elem1 == *elem2
+ * >0 *elem1 goes after *elem2
+ */
+ static bool sp_compare_x_position(SPItem *first, SPItem *second)
+ {
+ using Geom::X;
+ using Geom::Y;
- Geom::OptRect a = first->documentVisualBounds();
- Geom::OptRect b = second->documentVisualBounds();
+ Geom::OptRect a = first->documentVisualBounds();
+ Geom::OptRect b = second->documentVisualBounds();
- if ( !a || !b ) {
- // FIXME?
- return false;
- }
+ if ( !a || !b ) {
+ // FIXME?
+ return false;
+ }
- double const a_height = a->dimensions()[Y];
- double const b_height = b->dimensions()[Y];
+ double const a_height = a->dimensions()[Y];
+ double const b_height = b->dimensions()[Y];
- bool a_in_b_vert = false;
- if ((a->min()[Y] < b->min()[Y] + 0.1) && (a->min()[Y] > b->min()[Y] - b_height)) {
- a_in_b_vert = true;
- } else if ((b->min()[Y] < a->min()[Y] + 0.1) && (b->min()[Y] > a->min()[Y] - a_height)) {
- a_in_b_vert = true;
- } else if (b->min()[Y] == a->min()[Y]) {
- a_in_b_vert = true;
- } else {
- a_in_b_vert = false;
- }
+ bool a_in_b_vert = false;
+ if ((a->min()[Y] < b->min()[Y] + 0.1) && (a->min()[Y] > b->min()[Y] - b_height)) {
+ a_in_b_vert = true;
+ } else if ((b->min()[Y] < a->min()[Y] + 0.1) && (b->min()[Y] > a->min()[Y] - a_height)) {
+ a_in_b_vert = true;
+ } else if (b->min()[Y] == a->min()[Y]) {
+ a_in_b_vert = true;
+ } else {
+ a_in_b_vert = false;
+ }
- if (!a_in_b_vert) { // a and b are not in the same row
- return (a->min()[Y] < b->min()[Y]);
+ if (!a_in_b_vert) { // a and b are not in the same row
+ return (a->min()[Y] < b->min()[Y]);
+ }
+ return (a->min()[X] < b->min()[X]);
}
- return (a->min()[X] < b->min()[X]);
-}
-/*
- * Sort items by their y co-ordinates.
- */
-static bool sp_compare_y_position(SPItem *first, SPItem *second)
-{
- Geom::OptRect a = first->documentVisualBounds();
- Geom::OptRect b = second->documentVisualBounds();
+ /*
+ * Sort items by their y co-ordinates.
+ */
+ static bool sp_compare_y_position(SPItem *first, SPItem *second)
+ {
+ Geom::OptRect a = first->documentVisualBounds();
+ Geom::OptRect b = second->documentVisualBounds();
- if ( !a || !b ) {
- // FIXME?
- return false;
- }
+ if ( !a || !b ) {
+ // FIXME?
+ return false;
+ }
+
+ if (a->min()[Geom::Y] > b->min()[Geom::Y]) {
+ return false;
+ }
+ if (a->min()[Geom::Y] < b->min()[Geom::Y]) {
+ return true;
+ }
- if (a->min()[Geom::Y] > b->min()[Geom::Y]) {
return false;
}
- if (a->min()[Geom::Y] < b->min()[Geom::Y]) {
- return true;
- }
-
- return false;
-}
-namespace Inkscape {
-namespace UI {
-namespace Dialog {
+ namespace Inkscape {
+ namespace UI {
+ namespace Dialog {
-//#########################################################################
-//## E V E N T S
-//#########################################################################
-
-/*
- *
- * This arranges the selection in a grid pattern.
- *
- */
+ //#########################################################################
+ //## E V E N T S
+ //#########################################################################
-void GridArrangeTab::arrange()
-{
+ /*
+ *
+ * This arranges the selection in a grid pattern.
+ *
+ */
- int cnt,row_cnt,col_cnt,a,row,col;
- double grid_left,grid_top,col_width,row_height,paddingx,paddingy,width, height, new_x, new_y;
- double total_col_width,total_row_height;
- col_width = 0;
- row_height = 0;
- total_col_width=0;
- total_row_height=0;
+ void GridArrangeTab::arrange()
+ {
- // check for correct numbers in the row- and col-spinners
- on_col_spinbutton_changed();
- on_row_spinbutton_changed();
+ int cnt,row_cnt,col_cnt,a,row,col;
+ double grid_left,grid_top,col_width,row_height,paddingx,paddingy,width, height, new_x, new_y;
+ double total_col_width,total_row_height;
+ col_width = 0;
+ row_height = 0;
+ total_col_width=0;
+ total_row_height=0;
- // set padding to manual values
- paddingx = XPadding.getValue("px");
- paddingy = YPadding.getValue("px");
+ // check for correct numbers in the row- and col-spinners
+ on_col_spinbutton_changed();
+ on_row_spinbutton_changed();
- std::vector<double> row_heights;
- std::vector<double> col_widths;
- std::vector<double> row_ys;
- std::vector<double> col_xs;
+ // set padding to manual values
+ paddingx = XPadding.getValue("px");
+ paddingy = YPadding.getValue("px");
- int NoOfCols = NoOfColsSpinner.get_value_as_int();
- int NoOfRows = NoOfRowsSpinner.get_value_as_int();
+ std::vector<double> row_heights;
+ std::vector<double> col_widths;
+ std::vector<double> row_ys;
+ std::vector<double> col_xs;
- width = 0;
- for (a=0;a<NoOfCols; a++){
- col_widths.push_back(width);
- }
+ int NoOfCols = NoOfColsSpinner.get_value_as_int();
+ int NoOfRows = NoOfRowsSpinner.get_value_as_int();
- height = 0;
- for (a=0;a<NoOfRows; a++){
- row_heights.push_back(height);
- }
- grid_left = 99999;
- grid_top = 99999;
+ width = 0;
+ for (a=0;a<NoOfCols; a++){
+ col_widths.push_back(width);
+ }
- SPDesktop *desktop = Parent->getDesktop();
- desktop->getDocument()->ensureUpToDate();
+ height = 0;
+ for (a=0;a<NoOfRows; a++){
+ row_heights.push_back(height);
+ }
+ grid_left = 99999;
+ grid_top = 99999;
- Inkscape::Selection *selection = desktop->getSelection();
- std::vector<SPItem*> items;
- if (selection) {
- items.insert(items.end(), selection->items().begin(), selection->items().end());
- }
+ SPDesktop *desktop = Parent->getDesktop();
+ desktop->getDocument()->ensureUpToDate();
- for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end(); ++i){
- SPItem *item = *i;
- Geom::OptRect b = item->documentVisualBounds();
- if (!b) {
- continue;
+ Inkscape::Selection *selection = desktop->getSelection();
+ std::vector<SPItem*> items;
+ if (selection) {
+ items.insert(items.end(), selection->items().begin(), selection->items().end());
}
- width = b->dimensions()[Geom::X];
- height = b->dimensions()[Geom::Y];
+ for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end(); ++i){
+ SPItem *item = *i;
+ Geom::OptRect b = item->documentVisualBounds();
+ if (!b) {
+ continue;
+ }
+
+ width = b->dimensions()[Geom::X];
+ height = b->dimensions()[Geom::Y];
- if (b->min()[Geom::X] < grid_left) {
- grid_left = b->min()[Geom::X];
- }
- if (b->min()[Geom::Y] < grid_top) {
- grid_top = b->min()[Geom::Y];
- }
- if (width > col_width) {
- col_width = width;
- }
- if (height > row_height) {
- row_height = height;
+ if (b->min()[Geom::X] < grid_left) {
+ grid_left = b->min()[Geom::X];
+ }
+ if (b->min()[Geom::Y] < grid_top) {
+ grid_top = b->min()[Geom::Y];
+ }
+ if (width > col_width) {
+ col_width = width;
+ }
+ if (height > row_height) {
+ row_height = height;
+ }
}
- }
- // require the sorting done before we can calculate row heights etc.
+ // require the sorting done before we can calculate row heights etc.
- g_return_if_fail(selection);
- std::vector<SPItem*> sorted(selection->items().begin(), selection->items().end());
- sort(sorted.begin(),sorted.end(),sp_compare_y_position);
- sort(sorted.begin(),sorted.end(),sp_compare_x_position);
+ g_return_if_fail(selection);
+ std::vector<SPItem*> sorted(selection->items().begin(), selection->items().end());
+ sort(sorted.begin(),sorted.end(),sp_compare_y_position);
+ sort(sorted.begin(),sorted.end(),sp_compare_x_position);
- // Calculate individual Row and Column sizes if necessary
+ // Calculate individual Row and Column sizes if necessary
- cnt=0;
- const std::vector<SPItem*> sizes(sorted);
- for (std::vector<SPItem*>::const_iterator i = sizes.begin();i!=sizes.end(); ++i) {
- SPItem *item = *i;
- Geom::OptRect b = item->documentVisualBounds();
- if (b) {
- width = b->dimensions()[Geom::X];
- height = b->dimensions()[Geom::Y];
- if (width > col_widths[(cnt % NoOfCols)]) {
- col_widths[(cnt % NoOfCols)] = width;
+ cnt=0;
+ const std::vector<SPItem*> sizes(sorted);
+ for (std::vector<SPItem*>::const_iterator i = sizes.begin();i!=sizes.end(); ++i) {
+ SPItem *item = *i;
+ Geom::OptRect b = item->documentVisualBounds();
+ if (b) {
+ width = b->dimensions()[Geom::X];
+ height = b->dimensions()[Geom::Y];
+ if (width > col_widths[(cnt % NoOfCols)]) {
+ col_widths[(cnt % NoOfCols)] = width;
+ }
+ if (height > row_heights[(cnt / NoOfCols)]) {
+ row_heights[(cnt / NoOfCols)] = height;
+ }
}
- if (height > row_heights[(cnt / NoOfCols)]) {
- row_heights[(cnt / NoOfCols)] = height;
- }
- }
- cnt++;
- }
+ cnt++;
+ }
- /// Make sure the top and left of the grid dont move by compensating for align values.
+ /// Make sure the top and left of the grid dont move by compensating for align values.
if (RowHeightButton.get_active()){
grid_top = grid_top - (((row_height - row_heights[0]) / 2)*(VertAlign));
}
diff --git a/src/ui/dialog/guides.cpp b/src/ui/dialog/guides.cpp
index 8d6ca4143..9c8b14953 100644
--- a/src/ui/dialog/guides.cpp
+++ b/src/ui/dialog/guides.cpp
@@ -32,8 +32,6 @@
#include "message-context.h"
#include "verbs.h"
-#include <gtkmm/stock.h>
-
namespace Inkscape {
namespace UI {
namespace Dialogs {
@@ -158,9 +156,9 @@ void GuidelinePropertiesDialog::_response(gint response)
void GuidelinePropertiesDialog::_setup() {
set_title(_("Guideline"));
- add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
- add_button(Gtk::Stock::DELETE, -12);
- add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
+ add_button(_("_OK"), Gtk::RESPONSE_OK);
+ add_button(_("_Delete"), -12);
+ add_button(_("_Cancel"), Gtk::RESPONSE_CANCEL);
auto mainVBox = get_content_area();
_layout_table.set_row_spacing(4);
diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp
index a4fcc9947..19050fb1d 100644
--- a/src/ui/dialog/icon-preview.cpp
+++ b/src/ui/dialog/icon-preview.cpp
@@ -27,7 +27,6 @@
#include <gtkmm/alignment.h>
#include <gtkmm/checkbutton.h>
#include <gtkmm/frame.h>
-#include <gtkmm/stock.h>
#include "ui/widget/frame.h"
#include "desktop.h"
diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp
index f9540c989..c5e8a6de6 100644
--- a/src/ui/dialog/inkscape-preferences.cpp
+++ b/src/ui/dialog/inkscape-preferences.cpp
@@ -534,7 +534,7 @@ void InkscapePreferences::initPageUI()
_("Hebrew (he)"), _("Hindi (hi)"), _("Hungarian (hu)"),
_("Icelandic (is)"), _("Indonesian (id)"), _("Irish (ga)"), _("Italian (it)"),
_("Japanese (ja)"),
- _("Kannada (kn)"), _("Kashmiri in Peso-Arabic script (ks@aran)"), _("Kashmiri in Devanagari script (ks@deva)"), _("Khmer (km)"), _("Kinyarwanda (rw)"), _("Konkani (kok)"), _("Konkani in Latin script (kok@latin)"), _("Korean (ko)"),
+ _("Kannada (kn)"), _("Kashmiri in Perso-Arabic script (ks@aran)"), _("Kashmiri in Devanagari script (ks@deva)"), _("Khmer (km)"), _("Kinyarwanda (rw)"), _("Konkani (kok)"), _("Konkani in Latin script (kok@latin)"), _("Korean (ko)"),
_("Latvian (lv)"), _("Lithuanian (lt)"),
_("Macedonian (mk)"), _("Maithili (mai)"), _("Malayalam (ml)"), _("Manipuri (mni)"), _("Manipuri in Bengali script (mni@beng)"), _("Marathi (mr)"), _("Mongolian (mn)"),
_("Nepali (ne)"), _("Norwegian Bokmål (nb)"), _("Norwegian Nynorsk (nn)"),
diff --git a/src/ui/dialog/knot-properties.cpp b/src/ui/dialog/knot-properties.cpp
index 133ed6f4c..954fe2a66 100644
--- a/src/ui/dialog/knot-properties.cpp
+++ b/src/ui/dialog/knot-properties.cpp
@@ -14,11 +14,14 @@
*/
#ifdef HAVE_CONFIG_H
-#include "config.h"
+# include "config.h"
#endif
+
#include "ui/dialog/knot-properties.h"
+
#include <boost/lexical_cast.hpp>
#include <glibmm/i18n.h>
+#include <glibmm/main.h>
#include "inkscape.h"
#include "util/units.h"
#include "desktop.h"
@@ -35,7 +38,10 @@ namespace UI {
namespace Dialogs {
KnotPropertiesDialog::KnotPropertiesDialog()
-: _desktop(NULL), _knotpoint(NULL), _position_visible(false)
+ : _desktop(NULL),
+ _knotpoint(NULL),
+ _position_visible(false),
+ _close_button(_("_Close"), true)
{
Gtk::Box *mainVBox = get_vbox();
@@ -68,8 +74,6 @@ KnotPropertiesDialog::KnotPropertiesDialog()
mainVBox->pack_start(_layout_table, true, true, 4);
// Buttons
- _close_button.set_use_stock(true);
- _close_button.set_label(Gtk::Stock::CANCEL.id);
_close_button.set_can_default();
_apply_button.set_use_underline(true);
diff --git a/src/ui/dialog/knot-properties.h b/src/ui/dialog/knot-properties.h
index fd87df03d..f6157168f 100644
--- a/src/ui/dialog/knot-properties.h
+++ b/src/ui/dialog/knot-properties.h
@@ -12,11 +12,10 @@
#ifndef INKSCAPE_DIALOG_KNOT_PROPERTIES_H
#define INKSCAPE_DIALOG_KNOT_PROPERTIES_H
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <gtkmm.h>
+#include <gtkmm/dialog.h>
+#include <gtkmm/label.h>
+#include <gtkmm/spinbutton.h>
+#include <gtkmm/table.h>
#include <2geom/point.h>
#include "knot.h"
#include "ui/tools/measure-tool.h"
@@ -40,7 +39,7 @@ class KnotPropertiesDialog : public Gtk::Dialog {
protected:
SPDesktop *_desktop;
- SPKnot *_knotpoint;
+ SPKnot *_knotpoint;
Gtk::Label _knot_x_label;
Gtk::SpinButton _knot_x_entry;
diff --git a/src/ui/dialog/layer-properties.cpp b/src/ui/dialog/layer-properties.cpp
index f28f8336a..c8c42ef90 100644
--- a/src/ui/dialog/layer-properties.cpp
+++ b/src/ui/dialog/layer-properties.cpp
@@ -14,7 +14,6 @@
*/
#include "layer-properties.h"
-#include <gtkmm/stock.h>
#include <glibmm/i18n.h>
#include <glibmm/main.h>
@@ -36,7 +35,11 @@ namespace UI {
namespace Dialogs {
LayerPropertiesDialog::LayerPropertiesDialog()
-: _strategy(NULL), _desktop(NULL), _layer(NULL), _position_visible(false)
+ : _strategy(NULL),
+ _desktop(NULL),
+ _layer(NULL),
+ _position_visible(false),
+ _close_button(_("_Cancel"), true)
{
auto mainVBox = get_content_area();
_layout_table.set_row_spacing(4);
@@ -59,8 +62,6 @@ LayerPropertiesDialog::LayerPropertiesDialog()
mainVBox->pack_start(_layout_table, true, true, 4);
// Buttons
- _close_button.set_use_stock(true);
- _close_button.set_label(Gtk::Stock::CANCEL.id);
_close_button.set_can_default();
_apply_button.set_use_underline(true);
diff --git a/src/ui/dialog/livepatheffect-add.cpp b/src/ui/dialog/livepatheffect-add.cpp
index 917e48ac6..cada915c9 100644
--- a/src/ui/dialog/livepatheffect-add.cpp
+++ b/src/ui/dialog/livepatheffect-add.cpp
@@ -14,7 +14,6 @@
#include "livepatheffect-add.h"
#include <glibmm/i18n.h>
-#include <gtkmm/stock.h>
#include "desktop.h"
@@ -23,8 +22,8 @@ namespace UI {
namespace Dialog {
LivePathEffectAdd::LivePathEffectAdd() :
- add_button(Gtk::Stock::ADD),
- close_button(Gtk::Stock::CANCEL),
+ add_button(_("_Add"), true),
+ close_button(_("_Cancel"), true),
converter(Inkscape::LivePathEffect::LPETypeConverter),
applied(false)
{
@@ -68,7 +67,6 @@ LivePathEffectAdd::LivePathEffectAdd() :
/**
* Buttons
*/
- close_button.set_use_stock(true);
//close_button.set_can_default();
add_button.set_use_underline(true);
add_button.set_can_default();
diff --git a/src/ui/dialog/livepatheffect-editor.cpp b/src/ui/dialog/livepatheffect-editor.cpp
index 9bd4c093e..e5becdb5c 100644
--- a/src/ui/dialog/livepatheffect-editor.cpp
+++ b/src/ui/dialog/livepatheffect-editor.cpp
@@ -17,7 +17,6 @@
#endif
#include "livepatheffect-editor.h"
-#include <gtkmm/stock.h>
#include "desktop.h"
@@ -539,9 +538,11 @@ void LivePathEffectEditor::onDown()
void LivePathEffectEditor::on_effect_selection_changed()
{
Glib::RefPtr<Gtk::TreeSelection> sel = effectlist_view.get_selection();
- if (sel->count_selected_rows () == 0)
+ if (sel->count_selected_rows () == 0) {
+ button_remove.set_sensitive(false);
return;
-
+ }
+ button_remove.set_sensitive(true);
Gtk::TreeModel::iterator it = sel->get_selected();
LivePathEffect::LPEObjectReference * lperef = (*it)[columns.lperef];
diff --git a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp
index d33ee758d..d6ecae5a9 100644
--- a/src/ui/dialog/lpe-fillet-chamfer-properties.cpp
+++ b/src/ui/dialog/lpe-fillet-chamfer-properties.cpp
@@ -27,7 +27,10 @@ namespace UI {
namespace Dialogs {
FilletChamferPropertiesDialog::FilletChamferPropertiesDialog()
- : _desktop(NULL), _knotpoint(NULL), _position_visible(false)
+ : _desktop(NULL),
+ _knotpoint(NULL),
+ _position_visible(false),
+ _close_button(_("_Cancel"), true)
{
Gtk::Box *mainVBox = get_vbox();
mainVBox->set_homogeneous(false);
@@ -76,8 +79,6 @@ FilletChamferPropertiesDialog::FilletChamferPropertiesDialog()
mainVBox->pack_start(_fillet_chamfer_type_inverse_chamfer, true, true, 4);
// Buttons
- _close_button.set_use_stock(true);
- _close_button.set_label(Gtk::Stock::CANCEL.id);
_close_button.set_can_default();
_apply_button.set_use_underline(true);
@@ -264,6 +265,4 @@ void FilletChamferPropertiesDialog::_set_desktop(SPDesktop *desktop)
fill-column:99
End:
*/
-// vim:
-// filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
-// :
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99
diff --git a/src/ui/dialog/lpe-powerstroke-properties.cpp b/src/ui/dialog/lpe-powerstroke-properties.cpp
index d5b3bb30d..ca10721db 100644
--- a/src/ui/dialog/lpe-powerstroke-properties.cpp
+++ b/src/ui/dialog/lpe-powerstroke-properties.cpp
@@ -33,7 +33,10 @@ namespace UI {
namespace Dialogs {
PowerstrokePropertiesDialog::PowerstrokePropertiesDialog()
-: _desktop(NULL), _knotpoint(NULL), _position_visible(false)
+ : _desktop(NULL),
+ _knotpoint(NULL),
+ _position_visible(false),
+ _close_button(_("_Cancel"), true)
{
Gtk::Box *mainVBox = get_vbox();
@@ -66,8 +69,6 @@ PowerstrokePropertiesDialog::PowerstrokePropertiesDialog()
mainVBox->pack_start(_layout_table, true, true, 4);
// Buttons
- _close_button.set_use_stock(true);
- _close_button.set_label(Gtk::Stock::CANCEL.id);
_close_button.set_can_default();
_apply_button.set_use_underline(true);
diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp
index 446af4ccb..c7c696cdc 100644
--- a/src/ui/dialog/objects.cpp
+++ b/src/ui/dialog/objects.cpp
@@ -15,7 +15,6 @@
#include "objects.h"
#include <gtkmm/icontheme.h>
-#include <gtkmm/stock.h>
#include <gtkmm/imagemenuitem.h>
#include <gtkmm/separatormenuitem.h>
#include <glibmm/main.h>
diff --git a/src/ui/dialog/ocaldialogs.cpp b/src/ui/dialog/ocaldialogs.cpp
index 878b68d55..72a2814ed 100644
--- a/src/ui/dialog/ocaldialogs.cpp
+++ b/src/ui/dialog/ocaldialogs.cpp
@@ -27,7 +27,6 @@
#include <gtkmm/notebook.h>
#include <gtkmm/spinner.h>
-#include <gtkmm/stock.h>
#include <gdkmm/general.h>
#include <libxml/tree.h>
@@ -463,7 +462,8 @@ bool PreviewWidget::_on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
StatusWidget::StatusWidget() : Gtk::HBox(false, 6)
{
- image = new Gtk::Image(Gtk::Stock::DIALOG_ERROR, Gtk::ICON_SIZE_MENU);
+ image = new Gtk::Image();
+ image->set_from_icon_name("dialog-error", Gtk::ICON_SIZE_MENU);
spinner = new Gtk::Spinner();
label = new Gtk::Label();
@@ -488,7 +488,7 @@ void StatusWidget::set_info(Glib::ustring text)
spinner->hide();
image->show();
label->show();
- image->set(Gtk::Stock::DIALOG_INFO, Gtk::ICON_SIZE_MENU);
+ image->set_from_icon_name("dialog-information", Gtk::ICON_SIZE_MENU);
label->set_text(text);
}
@@ -497,7 +497,7 @@ void StatusWidget::set_error(Glib::ustring text)
spinner->hide();
image->show();
label->show();
- image->set(Gtk::Stock::DIALOG_ERROR, Gtk::ICON_SIZE_MENU);
+ image->set_from_icon_name("dialog-error", Gtk::ICON_SIZE_MENU);
label->set_text(text);
}
@@ -1086,7 +1086,7 @@ ImportDialog::ImportDialog(Gtk::Window& parent_window, FileDialogType file_types
Gtk::ScrolledWindow* scrolledwindow_preview = new Gtk::ScrolledWindow();
preview_files = new PreviewWidget();
/// Add the buttons in the bottom of the dialog
- button_cancel = new Gtk::Button(Gtk::Stock::CANCEL);
+ button_cancel = new Gtk::Button(_("_Cancel"), true);
button_close = new Gtk::Button(_("Close"));
button_import = new Gtk::Button(_("Import"));
list_results = new SearchResultList(RESULTS_COLUMN_LENGTH);
diff --git a/src/ui/dialog/panel-dialog.h b/src/ui/dialog/panel-dialog.h
index 39110f47a..5919fcaeb 100644
--- a/src/ui/dialog/panel-dialog.h
+++ b/src/ui/dialog/panel-dialog.h
@@ -15,8 +15,8 @@
# include <config.h>
#endif
+#include <glibmm/i18n.h>
#include <gtkmm/dialog.h>
-#include <gtkmm/stock.h>
#include "verbs.h"
#include "dialog.h"
@@ -165,7 +165,7 @@ PanelDialog<B>::PanelDialog(Widget::Panel &panel, char const *prefs_path, int co
panel.addResponseButton(apply_label, Gtk::RESPONSE_APPLY);
panel.setDefaultResponse(Gtk::RESPONSE_APPLY);
}
- panel.addResponseButton(Gtk::Stock::CLOSE, Gtk::RESPONSE_CLOSE);
+ panel.addResponseButton(_("_Close"), Gtk::RESPONSE_CLOSE);
}
show_all_children();
@@ -214,7 +214,7 @@ PanelDialog<Behavior::FloatingBehavior>::PanelDialog(UI::Widget::Panel &panel, c
panel.addResponseButton(apply_label, Gtk::RESPONSE_APPLY);
panel.setDefaultResponse(Gtk::RESPONSE_APPLY);
}
- panel.addResponseButton(Gtk::Stock::CLOSE, Gtk::RESPONSE_CLOSE);
+ panel.addResponseButton(_("_Close"), Gtk::RESPONSE_CLOSE);
}
show_all_children();
diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp
index b838b0842..3e6617cfe 100644
--- a/src/ui/dialog/pixelartdialog.cpp
+++ b/src/ui/dialog/pixelartdialog.cpp
@@ -28,7 +28,6 @@
#include "pixelartdialog.h"
#include <gtkmm/radiobutton.h>
-#include <gtkmm/stock.h>
#include <gtkmm/messagedialog.h>
#include <glibmm/i18n.h>
@@ -291,12 +290,12 @@ PixelArtDialogImpl::PixelArtDialogImpl() :
mainResetButton ->set_tooltip_text(_("Reset all settings to defaults"));
//## The OK button
- mainCancelButton = addResponseButton(Gtk::Stock::STOP, GTK_RESPONSE_CANCEL);
+ mainCancelButton = addResponseButton(_("_Stop"), GTK_RESPONSE_CANCEL);
if (mainCancelButton) {
mainCancelButton->set_tooltip_text(_("Abort a trace in progress"));
mainCancelButton->set_sensitive(false);
}
- mainOkButton = addResponseButton(Gtk::Stock::OK, GTK_RESPONSE_OK);
+ mainOkButton = addResponseButton(_("_OK"), GTK_RESPONSE_OK);
mainOkButton->set_tooltip_text(_("Execute the trace"));
contents->pack_start(buttonsHBox);
diff --git a/src/ui/dialog/svg-fonts-dialog.cpp b/src/ui/dialog/svg-fonts-dialog.cpp
index e55a32bd5..791677807 100644
--- a/src/ui/dialog/svg-fonts-dialog.cpp
+++ b/src/ui/dialog/svg-fonts-dialog.cpp
@@ -20,7 +20,6 @@
#include "document-undo.h"
#include <gtkmm/notebook.h>
#include <gtkmm/scale.h>
-#include <gtkmm/stock.h>
#include <gtkmm/imagemenuitem.h>
#include <message-stack.h>
#include "selection.h"
@@ -299,7 +298,7 @@ void SvgFontsDialog::fonts_list_button_release(GdkEventButton* event)
void SvgFontsDialog::create_glyphs_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
{
- Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
+ auto mi = Gtk::manage(new Gtk::MenuItem(_("_Remove"), true));
_GlyphsContextMenu.append(*mi);
mi->signal_activate().connect(rem);
mi->show();
@@ -308,7 +307,7 @@ void SvgFontsDialog::create_glyphs_popup_menu(Gtk::Widget& parent, sigc::slot<vo
void SvgFontsDialog::create_kerning_pairs_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
{
- Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
+ auto mi = Gtk::manage(new Gtk::MenuItem(_("_Remove"), true));
_KerningPairsContextMenu.append(*mi);
mi->signal_activate().connect(rem);
mi->show();
@@ -317,7 +316,7 @@ void SvgFontsDialog::create_kerning_pairs_popup_menu(Gtk::Widget& parent, sigc::
void SvgFontsDialog::create_fonts_popup_menu(Gtk::Widget& parent, sigc::slot<void> rem)
{
- Gtk::MenuItem* mi = Gtk::manage(new Gtk::ImageMenuItem(Gtk::Stock::REMOVE));
+ auto mi = Gtk::manage(new Gtk::MenuItem(_("_Remove"), true));
_FontsContextMenu.append(*mi);
mi->signal_activate().connect(rem);
mi->show();
@@ -986,7 +985,8 @@ void SvgFontsDialog::add_font(){
}
SvgFontsDialog::SvgFontsDialog()
- : UI::Widget::Panel("", "/dialogs/svgfonts", SP_VERB_DIALOG_SVG_FONTS), _add(Gtk::Stock::NEW)
+ : UI::Widget::Panel("", "/dialogs/svgfonts", SP_VERB_DIALOG_SVG_FONTS),
+ _add(_("_New"), true)
{
kerning_slider = Gtk::manage(new Gtk::Scale(Gtk::ORIENTATION_HORIZONTAL));
_add.signal_clicked().connect(sigc::mem_fun(*this, &SvgFontsDialog::add_font));
diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp
index a38085c85..94f307828 100644
--- a/src/ui/dialog/text-edit.cpp
+++ b/src/ui/dialog/text-edit.cpp
@@ -29,7 +29,6 @@ extern "C" {
}
#endif
-#include <gtkmm/stock.h>
#include <libnrtype/font-lister.h>
#include "helper/window.h"
@@ -64,8 +63,8 @@ TextEdit::TextEdit()
text_label(_("_Text"), true),
vari_label(_("_Variants"), true),
setasdefault_button(_("Set as _default")),
- close_button(Gtk::Stock::CLOSE),
- apply_button(Gtk::Stock::APPLY),
+ close_button(_("_Close"), true),
+ apply_button(_("_Apply"), true),
desktop(NULL),
deskTrack(),
selectChangedConn(),
diff --git a/src/ui/dialog/text-edit.h b/src/ui/dialog/text-edit.h
index e974874d2..1fc0099fb 100644
--- a/src/ui/dialog/text-edit.h
+++ b/src/ui/dialog/text-edit.h
@@ -22,6 +22,7 @@
# include <config.h>
#endif
+#include <gtkmm/alignment.h>
#include <gtkmm/box.h>
#include <gtkmm/notebook.h>
#include <gtkmm/button.h>
diff --git a/src/ui/dialog/tracedialog.cpp b/src/ui/dialog/tracedialog.cpp
index 1c0cb5708..a1d4d88b8 100644
--- a/src/ui/dialog/tracedialog.cpp
+++ b/src/ui/dialog/tracedialog.cpp
@@ -21,7 +21,6 @@
#include <gtkmm/radiobutton.h>
#include "ui/widget/spinbutton.h"
#include "ui/widget/frame.h"
-#include <gtkmm/stock.h>
#include <glibmm/i18n.h>
@@ -813,12 +812,12 @@ TraceDialogImpl::TraceDialogImpl() :
mainResetButton ->set_tooltip_text(_("Reset all settings to defaults"));
//## The OK button
- mainCancelButton = addResponseButton(Gtk::Stock::STOP, GTK_RESPONSE_CANCEL);
+ mainCancelButton = addResponseButton(_("_Stop"), GTK_RESPONSE_CANCEL);
if (mainCancelButton) {
mainCancelButton->set_tooltip_text(_("Abort a trace in progress"));
mainCancelButton->set_sensitive(false);
}
- mainOkButton = addResponseButton(Gtk::Stock::OK, GTK_RESPONSE_OK);
+ mainOkButton = addResponseButton(_("_OK"), GTK_RESPONSE_OK);
mainOkButton->set_tooltip_text(_("Execute the trace"));
show_all_children();
diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp
index 5ec47b0dc..d209a450c 100644
--- a/src/ui/dialog/transformation.cpp
+++ b/src/ui/dialog/transformation.cpp
@@ -16,7 +16,6 @@
#endif
#include <gtkmm/dialog.h>
-#include <gtkmm/stock.h>
#include <2geom/transforms.h>
#include "document.h"
@@ -134,14 +133,14 @@ Transformation::Transformation()
updateSelection(PAGE_MOVE, _getSelection());
- resetButton = addResponseButton(Gtk::Stock::CLEAR, 0);
+ resetButton = addResponseButton(_("_Clear"), 0);
if (resetButton) {
resetButton->set_tooltip_text(_("Reset the values on the current tab to defaults"));
resetButton->set_sensitive(true);
resetButton->signal_clicked().connect(sigc::mem_fun(*this, &Transformation::onClear));
}
- applyButton = addResponseButton(Gtk::Stock::APPLY, Gtk::RESPONSE_APPLY);
+ applyButton = addResponseButton(_("_Apply"), Gtk::RESPONSE_APPLY);
if (applyButton) {
applyButton->set_tooltip_text(_("Apply transformation to selection"));
applyButton->set_sensitive(false);
diff --git a/src/ui/dialog/undo-history.cpp b/src/ui/dialog/undo-history.cpp
index 53aa7e6ff..bf5bdc76d 100644
--- a/src/ui/dialog/undo-history.cpp
+++ b/src/ui/dialog/undo-history.cpp
@@ -24,7 +24,7 @@
#include "util/signal-blocker.h"
#include "desktop.h"
-#include <gtkmm/invisible.h>
+#include <gtkmm/icontheme.h>
namespace Inkscape {
namespace UI {
@@ -43,8 +43,8 @@ void CellRendererSPIcon::render_vfunc(const Cairo::RefPtr<Cairo::Context>& cr,
// if the icon isn't cached, render it to a pixbuf
if ( !_icon_cache[_property_event_type] ) {
- Glib::ustring image = Inkscape::Verb::get(_property_event_type)->get_image();
- Gtk::Widget* icon = sp_icon_get_icon(image, Inkscape::ICON_SIZE_MENU);
+ Glib::ustring image_name = Inkscape::Verb::get(_property_event_type)->get_image();
+ Gtk::Widget* icon = sp_icon_get_icon(image_name, Inkscape::ICON_SIZE_MENU);
if (icon) {
@@ -54,8 +54,8 @@ void CellRendererSPIcon::render_vfunc(const Cairo::RefPtr<Cairo::Context>& cr,
sp_icon_fetch_pixbuf(sp_icon);
_property_icon = Glib::wrap(sp_icon->pb, true);
} else if ( GTK_IS_IMAGE(icon->gobj()) ) {
- _property_icon = Gtk::Invisible().render_icon_pixbuf(Gtk::StockID(image),
- Gtk::ICON_SIZE_MENU);
+ auto icon_theme = Gtk::IconTheme::get_default();
+ _property_icon = icon_theme->load_icon(image_name, 16);
} else {
delete icon;
return;
diff --git a/src/ui/dialog/xml-tree.cpp b/src/ui/dialog/xml-tree.cpp
index d05c52531..fa35b092a 100644
--- a/src/ui/dialog/xml-tree.cpp
+++ b/src/ui/dialog/xml-tree.cpp
@@ -19,7 +19,6 @@
#include "xml-tree.h"
#include "widgets/icon.h"
#include <glibmm/i18n.h>
-#include <gtkmm/stock.h>
#include "desktop.h"
diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp
index e0c767509..d50c56b76 100644
--- a/src/ui/interface.cpp
+++ b/src/ui/interface.cpp
@@ -73,8 +73,6 @@
#include "message-stack.h"
#include "ui/dialog/layer-properties.h"
-#include "widgets/image-menu-item.h"
-
using Inkscape::DocumentUndo;
/* Drag and Drop */
@@ -405,7 +403,7 @@ sp_ui_menuitem_add_icon( GtkWidget *item, gchar *icon_name )
icon = sp_icon_new( Inkscape::ICON_SIZE_MENU, icon_name );
gtk_widget_show(icon);
- image_menu_item_set_image((ImageMenuItem *) item, icon);
+ gtk_image_menu_item_set_image((GtkImageMenuItem *) item, icon);
} // end of sp_ui_menu_add_icon
void
@@ -459,7 +457,7 @@ static GtkWidget *sp_ui_menu_append_item_from_verb(GtkMenu *menu, Inkscape::Verb
if (radio) {
item = gtk_radio_menu_item_new_with_mnemonic(group, action->name);
} else {
- item = image_menu_item_new_with_mnemonic(action->name);
+ item = gtk_image_menu_item_new_with_mnemonic(action->name);
}
gtk_label_set_markup_with_mnemonic( GTK_LABEL(gtk_bin_get_child(GTK_BIN (item))), action->name);
diff --git a/src/ui/object-edit.cpp b/src/ui/object-edit.cpp
index 2763e6c4b..cf2c03396 100644
--- a/src/ui/object-edit.cpp
+++ b/src/ui/object-edit.cpp
@@ -43,7 +43,7 @@ static KnotHolder *sp_lpe_knot_holder(SPLPEItem *item, SPDesktop *desktop)
KnotHolder *knot_holder = new KnotHolder(desktop, item, NULL);
Inkscape::LivePathEffect::Effect *effect = item->getCurrentLPE();
- effect->addHandles(knot_holder, desktop, item);
+ effect->addHandles(knot_holder, item);
return knot_holder;
}
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index 0e5a9279d..d6e491ac3 100644
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
@@ -326,10 +326,7 @@ bool Handle::grabbed(GdkEventMotion *)
void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event)
{
- if (tools_isactive(_desktop, TOOLS_NODES)) {
- Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(_desktop->event_context);
- nt->update_helperpath();
- }
+ Inkscape::UI::Tools::sp_update_helperpath();
Geom::Point parent_pos = _parent->position();
Geom::Point origin = _last_drag_origin();
SnapManager &sm = _desktop->namedview->snap_manager;
@@ -1199,10 +1196,7 @@ bool Node::grabbed(GdkEventMotion *event)
void Node::dragged(Geom::Point &new_pos, GdkEventMotion *event)
{
- if (tools_isactive(_desktop, TOOLS_NODES)) {
- Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(_desktop->event_context);
- nt->update_helperpath();
- }
+ Inkscape::UI::Tools::sp_update_helperpath();
// For a note on how snapping is implemented in Inkscape, see snap.h.
SnapManager &sm = _desktop->namedview->snap_manager;
// even if we won't really snap, we might still call the one of the
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp
index f316bea38..5746a8f86 100644
--- a/src/ui/tool/path-manipulator.cpp
+++ b/src/ui/tool/path-manipulator.cpp
@@ -1492,11 +1492,14 @@ void PathManipulator::_setGeometry()
}
} else {
if (empty()) return;
- //XML Tree being used here directly while it shouldn't be.
- if (_path->getRepr()->attribute("inkscape:original-d"))
- _path->set_original_curve(_spcurve, false, false);
- else
+ if (SPCurve * original = _path->get_original_curve()){
+ if(!_spcurve->is_equal(original)) {
+ _path->set_original_curve(_spcurve, false, false);
+ delete original;
+ }
+ } else if(!_spcurve->is_equal(_path->get_curve())) {
_path->setCurve(_spcurve, false);
+ }
}
}
diff --git a/src/ui/tool/transform-handle-set.cpp b/src/ui/tool/transform-handle-set.cpp
index 33015fe11..083a7d0ba 100644
--- a/src/ui/tool/transform-handle-set.cpp
+++ b/src/ui/tool/transform-handle-set.cpp
@@ -183,6 +183,11 @@ void TransformHandle::ungrabbed(GdkEventButton *)
_setState(_state);
endTransform();
_th.signal_commit.emit(getCommitEvent());
+
+ //updates the positions of the nodes
+ Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(_th._desktop->event_context);
+ ControlPointSelection* selection = nt->_selected_nodes;
+ selection->setOriginalPoints();
}
diff --git a/src/ui/tools/calligraphic-tool.cpp b/src/ui/tools/calligraphic-tool.cpp
index 9b4dbb1a2..c2b86b538 100644
--- a/src/ui/tools/calligraphic-tool.cpp
+++ b/src/ui/tools/calligraphic-tool.cpp
@@ -921,10 +921,10 @@ void CalligraphicTool::set_to_accumulated(bool unionize, bool subtract) {
if (unionize) {
desktop->getSelection()->add(this->repr);
- sp_selected_path_union_skip_undo(desktop->getSelection());
+ desktop->getSelection()->pathUnion(true);
} else if (subtract) {
desktop->getSelection()->add(this->repr);
- sp_selected_path_diff_skip_undo(desktop->getSelection());
+ desktop->getSelection()->pathDiff(true);
} else {
if (this->keep_selected) {
desktop->getSelection()->set(this->repr);
diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp
index 4f941e534..ae312e054 100644
--- a/src/ui/tools/eraser-tool.cpp
+++ b/src/ui/tools/eraser-tool.cpp
@@ -714,7 +714,7 @@ void EraserTool::set_to_accumulated() {
Inkscape::GC::release(dup); // parent takes over
selection->set(dup);
if (!this->nowidth) {
- sp_selected_path_union_skip_undo(selection);
+ selection->pathUnion(true);
}
selection->add(item);
if(item->style->fill_rule.value == SP_WIND_RULE_EVENODD){
@@ -725,9 +725,9 @@ void EraserTool::set_to_accumulated() {
css = 0;
}
if (this->nowidth) {
- sp_selected_path_cut_skip_undo(selection);
+ selection->pathCut(true);
} else {
- sp_selected_path_diff_skip_undo(selection);
+ selection->pathDiff(true);
}
workDone = true; // TODO set this only if something was cut.
bool break_apart = prefs->getBool("/tools/eraser/break_apart", false);
@@ -762,7 +762,7 @@ void EraserTool::set_to_accumulated() {
this->repr->parent()->appendChild(dup);
Inkscape::GC::release(dup); // parent takes over
selection->set(dup);
- sp_selected_path_union_skip_undo(selection);
+ selection->pathUnion(true);
if (bbox && bbox->intersects(*eraserBbox)) {
SPClipPath *clip_path = item->clip_ref->getObject();
if (clip_path) {
@@ -786,7 +786,7 @@ void EraserTool::set_to_accumulated() {
sp_object_unref(clip_path);
selection->raiseToTop(true);
selection->add(dup_clip);
- sp_selected_path_diff_skip_undo(selection);
+ selection->pathDiff(true);
SPItem * clip = SP_ITEM(*(selection->items().begin()));
}
}
@@ -802,7 +802,7 @@ void EraserTool::set_to_accumulated() {
rect->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
selection->raiseToTop(true);
selection->add(rect);
- sp_selected_path_diff_skip_undo(selection);
+ selection->pathDiff(true);
}
selection->raiseToTop(true);
selection->add(item);
diff --git a/src/ui/tools/flood-tool.cpp b/src/ui/tools/flood-tool.cpp
index 0b893a7ba..1801a0ea0 100644
--- a/src/ui/tools/flood-tool.cpp
+++ b/src/ui/tools/flood-tool.cpp
@@ -89,10 +89,10 @@ Glib::ustring ch_init[8] = {
const std::vector<Glib::ustring> FloodTool::channel_list( ch_init, ch_init+8 );
Glib::ustring gap_init[4] = {
- C_("Flood autogap", "None"),
- C_("Flood autogap", "Small"),
- C_("Flood autogap", "Medium"),
- C_("Flood autogap", "Large")
+ NC_("Flood autogap", "None"),
+ NC_("Flood autogap", "Small"),
+ NC_("Flood autogap", "Medium"),
+ NC_("Flood autogap", "Large")
};
const std::vector<Glib::ustring> FloodTool::gap_list( gap_init, gap_init+4 );
@@ -446,7 +446,7 @@ static void do_trace(bitmap_coords_info bci, guchar *trace_px, SPDesktop *deskto
ngettext("Area filled, path with <b>%d</b> node created and unioned with selection.","Area filled, path with <b>%d</b> nodes created and unioned with selection.",
SP_PATH(reprobj)->nodesInPath()), SP_PATH(reprobj)->nodesInPath() );
selection->add(reprobj);
- sp_selected_path_union_skip_undo(desktop->getSelection());
+ selection->pathUnion(true);
} else {
desktop->messageStack()->flashF( Inkscape::WARNING_MESSAGE,
ngettext("Area filled, path with <b>%d</b> node created.","Area filled, path with <b>%d</b> nodes created.",
diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp
index 16df225e0..750596808 100644
--- a/src/ui/tools/gradient-tool.cpp
+++ b/src/ui/tools/gradient-tool.cpp
@@ -79,6 +79,9 @@ GradientTool::~GradientTool() {
delete this->subselcon;
}
+// This must match GrPointType enum sp-gradient.h
+// We should move this to a shared header (can't simply move to gradient.h since that would require
+// including <glibmm/i18n.h> which messes up "N_" in extensions... argh!).
const gchar *gr_handle_descr [] = {
N_("Linear gradient <b>start</b>"), //POINT_LG_BEGIN
N_("Linear gradient <b>end</b>"),
@@ -88,7 +91,10 @@ const gchar *gr_handle_descr [] = {
N_("Radial gradient <b>radius</b>"),
N_("Radial gradient <b>focus</b>"), // POINT_RG_FOCUS
N_("Radial gradient <b>mid stop</b>"),
- N_("Radial gradient <b>mid stop</b>")
+ N_("Radial gradient <b>mid stop</b>"),
+ N_("Mesh gradient <b>corner</b>"),
+ N_("Mesh gradient <b>handle</b>"),
+ N_("Mesh gradient <b>tensor</b>")
};
void GradientTool::selection_changed(Inkscape::Selection*) {
@@ -831,6 +837,16 @@ bool GradientTool::root_handler(GdkEvent* event) {
ret = TRUE;
break;
+ case GDK_KEY_i:
+ case GDK_KEY_I:
+ if (MOD__SHIFT_ONLY(event)) {
+ // Shift+I - insert stops (alternate keybinding for keyboards
+ // that don't have the Insert key)
+ sp_gradient_context_add_stops_between_selected_stops (this);
+ ret = TRUE;
+ }
+ break;
+
case GDK_KEY_Delete:
case GDK_KEY_KP_Delete:
case GDK_KEY_BackSpace:
diff --git a/src/ui/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp
index c6983b94a..e628094d9 100644
--- a/src/ui/tools/mesh-tool.cpp
+++ b/src/ui/tools/mesh-tool.cpp
@@ -41,6 +41,7 @@
#include "sp-text.h"
#include "sp-defs.h"
#include "style.h"
+#include "ui/control-manager.h"
// Gradient specific
#include "gradient-drag.h"
@@ -74,6 +75,9 @@ MeshTool::MeshTool()
: ToolBase(cursor_gradient_xpm, 4, 4)
, cursor_addnode(false)
, node_added(false)
+ , show_handles(true)
+ , edit_fill(true)
+ , edit_stroke(true)
// TODO: Why are these connections stored as pointers?
, selcon(NULL)
, subselcon(NULL)
@@ -92,7 +96,19 @@ MeshTool::~MeshTool() {
delete this->subselcon;
}
+// This must match GrPointType enum sp-gradient.h
+// We should move this to a shared header (can't simply move to gradient.h since that would require
+// including <glibmm/i18n.h> which messes up "N_" in extensions... argh!).
const gchar *ms_handle_descr [] = {
+ N_("Linear gradient <b>start</b>"), //POINT_LG_BEGIN
+ N_("Linear gradient <b>end</b>"),
+ N_("Linear gradient <b>mid stop</b>"),
+ N_("Radial gradient <b>center</b>"),
+ N_("Radial gradient <b>radius</b>"),
+ N_("Radial gradient <b>radius</b>"),
+ N_("Radial gradient <b>focus</b>"), // POINT_RG_FOCUS
+ N_("Radial gradient <b>mid stop</b>"),
+ N_("Radial gradient <b>mid stop</b>"),
N_("Mesh gradient <b>corner</b>"),
N_("Mesh gradient <b>handle</b>"),
N_("Mesh gradient <b>tensor</b>")
@@ -240,7 +256,25 @@ void MeshTool::setup() {
)
));
+ sp_event_context_read(this, "show_handles");
+ sp_event_context_read(this, "edit_fill");
+ sp_event_context_read(this, "edit_stroke");
+
this->selection_changed(selection);
+
+}
+
+void MeshTool::set(const Inkscape::Preferences::Entry& value) {
+ Glib::ustring entry_name = value.getEntryName();
+ if (entry_name == "show_handles") {
+ this->show_handles = value.getBool(true);
+ } else if (entry_name == "edit_fill") {
+ this->edit_fill = value.getBool(true);
+ } else if (entry_name == "edit_stroke") {
+ this->edit_stroke = value.getBool(true);
+ } else {
+ ToolBase::set(value);
+ }
}
void
@@ -266,32 +300,39 @@ sp_mesh_context_select_prev (ToolBase *event_context)
}
/**
-Returns true if mouse cursor over mesh edge.
+Returns vector of control lines mouse is over. Returns only first if 'first' is true.
*/
-static bool
-sp_mesh_context_is_over_line (MeshTool *rc, SPCtrlLine *line, Geom::Point event_p)
+static std::vector<SPCtrlCurve *>
+sp_mesh_context_over_line (MeshTool *rc, Geom::Point event_p, bool first = true)
{
- if (!SP_IS_CTRLCURVE(line) ) {
- return false;
- }
-
SPDesktop *desktop = SP_EVENT_CONTEXT (rc)->desktop;
//Translate mouse point into proper coord system
rc->mousepoint_doc = desktop->w2d(event_p);
- SPCtrlCurve *curve = SP_CTRLCURVE(line);
- Geom::BezierCurveN<3> b( curve->p0, curve->p1, curve->p2, curve->p3 );
- Geom::Coord coord = b.nearestTime( rc->mousepoint_doc ); // Coord == double
- Geom::Point nearest = b( coord );
+ double tolerance = (double) SP_EVENT_CONTEXT(rc)->tolerance;
+
+ GrDrag *drag = rc->_grdrag;
- double dist_screen = Geom::L2 (rc->mousepoint_doc - nearest) * desktop->current_zoom();
+ std::vector<SPCtrlCurve *> selected;
- double tolerance = (double) SP_EVENT_CONTEXT(rc)->tolerance;
+ for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end(); ++l) {
+ if (!SP_IS_CTRLCURVE(*l)) continue;
- bool close = (dist_screen < tolerance);
+ SPCtrlCurve *curve = SP_CTRLCURVE(*l);
+ Geom::BezierCurveN<3> b( curve->p0, curve->p1, curve->p2, curve->p3 );
+ Geom::Coord coord = b.nearestTime( rc->mousepoint_doc ); // Coord == double
+ Geom::Point nearest = b( coord );
- return close;
+ double dist_screen = Geom::L2 (rc->mousepoint_doc - nearest) * desktop->current_zoom();
+ if (dist_screen < tolerance) {
+ selected.push_back(curve);
+ if (first) {
+ break;
+ }
+ }
+ }
+ return selected;
}
@@ -336,12 +377,13 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation )
std::map<SPMeshGradient*, std::vector<guint> > points;
std::map<SPMeshGradient*, SPItem*> items;
-
+ std::map<SPMeshGradient*, Inkscape::PaintTarget> fill_or_stroke;
+
// Get list of selected draggers for each mesh.
- // For all selected draggers
+ // For all selected draggers (a dragger may include draggerables from different meshes).
for (std::set<GrDragger *>::const_iterator i = drag->selected.begin(); i != drag->selected.end(); ++i) {
GrDragger *dragger = *i;
- // For all draggables of dragger
+ // For all draggables of dragger (a draggable corresponds to a unique mesh).
for (std::vector<GrDraggable *>::const_iterator j = dragger->draggables.begin(); j != dragger->draggables.end() ; ++j) {
GrDraggable *d = *j;
@@ -354,6 +396,7 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation )
// Collect points together for same gradient
points[gradient].push_back( d->point_i );
items[gradient] = d->item;
+ fill_or_stroke[gradient] = d->fill_or_stroke ? Inkscape::FOR_FILL: Inkscape::FOR_STROKE;
}
}
@@ -389,6 +432,11 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation )
noperation += mg->array.color_pick( iter->second, items[iter->first] );
break;
+ case MG_CORNER_INSERT:
+ // std::cout << "INSERT" << std::endl;
+ noperation += mg->array.insert( iter->second );
+ break;
+
default:
std::cout << "sp_mesh_corner_operation: unknown operation" << std::endl;
}
@@ -402,22 +450,31 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation )
case MG_CORNER_SIDE_TOGGLE:
DocumentUndo::done(doc, SP_VERB_CONTEXT_MESH, _("Toggled mesh path type."));
+ drag->local_change = true; // Don't create new draggers.
break;
case MG_CORNER_SIDE_ARC:
DocumentUndo::done(doc, SP_VERB_CONTEXT_MESH, _("Approximated arc for mesh side."));
+ drag->local_change = true; // Don't create new draggers.
break;
case MG_CORNER_TENSOR_TOGGLE:
DocumentUndo::done(doc, SP_VERB_CONTEXT_MESH, _("Toggled mesh tensors."));
+ drag->local_change = true; // Don't create new draggers.
break;
case MG_CORNER_COLOR_SMOOTH:
DocumentUndo::done(doc, SP_VERB_CONTEXT_MESH, _("Smoothed mesh corner color."));
+ drag->local_change = true; // Don't create new draggers.
break;
case MG_CORNER_COLOR_PICK:
DocumentUndo::done(doc, SP_VERB_CONTEXT_MESH, _("Picked mesh corner color."));
+ drag->local_change = true; // Don't create new draggers.
+ break;
+
+ case MG_CORNER_INSERT:
+ DocumentUndo::done(doc, SP_VERB_CONTEXT_MESH, _("Inserted new row or column."));
break;
default:
@@ -426,7 +483,9 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation )
}
}
}
- drag->updateDraggers();
+
+ // Not needed. Update is done via gr_drag_sel_modified().
+ // drag->updateDraggers();
}
@@ -456,38 +515,33 @@ sp_mesh_context_fit_mesh_in_bbox (MeshTool *rc)
SPItem *item = *i;
SPStyle *style = item->style;
- if (style && (style->fill.isPaintserver())) {
- SPPaintServer *server = item->style->getFillPaintServer();
- if ( SP_IS_MESHGRADIENT(server) ) {
-
- SPMeshGradient *gradient = SP_MESHGRADIENT(server);
- SPCurve * outline = gradient->array.outline_path();
- Geom::OptRect mesh_bbox = outline->get_pathvector().boundsExact();
- outline->unref();
- Geom::OptRect item_bbox = item->geometricBounds();
-
- if ((*mesh_bbox).width() == 0) {
- continue;
- }
- if ((*mesh_bbox).height() == 0) {
- continue;
+ if (style) {
+
+ if (style->fill.isPaintserver()) {
+ SPPaintServer *server = item->style->getFillPaintServer();
+ if ( SP_IS_MESHGRADIENT(server) ) {
+
+ Geom::OptRect item_bbox = item->geometricBounds();
+ SPMeshGradient *gradient = SP_MESHGRADIENT(server);
+ if (gradient->array.fill_box( item_bbox )) {
+ changed = true;
+ }
}
- double scale_x = (*item_bbox).width() /(*mesh_bbox).width() ;
- double scale_y = (*item_bbox).height()/(*mesh_bbox).height();
-
- Geom::Translate t1(-(*mesh_bbox).min());
- Geom::Scale scale(scale_x,scale_y);
- Geom::Translate t2((*item_bbox).min());
- Geom::Affine transform = t1 * scale * t2;
- if (!transform.isIdentity() ) {
- gradient->array.transform(transform);
- gradient->array.write( gradient );
- gradient->requestModified(SP_OBJECT_MODIFIED_FLAG);
- changed = true;
+ }
+
+ if (style->stroke.isPaintserver()) {
+ SPPaintServer *server = item->style->getStrokePaintServer();
+ if ( SP_IS_MESHGRADIENT(server) ) {
+
+ Geom::OptRect item_bbox = item->visualBounds();
+ SPMeshGradient *gradient = SP_MESHGRADIENT(server);
+ if (gradient->array.fill_box( item_bbox )) {
+ changed = true;
+ }
}
}
+
}
-
}
if (changed) {
DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MESH,
@@ -523,42 +577,42 @@ bool MeshTool::root_handler(GdkEvent* event) {
// Double click:
// If over a mesh line, divide mesh row/column
- // If not over a line, create new gradients for selected objects.
+ // If not over a line and no mesh, create new mesh for top selected object.
if ( event->button.button == 1 ) {
- // Are we over a mesh line?
- bool over_line = false;
- if (! drag->lines.empty()) {
- for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) {
- over_line |= sp_mesh_context_is_over_line (this, *l, Geom::Point(event->motion.x, event->motion.y));
- }
- }
+ // Are we over a mesh line?
+ std::vector<SPCtrlCurve *> over_line =
+ sp_mesh_context_over_line(this, Geom::Point(event->motion.x, event->motion.y));
- if (over_line) {
+ if (!over_line.empty()) {
// We take the first item in selection, because with doubleclick, the first click
// always resets selection to the single object under cursor
sp_mesh_context_split_near_point(this, selection->items().front(), this->mousepoint_doc, event->button.time);
} else {
- sp_mesh_new_default(*this);
// Create a new gradient with default coordinates.
-// auto items= selection->items();
-// for(auto i=items.begin();i!=items.end();++i){
-// SPItem *item = *i;
-// SPGradientType new_type = SP_GRADIENT_TYPE_MESH;
-// Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
-
-// #ifdef DEBUG_MESH
-// std::cout << "sp_mesh_context_root_handler: creating new mesh on: " << (fsmode == Inkscape::FOR_FILL ? "Fill" : "Stroke") << std::endl;
-// #endif
-// SPGradient *vector = sp_gradient_vector_for_object(desktop->getDocument(), desktop, item, fsmode);
-
-// SPGradient *priv = sp_item_set_gradient(item, vector, new_type, fsmode);
-// sp_gradient_reset_to_userspace(priv, item);
-// }
-
-// DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MESH,
-// _("Create default mesh"));
+
+ // Check if object already has mesh... if it does,
+ // don't create new mesh with click-drag.
+ bool has_mesh = false;
+ if (!selection->isEmpty()) {
+ SPStyle *style = selection->items().front()->style;
+ if (style) {
+ Inkscape::PaintTarget fill_or_stroke =
+ (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ?
+ Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
+ SPPaintServer *server =
+ (fill_or_stroke == Inkscape::FOR_FILL) ?
+ style->getFillPaintServer():
+ style->getStrokePaintServer();
+ if (server && SP_IS_MESHGRADIENT(server))
+ has_mesh = true;
+ }
+ }
+
+ if (!has_mesh) {
+ sp_mesh_new_default(*this);
+ }
}
ret = TRUE;
@@ -570,10 +624,36 @@ bool MeshTool::root_handler(GdkEvent* event) {
#ifdef DEBUG_MESH
std::cout << "sp_mesh_context_root_handler: GDK_BUTTON_PRESS" << std::endl;
#endif
+
// Button down
- // If Shift key down: do rubber band selection
- // Else set origin for drag. A drag creates a new gradient if one does not exist
+ // If mesh already exists, do rubber band selection.
+ // Else set origin for drag which will create a new gradient.
if ( event->button.button == 1 && !this->space_panning ) {
+
+ // Are we over a mesh line?
+ std::vector<SPCtrlCurve *> over_line =
+ sp_mesh_context_over_line(this, Geom::Point(event->motion.x, event->motion.y), false);
+
+ if (!over_line.empty()) {
+ for (std::vector<SPCtrlCurve *>::const_iterator it = over_line.begin();
+ it != over_line.end(); ++it ) {
+ SPItem *item = (*it)->item;
+ Inkscape::PaintTarget fill_or_stroke =
+ (*it)->is_fill ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
+ GrDragger* dragger0 = drag->getDraggerFor(item, POINT_MG_CORNER, (*it)->corner0, fill_or_stroke);
+ GrDragger* dragger1 = drag->getDraggerFor(item, POINT_MG_CORNER, (*it)->corner1, fill_or_stroke);
+ bool add = (event->button.state & GDK_SHIFT_MASK);
+ bool toggle = (event->button.state & GDK_CONTROL_MASK);
+ if ( !add && !toggle ) {
+ drag->deselectAll();
+ }
+ drag->setSelected( dragger0, true, !toggle );
+ drag->setSelected( dragger1, true, !toggle );
+ }
+ ret = true;
+ break; // To avoid putting the following code in an else block.
+ }
+
Geom::Point button_w(event->button.x, event->button.y);
// save drag origin
@@ -584,25 +664,43 @@ bool MeshTool::root_handler(GdkEvent* event) {
dragging = true;
Geom::Point button_dt = desktop->w2d(button_w);
- if (event->button.state & GDK_SHIFT_MASK) {
- Inkscape::Rubberband::get(desktop)->start(desktop, button_dt);
- } else {
- // remember clicked item, disregarding groups, honoring Alt; do nothing with Crtl to
- // enable Ctrl+doubleclick of exactly the selected item(s)
- if (!(event->button.state & GDK_CONTROL_MASK)) {
- this->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE);
+ // Check if object already has mesh... if it does,
+ // don't create new mesh with click-drag.
+ bool has_mesh = false;
+ if (!selection->isEmpty()) {
+ SPStyle *style = selection->items().front()->style;
+ if (style) {
+ Inkscape::PaintTarget fill_or_stroke =
+ (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ?
+ Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
+ SPPaintServer *server =
+ (fill_or_stroke == Inkscape::FOR_FILL) ?
+ style->getFillPaintServer():
+ style->getStrokePaintServer();
+ if (server && SP_IS_MESHGRADIENT(server))
+ has_mesh = true;
}
+ }
- if (!selection->isEmpty()) {
- SnapManager &m = desktop->namedview->snap_manager;
- m.setup(desktop);
- m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE);
- m.unSetup();
- }
+ if (has_mesh) {
+ Inkscape::Rubberband::get(desktop)->start(desktop, button_dt);
+ }
- this->origin = button_dt;
+ // remember clicked item, disregarding groups, honoring Alt; do nothing with Crtl to
+ // enable Ctrl+doubleclick of exactly the selected item(s)
+ if (!(event->button.state & GDK_CONTROL_MASK)) {
+ this->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE);
}
+ if (!selection->isEmpty()) {
+ SnapManager &m = desktop->namedview->snap_manager;
+ m.setup(desktop);
+ m.freeSnapReturnByRef(button_dt, Inkscape::SNAPSOURCE_NODE_HANDLE);
+ m.unSetup();
+ }
+
+ this->origin = button_dt;
+
ret = TRUE;
}
break;
@@ -663,19 +761,14 @@ bool MeshTool::root_handler(GdkEvent* event) {
}
// Change cursor shape if over line
- bool over_line = false;
+ std::vector<SPCtrlCurve *> over_line =
+ sp_mesh_context_over_line(this, Geom::Point(event->motion.x, event->motion.y));
- if (!drag->lines.empty()) {
- for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() ; ++l) {
- over_line |= sp_mesh_context_is_over_line (this, *l, Geom::Point(event->motion.x, event->motion.y));
- }
- }
-
- if (this->cursor_addnode && !over_line) {
+ if (this->cursor_addnode && over_line.empty()) {
this->cursor_shape = cursor_gradient_xpm;
this->sp_event_context_update_cursor();
this->cursor_addnode = false;
- } else if (!this->cursor_addnode && over_line) {
+ } else if (!this->cursor_addnode && !over_line.empty()) {
this->cursor_shape = cursor_gradient_add_xpm;
this->sp_event_context_update_cursor();
this->cursor_addnode = true;
@@ -692,23 +785,15 @@ bool MeshTool::root_handler(GdkEvent* event) {
this->xp = this->yp = 0;
if ( event->button.button == 1 && !this->space_panning ) {
- // Check if over line
- bool over_line = false;
- SPCtrlLine *line = NULL;
-
- if (!drag->lines.empty()) {
- for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) {
- over_line = sp_mesh_context_is_over_line (this, *l, Geom::Point(event->motion.x, event->motion.y));
- if (over_line) {
- break;
- }
- }
- }
+ // Check if over line
+ std::vector<SPCtrlCurve *> over_line =
+ sp_mesh_context_over_line(this, Geom::Point(event->motion.x, event->motion.y));
if ( (event->button.state & GDK_CONTROL_MASK) && (event->button.state & GDK_MOD1_MASK ) ) {
- if (over_line && line) {
- sp_mesh_context_split_near_point(this, line->item, this->mousepoint_doc, 0);
+ if (!over_line.empty()) {
+ sp_mesh_context_split_near_point(this, over_line[0]->item,
+ this->mousepoint_doc, 0);
ret = TRUE;
}
} else {
@@ -721,22 +806,47 @@ bool MeshTool::root_handler(GdkEvent* event) {
}
if (!this->within_tolerance) {
- // we've been dragging, either create a new gradient
- // or rubberband-select if we have rubberband
- Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
-
- if (r->is_started() && !this->within_tolerance) {
- // this was a rubberband drag
- if (r->getMode() == RUBBERBAND_MODE_RECT) {
- Geom::OptRect const b = r->getRectangle();
- drag->selectRect(*b);
+
+ // Check if object already has mesh... if it does,
+ // don't create new mesh with click-drag.
+ bool has_mesh = false;
+ if (!selection->isEmpty()) {
+ SPStyle *style = selection->items().front()->style;
+ if (style) {
+ Inkscape::PaintTarget fill_or_stroke =
+ (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ?
+ Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
+ SPPaintServer *server =
+ (fill_or_stroke == Inkscape::FOR_FILL) ?
+ style->getFillPaintServer():
+ style->getStrokePaintServer();
+ if (server && SP_IS_MESHGRADIENT(server))
+ has_mesh = true;
}
- } else {
- // Create a new mesh gradient
+ }
+
+ if (!has_mesh) {
sp_mesh_new_default(*this);
+ } else {
+
+ // we've been dragging, either create a new gradient
+ // or rubberband-select if we have rubberband
+ Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
+
+ if (r->is_started() && !this->within_tolerance) {
+ // this was a rubberband drag
+ if (r->getMode() == RUBBERBAND_MODE_RECT) {
+ Geom::OptRect const b = r->getRectangle();
+ if (!(event->button.state & GDK_SHIFT_MASK)) {
+ drag->deselectAll();
+ }
+ drag->selectRect(*b);
+ }
+ }
}
+
} else if (this->item_to_select) {
- if (over_line && line) {
+ if (!over_line.empty()) {
// Clicked on an existing mesh line, don't change selection. This stops
// possible change in selection during a double click with overlapping objects
} else {
@@ -744,15 +854,21 @@ bool MeshTool::root_handler(GdkEvent* event) {
if (event->button.state & GDK_SHIFT_MASK) {
selection->toggle(this->item_to_select);
} else {
+ drag->deselectAll();
selection->set(this->item_to_select);
}
}
} else {
- // click in an empty space; do the same as Esc
- if (!drag->selected.empty()) {
- drag->deselectAll();
+ if (!over_line.empty()) {
+ // Clicked on an existing mesh line, don't change selection. This stops
+ // possible change in selection during a double click with overlapping objects
} else {
- selection->clear();
+ // click in an empty space; do the same as Esc
+ if (!drag->selected.empty()) {
+ drag->deselectAll();
+ } else {
+ selection->clear();
+ }
}
}
@@ -780,10 +896,11 @@ bool MeshTool::root_handler(GdkEvent* event) {
case GDK_KEY_Shift_R:
case GDK_KEY_Meta_L: // Meta is when you press Shift+Alt (at least on my machine)
case GDK_KEY_Meta_R:
- sp_event_show_modifier_tip (this->defaultMessageContext(), event,
- _("FIXME<b>Ctrl</b>: snap mesh angle"),
- _("FIXME<b>Shift</b>: draw mesh around the starting point"),
- NULL);
+
+ // sp_event_show_modifier_tip (this->defaultMessageContext(), event,
+ // _("FIXME<b>Ctrl</b>: snap mesh angle"),
+ // _("FIXME<b>Shift</b>: draw mesh around the starting point"),
+ // NULL);
break;
case GDK_KEY_A:
@@ -901,25 +1018,33 @@ bool MeshTool::root_handler(GdkEvent* event) {
}
break;
+ // Mesh Operations --------------------------------------------
+
case GDK_KEY_Insert:
case GDK_KEY_KP_Insert:
// with any modifiers:
- //sp_gradient_context_add_stops_between_selected_stops (rc);
- std::cout << "Inserting stops between selected stops not implemented yet" << std::endl;
+ sp_mesh_context_corner_operation ( this, MG_CORNER_INSERT );
ret = TRUE;
break;
+ case GDK_KEY_i:
+ case GDK_KEY_I:
+ if (MOD__SHIFT_ONLY(event)) {
+ // Shift+I - insert corners (alternate keybinding for keyboards
+ // that don't have the Insert key)
+ sp_mesh_context_corner_operation ( this, MG_CORNER_INSERT );
+ ret = TRUE;
+ }
+ break;
+
case GDK_KEY_Delete:
case GDK_KEY_KP_Delete:
case GDK_KEY_BackSpace:
if ( !drag->selected.empty() ) {
- std::cout << "Deleting mesh stops not implemented yet" << std::endl;
ret = TRUE;
}
break;
- // Mesh Operations --------------------------------------------
-
case GDK_KEY_b: // Toggle mesh side between lineto and curveto.
case GDK_KEY_B:
if (MOD__ALT(event) && drag->isNonEmpty() && drag->hasSelection()) {
@@ -1011,6 +1136,16 @@ static void sp_mesh_new_default(MeshTool &rc) {
(prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ?
Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
+ // Ensure mesh is immediately editable.
+ // Editting both fill and stroke at same time doesn't work well so avoid.
+ if (fill_or_stroke == Inkscape::FOR_FILL) {
+ prefs->setBool("/tools/mesh/edit_fill", true );
+ prefs->setBool("/tools/mesh/edit_stroke", false);
+ } else {
+ prefs->setBool("/tools/mesh/edit_fill", false);
+ prefs->setBool("/tools/mesh/edit_stroke", true );
+ }
+
// HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs
SPCSSAttr *css = sp_repr_css_attr_new();
sp_repr_css_set_property(css, "fill-opacity", "1.0");
@@ -1065,7 +1200,6 @@ static void sp_mesh_new_default(MeshTool &rc) {
}
}
-
}
}
}
diff --git a/src/ui/tools/mesh-tool.h b/src/ui/tools/mesh-tool.h
index f142bfd9c..1f012dc53 100644
--- a/src/ui/tools/mesh-tool.h
+++ b/src/ui/tools/mesh-tool.h
@@ -31,29 +31,34 @@ namespace Tools {
class MeshTool : public ToolBase {
public:
- MeshTool();
- virtual ~MeshTool();
+ MeshTool();
+ virtual ~MeshTool();
Geom::Point origin;
- bool cursor_addnode;
-
- bool node_added;
-
Geom::Point mousepoint_doc; // stores mousepoint when over_line in doc coords
sigc::connection *selcon;
sigc::connection *subselcon;
- static const std::string prefsPath;
+ static const std::string prefsPath;
- virtual void setup();
- virtual bool root_handler(GdkEvent* event);
+ virtual void setup();
+ virtual void set(const Inkscape::Preferences::Entry& val);
+ virtual bool root_handler(GdkEvent* event);
- virtual const std::string& getPrefsPath();
+ virtual const std::string& getPrefsPath();
private:
- void selection_changed(Inkscape::Selection* sel);
+ void selection_changed(Inkscape::Selection* sel);
+
+ bool cursor_addnode;
+ bool node_added;
+ bool show_handles;
+ bool edit_fill;
+ bool edit_stroke;
+
+
};
void sp_mesh_context_select_next(ToolBase *event_context);
diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp
index f3679b40f..0c948c91c 100644
--- a/src/ui/tools/node-tool.cpp
+++ b/src/ui/tools/node-tool.cpp
@@ -32,6 +32,8 @@
#include "sp-text.h"
#include "ui/control-manager.h"
#include "ui/tools/node-tool.h"
+#include "ui/tools-switch.h"
+#include "ui/tools/tool-base.h"
#include "ui/tool/control-point-selection.h"
#include "ui/tool/event-utils.h"
#include "ui/tool/multi-path-manipulator.h"
@@ -209,7 +211,7 @@ void NodeTool::setup() {
this->_sizeUpdatedConn = ControlManager::getManager().connectCtrlSizeChanged(
sigc::mem_fun(this, &NodeTool::handleControlUiStyleChange)
);
-
+ this->helperpath_tmpitem = NULL;
this->_selected_nodes = new Inkscape::UI::ControlPointSelection(this->desktop, this->_transform_handle_group);
data.node_data.selection = this->_selected_nodes;
@@ -237,7 +239,6 @@ void NodeTool::setup() {
)))
);
- this->helperpath_tmpitem = NULL;
this->cursor_drag = false;
this->show_transform_handles = true;
this->single_node_transform_handles = false;
@@ -270,29 +271,34 @@ void NodeTool::setup() {
}
this->desktop->emitToolSubselectionChanged(NULL); // sets the coord entry fields to inactive
- this->update_helperpath();
+ sp_update_helperpath();
}
// show helper paths of the applied LPE, if any
-void NodeTool::update_helperpath () {
- Inkscape::Selection *selection = this->desktop->getSelection();
-
- if (this->helperpath_tmpitem) {
- this->desktop->remove_temporary_canvasitem(this->helperpath_tmpitem);
- this->helperpath_tmpitem = NULL;
+void sp_update_helperpath() {
+ SPDesktop * desktop = SP_ACTIVE_DESKTOP;
+ if (!desktop || !tools_isactive(desktop, TOOLS_NODES)) {
+ return;
+ }
+ Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(desktop->event_context);
+ Inkscape::Selection *selection = desktop->getSelection();
+ if (nt->helperpath_tmpitem) {
+ desktop->remove_temporary_canvasitem(nt->helperpath_tmpitem);
+ nt->helperpath_tmpitem = NULL;
}
if (SP_IS_LPE_ITEM(selection->singleItem())) {
Inkscape::LivePathEffect::Effect *lpe = SP_LPE_ITEM(selection->singleItem())->getCurrentLPE();
if (lpe && lpe->isVisible()/* && lpe->showOrigPath()*/) {
- Inkscape::UI::ControlPointSelection *selectionNodes = _selected_nodes;
+
+ Inkscape::UI::ControlPointSelection *selectionNodes = nt->_selected_nodes;
std::vector<Geom::Point> selectedNodesPositions;
for (Inkscape::UI::ControlPointSelection::iterator i = selectionNodes->begin(); i != selectionNodes->end(); ++i) {
Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i);
selectedNodesPositions.push_back(n->position());
}
lpe->setSelectedNodePoints(selectedNodesPositions);
- lpe->setCurrentZoom(this->desktop->current_zoom());
+ lpe->setCurrentZoom(desktop->current_zoom());
SPCurve *c = new SPCurve();
SPCurve *cc = new SPCurve();
std::vector<Geom::PathVector> cs = lpe->getCanvasIndicators(SP_LPE_ITEM(selection->singleItem()));
@@ -302,11 +308,11 @@ void NodeTool::update_helperpath () {
cc->reset();
}
if (!c->is_empty()) {
- SPCanvasItem *helperpath = sp_canvas_bpath_new(this->desktop->getTempGroup(), c, true);
+ SPCanvasItem *helperpath = sp_canvas_bpath_new(desktop->getTempGroup(), c, true);
sp_canvas_bpath_set_stroke(SP_CANVAS_BPATH(helperpath), 0x0000ff9A, 1.0, SP_STROKE_LINEJOIN_MITER, SP_STROKE_LINECAP_BUTT);
sp_canvas_bpath_set_fill(SP_CANVAS_BPATH(helperpath), 0, SP_WIND_RULE_NONZERO);
sp_canvas_item_affine_absolute(helperpath, selection->singleItem()->i2dt_affine());
- this->helperpath_tmpitem = this->desktop->add_temporary_canvasitem(helperpath, 0);
+ nt->helperpath_tmpitem = desktop->add_temporary_canvasitem(helperpath, 0);
}
c->unref();
cc->unref();
@@ -468,7 +474,7 @@ bool NodeTool::root_handler(GdkEvent* event) {
switch (event->type)
{
case GDK_MOTION_NOTIFY: {
- update_helperpath();
+ sp_update_helperpath();
combine_motion_events(desktop->canvas, event->motion, 0);
SPItem *over_item = sp_event_context_find_item (desktop, event_point(event->button),
FALSE, TRUE);
diff --git a/src/ui/tools/node-tool.h b/src/ui/tools/node-tool.h
index 8342d66a6..983ba6cee 100644
--- a/src/ui/tools/node-tool.h
+++ b/src/ui/tools/node-tool.h
@@ -49,14 +49,14 @@ public:
Inkscape::UI::ControlPointSelection* _selected_nodes;
Inkscape::UI::MultiPathManipulator* _multipath;
-
+ Inkscape::Display::TemporaryItem *helperpath_tmpitem;
+
bool edit_clipping_paths;
bool edit_masks;
static const std::string prefsPath;
virtual void setup();
- virtual void update_helperpath();
virtual void set(const Inkscape::Preferences::Entry& val);
virtual bool root_handler(GdkEvent* event);
@@ -68,7 +68,7 @@ private:
sigc::connection _sizeUpdatedConn;
SPItem *flashed_item;
- Inkscape::Display::TemporaryItem *helperpath_tmpitem;
+
Inkscape::Display::TemporaryItem *flash_tempitem;
Inkscape::UI::Selector* _selector;
Inkscape::UI::PathSharedData* _path_data;
@@ -96,8 +96,9 @@ private:
void update_tip(GdkEvent *event);
void handleControlUiStyleChange();
};
-
+ void sp_update_helperpath();
}
+
}
}
diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp
index 3649008ff..ad006627c 100644
--- a/src/ui/tools/spray-tool.cpp
+++ b/src/ui/tools/spray-tool.cpp
@@ -1026,7 +1026,7 @@ static bool sp_spray_recursive(SPDesktop *desktop,
if (unionResult) { // No need to add the very first item (initialized with NULL).
set->add(unionResult);
}
- sp_selected_path_union_skip_undo(set);
+ set->pathUnion(true);
set->add(parent_item);
Inkscape::GC::release(copy);
did = true;
@@ -1364,7 +1364,7 @@ bool SprayTool::root_handler(GdkEvent* event) {
SP_VERB_CONTEXT_SPRAY, _("Spray with clones"));
break;
case SPRAY_MODE_SINGLE_PATH:
- sp_selected_path_union_skip_undo(objectSet());
+ objectSet()->pathUnion(true);
desktop->getSelection()->add(object_set.objects().begin(), object_set.objects().end());
DocumentUndo::done(this->desktop->getDocument(),
SP_VERB_CONTEXT_SPRAY, _("Spray in single path"));
diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp
index a0394ecd4..ff5d623c2 100644
--- a/src/ui/tools/tweak-tool.cpp
+++ b/src/ui/tools/tweak-tool.cpp
@@ -56,6 +56,8 @@
#include "sp-gradient-reference.h"
#include "sp-linear-gradient.h"
#include "sp-radial-gradient.h"
+#include "sp-mesh-gradient.h"
+#include "sp-mesh-array.h"
#include "gradient-chemistry.h"
#include "sp-text.h"
#include "sp-flowtext.h"
@@ -761,112 +763,132 @@ static void tweak_colors_in_gradient(SPItem *item, Inkscape::PaintTarget fill_or
p *= (gradient->gradientTransform).inverse();
// now p is in gradient's original coordinates
- double pos = 0;
- double r = 0;
-
SPLinearGradient *lg = dynamic_cast<SPLinearGradient *>(gradient);
- if (lg) {
- Geom::Point p1(lg->x1.computed, lg->y1.computed);
- Geom::Point p2(lg->x2.computed, lg->y2.computed);
- Geom::Point pdiff(p2 - p1);
- double vl = Geom::L2(pdiff);
+ SPRadialGradient *rg = dynamic_cast<SPRadialGradient *>(gradient);
+ if (lg || rg) {
- // This is the matrix which moves and rotates the gradient line
- // so it's oriented along the X axis:
- Geom::Affine norm = Geom::Affine(Geom::Translate(-p1)) * Geom::Affine(Geom::Rotate(-atan2(pdiff[Geom::Y], pdiff[Geom::X])));
+ double pos = 0;
+ double r = 0;
- // Transform the mouse point by it to find out its projection onto the gradient line:
- Geom::Point pnorm = p * norm;
+ if (lg) {
+ Geom::Point p1(lg->x1.computed, lg->y1.computed);
+ Geom::Point p2(lg->x2.computed, lg->y2.computed);
+ Geom::Point pdiff(p2 - p1);
+ double vl = Geom::L2(pdiff);
- // Scale its X coordinate to match the length of the gradient line:
- pos = pnorm[Geom::X] / vl;
- // Calculate radius in lenfth-of-gradient-line units
- r = radius / vl;
+ // This is the matrix which moves and rotates the gradient line
+ // so it's oriented along the X axis:
+ Geom::Affine norm = Geom::Affine(Geom::Translate(-p1)) *
+ Geom::Affine(Geom::Rotate(-atan2(pdiff[Geom::Y], pdiff[Geom::X])));
- } else {
- SPRadialGradient *rg = dynamic_cast<SPRadialGradient *>(gradient);
+ // Transform the mouse point by it to find out its projection onto the gradient line:
+ Geom::Point pnorm = p * norm;
+
+ // Scale its X coordinate to match the length of the gradient line:
+ pos = pnorm[Geom::X] / vl;
+ // Calculate radius in lenfth-of-gradient-line units
+ r = radius / vl;
+
+ }
if (rg) {
Geom::Point c (rg->cx.computed, rg->cy.computed);
pos = Geom::L2(p - c) / rg->r.computed;
r = radius / rg->r.computed;
}
- }
- // Normalize pos to 0..1, taking into accound gradient spread:
- double pos_e = pos;
- if (gradient->getSpread() == SP_GRADIENT_SPREAD_PAD) {
- if (pos > 1) {
- pos_e = 1;
- }
- if (pos < 0) {
- pos_e = 0;
- }
- } else if (gradient->getSpread() == SP_GRADIENT_SPREAD_REPEAT) {
- if (pos > 1 || pos < 0) {
- pos_e = pos - floor(pos);
- }
- } else if (gradient->getSpread() == SP_GRADIENT_SPREAD_REFLECT) {
- if (pos > 1 || pos < 0) {
- bool odd = ((int)(floor(pos)) % 2 == 1);
- pos_e = pos - floor(pos);
- if (odd) {
- pos_e = 1 - pos_e;
+ // Normalize pos to 0..1, taking into accound gradient spread:
+ double pos_e = pos;
+ if (gradient->getSpread() == SP_GRADIENT_SPREAD_PAD) {
+ if (pos > 1) {
+ pos_e = 1;
+ }
+ if (pos < 0) {
+ pos_e = 0;
+ }
+ } else if (gradient->getSpread() == SP_GRADIENT_SPREAD_REPEAT) {
+ if (pos > 1 || pos < 0) {
+ pos_e = pos - floor(pos);
+ }
+ } else if (gradient->getSpread() == SP_GRADIENT_SPREAD_REFLECT) {
+ if (pos > 1 || pos < 0) {
+ bool odd = ((int)(floor(pos)) % 2 == 1);
+ pos_e = pos - floor(pos);
+ if (odd) {
+ pos_e = 1 - pos_e;
+ }
}
}
- }
- SPGradient *vector = sp_gradient_get_forked_vector_if_necessary(gradient, false);
+ SPGradient *vector = sp_gradient_get_forked_vector_if_necessary(gradient, false);
- double offset_l = 0;
- double offset_h = 0;
- SPObject *child_prev = NULL;
- for (auto& child: vector->children) {
- SPStop *stop = dynamic_cast<SPStop *>(&child);
- if (!stop) {
- continue;
- }
+ double offset_l = 0;
+ double offset_h = 0;
+ SPObject *child_prev = NULL;
+ for (auto& child: vector->children) {
+ SPStop *stop = dynamic_cast<SPStop *>(&child);
+ if (!stop) {
+ continue;
+ }
- offset_h = stop->offset;
-
- if (child_prev) {
- SPStop *prevStop = dynamic_cast<SPStop *>(child_prev);
- g_assert(prevStop != NULL);
-
- if (offset_h - offset_l > r && pos_e >= offset_l && pos_e <= offset_h) {
- // the summit falls in this interstop, and the radius is small,
- // so it only affects the ends of this interstop;
- // distribute the force between the two endstops so that they
- // get all the painting even if they are not touched by the brush
- tweak_color (mode, stop->specified_color.v.c, rgb_goal,
- force * (pos_e - offset_l) / (offset_h - offset_l),
- do_h, do_s, do_l);
- tweak_color(mode, prevStop->specified_color.v.c, rgb_goal,
- force * (offset_h - pos_e) / (offset_h - offset_l),
- do_h, do_s, do_l);
- stop->updateRepr();
- child_prev->updateRepr();
- break;
- } else {
- // wide brush, may affect more than 2 stops,
- // paint each stop by the force from the profile curve
- if (offset_l <= pos_e && offset_l > pos_e - r) {
+ offset_h = stop->offset;
+
+ if (child_prev) {
+ SPStop *prevStop = dynamic_cast<SPStop *>(child_prev);
+ g_assert(prevStop != NULL);
+
+ if (offset_h - offset_l > r && pos_e >= offset_l && pos_e <= offset_h) {
+ // the summit falls in this interstop, and the radius is small,
+ // so it only affects the ends of this interstop;
+ // distribute the force between the two endstops so that they
+ // get all the painting even if they are not touched by the brush
+ tweak_color (mode, stop->specified_color.v.c, rgb_goal,
+ force * (pos_e - offset_l) / (offset_h - offset_l),
+ do_h, do_s, do_l);
tweak_color(mode, prevStop->specified_color.v.c, rgb_goal,
- force * tweak_profile (fabs (pos_e - offset_l), r),
+ force * (offset_h - pos_e) / (offset_h - offset_l),
do_h, do_s, do_l);
+ stop->updateRepr();
child_prev->updateRepr();
+ break;
+ } else {
+ // wide brush, may affect more than 2 stops,
+ // paint each stop by the force from the profile curve
+ if (offset_l <= pos_e && offset_l > pos_e - r) {
+ tweak_color(mode, prevStop->specified_color.v.c, rgb_goal,
+ force * tweak_profile (fabs (pos_e - offset_l), r),
+ do_h, do_s, do_l);
+ child_prev->updateRepr();
+ }
+
+ if (offset_h >= pos_e && offset_h < pos_e + r) {
+ tweak_color (mode, stop->specified_color.v.c, rgb_goal,
+ force * tweak_profile (fabs (pos_e - offset_h), r),
+ do_h, do_s, do_l);
+ stop->updateRepr();
+ }
}
+ }
- if (offset_h >= pos_e && offset_h < pos_e + r) {
+ offset_l = offset_h;
+ child_prev = &child;
+ }
+ } else {
+ // Mesh
+ SPMeshGradient *mg = dynamic_cast<SPMeshGradient *>(gradient);
+ if (mg) {
+ SPMeshGradient *mg_array = dynamic_cast<SPMeshGradient *>(mg->getArray());
+ SPMeshNodeArray *array = &(mg_array->array);
+ // Every third node is a corner node
+ for( unsigned i=0; i < array->nodes.size(); i+=3 ) {
+ for( unsigned j=0; j < array->nodes[i].size(); j+=3 ) {
+ SPStop *stop = array->nodes[i][j]->stop;
+ double distance = Geom::L2(Geom::Point(p - array->nodes[i][j]->p));
tweak_color (mode, stop->specified_color.v.c, rgb_goal,
- force * tweak_profile (fabs (pos_e - offset_h), r),
- do_h, do_s, do_l);
+ force * tweak_profile (distance, radius), do_h, do_s, do_l);
stop->updateRepr();
}
}
}
-
- offset_l = offset_h;
- child_prev = &child;
}
}
@@ -1062,7 +1084,8 @@ sp_tweak_dilate (TweakTool *tc, Geom::Point event_p, Geom::Point p, Geom::Point
double move_force = get_move_force(tc);
double color_force = MIN(sqrt(path_force)/20.0, 1);
- auto items= selection->items();
+// auto items= selection->items();
+ std::vector<SPItem*> items(selection->items().begin(), selection->items().end());
for(auto i=items.begin();i!=items.end(); ++i){
SPItem *item = *i;
diff --git a/src/ui/widget/dock-item.cpp b/src/ui/widget/dock-item.cpp
index 979c09d2f..d124854ae 100644
--- a/src/ui/widget/dock-item.cpp
+++ b/src/ui/widget/dock-item.cpp
@@ -15,7 +15,6 @@
#include "widgets/icon.h"
#include <gtkmm/icontheme.h>
-#include <gtkmm/stockitem.h>
#include <glibmm/exceptionhandler.h>
namespace Inkscape {
@@ -47,18 +46,11 @@ DockItem::DockItem(Dock& dock, const Glib::ustring& name, const Glib::ustring& l
if (!iconTheme->has_icon(icon_name)) {
Inkscape::queueIconPrerender( INKSCAPE_ICON(icon_name.data()), Inkscape::ICON_SIZE_MENU );
}
- // Icon might be in the icon theme, or might be a stock item. Check the proper source:
if ( iconTheme->has_icon(icon_name) ) {
int width = 0;
int height = 0;
Gtk::IconSize::lookup(Gtk::ICON_SIZE_MENU, width, height);
_icon_pixbuf = iconTheme->load_icon(icon_name, width);
- } else {
- Gtk::StockItem item;
- Gtk::StockID stockId(icon_name);
- if ( Gtk::StockItem::lookup(stockId, item) ) {
- _icon_pixbuf = _dock.getWidget().render_icon_pixbuf( stockId, Gtk::ICON_SIZE_MENU );
- }
}
}
@@ -423,6 +415,8 @@ void
DockItem::_onStateChanged(State /*prev_state*/, State new_state)
{
_window = getWindow();
+ if(_window)
+ _window->set_type_hint(Gdk::WINDOW_TYPE_HINT_NORMAL);
if (new_state == FLOATING_STATE && _window) {
_window->signal_hide().connect(sigc::mem_fun(*this, &Inkscape::UI::Widget::DockItem::_onHideWindow));
diff --git a/src/ui/widget/dock.cpp b/src/ui/widget/dock.cpp
index 7744cb695..b2dec401f 100644
--- a/src/ui/widget/dock.cpp
+++ b/src/ui/widget/dock.cpp
@@ -256,7 +256,7 @@ void Dock::_onLayoutChanged()
_paned->get_child1()->set_size_request(-1, -1);
_scrolled_window->set_size_request(_default_empty_width);
}
- getParentPaned()->set_position(INT_MAX);
+ getParentPaned()->set_position(10000);
} else {
// unset any forced size requests
diff --git a/src/ui/widget/font-button.cpp b/src/ui/widget/font-button.cpp
index a472ac6a4..ed57c803a 100644
--- a/src/ui/widget/font-button.cpp
+++ b/src/ui/widget/font-button.cpp
@@ -8,8 +8,11 @@
#endif
#include "font-button.h"
+
#include <glibmm/i18n.h>
+#include <gtkmm/fontbutton.h>
+
namespace Inkscape {
namespace UI {
namespace Widget {
diff --git a/src/ui/widget/font-button.h b/src/ui/widget/font-button.h
index 1f1ad2d01..98c3db440 100644
--- a/src/ui/widget/font-button.h
+++ b/src/ui/widget/font-button.h
@@ -8,7 +8,6 @@
#ifndef INKSCAPE_UI_WIDGET_FONT_BUTTON_H
#define INKSCAPE_UI_WIDGET_FONT_BUTTON_H
-#include <gtkmm.h>
#include "labelled.h"
namespace Inkscape {
diff --git a/src/ui/widget/frame.cpp b/src/ui/widget/frame.cpp
index 65d10dcc4..6593d9c7c 100644
--- a/src/ui/widget/frame.cpp
+++ b/src/ui/widget/frame.cpp
@@ -21,26 +21,20 @@ namespace UI {
namespace Widget {
Frame::Frame(Glib::ustring const &label_text /*= ""*/, gboolean label_bold /*= TRUE*/ )
- : _label(label_text, 1.0, 0.5, TRUE),
- _alignment()
+ : _label(label_text, 1.0, 0.5, TRUE)
{
set_shadow_type(Gtk::SHADOW_NONE);
- //Put an indented GtkAlignment inside the frame.
- //Further children should be children of this GtkAlignment:
- Gtk::Frame::add(_alignment);
- set_padding(4, 0, 8, 0);
-
set_label_widget(_label);
set_label(label_text, label_bold);
-
- show_all_children();
}
void
Frame::add(Widget& widget)
{
- _alignment.add(widget);
+ Gtk::Frame::add(widget);
+ set_padding(4, 0, 8, 0);
+ show_all_children();
}
void
@@ -56,7 +50,21 @@ Frame::set_label(const Glib::ustring &label_text, gboolean label_bold /*= TRUE*/
void
Frame::set_padding (guint padding_top, guint padding_bottom, guint padding_left, guint padding_right)
{
- _alignment.set_padding(padding_top, padding_bottom, padding_left, padding_right);
+ auto child = get_child();
+
+ if(child)
+ {
+ child->set_margin_top(padding_top);
+ child->set_margin_bottom(padding_bottom);
+
+#if GTK_CHECK_VERSION(3,12,0)
+ child->set_margin_start(padding_left);
+ child->set_margin_end(padding_right);
+#else
+ child->set_margin_left(padding_left);
+ child->set_margin_right(padding_right);
+#endif
+ }
}
Gtk::Label const *
diff --git a/src/ui/widget/frame.h b/src/ui/widget/frame.h
index a04666651..24dd716e6 100644
--- a/src/ui/widget/frame.h
+++ b/src/ui/widget/frame.h
@@ -10,7 +10,6 @@
#ifndef INKSCAPE_UI_WIDGET_FRAME_H
#define INKSCAPE_UI_WIDGET_FRAME_H
-#include <gtkmm/alignment.h>
#include <gtkmm/frame.h>
#include <gtkmm/label.h>
@@ -55,8 +54,6 @@ public:
protected:
Gtk::Label _label;
- Gtk::Alignment _alignment;
-
};
} // namespace Widget
diff --git a/src/ui/widget/panel.cpp b/src/ui/widget/panel.cpp
index 6e6e6c527..dff92594b 100644
--- a/src/ui/widget/panel.cpp
+++ b/src/ui/widget/panel.cpp
@@ -17,7 +17,6 @@
#include <gtkmm/dialog.h> // for Gtk::RESPONSE_*
#include <gtkmm/menu.h>
-#include <gtkmm/stock.h>
#include <gtkmm/checkmenuitem.h>
#include <gtkmm/radiomenuitem.h>
#include <gtkmm/separatormenuitem.h>
@@ -66,7 +65,7 @@ Panel::Panel(Glib::ustring const &label, gchar const *prefs_path,
_label(label),
_apply_label(apply_label),
_verb_num(verb_num),
- _temp_arrow(Gtk::ARROW_LEFT, Gtk::SHADOW_ETCHED_OUT),
+ _temp_arrow(),
_menu(0),
_action_area(0),
_fillable(0)
@@ -269,11 +268,9 @@ void Panel::_init()
_top_bar.pack_end(_menu_popper, false, false);
gint width = 0;
gint height = 0;
-
- if ( gtk_icon_size_lookup( Inkscape::getRegisteredIconSize(Inkscape::ICON_SIZE_DECORATION), &width, &height ) ) {
- _temp_arrow.set_size_request(width, height);
- }
-
+ gtk_image_set_from_icon_name(_temp_arrow.gobj(),
+ "pan-start-symbolic",
+ Inkscape::getRegisteredIconSize(Inkscape::ICON_SIZE_SMALL_TOOLBAR));
_menu_popper.add(_temp_arrow);
_menu_popper.signal_button_press_event().connect_notify(sigc::mem_fun(*this, &Panel::_popper));
}
@@ -578,14 +575,7 @@ void Panel::_apply()
Gtk::Button *Panel::addResponseButton(const Glib::ustring &button_text, int response_id, bool pack_start)
{
- Gtk::Button *button = new Gtk::Button(button_text);
- _addResponseButton(button, response_id, pack_start);
- return button;
-}
-
-Gtk::Button *Panel::addResponseButton(const Gtk::StockID &stock_id, int response_id, bool pack_start)
-{
- Gtk::Button *button = new Gtk::Button(stock_id);
+ Gtk::Button *button = new Gtk::Button(button_text, true);
_addResponseButton(button, response_id, pack_start);
return button;
}
diff --git a/src/ui/widget/panel.h b/src/ui/widget/panel.h
index 370779586..9cbf39de9 100644
--- a/src/ui/widget/panel.h
+++ b/src/ui/widget/panel.h
@@ -18,9 +18,9 @@
#endif
#include <gtkmm/box.h>
-#include <gtkmm/arrow.h>
#include <gtkmm/button.h>
#include <gtkmm/eventbox.h>
+#include <gtkmm/image.h>
#include <gtkmm/label.h>
#include "enums.h"
#include <vector>
@@ -101,7 +101,6 @@ public:
/* Methods providing a Gtk::Dialog like interface for adding buttons that emit Gtk::RESPONSE
* signals on click. */
Gtk::Button* addResponseButton (const Glib::ustring &button_text, int response_id, bool pack_start=false);
- Gtk::Button* addResponseButton (const Gtk::StockID &stock_id, int response_id, bool pack_start=false);
void setDefaultResponse(int response_id);
void setResponseSensitive(int response_id, bool setting);
@@ -157,7 +156,7 @@ private:
Gtk::VBox _right_bar;
Gtk::VBox _contents;
Gtk::Label _tab_title;
- Gtk::Arrow _temp_arrow;
+ Gtk::Image _temp_arrow;
Gtk::EventBox _menu_popper;
Gtk::Button _close_button;
Gtk::Menu *_menu;
diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp
index 1205cd012..b2cebcaa6 100644
--- a/src/ui/widget/preferences-widget.cpp
+++ b/src/ui/widget/preferences-widget.cpp
@@ -18,7 +18,6 @@
#include <gtkmm/frame.h>
#include <gtkmm/alignment.h>
#include <gtkmm/scale.h>
-#include <gtkmm/stock.h>
#include <gtkmm/table.h>
#include "preferences.h"
@@ -708,8 +707,9 @@ void PrefEntryFileButtonHBox::init(Glib::ustring const &prefs_path,
relatedButton = new Gtk::Button();
Gtk::HBox* pixlabel = new Gtk::HBox(false, 3);
- Gtk::Image *im = new Gtk::Image(Gtk::StockID(Gtk::Stock::INDEX),
- Gtk::ICON_SIZE_BUTTON);
+ Gtk::Image *im = new Gtk::Image();
+ im->set_from_icon_name("applications-graphics",
+ Gtk::ICON_SIZE_BUTTON);
pixlabel->pack_start(*im);
Gtk::Label *l = new Gtk::Label();
l->set_markup_with_mnemonic(_("_Browse..."));
diff --git a/src/ui/widget/registered-widget.h b/src/ui/widget/registered-widget.h
index d410dbfe6..f66d5cbf2 100644
--- a/src/ui/widget/registered-widget.h
+++ b/src/ui/widget/registered-widget.h
@@ -135,7 +135,7 @@ private:
repr = NULL;
doc = NULL;
write_undo = false;
- event_type = -1;
+ event_type = 0; //SP_VERB_INVALID
}
};
diff --git a/src/ui/widget/selected-style.cpp b/src/ui/widget/selected-style.cpp
index ebc6fe919..0370d55db 100644
--- a/src/ui/widget/selected-style.cpp
+++ b/src/ui/widget/selected-style.cpp
@@ -781,56 +781,7 @@ void SelectedStyle::on_stroke_paste() {
}
void SelectedStyle::on_fillstroke_swap() {
- SPCSSAttr *css = sp_repr_css_attr_new ();
-
- switch (_mode[SS_FILL]) {
- case SS_NA:
- case SS_MANY:
- break;
- case SS_NONE:
- sp_repr_css_set_property (css, "stroke", "none");
- break;
- case SS_UNSET:
- sp_repr_css_unset_property (css, "stroke");
- break;
- case SS_COLOR:
- gchar c[64];
- sp_svg_write_color (c, sizeof(c), _thisselected[SS_FILL]);
- sp_repr_css_set_property (css, "stroke", c);
- break;
- case SS_LGRADIENT:
- case SS_RGRADIENT:
- case SS_PATTERN:
- sp_repr_css_set_property (css, "stroke", _paintserver_id[SS_FILL].c_str());
- break;
- }
-
- switch (_mode[SS_STROKE]) {
- case SS_NA:
- case SS_MANY:
- break;
- case SS_NONE:
- sp_repr_css_set_property (css, "fill", "none");
- break;
- case SS_UNSET:
- sp_repr_css_unset_property (css, "fill");
- break;
- case SS_COLOR:
- gchar c[64];
- sp_svg_write_color (c, sizeof(c), _thisselected[SS_STROKE]);
- sp_repr_css_set_property (css, "fill", c);
- break;
- case SS_LGRADIENT:
- case SS_RGRADIENT:
- case SS_PATTERN:
- sp_repr_css_set_property (css, "fill", _paintserver_id[SS_STROKE].c_str());
- break;
- }
-
- sp_desktop_set_style (_desktop, css);
- sp_repr_css_attr_unref (css);
- DocumentUndo::done(_desktop->getDocument(), SP_VERB_DIALOG_FILL_STROKE,
- _("Swap fill and stroke"));
+ _desktop->getSelection()->swapFillStroke();
}
void SelectedStyle::on_fill_edit() {
diff --git a/src/verbs.cpp b/src/verbs.cpp
index a5426f324..aeb742105 100644
--- a/src/verbs.cpp
+++ b/src/verbs.cpp
@@ -37,7 +37,6 @@
// If this is not done, then errors will be generate relating to Glib::Threads being undefined
#include <gtkmm/filechooserdialog.h>
#include <gtkmm/messagedialog.h>
-#include <gtkmm/stock.h>
#include "desktop.h"
@@ -1087,6 +1086,9 @@ void EditVerb::perform(SPAction *action, void *data)
case SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER:
sp_selection_next_patheffect_param(dt);
break;
+ case SP_VERB_EDIT_SWAP_FILL_STROKE:
+ dt->selection->swapFillStroke();
+ break;
case SP_VERB_EDIT_LINK_COLOR_PROFILE:
break;
case SP_VERB_EDIT_REMOVE_COLOR_PROFILE:
@@ -1115,22 +1117,22 @@ void SelectionVerb::perform(SPAction *action, void *data)
bool handled = true;
switch (reinterpret_cast<std::size_t>(data)) {
case SP_VERB_SELECTION_UNION:
- sp_selected_path_union(selection, dt);
+ selection->pathUnion();
break;
case SP_VERB_SELECTION_INTERSECT:
- sp_selected_path_intersect(selection, dt);
+ selection->pathIntersect();
break;
case SP_VERB_SELECTION_DIFF:
- sp_selected_path_diff(selection, dt);
+ selection->pathDiff();
break;
case SP_VERB_SELECTION_SYMDIFF:
- sp_selected_path_symdiff(selection, dt);
+ selection->pathSymDiff();
break;
case SP_VERB_SELECTION_CUT:
- sp_selected_path_cut(selection, dt);
+ selection->pathCut();
break;
case SP_VERB_SELECTION_SLICE:
- sp_selected_path_slice(selection, dt);
+ selection->pathSlice();
break;
case SP_VERB_SELECTION_GROW:
{
@@ -2586,6 +2588,8 @@ Verb *Verb::_base_verbs[] = {
N_("Create four guides aligned with the page borders"), NULL),
new EditVerb(SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER, "EditNextPathEffectParameter", N_("Next path effect parameter"),
N_("Show next editable path effect parameter"), INKSCAPE_ICON("path-effect-parameter-next")),
+ new EditVerb(SP_VERB_EDIT_SWAP_FILL_STROKE, "EditSwapFillStroke", N_("Swap fill and stroke"),
+ N_("Swap fill and stroke of an object"), NULL),
// Selection
new SelectionVerb(SP_VERB_SELECTION_TO_FRONT, "SelectionToFront", N_("Raise to _Top"),
diff --git a/src/verbs.h b/src/verbs.h
index d7e966ae4..76a7d19a6 100644
--- a/src/verbs.h
+++ b/src/verbs.h
@@ -110,6 +110,7 @@ enum {
SP_VERB_EDIT_GUIDES_TOGGLE_LOCK,
SP_VERB_EDIT_GUIDES_AROUND_PAGE,
SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER,
+ SP_VERB_EDIT_SWAP_FILL_STROKE,
/* Selection */
SP_VERB_SELECTION_TO_FRONT,
SP_VERB_SELECTION_TO_BACK,
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
index c87fa1500..1184291f2 100644
--- a/src/widgets/CMakeLists.txt
+++ b/src/widgets/CMakeLists.txt
@@ -22,7 +22,6 @@ set(widgets_SRC
gradient-toolbar.cpp
gradient-vector.cpp
icon.cpp
- image-menu-item.c
ink-action.cpp
ink-comboboxentry-action.cpp
ink-radio-action.cpp
@@ -80,7 +79,6 @@ set(widgets_SRC
gradient-toolbar.h
gradient-vector.h
icon.h
- image-menu-item.h
ink-action.h
ink-comboboxentry-action.h
ink-radio-action.h
diff --git a/src/widgets/dash-selector.cpp b/src/widgets/dash-selector.cpp
index 522705cec..05f3ab44c 100644
--- a/src/widgets/dash-selector.cpp
+++ b/src/widgets/dash-selector.cpp
@@ -174,11 +174,13 @@ void SPDashSelector::set_dash (int ndash, double *dash, double o)
else if(ndash==0) {
pos = 0;
}
-
if(pos>=0){
this->set_data("pattern", dashes[pos]);
this->dash_combo.set_active(pos);
this->offset->set_value(o);
+ if(pos == 10) {
+ this->offset->set_value(10.0);
+ }
}
else { // Hit a custom pattern in the SVG, write it into the combobox.
count--; // the one slot for custom patterns
diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp
index 4f5724ac2..cdab62f6a 100644
--- a/src/widgets/desktop-widget.cpp
+++ b/src/widgets/desktop-widget.cpp
@@ -325,13 +325,6 @@ static void canvas_tbl_size_allocate(GtkWidget * widget,
{
SPDesktopWidget *dtw = SP_DESKTOP_WIDGET(data);
sp_desktop_widget_update_rulers(dtw);
-
- GtkWidget* parent = gtk_widget_get_parent(widget);
- if(GTK_IS_PANED(parent)) {
- GtkPaned *paned = GTK_PANED(parent);
- // Could use gtk paned property 'max-position' here
- gtk_paned_set_position(paned, 10000);
- }
}
/**
diff --git a/src/widgets/eraser-toolbar.cpp b/src/widgets/eraser-toolbar.cpp
index 64aace4e7..7377cdc00 100644
--- a/src/widgets/eraser-toolbar.cpp
+++ b/src/widgets/eraser-toolbar.cpp
@@ -33,6 +33,8 @@
#include "eraser-toolbar.h"
#include "calligraphy-toolbar.h" // TODO: needed for update_presets_list
+#include <array>
+
#include "desktop.h"
#include "document-undo.h"
#include "widgets/ege-adjustment-action.h"
diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp
index 636d892f8..8946eb4b3 100644
--- a/src/widgets/fill-style.cpp
+++ b/src/widgets/fill-style.cpp
@@ -40,6 +40,7 @@
#include "sp-mesh-gradient.h"
#include "sp-pattern.h"
#include "sp-radial-gradient.h"
+#include "sp-text.h"
#include "style.h"
#include "widgets/paint-selector.h"
@@ -279,34 +280,35 @@ void FillNStroke::performUpdate()
SPPaintServer *server = (kind == FILL) ? query.getFillPaintServer() : query.getStrokePaintServer();
- if (server && SP_IS_GRADIENT(server) && SP_GRADIENT(server)->getVector()->isSwatch()) {
- SPGradient *vector = SP_GRADIENT(server)->getVector();
- psel->setSwatch( vector );
- } else if (SP_IS_LINEARGRADIENT(server)) {
- SPGradient *vector = SP_GRADIENT(server)->getVector();
- psel->setGradientLinear( vector );
-
- SPLinearGradient *lg = SP_LINEARGRADIENT(server);
- psel->setGradientProperties( lg->getUnits(),
- lg->getSpread() );
- } else if (SP_IS_RADIALGRADIENT(server)) {
- SPGradient *vector = SP_GRADIENT(server)->getVector();
- psel->setGradientRadial( vector );
-
- SPRadialGradient *rg = SP_RADIALGRADIENT(server);
- psel->setGradientProperties( rg->getUnits(),
- rg->getSpread() );
+ if (server) {
+ if (SP_IS_GRADIENT(server) && SP_GRADIENT(server)->getVector()->isSwatch()) {
+ SPGradient *vector = SP_GRADIENT(server)->getVector();
+ psel->setSwatch( vector );
+ } else if (SP_IS_LINEARGRADIENT(server)) {
+ SPGradient *vector = SP_GRADIENT(server)->getVector();
+ psel->setGradientLinear( vector );
+
+ SPLinearGradient *lg = SP_LINEARGRADIENT(server);
+ psel->setGradientProperties( lg->getUnits(),
+ lg->getSpread() );
+ } else if (SP_IS_RADIALGRADIENT(server)) {
+ SPGradient *vector = SP_GRADIENT(server)->getVector();
+ psel->setGradientRadial( vector );
+
+ SPRadialGradient *rg = SP_RADIALGRADIENT(server);
+ psel->setGradientProperties( rg->getUnits(),
+ rg->getSpread() );
#ifdef WITH_MESH
- } else if (SP_IS_MESHGRADIENT(server)) {
- SPGradient *array = SP_MESHGRADIENT(server)->getArray();
- psel->setGradientMesh( array );
-
- SPMeshGradient *mg = SP_MESHGRADIENT(server);
- psel->setMeshProperties( mg->getUnits() );
+ } else if (SP_IS_MESHGRADIENT(server)) {
+ SPGradient *array = SP_GRADIENT(server)->getArray();
+ psel->setGradientMesh( SP_MESHGRADIENT(array) );
+ SPMeshGradient *mg = SP_MESHGRADIENT(server);
+ psel->updateMeshList( SP_MESHGRADIENT( array ));
#endif
- } else if (SP_IS_PATTERN(server)) {
- SPPattern *pat = SP_PATTERN(server)->rootPattern();
- psel->updatePatternList( pat );
+ } else if (SP_IS_PATTERN(server)) {
+ SPPattern *pat = SP_PATTERN(server)->rootPattern();
+ psel->updatePatternList( pat );
+ }
}
}
break;
@@ -622,6 +624,107 @@ void FillNStroke::updateFromPaint()
}
break;
+#ifdef WITH_MESH
+ case SPPaintSelector::MODE_GRADIENT_MESH:
+
+ if (!items.empty()) {
+ SPGradientType const gradient_type = SP_GRADIENT_TYPE_MESH;
+
+ SPCSSAttr *css = 0;
+ if (kind == FILL) {
+ // HACK: reset fill-opacity - that 0.75 is annoying; BUT remove this when we have an opacity slider for all tabs
+ css = sp_repr_css_attr_new();
+ sp_repr_css_set_property(css, "fill-opacity", "1.0");
+ }
+
+ Inkscape::XML::Document *xml_doc = document->getReprDoc();
+ SPDefs *defs = document->getDefs();
+
+ SPMeshGradient * mesh = psel->getMeshGradient();
+
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){
+
+ //FIXME: see above
+ if (kind == FILL) {
+ sp_repr_css_change_recursive((*i)->getRepr(), css, "style");
+ }
+
+ // Check if object already has mesh.
+ bool has_mesh = false;
+ SPStyle *style = (*i)->style;
+ if (style) {
+ SPPaintServer *server =
+ (kind==FILL) ? style->getFillPaintServer():style->getStrokePaintServer();
+ if (server && SP_IS_MESHGRADIENT(server))
+ has_mesh = true;
+ }
+
+ if (!mesh || !has_mesh) {
+ // No mesh in document or object does not already have mesh ->
+ // Create new mesh.
+
+ // Create mesh element
+ Inkscape::XML::Node *repr = xml_doc->createElement("svg:meshgradient");
+
+ // privates are garbage-collectable
+ repr->setAttribute("inkscape:collect", "always");
+
+ // Attach to document
+ defs->getRepr()->appendChild(repr);
+ Inkscape::GC::release(repr);
+
+ // Get corresponding object
+ SPMeshGradient *mg = static_cast<SPMeshGradient *>(document->getObjectByRepr(repr));
+ mg->array.create(mg, *i, (kind==FILL) ?
+ (*i)->geometricBounds() : (*i)->visualBounds());
+
+ bool isText = SP_IS_TEXT(*i);
+ sp_style_set_property_url (*i, ((kind == FILL) ? "fill":"stroke"),
+ mg, isText);
+
+ // (*i)->requestModified(SP_OBJECT_MODIFIED_FLAG|SP_OBJECT_STYLE_MODIFIED_FLAG);
+
+ } else {
+ // Using found mesh
+
+ // Duplicate
+ Inkscape::XML::Node *mesh_repr = mesh->getRepr();
+ Inkscape::XML::Node *copy_repr = mesh_repr->duplicate(xml_doc);
+
+ // privates are garbage-collectable
+ copy_repr->setAttribute("inkscape:collect", "always");
+
+ // Attach to document
+ defs->getRepr()->appendChild(copy_repr);
+ Inkscape::GC::release(copy_repr);
+
+ // Get corresponding object
+ SPMeshGradient *mg =
+ static_cast<SPMeshGradient *>(document->getObjectByRepr(copy_repr));
+ // std::cout << " " << (mg->getId()?mg->getId():"null") << std::endl;
+ mg->array.read(mg);
+
+ Geom::OptRect item_bbox = (kind==FILL) ?
+ (*i)->geometricBounds() : (*i)->visualBounds();
+ mg->array.fill_box( item_bbox );
+
+ bool isText = SP_IS_TEXT(*i);
+ sp_style_set_property_url (*i, ((kind == FILL) ? "fill":"stroke"),
+ mg, isText);
+ }
+ }
+
+ if (css) {
+ sp_repr_css_attr_unref(css);
+ css = 0;
+ }
+
+ DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE,
+ (kind == FILL) ? _("Set mesh on fill") : _("Set mesh on stroke"));
+ }
+ break;
+#endif
+
case SPPaintSelector::MODE_PATTERN:
if (!items.empty()) {
diff --git a/src/widgets/font-selector.cpp b/src/widgets/font-selector.cpp
index f400de89c..819ac77b6 100644
--- a/src/widgets/font-selector.cpp
+++ b/src/widgets/font-selector.cpp
@@ -145,13 +145,6 @@ static void sp_font_selector_init(SPFontSelector *fsel)
gtk_widget_set_name( GTK_WIDGET(fsel->family_treeview), "font_selector_family" );
auto css_provider = gtk_css_provider_new();
- gtk_css_provider_load_from_data(css_provider,
- "#font_selector_family {\n"
- " -GtkWidget-wide-separators: true;\n"
- " -GtkWidget-separator-height: 6;\n"
- "}\n",
- -1, NULL);
-
auto screen = gdk_screen_get_default();
gtk_style_context_add_provider_for_screen(screen,
GTK_STYLE_PROVIDER(css_provider),
diff --git a/src/widgets/gimp/ruler.cpp b/src/widgets/gimp/ruler.cpp
index bfb9c9071..2a71b5c08 100644
--- a/src/widgets/gimp/ruler.cpp
+++ b/src/widgets/gimp/ruler.cpp
@@ -12,7 +12,9 @@
* - We use a default font size of PANGO_SCALE_X_SMALL for labels,
* GIMP uses PANGO_SCALE_SMALL (i.e., a bit larger than ours).
*
- * - We abbreviate large numbers in tick-labels (e.g., 10000 -> 10k)
+ * - We abbreviate large numbers in tick-labels (e.g., 10000 -> 10k)
+ *
+ * - GtkStateFlags are read from GtkStyleContext objects where appropriate
*
* Authors:
* Lauris Kaplinski <lauris@kaplinski.com>
@@ -548,7 +550,7 @@ sp_ruler_size_allocate (GtkWidget *widget,
resized = (widget_allocation.width != allocation->width ||
widget_allocation.height != allocation->height);
- gtk_widget_set_allocation(widget, allocation);
+ GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
if (gtk_widget_get_realized (widget))
{
@@ -578,7 +580,9 @@ sp_ruler_size_request (GtkWidget *widget,
GtkStyleContext *context = gtk_widget_get_style_context (widget);
GtkBorder border;
- gtk_style_context_get_border (context, static_cast<GtkStateFlags>(0), &border);
+ GtkStateFlags state_flags = gtk_style_context_get_state (context);
+
+ gtk_style_context_get_border (context, state_flags, &border);
requisition->width = border.left + border.right;
requisition->height = border.top + border.bottom;
@@ -725,7 +729,17 @@ sp_ruler_draw_pos (SPRuler *ruler,
cairo_fill (cr);
}
- priv->last_pos_rect = pos_rect;
+ if (priv->last_pos_rect.width != 0 &&
+ priv->last_pos_rect.height != 0)
+ {
+ gdk_rectangle_union (&priv->last_pos_rect,
+ &pos_rect,
+ &priv->last_pos_rect);
+ }
+ else
+ {
+ priv->last_pos_rect = pos_rect;
+ }
}
/**
@@ -999,6 +1013,12 @@ sp_ruler_set_position (SPRuler *ruler,
(ABS (xdiff) > IMMEDIATE_REDRAW_THRESHOLD ||
ABS (ydiff) > IMMEDIATE_REDRAW_THRESHOLD))
{
+ if (priv->pos_redraw_idle_id)
+ {
+ g_source_remove (priv->pos_redraw_idle_id);
+ priv->pos_redraw_idle_id = 0;
+ }
+
sp_ruler_queue_pos_redraw (ruler);
}
else if (! priv->pos_redraw_idle_id)
@@ -1072,7 +1092,9 @@ sp_ruler_draw_ticks (SPRuler *ruler)
gtk_widget_get_allocation (widget, &allocation);
- gtk_style_context_get_border (context, static_cast<GtkStateFlags>(0), &border);
+ GtkStateFlags state_flags = gtk_style_context_get_state (context);
+
+ gtk_style_context_get_border (context, state_flags, &border);
layout = sp_ruler_get_layout (widget, "0123456789");
pango_layout_get_extents (layout, &ink_rect, &logical_rect);
@@ -1284,7 +1306,9 @@ sp_ruler_get_pos_rect (SPRuler *ruler,
GtkStyleContext *context = gtk_widget_get_style_context (widget);
GtkBorder padding;
- gtk_style_context_get_border(context, static_cast<GtkStateFlags>(0), &padding);
+ GtkStateFlags state_flags = gtk_style_context_get_state (context);
+
+ gtk_style_context_get_border(context, state_flags, &padding);
xthickness = padding.left + padding.right;
ythickness = padding.top + padding.bottom;
@@ -1351,15 +1375,16 @@ sp_ruler_queue_pos_redraw (SPRuler *ruler)
gtk_widget_get_allocation (GTK_WIDGET(ruler), &allocation);
- gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
+ gtk_widget_queue_draw_area (GTK_WIDGET (ruler),
rect.x + allocation.x,
rect.y + allocation.y,
rect.width,
rect.height);
- if (priv->last_pos_rect.width != 0 || priv->last_pos_rect.height != 0)
+ if (priv->last_pos_rect.width != 0 &&
+ priv->last_pos_rect.height != 0)
{
- gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
+ gtk_widget_queue_draw_area (GTK_WIDGET (ruler),
priv->last_pos_rect.x + allocation.x,
priv->last_pos_rect.y + allocation.y,
priv->last_pos_rect.width,
diff --git a/src/widgets/gradient-selector.h b/src/widgets/gradient-selector.h
index 6b5d4ca60..e058c5112 100644
--- a/src/widgets/gradient-selector.h
+++ b/src/widgets/gradient-selector.h
@@ -50,9 +50,6 @@ struct SPGradientSelector {
enum SelectorMode {
MODE_LINEAR,
MODE_RADIAL,
-#ifdef WITH_MESH
- MODE_MESH,
-#endif
MODE_SWATCH
};
diff --git a/src/widgets/image-menu-item.c b/src/widgets/image-menu-item.c
deleted file mode 100644
index 2b9500ba0..000000000
--- a/src/widgets/image-menu-item.c
+++ /dev/null
@@ -1,1071 +0,0 @@
-/* GTK - The GIMP Toolkit
- * Copyright (C) 2001 Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000.
- * Forked by . Icons in menus are important to us.
- */
-
-#include "config.h"
-
-#include <glib/gi18n-lib.h>
-#include <gtk/gtk.h>
-
-#include "widgets/image-menu-item.h"
-
-/**
- * SECTION:gtkimagemenuitem
- * @Short_description: A menu item with an icon
- * @Title: ImageMenuItem
- *
- * A ImageMenuItem is a menu item which has an icon next to the text label.
- *
- * Note that the user can disable display of menu icons, so make sure to still
- * fill in the text label.
- */
-
-
-struct _ImageMenuItemPrivate
-{
- GtkWidget *image;
-
- gchar *label;
- guint use_stock : 1;
- guint toggle_size;
-};
-
-enum {
- PROP_0,
- PROP_IMAGE,
- PROP_USE_STOCK,
- PROP_ACCEL_GROUP,
-};
-
-static GtkActivatableIface *parent_activatable_iface;
-
-static void image_menu_item_destroy (GtkWidget *widget);
-static void image_menu_item_get_preferred_width (GtkWidget *widget,
- gint *minimum,
- gint *natural);
-static void image_menu_item_get_preferred_height (GtkWidget *widget,
- gint *minimum,
- gint *natural);
-static void image_menu_item_get_preferred_height_for_width (GtkWidget *widget,
- gint width,
- gint *minimum,
- gint *natural);
-static void image_menu_item_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation);
-static void image_menu_item_map (GtkWidget *widget);
-static void image_menu_item_remove (GtkContainer *container,
- GtkWidget *child);
-static void image_menu_item_toggle_size_request (GtkMenuItem *menu_item,
- gint *requisition);
-static void image_menu_item_set_label (GtkMenuItem *menu_item,
- const gchar *label);
-static const gchar * image_menu_item_get_label (GtkMenuItem *menu_item);
-
-static void image_menu_item_forall (GtkContainer *container,
- gboolean include_internals,
- GtkCallback callback,
- gpointer callback_data);
-
-static void image_menu_item_finalize (GObject *object);
-static void image_menu_item_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec);
-static void image_menu_item_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec);
-static void image_menu_item_screen_changed (GtkWidget *widget,
- GdkScreen *previous_screen);
-
-static void image_menu_item_recalculate (ImageMenuItem *image_menu_item);
-
-static void image_menu_item_activatable_interface_init (GtkActivatableIface *iface);
-static void image_menu_item_update (GtkActivatable *activatable,
- GtkAction *action,
- const gchar *property_name);
-static void image_menu_item_sync_action_properties (GtkActivatable *activatable,
- GtkAction *action);
-
-
-G_DEFINE_TYPE_WITH_CODE (ImageMenuItem, image_menu_item, GTK_TYPE_MENU_ITEM,
- G_ADD_PRIVATE (ImageMenuItem)
- G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIVATABLE,
- image_menu_item_activatable_interface_init))
-
-
-static void
-image_menu_item_class_init (ImageMenuItemClass *klass)
-{
- GObjectClass *gobject_class = (GObjectClass*) klass;
- GtkWidgetClass *widget_class = (GtkWidgetClass*) klass;
- GtkMenuItemClass *menu_item_class = (GtkMenuItemClass*) klass;
- GtkContainerClass *container_class = (GtkContainerClass*) klass;
-
- widget_class->destroy = image_menu_item_destroy;
- widget_class->screen_changed = image_menu_item_screen_changed;
- widget_class->get_preferred_width = image_menu_item_get_preferred_width;
- widget_class->get_preferred_height = image_menu_item_get_preferred_height;
- widget_class->get_preferred_height_for_width = image_menu_item_get_preferred_height_for_width;
- widget_class->size_allocate = image_menu_item_size_allocate;
- widget_class->map = image_menu_item_map;
-
- container_class->forall = image_menu_item_forall;
- container_class->remove = image_menu_item_remove;
-
- menu_item_class->toggle_size_request = image_menu_item_toggle_size_request;
- menu_item_class->set_label = image_menu_item_set_label;
- menu_item_class->get_label = image_menu_item_get_label;
-
- gobject_class->finalize = image_menu_item_finalize;
- gobject_class->set_property = image_menu_item_set_property;
- gobject_class->get_property = image_menu_item_get_property;
-
- /**
- * ImageMenuItem:image:
- *
- * Child widget to appear next to the menu text.
- *
- */
- g_object_class_install_property (gobject_class,
- PROP_IMAGE,
- g_param_spec_object ("image",
- _("Image widget"),
- _("Child widget to appear next to the menu text"),
- GTK_TYPE_WIDGET,
- GTK_PARAM_READWRITE | G_PARAM_DEPRECATED));
- /**
- * ImageMenuItem:use-stock:
- *
- * If %TRUE, the label set in the menuitem is used as a
- * stock id to select the stock item for the item.
- *
- * Since: 2.16
- *
- */
- g_object_class_install_property (gobject_class,
- PROP_USE_STOCK,
- g_param_spec_boolean ("use-stock",
- _("Use stock"),
- _("Whether to use the label text to create a stock menu item"),
- FALSE,
- GTK_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_DEPRECATED));
-
- /**
- * ImageMenuItem:accel-group:
- *
- * The Accel Group to use for stock accelerator keys
- *
- * Since: 2.16
- *
- */
- g_object_class_install_property (gobject_class,
- PROP_ACCEL_GROUP,
- g_param_spec_object ("accel-group",
- _("Accel Group"),
- _("The Accel Group to use for stock accelerator keys"),
- GTK_TYPE_ACCEL_GROUP,
- GTK_PARAM_WRITABLE | G_PARAM_DEPRECATED));
-
-}
-
-static void
-image_menu_item_init (ImageMenuItem *image_menu_item)
-{
- ImageMenuItemPrivate *priv;
-
- image_menu_item->priv = image_menu_item_get_instance_private (image_menu_item);
- priv = image_menu_item->priv;
-
- priv->image = NULL;
- priv->use_stock = FALSE;
- priv->label = NULL;
-}
-
-static void
-image_menu_item_finalize (GObject *object)
-{
- ImageMenuItemPrivate *priv = IMAGE_MENU_ITEM (object)->priv;
-
- g_free (priv->label);
- priv->label = NULL;
-
- G_OBJECT_CLASS (image_menu_item_parent_class)->finalize (object);
-}
-
-static void
-image_menu_item_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ImageMenuItem *image_menu_item = IMAGE_MENU_ITEM (object);
-
- switch (prop_id)
- {
- case PROP_IMAGE:
- image_menu_item_set_image (image_menu_item, (GtkWidget *) g_value_get_object (value));
- break;
- case PROP_USE_STOCK:
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
- image_menu_item_set_use_stock (image_menu_item, g_value_get_boolean (value));
- G_GNUC_END_IGNORE_DEPRECATIONS;
- break;
- case PROP_ACCEL_GROUP:
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
- image_menu_item_set_accel_group (image_menu_item, g_value_get_object (value));
- G_GNUC_END_IGNORE_DEPRECATIONS;
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-image_menu_item_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ImageMenuItem *image_menu_item = IMAGE_MENU_ITEM (object);
-
- switch (prop_id)
- {
- case PROP_IMAGE:
- g_value_set_object (value, image_menu_item_get_image (image_menu_item));
- break;
- case PROP_USE_STOCK:
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
- g_value_set_boolean (value, image_menu_item_get_use_stock (image_menu_item));
- G_GNUC_END_IGNORE_DEPRECATIONS;
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-image_menu_item_map (GtkWidget *widget)
-{
- ImageMenuItem *image_menu_item = IMAGE_MENU_ITEM (widget);
- ImageMenuItemPrivate *priv = image_menu_item->priv;
-
- GTK_WIDGET_CLASS (image_menu_item_parent_class)->map (widget);
-
- if (priv->image)
- g_object_set (priv->image, "visible", TRUE, NULL);
-}
-
-static void
-image_menu_item_destroy (GtkWidget *widget)
-{
- ImageMenuItem *image_menu_item = IMAGE_MENU_ITEM (widget);
- ImageMenuItemPrivate *priv = image_menu_item->priv;
-
- if (priv->image)
- gtk_container_remove (GTK_CONTAINER (image_menu_item),
- priv->image);
-
- GTK_WIDGET_CLASS (image_menu_item_parent_class)->destroy (widget);
-}
-
-static void
-image_menu_item_toggle_size_request (GtkMenuItem *menu_item,
- gint *requisition)
-{
- ImageMenuItem *image_menu_item = IMAGE_MENU_ITEM (menu_item);
- ImageMenuItemPrivate *priv = image_menu_item->priv;
- GtkPackDirection pack_dir;
- GtkWidget *parent;
- GtkWidget *widget = GTK_WIDGET (menu_item);
-
- parent = gtk_widget_get_parent (widget);
-
- if (GTK_IS_MENU_BAR (parent))
- pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
- else
- pack_dir = GTK_PACK_DIRECTION_LTR;
-
- *requisition = 0;
-
- if (priv->image && gtk_widget_get_visible (priv->image))
- {
- GtkRequisition image_requisition;
- guint toggle_spacing;
-
- gtk_widget_get_preferred_size (priv->image, &image_requisition, NULL);
-
- gtk_widget_style_get (GTK_WIDGET (menu_item),
- "toggle-spacing", &toggle_spacing,
- NULL);
-
- if (pack_dir == GTK_PACK_DIRECTION_LTR || pack_dir == GTK_PACK_DIRECTION_RTL)
- {
- if (image_requisition.width > 0)
- *requisition = image_requisition.width + toggle_spacing;
- }
- else
- {
- if (image_requisition.height > 0)
- *requisition = image_requisition.height + toggle_spacing;
- }
- }
-}
-
-static void
-image_menu_item_recalculate (ImageMenuItem *image_menu_item)
-{
- ImageMenuItemPrivate *priv = image_menu_item->priv;
- GtkStockItem stock_item;
- GtkWidget *image;
- const gchar *resolved_label = priv->label;
-
- if (priv->use_stock && priv->label)
- {
-
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-
- if (!priv->image)
- {
- image = gtk_image_new_from_stock (priv->label, GTK_ICON_SIZE_MENU);
- image_menu_item_set_image (image_menu_item, image);
- }
-
- if (gtk_stock_lookup (priv->label, &stock_item))
- resolved_label = stock_item.label;
-
- gtk_menu_item_set_use_underline (GTK_MENU_ITEM (image_menu_item), TRUE);
-
- G_GNUC_END_IGNORE_DEPRECATIONS;
- }
-
- GTK_MENU_ITEM_CLASS
- (image_menu_item_parent_class)->set_label (GTK_MENU_ITEM (image_menu_item), resolved_label);
-
-}
-
-static void
-image_menu_item_set_label (GtkMenuItem *menu_item,
- const gchar *label)
-{
- ImageMenuItemPrivate *priv = IMAGE_MENU_ITEM (menu_item)->priv;
-
- if (priv->label != label)
- {
- g_free (priv->label);
- priv->label = g_strdup (label);
-
- image_menu_item_recalculate (IMAGE_MENU_ITEM (menu_item));
-
- g_object_notify (G_OBJECT (menu_item), "label");
-
- }
-}
-
-static const gchar *
-image_menu_item_get_label (GtkMenuItem *menu_item)
-{
- ImageMenuItemPrivate *priv = IMAGE_MENU_ITEM (menu_item)->priv;
-
- return priv->label;
-}
-
-static void
-image_menu_item_get_preferred_width (GtkWidget *widget,
- gint *minimum,
- gint *natural)
-{
- ImageMenuItem *image_menu_item = IMAGE_MENU_ITEM (widget);
- ImageMenuItemPrivate *priv = image_menu_item->priv;
- GtkPackDirection pack_dir;
- GtkWidget *parent;
-
- parent = gtk_widget_get_parent (widget);
-
- if (GTK_IS_MENU_BAR (parent))
- pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
- else
- pack_dir = GTK_PACK_DIRECTION_LTR;
-
- GTK_WIDGET_CLASS (image_menu_item_parent_class)->get_preferred_width (widget, minimum, natural);
-
- if ((pack_dir == GTK_PACK_DIRECTION_TTB || pack_dir == GTK_PACK_DIRECTION_BTT) &&
- priv->image &&
- gtk_widget_get_visible (priv->image))
- {
- gint child_minimum, child_natural;
-
- gtk_widget_get_preferred_width (priv->image, &child_minimum, &child_natural);
-
- *minimum = MAX (*minimum, child_minimum);
- *natural = MAX (*natural, child_natural);
- }
-}
-
-static void
-image_menu_item_get_preferred_height (GtkWidget *widget,
- gint *minimum,
- gint *natural)
-{
- ImageMenuItem *image_menu_item = IMAGE_MENU_ITEM (widget);
- ImageMenuItemPrivate *priv = image_menu_item->priv;
- gint child_height = 0;
- GtkPackDirection pack_dir;
- GtkWidget *parent;
-
- parent = gtk_widget_get_parent (widget);
-
- if (GTK_IS_MENU_BAR (parent))
- pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
- else
- pack_dir = GTK_PACK_DIRECTION_LTR;
-
- if (priv->image && gtk_widget_get_visible (priv->image))
- {
- GtkRequisition child_requisition;
-
- gtk_widget_get_preferred_size (priv->image, &child_requisition, NULL);
-
- child_height = child_requisition.height;
- }
-
- GTK_WIDGET_CLASS (image_menu_item_parent_class)->get_preferred_height (widget, minimum, natural);
-
- if (pack_dir == GTK_PACK_DIRECTION_RTL || pack_dir == GTK_PACK_DIRECTION_LTR)
- {
- *minimum = MAX (*minimum, child_height);
- *natural = MAX (*natural, child_height);
- }
-}
-
-static void
-image_menu_item_get_preferred_height_for_width (GtkWidget *widget,
- gint width,
- gint *minimum,
- gint *natural)
-{
- ImageMenuItem *image_menu_item = IMAGE_MENU_ITEM (widget);
- ImageMenuItemPrivate *priv = image_menu_item->priv;
- gint child_height = 0;
- GtkPackDirection pack_dir;
- GtkWidget *parent;
-
- parent = gtk_widget_get_parent (widget);
-
- if (GTK_IS_MENU_BAR (parent))
- pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
- else
- pack_dir = GTK_PACK_DIRECTION_LTR;
-
- if (priv->image && gtk_widget_get_visible (priv->image))
- {
- GtkRequisition child_requisition;
-
- gtk_widget_get_preferred_size (priv->image, &child_requisition, NULL);
-
- child_height = child_requisition.height;
- }
-
- GTK_WIDGET_CLASS
- (image_menu_item_parent_class)->get_preferred_height_for_width (widget, width, minimum, natural);
-
- if (pack_dir == GTK_PACK_DIRECTION_RTL || pack_dir == GTK_PACK_DIRECTION_LTR)
- {
- *minimum = MAX (*minimum, child_height);
- *natural = MAX (*natural, child_height);
- }
-}
-
-
-static void
-image_menu_item_size_allocate (GtkWidget *widget,
- GtkAllocation *allocation)
-{
- ImageMenuItem *image_menu_item = IMAGE_MENU_ITEM (widget);
- ImageMenuItemPrivate *priv = image_menu_item->priv;
- GtkAllocation widget_allocation;
- GtkPackDirection pack_dir;
- GtkWidget *parent;
-
- parent = gtk_widget_get_parent (widget);
-
- if (GTK_IS_MENU_BAR (parent))
- pack_dir = gtk_menu_bar_get_child_pack_direction (GTK_MENU_BAR (parent));
- else
- pack_dir = GTK_PACK_DIRECTION_LTR;
-
- GTK_WIDGET_CLASS (image_menu_item_parent_class)->size_allocate (widget, allocation);
-
- if (priv->image && gtk_widget_get_visible (priv->image))
- {
- gint x, y, offset;
- GtkStyleContext *context;
- GtkStateFlags state;
- GtkBorder padding;
- GtkRequisition child_requisition;
- GtkAllocation child_allocation;
- guint horizontal_padding, toggle_spacing;
- gint toggle_size;
-
- toggle_size = image_menu_item->priv->toggle_size;
- gtk_widget_style_get (widget,
- "horizontal-padding", &horizontal_padding,
- "toggle-spacing", &toggle_spacing,
- NULL);
-
- /* Man this is lame hardcoding action, but I can't
- * come up with a solution that's really better.
- */
-
- gtk_widget_get_preferred_size (priv->image, &child_requisition, NULL);
-
- gtk_widget_get_allocation (widget, &widget_allocation);
-
- context = gtk_widget_get_style_context (widget);
- state = gtk_widget_get_state_flags (widget);
- gtk_style_context_get_padding (context, state, &padding);
- offset = gtk_container_get_border_width (GTK_CONTAINER (image_menu_item));
-
- if (pack_dir == GTK_PACK_DIRECTION_LTR ||
- pack_dir == GTK_PACK_DIRECTION_RTL)
- {
- if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) ==
- (pack_dir == GTK_PACK_DIRECTION_LTR))
- x = offset + horizontal_padding + padding.left +
- (toggle_size - toggle_spacing - child_requisition.width) / 2;
- else
- x = widget_allocation.width - offset - horizontal_padding - padding.right -
- toggle_size + toggle_spacing +
- (toggle_size - toggle_spacing - child_requisition.width) / 2;
-
- y = (widget_allocation.height - child_requisition.height) / 2;
- }
- else
- {
- if ((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR) ==
- (pack_dir == GTK_PACK_DIRECTION_TTB))
- y = offset + horizontal_padding + padding.top +
- (toggle_size - toggle_spacing - child_requisition.height) / 2;
- else
- y = widget_allocation.height - offset - horizontal_padding - padding.bottom -
- toggle_size + toggle_spacing +
- (toggle_size - toggle_spacing - child_requisition.height) / 2;
-
- x = (widget_allocation.width - child_requisition.width) / 2;
- }
-
- child_allocation.width = child_requisition.width;
- child_allocation.height = child_requisition.height;
- child_allocation.x = widget_allocation.x + MAX (x, 0);
- child_allocation.y = widget_allocation.y + MAX (y, 0);
-
- gtk_widget_size_allocate (priv->image, &child_allocation);
- }
-}
-
-static void
-image_menu_item_forall (GtkContainer *container,
- gboolean include_internals,
- GtkCallback callback,
- gpointer callback_data)
-{
- ImageMenuItem *image_menu_item = IMAGE_MENU_ITEM (container);
- ImageMenuItemPrivate *priv = image_menu_item->priv;
-
- GTK_CONTAINER_CLASS (image_menu_item_parent_class)->forall (container,
- include_internals,
- callback,
- callback_data);
-
- if (include_internals && priv->image)
- (* callback) (priv->image, callback_data);
-}
-
-
-static void
-image_menu_item_activatable_interface_init (GtkActivatableIface *iface)
-{
- parent_activatable_iface = g_type_interface_peek_parent (iface);
- iface->update = image_menu_item_update;
- iface->sync_action_properties = image_menu_item_sync_action_properties;
-}
-
-static gboolean
-activatable_update_stock_id (ImageMenuItem *image_menu_item, GtkAction *action)
-{
- GtkWidget *image;
- const gchar *stock_id = gtk_action_get_stock_id (action);
-
- image = image_menu_item_get_image (image_menu_item);
-
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-
- if (GTK_IS_IMAGE (image) &&
- stock_id && gtk_icon_factory_lookup_default (stock_id))
- {
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
- gtk_image_set_from_stock (GTK_IMAGE (image), stock_id, GTK_ICON_SIZE_MENU);
- G_GNUC_END_IGNORE_DEPRECATIONS;
- return TRUE;
- }
-
- G_GNUC_END_IGNORE_DEPRECATIONS;
-
- return FALSE;
-}
-
-static gboolean
-activatable_update_gicon (ImageMenuItem *image_menu_item, GtkAction *action)
-{
- GtkWidget *image;
- GIcon *icon = gtk_action_get_gicon (action);
- const gchar *stock_id;
- gboolean ret = FALSE;
-
- stock_id = gtk_action_get_stock_id (action);
-
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-
- image = image_menu_item_get_image (image_menu_item);
-
- if (icon && GTK_IS_IMAGE (image) &&
- !(stock_id && gtk_icon_factory_lookup_default (stock_id)))
- {
- gtk_image_set_from_gicon (GTK_IMAGE (image), icon, GTK_ICON_SIZE_MENU);
- ret = TRUE;
- }
-
- G_GNUC_END_IGNORE_DEPRECATIONS;
-
- return ret;
-}
-
-static void
-activatable_update_icon_name (ImageMenuItem *image_menu_item, GtkAction *action)
-{
- GtkWidget *image;
- const gchar *icon_name = gtk_action_get_icon_name (action);
-
- image = image_menu_item_get_image (image_menu_item);
-
- if (GTK_IS_IMAGE (image) &&
- (gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_EMPTY ||
- gtk_image_get_storage_type (GTK_IMAGE (image)) == GTK_IMAGE_ICON_NAME))
- {
- gtk_image_set_from_icon_name (GTK_IMAGE (image), icon_name, GTK_ICON_SIZE_MENU);
- }
-}
-
-static void
-image_menu_item_update (GtkActivatable *activatable,
- GtkAction *action,
- const gchar *property_name)
-{
- ImageMenuItem *image_menu_item;
- gboolean use_appearance;
-
- image_menu_item = IMAGE_MENU_ITEM (activatable);
-
- parent_activatable_iface->update (activatable, action, property_name);
-
- use_appearance = gtk_activatable_get_use_action_appearance (activatable);
- if (!use_appearance)
- return;
-
- if (strcmp (property_name, "stock-id") == 0)
- activatable_update_stock_id (image_menu_item, action);
- else if (strcmp (property_name, "gicon") == 0)
- activatable_update_gicon (image_menu_item, action);
- else if (strcmp (property_name, "icon-name") == 0)
- activatable_update_icon_name (image_menu_item, action);
-}
-
-static void
-image_menu_item_sync_action_properties (GtkActivatable *activatable,
- GtkAction *action)
-{
- ImageMenuItem *image_menu_item;
- GtkWidget *image;
- gboolean use_appearance;
-
- image_menu_item = IMAGE_MENU_ITEM (activatable);
-
- parent_activatable_iface->sync_action_properties (activatable, action);
-
- if (!action)
- return;
-
- use_appearance = gtk_activatable_get_use_action_appearance (activatable);
- if (!use_appearance)
- return;
-
- image = image_menu_item_get_image (image_menu_item);
- if (image && !GTK_IS_IMAGE (image))
- {
- image_menu_item_set_image (image_menu_item, NULL);
- image = NULL;
- }
-
- if (!image)
- {
- image = gtk_image_new ();
- gtk_widget_show (image);
- image_menu_item_set_image (IMAGE_MENU_ITEM (activatable),
- image);
- }
-
- if (!activatable_update_stock_id (image_menu_item, action) &&
- !activatable_update_gicon (image_menu_item, action))
- activatable_update_icon_name (image_menu_item, action);
-
-}
-
-
-/**
- * image_menu_item_new:
- *
- * Creates a new #ImageMenuItem with an empty label.
- *
- * Returns: a new #ImageMenuItem
- *
- */
-GtkWidget*
-image_menu_item_new (void)
-{
- return g_object_new (TYPE_IMAGE_MENU_ITEM, NULL);
-}
-
-/**
- * image_menu_item_new_with_label:
- * @label: the text of the menu item.
- *
- * Creates a new #ImageMenuItem containing a label.
- *
- * Returns: a new #ImageMenuItem.
- *
- */
-GtkWidget*
-image_menu_item_new_with_label (const gchar *label)
-{
- return g_object_new (TYPE_IMAGE_MENU_ITEM,
- "label", label,
- NULL);
-}
-
-/**
- * image_menu_item_new_with_mnemonic:
- * @label: the text of the menu item, with an underscore in front of the
- * mnemonic character
- *
- * Creates a new #ImageMenuItem containing a label. The label
- * will be created using gtk_label_new_with_mnemonic(), so underscores
- * in @label indicate the mnemonic for the menu item.
- *
- * Returns: a new #ImageMenuItem
- *
- */
-GtkWidget*
-image_menu_item_new_with_mnemonic (const gchar *label)
-{
- return g_object_new (TYPE_IMAGE_MENU_ITEM,
- "use-underline", TRUE,
- "label", label,
- NULL);
-}
-
-/**
- * image_menu_item_new_from_stock:
- * @stock_id: the name of the stock item.
- * @accel_group: (allow-none): the #GtkAccelGroup to add the menu items
- * accelerator to, or %NULL.
- *
- * Creates a new #ImageMenuItem containing the image and text from a
- * stock item. Some stock ids have preprocessor macros like #STOCK_OK
- * and #STOCK_APPLY.
- *
- * If you want this menu item to have changeable accelerators, then pass in
- * %NULL for accel_group. Next call gtk_menu_item_set_accel_path() with an
- * appropriate path for the menu item, use gtk_stock_lookup() to look up the
- * standard accelerator for the stock item, and if one is found, call
- * gtk_accel_map_add_entry() to register it.
- *
- * Returns: a new #ImageMenuItem.
- *
- */
-GtkWidget*
-image_menu_item_new_from_stock (const gchar *stock_id,
- GtkAccelGroup *accel_group)
-{
- return g_object_new (TYPE_IMAGE_MENU_ITEM,
- "label", stock_id,
- "use-stock", TRUE,
- "accel-group", accel_group,
- NULL);
-}
-
-/**
- * image_menu_item_set_use_stock:
- * @image_menu_item: a #ImageMenuItem
- * @use_stock: %TRUE if the menuitem should use a stock item
- *
- * If %TRUE, the label set in the menuitem is used as a
- * stock id to select the stock item for the item.
- *
- * Since: 2.16
- *
- */
-void
-image_menu_item_set_use_stock (ImageMenuItem *image_menu_item,
- gboolean use_stock)
-{
- ImageMenuItemPrivate *priv;
-
- g_return_if_fail (IS_IMAGE_MENU_ITEM (image_menu_item));
-
- priv = image_menu_item->priv;
-
- if (priv->use_stock != use_stock)
- {
- priv->use_stock = use_stock;
-
- image_menu_item_recalculate (image_menu_item);
-
- g_object_notify (G_OBJECT (image_menu_item), "use-stock");
- }
-}
-
-/**
- * image_menu_item_get_use_stock:
- * @image_menu_item: a #ImageMenuItem
- *
- * Checks whether the label set in the menuitem is used as a
- * stock id to select the stock item for the item.
- *
- * Returns: %TRUE if the label set in the menuitem is used as a
- * stock id to select the stock item for the item
- *
- * Since: 2.16
- *
- */
-gboolean
-image_menu_item_get_use_stock (ImageMenuItem *image_menu_item)
-{
- g_return_val_if_fail (IS_IMAGE_MENU_ITEM (image_menu_item), FALSE);
-
- return image_menu_item->priv->use_stock;
-}
-
-/**
- * image_menu_item_set_accel_group:
- * @image_menu_item: a #ImageMenuItem
- * @accel_group: the #GtkAccelGroup
- *
- * Specifies an @accel_group to add the menu items accelerator to
- * (this only applies to stock items so a stock item must already
- * be set, make sure to call image_menu_item_set_use_stock()
- * and gtk_menu_item_set_label() with a valid stock item first).
- *
- * If you want this menu item to have changeable accelerators then
- * you shouldnt need this (see image_menu_item_new_from_stock()).
- *
- * Since: 2.16
- *
- */
-void
-image_menu_item_set_accel_group (ImageMenuItem *image_menu_item,
- GtkAccelGroup *accel_group)
-{
- ImageMenuItemPrivate *priv;
- GtkStockItem stock_item;
-
- /* Silent return for the constructor */
- if (!accel_group)
- return;
-
- g_return_if_fail (IS_IMAGE_MENU_ITEM (image_menu_item));
- g_return_if_fail (GTK_IS_ACCEL_GROUP (accel_group));
-
- priv = image_menu_item->priv;
-
- G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
-
- if (priv->use_stock && priv->label && gtk_stock_lookup (priv->label, &stock_item))
- if (stock_item.keyval)
- {
- gtk_widget_add_accelerator (GTK_WIDGET (image_menu_item),
- "activate",
- accel_group,
- stock_item.keyval,
- stock_item.modifier,
- GTK_ACCEL_VISIBLE);
-
- g_object_notify (G_OBJECT (image_menu_item), "accel-group");
- }
-
- G_GNUC_END_IGNORE_DEPRECATIONS;
-
-}
-
-/**
- * image_menu_item_set_image:
- * @image_menu_item: a #ImageMenuItem.
- * @image: (allow-none): a widget to set as the image for the menu item.
- *
- * Sets the image of @image_menu_item to the given widget.
- * Note that it depends on the show-menu-images setting whether
- * the image will be displayed or not.
- *
- */
-void
-image_menu_item_set_image (ImageMenuItem *image_menu_item,
- GtkWidget *image)
-{
- ImageMenuItemPrivate *priv;
-
- g_return_if_fail (IS_IMAGE_MENU_ITEM (image_menu_item));
-
- priv = image_menu_item->priv;
-
- if (image == priv->image)
- return;
-
- if (priv->image)
- gtk_container_remove (GTK_CONTAINER (image_menu_item),
- priv->image);
-
- priv->image = image;
-
- if (image == NULL)
- return;
-
- gtk_widget_set_parent (image, GTK_WIDGET (image_menu_item));
- g_object_set (image, "visible", TRUE, "no-show-all", TRUE, NULL);
-
- g_object_notify (G_OBJECT (image_menu_item), "image");
-}
-
-/**
- * image_menu_item_get_image:
- * @image_menu_item: a #ImageMenuItem
- *
- * Gets the widget that is currently set as the image of @image_menu_item.
- * See image_menu_item_set_image().
- *
- * Return value: (transfer none): the widget set as image of @image_menu_item
- *
- **/
-GtkWidget*
-image_menu_item_get_image (ImageMenuItem *image_menu_item)
-{
- g_return_val_if_fail (IS_IMAGE_MENU_ITEM (image_menu_item), NULL);
-
- return image_menu_item->priv->image;
-}
-
-static void
-image_menu_item_remove (GtkContainer *container,
- GtkWidget *child)
-{
- ImageMenuItem *image_menu_item = IMAGE_MENU_ITEM (container);
- ImageMenuItemPrivate *priv = image_menu_item->priv;
-
- if (child == priv->image)
- {
- gboolean widget_was_visible;
-
- widget_was_visible = gtk_widget_get_visible (child);
-
- gtk_widget_unparent (child);
- priv->image = NULL;
-
- if (widget_was_visible &&
- gtk_widget_get_visible (GTK_WIDGET (container)))
- gtk_widget_queue_resize (GTK_WIDGET (container));
-
- g_object_notify (G_OBJECT (image_menu_item), "image");
- }
- else
- {
- GTK_CONTAINER_CLASS (image_menu_item_parent_class)->remove (container, child);
- }
-}
-
-static void
-show_image_change_notify (ImageMenuItem *image_menu_item)
-{
- ImageMenuItemPrivate *priv = image_menu_item->priv;
-
- if (priv->image)
- {
- gtk_widget_show (priv->image);
- }
-}
-
-static void
-traverse_container (GtkWidget *widget,
- gpointer data)
-{
- if (IS_IMAGE_MENU_ITEM (widget))
- show_image_change_notify (IMAGE_MENU_ITEM (widget));
- else if (GTK_IS_CONTAINER (widget))
- gtk_container_forall (GTK_CONTAINER (widget), traverse_container, NULL);
-}
-
-static void
-image_menu_item_setting_changed (GtkSettings *settings)
-{
- GList *list, *l;
-
- list = gtk_window_list_toplevels ();
-
- for (l = list; l; l = l->next)
- gtk_container_forall (GTK_CONTAINER (l->data),
- traverse_container, NULL);
-
- g_list_free (list);
-}
-
-static void
-image_menu_item_screen_changed (GtkWidget *widget,
- GdkScreen *previous_screen)
-{
- GtkSettings *settings;
- gulong show_image_connection;
-
- if (!gtk_widget_has_screen (widget))
- return;
-
- settings = gtk_widget_get_settings (widget);
-
- show_image_connection =
- g_signal_handler_find (settings, G_SIGNAL_MATCH_FUNC, 0, 0,
- NULL, image_menu_item_setting_changed, NULL);
-
- if (show_image_connection)
- return;
-
- g_signal_connect (settings, "notify::gtk-menu-images",
- G_CALLBACK (image_menu_item_setting_changed), NULL);
-
- show_image_change_notify (IMAGE_MENU_ITEM (widget));
-}
diff --git a/src/widgets/image-menu-item.h b/src/widgets/image-menu-item.h
deleted file mode 100644
index 61cc48f3a..000000000
--- a/src/widgets/image-menu-item.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/* GTK - The GIMP Toolkit
- * Copyright (C) Red Hat, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2000.
- * Forked for , icons in menus are important to us.
- */
-
-#ifndef __IMAGE_MENU_ITEM_H__
-#define __IMAGE_MENU_ITEM_H__
-
-#include <gtk/gtk.h>
-
-G_BEGIN_DECLS
-
-#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-#define GTK_PARAM_WRITABLE G_PARAM_WRITABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-
-#define TYPE_IMAGE_MENU_ITEM (image_menu_item_get_type ())
-#define IMAGE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_IMAGE_MENU_ITEM, ImageMenuItem))
-#define IMAGE_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_IMAGE_MENU_ITEM, ImageMenuItemClass))
-#define IS_IMAGE_MENU_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_IMAGE_MENU_ITEM))
-#define IS_IMAGE_MENU_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_IMAGE_MENU_ITEM))
-#define IMAGE_MENU_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_IMAGE_MENU_ITEM, ImageMenuItemClass))
-
-typedef struct _ImageMenuItem ImageMenuItem;
-typedef struct _ImageMenuItemPrivate ImageMenuItemPrivate;
-typedef struct _ImageMenuItemClass ImageMenuItemClass;
-
-struct _ImageMenuItem
-{
- GtkMenuItem menu_item;
-
- /*< private >*/
- ImageMenuItemPrivate *priv;
-};
-
-struct _ImageMenuItemClass
-{
- GtkMenuItemClass parent_class;
-
- /* Padding for future expansion */
- void (*_gtk_reserved1) (void);
- void (*_gtk_reserved2) (void);
- void (*_gtk_reserved3) (void);
- void (*_gtk_reserved4) (void);
-};
-
-GType image_menu_item_get_type (void) G_GNUC_CONST;
-GtkWidget* image_menu_item_new (void);
-GtkWidget* image_menu_item_new_with_label (const gchar *label);
-GtkWidget* image_menu_item_new_with_mnemonic (const gchar *label);
-GtkWidget* image_menu_item_new_from_stock (const gchar *stock_id,
- GtkAccelGroup *accel_group);
-void image_menu_item_set_image (ImageMenuItem *image_menu_item,
- GtkWidget *image);
-GtkWidget* image_menu_item_get_image (ImageMenuItem *image_menu_item);
-void image_menu_item_set_use_stock (ImageMenuItem *image_menu_item,
- gboolean use_stock);
-gboolean image_menu_item_get_use_stock (ImageMenuItem *image_menu_item);
-void image_menu_item_set_accel_group (ImageMenuItem *image_menu_item,
- GtkAccelGroup *accel_group);
-
-G_END_DECLS
-
-#endif /* __IMAGE_MENU_ITEM_H__ */
diff --git a/src/widgets/ink-action.cpp b/src/widgets/ink-action.cpp
index 2f1bf94e4..8859306f1 100644
--- a/src/widgets/ink-action.cpp
+++ b/src/widgets/ink-action.cpp
@@ -1,8 +1,6 @@
#include "ink-action.h"
#include "widgets/icon.h"
-#include "widgets/image-menu-item.h"
-
#include <gtk/gtk.h>
static void ink_action_finalize( GObject* obj );
@@ -155,7 +153,7 @@ static GtkWidget* ink_action_create_menu_item( GtkAction* action )
if ( act->private_data->iconId ) {
gchar* label = 0;
g_object_get( G_OBJECT(act), "label", &label, NULL );
- item = image_menu_item_new_with_mnemonic( label );
+ item = gtk_image_menu_item_new_with_mnemonic( label );
GtkWidget* child = sp_icon_new( Inkscape::ICON_SIZE_MENU, act->private_data->iconId );
// TODO this work-around is until SPIcon will live properly inside of a popup menu
@@ -170,7 +168,7 @@ static GtkWidget* ink_action_create_menu_item( GtkAction* action )
}
}
gtk_widget_show_all( child );
- image_menu_item_set_image( IMAGE_MENU_ITEM(item), child );
+ gtk_image_menu_item_set_image( GTK_IMAGE_MENU_ITEM(item), child );
g_free( label );
label = 0;
diff --git a/src/widgets/lpe-toolbar.cpp b/src/widgets/lpe-toolbar.cpp
index 5df5fde70..c714aba10 100644
--- a/src/widgets/lpe-toolbar.cpp
+++ b/src/widgets/lpe-toolbar.cpp
@@ -302,7 +302,7 @@ void sp_lpetool_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GO
gtk_list_store_append( model, &iter );
gtk_list_store_set( model, &iter,
0, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(),
- 1, Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str(),
+ 1, _(Inkscape::LivePathEffect::LPETypeConverter.get_label(type).c_str()),
2, lpesubtools[i].icon_name,
-1 );
}
diff --git a/src/widgets/measure-toolbar.cpp b/src/widgets/measure-toolbar.cpp
index a8c974bbc..066c3fbfa 100644
--- a/src/widgets/measure-toolbar.cpp
+++ b/src/widgets/measure-toolbar.cpp
@@ -326,7 +326,7 @@ void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, G
{
eact = create_adjustment_action( "MeasureOffsetAction",
_("Offset"), _("Offset:"),
- _("The offset size"),
+ _("Mark dimension offset"),
"/tools/measure/offset", 5.0,
GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
0.0, 90000.0, 1.0, 4.0,
diff --git a/src/widgets/mesh-toolbar.cpp b/src/widgets/mesh-toolbar.cpp
index 898104ad3..7a37376db 100644
--- a/src/widgets/mesh-toolbar.cpp
+++ b/src/widgets/mesh-toolbar.cpp
@@ -18,6 +18,8 @@
#include <config.h>
#endif
+#include <gtkmm.h>
+
// REVIEW THESE AT END OF REWRITE
#include "ui/widget/color-preview.h"
#include "toolbox.h"
@@ -66,76 +68,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
@@ -172,7 +177,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 );
@@ -203,34 +208,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
*/
@@ -295,18 +272,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"));
}
}
@@ -356,6 +332,41 @@ static void ms_fit_mesh(void)
}
}
+static void ms_toggle_handles(void)
+{
+ MeshTool *mt = get_mesh_tool();
+ if (mt) {
+ GrDrag *drag = mt->_grdrag;
+ drag->refreshDraggers();
+ }
+}
+
+static void ms_toggle_fill_stroke(InkToggleAction * /*act*/, gpointer data)
+{
+ MeshTool *mt = get_mesh_tool();
+ if (mt) {
+ GrDrag *drag = mt->_grdrag;
+ drag->updateDraggers();
+ drag->updateLines();
+ drag->updateLevels();
+ ms_tb_selection_changed(NULL, data); // Need to update Type widget
+ }
+}
+
+static void ms_warning_popup(void)
+{
+ char *msg = _("Mesh gradients are part of SVG 2:\n"
+ "* Syntax may change.\n"
+ "* Web browser implementation is not guaranteed.\n"
+ "\n"
+ "For web: convert to bitmap (Edit->Make bitmap copy).\n"
+ "For print: export to PDF.");
+ Gtk::MessageDialog dialog(msg, false, Gtk::MESSAGE_WARNING,
+ Gtk::BUTTONS_OK, true);
+ dialog.run();
+
+}
+
static void mesh_toolbox_watch_ec(SPDesktop* dt, Inkscape::UI::Tools::ToolBase* ec, GObject* holder);
/**
@@ -472,6 +483,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), holder);
}
/* Edit stroke mesh */
@@ -484,18 +496,20 @@ 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), holder);
}
/* Show/hide side and tensor handles */
{
InkToggleAction* act = ink_toggle_action_new( "MeshShowHandlesAction",
_("Show Handles"),
- _("Show side and tensor handles"),
+ _("Show handles"),
INKSCAPE_ICON("show-node-handles"),
secondarySize );
gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/mesh/show_handles");
g_signal_connect( holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_toggle_handles), 0);
}
g_object_set_data(holder, "desktop", desktop);
@@ -504,9 +518,14 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj
/* Warning */
{
- GtkAction* act = gtk_action_new( "MeshWarningAction",
- _("WARNING: Mesh SVG Syntax Subject to Change"), NULL, NULL );
+ InkAction* act = ink_action_new( "MeshWarningAction",
+ _("WARNING: Mesh SVG Syntax Subject to Change"),
+ _("WARNING: Mesh SVG Syntax Subject to Change"),
+ INKSCAPE_ICON("dialog-warning"),
+ secondarySize );
gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_warning_popup), holder );
+ gtk_action_set_sensitive( GTK_ACTION(act), TRUE );
}
/* Type */
@@ -520,6 +539,7 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj
gtk_list_store_append( model, &iter );
gtk_list_store_set( model, &iter, 0, _("Bicubic"), 1, SP_MESH_TYPE_BICUBIC, -1 );
+ // TRANSLATORS: Type of Smoothing. See https://en.wikipedia.org/wiki/Coons_patch
EgeSelectOneAction* act = ege_select_one_action_new( "MeshSmoothAction", _("Coons"),
_("Coons: no smoothing. Bicubic: smoothing across patch boundaries."),
NULL, GTK_TREE_MODEL(model) );
diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp
index 3e9f0687d..855371ddd 100644
--- a/src/widgets/paint-selector.cpp
+++ b/src/widgets/paint-selector.cpp
@@ -285,6 +285,11 @@ static void sp_paint_selector_dispose(GObject *object)
// clean up our long-living pattern menu
g_object_set_data(G_OBJECT(psel),"patternmenu",NULL);
+#ifdef WITH_MESH
+ // clean up our long-living mesh menu
+ g_object_set_data(G_OBJECT(psel),"meshmenu",NULL);
+#endif
+
if (psel->selected_color) {
delete psel->selected_color;
psel->selected_color = NULL;
@@ -492,7 +497,7 @@ void SPPaintSelector::setGradientRadial(SPGradient *vector)
}
#ifdef WITH_MESH
-void SPPaintSelector::setGradientMesh(SPGradient *array)
+void SPPaintSelector::setGradientMesh(SPMeshGradient *array)
{
#ifdef SP_PS_VERBOSE
g_print("PaintSelector set GRADIENT MESH\n");
@@ -524,24 +529,6 @@ void SPPaintSelector::getGradientProperties( SPGradientUnits &units, SPGradientS
spread = gsel->getSpread();
}
-#ifdef WITH_MESH
-void SPPaintSelector::setMeshProperties( SPGradientUnits units )
-{
- g_return_if_fail(mode == MODE_GRADIENT_MESH);
-
- // SPGradientSelector *gsel = getGradientFromData(this);
- // gsel->setUnits(units);
-}
-
-void SPPaintSelector::getMeshProperties( SPGradientUnits &units) const
-{
- g_return_if_fail(mode == MODE_GRADIENT_MESH);
-
- // SPGradientSelector *gsel = getGradientFromData(this);
- // units = gsel->getUnits();
-}
-#endif
-
/**
* \post (alpha == NULL) || (*alpha in [0.0, 1.0]).
@@ -788,7 +775,214 @@ static void sp_paint_selector_set_mode_gradient(SPPaintSelector *psel, SPPaintSe
#endif
}
+// ************************* MESH ************************
#ifdef WITH_MESH
+static void sp_psel_mesh_destroy(GtkWidget *widget, SPPaintSelector * /*psel*/)
+{
+ // drop our reference to the mesh menu widget
+ g_object_unref( G_OBJECT(widget) );
+}
+
+static void sp_psel_mesh_change(GtkWidget * /*widget*/, SPPaintSelector *psel)
+{
+ g_signal_emit(G_OBJECT(psel), psel_signals[CHANGED], 0);
+}
+
+
+/**
+ * Returns a list of meshes in the defs of the given source document as a GSList object
+ * Returns NULL if there are no meshes in the document.
+ */
+static GSList *
+ink_mesh_list_get (SPDocument *source)
+{
+ if (source == NULL)
+ return NULL;
+
+ GSList *pl = NULL;
+ std::vector<SPObject *> meshes = source->getResourceList("gradient");
+ for (std::vector<SPObject *>::const_iterator it = meshes.begin(); it != meshes.end(); ++it) {
+ if (SP_IS_MESHGRADIENT(*it) &&
+ SP_GRADIENT(*it) == SP_GRADIENT(*it)->getArray()) { // only if this is a root mesh
+ pl = g_slist_prepend(pl, *it);
+ }
+ }
+
+ pl = g_slist_reverse(pl);
+ return pl;
+}
+
+/**
+ * Adds menu items for mesh list.
+ */
+static void
+sp_mesh_menu_build (GtkWidget *combo, GSList *mesh_list, SPDocument */*source*/)
+{
+ GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo)));
+ GtkTreeIter iter;
+
+ for (; mesh_list != NULL; mesh_list = mesh_list->next) {
+
+ Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(mesh_list->data)->getRepr();
+
+ gchar const *meshid = repr->attribute("id");
+ gchar const *label = meshid;
+
+ // Only relevant if we supply a set of canned meshes.
+ gboolean stockid = false;
+ if (repr->attribute("inkscape:stockid")) {
+ label = _(repr->attribute("inkscape:stockid"));
+ stockid = true;
+ }
+
+ gtk_list_store_append(store, &iter);
+ gtk_list_store_set(store, &iter,
+ COMBO_COL_LABEL, label, COMBO_COL_STOCK, stockid, COMBO_COL_MESH, meshid, COMBO_COL_SEP, FALSE, -1);
+
+ }
+}
+
+/**
+ * Pick up all meshes from source, except those that are in
+ * current_doc (if non-NULL), and add items to the mesh menu.
+ */
+static void sp_mesh_list_from_doc(GtkWidget *combo, SPDocument * /*current_doc*/, SPDocument *source, SPDocument * /*mesh_doc*/)
+{
+ GSList *pl = ink_mesh_list_get(source);
+ GSList *clean_pl = NULL;
+
+ for (; pl != NULL; pl = pl->next) {
+ if (!SP_IS_MESHGRADIENT(pl->data)) {
+ continue;
+ }
+ // Add to the list of meshes we really do wish to show
+ clean_pl = g_slist_prepend (clean_pl, pl->data);
+ }
+
+ sp_mesh_menu_build (combo, clean_pl, source);
+
+ g_slist_free (pl);
+ g_slist_free (clean_pl);
+}
+
+
+static void
+ink_mesh_menu_populate_menu(GtkWidget *combo, SPDocument *doc)
+{
+ static SPDocument *meshes_doc = NULL;
+
+ // If we ever add a list of canned mesh gradients, uncomment following:
+
+ // find and load meshes.svg
+ // if (meshes_doc == NULL) {
+ // char *meshes_source = g_build_filename(INKSCAPE_MESHESDIR, "meshes.svg", NULL);
+ // if (Inkscape::IO::file_test(meshes_source, G_FILE_TEST_IS_REGULAR)) {
+ // meshes_doc = SPDocument::createNewDoc(meshes_source, FALSE);
+ // }
+ // g_free(meshes_source);
+ // }
+
+ // suck in from current doc
+ sp_mesh_list_from_doc ( combo, NULL, doc, meshes_doc );
+
+ // add separator
+ // {
+ // GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo)));
+ // GtkTreeIter iter;
+ // gtk_list_store_append (store, &iter);
+ // gtk_list_store_set(store, &iter,
+ // COMBO_COL_LABEL, "", COMBO_COL_STOCK, false, COMBO_COL_MESH, "", COMBO_COL_SEP, true, -1);
+ // }
+
+ // suck in from meshes.svg
+ // if (meshes_doc) {
+ // doc->ensureUpToDate();
+ // sp_mesh_list_from_doc ( combo, doc, meshes_doc, NULL );
+ // }
+
+}
+
+
+static GtkWidget*
+ink_mesh_menu(GtkWidget *combo)
+{
+ SPDocument *doc = SP_ACTIVE_DOCUMENT;
+
+ GtkListStore *store = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(combo)));
+ GtkTreeIter iter;
+
+ if (!doc) {
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COMBO_COL_LABEL, _("No document selected"), COMBO_COL_STOCK, false, COMBO_COL_MESH, "", COMBO_COL_SEP, false, -1);
+ gtk_widget_set_sensitive(combo, FALSE);
+
+ } else {
+
+ ink_mesh_menu_populate_menu(combo, doc);
+ gtk_widget_set_sensitive(combo, TRUE);
+
+ }
+
+ // Select the first item that is not a separator
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter)) {
+ gboolean sep = false;
+ gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, COMBO_COL_SEP, &sep, -1);
+ if (sep) {
+ gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter);
+ }
+ gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo), &iter);
+ }
+
+ return combo;
+}
+
+
+/*update mesh list*/
+void SPPaintSelector::updateMeshList( SPMeshGradient *mesh )
+{
+ if (update) {
+ return;
+ }
+
+ GtkWidget *combo = GTK_WIDGET(g_object_get_data(G_OBJECT(this), "meshmenu"));
+ g_assert( combo != NULL );
+
+ /* Clear existing menu if any */
+ GtkTreeModel *store = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
+ gtk_list_store_clear(GTK_LIST_STORE(store));
+
+ ink_mesh_menu(combo);
+
+ /* Set history */
+
+ if (mesh && !g_object_get_data(G_OBJECT(combo), "update")) {
+
+ g_object_set_data(G_OBJECT(combo), "update", GINT_TO_POINTER(TRUE));
+ gchar const *meshname = mesh->getRepr()->attribute("id");
+
+ // Find this mesh and set it active in the combo_box
+ GtkTreeIter iter ;
+ gchar *meshid = NULL;
+ bool valid = gtk_tree_model_get_iter_first (store, &iter);
+ if (!valid) {
+ return;
+ }
+ gtk_tree_model_get (store, &iter, COMBO_COL_MESH, &meshid, -1);
+ while (valid && strcmp(meshid, meshname) != 0) {
+ valid = gtk_tree_model_iter_next (store, &iter);
+ gtk_tree_model_get (store, &iter, COMBO_COL_MESH, &meshid, -1);
+ }
+
+ if (valid) {
+ gtk_combo_box_set_active_iter(GTK_COMBO_BOX(combo), &iter);
+ }
+
+ g_object_set_data(G_OBJECT(combo), "update", GINT_TO_POINTER(FALSE));
+ }
+}
+
static void sp_paint_selector_set_mode_mesh(SPPaintSelector *psel, SPPaintSelector::Mode mode)
{
if (mode == SPPaintSelector::MODE_GRADIENT_MESH) {
@@ -799,23 +993,50 @@ static void sp_paint_selector_set_mode_mesh(SPPaintSelector *psel, SPPaintSelect
GtkWidget *tbl = NULL;
if (psel->mode == SPPaintSelector::MODE_GRADIENT_MESH) {
- /* Already have mesh selector */
+ /* Already have mesh menu */
tbl = GTK_WIDGET(g_object_get_data(G_OBJECT(psel->selector), "mesh-selector"));
} else {
sp_paint_selector_clear_frame(psel);
- /* We could create a new gradient selector once adapted for meshes.
- But for the moment we just create an empty widget. */
/* Create vbox */
tbl = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
gtk_box_set_homogeneous(GTK_BOX(tbl), FALSE);
gtk_widget_show(tbl);
{
+ auto hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 1);
+ gtk_box_set_homogeneous(GTK_BOX(hb), FALSE);
+
+ /**
+ * Create a combo_box and store with 4 columns,
+ * The label, a pointer to the mesh, is stockid or not, is a separator or not.
+ */
+ GtkListStore *store = gtk_list_store_new (COMBO_N_COLS, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_BOOLEAN);
+ GtkWidget *combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL (store));
+ gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(combo), SPPaintSelector::isSeparator, NULL, NULL);
+
+ GtkCellRenderer *renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_renderer_set_padding (renderer, 2, 0);
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
+ gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo), renderer, "text", COMBO_COL_LABEL, NULL);
+
+ ink_mesh_menu(combo);
+ g_signal_connect(G_OBJECT(combo), "changed", G_CALLBACK(sp_psel_mesh_change), psel);
+ g_signal_connect(G_OBJECT(combo), "destroy", G_CALLBACK(sp_psel_mesh_destroy), psel);
+ g_object_set_data(G_OBJECT(psel), "meshmenu", combo);
+ g_object_ref( G_OBJECT(combo));
+
+ gtk_container_add(GTK_CONTAINER(hb), combo);
+ gtk_box_pack_start(GTK_BOX(tbl), hb, FALSE, FALSE, AUX_BETWEEN_BUTTON_GROUPS);
+
+ g_object_unref( G_OBJECT(store));
+ }
+
+ {
auto hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_set_homogeneous(GTK_BOX(hb), FALSE);
auto l = gtk_label_new(NULL);
- gtk_label_set_markup(GTK_LABEL(l), _("Use the <b>Mesh tool</b> to create new and edit existing meshes. Mesh selection and copying not yet implemented."));
+ gtk_label_set_markup(GTK_LABEL(l), _("Use the <b>Mesh tool</b> to modify the mesh."));
gtk_label_set_line_wrap(GTK_LABEL(l), true);
gtk_widget_set_size_request(l, 180, -1);
gtk_box_pack_start(GTK_BOX(hb), l, TRUE, TRUE, AUX_BETWEEN_BUTTON_GROUPS);
@@ -828,11 +1049,66 @@ static void sp_paint_selector_set_mode_mesh(SPPaintSelector *psel, SPPaintSelect
psel->selector = tbl;
g_object_set_data(G_OBJECT(psel->selector), "mesh-selector", tbl);
- gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Mesh gradient</b>"));
+ gtk_label_set_markup(GTK_LABEL(psel->label), _("<b>Mesh fill</b>"));
}
+#ifdef SP_PS_VERBOSE
+ g_print("Mesh req\n");
+#endif
+}
+
+SPMeshGradient *SPPaintSelector::getMeshGradient()
+{
+ g_return_val_if_fail((mode == MODE_GRADIENT_MESH) , NULL);
+
+ GtkWidget *combo = GTK_WIDGET(g_object_get_data(G_OBJECT(this), "meshmenu"));
+ /* no mesh menu if we were just selected */
+ if ( combo == NULL ) {
+ return NULL;
+ }
+ GtkTreeModel *store = gtk_combo_box_get_model(GTK_COMBO_BOX(combo));
+
+ /* Get the selected mesh */
+ GtkTreeIter iter;
+ if (!gtk_combo_box_get_active_iter (GTK_COMBO_BOX(combo), &iter) ||
+ !gtk_list_store_iter_is_valid(GTK_LIST_STORE(store), &iter)) {
+ return NULL;
+ }
+
+ gchar *meshid = NULL;
+ gboolean stockid = FALSE;
+ gchar *label = NULL;
+ gtk_tree_model_get (store, &iter, COMBO_COL_LABEL, &label, COMBO_COL_STOCK, &stockid, COMBO_COL_MESH, &meshid, -1);
+ // std::cout << " .. meshid: " << (meshid?meshid:"null") << " label: " << (label?label:"null") << std::endl;
+ if (meshid == NULL) {
+ return NULL;
+ }
+
+ SPMeshGradient *mesh = 0;
+ if (strcmp(meshid, "none")){
+
+ gchar *mesh_name;
+ if (stockid) {
+ mesh_name = g_strconcat("urn:inkscape:mesh:", meshid, NULL);
+ } else {
+ mesh_name = g_strdup(meshid);
+ }
+
+ SPObject *mesh_obj = get_stock_item(mesh_name);
+ if (mesh_obj && SP_IS_MESHGRADIENT(mesh_obj)) {
+ mesh = SP_MESHGRADIENT(mesh_obj);
+ }
+ g_free(mesh_name);
+
+ } else {
+ std::cerr << "SPPaintSelector::getMeshGradient: Unexpected meshid value." << std::endl;
+ }
+
+ return mesh;
}
+
#endif
+// ************************ End Mesh ************************
static void
sp_paint_selector_set_style_buttons(SPPaintSelector *psel, GtkWidget *active)
diff --git a/src/widgets/paint-selector.h b/src/widgets/paint-selector.h
index 815a6da0b..3302632b8 100644
--- a/src/widgets/paint-selector.h
+++ b/src/widgets/paint-selector.h
@@ -26,6 +26,9 @@
#include "ui/selected-color.h"
class SPGradient;
+#ifdef WITH_MESH
+class SPMeshGradient;
+#endif
class SPDesktop;
class SPPattern;
class SPStyle;
@@ -98,18 +101,21 @@ struct SPPaintSelector {
void setGradientLinear( SPGradient *vector );
void setGradientRadial( SPGradient *vector );
#ifdef WITH_MESH
- void setGradientMesh(SPGradient *array);
+ void setGradientMesh(SPMeshGradient *array);
#endif
void setSwatch( SPGradient *vector );
void setGradientProperties( SPGradientUnits units, SPGradientSpread spread );
void getGradientProperties( SPGradientUnits &units, SPGradientSpread &spread ) const;
- void setMeshProperties( SPGradientUnits units );
- void getMeshProperties( SPGradientUnits &units ) const;
-
void pushAttrsToGradient( SPGradient *gr ) const;
SPGradient *getGradientVector();
+
+#ifdef WITH_MESH
+ SPMeshGradient * getMeshGradient();
+ void updateMeshList( SPMeshGradient *pat );
+#endif
+
SPPattern * getPattern();
void updatePatternList( SPPattern *pat );
@@ -124,8 +130,14 @@ struct SPPaintSelector {
void onSelectedColorChanged();
};
-enum {COMBO_COL_LABEL=0, COMBO_COL_STOCK=1, COMBO_COL_PATTERN=2, COMBO_COL_SEP=3, COMBO_N_COLS=4};
-
+enum {
+ COMBO_COL_LABEL = 0,
+ COMBO_COL_STOCK = 1,
+ COMBO_COL_PATTERN = 2,
+ COMBO_COL_MESH = COMBO_COL_PATTERN,
+ COMBO_COL_SEP = 3,
+ COMBO_N_COLS = 4
+};
/// The SPPaintSelector vtable
struct SPPaintSelectorClass {
diff --git a/src/widgets/paintbucket-toolbar.cpp b/src/widgets/paintbucket-toolbar.cpp
index 3d1565924..e2212b64f 100644
--- a/src/widgets/paintbucket-toolbar.cpp
+++ b/src/widgets/paintbucket-toolbar.cpp
@@ -192,7 +192,7 @@ void sp_paintbucket_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions
iterator != gap_list.end(); ++iterator ) {
GtkTreeIter iter;
gtk_list_store_append( model, &iter );
- gtk_list_store_set( model, &iter, 0, _((*iterator).c_str()), 1, count, -1 );
+ gtk_list_store_set( model, &iter, 0, g_dpgettext2(NULL, "Flood autogap", (*iterator).c_str()), 1, count, -1 );
count++;
}
EgeSelectOneAction* act2 = ege_select_one_action_new( "AutoGapAction", _("Close gaps"), (""), NULL, GTK_TREE_MODEL(model) );
diff --git a/src/widgets/select-toolbar.cpp b/src/widgets/select-toolbar.cpp
index c5ff713bd..2ac7447dd 100644
--- a/src/widgets/select-toolbar.cpp
+++ b/src/widgets/select-toolbar.cpp
@@ -550,14 +550,14 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb
} else {
g_warning("Unexpected holder type");
}
-
// "Transform with object" buttons
{
+
InkToggleAction* itact = ink_toggle_action_new( "transform_stroke",
_("Scale stroke width"),
_("When scaling objects, scale the stroke width by the same proportion"),
- INKSCAPE_ICON("transform-affect-stroke"),
- Inkscape::ICON_SIZE_DECORATION );
+ "transform-affect-stroke",
+ secondarySize );
gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/stroke", true) );
g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_stroke), desktop) ;
gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
@@ -567,8 +567,8 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb
InkToggleAction* itact = ink_toggle_action_new( "transform_corners",
_("Scale rounded corners"),
_("When scaling rectangles, scale the radii of rounded corners"),
- INKSCAPE_ICON("transform-affect-rounded-corners"),
- Inkscape::ICON_SIZE_DECORATION );
+ "transform-affect-rounded-corners",
+ secondarySize );
gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/rectcorners", true) );
g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_corners), desktop) ;
gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
@@ -578,8 +578,8 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb
InkToggleAction* itact = ink_toggle_action_new( "transform_gradient",
_("Move gradients"),
_("Move gradients (in fill or stroke) along with the objects"),
- INKSCAPE_ICON("transform-affect-gradient"),
- Inkscape::ICON_SIZE_DECORATION );
+ "transform-affect-gradient",
+ secondarySize );
gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/gradient", true) );
g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_gradient), desktop) ;
gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
@@ -589,8 +589,8 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb
InkToggleAction* itact = ink_toggle_action_new( "transform_pattern",
_("Move patterns"),
_("Move patterns (in fill or stroke) along with the objects"),
- INKSCAPE_ICON("transform-affect-pattern"),
- Inkscape::ICON_SIZE_DECORATION );
+ "transform-affect-pattern",
+ secondarySize );
gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(itact), prefs->getBool("/options/transform/pattern", true) );
g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(toggle_pattern), desktop) ;
gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp
index 81a8e8115..de3e98297 100644
--- a/src/widgets/stroke-style.cpp
+++ b/src/widgets/stroke-style.cpp
@@ -940,7 +940,7 @@ StrokeStyle::updateLine()
SPStyle * const style = object->style;
/* Markers */
- updateAllMarkers(objects); // FIXME: make this desktop query too
+ updateAllMarkers(objects, true); // FIXME: make this desktop query too
/* Dash */
setDashSelectorFromStyle(dashSelector, style); // FIXME: make this desktop query too
@@ -1192,7 +1192,7 @@ StrokeStyle::setPaintOrderButtons(Gtk::ToggleButton *active)
* that marker.
*/
void
-StrokeStyle::updateAllMarkers(std::vector<SPItem*> const &objects)
+StrokeStyle::updateAllMarkers(std::vector<SPItem*> const &objects, bool skip_undo)
{
struct { MarkerComboBox *key; int loc; } const keyloc[] = {
{ startMarkerCombo, SP_MARKER_LOC_START },
@@ -1246,9 +1246,11 @@ StrokeStyle::updateAllMarkers(std::vector<SPItem*> const &objects)
if (update) {
setMarkerColor(marker, combo->get_loc(), SP_ITEM(object));
- SPDocument *document = desktop->getDocument();
- DocumentUndo::done(document, SP_VERB_DIALOG_FILL_STROKE,
+ if (!skip_undo) {
+ SPDocument *document = desktop->getDocument();
+ DocumentUndo::maybeDone(document, "UaM", SP_VERB_DIALOG_FILL_STROKE,
_("Set marker color"));
+ }
}
} else {
diff --git a/src/widgets/stroke-style.h b/src/widgets/stroke-style.h
index 2d7e187a1..cdd825c7d 100644
--- a/src/widgets/stroke-style.h
+++ b/src/widgets/stroke-style.h
@@ -149,7 +149,7 @@ private:
};
void updateLine();
- void updateAllMarkers(std::vector<SPItem*> const &objects);
+ void updateAllMarkers(std::vector<SPItem*> const &objects, bool skip_undo = false);
void updateMarkerHist(SPMarkerLoc const which);
void setDashSelectorFromStyle(SPDashSelector *dsel, SPStyle *style);
void setJoinType (unsigned const jointype);
diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp
index 788ac4eb3..ba79517d2 100644
--- a/src/widgets/text-toolbar.cpp
+++ b/src/widgets/text-toolbar.cpp
@@ -117,6 +117,8 @@ static void sp_print_fontstyle( SPStyle *query ) {
}
#endif
+static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/, GObject *tbl, bool subselection = false);
+
// Font family
static void sp_text_fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, GObject *tbl )
{
@@ -225,8 +227,35 @@ static void sp_text_fontsize_value_changed( Ink_ComboBoxEntry_Action *act, GObje
sp_repr_css_set_property (css, "font-size", osfs.str().c_str());
// Apply font size to selected objects.
+ // Calling sp_desktop_set_style will result in a call to TextTool::_styleSet() which
+ // will set the style on selected text inside the <text> element. If we want to set
+ // the style on the outer <text> objects we need to bypass this call.
+ bool outer = prefs->getInt("/tools/text/outer_style", false);
SPDesktop *desktop = SP_ACTIVE_DESKTOP;
- sp_desktop_set_style (desktop, css, true, true);
+ if (outer) {
+ Inkscape::Selection *selection = desktop->getSelection();
+ auto itemlist= selection->items();
+ for(auto i=itemlist.begin();i!=itemlist.end(); ++i){
+ if (dynamic_cast<SPText *>(*i) || dynamic_cast<SPFlowtext *>(*i)) {
+ SPItem *item = *i;
+
+ // Scale by inverse of accumulated parent transform
+ SPCSSAttr *css_set = sp_repr_css_attr_new();
+ sp_repr_css_merge(css_set, css);
+ Geom::Affine const local(item->i2doc_affine());
+ double const ex(local.descrim());
+ if ( (ex != 0.0) && (ex != 1.0) ) {
+ sp_css_attr_scale(css_set, 1/ex);
+ }
+
+ item->changeCSS(css_set,"style");
+
+ sp_repr_css_attr_unref(css_set);
+ }
+ }
+ } else {
+ sp_desktop_set_style (desktop, css, true, true);
+ }
// If no selected objects, set default.
SPStyle query(SP_ACTIVE_DOCUMENT);
@@ -281,6 +310,40 @@ static void sp_text_fontstyle_value_changed( Ink_ComboBoxEntry_Action *act, GObj
g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
}
+// Changes selection to only text outer elements.
+static void sp_text_outer_style_changed( InkToggleAction*act, GObject *tbl )
+{
+ bool outer = gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(act) );
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setInt("/tools/text/outer_style", outer);
+
+ // Update widgets to reflect new state of Text Outer Style button.
+ sp_text_toolbox_selection_changed( NULL, tbl );
+}
+
+// Unset line height on selection's inner text objects (tspan, etc.).
+static void sp_text_lineheight_unset_changed( InkToggleAction*act, GObject *tbl )
+{
+ // quit if run by the _changed callbacks
+ if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
+ return;
+ }
+ g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
+
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_unset_property(css, "line-height");
+
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ sp_desktop_set_style (desktop, css);
+
+ sp_repr_css_attr_unref(css);
+
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_TEXT,
+ _("Text: Unset line height."));
+
+ g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
+}
+
// Handles both Superscripts and Subscripts
static void sp_text_script_changed( InkToggleAction* act, GObject *tbl )
{
@@ -508,7 +571,7 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl )
static bool is_relative( Unit const *unit ) {
return (unit->abbr == "" || unit->abbr == "em" || unit->abbr == "ex" || unit->abbr == "%");
}
-
+
static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl )
{
// quit if run by the _changed callbacks
@@ -549,9 +612,34 @@ static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl )
sp_repr_css_set_property (css, "line-height", osfs.str().c_str());
- // Apply line-height to selected objects.
+ // Apply line-height to selected objects. See comment in font size function.
+ bool outer = prefs->getInt("/tools/text/outer_style", false);
SPDesktop *desktop = SP_ACTIVE_DESKTOP;
- sp_desktop_set_style (desktop, css, true, false);
+ if (outer) {
+ Inkscape::Selection *selection = desktop->getSelection();
+ auto itemlist= selection->items();
+ for(auto i=itemlist.begin();i!=itemlist.end(); ++i){
+ if (dynamic_cast<SPText *>(*i) || dynamic_cast<SPFlowtext *>(*i)) {
+ SPItem *item = *i;
+
+ // Scale by inverse of accumulated parent transform
+ SPCSSAttr *css_set = sp_repr_css_attr_new();
+ sp_repr_css_merge(css_set, css);
+ Geom::Affine const local(item->i2doc_affine());
+ double const ex(local.descrim());
+ if ( (ex != 0.0) && (ex != 1.0) ) {
+ sp_css_attr_scale(css_set, 1/ex);
+ }
+
+ item->changeCSS(css_set,"style");
+
+ sp_repr_css_attr_unref(css_set);
+ }
+ }
+ } else {
+ sp_desktop_set_style (desktop, css, true, true);
+ }
+
// Only need to save for undo if a text item has been changed.
@@ -652,7 +740,7 @@ static void sp_text_lineheight_unit_changed( gpointer /* */, GObject *tbl )
double font_size = 0;
int count = 0;
for(auto i=itemlist.begin();i!=itemlist.end(); ++i){
- if (SP_IS_TEXT (*i)) {
+ if (SP_IS_TEXT (*i) || SP_IS_FLOWTEXT(*i)) {
double doc_scale = Geom::Affine((*i)->i2dt_affine()).descrim();
font_size += (*i)->style->font_size.computed * doc_scale;
++count;
@@ -681,7 +769,7 @@ static void sp_text_lineheight_unit_changed( gpointer /* */, GObject *tbl )
double font_size = 0;
int count = 0;
for(auto i=itemlist.begin();i!=itemlist.end(); ++i){
- if (SP_IS_TEXT (*i)) {
+ if (SP_IS_TEXT (*i) || SP_IS_FLOWTEXT (*i)) {
double doc_scale = Geom::Affine((*i)->i2dt_affine()).descrim();
font_size += (*i)->style->font_size.computed * doc_scale;
++count;
@@ -1073,7 +1161,7 @@ static void sp_text_set_sizes(GtkListStore* model_size, int unit)
* It is called whenever a text selection is changed, including stepping cursor
* through text, or setting focus to text.
*/
-static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/, GObject *tbl, bool subselection = false) // don't bother to update font list if subsel changed
+static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/, GObject *tbl, bool subselection) // don't bother to update font list if subsel changed
{
#ifdef DEBUG_TEXT
static int count = 0;
@@ -1082,12 +1170,11 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
std::cout << "&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&" << std::endl;
std::cout << "sp_text_toolbox_selection_changed: start " << count << std::endl;
- std::cout << " Selected items:" << std::endl;
- for (GSList const *items = SP_ACTIVE_DESKTOP->getSelection()->itemList();
- items != NULL;
- items = items->next)
- {
- const gchar* id = reinterpret_cast<SPItem *>(items->data)->getId();
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Inkscape::Selection *selection = desktop->getSelection();
+ auto itemlist0= selection->items();
+ for(auto i=itemlist0.begin();i!=itemlist0.end(); ++i) {
+ const gchar* id = (*i)->getId();
std::cout << " " << id << std::endl;
}
Glib::ustring selected_text = sp_text_get_selected_text((SP_ACTIVE_DESKTOP)->event_context);
@@ -1129,8 +1216,7 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
gboolean isFlow = false;
auto itemlist= SP_ACTIVE_DESKTOP->getSelection()->items();
for(auto i=itemlist.begin();i!=itemlist.end(); ++i){
- // const gchar* id = reinterpret_cast<SPItem *>(items->data)->getId();
- // std::cout << " " << id << std::endl;
+ // std::cout << " " << ((*i)->getId()?(*i)->getId():"null") << std::endl;
if( SP_IS_FLOWTEXT(*i)) {
isFlow = true;
// std::cout << " Found flowed text" << std::endl;
@@ -1148,10 +1234,26 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
SPStyle query(SP_ACTIVE_DOCUMENT);
int result_family = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTFAMILY);
int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTSTYLE);
- int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_BASELINES);
int result_wmode = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_WRITINGMODES);
+ // Calling sp_desktop_query_style will result in a call to TextTool::_styleQueried().
+ // This returns the style of the selected text inside the <text> element... which
+ // is often the style of one or more <tspan>s. If we want the style of the outer
+ // <text> objects then we need to bypass the call to TextTool::_styleQueried().
+ // The desktop selection never includes the elements inside the <text> element.
+ int result_numbers = 0;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ bool outer = prefs->getInt("/tools/text/outer_style", false);
+ if (outer) {
+ Inkscape::Selection *selection = desktop->getSelection();
+ std::vector<SPItem *> vec(selection->items().begin(), selection->items().end());
+ result_numbers = sp_desktop_query_style_from_list (vec, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
+ } else {
+ result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
+ }
+
/*
* If no text in selection (querying returned nothing), read the style from
* the /tools/text preferencess (default style for new texts). Return if
@@ -1326,7 +1428,13 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
}
// Save unit so we can do convertions between new/old units.
g_object_set_data( tbl, "lineheight_unit", GINT_TO_POINTER(line_height_unit));
-
+
+ // Enable and turn on only if selection includes an object with line height set.
+ InkToggleAction* lineHeightUnset =
+ INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextLineHeightUnsetAction"));
+ gtk_action_set_sensitive(GTK_ACTION(lineHeightUnset), query.line_height.set );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(lineHeightUnset), query.line_height.set );
+
// Word spacing
double wordSpacing;
if (query.word_spacing.normal) wordSpacing = 0.0;
@@ -1573,10 +1681,6 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje
gtk_css_provider_load_from_data(css_provider,
"#TextFontFamilyAction_combobox {\n"
" -GtkComboBox-appears-as-list: true;\n"
- "}\n"
- "combobox window.popup scrolledwindow treeview separator {\n"
- " -GtkWidget-wide-separators: true;\n"
- " -GtkWidget-separator-height: 6;\n"
"}\n",
-1, NULL);
@@ -1602,7 +1706,7 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje
_(tooltip.c_str()),
NULL,
GTK_TREE_MODEL(model_size),
- 4, // Width in characters
+ 8, // Width in characters
0, // Extra list width
NULL, // Cell layout
NULL, // Separator
@@ -2025,6 +2129,32 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje
g_object_set( G_OBJECT(eact), "iconId", "text_rotation", NULL );
}
+ /* Text line height unset */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "TextLineHeightUnsetAction", // Name
+ _("Unset line height"), // Label
+ _("If enabled, line height is set on part of selection. Click to unset."),
+ INKSCAPE_ICON("paint-unknown"),
+ secondarySize ); // Icon size
+ gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_lineheight_unset_changed), holder );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/line_height_unset", false) );
+ g_object_set_data( holder, "TextLineHeightUnsetAction", act );
+ }
+
+ /* Text outer style */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "TextOuterStyleAction", // Name
+ _("Show outer style"), // Label
+ _("Show style of outermost text element. The 'font-size' and 'line-height' values of the outermost text element determine the minimum line spacing in the block."),
+ INKSCAPE_ICON("text_outer_style"),
+ secondarySize ); // Icon size
+ gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_outer_style_changed), holder );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/outer_style", false) );
+ g_object_set_data( holder, "TextOuterStyleAction", act );
+ }
+
// Is this necessary to call? Shouldn't hurt.
sp_text_toolbox_selection_changed(desktop->getSelection(), holder);
diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp
index d3715cf4e..126eac9cd 100644
--- a/src/widgets/toolbox.cpp
+++ b/src/widgets/toolbox.cpp
@@ -362,8 +362,6 @@ static gchar const * ui_descr =
" <separator />"
" <toolitem action='MeasureScaleAction' />"
" <separator />"
- " <toolitem action='MeasureOffsetAction' />"
- " <separator />"
" <toolitem action='measure_units_label' />"
" <toolitem action='MeasureUnitsAction' />"
" <toolitem action='MeasureIgnore1stAndLast' />"
@@ -373,8 +371,9 @@ static gchar const * ui_descr =
" <toolitem action='MeasureReverse' />"
" <toolitem action='MeasureToPhantom' />"
" <toolitem action='MeasureToGuides' />"
- " <toolitem action='MeasureMarkDimension' />"
" <toolitem action='MeasureToItem' />"
+ " <toolitem action='MeasureMarkDimension' />"
+ " <toolitem action='MeasureOffsetAction' />"
" </toolbar>"
" <toolbar name='StarToolbar'>"
@@ -508,18 +507,19 @@ static gchar const * ui_descr =
" <toolbar name='TextToolbar'>"
" <toolitem action='TextFontFamilyAction' />"
- " <toolitem action='TextFontSizeAction' />"
" <toolitem action='TextFontStyleAction' />"
-// " <toolitem action='TextBoldAction' />"
-// " <toolitem action='TextItalicAction' />"
+ " <separator />"
+ " <toolitem action='TextOuterStyleAction' />"
+ " <toolitem action='TextFontSizeAction' />"
+ " <toolitem action='TextLineHeightAction' />"
+ " <toolitem action='TextLineHeightUnitsAction' />"
+ " <toolitem action='TextLineHeightUnsetAction' />"
" <separator />"
" <toolitem action='TextAlignAction' />"
" <separator />"
" <toolitem action='TextSuperscriptAction' />"
" <toolitem action='TextSubscriptAction' />"
" <separator />"
- " <toolitem action='TextLineHeightAction' />"
- " <toolitem action='TextLineHeightUnitsAction' />"
" <toolitem action='TextLetterSpacingAction' />"
" <toolitem action='TextWordSpacingAction' />"
" <toolitem action='TextDxAction' />"
@@ -574,7 +574,12 @@ static gchar const * ui_descr =
" <toolitem action='MeshPickColorsAction' />"
" <toolitem action='MeshFitInBoundingBoxAction' />"
" <separator />"
+ " <toolitem action='MeshShowHandlesAction' />"
+ " <toolitem action='MeshEditFillAction' />"
+ " <toolitem action='MeshEditStrokeAction' />"
+ " <separator />"
" <toolitem action='MeshWarningAction' />"
+ " <separator />"
" <toolitem action='MeshSmoothAction' />"
" </toolbar>"
@@ -655,7 +660,7 @@ Glib::RefPtr<VerbAction> VerbAction::create(Inkscape::Verb* verb, Inkscape::Verb
}
VerbAction::VerbAction(Inkscape::Verb* verb, Inkscape::Verb* verb2, Inkscape::UI::View::View *view) :
- Gtk::Action(Glib::ustring(verb->get_id()), Gtk::StockID(verb->get_image()), Glib::ustring(g_dpgettext2(NULL, "ContextVerb", verb->get_name())), Glib::ustring(_(verb->get_tip()))),
+ Gtk::Action(Glib::ustring(verb->get_id()), verb->get_image(), Glib::ustring(g_dpgettext2(NULL, "ContextVerb", verb->get_name())), Glib::ustring(_(verb->get_tip()))),
verb(verb),
verb2(verb2),
view(view),
@@ -670,7 +675,7 @@ VerbAction::~VerbAction()
Gtk::Widget* VerbAction::create_menu_item_vfunc()
{
// First call in to get the icon rendered if present in SVG
- Gtk::Widget *widget = sp_icon_get_icon( property_stock_id().get_value().get_string(), Inkscape::ICON_SIZE_MENU );
+ Gtk::Widget *widget = sp_icon_get_icon( get_icon_name(), Inkscape::ICON_SIZE_MENU );
delete widget;
widget = 0;