diff options
| author | Shlomi Fish <shlomif@shlomifish.org> | 2016-10-08 15:39:06 +0000 |
|---|---|---|
| committer | Shlomi Fish <shlomif@shlomifish.org> | 2016-10-08 15:39:06 +0000 |
| commit | 2a5534a166dff8bfe6b56c8a3b496e989280fbd1 (patch) | |
| tree | dbd8330a6b3dcfb201ee751dbf283a17a41a2dfa | |
| parent | Merged. (diff) | |
| parent | [Bug #770681] KEY MAPPING: Comma and period hijacked by scaling. (diff) | |
| download | inkscape-2a5534a166dff8bfe6b56c8a3b496e989280fbd1.tar.gz inkscape-2a5534a166dff8bfe6b56c8a3b496e989280fbd1.zip | |
Merged.
(bzr r15100.1.31)
68 files changed, 2622 insertions, 179 deletions
@@ -148,6 +148,7 @@ Abhishek Sharma Shivaken Michael Sloan John Smith +Sandra Snan Boštjan Špetič Aaron Spike Kaushik Sridharan diff --git a/CMakeLists.txt b/CMakeLists.txt index d928f2aac..300af32a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,6 +67,7 @@ option(WITH_LIBCDR "Compile with support of libcdr for CorelDRAW Diagrams" ON) option(WITH_LIBVISIO "Compile with support of libvisio for Microsoft Visio Diagrams" ON) option(WITH_LIBWPG "Compile with support of libwpg for WordPerfect Graphics" ON) option(WITH_NLS "Compile with Native Language Support (using gettext)" ON) +option(WITH_YAML "Compile with YAML support (enables xverbs)" ON) option(ENABLE_BINRELOC "Enable relocatable binaries" OFF) @@ -255,6 +256,7 @@ message("WITH_LIBWPG: ${WITH_LIBWPG}") message("WITH_NLS: ${WITH_NLS}") message("WITH_OPENMP: ${WITH_OPENMP}") message("WITH_PROFILING: ${WITH_PROFILING}") +message("WITH_YAML: ${WITH_YAML}") if(WIN32) message("") diff --git a/CMakeScripts/DefineDependsandFlags.cmake b/CMakeScripts/DefineDependsandFlags.cmake index e3bc9258e..ad2d51724 100644 --- a/CMakeScripts/DefineDependsandFlags.cmake +++ b/CMakeScripts/DefineDependsandFlags.cmake @@ -387,6 +387,17 @@ list(APPEND INKSCAPE_LIBS ${SIGC++_LDFLAGS}) list(APPEND INKSCAPE_CXX_FLAGS ${SIGC++_CFLAGS_OTHER}) +find_package(yaml) +if(YAML_FOUND) + set (WITH_YAML ON) + list(APPEND INKSCAPE_INCS_SYS ${YAML_INCLUDE_DIRS}) + list(APPEND INKSCAPE_LIBS ${YAML_LIBRARIES}) + add_definitions(-DWITH_YAML) +else(YAML_FOUND) + set(WITH_YAML OFF) + message(STATUS "Could not locate the yaml library headers: xverb feature will be disabled") +endif() + list(REMOVE_DUPLICATES INKSCAPE_CXX_FLAGS) foreach(flag ${INKSCAPE_CXX_FLAGS}) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${flag}" CACHE STRING "" FORCE) diff --git a/CMakeScripts/Modules/Findyaml.cmake b/CMakeScripts/Modules/Findyaml.cmake new file mode 100644 index 000000000..154f2ed43 --- /dev/null +++ b/CMakeScripts/Modules/Findyaml.cmake @@ -0,0 +1,49 @@ +# - Try to find the YAML library +# Once done this will define +# +# YAML_FOUND - system has yaml +# YAML_INCLUDE_DIR - the yaml include directory +# YAML_LIBRARIES - the libraries needed to use yaml + +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +if (YAML_INCLUDE_DIR AND YAML_LIBRARIES) + # in cache already + SET(YAML_FOUND TRUE) +else (YAML_INCLUDE_DIR AND YAML_LIBRARIES) + IF (NOT WIN32) + FIND_PACKAGE(PkgConfig) + IF (PKG_CONFIG_FOUND) + # use pkg-config to get the directories and then use these values + # in the FIND_PATH() and FIND_LIBRARY() calls + pkg_check_modules(_YAML_PC QUIET yaml-1) + ENDIF (PKG_CONFIG_FOUND) + ENDIF (NOT WIN32) + + FIND_PATH(YAML_INCLUDE_DIR yaml.h + /usr/include + /usr/local/include + ) + + FIND_LIBRARY(YAML_LIBRARIES NAMES yaml + PATHS) + + if (YAML_INCLUDE_DIR AND YAML_LIBRARIES) + set(YAML_FOUND TRUE) + endif (YAML_INCLUDE_DIR AND YAML_LIBRARIES) + + + if (YAML_FOUND) + if (NOT YAML_FIND_QUIETLY) + message(STATUS "Found YAML: ${YAML_LIBRARIES}") + endif (NOT YAML_FIND_QUIETLY) + else (YAML_FOUND) + if (YAML_FIND_REQUIRED) + message(FATAL_ERROR "Could NOT find YAML") + endif (YAML_FIND_REQUIRED) + endif (YAML_FOUND) + + MARK_AS_ADVANCED(YAML_INCLUDE_DIR YAML_LIBRARIES) + +endif (YAML_INCLUDE_DIR AND YAML_LIBRARIES) diff --git a/po/POTFILES.in b/po/POTFILES.in index 8824a72c8..f73e3a9d9 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -154,6 +154,7 @@ src/live_effects/lpe-powerstroke.cpp src/live_effects/lpe-rough-hatches.cpp src/live_effects/lpe-roughen.cpp src/live_effects/lpe-ruler.cpp +src/live_effects/lpe-measure-line.cpp src/live_effects/lpe-show_handles.cpp src/live_effects/lpe-simplify.cpp src/live_effects/lpe-sketch.cpp @@ -171,6 +172,7 @@ src/live_effects/parameter/point.cpp src/live_effects/parameter/powerstrokepointarray.cpp src/live_effects/parameter/random.cpp src/live_effects/parameter/text.cpp +src/live_effects/parameter/fontbutton.cpp src/live_effects/parameter/togglebutton.cpp src/live_effects/parameter/transformedpoint.cpp src/live_effects/parameter/unit.cpp diff --git a/share/keys/default.xml b/share/keys/default.xml index f16be0689..581716d12 100644 --- a/share/keys/default.xml +++ b/share/keys/default.xml @@ -405,6 +405,24 @@ override) the bindings in the main default.xml. <bind key="Page_Down" action="SelectionLower" display="true" /> <bind key="KP_Page_Down" action="SelectionLower" /> + + <bind key="comma" action="SelectionShrink" display="true" /> + <bind key="less" action="SelectionShrink" /> + + <bind key="comma" modifiers="Alt" action="SelectionShrinkScreen" /> + <bind key="less" modifiers="Alt" action="SelectionShrinkScreen" /> + + <bind key="comma" modifiers="Ctrl" action="SelectionShrinkHalve" /> + <bind key="less" modifiers="Ctrl" action="SelectionShrinkHalve" /> + + <bind key="period" action="SelectionGrow" display="true" /> + <bind key="greater" action="SelectionGrow" /> + + <bind key="period" modifiers="Alt" action="SelectionGrowScreen" /> + <bind key="greater" modifiers="Alt" action="SelectionGrowScreen" /> + + <bind key="period" modifiers="Ctrl" action="SelectionGrowDouble" /> + <bind key="greater" modifiers="Ctrl" action="SelectionGrowDouble" /> <bind key="g" modifiers="Ctrl" action="SelectionGroup" display="true" /> <bind key="G" modifiers="Ctrl" action="SelectionGroup" /> diff --git a/share/keys/inkscape.xml b/share/keys/inkscape.xml index 07192cb37..581716d12 100644 --- a/share/keys/inkscape.xml +++ b/share/keys/inkscape.xml @@ -297,8 +297,7 @@ override) the bindings in the main default.xml. <bind key="z" modifiers="Ctrl" action="EditUndo" display="true" /> <bind key="Z" modifiers="Ctrl" action="EditUndo" /> - <bind key="y" modifiers="Ctrl,Shift" action="EditUndo" /> - <bind key="Y" modifiers="Ctrl,Shift" action="EditUndo" /> + <!--Do not put in Ctrl,Shift+Y, already used--> <bind key="z" modifiers="Ctrl,Shift" action="EditRedo" display="true" /> <bind key="Z" modifiers="Ctrl,Shift" action="EditRedo" /> @@ -384,6 +383,9 @@ override) the bindings in the main default.xml. <bind key="7" action="EditNextPathEffectParameter" display="true" /> + <bind key="r" modifiers="Ctrl,Shift" action="FitCanvasToSelectionOrDrawing" display="true" /> + <bind key="R" modifiers="Ctrl,Shift" action="FitCanvasToSelectionOrDrawing" display="true" /> + <!-- Objects/selection --> <bind key="h" action="ObjectFlipHorizontally" display="true" /> @@ -403,6 +405,24 @@ override) the bindings in the main default.xml. <bind key="Page_Down" action="SelectionLower" display="true" /> <bind key="KP_Page_Down" action="SelectionLower" /> + + <bind key="comma" action="SelectionShrink" display="true" /> + <bind key="less" action="SelectionShrink" /> + + <bind key="comma" modifiers="Alt" action="SelectionShrinkScreen" /> + <bind key="less" modifiers="Alt" action="SelectionShrinkScreen" /> + + <bind key="comma" modifiers="Ctrl" action="SelectionShrinkHalve" /> + <bind key="less" modifiers="Ctrl" action="SelectionShrinkHalve" /> + + <bind key="period" action="SelectionGrow" display="true" /> + <bind key="greater" action="SelectionGrow" /> + + <bind key="period" modifiers="Alt" action="SelectionGrowScreen" /> + <bind key="greater" modifiers="Alt" action="SelectionGrowScreen" /> + + <bind key="period" modifiers="Ctrl" action="SelectionGrowDouble" /> + <bind key="greater" modifiers="Ctrl" action="SelectionGrowDouble" /> <bind key="g" modifiers="Ctrl" action="SelectionGroup" display="true" /> <bind key="G" modifiers="Ctrl" action="SelectionGroup" /> diff --git a/share/keys/xara.xml b/share/keys/xara.xml index 25ebfcb48..92a84d33e 100644 --- a/share/keys/xara.xml +++ b/share/keys/xara.xml @@ -263,13 +263,13 @@ Hom/end keys-select minimum or maximum feather values <bind key="Z" modifiers="Ctrl" action="EditUndo" display="true"/> <bind key="y" modifiers="Ctrl,Shift" action="EditUndo" /> <bind key="Y" modifiers="Ctrl,Shift" action="EditUndo" /> - <bind key="less" modifiers="Ctrl" action="EditUndo" /> <!-- FIXME: stolen by scaling, redirect that through a verb --> - <bind key="comma" modifiers="Ctrl" action="EditUndo" /> <!-- FIXME: stolen by scaling, redirect that through a verb --> + <bind key="less" modifiers="Ctrl" action="EditUndo" /> + <bind key="comma" modifiers="Ctrl" action="EditUndo" /> <bind key="y" modifiers="Ctrl" action="EditRedo" display="true"/> <bind key="Y" modifiers="Ctrl" action="EditRedo" /> - <bind key="greater" modifiers="Ctrl" action="EditRedo" /> <!-- FIXME: stolen by scaling, redirect that through a verb --> - <bind key="period" modifiers="Ctrl" action="EditRedo" /> <!-- FIXME: stolen by scaling, redirect that through a verb --> + <bind key="greater" modifiers="Ctrl" action="EditRedo" /> + <bind key="period" modifiers="Ctrl" action="EditRedo" /> <bind key="x" modifiers="Ctrl" action="EditCut" display="true"/> <bind key="X" modifiers="Ctrl" action="EditCut" /> diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3c4f28aa8..6a2af6b4b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -221,6 +221,7 @@ set(inkscape_SRC line-geometry.cpp line-snapper.cpp main-cmdlineact.cpp + main-cmdlinexact.cpp media.cpp message-context.cpp message-stack.cpp @@ -337,6 +338,7 @@ set(inkscape_SRC line-snapper.h macros.h main-cmdlineact.h + main-cmdlinexact.h media.h menus-skeleton.h message-context.h diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp index 061fadbaa..cf5cda180 100644 --- a/src/gradient-chemistry.cpp +++ b/src/gradient-chemistry.cpp @@ -434,6 +434,11 @@ SPGradient *sp_gradient_convert_to_userspace(SPGradient *gr, SPItem *item, gchar return gr; } + // FIXME Transforming a mesh gradient is more complicated... probably need to add function to SPMeshArray.wq + if ( gr && SP_IS_MESHGRADIENT( gr ) ) { + return gr; + } + // First, fork it if it is shared gr = sp_gradient_fork_private_if_necessary(gr, gr->getVector(), SP_IS_RADIALGRADIENT(gr) ? SP_GRADIENT_TYPE_RADIAL : SP_GRADIENT_TYPE_LINEAR, item); diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt index 9a2f06a76..784317090 100644 --- a/src/live_effects/CMakeLists.txt +++ b/src/live_effects/CMakeLists.txt @@ -27,6 +27,7 @@ set(live_effects_SRC lpe-lattice.cpp lpe-lattice2.cpp lpe-line_segment.cpp + lpe-measure-line.cpp lpe-mirror_symmetry.cpp lpe-offset.cpp lpe-parallel.cpp @@ -68,6 +69,7 @@ set(live_effects_SRC parameter/powerstrokepointarray.cpp parameter/random.cpp parameter/text.cpp + parameter/fontbutton.cpp parameter/togglebutton.cpp parameter/transformedpoint.cpp parameter/unit.cpp @@ -105,6 +107,7 @@ set(live_effects_SRC lpe-lattice.h lpe-lattice2.h lpe-line_segment.h + lpe-measure-line.h lpe-mirror_symmetry.h lpe-offset.h lpe-parallel.h @@ -148,6 +151,7 @@ set(live_effects_SRC parameter/powerstrokepointarray.h parameter/random.h parameter/text.h + parameter/fontbutton.h parameter/togglebutton.h parameter/transformedpoint.h parameter/unit.h diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h index eea26184c..3682aa1bd 100644 --- a/src/live_effects/effect-enum.h +++ b/src/live_effects/effect-enum.h @@ -36,6 +36,7 @@ enum EffectType { CONSTRUCT_GRID, PERP_BISECTOR, TANGENT_TO_CURVE, + MEASURE_LINE, MIRROR_SYMMETRY, CIRCLE_3PTS, TRANSFORM_2PTS, diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 007a8ca38..792bb5d7a 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -39,6 +39,7 @@ #include "live_effects/lpe-lattice2.h" #include "live_effects/lpe-lattice.h" #include "live_effects/lpe-line_segment.h" +#include "live_effects/lpe-measure-line.h" #include "live_effects/lpe-mirror_symmetry.h" #include "live_effects/lpe-offset.h" #include "live_effects/lpe-parallel.h" @@ -135,6 +136,8 @@ const Util::EnumData<EffectType> LPETypeData[] = { {FILL_BETWEEN_MANY, N_("Fill between many"), "fill_between_many"}, {ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"}, {BOUNDING_BOX, N_("Bounding Box"), "bounding_box"}, +/* 9.93 */ + {MEASURE_LINE, N_("Measure Line"), "measure-line"}, }; const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData)); @@ -303,6 +306,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj) case TRANSFORM_2PTS: neweffect = static_cast<Effect*> ( new LPETransform2Pts(lpeobj) ); break; + case MEASURE_LINE: + neweffect = static_cast<Effect*> ( new LPEMeasureLine(lpeobj) ); + break; default: g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr); neweffect = NULL; @@ -348,6 +354,7 @@ Effect::Effect(LivePathEffectObject *lpeobject) concatenate_before_pwd2(false), sp_lpe_item(NULL), current_zoom(1), + upd_params(true), sp_curve(NULL), provides_own_flash_paths(true), // is automatically set to false if providesOwnFlashPaths() is not overridden is_ready(false) // is automatically set to false if providesOwnFlashPaths() is not overridden @@ -431,7 +438,9 @@ void Effect::doAfterEffect (SPLPEItem const* /*lpeitem*/) void Effect::doOnRemove (SPLPEItem const* /*lpeitem*/) { } - +void Effect::doOnVisibilityToggled(SPLPEItem const* /*lpeitem*/) +{ +} //secret impl methods (shhhh!) void Effect::doOnApply_impl(SPLPEItem const* lpeitem) { @@ -690,7 +699,7 @@ Effect::newWidget() ++it; } - + upd_params = false; return dynamic_cast<Gtk::Widget *>(vbox); } diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h index 840f723fa..5ca53486c 100644 --- a/src/live_effects/effect.h +++ b/src/live_effects/effect.h @@ -66,7 +66,7 @@ public: virtual void doAfterEffect (SPLPEItem const* lpeitem); virtual void doOnRemove (SPLPEItem const* lpeitem); - + virtual void doOnVisibilityToggled(SPLPEItem const* lpeitem); void writeParamsToSVG(); virtual void acceptParamPath (SPPath const* param_path); @@ -123,6 +123,7 @@ public: void editNextParamOncanvas(SPItem * item, SPDesktop * desktop); bool apply_to_clippath_and_mask; + bool upd_params; protected: Effect(LivePathEffectObject *lpeobject); diff --git a/src/live_effects/lpe-ellipse_5pts.cpp b/src/live_effects/lpe-ellipse_5pts.cpp index 8f0f8e18a..0371fc313 100644 --- a/src/live_effects/lpe-ellipse_5pts.cpp +++ b/src/live_effects/lpe-ellipse_5pts.cpp @@ -170,7 +170,7 @@ LPEEllipse5Pts::doEffect_path (Geom::PathVector const & path_in) // figure out if we have a slice, guarding against rounding errors - Path p(Geom::Point(cos(0), sin(0))); + Geom::Path p(Geom::Point(cos(0), sin(0))); double end = 2 * M_PI; for (s = 0; s < end; s += M_PI_2) { diff --git a/src/live_effects/lpe-extrude.cpp b/src/live_effects/lpe-extrude.cpp index 22cdf3c3e..d22007f76 100644 --- a/src/live_effects/lpe-extrude.cpp +++ b/src/live_effects/lpe-extrude.cpp @@ -61,7 +61,7 @@ LPEExtrude::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2 using namespace Geom; // generate connecting lines (the 'sides' of the extrusion) - Path path(Point(0.,0.)); + Geom::Path path(Point(0.,0.)); path.appendNew<Geom::LineSegment>( extrude_vector.getVector() ); Piecewise<D2<SBasis> > connector = path.toPwSb(); diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp index 221d03ebf..fbc32cf3e 100644 --- a/src/live_effects/lpe-knot.cpp +++ b/src/live_effects/lpe-knot.cpp @@ -94,7 +94,7 @@ findShadowedTime(Geom::Path const &patha, std::vector<Geom::Point> const &pt_and Affine mat = from_basis( T, N, pt_and_dir[0] ); mat = mat.inverse(); - Path p = patha * mat; + Geom::Path p = patha * mat; std::vector<double> times; @@ -477,7 +477,7 @@ LPEKnot::doEffect_path (Geom::PathVector const &path_in) // std::cout<<"fusing first and last component\n"; ++beg_comp; --end_comp; - Path first = gpaths[i0].portion(dom.back()); + Geom::Path first = gpaths[i0].portion(dom.back()); //FIXME: stitching should not be necessary (?!?) first.setStitching(true); first.append(gpaths[i0].portion(dom.front())); diff --git a/src/live_effects/lpe-measure-line.cpp b/src/live_effects/lpe-measure-line.cpp new file mode 100644 index 000000000..e8ceb7e51 --- /dev/null +++ b/src/live_effects/lpe-measure-line.cpp @@ -0,0 +1,892 @@ +/* + * Author(s): + * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> + * Some code and ideas migrated from dimensioning.py by + * Johannes B. Rutzmoser, johannes.rutzmoser (at) googlemail (dot) com + * https://github.com/Rutzmoser/inkscape_dimensioning + * Copyright (C) 2014 Author(s) + + * Released under GNU GPL, read the file 'COPYING' for more information + */ +#include "live_effects/lpe-measure-line.h" +#include <pangomm/fontdescription.h> +#include "ui/dialog/livepatheffect-editor.h" +#include <libnrtype/font-lister.h> +#include "inkscape.h" +#include "xml/node.h" +#include "uri.h" +#include "uri-references.h" +#include "preferences.h" +#include "util/units.h" +#include "svg/svg-length.h" +#include "svg/svg-color.h" +#include "svg/svg.h" +#include "display/curve.h" +#include "2geom/affine.h" +#include "style.h" +#include "sp-root.h" +#include "sp-defs.h" +#include "sp-item.h" +#include "sp-shape.h" +#include "sp-path.h" +#include "desktop.h" +#include "document.h" +#include <iomanip> + +// TODO due to internal breakage in glibmm headers, this must be last: +#include <glibmm/i18n.h> + +using namespace Geom; +namespace Inkscape { +namespace LivePathEffect { + +static const Util::EnumData<OrientationMethod> OrientationMethodData[] = { + { OM_HORIZONTAL, N_("Horizontal"), "horizontal" }, + { OM_VERTICAL, N_("Vertical"), "vertical" }, + { OM_PARALLEL, N_("Parallel"), "parallel" } +}; +static const Util::EnumDataConverter<OrientationMethod> OMConverter(OrientationMethodData, OM_END); + +LPEMeasureLine::LPEMeasureLine(LivePathEffectObject *lpeobject) : + Effect(lpeobject), + unit(_("Unit*"), _("Unit"), "unit", &wr, this, "px"), + fontbutton(_("Font*"), _("Font Selector"), "fontbutton", &wr, this), + 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), + 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"), + 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), + 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), + hide_back(_("Hide if label over*"), _("Hide DIN line if label over"), "hide_back", &wr, this, true), + dimline_format(_("CSS DIN line*"), _("Override CSS to DIN line, return to save, empty to reset to DIM"), "dimline_format", &wr, this,""), + helperlines_format(_("CSS helpers*"), _("Override CSS to helper lines, return to save, empty to reset to DIM"), "helperlines_format", &wr, this,""), + anotation_format(_("CSS anotation*"), _("Override CSS to anotation text, return to save, empty to reset to DIM"), "anotation_format", &wr, this,""), + arrows_format(_("CSS arrows*"), _("Override CSS to arrows, return to save, empty to reset DIM"), "arrows_format", &wr, this,""), + expanded(false) +{ + registerParameter(&unit); + registerParameter(&fontbutton); + registerParameter(&orientation); + registerParameter(&curve_linked); + registerParameter(&precision); + registerParameter(&position); + registerParameter(&text_top_bottom); + registerParameter(&text_right_left); + registerParameter(&helpline_distance); + registerParameter(&helpline_overlap); + registerParameter(&scale); + registerParameter(&format); + registerParameter(&arrows_outside); + registerParameter(&flip_side); + registerParameter(&scale_insensitive); + registerParameter(&local_locale); + registerParameter(&line_group_05); + registerParameter(&rotate_anotation); + registerParameter(&hide_back); + registerParameter(&dimline_format); + registerParameter(&helperlines_format); + registerParameter(&anotation_format); + registerParameter(&arrows_format); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + Glib::ustring fontbutton_value = prefs->getString("/live_effects/measure-line/fontbutton"); + if(fontbutton_value.empty()){ + fontbutton_value = "Sans 10"; + } + fontbutton.param_update_default(fontbutton_value); + scale.param_update_default(prefs->getDouble("/live_effects/measure-line/scale", 1.0)); + precision.param_update_default(prefs->getInt("/live_effects/measure-line/precision", 2)); + position.param_update_default(prefs->getDouble("/live_effects/measure-line/position", 10.0)); + text_top_bottom.param_update_default(prefs->getDouble("/live_effects/measure-line/text_top_bottom", 5.0)); + helpline_distance.param_update_default(prefs->getDouble("/live_effects/measure-line/helpline_distance", 0.0)); + helpline_overlap.param_update_default(prefs->getDouble("/live_effects/measure-line/helpline_overlap", 0.0)); + Glib::ustring unit_value = prefs->getString("/live_effects/measure-line/unit"); + if(unit_value.empty()){ + unit_value = "px"; + } + unit.param_update_default(unit_value); + Glib::ustring format_value = prefs->getString("/live_effects/measure-line/format"); + if(format_value.empty()){ + format_value = "{measure}{unit}"; + } + format.param_update_default(format_value); + dimline_format.param_update_default(prefs->getString("/live_effects/measure-line/dimline_format")); + helperlines_format.param_update_default(prefs->getString("/live_effects/measure-line/helperlines_format")); + 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")); + 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")); + hide_back.param_update_default(prefs->getBool("/live_effects/measure-line/hide_back")); + format.param_hide_canvas_text(); + dimline_format.param_hide_canvas_text(); + helperlines_format.param_hide_canvas_text(); + anotation_format.param_hide_canvas_text(); + arrows_format.param_hide_canvas_text(); + precision.param_set_range(0, 100); + precision.param_set_increments(1, 1); + precision.param_set_digits(0); + precision.param_make_integer(true); + curve_linked.param_set_range(0, 999); + curve_linked.param_set_increments(1, 1); + curve_linked.param_set_digits(0); + curve_linked.param_make_integer(true); + precision.param_make_integer(true); + position.param_set_range(-999999.0, 999999.0); + position.param_set_increments(1, 1); + position.param_set_digits(2); + text_top_bottom.param_set_range(-999999.0, 999999.0); + text_top_bottom.param_set_increments(1, 1); + text_top_bottom.param_set_digits(2); + text_right_left.param_set_range(-999999.0, 999999.0); + text_right_left.param_set_increments(1, 1); + text_right_left.param_set_digits(2); + helpline_distance.param_set_range(-999999.0, 999999.0); + helpline_distance.param_set_increments(1, 1); + helpline_distance.param_set_digits(2); + helpline_overlap.param_set_range(-999999.0, 999999.0); + helpline_overlap.param_set_increments(1, 1); + helpline_overlap.param_set_digits(2); + erase = true; +} + +LPEMeasureLine::~LPEMeasureLine() {} + +void swap(Geom::Point &A, Geom::Point &B){ + Geom::Point tmp = A; + 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*/) +{ + 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); + } + } + 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); + } + } + } +} + +void +LPEMeasureLine::createArrowMarker(Glib::ustring mode) +{ + 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()); + } + } + } + } +} + +void +LPEMeasureLine::createTextLabel(Geom::Point pos, double length, Geom::Coord angle, bool remove) +{ + 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("")); + } 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()); + } + 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_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(); + } +} + +void +LPEMeasureLine::createLine(Geom::Point start,Geom::Point end, Glib::ustring id, bool main, bool overflow, bool remove, bool arrows) +{ + 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); + } + } +} + +void +LPEMeasureLine::doBeforeEffect (SPLPEItem const* lpeitem) +{ + SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem); + 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::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"); + } + if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) { + if (((Glib::ustring)format.param_getSVGValue()).empty()) { + format.param_setValue((Glib::ustring)"{measure}{unit}"); + this->upd_params = true; + } + 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); + } + 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]); + } + 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]); + } + 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; + } + } + 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; + } + //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); + 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; + } + 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)); + } + } 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)); + } + } + 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 ); + } + id = (Glib::ustring)"infoline-" + (Glib::ustring)this->getRepr()->attribute("id"); + createLine(hstart, hend, id, true, overflow, remove, true); + } + } +} + +void LPEMeasureLine::doOnRemove (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(); + } + } +} + +void LPEMeasureLine::toObjects() +{ + 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); + } + 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)); + } + } +} + +Gtk::Widget *LPEMeasureLine::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(); + 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); + 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 != "dimline_format" && + param->param_key != "helperlines_format" && + param->param_key != "arrows_format" && + param->param_key != "anotation_format") { + vbox->pack_start(*widg, true, true, 2); + } else { + vbox_expander->pack_start(*widg, true, true, 2); + } + if (tip) { + widg->set_tooltip_text(*tip); + } else { + widg->set_tooltip_text(""); + widg->set_has_tooltip(false); + } + } + } + + ++it; + } + 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); +} + +void +LPEMeasureLine::onExpanderChanged() +{ + expanded = expander->get_expanded(); + if(expanded) { + expander->set_label (Glib::ustring(_("Hide DIM CSS style override"))); + } else { + expander->set_label (Glib::ustring(_("Show DIM CSS style override"))); + } +} + +Geom::PathVector +LPEMeasureLine::doEffect_path(Geom::PathVector const &path_in) +{ + return path_in; +} + +void +LPEMeasureLine::saveDefault() +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + 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->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/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); + prefs->setBool("/live_effects/measure-line/hide_back", hide_back); +} + +}; //namespace LivePathEffect +}; /* namespace Inkscape */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offset:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-measure-line.h b/src/live_effects/lpe-measure-line.h new file mode 100644 index 000000000..2fab9dbb9 --- /dev/null +++ b/src/live_effects/lpe-measure-line.h @@ -0,0 +1,103 @@ +#ifndef INKSCAPE_LPE_MEASURE_LINE_H +#define INKSCAPE_LPE_MEASURE_LINE_H + +/* + * Author(s): + * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> + * + * Copyright (C) 2014 Author(s) + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include "live_effects/effect.h" +#include "live_effects/parameter/enum.h" +#include "live_effects/parameter/fontbutton.h" +#include "live_effects/parameter/text.h" +#include "live_effects/parameter/unit.h" +#include "live_effects/parameter/bool.h" +#include "live_effects/parameter/originalpath.h" +#include <libnrtype/font-lister.h> +#include <2geom/angle.h> +#include <2geom/ray.h> +#include <2geom/point.h> + +namespace Inkscape { +namespace LivePathEffect { + +enum OrientationMethod { + OM_HORIZONTAL, + OM_VERTICAL, + OM_PARALLEL, + OM_END +}; + +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 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 onExpanderChanged(); + void toObjects(); + void createArrowMarker(Glib::ustring mode); + void saveDefault(); + virtual Gtk::Widget *newWidget(); +private: + UnitParam unit; + FontButtonParam fontbutton; + EnumParam<OrientationMethod> orientation; + ScalarParam curve_linked; + ScalarParam precision; + ScalarParam position; + ScalarParam text_top_bottom; + ScalarParam text_right_left; + ScalarParam helpline_distance; + ScalarParam helpline_overlap; + ScalarParam scale; + TextParam format; + BoolParam arrows_outside; + BoolParam flip_side; + BoolParam scale_insensitive; + BoolParam local_locale; + BoolParam line_group_05; + BoolParam rotate_anotation; + BoolParam hide_back; + TextParam dimline_format; + TextParam helperlines_format; + TextParam anotation_format; + TextParam arrows_format; + Glib::ustring display_unit; + bool expanded; + Gtk::Expander * expander; + double doc_scale; + double fontsize; + double anotation_width; + double arrow_gap; + bool erase; +/* Geom::Affine affine_over;*/ + LPEMeasureLine(const LPEMeasureLine &); + LPEMeasureLine &operator=(const LPEMeasureLine &); + +}; + +} //namespace LivePathEffect +} //namespace Inkscape + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp index 0de668847..329a00756 100644 --- a/src/live_effects/lpe-powerstroke.cpp +++ b/src/live_effects/lpe-powerstroke.cpp @@ -609,11 +609,12 @@ LPEPowerStroke::doEffect_path (Geom::PathVector const & path_in) // find time values for which x lies outside path domain // and only take portion of x and y that lies within those time values std::vector< double > rtsmin = roots (x - pwd2_in.domain().min()); - std::vector< double > rtsmax = roots (x - pwd2_in.domain().max()); + std::vector< double > rtsmax = roots (x + pwd2_in.domain().max()); if ( !rtsmin.empty() && !rtsmax.empty() ) { x = portion(x, rtsmin.at(0), rtsmax.at(0)); y = portion(y, rtsmin.at(0), rtsmax.at(0)); } + LineJoinType jointype = static_cast<LineJoinType>(linejoin_type.get_value()); Piecewise<D2<SBasis> > pwd2_out = compose(pwd2_in,x) + y*compose(n,x); diff --git a/src/live_effects/lpe-transform_2pts.cpp b/src/live_effects/lpe-transform_2pts.cpp index 2b03a4bb2..78db622f2 100644 --- a/src/live_effects/lpe-transform_2pts.cpp +++ b/src/live_effects/lpe-transform_2pts.cpp @@ -87,7 +87,6 @@ LPETransform2Pts::doOnApply(SPLPEItem const* lpeitem) { using namespace Geom; original_bbox(lpeitem); - point_a = Point(boundingbox_X.min(), boundingbox_Y.middle()); point_b = Point(boundingbox_X.max(), boundingbox_Y.middle()); SPLPEItem * splpeitem = const_cast<SPLPEItem *>(lpeitem); diff --git a/src/live_effects/lpeobject.h b/src/live_effects/lpeobject.h index 2e62707e3..087223947 100644 --- a/src/live_effects/lpeobject.h +++ b/src/live_effects/lpeobject.h @@ -38,8 +38,14 @@ public: /* Note that the returned pointer can be NULL in a valid LivePathEffectObject contained in a valid list of lpeobjects in an lpeitem! * So one should always check whether the returned value is NULL or not */ - Inkscape::LivePathEffect::Effect * get_lpe() { return lpe; }; - Inkscape::LivePathEffect::Effect const * get_lpe() const { return lpe; }; + Inkscape::LivePathEffect::Effect * get_lpe() { + if(this) return lpe; + else return NULL; + } + Inkscape::LivePathEffect::Effect const * get_lpe() const { + if(this) return lpe; + else return NULL; + }; Inkscape::LivePathEffect::Effect *lpe; // this can be NULL in a valid LivePathEffectObject diff --git a/src/live_effects/parameter/bool.cpp b/src/live_effects/parameter/bool.cpp index 9ecadbdeb..af99ef362 100644 --- a/src/live_effects/parameter/bool.cpp +++ b/src/live_effects/parameter/bool.cpp @@ -36,6 +36,12 @@ BoolParam::param_set_default() param_setValue(defvalue); } +void +BoolParam::param_update_default(bool const default_value) +{ + defvalue = default_value; +} + bool BoolParam::param_readSVGValue(const gchar * strvalue) { diff --git a/src/live_effects/parameter/bool.h b/src/live_effects/parameter/bool.h index 403dd0b87..7ad8a9368 100644 --- a/src/live_effects/parameter/bool.h +++ b/src/live_effects/parameter/bool.h @@ -36,7 +36,7 @@ public: void param_setValue(bool newvalue); virtual void param_set_default(); - + void param_update_default(bool const default_value); bool get_value() const { return value; }; inline operator bool() const { return value; }; diff --git a/src/live_effects/parameter/enum.h b/src/live_effects/parameter/enum.h index 2340663c3..dbfc68623 100644 --- a/src/live_effects/parameter/enum.h +++ b/src/live_effects/parameter/enum.h @@ -27,12 +27,14 @@ public: const Util::EnumDataConverter<E>& c, Inkscape::UI::Widget::Registry* wr, Effect* effect, - E default_value) + E default_value, + bool sort = true) : Parameter(label, tip, key, wr, effect) { enumdataconv = &c; defvalue = default_value; value = defvalue; + sorted = sort; }; virtual ~EnumParam() { }; @@ -40,12 +42,11 @@ public: virtual Gtk::Widget * param_newWidget() { Inkscape::UI::Widget::RegisteredEnum<E> *regenum = Gtk::manage ( new Inkscape::UI::Widget::RegisteredEnum<E>( param_label, param_tooltip, - param_key, *enumdataconv, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) ); + param_key, *enumdataconv, *param_wr, param_effect->getRepr(), param_effect->getSPDoc(), sorted ) ); regenum->set_active_by_id(value); regenum->combobox()->setProgrammatically = false; regenum->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change enumeration parameter")); - return dynamic_cast<Gtk::Widget *> (regenum); }; @@ -86,6 +87,7 @@ private: E value; E defvalue; + bool sorted; const Util::EnumDataConverter<E> * enumdataconv; }; diff --git a/src/live_effects/parameter/fontbutton.cpp b/src/live_effects/parameter/fontbutton.cpp new file mode 100644 index 000000000..ff8ab76a0 --- /dev/null +++ b/src/live_effects/parameter/fontbutton.cpp @@ -0,0 +1,92 @@ +/* + * Authors: + * + * Released under GNU GPL, read the file 'COPYING' for more information + */ + + +#include "ui/widget/registered-widget.h" +#include "live_effects/parameter/fontbutton.h" +#include "live_effects/effect.h" +#include "ui/widget/font-button.h" +#include "svg/svg.h" +#include "svg/stringstream.h" +#include "verbs.h" + +#include <glibmm/i18n.h> + +namespace Inkscape { + +namespace LivePathEffect { + +FontButtonParam::FontButtonParam( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr, + Effect* effect, const Glib::ustring default_value ) + : Parameter(label, tip, key, wr, effect), + value(default_value), + defvalue(default_value) +{ +} + +void +FontButtonParam::param_set_default() +{ + param_setValue(defvalue); +} +void +FontButtonParam::param_update_default(const Glib::ustring default_value){ + defvalue = default_value; +} + +bool +FontButtonParam::param_readSVGValue(const gchar * strvalue) +{ + Inkscape::SVGOStringStream os; + os << strvalue; + param_setValue((Glib::ustring)os.str()); + return true; +} + +gchar * +FontButtonParam::param_getSVGValue() const +{ + return g_strdup(value.c_str()); +} + +Gtk::Widget * +FontButtonParam::param_newWidget() +{ + Inkscape::UI::Widget::RegisteredFontButton * fontbuttonwdg = Gtk::manage( + new Inkscape::UI::Widget::RegisteredFontButton( param_label, + param_tooltip, + param_key, + *param_wr, + param_effect->getRepr(), + param_effect->getSPDoc() ) ); + Glib::ustring fontspec = param_getSVGValue(); + fontbuttonwdg->setValue( fontspec); + fontbuttonwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change font button parameter")); + param_effect->upd_params = false; + return dynamic_cast<Gtk::Widget *> (fontbuttonwdg); +} + +void +FontButtonParam::param_setValue(const Glib::ustring newvalue) +{ + value = newvalue; +} + +} /* namespace LivePathEffect */ + +} /* namespace Inkscape */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/parameter/fontbutton.h b/src/live_effects/parameter/fontbutton.h new file mode 100644 index 000000000..387ad130b --- /dev/null +++ b/src/live_effects/parameter/fontbutton.h @@ -0,0 +1,62 @@ +#ifndef INKSCAPE_LIVEPATHEFFECT_PARAMETER_FONT_H +#define INKSCAPE_LIVEPATHEFFECT_PARAMETER_FONT_H + +/* + * Inkscape::LivePathEffectParameters + * + * Authors: + * 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 { + +namespace LivePathEffect { + +class FontButtonParam : public Parameter { +public: + FontButtonParam( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Inkscape::UI::Widget::Registry* wr, + Effect* effect, + const Glib::ustring default_value = ""); + virtual ~FontButtonParam() {} + + virtual Gtk::Widget * param_newWidget(); + virtual bool param_readSVGValue(const gchar * strvalue); + void param_update_default(const Glib::ustring defvalue); + virtual gchar * param_getSVGValue() const; + + void param_setValue(const Glib::ustring newvalue); + + virtual void param_set_default(); + + const Glib::ustring get_value() const { return defvalue; }; + +private: + FontButtonParam(const FontButtonParam&); + FontButtonParam& operator=(const FontButtonParam&); + Glib::ustring value; + Glib::ustring defvalue; + +}; + +} //namespace LivePathEffect + +} //namespace Inkscape + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp index d4e213948..befac4df1 100644 --- a/src/live_effects/parameter/parameter.cpp +++ b/src/live_effects/parameter/parameter.cpp @@ -4,11 +4,9 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "ui/widget/registered-widget.h" -#include <glibmm/i18n.h> -#include "live_effects/parameter/parameter.h" #include "live_effects/effect.h" +#include "live_effects/parameter/parameter.h" #include "svg/svg.h" #include "xml/repr.h" @@ -16,6 +14,8 @@ #include "verbs.h" +#include <glibmm/i18n.h> + #define noLPEREALPARAM_DEBUG namespace Inkscape { @@ -101,9 +101,16 @@ ScalarParam::param_set_default() param_set_value(defvalue); } +void +ScalarParam::param_update_default(gdouble default_value) +{ + defvalue = default_value; +} + void ScalarParam::param_set_value(gdouble val) { + param_effect->upd_params = true; value = val; if (integer) value = round(value); @@ -121,7 +128,7 @@ ScalarParam::param_set_range(gdouble min, gdouble max) // Once again, in gtk2, this is not a problem. But in gtk3, // widgets get allocated the amount of size they ask for, // leading to excessively long widgets. - + param_effect->upd_params = true; if (min >= -SCALARPARAM_G_MAXDOUBLE) { this->min = min; } else { @@ -130,15 +137,15 @@ ScalarParam::param_set_range(gdouble min, gdouble max) if (max <= SCALARPARAM_G_MAXDOUBLE) { this->max = max; } else { - this->max = SCALARPARAM_G_MAXDOUBLE; + this->max = SCALARPARAM_G_MAXDOUBLE; } - param_set_value(value); // reset value to see whether it is in ranges } void ScalarParam::param_make_integer(bool yes) { + param_effect->upd_params = true; integer = yes; digits = 0; inc_step = 1; @@ -169,6 +176,7 @@ ScalarParam::param_newWidget() if(!overwrite_widget){ rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter")); } + param_effect->upd_params = false; return dynamic_cast<Gtk::Widget *> (rsu); } else { return NULL; @@ -178,12 +186,14 @@ ScalarParam::param_newWidget() void ScalarParam::param_set_digits(unsigned digits) { + param_effect->upd_params = true; this->digits = digits; } void ScalarParam::param_set_increments(double step, double page) { + param_effect->upd_params = true; inc_step = step; inc_page = page; } diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h index 0ef28650a..3658bded8 100644 --- a/src/live_effects/parameter/parameter.h +++ b/src/live_effects/parameter/parameter.h @@ -12,6 +12,7 @@ #include <glibmm/ustring.h> #include <2geom/forward.h> #include <2geom/pathvector.h> +#include "ui/widget/registered-widget.h" // In gtk2, this wasn't an issue; we could toss around // G_MAXDOUBLE and not worry about size allocations. But @@ -110,12 +111,12 @@ public: virtual gchar * param_getSVGValue() const; virtual void param_set_default(); + void param_update_default(gdouble default_value); void param_set_value(gdouble val); void param_make_integer(bool yes = true); void param_set_range(gdouble min, gdouble max); 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; }; void param_overwrite_widget(bool overwrite_widget); diff --git a/src/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp index ca3471b29..3442fd851 100644 --- a/src/live_effects/parameter/point.cpp +++ b/src/live_effects/parameter/point.cpp @@ -4,7 +4,6 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ -#include "ui/widget/registered-widget.h" #include "live_effects/parameter/point.h" #include "live_effects/effect.h" #include "svg/svg.h" @@ -30,7 +29,8 @@ PointParam::PointParam( const Glib::ustring& label, const Glib::ustring& tip, : Parameter(label, tip, key, wr, effect), defvalue(default_value), liveupdate(live_update), - knoth(NULL) + knoth(NULL), + _pointwdg(NULL) { knot_shape = SP_KNOT_SHAPE_DIAMOND; knot_mode = SP_KNOT_MODE_XOR; @@ -62,9 +62,9 @@ PointParam::param_get_default() const{ } void -PointParam::param_update_default(Geom::Point newpoint) +PointParam::param_update_default(const Geom::Point default_point) { - defvalue = newpoint; + defvalue = default_point; } void @@ -81,6 +81,9 @@ PointParam::param_setValue(Geom::Point newpoint, bool write) if(knoth && liveupdate){ knoth->update_knots(); } + if (_pointwdg) { + _pointwdg->setValue( newpoint ); + } } bool @@ -116,7 +119,7 @@ PointParam::param_transform_multiply(Geom::Affine const& postmul, bool /*set*/) Gtk::Widget * PointParam::param_newWidget() { - Inkscape::UI::Widget::RegisteredTransformedPoint * pointwdg = Gtk::manage( + _pointwdg = Gtk::manage( new Inkscape::UI::Widget::RegisteredTransformedPoint( param_label, param_tooltip, param_key, @@ -126,15 +129,15 @@ PointParam::param_newWidget() // TODO: fix to get correct desktop (don't use SP_ACTIVE_DESKTOP) SPDesktop *desktop = SP_ACTIVE_DESKTOP; Geom::Affine transf = desktop->doc2dt(); - pointwdg->setTransform(transf); - pointwdg->setValue( *this ); - pointwdg->clearProgrammatically(); - pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change point parameter")); + _pointwdg->setTransform(transf); + _pointwdg->setValue( *this ); + _pointwdg->clearProgrammatically(); + _pointwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change point parameter")); Gtk::HBox * hbox = Gtk::manage( new Gtk::HBox() ); - static_cast<Gtk::HBox*>(hbox)->pack_start(*pointwdg, true, true); + static_cast<Gtk::HBox*>(hbox)->pack_start(*_pointwdg, true, true); static_cast<Gtk::HBox*>(hbox)->show_all_children(); - + param_effect->upd_params = false; return dynamic_cast<Gtk::Widget *> (hbox); } @@ -191,13 +194,13 @@ void PointParamKnotHolderEntity::knot_click(guint state) { if (state & GDK_CONTROL_MASK) { - if (state & GDK_MOD1_MASK) { - this->pparam->param_set_default(); - SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item); - if(splpeitem){ - sp_lpe_item_update_patheffect(splpeitem, false, false); - } + if (state & GDK_MOD1_MASK) { + this->pparam->param_set_default(); + SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item); + if(splpeitem){ + sp_lpe_item_update_patheffect(splpeitem, false, false); } + } } } diff --git a/src/live_effects/parameter/point.h b/src/live_effects/parameter/point.h index 4329e0bcd..62c6fb83d 100644 --- a/src/live_effects/parameter/point.h +++ b/src/live_effects/parameter/point.h @@ -11,7 +11,7 @@ #include <glib.h> #include <2geom/point.h> - +#include "ui/widget/registered-widget.h" #include "live_effects/parameter/parameter.h" #include "knot-holder-entity.h" @@ -43,7 +43,7 @@ public: void param_set_default(); Geom::Point param_get_default() const; void param_set_liveupdate(bool live_update); - void param_update_default(Geom::Point newpoint); + void param_update_default(const Geom::Point default_point); virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/); void set_oncanvas_looks(SPKnotShapeType shape, SPKnotModeType mode, guint32 color); @@ -62,6 +62,7 @@ private: SPKnotModeType knot_mode; guint32 knot_color; gchar *handle_tip; + Inkscape::UI::Widget::RegisteredTransformedPoint * _pointwdg; }; diff --git a/src/live_effects/parameter/text.cpp b/src/live_effects/parameter/text.cpp index 234a6174d..0650b7e66 100644 --- a/src/live_effects/parameter/text.cpp +++ b/src/live_effects/parameter/text.cpp @@ -31,12 +31,16 @@ TextParam::TextParam( const Glib::ustring& label, const Glib::ustring& tip, Effect* effect, const Glib::ustring default_value ) : Parameter(label, tip, key, wr, effect), value(default_value), - defvalue(default_value) + defvalue(default_value), + _hide_canvas_text(false) { - SPDesktop *desktop = SP_ACTIVE_DESKTOP; // FIXME: we shouldn't use this! - canvas_text = (SPCanvasText *) sp_canvastext_new(desktop->getTempGroup(), desktop, Geom::Point(0,0), ""); - sp_canvastext_set_text (canvas_text, default_value.c_str()); - sp_canvastext_set_coords (canvas_text, 0, 0); + if (SPDesktop *desktop = SP_ACTIVE_DESKTOP) { // FIXME: we shouldn't use this! + canvas_text = (SPCanvasText *) sp_canvastext_new(desktop->getTempGroup(), desktop, Geom::Point(0,0), ""); + sp_canvastext_set_text (canvas_text, default_value.c_str()); + sp_canvastext_set_coords (canvas_text, 0, 0); + } else { + _hide_canvas_text = true; + } } void @@ -46,9 +50,26 @@ TextParam::param_set_default() } void +TextParam::param_update_default(Glib::ustring default_value) +{ + defvalue = default_value; +} + +void +TextParam::param_hide_canvas_text() +{ + if (!_hide_canvas_text) { + sp_canvastext_set_text(canvas_text, " "); + _hide_canvas_text = true; + } +} + +void TextParam::setPos(Geom::Point pos) { - sp_canvastext_set_coords (canvas_text, pos); + if (!_hide_canvas_text) { + sp_canvastext_set_coords (canvas_text, pos); + } } void @@ -63,9 +84,10 @@ TextParam::setPosAndAnchor(const Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2, Point dir = unit_vector(derivative(pwd2_reparam).valueAt(t_reparam)); Point n = -rot90(dir); double angle = Geom::angle_between(dir, Point(1,0)); - - sp_canvastext_set_coords(canvas_text, pos + n * length); - sp_canvastext_set_anchor_manually(canvas_text, std::sin(angle), -std::cos(angle)); + if (!_hide_canvas_text) { + sp_canvastext_set_coords(canvas_text, pos + n * length); + sp_canvastext_set_anchor_manually(canvas_text, std::sin(angle), -std::cos(angle)); + } } void @@ -73,7 +95,9 @@ TextParam::setAnchor(double x_value, double y_value) { anchor_x = x_value; anchor_y = y_value; - sp_canvastext_set_anchor_manually (canvas_text, anchor_x, anchor_y); + if (!_hide_canvas_text) { + sp_canvastext_set_anchor_manually (canvas_text, anchor_x, anchor_y); + } } bool @@ -94,8 +118,7 @@ TextParam::param_newWidget() { Inkscape::UI::Widget::RegisteredText *rsu = Gtk::manage(new Inkscape::UI::Widget::RegisteredText( param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc())); - - rsu->setText(value.c_str()); + rsu->setText(value); rsu->setProgrammatically = false; rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change text parameter")); @@ -107,8 +130,9 @@ void TextParam::param_setValue(const Glib::ustring newvalue) { value = newvalue; - - sp_canvastext_set_text (canvas_text, newvalue.c_str()); + if (!_hide_canvas_text) { + sp_canvastext_set_text (canvas_text, newvalue.c_str()); + } } } /* namespace LivePathEffect */ diff --git a/src/live_effects/parameter/text.h b/src/live_effects/parameter/text.h index 62de70eec..553c84c0a 100644 --- a/src/live_effects/parameter/text.h +++ b/src/live_effects/parameter/text.h @@ -40,7 +40,9 @@ public: virtual gchar * param_getSVGValue() const; void param_setValue(const Glib::ustring newvalue); + void param_hide_canvas_text(); virtual void param_set_default(); + void param_update_default(Glib::ustring default_value); void setPos(Geom::Point pos); void setPosAndAnchor(const Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2, const double t, const double length, bool use_curvature = false); @@ -53,7 +55,7 @@ private: TextParam& operator=(const TextParam&); double anchor_x; double anchor_y; - + bool _hide_canvas_text; Glib::ustring value; Glib::ustring defvalue; diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp index 023bebc03..b3f6442bb 100644 --- a/src/live_effects/parameter/togglebutton.cpp +++ b/src/live_effects/parameter/togglebutton.cpp @@ -12,6 +12,7 @@ #include "live_effects/effect.h" #include "svg/svg.h" #include "svg/stringstream.h" +#include "selection.h" #include "widgets/icon.h" #include "inkscape.h" #include "verbs.h" @@ -104,13 +105,14 @@ ToggleButtonParam::param_newWidget() }else{ gtk_box_pack_start (GTK_BOX(box_button), label_button, false, false, 1); } + checkwdg->add(*Gtk::manage(Glib::wrap(box_button))); checkwdg->setActive(value); checkwdg->setProgrammatically = false; checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change togglebutton parameter")); _toggled_connection = checkwdg->signal_toggled().connect(sigc::mem_fun(*this, &ToggleButtonParam::toggled)); - + param_effect->upd_params = false; return checkwdg; } @@ -157,6 +159,12 @@ ToggleButtonParam::param_setValue(bool newvalue) void ToggleButtonParam::toggled() { + //Force redraw for update widgets + param_effect->upd_params = true; + if (SP_ACTIVE_DESKTOP) { + Inkscape::Selection *selection = SP_ACTIVE_DESKTOP->getSelection(); + selection->emitModified(); + } _signal_toggled.emit(); } diff --git a/src/live_effects/parameter/unit.cpp b/src/live_effects/parameter/unit.cpp index 0ee553e2c..b6ea99bfe 100644 --- a/src/live_effects/parameter/unit.cpp +++ b/src/live_effects/parameter/unit.cpp @@ -54,6 +54,12 @@ UnitParam::param_set_default() param_set_value(*defunit); } +void +UnitParam::param_update_default(const Glib::ustring default_unit) +{ + defunit = unit_table.getUnit(default_unit); +} + void UnitParam::param_set_value(Inkscape::Util::Unit const &val) { diff --git a/src/live_effects/parameter/unit.h b/src/live_effects/parameter/unit.h index 59a483018..ae58cf956 100644 --- a/src/live_effects/parameter/unit.h +++ b/src/live_effects/parameter/unit.h @@ -33,6 +33,7 @@ public: virtual gchar * param_getSVGValue() const; virtual void param_set_default(); void param_set_value(Inkscape::Util::Unit const &val); + void param_update_default(const Glib::ustring default_unit); const gchar *get_abbreviation() const; virtual Gtk::Widget * param_newWidget(); diff --git a/src/main-cmdlineact.cpp b/src/main-cmdlineact.cpp index a23c036a0..03bf4083c 100644 --- a/src/main-cmdlineact.cpp +++ b/src/main-cmdlineact.cpp @@ -14,6 +14,7 @@ #include <verbs.h> #include <inkscape.h> #include <document.h> +#include <file.h> #include <glibmm/i18n.h> @@ -23,8 +24,7 @@ namespace Inkscape { std::list <CmdLineAction *> CmdLineAction::_list; -CmdLineAction::CmdLineAction(bool isVerb, gchar const *arg) : _isVerb(isVerb), _arg(NULL) -{ +CmdLineAction::CmdLineAction (bool isVerb, gchar const * arg) : _isVerb(isVerb), _arg(NULL) { if (arg != NULL) { _arg = g_strdup(arg); } @@ -34,58 +34,68 @@ CmdLineAction::CmdLineAction(bool isVerb, gchar const *arg) : _isVerb(isVerb), _ return; } -CmdLineAction::~CmdLineAction() -{ +CmdLineAction::~CmdLineAction () { if (_arg != NULL) { g_free(_arg); } } +bool +CmdLineAction::isExtended() { + return false; +} + void -CmdLineAction::doIt(ActionContext const &context) +CmdLineAction::doItX (ActionContext const & context) { + (void)context; + printf("CmdLineAction::doItX() %s\n", _arg); +} + +void +CmdLineAction::doIt (ActionContext const & context) { //printf("Doing: %s\n", _arg); if (_isVerb) { - Inkscape::Verb *verb = Inkscape::Verb::getbyid(_arg); + if (isExtended()) { + doItX(context); + return; + } + + Inkscape::Verb * verb = Inkscape::Verb::getbyid(_arg); if (verb == NULL) { printf(_("Unable to find verb ID '%s' specified on the command line.\n"), _arg); return; } - SPAction *action = verb->get_action(context); + SPAction * action = verb->get_action(context); sp_action_perform(action, NULL); } else { - if (context.getDocument() == NULL || context.getSelection() == NULL) { - return; - } + if (context.getDocument() == NULL || context.getSelection() == NULL) { return; } - SPDocument *doc = context.getDocument(); - SPObject *obj = doc->getObjectById(_arg); + SPDocument * doc = context.getDocument(); + SPObject * obj = doc->getObjectById(_arg); if (obj == NULL) { printf(_("Unable to find node ID: '%s'\n"), _arg); return; } - Inkscape::Selection *selection = context.getSelection(); + Inkscape::Selection * selection = context.getSelection(); selection->add(obj); } return; } bool -CmdLineAction::doList(ActionContext const &context) -{ +CmdLineAction::doList (ActionContext const & context) { bool hasActions = !_list.empty(); - for (std::list<CmdLineAction *>::iterator i = _list.begin(); - i != _list.end(); ++i) { - CmdLineAction *entry = *i; + for (std::list<CmdLineAction *>::iterator i = _list.begin(); i != _list.end(); ++i) { + CmdLineAction * entry = *i; entry->doIt(context); } return hasActions; } bool -CmdLineAction::idle(void) -{ +CmdLineAction::idle (void) { std::list<SPDesktop *> desktops; INKSCAPE.get_all_desktops(desktops); @@ -93,8 +103,8 @@ CmdLineAction::idle(void) // should have had time to make more at this point. for (std::list<SPDesktop *>::iterator i = desktops.begin(); i != desktops.end(); ++i) { - SPDesktop *desktop = *i; - //Inkscape::UI::View::View * view = dynamic_cast<Inkscape::UI::View::View *>(desktop); + SPDesktop * desktop = *i; + //Inkscape::UI::View::View * view = dynamic_cast<Inkscape::UI::View::View *>(desktop); doList(ActionContext(desktop)); } return false; diff --git a/src/main-cmdlineact.h b/src/main-cmdlineact.h index 171313401..f50e70e5a 100644 --- a/src/main-cmdlineact.h +++ b/src/main-cmdlineact.h @@ -21,18 +21,23 @@ class ActionContext; class CmdLineAction { bool _isVerb; - char *_arg; - static std::list <CmdLineAction *> _list; + static bool _requestQuit; + +protected: + char * _arg; public: - CmdLineAction(bool isVerb, char const *arg); - virtual ~CmdLineAction(); + CmdLineAction (bool isVerb, char const * arg); + virtual ~CmdLineAction (); + virtual bool isExtended(); + virtual void doItX (ActionContext const & context); + + void doIt (ActionContext const & context); - void doIt(ActionContext const &context); /** Return true if any actions were performed */ - static bool doList(ActionContext const &context); - static bool idle(void); + static bool doList (ActionContext const & context); + static bool idle (void); }; } // Inkscape diff --git a/src/main-cmdlinexact.cpp b/src/main-cmdlinexact.cpp new file mode 100644 index 000000000..99f0c699b --- /dev/null +++ b/src/main-cmdlinexact.cpp @@ -0,0 +1,576 @@ +/* + * Authors: + * Dmitry Zhulanov <dmitry.zhulanov@gmail.com> + * + * Copyright (C) 2016 Authors + * + * Released under GNU GPL v2, read the file 'COPYING' for more information + * + * Format of xverbs.yaml + * using: $ inkscape -B xverbs.yaml + * + * verbose: yes # only "verbose: yes" enable logging + * run: + * # open document to process + * - xverb-id: XFileOpen, gfx_sources/loading_screen/sandclock_atlas.svg + * - xverb-id: XUndoLabel, fresh_document # set label for UndoToLabel xverb works + * # note: if something wrong with undo labels use verb EditUndo instead of XUndoLabel and UndoToLabel at all + * + * # select element to handle + * - xverb-id: XSelectElement, top_sand + * + * # verbs + * - verb-id: EditInvertInAllLayers + * - verb-id: EditDelete + * - verb-id: FitCanvasToDrawing + * + * # save element to separated svg document + * - xverb-id: XFileSaveAs, output/thegame/linux/data/gfx/loading_screen/top_sand.svg + * + * # also save png preview + * - xverb-id: XFileExportPNG, output/thegame/linux/data/gfx_preview/loading_screen/top_sand.png + * + * # return to the fresh_state of document + * - xverb-id: UndoToLabel, fresh_document + * + * # do any other handling + * + * # inkscape have a lot of useful verbs + * - verb-id: FileQuit + */ +#ifdef WITH_YAML +#include <ui/view/view.h> +#include <desktop.h> +#include <helper/action.h> +#include <helper/action-context.h> +#include <selection.h> +#include <verbs.h> +#include <inkscape.h> + +#include <document.h> + +#include <glibmm/i18n.h> + +#include "main-cmdlinexact.h" + +#include "yaml.h" + +#include "extension/system.h" +#include "file.h" +#include <glib.h> +#include "sp-root.h" +#include "document-undo.h" +#include "util/units.h" +#include "sp-namedview.h" +#include "resource-manager.h" +#include "ui/dialog/font-substitution.h" +#include "extension/db.h" +#include "preferences.h" +#include "helper/png-write.h" +#include <document-undo.h> +#include <ui/view/view-widget.h> +#include <ui/interface.h> +#include <verbs.h> + +#define DPI_BASE Inkscape::Util::Quantity::convert(1, "in", "px") + +namespace +{ +bool s_verbose = false; + +bool createDirForFilename( const std::string &filename ) +{ + size_t found = filename.find_last_of("/\\"); + std::string output_directory = filename.substr(0,found); + + if( output_directory == filename ) + return true; + + if (g_mkdir_with_parents(output_directory.c_str(), 0755)) { + printf("Can't create directory %s\n", output_directory.c_str()); + fflush(stdout); + + return false; + } + + return true; +} + +std::vector<std::string> vectorFromString(const std::string &csv) +{ + std::vector<std::string> result; + + std::string delimiters = ","; + + // Skip delimiters at beginning. + std::string::size_type lastPos = csv.find_first_not_of(delimiters, 0); + + // Find first non-delimiter. + std::string::size_type pos = csv.find_first_of(delimiters, lastPos); + + while (std::string::npos != pos || std::string::npos != lastPos) { + // Found a token, add it to the vector. + std::string token = csv.substr(lastPos, pos - lastPos); + token.erase(0, token.find_first_not_of(' ')); //prefixing spaces + token.erase(token.find_last_not_of(' ')+1); //surfixing spaces + result.push_back(token); + + // Skip delimiters. + lastPos = csv.find_first_not_of(delimiters, pos); + + // Find next non-delimiter. + pos = csv.find_first_of(delimiters, lastPos); + } + + return result; +} + +void xFileOpen( const Glib::ustring &uri ) +{ + if (s_verbose) { + printf("open %s\n", uri.c_str()); + fflush(stdout); + } + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (desktop) { + SPDocument *old_document = desktop->getDocument(); + desktop->setWaitingCursor(); + Inkscape::DocumentUndo::clearRedo(old_document); + } + + SPDocument *doc = NULL; + Inkscape::Extension::Extension *key = NULL; + try { + doc = Inkscape::Extension::open(key, uri.c_str()); + } catch (std::exception &e) { + doc = NULL; + std::string exeption_mgs = e.what(); + printf("Error: open %s:%s\n",uri.c_str(), exeption_mgs.c_str() ); + fflush(stdout); + } + + // Set viewBox if it doesn't exist + if (!doc->getRoot()->viewBox_set + && (doc->getRoot()->width.unit != SVGLength::PERCENT) + && (doc->getRoot()->height.unit != SVGLength::PERCENT)) { + doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDisplayUnit()), doc->getHeight().value(doc->getDisplayUnit()))); + } + + desktop->change_document(doc); + doc->emitResizedSignal(doc->getWidth().value("px"), doc->getHeight().value("px")); + if(desktop) + desktop->clearWaitingCursor(); + + doc->virgin = FALSE; + + // everyone who cares now has a reference, get rid of our`s + doc->doUnref(); + + // resize the window to match the document properties + sp_namedview_window_from_document(desktop); + sp_namedview_update_layers_from_document(desktop); + + if ( INKSCAPE.use_gui() ) { + // Perform a fixup pass for hrefs. + if ( Inkscape::ResourceManager::getManager().fixupBrokenLinks(doc) ) { + Glib::ustring msg = _("Broken links have been changed to point to existing files."); + desktop->showInfoDialog(msg); + } + + // Check for font substitutions + Inkscape::UI::Dialog::FontSubstitution::getInstance().checkFontSubstitutions(doc); + } +} + +void xFileSaveAs( Inkscape::ActionContext const & context, const Glib::ustring &uri ) +{ + SPDocument *doc = context.getDocument(); + if (s_verbose) { + printf("save as %s\n", uri.c_str()); + fflush(stdout); + } + + if( createDirForFilename( uri )) { + Inkscape::Extension::save( + Inkscape::Extension::db.get("org.inkscape.output.svg.inkscape"), + doc, uri.c_str(), false, false, true, Inkscape::Extension::FILE_SAVE_METHOD_SAVE_AS); + if (s_verbose) { + printf("save done: %s\n", uri.c_str() ); + fflush(stdout); + } + } + else { + printf("can't create dirs for filename %s\n", uri.c_str() ); + fflush(stdout); + } +} + +void xFileExportPNG( Inkscape::ActionContext const & context, const Glib::ustring &uri ) +{ + if (s_verbose) { + printf("export png %s\n", uri.c_str()); + fflush(stdout); + } + + SPDocument *doc = context.getDocument(); + + gdouble dpi = 200.0; + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + dpi = prefs->getDouble("/dialogs/export/defaultxdpi/value", DPI_BASE); + + gdouble width = doc->getWidth().value(doc->getDisplayUnit()); + gdouble height = doc->getHeight().value(doc->getDisplayUnit()); + + gdouble bmwidth = (width) * dpi / DPI_BASE; + gdouble bmheight = (height) * dpi / DPI_BASE; + + int png_width = (int)(0.5 + bmwidth); + int png_height = (int)(0.5 + bmheight); + + SPNamedView *nv = desktop->getNamedView(); + + ExportResult status = sp_export_png_file(doc, uri.c_str(), + Geom::Rect(Geom::Point(0,0), Geom::Point(width, height)), png_width, png_height, dpi, dpi, + nv->pagecolor, 0, 0, TRUE); +} + +void xSelectElement( Inkscape::ActionContext const & context, const Glib::ustring &uri ) +{ + if (context.getDocument() == NULL || context.getSelection() == NULL) { + return; + } + + if (s_verbose) { + printf("select element: %s\n", uri.c_str()); + fflush(stdout); + } + + SPDocument * doc = context.getDocument(); + SPObject * obj = doc->getObjectById(uri); + + if (obj == NULL) { + printf(_("Unable to find node ID: '%s'\n"), uri.c_str()); + fflush(stdout); + return; + } + + Inkscape::Selection * selection = context.getSelection(); + selection->add(obj); + + if (s_verbose) { + printf("select done %s\n", uri.c_str()); + fflush(stdout); + } +} + +} // end of unnamed namespace + +namespace Inkscape { + +CmdLineXAction::CmdLineXAction (gchar const * arg, xaction_args_values_map_t &values_map): + CmdLineAction(true, arg), _values_map(values_map) { + this->arg = (char *)arg; + return; +} + +bool +CmdLineXAction::isExtended() { + return true; +} + +void +CmdLineXAction::doItX (ActionContext const & context) { + (void)(context); + + if( arg == "XFileSaveAs") + xFileSaveAs( context, _values_map["filename"] ); + else if (arg == "XFileOpen") + xFileOpen( _values_map["filename"] ); + else if (arg == "XFileExportPNG") + xFileExportPNG( context, _values_map["png_filename"] ); + else if (arg == "XSelectElement") + xSelectElement( context, _values_map["element-id"] ); + else { + printf("unknown xverb: %s", arg.c_str()); + fflush(stdout); + } + + return; +} + +enum parser_state_t { HANDLING_ROOT, + HANDLING_VERBOSE, // options + HANDLING_RUN, HANDLING_RUN_LIST, HANDLING_RUN_LIST_ENTRY + }; // run entries + +struct verb_info_t +{ + bool xverb; + std::vector<std::string> args; +}; + +typedef std::list<verb_info_t> verbs_list_t; + +static verbs_list_t +parseVerbsYAMLFile(gchar const *yaml_filename) +{ + verbs_list_t verbs_list; + + FILE *fh = fopen(yaml_filename, "r"); + if(fh == NULL) { + printf("Failed to open file!\n"); + fflush(stdout); + return verbs_list; + } + + yaml_parser_t parser; + if(!yaml_parser_initialize(&parser)) { + printf("Failed to initialize parser!\n"); + fflush(stdout); + return verbs_list; + } + + /* Set input file */ + yaml_parser_set_input_file(&parser, fh); + + parser_state_t state = HANDLING_ROOT; + + bool handling_key = false; + bool handling_value = false; + + std::string key; + + // parse + yaml_token_t token; + do { + yaml_parser_scan(&parser, &token); + switch(token.type) + { + // avoid "warning: enumeration value", "-Wswitch" + case YAML_NO_TOKEN: + break; + case YAML_STREAM_START_TOKEN: + break; + case YAML_STREAM_END_TOKEN: + break; + case YAML_VERSION_DIRECTIVE_TOKEN: + break; + case YAML_TAG_DIRECTIVE_TOKEN: + break; + case YAML_DOCUMENT_START_TOKEN: + break; + case YAML_DOCUMENT_END_TOKEN: + break; + case YAML_FLOW_SEQUENCE_START_TOKEN: + break; + case YAML_FLOW_SEQUENCE_END_TOKEN: + break; + case YAML_FLOW_MAPPING_START_TOKEN: + break; + case YAML_FLOW_MAPPING_END_TOKEN: + break; + case YAML_FLOW_ENTRY_TOKEN: + break; + case YAML_ALIAS_TOKEN: + break; + case YAML_ANCHOR_TOKEN: + break; + case YAML_TAG_TOKEN: + break; + + /* Token types (read before actual token) */ + case YAML_KEY_TOKEN: + handling_key = true; + handling_value = false; + break; + case YAML_VALUE_TOKEN: + handling_key = false; + handling_value = true; + break; + + /* Block delimeters */ + case YAML_BLOCK_SEQUENCE_START_TOKEN: + if( state == HANDLING_ROOT ) { + if( key == "run" ) + state = HANDLING_RUN; + } + break; + case YAML_BLOCK_ENTRY_TOKEN: + if( state == HANDLING_RUN ) + state = HANDLING_RUN_LIST; + else if( state == HANDLING_RUN_LIST ) + state = HANDLING_RUN_LIST_ENTRY; + else if( state == HANDLING_VERBOSE ) + state = HANDLING_ROOT; + break; + case YAML_BLOCK_END_TOKEN: + if( state == HANDLING_RUN_LIST_ENTRY ) + state = HANDLING_RUN_LIST; + else if( state == HANDLING_RUN_LIST ) + state = HANDLING_RUN; + else if( state == HANDLING_VERBOSE ) + state = HANDLING_ROOT; + else if( state == HANDLING_RUN ) + state = HANDLING_ROOT; + break; + + /* Data */ + case YAML_BLOCK_MAPPING_START_TOKEN: + break; + case YAML_SCALAR_TOKEN: + if( handling_key ) + key = (char *)token.data.scalar.value; + else if ( handling_value ) { + if(state == HANDLING_RUN_LIST) { + if(key == "xverb-id") { + verb_info_t verb; + verb.xverb = true; + verb.args = vectorFromString((char *)token.data.scalar.value); + if ((verb.args.size() > 1) && Verb::getbyid((char *)token.data.scalar.value, false)) + verb.xverb = false; + verbs_list.push_back(verb); + } + else if(key == "verb-id") { + verb_info_t verb; + verb.xverb = false; + verb.args = vectorFromString((char *)token.data.scalar.value); + verbs_list.push_back(verb); + } + else { + printf("unknown verb type [%s]\n", key.c_str()); + fflush(stdout); + } + } + else if(state == HANDLING_ROOT) { + std::string value = (char *)token.data.scalar.value; + if( (key == "verbose") && (value == "yes") ) + s_verbose = true; + } + } + break; + } + } while(token.type != YAML_STREAM_END_TOKEN); + + /* Cleanup */ + yaml_token_delete(&token); + yaml_parser_delete(&parser); + fclose(fh); + + return verbs_list; +} + +void +CmdLineXAction::createActionsFromYAML( gchar const *yaml_filename ) +{ + verbs_list_t verbs_list = parseVerbsYAMLFile(yaml_filename); + + typedef std::map<std::string,int> undo_labels_map_t; + undo_labels_map_t undo_labels_map; + int undo_counter = 0; + + verbs_list_t::iterator iter = verbs_list.begin(); + for (; iter != verbs_list.end(); ++iter) { + verb_info_t &verb = *iter; + std::string &verb_word = verb.args[0]; + if (s_verbose) + printf("handle %s and args count is %d\n", verb_word.c_str(), (int)verb.args.size()); + + if (verb_word == "XFileOpen") { + if( verb.args.size() < 2 ) + { + printf("bad arguments for XFileOpen\n"); + continue; + } + + xaction_args_values_map_t values_map; + values_map["filename"] = verb.args[1]; + new CmdLineXAction(verb_word.c_str(), values_map); + } else if (verb_word == "XFileSaveAs") + { + if (verb.args.size() < 2) { + printf("bad arguments for XFileSaveAs\n"); + continue; + } + + xaction_args_values_map_t values_map; + values_map["filename"] = verb.args[1]; + new CmdLineXAction(verb_word.c_str(), values_map); + } else if (verb_word == "XUndoLabel") { + if (verb.args.size() < 2) { + printf("bad arguments for XUndoLabel\n"); + continue; + } + undo_labels_map[verb.args[1]] = undo_counter; + } else if (verb_word == "UndoToLabel") { + if (verb.args.size() < 2) { + printf("bad arguments for UndoToLabel\n"); + continue; + } + + undo_labels_map_t::iterator iter = undo_labels_map.find(verb.args[1]); + if(iter != undo_labels_map.end()) { + int counter = undo_counter - iter->second; + if( counter > 0 ) { + for(int i = 0; i < counter; ++i) + new CmdLineAction(true, "EditUndo"); + undo_counter -= counter; + } + } + } else if (verb_word == "XSelectElement") { + if (verb.args.size() < 2) { + printf("bad arguments for XSelectElement\n"); + continue; + } + ++undo_counter; + + xaction_args_values_map_t values_map; + values_map["element-id"] = verb.args[1]; + new CmdLineXAction(verb_word.c_str(), values_map); + } else if (verb_word == "XFileExportPNG") { + if (verb.args.size() < 2) { + printf("bad arguments for XFileExportPNG\n"); + continue; + } + + xaction_args_values_map_t values_map; + std::string &png_filename = verb.args[1]; + values_map["png_filename"] = png_filename; + if(createDirForFilename( png_filename )) + new CmdLineXAction(verb_word.c_str(), values_map); + } + else if(!verb.xverb) { + ++undo_counter; + new CmdLineAction(true, verb.args[0].c_str()); + } + else if( Verb::getbyid(verb.args[0].c_str()) != NULL ) + { + ++undo_counter; + new CmdLineAction(true, verb.args[0].c_str()); + } + else { + printf("Unhadled xverb %s\n", verb.args[0].c_str()); + fflush(stdout); + } + } + + fflush(stdout); +} + + +} // Inkscape + +#endif // WITH_YAML + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/main-cmdlinexact.h b/src/main-cmdlinexact.h new file mode 100644 index 000000000..8634f3875 --- /dev/null +++ b/src/main-cmdlinexact.h @@ -0,0 +1,54 @@ + +#ifndef __INK_MAIN_CMD_LINE_XACTIONS_H__ +#define __INK_MAIN_CMD_LINE_XACTIONS_H__ + +#ifdef WITH_YAML + +/** \file + * Extended actions that can be queued at the yaml file + */ + +/* + * Authors: + * Dmitry Zhulanov <dmitry.zhulanov@gmail.com> + * + * Copyright (C) 2016 Authors + * + * Released under GNU GPL v2.x, read the file 'COPYING' for more information + */ + +#include "main-cmdlineact.h" +#include <string> + +namespace Inkscape { + +typedef std::map<std::string, std::string > xaction_args_values_map_t; + +class CmdLineXAction : public CmdLineAction { + std::string arg; + xaction_args_values_map_t _values_map; +public: + CmdLineXAction (gchar const * arg, xaction_args_values_map_t &values_map); + + virtual void doItX (ActionContext const & context); + virtual bool isExtended(); + + static void createActionsFromYAML( gchar const *filename ); +}; + +} // Inkscape + + +#endif // WITH_YAML +#endif /* __INK_MAIN_CMD_LINE_XACTIONS_H__ */ + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : diff --git a/src/main.cpp b/src/main.cpp index 004d96191..0d5f35797 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -112,6 +112,7 @@ #endif #include "main-cmdlineact.h" +#include "main-cmdlinexact.h" #include "widgets/icon.h" #include <errno.h> @@ -127,6 +128,7 @@ enum { SP_ARG_NOGUI, SP_ARG_GUI, SP_ARG_FILE, + SP_ARG_XVERBS, SP_ARG_PRINT, SP_ARG_EXPORT_PNG, SP_ARG_EXPORT_DPI, @@ -227,6 +229,11 @@ static gchar *sp_export_png_utf8 = NULL; static gchar *sp_export_svg_utf8 = NULL; static gchar *sp_global_printer_utf8 = NULL; +#ifdef WITH_YAML +static gchar *sp_xverbs_yaml_utf8 = NULL; +static gchar *sp_xverbs_yaml = NULL; +#endif // WITH_YAML + /** * Reset variables to default values. @@ -300,7 +307,12 @@ struct poptOption options[] = { POPT_ARG_STRING, NULL, SP_ARG_FILE, N_("Open specified document(s) (option string may be excluded)"), N_("FILENAME")}, - +#ifdef WITH_YAML + {"xverbs", 0, + POPT_ARG_STRING, &sp_xverbs_yaml, SP_ARG_XVERBS, + N_("xverbs command"), + N_("XVERBS_FILENAME")}, +#endif // WITH_YAML {"print", 'p', POPT_ARG_STRING, &sp_global_printer, SP_ARG_PRINT, N_("Print document(s) to specified output file (use '| program' for pipe)"), @@ -881,6 +893,9 @@ static int sp_common_main( int argc, char const **argv, GSList **flDest ) fixupSingleFilename( &sp_export_png, &sp_export_png_utf8 ); fixupSingleFilename( &sp_export_svg, &sp_export_svg_utf8 ); fixupSingleFilename( &sp_global_printer, &sp_global_printer_utf8 ); +#ifdef WITH_YAML + fixupSingleFilename( &sp_xverbs_yaml, &sp_xverbs_yaml_utf8 ); +#endif // WITH_YAML } else { @@ -890,6 +905,10 @@ static int sp_common_main( int argc, char const **argv, GSList **flDest ) sp_export_svg_utf8 = g_strdup( sp_export_svg ); if ( sp_global_printer ) sp_global_printer_utf8 = g_strdup( sp_global_printer ); +#ifdef WITH_YAML + if ( sp_xverbs_yaml ) + sp_xverbs_yaml_utf8 = g_strdup( sp_xverbs_yaml ); +#endif // WITH_YAML } #ifdef WITH_DBUS @@ -2131,6 +2150,16 @@ sp_process_args(poptContext ctx) } break; } +#ifdef WITH_YAML + case SP_ARG_XVERBS: { + gchar const *fn = poptGetOptArg(ctx); + if (fn != NULL) { + sp_xverbs_yaml = g_strdup(fn); + Inkscape::CmdLineXAction::createActionsFromYAML((const char *)sp_xverbs_yaml); + } + break; + } +#endif // WITH_YAML case SP_ARG_VERSION: { printf("Inkscape %s (%s)\n", Inkscape::version_string, __DATE__); exit(0); diff --git a/src/selection.h b/src/selection.h index 4ea70c38d..cf00ba1f4 100644 --- a/src/selection.h +++ b/src/selection.h @@ -134,6 +134,7 @@ public: */ void setReprList(std::vector<XML::Node*> const &reprs); + using ObjectSet::includes; /** @@ -166,6 +167,7 @@ public: * * @return the resulting connection */ + void emitModified(){ _emitModified(this->_flags); }; sigc::connection connectChanged(sigc::slot<void, Selection *> const &slot) { return _changed_signal.connect(slot); } diff --git a/src/sp-item.cpp b/src/sp-item.cpp index d161562fd..f52784489 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -76,7 +76,6 @@ SPItem::SPItem() : SPObject() { transform_center_y = 0; freeze_stroke_width = false; - _is_evaluated = true; _evaluated_status = StatusUnknown; @@ -1409,7 +1408,6 @@ Geom::Affine SPItem::set_transform(Geom::Affine const &transform) { void SPItem::doWriteTransform(Inkscape::XML::Node *repr, Geom::Affine const &transform, Geom::Affine const *adv, bool compensate) { g_return_if_fail(repr != NULL); - // calculate the relative transform, if not given by the adv attribute Geom::Affine advertized_transform; if (adv != NULL) { diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index d39540cd9..c4247bd5a 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -73,6 +73,7 @@ void SPLPEItem::build(SPDocument *document, Inkscape::XML::Node *repr) { void SPLPEItem::release() { // disconnect all modified listeners: + for (std::list<sigc::connection>::iterator mod_it = this->lpe_modified_connection_list->begin(); mod_it != this->lpe_modified_connection_list->end(); ++mod_it) { @@ -83,7 +84,7 @@ void SPLPEItem::release() { this->lpe_modified_connection_list = NULL; PathEffectList::iterator it = this->path_effect_list->begin(); - + while ( it != this->path_effect_list->end() ) { // unlink and delete all references in the list (*it)->unlink(); @@ -121,8 +122,10 @@ void SPLPEItem::set(unsigned int key, gchar const* value) { while ( it != this->path_effect_list->end() ) { + LivePathEffectObject *lpeobj = (*it)->lpeobject; + lpeobj->get_lpe()->doOnRemove(this); (*it)->unlink(); - delete *it; + delete (*it); it = this->path_effect_list->erase(it); } diff --git a/src/sp-object.cpp b/src/sp-object.cpp index da4367d5b..cbd7aa969 100644 --- a/src/sp-object.cpp +++ b/src/sp-object.cpp @@ -485,13 +485,16 @@ void SPObject::_sendDeleteSignalRecursive() { void SPObject::deleteObject(bool propagate, bool propagate_descendants) { sp_object_ref(this, NULL); + if ( SP_IS_LPE_ITEM(this) ) { + SP_LPE_ITEM(this)->removeAllPathEffects(false); + } if (propagate) { _delete_signal.emit(this); } if (propagate_descendants) { this->_sendDeleteSignalRecursive(); } - + Inkscape::XML::Node *repr = getRepr(); if (repr && repr->parent()) { sp_repr_unparent(repr); diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt index 9e641edc3..f2a256698 100644 --- a/src/ui/CMakeLists.txt +++ b/src/ui/CMakeLists.txt @@ -128,6 +128,7 @@ set(ui_SRC widget/entity-entry.cpp widget/entry.cpp widget/filter-effect-chooser.cpp + widget/font-button.cpp widget/font-variants.cpp widget/frame.cpp widget/highlight-picker.cpp @@ -312,6 +313,7 @@ set(ui_SRC widget/entity-entry.h widget/entry.h widget/filter-effect-chooser.h + widget/font-button.h widget/font-variants.h widget/frame.h widget/highlight-picker.h diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp index a0cd786dc..f657e1b76 100644 --- a/src/ui/dialog/filter-effects-dialog.cpp +++ b/src/ui/dialog/filter-effects-dialog.cpp @@ -860,6 +860,17 @@ public: return dss; } + // SpinButton + SpinButtonAttr* add_spinbutton(double defalt_value, const SPAttributeEnum attr, const Glib::ustring& label, + const double lo, const double hi, const double step_inc, + const double climb, const int digits, char* tip = NULL) + { + SpinButtonAttr* sb = new SpinButtonAttr(lo, hi, step_inc, climb, digits, attr, defalt_value, tip); + add_widget(sb, label); + add_attr_widget(sb); + return sb; + } + // DualSpinButton DualSpinButton* add_dualspinbutton(char* defalt_value, const SPAttributeEnum attr, const Glib::ustring& label, const double lo, const double hi, const double step_inc, @@ -2785,8 +2796,14 @@ void FilterEffectsDialog::init_settings_widgets() _settings->type(NR_FILTER_IMAGE); _settings->add_fileorelement(SP_ATTR_XLINK_HREF, _("Source of Image:")); - + _image_x = _settings->add_entry(SP_ATTR_X,_("X"),_("X")); + _image_x->signal_attr_changed().connect(sigc::mem_fun(*this, &FilterEffectsDialog::image_x_changed)); + //This commented because we want the default empty value of X or Y and couldent get it from SpinButton + //_image_y = _settings->add_spinbutton(0, SP_ATTR_Y, _("Y:"), -DBL_MAX, DBL_MAX, 1, 1, 5, _("Y")); + _image_y = _settings->add_entry(SP_ATTR_Y,_("Y"),_("Y")); + _image_y->signal_attr_changed().connect(sigc::mem_fun(*this, &FilterEffectsDialog::image_y_changed)); _settings->type(NR_FILTER_OFFSET); + _settings->add_checkbutton(false, SP_ATTR_PRESERVEALPHA, _("Preserve Alpha"), "true", "false", _("If set, the alpha channel won't be altered by this filter primitive.")); _settings->add_spinscale(0, SP_ATTR_DX, _("Delta X:"), -100, 100, 1, 0.01, 1, _("This is how far the input image gets shifted to the right")); _settings->add_spinscale(0, SP_ATTR_DY, _("Delta Y:"), -100, 100, 1, 0.01, 1, _("This is how far the input image gets shifted downwards")); @@ -2926,6 +2943,33 @@ void FilterEffectsDialog::convolve_order_changed() _convolve_target->get_spinbuttons()[1]->get_adjustment()->set_upper(_convolve_order->get_spinbutton2().get_value() - 1); } +bool number_or_empy(const Glib::ustring& text) { + if (text.empty()) { + return true; + } + double n = atof( text.c_str() ); + if (n == 0.0 && strcmp(text.c_str(), "0") != 0 && strcmp(text.c_str(), "0.0") != 0) { + return false; + } + else { + return true; + } +} + +void FilterEffectsDialog::image_x_changed() +{ + if (number_or_empy(_image_x->get_text())) { + _image_x->set_from_attribute(_primitive_list.get_selected()); + } +} + +void FilterEffectsDialog::image_y_changed() +{ + if (number_or_empy(_image_y->get_text())) { + _image_y->set_from_attribute(_primitive_list.get_selected()); + } +} + void FilterEffectsDialog::set_attr_direct(const AttrWidget* input) { set_attr(_primitive_list.get_selected(), input->get_attribute(), input->get_as_attribute().c_str()); diff --git a/src/ui/dialog/filter-effects-dialog.h b/src/ui/dialog/filter-effects-dialog.h index eae0fc317..32fabb741 100644 --- a/src/ui/dialog/filter-effects-dialog.h +++ b/src/ui/dialog/filter-effects-dialog.h @@ -35,6 +35,8 @@ namespace Inkscape { namespace UI { namespace Dialog { +class EntryAttr; +//class SpinButtonAttr; class DualSpinButton; class MultiSpinButton; class FilterEffectsDialog : public UI::Widget::Panel { @@ -258,6 +260,8 @@ private: void remove_primitive(); void duplicate_primitive(); void convolve_order_changed(); + void image_x_changed(); + void image_y_changed(); void set_attr_direct(const UI::Widget::AttrWidget*); void set_child_attr_direct(const UI::Widget::AttrWidget*); @@ -308,6 +312,10 @@ private: DualSpinButton* _convolve_order; MultiSpinButton* _convolve_target; + // Image + EntryAttr* _image_x; + EntryAttr* _image_y; + // For controlling setting sensitivity Gtk::Widget* _k1, *_k2, *_k3, *_k4; diff --git a/src/ui/dialog/livepatheffect-editor.cpp b/src/ui/dialog/livepatheffect-editor.cpp index 459d8d4ee..73f8debd6 100644 --- a/src/ui/dialog/livepatheffect-editor.cpp +++ b/src/ui/dialog/livepatheffect-editor.cpp @@ -52,7 +52,7 @@ void lpeeditor_selection_changed (Inkscape::Selection * selection, gpointer data { LivePathEffectEditor *lpeeditor = static_cast<LivePathEffectEditor *>(data); lpeeditor->lpe_list_locked = false; - lpeeditor->onSelectionChanged(selection); + lpeeditor->onSelectionChanged(selection, true); } static void lpeeditor_selection_modified (Inkscape::Selection * selection, guint /*flags*/, gpointer data) @@ -89,7 +89,8 @@ LivePathEffectEditor::LivePathEffectEditor() button_up(), button_down(), current_desktop(NULL), - current_lpeitem(NULL) + current_lpeitem(NULL), + current_lperef(NULL) { Gtk::Box *contents = _getContents(); contents->set_spacing(4); @@ -190,6 +191,10 @@ LivePathEffectEditor::~LivePathEffectEditor() void LivePathEffectEditor::showParams(LivePathEffect::Effect& effect) { + if ( ! effect.upd_params ) { + return; + } + if (effectwidget) { effectcontrol_vbox.remove(*effectwidget); delete effectwidget; @@ -249,9 +254,8 @@ LivePathEffectEditor::set_sensitize_all(bool sensitive) button_down.set_sensitive(sensitive); } - void -LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel) +LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel, bool upd_params) { if (lpe_list_locked) { // this was triggered by selecting a row in the list, so skip reloading @@ -275,6 +279,9 @@ LivePathEffectEditor::onSelectionChanged(Inkscape::Selection *sel) if ( lpeitem->hasPathEffect() ) { Inkscape::LivePathEffect::Effect *lpe = lpeitem->getCurrentLPE(); if (lpe) { + if (upd_params) { + lpe->upd_params = true; + } showParams(*lpe); lpe_list_locked = true; selectInList(lpe); @@ -478,6 +485,12 @@ LivePathEffectEditor::onRemove() SPItem *item = sel->singleItem(); SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item); if ( lpeitem ) { + if (current_lperef && current_lperef->lpeobject) { + LivePathEffect::Effect * effect = current_lperef->lpeobject->get_lpe(); + if (effect) { + effect->upd_params = true; + } + } lpeitem->removeCurrentPathEffect(false); DocumentUndo::done( current_desktop->getDocument(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, @@ -532,11 +545,17 @@ void LivePathEffectEditor::on_effect_selection_changed() Gtk::TreeModel::iterator it = sel->get_selected(); LivePathEffect::LPEObjectReference * lperef = (*it)[columns.lperef]; - if (lperef && current_lpeitem) { + if (lperef && current_lpeitem && current_lperef != lperef) { + //The last condition ignore Gtk::TreeModel may occasionally be changed emitted when nothing has happened if (lperef->lpeobject->get_lpe()) { lpe_list_locked = true; // prevent reload of the list which would lose selection current_lpeitem->setCurrentPathEffect(lperef); - showParams(*lperef->lpeobject->get_lpe()); + current_lperef = lperef; + LivePathEffect::Effect * effect = lperef->lpeobject->get_lpe(); + if (effect) { + effect->upd_params = true; + showParams(*effect); + } } } } @@ -554,6 +573,14 @@ void LivePathEffectEditor::on_visibility_toggled( Glib::ustring const& str ) /* FIXME: this explicit writing to SVG is wrong. The lpe_item should have a method to disable/enable an effect within its stack. * So one can call: lpe_item->setActive(lpeobjref->lpeobject); */ lpeobjref->lpeobject->get_lpe()->getRepr()->setAttribute("is_visible", newValue ? "true" : "false"); + Inkscape::Selection *sel = _getSelection(); + if ( sel && !sel->isEmpty() ) { + SPItem *item = sel->singleItem(); + SPLPEItem *lpeitem = dynamic_cast<SPLPEItem *>(item); + if ( lpeitem ) { + lpeobjref->lpeobject->get_lpe()->doOnVisibilityToggled(lpeitem); + } + } DocumentUndo::done( current_desktop->getDocument(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, newValue ? _("Activate path effect") : _("Deactivate path effect")); } diff --git a/src/ui/dialog/livepatheffect-editor.h b/src/ui/dialog/livepatheffect-editor.h index b69ee007a..a7c749ef3 100644 --- a/src/ui/dialog/livepatheffect-editor.h +++ b/src/ui/dialog/livepatheffect-editor.h @@ -45,7 +45,8 @@ public: static LivePathEffectEditor &getInstance() { return *new LivePathEffectEditor(); } - void onSelectionChanged(Inkscape::Selection *sel); + void onSelectionChanged(Inkscape::Selection *sel, bool upd_params = false); + void onSelectionModified(Inkscape::Selection *sel); virtual void on_effect_selection_changed(); void setDesktop(SPDesktop *desktop); @@ -63,15 +64,15 @@ private: sigc::connection selection_changed_connection; sigc::connection selection_modified_connection; + // void add_entry(const char* name ); + void effect_list_reload(SPLPEItem *lpeitem); + void set_sensitize_all(bool sensitive); void showParams(LivePathEffect::Effect& effect); void showText(Glib::ustring const &str); void selectInList(LivePathEffect::Effect* effect); - // void add_entry(const char* name ); - void effect_list_reload(SPLPEItem *lpeitem); - // callback methods for buttons on grids page. void onAdd(); void onRemove(); @@ -122,6 +123,8 @@ private: SPLPEItem * current_lpeitem; + LivePathEffect::LPEObjectReference * current_lperef; + friend void lpeeditor_selection_changed (Inkscape::Selection * selection, gpointer data); LivePathEffectEditor(LivePathEffectEditor const &d); diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp index 38c72cac0..12686160b 100644 --- a/src/ui/tools/eraser-tool.cpp +++ b/src/ui/tools/eraser-tool.cpp @@ -766,9 +766,17 @@ void EraserTool::set_to_accumulated() { if (bbox && bbox->intersects(*eraserBbox)) { SPClipPath *clip_path = item->clip_ref->getObject(); if (clip_path) { - SPPath *clip_data = SP_PATH(clip_path->firstChild()); + std::vector<SPItem*> selected; + selected.push_back(SP_ITEM(clip_path->firstChild())); + std::vector<Inkscape::XML::Node*> to_select; + std::vector<SPItem*> items(selected); + sp_item_list_to_curves(items, selected, to_select); + Inkscape::XML::Node * clip_data = SP_ITEM(clip_path->firstChild())->getRepr(); + if (!clip_data && !to_select.empty()) { + clip_data = *(to_select.begin()); + } if (clip_data) { - Inkscape::XML::Node *dup_clip = SP_OBJECT(clip_data)->getRepr()->duplicate(xml_doc); + Inkscape::XML::Node *dup_clip = clip_data->duplicate(xml_doc); if (dup_clip) { SPItem * dup_clip_obj = SP_ITEM(item_repr->parent->appendChildRepr(dup_clip)); if (dup_clip_obj) { diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp index c941b9bee..f3185649b 100644 --- a/src/ui/tools/measure-tool.cpp +++ b/src/ui/tools/measure-tool.cpp @@ -378,6 +378,10 @@ MeasureTool::~MeasureTool() sp_canvas_item_destroy(measure_tmp_items[idx]); } measure_tmp_items.clear(); + for (size_t idx = 0; idx < measure_item.size(); ++idx) { + sp_canvas_item_destroy(measure_item[idx]); + } + measure_item.clear(); for (size_t idx = 0; idx < measure_phantom_items.size(); ++idx) { sp_canvas_item_destroy(measure_phantom_items[idx]); } @@ -591,6 +595,12 @@ bool MeasureTool::root_handler(GdkEvent* event) snap_manager.preSnap(scp); snap_manager.unSetup(); } + Geom::Point const motion_w(event->motion.x, event->motion.y); + if(event->motion.state & GDK_SHIFT_MASK) { + showInfoBox(motion_w, true); + } else { + showInfoBox(motion_w, false); + } } else { ret = TRUE; Inkscape::Preferences *prefs = Inkscape::Preferences::get(); @@ -1111,6 +1121,108 @@ void MeasureTool::setMeasureCanvasControlLine(Geom::Point start, Geom::Point end } } +void MeasureTool::showItemInfoText(Geom::Point pos, gchar *measure_str, double fontsize) +{ + SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(), + desktop, + pos, + measure_str); + sp_canvastext_set_fontsize(canvas_tooltip, fontsize); + canvas_tooltip->rgba = 0xffffffff; + canvas_tooltip->outline = false; + canvas_tooltip->background = true; + canvas_tooltip->anchor_position = TEXT_ANCHOR_LEFT; + canvas_tooltip->rgba_background = 0x00000099; + measure_item.push_back(SP_CANVAS_ITEM(canvas_tooltip)); + sp_canvas_item_show(SP_CANVAS_ITEM(canvas_tooltip)); +} + +void MeasureTool::showInfoBox(Geom::Point cursor, bool into_groups) +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Inkscape::Util::Unit const * unit = desktop->getNamedView()->getDisplayUnit(); + for (size_t idx = 0; idx < measure_item.size(); ++idx) { + sp_canvas_item_destroy(measure_item[idx]); + } + measure_item.clear(); + + SPItem *newover = desktop->getItemAtPoint(cursor, into_groups); + if (newover) { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0); + double scale = prefs->getDouble("/tools/measure/scale", 100.0) / 100.0; + int precision = prefs->getInt("/tools/measure/precision", 2); + Glib::ustring unit_name = prefs->getString("/tools/measure/unit"); + if (!unit_name.compare("")) { + unit_name = "px"; + } + Geom::Scale zoom = Geom::Scale(Inkscape::Util::Quantity::convert(desktop->current_zoom(), "px", unit->abbr)).inverse(); + if(newover != over){ + over = newover; + Preferences *prefs = Preferences::get(); + int prefs_bbox = prefs->getBool("/tools/bounding_box", 0); + SPItem::BBoxType bbox_type = !prefs_bbox ? SPItem::VISUAL_BBOX : SPItem::GEOMETRIC_BBOX; + Geom::OptRect bbox = over->bounds(bbox_type); + if (bbox) { + + item_width = Inkscape::Util::Quantity::convert((*bbox).width() * scale, unit->abbr, unit_name); + item_height = Inkscape::Util::Quantity::convert((*bbox).height() * scale, unit->abbr, unit_name); + item_x = Inkscape::Util::Quantity::convert((*bbox).left(), unit->abbr, unit_name); + Geom::Point y_point(0,Inkscape::Util::Quantity::convert((*bbox).bottom() * scale, unit->abbr, "px")); + y_point *= desktop->doc2dt(); + item_y = Inkscape::Util::Quantity::convert(y_point[Geom::Y] * scale, "px", unit_name); + if (SP_IS_SHAPE(over)) { + Geom::PathVector shape = SP_SHAPE(over)->getCurve()->get_pathvector(); + item_length = Geom::length(paths_to_pw(shape)); + item_length = Inkscape::Util::Quantity::convert(item_length * scale, unit->abbr, unit_name); + } + } + } + gchar *measure_str = NULL; + std::stringstream precision_str; + precision_str.imbue(std::locale::classic()); + double origin = Inkscape::Util::Quantity::convert(14, "px", unit->abbr); + Geom::Point rel_position = Geom::Point(origin, origin); + Geom::Point pos = desktop->w2d(cursor); + double gap = Inkscape::Util::Quantity::convert(7 + fontsize, "px", unit->abbr); + if (SP_IS_SHAPE(over)) { + precision_str << _("Length") << ": %." << precision << "f %s"; + measure_str = g_strdup_printf(precision_str.str().c_str(), item_length, unit_name.c_str()); + precision_str.str(""); + showItemInfoText(pos + (rel_position * zoom),measure_str,fontsize); + rel_position = Geom::Point(rel_position[Geom::X], rel_position[Geom::Y] + gap); + } else if (SP_IS_GROUP(over)) { + measure_str = _("Shift to measure into group"); + showItemInfoText(pos + (rel_position * zoom),measure_str,fontsize); + rel_position = Geom::Point(rel_position[Geom::X], rel_position[Geom::Y] + gap); + } + + precision_str << "Y: %." << precision << "f %s"; + measure_str = g_strdup_printf(precision_str.str().c_str(), item_y, unit_name.c_str()); + precision_str.str(""); + showItemInfoText(pos + (rel_position * zoom),measure_str,fontsize); + rel_position = Geom::Point(rel_position[Geom::X], rel_position[Geom::Y] + gap); + + precision_str << "X: %." << precision << "f %s"; + measure_str = g_strdup_printf(precision_str.str().c_str(), item_x, unit_name.c_str()); + precision_str.str(""); + showItemInfoText(pos + (rel_position * zoom),measure_str,fontsize); + rel_position = Geom::Point(rel_position[Geom::X], rel_position[Geom::Y] + gap); + + precision_str << _("Height") << ": %." << precision << "f %s"; + measure_str = g_strdup_printf(precision_str.str().c_str(), item_height, unit_name.c_str()); + precision_str.str(""); + showItemInfoText(pos + (rel_position * zoom),measure_str,fontsize); + rel_position = Geom::Point(rel_position[Geom::X], rel_position[Geom::Y] + gap); + + precision_str << _("Width") << ": %." << precision << "f %s"; + measure_str = g_strdup_printf(precision_str.str().c_str(), item_width, unit_name.c_str()); + precision_str.str(""); + showItemInfoText(pos + (rel_position * zoom),measure_str,fontsize); + g_free(measure_str); + } +} + void MeasureTool::showCanvasItems(bool to_guides, bool to_item, bool to_phantom, Inkscape::XML::Node *measure_repr) { SPDesktop *desktop = SP_ACTIVE_DESKTOP; diff --git a/src/ui/tools/measure-tool.h b/src/ui/tools/measure-tool.h index 14fc9f81a..42122dca1 100644 --- a/src/ui/tools/measure-tool.h +++ b/src/ui/tools/measure-tool.h @@ -54,6 +54,8 @@ public: virtual void setMarker(bool isStart); virtual const std::string& getPrefsPath(); Geom::Point readMeasurePoint(bool is_start); + void showInfoBox(Geom::Point cursor, bool into_groups); + void showItemInfoText(Geom::Point pos, gchar *measure_str, double fontsize); void writeMeasurePoint(Geom::Point point, bool is_start); void setGuide(Geom::Point origin, double angle, const char *label); void setPoint(Geom::Point origin, Inkscape::XML::Node *measure_repr); @@ -77,6 +79,13 @@ private: Geom::Point end_p; std::vector<SPCanvasItem *> measure_tmp_items; std::vector<SPCanvasItem *> measure_phantom_items; + std::vector<SPCanvasItem *> measure_item; + double item_width; + double item_height; + double item_x; + double item_y; + double item_length; + SPItem *over; sigc::connection _knot_start_moved_connection; sigc::connection _knot_start_ungrabbed_connection; sigc::connection _knot_start_click_connection; diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp index 2bd4fdea3..f3679b40f 100644 --- a/src/ui/tools/node-tool.cpp +++ b/src/ui/tools/node-tool.cpp @@ -285,13 +285,11 @@ void NodeTool::update_helperpath () { 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::Set &selectionNodes = _selected_nodes->allPoints(); + Inkscape::UI::ControlPointSelection *selectionNodes = _selected_nodes; std::vector<Geom::Point> selectedNodesPositions; - for (Inkscape::UI::ControlPointSelection::Set::iterator i = selectionNodes.begin(); i != selectionNodes.end(); ++i) { - if ((*i)->selected()) { - Inkscape::UI::Node *n = dynamic_cast<Inkscape::UI::Node *>(*i); - selectedNodesPositions.push_back(n->position()); - } + 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()); @@ -470,6 +468,7 @@ bool NodeTool::root_handler(GdkEvent* event) { switch (event->type) { case GDK_MOTION_NOTIFY: { + 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/select-tool.cpp b/src/ui/tools/select-tool.cpp index 86a2dbed3..0cdeda0b6 100644 --- a/src/ui/tools/select-tool.cpp +++ b/src/ui/tools/select-tool.cpp @@ -1045,37 +1045,7 @@ bool SelectTool::root_handler(GdkEvent* event) { ret = TRUE; break; - - case GDK_KEY_less: - case GDK_KEY_comma: - if (MOD__ALT(event)) { - gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask - sp_selection_scale_screen(selection, -2*mul); - } else if (MOD__CTRL(event)) { - sp_selection_scale_times(selection, 0.5); - } else { - gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask - sp_selection_scale(selection, -offset*mul); - } - - ret = TRUE; - break; - - case GDK_KEY_greater: - case GDK_KEY_period: - if (MOD__ALT(event)) { - gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask - sp_selection_scale_screen(selection, 2*mul); - } else if (MOD__CTRL(event)) { - sp_selection_scale_times(selection, 2); - } else { - gint mul = 1 + gobble_key_events(get_group0_keyval(&event->key), 0); // with any mask - sp_selection_scale(selection, offset*mul); - } - - ret = TRUE; - break; - + case GDK_KEY_Return: if (MOD__CTRL_ONLY(event)) { if (selection->singleItem()) { diff --git a/src/ui/widget/combo-enums.h b/src/ui/widget/combo-enums.h index 4678ab83b..e7524ac71 100644 --- a/src/ui/widget/combo-enums.h +++ b/src/ui/widget/combo-enums.h @@ -16,7 +16,6 @@ #include <gtkmm/liststore.h> #include "attr-widget.h" #include "util/enums.h" - #include <glibmm/i18n.h> namespace Inkscape { @@ -190,9 +189,11 @@ public: const Util::EnumDataConverter<E>& c, Glib::ustring const &suffix = "", Glib::ustring const &icon = "", - bool mnemonic = true) - : Labelled(label, tooltip, new ComboBoxEnum<E>(c), suffix, icon, mnemonic) - { } + bool mnemonic = true, + bool sorted = true) + : Labelled(label, tooltip, new ComboBoxEnum<E>(c, SP_ATTR_INVALID, sorted), suffix, icon, mnemonic) + { + } ComboBoxEnum<E>* getCombobox() { return static_cast< ComboBoxEnum<E>* > (_widget); diff --git a/src/ui/widget/font-button.cpp b/src/ui/widget/font-button.cpp new file mode 100644 index 000000000..a472ac6a4 --- /dev/null +++ b/src/ui/widget/font-button.cpp @@ -0,0 +1,58 @@ +/* + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include "font-button.h" +#include <glibmm/i18n.h> + +namespace Inkscape { +namespace UI { +namespace Widget { + +FontButton::FontButton(Glib::ustring const &label, Glib::ustring const &tooltip, + Glib::ustring const &suffix, + Glib::ustring const &icon, + bool mnemonic) + : Labelled(label, tooltip, new Gtk::FontButton("Sans 10"), suffix, icon, mnemonic) +{ +} + +Glib::ustring FontButton::getValue() const +{ + g_assert(_widget != NULL); + return static_cast<Gtk::FontButton*>(_widget)->get_font_name(); +} + + +void FontButton::setValue (Glib::ustring fontspec) +{ + g_assert(_widget != NULL); + static_cast<Gtk::FontButton*>(_widget)->set_font_name(fontspec); +} + +Glib::SignalProxy0<void> FontButton::signal_font_value_changed() +{ + g_assert(_widget != NULL); + return static_cast<Gtk::FontButton*>(_widget)->signal_font_set(); +} + + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/font-button.h b/src/ui/widget/font-button.h new file mode 100644 index 000000000..1f1ad2d01 --- /dev/null +++ b/src/ui/widget/font-button.h @@ -0,0 +1,63 @@ +/* + * + * Copyright (C) 2007 Author + * + * Released under GNU GPL. Read the file 'COPYING' for more information. + */ + +#ifndef INKSCAPE_UI_WIDGET_FONT_BUTTON_H +#define INKSCAPE_UI_WIDGET_FONT_BUTTON_H + +#include <gtkmm.h> +#include "labelled.h" + +namespace Inkscape { +namespace UI { +namespace Widget { + +/** + * A labelled font button for entering font values + */ +class FontButton : public Labelled +{ +public: + /** + * Construct a FontButton Widget. + * + * @param label Label. + * @param suffix Suffix, placed after the widget (defaults to ""). + * @param icon Icon filename, placed before the label (defaults to ""). + * @param mnemonic Mnemonic toggle; if true, an underscore (_) in the label + * indicates the next character should be used for the + * mnemonic accelerator key (defaults to false). + */ + FontButton( Glib::ustring const &label, + Glib::ustring const &tooltip, + Glib::ustring const &suffix = "", + Glib::ustring const &icon = "", + bool mnemonic = true); + + Glib::ustring getValue() const; + void setValue (Glib::ustring fontspec); + /** + * Signal raised when the font button's value changes. + */ + Glib::SignalProxy0<void> signal_font_value_changed(); +}; + +} // namespace Widget +} // namespace UI +} // namespace Inkscape + +#endif // INKSCAPE_UI_WIDGET_RANDOM_H + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 : diff --git a/src/ui/widget/registered-enums.h b/src/ui/widget/registered-enums.h index 9e1682c7d..1d5074836 100644 --- a/src/ui/widget/registered-enums.h +++ b/src/ui/widget/registered-enums.h @@ -33,11 +33,11 @@ public: const Util::EnumDataConverter<E>& c, Registry& wr, Inkscape::XML::Node* repr_in = NULL, - SPDocument *doc_in = NULL ) - : RegisteredWidget< LabelledComboBoxEnum<E> >(label, tip, c) + SPDocument *doc_in = NULL, + bool sorted = true ) + : RegisteredWidget< LabelledComboBoxEnum<E> >(label, tip, c, (const Glib::ustring &)"", (const Glib::ustring &)"", true, sorted) { RegisteredWidget< LabelledComboBoxEnum<E> >::init_parent(key, wr, repr_in, doc_in); - _changed_connection = combobox()->signal_changed().connect (sigc::mem_fun (*this, &RegisteredEnum::on_changed)); } diff --git a/src/ui/widget/registered-widget.cpp b/src/ui/widget/registered-widget.cpp index 7dc5abc75..be677a434 100644 --- a/src/ui/widget/registered-widget.cpp +++ b/src/ui/widget/registered-widget.cpp @@ -285,7 +285,6 @@ RegisteredScalar::on_value_changed() setProgrammatically = false; return; } - if (_wr->isUpdating()) { return; } @@ -319,8 +318,6 @@ RegisteredText::RegisteredText ( const Glib::ustring& label, const Glib::ustring init_parent(key, wr, repr_in, doc_in); setProgrammatically = false; - - setText(""); _activate_connection = signal_activate().connect (sigc::mem_fun (*this, &RegisteredText::on_activate)); } @@ -336,16 +333,12 @@ RegisteredText::on_activate() return; } _wr->setUpdating (true); - - Inkscape::SVGOStringStream os; - os << getText(); - + Glib::ustring str(getText()); set_sensitive(false); + Inkscape::SVGOStringStream os; + os << str; write_to_xml(os.str().c_str()); set_sensitive(true); - - setText(os.str().c_str()); - _wr->setUpdating (false); } @@ -791,6 +784,47 @@ RegisteredRandom::on_value_changed() _wr->setUpdating (false); } +/*######################################### + * Registered FONT-BUTTON + */ + +RegisteredFontButton::~RegisteredFontButton() +{ + _signal_font_set.disconnect(); +} + +RegisteredFontButton::RegisteredFontButton ( const Glib::ustring& label, const Glib::ustring& tip, + const Glib::ustring& key, Registry& wr, Inkscape::XML::Node* repr_in, + SPDocument* doc_in ) + : RegisteredWidget<FontButton>(label, tip) +{ + init_parent(key, wr, repr_in, doc_in); + _signal_font_set = signal_font_value_changed().connect (sigc::mem_fun (*this, &RegisteredFontButton::on_value_changed)); +} + +void +RegisteredFontButton::setValue (Glib::ustring fontspec) +{ + FontButton::setValue(fontspec); +} + +void +RegisteredFontButton::on_value_changed() +{ + + if (_wr->isUpdating()) + return; + + _wr->setUpdating (true); + + Inkscape::SVGOStringStream os; + os << getValue(); + + write_to_xml(os.str().c_str()); + + _wr->setUpdating (false); +} + } // namespace Dialog } // namespace UI } // namespace Inkscape diff --git a/src/ui/widget/registered-widget.h b/src/ui/widget/registered-widget.h index ab2e4c8e4..d410dbfe6 100644 --- a/src/ui/widget/registered-widget.h +++ b/src/ui/widget/registered-widget.h @@ -22,6 +22,7 @@ #include "ui/widget/text.h" #include "ui/widget/random.h" #include "ui/widget/unit-menu.h" +#include "ui/widget/font-button.h" #include "ui/widget/color-picker.h" #include "inkscape.h" @@ -77,6 +78,8 @@ protected: RegisteredWidget( A& a, B& b, C c, D d ): W( a, b, c, d ) { construct(); } template< typename A, typename B, typename C, typename D, typename E , typename F> RegisteredWidget( A& a, B& b, C c, D& d, E& e, F* f): W( a, b, c, d, e, f) { construct(); } + template< typename A, typename B, typename C, typename D, typename E , typename F, typename G> + RegisteredWidget( A& a, B& b, C& c, D& d, E& e, F f, G& g): W( a, b, c, d, e, f, g) { construct(); } virtual ~RegisteredWidget() {}; @@ -418,6 +421,23 @@ protected: void on_value_changed(); }; +class RegisteredFontButton : public RegisteredWidget<FontButton> { +public: + virtual ~RegisteredFontButton(); + RegisteredFontButton ( const Glib::ustring& label, + const Glib::ustring& tip, + const Glib::ustring& key, + Registry& wr, + Inkscape::XML::Node* repr_in = NULL, + SPDocument *doc_in = NULL); + + void setValue (Glib::ustring fontspec); + +protected: + sigc::connection _signal_font_set; + void on_value_changed(); +}; + } // namespace Widget } // namespace UI } // namespace Inkscape diff --git a/src/ui/widget/scalar.cpp b/src/ui/widget/scalar.cpp index 434c2c0bb..f8543a371 100644 --- a/src/ui/widget/scalar.cpp +++ b/src/ui/widget/scalar.cpp @@ -122,10 +122,12 @@ void Scalar::setRange(double min, double max) static_cast<SpinButton*>(_widget)->set_range(min, max); } -void Scalar::setValue(double value) +void Scalar::setValue(double value, bool setProg) { g_assert(_widget != NULL); - setProgrammatically = true; // callback is supposed to reset back, if it cares + if (setProg) { + setProgrammatically = true; // callback is supposed to reset back, if it cares + } static_cast<SpinButton*>(_widget)->set_value(value); } diff --git a/src/ui/widget/scalar.h b/src/ui/widget/scalar.h index 847790b96..f186f46ac 100644 --- a/src/ui/widget/scalar.h +++ b/src/ui/widget/scalar.h @@ -135,7 +135,7 @@ public: /** * Sets the value of the spin button. */ - void setValue(double value); + void setValue(double value, bool setProg = true); /** * Manually forces an update of the spin button. diff --git a/src/ui/widget/text.cpp b/src/ui/widget/text.cpp index ec58d5bb4..e6795b138 100644 --- a/src/ui/widget/text.cpp +++ b/src/ui/widget/text.cpp @@ -28,13 +28,13 @@ Text::Text(Glib::ustring const &label, Glib::ustring const &tooltip, { } -const char *Text::getText() const +Glib::ustring const Text::getText() const { g_assert(_widget != NULL); - return static_cast<Gtk::Entry*>(_widget)->get_text().c_str(); + return static_cast<Gtk::Entry*>(_widget)->get_text(); } -void Text::setText(const char* text) +void Text::setText(Glib::ustring const text) { g_assert(_widget != NULL); setProgrammatically = true; // callback is supposed to reset back, if it cares diff --git a/src/ui/widget/text.h b/src/ui/widget/text.h index b90788940..593875b23 100644 --- a/src/ui/widget/text.h +++ b/src/ui/widget/text.h @@ -44,12 +44,12 @@ public: /** * Get the text in the entry. */ - const char* getText() const; + Glib::ustring const getText() const; /** * Sets the text of the text entry. */ - void setText(const char* text); + void setText(Glib::ustring const text); void update(); diff --git a/src/verbs.cpp b/src/verbs.cpp index 5130f1701..e061eaab6 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -817,7 +817,7 @@ Verb *Verb::get_search(unsigned int code) * * @param id Which id to search for. */ -Verb *Verb::getbyid(gchar const *id) +Verb *Verb::getbyid(gchar const *id, bool verbose) { Verb *verb = NULL; VerbIDTable::iterator verb_found = _verb_ids.find(id); @@ -833,8 +833,10 @@ Verb *Verb::getbyid(gchar const *id) && strcmp(id, "SelectionTrace") != 0 && strcmp(id, "PaintBucketPrefs") != 0 #endif - ) - printf("Unable to find: %s\n", id); + ) { + if (verbose) + printf("Unable to find: %s\n", id); + } return verb; } @@ -1099,6 +1101,7 @@ void SelectionVerb::perform(SPAction *action, void *data) { Inkscape::Selection *selection = sp_action_get_selection(action); SPDesktop *dt = sp_action_get_desktop(action); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); // Some of these operations have been modified so they work in command-line mode! // In this case, all we need is a selection @@ -1126,6 +1129,38 @@ void SelectionVerb::perform(SPAction *action, void *data) case SP_VERB_SELECTION_SLICE: sp_selected_path_slice(selection, dt); break; + case SP_VERB_SELECTION_GROW: + { + // FIXME these and the other grow/shrink they should use gobble_key_events. + // the problem is how to get access to which key, if any, to gobble. + sp_selection_scale(selection, prefs->getDoubleLimited("/options/defaultscale/value", 2, 0, 1000)); + break; + } + case SP_VERB_SELECTION_GROW_SCREEN: + { + sp_selection_scale_screen(selection, 2); + break; + } + case SP_VERB_SELECTION_GROW_DOUBLE: + { + sp_selection_scale_times(selection, 2); + break; + } + case SP_VERB_SELECTION_SHRINK: + { + sp_selection_scale(selection, -prefs->getDoubleLimited("/options/defaultscale/value", 2, 0, 1000)); + break; + } + case SP_VERB_SELECTION_SHRINK_SCREEN: + { + sp_selection_scale_screen(selection, -2); + break; + } + case SP_VERB_SELECTION_SHRINK_HALVE: + { + sp_selection_scale_times(selection, 0.5); + break; + } case SP_VERB_SELECTION_TO_FRONT: sp_selection_raise_to_top(selection, dt); break; @@ -1856,6 +1891,7 @@ void ZoomVerb::perform(SPAction *action, void *data) { gint mul = 1 + Inkscape::UI::Tools::gobble_key_events( GDK_KEY_KP_Add, 0); // with any mask + // FIXME what if zoom out is bound to something other than subtract? // While drawing with the pen/pencil tool, zoom towards the end of the unfinished path if (tools_isactive(dt, TOOLS_FREEHAND_PENCIL) || tools_isactive(dt, TOOLS_FREEHAND_PEN)) { SPCurve *rc = SP_DRAW_CONTEXT(ec)->red_curve; @@ -2585,6 +2621,18 @@ Verb *Verb::_base_verbs[] = { // Advanced tutorial for more info new SelectionVerb(SP_VERB_SELECTION_SLICE, "SelectionCutPath", N_("Cut _Path"), N_("Cut the bottom path's stroke into pieces, removing fill"), INKSCAPE_ICON("path-cut")), + new SelectionVerb(SP_VERB_SELECTION_GROW, "SelectionGrow", N_("_Grow"), + N_("Make selected objects bigger"), INKSCAPE_ICON("selection-grow")), + new SelectionVerb(SP_VERB_SELECTION_GROW_SCREEN, "SelectionGrowScreen", N_("_Grow on screen"), + N_("Make selected objects bigger relative to screen"), INKSCAPE_ICON("selection-grow-screen")), + new SelectionVerb(SP_VERB_SELECTION_GROW_DOUBLE, "SelectionGrowDouble", N_("_Double size"), + N_("Double the size of selected objects"), INKSCAPE_ICON("selection-grow-double")), + new SelectionVerb(SP_VERB_SELECTION_SHRINK, "SelectionShrink", N_("_Shrink"), + N_("Make selected objects smaller"), INKSCAPE_ICON("selection-shrink")), + new SelectionVerb(SP_VERB_SELECTION_SHRINK_SCREEN, "SelectionShrinkScreen", N_("_Shrink on screen"), + N_("Make selected objects smaller relative to screen"), INKSCAPE_ICON("selection-shrink-screen")), + new SelectionVerb(SP_VERB_SELECTION_SHRINK_HALVE, "SelectionShrinkHalve", N_("_Halve size"), + N_("Halve the size of selected objects"), INKSCAPE_ICON("selection-shrink-halve")), // TRANSLATORS: "outset": expand a shape by offsetting the object's path, // i.e. by displacing it perpendicular to the path in each point. // See also the Advanced Tutorial for explanation. diff --git a/src/verbs.h b/src/verbs.h index 16f88c408..1780e0ebf 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -126,6 +126,12 @@ enum { SP_VERB_SELECTION_SYMDIFF, SP_VERB_SELECTION_CUT, SP_VERB_SELECTION_SLICE, + SP_VERB_SELECTION_GROW, + SP_VERB_SELECTION_GROW_SCREEN, + SP_VERB_SELECTION_GROW_DOUBLE, + SP_VERB_SELECTION_SHRINK, + SP_VERB_SELECTION_SHRINK_SCREEN, + SP_VERB_SELECTION_SHRINK_HALVE, SP_VERB_SELECTION_OFFSET, SP_VERB_SELECTION_OFFSET_SCREEN, SP_VERB_SELECTION_OFFSET_SCREEN_10, @@ -575,7 +581,7 @@ public: return get_search(code); } } - static Verb * getbyid (gchar const * id); + static Verb * getbyid (gchar const * id, bool verbose = true); /** * Print a message to stderr indicating that this verb needs a GUI to run diff --git a/src/widgets/pencil-toolbar.cpp b/src/widgets/pencil-toolbar.cpp index 582fb66ba..96733cb22 100644 --- a/src/widgets/pencil-toolbar.cpp +++ b/src/widgets/pencil-toolbar.cpp @@ -238,11 +238,12 @@ static void sp_simplify_flatten(GtkWidget * /*widget*/, GObject *obj) { SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(obj, "desktop")); auto selected = desktop->getSelection()->items(); + SPLPEItem* lpeitem = NULL; for (auto it(selected.begin()); it != selected.end(); ++it){ - SPLPEItem* lpeitem = dynamic_cast<SPLPEItem*>(*it); + lpeitem = dynamic_cast<SPLPEItem*>(*it); if (lpeitem && lpeitem->hasPathEffect()){ PathEffectList lpelist = lpeitem->getEffectList(); - std::list<Inkscape::LivePathEffect::LPEObjectReference *>::iterator i; + PathEffectList::iterator i; for (i = lpelist.begin(); i != lpelist.end(); ++i) { LivePathEffectObject *lpeobj = (*i)->lpeobject; if (lpeobj) { @@ -267,6 +268,10 @@ static void sp_simplify_flatten(GtkWidget * /*widget*/, GObject *obj) } } } + if (lpeitem) { + desktop->getSelection()->remove(lpeitem->getRepr()); + desktop->getSelection()->add(lpeitem->getRepr()); + } } static void sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl) |
