summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJabier Arraiza Cenoz <jabier.arraiza@marker.es>2016-03-14 16:37:50 +0000
committerJabiertxof <jtx@jtx.marker.es>2016-03-14 16:37:50 +0000
commitb8d22beef5345210ad27cdc2685083aeae6f8f3b (patch)
treed69b8bfd19d3627a8425a1b265c2abf229b05354 /src
parentfixes for update to trunk (diff)
parent"Relative to" option for node alignment. (diff)
downloadinkscape-b8d22beef5345210ad27cdc2685083aeae6f8f3b.tar.gz
inkscape-b8d22beef5345210ad27cdc2685083aeae6f8f3b.zip
update to trunk
(bzr r13708.1.39)
Diffstat (limited to 'src')
-rw-r--r--src/2geom/CMakeLists.txt2
-rw-r--r--src/2geom/Makefile_insert2
-rw-r--r--src/2geom/angle.h4
-rw-r--r--src/2geom/bezier-clipping.cpp4
-rw-r--r--src/2geom/bezier-curve.cpp98
-rw-r--r--src/2geom/bezier-curve.h14
-rw-r--r--src/2geom/circle.cpp8
-rw-r--r--src/2geom/conicsec.cpp14
-rw-r--r--src/2geom/coord.cpp9
-rw-r--r--src/2geom/crossing.h2
-rw-r--r--src/2geom/curve.cpp4
-rw-r--r--src/2geom/curve.h3
-rw-r--r--src/2geom/d2-sbasis.cpp60
-rw-r--r--src/2geom/d2-sbasis.h165
-rw-r--r--src/2geom/d2.h81
-rw-r--r--src/2geom/ellipse.cpp78
-rw-r--r--src/2geom/ellipse.h3
-rw-r--r--src/2geom/elliptical-arc.cpp299
-rw-r--r--src/2geom/elliptical-arc.h4
-rw-r--r--src/2geom/generic-interval.h5
-rw-r--r--src/2geom/generic-rect.h7
-rw-r--r--src/2geom/int-point.h13
-rw-r--r--src/2geom/intersection-graph.cpp373
-rw-r--r--src/2geom/intersection-graph.h67
-rw-r--r--src/2geom/line.cpp48
-rw-r--r--src/2geom/line.h43
-rw-r--r--src/2geom/linear.h137
-rw-r--r--src/2geom/numeric/fitting-model.h1
-rw-r--r--src/2geom/path-sink.cpp4
-rw-r--r--src/2geom/path-sink.h6
-rw-r--r--src/2geom/path.cpp268
-rw-r--r--src/2geom/path.h76
-rw-r--r--src/2geom/pathvector.cpp111
-rw-r--r--src/2geom/pathvector.h2
-rw-r--r--src/2geom/piecewise.h2
-rw-r--r--src/2geom/ray.h47
-rw-r--r--src/2geom/rect.cpp78
-rw-r--r--src/2geom/rect.h57
-rw-r--r--src/2geom/sbasis-curve.h5
-rw-r--r--src/2geom/sbasis-geometric.cpp2
-rw-r--r--src/2geom/sbasis-math.cpp3
-rw-r--r--src/2geom/sbasis-roots.cpp6
-rw-r--r--src/2geom/sbasis-to-bezier.cpp8
-rw-r--r--src/2geom/sbasis.cpp6
-rw-r--r--src/2geom/sbasis.h73
-rw-r--r--src/2geom/svg-path-parser.cpp4
-rw-r--r--src/2geom/svg-path-writer.cpp2
-rw-r--r--src/2geom/sweeper.h244
-rw-r--r--src/2geom/utils.h26
-rw-r--r--src/2geom/viewbox.cpp133
-rw-r--r--src/2geom/viewbox.h102
-rw-r--r--src/CMakeLists.txt58
-rw-r--r--src/Makefile.am8
-rw-r--r--src/Makefile_insert1
-rw-r--r--src/attributes-test.h7
-rw-r--r--src/attributes.cpp28
-rw-r--r--src/attributes.h8
-rw-r--r--src/box3d.cpp7
-rw-r--r--src/color-profile.cpp12
-rw-r--r--src/conn-avoid-ref.cpp32
-rw-r--r--src/conn-avoid-ref.h7
-rw-r--r--src/desktop-events.cpp13
-rw-r--r--src/desktop-style.cpp182
-rw-r--r--src/desktop-style.h3
-rw-r--r--src/desktop.cpp31
-rw-r--r--src/desktop.h2
-rw-r--r--src/display/CMakeLists.txt2
-rw-r--r--src/display/Makefile_insert2
-rw-r--r--src/display/cairo-utils.cpp4
-rw-r--r--src/display/canvas-axonomgrid.cpp8
-rw-r--r--src/display/canvas-text.cpp6
-rw-r--r--src/display/curve.cpp2
-rw-r--r--src/display/drawing-image.cpp2
-rw-r--r--src/display/guideline.cpp63
-rw-r--r--src/display/guideline.h6
-rw-r--r--src/display/nr-filter-component-transfer.cpp203
-rw-r--r--src/display/nr-filter-image.cpp2
-rw-r--r--src/display/nr-filter-offset.cpp4
-rw-r--r--src/display/nr-filter-primitive.cpp19
-rw-r--r--src/display/nr-filter-slot.cpp21
-rw-r--r--src/display/nr-filter-slot.h8
-rw-r--r--src/display/nr-filter-tile.cpp99
-rw-r--r--src/display/nr-filter-tile.h1
-rw-r--r--src/display/nr-filter.cpp2
-rw-r--r--src/display/nr-style.cpp2
-rw-r--r--src/display/nr-style.h1
-rw-r--r--src/display/snap-indicator.cpp11
-rw-r--r--src/display/sodipodi-ctrlrect.cpp15
-rw-r--r--src/display/sodipodi-ctrlrect.h3
-rw-r--r--src/display/sp-canvas-item.h2
-rw-r--r--src/display/sp-canvas-util.cpp3
-rw-r--r--src/display/sp-canvas.cpp212
-rw-r--r--src/display/sp-ctrlpoint.cpp159
-rw-r--r--src/display/sp-ctrlpoint.h52
-rw-r--r--src/document-private.h15
-rw-r--r--src/document-undo.cpp70
-rw-r--r--src/document.cpp254
-rw-r--r--src/document.h15
-rw-r--r--src/extension/execution-env.cpp4
-rw-r--r--src/extension/implementation/implementation.cpp1
-rw-r--r--src/extension/implementation/script.cpp59
-rw-r--r--src/extension/internal/bitmap/imagemagick.cpp3
-rw-r--r--src/extension/internal/bluredge.cpp2
-rw-r--r--src/extension/internal/cairo-render-context.cpp113
-rw-r--r--src/extension/internal/cairo-render-context.h11
-rw-r--r--src/extension/internal/cairo-renderer.cpp32
-rw-r--r--src/extension/internal/emf-inout.cpp37
-rw-r--r--src/extension/internal/emf-print.cpp55
-rw-r--r--src/extension/internal/filter/filter.cpp1
-rw-r--r--src/extension/internal/gdkpixbuf-input.cpp9
-rw-r--r--src/extension/internal/grid.cpp1
-rw-r--r--src/extension/internal/latex-text-renderer.cpp2
-rw-r--r--src/extension/internal/metafile-print.cpp4
-rw-r--r--src/extension/internal/pdfinput/pdf-input.cpp1
-rw-r--r--src/extension/internal/pdfinput/pdf-parser.cpp258
-rw-r--r--src/extension/internal/pdfinput/svg-builder.cpp1
-rw-r--r--src/extension/internal/text_reassemble.c82
-rw-r--r--src/extension/internal/wmf-inout.cpp32
-rw-r--r--src/extension/internal/wmf-print.cpp5
-rw-r--r--src/extension/param/parameter.cpp7
-rw-r--r--src/extension/param/string.cpp2
-rw-r--r--src/file.cpp34
-rw-r--r--src/gradient-chemistry.cpp14
-rw-r--r--src/gradient-drag.cpp395
-rw-r--r--src/gradient-drag.h23
-rw-r--r--src/graphlayout.cpp12
-rw-r--r--src/graphlayout.h1
-rw-r--r--src/guide-snapper.cpp9
-rw-r--r--src/helper/geom-pathstroke.cpp364
-rw-r--r--src/helper/geom-pathstroke.h3
-rw-r--r--src/helper/png-write.cpp6
-rw-r--r--src/inkgc/gc.cpp6
-rw-r--r--src/inkview.cpp365
-rw-r--r--src/io/inkjar.cpp17
-rw-r--r--src/io/streamtest.cpp1
-rw-r--r--src/knot-holder-entity.h5
-rw-r--r--src/knot.cpp249
-rw-r--r--src/layer-manager.cpp19
-rw-r--r--src/libcroco/cr-additional-sel.c16
-rw-r--r--src/libcroco/cr-attr-sel.c8
-rw-r--r--src/libcroco/cr-cascade.c2
-rw-r--r--src/libcroco/cr-declaration.c26
-rw-r--r--src/libcroco/cr-enc-handler.c8
-rw-r--r--src/libcroco/cr-fonts.c12
-rw-r--r--src/libcroco/cr-input.c4
-rw-r--r--src/libcroco/cr-num.c4
-rw-r--r--src/libcroco/cr-om-parser.c61
-rw-r--r--src/libcroco/cr-parser.c40
-rw-r--r--src/libcroco/cr-pseudo.c12
-rw-r--r--src/libcroco/cr-rgb.c13
-rw-r--r--src/libcroco/cr-sel-eng.c44
-rw-r--r--src/libcroco/cr-sel-eng.h6
-rw-r--r--src/libcroco/cr-selector.c15
-rw-r--r--src/libcroco/cr-simple-sel.c24
-rw-r--r--src/libcroco/cr-statement.c131
-rw-r--r--src/libcroco/cr-string.c15
-rw-r--r--src/libcroco/cr-style.c60
-rw-r--r--src/libcroco/cr-stylesheet.c4
-rw-r--r--src/libcroco/cr-term.c71
-rw-r--r--src/libcroco/cr-tknzr.c26
-rw-r--r--src/libcroco/cr-token.c4
-rw-r--r--src/libcroco/cr-utils.c26
-rw-r--r--src/libgdl/CMakeLists.txt87
-rw-r--r--src/libgdl/gdl-dock-item-grip.c3
-rw-r--r--src/libgdl/gdl-dock-item.c3
-rw-r--r--src/libnrtype/FontInstance.cpp238
-rw-r--r--src/libnrtype/Layout-TNG-Compute.cpp454
-rw-r--r--src/libnrtype/Layout-TNG-Input.cpp94
-rw-r--r--src/libnrtype/Layout-TNG-OutIter.cpp17
-rw-r--r--src/libnrtype/Layout-TNG-Output.cpp58
-rw-r--r--src/libnrtype/Layout-TNG-Scanline-Maker.h30
-rw-r--r--src/libnrtype/Layout-TNG-Scanline-Makers.cpp50
-rw-r--r--src/libnrtype/Layout-TNG.cpp2
-rw-r--r--src/libnrtype/Layout-TNG.h103
-rw-r--r--src/libnrtype/TextWrapper.cpp4
-rw-r--r--src/libnrtype/font-instance.h33
-rw-r--r--src/libnrtype/font-lister.cpp1
-rw-r--r--src/libnrtype/one-box.h2
-rw-r--r--src/libuemf/uemf.c12
-rw-r--r--src/libuemf/uemf.h26
-rw-r--r--src/libuemf/uemf_print.c18
-rw-r--r--src/libuemf/uemf_safe.c8
-rw-r--r--src/libuemf/upmf.c16
-rw-r--r--src/libuemf/upmf.h11
-rw-r--r--src/libuemf/upmf_print.c14
-rw-r--r--src/libuemf/uwmf.h9
-rw-r--r--src/live_effects/CMakeLists.txt2
-rw-r--r--src/live_effects/Makefile_insert2
-rw-r--r--src/live_effects/effect-enum.h1
-rw-r--r--src/live_effects/effect.cpp14
-rw-r--r--src/live_effects/effect.h2
-rw-r--r--src/live_effects/lpe-angle_bisector.cpp2
-rw-r--r--src/live_effects/lpe-bendpath.cpp93
-rw-r--r--src/live_effects/lpe-bendpath.h18
-rw-r--r--src/live_effects/lpe-bspline.cpp368
-rw-r--r--src/live_effects/lpe-bspline.h16
-rw-r--r--src/live_effects/lpe-copy_rotate.cpp14
-rw-r--r--src/live_effects/lpe-dynastroke.cpp1
-rw-r--r--src/live_effects/lpe-envelope.cpp4
-rw-r--r--src/live_effects/lpe-fill-between-many.cpp2
-rw-r--r--src/live_effects/lpe-fillet-chamfer.cpp18
-rw-r--r--src/live_effects/lpe-interpolate.cpp1
-rw-r--r--src/live_effects/lpe-interpolate_points.cpp5
-rw-r--r--src/live_effects/lpe-jointype.cpp3
-rw-r--r--src/live_effects/lpe-knot.cpp3
-rw-r--r--src/live_effects/lpe-lattice.cpp5
-rw-r--r--src/live_effects/lpe-lattice2.cpp41
-rw-r--r--src/live_effects/lpe-lattice2.h1
-rw-r--r--src/live_effects/lpe-mirror_symmetry.cpp10
-rw-r--r--src/live_effects/lpe-mirror_symmetry.h2
-rw-r--r--src/live_effects/lpe-offset.cpp10
-rw-r--r--src/live_effects/lpe-offset.h2
-rw-r--r--src/live_effects/lpe-patternalongpath.cpp107
-rw-r--r--src/live_effects/lpe-patternalongpath.h19
-rw-r--r--src/live_effects/lpe-perspective-envelope.cpp4
-rw-r--r--src/live_effects/lpe-perspective_path.cpp3
-rw-r--r--src/live_effects/lpe-powerstroke.cpp7
-rw-r--r--src/live_effects/lpe-roughen.cpp392
-rw-r--r--src/live_effects/lpe-roughen.h21
-rw-r--r--src/live_effects/lpe-simplify.cpp28
-rw-r--r--src/live_effects/lpe-spiro.cpp16
-rw-r--r--src/live_effects/lpe-spiro.h2
-rw-r--r--src/live_effects/lpe-taperstroke.cpp3
-rw-r--r--src/live_effects/lpe-transform_2pts.cpp461
-rw-r--r--src/live_effects/lpe-transform_2pts.h91
-rw-r--r--src/live_effects/lpe-vonkoch.cpp5
-rw-r--r--src/live_effects/parameter/bool.cpp32
-rw-r--r--src/live_effects/parameter/bool.h4
-rw-r--r--src/live_effects/parameter/filletchamferpointarray.cpp12
-rw-r--r--src/live_effects/parameter/originalpatharray.cpp12
-rw-r--r--src/live_effects/parameter/parameter.cpp44
-rw-r--r--src/live_effects/parameter/parameter.h6
-rw-r--r--src/live_effects/parameter/point.cpp16
-rw-r--r--src/live_effects/parameter/point.h7
-rw-r--r--src/live_effects/parameter/togglebutton.cpp4
-rw-r--r--src/live_effects/spiro-converters.cpp32
-rw-r--r--src/live_effects/spiro-converters.h24
-rw-r--r--src/live_effects/spiro.cpp15
-rw-r--r--src/main.cpp10
-rw-r--r--src/menus-skeleton.h11
-rw-r--r--src/object-snapper.cpp46
-rw-r--r--src/path-chemistry.cpp46
-rw-r--r--src/path-chemistry.h5
-rw-r--r--src/path-prefix.h2
-rw-r--r--src/persp3d.cpp8
-rw-r--r--src/pixmaps/cursor-select.xpm38
-rw-r--r--src/preferences-skeleton.h2
-rw-r--r--src/profile-manager.cpp8
-rw-r--r--src/pure-transform.cpp359
-rw-r--r--src/pure-transform.h228
-rw-r--r--src/removeoverlap.cpp1
-rw-r--r--src/removeoverlap.h2
-rw-r--r--src/resource-manager.cpp28
-rw-r--r--src/satisfied-guide-cns.cpp4
-rw-r--r--src/selcue.cpp6
-rw-r--r--src/selection-chemistry.cpp150
-rw-r--r--src/selection-chemistry.h2
-rw-r--r--src/selection-describer.cpp6
-rw-r--r--src/selection.cpp54
-rw-r--r--src/seltrans.cpp217
-rw-r--r--src/seltrans.h1
-rw-r--r--src/shortcuts.cpp9
-rw-r--r--src/snap.cpp497
-rw-r--r--src/snap.h169
-rw-r--r--src/snapped-point.cpp5
-rw-r--r--src/snapped-point.h4
-rw-r--r--src/snapper.h2
-rw-r--r--src/sp-clippath.cpp2
-rw-r--r--src/sp-clippath.h9
-rw-r--r--src/sp-conn-end.cpp2
-rw-r--r--src/sp-defs.cpp2
-rw-r--r--src/sp-factory.cpp4
-rw-r--r--src/sp-filter-primitive.cpp4
-rw-r--r--src/sp-filter.cpp2
-rw-r--r--src/sp-flowtext.cpp6
-rw-r--r--src/sp-guide.cpp111
-rw-r--r--src/sp-guide.h9
-rw-r--r--src/sp-hatch.cpp2
-rw-r--r--src/sp-item-group.cpp44
-rw-r--r--src/sp-item-group.h1
-rw-r--r--src/sp-item.cpp4
-rw-r--r--src/sp-lpe-item.cpp210
-rw-r--r--src/sp-lpe-item.h40
-rw-r--r--src/sp-marker.cpp25
-rw-r--r--src/sp-mask.cpp41
-rw-r--r--src/sp-mask.h8
-rw-r--r--src/sp-mesh-array.cpp19
-rw-r--r--src/sp-namedview.cpp201
-rw-r--r--src/sp-namedview.h12
-rw-r--r--src/sp-object.h1
-rw-r--r--src/sp-paint-server.cpp4
-rw-r--r--src/sp-path.cpp3
-rw-r--r--src/sp-pattern.cpp15
-rw-r--r--src/sp-radial-gradient.cpp18
-rw-r--r--src/sp-radial-gradient.h1
-rw-r--r--src/sp-rect.cpp12
-rw-r--r--src/sp-star.cpp13
-rw-r--r--src/sp-switch.cpp4
-rw-r--r--src/sp-switch.h1
-rw-r--r--src/sp-text.cpp102
-rw-r--r--src/sp-tref.cpp2
-rw-r--r--src/sp-tspan.cpp32
-rw-r--r--src/splivarot.cpp14
-rw-r--r--src/splivarot.h1
-rw-r--r--src/style-enums.h66
-rw-r--r--src/style-internal.cpp3
-rw-r--r--src/style-internal.h5
-rw-r--r--src/style.cpp46
-rw-r--r--src/style.h10
-rw-r--r--src/svg/CMakeLists.txt2
-rw-r--r--src/svg/svg-affine.cpp2
-rw-r--r--src/svg/svg-length.cpp2
-rw-r--r--src/svg/svg-length.h2
-rw-r--r--src/svg/svg-path.cpp2
-rw-r--r--src/text-chemistry.cpp16
-rw-r--r--src/text-editing.cpp14
-rw-r--r--src/text-tag-attributes.h5
-rw-r--r--src/trace/CMakeLists.txt20
-rw-r--r--src/trace/Makefile_insert21
-rw-r--r--src/trace/potrace/auxiliary.h80
-rw-r--r--src/trace/potrace/bitmap.h17
-rw-r--r--src/trace/potrace/bitops.h83
-rw-r--r--src/trace/potrace/curve.cpp108
-rw-r--r--src/trace/potrace/curve.h77
-rw-r--r--src/trace/potrace/decompose.cpp511
-rw-r--r--src/trace/potrace/decompose.h16
-rw-r--r--src/trace/potrace/greymap.cpp941
-rw-r--r--src/trace/potrace/greymap.h58
-rw-r--r--src/trace/potrace/inkscape-potrace.cpp7
-rw-r--r--src/trace/potrace/inkscape-potrace.h2
-rw-r--r--src/trace/potrace/lists.h285
-rw-r--r--src/trace/potrace/potracelib.cpp128
-rw-r--r--src/trace/potrace/potracelib.h139
-rw-r--r--src/trace/potrace/progress.h77
-rw-r--r--src/trace/potrace/render.cpp243
-rw-r--r--src/trace/potrace/render.h27
-rw-r--r--src/trace/potrace/trace.cpp1245
-rw-r--r--src/trace/potrace/trace.h15
-rw-r--r--src/trace/trace.cpp2
-rw-r--r--src/ui/CMakeLists.txt17
-rw-r--r--src/ui/clipboard.cpp51
-rw-r--r--src/ui/control-manager.cpp22
-rw-r--r--src/ui/control-manager.h6
-rw-r--r--src/ui/control-types.h1
-rw-r--r--src/ui/dialog/Makefile_insert12
-rw-r--r--src/ui/dialog/align-and-distribute.cpp128
-rw-r--r--src/ui/dialog/align-and-distribute.h13
-rw-r--r--src/ui/dialog/clonetiler.cpp34
-rw-r--r--src/ui/dialog/clonetiler.h4
-rw-r--r--src/ui/dialog/dialog-manager.cpp14
-rw-r--r--src/ui/dialog/document-properties.cpp126
-rw-r--r--src/ui/dialog/document-properties.h1
-rw-r--r--src/ui/dialog/export.cpp13
-rw-r--r--src/ui/dialog/filedialogimpl-gtkmm.cpp68
-rw-r--r--src/ui/dialog/filter-effects-dialog.cpp21
-rw-r--r--src/ui/dialog/filter-effects-dialog.h8
-rw-r--r--src/ui/dialog/find.cpp16
-rw-r--r--src/ui/dialog/font-substitution.cpp2
-rw-r--r--src/ui/dialog/glyphs.cpp4
-rw-r--r--src/ui/dialog/grid-arrange-tab.cpp20
-rw-r--r--src/ui/dialog/guides.cpp29
-rw-r--r--src/ui/dialog/guides.h1
-rw-r--r--src/ui/dialog/icon-preview.cpp2
-rw-r--r--src/ui/dialog/inkscape-preferences.cpp114
-rw-r--r--src/ui/dialog/inkscape-preferences.h10
-rw-r--r--src/ui/dialog/knot-properties.cpp213
-rw-r--r--src/ui/dialog/knot-properties.h97
-rw-r--r--src/ui/dialog/layers.cpp12
-rw-r--r--src/ui/dialog/new-from-template.cpp18
-rw-r--r--src/ui/dialog/new-from-template.h6
-rw-r--r--src/ui/dialog/objects.cpp16
-rw-r--r--src/ui/dialog/pixelartdialog.cpp2
-rw-r--r--src/ui/dialog/polar-arrange-tab.cpp4
-rw-r--r--src/ui/dialog/svg-fonts-dialog.cpp6
-rw-r--r--src/ui/dialog/swatches.cpp38
-rw-r--r--src/ui/dialog/tags.cpp8
-rw-r--r--src/ui/dialog/template-load-tab.cpp38
-rw-r--r--src/ui/dialog/template-load-tab.h4
-rw-r--r--src/ui/dialog/template-widget.cpp26
-rw-r--r--src/ui/dialog/template-widget.h1
-rw-r--r--src/ui/dialog/text-edit.cpp24
-rw-r--r--src/ui/dialog/transformation.cpp12
-rw-r--r--src/ui/interface.cpp27
-rw-r--r--src/ui/object-edit.cpp8
-rw-r--r--src/ui/tool-factory.cpp8
-rw-r--r--src/ui/tool/control-point-selection.cpp29
-rw-r--r--src/ui/tool/control-point-selection.h3
-rw-r--r--src/ui/tool/multi-path-manipulator.cpp9
-rw-r--r--src/ui/tool/node.cpp107
-rw-r--r--src/ui/tool/path-manipulator.cpp29
-rw-r--r--src/ui/tool/path-manipulator.h4
-rw-r--r--src/ui/tool/selector.cpp1
-rw-r--r--src/ui/tool/transform-handle-set.cpp48
-rw-r--r--src/ui/tools-switch.cpp8
-rw-r--r--src/ui/tools-switch.h8
-rw-r--r--src/ui/tools/Makefile_insert10
-rw-r--r--src/ui/tools/connector-tool.cpp2
-rw-r--r--src/ui/tools/eraser-tool.cpp216
-rw-r--r--src/ui/tools/eraser-tool.h1
-rw-r--r--src/ui/tools/freehand-base.cpp175
-rw-r--r--src/ui/tools/gradient-tool.cpp42
-rw-r--r--src/ui/tools/lpe-tool.cpp2
-rw-r--r--src/ui/tools/measure-tool.cpp1520
-rw-r--r--src/ui/tools/measure-tool.h81
-rw-r--r--src/ui/tools/mesh-tool.cpp67
-rw-r--r--src/ui/tools/mesh-tool.h2
-rw-r--r--src/ui/tools/node-tool.cpp6
-rw-r--r--src/ui/tools/pen-tool.cpp265
-rw-r--r--src/ui/tools/pen-tool.h104
-rw-r--r--src/ui/tools/pencil-tool.cpp20
-rw-r--r--src/ui/tools/select-tool.cpp96
-rw-r--r--src/ui/tools/select-tool.h8
-rw-r--r--src/ui/tools/spray-tool.cpp757
-rw-r--r--src/ui/tools/spray-tool.h29
-rw-r--r--src/ui/tools/tool-base.cpp11
-rw-r--r--src/ui/tools/tool-base.h7
-rw-r--r--src/ui/tools/tweak-tool.cpp2
-rw-r--r--src/ui/tools/zoom-tool.cpp2
-rw-r--r--src/ui/uxmanager.cpp9
-rw-r--r--src/ui/view/edit-widget-interface.h3
-rw-r--r--src/ui/widget/color-entry.h2
-rw-r--r--src/ui/widget/color-icc-selector.cpp7
-rw-r--r--src/ui/widget/font-variants.cpp70
-rw-r--r--src/ui/widget/preferences-widget.cpp1
-rw-r--r--src/ui/widget/preferences-widget.h1
-rw-r--r--src/ui/widget/unit-tracker.cpp10
-rw-r--r--src/ui/widget/unit-tracker.h1
-rw-r--r--src/unclump.cpp10
-rw-r--r--src/unclump.h1
-rw-r--r--src/uri-references.cpp167
-rw-r--r--src/uri.cpp2
-rw-r--r--src/uri.h2
-rw-r--r--src/util/CMakeLists.txt1
-rw-r--r--src/util/Makefile_insert1
-rw-r--r--src/util/glib-list-iterators.h237
-rw-r--r--src/util/units.cpp70
-rw-r--r--src/util/units.h8
-rw-r--r--src/vanishing-point.cpp119
-rw-r--r--src/vanishing-point.h8
-rw-r--r--src/verbs.cpp58
-rw-r--r--src/verbs.h20
-rw-r--r--src/widgets/CMakeLists.txt11
-rw-r--r--src/widgets/Makefile_insert10
-rw-r--r--src/widgets/arc-toolbar.cpp8
-rw-r--r--src/widgets/connector-toolbar.cpp14
-rw-r--r--src/widgets/desktop-widget.cpp80
-rw-r--r--src/widgets/desktop-widget.h4
-rw-r--r--src/widgets/eraser-toolbar.cpp82
-rw-r--r--src/widgets/fill-style.cpp12
-rw-r--r--src/widgets/gradient-selector.cpp21
-rw-r--r--src/widgets/gradient-toolbar.cpp69
-rw-r--r--src/widgets/gradient-vector.cpp11
-rw-r--r--src/widgets/measure-toolbar.cpp341
-rw-r--r--src/widgets/mesh-toolbar.cpp95
-rw-r--r--src/widgets/paint-selector.cpp10
-rw-r--r--src/widgets/pencil-toolbar.cpp129
-rw-r--r--src/widgets/rect-toolbar.cpp4
-rw-r--r--src/widgets/ruler.cpp344
-rw-r--r--src/widgets/select-toolbar.cpp159
-rw-r--r--src/widgets/sp-color-selector.cpp4
-rw-r--r--src/widgets/sp-color-selector.h4
-rw-r--r--src/widgets/sp-xmlview-attr-list.cpp2
-rw-r--r--src/widgets/spiral-toolbar.cpp4
-rw-r--r--src/widgets/spray-toolbar.cpp391
-rw-r--r--src/widgets/spray-toolbar.h2
-rw-r--r--src/widgets/star-toolbar.cpp24
-rw-r--r--src/widgets/stroke-style.cpp225
-rw-r--r--src/widgets/stroke-style.h11
-rw-r--r--src/widgets/text-toolbar.cpp270
-rw-r--r--src/widgets/toolbox.cpp96
-rw-r--r--src/widgets/tweak-toolbar.cpp26
-rw-r--r--src/xml/quote.cpp118
-rw-r--r--src/xml/rebase-hrefs.cpp6
-rw-r--r--src/xml/repr-io.cpp18
-rw-r--r--src/xml/repr-util.cpp1
475 files changed, 13838 insertions, 12387 deletions
diff --git a/src/2geom/CMakeLists.txt b/src/2geom/CMakeLists.txt
index eb7abb614..97b47b630 100644
--- a/src/2geom/CMakeLists.txt
+++ b/src/2geom/CMakeLists.txt
@@ -48,7 +48,6 @@ set(2geom_SRC
toposweep.cpp
transforms.cpp
utils.cpp
- viewbox.cpp
# -------
@@ -72,7 +71,6 @@ set(2geom_SRC
crossing.h
curve.h
curves.h
- d2-sbasis.h
d2.h
ellipse.h
elliptical-arc.h
diff --git a/src/2geom/Makefile_insert b/src/2geom/Makefile_insert
index e3c6836fd..b56942caa 100644
--- a/src/2geom/Makefile_insert
+++ b/src/2geom/Makefile_insert
@@ -120,8 +120,6 @@
2geom/transforms.h \
2geom/utils.cpp \
2geom/utils.h \
- 2geom/viewbox.cpp \
- 2geom/viewbox.h \
2geom/numeric/fitting-model.h \
2geom/numeric/fitting-tool.h \
2geom/numeric/linear_system.h \
diff --git a/src/2geom/angle.h b/src/2geom/angle.h
index af4442e88..f0caaba6b 100644
--- a/src/2geom/angle.h
+++ b/src/2geom/angle.h
@@ -383,10 +383,10 @@ private:
/** @brief Given an angle in degrees, return radians
* @relates Angle */
-inline Coord deg_to_rad(Coord deg) { return deg*M_PI/180.0;}
+inline Coord rad_from_deg(Coord deg) { return deg*M_PI/180.0;}
/** @brief Given an angle in radians, return degrees
* @relates Angle */
-inline Coord rad_to_deg(Coord rad) { return rad*180.0/M_PI;}
+inline Coord deg_from_rad(Coord rad) { return rad*180.0/M_PI;}
} // end namespace Geom
diff --git a/src/2geom/bezier-clipping.cpp b/src/2geom/bezier-clipping.cpp
index be8dd5a5f..03a6dfecd 100644
--- a/src/2geom/bezier-clipping.cpp
+++ b/src/2geom/bezier-clipping.cpp
@@ -788,7 +788,7 @@ void iterate<intersection_point_tag> (std::vector<Interval>& domsA,
#endif
dom = clip<intersection_point_tag>(*C1, *C2, precision);
- if (dom.isEmpty())
+ if (dom.empty())
{
#if VERBOSE
std::cerr << "dom: empty" << std::endl;
@@ -937,7 +937,7 @@ void iterate<collinear_normal_tag> (std::vector<Interval>& domsA,
#endif
dom = clip<collinear_normal_tag>(*C1, *C2, precision);
- if (dom.isEmpty()) {
+ if (dom.empty()) {
#if VERBOSE
std::cerr << "dom: empty" << std::endl;
#endif
diff --git a/src/2geom/bezier-curve.cpp b/src/2geom/bezier-curve.cpp
index 17221264b..866263047 100644
--- a/src/2geom/bezier-curve.cpp
+++ b/src/2geom/bezier-curve.cpp
@@ -115,6 +115,17 @@ BezierCurve::BezierCurve(std::vector<Point> const &pts)
}
}
+bool BezierCurve::isDegenerate() const
+{
+ for (unsigned d = 0; d < 2; ++d) {
+ Coord ic = inner[d][0];
+ for (unsigned i = 1; i < size(); ++i) {
+ if (inner[d][i] != ic) return false;
+ }
+ }
+ return true;
+}
+
Coord BezierCurve::length(Coord tolerance) const
{
switch (order())
@@ -169,6 +180,29 @@ BezierCurve::intersect(Curve const &other, Coord eps) const
return result;
}
+bool BezierCurve::isNear(Curve const &c, Coord precision) const
+{
+ if (this == &c) return true;
+
+ BezierCurve const *other = dynamic_cast<BezierCurve const *>(&c);
+ if (!other) return false;
+
+ if (!are_near(inner.at0(), other->inner.at0(), precision)) return false;
+ if (!are_near(inner.at1(), other->inner.at1(), precision)) return false;
+
+ if (size() == other->size()) {
+ for (unsigned i = 1; i < order(); ++i) {
+ if (!are_near(inner.point(i), other->inner.point(i), precision)) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ // TODO: comparison after degree elevation
+ return false;
+ }
+}
+
bool BezierCurve::operator==(Curve const &c) const
{
if (this == &c) return true;
@@ -281,6 +315,23 @@ std::vector<CurveIntersection> BezierCurveN<1>::intersect(Curve const &other, Co
}
template <>
+int BezierCurveN<1>::winding(Point const &p) const
+{
+ Point ip = inner.at0(), fp = inner.at1();
+ if (p[Y] == std::max(ip[Y], fp[Y])) return 0;
+
+ Point v = fp - ip;
+ assert(v[Y] != 0);
+ Coord t = (p[Y] - ip[Y]) / v[Y];
+ assert(t >= 0 && t <= 1);
+ Coord xcross = lerp(t, ip[X], fp[X]);
+ if (xcross > p[X]) {
+ return v[Y] > 0 ? 1 : -1;
+ }
+ return 0;
+}
+
+template <>
void BezierCurveN<1>::feed(PathSink &sink, bool moveto_initial) const
{
if (moveto_initial) {
@@ -308,7 +359,7 @@ void BezierCurveN<3>::feed(PathSink &sink, bool moveto_initial) const
}
-static Coord bezier_length_internal(std::vector<Point> &v1, Coord tolerance)
+static Coord bezier_length_internal(std::vector<Point> &v1, Coord tolerance, int level)
{
/* The Bezier length algorithm used in 2Geom utilizes a simple fact:
* the Bezier curve is longer than the distance between its endpoints
@@ -317,13 +368,15 @@ static Coord bezier_length_internal(std::vector<Point> &v1, Coord tolerance)
* error tolerance, we can be sure that the true value is no further than
* 0.5 * tolerance from their arithmetic mean. When it's larger, we recursively
* subdivide the Bezier curve into two parts and add their lengths.
+ *
+ * We cap the maximum number of subdivisions at 256, which corresponds to 8 levels.
*/
Coord lower = distance(v1.front(), v1.back());
Coord upper = 0.0;
for (size_t i = 0; i < v1.size() - 1; ++i) {
upper += distance(v1[i], v1[i+1]);
}
- if (upper - lower < 2*tolerance) {
+ if (upper - lower <= 2*tolerance || level >= 8) {
return (lower + upper) / 2;
}
@@ -381,7 +434,8 @@ static Coord bezier_length_internal(std::vector<Point> &v1, Coord tolerance)
v2[i] = v1[0];
}
- return bezier_length_internal(v1, 0.5*tolerance) + bezier_length_internal(v2, 0.5*tolerance);
+ return bezier_length_internal(v1, 0.5 * tolerance, level + 1) +
+ bezier_length_internal(v2, 0.5 * tolerance, level + 1);
}
/** @brief Compute the length of a bezier curve given by a vector of its control points
@@ -390,17 +444,17 @@ Coord bezier_length(std::vector<Point> const &points, Coord tolerance)
{
if (points.size() < 2) return 0.0;
std::vector<Point> v1 = points;
- return bezier_length_internal(v1, tolerance);
+ return bezier_length_internal(v1, tolerance, 0);
}
-/** @brief Compute the length of a quadratic bezier curve given by its control points
- * @relatesalso QuadraticBezier */
-Coord bezier_length(Point a0, Point a1, Point a2, Coord tolerance)
+static Coord bezier_length_internal(Point a0, Point a1, Point a2, Coord tolerance, int level)
{
Coord lower = distance(a0, a2);
Coord upper = distance(a0, a1) + distance(a1, a2);
- if (upper - lower < 2*tolerance) return (lower + upper)/2;
+ if (upper - lower <= 2*tolerance || level >= 8) {
+ return (lower + upper) / 2;
+ }
Point // Casteljau subdivision
// b0 = a0,
@@ -408,17 +462,25 @@ Coord bezier_length(Point a0, Point a1, Point a2, Coord tolerance)
b1 = 0.5*(a0 + a1),
c1 = 0.5*(a1 + a2),
b2 = 0.5*(b1 + c1); // == c2
- return bezier_length(a0, b1, b2, 0.5*tolerance) + bezier_length(b2, c1, a2, 0.5*tolerance);
+ return bezier_length_internal(a0, b1, b2, 0.5 * tolerance, level + 1) +
+ bezier_length_internal(b2, c1, a2, 0.5 * tolerance, level + 1);
}
-/** @brief Compute the length of a cubic bezier curve given by its control points
- * @relatesalso CubicBezier */
-Coord bezier_length(Point a0, Point a1, Point a2, Point a3, Coord tolerance)
+/** @brief Compute the length of a quadratic bezier curve given by its control points
+ * @relatesalso QuadraticBezier */
+Coord bezier_length(Point a0, Point a1, Point a2, Coord tolerance)
+{
+ return bezier_length_internal(a0, a1, a2, tolerance, 0);
+}
+
+static Coord bezier_length_internal(Point a0, Point a1, Point a2, Point a3, Coord tolerance, int level)
{
Coord lower = distance(a0, a3);
Coord upper = distance(a0, a1) + distance(a1, a2) + distance(a2, a3);
- if (upper - lower < 2*tolerance) return (lower + upper)/2;
+ if (upper - lower <= 2*tolerance || level >= 8) {
+ return (lower + upper) / 2;
+ }
Point // Casteljau subdivision
// b0 = a0,
@@ -429,7 +491,15 @@ Coord bezier_length(Point a0, Point a1, Point a2, Point a3, Coord tolerance)
b2 = 0.5*(b1 + t0),
c2 = 0.5*(t0 + c1),
b3 = 0.5*(b2 + c2); // == c3
- return bezier_length(a0, b1, b2, b3, 0.5*tolerance) + bezier_length(b3, c2, c1, a3, 0.5*tolerance);
+ return bezier_length_internal(a0, b1, b2, b3, 0.5 * tolerance, level + 1) +
+ bezier_length_internal(b3, c2, c1, a3, 0.5 * tolerance, level + 1);
+}
+
+/** @brief Compute the length of a cubic bezier curve given by its control points
+ * @relatesalso CubicBezier */
+Coord bezier_length(Point a0, Point a1, Point a2, Point a3, Coord tolerance)
+{
+ return bezier_length_internal(a0, a1, a2, a3, tolerance, 0);
}
} // end namespace Geom
diff --git a/src/2geom/bezier-curve.h b/src/2geom/bezier-curve.h
index 9ac4d7b4d..9416ba78c 100644
--- a/src/2geom/bezier-curve.h
+++ b/src/2geom/bezier-curve.h
@@ -104,7 +104,7 @@ public:
// implementation of virtual methods goes here
virtual Point initialPoint() const { return inner.at0(); }
virtual Point finalPoint() const { return inner.at1(); }
- virtual bool isDegenerate() const { return inner.isConstant(0); }
+ virtual bool isDegenerate() const;
virtual bool isLineSegment() const { return size() == 2; }
virtual void setInitial(Point const &v) { setPoint(0, v); }
virtual void setFinal(Point const &v) { setPoint(order(), v); }
@@ -166,6 +166,7 @@ public:
}
virtual Coord valueAt(Coord t, Dim2 d) const { return inner[d].valueAt(t); }
virtual D2<SBasis> toSBasis() const {return inner.toSBasis(); }
+ virtual bool isNear(Curve const &c, Coord precision) const;
virtual bool operator==(Curve const &c) const;
virtual void feed(PathSink &sink, bool) const;
};
@@ -244,6 +245,10 @@ public:
BezierCurveN(sx.second, sy.second));
}
+ virtual bool isDegenerate() const {
+ return BezierCurve::isDegenerate();
+ }
+
virtual bool isLineSegment() const {
return size() == 2;
}
@@ -274,6 +279,9 @@ public:
// call super. this is implemented only to allow specializations
return BezierCurve::intersect(other, eps);
}
+ virtual int winding(Point const &p) const {
+ return Curve::winding(p);
+ }
virtual void feed(PathSink &sink, bool moveto_initial) const {
// call super. this is implemented only to allow specializations
BezierCurve::feed(sink, moveto_initial);
@@ -304,10 +312,14 @@ Curve *BezierCurveN<degree>::derivative() const {
}
// optimized specializations
+template <> inline bool BezierCurveN<1>::isDegenerate() const {
+ return inner[X][0] == inner[X][1] && inner[Y][0] == inner[Y][1];
+}
template <> inline bool BezierCurveN<1>::isLineSegment() const { return true; }
template <> Curve *BezierCurveN<1>::derivative() const;
template <> Coord BezierCurveN<1>::nearestTime(Point const &, Coord, Coord) const;
template <> std::vector<CurveIntersection> BezierCurveN<1>::intersect(Curve const &, Coord) const;
+template <> int BezierCurveN<1>::winding(Point const &) const;
template <> void BezierCurveN<1>::feed(PathSink &sink, bool moveto_initial) const;
template <> void BezierCurveN<2>::feed(PathSink &sink, bool moveto_initial) const;
template <> void BezierCurveN<3>::feed(PathSink &sink, bool moveto_initial) const;
diff --git a/src/2geom/circle.cpp b/src/2geom/circle.cpp
index 553981a72..934a8d3ab 100644
--- a/src/2geom/circle.cpp
+++ b/src/2geom/circle.cpp
@@ -144,7 +144,7 @@ bool Circle::contains(Circle const &other) const
bool Circle::intersects(Line const &l) const
{
// http://mathworld.wolfram.com/Circle-LineIntersection.html
- Coord dr = l.versor().length();
+ Coord dr = l.vector().length();
Coord r = _radius;
Coord D = cross(l.initialPoint(), l.finalPoint());
Coord delta = r*r * dr*dr - D*D;
@@ -163,9 +163,9 @@ bool Circle::intersects(Circle const &other) const
std::vector<ShapeIntersection> Circle::intersect(Line const &l) const
{
// http://mathworld.wolfram.com/Circle-LineIntersection.html
- Coord dr = l.versor().length();
- Coord dx = l.versor().x();
- Coord dy = l.versor().y();
+ Coord dr = l.vector().length();
+ Coord dx = l.vector().x();
+ Coord dy = l.vector().y();
Coord D = cross(l.initialPoint() - _center, l.finalPoint() - _center);
Coord delta = _radius*_radius * dr*dr - D*D;
diff --git a/src/2geom/conicsec.cpp b/src/2geom/conicsec.cpp
index 089db71a4..2d396ba30 100644
--- a/src/2geom/conicsec.cpp
+++ b/src/2geom/conicsec.cpp
@@ -114,8 +114,8 @@ double RatQuad::lambda() const {
RatQuad RatQuad::fromPointsTangents(Point P0, Point dP0,
Point P,
Point P2, Point dP2) {
- Line Line0 = Line::from_origin_and_versor(P0, dP0);
- Line Line2 = Line::from_origin_and_versor(P2, dP2);
+ Line Line0 = Line::from_origin_and_vector(P0, dP0);
+ Line Line2 = Line::from_origin_and_vector(P2, dP2);
try {
OptCrossing oc = intersection(Line0, Line2);
if(!oc) // what to do?
@@ -276,8 +276,8 @@ std::vector<Point> decompose_degenerate(xAx const & C1, xAx const & C2, xAx cons
n1 = Point(b-d, 1);
}
- Line L0 = Line::from_origin_and_versor(B0, rot90(n0));
- Line L1 = Line::from_origin_and_versor(B0, rot90(n1));
+ Line L0 = Line::from_origin_and_vector(B0, rot90(n0));
+ Line L1 = Line::from_origin_and_vector(B0, rot90(n1));
std::vector<double> rts = C1.roots(L0);
for(unsigned i = 0; i < rts.size(); i++) {
@@ -327,12 +327,12 @@ std::vector<Point> decompose_degenerate(xAx const & C1, xAx const & C2, xAx cons
*/
assert(L2sq(g) != 0);
- Line Lx = Line::from_origin_and_versor(trial_pt, g); // a line along the gradient
+ Line Lx = Line::from_origin_and_vector(trial_pt, g); // a line along the gradient
std::vector<double> rts = xC0.roots(Lx);
for(unsigned i = 0; i < rts.size(); i++) {
Point P0 = Lx.pointAt(rts[i]);
//std::cout << P0 << "\n";
- Line L = Line::from_origin_and_versor(P0, rot90(g));
+ Line L = Line::from_origin_and_vector(P0, rot90(g));
std::vector<double> cnrts;
// It's very likely that at least one of the conics is degenerate, this will hopefully pick the more generate of the two.
if(fabs(C1.hessian().det()) > fabs(C2.hessian().det()))
@@ -515,7 +515,7 @@ xAx xAx::operator*(double const &b) const {
if(L2sq(dA) <= 1e-10) { // perhaps a single point?
return boost::optional<RatQuad> ();
}
- LineSegment ls = intersection(Line::from_origin_and_versor(A, dA), bnd);
+ LineSegment ls = intersection(Line::from_origin_and_vector(A, dA), bnd);
return RatQuad::fromPointsTangents(A, dA, ls.pointAt(0.5), ls[1], dA);
}
else if(crs.size() >= 2 && crs.size() < 4) {
diff --git a/src/2geom/coord.cpp b/src/2geom/coord.cpp
index 8b5e28586..8c7485883 100644
--- a/src/2geom/coord.cpp
+++ b/src/2geom/coord.cpp
@@ -111,12 +111,6 @@ namespace Geom {
namespace {
-inline int StrLength(const char* string) {
- size_t length = strlen(string);
- ASSERT(length == static_cast<size_t>(static_cast<int>(length)));
- return static_cast<int>(length);
-}
-
template <typename T>
class Vector {
public:
@@ -1733,8 +1727,6 @@ enum FastDtoaMode {
FAST_DTOA_PRECISION
};
-static const int kFastDtoaMaximalLength = 17;
-
bool FastDtoa(double d,
FastDtoaMode mode,
int requested_digits,
@@ -2350,7 +2342,6 @@ bool FastFixedDtoa(double v,
return true;
}
-static const int kMaxExactDoubleIntegerDecimalDigits = 15;
static const int kMaxUint64DecimalDigits = 19;
static const int kMaxDecimalPower = 309;
diff --git a/src/2geom/crossing.h b/src/2geom/crossing.h
index 425fa58f5..0f007b192 100644
--- a/src/2geom/crossing.h
+++ b/src/2geom/crossing.h
@@ -119,7 +119,7 @@ struct CrossingOrder {
(ix == b.a ? b.ta : b.tb);
else
return (ix == a.a ? a.ta : a.tb) >
- (ix == a.a ? a.ta : a.tb);
+ (ix == b.a ? b.ta : b.tb);
}
};
diff --git a/src/2geom/curve.cpp b/src/2geom/curve.cpp
index b45228514..387a9180b 100644
--- a/src/2geom/curve.cpp
+++ b/src/2geom/curve.cpp
@@ -69,14 +69,14 @@ int Curve::winding(Point const &p) const
// skip endpoint roots when they are local maxima on the Y axis
// this follows the convention used in other winding routines,
// i.e. that the bottommost coordinate is not part of the shape
- bool ingore_0 = unitTangentAt(0)[Y] <= 0;
+ bool ignore_0 = unitTangentAt(0)[Y] <= 0;
bool ignore_1 = unitTangentAt(1)[Y] >= 0;
int wind = 0;
for (std::size_t i = 0; i < ts.size(); ++i) {
Coord t = ts[i];
//std::cout << t << std::endl;
- if ((t == 0 && ingore_0) || (t == 1 && ignore_1)) continue;
+ if ((t == 0 && ignore_0) || (t == 1 && ignore_1)) continue;
if (valueAt(t, X) > p[X]) { // root is ray intersection
Point tangent = unitTangentAt(t);
if (tangent[Y] > 0) {
diff --git a/src/2geom/curve.h b/src/2geom/curve.h
index abbdb1100..41db9ca8a 100644
--- a/src/2geom/curve.h
+++ b/src/2geom/curve.h
@@ -333,6 +333,9 @@ public:
* @return True if the curves are identical, false otherwise */
virtual bool operator==(Curve const &c) const = 0;
+ /** @brief Test whether two curves are approximately the same. */
+ virtual bool isNear(Curve const &c, Coord precision) const = 0;
+
/** @brief Feed the curve to a PathSink */
virtual void feed(PathSink &sink, bool moveto_initial) const;
/// @}
diff --git a/src/2geom/d2-sbasis.cpp b/src/2geom/d2-sbasis.cpp
index ebec16fdd..07eccce76 100644
--- a/src/2geom/d2-sbasis.cpp
+++ b/src/2geom/d2-sbasis.cpp
@@ -1,7 +1,41 @@
+/**
+ * \file
+ * \brief Some two-dimensional SBasis operations
+ *//*
+ * Authors:
+ * MenTaLguy <mental@rydia.net>
+ * Jean-François Barraud <jf.barraud@gmail.com>
+ * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl>
+ *
+ * Copyright 2007-2012 Authors
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it either under the terms of the GNU Lesser General Public
+ * License version 2.1 as published by the Free Software Foundation
+ * (the "LGPL") or, at your option, under the terms of the Mozilla
+ * Public License Version 1.1 (the "MPL"). If you do not alter this
+ * notice, a recipient may use your version of this file under either
+ * the MPL or the LGPL.
+ *
+ * You should have received a copy of the LGPL along with this library
+ * in the file COPYING-LGPL-2.1; if not, output to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * You should have received a copy of the MPL along with this library
+ * in the file COPYING-MPL-1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
+ * OF ANY KIND, either express or implied. See the LGPL or the MPL for
+ * the specific language governing rights and limitations.
+ *
+ */
+
#include <2geom/d2.h>
-/* One would think that we would include d2-sbasis.h, however,
- * you cannot actually include it in anything - only d2 may import it.
- * This is due to the trickinesses of template submatching. */
+#include <2geom/piecewise.h>
namespace Geom {
@@ -147,12 +181,12 @@ Piecewise<D2<SBasis> > force_continuity(Piecewise<D2<SBasis> > const &f, double
SBasis &prev_sb=result.segs[prev][dim];
SBasis &cur_sb =result.segs[cur][dim];
Coord const c=pt0[dim];
- if (prev_sb.empty()) {
+ if (prev_sb.isZero(0)) {
prev_sb = SBasis(Linear(0.0, c));
} else {
prev_sb[0][1] = c;
}
- if (cur_sb.empty()) {
+ if (cur_sb.isZero(0)) {
cur_sb = SBasis(Linear(c, 0.0));
} else {
cur_sb[0][0] = c;
@@ -198,30 +232,22 @@ Point unitTangentAt(D2<SBasis> const & a, Coord t, unsigned n)
return Point (0,0);
}
-static void set_first_point(Piecewise<D2<SBasis> > &f, Point a){
+static void set_first_point(Piecewise<D2<SBasis> > &f, Point const &a){
if ( f.empty() ){
f.concat(Piecewise<D2<SBasis> >(D2<SBasis>(SBasis(Linear(a[X])), SBasis(Linear(a[Y])))));
return;
}
for (unsigned dim=0; dim<2; dim++){
- if (f.segs.front()[dim].size() == 0){
- f.segs.front()[dim] = SBasis(Linear(a[dim],0));
- }else{
- f.segs.front()[dim][0][0] = a[dim];
- }
+ f.segs.front()[dim][0][0] = a[dim];
}
}
-static void set_last_point(Piecewise<D2<SBasis> > &f, Point a){
+static void set_last_point(Piecewise<D2<SBasis> > &f, Point const &a){
if ( f.empty() ){
f.concat(Piecewise<D2<SBasis> >(D2<SBasis>(SBasis(Linear(a[X])), SBasis(Linear(a[Y])))));
return;
}
for (unsigned dim=0; dim<2; dim++){
- if (f.segs.back()[dim].size() == 0){
- f.segs.back()[dim] = SBasis(Linear(0,a[dim]));
- }else{
- f.segs.back()[dim][0][1] = a[dim];
- }
+ f.segs.back()[dim][0][1] = a[dim];
}
}
diff --git a/src/2geom/d2-sbasis.h b/src/2geom/d2-sbasis.h
deleted file mode 100644
index a0769b314..000000000
--- a/src/2geom/d2-sbasis.h
+++ /dev/null
@@ -1,165 +0,0 @@
-/**
- * \file
- * \brief Do not include this file
- *
- * We don't actually want anyone to
- * include this, other than D2.h.
- *//*
- * Authors:
- * ? <?@?.?>
- *
- * Copyright ?-? authors
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- *
- */
-
-#ifdef LIB2GEOM_SEEN_D2_H /*This is intentional: we don't actually want anyone to
- include this, other than D2.h. If somone else tries, D2
- won't be defined. If it is, this will already be included. */
-#ifndef LIB2GEOM_SEEN_D2_SBASIS_H
-#define LIB2GEOM_SEEN_D2_SBASIS_H
-
-#include <2geom/sbasis.h>
-#include <2geom/sbasis-2d.h>
-#include <2geom/piecewise.h>
-#include <2geom/affine.h>
-
-//TODO: implement intersect
-
-namespace Geom {
-
-inline D2<SBasis> compose(D2<SBasis> const & a, SBasis const & b) {
- return D2<SBasis>(compose(a[X], b), compose(a[Y], b));
-}
-
-SBasis L2(D2<SBasis> const & a, unsigned k);
-double L2(D2<double> const & a);
-
-D2<SBasis> multiply(Linear const & a, D2<SBasis> const & b);
-inline D2<SBasis> operator*(Linear const & a, D2<SBasis> const & b) { return multiply(a, b); }
-D2<SBasis> multiply(SBasis const & a, D2<SBasis> const & b);
-inline D2<SBasis> operator*(SBasis const & a, D2<SBasis> const & b) { return multiply(a, b); }
-D2<SBasis> truncate(D2<SBasis> const & a, unsigned terms);
-
-unsigned sbasis_size(D2<SBasis> const & a);
-double tail_error(D2<SBasis> const & a, unsigned tail);
-
-//Piecewise<D2<SBasis> > specific decls:
-
-Piecewise<D2<SBasis> > sectionize(D2<Piecewise<SBasis> > const &a);
-D2<Piecewise<SBasis> > make_cuts_independent(Piecewise<D2<SBasis> > const &a);
-Piecewise<D2<SBasis> > rot90(Piecewise<D2<SBasis> > const &a);
-Piecewise<SBasis> dot(Piecewise<D2<SBasis> > const &a, Piecewise<D2<SBasis> > const &b);
-Piecewise<SBasis> dot(Piecewise<D2<SBasis> > const &a, Point const &b);
-Piecewise<SBasis> cross(Piecewise<D2<SBasis> > const &a, Piecewise<D2<SBasis> > const &b);
-
-Piecewise<D2<SBasis> > operator*(Piecewise<D2<SBasis> > const &a, Affine const &m);
-
-Piecewise<D2<SBasis> > force_continuity(Piecewise<D2<SBasis> > const &f, double tol=0, bool closed=false);
-
-std::vector<Piecewise<D2<SBasis> > > fuse_nearby_ends(std::vector<Piecewise<D2<SBasis> > > const &f, double tol=0);
-
-std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > split_at_discontinuities (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwsbin, double tol = .0001);
-
-/**
-* note that -unitTangentAt(reverse(a),0.) == unitTangentAt(a,1.) but the former is more reliable (sometimes the sign is wrong for the latter)
-*/
-Point unitTangentAt(D2<SBasis> const & a, Coord t, unsigned n = 3);
-
-class CoordIterator
-: public std::iterator<std::input_iterator_tag, SBasis const>
-{
-public:
- CoordIterator(std::vector<D2<SBasis> >::const_iterator const &iter, unsigned d) : impl_(iter), ix_(d) {}
-
- inline bool operator==(CoordIterator const &other) { return other.impl_ == impl_; }
- inline bool operator!=(CoordIterator const &other) { return other.impl_ != impl_; }
-
- inline SBasis operator*() const {
- return (*impl_)[ix_];
- }
-
- inline CoordIterator &operator++() {
- ++impl_;
- return *this;
- }
- inline CoordIterator operator++(int) {
- CoordIterator old=*this;
- ++(*this);
- return old;
- }
-
-private:
- std::vector<D2<SBasis> >::const_iterator impl_;
- unsigned ix_;
-};
-
-inline CoordIterator iterateCoord(Piecewise<D2<SBasis> > const &a, unsigned d) {
- return CoordIterator(a.segs.begin(), d);
-}
-
-//bounds specializations with order
-inline OptRect bounds_fast(D2<SBasis> const & s, unsigned order=0) {
- OptRect retval;
- OptInterval xint = bounds_fast(s[X], order);
- if (xint) {
- OptInterval yint = bounds_fast(s[Y], order);
- if (yint) {
- retval = Rect(*xint, *yint);
- }
- }
- return retval;
-}
-inline OptRect bounds_local(D2<SBasis> const & s, OptInterval i, unsigned order=0) {
- OptRect retval;
- OptInterval xint = bounds_local(s[X], i, order);
- OptInterval yint = bounds_local(s[Y], i, order);
- if (xint && yint) {
- retval = Rect(*xint, *yint);
- }
- return retval;
-}
-
-std::vector<Interval> level_set( D2<SBasis> const &f, Rect region);
-std::vector<Interval> level_set( D2<SBasis> const &f, Point p, double tol);
-std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Rect> regions);
-std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Point> pts, double tol);
-
-}
-
-#endif // LIB2GEOM_SEEN_D2_SBASIS_H
-#endif // LIB2GEOM_SEEN_D2_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/2geom/d2.h b/src/2geom/d2.h
index dca6fa614..cd67ec65b 100644
--- a/src/2geom/d2.h
+++ b/src/2geom/d2.h
@@ -1,8 +1,12 @@
/**
* \file
- * \brief Lifts one dimensional objects into 2d
+ * \brief Lifts one dimensional objects into 2D
*//*
- * Copyright 2007 Michael Sloan <mgsloan@gmail.com>
+ * Authors:
+ * Michael Sloan <mgsloan@gmail.com>
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * Copyright 2007-2015 Authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -461,12 +465,6 @@ inline std::ostream &operator<< (std::ostream &out_file, const Geom::D2<T> &in_d
return out_file;
}
-} //end namespace Geom
-
-#include <2geom/d2-sbasis.h>
-
-namespace Geom {
-
//Some D2 Fragment implementation which requires rect:
template <typename T>
OptRect bounds_fast(const D2<T> &a) {
@@ -484,6 +482,73 @@ OptRect bounds_local(const D2<T> &a, const OptInterval &t) {
return OptRect(bounds_local(a[X], t), bounds_local(a[Y], t));
}
+
+
+// SBasis-specific declarations
+
+inline D2<SBasis> compose(D2<SBasis> const & a, SBasis const & b) {
+ return D2<SBasis>(compose(a[X], b), compose(a[Y], b));
+}
+
+SBasis L2(D2<SBasis> const & a, unsigned k);
+double L2(D2<double> const & a);
+
+D2<SBasis> multiply(Linear const & a, D2<SBasis> const & b);
+inline D2<SBasis> operator*(Linear const & a, D2<SBasis> const & b) { return multiply(a, b); }
+D2<SBasis> multiply(SBasis const & a, D2<SBasis> const & b);
+inline D2<SBasis> operator*(SBasis const & a, D2<SBasis> const & b) { return multiply(a, b); }
+D2<SBasis> truncate(D2<SBasis> const & a, unsigned terms);
+
+unsigned sbasis_size(D2<SBasis> const & a);
+double tail_error(D2<SBasis> const & a, unsigned tail);
+
+//Piecewise<D2<SBasis> > specific declarations
+
+Piecewise<D2<SBasis> > sectionize(D2<Piecewise<SBasis> > const &a);
+D2<Piecewise<SBasis> > make_cuts_independent(Piecewise<D2<SBasis> > const &a);
+Piecewise<D2<SBasis> > rot90(Piecewise<D2<SBasis> > const &a);
+Piecewise<SBasis> dot(Piecewise<D2<SBasis> > const &a, Piecewise<D2<SBasis> > const &b);
+Piecewise<SBasis> dot(Piecewise<D2<SBasis> > const &a, Point const &b);
+Piecewise<SBasis> cross(Piecewise<D2<SBasis> > const &a, Piecewise<D2<SBasis> > const &b);
+
+Piecewise<D2<SBasis> > operator*(Piecewise<D2<SBasis> > const &a, Affine const &m);
+
+Piecewise<D2<SBasis> > force_continuity(Piecewise<D2<SBasis> > const &f, double tol=0, bool closed=false);
+
+std::vector<Piecewise<D2<SBasis> > > fuse_nearby_ends(std::vector<Piecewise<D2<SBasis> > > const &f, double tol=0);
+
+std::vector<Geom::Piecewise<Geom::D2<Geom::SBasis> > > split_at_discontinuities (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwsbin, double tol = .0001);
+
+Point unitTangentAt(D2<SBasis> const & a, Coord t, unsigned n = 3);
+
+//bounds specializations with order
+inline OptRect bounds_fast(D2<SBasis> const & s, unsigned order=0) {
+ OptRect retval;
+ OptInterval xint = bounds_fast(s[X], order);
+ if (xint) {
+ OptInterval yint = bounds_fast(s[Y], order);
+ if (yint) {
+ retval = Rect(*xint, *yint);
+ }
+ }
+ return retval;
+}
+inline OptRect bounds_local(D2<SBasis> const & s, OptInterval i, unsigned order=0) {
+ OptRect retval;
+ OptInterval xint = bounds_local(s[X], i, order);
+ OptInterval yint = bounds_local(s[Y], i, order);
+ if (xint && yint) {
+ retval = Rect(*xint, *yint);
+ }
+ return retval;
+}
+
+std::vector<Interval> level_set( D2<SBasis> const &f, Rect region);
+std::vector<Interval> level_set( D2<SBasis> const &f, Point p, double tol);
+std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Rect> regions);
+std::vector<std::vector<Interval> > level_sets( D2<SBasis> const &f, std::vector<Point> pts, double tol);
+
+
} // end namespace Geom
#endif
diff --git a/src/2geom/ellipse.cpp b/src/2geom/ellipse.cpp
index 4b5ad9762..f4704460f 100644
--- a/src/2geom/ellipse.cpp
+++ b/src/2geom/ellipse.cpp
@@ -142,6 +142,24 @@ LineSegment Ellipse::semiaxis(Dim2 d, int sign) const
return ls;
}
+Rect Ellipse::boundsExact() const
+{
+ Angle extremes[2][2];
+ double sinrot, cosrot;
+ sincos(_angle, sinrot, cosrot);
+
+ extremes[X][0] = std::atan2( -ray(Y) * sinrot, ray(X) * cosrot );
+ extremes[X][1] = extremes[X][0] + M_PI;
+ extremes[Y][0] = std::atan2( ray(Y) * cosrot, ray(X) * sinrot );
+ extremes[Y][1] = extremes[Y][0] + M_PI;
+
+ Rect result;
+ for (unsigned d = 0; d < 2; ++d) {
+ result[d] = Interval(valueAt(extremes[d][0], d ? Y : X),
+ valueAt(extremes[d][1], d ? Y : X));
+ }
+ return result;
+}
std::vector<double> Ellipse::coefficients() const
{
@@ -396,45 +414,39 @@ std::vector<ShapeIntersection> Ellipse::intersect(Line const &line) const
coefficients(A, B, C, D, E, F);
Affine iuct = inverseUnitCircleTransform();
- if (line.isHorizontal()) {
- // substitute y into the ellipse equation and solve
- Coord y = line.initialPoint()[Y];
- std::vector<Coord> xs = solve_quadratic(A, B*y + D, C*y*y + E*y + F);
- for (unsigned i = 0; i < xs.size(); ++i) {
- Point p(xs[i], y);
- result.push_back(ShapeIntersection(atan2(p * iuct), line.timeAt(p), p));
- }
- return result;
- }
- if (line.isVertical()) {
- // substitute y into the ellipse equation and solve
- Coord x = line.initialPoint()[X];
- std::vector<Coord> ys = solve_quadratic(C, B*x + E, A*x*x + D*x + F);
- for (unsigned i = 0; i < ys.size(); ++i) {
- Point p(x, ys[i]);
- result.push_back(ShapeIntersection(atan2(p * iuct), line.timeAt(p), p));
- }
- return result;
- }
-
// generic case
Coord a, b, c;
line.coefficients(a, b, c);
+ Point lv = line.vector();
- // y = -a/b x - C/B
- // TODO: when is it better to substitute X?
- Coord q = -a/b;
- Coord r = -c/b;
+ if (fabs(lv[X]) > fabs(lv[Y])) {
+ // y = -a/b x - c/b
+ Coord q = -a/b;
+ Coord r = -c/b;
- // substitute that into the ellipse equation, making it quadratic in x
- Coord I = A + B*q + C*q*q; // x^2 terms
- Coord J = B*r + C*2*q*r + D + E*q; // x^1 terms
- Coord K = C*r*r + E*r + F; // x^0 terms
- std::vector<Coord> xs = solve_quadratic(I, J, K);
+ // substitute that into the ellipse equation, making it quadratic in x
+ Coord I = A + B*q + C*q*q; // x^2 terms
+ Coord J = B*r + C*2*q*r + D + E*q; // x^1 terms
+ Coord K = C*r*r + E*r + F; // x^0 terms
+ std::vector<Coord> xs = solve_quadratic(I, J, K);
- for (unsigned i = 0; i < xs.size(); ++i) {
- Point p(xs[i], q*xs[i] + r);
- result.push_back(ShapeIntersection(atan2(p * iuct), line.timeAt(p), p));
+ for (unsigned i = 0; i < xs.size(); ++i) {
+ Point p(xs[i], q*xs[i] + r);
+ result.push_back(ShapeIntersection(atan2(p * iuct), line.timeAt(p), p));
+ }
+ } else {
+ Coord q = -b/a;
+ Coord r = -c/a;
+
+ Coord I = A*q*q + B*q + C;
+ Coord J = A*2*q*r + B*r + D*q + E;
+ Coord K = A*r*r + D*r + F;
+ std::vector<Coord> xs = solve_quadratic(I, J, K);
+
+ for (unsigned i = 0; i < xs.size(); ++i) {
+ Point p(q*xs[i] + r, xs[i]);
+ result.push_back(ShapeIntersection(atan2(p * iuct), line.timeAt(p), p));
+ }
}
return result;
}
diff --git a/src/2geom/ellipse.h b/src/2geom/ellipse.h
index 4b1701cce..f6089c944 100644
--- a/src/2geom/ellipse.h
+++ b/src/2geom/ellipse.h
@@ -171,6 +171,9 @@ public:
LineSegment axis(Dim2 d) const;
LineSegment semiaxis(Dim2 d, int sign = 1) const;
+ /// Get the tight-fitting bounding box of the ellipse.
+ Rect boundsExact() const;
+
/// Get the coefficients of the ellipse's implicit equation.
std::vector<double> coefficients() const;
void coefficients(Coord &A, Coord &B, Coord &C, Coord &D, Coord &E, Coord &F) const;
diff --git a/src/2geom/elliptical-arc.cpp b/src/2geom/elliptical-arc.cpp
index 25a78b4ad..a0e379a21 100644
--- a/src/2geom/elliptical-arc.cpp
+++ b/src/2geom/elliptical-arc.cpp
@@ -92,47 +92,58 @@ namespace Geom
* @ingroup Curves
*/
+
+/** @brief Compute bounds of an elliptical arc.
+ * The bounds computation works as follows. The extreme X and Y points
+ * are either the endpoints or local minima / maxima of the ellipse.
+ * We already have endpoints, and we can find the local extremes
+ * by computing a partial derivative with respect to the angle
+ * and equating that to zero:
+ * \f{align*}{
+ x &= r_x \cos \varphi \cos \theta - r_y \sin \varphi \sin \theta + c_x \\
+ \frac{\partial x}{\partial \theta} &= -r_x \cos \varphi \sin \theta - r_y \sin \varphi \cos \theta = 0 \\
+ \frac{\sin \theta}{\cos \theta} &= \tan\theta = -\frac{r_y \sin \varphi}{r_x \cos \varphi} \\
+ \theta &= \tan^{-1} \frac{-r_y \sin \varphi}{r_x \cos \varphi}
+ \f}
+ * The local extremes correspond to two angles separated by \f$\pi\f$.
+ * Once we compute these angles, we check whether they belong to the arc,
+ * and if they do, we evaluate the ellipse at these angles.
+ * The bounding box of the arc is equal to the bounding box of the endpoints
+ * and the local extrema that belong to the arc.
+ */
Rect EllipticalArc::boundsExact() const
{
if (isChord()) {
return chord().boundsExact();
}
- using std::swap;
+ Coord coord[2][4] = {
+ { _initial_point[X], _final_point[X], 0, 0 },
+ { _initial_point[Y], _final_point[Y], 0, 0 }
+ };
+ int ncoord[2] = { 2, 2 };
- // TODO: simplify / document what is going on here.
- double extremes[4];
+ Angle extremes[2][2];
double sinrot, cosrot;
sincos(rotationAngle(), sinrot, cosrot);
- extremes[0] = std::atan2( -ray(Y) * sinrot, ray(X) * cosrot );
- extremes[1] = extremes[0] + M_PI;
- if ( extremes[0] < 0 ) extremes[0] += 2*M_PI;
- extremes[2] = std::atan2( ray(Y) * cosrot, ray(X) * sinrot );
- extremes[3] = extremes[2] + M_PI;
- if ( extremes[2] < 0 ) extremes[2] += 2*M_PI;
-
-
- double arc_extremes[4];
- arc_extremes[0] = initialPoint()[X];
- arc_extremes[1] = finalPoint()[X];
- if ( arc_extremes[0] < arc_extremes[1] )
- swap(arc_extremes[0], arc_extremes[1]);
- arc_extremes[2] = initialPoint()[Y];
- arc_extremes[3] = finalPoint()[Y];
- if ( arc_extremes[2] < arc_extremes[3] )
- swap(arc_extremes[2], arc_extremes[3]);
-
- if ( !are_near(initialPoint(), finalPoint()) ) {
- for (unsigned i = 0; i < 4; ++i) {
- if (containsAngle(extremes[i])) {
- arc_extremes[i] = valueAtAngle(extremes[i], (i >> 1) ? Y : X);
+ extremes[X][0] = std::atan2( -ray(Y) * sinrot, ray(X) * cosrot );
+ extremes[X][1] = extremes[X][0] + M_PI;
+ extremes[Y][0] = std::atan2( ray(Y) * cosrot, ray(X) * sinrot );
+ extremes[Y][1] = extremes[Y][0] + M_PI;
+
+ for (unsigned d = 0; d < 2; ++d) {
+ for (unsigned i = 0; i < 2; ++i) {
+ if (containsAngle(extremes[d][i])) {
+ coord[d][ncoord[d]++] = valueAtAngle(extremes[d][i], d ? Y : X);
}
}
}
- return Rect( Point(arc_extremes[1], arc_extremes[3]) ,
- Point(arc_extremes[0], arc_extremes[2]) );
+ Interval xival = Interval::from_range(coord[X], coord[X] + ncoord[X]);
+ Interval yival = Interval::from_range(coord[Y], coord[Y] + ncoord[Y]);
+ Rect result(xival, yival);
+ return result;
}
@@ -149,116 +160,14 @@ Coord EllipticalArc::valueAtAngle(Coord t, Dim2 d) const
std::vector<Coord> EllipticalArc::roots(Coord v, Dim2 d) const
{
- if (isChord()) {
- return chord().roots(v, d);
- }
-
std::vector<Coord> sol;
- Interval unit_interval(0, 1);
- if ( are_near(ray(X), 0) && are_near(ray(Y), 0) ) {
- if ( center(d) == v )
- sol.push_back(0);
+ if (isChord()) {
+ sol = chord().roots(v, d);
return sol;
}
- static const char* msg[2][2] =
- {
- { "d == X; ray(X) == 0; "
- "s = (v - center(X)) / ( -ray(Y) * std::sin(_rot_angle) ); "
- "s should be contained in [-1,1]",
- "d == X; ray(Y) == 0; "
- "s = (v - center(X)) / ( ray(X) * std::cos(_rot_angle) ); "
- "s should be contained in [-1,1]"
- },
- { "d == Y; ray(X) == 0; "
- "s = (v - center(X)) / ( ray(Y) * std::cos(_rot_angle) ); "
- "s should be contained in [-1,1]",
- "d == Y; ray(Y) == 0; "
- "s = (v - center(X)) / ( ray(X) * std::sin(_rot_angle) ); "
- "s should be contained in [-1,1]"
- },
- };
-
- for ( unsigned int dim = 0; dim < 2; ++dim )
- {
- if (ray((Dim2) dim) == 0)
- {
- if ( initialPoint()[d] == v && finalPoint()[d] == v )
- {
- THROW_INFINITESOLUTIONS(0);
- }
- if ( (initialPoint()[d] < finalPoint()[d])
- && (initialPoint()[d] > v || finalPoint()[d] < v) )
- {
- return sol;
- }
- if ( (initialPoint()[d] > finalPoint()[d])
- && (finalPoint()[d] > v || initialPoint()[d] < v) )
- {
- return sol;
- }
- double ray_prj = 0.0;
- switch(d)
- {
- case X:
- switch(dim)
- {
- case X: ray_prj = -ray(Y) * std::sin(rotationAngle());
- break;
- case Y: ray_prj = ray(X) * std::cos(rotationAngle());
- break;
- }
- break;
- case Y:
- switch(dim)
- {
- case X: ray_prj = ray(Y) * std::cos(rotationAngle());
- break;
- case Y: ray_prj = ray(X) * std::sin(rotationAngle());
- break;
- }
- break;
- }
-
- double s = (v - center(d)) / ray_prj;
- if ( s < -1 || s > 1 )
- {
- THROW_LOGICALERROR(msg[d][dim]);
- }
- switch(dim)
- {
- case X:
- s = std::asin(s); // return a value in [-PI/2,PI/2]
- if ( logical_xor( sweep(), are_near(initialAngle(), M_PI/2) ) )
- {
- if ( s < 0 ) s += 2*M_PI;
- }
- else
- {
- s = M_PI - s;
- if (!(s < 2*M_PI) ) s -= 2*M_PI;
- }
- break;
- case Y:
- s = std::acos(s); // return a value in [0,PI]
- if ( logical_xor( sweep(), are_near(initialAngle(), 0) ) )
- {
- s = 2*M_PI - s;
- if ( !(s < 2*M_PI) ) s -= 2*M_PI;
- }
- break;
- }
-
- //std::cerr << "s = " << rad_to_deg(s);
- s = timeAtAngle(s);
- //std::cerr << " -> t: " << s << std::endl;
- if (unit_interval.contains(s)) {
- sol.push_back(s);
- }
- return sol;
- }
- }
+ Interval unit_interval(0, 1);
double rotx, roty;
if (d == X) {
@@ -278,10 +187,10 @@ std::vector<Coord> EllipticalArc::roots(Coord v, Dim2 d) const
//std::cerr << "b = " << b << std::endl;
//std::cerr << "c = " << c << std::endl;
- if ( are_near(a,0) )
+ if (a == 0)
{
sol.push_back(M_PI);
- if ( !are_near(b,0) )
+ if (b != 0)
{
double s = 2 * std::atan(-c/(2*b));
if ( s < 0 ) s += 2*M_PI;
@@ -292,8 +201,7 @@ std::vector<Coord> EllipticalArc::roots(Coord v, Dim2 d) const
{
double delta = b * b - a * c;
//std::cerr << "delta = " << delta << std::endl;
- if ( are_near(delta, 0) )
- {
+ if (delta == 0) {
double s = 2 * std::atan(-b/a);
if ( s < 0 ) s += 2*M_PI;
sol.push_back(s);
@@ -312,7 +220,7 @@ std::vector<Coord> EllipticalArc::roots(Coord v, Dim2 d) const
std::vector<double> arc_sol;
for (unsigned int i = 0; i < sol.size(); ++i ) {
- //std::cerr << "s = " << rad_to_deg(sol[i]);
+ //std::cerr << "s = " << deg_from_rad(sol[i]);
sol[i] = timeAtAngle(sol[i]);
//std::cerr << " -> t: " << sol[i] << std::endl;
if (unit_interval.contains(sol[i])) {
@@ -886,6 +794,25 @@ bool EllipticalArc::operator==(Curve const &c) const
return true;
}
+bool EllipticalArc::isNear(Curve const &c, Coord precision) const
+{
+ EllipticalArc const *other = dynamic_cast<EllipticalArc const *>(&c);
+ if (!other) {
+ if (isChord()) {
+ return c.isNear(chord(), precision);
+ }
+ return false;
+ }
+
+ if (!are_near(_initial_point, other->_initial_point, precision)) return false;
+ if (!are_near(_final_point, other->_final_point, precision)) return false;
+ if (isChord() && other->isChord()) return true;
+
+ if (sweep() != other->sweep()) return false;
+ if (!are_near(_ellipse, other->_ellipse, precision)) return false;
+ return true;
+}
+
void EllipticalArc::feed(PathSink &sink, bool moveto_initial) const
{
if (moveto_initial) {
@@ -894,6 +821,104 @@ void EllipticalArc::feed(PathSink &sink, bool moveto_initial) const
sink.arcTo(ray(X), ray(Y), rotationAngle(), _large_arc, sweep(), _final_point);
}
+int EllipticalArc::winding(Point const &p) const
+{
+ using std::swap;
+
+ double sinrot, cosrot;
+ sincos(rotationAngle(), sinrot, cosrot);
+
+ Angle ymin_a = std::atan2( ray(Y) * cosrot, ray(X) * sinrot );
+ Angle ymax_a = ymin_a + M_PI;
+
+ Point ymin = pointAtAngle(ymin_a);
+ Point ymax = pointAtAngle(ymax_a);
+ if (ymin[Y] > ymax[Y]) {
+ swap(ymin, ymax);
+ swap(ymin_a, ymax_a);
+ }
+
+ Interval yspan(ymin[Y], ymax[Y]);
+ if (!yspan.lowerContains(p[Y])) return 0;
+
+ bool left = cross(ymax - ymin, p - ymin) > 0;
+ bool inside = _ellipse.contains(p);
+ bool includes_ymin = _angles.contains(ymin_a);
+ bool includes_ymax = _angles.contains(ymax_a);
+
+ AngleInterval rarc(ymin_a, ymax_a, true),
+ larc(ymax_a, ymin_a, true);
+
+ // we'll compute the result for an arc in the direction of increasing angles
+ // and then negate if necessary
+ Angle ia = initialAngle(), fa = finalAngle();
+ Point ip = _initial_point, fp = _final_point;
+ if (!sweep()) {
+ swap(ia, fa);
+ swap(ip, fp);
+ }
+
+ bool initial_left = larc.contains(ia);
+ bool initial_right = !initial_left; //rarc.contains(ia);
+ bool final_right = rarc.contains(fa);
+ bool final_left = !final_right;//larc.contains(fa);
+
+ int result = 0;
+ if (inside || left) {
+ if (includes_ymin && final_right) {
+ Interval ival(ymin[Y], fp[Y]);
+ if (ival.lowerContains(p[Y])) {
+ ++result;
+ }
+ }
+ if (initial_right && final_right && !largeArc()) {
+ Interval ival(ip[Y], fp[Y]);
+ if (ival.lowerContains(p[Y])) {
+ ++result;
+ }
+ }
+ if (initial_right && includes_ymax) {
+ Interval ival(ip[Y], ymax[Y]);
+ if (ival.lowerContains(p[Y])) {
+ ++result;
+ }
+ }
+ if (!initial_right && !final_right && includes_ymin && includes_ymax) {
+ Interval ival(ymax[Y], ymin[Y]);
+ if (ival.lowerContains(p[Y])) {
+ ++result;
+ }
+ }
+ }
+ if (left && !inside) {
+ if (includes_ymin && initial_left) {
+ Interval ival(ymin[Y], ip[Y]);
+ if (ival.lowerContains(p[Y])) {
+ --result;
+ }
+ }
+ if (initial_left && final_left && !largeArc()) {
+ Interval ival(ip[Y], fp[Y]);
+ if (ival.lowerContains(p[Y])) {
+ --result;
+ }
+ }
+ if (final_left && includes_ymax) {
+ Interval ival(fp[Y], ymax[Y]);
+ if (ival.lowerContains(p[Y])) {
+ --result;
+ }
+ }
+ if (!initial_left && !final_left && includes_ymin && includes_ymax) {
+ Interval ival(ymax[Y], ymin[Y]);
+ if (ival.lowerContains(p[Y])) {
+ --result;
+ }
+ }
+ }
+ return sweep() ? result : -result;
+}
+
std::ostream &operator<<(std::ostream &out, EllipticalArc const &ea)
{
out << "EllipticalArc("
diff --git a/src/2geom/elliptical-arc.h b/src/2geom/elliptical-arc.h
index fbb290dca..96a92eb88 100644
--- a/src/2geom/elliptical-arc.h
+++ b/src/2geom/elliptical-arc.h
@@ -215,7 +215,7 @@ public:
/// Get the angular interval of the arc.
AngleInterval angularInterval() const { return _angles; }
- /// Evaluate the arc in the curve domain, i.e. \f$[0, 1]\$.
+ /// Evaluate the arc in the curve domain, i.e. \f$[0, 1]\f$.
virtual Point pointAt(Coord t) const;
/// Evaluate a single coordinate on the arc in the curve domain.
@@ -300,7 +300,9 @@ public:
virtual Curve *portion(double f, double t) const;
virtual Curve *reverse() const;
virtual bool operator==(Curve const &c) const;
+ virtual bool isNear(Curve const &other, Coord precision) const;
virtual void feed(PathSink &sink, bool moveto_initial) const;
+ virtual int winding(Point const &p) const;
private:
void _updateCenterAndAngles();
diff --git a/src/2geom/generic-interval.h b/src/2geom/generic-interval.h
index 716390e57..e7892e2dd 100644
--- a/src/2geom/generic-interval.h
+++ b/src/2geom/generic-interval.h
@@ -32,6 +32,7 @@
#define LIB2GEOM_SEEN_GENERIC_INTERVAL_H
#include <cassert>
+#include <iostream>
#include <boost/none.hpp>
#include <boost/optional.hpp>
#include <2geom/coord.h>
@@ -291,8 +292,6 @@ public:
/// @}
/** @brief Check whether this interval is empty. */
- bool isEmpty() { return !*this; };
- /// Alias of isEmpty() for STL similarity.
bool empty() { return !*this; }
/** @brief Union with another interval, gracefully handling empty ones. */
@@ -340,14 +339,12 @@ inline GenericOptInterval<C> operator&(GenericInterval<C> const &a, GenericInter
return GenericOptInterval<C>(a) & GenericOptInterval<C>(b);
}
-#ifdef _GLIBCXX_IOSTREAM
template <typename C>
inline std::ostream &operator<< (std::ostream &os,
Geom::GenericInterval<C> const &I) {
os << "Interval("<<I.min() << ", "<<I.max() << ")";
return os;
}
-#endif
} // namespace Geom
#endif // !LIB2GEOM_SEEN_GENERIC_INTERVAL_H
diff --git a/src/2geom/generic-rect.h b/src/2geom/generic-rect.h
index f7d722757..fdc7f369b 100644
--- a/src/2geom/generic-rect.h
+++ b/src/2geom/generic-rect.h
@@ -41,6 +41,7 @@
#define LIB2GEOM_SEEN_GENERIC_RECT_H
#include <limits>
+#include <iostream>
#include <boost/optional.hpp>
#include <2geom/coord.h>
@@ -393,7 +394,7 @@ public:
/// @name Check other rectangles and points for inclusion.
/// @{
/** @brief Check for emptiness. */
- inline bool isEmpty() const { return !*this; };
+ inline bool empty() const { return !*this; };
/** @brief Check whether the rectangles have any common points.
* Empty rectangles will not intersect with any other rectangle. */
bool intersects(CRect const &r) const { return r.intersects(*this); }
@@ -513,13 +514,11 @@ inline bool GenericRect<C>::contains(OptCRect const &r) const {
return !r || contains(*r);
}
-#ifdef _GLIBCXX_IOSTREAM
template <typename C>
inline std::ostream &operator<<(std::ostream &out, GenericRect<C> const &r) {
- out << "X: " << r[X] << " Y: " << r[Y];
+ out << "Rect " << r[X] << " x " << r[Y];
return out;
}
-#endif
} // end namespace Geom
diff --git a/src/2geom/int-point.h b/src/2geom/int-point.h
index 7c737b1d7..50d3a6720 100644
--- a/src/2geom/int-point.h
+++ b/src/2geom/int-point.h
@@ -60,15 +60,6 @@ public:
_pt[X] = x;
_pt[Y] = y;
}
- IntPoint(IntPoint const &p) {
- _pt[X] = p._pt[X];
- _pt[Y] = p._pt[Y];
- }
- IntPoint &operator=(IntPoint const &p) {
- _pt[X] = p._pt[X];
- _pt[Y] = p._pt[Y];
- return *this;
- }
/// @}
/// @name Access the coordinates of a point
@@ -92,6 +83,10 @@ public:
/// @name Vector-like arithmetic operations
/// @{
+ IntPoint operator-() const {
+ IntPoint ret(-_pt[X], -_pt[Y]);
+ return ret;
+ }
IntPoint &operator+=(IntPoint const &o) {
_pt[X] += o._pt[X];
_pt[Y] += o._pt[Y];
diff --git a/src/2geom/intersection-graph.cpp b/src/2geom/intersection-graph.cpp
index e18561f67..d469d3ffc 100644
--- a/src/2geom/intersection-graph.cpp
+++ b/src/2geom/intersection-graph.cpp
@@ -34,6 +34,7 @@
#include <2geom/intersection-graph.h>
#include <2geom/path.h>
#include <2geom/pathvector.h>
+#include <2geom/utils.h>
#include <iostream>
#include <iterator>
@@ -56,101 +57,174 @@ struct PathIntersectionGraph::IntersectionVertexLess {
*/
PathIntersectionGraph::PathIntersectionGraph(PathVector const &a, PathVector const &b, Coord precision)
- : _a(a)
- , _b(b)
+ : _graph_valid(true)
{
if (a.empty() || b.empty()) return;
+ _pv[0] = a;
+ _pv[1] = b;
+
+ _prepareArguments();
+ bool has_intersections = _prepareIntersectionLists(precision);
+ if (!has_intersections) return;
+
+ _assignEdgeWindingParities(precision);
+ _assignComponentStatusFromDegenerateIntersections();
+ _removeDegenerateIntersections();
+ if (_graph_valid) {
+ _verify();
+ }
+}
+
+void PathIntersectionGraph::_prepareArguments()
+{
// all paths must be closed, otherwise we will miss some intersections
- for (std::size_t i = 0; i < a.size(); ++i) {
- _a[i].close();
+ for (int w = 0; w < 2; ++w) {
+ for (std::size_t i = 0; i < _pv[w].size(); ++i) {
+ _pv[w][i].close();
+ }
}
- for (std::size_t i = 0; i < b.size(); ++i) {
- _b[i].close();
+ // remove degenerate segments
+ for (int w = 0; w < 2; ++w) {
+ for (std::size_t i = _pv[w].size(); i > 0; --i) {
+ if (_pv[w][i-1].empty()) {
+ _pv[w].erase(_pv[w].begin() + (i-1));
+ }
+ for (std::size_t j = _pv[w][i-1].size(); j > 0; --j) {
+ if (_pv[w][i-1][j-1].isDegenerate()) {
+ _pv[w][i-1].erase(_pv[w][i-1].begin() + (j-1));
+ }
+ }
+ }
}
+}
- std::vector<PVIntersection> pxs = _a.intersect(_b, precision);
+bool PathIntersectionGraph::_prepareIntersectionLists(Coord precision)
+{
+ std::vector<PVIntersection> pxs = _pv[0].intersect(_pv[1], precision);
// NOTE: this early return means that the path data structures will not be created
// if there are no intersections at all!
- if (pxs.empty()) return;
+ if (pxs.empty()) return false;
// prepare intersection lists for each path component
- for (std::size_t i = 0; i < _a.size(); ++i) {
- _apaths.push_back(new PathData());
- }
- for (std::size_t i = 0; i < _b.size(); ++i) {
- _bpaths.push_back(new PathData());
+ for (unsigned w = 0; w < 2; ++w) {
+ for (std::size_t i = 0; i < _pv[w].size(); ++i) {
+ _components[w].push_back(new PathData(w, i));
+ }
}
+ // create intersection vertices
for (std::size_t i = 0; i < pxs.size(); ++i) {
IntersectionVertex *xa, *xb;
xa = new IntersectionVertex();
xb = new IntersectionVertex();
- xa->processed = xb->processed = false;
+ //xa->processed = xb->processed = false;
+ xa->which = 0; xb->which = 1;
xa->pos = pxs[i].first;
xb->pos = pxs[i].second;
xa->p = xb->p = pxs[i].point();
xa->neighbor = xb;
xb->neighbor = xa;
+ xa->next_edge = xb->next_edge = OUTSIDE;
+ xa->defective = xb->defective = false;
_xs.push_back(xa);
_xs.push_back(xb);
- _apaths[xa->pos.path_index].xlist.push_back(*xa);
- _bpaths[xb->pos.path_index].xlist.push_back(*xb);
+ _components[0][xa->pos.path_index].xlist.push_back(*xa);
+ _components[1][xb->pos.path_index].xlist.push_back(*xb);
}
- for (std::size_t i = 0; i < _apaths.size(); ++i) {
- _apaths[i].xlist.sort(IntersectionVertexLess());
- }
- for (std::size_t i = 0; i < _bpaths.size(); ++i) {
- _bpaths[i].xlist.sort(IntersectionVertexLess());
+ // sort components according to time value of intersections
+ for (unsigned w = 0; w < 2; ++w) {
+ for (std::size_t i = 0; i < _components[w].size(); ++i) {
+ _components[w][i].xlist.sort(IntersectionVertexLess());
+ }
}
- typedef IntersectionList::iterator Iter;
-
- // determine in/out/on flags using winding
- for (unsigned npv = 0; npv < 2; ++npv) {
- boost::ptr_vector<PathData> &ls = npv ? _bpaths : _apaths;
- boost::ptr_vector<PathData> &ols = npv ? _apaths : _bpaths;
- PathVector const &pv = npv ? b : a;
- PathVector const &other = npv ? a : b;
-
- for (unsigned li = 0; li < ls.size(); ++li) {
- IntersectionList &xl = ls[li].xlist;
- for (Iter i = xl.begin(); i != xl.end(); ++i) {
- Iter n = boost::next(i);
- if (n == xl.end()) {
- n = xl.begin();
- }
+ return true;
+}
+
+void PathIntersectionGraph::_assignEdgeWindingParities(Coord precision)
+{
+ // determine the winding numbers of path portions between intersections
+ for (unsigned w = 0; w < 2; ++w) {
+ unsigned ow = (w+1) % 2;
+
+ for (unsigned li = 0; li < _components[w].size(); ++li) {
+ IntersectionList &xl = _components[w][li].xlist;
+ for (ILIter i = xl.begin(); i != xl.end(); ++i) {
+ ILIter n = cyclic_next(i, xl);
std::size_t pi = i->pos.path_index;
- PathInterval ival = forward_interval(i->pos, n->pos, pv[pi].size());
+ PathInterval ival = forward_interval(i->pos, n->pos, _pv[w][pi].size());
PathTime mid = ival.inside(precision);
- // TODO check for degenerate cases
- int w = other.winding(pv[pi].pointAt(mid));
- if (w % 2) {
- i->next = POINT_INSIDE;
- n->previous = POINT_INSIDE;
+ Point wpoint = _pv[w][pi].pointAt(mid);
+ _winding_points.push_back(wpoint);
+ int wdg = _pv[ow].winding(wpoint);
+ if (wdg % 2) {
+ i->next_edge = INSIDE;
} else {
- i->next = POINT_OUTSIDE;
- n->previous = POINT_OUTSIDE;
+ i->next_edge = OUTSIDE;
}
}
+ }
+ }
+}
+
+void PathIntersectionGraph::_assignComponentStatusFromDegenerateIntersections()
+{
+ // If a path has only degenerate intersections, assign its status now.
+ // This protects against later accidentaly picking a point for winding
+ // determination that is exactly at a removed intersection.
+ for (unsigned w = 0; w < 2; ++w) {
+ for (unsigned li = 0; li < _components[w].size(); ++li) {
+ IntersectionList &xl = _components[w][li].xlist;
+ bool has_in = false;
+ bool has_out = false;
+ for (ILIter i = xl.begin(); i != xl.end(); ++i) {
+ has_in |= (i->next_edge == INSIDE);
+ has_out |= (i->next_edge == OUTSIDE);
+ }
+ if (has_in && !has_out) {
+ _components[w][li].status = INSIDE;
+ }
+ if (!has_in && has_out) {
+ _components[w][li].status = OUTSIDE;
+ }
+ }
+ }
+}
- // remove intersections that don't change between in/out
- // and assign exit / entry flags
- for (Iter i = xl.begin(); i != xl.end();) {
- if (i->previous == i->next) {
- IntersectionList &oxl = ols[i->neighbor->pos.path_index].xlist;
- oxl.erase(oxl.iterator_to(*i->neighbor));
- xl.erase(i++);
- if (i->next == POINT_INSIDE) {
- ++ls[li].removed_in;
- } else {
- ++ls[li].removed_out;
+void PathIntersectionGraph::_removeDegenerateIntersections()
+{
+ // remove intersections that don't change between in/out
+ for (unsigned w = 0; w < 2; ++w) {
+ for (unsigned li = 0; li < _components[w].size(); ++li) {
+ IntersectionList &xl = _components[w][li].xlist;
+ for (ILIter i = xl.begin(); i != xl.end();) {
+ ILIter n = cyclic_next(i, xl);
+ if (i->next_edge == n->next_edge) {
+ bool last_node = (i == n);
+ ILIter nn = _getNeighbor(n);
+ IntersectionList &oxl = _getPathData(nn).xlist;
+
+ // When exactly 3 out of 4 edges adjacent to an intersection
+ // have the same winding, we have a defective intersection,
+ // which is neither degenerate nor normal. Those can occur in paths
+ // that contain overlapping segments. We cannot handle that case
+ // for now, so throw an exception.
+ if (cyclic_prior(nn, oxl)->next_edge != nn->next_edge) {
+ _graph_valid = false;
+ n->defective = true;
+ nn->defective = true;
+ ++i;
+ continue;
}
+
+ oxl.erase(nn);
+ xl.erase(n);
+ if (last_node) break;
} else {
- i->entry = ((i->next == POINT_INSIDE) && (i->previous == POINT_OUTSIDE));
++i;
}
}
@@ -158,6 +232,20 @@ PathIntersectionGraph::PathIntersectionGraph(PathVector const &a, PathVector con
}
}
+void PathIntersectionGraph::_verify()
+{
+ for (unsigned w = 0; w < 2; ++w) {
+ for (unsigned li = 0; li < _components[w].size(); ++li) {
+ IntersectionList &xl = _components[w][li].xlist;
+ assert(xl.size() % 2 == 0);
+ for (ILIter i = xl.begin(); i != xl.end(); ++i) {
+ ILIter j = cyclic_next(i, xl);
+ assert(i->next_edge != j->next_edge);
+ }
+ }
+ }
+}
+
PathVector PathIntersectionGraph::getUnion()
{
PathVector result = _getResult(false, false);
@@ -192,8 +280,9 @@ PathVector PathIntersectionGraph::getBminusA()
PathVector PathIntersectionGraph::getXOR()
{
- PathVector r1 = getAminusB();
- PathVector r2 = getBminusA();
+ PathVector r1, r2;
+ r1 = getAminusB();
+ r2 = getBminusA();
std::copy(r2.begin(), r2.end(), std::back_inserter(r1));
return r1;
}
@@ -201,37 +290,61 @@ PathVector PathIntersectionGraph::getXOR()
std::size_t PathIntersectionGraph::size() const
{
std::size_t result = 0;
- for (std::size_t i = 0; i < _apaths.size(); ++i) {
- result += _apaths[i].xlist.size();
+ for (std::size_t i = 0; i < _components[0].size(); ++i) {
+ result += _components[0][i].xlist.size();
}
return result;
}
-std::vector<Point> PathIntersectionGraph::intersectionPoints() const
+std::vector<Point> PathIntersectionGraph::intersectionPoints(bool defective) const
{
std::vector<Point> result;
- typedef IntersectionList::const_iterator Iter;
- for (std::size_t i = 0; i < _apaths.size(); ++i) {
- for (Iter j = _apaths[i].xlist.begin(); j != _apaths[i].xlist.end(); ++j) {
- result.push_back(j->p);
+ typedef IntersectionList::const_iterator CILIter;
+ for (std::size_t i = 0; i < _components[0].size(); ++i) {
+ for (CILIter j = _components[0][i].xlist.begin(); j != _components[0][i].xlist.end(); ++j) {
+ if (j->defective == defective) {
+ result.push_back(j->p);
+ }
}
}
return result;
}
+void PathIntersectionGraph::fragments(PathVector &in, PathVector &out) const
+{
+ typedef boost::ptr_vector<PathData>::const_iterator PIter;
+ for (unsigned w = 0; w < 2; ++w) {
+ for (PIter li = _components[w].begin(); li != _components[w].end(); ++li) {
+ for (CILIter k = li->xlist.begin(); k != li->xlist.end(); ++k) {
+ CILIter n = cyclic_next(k, li->xlist);
+ // TODO: investigate why non-contiguous paths are sometimes generated here
+ Path frag(k->p);
+ frag.setStitching(true);
+ PathInterval ival = forward_interval(k->pos, n->pos, _pv[w][k->pos.path_index].size());
+ _pv[w][k->pos.path_index].appendPortionTo(frag, ival, k->p, n->p);
+ if (k->next_edge == INSIDE) {
+ in.push_back(frag);
+ } else {
+ out.push_back(frag);
+ }
+ }
+ }
+ }
+}
+
PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b)
{
- typedef IntersectionList::iterator Iter;
+ typedef boost::ptr_vector<PathData>::iterator PIter;
PathVector result;
if (_xs.empty()) return result;
// reset processed status
- for (unsigned npv = 0; npv < 2; ++npv) {
- boost::ptr_vector<PathData> &ls = npv ? _bpaths : _apaths;
- for (std::size_t li = 0; li < ls.size(); ++li) {
- for (Iter k = ls[li].xlist.begin(); k != ls[li].xlist.end(); ++k) {
- k->processed = false;
+ _ulist.clear();
+ for (unsigned w = 0; w < 2; ++w) {
+ for (PIter li = _components[w].begin(); li != _components[w].end(); ++li) {
+ for (ILIter k = li->xlist.begin(); k != li->xlist.end(); ++k) {
+ _ulist.push_back(*k);
}
}
}
@@ -239,18 +352,17 @@ PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b)
unsigned n_processed = 0;
while (true) {
- PathVector const *cur = &_a, *other = &_b;
- boost::ptr_vector<PathData> *lscur = &_apaths, *lsother = &_bpaths;
-
- // find unprocessed intersection
- Iter i;
- if (!_findUnprocessed(i)) break;
+ // get unprocessed intersection
+ if (_ulist.empty()) break;
+ IntersectionVertex &iv = _ulist.front();
+ unsigned w = iv.which;
+ ILIter i = _components[w][iv.pos.path_index].xlist.iterator_to(iv);
result.push_back(Path(i->p));
result.back().setStitching(true);
- while (!i->processed) {
- Iter prev = i;
+ while (i->_proc_hook.is_linked()) {
+ ILIter prev = i;
std::size_t pi = i->pos.path_index;
// determine which direction to go
// union: always go outside
@@ -258,53 +370,55 @@ PathVector PathIntersectionGraph::_getResult(bool enter_a, bool enter_b)
// a minus b: go inside in b, outside in a
// b minus a: go inside in a, outside in b
bool reverse = false;
- if (cur == &_a) {
- reverse = i->entry ^ enter_a;
+ if (w == 0) {
+ reverse = (i->next_edge == INSIDE) ^ enter_a;
} else {
- reverse = i->entry ^ enter_b;
+ reverse = (i->next_edge == INSIDE) ^ enter_b;
}
// get next intersection
if (reverse) {
- if (i == (*lscur)[pi].xlist.begin()) {
- i = (*lscur)[pi].xlist.end();
- }
- --i;
+ i = cyclic_prior(i, _components[w][pi].xlist);
} else {
- ++i;
- if (i == (*lscur)[pi].xlist.end()) {
- i = (*lscur)[pi].xlist.begin();
- }
+ i = cyclic_next(i, _components[w][pi].xlist);
}
// append portion of path
PathInterval ival = PathInterval::from_direction(
prev->pos.asPathTime(), i->pos.asPathTime(),
- reverse, (*cur)[pi].size());
+ reverse, _pv[i->which][pi].size());
- (*cur)[pi].appendPortionTo(result.back(), ival, prev->p, i->p);
+ _pv[i->which][pi].appendPortionTo(result.back(), ival, prev->p, i->p);
// mark both vertices as processed
- prev->processed = true;
- i->processed = true;
+ //prev->processed = true;
+ //i->processed = true;
n_processed += 2;
+ if (prev->_proc_hook.is_linked()) {
+ _ulist.erase(_ulist.iterator_to(*prev));
+ }
+ if (i->_proc_hook.is_linked()) {
+ _ulist.erase(_ulist.iterator_to(*i));
+ }
// switch to the other path
- i = (*lsother)[i->neighbor->pos.path_index].xlist.iterator_to(*i->neighbor);
- std::swap(lscur, lsother);
- std::swap(cur, other);
+ i = _getNeighbor(i);
+ w = i->which;
}
result.back().close(true);
assert(!result.back().empty());
}
+ /*if (n_processed != size() * 2) {
+ std::cerr << "Processed " << n_processed << " intersections, expected " << (size() * 2) << std::endl;
+ }*/
assert(n_processed == size() * 2);
return result;
}
-void PathIntersectionGraph::_handleNonintersectingPaths(PathVector &result, int which, bool inside)
+void PathIntersectionGraph::_handleNonintersectingPaths(PathVector &result, unsigned which, bool inside)
{
/* Every component that has any intersections will be processed by _getResult.
* Here we take care of paths that don't have any intersections. They are either
@@ -312,68 +426,53 @@ void PathIntersectionGraph::_handleNonintersectingPaths(PathVector &result, int
* evaluating the winding rule at the initial point. If inside is true and
* the path is inside, we add it to the result.
*/
- boost::ptr_vector<PathData> const &ls = which ? _bpaths : _apaths;
- PathVector const &cur = which ? _b : _a;
- PathVector const &other = which ? _a : _b;
+ unsigned w = which;
+ unsigned ow = (w+1) % 2;
- for (std::size_t i = 0; i < cur.size(); ++i) {
+ for (std::size_t i = 0; i < _pv[w].size(); ++i) {
// the path data vector might have been left empty if there were no intersections at all
- bool has_path_data = !ls.empty();
+ bool has_path_data = !_components[w].empty();
// Skip if the path has intersections
- if (has_path_data && !ls[i].xlist.empty()) continue;
+ if (has_path_data && !_components[w][i].xlist.empty()) continue;
bool path_inside = false;
- // If the path had any intersections removed, use the result of that,
- // since one of those might have been at the initial point.
- // Also, it saves time.
- if (has_path_data && ls[i].removed_in != 0) {
+ // Use the in/out determination from constructor, if available
+ if (has_path_data && _components[w][i].status == INSIDE) {
path_inside = true;
- } else if (has_path_data && ls[i].removed_out != 0) {
+ } else if (has_path_data && _components[w][i].status == OUTSIDE) {
path_inside = false;
} else {
- int w = other.winding(cur[i].initialPoint());
- path_inside = w % 2 != 0;
+ int wdg = _pv[ow].winding(_pv[w][i].initialPoint());
+ path_inside = wdg % 2 != 0;
}
if (path_inside == inside) {
- result.push_back(cur[i]);
+ result.push_back(_pv[w][i]);
}
}
}
-bool PathIntersectionGraph::_findUnprocessed(IntersectionList::iterator &result)
+PathIntersectionGraph::ILIter PathIntersectionGraph::_getNeighbor(ILIter iter)
{
- typedef IntersectionList::iterator Iter;
-
- Iter it, last;
-
- for (std::size_t k = 0; k < _apaths.size(); ++k) {
- it = _apaths[k].xlist.begin();
- last = _apaths[k].xlist.end();
- for (; it != last; ++it) {
- if (!it->_hook.is_linked()) {
- // this intersection was removed since it did not change inside/outside status
- continue;
- }
- if (!it->processed) {
- result = it;
- return true;
- }
- }
- }
-
- return false;
+ unsigned ow = (iter->which + 1) % 2;
+ return _components[ow][iter->neighbor->pos.path_index].xlist.iterator_to(*iter->neighbor);
}
+PathIntersectionGraph::PathData &
+PathIntersectionGraph::_getPathData(ILIter iter)
+{
+ return _components[iter->which][iter->pos.path_index];
+}
std::ostream &operator<<(std::ostream &os, PathIntersectionGraph const &pig)
{
+ typedef PathIntersectionGraph::IntersectionList::const_iterator CILIter;
os << "Intersection graph:\n"
<< pig._xs.size()/2 << " total intersections\n"
<< pig.size() << " considered intersections\n";
- for (std::size_t i = 0; i < pig._apaths.size(); ++i) {
- typedef PathIntersectionGraph::IntersectionList::const_iterator Iter;
- for (Iter j = pig._apaths[i].xlist.begin(); j != pig._apaths[i].xlist.end(); ++j) {
+ for (std::size_t i = 0; i < pig._components[0].size(); ++i) {
+ PathIntersectionGraph::IntersectionList const &xl = pig._components[0][i].xlist;
+ for (CILIter j = xl.begin(); j != xl.end(); ++j) {
os << j->pos << " - " << j->neighbor->pos << " @ " << j->p << "\n";
}
}
diff --git a/src/2geom/intersection-graph.h b/src/2geom/intersection-graph.h
index bd9aaee81..332c83f18 100644
--- a/src/2geom/intersection-graph.h
+++ b/src/2geom/intersection-graph.h
@@ -58,23 +58,29 @@ public:
/// Returns the number of intersections used when computing Boolean operations.
std::size_t size() const;
- std::vector<Point> intersectionPoints() const;
+ std::vector<Point> intersectionPoints(bool defective = false) const;
+ std::vector<Point> windingPoints() const {
+ return _winding_points;
+ }
+ void fragments(PathVector &in, PathVector &out) const;
+ bool valid() const { return _graph_valid; }
private:
enum InOutFlag {
- POINT_INSIDE,
- POINT_OUTSIDE
+ INSIDE,
+ OUTSIDE,
+ BOTH
};
struct IntersectionVertex {
boost::intrusive::list_member_hook<> _hook;
+ boost::intrusive::list_member_hook<> _proc_hook;
PathVectorTime pos;
Point p; // guarantees that endpoints are exact
IntersectionVertex *neighbor;
- bool entry; // going in +t direction enters the other path
- InOutFlag previous;
- InOutFlag next;
- bool processed; // TODO: use intrusive unprocessed list instead
+ InOutFlag next_edge;
+ unsigned which;
+ bool defective;
};
typedef boost::intrusive::list
@@ -86,27 +92,50 @@ private:
>
> IntersectionList;
+ typedef boost::intrusive::list
+ < IntersectionVertex
+ , boost::intrusive::member_hook
+ < IntersectionVertex
+ , boost::intrusive::list_member_hook<>
+ , &IntersectionVertex::_proc_hook
+ >
+ > UnprocessedList;
+
struct PathData {
IntersectionList xlist;
- unsigned removed_in;
- unsigned removed_out;
-
- PathData()
- : removed_in(0)
- , removed_out(0)
+ std::size_t path_index;
+ int which;
+ InOutFlag status;
+
+ PathData(int w, std::size_t pi)
+ : path_index(pi)
+ , which(w)
+ , status(BOTH)
{}
};
struct IntersectionVertexLess;
+ typedef IntersectionList::iterator ILIter;
+ typedef IntersectionList::const_iterator CILIter;
PathVector _getResult(bool enter_a, bool enter_b);
- void _handleNonintersectingPaths(PathVector &result, int which, bool inside);
- bool _findUnprocessed(IntersectionList::iterator &result);
-
- PathVector _a, _b;
+ void _handleNonintersectingPaths(PathVector &result, unsigned which, bool inside);
+ void _prepareArguments();
+ bool _prepareIntersectionLists(Coord precision);
+ void _assignEdgeWindingParities(Coord precision);
+ void _assignComponentStatusFromDegenerateIntersections();
+ void _removeDegenerateIntersections();
+ void _verify();
+
+ ILIter _getNeighbor(ILIter iter);
+ PathData &_getPathData(ILIter iter);
+
+ PathVector _pv[2];
boost::ptr_vector<IntersectionVertex> _xs;
- boost::ptr_vector<PathData> _apaths;
- boost::ptr_vector<PathData> _bpaths;
+ boost::ptr_vector<PathData> _components[2];
+ UnprocessedList _ulist;
+ bool _graph_valid;
+ std::vector<Point> _winding_points;
friend std::ostream &operator<<(std::ostream &, PathIntersectionGraph const &);
};
diff --git a/src/2geom/line.cpp b/src/2geom/line.cpp
index bada8ef38..a9cc0e251 100644
--- a/src/2geom/line.cpp
+++ b/src/2geom/line.cpp
@@ -103,7 +103,7 @@ void Line::setCoefficients (Coord a, Coord b, Coord c)
void Line::coefficients(Coord &a, Coord &b, Coord &c) const
{
- Point v = versor().cw();
+ Point v = vector().cw();
a = v[X];
b = v[Y];
c = cross(_initial, _final);
@@ -139,7 +139,7 @@ std::vector<Coord> Line::roots(Coord v, Dim2 d) const {
Coord Line::root(Coord v, Dim2 d) const
{
assert(d == X || d == Y);
- Point vs = versor();
+ Point vs = vector();
if (vs[d] != 0) {
return (v - _initial[d]) / vs[d];
} else {
@@ -149,7 +149,7 @@ Coord Line::root(Coord v, Dim2 d) const
boost::optional<LineSegment> Line::clip(Rect const &r) const
{
- Point v = versor();
+ Point v = vector();
// handle horizontal and vertical lines first,
// since the root-based code below will break for them
for (unsigned i = 0; i < 2; ++i) {
@@ -221,7 +221,7 @@ boost::optional<LineSegment> Line::clip(Rect const &r) const
* @see timeAtProjection */
Coord Line::timeAt(Point const &p) const
{
- Point v = versor();
+ Point v = vector();
// degenerate case
if (v[X] == 0 && v[Y] == 0) {
return 0;
@@ -235,12 +235,26 @@ Coord Line::timeAt(Point const &p) const
}
}
+/** @brief Create a transformation that maps one line to another.
+ * This will return a transformation \f$A\f$ such that
+ * \f$L_1(t) \cdot A = L_2(t)\f$, where \f$L_1\f$ is this line
+ * and \f$L_2\f$ is the line passed as the parameter. The returned
+ * transformation will preserve angles. */
+Affine Line::transformTo(Line const &other) const
+{
+ Affine result = Translate(-_initial);
+ result *= Rotate(angle_between(vector(), other.vector()));
+ result *= Scale(other.vector().length() / vector().length());
+ result *= Translate(other._initial);
+ return result;
+}
+
std::vector<ShapeIntersection> Line::intersect(Line const &other) const
{
std::vector<ShapeIntersection> result;
- Point v1 = versor();
- Point v2 = other.versor();
+ Point v1 = vector();
+ Point v2 = other.vector();
Coord cp = cross(v1, v2);
if (cp == 0) return result;
@@ -319,8 +333,8 @@ OptCrossing intersection_impl(Ray const& r1, Line const& l2, unsigned int i)
using std::swap;
OptCrossing crossing =
- intersection_impl(r1.versor(), r1.origin(),
- l2.versor(), l2.origin() );
+ intersection_impl(r1.vector(), r1.origin(),
+ l2.vector(), l2.origin() );
if (crossing) {
if (crossing->ta < 0) {
@@ -349,7 +363,7 @@ OptCrossing intersection_impl( LineSegment const& ls1,
OptCrossing crossing =
intersection_impl(ls1.finalPoint() - ls1.initialPoint(),
ls1.initialPoint(),
- l2.versor(),
+ l2.vector(),
l2.origin() );
if (crossing) {
@@ -382,7 +396,7 @@ OptCrossing intersection_impl( LineSegment const& ls1,
OptCrossing crossing =
intersection_impl( direction,
ls1.initialPoint(),
- r2.versor(),
+ r2.vector(),
r2.origin() );
if (crossing) {
@@ -400,7 +414,7 @@ OptCrossing intersection_impl( LineSegment const& ls1,
}
if ( are_near(r2.origin(), ls1) ) {
- bool eqvs = (dot(direction, r2.versor()) > 0);
+ bool eqvs = (dot(direction, r2.vector()) > 0);
if ( are_near(ls1.initialPoint(), r2.origin()) && !eqvs) {
crossing->ta = crossing->tb = 0;
return crossing;
@@ -431,8 +445,8 @@ OptCrossing intersection_impl( LineSegment const& ls1,
OptCrossing intersection(Line const& l1, Line const& l2)
{
OptCrossing c = detail::intersection_impl(
- l1.versor(), l1.origin(),
- l2.versor(), l2.origin());
+ l1.vector(), l1.origin(),
+ l2.vector(), l2.origin());
if (!c && distance(l1.origin(), l2) == 0) {
THROW_INFINITESOLUTIONS();
@@ -443,8 +457,8 @@ OptCrossing intersection(Line const& l1, Line const& l2)
OptCrossing intersection(Ray const& r1, Ray const& r2)
{
OptCrossing crossing =
- detail::intersection_impl( r1.versor(), r1.origin(),
- r2.versor(), r2.origin() );
+ detail::intersection_impl( r1.vector(), r1.origin(),
+ r2.vector(), r2.origin() );
if (crossing)
{
@@ -463,7 +477,7 @@ OptCrossing intersection(Ray const& r1, Ray const& r2)
if ( are_near(r1.origin(), r2) || are_near(r2.origin(), r1) )
{
if ( are_near(r1.origin(), r2.origin())
- && !are_near(r1.versor(), r2.versor()) )
+ && !are_near(r1.vector(), r2.vector()) )
{
crossing->ta = crossing->tb = 0;
return crossing;
@@ -568,7 +582,7 @@ Line make_angle_bisector_line(Line const& l1, Line const& l2)
}
Point O = l1.pointAt(crossing->ta);
Point A = l1.pointAt(crossing->ta + 1);
- double angle = angle_between(l1.versor(), l2.versor());
+ double angle = angle_between(l1.vector(), l2.vector());
Point B = (angle > 0) ? l2.pointAt(crossing->tb + 1)
: l2.pointAt(crossing->tb - 1);
diff --git a/src/2geom/line.h b/src/2geom/line.h
index 7d4766e12..62b3652f1 100644
--- a/src/2geom/line.h
+++ b/src/2geom/line.h
@@ -98,7 +98,7 @@ public:
/// Create a line by extending a ray.
explicit Line(Ray const &r)
: _initial(r.origin())
- , _final(r.origin() + r.versor())
+ , _final(r.origin() + r.vector())
{}
/// Create a line normal to a vector at a specified distance from origin.
@@ -111,7 +111,7 @@ public:
* Note that each line direction has two possible unit vectors.
* @param o Point through which the line will pass
* @param v Unit vector of the line's direction */
- static Line from_origin_and_versor(Point const &o, Point const &v) {
+ static Line from_origin_and_vector(Point const &o, Point const &v) {
Line l(o, o + v);
return l;
}
@@ -126,9 +126,12 @@ public:
/// Get the line's origin point.
Point origin() const { return _initial; }
- /** @brief Get the line's direction vector.
- * Note that the retrieved vector is not normalized to unit length. */
- Point versor() const { return _final - _initial; }
+ /** @brief Get the line's raw direction vector.
+ * The retrieved vector is normalized to unit length. */
+ Point vector() const { return _final - _initial; }
+ /** @brief Get the line's normalized direction vector.
+ * The retrieved vector is normalized to unit length. */
+ Point versor() const { return (_final - _initial).normalized(); }
/// Angle the line makes with the X axis, in mathematical convention.
Coord angle() const {
Point d = _final - _initial;
@@ -147,7 +150,7 @@ public:
}
/** @brief Set the speed of the line.
* Origin remains unchanged. */
- void setVersor(Point const &v) {
+ void setVector(Point const &v) {
_final = _initial + v;
}
@@ -239,7 +242,7 @@ public:
* @return Time value corresponding to a point closest to @c p. */
Coord timeAtProjection(Point const& p) const {
if ( isDegenerate() ) return 0;
- Point v = versor();
+ Point v = vector();
return dot(p - _initial, v) / dot(v, v);
}
@@ -284,22 +287,22 @@ public:
boost::optional<LineSegment> clip(Rect const &r) const;
/** @brief Create a ray starting at the specified time value.
- * The created ray will go in the direction of the line's versor (in the direction
+ * The created ray will go in the direction of the line's vector (in the direction
* of increasing time values).
* @param t Time value where the ray should start
- * @return Ray starting at t and going in the direction of the versor */
+ * @return Ray starting at t and going in the direction of the vector */
Ray ray(Coord t) {
Ray result;
result.setOrigin(pointAt(t));
- result.setVersor(versor());
+ result.setVector(vector());
return result;
}
/** @brief Create a derivative of the line.
* The new line will always be degenerate. Its origin will be equal to this
- * line's versor. */
+ * line's vector. */
Line derivative() const {
- Point v = versor();
+ Point v = vector();
Line result(v, v);
return result;
}
@@ -314,7 +317,7 @@ public:
* If Y grows upwards, then this is the left normal. If Y grows downwards,
* then this is the right normal. */
Point normal() const {
- return rot90(versor()).normalized();
+ return rot90(vector()).normalized();
}
// what does this do?
@@ -326,7 +329,7 @@ public:
/// Compute an affine matrix representing a reflection about the line.
Affine reflection() const {
- Point v = versor().normalized();
+ Point v = versor();
Coord x2 = v[X]*v[X], y2 = v[Y]*v[Y], xy = v[X]*v[Y];
Affine m(x2-y2, 2.*xy,
2.*xy, y2-x2,
@@ -344,7 +347,7 @@ public:
* lower precision than e.g. a shear transform.
* @param d Which coordinate of points on the line should be zero after the transformation */
Affine rotationToZero(Dim2 d) const {
- Point v = versor();
+ Point v = vector();
if (d == X) {
std::swap(v[X], v[Y]);
} else {
@@ -359,6 +362,8 @@ public:
Affine m = rotationToZero(other_dimension(d));
return m;
}
+
+ Affine transformTo(Line const &other) const;
/// @}
std::vector<ShapeIntersection> intersect(Line const &other) const;
@@ -419,7 +424,7 @@ bool are_near(Point const &p, Line const &line, double eps = EPSILON)
inline
bool are_parallel(Line const &l1, Line const &l2, double eps = EPSILON)
{
- return are_near(cross(l1.versor(), l2.versor()), 0, eps);
+ return are_near(cross(l1.vector(), l2.vector()), 0, eps);
}
/** @brief Test whether two lines are approximately the same.
@@ -440,7 +445,7 @@ bool are_same(Line const &l1, Line const &l2, double eps = EPSILON)
inline
bool are_orthogonal(Line const &l1, Line const &l2, double eps = EPSILON)
{
- return are_near(dot(l1.versor(), l2.versor()), 0, eps);
+ return are_near(dot(l1.vector(), l2.vector()), 0, eps);
}
// evaluate the angle between l1 and l2 rotating l1 in cw direction
@@ -449,7 +454,7 @@ bool are_orthogonal(Line const &l1, Line const &l2, double eps = EPSILON)
inline
double angle_between(Line const& l1, Line const& l2)
{
- double angle = angle_between(l1.versor(), l2.versor());
+ double angle = angle_between(l1.vector(), l2.vector());
if (angle < 0) angle += M_PI;
if (angle == M_PI) angle = 0;
return angle;
@@ -472,7 +477,7 @@ bool are_near(Point const &p, LineSegment const &seg, double eps = EPSILON)
inline
Line make_orthogonal_line(Point const &p, Line const &line)
{
- Point d = line.versor().cw();
+ Point d = line.vector().cw();
Line l(p, p + d);
return l;
}
diff --git a/src/2geom/linear.h b/src/2geom/linear.h
index b0306fb9f..316ed8639 100644
--- a/src/2geom/linear.h
+++ b/src/2geom/linear.h
@@ -5,8 +5,9 @@
* Authors:
* Nathan Hurst <njh@mail.csse.monash.edu.au>
* Michael Sloan <mgsloan@gmail.com>
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
*
- * Copyright (C) 2006-2007 authors
+ * Copyright (C) 2006-2015 authors
*
* This library is free software; you can redistribute it and/or
* modify it either under the terms of the GNU Lesser General Public
@@ -38,14 +39,6 @@
#include <2geom/interval.h>
#include <2geom/math-utils.h>
-//#define USE_SBASIS_OF
-
-#ifdef USE_SBASIS_OF
-
-#include "linear-of.h"
-
-#else
-
namespace Geom {
class SBasis;
@@ -54,26 +47,31 @@ class SBasis;
* @brief Function that interpolates linearly between two values.
* @ingroup Fragments
*/
-class Linear {
+class Linear
+ : boost::additive< Linear
+ , boost::arithmetic< Linear, Coord
+ , boost::equality_comparable< Linear
+ > > >
+{
public:
- double a[2];
+ Coord a[2];
Linear() {a[0]=0; a[1]=0;}
- Linear(double aa, double b) {a[0] = aa; a[1] = b;}
- Linear(double aa) {a[0] = aa; a[1] = aa;}
+ Linear(Coord aa, Coord b) {a[0] = aa; a[1] = b;}
+ Linear(Coord aa) {a[0] = aa; a[1] = aa;}
- double operator[](unsigned i) const {
+ Coord operator[](unsigned i) const {
assert(i < 2);
return a[i];
}
- double &operator[](unsigned i) {
+ Coord &operator[](unsigned i) {
assert(i < 2);
return a[i];
}
//IMPL: FragmentConcept
- typedef double output_type;
- bool isZero(double eps=EPSILON) const { return are_near(a[0], 0., eps) && are_near(a[1], 0., eps); }
- bool isConstant(double eps=EPSILON) const { return are_near(a[0], a[1], eps); }
+ typedef Coord output_type;
+ bool isZero(Coord eps=EPSILON) const { return are_near(a[0], 0., eps) && are_near(a[1], 0., eps); }
+ bool isConstant(Coord eps=EPSILON) const { return are_near(a[0], a[1], eps); }
bool isFinite() const { return IS_FINITE(a[0]) && IS_FINITE(a[1]); }
Coord at0() const { return a[0]; }
@@ -81,10 +79,10 @@ public:
Coord at1() const { return a[1]; }
Coord &at1() { return a[1]; }
- double valueAt(double t) const { return lerp(t, a[0], a[1]); }
- double operator()(double t) const { return valueAt(t); }
+ Coord valueAt(Coord t) const { return lerp(t, a[0], a[1]); }
+ Coord operator()(Coord t) const { return valueAt(t); }
- // not very useful, but required for ShapeConcept
+ // not very useful, but required for FragmentConcept
std::vector<Coord> valueAndDerivatives(Coord t, unsigned n) {
std::vector<Coord> result(n+1, 0.0);
result[0] = valueAt(t);
@@ -107,6 +105,44 @@ public:
double hat() const {
return (a[1] + a[0])/2;
}
+
+ // addition of other Linears
+ Linear &operator+=(Linear const &other) {
+ a[0] += other.a[0];
+ a[1] += other.a[1];
+ return *this;
+ }
+ Linear &operator-=(Linear const &other) {
+ a[0] -= other.a[0];
+ a[1] -= other.a[1];
+ return *this;
+ }
+
+ //
+ Linear &operator+=(Coord x) {
+ a[0] += x; a[1] += x;
+ return *this;
+ }
+ Linear &operator-=(Coord x) {
+ a[0] -= x; a[1] -= x;
+ return *this;
+ }
+ Linear &operator*=(Coord x) {
+ a[0] *= x; a[1] *= x;
+ return *this;
+ }
+ Linear &operator/=(Coord x) {
+ a[0] /= x; a[1] /= x;
+ return *this;
+ }
+ Linear operator-() const {
+ Linear ret(-a[0], -a[1]);
+ return ret;
+ }
+
+ bool operator==(Linear const &other) const {
+ return a[0] == other.a[0] && a[1] == other.a[1];
+ }
};
inline Linear reverse(Linear const &a) { return Linear(a[1], a[0]); }
@@ -115,64 +151,7 @@ inline Linear portion(Linear const &a, Coord from, Coord to) {
return result;
}
-//IMPL: AddableConcept
-inline Linear operator+(Linear const & a, Linear const & b) {
- return Linear(a[0] + b[0], a[1] + b[1]);
-}
-inline Linear operator-(Linear const & a, Linear const & b) {
- return Linear(a[0] - b[0], a[1] - b[1]);
-}
-inline Linear& operator+=(Linear & a, Linear const & b) {
- a[0] += b[0]; a[1] += b[1];
- return a;
-}
-inline Linear& operator-=(Linear & a, Linear const & b) {
- a[0] -= b[0]; a[1] -= b[1];
- return a;
-}
-//IMPL: OffsetableConcept
-inline Linear operator+(Linear const & a, double b) {
- return Linear(a[0] + b, a[1] + b);
-}
-inline Linear operator-(Linear const & a, double b) {
- return Linear(a[0] - b, a[1] - b);
-}
-inline Linear& operator+=(Linear & a, double b) {
- a[0] += b; a[1] += b;
- return a;
-}
-inline Linear& operator-=(Linear & a, double b) {
- a[0] -= b; a[1] -= b;
- return a;
-}
-//IMPL: boost::EqualityComparableConcept
-inline bool operator==(Linear const & a, Linear const & b) {
- return a[0] == b[0] && a[1] == b[1];
-}
-inline bool operator!=(Linear const & a, Linear const & b) {
- return a[0] != b[0] || a[1] != b[1];
-}
-//IMPL: ScalableConcept
-inline Linear operator-(Linear const &a) {
- return Linear(-a[0], -a[1]);
-}
-inline Linear operator*(Linear const & a, double b) {
- return Linear(a[0]*b, a[1]*b);
-}
-inline Linear operator/(Linear const & a, double b) {
- return Linear(a[0]/b, a[1]/b);
-}
-inline Linear operator*=(Linear & a, double b) {
- a[0] *= b; a[1] *= b;
- return a;
-}
-inline Linear operator/=(Linear & a, double b) {
- a[0] /= b; a[1] /= b;
- return a;
-}
-
-}
-#endif
+} // end namespace Geom
#endif //LIB2GEOM_SEEN_LINEAR_H
diff --git a/src/2geom/numeric/fitting-model.h b/src/2geom/numeric/fitting-model.h
index fb96d1d2a..b2ca92ad8 100644
--- a/src/2geom/numeric/fitting-model.h
+++ b/src/2geom/numeric/fitting-model.h
@@ -372,7 +372,6 @@ class LFMSBasis
void instance(SBasis & sb, ConstVectorView const& raw_data) const
{
- sb.clear();
sb.resize(m_order+1);
for (unsigned int i = 0, k = 0; i < raw_data.size(); i+=2, ++k)
{
diff --git a/src/2geom/path-sink.cpp b/src/2geom/path-sink.cpp
index 3b8d407f8..77301b716 100644
--- a/src/2geom/path-sink.cpp
+++ b/src/2geom/path-sink.cpp
@@ -73,8 +73,8 @@ void PathSink::feed(Rect const &r) {
void PathSink::feed(Circle const &e) {
Coord r = e.radius();
Point c = e.center();
- Point a = c + Point(0, c[Y] + r);
- Point b = c + Point(0, c[Y] - r);
+ Point a = c + Point(0, +r);
+ Point b = c + Point(0, -r);
moveTo(a);
arcTo(r, r, 0, false, false, b);
diff --git a/src/2geom/path-sink.h b/src/2geom/path-sink.h
index 17ede18a4..3bdb00783 100644
--- a/src/2geom/path-sink.h
+++ b/src/2geom/path-sink.h
@@ -179,8 +179,10 @@ public:
}
void closePath() {
- _path.close();
- flush();
+ if (_in_path) {
+ _path.close();
+ flush();
+ }
}
void flush() {
diff --git a/src/2geom/path.cpp b/src/2geom/path.cpp
index 871441751..2e2bce9f1 100644
--- a/src/2geom/path.cpp
+++ b/src/2geom/path.cpp
@@ -98,6 +98,24 @@ bool PathInterval::contains(PathTime const &pos) const {
}
}
+PathInterval::size_type PathInterval::curveCount() const
+{
+ if (isDegenerate()) return 0;
+ if (_cross_start) {
+ if (_reverse) {
+ return _path_size - _to.curve_index + _from.curve_index + 1;
+ } else {
+ return _path_size - _from.curve_index + _to.curve_index + 1;
+ }
+ } else {
+ if (_reverse) {
+ return _from.curve_index - _to.curve_index + 1;
+ } else {
+ return _to.curve_index - _from.curve_index + 1;
+ }
+ }
+}
+
PathTime PathInterval::inside(Coord min_dist) const
{
// If there is some node further than min_dist (in time coord) from the ends,
@@ -220,25 +238,25 @@ PathInterval PathInterval::from_direction(PathTime const &from, PathTime const &
Path::Path(Rect const &r)
- : _curves(new Sequence())
+ : _data(new PathData())
, _closing_seg(new ClosingSegment(r.corner(3), r.corner(0)))
, _closed(true)
, _exception_on_stitch(true)
{
for (unsigned i = 0; i < 3; ++i) {
- _curves->push_back(new LineSegment(r.corner(i), r.corner(i+1)));
+ _data->curves.push_back(new LineSegment(r.corner(i), r.corner(i+1)));
}
- _curves->push_back(_closing_seg);
+ _data->curves.push_back(_closing_seg);
}
Path::Path(ConvexHull const &ch)
- : _curves(new Sequence())
+ : _data(new PathData())
, _closing_seg(new ClosingSegment(Point(), Point()))
, _closed(true)
, _exception_on_stitch(true)
{
if (ch.empty()) {
- _curves->push_back(_closing_seg);
+ _data->curves.push_back(_closing_seg);
return;
}
@@ -248,52 +266,52 @@ Path::Path(ConvexHull const &ch)
Point last = ch.front();
for (std::size_t i = 1; i < ch.size(); ++i) {
- _curves->push_back(new LineSegment(last, ch[i]));
+ _data->curves.push_back(new LineSegment(last, ch[i]));
last = ch[i];
}
- _curves->push_back(_closing_seg);
+ _data->curves.push_back(_closing_seg);
_closed = true;
}
Path::Path(Circle const &c)
- : _curves(new Sequence())
+ : _data(new PathData())
, _closing_seg(NULL)
, _closed(true)
, _exception_on_stitch(true)
{
Point p1 = c.pointAt(0);
Point p2 = c.pointAt(M_PI);
- _curves->push_back(new EllipticalArc(p1, c.radius(), c.radius(), 0, false, true, p2));
- _curves->push_back(new EllipticalArc(p2, c.radius(), c.radius(), 0, false, true, p1));
+ _data->curves.push_back(new EllipticalArc(p1, c.radius(), c.radius(), 0, false, true, p2));
+ _data->curves.push_back(new EllipticalArc(p2, c.radius(), c.radius(), 0, false, true, p1));
_closing_seg = new ClosingSegment(p1, p1);
- _curves->push_back(_closing_seg);
+ _data->curves.push_back(_closing_seg);
}
Path::Path(Ellipse const &e)
- : _curves(new Sequence())
+ : _data(new PathData())
, _closing_seg(NULL)
, _closed(true)
, _exception_on_stitch(true)
{
Point p1 = e.pointAt(0);
Point p2 = e.pointAt(M_PI);
- _curves->push_back(new EllipticalArc(p1, e.rays(), e.rotationAngle(), false, true, p2));
- _curves->push_back(new EllipticalArc(p2, e.rays(), e.rotationAngle(), false, true, p1));
+ _data->curves.push_back(new EllipticalArc(p1, e.rays(), e.rotationAngle(), false, true, p2));
+ _data->curves.push_back(new EllipticalArc(p2, e.rays(), e.rotationAngle(), false, true, p1));
_closing_seg = new ClosingSegment(p1, p1);
- _curves->push_back(_closing_seg);
+ _data->curves.push_back(_closing_seg);
}
void Path::close(bool c)
{
if (c == _closed) return;
- if (c && _curves->size() >= 2) {
+ if (c && _data->curves.size() >= 2) {
// when closing, if last segment is linear and ends at initial point,
// replace it with the closing segment
- Sequence::iterator last = _curves->end() - 2;
+ Sequence::iterator last = _data->curves.end() - 2;
if (last->isLineSegment() && last->finalPoint() == initialPoint()) {
_closing_seg->setInitial(last->initialPoint());
- _curves->erase(last);
+ _data->curves.erase(last);
}
}
_closed = c;
@@ -302,27 +320,35 @@ void Path::close(bool c)
void Path::clear()
{
_unshare();
- _curves->pop_back().release();
- _curves->clear();
+ _data->curves.pop_back().release();
+ _data->curves.clear();
_closing_seg->setInitial(Point(0, 0));
_closing_seg->setFinal(Point(0, 0));
- _curves->push_back(_closing_seg);
+ _data->curves.push_back(_closing_seg);
_closed = false;
}
OptRect Path::boundsFast() const
{
OptRect bounds;
- if (empty())
+ if (empty()) {
return bounds;
+ }
+ // if the path is not empty, we look for cached bounds
+ if (_data->fast_bounds) {
+ return _data->fast_bounds;
+ }
+
bounds = front().boundsFast();
const_iterator iter = begin();
- // the closing path segment can be ignored, because it will always lie within the bbox of the rest of the path
+ // the closing path segment can be ignored, because it will always
+ // lie within the bbox of the rest of the path
if (iter != end()) {
for (++iter; iter != end(); ++iter) {
bounds.unionWith(iter->boundsFast());
}
}
+ _data->fast_bounds = bounds;
return bounds;
}
@@ -377,11 +403,11 @@ bool Path::operator==(Path const &other) const
return true;
if (_closed != other._closed)
return false;
- return *_curves == *other._curves;
+ return _data->curves == other._data->curves;
}
void Path::start(Point const &p) {
- if (_curves->size() > 1) {
+ if (_data->curves.size() > 1) {
clear();
}
_closing_seg->setInitial(p);
@@ -442,86 +468,106 @@ std::vector<PathTime> Path::roots(Coord v, Dim2 d) const
// Instead of O(N^2), this takes O(N + X), where X is the number of overlaps
// between the bounding boxes of curves.
-struct CurveSweepTraits {
- struct Bound {
- Rect r;
+struct CurveIntersectionSweepSet
+{
+public:
+ struct CurveRecord {
+ boost::intrusive::list_member_hook<> _hook;
+ Curve const *curve;
+ Rect bounds;
std::size_t index;
- int which;
+ unsigned which;
+
+ CurveRecord(Curve const *pc, std::size_t idx, unsigned w)
+ : curve(pc)
+ , bounds(curve->boundsFast())
+ , index(idx)
+ , which(w)
+ {}
};
- typedef std::less<Coord> Compare;
- inline static Coord entry_value(Bound const &b) { return b.r[X].min(); }
- inline static Coord exit_value(Bound const &b) { return b.r[X].max(); }
-};
-class CurveSweeper
- : public Sweeper<Curve const *, CurveSweepTraits>
-{
-public:
- CurveSweeper(Path const &a, Path const &b, std::vector<PathIntersection> &result, Coord prec)
+ typedef std::vector<CurveRecord>::const_iterator ItemIterator;
+
+ CurveIntersectionSweepSet(std::vector<PathIntersection> &result,
+ Path const &a, Path const &b, Coord precision)
: _result(result)
- , _precision(prec)
+ , _precision(precision)
+ , _sweep_dir(X)
{
- for (std::size_t i = 0; i < a.size(); ++i) {
- Bound bound;
- bound.r = a[i].boundsFast();
- bound.index = i;
- bound.which = 0;
- insert(bound, &a[i]);
+ std::size_t asz = a.size(), bsz = b.size();
+ _records.reserve(asz + bsz);
+
+ for (std::size_t i = 0; i < asz; ++i) {
+ _records.push_back(CurveRecord(&a[i], i, 0));
}
- for (std::size_t i = 0; i < b.size(); ++i) {
- Bound bound;
- bound.r = b[i].boundsFast();
- bound.index = i;
- bound.which = 1;
- insert(bound, &b[i]);
+ for (std::size_t i = 0; i < bsz; ++i) {
+ _records.push_back(CurveRecord(&b[i], i, 1));
}
- }
-protected:
- void _enter(Record const &record) {
- int which = record.bound.which;
-
- for (RecordList::iterator i = _active_items.begin(); i != _active_items.end(); ++i) {
- // do not intersect in the same path
- if (i->bound.which == which) continue;
- // do not intersect if boxes do not overlap in Y
- if (!record.bound.r[Y].intersects(i->bound.r[Y])) continue;
-
- std::vector<CurveIntersection> cx;
- int ia = record.bound.index;
- int ib = i->bound.index;
+ OptRect abb = a.boundsFast() | b.boundsFast();
+ if (abb && abb->height() > abb->width()) {
+ _sweep_dir = Y;
+ }
+ }
- if (which == 0) {
- cx = record.item->intersect(*i->item, _precision);
- } else {
- cx = i->item->intersect(*record.item, _precision);
- std::swap(ia, ib);
- }
+ std::vector<CurveRecord> const &items() { return _records; }
+ Interval itemBounds(ItemIterator ii) {
+ return ii->bounds[_sweep_dir];
+ }
- for (std::size_t ci = 0; ci < cx.size(); ++ci) {
- PathTime a(ia, cx[ci].first), b(ib, cx[ci].second);
- PathIntersection px(a, b, cx[ci].point());
- _result.push_back(px);
+ void addActiveItem(ItemIterator ii) {
+ unsigned w = ii->which;
+ unsigned ow = (w+1) % 2;
+
+ _active[w].push_back(const_cast<CurveRecord&>(*ii));
+
+ for (ActiveCurveList::iterator i = _active[ow].begin(); i != _active[ow].end(); ++i) {
+ if (!ii->bounds.intersects(i->bounds)) continue;
+ std::vector<CurveIntersection> cx = ii->curve->intersect(*i->curve, _precision);
+ for (std::size_t k = 0; k < cx.size(); ++k) {
+ PathTime tw(ii->index, cx[k].first), tow(i->index, cx[k].second);
+ _result.push_back(PathIntersection(
+ w == 0 ? tw : tow,
+ w == 0 ? tow : tw,
+ cx[k].point()));
}
}
}
+ void removeActiveItem(ItemIterator ii) {
+ ActiveCurveList &acl = _active[ii->which];
+ acl.erase(acl.iterator_to(*ii));
+ }
private:
+ typedef boost::intrusive::list
+ < CurveRecord
+ , boost::intrusive::member_hook
+ < CurveRecord
+ , boost::intrusive::list_member_hook<>
+ , &CurveRecord::_hook
+ >
+ > ActiveCurveList;
+
+ std::vector<CurveRecord> _records;
std::vector<PathIntersection> &_result;
+ ActiveCurveList _active[2];
Coord _precision;
+ Dim2 _sweep_dir;
};
std::vector<PathIntersection> Path::intersect(Path const &other, Coord precision) const
{
std::vector<PathIntersection> result;
- CurveSweeper sweeper(*this, other, result, precision);
+ CurveIntersectionSweepSet cisset(result, *this, other, precision);
+ Sweeper<CurveIntersectionSweepSet> sweeper(cisset);
sweeper.process();
// preprocessing to remove duplicate intersections at endpoints
+ std::size_t asz = size(), bsz = other.size();
for (std::size_t i = 0; i < result.size(); ++i) {
- result[i].first.normalizeForward(size());
- result[i].second.normalizeForward(other.size());
+ result[i].first.normalizeForward(asz);
+ result[i].second.normalizeForward(bsz);
}
std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()), result.end());
@@ -672,7 +718,7 @@ PathTime Path::nearestTime(Point const &p, Coord *dist) const
Coord mindist = std::numeric_limits<Coord>::max();
PathTime ret;
- if (_curves->size() == 1) {
+ if (_data->curves.size() == 1) {
// naked moveto
ret.curve_index = 0;
ret.t = 0;
@@ -701,6 +747,16 @@ PathTime Path::nearestTime(Point const &p, Coord *dist) const
return ret;
}
+std::vector<Point> Path::nodes() const
+{
+ std::vector<Point> result;
+ size_type path_size = size_closed();
+ for (size_type i = 0; i < path_size; ++i) {
+ result.push_back(_data->curves[i].initialPoint());
+ }
+ return result;
+}
+
void Path::appendPortionTo(Path &ret, double from, double to) const
{
if (!(from >= 0 && to >= 0)) {
@@ -797,16 +853,16 @@ Path Path::reversed() const
Path ret(finalPoint());
if (empty()) return ret;
- ret._curves->pop_back(); // this also deletes the closing segment from ret
+ ret._data->curves.pop_back(); // this also deletes the closing segment from ret
- RIter iter(_includesClosingSegment() ? _curves->end() : _curves->end() - 1);
- RIter rend(_curves->begin());
+ RIter iter(_includesClosingSegment() ? _data->curves.end() : _data->curves.end() - 1);
+ RIter rend(_data->curves.begin());
if (_closed) {
// when the path is closed, there are two cases:
if (front().isLineSegment()) {
// 1. initial segment is linear: it becomes the new closing segment.
- rend = RIter(_curves->begin() + 1);
+ rend = RIter(_data->curves.begin() + 1);
ret._closing_seg = new ClosingSegment(front().finalPoint(), front().initialPoint());
} else {
// 2. initial segment is not linear: the closing segment becomes degenerate.
@@ -820,9 +876,9 @@ Path Path::reversed() const
}
for (; iter != rend; ++iter) {
- ret._curves->push_back(iter->reverse());
+ ret._data->curves.push_back(iter->reverse());
}
- ret._curves->push_back(ret._closing_seg);
+ ret._data->curves.push_back(ret._closing_seg);
ret._closed = _closed;
return ret;
}
@@ -896,10 +952,10 @@ void Path::replace(iterator first, iterator last, Path const &path)
void Path::snapEnds(Coord precision)
{
if (!_closed) return;
- if (_curves->size() > 1 && are_near(_closing_seg->length(precision), 0, precision)) {
+ if (_data->curves.size() > 1 && are_near(_closing_seg->length(precision), 0, precision)) {
_unshare();
_closing_seg->setInitial(_closing_seg->finalPoint());
- (_curves->end() - 1)->setFinal(_closing_seg->finalPoint());
+ (_data->curves.end() - 1)->setFinal(_closing_seg->finalPoint());
}
}
@@ -908,7 +964,7 @@ void Path::snapEnds(Coord precision)
void Path::do_update(Sequence::iterator first, Sequence::iterator last, Sequence &source)
{
// TODO: handle cases where first > last in closed paths?
- bool last_beyond_closing_segment = (last == _curves->end());
+ bool last_beyond_closing_segment = (last == _data->curves.end());
// special case:
// if do_update replaces the closing segment, we have to regenerate it
@@ -916,7 +972,7 @@ void Path::do_update(Sequence::iterator first, Sequence::iterator last, Sequence
if (first == last) return; // nothing to do
// only removing some segments
- if ((!_closed && first == _curves->begin()) || (!_closed && last == _curves->end() - 1) || last_beyond_closing_segment) {
+ if ((!_closed && first == _data->curves.begin()) || (!_closed && last == _data->curves.end() - 1) || last_beyond_closing_segment) {
// just adjust the closing segment
// do nothing
} else if (first->initialPoint() != (last - 1)->finalPoint()) {
@@ -927,17 +983,17 @@ void Path::do_update(Sequence::iterator first, Sequence::iterator last, Sequence
}
} else {
// replacing
- if (first == _curves->begin() && last == _curves->end()) {
+ if (first == _data->curves.begin() && last == _data->curves.end()) {
// special case: replacing everything should work the same in open and closed curves
- _curves->erase(_curves->begin(), _curves->end() - 1);
+ _data->curves.erase(_data->curves.begin(), _data->curves.end() - 1);
_closing_seg->setFinal(source.front().initialPoint());
_closing_seg->setInitial(source.back().finalPoint());
- _curves->transfer(_curves->begin(), source.begin(), source.end(), source);
+ _data->curves.transfer(_data->curves.begin(), source.begin(), source.end(), source);
return;
}
// stitch in front
- if (!_closed && first == _curves->begin()) {
+ if (!_closed && first == _data->curves.begin()) {
// not necessary to stitch in front
} else if (first->initialPoint() != source.front().initialPoint()) {
if (_exception_on_stitch) {
@@ -947,7 +1003,7 @@ void Path::do_update(Sequence::iterator first, Sequence::iterator last, Sequence
}
// stitch at the end
- if ((!_closed && last == _curves->end() - 1) || last_beyond_closing_segment) {
+ if ((!_closed && last == _data->curves.end() - 1) || last_beyond_closing_segment) {
// repurpose the closing segment as the stitch segment
// do nothing
} else if (source.back().finalPoint() != (last - 1)->finalPoint()) {
@@ -962,8 +1018,8 @@ void Path::do_update(Sequence::iterator first, Sequence::iterator last, Sequence
if (last_beyond_closing_segment) {
--last;
}
- _curves->erase(first, last);
- _curves->transfer(first, source.begin(), source.end(), source);
+ _data->curves.erase(first, last);
+ _data->curves.transfer(first, source.begin(), source.end(), source);
// adjust closing segment
if (size_open() == 0) {
@@ -978,7 +1034,7 @@ void Path::do_update(Sequence::iterator first, Sequence::iterator last, Sequence
void Path::do_append(Curve *c)
{
- if (&_curves->front() == _closing_seg) {
+ if (&_data->curves.front() == _closing_seg) {
_closing_seg->setFinal(c->initialPoint());
} else {
// if we can't freely move the closing segment, we check whether
@@ -994,20 +1050,20 @@ void Path::do_append(Curve *c)
return;
}
}
- _curves->insert(_curves->end() - 1, c);
+ _data->curves.insert(_data->curves.end() - 1, c);
_closing_seg->setInitial(c->finalPoint());
}
void Path::checkContinuity() const
{
- Sequence::const_iterator i = _curves->begin(), j = _curves->begin();
+ Sequence::const_iterator i = _data->curves.begin(), j = _data->curves.begin();
++j;
- for (; j != _curves->end(); ++i, ++j) {
+ for (; j != _data->curves.end(); ++i, ++j) {
if (i->finalPoint() != j->initialPoint()) {
THROW_CONTINUITYERROR();
}
}
- if (_curves->front().initialPoint() != _curves->back().finalPoint()) {
+ if (_data->curves.front().initialPoint() != _data->curves.back().finalPoint()) {
THROW_CONTINUITYERROR();
}
}
@@ -1040,6 +1096,16 @@ Piecewise<D2<SBasis> > paths_to_pw(PathVector const &paths)
return ret;
}
+bool are_near(Path const &a, Path const &b, Coord precision)
+{
+ if (a.size() != b.size()) return false;
+
+ for (unsigned i = 0; i < a.size(); ++i) {
+ if (!a[i].isNear(b[i], precision)) return false;
+ }
+ return true;
+}
+
std::ostream &operator<<(std::ostream &out, Path const &path)
{
SVGPathWriter pw;
diff --git a/src/2geom/path.h b/src/2geom/path.h
index 3ca43e0e5..3552ec43e 100644
--- a/src/2geom/path.h
+++ b/src/2geom/path.h
@@ -55,6 +55,11 @@ namespace PathInternal {
typedef boost::ptr_vector<Curve> Sequence;
+struct PathData {
+ Sequence curves;
+ OptRect fast_bounds;
+};
+
template <typename P>
class BaseIterator
: public boost::random_access_iterator_helper
@@ -221,6 +226,7 @@ public:
}
size_type pathSize() const { return _path_size; }
+ size_type curveCount() const;
private:
PathTime _from, _to;
@@ -316,6 +322,7 @@ class Path
: boost::equality_comparable< Path >
{
public:
+ typedef PathInternal::PathData PathData;
typedef PathInternal::Sequence Sequence;
typedef PathInternal::BaseIterator<Path> iterator;
typedef PathInternal::BaseIterator<Path const> const_iterator;
@@ -342,31 +349,31 @@ public:
/// Construct an empty path starting at the specified point.
explicit Path(Point const &p = Point())
- : _curves(new Sequence())
+ : _data(new PathData())
, _closing_seg(new ClosingSegment(p, p))
, _closed(false)
, _exception_on_stitch(true)
{
- _curves->push_back(_closing_seg);
+ _data->curves.push_back(_closing_seg);
}
/// Construct a path containing a range of curves.
template <typename Iter>
Path(Iter first, Iter last, bool closed = false, bool stitch = false)
- : _curves(new Sequence())
+ : _data(new PathData())
, _closed(closed)
, _exception_on_stitch(!stitch)
{
for (Iter i = first; i != last; ++i) {
- _curves->push_back(i->duplicate());
+ _data->curves.push_back(i->duplicate());
}
- if (!_curves->empty()) {
- _closing_seg = new ClosingSegment(_curves->back().finalPoint(),
- _curves->front().initialPoint());
+ if (!_data->curves.empty()) {
+ _closing_seg = new ClosingSegment(_data->curves.back().finalPoint(),
+ _data->curves.front().initialPoint());
} else {
_closing_seg = new ClosingSegment();
}
- _curves->push_back(_closing_seg);
+ _data->curves.push_back(_closing_seg);
}
/// Create a path from a rectangle.
@@ -386,7 +393,7 @@ public:
* @todo Add noexcept specifiers for C++11 */
void swap(Path &other) throw() {
using std::swap;
- swap(other._curves, _curves);
+ swap(other._data, _data);
swap(other._closing_seg, _closing_seg);
swap(other._closed, _closed);
swap(other._exception_on_stitch, _exception_on_stitch);
@@ -396,26 +403,26 @@ public:
friend inline void swap(Path &a, Path &b) throw() { a.swap(b); }
/** @brief Access a curve by index */
- Curve const &operator[](size_type i) const { return (*_curves)[i]; }
+ Curve const &operator[](size_type i) const { return _data->curves[i]; }
/** @brief Access a curve by index */
- Curve const &at(size_type i) const { return _curves->at(i); }
+ Curve const &at(size_type i) const { return _data->curves.at(i); }
/** @brief Access the first curve in the path.
* Since the curve always contains at least a degenerate closing segment,
* it is always safe to use this method. */
- Curve const &front() const { return _curves->front(); }
+ Curve const &front() const { return _data->curves.front(); }
/// Alias for front().
- Curve const &initialCurve() const { return _curves->front(); }
+ Curve const &initialCurve() const { return _data->curves.front(); }
/** @brief Access the last curve in the path. */
Curve const &back() const { return back_default(); }
Curve const &back_open() const {
- if (empty()) return _curves->back();
- return (*_curves)[_curves->size() - 2];
+ if (empty()) return _data->curves.back();
+ return _data->curves[_data->curves.size() - 2];
}
Curve const &back_closed() const {
return _closing_seg->isDegenerate()
- ? (*_curves)[_curves->size() - 2]
- : (*_curves)[_curves->size() - 1];
+ ? _data->curves[_data->curves.size() - 2]
+ : _data->curves[_data->curves.size() - 1];
}
Curve const &back_default() const {
return _includesClosingSegment()
@@ -436,13 +443,13 @@ public:
iterator end_closed() { return iterator(*this, size_closed()); }
/// Size without the closing segment, even if the path is closed.
- size_type size_open() const { return _curves->size() - 1; }
+ size_type size_open() const { return _data->curves.size() - 1; }
/** @brief Size with the closing segment, if it makes a difference.
* If the closing segment is degenerate, i.e. its initial and final points
* are exactly equal, then it is not included in this size. */
size_type size_closed() const {
- return _closing_seg->isDegenerate() ? _curves->size() - 1 : _curves->size();
+ return _closing_seg->isDegenerate() ? _data->curves.size() - 1 : _data->curves.size();
}
/// Natural size of the path.
@@ -452,7 +459,7 @@ public:
/// Natural size of the path.
size_type size() const { return size_default(); }
- size_type max_size() const { return _curves->max_size() - 1; }
+ size_type max_size() const { return _data->curves.max_size() - 1; }
/** @brief Check whether path is empty.
* The path is empty if it contains only the closing segment, which according
@@ -460,7 +467,7 @@ public:
* containers, two empty paths are not necessarily identical, because the
* degenerate closing segment may be at a different point, affecting the operation
* of methods such as appendNew(). */
- bool empty() const { return (_curves->size() == 1); }
+ bool empty() const { return (_data->curves.size() == 1); }
/// Check whether the path is closed.
bool closed() const { return _closed; }
@@ -497,8 +504,8 @@ public:
Path &operator*=(T const &tr) {
BOOST_CONCEPT_ASSERT((TransformConcept<T>));
_unshare();
- for (std::size_t i = 0; i < _curves->size(); ++i) {
- (*_curves)[i] *= tr;
+ for (std::size_t i = 0; i < _data->curves.size(); ++i) {
+ _data->curves[i] *= tr;
}
return *this;
}
@@ -570,6 +577,8 @@ public:
PathTime nearestTime(Point const &p, Coord *dist = NULL) const;
std::vector<Coord> nearestTimePerCurve(Point const &p) const;
+ std::vector<Point> nodes() const;
+
void appendPortionTo(Path &p, Coord f, Coord t) const;
/** @brief Append a subset of this path to another path.
@@ -662,13 +671,13 @@ public:
void setInitial(Point const &p) {
_unshare();
_closed = false;
- _curves->front().setInitial(p);
+ _data->curves.front().setInitial(p);
_closing_seg->setFinal(p);
}
void setFinal(Point const &p) {
_unshare();
_closed = false;
- (*_curves)[size_open() - 1].setFinal(p);
+ _data->curves[size_open() - 1].setFinal(p);
_closing_seg->setInitial(p);
}
@@ -804,10 +813,10 @@ public:
private:
static Sequence::iterator seq_iter(iterator const &iter) {
- return iter.path->_curves->begin() + iter.index;
+ return iter.path->_data->curves.begin() + iter.index;
}
static Sequence::const_iterator seq_iter(const_iterator const &iter) {
- return iter.path->_curves->begin() + iter.index;
+ return iter.path->_data->curves.begin() + iter.index;
}
// whether the closing segment is part of the path
@@ -815,10 +824,13 @@ private:
return _closed && !_closing_seg->isDegenerate();
}
void _unshare() {
- if (!_curves.unique()) {
- _curves.reset(new Sequence(*_curves));
- _closing_seg = static_cast<ClosingSegment*>(&_curves->back());
+ // Called before every mutation.
+ // Ensure we have our own copy of curve data and reset cached values
+ if (!_data.unique()) {
+ _data.reset(new PathData(*_data));
+ _closing_seg = static_cast<ClosingSegment*>(&_data->curves.back());
}
+ _data->fast_bounds = OptRect();
}
PathTime _factorTime(Coord t) const;
@@ -828,7 +840,7 @@ private:
// n.b. takes ownership of curve object
void do_append(Curve *curve);
- boost::shared_ptr<Sequence> _curves;
+ boost::shared_ptr<PathData> _data;
ClosingSegment *_closing_seg;
bool _closed;
bool _exception_on_stitch;
@@ -841,6 +853,8 @@ inline Coord nearest_time(Point const &p, Path const &c) {
return pt.curve_index + pt.t;
}
+bool are_near(Path const &a, Path const &b, Coord precision = EPSILON);
+
std::ostream &operator<<(std::ostream &out, Path const &path);
} // end namespace Geom
diff --git a/src/2geom/pathvector.cpp b/src/2geom/pathvector.cpp
index bff201c71..28ab26237 100644
--- a/src/2geom/pathvector.cpp
+++ b/src/2geom/pathvector.cpp
@@ -35,6 +35,7 @@
#include <2geom/path.h>
#include <2geom/pathvector.h>
#include <2geom/svg-path-writer.h>
+#include <2geom/sweeper.h>
namespace Geom {
@@ -133,19 +134,96 @@ void PathVector::snapEnds(Coord precision)
}
}
-std::vector<PVIntersection> PathVector::intersect(PathVector const &other, Coord precision) const
-{
- typedef PathVectorTime PVPos;
- std::vector<PVIntersection> result;
- for (std::size_t i = 0; i < size(); ++i) {
- for (std::size_t j = 0; j < other.size(); ++j) {
- std::vector<PathIntersection> xs = (*this)[i].intersect(other[j], precision);
- for (std::size_t k = 0; k < xs.size(); ++k) {
- PVIntersection pvx(PVPos(i, xs[k].first), PVPos(j, xs[k].second), xs[k].point());
- result.push_back(pvx);
+// sweepline optimization
+// this is very similar to CurveIntersectionSweepSet in path.cpp
+// should probably be merged
+class PathIntersectionSweepSet {
+public:
+ struct PathRecord {
+ boost::intrusive::list_member_hook<> _hook;
+ Path const *path;
+ std::size_t index;
+ unsigned which;
+
+ PathRecord(Path const &p, std::size_t i, unsigned w)
+ : path(&p)
+ , index(i)
+ , which(w)
+ {}
+ };
+
+ typedef std::vector<PathRecord>::iterator ItemIterator;
+
+ PathIntersectionSweepSet(std::vector<PVIntersection> &result,
+ PathVector const &a, PathVector const &b, Coord precision)
+ : _result(result)
+ , _precision(precision)
+ {
+ _records.reserve(a.size() + b.size());
+ for (std::size_t i = 0; i < a.size(); ++i) {
+ _records.push_back(PathRecord(a[i], i, 0));
+ }
+ for (std::size_t i = 0; i < b.size(); ++i) {
+ _records.push_back(PathRecord(b[i], i, 1));
+ }
+ }
+
+ std::vector<PathRecord> &items() { return _records; }
+
+ Interval itemBounds(ItemIterator ii) {
+ OptRect r = ii->path->boundsFast();
+ return (*r)[X];
+ }
+
+ void addActiveItem(ItemIterator ii) {
+ unsigned w = ii->which;
+ unsigned ow = (ii->which + 1) % 2;
+
+ for (ActivePathList::iterator i = _active[ow].begin(); i != _active[ow].end(); ++i) {
+ if (!ii->path->boundsFast().intersects(i->path->boundsFast())) continue;
+ std::vector<PathIntersection> px = ii->path->intersect(*i->path, _precision);
+ for (std::size_t k = 0; k < px.size(); ++k) {
+ PathVectorTime tw(ii->index, px[k].first), tow(i->index, px[k].second);
+ _result.push_back(PVIntersection(
+ w == 0 ? tw : tow,
+ w == 0 ? tow : tw,
+ px[k].point()));
}
}
+ _active[w].push_back(*ii);
+ }
+
+ void removeActiveItem(ItemIterator ii) {
+ ActivePathList &apl = _active[ii->which];
+ apl.erase(apl.iterator_to(*ii));
}
+
+private:
+ typedef boost::intrusive::list
+ < PathRecord
+ , boost::intrusive::member_hook
+ < PathRecord
+ , boost::intrusive::list_member_hook<>
+ , &PathRecord::_hook
+ >
+ > ActivePathList;
+
+ std::vector<PVIntersection> &_result;
+ std::vector<PathRecord> _records;
+ ActivePathList _active[2];
+ Coord _precision;
+};
+
+std::vector<PVIntersection> PathVector::intersect(PathVector const &other, Coord precision) const
+{
+ std::vector<PVIntersection> result;
+
+ PathIntersectionSweepSet pisset(result, *this, other, precision);
+ Sweeper<PathIntersectionSweepSet> sweeper(pisset);
+ sweeper.process();
+
+ std::sort(result.begin(), result.end());
+
return result;
}
@@ -153,6 +231,7 @@ int PathVector::winding(Point const &p) const
{
int wind = 0;
for (const_iterator i = begin(); i != end(); ++i) {
+ if (!i->boundsFast().contains(p)) continue;
wind += i->winding(p);
}
return wind;
@@ -201,6 +280,18 @@ std::vector<PathVectorTime> PathVector::allNearestTimes(Point const &p, Coord *d
return retval;
}
+std::vector<Point> PathVector::nodes() const
+{
+ std::vector<Point> result;
+ for (size_type i = 0; i < size(); ++i) {
+ size_type path_size = (*this)[i].size_closed();
+ for (size_type j = 0; j < path_size; ++j) {
+ result.push_back((*this)[i][j].initialPoint());
+ }
+ }
+ return result;
+}
+
PathVectorTime PathVector::_factorTime(Coord t) const
{
PathVectorTime ret;
diff --git a/src/2geom/pathvector.h b/src/2geom/pathvector.h
index 108f2aa05..0cbe5bf52 100644
--- a/src/2geom/pathvector.h
+++ b/src/2geom/pathvector.h
@@ -272,6 +272,8 @@ public:
boost::optional<PathVectorTime> nearestTime(Point const &p, Coord *dist = NULL) const;
std::vector<PathVectorTime> allNearestTimes(Point const &p, Coord *dist = NULL) const;
+ std::vector<Point> nodes() const;
+
private:
PathVectorTime _factorTime(Coord t) const;
diff --git a/src/2geom/piecewise.h b/src/2geom/piecewise.h
index a5a65a9fe..3a12671e0 100644
--- a/src/2geom/piecewise.h
+++ b/src/2geom/piecewise.h
@@ -222,7 +222,7 @@ class Piecewise {
inline void setDomain(Interval dom) {
if(empty()) return;
/* dom can not be empty
- if(dom.isEmpty()) {
+ if(dom.empty()) {
cuts.clear(); segs.clear();
return;
}*/
diff --git a/src/2geom/ray.h b/src/2geom/ray.h
index a336e3132..4e60fd814 100644
--- a/src/2geom/ray.h
+++ b/src/2geom/ray.h
@@ -53,61 +53,62 @@ namespace Geom
class Ray {
private:
Point _origin;
- Point _versor;
+ Point _vector;
public:
- Ray() : _origin(0,0), _versor(1,0) {}
+ Ray() : _origin(0,0), _vector(1,0) {}
Ray(Point const& origin, Coord angle)
: _origin(origin)
{
- sincos(angle, _versor[Y], _versor[X]);
+ sincos(angle, _vector[Y], _vector[X]);
}
Ray(Point const& A, Point const& B) {
setPoints(A, B);
}
Point origin() const { return _origin; }
- Point versor() const { return _versor; }
+ Point vector() const { return _vector; }
+ Point versor() const { return _vector.normalized(); }
void setOrigin(Point const &o) { _origin = o; }
- void setVersor(Point const& v) { _versor = v; }
- Coord angle() const { return std::atan2(_versor[Y], _versor[X]); }
- void setAngle(Coord a) { sincos(a, _versor[Y], _versor[X]); }
+ void setVector(Point const& v) { _vector = v; }
+ Coord angle() const { return std::atan2(_vector[Y], _vector[X]); }
+ void setAngle(Coord a) { sincos(a, _vector[Y], _vector[X]); }
void setPoints(Point const &a, Point const &b) {
_origin = a;
- _versor = b - a;
- if (are_near(_versor, Point(0,0)) )
- _versor = Point(0,0);
+ _vector = b - a;
+ if (are_near(_vector, Point(0,0)) )
+ _vector = Point(0,0);
else
- _versor.normalize();
+ _vector.normalize();
}
bool isDegenerate() const {
- return ( _versor[X] == 0 && _versor[Y] == 0 );
+ return ( _vector[X] == 0 && _vector[Y] == 0 );
}
Point pointAt(Coord t) const {
- return _origin + _versor * t;
+ return _origin + _vector * t;
}
Coord valueAt(Coord t, Dim2 d) const {
- return _origin[d] + _versor[d] * t;
+ return _origin[d] + _vector[d] * t;
}
std::vector<Coord> roots(Coord v, Dim2 d) const {
std::vector<Coord> result;
- if ( _versor[d] != 0 ) {
- double t = (v - _origin[d]) / _versor[d];
+ if ( _vector[d] != 0 ) {
+ double t = (v - _origin[d]) / _vector[d];
if (t >= 0) result.push_back(t);
- } else if (_versor[(d+1)%2] == v) {
+ } else if (_vector[(d+1)%2] == v) {
THROW_INFINITESOLUTIONS();
}
return result;
}
Coord nearestTime(Point const& point) const {
if ( isDegenerate() ) return 0;
- double t = dot(point - _origin, _versor);
+ double t = dot(point - _origin, _vector);
if (t < 0) t = 0;
return t;
}
Ray reverse() const {
Ray result;
result.setOrigin(_origin);
- result.setVersor(-_versor);
+ result.setVector(-_vector);
return result;
}
Curve *portion(Coord f, Coord t) const {
@@ -117,7 +118,7 @@ public:
return LineSegment(pointAt(f), pointAt(t));
}
Ray transformed(Affine const& m) const {
- return Ray(_origin * m, (_origin + _versor) * m);
+ return Ray(_origin * m, (_origin + _vector) * m);
}
}; // end class Ray
@@ -134,7 +135,7 @@ bool are_near(Point const& _point, Ray const& _ray, double eps = EPSILON) {
inline
bool are_same(Ray const& r1, Ray const& r2, double eps = EPSILON) {
- return are_near(r1.versor(), r2.versor(), eps)
+ return are_near(r1.vector(), r2.vector(), eps)
&& are_near(r1.origin(), r2.origin(), eps);
}
@@ -142,7 +143,7 @@ bool are_same(Ray const& r1, Ray const& r2, double eps = EPSILON) {
// the returned value is an angle in the interval [0, 2PI[
inline
double angle_between(Ray const& r1, Ray const& r2, bool cw = true) {
- double angle = angle_between(r1.versor(), r2.versor());
+ double angle = angle_between(r1.vector(), r2.vector());
if (angle < 0) angle += 2*M_PI;
if (!cw) angle = 2*M_PI - angle;
return angle;
@@ -170,7 +171,7 @@ Ray make_angle_bisector_ray(Ray const& r1, Ray const& r2, bool cw = true)
THROW_RANGEERROR("passed rays do not have the same origin");
}
- Ray bisector(r1.origin(), r1.origin() + r1.versor() * Rotate(angle_between(r1, r2) / 2.0));
+ Ray bisector(r1.origin(), r1.origin() + r1.vector() * Rotate(angle_between(r1, r2) / 2.0));
return (cw ? bisector : bisector.reverse());
}
diff --git a/src/2geom/rect.cpp b/src/2geom/rect.cpp
index 383e72c8e..5a821e9f9 100644
--- a/src/2geom/rect.cpp
+++ b/src/2geom/rect.cpp
@@ -30,9 +30,56 @@
*/
#include <2geom/rect.h>
+#include <2geom/transforms.h>
namespace Geom {
+Point align_factors(Align g) {
+ Point p;
+ switch (g) {
+ case ALIGN_XMIN_YMIN:
+ p[X] = 0.0;
+ p[Y] = 0.0;
+ break;
+ case ALIGN_XMID_YMIN:
+ p[X] = 0.5;
+ p[Y] = 0.0;
+ break;
+ case ALIGN_XMAX_YMIN:
+ p[X] = 1.0;
+ p[Y] = 0.0;
+ break;
+ case ALIGN_XMIN_YMID:
+ p[X] = 0.0;
+ p[Y] = 0.5;
+ break;
+ case ALIGN_XMID_YMID:
+ p[X] = 0.5;
+ p[Y] = 0.5;
+ break;
+ case ALIGN_XMAX_YMID:
+ p[X] = 1.0;
+ p[Y] = 0.5;
+ break;
+ case ALIGN_XMIN_YMAX:
+ p[X] = 0.0;
+ p[Y] = 1.0;
+ break;
+ case ALIGN_XMID_YMAX:
+ p[X] = 0.5;
+ p[Y] = 1.0;
+ break;
+ case ALIGN_XMAX_YMAX:
+ p[X] = 1.0;
+ p[Y] = 1.0;
+ break;
+ default:
+ break;
+ }
+ return p;
+}
+
+
/** @brief Transform the rectangle by an affine.
* The result of the transformation might not be axis-aligned. The return value
* of this operation will be the smallest axis-aligned rectangle containing
@@ -49,6 +96,37 @@ Rect &Rect::operator*=(Affine const &m) {
return *this;
}
+Affine Rect::transformTo(Rect const &viewport, Aspect const &aspect) const
+{
+ // 1. translate viewbox to origin
+ Geom::Affine total = Translate(-min());
+
+ // 2. compute scale
+ Geom::Point vdims = viewport.dimensions();
+ Geom::Point dims = dimensions();
+ Geom::Scale scale(vdims[X] / dims[X], vdims[Y] / dims[Y]);
+
+ if (aspect.align == ALIGN_NONE) {
+ // apply non-uniform scale
+ total *= scale * Translate(viewport.min());
+ } else {
+ double uscale = 0;
+ if (aspect.expansion == EXPANSION_MEET) {
+ uscale = std::min(scale[X], scale[Y]);
+ } else {
+ uscale = std::max(scale[X], scale[Y]);
+ }
+ scale = Scale(uscale);
+
+ // compute offset for align
+ Geom::Point offset = vdims - dims * scale;
+ offset *= Scale(align_factors(aspect.align));
+ total *= scale * Translate(viewport.min() + offset);
+ }
+
+ return total;
+}
+
Coord distanceSq(Point const &p, Rect const &rect)
{
double dx = 0, dy = 0;
diff --git a/src/2geom/rect.h b/src/2geom/rect.h
index 51daf6b5a..d86741476 100644
--- a/src/2geom/rect.h
+++ b/src/2geom/rect.h
@@ -47,6 +47,43 @@
namespace Geom {
+/** Values for the <align> parameter of preserveAspectRatio.
+ * See: http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute */
+enum Align {
+ ALIGN_NONE,
+ ALIGN_XMIN_YMIN,
+ ALIGN_XMID_YMIN,
+ ALIGN_XMAX_YMIN,
+ ALIGN_XMIN_YMID,
+ ALIGN_XMID_YMID,
+ ALIGN_XMAX_YMID,
+ ALIGN_XMIN_YMAX,
+ ALIGN_XMID_YMAX,
+ ALIGN_XMAX_YMAX
+};
+
+/** Values for the <meetOrSlice> parameter of preserveAspectRatio.
+ * See: http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute */
+enum Expansion {
+ EXPANSION_MEET,
+ EXPANSION_SLICE
+};
+
+/// Convert an align specification to coordinate fractions.
+Point align_factors(Align align);
+
+/** @brief Structure that specifies placement of within a viewport.
+ * Use this to create transformations that preserve aspect. */
+struct Aspect {
+ Align align;
+ Expansion expansion;
+ bool deferred; ///< for SVG compatibility
+
+ Aspect(Align a = ALIGN_NONE, Expansion ex = EXPANSION_MEET)
+ : align(a), expansion(ex), deferred(false)
+ {}
+};
+
/**
* @brief Axis aligned, non-empty rectangle.
* @ingroup Primitives
@@ -113,6 +150,16 @@ public:
}
/// @}
+ /// @name SVG viewbox functionality.
+ /// @{
+ /** @brief Transform contents to viewport.
+ * Computes an affine that transforms the contents of this rectangle
+ * to the specified viewport. The aspect parameter specifies how to
+ * to the transformation (whether the aspect ratio of content
+ * should be kept and where it should be placed in the viewport). */
+ Affine transformTo(Rect const &viewport, Aspect const &aspect = Aspect()) const;
+ /// @}
+
/// @name Operators
/// @{
Rect &operator*=(Affine const &m);
@@ -145,8 +192,14 @@ public:
OptRect(OptIntRect const &r) : Base() {
if (r) *this = Rect(*r);
}
- // actually, the only reason we have this class, instead of typedefing
- // to GenericOptRect<Coord>, are the above constructors
+
+ Affine transformTo(Rect const &viewport, Aspect const &aspect = Aspect()) {
+ Affine ret = Affine::identity();
+ if (empty()) return ret;
+ ret = (*this)->transformTo(viewport, aspect);
+ return ret;
+ }
+
bool operator==(OptRect const &other) const {
return Base::operator==(other);
}
diff --git a/src/2geom/sbasis-curve.h b/src/2geom/sbasis-curve.h
index affe7edc0..cfc4ee9a8 100644
--- a/src/2geom/sbasis-curve.h
+++ b/src/2geom/sbasis-curve.h
@@ -37,6 +37,7 @@
#define LIB2GEOM_SEEN_SBASIS_CURVE_H
#include <2geom/curve.h>
+#include <2geom/exception.h>
#include <2geom/nearest-time.h>
#include <2geom/sbasis-geometric.h>
#include <2geom/transforms.h>
@@ -131,6 +132,10 @@ public:
if (!other) return false;
return inner == other->inner;
}
+ virtual bool isNear(Curve const &/*c*/, Coord /*eps*/) const {
+ THROW_NOTIMPLEMENTED();
+ return false;
+ }
virtual int degreesOfFreedom() const {
return inner[0].degreesOfFreedom() + inner[1].degreesOfFreedom();
}
diff --git a/src/2geom/sbasis-geometric.cpp b/src/2geom/sbasis-geometric.cpp
index 4c474f7f0..8aaa15144 100644
--- a/src/2geom/sbasis-geometric.cpp
+++ b/src/2geom/sbasis-geometric.cpp
@@ -228,7 +228,7 @@ Geom::unitVector(D2<SBasis> const &V_in, double tol, unsigned order){
// -This done, unitVector will have jumps at zeros: fill the gaps with arcs of circles.
D2<SBasis> V = RescaleForNonVanishingEnds(V_in);
- if (V[0].empty() && V[1].empty())
+ if (V[0].isZero(0) && V[1].isZero(0))
return Piecewise<D2<SBasis> >(D2<SBasis>(Linear(1),SBasis()));
SBasis x = V[0], y = V[1];
SBasis r_eqn1, r_eqn2;
diff --git a/src/2geom/sbasis-math.cpp b/src/2geom/sbasis-math.cpp
index 896eb18a7..e9ee917de 100644
--- a/src/2geom/sbasis-math.cpp
+++ b/src/2geom/sbasis-math.cpp
@@ -34,9 +34,8 @@
//TODO: define a truncated compose(sb,sb, order) and extend it to pw<sb>.
//TODO: in all these functions, compute 'order' according to 'tol'.
+#include <2geom/d2.h>
#include <2geom/sbasis-math.h>
-
-#include <2geom/d2-sbasis.h>
#include <stdio.h>
#include <math.h>
//#define ZERO 1e-3
diff --git a/src/2geom/sbasis-roots.cpp b/src/2geom/sbasis-roots.cpp
index 57bef4c0f..e3e5e4441 100644
--- a/src/2geom/sbasis-roots.cpp
+++ b/src/2geom/sbasis-roots.cpp
@@ -222,7 +222,7 @@ static void multi_roots_internal(SBasis const &f,
double b,
double fb){
- if (f.size()==0){
+ if (f.isZero(0)){
int idx;
idx=upper_level(levels,0,vtol);
if (idx<(int)levels.size()&&fabs(levels.at(idx))<=vtol){
@@ -414,7 +414,7 @@ static void level_sets_internal(SBasis const &f,
double fb,
double tol=1e-5){
- if (f.size()==0){
+ if (f.isZero(0)){
unsigned idx;
idx=upper_level( levels, 0. );
if (idx<levels.size() && levels[idx].contains(0.)){
@@ -614,6 +614,7 @@ std::vector<double> roots1(SBasis const & s, Interval const ivl) {
std::vector<double> roots(SBasis const & s) {
switch(s.size()) {
case 0:
+ assert(false);
return std::vector<double>();
case 1:
return roots1(s);
@@ -628,6 +629,7 @@ std::vector<double> roots(SBasis const & s) {
std::vector<double> roots(SBasis const & s, Interval const ivl) {
switch(s.size()) {
case 0:
+ assert(false);
return std::vector<double>();
case 1:
return roots1(s, ivl);
diff --git a/src/2geom/sbasis-to-bezier.cpp b/src/2geom/sbasis-to-bezier.cpp
index 09fbb03ef..8a18cfd4a 100644
--- a/src/2geom/sbasis-to-bezier.cpp
+++ b/src/2geom/sbasis-to-bezier.cpp
@@ -100,9 +100,7 @@ int sgn(unsigned int j, unsigned int k)
*/
void sbasis_to_bezier (Bezier & bz, SBasis const& sb, size_t sz)
{
- if (sb.size() == 0) {
- THROW_RANGEERROR("size of sb is too small");
- }
+ assert(sb.size() > 0);
size_t q, n;
bool even;
@@ -207,11 +205,11 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb)
xprime[i] = sb[X][0][1] - sb[X][0][0];
yprime[i] = sb[Y][0][1] - sb[Y][0][0];
}
- if (sb[X].size() > 0) {
+ if (sb[X].size() > 1) {
xprime[0] += sb[X][1][0];
xprime[1] -= sb[X][1][1];
}
- if (sb[Y].size() > 0) {
+ if (sb[Y].size() > 1) {
yprime[0] += sb[Y][1][0];
yprime[1] -= sb[Y][1][1];
}
diff --git a/src/2geom/sbasis.cpp b/src/2geom/sbasis.cpp
index 42d92d7b8..0f4159e94 100644
--- a/src/2geom/sbasis.cpp
+++ b/src/2geom/sbasis.cpp
@@ -279,9 +279,11 @@ SBasis multiply_add(SBasis const &a, SBasis const &b, SBasis c) {
*/
SBasis multiply(SBasis const &a, SBasis const &b) {
- SBasis c(a.size() + b.size(), Linear(0,0));
- if(a.isZero() || b.isZero())
+ if(a.isZero() || b.isZero()) {
+ SBasis c(1, Linear(0,0));
return c;
+ }
+ SBasis c(a.size() + b.size(), Linear(0,0));
return multiply_add(a, b, c);
}
#endif
diff --git a/src/2geom/sbasis.h b/src/2geom/sbasis.h
index 787e8b722..6923017be 100644
--- a/src/2geom/sbasis.h
+++ b/src/2geom/sbasis.h
@@ -83,49 +83,52 @@ public:
const_iterator end() const { return d.end();}
iterator begin() { return d.begin();}
iterator end() { return d.end();}
- bool empty() const {return d.empty();}
+ bool empty() const { return d.size() == 1 && d[0][0] == 0 && d[0][1] == 0; }
Linear &back() {return d.back();}
Linear const &back() const {return d.back();}
- void pop_back() { d.pop_back();}
- void resize(unsigned n) { d.resize(n);}
- void resize(unsigned n, Linear const& l) { d.resize(n, l);}
+ void pop_back() {
+ if (d.size() > 1) {
+ d.pop_back();
+ } else {
+ d[0][0] = 0;
+ d[0][1] = 0;
+ }
+ }
+ void resize(unsigned n) { d.resize(std::max<unsigned>(n, 1));}
+ void resize(unsigned n, Linear const& l) { d.resize(std::max<unsigned>(n, 1), l);}
void reserve(unsigned n) { d.reserve(n);}
- void clear() {d.clear();}
+ void clear() {
+ d.resize(1);
+ d[0][0] = 0;
+ d[0][1] = 0;
+ }
void insert(iterator before, const_iterator src_begin, const_iterator src_end) { d.insert(before, src_begin, src_end);}
Linear& at(unsigned i) { return d.at(i);}
//void insert(Linear* before, int& n, Linear const &l) { d.insert(std::vector<Linear>::iterator(before), n, l);}
bool operator==(SBasis const&B) const { return d == B.d;}
bool operator!=(SBasis const&B) const { return d != B.d;}
- operator std::vector<Linear>() { return d;}
-
- SBasis() {}
+ SBasis()
+ : d(1, Linear(0, 0))
+ {}
explicit SBasis(double a)
- : d(1)
- {
- d[0][0] = a;
- d[0][1] = a;
- }
+ : d(1, Linear(a, a))
+ {}
explicit SBasis(double a, double b)
- : d(1)
- {
- d[0][0] = a;
- d[0][1] = b;
- }
- SBasis(SBasis const & a) :
- d(a.d)
+ : d(1, Linear(a, b))
{}
- SBasis(std::vector<Linear> const & ls) :
- d(ls)
+ SBasis(SBasis const &a)
+ : d(a.d)
+ {}
+ SBasis(std::vector<Linear> const &ls)
+ : d(ls)
+ {}
+ SBasis(Linear const &bo)
+ : d(1, bo)
+ {}
+ SBasis(Linear* bo)
+ : d(1, bo ? *bo : Linear(0, 0))
{}
- SBasis(Linear const & bo) {
- push_back(bo);
- }
- SBasis(Linear* bo) {
- if (bo) {
- push_back(*bo);
- }
- }
explicit SBasis(size_t n, Linear const&l) : d(n, l) {}
SBasis(Coord c0, Coord c1, Coord c2, Coord c3)
@@ -179,6 +182,7 @@ public:
template <typename Iter>
SBasis(Iter first, Iter last) {
assert(std::distance(first, last) % 2 == 0);
+ assert(std::distance(first, last) >= 2);
for (; first != last; ++first) {
--last;
push_back(Linear(*first, *last));
@@ -188,14 +192,14 @@ public:
//IMPL: FragmentConcept
typedef double output_type;
inline bool isZero(double eps=EPSILON) const {
- if(empty()) return true;
+ assert(size() > 0);
for(unsigned i = 0; i < size(); i++) {
if(!(*this)[i].isZero(eps)) return false;
}
return true;
}
inline bool isConstant(double eps=EPSILON) const {
- if (empty()) return true;
+ assert(size() > 0);
if(!(*this)[0].isConstant(eps)) return false;
for (unsigned i = 1; i < size(); i++) {
if(!(*this)[i].isZero(eps)) return false;
@@ -212,6 +216,7 @@ public:
int degreesOfFreedom() const { return size()*2;}
double valueAt(double t) const {
+ assert(size() > 0);
double s = t*(1-t);
double p0 = 0, p1 = 0;
for(unsigned k = size(); k > 0; k--) {
@@ -239,11 +244,11 @@ public:
//MUTATOR PRISON
//remove extra zeros
void normalize() {
- while(!empty() && 0 == back()[0] && 0 == back()[1])
+ while(size() > 1 && back().isZero(0))
pop_back();
}
- void truncate(unsigned k) { if(k < size()) resize(k); }
+ void truncate(unsigned k) { if(k < size()) resize(std::max<size_t>(k, 1)); }
private:
void derive(); // in place version
};
diff --git a/src/2geom/svg-path-parser.cpp b/src/2geom/svg-path-parser.cpp
index b6e6da869..93694156d 100644
--- a/src/2geom/svg-path-parser.cpp
+++ b/src/2geom/svg-path-parser.cpp
@@ -1424,7 +1424,7 @@ _match:
Point point = _pop_point();
bool sweep = _pop_flag();
bool large_arc = _pop_flag();
- double angle = deg_to_rad(_pop());
+ double angle = rad_from_deg(_pop());
double ry = _pop();
double rx = _pop();
@@ -1530,7 +1530,7 @@ _again:
Point point = _pop_point();
bool sweep = _pop_flag();
bool large_arc = _pop_flag();
- double angle = deg_to_rad(_pop());
+ double angle = rad_from_deg(_pop());
double ry = _pop();
double rx = _pop();
diff --git a/src/2geom/svg-path-writer.cpp b/src/2geom/svg-path-writer.cpp
index 1c40ba64e..c484a172b 100644
--- a/src/2geom/svg-path-writer.cpp
+++ b/src/2geom/svg-path-writer.cpp
@@ -150,7 +150,7 @@ void SVGPathWriter::arcTo(double rx, double ry, double angle,
_setCommand('A');
_current_pars.push_back(rx);
_current_pars.push_back(ry);
- _current_pars.push_back(rad_to_deg(angle));
+ _current_pars.push_back(deg_from_rad(angle));
_current_pars.push_back(large_arc ? 1. : 0.);
_current_pars.push_back(sweep ? 1. : 0.);
_current_pars.push_back(p[X]);
diff --git a/src/2geom/sweeper.h b/src/2geom/sweeper.h
index 8c4e182a6..469108465 100644
--- a/src/2geom/sweeper.h
+++ b/src/2geom/sweeper.h
@@ -41,32 +41,24 @@
namespace Geom {
-/** @brief Sweep traits class for interval bounds.
- * @relates Sweeper
- * @ingroup Utilities */
-struct IntervalSweepTraits {
- typedef Interval Bound;
- typedef std::less<Coord> Compare;
- inline static Coord entry_value(Bound const &b) { return b.min(); }
- inline static Coord exit_value(Bound const &b) { return b.max(); }
-};
+// exposition only
+template <typename Item>
+class SweepVector {
+public:
+ typedef typename std::vector<Item>::const_iterator ItemIterator;
-/** @brief Sweep traits class for rectangle bounds.
- * @tparam D Which axis to use for sweeping
- * @ingroup Utilities */
-template <Dim2 D>
-struct RectSweepTraits {
- typedef Rect Bound;
- typedef std::less<Coord> Compare;
- inline static Coord entry_value(Bound const &b) { return b[D].min(); }
- inline static Coord exit_value(Bound const &b) { return b[D].max(); }
-};
+ SweepVector(std::vector<Item> const &v)
+ : _items(v)
+ {}
-template <typename T>
-struct BoundsFast {
- Rect operator()(T const &item) const {
- return item.boundsFast();
- }
+ std::vector<Item> const &items() { return _items; }
+ Interval itemBounds(ItemIterator /*ii*/) { return Interval(); }
+
+ void addActiveItem(ItemIterator /*ii*/) {}
+ void removeActiveItem(ItemIterator /*ii*/) {}
+
+private:
+ std::vector<Item> const &_items;
};
/** @brief Generic sweepline algorithm.
@@ -77,13 +69,19 @@ struct BoundsFast {
* the line starts intersecting their bounds, and removed when it completely
* passes over them.
*
- * To use this, create a derived class and reimplement the _enter()
- * and/or _leave() virtual functions, insert all the objects,
- * and finally call process(). Inside _enter() and _leave(), the items that have
- * their bounds intersected by the sweepline are available in a list called
- * _active_items. This is an intrusive linked list, so you should access it using
- * iterators. Do not add or remove items from it. You can specify the bound type
- * and how it should be accessed by defining a custom SweepTraits class.
+ * To use this, create a class that exposes the following methods:
+ * - Range items() - returns a forward iterable range of items that will be swept.
+ * - Interval itemBounds(iterator i) - given an iterator from the above range,
+ * compute the bounding interval of the referenced item in the direction of sweep.
+ * - void addActiveItem(iterator i) - add an item to the active list.
+ * - void removeActiveItem(iterator i) - remove an item from the active list.
+ *
+ * Create the object, then instantiate this template with the above class
+ * as the template parameter, pass it the constructed object of the class,
+ * and call the process() method.
+ *
+ * A good choice for the active list is a Boost intrusive list, which allows
+ * you to get an iterator from a value in constant time.
*
* Look in path.cpp for example usage.
*
@@ -92,148 +90,88 @@ struct BoundsFast {
* how to interpret them and how to sort the events
* @ingroup Utilities
*/
-template <typename Item, typename SweepTraits = IntervalSweepTraits>
+template <typename SweepSet>
class Sweeper {
public:
- /// Type of the item's boundary - usually this will be an Interval or Rect.
- typedef typename SweepTraits::Bound Bound;
-
- Sweeper() {}
-
- /** @brief Insert a single item for sweeping.
- * @param bound Boundary of the item, as defined in sweep traits
- * @param item The item itself */
- void insert(Bound const &bound, Item const &item) {
- assert(!(typename SweepTraits::Compare()(
- SweepTraits::exit_value(bound),
- SweepTraits::entry_value(bound))));
- _items.push_back(Record(bound, item));
- }
-
- /** @brief Insert a range of items using the supplied bounds functor.
- * The bounds are computed from items using the supplied bounds functor.
- * @param first Start of range
- * @param last End of range (one-past-the-end iterator)
- * @param f Bounds functor */
- template <typename Iter, typename BoundFunc>
- void insert(Iter first, Iter last, BoundFunc f = BoundFunc()) {
- for (; first != last; ++first) {
- Bound b = f(*first);
- assert(!(typename SweepTraits::Compare()(
- SweepTraits::exit_value(b),
- SweepTraits::entry_value(b))));
- _items.push_back(Record(b, *first));
- }
+ typedef typename SweepSet::ItemIterator Iter;
+
+ explicit Sweeper(SweepSet &set)
+ : _set(set)
+ {
+ std::size_t sz = std::distance(set.items().begin(), set.items().end());
+ _entry_events.reserve(sz);
+ _exit_events.reserve(sz);
}
/** @brief Process entry and exit events.
- * This will iterate over all inserted items, calling the virtual protected
- * functions _enter() and _leave() according to the order of the boundaries
- * of each item. */
+ * This will iterate over all inserted items, calling the methods
+ * addActiveItem and removeActiveItem on the SweepSet passed at construction
+ * according to the order of the boundaries of each item. */
void process() {
- if (_items.empty()) return;
+ if (_set.items().empty()) return;
+
+ Iter last = _set.items().end();
+ for (Iter i = _set.items().begin(); i != last; ++i) {
+ Interval b = _set.itemBounds(i);
+ // guard against NANs
+ assert(b.min() == b.min() && b.max() == b.max());
+ _entry_events.push_back(Event(b.max(), i));
+ _exit_events.push_back(Event(b.min(), i));
+ }
- typename SweepTraits::Compare cmp;
+ boost::make_heap(_entry_events);
+ boost::make_heap(_exit_events);
- // we store the events in heaps, which is slightly more efficient
- // than sorting them, since a heap requires linear time to construct
- for (RecordIter i = _items.begin(); i != _items.end(); ++i) {
- _entry_events.push_back(i);
- _exit_events.push_back(i);
- }
- boost::make_heap(_entry_events, _entry_heap_compare);
- boost::make_heap(_exit_events, _exit_heap_compare);
- boost::pop_heap(_entry_events, _entry_heap_compare);
- boost::pop_heap(_exit_events, _exit_heap_compare);
-
- RecordIter next_entry = _entry_events.back();
- RecordIter next_exit = _exit_events.back();
- _entry_events.pop_back();
- _exit_events.pop_back();
-
- while (next_entry != _items.end() || next_exit != _items.end()) {
- assert(next_exit != _items.end());
-
- if (next_entry == _items.end() ||
- cmp(SweepTraits::exit_value(next_exit->bound),
- SweepTraits::entry_value(next_entry->bound)))
- {
+ Event next_entry = _get_next(_entry_events);
+ Event next_exit = _get_next(_exit_events);
+
+ while (next_entry || next_exit) {
+ assert(next_exit);
+
+ if (!next_entry || next_exit > next_entry) {
// exit event - remove record from active list
- _leave(*next_exit);
- _active_items.erase(_active_items.iterator_to(*next_exit));
- if (!_exit_events.empty()) {
- boost::pop_heap(_exit_events, _exit_heap_compare);
- next_exit = _exit_events.back();
- _exit_events.pop_back();
- } else {
- next_exit = _items.end();
- // we should end the loop after this happens
- }
+ _set.removeActiveItem(next_exit.item);
+ next_exit = _get_next(_exit_events);
} else {
// entry event - add record to active list
- _enter(*next_entry);
- _active_items.push_back(*next_entry);
- if (!_entry_events.empty()) {
- boost::pop_heap(_entry_events, _entry_heap_compare);
- next_entry = _entry_events.back();
- _entry_events.pop_back();
- } else {
- next_entry = _items.end();
- }
+ _set.addActiveItem(next_entry.item);
+ next_entry = _get_next(_entry_events);
}
}
-
- assert(_active_items.empty());
}
-protected:
- /// The item and its sweepline boundary.
- struct Record {
- boost::intrusive::list_member_hook<> _hook;
- Bound bound;
- Item item;
-
- Record(Bound const &b, Item const &i)
- : bound(b), item(i)
+private:
+ struct Event
+ : boost::totally_ordered<Event>
+ {
+ Coord coord;
+ Iter item;
+
+ Event(Coord c, Iter const &i)
+ : coord(c), item(i)
+ {}
+ Event()
+ : coord(nan("")), item()
{}
+ bool operator<(Event const &other) const { return coord < other.coord; }
+ bool operator==(Event const &other) const { return coord == other.coord; }
+ operator bool() const { return !IS_NAN(coord); }
};
- typedef typename std::vector<Record>::iterator RecordIter;
-
- typedef boost::intrusive::list
- < Record
- , boost::intrusive::member_hook
- < Record
- , boost::intrusive::list_member_hook<>
- , &Record::_hook
- >
- > RecordList;
-
- /** @brief Enter an item record.
- * Override this to process an item as it is about to enter the active list.
- * When called, the passed record will not be part of the active list. */
- virtual void _enter(Record const &) {}
- /** @brief Leave an item record.
- * Override this to process an item as it is about to leave the active list.
- * When called, the passed record will be part of the active list. */
- virtual void _leave(Record const &) {}
-
- /// The list of all item records undergoing sweeping.
- std::vector<Record> _items;
- /// The list of active item records.
- RecordList _active_items;
-private:
- inline static bool _entry_heap_compare(RecordIter a, RecordIter b) {
- typename SweepTraits::Compare cmp;
- return cmp(SweepTraits::entry_value(b->bound), SweepTraits::entry_value(a->bound));
- }
- inline static bool _exit_heap_compare(RecordIter a, RecordIter b) {
- typename SweepTraits::Compare cmp;
- return cmp(SweepTraits::exit_value(b->bound), SweepTraits::exit_value(a->bound));
+ static Event _get_next(std::vector<Event> &heap) {
+ if (heap.empty()) {
+ Event e;
+ return e;
+ }
+ boost::pop_heap(heap);
+ Event ret = heap.back();
+ heap.pop_back();
+ return ret;
}
- std::vector<RecordIter> _entry_events;
- std::vector<RecordIter> _exit_events;
+ SweepSet &_set;
+ std::vector<Event> _entry_events;
+ std::vector<Event> _exit_events;
};
} // namespace Geom
diff --git a/src/2geom/utils.h b/src/2geom/utils.h
index bc0ad74b8..01579d81b 100644
--- a/src/2geom/utils.h
+++ b/src/2geom/utils.h
@@ -68,9 +68,33 @@ struct NullIterator
NullIterator() {}
template <typename T>
- void operator=(T const &v) {}
+ void operator=(T const &) {}
};
+/** @brief Get the next iterator in the container with wrap-around.
+ * If the iterator would become the end iterator after incrementing,
+ * return the begin iterator instead. */
+template <typename Iter, typename Container>
+Iter cyclic_next(Iter i, Container &c) {
+ ++i;
+ if (i == c.end()) {
+ i = c.begin();
+ }
+ return i;
+}
+
+/** @brief Get the previous iterator in the container with wrap-around.
+ * If the passed iterator is the begin iterator, return the iterator
+ * just before the end iterator instead. */
+template <typename Iter, typename Container>
+Iter cyclic_prior(Iter i, Container &c) {
+ if (i == c.begin()) {
+ i = c.end();
+ }
+ --i;
+ return i;
+}
+
} // end namespace Geom
#endif // LIB2GEOM_SEEN_UTILS_H
diff --git a/src/2geom/viewbox.cpp b/src/2geom/viewbox.cpp
deleted file mode 100644
index 69bd0c487..000000000
--- a/src/2geom/viewbox.cpp
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * \file
- * \brief Convenience class for SVG viewBox handling
- *//*
- * Authors:
- * Krzysztof Kosiński <tweenk.pl@gmail.com>
- *
- * Copyright (C) 2013 Authors
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- */
-
-#include <2geom/transforms.h>
-#include <2geom/viewbox.h>
-
-namespace Geom {
-
-/** Convert an align specification to coordinate fractions. */
-Point align_factors(Align g) {
- Point p;
- switch (g) {
- case ALIGN_XMIN_YMIN:
- p[X] = 0.0;
- p[Y] = 0.0;
- break;
- case ALIGN_XMID_YMIN:
- p[X] = 0.5;
- p[Y] = 0.0;
- break;
- case ALIGN_XMAX_YMIN:
- p[X] = 1.0;
- p[Y] = 0.0;
- break;
- case ALIGN_XMIN_YMID:
- p[X] = 0.0;
- p[Y] = 0.5;
- break;
- case ALIGN_XMID_YMID:
- p[X] = 0.5;
- p[Y] = 0.5;
- break;
- case ALIGN_XMAX_YMID:
- p[X] = 1.0;
- p[Y] = 0.5;
- break;
- case ALIGN_XMIN_YMAX:
- p[X] = 0.0;
- p[Y] = 1.0;
- break;
- case ALIGN_XMID_YMAX:
- p[X] = 0.5;
- p[Y] = 1.0;
- break;
- case ALIGN_XMAX_YMAX:
- p[X] = 1.0;
- p[Y] = 1.0;
- break;
- default:
- break;
- }
- return p;
-}
-
-/** Obtain transformation from the viewbox to the specified viewport. */
-Affine ViewBox::transformTo(Geom::Rect const &viewport) const
-{
- if (!_box) {
- return Geom::Affine::identity();
- }
-
- // 1. translate viewbox to origin
- Geom::Affine total = Translate(-_box->min());
-
- // 2. compute scale
- Geom::Point vdims = viewport.dimensions();
- Geom::Point bdims = _box->dimensions();
- Geom::Scale scale(vdims[X] / bdims[X], vdims[Y] / bdims[Y]);
-
- if (_align == ALIGN_NONE) {
- // apply non-uniform scale
- // = Scale(_box->dimensions()).inverse() * Scale(viewport.dimensions())
- total *= scale * Translate(viewport.min());
- } else {
- double uscale = 0;
- if (_expansion == EXPANSION_MEET) {
- uscale = std::min(scale[X], scale[Y]);
- } else {
- uscale = std::max(scale[X], scale[Y]);
- }
- scale = Scale(uscale);
-
- // compute offset for align
- Geom::Point offset = bdims * scale - vdims;
- offset *= Scale(align_factors(_align));
- total *= Translate(-offset);
- }
-
- return total;
-}
-
-} // namespace Geom
-
-/*
- 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/2geom/viewbox.h b/src/2geom/viewbox.h
deleted file mode 100644
index 81f59ee36..000000000
--- a/src/2geom/viewbox.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/**
- * \file
- * \brief Convenience class for SVG viewBox handling
- *//*
- * Authors:
- * Krzysztof Kosiński <tweenk.pl@gmail.com>
- *
- * Copyright (C) 2013 Authors
- *
- * This library is free software; you can redistribute it and/or
- * modify it either under the terms of the GNU Lesser General Public
- * License version 2.1 as published by the Free Software Foundation
- * (the "LGPL") or, at your option, under the terms of the Mozilla
- * Public License Version 1.1 (the "MPL"). If you do not alter this
- * notice, a recipient may use your version of this file under either
- * the MPL or the LGPL.
- *
- * You should have received a copy of the LGPL along with this library
- * in the file COPYING-LGPL-2.1; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- * You should have received a copy of the MPL along with this library
- * in the file COPYING-MPL-1.1
- *
- * The contents of this file are subject to the Mozilla Public License
- * Version 1.1 (the "License"); you may not use this file except in
- * compliance with the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
- * OF ANY KIND, either express or implied. See the LGPL or the MPL for
- * the specific language governing rights and limitations.
- */
-
-#ifndef LIB2GEOM_SEEN_VIEWBOX_H
-#define LIB2GEOM_SEEN_VIEWBOX_H
-
-#include <2geom/affine.h>
-#include <2geom/rect.h>
-
-namespace Geom {
-
-/** Values for the <align> parameter of preserveAspectRatio.
- * See: http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute */
-enum Align {
- ALIGN_NONE,
- ALIGN_XMIN_YMIN,
- ALIGN_XMID_YMIN,
- ALIGN_XMAX_YMIN,
- ALIGN_XMIN_YMID,
- ALIGN_XMID_YMID,
- ALIGN_XMAX_YMID,
- ALIGN_XMIN_YMAX,
- ALIGN_XMID_YMAX,
- ALIGN_XMAX_YMAX
-};
-
-/** Values for the <meetOrSlice> parameter of preserveAspectRatio.
- * See: http://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute */
-enum Expansion {
- EXPANSION_MEET,
- EXPANSION_SLICE
-};
-
-Point align_factors(Align align);
-
-class ViewBox {
- OptRect _box;
- Align _align;
- Expansion _expansion;
-
-public:
- explicit ViewBox(OptRect const &r = OptRect(), Align a = ALIGN_XMID_YMID, Expansion ex = EXPANSION_MEET)
- : _box(r)
- , _align(a)
- , _expansion(ex)
- {}
-
- void setBox(OptRect const &r) { _box = r; }
- void setAlign(Align a) { _align = a; }
- void setExpansion(Expansion ex) { _expansion = ex; }
- OptRect const &box() const { return _box; }
- Align align() const { return _align; }
- Expansion expansion() const { return _expansion; }
-
- /** Obtain transformation from the viewbox to the specified viewport. */
- Affine transformTo(Geom::Rect const &viewport) const;
-};
-
-} // namespace Geom
-
-#endif // !LIB2GEOM_SEEN_VIEWBOX_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/CMakeLists.txt b/src/CMakeLists.txt
index c416b0dea..30af55925 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -240,6 +240,7 @@ set(inkscape_SRC
print.cpp
profile-manager.cpp
proj_pt.cpp
+ pure-transform.cpp
rdf.cpp
removeoverlap.cpp
resource-manager.cpp
@@ -367,6 +368,7 @@ set(inkscape_SRC
print.h
profile-manager.h
proj_pt.h
+ pure-transform.h
rdf.h
remove-last.h
removeoverlap.h
@@ -509,8 +511,14 @@ set(inkscape_SRC
#add_inkscape_lib(sp_LIB "${sp_SRC}")
#add_inkscape_lib(inkscape_LIB "${inkscape_SRC}")
-# make executable for INKSCAPE
-add_executable(inkscape ${main_SRC} ${inkscape_SRC} ${sp_SRC})
+# Build everything except main and inkview.c in a CMake "object" library.
+# An object library is just a bunch of .o files. Linking them with main.c or inkview.c
+# we get the inkscape and inkview executables respectively.
+add_library(inkscape_base OBJECT ${inkscape_SRC} ${sp_SRC})
+
+# make executables for inkscape and inkview
+add_executable(inkscape ${main_SRC} $<TARGET_OBJECTS:inkscape_base>)
+add_executable(inkview inkview.cpp $<TARGET_OBJECTS:inkscape_base>)
if(UNIX)
# message after building.
@@ -523,31 +531,31 @@ endif()
add_dependencies(inkscape inkscape_version)
-target_link_libraries(inkscape
- # order from automake
- #sp_LIB
- #nrtype_LIB
+if (NOT "${WITH_EXT_GDL}")
+ list (APPEND INKSCAPE_LIBS "gdl_LIB")
+endif()
- #inkscape_LIB
- #sp_LIB # annoying, we need both!
- nrtype_LIB # annoying, we need both!
+set(INKSCAPE_TARGET_LIBS
+ # order from automake
+ #sp_LIB
+ #nrtype_LIB
- croco_LIB
- avoid_LIB
- gdl_LIB
- cola_LIB
- vpsc_LIB
- livarot_LIB
- uemf_LIB
- 2geom_LIB
- depixelize_LIB
- util_LIB
- gc_LIB
+ #inkscape_LIB
+ #sp_LIB # annoying, we need both!
+ nrtype_LIB # annoying, we need both!
- ${INKSCAPE_LIBS}
+ croco_LIB
+ avoid_LIB
+ cola_LIB
+ vpsc_LIB
+ livarot_LIB
+ uemf_LIB
+ 2geom_LIB
+ depixelize_LIB
+ util_LIB
+ gc_LIB
+ ${INKSCAPE_LIBS}
)
-# TODO
-# make executable for INKVIEW
-#add_executable(inkview inkview.cpp)
-# ...
+target_link_libraries(inkscape ${INKSCAPE_TARGET_LIBS})
+target_link_libraries(inkview ${INKSCAPE_TARGET_LIBS})
diff --git a/src/Makefile.am b/src/Makefile.am
index 7a37f13e8..087a727de 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -40,13 +40,13 @@ noinst_LIBRARIES = \
all_libs = \
$(noinst_LIBRARIES) \
$(INKSCAPE_LIBS) \
+ $(INKSCAPE_CXX_DEPS_LIBS) \
$(EXIF_LIBS) \
$(GNOME_VFS_LIBS) \
$(XFT_LIBS) \
$(FREETYPE_LIBS) \
$(kdeldadd) \
$(win32ldflags) \
- $(CARBON_LDFLAGS) \
$(LIBWPG_LIBS) \
$(LIBVISIO_LIBS) \
$(LIBCDR_LIBS) \
@@ -66,6 +66,10 @@ BUILT_SOURCES =
# Extra files to distribute
EXTRA_DIST =
+# C++-specific flags defined here
+AM_CXXFLAGS = \
+ $(INKSCAPE_CXX_DEPS_CFLAGS)
+
AM_CPPFLAGS = \
-I$(top_srcdir)/cxxtest \
-I$(builddir)/extension/dbus \
@@ -260,9 +264,7 @@ check-local:
# the XFAIL_TESTS build target should be removed.
# See the following Launchpad bugs:
#
-# LP #1202271 <cxxtest: preferences-test.h fails>
# LP #1208013 <cxxtest: curve-test.h fails>
-# LP #1208002 <cxxtest: svg-length-test.h fails>
# LP #1208005 <cxxtest: svg-path-geom-test.h fails>
# LP #1207502 <cxxtest: svg-affine-test.h fails>
diff --git a/src/Makefile_insert b/src/Makefile_insert
index 800752df4..b9723ac42 100644
--- a/src/Makefile_insert
+++ b/src/Makefile_insert
@@ -88,6 +88,7 @@ ink_common_sources += \
print.cpp print.h \
profile-manager.cpp profile-manager.h \
proj_pt.cpp proj_pt.h \
+ pure-transform.cpp pure-transform.h \
removeoverlap.cpp removeoverlap.h \
rdf.cpp rdf.h \
resource-manager.cpp resource-manager.h \
diff --git a/src/attributes-test.h b/src/attributes-test.h
index 411304ec3..b8d5d98a5 100644
--- a/src/attributes-test.h
+++ b/src/attributes-test.h
@@ -42,7 +42,8 @@ public:
SVG 2: white-space, shape-inside, shape-outside, shape-padding, shape-margin
SVG 2: text-decoration-fill, text-decoration-stroke
SVG 2: solid-color, solid-opacity
- SVG 2: Hatches and Meshes
+ SVG 2: Hatches and Meshes, radial gradient 'fr'
+ CSS 3: text-orientation
CSS 3: font-variant-xxx, font-feature-settings
*/
struct {char const *attr; bool supported;} const all_attrs[] = {
@@ -69,7 +70,6 @@ struct {char const *attr; bool supported;} const all_attrs[] = {
{"baseProfile", false},
{"bbox", true},
{"bias", true},
- {"block-progression", true},
{"by", true},
{"calcMode", true},
{"cap-height", true},
@@ -145,6 +145,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = {
{"from", true},
{"fx", true},
{"fy", true},
+ {"fr", true},
{"g1", true},
{"g2", true},
{"glyph-name", true},
@@ -334,6 +335,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = {
{"widths", true},
{"word-spacing", true},
{"writing-mode", true},
+ {"text-orientation", true},
{"x", true},
{"x-height", true},
{"x1", true},
@@ -489,6 +491,7 @@ struct {char const *attr; bool supported;} const all_attrs[] = {
{"showgrid", true},
// {"gridtype", true},
{"showguides", true},
+// {"inkscape:lockguides", false}, //not sure about uncomment
{"gridtolerance", true},
{"guidetolerance", true},
{"objecttolerance", true},
diff --git a/src/attributes.cpp b/src/attributes.cpp
index af19360c1..646c2ab0c 100644
--- a/src/attributes.cpp
+++ b/src/attributes.cpp
@@ -41,6 +41,7 @@ static SPStyleProp const props[] = {
{SP_ATTR_TRANSFORM_CENTER_Y, "inkscape:transform-center-y"},
{SP_ATTR_INKSCAPE_PATH_EFFECT, "inkscape:path-effect"},
{SP_ATTR_INKSCAPE_HIGHLIGHT_COLOR, "inkscape:highlight-color"},
+ {SP_ATTR_INKSCAPE_SPRAY_ORIGIN, "inkscape:spray-origin"},
/* SPAnchor */
{SP_ATTR_XLINK_HREF, "xlink:href"},
{SP_ATTR_XLINK_TYPE, "xlink:type"},
@@ -81,6 +82,7 @@ static SPStyleProp const props[] = {
{SP_ATTR_FIT_MARGIN_LEFT, "fit-margin-left"},
{SP_ATTR_FIT_MARGIN_RIGHT, "fit-margin-right"},
{SP_ATTR_FIT_MARGIN_BOTTOM, "fit-margin-bottom"},
+ {SP_ATTR_INKSCAPE_PAGECHECKERBOARD, "inkscape:pagecheckerboard"},
{SP_ATTR_INKSCAPE_PAGEOPACITY, "inkscape:pageopacity"},
{SP_ATTR_INKSCAPE_PAGESHADOW, "inkscape:pageshadow"},
{SP_ATTR_INKSCAPE_ZOOM, "inkscape:zoom"},
@@ -116,6 +118,7 @@ static SPStyleProp const props[] = {
{SP_ATTR_INKSCAPE_SNAP_PAGE_BORDER, "inkscape:snap-page"},
{SP_ATTR_INKSCAPE_CURRENT_LAYER, "inkscape:current-layer"},
{SP_ATTR_INKSCAPE_DOCUMENT_UNITS, "inkscape:document-units"}, // This setting sets the Display units, *not* the units used in SVG
+ {SP_ATTR_INKSCAPE_LOCKGUIDES, "inkscape:lockguides"},
{SP_ATTR_UNITS, "units"},
{SP_ATTR_INKSCAPE_CONNECTOR_SPACING, "inkscape:connector-spacing"},
/* SPColorProfile */
@@ -125,6 +128,8 @@ static SPStyleProp const props[] = {
/* SPGuide */
{SP_ATTR_ORIENTATION, "orientation"},
{SP_ATTR_POSITION, "position"},
+ {SP_ATTR_INKSCAPE_COLOR, "inkscape:color"},
+ {SP_ATTR_INKSCAPE_LOCKED, "inkscape:locked"},
/* SPImage */
{SP_ATTR_X, "x"},
{SP_ATTR_Y, "y"},
@@ -289,6 +294,7 @@ static SPStyleProp const props[] = {
/* SPRadialGradient */
{SP_ATTR_FX, "fx"},
{SP_ATTR_FY, "fy"},
+ {SP_ATTR_FR, "fr"},
/* SPMeshPatch */
{SP_ATTR_TENSOR, "tensor"},
//{SP_ATTR_TYPE, "type"},
@@ -439,8 +445,8 @@ static SPStyleProp const props[] = {
/* Text (css3) */
{SP_PROP_DIRECTION, "direction"},
- {SP_PROP_BLOCK_PROGRESSION, "block-progression"},
{SP_PROP_WRITING_MODE, "writing-mode"},
+ {SP_PROP_TEXT_ORIENTATION, "text-orientation"},
{SP_PROP_UNICODE_BIDI, "unicode-bidi"},
{SP_PROP_ALIGNMENT_BASELINE, "alignment-baseline"},
{SP_PROP_BASELINE_SHIFT, "baseline-shift"},
@@ -532,21 +538,13 @@ static SPStyleProp const props[] = {
unsigned
sp_attribute_lookup(gchar const *key)
{
- static GHashTable *propdict = NULL;
-
- if (!propdict) {
- unsigned int i;
- propdict = g_hash_table_new(g_str_hash, g_str_equal);
- for (i = 1; i < n_attrs; i++) {
- g_assert(props[i].code == static_cast< gint >(i) );
- // If this g_assert fails, then the sort order of SPAttributeEnum does not match the order in props[]!
- g_hash_table_insert(propdict,
- const_cast<void *>(static_cast<void const *>(props[i].name)),
- GINT_TO_POINTER(props[i].code));
- }
+ for (unsigned int i = 1; i < n_attrs; i++) {
+ g_assert(props[i].code == static_cast< gint >(i) );
+ // If this g_assert fails, then the sort order of SPAttributeEnum does not match the order in props[]!
+ if(g_str_equal(const_cast<void *>(static_cast<void const *>(props[i].name)), key))
+ return GPOINTER_TO_UINT(GINT_TO_POINTER(props[i].code));
}
-
- return GPOINTER_TO_UINT(g_hash_table_lookup(propdict, key));
+ return SP_ATTR_INVALID;
}
unsigned char const *
diff --git a/src/attributes.h b/src/attributes.h
index 7d6ea70a0..f5544d0a1 100644
--- a/src/attributes.h
+++ b/src/attributes.h
@@ -41,6 +41,7 @@ enum SPAttributeEnum {
SP_ATTR_TRANSFORM_CENTER_Y,
SP_ATTR_INKSCAPE_PATH_EFFECT,
SP_ATTR_INKSCAPE_HIGHLIGHT_COLOR,
+ SP_ATTR_INKSCAPE_SPRAY_ORIGIN,
/* SPAnchor */
SP_ATTR_XLINK_HREF,
SP_ATTR_XLINK_TYPE,
@@ -82,6 +83,7 @@ enum SPAttributeEnum {
SP_ATTR_FIT_MARGIN_LEFT,
SP_ATTR_FIT_MARGIN_RIGHT,
SP_ATTR_FIT_MARGIN_BOTTOM,
+ SP_ATTR_INKSCAPE_PAGECHECKERBOARD,
SP_ATTR_INKSCAPE_PAGEOPACITY,
SP_ATTR_INKSCAPE_PAGESHADOW,
SP_ATTR_INKSCAPE_ZOOM,
@@ -118,6 +120,7 @@ enum SPAttributeEnum {
SP_ATTR_INKSCAPE_SNAP_PAGE_BORDER,
SP_ATTR_INKSCAPE_CURRENT_LAYER,
SP_ATTR_INKSCAPE_DOCUMENT_UNITS,
+ SP_ATTR_INKSCAPE_LOCKGUIDES,
SP_ATTR_UNITS,
SP_ATTR_INKSCAPE_CONNECTOR_SPACING,
/* SPColorProfile */
@@ -127,6 +130,8 @@ enum SPAttributeEnum {
/* SPGuide */
SP_ATTR_ORIENTATION,
SP_ATTR_POSITION,
+ SP_ATTR_INKSCAPE_COLOR,
+ SP_ATTR_INKSCAPE_LOCKED,
/* SPImage */
SP_ATTR_X,
SP_ATTR_Y,
@@ -291,6 +296,7 @@ enum SPAttributeEnum {
/* SPRadialGradient */
SP_ATTR_FX,
SP_ATTR_FY,
+ SP_ATTR_FR,
/* SPMeshPatch */
SP_ATTR_TENSOR,
//SP_ATTR_TYPE,
@@ -443,8 +449,8 @@ enum SPAttributeEnum {
SP_PROP_TEXT_TRANSFORM,
SP_PROP_DIRECTION,
- SP_PROP_BLOCK_PROGRESSION,
SP_PROP_WRITING_MODE,
+ SP_PROP_TEXT_ORIENTATION,
SP_PROP_UNICODE_BIDI,
SP_PROP_ALIGNMENT_BASELINE,
SP_PROP_BASELINE_SHIFT,
diff --git a/src/box3d.cpp b/src/box3d.cpp
index dc04a2eb6..c4c2728e4 100644
--- a/src/box3d.cpp
+++ b/src/box3d.cpp
@@ -50,6 +50,11 @@ SPBox3D::SPBox3D() : SPGroup() {
this->persp_href = NULL;
this->persp_ref = new Persp3DReference(this);
+
+ /* we initialize the z-orders to zero so that they are updated during dragging */
+ for (int i = 0; i < 6; ++i) {
+ z_orders[i] = 0;
+ }
}
SPBox3D::~SPBox3D() {
@@ -902,7 +907,7 @@ box3d_swap_sides(int z_orders[6], Box3D::Axis axis) {
}
}
- if (pos1 != -1){
+ if ((pos1 != -1) && (pos2 != -1)){
int tmp = z_orders[pos1];
z_orders[pos1] = z_orders[pos2];
z_orders[pos2] = tmp;
diff --git a/src/color-profile.cpp b/src/color-profile.cpp
index 690a72654..bcefe994a 100644
--- a/src/color-profile.cpp
+++ b/src/color-profile.cpp
@@ -271,6 +271,7 @@ void ColorProfile::build(SPDocument *document, Inkscape::XML::Node *repr) {
SPObject::build(document, repr);
this->readAttr( "xlink:href" );
+ this->readAttr( "id" );
this->readAttr( "local" );
this->readAttr( "name" );
this->readAttr( "rendering-intent" );
@@ -488,18 +489,17 @@ static int getLcmsIntent( guint svgIntent )
static SPObject* bruteFind( SPDocument* document, gchar const* name )
{
SPObject* result = 0;
- const GSList * current = document->getResourceList("iccprofile");
- while ( current && !result ) {
- if ( IS_COLORPROFILE(current->data) ) {
- ColorProfile* prof = COLORPROFILE(current->data);
+ std::set<SPObject *> current = document->getResourceList("iccprofile");
+ for (std::set<SPObject *>::const_iterator it = current.begin(); (!result) && (it != current.end()); ++it) {
+ if ( IS_COLORPROFILE(*it) ) {
+ ColorProfile* prof = COLORPROFILE(*it);
if ( prof ) {
if ( prof->name && (strcmp(prof->name, name) == 0) ) {
- result = SP_OBJECT(current->data);
+ result = SP_OBJECT(*it);
break;
}
}
}
- current = g_slist_next(current);
}
return result;
diff --git a/src/conn-avoid-ref.cpp b/src/conn-avoid-ref.cpp
index ec9aba793..9190fe633 100644
--- a/src/conn-avoid-ref.cpp
+++ b/src/conn-avoid-ref.cpp
@@ -139,9 +139,9 @@ void SPAvoidRef::handleSettingChange(void)
}
-GSList *SPAvoidRef::getAttachedShapes(const unsigned int type)
+std::vector<SPItem *> SPAvoidRef::getAttachedShapes(const unsigned int type)
{
- GSList *list = NULL;
+ std::vector<SPItem *> list;
Avoid::IntList shapes;
GQuark shapeId = g_quark_from_string(item->getId());
@@ -157,15 +157,15 @@ GSList *SPAvoidRef::getAttachedShapes(const unsigned int type)
continue;
}
SPItem *shapeItem = SP_ITEM(obj);
- list = g_slist_prepend(list, shapeItem);
+ list.push_back(shapeItem);
}
return list;
}
-GSList *SPAvoidRef::getAttachedConnectors(const unsigned int type)
+std::vector<SPItem *> SPAvoidRef::getAttachedConnectors(const unsigned int type)
{
- GSList *list = NULL;
+ std::vector<SPItem *> list;
Avoid::IntList conns;
GQuark shapeId = g_quark_from_string(item->getId());
@@ -181,7 +181,7 @@ GSList *SPAvoidRef::getAttachedConnectors(const unsigned int type)
continue;
}
SPItem *connItem = SP_ITEM(obj);
- list = g_slist_prepend(list, connItem);
+ list.push_back(connItem);
}
return list;
}
@@ -253,7 +253,7 @@ static std::vector<Geom::Point> approxItemWithPoints(SPItem const *item, const G
SPGroup* group = SP_GROUP(item);
// consider all first-order children
std::vector<SPItem*> itemlist = sp_item_group_item_list(group);
- for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i != itemlist.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i != itemlist.end(); ++i) {
SPItem* child_item = *i;
std::vector<Geom::Point> child_points = approxItemWithPoints(child_item, item_transform * child_item->transform);
poly_points.insert(poly_points.end(), child_points.begin(), child_points.end());
@@ -296,14 +296,14 @@ static Avoid::Polygon avoid_item_poly(SPItem const *item)
Geom::Line hull_edge(hull[-1], hull[0]);
Geom::Line prev_parallel_hull_edge;
prev_parallel_hull_edge.setOrigin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
- prev_parallel_hull_edge.setVersor(hull_edge.versor());
+ prev_parallel_hull_edge.setVector(hull_edge.versor());
int hull_size = hull.size();
for (int i = 0; i < hull_size; ++i)
{
hull_edge.setPoints(hull[i], hull[i+1]);
Geom::Line parallel_hull_edge;
parallel_hull_edge.setOrigin(hull_edge.origin()+hull_edge.versor().ccw()*spacing);
- parallel_hull_edge.setVersor(hull_edge.versor());
+ parallel_hull_edge.setVector(hull_edge.versor());
// determine the intersection point
try {
@@ -331,7 +331,7 @@ static Avoid::Polygon avoid_item_poly(SPItem const *item)
}
-GSList *get_avoided_items(GSList *list, SPObject *from, SPDesktop *desktop,
+std::vector<SPItem *> get_avoided_items(std::vector<SPItem *> &list, SPObject *from, SPDesktop *desktop,
bool initialised)
{
for (SPObject *child = from->firstChild() ; child != NULL; child = child->next ) {
@@ -342,7 +342,7 @@ GSList *get_avoided_items(GSList *list, SPObject *from, SPDesktop *desktop,
(!initialised || SP_ITEM(child)->avoidRef->shapeRef)
)
{
- list = g_slist_prepend (list, SP_ITEM(child));
+ list.push_back(SP_ITEM(child));
}
if (SP_IS_ITEM(child) && desktop->isLayer(SP_ITEM(child))) {
@@ -376,17 +376,15 @@ void init_avoided_shape_geometry(SPDesktop *desktop)
DocumentUndo::setUndoSensitive(document, false);
bool initialised = false;
- GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop,
+ std::vector<SPItem *> tmp;
+ std::vector<SPItem *> items = get_avoided_items(tmp, desktop->currentRoot(), desktop,
initialised);
- for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
- SPItem *item = reinterpret_cast<SPItem *>(iter->data);
+ for (std::vector<SPItem *>::const_iterator iter = items.begin(); iter != items.end(); ++iter) {
+ SPItem *item = *iter;
item->avoidRef->handleSettingChange();
}
- if (items) {
- g_slist_free(items);
- }
DocumentUndo::setUndoSensitive(document, saved);
}
diff --git a/src/conn-avoid-ref.h b/src/conn-avoid-ref.h
index e9e12118f..2c7da9aae 100644
--- a/src/conn-avoid-ref.h
+++ b/src/conn-avoid-ref.h
@@ -20,7 +20,6 @@
class SPDesktop;
class SPObject;
class SPItem;
-typedef struct _GSList GSList;
namespace Avoid { class ShapeRef; }
class SPAvoidRef {
@@ -41,8 +40,8 @@ public:
// Avoid::runningTo
// Avoid::runningFrom
// Avoid::runningToAndFrom
- GSList *getAttachedShapes(const unsigned int type);
- GSList *getAttachedConnectors(const unsigned int type);
+ std::vector<SPItem *> getAttachedShapes(const unsigned int type);
+ std::vector<SPItem *> getAttachedConnectors(const unsigned int type);
private:
SPItem *item;
@@ -55,7 +54,7 @@ private:
sigc::connection _transformed_connection;
};
-extern GSList *get_avoided_items(GSList *list, SPObject *from,
+extern std::vector<SPItem *> get_avoided_items(std::vector<SPItem *> &list, SPObject *from,
SPDesktop *desktop, bool initialised = true);
extern void avoid_item_move(Geom::Affine const *mp, SPItem *moved_item);
extern void init_avoided_shape_geometry(SPDesktop *desktop);
diff --git a/src/desktop-events.cpp b/src/desktop-events.cpp
index b685dacbf..99bc4f7ae 100644
--- a/src/desktop-events.cpp
+++ b/src/desktop-events.cpp
@@ -50,6 +50,8 @@
#include "ui/tools-switch.h"
#include "verbs.h"
#include "widgets/desktop-widget.h"
+#include "sp-cursor.h"
+#include "pixmaps/cursor-select.xpm"
#include "xml/repr.h"
using Inkscape::DocumentUndo;
@@ -514,14 +516,18 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data)
break;
case GDK_ENTER_NOTIFY:
{
- sp_guideline_set_color(SP_GUIDELINE(item), guide->getHiColor());
-
+ if (!guide->getLocked()) {
+ sp_guideline_set_color(SP_GUIDELINE(item), guide->getHiColor());
+ }
// set move or rotate cursor
Geom::Point const event_w(event->crossing.x, event->crossing.y);
if ((event->crossing.state & GDK_SHIFT_MASK) && (drag_type != SP_DRAG_MOVE_ORIGIN)) {
GdkCursor *guide_cursor;
guide_cursor = gdk_cursor_new (GDK_EXCHANGE);
+ if(guide->getLocked()){
+ guide_cursor = sp_cursor_new_from_xpm(cursor_select_xpm , 1, 1);
+ }
gdk_window_set_cursor(gtk_widget_get_window (GTK_WIDGET(desktop->getCanvas())), guide_cursor);
#if GTK_CHECK_VERSION(3,0,0)
g_object_unref(guide_cursor);
@@ -531,6 +537,9 @@ gint sp_dt_guide_event(SPCanvasItem *item, GdkEvent *event, gpointer data)
} else {
GdkCursor *guide_cursor;
guide_cursor = gdk_cursor_new (GDK_HAND1);
+ if(guide->getLocked()){
+ guide_cursor = sp_cursor_new_from_xpm(cursor_select_xpm , 1, 1);
+ }
gdk_window_set_cursor(gtk_widget_get_window (GTK_WIDGET(desktop->getCanvas())), guide_cursor);
#if GTK_CHECK_VERSION(3,0,0)
g_object_unref(guide_cursor);
diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp
index 02c18339b..c28302d22 100644
--- a/src/desktop-style.cpp
+++ b/src/desktop-style.cpp
@@ -195,7 +195,7 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write
sp_css_attr_unset_uris(css_write);
prefs->mergeStyle("/desktop/style", css_write);
std::vector<SPItem*> const itemlist = desktop->selection->itemList();
- for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i!= itemlist.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i!= itemlist.end(); ++i) {
/* last used styles for 3D box faces are stored separately */
SPObject *obj = *i;
Box3DSide *side = dynamic_cast<Box3DSide *>(obj);
@@ -235,7 +235,7 @@ sp_desktop_set_style(SPDesktop *desktop, SPCSSAttr *css, bool change, bool write
css_no_text = sp_css_attr_unset_text(css_no_text);
std::vector<SPItem*> const itemlist = desktop->selection->itemList();
- for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i!= itemlist.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i!= itemlist.end(); ++i) {
SPItem *item = *i;
// If not text, don't apply text attributes (can a group have text attributes? Yes! FIXME)
@@ -447,7 +447,7 @@ stroke_average_width (const std::vector<SPItem*> &objects)
gdouble avgwidth = 0.0;
bool notstroked = true;
int n_notstroked = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPItem *item = *i;
if (!item) {
continue;
@@ -500,7 +500,7 @@ objects_query_fillstroke (const std::vector<SPItem*> &objects, SPStyle *style_re
SPIPaint *paint_res = isfill? &style_res->fill : &style_res->stroke;
bool paintImpossible = true;
- paint_res->set = TRUE;
+ paint_res->set = true;
SVGICCColor* iccColor = 0;
@@ -513,7 +513,7 @@ objects_query_fillstroke (const std::vector<SPItem*> &objects, SPStyle *style_re
prev[0] = prev[1] = prev[2] = 0.0;
bool same_color = true;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i!= objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i!= objects.end(); ++i) {
SPObject *obj = *i;
if (!obj) {
continue;
@@ -697,7 +697,7 @@ objects_query_opacity (const std::vector<SPItem*> &objects, SPStyle *style_res)
guint opacity_items = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!obj) {
continue;
@@ -753,7 +753,7 @@ objects_query_strokewidth (const std::vector<SPItem*> &objects, SPStyle *style_r
int n_stroked = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!obj) {
continue;
@@ -827,7 +827,7 @@ objects_query_miterlimit (const std::vector<SPItem*> &objects, SPStyle *style_re
gdouble prev_ml = -1;
bool same_ml = true;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!dynamic_cast<SPItem *>(obj)) {
continue;
@@ -881,12 +881,11 @@ objects_query_strokecap (const std::vector<SPItem*> &objects, SPStyle *style_res
return QUERY_STYLE_NOTHING;
}
- int cap = -1;
- gdouble prev_cap = -1;
+ int prev_cap = -1;
bool same_cap = true;
int n_stroked = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!dynamic_cast<SPItem *>(obj)) {
continue;
@@ -905,11 +904,9 @@ objects_query_strokecap (const std::vector<SPItem*> &objects, SPStyle *style_res
if (prev_cap != -1 && style->stroke_linecap.value != prev_cap)
same_cap = false;
prev_cap = style->stroke_linecap.value;
-
- cap = style->stroke_linecap.value;
}
- style_res->stroke_linecap.value = cap;
+ style_res->stroke_linecap.value = prev_cap;
style_res->stroke_linecap.set = true;
if (n_stroked == 0) {
@@ -935,12 +932,11 @@ objects_query_strokejoin (const std::vector<SPItem*> &objects, SPStyle *style_re
return QUERY_STYLE_NOTHING;
}
- int join = -1;
- gdouble prev_join = -1;
+ int prev_join = -1;
bool same_join = true;
int n_stroked = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!dynamic_cast<SPItem *>(obj)) {
continue;
@@ -960,11 +956,9 @@ objects_query_strokejoin (const std::vector<SPItem*> &objects, SPStyle *style_re
same_join = false;
}
prev_join = style->stroke_linejoin.value;
-
- join = style->stroke_linejoin.value;
}
- style_res->stroke_linejoin.value = join;
+ style_res->stroke_linejoin.value = prev_join;
style_res->stroke_linejoin.set = true;
if (n_stroked == 0) {
@@ -980,6 +974,62 @@ objects_query_strokejoin (const std::vector<SPItem*> &objects, SPStyle *style_re
}
/**
+ * Write to style_res the paint order of a list of objects.
+ */
+int
+objects_query_paintorder (const std::vector<SPItem*> &objects, SPStyle *style_res)
+{
+ if (objects.empty()) {
+ /* No objects, set empty */
+ return QUERY_STYLE_NOTHING;
+ }
+
+ std::string prev_order;
+ bool same_order = true;
+ int n_order = 0;
+
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
+ SPObject *obj = *i;
+ if (!dynamic_cast<SPItem *>(obj)) {
+ continue;
+ }
+ SPStyle *style = obj->style;
+ if (!style) {
+ continue;
+ }
+
+ if ( style->stroke.isNone() ) {
+ continue;
+ }
+
+ n_order ++;
+
+ if (!prev_order.empty() && prev_order.compare( style->paint_order.value ) != 0) {
+ same_order = false;
+ }
+ if (style->paint_order.set) {
+ prev_order = style->paint_order.value;
+ }
+ }
+
+
+ g_free( style_res->paint_order.value );
+ style_res->paint_order.value= g_strdup( prev_order.c_str() );
+ style_res->paint_order.set = true;
+
+ if (n_order == 0) {
+ return QUERY_STYLE_NOTHING;
+ } else if (n_order == 1) {
+ return QUERY_STYLE_SINGLE;
+ } else {
+ if (same_order)
+ return QUERY_STYLE_MULTIPLE_SAME;
+ else
+ return QUERY_STYLE_MULTIPLE_DIFFERENT;
+ }
+}
+
+/**
* Write to style_res the average font size and spacing of objects.
*/
int
@@ -999,11 +1049,12 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r
double letterspacing_prev = 0;
double wordspacing_prev = 0;
double linespacing_prev = 0;
+ int linespacing_unit = 0;
int texts = 0;
int no_size = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!isTextualItem(obj)) {
@@ -1055,6 +1106,11 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r
linespacing_current = style->line_height.computed;
linespacing_normal = false;
}
+ if (linespacing_unit == 0) {
+ linespacing_unit = style->line_height.unit;
+ } else if (linespacing_unit != style->line_height.unit) {
+ linespacing_unit = SP_CSS_UNIT_PERCENT;
+ }
linespacing += linespacing_current;
if ((size_prev != 0 && style->font_size.computed != size_prev) ||
@@ -1098,7 +1154,7 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r
style_res->line_height.normal = linespacing_normal;
style_res->line_height.computed = linespacing;
style_res->line_height.value = linespacing;
- style_res->line_height.unit = SP_CSS_UNIT_PERCENT;
+ style_res->line_height.unit = linespacing_unit;
if (texts > 1) {
if (different) {
@@ -1122,7 +1178,7 @@ objects_query_fontstyle (const std::vector<SPItem*> &objects, SPStyle *style_res
int texts = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!isTextualItem(obj)) {
@@ -1144,7 +1200,7 @@ objects_query_fontstyle (const std::vector<SPItem*> &objects, SPStyle *style_res
different = true; // different styles
}
- set = TRUE;
+ set = true;
style_res->font_weight.value = style_res->font_weight.computed = style->font_weight.computed;
style_res->font_style.value = style_res->font_style.computed = style->font_style.computed;
style_res->font_stretch.value = style_res->font_stretch.computed = style->font_stretch.computed;
@@ -1192,7 +1248,7 @@ objects_query_fontvariants (const std::vector<SPItem*> &objects, SPStyle *style_
caps_res->value = 0;
numeric_res->value = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!isTextualItem(obj)) {
@@ -1256,6 +1312,56 @@ objects_query_fontvariants (const std::vector<SPItem*> &objects, SPStyle *style_
}
+/**
+ * Write to style_res the average writing modes style of objects.
+ */
+int
+objects_query_writing_modes (const std::vector<SPItem*> &objects, SPStyle *style_res)
+{
+ bool different = false;
+ bool set = false;
+
+ int texts = 0;
+
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
+ SPObject *obj = *i;
+
+ if (!isTextualItem(obj)) {
+ continue;
+ }
+
+ SPStyle *style = obj->style;
+ if (!style) {
+ continue;
+ }
+
+ texts ++;
+
+ if (set &&
+ ( ( style_res->writing_mode.computed != style->writing_mode.computed ) ||
+ ( style_res->text_orientation.computed != style->text_orientation.computed ) ) ) {
+ different = true; // different styles
+ }
+
+ set = true;
+ style_res->writing_mode.computed = style->writing_mode.computed;
+ style_res->text_orientation.computed = style->text_orientation.computed;
+ }
+
+ if (texts == 0 || !set)
+ return QUERY_STYLE_NOTHING;
+
+ if (texts > 1) {
+ if (different) {
+ return QUERY_STYLE_MULTIPLE_DIFFERENT;
+ } else {
+ return QUERY_STYLE_MULTIPLE_SAME;
+ }
+ } else {
+ return QUERY_STYLE_SINGLE;
+ }
+}
+
int
objects_query_fontfeaturesettings (const std::vector<SPItem*> &objects, SPStyle *style_res)
{
@@ -1268,7 +1374,7 @@ objects_query_fontfeaturesettings (const std::vector<SPItem*> &objects, SPStyle
}
style_res->font_feature_settings.set = FALSE;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
// std::cout << " " << reinterpret_cast<SPObject*>(i->data)->getId() << std::endl;
@@ -1293,7 +1399,7 @@ objects_query_fontfeaturesettings (const std::vector<SPItem*> &objects, SPStyle
style_res->font_feature_settings.value = NULL;
}
- style_res->font_feature_settings.set = TRUE;
+ style_res->font_feature_settings.set = true;
style_res->font_feature_settings.value = g_strdup(style->font_feature_settings.value);
}
@@ -1336,7 +1442,7 @@ objects_query_baselines (const std::vector<SPItem*> &objects, SPStyle *style_res
int texts = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!isTextualItem(obj)) {
@@ -1424,7 +1530,7 @@ objects_query_fontfamily (const std::vector<SPItem*> &objects, SPStyle *style_re
}
style_res->font_family.set = FALSE;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
// std::cout << " " << reinterpret_cast<SPObject*>(i->data)->getId() << std::endl;
@@ -1449,7 +1555,7 @@ objects_query_fontfamily (const std::vector<SPItem*> &objects, SPStyle *style_re
style_res->font_family.value = NULL;
}
- style_res->font_family.set = TRUE;
+ style_res->font_family.set = true;
style_res->font_family.value = g_strdup(style->font_family.value);
}
@@ -1480,7 +1586,7 @@ objects_query_fontspecification (const std::vector<SPItem*> &objects, SPStyle *s
}
style_res->font_specification.set = FALSE;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
// std::cout << " " << reinterpret_cast<SPObject*>(i->data)->getId() << std::endl;
@@ -1508,7 +1614,7 @@ objects_query_fontspecification (const std::vector<SPItem*> &objects, SPStyle *s
style_res->font_specification.value = NULL;
}
- style_res->font_specification.set = TRUE;
+ style_res->font_specification.set = true;
style_res->font_specification.value = g_strdup(style->font_specification.value);
}
}
@@ -1538,7 +1644,7 @@ objects_query_blend (const std::vector<SPItem*> &objects, SPStyle *style_res)
bool same_blend = true;
guint items = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!obj) {
continue;
@@ -1628,7 +1734,7 @@ objects_query_blur (const std::vector<SPItem*> &objects, SPStyle *style_res)
guint blur_items = 0;
guint items = 0;
- for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = objects.begin(); i != objects.end(); ++i) {
SPObject *obj = *i;
if (!obj) {
continue;
@@ -1713,6 +1819,8 @@ sp_desktop_query_style_from_list (const std::vector<SPItem*> &list, SPStyle *sty
} else if (property == QUERY_STYLE_PROPERTY_STROKEJOIN) {
return objects_query_strokejoin (list, style);
+ } else if (property == QUERY_STYLE_PROPERTY_PAINTORDER) {
+ return objects_query_paintorder (list, style);
} else if (property == QUERY_STYLE_PROPERTY_MASTEROPACITY) {
return objects_query_opacity (list, style);
@@ -1728,6 +1836,8 @@ sp_desktop_query_style_from_list (const std::vector<SPItem*> &list, SPStyle *sty
return objects_query_fontfeaturesettings (list, style);
} else if (property == QUERY_STYLE_PROPERTY_FONTNUMBERS) {
return objects_query_fontnumbers (list, style);
+ } else if (property == QUERY_STYLE_PROPERTY_WRITINGMODES) {
+ return objects_query_writing_modes (list, style);
} else if (property == QUERY_STYLE_PROPERTY_BASELINES) {
return objects_query_baselines (list, style);
@@ -1777,6 +1887,9 @@ sp_desktop_query_style_all (SPDesktop *desktop, SPStyle *query)
int result_strokemiterlimit = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_STROKEMITERLIMIT);
int result_strokecap = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_STROKECAP);
int result_strokejoin = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_STROKEJOIN);
+
+ int result_paintorder = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_PAINTORDER);
+
int result_opacity = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_MASTEROPACITY);
int result_blur = sp_desktop_query_style (desktop, query, QUERY_STYLE_PROPERTY_BLUR);
@@ -1790,6 +1903,7 @@ sp_desktop_query_style_all (SPDesktop *desktop, SPStyle *query)
result_strokemiterlimit != QUERY_STYLE_NOTHING ||
result_strokecap != QUERY_STYLE_NOTHING ||
result_strokejoin != QUERY_STYLE_NOTHING ||
+ result_paintorder != QUERY_STYLE_NOTHING ||
result_blur != QUERY_STYLE_NOTHING);
}
diff --git a/src/desktop-style.h b/src/desktop-style.h
index 95c434844..f3d6775a4 100644
--- a/src/desktop-style.h
+++ b/src/desktop-style.h
@@ -19,7 +19,6 @@ class SPDesktop;
class SPObject;
class SPItem;
class SPStyle;
-typedef struct _GSList GSList;
namespace Inkscape {
namespace XML {
class Node;
@@ -44,6 +43,7 @@ enum { // which property was queried (add when you need more)
QUERY_STYLE_PROPERTY_STROKEJOIN, // stroke join
QUERY_STYLE_PROPERTY_STROKECAP, // stroke cap
QUERY_STYLE_PROPERTY_STROKESTYLE, // markers, dasharray, miterlimit, stroke-width, stroke-cap, stroke-join
+ QUERY_STYLE_PROPERTY_PAINTORDER, // paint-order
QUERY_STYLE_PROPERTY_FONT_SPECIFICATION, //-inkscape-font-specification
QUERY_STYLE_PROPERTY_FONTFAMILY, // font-family
QUERY_STYLE_PROPERTY_FONTSTYLE, // font style
@@ -51,6 +51,7 @@ enum { // which property was queried (add when you need more)
QUERY_STYLE_PROPERTY_FONTFEATURESETTINGS, // font feature settings (OpenType features)
QUERY_STYLE_PROPERTY_FONTNUMBERS, // size, spacings
QUERY_STYLE_PROPERTY_BASELINES, // baseline-shift
+ QUERY_STYLE_PROPERTY_WRITINGMODES, // writing-mode, text-orientation
QUERY_STYLE_PROPERTY_MASTEROPACITY, // opacity
QUERY_STYLE_PROPERTY_BLEND, // blend
QUERY_STYLE_PROPERTY_BLUR // blur
diff --git a/src/desktop.cpp b/src/desktop.cpp
index 02df50c6b..f099ba39f 100644
--- a/src/desktop.cpp
+++ b/src/desktop.cpp
@@ -210,9 +210,11 @@ SPDesktop::init (SPNamedView *nv, SPCanvas *aCanvas, Inkscape::UI::View::EditWid
main = (SPCanvasGroup *) sp_canvas_item_new (root, SP_TYPE_CANVAS_GROUP, NULL);
g_signal_connect (G_OBJECT (main), "event", G_CALLBACK (sp_desktop_root_handler), this);
+ /* This is the background the page sits on. */
table = sp_canvas_item_new (main, SP_TYPE_CTRLRECT, NULL);
SP_CTRLRECT(table)->setRectangle(Geom::Rect(Geom::Point(-80000, -80000), Geom::Point(80000, 80000)));
SP_CTRLRECT(table)->setColor(0x00000000, true, 0x00000000);
+ SP_CTRLRECT(table)->setCheckerboard( false );
sp_canvas_item_move_to_z (table, 0);
page = sp_canvas_item_new (main, SP_TYPE_CTRLRECT, NULL);
@@ -1467,6 +1469,11 @@ void SPDesktop::toggleColorProfAdjust()
_widget->toggleColorProfAdjust();
}
+void SPDesktop::toggleGuidesLock()
+{
+ _widget->toggleGuidesLock();
+}
+
bool SPDesktop::colorProfAdjustEnabled()
{
return _widget->colorProfAdjustEnabled();
@@ -1474,7 +1481,7 @@ bool SPDesktop::colorProfAdjustEnabled()
void SPDesktop::toggleGrids()
{
- if (namedview->grids) {
+ if (! namedview->grids.empty()) {
if(gridgroup) {
showGrids(!grids_visible);
}
@@ -1699,12 +1706,6 @@ static void _reconstruction_start(SPDesktop * desktop)
desktop->_reconstruction_old_layer_id = desktop->currentLayer()->getId() ? desktop->currentLayer()->getId() : "";
desktop->layers->reset();
- /*
- GSList const * selection_objs = desktop->selection->list();
- for (; selection_objs != NULL; selection_objs = selection_objs->next) {
-
- }
- */
desktop->selection->clear();
}
@@ -1732,14 +1733,16 @@ static void _namedview_modified (SPObject *obj, guint flags, SPDesktop *desktop)
if (flags & SP_OBJECT_MODIFIED_FLAG) {
- /* Show/hide page background */
- if (nv->pagecolor | (0xff != 0xffffffff)) {
- sp_canvas_item_show (desktop->table);
- ((CtrlRect *) desktop->table)->setColor(0x00000000, true, nv->pagecolor | 0xff);
- sp_canvas_item_move_to_z (desktop->table, 0);
+ /* Set page background */
+ sp_canvas_item_show (desktop->table);
+ if (nv->pagecheckerboard) {
+ ((CtrlRect *) desktop->table)->setCheckerboard( true );
+ ((CtrlRect *) desktop->table)->setColor(0x00000000, true, nv->pagecolor ); // | 0xff);
} else {
- sp_canvas_item_hide (desktop->table);
+ ((CtrlRect *) desktop->table)->setCheckerboard( false );
+ ((CtrlRect *) desktop->table)->setColor(0x00000000, true, nv->pagecolor | 0xff);
}
+ sp_canvas_item_move_to_z (desktop->table, 0);
/* Show/hide page border */
if (nv->showborder) {
@@ -1876,6 +1879,8 @@ SPDesktop::show_dialogs()
mapVerbPreference.insert(std::make_pair ("ObjectProperties", "/dialogs/object") );
mapVerbPreference.insert(std::make_pair ("SpellCheck", "/dialogs/spellcheck") );
mapVerbPreference.insert(std::make_pair ("Symbols", "/dialogs/symbols") );
+ mapVerbPreference.insert(std::make_pair ("ObjectsPanel", "/dialogs/objects") );
+ mapVerbPreference.insert(std::make_pair ("TagsPanel", "/dialogs/tags") );
for (std::map<Glib::ustring, Glib::ustring>::const_iterator iter = mapVerbPreference.begin(); iter != mapVerbPreference.end(); ++iter) {
Glib::ustring pref = iter->second;
diff --git a/src/desktop.h b/src/desktop.h
index 754e09766..f1444ba7b 100644
--- a/src/desktop.h
+++ b/src/desktop.h
@@ -383,6 +383,8 @@ public:
void clearWaitingCursor();
bool isWaitingCursor() const { return waiting_cursor; };
+ void toggleGuidesLock();
+
void toggleColorProfAdjust();
bool colorProfAdjustEnabled();
diff --git a/src/display/CMakeLists.txt b/src/display/CMakeLists.txt
index d4f8c16ff..0bf1d6e45 100644
--- a/src/display/CMakeLists.txt
+++ b/src/display/CMakeLists.txt
@@ -54,7 +54,6 @@ set(display_SRC
sp-canvas.cpp
sp-ctrlcurve.cpp
sp-ctrlline.cpp
- sp-ctrlpoint.cpp
sp-ctrlquadr.cpp
@@ -120,7 +119,6 @@ set(display_SRC
sp-canvas.h
sp-ctrlcurve.h
sp-ctrlline.h
- sp-ctrlpoint.h
sp-ctrlquadr.h
)
diff --git a/src/display/Makefile_insert b/src/display/Makefile_insert
index 20e498981..419852f7d 100644
--- a/src/display/Makefile_insert
+++ b/src/display/Makefile_insert
@@ -115,8 +115,6 @@ ink_common_sources += \
display/sp-ctrlcurve.h \
display/sp-ctrlline.cpp \
display/sp-ctrlline.h \
- display/sp-ctrlpoint.cpp \
- display/sp-ctrlpoint.h \
display/sp-ctrlquadr.cpp \
display/sp-ctrlquadr.h
diff --git a/src/display/cairo-utils.cpp b/src/display/cairo-utils.cpp
index 59e190676..24a75de4c 100644
--- a/src/display/cairo-utils.cpp
+++ b/src/display/cairo-utils.cpp
@@ -1120,9 +1120,9 @@ ink_cairo_pattern_create_checkerboard()
cairo_t *ct = cairo_create(s);
cairo_set_operator(ct, CAIRO_OPERATOR_SOURCE);
- cairo_set_source_rgb(ct, 0.75, 0.75, 0.75);
+ cairo_set_source_rgb(ct, 0.77, 0.77, 0.77);
cairo_paint(ct);
- cairo_set_source_rgb(ct, 0.5, 0.5, 0.5);
+ cairo_set_source_rgb(ct, 0.69, 0.69, 0.69);
cairo_rectangle(ct, 0, 0, w, h);
cairo_rectangle(ct, w, h, w, h);
cairo_fill(ct);
diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp
index 1794ccbab..14f36376f 100644
--- a/src/display/canvas-axonomgrid.cpp
+++ b/src/display/canvas-axonomgrid.cpp
@@ -172,9 +172,9 @@ CanvasAxonomGrid::CanvasAxonomGrid (SPNamedView * nv, Inkscape::XML::Node * in_r
angle_deg[Z] = prefs->getDouble("/options/grids/axonom/angle_z", 30.0);
angle_deg[Y] = 0;
- angle_rad[X] = Geom::deg_to_rad(angle_deg[X]);
+ angle_rad[X] = Geom::rad_from_deg(angle_deg[X]);
tan_angle[X] = tan(angle_rad[X]);
- angle_rad[Z] = Geom::deg_to_rad(angle_deg[Z]);
+ angle_rad[Z] = Geom::rad_from_deg(angle_deg[Z]);
tan_angle[Z] = tan(angle_rad[Z]);
snapper = new CanvasAxonomGridSnapper(this, &namedview->snap_manager, 0);
@@ -272,7 +272,7 @@ CanvasAxonomGrid::readRepr()
angle_deg[X] = g_ascii_strtod(value, NULL);
if (angle_deg[X] < 0.) angle_deg[X] = 0.;
if (angle_deg[X] > 89.0) angle_deg[X] = 89.0;
- angle_rad[X] = Geom::deg_to_rad(angle_deg[X]);
+ angle_rad[X] = Geom::rad_from_deg(angle_deg[X]);
tan_angle[X] = tan(angle_rad[X]);
}
@@ -280,7 +280,7 @@ CanvasAxonomGrid::readRepr()
angle_deg[Z] = g_ascii_strtod(value, NULL);
if (angle_deg[Z] < 0.) angle_deg[Z] = 0.;
if (angle_deg[Z] > 89.0) angle_deg[Z] = 89.0;
- angle_rad[Z] = Geom::deg_to_rad(angle_deg[Z]);
+ angle_rad[Z] = Geom::rad_from_deg(angle_deg[Z]);
tan_angle[Z] = tan(angle_rad[Z]);
}
diff --git a/src/display/canvas-text.cpp b/src/display/canvas-text.cpp
index 5ad87b4ef..7c019caf5 100644
--- a/src/display/canvas-text.cpp
+++ b/src/display/canvas-text.cpp
@@ -266,10 +266,10 @@ sp_canvastext_set_coords (SPCanvasText *ct, gdouble x0, gdouble y0)
void
sp_canvastext_set_coords (SPCanvasText *ct, const Geom::Point start)
{
- Geom::Point pos = ct->desktop->doc2dt(start);
-
- g_return_if_fail (ct != NULL);
+ g_return_if_fail (ct && ct->desktop);
g_return_if_fail (SP_IS_CANVASTEXT (ct));
+
+ Geom::Point pos = ct->desktop->doc2dt(start);
if (DIFFER (pos[0], ct->s[Geom::X]) || DIFFER (pos[1], ct->s[Geom::Y])) {
ct->s[Geom::X] = pos[0];
diff --git a/src/display/curve.cpp b/src/display/curve.cpp
index 3024d1276..b6c387034 100644
--- a/src/display/curve.cpp
+++ b/src/display/curve.cpp
@@ -496,7 +496,7 @@ SPCurve::append(SPCurve const *curve2,
_pathv.push_back( (*it) );
}
- for (it++; it != curve2->_pathv.end(); ++it) {
+ for (++it; it != curve2->_pathv.end(); ++it) {
_pathv.push_back( (*it) );
}
} else {
diff --git a/src/display/drawing-image.cpp b/src/display/drawing-image.cpp
index 1594614ac..2a943d16c 100644
--- a/src/display/drawing-image.cpp
+++ b/src/display/drawing-image.cpp
@@ -132,7 +132,7 @@ unsigned DrawingImage::_renderItem(DrawingContext &dc, Geom::IntRect const &/*ar
}
}
- dc.paint(_opacity);
+ dc.paint(1);
} else { // outline; draw a rect instead
diff --git a/src/display/guideline.cpp b/src/display/guideline.cpp
index 44bbd14bd..126fcf87c 100644
--- a/src/display/guideline.cpp
+++ b/src/display/guideline.cpp
@@ -17,17 +17,10 @@
#include <2geom/coord.h>
#include <2geom/transforms.h>
#include "sp-canvas-util.h"
-#include "sp-ctrlpoint.h"
#include "guideline.h"
#include "display/cairo-utils.h"
-
-#include "inkscape.h" // for inkscape_active_desktop()
-#include "desktop.h"
-#include "sp-namedview.h"
#include "display/sp-canvas.h"
-#include "ui/control-manager.h"
-
-using Inkscape::ControlManager;
+#include "display/sodipodi-ctrl.h"
static void sp_guideline_destroy(SPCanvasItem *object);
@@ -53,6 +46,7 @@ static void sp_guideline_init(SPGuideLine *gl)
{
gl->rgba = 0x0000ff7f;
+ gl->locked = false;
gl->normal_to_line = Geom::Point(0,1);
gl->angle = 3.14159265358979323846/2;
gl->point_on_line = Geom::Point(0,0);
@@ -66,16 +60,11 @@ static void sp_guideline_destroy(SPCanvasItem *object)
{
g_return_if_fail (object != NULL);
g_return_if_fail (SP_IS_GUIDELINE (object));
- //g_return_if_fail (SP_GUIDELINE(object)->origin != NULL);
- //g_return_if_fail (SP_IS_CTRLPOINT(SP_GUIDELINE(object)->origin));
SPGuideLine *gl = SP_GUIDELINE(object);
- if (gl->origin != NULL && SP_IS_CTRLPOINT(gl->origin)) {
- sp_canvas_item_destroy(gl->origin);
- } else {
- // FIXME: This branch shouldn't be reached (although it seems to be harmless).
- //g_error("Why can it be that gl->origin is not a valid SPCtrlPoint?\n");
+ if (gl->origin) {
+ sp_canvas_item_destroy(SP_CANVAS_ITEM(gl->origin));
}
if (gl->label) {
@@ -175,12 +164,22 @@ static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine,
(SP_CANVAS_ITEM_CLASS(sp_guideline_parent_class))->update(item, affine, flags);
}
- gl->affine = affine;
-
- sp_ctrlpoint_set_coords(gl->origin, gl->point_on_line);
- sp_canvas_item_request_update(SP_CANVAS_ITEM (gl->origin));
+ if (item->visible) {
+ if (gl->locked) {
+ g_object_set(G_OBJECT(gl->origin), "stroke_color", 0x0000ff88,
+ "shape", SP_CTRL_SHAPE_CROSS,
+ "size", 6., NULL);
+ } else {
+ g_object_set(G_OBJECT(gl->origin), "stroke_color", 0xff000088,
+ "shape", SP_CTRL_SHAPE_CIRCLE,
+ "size", 4., NULL);
+ }
+ gl->origin->moveto(gl->point_on_line);
+ sp_canvas_item_request_update(SP_CANVAS_ITEM(gl->origin));
+ }
- Geom::Point pol_transformed = gl->point_on_line*affine;
+ gl->affine = affine;
+ Geom::Point pol_transformed = gl->point_on_line * affine;
if (gl->is_horizontal()) {
sp_canvas_update_bbox (item, -1000000, round(pol_transformed[Geom::Y] - 16), 1000000, round(pol_transformed[Geom::Y] + 1));
} else if (gl->is_vertical()) {
@@ -210,20 +209,22 @@ static double sp_guideline_point(SPCanvasItem *item, Geom::Point p, SPCanvasItem
SPCanvasItem *sp_guideline_new(SPCanvasGroup *parent, char* label, Geom::Point point_on_line, Geom::Point normal)
{
SPCanvasItem *item = sp_canvas_item_new(parent, SP_TYPE_GUIDELINE, NULL);
- SPCanvasItem *origin = ControlManager::getManager().createControl(parent, Inkscape::CTRL_TYPE_ORIGIN);
- ControlManager::getManager().track(origin);
-
SPGuideLine *gl = SP_GUIDELINE(item);
- SPCtrlPoint *cp = SP_CTRLPOINT(origin);
- gl->origin = cp;
normal.normalize();
gl->label = label;
+ gl->locked = false;
gl->normal_to_line = normal;
gl->angle = tan( -gl->normal_to_line[Geom::X] / gl->normal_to_line[Geom::Y]);
sp_guideline_set_position(gl, point_on_line);
- sp_ctrlpoint_set_coords(cp, point_on_line);
+ gl->origin = (SPCtrl *) sp_canvas_item_new(parent, SP_TYPE_CTRL,
+ "anchor", SP_ANCHOR_CENTER,
+ "mode", SP_CTRL_MODE_COLOR,
+ "filled", FALSE,
+ "stroked", TRUE,
+ "stroke_color", 0x01000000, NULL);
+ gl->origin->pickable = false;
return item;
}
@@ -238,6 +239,12 @@ void sp_guideline_set_label(SPGuideLine *gl, const char* label)
sp_canvas_item_request_update(SP_CANVAS_ITEM (gl));
}
+void sp_guideline_set_locked(SPGuideLine *gl, const bool locked)
+{
+ gl->locked = locked;
+ sp_canvas_item_request_update(SP_CANVAS_ITEM (gl));
+}
+
void sp_guideline_set_position(SPGuideLine *gl, Geom::Point point_on_line)
{
gl->point_on_line = point_on_line;
@@ -255,8 +262,7 @@ void sp_guideline_set_normal(SPGuideLine *gl, Geom::Point normal_to_line)
void sp_guideline_set_color(SPGuideLine *gl, unsigned int rgba)
{
gl->rgba = rgba;
- sp_ctrlpoint_set_color(gl->origin, rgba);
-
+ g_object_set(G_OBJECT(gl->origin), "stroke_color", rgba, NULL);
sp_canvas_item_request_update(SP_CANVAS_ITEM(gl));
}
@@ -267,7 +273,6 @@ void sp_guideline_set_sensitive(SPGuideLine *gl, int sensitive)
void sp_guideline_delete(SPGuideLine *gl)
{
- //gtk_object_destroy(GTK_OBJECT(gl->origin));
sp_canvas_item_destroy(SP_CANVAS_ITEM(gl));
}
diff --git a/src/display/guideline.h b/src/display/guideline.h
index 2d9a87d9b..44aed88d9 100644
--- a/src/display/guideline.h
+++ b/src/display/guideline.h
@@ -21,17 +21,18 @@
#define SP_GUIDELINE(o) (G_TYPE_CHECK_INSTANCE_CAST((o), SP_TYPE_GUIDELINE, SPGuideLine))
#define SP_IS_GUIDELINE(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), SP_TYPE_GUIDELINE))
-struct SPCtrlPoint;
+struct SPCtrl;
struct SPGuideLine {
SPCanvasItem item;
Geom::Affine affine;
- SPCtrlPoint *origin; // unlike 'item', this is only held locally
+ SPCtrl *origin; // unlike 'item', this is only held locally
guint32 rgba;
char* label;
+ bool locked;
Geom::Point normal_to_line;
Geom::Point point_on_line;
double angle;
@@ -51,6 +52,7 @@ GType sp_guideline_get_type();
SPCanvasItem *sp_guideline_new(SPCanvasGroup *parent, char* label, Geom::Point point_on_line, Geom::Point normal);
void sp_guideline_set_label(SPGuideLine *gl, const char* label);
+void sp_guideline_set_locked(SPGuideLine *gl, const bool locked);
void sp_guideline_set_position(SPGuideLine *gl, Geom::Point point_on_line);
void sp_guideline_set_normal(SPGuideLine *gl, Geom::Point normal_to_line);
void sp_guideline_set_color(SPGuideLine *gl, unsigned int rgba);
diff --git a/src/display/nr-filter-component-transfer.cpp b/src/display/nr-filter-component-transfer.cpp
index dd90193fe..b2545b76f 100644
--- a/src/display/nr-filter-component-transfer.cpp
+++ b/src/display/nr-filter-component-transfer.cpp
@@ -30,6 +30,32 @@ FilterPrimitive * FilterComponentTransfer::create() {
FilterComponentTransfer::~FilterComponentTransfer()
{}
+struct UnmultiplyAlpha {
+ guint32 operator()(guint32 in) {
+ EXTRACT_ARGB32(in, a, r, g, b);
+ if (a == 0 )
+ return in;
+ r = unpremul_alpha(r, a);
+ g = unpremul_alpha(g, a);
+ b = unpremul_alpha(b, a);
+ ASSEMBLE_ARGB32(out, a, r, g, b);
+ return out;
+ }
+};
+
+struct MultiplyAlpha {
+ guint32 operator()(guint32 in) {
+ EXTRACT_ARGB32(in, a, r, g, b);
+ if (a == 0 )
+ return in;
+ r = premul_alpha(r, a);
+ g = premul_alpha(g, a);
+ b = premul_alpha(b, a);
+ ASSEMBLE_ARGB32(out, a, r, g, b);
+ return out;
+ }
+};
+
struct ComponentTransfer {
ComponentTransfer(guint32 color)
: _shift(color * 8)
@@ -40,11 +66,7 @@ protected:
guint32 _mask;
};
-template <bool alpha>
-struct ComponentTransferTable;
-
-template <>
-struct ComponentTransferTable<false> : public ComponentTransfer {
+struct ComponentTransferTable : public ComponentTransfer {
ComponentTransferTable(guint32 color, std::vector<double> const &values)
: ComponentTransfer(color)
, _v(values.size())
@@ -55,49 +77,17 @@ struct ComponentTransferTable<false> : public ComponentTransfer {
}
guint32 operator()(guint32 in) {
guint32 component = (in & _mask) >> _shift;
- guint32 alpha = (in & 0xff000000) >> 24;
- if (alpha == 0) return in;
-
- component = (255 * component + alpha/2) / alpha;
guint32 k = (_v.size() - 1) * component;
guint32 dx = k % 255; k /= 255;
component = _v[k]*255 + (_v[k+1] - _v[k])*dx;
component = (component + 127) / 255;
- component = premul_alpha(component, alpha);
return (in & ~_mask) | (component << _shift);
}
private:
std::vector<guint32> _v;
};
-template <>
-struct ComponentTransferTable<true> {
- ComponentTransferTable(std::vector<double> const &values)
- : _v(values.size())
- {
- for (unsigned i = 0; i< values.size(); ++i) {
- _v[i] = round(CLAMP(values[i], 0.0, 1.0) * 255);
- }
- }
- guint32 operator()(guint32 in) {
- guint32 alpha = (in & 0xff000000) >> 24;
- if (alpha == 0) return in;
-
- guint32 k = (_v.size() - 1) * alpha;
- guint32 dx = k % 255; k /= 255;
- alpha = _v[k]*255 + (_v[k+1] - _v[k])*dx;
- alpha = (alpha + 127) / 255;
- return (in & 0x00ffffff) | (alpha << 24);
- }
-private:
- std::vector<guint32> _v;
-};
-
-template <bool alpha>
-struct ComponentTransferDiscrete;
-
-template <>
-struct ComponentTransferDiscrete<false> : public ComponentTransfer {
+struct ComponentTransferDiscrete : public ComponentTransfer {
ComponentTransferDiscrete(guint32 color, std::vector<double> const &values)
: ComponentTransfer(color)
, _v(values.size())
@@ -108,45 +98,16 @@ struct ComponentTransferDiscrete<false> : public ComponentTransfer {
}
guint32 operator()(guint32 in) {
guint32 component = (in & _mask) >> _shift;
- guint32 alpha = (in & 0xff000000) >> 24;
- if (alpha == 0) return in;
-
- component = (255 * component + alpha/2) / alpha;
- guint32 k = (_v.size() - 1) * component / 255;
+ guint32 k = (_v.size()) * component / 255;
+ if( k == _v.size() ) --k;
component = _v[k];
- component = premul_alpha(component, alpha);
- return (in & ~_mask) | (component << _shift);
+ return (in & ~_mask) | ((guint32)component << _shift);
}
private:
std::vector<guint32> _v;
};
-template <>
-struct ComponentTransferDiscrete<true> {
- ComponentTransferDiscrete(std::vector<double> const &values)
- : _v(values.size())
- {
- for (unsigned i = 0; i< values.size(); ++i) {
- _v[i] = round(CLAMP(values[i], 0.0, 1.0) * 255);
- }
- }
- guint32 operator()(guint32 in) {
- guint32 alpha = (in & 0xff000000) >> 24;
- if (alpha == 0) return in;
-
- guint32 k = (_v.size() - 1) * alpha / 255;
- alpha = _v[k];
- return (in & 0x00ffffff) | (alpha << 24);
- }
-private:
- std::vector<guint32> _v;
-};
-
-template <bool alpha>
-struct ComponentTransferLinear;
-
-template <>
-struct ComponentTransferLinear<false> : public ComponentTransfer {
+struct ComponentTransferLinear : public ComponentTransfer {
ComponentTransferLinear(guint32 color, double intercept, double slope)
: ComponentTransfer(color)
, _intercept(round(intercept*255*255))
@@ -154,14 +115,10 @@ struct ComponentTransferLinear<false> : public ComponentTransfer {
{}
guint32 operator()(guint32 in) {
gint32 component = (in & _mask) >> _shift;
- guint32 alpha = (in & 0xff000000) >> 24;
- if (alpha == 0) return 0;
// TODO: this can probably be reduced to something simpler
- component = (255 * component + alpha/2) / alpha;
component = pxclamp(_slope * component + _intercept, 0, 255*255);
component = (component + 127) / 255;
- component = premul_alpha(component, alpha);
return (in & ~_mask) | (component << _shift);
}
private:
@@ -169,28 +126,7 @@ private:
gint32 _slope;
};
-template <>
-struct ComponentTransferLinear<true> {
- ComponentTransferLinear(double intercept, double slope)
- : _intercept(round(intercept*255*255))
- , _slope(round(slope*255))
- {}
- guint32 operator()(guint32 in) {
- gint32 alpha = (in & 0xff000000) >> 24;
- alpha = pxclamp(_slope * alpha + _intercept, 0, 255*255);
- alpha = (alpha + 127) / 255;
- return (in & 0x00ffffff) | (alpha << 24);
- }
-private:
- gint32 _intercept;
- gint32 _slope;
-};
-
-template <bool alpha>
-struct ComponentTransferGamma;
-
-template <>
-struct ComponentTransferGamma<false> : public ComponentTransfer {
+struct ComponentTransferGamma : public ComponentTransfer {
ComponentTransferGamma(guint32 color, double amplitude, double exponent, double offset)
: ComponentTransfer(color)
, _amplitude(amplitude)
@@ -199,13 +135,9 @@ struct ComponentTransferGamma<false> : public ComponentTransfer {
{}
guint32 operator()(guint32 in) {
double component = (in & _mask) >> _shift;
- guint32 alpha = (in & 0xff000000) >> 24;
- if (alpha == 0) return 0;
-
- double alphaf = alpha;
- component /= alphaf;
+ component /= 255.0;
component = _amplitude * pow(component, _exponent) + _offset;
- guint32 cpx = pxclamp(component * alphaf, 0, 255);
+ guint32 cpx = pxclamp(component * 255.0, 0, 255);
return (in & ~_mask) | (cpx << _shift);
}
private:
@@ -214,26 +146,6 @@ private:
double _offset;
};
-template <>
-struct ComponentTransferGamma<true> {
- ComponentTransferGamma(double amplitude, double exponent, double offset)
- : _amplitude(amplitude)
- , _exponent(exponent)
- , _offset(offset)
- {}
- guint32 operator()(guint32 in) {
- double alpha = (in & 0xff000000) >> 24;
- alpha /= 255.0;
- alpha = _amplitude * pow(alpha, _exponent) + _offset;
- guint32 cpx = pxclamp(alpha * 255.0, 0, 255);
- return (in & 0x00ffffff) | (cpx << 24);
- }
-private:
- double _amplitude;
- double _exponent;
- double _offset;
-};
-
void FilterComponentTransfer::render_cairo(FilterSlot &slot)
{
cairo_surface_t *input = slot.getcairo(_input);
@@ -252,31 +164,38 @@ void FilterComponentTransfer::render_cairo(FilterSlot &slot)
//cairo_surface_t *outtemp = ink_cairo_surface_create_identical(out);
ink_cairo_surface_blit(input, out);
+ // We need to operate on unmultipled by alpha color values otherwise a change in alpha screws
+ // up the premultiplied by alpha r, g, b values.
+ ink_cairo_surface_filter(out, out, UnmultiplyAlpha());
+
// parameters: R = 0, G = 1, B = 2, A = 3
// Cairo: R = 2, G = 1, B = 0, A = 3
// If tableValues is empty, use identity.
- for (unsigned i = 0; i < 3; ++i) {
+ for (unsigned i = 0; i < 4; ++i) {
+
guint32 color = 2 - i;
+ if(i==3) color = 3; // alpha
+
switch (type[i]) {
case COMPONENTTRANSFER_TYPE_TABLE:
if(!tableValues[i].empty()) {
ink_cairo_surface_filter(out, out,
- ComponentTransferTable<false>(color, tableValues[i]));
+ ComponentTransferTable(color, tableValues[i]));
}
break;
case COMPONENTTRANSFER_TYPE_DISCRETE:
if(!tableValues[i].empty()) {
ink_cairo_surface_filter(out, out,
- ComponentTransferDiscrete<false>(color, tableValues[i]));
+ ComponentTransferDiscrete(color, tableValues[i]));
}
break;
case COMPONENTTRANSFER_TYPE_LINEAR:
ink_cairo_surface_filter(out, out,
- ComponentTransferLinear<false>(color, intercept[i], slope[i]));
+ ComponentTransferLinear(color, intercept[i], slope[i]));
break;
case COMPONENTTRANSFER_TYPE_GAMMA:
ink_cairo_surface_filter(out, out,
- ComponentTransferGamma<false>(color, amplitude[i], exponent[i], offset[i]));
+ ComponentTransferGamma(color, amplitude[i], exponent[i], offset[i]));
break;
case COMPONENTTRANSFER_TYPE_ERROR:
case COMPONENTTRANSFER_TYPE_IDENTITY:
@@ -286,33 +205,7 @@ void FilterComponentTransfer::render_cairo(FilterSlot &slot)
//ink_cairo_surface_blit(out, outtemp);
}
- // fast paths for alpha channel
- switch (type[3]) {
- case COMPONENTTRANSFER_TYPE_TABLE:
- if(!tableValues[3].empty()) {
- ink_cairo_surface_filter(out, out,
- ComponentTransferTable<true>(tableValues[3]));
- }
- break;
- case COMPONENTTRANSFER_TYPE_DISCRETE:
- if(!tableValues[3].empty()) {
- ink_cairo_surface_filter(out, out,
- ComponentTransferDiscrete<true>(tableValues[3]));
- }
- break;
- case COMPONENTTRANSFER_TYPE_LINEAR:
- ink_cairo_surface_filter(out, out,
- ComponentTransferLinear<true>(intercept[3], slope[3]));
- break;
- case COMPONENTTRANSFER_TYPE_GAMMA:
- ink_cairo_surface_filter(out, out,
- ComponentTransferGamma<true>(amplitude[3], exponent[3], offset[3]));
- break;
- case COMPONENTTRANSFER_TYPE_ERROR:
- case COMPONENTTRANSFER_TYPE_IDENTITY:
- default:
- break;
- }
+ ink_cairo_surface_filter(out, out, MultiplyAlpha());
slot.set(_output, out);
cairo_surface_destroy(out);
diff --git a/src/display/nr-filter-image.cpp b/src/display/nr-filter-image.cpp
index 179ba0e0a..af89d98e0 100644
--- a/src/display/nr-filter-image.cpp
+++ b/src/display/nr-filter-image.cpp
@@ -56,6 +56,8 @@ void FilterImage::render_cairo(FilterSlot &slot)
// Note: viewport calculation in non-trivial. Do not rely
// on get_matrix_primitiveunits2pb().
Geom::Rect vp = filter_primitive_area( slot.get_units() );
+ slot.set_primitive_area(_output, vp); // Needed for tiling
+
double feImageX = vp.min()[Geom::X];
double feImageY = vp.min()[Geom::Y];
double feImageWidth = vp.width();
diff --git a/src/display/nr-filter-offset.cpp b/src/display/nr-filter-offset.cpp
index af1081abe..93bab7d39 100644
--- a/src/display/nr-filter-offset.cpp
+++ b/src/display/nr-filter-offset.cpp
@@ -37,9 +37,11 @@ void FilterOffset::render_cairo(FilterSlot &slot)
cairo_surface_t *out = ink_cairo_surface_create_identical(in);
// color_interpolation_filters for out same as in. See spec (DisplacementMap).
copy_cairo_surface_ci(in, out);
-
cairo_t *ct = cairo_create(out);
+ Geom::Rect vp = filter_primitive_area( slot.get_units() );
+ slot.set_primitive_area(_output, vp); // Needed for tiling
+
// Handle bounding box case
double x = dx;
double y = dy;
diff --git a/src/display/nr-filter-primitive.cpp b/src/display/nr-filter-primitive.cpp
index c8b569036..ea72efff0 100644
--- a/src/display/nr-filter-primitive.cpp
+++ b/src/display/nr-filter-primitive.cpp
@@ -110,17 +110,12 @@ void FilterPrimitive::set_subregion(SVGLength const &x, SVGLength const &y,
Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units)
{
- Geom::OptRect const bb_opt = units.get_item_bbox();
Geom::OptRect const fa_opt = units.get_filter_area();
- Geom::Rect bb;
- Geom::Rect fa;
- if (!bb_opt || !fa_opt) {
+ if (!fa_opt) {
+ std::cerr << "FilterPrimitive::filter_primitive_area: filter area undefined." << std::endl;
return Geom::Rect (Geom::Point(0.,0.), Geom::Point(0.,0.));
- } else {
- bb = *bb_opt;
- fa = *fa_opt;
}
-
+ Geom::Rect fa = *fa_opt;
// x, y, width, and height are independently defined (i.e. one can be defined, by default, to
// the filter area (via default value ) while another is defined relative to the bounding
@@ -138,6 +133,14 @@ Geom::Rect FilterPrimitive::filter_primitive_area(FilterUnits const &units)
if( units.get_primitive_units() == SP_FILTER_UNITS_OBJECTBOUNDINGBOX ) {
+ Geom::OptRect const bb_opt = units.get_item_bbox();
+ if (!bb_opt) {
+ std::cerr << "FilterPrimitive::filter_primitive_area: bounding box undefined and 'primitiveUnits' is 'objectBoundingBox'." << std::endl;
+ return Geom::Rect (Geom::Point(0.,0.), Geom::Point(0.,0.));
+ }
+ Geom::Rect bb = *bb_opt;
+
+
// Update computed values for ex, em, %.
// For %, assumes primitive unit is objectBoundingBox.
// TODO: fetch somehow the object ex and em lengths; 12, 6 are just dummy values.
diff --git a/src/display/nr-filter-slot.cpp b/src/display/nr-filter-slot.cpp
index e4c2f048e..a6e0c5c4e 100644
--- a/src/display/nr-filter-slot.cpp
+++ b/src/display/nr-filter-slot.cpp
@@ -232,6 +232,27 @@ void FilterSlot::set(int slot_nr, cairo_surface_t *surface)
_last_out = slot_nr;
}
+void FilterSlot::set_primitive_area(int slot_nr, Geom::Rect &area)
+{
+ if (slot_nr == NR_FILTER_SLOT_NOT_SET)
+ slot_nr = NR_FILTER_UNNAMED_SLOT;
+
+ _primitiveAreas[slot_nr] = area;
+}
+
+Geom::Rect FilterSlot::get_primitive_area(int slot_nr)
+{
+ if (slot_nr == NR_FILTER_SLOT_NOT_SET)
+ slot_nr = _last_out;
+
+ PrimitiveAreaMap::iterator s = _primitiveAreas.find(slot_nr);
+
+ if (s == _primitiveAreas.end()) {
+ return *(_units.get_filter_area());
+ }
+ return s->second;
+}
+
int FilterSlot::get_slot_count()
{
return _slots.size();
diff --git a/src/display/nr-filter-slot.h b/src/display/nr-filter-slot.h
index 987dedfd1..166b2e718 100644
--- a/src/display/nr-filter-slot.h
+++ b/src/display/nr-filter-slot.h
@@ -54,6 +54,9 @@ public:
cairo_surface_t *get_result(int slot_nr);
+ void set_primitive_area(int slot, Geom::Rect &area);
+ Geom::Rect get_primitive_area(int slot);
+
/** Returns the number of slots in use. */
int get_slot_count();
@@ -75,6 +78,11 @@ public:
private:
typedef std::map<int, cairo_surface_t *> SlotMap;
SlotMap _slots;
+
+ // We need to keep track of the primitive area as this is needed in feTile
+ typedef std::map<int, Geom::Rect> PrimitiveAreaMap;
+ PrimitiveAreaMap _primitiveAreas;
+
DrawingItem *_item;
//Geom::Rect _source_bbox; ///< bounding box of source graphic surface
diff --git a/src/display/nr-filter-tile.cpp b/src/display/nr-filter-tile.cpp
index 93ca50210..913812828 100644
--- a/src/display/nr-filter-tile.cpp
+++ b/src/display/nr-filter-tile.cpp
@@ -10,6 +10,8 @@
*/
#include <glib.h>
+
+#include "display/cairo-utils.h"
#include "display/nr-filter-tile.h"
#include "display/nr-filter-slot.h"
#include "display/nr-filter-units.h"
@@ -30,16 +32,105 @@ FilterTile::~FilterTile()
void FilterTile::render_cairo(FilterSlot &slot)
{
+ // FIX ME!
static bool tile_warning = false;
-
-//IMPLEMENT ME!
if (!tile_warning) {
- g_warning("Renderer for feTile is not implemented.");
+ g_warning("Renderer for feTile has non-optimal implementation, expect slowness and bugs.");
tile_warning = true;
}
+ // Fixing isn't so easy as the Inkscape renderer breaks the canvas into "rendering" tiles for
+ // faster rendering. (The "rendering" tiles are not the same as the tiles in this primitive.)
+ // Only if the the feTile tile source falls inside the current "rendering" tile will the tile
+ // image be available.
+
+ // This input source contains only the "rendering" tile.
cairo_surface_t *in = slot.getcairo(_input);
- slot.set(_output, in);
+
+ // For debugging
+ // static int i = 0;
+ // ++i;
+ // std::stringstream filename;
+ // filename << "dump." << i << ".png";
+ // cairo_surface_write_to_png( in, filename.str().c_str() );
+
+ // This is the feTile source area as determined by the input primitive area (see SVG spec).
+ Geom::Rect tile_area = slot.get_primitive_area(_input);
+
+ if( tile_area.width() == 0.0 || tile_area.height() == 0.0 ) {
+
+ slot.set(_output, in);
+ std::cerr << "FileTile::render_cairo: tile has zero width or height" << std::endl;
+
+ } else {
+
+ cairo_surface_t *out = ink_cairo_surface_create_identical(in);
+ // color_interpolation_filters for out same as in.
+ copy_cairo_surface_ci(in, out);
+ cairo_t *ct = cairo_create(out);
+
+ // The rectangle of the "rendering" tile.
+ Geom::Rect sa = slot.get_slot_area();
+
+ Geom::Affine trans = slot.get_units().get_matrix_user2pb();
+
+ // Create feTile tile ----------------
+
+ // Get tile area in pixbuf units (tile transformed).
+ Geom::Rect tt = tile_area * trans;
+
+ // Shift between "rendering" tile and feTile tile
+ Geom::Point shift = sa.min() - tt.min();
+
+ // Create feTile tile surface
+ cairo_surface_t *tile = cairo_surface_create_similar(in, cairo_surface_get_content(in),
+ tt.width(), tt.height());
+ cairo_t *ct_tile = cairo_create(tile);
+ cairo_set_source_surface(ct_tile, in, shift[Geom::X], shift[Geom::Y]);
+ cairo_paint(ct_tile);
+
+ // Paint tiles ------------------
+
+ // For debugging
+ // std::stringstream filename;
+ // filename << "tile." << i << ".png";
+ // cairo_surface_write_to_png( tile, filename.str().c_str() );
+
+ // Determine number of feTile rows and columns
+ Geom::Rect pr = filter_primitive_area( slot.get_units() );
+ int tile_cols = ceil( pr.width() / tile_area.width() );
+ int tile_rows = ceil( pr.height() / tile_area.height() );
+
+ // Do tiling (TO DO: restrict to slot area.)
+ for( int col=0; col < tile_cols; ++col ) {
+ for( int row=0; row < tile_rows; ++row ) {
+
+ Geom::Point offset( col*tile_area.width(), row*tile_area.height() );
+ offset *= trans;
+ offset[Geom::X] -= trans[4];
+ offset[Geom::Y] -= trans[5];
+
+ cairo_set_source_surface(ct, tile, offset[Geom::X], offset[Geom::Y]);
+ cairo_paint(ct);
+ }
+ }
+ slot.set(_output, out);
+
+ // Clean up
+ cairo_destroy(ct);
+ cairo_surface_destroy(out);
+ cairo_destroy(ct_tile);
+ cairo_surface_destroy(tile);
+ }
+}
+
+void FilterTile::area_enlarge(Geom::IntRect &area, Geom::Affine const &trans)
+{
+ // We need to enlarge enough to get tile source... we don't the area of the source tile in this
+ // function so we guess. This is VERY inefficient.
+ Geom::Point enlarge(200, 200);
+ enlarge *= trans;
+ area.expandBy( enlarge[Geom::X] < 100 ? 100: enlarge[Geom::X] );
}
double FilterTile::complexity(Geom::Affine const &)
diff --git a/src/display/nr-filter-tile.h b/src/display/nr-filter-tile.h
index 29087f2d6..239ecff4b 100644
--- a/src/display/nr-filter-tile.h
+++ b/src/display/nr-filter-tile.h
@@ -26,6 +26,7 @@ public:
virtual ~FilterTile();
virtual void render_cairo(FilterSlot &slot);
+ virtual void area_enlarge(Geom::IntRect &area, Geom::Affine const &trans);
virtual double complexity(Geom::Affine const &ctm);
};
diff --git a/src/display/nr-filter.cpp b/src/display/nr-filter.cpp
index dec5b1f57..8591be7eb 100644
--- a/src/display/nr-filter.cpp
+++ b/src/display/nr-filter.cpp
@@ -200,7 +200,7 @@ void Filter::area_enlarge(Geom::IntRect &bbox, Inkscape::DrawingItem const *item
Geom::Rect item_bbox;
Geom::OptRect maybe_bbox = item->itemBounds();
- if (maybe_bbox.isEmpty()) {
+ if (maybe_bbox.empty()) {
// Code below needs a bounding box
return;
}
diff --git a/src/display/nr-style.cpp b/src/display/nr-style.cpp
index 1740785e2..8b82a1dff 100644
--- a/src/display/nr-style.cpp
+++ b/src/display/nr-style.cpp
@@ -68,7 +68,6 @@ NRStyle::NRStyle()
, tspan_width(0)
, ascender(0)
, descender(0)
- , line_gap(0)
, underline_thickness(0)
, underline_position(0)
, line_through_thickness(0)
@@ -330,7 +329,6 @@ void NRStyle::set(SPStyle *style, SPStyle *context_style)
tspan_width = style->text_decoration_data.tspan_width;
ascender = style->text_decoration_data.ascender;
descender = style->text_decoration_data.descender;
- line_gap = style->text_decoration_data.line_gap;
underline_thickness = style->text_decoration_data.underline_thickness;
underline_position = style->text_decoration_data.underline_position;
line_through_thickness = style->text_decoration_data.line_through_thickness;
diff --git a/src/display/nr-style.h b/src/display/nr-style.h
index 5f78795d3..6c652311a 100644
--- a/src/display/nr-style.h
+++ b/src/display/nr-style.h
@@ -115,7 +115,6 @@ struct NRStyle {
float tspan_width;
float ascender;
float descender;
- float line_gap;
float underline_thickness;
float underline_position;
float line_through_thickness;
diff --git a/src/display/snap-indicator.cpp b/src/display/snap-indicator.cpp
index 926b35599..17deea16d 100644
--- a/src/display/snap-indicator.cpp
+++ b/src/display/snap-indicator.cpp
@@ -256,7 +256,12 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap
"shape", SP_KNOT_SHAPE_CROSS,
NULL );
- const int timeout_val = 4000;
+ double timeout_val = prefs->getDouble("/options/snapindicatorpersistence/value", 2.0);
+ if (timeout_val < 0.1) {
+ timeout_val = 0.1; // a zero value would mean infinite persistence (i.e. until new snap occurs)
+ // Besides, negatives values would ....?
+ }
+
// The snap indicator will be deleted after some time-out, and sp_canvas_item_dispose
// will be called. This will set canvas->current_item to NULL if the snap indicator was
@@ -272,7 +277,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap
SP_CTRL(canvasitem)->pickable = false;
SP_CTRL(canvasitem)->moveto(p.getPoint());
- _snaptarget = _desktop->add_temporary_canvasitem(canvasitem, timeout_val);
+ _snaptarget = _desktop->add_temporary_canvasitem(canvasitem, timeout_val*1000.0);
_snaptarget_is_presnap = pre_snap;
// Display the tooltip, which reveals the type of snap source and the type of snap target
@@ -307,7 +312,7 @@ SnapIndicator::set_new_snaptarget(Inkscape::SnappedPoint const &p, bool pre_snap
SP_CANVASTEXT(canvas_tooltip)->anchor_position = TEXT_ANCHOR_CENTER;
g_free(tooltip_str);
- _snaptarget_tooltip = _desktop->add_temporary_canvasitem(canvas_tooltip, timeout_val);
+ _snaptarget_tooltip = _desktop->add_temporary_canvasitem(canvas_tooltip, timeout_val*1000.0);
}
// Display the bounding box, if we snapped to one
diff --git a/src/display/sodipodi-ctrlrect.cpp b/src/display/sodipodi-ctrlrect.cpp
index 75789ff50..ecc952c48 100644
--- a/src/display/sodipodi-ctrlrect.cpp
+++ b/src/display/sodipodi-ctrlrect.cpp
@@ -74,6 +74,8 @@ void CtrlRect::init()
{
_has_fill = false;
_dashed = false;
+ _checkerboard = false;
+
_shadow = 0;
_area = Geom::OptIntRect();
@@ -109,10 +111,17 @@ void CtrlRect::render(SPCanvasBuf *buf)
cairo_rectangle(buf->ct, 0.5 + area[X].min(), 0.5 + area[Y].min(),
area[X].max() - area[X].min(), area[Y].max() - area[Y].min());
+ if (_checkerboard) {
+ cairo_pattern_t *cb = ink_cairo_pattern_create_checkerboard();
+ cairo_set_source(buf->ct, cb);
+ cairo_pattern_destroy(cb);
+ cairo_fill_preserve(buf->ct);
+ }
if (_has_fill) {
ink_cairo_set_source_rgba32(buf->ct, _fill_color);
cairo_fill_preserve(buf->ct);
}
+
ink_cairo_set_source_rgba32(buf->ct, _border_color);
cairo_stroke(buf->ct);
@@ -297,6 +306,12 @@ void CtrlRect::setDashed(bool d)
_requestUpdate();
}
+void CtrlRect::setCheckerboard(bool d)
+{
+ _checkerboard = d;
+ _requestUpdate();
+}
+
void CtrlRect::_requestUpdate()
{
sp_canvas_item_request_update(SP_CANVAS_ITEM(this));
diff --git a/src/display/sodipodi-ctrlrect.h b/src/display/sodipodi-ctrlrect.h
index ff6c55b06..08a085649 100644
--- a/src/display/sodipodi-ctrlrect.h
+++ b/src/display/sodipodi-ctrlrect.h
@@ -39,6 +39,7 @@ public:
void setShadow(int s, guint c);
void setRectangle(Geom::Rect const &r);
void setDashed(bool d);
+ void setCheckerboard(bool d);
void render(SPCanvasBuf *buf);
void update(Geom::Affine const &affine, unsigned int flags);
@@ -49,6 +50,8 @@ private:
Geom::Rect _rect;
bool _has_fill;
bool _dashed;
+ bool _checkerboard;
+
Geom::OptIntRect _area;
gint _shadow_size;
guint32 _border_color;
diff --git a/src/display/sp-canvas-item.h b/src/display/sp-canvas-item.h
index 3e9e085a0..66cd03dd9 100644
--- a/src/display/sp-canvas-item.h
+++ b/src/display/sp-canvas-item.h
@@ -116,7 +116,9 @@ G_END_DECLS
void sp_canvas_item_affine_absolute(SPCanvasItem *item, Geom::Affine const &aff);
void sp_canvas_item_raise(SPCanvasItem *item, int positions);
+void sp_canvas_item_raise_to_top(SPCanvasItem *item);
void sp_canvas_item_lower(SPCanvasItem *item, int positions);
+void sp_canvas_item_lower_to_bottom(SPCanvasItem *item);
bool sp_canvas_item_is_visible(SPCanvasItem *item);
void sp_canvas_item_show(SPCanvasItem *item);
void sp_canvas_item_hide(SPCanvasItem *item);
diff --git a/src/display/sp-canvas-util.cpp b/src/display/sp-canvas-util.cpp
index 79c8c614e..25b70824b 100644
--- a/src/display/sp-canvas-util.cpp
+++ b/src/display/sp-canvas-util.cpp
@@ -67,6 +67,9 @@ void sp_canvas_item_set_i2w_affine (SPCanvasItem * item, Geom::Affine const &i2
void sp_canvas_item_move_to_z (SPCanvasItem * item, gint z)
{
g_assert (item != NULL);
+
+ if (z == 0)
+ return sp_canvas_item_lower_to_bottom(item);
gint current_z = sp_canvas_item_order (item);
diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp
index 5efc4ce86..d17271752 100644
--- a/src/display/sp-canvas.cpp
+++ b/src/display/sp-canvas.cpp
@@ -58,7 +58,7 @@ struct SPCanvasGroupClass {
};
/**
- * A group of Items.
+ * A group of items.
*/
struct SPCanvasGroup {
/**
@@ -109,8 +109,8 @@ struct SPCanvasGroup {
SPCanvasItem item;
- GList *items;
- GList *last;
+ std::list<SPCanvasItem *> items;
+
};
/**
@@ -167,13 +167,6 @@ static guint object_signals[LAST_SIGNAL] = { 0 };
void sp_canvas_item_construct(SPCanvasItem *item, SPCanvasGroup *parent, gchar const *first_arg_name, va_list args);
/**
- * Convenience function to reorder items in a group's child list.
- *
- * This puts the specified link after the "before" link.
- */
-void put_item_after(GList *link, GList *before);
-
-/**
* Helper that returns true iff item is descendant of parent.
*/
bool is_descendant(SPCanvasItem const *item, SPCanvasItem const *parent);
@@ -426,7 +419,7 @@ static void redraw_if_visible(SPCanvasItem *item)
int y1 = (int)(item->y2);
if (x0 !=0 || x1 !=0 || y0 !=0 || y1 !=0) {
- item->canvas->requestRedraw((int)(item->x1), (int)(item->y1), (int)(item->x2 + 1), (int)(item->y2 + 1));
+ item->canvas->requestRedraw((int)(item->x1 - 1), (int)(item->y1 -1), (int)(item->x2 + 1), (int)(item->y2 + 1));
}
}
}
@@ -590,64 +583,6 @@ void sp_canvas_item_affine_absolute(SPCanvasItem *item, Geom::Affine const &affi
item->canvas->need_repick = TRUE;
}
-namespace {
-
-void put_item_after(GList *link, GList *before)
-{
- if (link == before) {
- return;
- }
-
- SPCanvasGroup *parent = SP_CANVAS_GROUP (SP_CANVAS_ITEM (link->data)->parent);
-
- if (before == NULL) {
- if (link == parent->items) {
- return;
- }
-
- link->prev->next = link->next;
-
- if (link->next) {
- link->next->prev = link->prev;
- } else {
- parent->last = link->prev;
- }
-
- link->prev = before;
- link->next = parent->items;
- link->next->prev = link;
- parent->items = link;
- } else {
- if ((link == parent->last) && (before == parent->last->prev)) {
- return;
- }
-
- if (link->next) {
- link->next->prev = link->prev;
- }
-
- if (link->prev) {
- link->prev->next = link->next;
- } else {
- parent->items = link->next;
- parent->items->prev = NULL;
- }
-
- link->prev = before;
- link->next = before->next;
-
- link->prev->next = link;
-
- if (link->next) {
- link->next->prev = link;
- } else {
- parent->last = link;
- }
- }
-}
-
-} // namespace
-
/**
* Raises the item in its parent's stack by the specified number of positions.
*
@@ -668,24 +603,34 @@ void sp_canvas_item_raise(SPCanvasItem *item, int positions)
}
SPCanvasGroup *parent = SP_CANVAS_GROUP (item->parent);
- GList *link = g_list_find (parent->items, item);
- g_assert (link != NULL);
+ std::list<SPCanvasItem *>::iterator l = std::find(parent->items.begin(),parent->items.end(), item);
+ g_assert (l != parent->items.end());
- GList *before;
- for (before = link; positions && before; positions--)
- before = before->next;
+ for (int i=0; i<=positions && l != parent->items.end(); ++i)
+ ++l;
- if (!before) {
- before = parent->last;
- }
+ parent->items.remove(item);
+ parent->items.insert(l, item);
- put_item_after (link, before);
+ redraw_if_visible (item);
+ item->canvas->need_repick = TRUE;
+}
+void sp_canvas_item_raise_to_top(SPCanvasItem *item)
+{
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (SP_IS_CANVAS_ITEM (item));
+ if (!item->parent)
+ return;
+ SPCanvasGroup *parent = SP_CANVAS_GROUP (item->parent);
+ parent->items.remove(item);
+ parent->items.push_back(item);
redraw_if_visible (item);
item->canvas->need_repick = TRUE;
}
+
/**
* Lowers the item in its parent's stack by the specified number of positions.
*
@@ -701,32 +646,41 @@ void sp_canvas_item_lower(SPCanvasItem *item, int positions)
g_return_if_fail (SP_IS_CANVAS_ITEM (item));
g_return_if_fail (positions >= 1);
- if (!item->parent || positions == 0) {
+ SPCanvasGroup *parent = SP_CANVAS_GROUP(item->parent);
+
+ if (!parent || positions == 0 || item == parent->items.front() ) {
return;
}
- SPCanvasGroup *parent = SP_CANVAS_GROUP (item->parent);
- GList *link = g_list_find (parent->items, item);
- g_assert (link != NULL);
+ std::list<SPCanvasItem *>::iterator l = std::find(parent->items.begin(), parent->items.end(), item);
+ g_assert (l != parent->items.end());
- GList *before;
- if (link->prev) {
- for (before = link->prev; positions && before; positions--) {
- before = before->prev;
- }
- } else {
- before = NULL;
- }
-
- put_item_after (link, before);
+ for (int i=0; i<positions && l != parent->items.begin(); ++i)
+ --l;
+
+ parent->items.remove(item);
+ parent->items.insert(l, item);
redraw_if_visible (item);
item->canvas->need_repick = TRUE;
}
+void sp_canvas_item_lower_to_bottom(SPCanvasItem *item)
+{
+ g_return_if_fail (item != NULL);
+ g_return_if_fail (SP_IS_CANVAS_ITEM (item));
+ if (!item->parent)
+ return;
+ SPCanvasGroup *parent = SP_CANVAS_GROUP (item->parent);
+ parent->items.remove(item);
+ parent->items.push_front(item);
+ redraw_if_visible (item);
+ item->canvas->need_repick = TRUE;
+}
+
bool sp_canvas_item_is_visible(SPCanvasItem *item)
{
- return item->visible;
+ return item->visible;
}
/**
@@ -919,7 +873,15 @@ void sp_canvas_item_request_update(SPCanvasItem *item)
*/
gint sp_canvas_item_order (SPCanvasItem * item)
{
- return g_list_index (SP_CANVAS_GROUP (item->parent)->items, item);
+ SPCanvasGroup * p = SP_CANVAS_GROUP(item->parent);
+ size_t index = 0;
+ for (std::list<SPCanvasItem*>::const_iterator it = p->items.begin(); it != p->items.end(); ++it, ++index) {
+ if ((*it) == item) {
+ return index;
+ }
+ }
+
+ return -1;
}
// SPCanvasGroup
@@ -936,9 +898,9 @@ static void sp_canvas_group_class_init(SPCanvasGroupClass *klass)
item_class->viewbox_changed = SPCanvasGroup::viewboxChanged;
}
-static void sp_canvas_group_init(SPCanvasGroup * /*group*/)
+static void sp_canvas_group_init(SPCanvasGroup * group)
{
- // Nothing here
+ new (&group->items) std::list<SPCanvasItem *>;
}
void SPCanvasGroup::destroy(SPCanvasItem *object)
@@ -946,16 +908,15 @@ void SPCanvasGroup::destroy(SPCanvasItem *object)
g_return_if_fail(object != NULL);
g_return_if_fail(SP_IS_CANVAS_GROUP(object));
- SPCanvasGroup const *group = SP_CANVAS_GROUP(object);
-
- GList *list = group->items;
- while (list) {
- SPCanvasItem *child = reinterpret_cast<SPCanvasItem *>(list->data);
- list = list->next;
+ SPCanvasGroup *group = SP_CANVAS_GROUP(object);
- sp_canvas_item_destroy(child);
+ for (std::list<SPCanvasItem *>::iterator it = group->items.begin(); it != group->items.end(); ++it) {
+ sp_canvas_item_destroy(*it);
}
+ group->items.clear();
+ group->items.~list(); // invoke manually
+
if (SP_CANVAS_ITEM_CLASS(sp_canvas_group_parent_class)->destroy) {
(* SP_CANVAS_ITEM_CLASS(sp_canvas_group_parent_class)->destroy)(object);
}
@@ -966,8 +927,8 @@ void SPCanvasGroup::update(SPCanvasItem *item, Geom::Affine const &affine, unsig
SPCanvasGroup const *group = SP_CANVAS_GROUP(item);
Geom::OptRect bounds;
- for (GList *list = group->items; list; list = list->next) {
- SPCanvasItem *i = SP_CANVAS_ITEM(list->data);
+ for (std::list<SPCanvasItem *>::const_iterator it = group->items.begin(); it != group->items.end(); ++it) {
+ SPCanvasItem *i = *it;
sp_canvas_item_invoke_update (i, affine, flags);
@@ -1002,9 +963,8 @@ double SPCanvasGroup::point(SPCanvasItem *item, Geom::Point p, SPCanvasItem **ac
*actual_item = NULL;
double dist = 0.0;
-
- for (GList *list = group->items; list; list = list->next) {
- SPCanvasItem *child = SP_CANVAS_ITEM(list->data);
+ for (std::list<SPCanvasItem *>::const_iterator it = group->items.begin(); it != group->items.end(); ++it) {
+ SPCanvasItem *child = *it;
if ((child->x1 <= x2) && (child->y1 <= y2) && (child->x2 >= x1) && (child->y2 >= y1)) {
SPCanvasItem *point_item = NULL; // cater for incomplete item implementations
@@ -1037,8 +997,8 @@ void SPCanvasGroup::render(SPCanvasItem *item, SPCanvasBuf *buf)
{
SPCanvasGroup const *group = SP_CANVAS_GROUP(item);
- for (GList *list = group->items; list; list = list->next) {
- SPCanvasItem *child = SP_CANVAS_ITEM(list->data);
+ for (std::list<SPCanvasItem *>::const_iterator it = group->items.begin(); it != group->items.end(); ++it) {
+ SPCanvasItem *child = *it;
if (child->visible) {
if ((child->x1 < buf->rect.right()) &&
(child->y1 < buf->rect.bottom()) &&
@@ -1056,8 +1016,8 @@ void SPCanvasGroup::viewboxChanged(SPCanvasItem *item, Geom::IntRect const &new_
{
SPCanvasGroup *group = SP_CANVAS_GROUP(item);
- for (GList *list = group->items; list; list = list->next) {
- SPCanvasItem *child = SP_CANVAS_ITEM(list->data);
+ for (std::list<SPCanvasItem *>::const_iterator it = group->items.begin(); it != group->items.end(); ++it) {
+ SPCanvasItem *child = *it;
if (child->visible) {
if (SP_CANVAS_ITEM_GET_CLASS(child)->viewbox_changed) {
SP_CANVAS_ITEM_GET_CLASS(child)->viewbox_changed(child, new_area);
@@ -1071,37 +1031,21 @@ void SPCanvasGroup::add(SPCanvasItem *item)
g_object_ref(item);
g_object_ref_sink(item);
- if (!items) {
- items = g_list_append(items, item);
- last = items;
- } else {
- last = g_list_append(last, item)->next;
- }
+ items.push_back(item);
sp_canvas_item_request_update(item);
}
void SPCanvasGroup::remove(SPCanvasItem *item)
{
+
g_return_if_fail(item != NULL);
+ items.remove(item);
- for (GList *children = items; children; children = children->next) {
- if (children->data == item) {
+ // Unparent the child
+ item->parent = NULL;
+ g_object_unref(item);
- // Unparent the child
- item->parent = NULL;
- g_object_unref(item);
-
- // Remove it from the list
- if (children == last) {
- last = children->prev;
- }
-
- items = g_list_remove_link(items, children);
- g_list_free(children);
- break;
- }
- }
}
static void sp_canvas_dispose (GObject *object);
diff --git a/src/display/sp-ctrlpoint.cpp b/src/display/sp-ctrlpoint.cpp
deleted file mode 100644
index 1082cb1b3..000000000
--- a/src/display/sp-ctrlpoint.cpp
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Simple point
- *
- * Author:
- * Maximilian Albert <maximilian.albert@gmail.com>
- * Jon A. Cruz <jon@joncruz.org>
- *
- * Copyright (C) 2008 Maximilian Albert
- *
- * Released under GNU GPL
- */
-
-#include "sp-canvas-util.h"
-#include "sp-ctrlpoint.h"
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-#include <color.h>
-#include "display/cairo-utils.h"
-#include "display/sp-canvas.h"
-
-static void sp_ctrlpoint_destroy(SPCanvasItem *object);
-
-static void sp_ctrlpoint_update (SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags);
-static void sp_ctrlpoint_render (SPCanvasItem *item, SPCanvasBuf *buf);
-
-G_DEFINE_TYPE(SPCtrlPoint, sp_ctrlpoint, SP_TYPE_CANVAS_ITEM);
-
-static void sp_ctrlpoint_class_init(SPCtrlPointClass *klass)
-{
- SPCanvasItemClass *item_class = SP_CANVAS_ITEM_CLASS(klass);
-
- item_class->destroy = sp_ctrlpoint_destroy;
- item_class->update = sp_ctrlpoint_update;
- item_class->render = sp_ctrlpoint_render;
-}
-
-static void
-sp_ctrlpoint_init (SPCtrlPoint *ctrlpoint)
-{
- ctrlpoint->rgba = 0x0000ff7f;
- ctrlpoint->pt[Geom::X] = ctrlpoint->pt[Geom::Y] = 0.0;
- ctrlpoint->item=NULL;
- ctrlpoint->radius = 2;
-}
-
-static void sp_ctrlpoint_destroy(SPCanvasItem *object)
-{
- g_return_if_fail (object != NULL);
- g_return_if_fail (SP_IS_CTRLPOINT (object));
-
- SPCtrlPoint *ctrlpoint = SP_CTRLPOINT (object);
-
- ctrlpoint->item=NULL;
-
- if (SP_CANVAS_ITEM_CLASS(sp_ctrlpoint_parent_class)->destroy)
- SP_CANVAS_ITEM_CLASS(sp_ctrlpoint_parent_class)->destroy(object);
-}
-
-static void
-sp_ctrlpoint_render (SPCanvasItem *item, SPCanvasBuf *buf)
-{
- SPCtrlPoint *cp = SP_CTRLPOINT (item);
-
- if (!buf->ct)
- return;
-
- sp_canvas_prepare_buffer (buf);
-
- guint32 rgba = cp->rgba;
- cairo_set_source_rgba(buf->ct, SP_RGBA32_B_F(rgba), SP_RGBA32_G_F(rgba), SP_RGBA32_R_F(rgba), SP_RGBA32_A_F(rgba));
-
- cairo_set_line_width(buf->ct, 1);
- cairo_new_path(buf->ct);
-
- Geom::Point pt = cp->pt * cp->affine;
-
- cairo_arc(buf->ct, pt[Geom::X] - buf->rect.left(), pt[Geom::Y] - buf->rect.top(), cp->radius, 0.0, 2 * M_PI);
- cairo_stroke(buf->ct);
-}
-
-static void sp_ctrlpoint_update(SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags)
-{
- SPCtrlPoint *cp = SP_CTRLPOINT(item);
-
- item->canvas->requestRedraw((int)item->x1, (int)item->y1, (int)item->x2, (int)item->y2);
-
- if (SP_CANVAS_ITEM_CLASS(sp_ctrlpoint_parent_class)->update) {
- SP_CANVAS_ITEM_CLASS(sp_ctrlpoint_parent_class)->update(item, affine, flags);
- }
-
- sp_canvas_item_reset_bounds (item);
-
- cp->affine = affine;
-
- Geom::Point pt = cp->pt * affine;
-
- item->x1 = pt[Geom::X] - cp->radius;
- item->y1 = pt[Geom::Y] - cp->radius;
- item->x2 = pt[Geom::X] + cp->radius;
- item->y2 = pt[Geom::Y] + cp->radius;
-
- item->canvas->requestRedraw((int)item->x1 - 15, (int)item->y1 - 15,
- (int)item->x1 + 15, (int)item->y1 + 15);
-}
-
-void
-sp_ctrlpoint_set_color (SPCtrlPoint *cp, guint32 rgba)
-{
- g_return_if_fail (cp != NULL);
- g_return_if_fail (SP_IS_CTRLPOINT (cp));
-
- if (rgba != cp->rgba) {
- SPCanvasItem *item;
- cp->rgba = rgba;
- item = SP_CANVAS_ITEM (cp);
- item->canvas->requestRedraw((int)item->x1, (int)item->y1, (int)item->x2, (int)item->y2);
- }
-}
-
-#define EPSILON 1e-6
-#define DIFFER(a,b) (fabs ((a) - (b)) > EPSILON)
-
-void
-sp_ctrlpoint_set_coords (SPCtrlPoint *cp, const gdouble x, const gdouble y)
-{
- g_return_if_fail (cp != NULL);
- g_return_if_fail (SP_IS_CTRLPOINT (cp));
-
- if (DIFFER (x, cp->pt[Geom::X]) || DIFFER (y, cp->pt[Geom::Y])) {
- cp->pt[Geom::X] = x;
- cp->pt[Geom::Y] = y;
- sp_canvas_item_request_update (SP_CANVAS_ITEM (cp));
- }
-}
-
-void
-sp_ctrlpoint_set_coords (SPCtrlPoint *cp, const Geom::Point pt)
-{
- sp_ctrlpoint_set_coords(cp, pt[Geom::X], pt[Geom::Y]);
-}
-
-void
-sp_ctrlpoint_set_radius (SPCtrlPoint *cp, const double r)
-{
- cp->radius = r;
-}
-
-/*
- 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/display/sp-ctrlpoint.h b/src/display/sp-ctrlpoint.h
deleted file mode 100644
index a7a5475b7..000000000
--- a/src/display/sp-ctrlpoint.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef SEEN_INKSCAPE_CTRLPOINT_H
-#define SEEN_INKSCAPE_CTRLPOINT_H
-
-/*
- * A simple point
- *
- * Author:
- * Maximilian Albert <maximilian.albert@gmail.com>
- *
- * Copyright (C) 2008 Maximilian Albert
- *
- * Released under GNU GPL
- */
-
-#include "sp-canvas-item.h"
-
-class SPItem;
-
-#define SP_TYPE_CTRLPOINT (sp_ctrlpoint_get_type ())
-#define SP_CTRLPOINT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_CTRLPOINT, SPCtrlPoint))
-#define SP_IS_CTRLPOINT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_CTRLPOINT))
-
-struct SPCtrlPoint : public SPCanvasItem {
- SPItem *item; // the item to which this line belongs in some sense; may be NULL for some users
- guint32 rgba;
- Geom::Point pt;
- Geom::Affine affine;
- double radius;
-};
-struct SPCtrlPointClass : public SPCanvasItemClass{};
-
-GType sp_ctrlpoint_get_type (void);
-
-void sp_ctrlpoint_set_color (SPCtrlPoint *cp, guint32 rgba);
-void sp_ctrlpoint_set_coords (SPCtrlPoint *cp, const gdouble x, const gdouble y);
-void sp_ctrlpoint_set_coords (SPCtrlPoint *cp, const Geom::Point pt);
-void sp_ctrlpoint_set_radius (SPCtrlPoint *cp, const double r);
-
-
-
-#endif // SEEN_INKSCAPE_CTRLPOINT_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/document-private.h b/src/document-private.h
index a5033b3c2..eaed0020e 100644
--- a/src/document-private.h
+++ b/src/document-private.h
@@ -15,6 +15,8 @@
*/
#include <map>
+#include <set>
+#include <string>
#include <stddef.h>
#include <sigc++/sigc++.h>
#include "xml/event-fns.h"
@@ -34,14 +36,12 @@ class Event;
}
}
-typedef struct _GHashTable GHashTable;
-
struct SPDocumentPrivate {
typedef std::map<GQuark, SPDocument::IDChangedSignal> IDChangedSignalMap;
typedef std::map<GQuark, SPDocument::ResourcesChangedSignal> ResourcesChangedSignalMap;
- GHashTable *iddef; /**< Dictionary of id -> SPObject mappings */
- GHashTable *reprdef; /**< Dictionary of Inkscape::XML::Node -> SPObject mappings */
+ std::map<std::string, SPObject *> iddef;
+ std::map<Inkscape::XML::Node *, SPObject *> reprdef;
unsigned long serial;
@@ -49,8 +49,7 @@ struct SPDocumentPrivate {
IDChangedSignalMap id_changed_signals;
/* Resources */
- /* It is GHashTable of GSLists */
- GHashTable *resources;
+ std::map<std::string, std::set<SPObject *> > resources;
ResourcesChangedSignalMap resources_changed_signals;
sigc::signal<void> destroySignal;
@@ -65,8 +64,8 @@ struct SPDocumentPrivate {
bool sensitive; /* If we save actions to undo stack */
Inkscape::XML::Event * partial; /* partial undo log when interrupted */
int history_size;
- GSList * undo; /* Undo stack of reprs */
- GSList * redo; /* Redo stack of reprs */
+ std::vector<Inkscape::Event *> undo; /* Undo stack of reprs */
+ std::vector<Inkscape::Event *> redo; /* Redo stack of reprs */
/* Undo listener */
Inkscape::CompositeUndoStackObserver undoStackObservers;
diff --git a/src/document-undo.cpp b/src/document-undo.cpp
index 59e060cd5..eb0ac7707 100644
--- a/src/document-undo.cpp
+++ b/src/document-undo.cpp
@@ -162,12 +162,12 @@ void Inkscape::DocumentUndo::maybeDone(SPDocument *doc, const gchar *key, const
return;
}
- if (key && !doc->actionkey.empty() && (doc->actionkey == key) && doc->priv->undo) {
- ((Inkscape::Event *)doc->priv->undo->data)->event =
- sp_repr_coalesce_log (((Inkscape::Event *)doc->priv->undo->data)->event, log);
+ if (key && !doc->actionkey.empty() && (doc->actionkey == key) && !doc->priv->undo.empty()) {
+ (doc->priv->undo.back())->event =
+ sp_repr_coalesce_log ((doc->priv->undo.back())->event, log);
} else {
Inkscape::Event *event = new Inkscape::Event(log, event_type, event_description);
- doc->priv->undo = g_slist_prepend (doc->priv->undo, event);
+ doc->priv->undo.push_back(event);
doc->priv->history_size++;
doc->priv->undoStackObservers.notifyUndoCommitEvent(event);
}
@@ -211,7 +211,7 @@ static void finish_incomplete_transaction(SPDocument &doc) {
priv.partial = sp_repr_coalesce_log(priv.partial, log);
sp_repr_debug_print_log(priv.partial);
Inkscape::Event *event = new Inkscape::Event(priv.partial);
- priv.undo = g_slist_prepend(priv.undo, event);
+ priv.undo.push_back(event);
priv.undoStackObservers.notifyUndoCommitEvent(event);
priv.partial = NULL;
}
@@ -227,8 +227,8 @@ static void perform_document_update(SPDocument &doc) {
sp_repr_debug_print_log(update_log);
//Coalesce the update changes with the last action performed by user
- Inkscape::Event* undo_stack_top = (Inkscape::Event *)doc.priv->undo->data;
- if (undo_stack_top) {
+ if (!doc.priv->undo.empty()) {
+ Inkscape::Event* undo_stack_top = doc.priv->undo.back();
undo_stack_top->event = sp_repr_coalesce_log(undo_stack_top->event, update_log);
} else {
sp_repr_free_log(update_log);
@@ -256,13 +256,13 @@ gboolean Inkscape::DocumentUndo::undo(SPDocument *doc)
finish_incomplete_transaction(*doc);
- if (doc->priv->undo) {
- Inkscape::Event *log=(Inkscape::Event *)doc->priv->undo->data;
- doc->priv->undo = g_slist_remove (doc->priv->undo, log);
+ if (! doc->priv->undo.empty()) {
+ Inkscape::Event *log = doc->priv->undo.back();
+ doc->priv->undo.pop_back();
sp_repr_undo_log (log->event);
perform_document_update(*doc);
- doc->priv->redo = g_slist_prepend (doc->priv->redo, log);
+ doc->priv->redo.push_back(log);
doc->setModifiedSinceSave();
doc->priv->undoStackObservers.notifyUndoEvent(log);
@@ -303,11 +303,11 @@ gboolean Inkscape::DocumentUndo::redo(SPDocument *doc)
finish_incomplete_transaction(*doc);
- if (doc->priv->redo) {
- Inkscape::Event *log=(Inkscape::Event *)doc->priv->redo->data;
- doc->priv->redo = g_slist_remove (doc->priv->redo, log);
+ if (! doc->priv->redo.empty()) {
+ Inkscape::Event *log = doc->priv->redo.back();
+ doc->priv->redo.pop_back();
sp_repr_replay_log (log->event);
- doc->priv->undo = g_slist_prepend (doc->priv->undo, log);
+ doc->priv->undo.push_back(log);
doc->setModifiedSinceSave();
doc->priv->undoStackObservers.notifyRedoEvent(log);
@@ -330,37 +330,29 @@ gboolean Inkscape::DocumentUndo::redo(SPDocument *doc)
void Inkscape::DocumentUndo::clearUndo(SPDocument *doc)
{
- if (doc->priv->undo)
- doc->priv->undoStackObservers.notifyClearUndoEvent();
-
- while (doc->priv->undo) {
- GSList *current;
-
- current = doc->priv->undo;
- doc->priv->undo = current->next;
- doc->priv->history_size--;
-
- delete ((Inkscape::Event *) current->data);
- g_slist_free_1 (current);
- }
+ if (! doc->priv->undo.empty())
+ doc->priv->undoStackObservers.notifyClearUndoEvent();
+ while (! doc->priv->undo.empty()) {
+ Inkscape::Event *e = doc->priv->undo.back();
+ doc->priv->undo.pop_back();
+ delete e;
+ doc->priv->history_size--;
+ }
}
void Inkscape::DocumentUndo::clearRedo(SPDocument *doc)
{
- if (doc->priv->redo)
+ if (!doc->priv->redo.empty())
doc->priv->undoStackObservers.notifyClearRedoEvent();
- while (doc->priv->redo) {
- GSList *current;
-
- current = doc->priv->redo;
- doc->priv->redo = current->next;
- doc->priv->history_size--;
-
- delete ((Inkscape::Event *) current->data);
- g_slist_free_1 (current);
- }
+ while (! doc->priv->redo.empty()) {
+ Inkscape::Event *e = doc->priv->redo.back();
+ doc->priv->redo.pop_back();
+ delete e;
+ doc->priv->history_size--;
+ }
}
+
/*
Local Variables:
mode:c++
diff --git a/src/document.cpp b/src/document.cpp
index ebf5d312f..ae03b1ba1 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -81,7 +81,7 @@ using Inkscape::Util::unit_table;
static gint sp_document_idle_handler(gpointer data);
static gint sp_document_rerouting_handler(gpointer data);
-gboolean sp_document_resource_list_free(gpointer key, gpointer value, gpointer data);
+//gboolean sp_document_resource_list_free(gpointer key, gpointer value, gpointer data);
static gint doc_count = 0;
static gint doc_mem_count = 0;
@@ -105,11 +105,11 @@ SPDocument::SPDocument() :
rerouting_handler_id(0),
profileManager(NULL), // deferred until after other initialization
router(new Avoid::Router(Avoid::PolyLineRouting|Avoid::OrthogonalRouting)),
- _collection_queue(NULL),
oldSignalsConnected(false),
current_persp3d(NULL),
current_persp3d_impl(NULL),
- _parent_document(NULL)
+ _parent_document(NULL),
+ _node_cache_valid(false)
{
// Penalise libavoid for choosing paths with needless extra segments.
// This results in much better looking orthogonal connector paths.
@@ -119,16 +119,9 @@ SPDocument::SPDocument() :
p->serial = next_serial++;
- p->iddef = g_hash_table_new(g_direct_hash, g_direct_equal);
- p->reprdef = g_hash_table_new(g_direct_hash, g_direct_equal);
-
- p->resources = g_hash_table_new(g_str_hash, g_str_equal);
-
p->sensitive = false;
p->partial = NULL;
p->history_size = 0;
- p->undo = NULL;
- p->redo = NULL;
p->seeking = false;
priv = p;
@@ -138,6 +131,7 @@ SPDocument::SPDocument() :
// XXX only for testing!
priv->undoStackObservers.add(p->console_output_undo_observer);
+ _node_cache = std::deque<SPItem*>();
}
SPDocument::~SPDocument() {
@@ -177,17 +171,10 @@ SPDocument::~SPDocument() {
root = NULL;
}
- if (priv->iddef) g_hash_table_destroy(priv->iddef);
- if (priv->reprdef) g_hash_table_destroy(priv->reprdef);
-
if (rdoc) Inkscape::GC::release(rdoc);
/* Free resources */
- g_hash_table_foreach_remove(priv->resources, sp_document_resource_list_free, this);
- g_hash_table_destroy(priv->resources);
-
- delete priv;
- priv = NULL;
+ priv->resources.clear();
}
cr_cascade_unref(style_cascade);
@@ -295,19 +282,18 @@ void SPDocument::queueForOrphanCollection(SPObject *object) {
g_return_if_fail(object->document == this);
sp_object_ref(object, NULL);
- _collection_queue = g_slist_prepend(_collection_queue, object);
+ _collection_queue.push_back(object);
}
void SPDocument::collectOrphans() {
- while (_collection_queue) {
- GSList *objects=_collection_queue;
- _collection_queue = NULL;
- for ( GSList *iter=objects ; iter ; iter = iter->next ) {
- SPObject *object=reinterpret_cast<SPObject *>(iter->data);
+ while (!_collection_queue.empty()) {
+ std::vector<SPObject *> objects(_collection_queue);
+ _collection_queue.clear();
+ for (std::vector<SPObject *>::const_iterator iter = objects.begin(); iter != objects.end(); ++iter) {
+ SPObject *object = *iter;
object->collectOrphan();
sp_object_unref(object, NULL);
}
- g_slist_free(objects);
}
}
@@ -1002,17 +988,24 @@ void SPDocument::_emitModified() {
static guint const flags = SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG | SP_OBJECT_PARENT_MODIFIED_FLAG;
root->emitModified(0);
priv->modified_signal.emit(flags);
+ _node_cache_valid=false;
}
void SPDocument::bindObjectToId(gchar const *id, SPObject *object) {
GQuark idq = g_quark_from_string(id);
if (object) {
- g_assert(g_hash_table_lookup(priv->iddef, GINT_TO_POINTER(idq)) == NULL);
- g_hash_table_insert(priv->iddef, GINT_TO_POINTER(idq), object);
+ if(object->getId())
+ priv->iddef.erase(object->getId());
+ g_assert(priv->iddef.find(id)==priv->iddef.end());
+ priv->iddef[id] = object;
+ //g_assert(g_hash_table_lookup(priv->iddef, GINT_TO_POINTER(idq)) == NULL);
+ //g_hash_table_insert(priv->iddef, GINT_TO_POINTER(idq), object);
} else {
- g_assert(g_hash_table_lookup(priv->iddef, GINT_TO_POINTER(idq)) != NULL);
- g_hash_table_remove(priv->iddef, GINT_TO_POINTER(idq));
+ g_assert(priv->iddef.find(id)!=priv->iddef.end());
+ priv->iddef.erase(id);
+ //g_assert(g_hash_table_lookup(priv->iddef, GINT_TO_POINTER(idq)) != NULL);
+ //g_hash_table_remove(priv->iddef, GINT_TO_POINTER(idq));
}
SPDocumentPrivate::IDChangedSignalMap::iterator pos;
@@ -1047,15 +1040,16 @@ SPObject *SPDocument::getObjectById(Glib::ustring const &id) const
SPObject *SPDocument::getObjectById(gchar const *id) const
{
g_return_val_if_fail(id != NULL, NULL);
- if (!priv || !priv->iddef) {
+ if (!priv || priv->iddef.empty()) {
return NULL;
}
- GQuark idq = g_quark_from_string(id);
- gpointer rv = g_hash_table_lookup(priv->iddef, GINT_TO_POINTER(idq));
- if(rv != NULL)
+ // GQuark idq = g_quark_from_string(id);
+ std::map<std::string, SPObject *>::iterator rv = priv->iddef.find(id);
+ //gpointer rv = g_hash_table_lookup(priv->iddef, GINT_TO_POINTER(idq));
+ if(rv != priv->iddef.end())
{
- return static_cast<SPObject*>(rv);
+ return (rv->second);
}
else
{
@@ -1072,18 +1066,22 @@ sigc::connection SPDocument::connectIdChanged(gchar const *id,
void SPDocument::bindObjectToRepr(Inkscape::XML::Node *repr, SPObject *object)
{
if (object) {
- g_assert(g_hash_table_lookup(priv->reprdef, repr) == NULL);
- g_hash_table_insert(priv->reprdef, repr, object);
+ g_assert(priv->reprdef.find(repr)==priv->reprdef.end());
+ priv->reprdef[repr] = object;
} else {
- g_assert(g_hash_table_lookup(priv->reprdef, repr) != NULL);
- g_hash_table_remove(priv->reprdef, repr);
+ g_assert(priv->reprdef.find(repr)!=priv->reprdef.end());
+ priv->reprdef.erase(repr);
}
}
SPObject *SPDocument::getObjectByRepr(Inkscape::XML::Node *repr) const
{
g_return_val_if_fail(repr != NULL, NULL);
- return static_cast<SPObject*>(g_hash_table_lookup(priv->reprdef, repr));
+ std::map<Inkscape::XML::Node *, SPObject *>::iterator rv = priv->reprdef.find(repr);
+ if(rv != priv->reprdef.end())
+ return (rv->second);
+ else
+ return NULL;
}
Glib::ustring SPDocument::getLanguage() const
@@ -1267,14 +1265,14 @@ static bool overlaps(Geom::Rect const &area, Geom::Rect const &box)
}
static std::vector<SPItem*> &find_items_in_area(std::vector<SPItem*> &s, SPGroup *group, unsigned int dkey, Geom::Rect const &area,
- bool (*test)(Geom::Rect const &, Geom::Rect const &), bool take_insensitive = false)
+ bool (*test)(Geom::Rect const &, Geom::Rect const &), bool take_insensitive = false, bool into_groups = false)
{
g_return_val_if_fail(SP_IS_GROUP(group), s);
for ( SPObject *o = group->firstChild() ; o ; o = o->getNext() ) {
if ( SP_IS_ITEM(o) ) {
- if (SP_IS_GROUP(o) && SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER ) {
- s = find_items_in_area(s, SP_GROUP(o), dkey, area, test);
+ if (SP_IS_GROUP(o) && (SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) {
+ s = find_items_in_area(s, SP_GROUP(o), dkey, area, test, take_insensitive, into_groups);
} else {
SPItem *child = SP_ITEM(o);
Geom::OptRect box = child->desktopVisualBounds();
@@ -1335,51 +1333,60 @@ SPItem *SPDocument::getItemFromListAtPointBottom(unsigned int dkey, SPGroup *gro
}
/**
+Turn the SVG DOM into a flat list of nodes that can be searched from top-down.
+The list can be persisted, which improves "find at multiple points" speed.
+*/
+void SPDocument::build_flat_item_list(unsigned int dkey, SPGroup *group, gboolean into_groups) const
+{
+ for ( SPObject *o = group->firstChild() ; o ; o = o->getNext() ) {
+ if (!SP_IS_ITEM(o)) {
+ continue;
+ }
+
+ if (SP_IS_GROUP(o) && (SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) {
+ build_flat_item_list(dkey, SP_GROUP(o), into_groups);
+ } else {
+ SPItem *child = SP_ITEM(o);
+
+ if (child->isVisibleAndUnlocked(dkey)) {
+ _node_cache.push_front(child);
+ }
+ }
+ }
+}
+
+/**
Returns the topmost (in z-order) item from the descendants of group (recursively) which
is at the point p, or NULL if none. Honors into_groups on whether to recurse into
non-layer groups or not. Honors take_insensitive on whether to return insensitive
items. If upto != NULL, then if item upto is encountered (at any level), stops searching
upwards in z-order and returns what it has found so far (i.e. the found item is
-guaranteed to be lower than upto).
+guaranteed to be lower than upto). Requires a list of nodes built by
+build_flat_item_list.
*/
-static SPItem *find_item_at_point(unsigned int dkey, SPGroup *group, Geom::Point const &p, gboolean into_groups, bool take_insensitive = false, SPItem *upto = NULL)
+static SPItem *find_item_at_point(std::deque<SPItem*> *nodes, unsigned int dkey, Geom::Point const &p, SPItem* upto=NULL)
{
- SPItem *seen = NULL;
- SPItem *newseen = NULL;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
gdouble delta = prefs->getDouble("/options/cursortolerance/value", 1.0);
- for ( SPObject *o = group->firstChild() ; o ; o = o->getNext() ) {
- if (!SP_IS_ITEM(o)) {
+ SPItem *seen = NULL;
+ SPItem *child;
+ bool seen_upto = (!upto);
+ for (std::deque<SPItem*>::const_iterator i = nodes->begin(); i != nodes->end(); ++i) {
+ child = *i;
+ if (!seen_upto){
+ if(child == upto)
+ seen_upto = true;
continue;
}
+ Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey);
- if (upto && SP_ITEM(o) == upto) {
+ if (arenaitem && arenaitem->pick(p, delta, 1) != NULL) {
+ seen = child;
break;
}
-
- if (SP_IS_GROUP(o) && (SP_GROUP(o)->effectiveLayerMode(dkey) == SPGroup::LAYER || into_groups)) {
- // if nothing found yet, recurse into the group
- newseen = find_item_at_point(dkey, SP_GROUP(o), p, into_groups, take_insensitive, upto);
- if (newseen) {
- seen = newseen;
- newseen = NULL;
- }
-
- if (item_is_in_group(upto, SP_GROUP(o))) {
- break;
- }
- } else {
- SPItem *child = SP_ITEM(o);
- Inkscape::DrawingItem *arenaitem = child->get_arenaitem(dkey);
-
- // seen remembers the last (topmost) of items pickable at this point
- if (arenaitem && arenaitem->pick(p, delta, 1) != NULL
- && (take_insensitive || child->isVisibleAndUnlocked(dkey))) {
- seen = child;
- }
- }
}
+
return seen;
}
@@ -1422,11 +1429,11 @@ static SPItem *find_group_at_point(unsigned int dkey, SPGroup *group, Geom::Poin
* Assumes box is normalized (and g_asserts it!)
*
*/
-std::vector<SPItem*> SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect const &box) const
+std::vector<SPItem*> SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect const &box, bool into_groups) const
{
std::vector<SPItem*> x;
g_return_val_if_fail(this->priv != NULL, x);
- return find_items_in_area(x, SP_GROUP(this->root), dkey, box, is_within);
+ return find_items_in_area(x, SP_GROUP(this->root), dkey, box, is_within, false, into_groups);
}
/*
@@ -1436,14 +1443,14 @@ std::vector<SPItem*> SPDocument::getItemsInBox(unsigned int dkey, Geom::Rect con
*
*/
-std::vector<SPItem*> SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const
+std::vector<SPItem*> SPDocument::getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box, bool into_groups) const
{
std::vector<SPItem*> x;
g_return_val_if_fail(this->priv != NULL, x);
- return find_items_in_area(x, SP_GROUP(this->root), dkey, box, overlaps);
+ return find_items_in_area(x, SP_GROUP(this->root), dkey, box, overlaps, false, into_groups);
}
-std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points) const
+std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers, size_t limit) const
{
std::vector<SPItem*> items;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -1454,11 +1461,31 @@ std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vecto
gdouble saved_delta = prefs->getDouble("/options/cursortolerance/value", 1.0);
prefs->setDouble("/options/cursortolerance/value", 0.25);
+ // Cache a flattened SVG DOM to speed up selection.
+ if(!_node_cache_valid){
+ _node_cache.clear();
+ build_flat_item_list(key, SP_GROUP(this->root), true);
+ _node_cache_valid=true;
+ }
+ SPObject *current_layer = SP_ACTIVE_DESKTOP->currentLayer();
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Inkscape::LayerModel *layer_model = NULL;
+ if(desktop){
+ layer_model = desktop->layers;
+ }
+ size_t item_counter = 0;
for(int i = points.size()-1;i>=0; i--) {
- SPItem *item = getItemAtPoint(key, points[i],
- false, NULL);
+ SPItem *item = find_item_at_point(&_node_cache, key, points[i]);
if (item && items.end()==find(items.begin(),items.end(), item))
- items.push_back(item);
+ if(all_layers || (layer_model && layer_model->layerForObject(item) == current_layer)){
+ items.push_back(item);
+ item_counter++;
+ //limit 0 = no limit
+ if(item_counter == limit){
+ prefs->setDouble("/options/cursortolerance/value", saved_delta);
+ return items;
+ }
+ }
}
// and now we restore it back
@@ -1468,11 +1495,26 @@ std::vector<SPItem*> SPDocument::getItemsAtPoints(unsigned const key, std::vecto
}
SPItem *SPDocument::getItemAtPoint( unsigned const key, Geom::Point const &p,
- bool const into_groups, SPItem *upto) const
+ bool const into_groups, SPItem *upto) const
{
g_return_val_if_fail(this->priv != NULL, NULL);
- return find_item_at_point(key, SP_GROUP(this->root), p, into_groups, false, upto);
+ // Build a flattened SVG DOM for find_item_at_point.
+ std::deque<SPItem*> bak(_node_cache);
+ if(!into_groups){
+ _node_cache.clear();
+ build_flat_item_list(key, SP_GROUP(this->root), into_groups);
+ }
+ if(!_node_cache_valid && into_groups){
+ _node_cache.clear();
+ build_flat_item_list(key, SP_GROUP(this->root), true);
+ _node_cache_valid=true;
+ }
+
+ SPItem *res = find_item_at_point(&_node_cache, key, p, upto);
+ if(!into_groups)
+ _node_cache = bak;
+ return res;
}
SPItem *SPDocument::getGroupAtPoint(unsigned int key, Geom::Point const &p) const
@@ -1482,7 +1524,6 @@ SPItem *SPDocument::getGroupAtPoint(unsigned int key, Geom::Point const &p) cons
return find_group_at_point(key, SP_GROUP(this->root), p);
}
-
// Resource management
bool SPDocument::addResource(gchar const *key, SPObject *object)
@@ -1495,13 +1536,20 @@ bool SPDocument::addResource(gchar const *key, SPObject *object)
bool result = false;
if ( !object->cloned ) {
- GSList *rlist = (GSList*)g_hash_table_lookup(priv->resources, key);
- g_return_val_if_fail(!g_slist_find(rlist, object), false);
- rlist = g_slist_prepend(rlist, object);
- g_hash_table_insert(priv->resources, (gpointer) key, rlist);
+ std::set<SPObject *> rlist = priv->resources[key];
+ g_return_val_if_fail(rlist.find(object) == rlist.end(), false);
+ priv->resources[key].insert(object);
GQuark q = g_quark_from_string(key);
- priv->resources_changed_signals[q].emit();
+
+ /*in general, do not send signal if the object has no id (yet),
+ it means the object is not completely built.
+ (happens when pasting swatches across documents, cf bug 1495106)
+ [this check should be more generally presend on emit() calls since
+ the backtrace is unusable with crashed from this cause]
+ */
+ if(object->getId() || dynamic_cast<SPGroup*>(object) )
+ priv->resources_changed_signals[q].emit();
result = true;
}
@@ -1519,11 +1567,10 @@ bool SPDocument::removeResource(gchar const *key, SPObject *object)
bool result = false;
if ( !object->cloned ) {
- GSList *rlist = (GSList*)g_hash_table_lookup(priv->resources, key);
- g_return_val_if_fail(rlist != NULL, false);
- g_return_val_if_fail(g_slist_find(rlist, object), false);
- rlist = g_slist_remove(rlist, object);
- g_hash_table_insert(priv->resources, (gpointer) key, rlist);
+ std::set<SPObject *> rlist = priv->resources[key];
+ g_return_val_if_fail(!rlist.empty(), false);
+ g_return_val_if_fail(rlist.find(object) != rlist.end(), false);
+ priv->resources[key].erase(object);
GQuark q = g_quark_from_string(key);
priv->resources_changed_signals[q].emit();
@@ -1534,12 +1581,13 @@ bool SPDocument::removeResource(gchar const *key, SPObject *object)
return result;
}
-GSList const *SPDocument::getResourceList(gchar const *key) const
+std::set<SPObject *> const SPDocument::getResourceList(gchar const *key) const
{
- g_return_val_if_fail(key != NULL, NULL);
- g_return_val_if_fail(*key != '\0', NULL);
+ std::set<SPObject *> emptyset;
+ g_return_val_if_fail(key != NULL, emptyset);
+ g_return_val_if_fail(*key != '\0', emptyset);
- return (GSList*)g_hash_table_lookup(this->priv->resources, key);
+ return this->priv->resources[key];
}
sigc::connection SPDocument::connectResourcesChanged(gchar const *key,
@@ -1551,13 +1599,6 @@ sigc::connection SPDocument::connectResourcesChanged(gchar const *key,
/* Helpers */
-gboolean
-sp_document_resource_list_free(gpointer /*key*/, gpointer value, gpointer /*data*/)
-{
- g_slist_free((GSList *) value);
- return TRUE;
-}
-
static unsigned int count_objects_recursive(SPObject *obj, unsigned int count)
{
count++; // obj itself
@@ -1640,7 +1681,7 @@ void SPDocument::importDefs(SPDocument *source)
prevent_id_clashes(source, this);
for (std::vector<Inkscape::XML::Node const *>::iterator defs = defsNodes.begin(); defs != defsNodes.end(); ++defs) {
- importDefsNode(source, const_cast<Inkscape::XML::Node *>(*defs), target_defs);
+ importDefsNode(source, const_cast<Inkscape::XML::Node *>(*defs), target_defs);
}
}
@@ -1688,11 +1729,10 @@ void SPDocument::importDefsNode(SPDocument *source, Inkscape::XML::Node *defs, I
/* First pass: remove duplicates in clipboard of definitions in document */
for (Inkscape::XML::Node *def = defs->firstChild() ; def ; def = def->next()) {
-
+ if(def->type() != Inkscape::XML::ELEMENT_NODE)continue;
/* If this clipboard has been pasted into one document, and is now being pasted into another,
or pasted again into the same, it will already have been processed. If we detect that then
skip the rest of this pass. */
-
Glib::ustring defid = def->attribute("id");
if( defid.find( DuplicateDefString ) != Glib::ustring::npos )break;
@@ -1722,6 +1762,7 @@ void SPDocument::importDefsNode(SPDocument *source, Inkscape::XML::Node *defs, I
/* Second pass: remove duplicates in clipboard of earlier definitions in clipboard */
for (Inkscape::XML::Node *def = defs->firstChild() ; def ; def = def->next()) {
+ if(def->type() != Inkscape::XML::ELEMENT_NODE)continue;
Glib::ustring defid = def->attribute("id");
if( defid.find( DuplicateDefString ) != Glib::ustring::npos )continue; // this one already handled
SPObject *src = source->getObjectByRepr(def);
@@ -1749,6 +1790,7 @@ void SPDocument::importDefsNode(SPDocument *source, Inkscape::XML::Node *defs, I
/* Final pass: copy over those parts which are not duplicates */
for (Inkscape::XML::Node *def = defs->firstChild() ; def ; def = def->next()) {
+ if(def->type() != Inkscape::XML::ELEMENT_NODE)continue;
/* Ignore duplicate defs marked in the first pass */
Glib::ustring defid = def->attribute("id");
diff --git a/src/document.h b/src/document.h
index dd1e295a2..825049cd5 100644
--- a/src/document.h
+++ b/src/document.h
@@ -27,6 +27,8 @@
#include <glibmm/ustring.h>
#include <boost/ptr_container/ptr_list.hpp>
#include <vector>
+#include <set>
+#include <deque>
namespace Avoid {
class Router;
@@ -121,7 +123,7 @@ public:
// Instance of the connector router
Avoid::Router *router;
- GSList *_collection_queue;
+ std::vector<SPObject *> _collection_queue;
bool oldSignalsConnected;
@@ -258,11 +260,11 @@ public:
int ensureUpToDate();
bool addResource(char const *key, SPObject *object);
bool removeResource(char const *key, SPObject *object);
- const GSList *getResourceList(char const *key) const;
- std::vector<SPItem*> getItemsInBox(unsigned int dkey, Geom::Rect const &box) const;
- std::vector<SPItem*> getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box) const;
+ const std::set<SPObject *> getResourceList(char const *key) const;
+ std::vector<SPItem*> getItemsInBox(unsigned int dkey, Geom::Rect const &box, bool into_groups = false) const;
+ std::vector<SPItem*> getItemsPartiallyInBox(unsigned int dkey, Geom::Rect const &box, bool into_groups = false) const;
SPItem *getItemAtPoint(unsigned int key, Geom::Point const &p, bool into_groups, SPItem *upto = NULL) const;
- std::vector<SPItem*> getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points) const;
+ std::vector<SPItem*> getItemsAtPoints(unsigned const key, std::vector<Geom::Point> points, bool all_layers = true, size_t limit = 0) const ;
SPItem *getGroupAtPoint(unsigned int key, Geom::Point const &p) const;
void changeUriAndHrefs(char const *uri);
@@ -276,6 +278,9 @@ private:
void do_change_uri(char const *const filename, bool const rebase);
void setupViewport(SPItemCtx *ctx);
void importDefsNode(SPDocument *source, Inkscape::XML::Node *defs, Inkscape::XML::Node *target_defs);
+ void build_flat_item_list(unsigned int dkey, SPGroup *group, gboolean into_groups) const;
+ mutable std::deque<SPItem*> _node_cache;
+ mutable bool _node_cache_valid;
};
/*
diff --git a/src/extension/execution-env.cpp b/src/extension/execution-env.cpp
index 29c2b5537..31491605b 100644
--- a/src/extension/execution-env.cpp
+++ b/src/extension/execution-env.cpp
@@ -30,8 +30,6 @@
#include "display/sp-canvas.h"
-#include "util/glib-list-iterators.h"
-
namespace Inkscape {
namespace Extension {
@@ -61,7 +59,7 @@ ExecutionEnv::ExecutionEnv (Effect * effect, Inkscape::UI::View::View * doc, Imp
if (desktop != NULL) {
std::vector<SPItem*> selected = desktop->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); x++){
+ for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); ++x){
Glib::ustring selected_id;
selected_id = (*x)->getId();
_selected.insert(_selected.end(), selected_id);
diff --git a/src/extension/implementation/implementation.cpp b/src/extension/implementation/implementation.cpp
index b0ff3e91c..92a8a2833 100644
--- a/src/extension/implementation/implementation.cpp
+++ b/src/extension/implementation/implementation.cpp
@@ -23,7 +23,6 @@
#include "desktop.h"
#include "ui/view/view.h"
-#include "util/glib-list-iterators.h"
namespace Inkscape {
namespace Extension {
diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp
index e07a3963c..4cb0c9b73 100644
--- a/src/extension/implementation/script.cpp
+++ b/src/extension/implementation/script.cpp
@@ -41,8 +41,12 @@
#include "ui/view/view.h"
#include "xml/node.h"
#include "xml/attribute-record.h"
+#include "ui/tools/node-tool.h"
+#include "ui/tool/multi-path-manipulator.h"
+#include "ui/tool/path-manipulator.h"
+#include "ui/tool/control-point-selection.h"
+
-#include "util/glib-list-iterators.h"
#include "path-prefix.h"
#ifdef WIN32
@@ -310,9 +314,9 @@ bool Script::load(Inkscape::Extension::Extension *module)
const gchar *interpretstr = child_repr->attribute("interpreter");
if (interpretstr != NULL) {
std::string interpString = resolveInterpreterExecutable(interpretstr);
- command.insert(command.end(), interpString);
+ command.push_back(interpString);
}
- command.insert(command.end(), solve_reldir(child_repr));
+ command.push_back(solve_reldir(child_repr));
}
if (!strcmp(child_repr->name(), INKSCAPE_EXTENSION_NS "helper_extension")) {
helper_extension = child_repr->firstChild()->content();
@@ -691,13 +695,56 @@ void Script::effect(Inkscape::Extension::Effect *module,
std::vector<SPItem*> selected =
desktop->getSelection()->itemList(); //desktop should not be NULL since doc was checked and desktop is a casted pointer
- for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); x++){
+ for(std::vector<SPItem*>::const_iterator x = selected.begin(); x != selected.end(); ++x){
Glib::ustring selected_id;
selected_id += "--id=";
selected_id += (*x)->getId();
- params.insert(params.begin(), selected_id);
+ params.push_front(selected_id);
}
+ {//add selected nodes
+ Inkscape::UI::Tools::NodeTool *tool = 0;
+ if (SP_ACTIVE_DESKTOP ) {
+ Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context;
+ if (INK_IS_NODE_TOOL(ec)) {
+ tool = static_cast<Inkscape::UI::Tools::NodeTool*>(ec);
+ }
+ }
+
+ if(tool){
+ Inkscape::UI::ControlPointSelection *cps = tool->_selected_nodes;
+ for (Inkscape::UI::ControlPointSelection::iterator i = cps->begin(); i != cps->end(); ++i) {
+ Inkscape::UI::Node *node = dynamic_cast<Inkscape::UI::Node*>(*i);
+ if (node) {
+ std::string id = node->nodeList().subpathList().pm().item()->getId();
+
+ int sp = 0;
+ bool found_sp = false;
+ for(Inkscape::UI::SubpathList::iterator i = node->nodeList().subpathList().begin(); i != node->nodeList().subpathList().end(); ++i,++sp){
+ if(&**i == &(node->nodeList())){
+ found_sp = true;
+ break;
+ }
+ }
+ int nl=0;
+ bool found_nl = false;
+ for (Inkscape::UI::NodeList::iterator j = node->nodeList().begin(); j != node->nodeList().end(); ++j, ++nl){
+ if(&*j==node){
+ found_nl = true;
+ break;
+ }
+ }
+ std::ostringstream ss;
+ ss<< "--selected-nodes=" << id << ":" << sp << ":" << nl;
+ Glib::ustring selected = ss.str();
+
+ if(found_nl && found_sp)params.push_front(selected);
+ else g_warning("Something went wrong while trying to pass selected nodes to extension. Please report a bug.");
+ }
+ }
+ }
+ }//end add selected nodes
+
file_listener fileout;
int data_read = execute(command, params, dc->_filename, fileout);
fileout.toFile(tempfilename_out);
@@ -1014,6 +1061,8 @@ int Script::execute (const std::list<std::string> &in_command,
}
}
+ //for(int i=0;i<argv.size(); ++i){printf("%s ",argv[i].c_str());}printf("\n");
+
int stdout_pipe, stderr_pipe;
try {
diff --git a/src/extension/internal/bitmap/imagemagick.cpp b/src/extension/internal/bitmap/imagemagick.cpp
index bc0dd8e33..a235dcb0f 100644
--- a/src/extension/internal/bitmap/imagemagick.cpp
+++ b/src/extension/internal/bitmap/imagemagick.cpp
@@ -24,7 +24,6 @@
#include "selection.h"
#include "sp-object.h"
-#include "util/glib-list-iterators.h"
#include "extension/effect.h"
#include "extension/system.h"
@@ -79,7 +78,7 @@ ImageMagickDocCache::ImageMagickDocCache(Inkscape::UI::View::View * view) :
_imageItems = new SPItem*[selectCount];
// Loop through selected items
- for (std::vector<SPItem*>::const_iterator i = selectedItemList.begin(); i != selectedItemList.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = selectedItemList.begin(); i != selectedItemList.end(); ++i) {
SPItem *item = *i;
Inkscape::XML::Node *node = reinterpret_cast<Inkscape::XML::Node *>(item->getRepr());
if (!strcmp(node->name(), "image") || !strcmp(node->name(), "svg:image"))
diff --git a/src/extension/internal/bluredge.cpp b/src/extension/internal/bluredge.cpp
index 9f19f8b3b..0e3aa98ce 100644
--- a/src/extension/internal/bluredge.cpp
+++ b/src/extension/internal/bluredge.cpp
@@ -22,8 +22,6 @@
#include "path-chemistry.h"
#include "sp-item.h"
-#include "util/glib-list-iterators.h"
-
#include "extension/effect.h"
#include "extension/system.h"
diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp
index c3e416184..5d8b0e076 100644
--- a/src/extension/internal/cairo-render-context.cpp
+++ b/src/extension/internal/cairo-render-context.cpp
@@ -130,14 +130,12 @@ CairoRenderContext::CairoRenderContext(CairoRenderer *parent) :
_clip_mode(CLIP_MODE_MASK),
_omittext_state(EMPTY)
{
- font_table = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, font_data_free);
}
CairoRenderContext::~CairoRenderContext(void)
{
- if(font_table != NULL) {
- g_hash_table_remove_all(font_table);
- }
+ for (std::map<gpointer, cairo_font_face_t *>::const_iterator iter = font_table.begin(); iter != font_table.end(); ++iter)
+ font_data_free(iter->second);
if (_cr) cairo_destroy(_cr);
if (_surface) cairo_surface_destroy(_surface);
@@ -1182,7 +1180,7 @@ CairoRenderContext::_createHatchPainter(SPPaintServer const *const paintserver,
std::vector<SPHatchPath *> children(evil->hatchPaths());
for (int i = 0; i < overflow_steps; i++) {
- for (std::vector<SPHatchPath *>::iterator iter = children.begin(); iter != children.end(); iter++) {
+ for (std::vector<SPHatchPath *>::iterator iter = children.begin(); iter != children.end(); ++iter) {
SPHatchPath *path = *iter;
_renderer->renderHatchPath(pattern_ctx, *path, dkey);
}
@@ -1247,11 +1245,12 @@ CairoRenderContext::_createPatternForPaintServer(SPPaintServer const *const pain
Geom::Point c (rg->cx.computed, rg->cy.computed);
Geom::Point f (rg->fx.computed, rg->fy.computed);
double r = rg->r.computed;
+ double fr = rg->fr.computed;
if (pbox && SP_GRADIENT(rg)->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX)
apply_bbox2user = true;
// create radial gradient pattern
- pattern = cairo_pattern_create_radial(f[Geom::X], f[Geom::Y], 0, c[Geom::X], c[Geom::Y], r);
+ pattern = cairo_pattern_create_radial(f[Geom::X], f[Geom::Y], fr, c[Geom::X], c[Geom::Y], r);
// add stops
for (gint i = 0; unsigned(i) < rg->vector.stops.size(); i++) {
@@ -1454,8 +1453,11 @@ CairoRenderContext::_prepareRenderText()
}
}
+/* We need CairoPaintOrder as markers are rendered in a separate step and may be rendered
+ * inbetween fill and stroke.
+ */
bool
-CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle const *style, Geom::OptRect const &pbox)
+CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle const *style, Geom::OptRect const &pbox, CairoPaintOrder order)
{
g_assert( _is_valid );
@@ -1477,9 +1479,10 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con
return true;
}
- bool no_fill = style->fill.isNone() || style->fill_opacity.value == 0;
+ bool no_fill = style->fill.isNone() || style->fill_opacity.value == 0 ||
+ order == STROKE_ONLY;
bool no_stroke = style->stroke.isNone() || style->stroke_width.computed < 1e-9 ||
- style->stroke_opacity.value == 0;
+ style->stroke_opacity.value == 0 || order == FILL_ONLY;
if (no_fill && no_stroke)
return true;
@@ -1493,14 +1496,17 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con
pushLayer();
if (!no_fill) {
- _setFillStyle(style, pbox);
- setPathVector(pathv);
-
if (style->fill_rule.computed == SP_WIND_RULE_EVENODD) {
cairo_set_fill_rule(_cr, CAIRO_FILL_RULE_EVEN_ODD);
} else {
cairo_set_fill_rule(_cr, CAIRO_FILL_RULE_WINDING);
}
+ }
+
+ setPathVector(pathv);
+
+ if (!no_fill && (order == STROKE_OVER_FILL || order == FILL_ONLY)) {
+ _setFillStyle(style, pbox);
if (no_stroke)
cairo_fill(_cr);
@@ -1510,10 +1516,17 @@ CairoRenderContext::renderPathVector(Geom::PathVector const & pathv, SPStyle con
if (!no_stroke) {
_setStrokeStyle(style, pbox);
- if (no_fill)
- setPathVector(pathv);
- cairo_stroke(_cr);
+ if (no_fill || order == STROKE_OVER_FILL)
+ cairo_stroke(_cr);
+ else
+ cairo_stroke_preserve(_cr);
+ }
+
+ if (!no_fill && order == FILL_OVER_STROKE) {
+ _setFillStyle(style, pbox);
+
+ cairo_fill(_cr);
}
if (need_layer)
@@ -1643,9 +1656,11 @@ CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Affine const &font_ma
return true;
// create a cairo_font_face from PangoFont
- double size = style->font_size.computed; /// \fixme why is this variable never used?
+ // double size = style->font_size.computed; /// \fixme why is this variable never used?
gpointer fonthash = (gpointer)font;
- cairo_font_face_t *font_face = (cairo_font_face_t *)g_hash_table_lookup(font_table, fonthash);
+ cairo_font_face_t *font_face = NULL;
+ if(font_table.find(fonthash)!=font_table.end())
+ font_face = font_table[fonthash];
FcPattern *fc_pattern = NULL;
@@ -1660,7 +1675,7 @@ CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Affine const &font_ma
if(font_face == NULL) {
font_face = cairo_win32_font_face_create_for_logfontw(&lfw);
- g_hash_table_insert(font_table, fonthash, font_face);
+ font_table[fonthash] = font_face;
}
# endif
#else
@@ -1669,7 +1684,7 @@ CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Affine const &font_ma
fc_pattern = fc_font->font_pattern;
if(font_face == NULL) {
font_face = cairo_ft_font_face_create_for_pattern(fc_pattern);
- g_hash_table_insert(font_table, fonthash, font_face);
+ font_table[fonthash] = font_face;
}
# endif
#endif
@@ -1677,8 +1692,8 @@ CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Affine const &font_ma
cairo_save(_cr);
cairo_set_font_face(_cr, font_face);
- if (fc_pattern && FcPatternGetDouble(fc_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch)
- size = 12.0;
+ //if (fc_pattern && FcPatternGetDouble(fc_pattern, FC_PIXEL_SIZE, 0, &size) != FcResultMatch)
+ // size = 12.0;
// set the given font matrix
cairo_matrix_t matrix;
@@ -1698,30 +1713,72 @@ CairoRenderContext::renderGlyphtext(PangoFont *font, Geom::Affine const &font_ma
_showGlyphs(_cr, font, glyphtext, TRUE);
}
} else {
- bool fill = false, stroke = false, have_path = false;
+
+ bool fill = false;
if (style->fill.isColor() || style->fill.isPaintserver()) {
fill = true;
}
+ bool stroke = false;
if (style->stroke.isColor() || style->stroke.isPaintserver()) {
stroke = true;
}
- if (fill) {
+
+ // Text never has markers
+ bool stroke_over_fill = true;
+ if ( (style->paint_order.layer[0] == SP_CSS_PAINT_ORDER_STROKE &&
+ style->paint_order.layer[1] == SP_CSS_PAINT_ORDER_FILL) ||
+
+ (style->paint_order.layer[0] == SP_CSS_PAINT_ORDER_STROKE &&
+ style->paint_order.layer[2] == SP_CSS_PAINT_ORDER_FILL) ||
+
+ (style->paint_order.layer[1] == SP_CSS_PAINT_ORDER_STROKE &&
+ style->paint_order.layer[2] == SP_CSS_PAINT_ORDER_FILL) ) {
+ stroke_over_fill = false;
+ }
+
+ bool have_path = false;
+ if (fill && stroke_over_fill) {
_setFillStyle(style, Geom::OptRect());
if (_is_texttopath) {
_showGlyphs(_cr, font, glyphtext, true);
- have_path = true;
- if (stroke) cairo_fill_preserve(_cr);
- else cairo_fill(_cr);
+ if (stroke) {
+ cairo_fill_preserve(_cr);
+ have_path = true;
+ } else {
+ cairo_fill(_cr);
+ }
} else {
_showGlyphs(_cr, font, glyphtext, false);
}
}
+
if (stroke) {
_setStrokeStyle(style, Geom::OptRect());
- if (!have_path) _showGlyphs(_cr, font, glyphtext, true);
- cairo_stroke(_cr);
+ if (!have_path) {
+ _showGlyphs(_cr, font, glyphtext, true);
+ }
+ if (fill && _is_texttopath && !stroke_over_fill) {
+ cairo_stroke_preserve(_cr);
+ have_path = true;
+ } else {
+ cairo_stroke(_cr);
+ }
+ }
+
+ if (fill && !stroke_over_fill) {
+ _setFillStyle(style, Geom::OptRect());
+ if (_is_texttopath) {
+ if (!have_path) {
+ // Could happen if both 'stroke' and 'stroke_over_fill' are false
+ _showGlyphs(_cr, font, glyphtext, true);
+ }
+ cairo_fill(_cr);
+ } else {
+ _showGlyphs(_cr, font, glyphtext, false);
+ }
}
+
}
cairo_restore(_cr);
diff --git a/src/extension/internal/cairo-render-context.h b/src/extension/internal/cairo-render-context.h
index 57d155b60..dfa6084d1 100644
--- a/src/extension/internal/cairo-render-context.h
+++ b/src/extension/internal/cairo-render-context.h
@@ -148,7 +148,14 @@ public:
void addClippingRect(double x, double y, double width, double height);
/* Rendering methods */
- bool renderPathVector(Geom::PathVector const &pathv, SPStyle const *style, Geom::OptRect const &pbox);
+ enum CairoPaintOrder {
+ STROKE_OVER_FILL,
+ FILL_OVER_STROKE,
+ FILL_ONLY,
+ STROKE_ONLY
+ };
+
+ bool renderPathVector(Geom::PathVector const &pathv, SPStyle const *style, Geom::OptRect const &pbox, CairoPaintOrder order = STROKE_OVER_FILL);
bool renderImage(Inkscape::Pixbuf *pb,
Geom::Affine const &image_transform, SPStyle const *style);
bool renderGlyphtext(PangoFont *font, Geom::Affine const &font_matrix,
@@ -219,7 +226,7 @@ protected:
void _prepareRenderGraphic(void);
void _prepareRenderText(void);
- GHashTable *font_table;
+ std::map<gpointer, cairo_font_face_t *> font_table;
static void font_data_free(gpointer data);
CairoRenderState *_createState(void);
diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp
index 5a5553e97..5dc20ab06 100644
--- a/src/extension/internal/cairo-renderer.cpp
+++ b/src/extension/internal/cairo-renderer.cpp
@@ -194,7 +194,20 @@ static void sp_shape_render(SPShape *shape, CairoRenderContext *ctx)
return;
}
- ctx->renderPathVector(pathv, style, pbox);
+ if (style->paint_order.layer[0] == SP_CSS_PAINT_ORDER_NORMAL ||
+ (style->paint_order.layer[0] == SP_CSS_PAINT_ORDER_FILL &&
+ style->paint_order.layer[1] == SP_CSS_PAINT_ORDER_STROKE)) {
+ ctx->renderPathVector(pathv, style, pbox, CairoRenderContext::STROKE_OVER_FILL);
+ } else if (style->paint_order.layer[0] == SP_CSS_PAINT_ORDER_STROKE &&
+ style->paint_order.layer[1] == SP_CSS_PAINT_ORDER_FILL ) {
+ ctx->renderPathVector(pathv, style, pbox, CairoRenderContext::FILL_OVER_STROKE);
+ } else if (style->paint_order.layer[0] == SP_CSS_PAINT_ORDER_STROKE &&
+ style->paint_order.layer[1] == SP_CSS_PAINT_ORDER_MARKER ) {
+ ctx->renderPathVector(pathv, style, pbox, CairoRenderContext::STROKE_ONLY);
+ } else if (style->paint_order.layer[0] == SP_CSS_PAINT_ORDER_FILL &&
+ style->paint_order.layer[1] == SP_CSS_PAINT_ORDER_MARKER ) {
+ ctx->renderPathVector(pathv, style, pbox, CairoRenderContext::FILL_ONLY);
+ }
// START marker
for (int i = 0; i < 2; i++) { // SP_MARKER_LOC and SP_MARKER_LOC_START
@@ -287,6 +300,21 @@ static void sp_shape_render(SPShape *shape, CairoRenderContext *ctx)
sp_shape_render_invoke_marker_rendering(marker, tr, style, ctx);
}
}
+
+ if (style->paint_order.layer[1] == SP_CSS_PAINT_ORDER_FILL &&
+ style->paint_order.layer[2] == SP_CSS_PAINT_ORDER_STROKE) {
+ ctx->renderPathVector(pathv, style, pbox, CairoRenderContext::STROKE_OVER_FILL);
+ } else if (style->paint_order.layer[1] == SP_CSS_PAINT_ORDER_STROKE &&
+ style->paint_order.layer[2] == SP_CSS_PAINT_ORDER_FILL ) {
+ ctx->renderPathVector(pathv, style, pbox, CairoRenderContext::FILL_OVER_STROKE);
+ } else if (style->paint_order.layer[2] == SP_CSS_PAINT_ORDER_STROKE &&
+ style->paint_order.layer[1] == SP_CSS_PAINT_ORDER_MARKER ) {
+ ctx->renderPathVector(pathv, style, pbox, CairoRenderContext::STROKE_ONLY);
+ } else if (style->paint_order.layer[2] == SP_CSS_PAINT_ORDER_FILL &&
+ style->paint_order.layer[1] == SP_CSS_PAINT_ORDER_MARKER ) {
+ ctx->renderPathVector(pathv, style, pbox, CairoRenderContext::FILL_ONLY);
+ }
+
}
static void sp_group_render(SPGroup *group, CairoRenderContext *ctx)
@@ -295,7 +323,7 @@ static void sp_group_render(SPGroup *group, CairoRenderContext *ctx)
TRACE(("sp_group_render opacity: %f\n", SP_SCALE24_TO_FLOAT(item->style->opacity.value)));
std::vector<SPObject*> l(group->childList(false));
- for(std::vector<SPObject*>::const_iterator x = l.begin(); x!= l.end(); x++){
+ for(std::vector<SPObject*>::const_iterator x = l.begin(); x!= l.end(); ++x){
SPItem *item = dynamic_cast<SPItem*>(*x);
if (item) {
renderer->renderItem(ctx, item);
diff --git a/src/extension/internal/emf-inout.cpp b/src/extension/internal/emf-inout.cpp
index e88cf3d42..13520c40b 100644
--- a/src/extension/internal/emf-inout.cpp
+++ b/src/extension/internal/emf-inout.cpp
@@ -1174,10 +1174,7 @@ Emf::select_extpen(PEMF_CALLBACK_DATA d, int index)
if (!d->dc[d->level].style.stroke_dasharray.values.empty() && (d->level==0 || (d->level>0 && d->dc[d->level].style.stroke_dasharray.values!=d->dc[d->level-1].style.stroke_dasharray.values)))
d->dc[d->level].style.stroke_dasharray.values.clear();
for (unsigned int i=0; i<pEmr->elp.elpNumEntries; i++) {
-// Doing it this way typically results in a pattern that is tiny, better to assume the array
-// is the same scale as for dot/dash below, that is, no scaling should be applied
-// double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] );
- double dash_length = pEmr->elp.elpStyleEntry[i];
+ double dash_length = pix_to_abs_size( d, pEmr->elp.elpStyleEntry[i] );
d->dc[d->level].style.stroke_dasharray.values.push_back(dash_length);
}
d->dc[d->level].style.stroke_dasharray.set = 1;
@@ -1620,6 +1617,17 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA
uint32_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written
U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor
+ // code for end user debugging
+ int eDbgRecord=0;
+ int eDbgComment=0;
+ int eDbgFinal=0;
+ char const* eDbgString = getenv( "INKSCAPE_DBG_EMF" );
+ if ( eDbgString != NULL ) {
+ if(strstr(eDbgString,"RECORD")){ eDbgRecord = 1; }
+ if(strstr(eDbgString,"COMMENT")){ eDbgComment = 1; }
+ if(strstr(eDbgString,"FINAL")){ eDbgFinal = 1; }
+ }
+
/* initialize the tsp for text reassembly */
tsp.string = NULL;
tsp.ori = 0.0; /* degrees */
@@ -1662,8 +1670,11 @@ int Emf::myEnhMetaFileProc(char *contents, unsigned int length, PEMF_CALLBACK_DA
lpEMFR = (PU_ENHMETARECORD)(contents + off);
-// Uncomment the following to track down toxic records
-// std::cout << "record type: " << iType << " name " << U_emr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
+// At run time define environment variable INKSCAPE_DBG_EMF to include string RECORD.
+// Users may employ this to track down toxic records
+ if(eDbgRecord){
+ std::cout << "record type: " << iType << " name " << U_emr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
+ }
off += nSize;
SVGOStringStream tmp_outsvg;
@@ -3478,14 +3489,20 @@ std::cout << "BEFORE DRAW"
dbg_str << "<!-- U_EMR_??? -->\n";
break;
} //end of switch
-// When testing, uncomment the following to place a comment for each processed EMR record in the SVG
-// d->outsvg += dbg_str.str().c_str();
+// At run time define environment variable INKSCAPE_DBG_EMF to include string COMMENT.
+// Users may employ this to to place a comment for each processed EMR record in the SVG
+ if(eDbgComment){
+ d->outsvg += dbg_str.str().c_str();
+ }
d->outsvg += tmp_outsvg.str().c_str();
d->path += tmp_path.str().c_str();
} //end of while
-// When testing, uncomment the following to show the final SVG derived from the EMF
-// std::cout << d->outsvg << std::endl;
+// At run time define environment variable INKSCAPE_DBG_EMF to include string FINAL
+// Users may employ this to to show the final SVG derived from the EMF
+ if(eDbgFinal){
+ std::cout << d->outsvg << std::endl;
+ }
(void) emr_properties(U_EMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant
return(file_status);
diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp
index 5b8aae655..1c85182ae 100644
--- a/src/extension/internal/emf-print.cpp
+++ b/src/extension/internal/emf-print.cpp
@@ -253,7 +253,7 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc)
char *oldlocale = g_strdup(setlocale(LC_NUMERIC, NULL));
setlocale(LC_NUMERIC, "C");
- snprintf(buff, sizeof(buff) - 1, "Drawing=%.1lfx%.1lfpx, %.1lfx%.1lfmm", _width, _height, Inkscape::Util::Quantity::convert(dwInchesX, "in", "mm"), Inkscape::Util::Quantity::convert(dwInchesY, "in", "mm"));
+ snprintf(buff, sizeof(buff) - 1, "Drawing=%.1fx%.1fpx, %.1fx%.1fmm", _width, _height, Inkscape::Util::Quantity::convert(dwInchesX, "in", "mm"), Inkscape::Util::Quantity::convert(dwInchesY, "in", "mm"));
setlocale(LC_NUMERIC, oldlocale);
g_free(oldlocale);
rec = textcomment_set(buff);
@@ -708,7 +708,7 @@ int PrintEmf::create_pen(SPStyle const *style, const Geom::Affine &transform)
n_dash = style->stroke_dasharray.values.size();
dash = new uint32_t[n_dash];
for (i = 0; i < n_dash; i++) {
- dash[i] = style->stroke_dasharray.values[i];
+ dash[i] = MAX(1, (uint32_t) round(scale * style->stroke_dasharray.values[i] * PX2WORLD));
}
}
}
@@ -792,9 +792,9 @@ void PrintEmf::destroy_pen()
}
}
-/* Return a Path consisting of just the corner points of the single path in a a PathVector. If the
+/* Return a Path consisting of just the corner points of the single path in a PathVector. If the
PathVector has more than one path, or that one path is open, or any of its segments are curved, then the
-returned PathVector is . If the input path is already just straight lines and vertices the output will be the
+returned PathVector is an empty path. If the input path is already just straight lines and vertices the output will be the
same as the sole path in the input. */
Geom::Path PrintEmf::pathv_to_simple_polygon(Geom::PathVector const &pathv, int *vertices)
@@ -808,6 +808,7 @@ Geom::Path PrintEmf::pathv_to_simple_polygon(Geom::PathVector const &pathv, int
Geom::PathVector pv = pathv_to_linear_and_cubic_beziers(pathv);
Geom::PathVector::const_iterator pit = pv.begin();
Geom::PathVector::const_iterator pit2 = pv.begin();
+ int first_seg=1;
++pit2;
*vertices = 0;
if(pit->end_closed() != pit->end_default())return(bad); // path must be closed
@@ -833,9 +834,17 @@ Geom::Path PrintEmf::pathv_to_simple_polygon(Geom::PathVector const &pathv, int
output.start( P1 );
output.close( pit->closed() );
}
- *vertices += 1;
- Geom::LineSegment ls(P1_trail, P1);
- output.append(ls);
+ if(!Geom::are_near(P1, P1_trail, 1e-5)){ // possible for P1 to start on the end point
+ Geom::LineSegment ls(P1_trail, P1);
+ output.append(ls);
+ if(first_seg){
+ *vertices += 2;
+ first_seg=0;
+ }
+ else {
+ *vertices += 1;
+ }
+ }
P1_trail = P1;
P1 = P1_lead;
}
@@ -850,7 +859,6 @@ Geom::Path PrintEmf::pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect,
{
Geom::Point P1_trail;
Geom::Point P1;
- Geom::Point P1_lead;
Geom::Point v1,v2;
int vertices;
Geom::Path pR = pathv_to_simple_polygon(pathv, &vertices);
@@ -860,7 +868,7 @@ Geom::Path PrintEmf::pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect,
/* Get the ends of the LAST line segment.
Find minimum rotation to align rectangle with X,Y axes. (Very degenerate if it is rotated 45 degrees.) */
*angle = 10.0; /* must be > than the actual angle in radians. */
- for(Geom::Path::iterator cit = pR.begin(); cit != pR.end_open(); ++cit){
+ for(Geom::Path::iterator cit = pR.begin();; ++cit){
P1_trail = cit->initialPoint();
P1 = cit->finalPoint();
v1 = unit_vector(P1 - P1_trail);
@@ -868,21 +876,23 @@ Geom::Path PrintEmf::pathv_to_rect(Geom::PathVector const &pathv, bool *is_rect,
double ang = asin(v1[Geom::Y]); // because component is rotation by ang of {1,0| vector
if(fabs(ang) < fabs(*angle))*angle = -ang; // y increases down, flips sign on angle
}
+ if(cit == pR.end_open())break;
}
/* For increased numerical stability, snap the angle to the nearest 1/100th of a degree. */
double convert = 36000.0/ (2.0 * M_PI);
*angle = round(*angle * convert)/convert;
- for(Geom::Path::iterator cit = pR.begin(); cit != pR.end_open();++cit) {
- P1_lead = cit->finalPoint();
+ // at this stage v1 holds the last vector in the path, whichever direction it points.
+ for(Geom::Path::iterator cit = pR.begin(); ;++cit) {
+ v2 = v1;
+ P1_trail = cit->initialPoint();
+ P1 = cit->finalPoint();
v1 = unit_vector(P1 - P1_trail);
- v2 = unit_vector(P1_lead - P1 );
// P1 is center of a turn that is not 90 degrees. Limit comes from cos(89.9) = .001745
if(!Geom::are_near(dot(v1,v2), 0.0, 2e-3))break;
- P1_trail = P1;
- P1 = P1_lead;
vertex_count++;
+ if(cit == pR.end_open())break;
}
if(vertex_count == 4){
*is_rect=true;
@@ -903,13 +913,11 @@ int PrintEmf::vector_rect_alignment(double angle, Geom::Point vtest){
int stat = 0;
Geom::Point v1 = Geom::unit_vector(vtest); // unit vector to test alignment
Geom::Point v2 = Geom::Point(1,0) * Geom::Rotate(-angle); // unit horizontal side (sign change because Y increases DOWN)
+ Geom::Point v3 = Geom::Point(0,1) * Geom::Rotate(-angle); // unit horizontal side (sign change because Y increases DOWN)
if( Geom::are_near(dot(v1,v2), 1.0, 1e-5)){ stat = 1; }
else if(Geom::are_near(dot(v1,v2),-1.0, 1e-5)){ stat = 2; }
- if(!stat){
- v2 = Geom::Point(0,1) * Geom::Rotate(-angle); // unit vertical side
- if( Geom::are_near(dot(v1,v2), 1.0, 1e-5)){ stat = 3; }
- else if(Geom::are_near(dot(v1,v2),-1.0, 1e-5)){ stat = 4; }
- }
+ else if(Geom::are_near(dot(v1,v3), 1.0, 1e-5)){ stat = 3; }
+ else if(Geom::are_near(dot(v1,v3),-1.0, 1e-5)){ stat = 4; }
return(stat);
}
@@ -924,8 +932,9 @@ int PrintEmf::vector_rect_alignment(double angle, Geom::Point vtest){
*/
Geom::Point PrintEmf::get_pathrect_corner(Geom::Path pathRect, double angle, int corner){
Geom::Point center(0,0);
- for(Geom::Path::iterator cit = pathRect.begin(); cit != pathRect.end_open(); ++cit) {
+ for(Geom::Path::iterator cit = pathRect.begin(); ; ++cit) {
center += cit->initialPoint()/4.0;
+ if(cit == pathRect.end_open())break;
}
int LR; // 1 if Left, 0 if Right
@@ -952,11 +961,12 @@ Geom::Point PrintEmf::get_pathrect_corner(Geom::Path pathRect, double angle, int
Geom::Point v1 = Geom::Point(1,0) * Geom::Rotate(-angle); // unit horizontal side (sign change because Y increases DOWN)
Geom::Point v2 = Geom::Point(0,1) * Geom::Rotate(-angle); // unit vertical side (sign change because Y increases DOWN)
Geom::Point P1;
- for(Geom::Path::iterator cit = pathRect.begin(); cit != pathRect.end_open(); ++cit) {
+ for(Geom::Path::iterator cit = pathRect.begin(); ; ++cit) {
P1 = cit->initialPoint();
if ( ( LR == (dot(P1 - center,v1) > 0 ? 0 : 1) )
&& ( UL == (dot(P1 - center,v2) > 0 ? 1 : 0) ) ) break;
+ if(cit == pathRect.end_open())break;
}
return(P1);
}
@@ -1279,6 +1289,7 @@ unsigned int PrintEmf::fill(
outLR = Geom::Point(wRect,doff_range*hRect);
gMode = U_GRADIENT_FILL_RECT_V;
}
+
doff_base = doff_range;
rcb.left = round(outUL[X]); // use explicit round for better stability
rcb.top = round(outUL[Y]);
@@ -1955,7 +1966,7 @@ unsigned int PrintEmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af
unsigned int PrintEmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p,
SPStyle const *const style)
{
- if (!et) {
+ if (!et || !text) {
return 0;
}
diff --git a/src/extension/internal/filter/filter.cpp b/src/extension/internal/filter/filter.cpp
index 65162af22..25e89bbf3 100644
--- a/src/extension/internal/filter/filter.cpp
+++ b/src/extension/internal/filter/filter.cpp
@@ -11,7 +11,6 @@
#include "selection.h"
#include "document-private.h"
#include "sp-item.h"
-#include "util/glib-list-iterators.h"
#include "extension/extension.h"
#include "extension/effect.h"
#include "extension/system.h"
diff --git a/src/extension/internal/gdkpixbuf-input.cpp b/src/extension/internal/gdkpixbuf-input.cpp
index f5fab1fa2..c15e28854 100644
--- a/src/extension/internal/gdkpixbuf-input.cpp
+++ b/src/extension/internal/gdkpixbuf-input.cpp
@@ -86,8 +86,13 @@ GdkpixbufInput::open(Inkscape::Extension::Input *mod, char const *uri)
ir = new ImageResolution(uri);
}
if (ir && ir->ok()) {
- xscale = 960.0 / floor(10.*ir->x() + .5); // round-off to 0.1 dpi
- yscale = 960.0 / floor(10.*ir->y() + .5);
+ xscale = 960.0 / round(10.*ir->x()); // round-off to 0.1 dpi
+ yscale = 960.0 / round(10.*ir->y());
+ // prevent crash on image with too small dpi (bug 1479193)
+ if (ir->x() <= .05)
+ xscale = 960.0;
+ if (ir->y() <= .05)
+ yscale = 960.0;
} else {
xscale = 96.0 / defaultxdpi;
yscale = 96.0 / defaultxdpi;
diff --git a/src/extension/internal/grid.cpp b/src/extension/internal/grid.cpp
index 8fd82b675..8a9c7a72f 100644
--- a/src/extension/internal/grid.cpp
+++ b/src/extension/internal/grid.cpp
@@ -24,7 +24,6 @@
#include "document.h"
#include "selection.h"
#include "sp-object.h"
-#include "util/glib-list-iterators.h"
#include "2geom/geom.h"
#include "svg/path-string.h"
diff --git a/src/extension/internal/latex-text-renderer.cpp b/src/extension/internal/latex-text-renderer.cpp
index 5933dd526..dec75aeb6 100644
--- a/src/extension/internal/latex-text-renderer.cpp
+++ b/src/extension/internal/latex-text-renderer.cpp
@@ -229,7 +229,7 @@ LaTeXTextRenderer::writePostamble()
void LaTeXTextRenderer::sp_group_render(SPGroup *group)
{
std::vector<SPObject*> l = (group->childList(false));
- for(std::vector<SPObject*>::const_iterator x = l.begin(); x != l.end(); x++){
+ for(std::vector<SPObject*>::const_iterator x = l.begin(); x != l.end(); ++x){
SPItem *item = dynamic_cast<SPItem*>(*x);
if (item) {
renderItem(item);
diff --git a/src/extension/internal/metafile-print.cpp b/src/extension/internal/metafile-print.cpp
index 2fb36be85..47ba5971c 100644
--- a/src/extension/internal/metafile-print.cpp
+++ b/src/extension/internal/metafile-print.cpp
@@ -285,8 +285,8 @@ void PrintMetafile::brush_classify(SPObject *parent, int depth, Inkscape::Pixbuf
return;
}
char temp[32]; // large enough
- temp[31] = '\0';
- strncpy(temp, pat_i->getAttribute("id"), 31); // Some names may be longer than [EW]MFhatch#_######
+ strncpy(temp, pat_i->getAttribute("id"), sizeof(temp)-1); // Some names may be longer than [EW]MFhatch#_######
+ temp[sizeof(temp)-1] = '\0';
hatch_classify(temp, hatchType, hatchColor, bkColor);
if (*hatchType != -1) {
return;
diff --git a/src/extension/internal/pdfinput/pdf-input.cpp b/src/extension/internal/pdfinput/pdf-input.cpp
index 363061734..c1940b16a 100644
--- a/src/extension/internal/pdfinput/pdf-input.cpp
+++ b/src/extension/internal/pdfinput/pdf-input.cpp
@@ -223,6 +223,7 @@ PdfImportDialog::PdfImportDialog(PDFDoc *doc, const gchar */*uri*/)
_importViaInternal->set_can_focus();
_importViaInternal->set_relief(Gtk::RELIEF_NORMAL);
_importViaInternal->set_mode(true);
+ _importViaInternal->set_active(true);
_labelViaPoppler->set_line_wrap(true);
_labelViaInternal->set_line_wrap(true);
#endif
diff --git a/src/extension/internal/pdfinput/pdf-parser.cpp b/src/extension/internal/pdfinput/pdf-parser.cpp
index 836c34c32..5ede59bf3 100644
--- a/src/extension/internal/pdfinput/pdf-parser.cpp
+++ b/src/extension/internal/pdfinput/pdf-parser.cpp
@@ -416,22 +416,14 @@ void PdfParser::parse(Object *obj, GBool topLevel) {
for (int i = 0; i < obj->arrayGetLength(); ++i) {
obj->arrayGet(i, &obj2);
if (!obj2.isStream()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errInternal, -1, "Weird page contents");
-#else
- error(-1, const_cast<char*>("Weird page contents"));
-#endif
obj2.free();
return;
}
obj2.free();
}
} else if (!obj->isStream()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errInternal, -1, "Weird page contents");
-#else
- error(-1, const_cast<char*>("Weird page contents"));
-#endif
return;
}
parser = new Parser(xref, new Lexer(xref, obj), gFalse);
@@ -476,11 +468,7 @@ void PdfParser::go(GBool /*topLevel*/)
// too many arguments - something is wrong
} else {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Too many args in content stream");
-#else
- error(getPos(), const_cast<char*>("Too many args in content stream"));
-#endif
if (printCommands) {
printf("throwing away arg: ");
obj.print(stdout);
@@ -497,11 +485,7 @@ void PdfParser::go(GBool /*topLevel*/)
// args at end with no command
if (numArgs > 0) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Leftover args in content stream");
-#else
- error(getPos(), const_cast<char*>("Leftover args in content stream"));
-#endif
if (printCommands) {
printf("%d leftovers:", numArgs);
for (int i = 0; i < numArgs; ++i) {
@@ -568,11 +552,7 @@ void PdfParser::execOp(Object *cmd, Object args[], int numArgs) {
name = cmd->getCmd();
if (!(op = findOp(name))) {
if (ignoreUndef == 0)
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Unknown operator '{0:s}'", name);
-#else
- error(getPos(), const_cast<char*>("Unknown operator '%s'"), name);
-#endif
return;
}
@@ -580,42 +560,26 @@ void PdfParser::execOp(Object *cmd, Object args[], int numArgs) {
argPtr = args;
if (op->numArgs >= 0) {
if (numArgs < op->numArgs) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Too few ({0:d}) args to '{1:d}' operator", numArgs, name);
-#else
- error(getPos(), const_cast<char*>("Too few (%d) args to '%s' operator"), numArgs, name);
-#endif
return;
}
if (numArgs > op->numArgs) {
#if 0
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator", numArgs, name);
-#else
- error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name);
-#endif
#endif
argPtr += numArgs - op->numArgs;
numArgs = op->numArgs;
}
} else {
if (numArgs > -op->numArgs) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Too many ({0:d}) args to '{1:s}' operator",
-#else
- error(getPos(), const_cast<char*>("Too many (%d) args to '%s' operator"),
-#endif
numArgs, name);
return;
}
}
for (i = 0; i < numArgs; ++i) {
if (!checkArg(&argPtr[i], op->tchk[i])) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Arg #{0:d} to '{1:s}' operator is wrong type ({2:s})",
-#else
- error(getPos(), const_cast<char*>("Arg #%d to '%s' operator is wrong type (%s)"),
-#endif
i, name, argPtr[i].getTypeName());
return;
}
@@ -784,11 +748,7 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
return;
}
if (!obj1.isDict()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "ExtGState '{0:s}' is wrong type"), args[0].getName();
-#else
- error(getPos(), const_cast<char*>("ExtGState '%s' is wrong type"), args[0].getName());
-#endif
obj1.free();
return;
}
@@ -804,11 +764,7 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
if (state->parseBlendMode(&obj2, &mode)) {
state->setBlendMode(mode);
} else {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Invalid blend mode in ExtGState");
-#else
- error(getPos(), const_cast<char*>("Invalid blend mode in ExtGState"));
-#endif
}
}
obj2.free();
@@ -870,11 +826,7 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
state->setTransfer(funcs);
}
} else if (!obj2.isNull()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Invalid transfer function in ExtGState");
-#else
- error(getPos(), const_cast<char*>("Invalid transfer function in ExtGState"));
-#endif
}
obj2.free();
@@ -894,11 +846,7 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
funcs[0] = Function::parse(&obj3);
if (funcs[0]->getInputSize() != 1 ||
funcs[0]->getOutputSize() != 1) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Invalid transfer function in soft mask in ExtGState");
-#else
- error(getPos(), const_cast<char*>("Invalid transfer function in soft mask in ExtGState"));
-#endif
delete funcs[0];
funcs[0] = NULL;
}
@@ -927,10 +875,8 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
blendingColorSpace = GfxColorSpace::parse(NULL, &obj5, NULL, NULL);
#elif defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API)
blendingColorSpace = GfxColorSpace::parse(&obj5, NULL, NULL);
-#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
- blendingColorSpace = GfxColorSpace::parse(&obj5, NULL);
#else
- blendingColorSpace = GfxColorSpace::parse(&obj5);
+ blendingColorSpace = GfxColorSpace::parse(&obj5, NULL);
#endif
}
obj5.free();
@@ -958,27 +904,15 @@ void PdfParser::opSetExtGState(Object args[], int /*numArgs*/)
delete funcs[0];
}
} else {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
-#else
- error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
-#endif
}
obj4.free();
} else {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState - missing group");
-#else
- error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState - missing group"));
-#endif
}
obj3.free();
} else if (!obj2.isNull()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Invalid soft mask in ExtGState");
-#else
- error(getPos(), const_cast<char*>("Invalid soft mask in ExtGState"));
-#endif
}
}
obj2.free();
@@ -1006,11 +940,7 @@ void PdfParser::doSoftMask(Object *str, GBool alpha,
// check form type
dict->lookup(const_cast<char*>("FormType"), &obj1);
if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Unknown form type");
-#else
- error(getPos(), const_cast<char*>("Unknown form type"));
-#endif
}
obj1.free();
@@ -1018,11 +948,7 @@ void PdfParser::doSoftMask(Object *str, GBool alpha,
dict->lookup(const_cast<char*>("BBox"), &obj1);
if (!obj1.isArray()) {
obj1.free();
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Bad form bounding box");
-#else
- error(getPos(), const_cast<char*>("Bad form bounding box"));
-#endif
return;
}
for (i = 0; i < 4; ++i) {
@@ -1173,18 +1099,12 @@ void PdfParser::opSetFillColorSpace(Object args[], int /*numArgs*/)
} else {
colorSpace = GfxColorSpace::parse(&obj, NULL, NULL);
}
-#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
+#else
if (obj.isNull()) {
colorSpace = GfxColorSpace::parse(&args[0], NULL);
} else {
colorSpace = GfxColorSpace::parse(&obj, NULL);
}
-#else
- if (obj.isNull()) {
- colorSpace = GfxColorSpace::parse(&args[0]);
- } else {
- colorSpace = GfxColorSpace::parse(&obj);
- }
#endif
obj.free();
if (colorSpace) {
@@ -1194,11 +1114,7 @@ void PdfParser::opSetFillColorSpace(Object args[], int /*numArgs*/)
state->setFillColor(&color);
builder->updateStyle(state);
} else {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Bad color space (fill)");
-#else
- error(getPos(), const_cast<char*>("Bad color space (fill)"));
-#endif
}
}
@@ -1222,18 +1138,12 @@ void PdfParser::opSetStrokeColorSpace(Object args[], int /*numArgs*/)
} else {
colorSpace = GfxColorSpace::parse(&obj, NULL, NULL);
}
-#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
+#else
if (obj.isNull()) {
colorSpace = GfxColorSpace::parse(&args[0], NULL);
} else {
colorSpace = GfxColorSpace::parse(&obj, NULL);
}
-#else
- if (obj.isNull()) {
- colorSpace = GfxColorSpace::parse(&args[0]);
- } else {
- colorSpace = GfxColorSpace::parse(&obj);
- }
#endif
obj.free();
if (colorSpace) {
@@ -1243,11 +1153,7 @@ void PdfParser::opSetStrokeColorSpace(Object args[], int /*numArgs*/)
state->setStrokeColor(&color);
builder->updateStyle(state);
} else {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Bad color space (stroke)");
-#else
- error(getPos(), const_cast<char*>("Bad color space (stroke)"));
-#endif
}
}
@@ -1256,11 +1162,7 @@ void PdfParser::opSetFillColor(Object args[], int numArgs) {
int i;
if (numArgs != state->getFillColorSpace()->getNComps()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'sc' command");
-#else
- error(getPos(), const_cast<char*>("Incorrect number of arguments in 'sc' command"));
-#endif
return;
}
state->setFillPattern(NULL);
@@ -1276,11 +1178,7 @@ void PdfParser::opSetStrokeColor(Object args[], int numArgs) {
int i;
if (numArgs != state->getStrokeColorSpace()->getNComps()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SC' command");
-#else
- error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SC' command"));
-#endif
return;
}
state->setStrokePattern(NULL);
@@ -1300,11 +1198,7 @@ void PdfParser::opSetFillColorN(Object args[], int numArgs) {
if (!((GfxPatternColorSpace *)state->getFillColorSpace())->getUnder() ||
numArgs - 1 != ((GfxPatternColorSpace *)state->getFillColorSpace())
->getUnder()->getNComps()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
-#else
- error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
-#endif
return;
}
for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
@@ -1322,15 +1216,9 @@ void PdfParser::opSetFillColorN(Object args[], int numArgs) {
state->setFillPattern(pattern);
builder->updateStyle(state);
}
-#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
- if (args[numArgs-1].isName() &&
- (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
- state->setFillPattern(pattern);
- builder->updateStyle(state);
- }
#else
if (args[numArgs-1].isName() &&
- (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
+ (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
state->setFillPattern(pattern);
builder->updateStyle(state);
}
@@ -1338,11 +1226,7 @@ void PdfParser::opSetFillColorN(Object args[], int numArgs) {
} else {
if (numArgs != state->getFillColorSpace()->getNComps()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'scn' command");
-#else
- error(getPos(), const_cast<char*>("Incorrect number of arguments in 'scn' command"));
-#endif
return;
}
state->setFillPattern(NULL);
@@ -1366,11 +1250,7 @@ void PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
->getUnder() ||
numArgs - 1 != ((GfxPatternColorSpace *)state->getStrokeColorSpace())
->getUnder()->getNComps()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
-#else
- error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
-#endif
return;
}
for (i = 0; i < numArgs - 1 && i < gfxColorMaxComps; ++i) {
@@ -1388,15 +1268,9 @@ void PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
state->setStrokePattern(pattern);
builder->updateStyle(state);
}
-#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
- if (args[numArgs-1].isName() &&
- (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
- state->setStrokePattern(pattern);
- builder->updateStyle(state);
- }
#else
if (args[numArgs-1].isName() &&
- (pattern = res->lookupPattern(args[numArgs-1].getName()))) {
+ (pattern = res->lookupPattern(args[numArgs-1].getName(), NULL))) {
state->setStrokePattern(pattern);
builder->updateStyle(state);
}
@@ -1404,11 +1278,7 @@ void PdfParser::opSetStrokeColorN(Object args[], int numArgs) {
} else {
if (numArgs != state->getStrokeColorSpace()->getNComps()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Incorrect number of arguments in 'SCN' command");
-#else
- error(getPos(), const_cast<char*>("Incorrect number of arguments in 'SCN' command"));
-#endif
return;
}
state->setStrokePattern(NULL);
@@ -1436,11 +1306,7 @@ void PdfParser::opMoveTo(Object args[], int /*numArgs*/)
void PdfParser::opLineTo(Object args[], int /*numArgs*/)
{
if (!state->isCurPt()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No current point in lineto");
-#else
- error(getPos(), const_cast<char*>("No current point in lineto"));
-#endif
return;
}
state->lineTo(args[0].getNum(), args[1].getNum());
@@ -1450,11 +1316,7 @@ void PdfParser::opLineTo(Object args[], int /*numArgs*/)
void PdfParser::opCurveTo(Object args[], int /*numArgs*/)
{
if (!state->isCurPt()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No current point in curveto");
-#else
- error(getPos(), const_cast<char*>("No current point in curveto"));
-#endif
return;
}
double x1 = args[0].getNum();
@@ -1470,11 +1332,7 @@ void PdfParser::opCurveTo(Object args[], int /*numArgs*/)
void PdfParser::opCurveTo1(Object args[], int /*numArgs*/)
{
if (!state->isCurPt()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No current point in curveto1");
-#else
- error(getPos(), const_cast<char*>("No current point in curveto1"));
-#endif
return;
}
double x1 = state->getCurX();
@@ -1490,11 +1348,7 @@ void PdfParser::opCurveTo1(Object args[], int /*numArgs*/)
void PdfParser::opCurveTo2(Object args[], int /*numArgs*/)
{
if (!state->isCurPt()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No current point in curveto2");
-#else
- error(getPos(), const_cast<char*>("No current point in curveto2"));
-#endif
return;
}
double x1 = args[0].getNum();
@@ -1523,11 +1377,7 @@ void PdfParser::opRectangle(Object args[], int /*numArgs*/)
void PdfParser::opClosePath(Object /*args*/[], int /*numArgs*/)
{
if (!state->isCurPt()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No current point in closepath");
-#else
- error(getPos(), const_cast<char*>("No current point in closepath"));
-#endif
return;
}
state->closePath();
@@ -1693,11 +1543,7 @@ void PdfParser::doPatternFillFallback(GBool eoFill) {
doShadingPatternFillFallback(static_cast<GfxShadingPattern *>(pattern), gFalse, eoFill);
break;
default:
-#ifdef POPPLER_NEW_ERRORAPI
error(errUnimplemented, getPos(), "Unimplemented pattern type (%d) in fill",
-#else
- error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in fill"),
-#endif
pattern->getType());
break;
}
@@ -1716,11 +1562,7 @@ void PdfParser::doPatternStrokeFallback() {
doShadingPatternFillFallback(static_cast<GfxShadingPattern *>(pattern), gTrue, gFalse);
break;
default:
-#ifdef POPPLER_NEW_ERRORAPI
error(errUnimplemented, getPos(), "Unimplemented pattern type ({0:d}) in stroke",
-#else
- error(getPos(), const_cast<char*>("Unimplemented pattern type (%d) in stroke"),
-#endif
pattern->getType());
break;
}
@@ -1847,12 +1689,8 @@ void PdfParser::opShFill(Object args[], int /*numArgs*/)
if (!(shading = res->lookupShading(args[0].getName(), NULL, NULL))) {
return;
}
-#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
- if (!(shading = res->lookupShading(args[0].getName(), NULL))) {
- return;
- }
#else
- if (!(shading = res->lookupShading(args[0].getName()))) {
+ if (!(shading = res->lookupShading(args[0].getName(), NULL))) {
return;
}
#endif
@@ -2161,9 +1999,7 @@ void PdfParser::fillPatch(GfxPatch *patch, int nComps, int depth) {
GfxPatch patch01 = blankPatch();
GfxPatch patch10 = blankPatch();
GfxPatch patch11 = blankPatch();
-#ifdef POPPLER_NEW_GFXPATCH
GfxColor color = {{0}};
-#endif
double xx[4][8];
double yy[4][8];
double xxm;
@@ -2183,16 +2019,10 @@ void PdfParser::fillPatch(GfxPatch *patch, int nComps, int depth) {
> patchColorDelta) {
break;
}
-#ifdef POPPLER_NEW_GFXPATCH
color.c[i] = GfxColorComp(patch->color[0][0].c[i]);
-#endif
}
if (i == nComps || depth == maxDepths[pdfPatchMeshShading-1]) {
-#ifdef POPPLER_NEW_GFXPATCH
state->setFillColor(&color);
-#else
- state->setFillColor(&patch->color[0][0]);
-#endif
state->moveTo(patch->x[0][0], patch->y[0][0]);
state->curveTo(patch->x[0][1], patch->y[0][1],
patch->x[0][2], patch->y[0][2],
@@ -2473,11 +2303,7 @@ void PdfParser::opTextNextLine(Object /*args*/[], int /*numArgs*/)
void PdfParser::opShowText(Object args[], int /*numArgs*/)
{
if (!state->getFont()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No font in show");
-#else
- error(getPos(), const_cast<char*>("No font in show"));
-#endif
return;
}
if (fontChanged) {
@@ -2494,11 +2320,7 @@ void PdfParser::opMoveShowText(Object args[], int /*numArgs*/)
double ty = 0;
if (!state->getFont()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No font in move/show");
-#else
- error(getPos(), const_cast<char*>("No font in move/show"));
-#endif
return;
}
if (fontChanged) {
@@ -2519,11 +2341,7 @@ void PdfParser::opMoveSetShowText(Object args[], int /*numArgs*/)
double ty = 0;
if (!state->getFont()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No font in move/set/show");
-#else
- error(getPos(), const_cast<char*>("No font in move/set/show"));
-#endif
return;
}
if (fontChanged) {
@@ -2547,11 +2365,7 @@ void PdfParser::opShowSpaceText(Object args[], int /*numArgs*/)
int wMode = 0;
if (!state->getFont()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "No font in show/space");
-#else
- error(getPos(), const_cast<char*>("No font in show/space"));
-#endif
return;
}
if (fontChanged) {
@@ -2576,11 +2390,7 @@ void PdfParser::opShowSpaceText(Object args[], int /*numArgs*/)
} else if (obj.isString()) {
doShowText(obj.getString());
} else {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Element of show/space array must be number or string");
-#else
- error(getPos(), const_cast<char*>("Element of show/space array must be number or string"));
-#endif
}
obj.free();
}
@@ -2662,11 +2472,7 @@ void PdfParser::doShowText(GooString *s) {
if (charProc.isStream()) {
//parse(&charProc, gFalse); // TODO: parse into SVG font
} else {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Missing or bad Type3 CharProc entry");
-#else
- error(getPos(), const_cast<char*>("Missing or bad Type3 CharProc entry"));
-#endif
}
//out->endType3Char(state);
if (resDict) {
@@ -2739,11 +2545,7 @@ void PdfParser::opXObject(Object args[], int /*numArgs*/)
return;
}
if (!obj1.isStream()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "XObject '{0:s}' is wrong type", name);
-#else
- error(getPos(), const_cast<char*>("XObject '%s' is wrong type"), name);
-#endif
obj1.free();
return;
}
@@ -2759,17 +2561,9 @@ void PdfParser::opXObject(Object args[], int /*numArgs*/)
/* out->psXObject(obj1.getStream(),
obj3.isStream() ? obj3.getStream() : (Stream *)NULL);*/
} else if (obj2.isName()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Unknown XObject subtype '{0:s}'", obj2.getName());
-#else
- error(getPos(), const_cast<char*>("Unknown XObject subtype '%s'"), obj2.getName());
-#endif
} else {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "XObject subtype is missing or wrong type");
-#else
- error(getPos(), const_cast<char*>("XObject subtype is missing or wrong type"));
-#endif
}
obj2.free();
obj1.free();
@@ -2923,10 +2717,8 @@ void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg)
colorSpace = GfxColorSpace::parse(NULL, &obj1, NULL, NULL);
#elif defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API)
colorSpace = GfxColorSpace::parse(&obj1, NULL, NULL);
-#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
- colorSpace = GfxColorSpace::parse(&obj1, NULL);
#else
- colorSpace = GfxColorSpace::parse(&obj1);
+ colorSpace = GfxColorSpace::parse(&obj1, NULL);
#endif
} else if (csMode == streamCSDeviceGray) {
colorSpace = new GfxDeviceGrayColorSpace();
@@ -3029,10 +2821,8 @@ void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg)
GfxColorSpace *maskColorSpace = GfxColorSpace::parse(NULL, &obj1, NULL, NULL);
#elif defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API)
GfxColorSpace *maskColorSpace = GfxColorSpace::parse(&obj1, NULL, NULL);
-#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
- GfxColorSpace *maskColorSpace = GfxColorSpace::parse(&obj1, NULL);
#else
- GfxColorSpace *maskColorSpace = GfxColorSpace::parse(&obj1);
+ GfxColorSpace *maskColorSpace = GfxColorSpace::parse(&obj1, NULL);
#endif
obj1.free();
if (!maskColorSpace || maskColorSpace->getMode() != csDeviceGray) {
@@ -3148,11 +2938,7 @@ void PdfParser::doImage(Object * /*ref*/, Stream *str, GBool inlineImg)
err2:
obj1.free();
err1:
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Bad image parameters");
-#else
- error(getPos(), const_cast<char*>("Bad image parameters"));
-#endif
}
void PdfParser::doForm(Object *str) {
@@ -3177,11 +2963,7 @@ void PdfParser::doForm(Object *str) {
// check form type
dict->lookup(const_cast<char*>("FormType"), &obj1);
if (!(obj1.isNull() || (obj1.isInt() && obj1.getInt() == 1))) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Unknown form type");
-#else
- error(getPos(), const_cast<char*>("Unknown form type"));
-#endif
}
obj1.free();
@@ -3189,11 +2971,7 @@ void PdfParser::doForm(Object *str) {
dict->lookup(const_cast<char*>("BBox"), &bboxObj);
if (!bboxObj.isArray()) {
bboxObj.free();
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Bad form bounding box");
-#else
- error(getPos(), const_cast<char*>("Bad form bounding box"));
-#endif
return;
}
for (i = 0; i < 4; ++i) {
@@ -3233,10 +3011,8 @@ void PdfParser::doForm(Object *str) {
blendingColorSpace = GfxColorSpace::parse(NULL, &obj3, NULL, NULL);
#elif defined(POPPLER_EVEN_NEWER_COLOR_SPACE_API)
blendingColorSpace = GfxColorSpace::parse(&obj3, NULL, NULL);
-#elif defined(POPPLER_NEW_COLOR_SPACE_API) || defined(POPPLER_NEW_ERRORAPI)
- blendingColorSpace = GfxColorSpace::parse(&obj3, NULL);
#else
- blendingColorSpace = GfxColorSpace::parse(&obj3);
+ blendingColorSpace = GfxColorSpace::parse(&obj3, NULL);
#endif
}
obj3.free();
@@ -3394,11 +3170,7 @@ Stream *PdfParser::buildImageStream() {
parser->getObj(&obj);
while (!obj.isCmd(const_cast<char*>("ID")) && !obj.isEOF()) {
if (!obj.isName()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "Inline image dictionary key must be a name object");
-#else
- error(getPos(), const_cast<char*>("Inline image dictionary key must be a name object"));
-#endif
obj.free();
} else {
key = copyString(obj.getName());
@@ -3413,11 +3185,7 @@ Stream *PdfParser::buildImageStream() {
parser->getObj(&obj);
}
if (obj.isEOF()) {
-#ifdef POPPLER_NEW_ERRORAPI
error(errSyntaxError, getPos(), "End of file in inline image");
-#else
- error(getPos(), const_cast<char*>("End of file in inline image"));
-#endif
obj.free();
dict.free();
return NULL;
@@ -3433,20 +3201,12 @@ Stream *PdfParser::buildImageStream() {
void PdfParser::opImageData(Object /*args*/[], int /*numArgs*/)
{
-#ifdef POPPLER_NEW_ERRORAPI
error(errInternal, getPos(), "Internal: got 'ID' operator");
-#else
- error(getPos(), const_cast<char*>("Internal: got 'ID' operator"));
-#endif
}
void PdfParser::opEndImage(Object /*args*/[], int /*numArgs*/)
{
-#ifdef POPPLER_NEW_ERRORAPI
error(errInternal, getPos(), "Internal: got 'EI' operator");
-#else
- error(getPos(), const_cast<char*>("Internal: got 'EI' operator"));
-#endif
}
//------------------------------------------------------------------------
diff --git a/src/extension/internal/pdfinput/svg-builder.cpp b/src/extension/internal/pdfinput/svg-builder.cpp
index 58e2030d9..a448be639 100644
--- a/src/extension/internal/pdfinput/svg-builder.cpp
+++ b/src/extension/internal/pdfinput/svg-builder.cpp
@@ -498,6 +498,7 @@ void SvgBuilder::addShadedFill(GfxShading *shading, double *matrix, GfxPath *pat
// Obtain clipping path's id from the URL
gchar clip_path_id[32];
strncpy(clip_path_id, clip_path_url + 5, strlen(clip_path_url) - 6);
+ clip_path_id[sizeof (clip_path_id) - 1] = '\0';
SPObject *clip_obj = _doc->getObjectById(clip_path_id);
if (clip_obj) {
clip_obj->deleteObject();
diff --git a/src/extension/internal/text_reassemble.c b/src/extension/internal/text_reassemble.c
index fa983b83d..b23176ed5 100644
--- a/src/extension/internal/text_reassemble.c
+++ b/src/extension/internal/text_reassemble.c
@@ -67,11 +67,11 @@ Optional compiler switches for development:
File: text_reassemble.c
-Version: 0.0.17
-Date: 21-MAY-2015
+Version: 0.0.18
+Date: 11-MAR-2016
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
-Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
*/
#ifdef __cplusplus
@@ -223,7 +223,7 @@ char *TR_construct_fontspec(const TCHUNK_SPECS *tsp, const char *fontname){
int newlen = 128 + strlen(fontname); /* too big, but not by much */
char *newfs = NULL;
newfs = (char *) malloc(newlen);
- sprintf(newfs,"%s:slant=%d:weight=%d:size=%lf:width=%d",fontname,tsp->italics,tsp->weight,tsp->fs,(tsp->co ? 75 : tsp->condensed));
+ sprintf(newfs,"%s:slant=%d:weight=%d:size=%f:width=%d",fontname,tsp->italics,tsp->weight,tsp->fs,(tsp->co ? 75 : tsp->condensed));
return(newfs);
}
@@ -804,7 +804,7 @@ int ftinfo_load_fontname(FT_INFO *fti, const char *fontspec){
int fb;
if(FcPatternGetBool( fpat, FC_OUTLINE, 0, &fb)== FcResultMatch){ printf("outline: %d\n",fb);fflush(stdout); }
if(FcPatternGetBool( fpat, FC_SCALABLE, 0, &fb)== FcResultMatch){ printf("scalable: %d\n",fb);fflush(stdout); }
- if(FcPatternGetDouble( fpat, FC_DPI, 0, &fd)== FcResultMatch){ printf("DPI: %lf\n",fd);fflush(stdout); }
+ if(FcPatternGetDouble( fpat, FC_DPI, 0, &fd)== FcResultMatch){ printf("DPI: %f\n",fd);fflush(stdout); }
if(FcPatternGetInteger( fpat, FC_FONTVERSION, 0, &fb)== FcResultMatch){ printf("fontversion: %d\n",fb);fflush(stdout); }
if(FcPatternGetString( fpat, FC_FULLNAME , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FULLNAME : %s\n",fs);fflush(stdout); }
if(FcPatternGetString( fpat, FC_FAMILY , 0, (FcChar8 **)&fs)== FcResultMatch){ printf("FAMILY : %s\n",fs);fflush(stdout); }
@@ -831,7 +831,7 @@ void ftinfo_dump(const FT_INFO *fti){
printf("fti used: %d\n",fti->used);
for(i=0; i< fti->used; i++){
fsp = &(fti->fonts[i]);
- printf("fti font: %6d space: %6d used: %6d spcadv %8lf fsize %8lf \n",i,fsp->space,fsp->used,fsp->spcadv,fsp->fsize);
+ printf("fti font: %6d space: %6d used: %6d spcadv %8f fsize %8f \n",i,fsp->space,fsp->used,fsp->spcadv,fsp->fsize);
printf(" file: %s\n",fsp->file);
printf(" fspc: %s\n",fsp->fontspec);
for(j=0;j<fsp->used;j++){
@@ -1123,18 +1123,18 @@ void cxinfo_dump(const TR_INFO *tri){
printf("cxi phase1: %d\n",cxi->phase1);
printf("cxi lines: %d\n",cxi->lines);
printf("cxi paras: %d\n",cxi->paras);
- printf("cxi xy: %lf , %lf\n",tri->x,tri->y);
+ printf("cxi xy: %f , %f\n",tri->x,tri->y);
for(i=0;i<cxi->used;i++){
csp = &(cxi->cx[i]);
bsp = &(bri->rects[csp->rt_cidx]);
printf("cxi cx[%d] type:%d rt_tidx:%d kids_used:%d kids_space:%d\n",i, csp->type, csp->rt_cidx, csp->kids.used, csp->kids.space);
- printf("cxi cx[%d] br (LL,UR) (%lf,%lf),(%lf,%lf)\n",i,bsp->xll,bsp->yll,bsp->xur,bsp->yur);
+ printf("cxi cx[%d] br (LL,UR) (%f,%f),(%f,%f)\n",i,bsp->xll,bsp->yll,bsp->xur,bsp->yur);
for(j=0;j<csp->kids.used;j++){
k = csp->kids.members[j];
bsp = &(bri->rects[k]);
if(csp->type == TR_TEXT || csp->type == TR_LINE){
- printf("cxi cx[%d] member:%3d tp_idx:%3d ldir:%d rt_tidx:%3d br (LL,UR) (%8.3lf,%8.3lf),(%8.3lf,%8.3lf) xy (%8.3lf,%8.3lf) kern (%8.3lf,%8.3lf) text:<%s> decor:%5.5x\n",
+ printf("cxi cx[%d] member:%3d tp_idx:%3d ldir:%d rt_tidx:%3d br (LL,UR) (%8.3f,%8.3f),(%8.3f,%8.3f) xy (%8.3f,%8.3f) kern (%8.3f,%8.3f) text:<%s> decor:%5.5x\n",
i, j, k, tpi->chunks[k].ldir, tpi->chunks[k].rt_tidx,
bsp->xll,bsp->yll,bsp->xur,bsp->yur,
tpi->chunks[k].x, tpi->chunks[k].y,
@@ -1311,7 +1311,7 @@ int brinfo_merge(BR_INFO *bri, int dst, int src){
bri->rects[dst].xur = TEREMAX(bri->rects[dst].xur, bri->rects[src].xur);
bri->rects[dst].yur = TEREMIN(bri->rects[dst].yur, bri->rects[src].yur); /* MIN because Y is positive DOWN */
/*
-printf("bri_Merge into rect:%d (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n",dst,
+printf("bri_Merge into rect:%d (LL,UR) dst:(%f,%f),(%f,%f) src:(%f,%f),(%f,%f)\n",dst,
(bri->rects[dst].xll),
(bri->rects[dst].yll),
(bri->rects[dst].xur),
@@ -1374,7 +1374,7 @@ int brinfo_overlap(const BR_INFO *bri, int dst, int src, RT_PAD *rp_dst, RT_PAD
}
}
/*
-printf("Overlap status:%d\nOverlap trects (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n",
+printf("Overlap status:%d\nOverlap trects (LL,UR) dst:(%f,%f),(%f,%f) src:(%f,%f),(%f,%f)\n",
status,
(br_dst->xll - rp_dst->left ),
(br_dst->yll - rp_dst->down ),
@@ -1384,7 +1384,7 @@ status,
(br_src->yll - rp_src->down ),
(br_src->xur + rp_src->right),
(br_src->yur + rp_src->up ));
-printf("Overlap brects (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n",
+printf("Overlap brects (LL,UR) dst:(%f,%f),(%f,%f) src:(%f,%f),(%f,%f)\n",
(br_dst->xll),
(br_dst->yll),
(br_dst->xur),
@@ -1393,7 +1393,7 @@ printf("Overlap brects (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n
(br_src->yll),
(br_src->xur),
(br_src->yur));
-printf("Overlap rprect (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n",
+printf("Overlap rprect (LL,UR) dst:(%f,%f),(%f,%f) src:(%f,%f),(%f,%f)\n",
(rp_dst->left),
(rp_dst->down),
(rp_dst->right),
@@ -1481,7 +1481,7 @@ enum tr_classes brinfo_pp_alignment(const BR_INFO *bri, int dst, int src, double
newtype = TR_PARA_UJ;
}
/*
-printf("pp_align newtype:%d brects (LL,UR) dst:(%lf,%lf),(%lf,%lf) src:(%lf,%lf),(%lf,%lf)\n",
+printf("pp_align newtype:%d brects (LL,UR) dst:(%f,%f),(%f,%f) src:(%f,%f),(%f,%f)\n",
newtype,
(br_dst->xll),
(br_dst->yll),
@@ -1779,7 +1779,7 @@ int trinfo_load_textrec(TR_INFO *tri, const TCHUNK_SPECS *tsp, double escapement
tpi->chunks[current].y = x * sin(escapement) + y * cos(escapement);
/* Careful! face bbox does NOT scale with FT_Set_Char_Size
-printf("Face idx:%d bbox: xMax/Min:%ld,%ld yMax/Min:%ld,%ld UpEM:%d asc/des:%d,%d height:%d size:%lf\n",
+printf("Face idx:%d bbox: xMax/Min:%ld,%ld yMax/Min:%ld,%ld UpEM:%d asc/des:%d,%d height:%d size:%f\n",
idx,
fsp->face->bbox.xMax,fsp->face->bbox.xMin,
fsp->face->bbox.yMax,fsp->face->bbox.yMin,
@@ -1955,7 +1955,7 @@ void TR_layout_2_svg(TR_INFO *tri){
/* put rectangles down for each text string - debugging!!! This will not work properly for any Narrow fonts */
esc = tri->esc;
esc *= 2.0 * M_PI / 360.0; /* degrees to radians and change direction of rotation */
- sprintf(stransform,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc), 1.25*x,1.25*y);
+ sprintf(stransform,"transform=\"matrix(%f,%f,%f,%f,%f,%f)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc), 1.25*x,1.25*y);
for(i=cxi->phase1; i<cxi->used;i++){ /* over all complex members from phase2 == TR_PARA_* complexes */
csp = &(cxi->cx[i]);
for(j=0; j<csp->kids.used; j++){ /* over all members of these complexes, which are phase1 complexes */
@@ -1968,11 +1968,11 @@ void TR_layout_2_svg(TR_INFO *tri){
#if DBG_TR_PARA
TRPRINT(tri, "<rect\n");
TRPRINT(tri, "style=\"color:#0000FF;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:none;stroke:#000000;stroke-width:0.8;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n");
- sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[csp->rt_cidx].xur - bri->rects[csp->rt_cidx].xll));
+ sprintf(obuf,"width=\"%f\"\n", 1.25*(bri->rects[csp->rt_cidx].xur - bri->rects[csp->rt_cidx].xll));
TRPRINT(tri, obuf);
- sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].yll - bri->rects[csp->rt_cidx].yur));
+ sprintf(obuf,"height=\"%f\"\n",1.25*(bri->rects[csp->rt_cidx].yll - bri->rects[csp->rt_cidx].yur));
TRPRINT(tri, obuf);
- sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].xll),1.25*(bri->rects[csp->rt_cidx].yur));
+ sprintf(obuf,"x=\"%f\" y=\"%f\"\n",1.25*(bri->rects[csp->rt_cidx].xll),1.25*(bri->rects[csp->rt_cidx].yur));
TRPRINT(tri, obuf);
TRPRINT(tri, stransform);
TRPRINT(tri, "/>\n");
@@ -1983,23 +1983,23 @@ void TR_layout_2_svg(TR_INFO *tri){
newy = 1.25*(bri->rects[tsp->rt_tidx].yur);
TRPRINT(tri, "<rect\n");
TRPRINT(tri, "style=\"color:#000000;color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:none;stroke:#00FF00;stroke-width:0.3;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n");
- sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[tsp->rt_tidx].xur - bri->rects[tsp->rt_tidx].xll));
+ sprintf(obuf,"width=\"%f\"\n", 1.25*(bri->rects[tsp->rt_tidx].xur - bri->rects[tsp->rt_tidx].xll));
TRPRINT(tri, obuf);
- sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[tsp->rt_tidx].yll - bri->rects[tsp->rt_tidx].yur));
+ sprintf(obuf,"height=\"%f\"\n",1.25*(bri->rects[tsp->rt_tidx].yll - bri->rects[tsp->rt_tidx].yur));
TRPRINT(tri, obuf);
- sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[tsp->rt_tidx].xll),newy);
+ sprintf(obuf,"x=\"%f\" y=\"%f\"\n",1.25*(bri->rects[tsp->rt_tidx].xll),newy);
TRPRINT(tri, obuf);
TRPRINT(tri, stransform);
TRPRINT(tri, "/>\n");
newy = 1.25*(bri->rects[tsp->rt_tidx].yll - tsp->boff);
- sprintf(obuf,"<text x=\"%lf\" y=\"%lf\"\n",newx, newy );
+ sprintf(obuf,"<text x=\"%f\" y=\"%f\"\n",newx, newy );
TRPRINT(tri, obuf);
sprintf(obuf,"xml:space=\"preserve\"\n");
TRPRINT(tri, obuf);
TRPRINT(tri, stransform);
TRPRINT(tri, "style=\"fill:#FF0000;");
- sprintf(obuf,"font-size:%lfpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/
+ sprintf(obuf,"font-size:%fpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/
TRPRINT(tri, obuf);
sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal"));
TRPRINT(tri, obuf);
@@ -2025,7 +2025,7 @@ void TR_layout_2_svg(TR_INFO *tri){
if(tri->usebk){
esc = tri->esc;
esc *= 2.0 * M_PI / 360.0; /* degrees to radians and change direction of rotation */
- sprintf(stransform,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc), 1.25*x,1.25*y);
+ sprintf(stransform,"transform=\"matrix(%f,%f,%f,%f,%f,%f)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc), 1.25*x,1.25*y);
for(i=cxi->phase1; i<cxi->used;i++){ /* over all complex members from phase2 == TR_PARA_* complexes */
TRPRINT(tri, "<g>\n"); /* group backgrounds for each <text> object in the SVG */
@@ -2037,11 +2037,11 @@ void TR_layout_2_svg(TR_INFO *tri){
TRPRINT(tri, "<rect\n");
sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue);
TRPRINT(tri, obuf);
- sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[cline_sp->rt_cidx].xur - bri->rects[cline_sp->rt_cidx].xll));
+ sprintf(obuf,"width=\"%f\"\n", 1.25*(bri->rects[cline_sp->rt_cidx].xur - bri->rects[cline_sp->rt_cidx].xll));
TRPRINT(tri, obuf);
- sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[cline_sp->rt_cidx].yll - bri->rects[cline_sp->rt_cidx].yur));
+ sprintf(obuf,"height=\"%f\"\n",1.25*(bri->rects[cline_sp->rt_cidx].yll - bri->rects[cline_sp->rt_cidx].yur));
TRPRINT(tri, obuf);
- sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[cline_sp->rt_cidx].xll),1.25*(bri->rects[cline_sp->rt_cidx].yur));
+ sprintf(obuf,"x=\"%f\" y=\"%f\"\n",1.25*(bri->rects[cline_sp->rt_cidx].xll),1.25*(bri->rects[cline_sp->rt_cidx].yur));
TRPRINT(tri, obuf);
TRPRINT(tri, stransform);
TRPRINT(tri, "/>\n");
@@ -2056,11 +2056,11 @@ void TR_layout_2_svg(TR_INFO *tri){
TRPRINT(tri, "<rect\n");
sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue);
TRPRINT(tri, obuf);
- sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[csp->rt_cidx].xur - bri->rects[csp->rt_cidx].xll));
+ sprintf(obuf,"width=\"%f\"\n", 1.25*(bri->rects[csp->rt_cidx].xur - bri->rects[csp->rt_cidx].xll));
TRPRINT(tri, obuf);
- sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].yll - bri->rects[csp->rt_cidx].yur));
+ sprintf(obuf,"height=\"%f\"\n",1.25*(bri->rects[csp->rt_cidx].yll - bri->rects[csp->rt_cidx].yur));
TRPRINT(tri, obuf);
- sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",1.25*(bri->rects[csp->rt_cidx].xll),1.25*(bri->rects[csp->rt_cidx].yur));
+ sprintf(obuf,"x=\"%f\" y=\"%f\"\n",1.25*(bri->rects[csp->rt_cidx].xll),1.25*(bri->rects[csp->rt_cidx].yur));
TRPRINT(tri, obuf);
TRPRINT(tri, stransform);
TRPRINT(tri, "/>\n");
@@ -2072,11 +2072,11 @@ void TR_layout_2_svg(TR_INFO *tri){
TRPRINT(tri, "<rect\n");
sprintf(obuf,"style=\"color-interpolation:sRGB;color-interpolation-filters:linearRGB;fill:#%2.2X%2.2X%2.2X;;stroke:none;;stroke-dasharray:none;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;clip-rule:nonzero\"\n",tri->bkcolor.Red,tri->bkcolor.Green,tri->bkcolor.Blue);
TRPRINT(tri, obuf);
- sprintf(obuf,"width=\"%lf\"\n", 1.25*(bri->rects[tsp->rt_tidx].xur - bri->rects[tsp->rt_tidx].xll));
+ sprintf(obuf,"width=\"%f\"\n", 1.25*(bri->rects[tsp->rt_tidx].xur - bri->rects[tsp->rt_tidx].xll));
TRPRINT(tri, obuf);
- sprintf(obuf,"height=\"%lf\"\n",1.25*(bri->rects[tsp->rt_tidx].yll - bri->rects[tsp->rt_tidx].yur));
+ sprintf(obuf,"height=\"%f\"\n",1.25*(bri->rects[tsp->rt_tidx].yll - bri->rects[tsp->rt_tidx].yur));
TRPRINT(tri, obuf);
- sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n",newx,newy);
+ sprintf(obuf,"x=\"%f\" y=\"%f\"\n",newx,newy);
TRPRINT(tri, obuf);
TRPRINT(tri, stransform);
TRPRINT(tri, "/>\n");
@@ -2135,7 +2135,7 @@ void TR_layout_2_svg(TR_INFO *tri){
TRPRINT(tri, "<text\n");
TRPRINT(tri, "xml:space=\"preserve\"\n");
TRPRINT(tri, "style=\"");
- sprintf(obuf,"font-size:%lfpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/
+ sprintf(obuf,"font-size:%fpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/
TRPRINT(tri, obuf);
sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal"));
TRPRINT(tri, obuf);
@@ -2146,7 +2146,7 @@ void TR_layout_2_svg(TR_INFO *tri){
TRPRINT(tri, obuf);
if(tsp->vadvance){ lineheight = tsp->vadvance *100.0; }
else { lineheight = 125.0; }
- sprintf(obuf,"line-height:%lf%%;",lineheight);
+ sprintf(obuf,"line-height:%f%%;",lineheight);
TRPRINT(tri, obuf);
TRPRINT(tri, "letter-spacing:0px;");
TRPRINT(tri, "word-spacing:0px;");
@@ -2174,14 +2174,14 @@ void TR_layout_2_svg(TR_INFO *tri){
}
TRPRINT(tri, obuf);
TRPRINT(tri, "\"\n"); /* End of style specification */
- sprintf(obuf,"transform=\"matrix(%lf,%lf,%lf,%lf,%lf,%lf)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc),1.25*x,1.25*y);
+ sprintf(obuf,"transform=\"matrix(%f,%f,%f,%f,%f,%f)\"\n",cos(esc),-sin(esc),sin(esc),cos(esc),1.25*x,1.25*y);
TRPRINT(tri, obuf);
tmpx = 1.25*((ldir == LDIR_RL ? bri->rects[kdx].xur : bri->rects[kdx].xll) + recenter);
- sprintf(obuf,"x=\"%lf\" y=\"%lf\"\n>",tmpx,1.25*(bri->rects[kdx].yll - tsp->boff));
+ sprintf(obuf,"x=\"%f\" y=\"%f\"\n>",tmpx,1.25*(bri->rects[kdx].yll - tsp->boff));
TRPRINT(tri, obuf);
}
tmpx = 1.25*((ldir == LDIR_RL ? bri->rects[kdx].xur : bri->rects[kdx].xll) + recenter);
- sprintf(obuf,"<tspan sodipodi:role=\"line\"\nx=\"%lf\" y=\"%lf\"\n>",tmpx,1.25*(bri->rects[kdx].yll - tsp->boff));
+ sprintf(obuf,"<tspan sodipodi:role=\"line\"\nx=\"%f\" y=\"%f\"\n>",tmpx,1.25*(bri->rects[kdx].yll - tsp->boff));
TRPRINT(tri, obuf);
}
TRPRINT(tri, "<tspan\n");
@@ -2192,11 +2192,11 @@ void TR_layout_2_svg(TR_INFO *tri){
dx = 1.25 * tsp->xkern;
dy = 1.25 * tsp->ykern;
- sprintf(obuf,"dx=\"%lf\" dy=\"%lf\" ",dx, dy);
+ sprintf(obuf,"dx=\"%f\" dy=\"%f\" ",dx, dy);
TRPRINT(tri, obuf);
sprintf(obuf,"style=\"fill:#%2.2X%2.2X%2.2X;",tsp->color.Red,tsp->color.Green,tsp->color.Blue);
TRPRINT(tri, obuf);
- sprintf(obuf,"font-size:%lfpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/
+ sprintf(obuf,"font-size:%fpx;",tsp->fs*1.25); /*IMPORTANT, if the FS is given in pt it looks like crap in browsers. As if px != 1.25 pt, maybe 96 dpi not 90?*/
TRPRINT(tri, obuf);
sprintf(obuf,"font-style:%s;",(tsp->italics ? "italic" : "normal"));
TRPRINT(tri, obuf);
diff --git a/src/extension/internal/wmf-inout.cpp b/src/extension/internal/wmf-inout.cpp
index d17180d91..b8b0c73de 100644
--- a/src/extension/internal/wmf-inout.cpp
+++ b/src/extension/internal/wmf-inout.cpp
@@ -1528,6 +1528,17 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
uint16_t tbkMode = U_TRANSPARENT; // holds proposed change to bkMode, if text is involved saving these to the DC must wait until the text is written
U_COLORREF tbkColor = U_RGB(255, 255, 255); // holds proposed change to bkColor
+ // code for end user debugging
+ int wDbgRecord=0;
+ int wDbgComment=0;
+ int wDbgFinal=0;
+ char const* wDbgString = getenv( "INKSCAPE_DBG_WMF" );
+ if ( wDbgString != NULL ) {
+ if(strstr(wDbgString,"RECORD")){ wDbgRecord = 1; }
+ if(strstr(wDbgString,"COMMENT")){ wDbgComment = 1; }
+ if(strstr(wDbgString,"FINAL")){ wDbgFinal = 1; }
+ }
+
/* initialize the tsp for text reassembly */
tsp.string = NULL;
tsp.ori = 0.0; /* degrees */
@@ -1692,8 +1703,11 @@ int Wmf::myMetaFileProc(const char *contents, unsigned int length, PWMF_CALLBACK
file_status = 0;
break;
}
-// Uncomment the following to track down toxic records
-// std::cout << "record type: " << (int) iType << " name " << U_wmr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
+// At run time define environment variable INKSCAPE_DBG_WMF to include string RECORD.
+// Users may employ this to track down toxic records
+ if(wDbgRecord){
+ std::cout << "record type: " << iType << " name " << U_wmr_names(iType) << " length: " << nSize << " offset: " << off <<std::endl;
+ }
SVGOStringStream tmp_path;
SVGOStringStream tmp_str;
@@ -3034,8 +3048,11 @@ std::cout << "BEFORE DRAW"
dbg_str << "<!-- U_WMR_??? -->\n";
break;
} //end of switch
-// When testing, uncomment the following to place a comment for each processed WMR record in the SVG
-// d->outsvg += dbg_str.str().c_str();
+// At run time define environment variable INKSCAPE_DBG_WMF to include string COMMENT.
+// Users may employ this to to place a comment for each processed WMR record in the SVG
+ if(wDbgComment){
+ d->outsvg += dbg_str.str().c_str();
+ }
d->path += tmp_path.str().c_str();
if(!nSize){ // There was some problem with the processing of this record, it is not safe to continue
file_status = 0;
@@ -3043,8 +3060,11 @@ std::cout << "BEFORE DRAW"
}
} //end of while on OK
-// When testing, uncomment the following to show the final SVG derived from the WMF
-// std::cout << d->outsvg << std::endl;
+// At run time define environment variable INKSCAPE_DBG_WMF to include string FINAL
+// Users may employ this to to show the final SVG derived from the WMF
+ if(wDbgFinal){
+ std::cout << d->outsvg << std::endl;
+ }
(void) U_wmr_properties(U_WMR_INVALID); // force the release of the lookup table memory, returned value is irrelevant
return(file_status);
diff --git a/src/extension/internal/wmf-print.cpp b/src/extension/internal/wmf-print.cpp
index 431053085..3d913bf1e 100644
--- a/src/extension/internal/wmf-print.cpp
+++ b/src/extension/internal/wmf-print.cpp
@@ -1325,7 +1325,7 @@ unsigned int PrintWmf::print_pathv(Geom::PathVector const &pathv, const Geom::Af
unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *text, Geom::Point const &p,
SPStyle const *const style)
{
- if (!wt) {
+ if (!wt || !text) {
return 0;
}
@@ -1369,6 +1369,9 @@ unsigned int PrintWmf::text(Inkscape::Extension::Print * /*mod*/, char const *te
char *latin1_text = U_Utf16leToLatin1(unicode_text, 0, NULL);
free(unicode_text);
+ // in some cases a UTF string may reduce to NO latin1 characters, which returns NULL
+ if(!latin1_text){ return 0; }
+
//PPT gets funky with text within +-1 degree of a multiple of 90, but only for SOME fonts.Snap those to the central value
//Some funky ones: Arial, Times New Roman
//Some not funky ones: Symbol and Verdana.
diff --git a/src/extension/param/parameter.cpp b/src/extension/param/parameter.cpp
index 8c99ee55d..10029893f 100644
--- a/src/extension/param/parameter.cpp
+++ b/src/extension/param/parameter.cpp
@@ -15,22 +15,19 @@
# include "config.h"
#endif
-#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
-#include <glibmm/threads.h>
-#endif
-
#ifdef linux // does the dollar sign need escaping when passed as string parameter?
# define ESCAPE_DOLLAR_COMMANDLINE
#endif
#include <cstring>
+
+#include "ui/widget/color-notebook.h"
#include <xml/node.h>
#include <extension/extension.h>
#include "document-private.h"
#include "sp-object.h"
#include <color.h>
-#include "ui/widget/color-notebook.h"
#include "parameter.h"
#include "bool.h"
diff --git a/src/extension/param/string.cpp b/src/extension/param/string.cpp
index 4e525ff73..1d9205502 100644
--- a/src/extension/param/string.cpp
+++ b/src/extension/param/string.cpp
@@ -132,7 +132,7 @@ public:
if (_pref->get(NULL, NULL) != NULL) {
this->set_text(Glib::ustring(_pref->get(NULL, NULL)));
}
- this->set_max_length(_pref->getMaxLength()); //Set the max lenght - default zero means no maximum
+ this->set_max_length(_pref->getMaxLength()); //Set the max length - default zero means no maximum
this->signal_changed().connect(sigc::mem_fun(this, &ParamStringEntry::changed_text));
};
void changed_text (void);
diff --git a/src/file.cpp b/src/file.cpp
index 984bf7e08..9d390908e 100644
--- a/src/file.cpp
+++ b/src/file.cpp
@@ -142,7 +142,9 @@ SPDesktop *sp_file_new(const std::string &templ)
}
// Set viewBox if it doesn't exist
- if (!doc->getRoot()->viewBox_set) {
+ if (!doc->getRoot()->viewBox_set
+ && (doc->getRoot()->width.unit != SVGLength::PERCENT)
+ && (doc->getRoot()->height.unit != SVGLength::PERCENT)) {
DocumentUndo::setUndoSensitive(doc, false);
doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDisplayUnit()), doc->getHeight().value(doc->getDisplayUnit())));
DocumentUndo::setUndoSensitive(doc, true);
@@ -289,7 +291,9 @@ bool sp_file_open(const Glib::ustring &uri,
if (doc) {
// Set viewBox if it doesn't exist
- if (!doc->getRoot()->viewBox_set) {
+ if (!doc->getRoot()->viewBox_set
+ && (doc->getRoot()->width.unit != SVGLength::PERCENT)
+ && (doc->getRoot()->height.unit != SVGLength::PERCENT)) {
DocumentUndo::setUndoSensitive(doc, false);
doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDisplayUnit()), doc->getHeight().value(doc->getDisplayUnit())));
DocumentUndo::setUndoSensitive(doc, true);
@@ -1068,6 +1072,7 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place)
// copy definitions
desktop->doc()->importDefs(clipdoc);
+ Inkscape::XML::Node* clipboard = NULL;
// copy objects
std::vector<Inkscape::XML::Node*> pasted_objects;
for (Inkscape::XML::Node *obj = root->firstChild() ; obj ; obj = obj->next()) {
@@ -1082,6 +1087,7 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place)
continue;
}
if (!strcmp(obj->name(), "inkscape:clipboard")) {
+ clipboard = obj;
continue;
}
Inkscape::XML::Node *obj_copy = obj->duplicate(target_document->getReprDoc());
@@ -1090,12 +1096,32 @@ void sp_import_document(SPDesktop *desktop, SPDocument *clipdoc, bool in_place)
pasted_objects.push_back(obj_copy);
}
- // Change the selection to the freshly pasted objects
+
+ /* take that stuff into account:
+ * if( use && selection->includes(use->get_original()) ){//we are copying something whose parent is also copied (!)
+ * transform = ((SPItem*)(use->get_original()->parent))->i2doc_affine().inverse() * transform;
+ * }
+ *
+ */
+ std::vector<Inkscape::XML::Node*> pasted_objects_not;
+ if(clipboard)
+ for (Inkscape::XML::Node *obj = clipboard->firstChild() ; obj ; obj = obj->next()) {
+ if(target_document->getObjectById(obj->attribute("id"))) continue;
+ Inkscape::XML::Node *obj_copy = obj->duplicate(target_document->getReprDoc());
+ target_parent->appendChild(obj_copy);
+ Inkscape::GC::release(obj_copy);
+ pasted_objects_not.push_back(obj_copy);
+ }
Inkscape::Selection *selection = desktop->getSelection();
+ selection->setReprList(pasted_objects_not);
+ Geom::Affine doc2parent = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ sp_selection_apply_affine(selection, desktop->dt2doc() * doc2parent * desktop->doc2dt(), true, false, false);
+ sp_selection_delete(desktop);
+
+ // Change the selection to the freshly pasted objects
selection->setReprList(pasted_objects);
// Apply inverse of parent transform
- Geom::Affine doc2parent = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
sp_selection_apply_affine(selection, desktop->dt2doc() * doc2parent * desktop->doc2dt(), true, false, false);
// Update (among other things) all curves in paths, for bounds() to work
diff --git a/src/gradient-chemistry.cpp b/src/gradient-chemistry.cpp
index 409e9f0e6..7b4c0ac20 100644
--- a/src/gradient-chemistry.cpp
+++ b/src/gradient-chemistry.cpp
@@ -379,7 +379,7 @@ SPGradient *sp_gradient_reset_to_userspace(SPGradient *gr, SPItem *item)
if (angle != 0.0) {
- Geom::Line grl(center, Geom::deg_to_rad(angle));
+ Geom::Line grl(center, Geom::rad_from_deg(angle));
Geom::LineSegment bbl1(bbox->corner(0), bbox->corner(1));
Geom::LineSegment bbl2(bbox->corner(1), bbox->corner(2));
Geom::LineSegment bbl3(bbox->corner(2), bbox->corner(3));
@@ -1571,7 +1571,7 @@ void sp_gradient_invert_selected_gradients(SPDesktop *desktop, Inkscape::PaintTa
Inkscape::Selection *selection = desktop->getSelection();
const std::vector<SPItem*> list=selection->itemList();
- for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); ++i) {
sp_item_gradient_invert_vector_color(*i, fill_or_stroke);
}
@@ -1592,11 +1592,11 @@ void sp_gradient_reverse_selected_gradients(SPDesktop *desktop)
GrDrag *drag = ev->get_drag();
// First try selected dragger
- if (drag && drag->selected) {
+ if (drag && !drag->selected.empty()) {
drag->selected_reverse_vector();
} else { // If no drag or no dragger selected, act on selection (both fill and stroke gradients)
const std::vector<SPItem*> list=selection->itemList();
- for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); ++i) {
sp_item_gradient_reverse_vector(*i, Inkscape::FOR_FILL);
sp_item_gradient_reverse_vector(*i, Inkscape::FOR_STROKE);
}
@@ -1612,9 +1612,9 @@ void sp_gradient_unset_swatch(SPDesktop *desktop, std::string id)
SPDocument *doc = desktop ? desktop->doc() : 0;
if (doc) {
- const GSList *gradients = doc->getResourceList("gradient");
- for (const GSList *item = gradients; item; item = item->next) {
- SPGradient* grad = SP_GRADIENT(item->data);
+ const std::set<SPObject *> gradients = doc->getResourceList("gradient");
+ for (std::set<SPObject *>::const_iterator i = gradients.begin(); i != gradients.end(); ++i) {
+ SPGradient* grad = SP_GRADIENT(*i);
if ( id == grad->getId() ) {
grad->setSwatch(false);
DocumentUndo::done(doc, SP_VERB_CONTEXT_GRADIENT,
diff --git a/src/gradient-drag.cpp b/src/gradient-drag.cpp
index b5a988729..8fd997121 100644
--- a/src/gradient-drag.cpp
+++ b/src/gradient-drag.cpp
@@ -142,7 +142,7 @@ static int gr_drag_style_query(SPStyle *style, int property, gpointer data)
return QUERY_STYLE_NOTHING;
}
- if (!drag->selected) {
+ if (drag->selected.empty()) {
return QUERY_STYLE_NOTHING;
} else {
int ret = QUERY_STYLE_NOTHING;
@@ -151,11 +151,10 @@ static int gr_drag_style_query(SPStyle *style, int property, gpointer data)
cf[0] = cf[1] = cf[2] = cf[3] = 0;
int count = 0;
-
- for (GList *i = drag->selected; i != NULL; i = i->next) { // for all selected draggers
- GrDragger *d = (GrDragger *) i->data;
- for (GSList const* j = d->draggables; j != NULL; j = j->next) { // for all draggables of dragger
- GrDraggable *draggable = (GrDraggable *) j->data;
+ for(std::set<GrDragger *>::const_iterator it = drag->selected.begin(); it != drag->selected.end(); ++it) { //for all selected draggers
+ GrDragger *d = *it;
+ for(std::vector<GrDraggable *>::const_iterator it2 = d->draggables.begin(); it2 != d->draggables.end(); ++it2 ) { //for all draggables of dragger
+ GrDraggable *draggable = *it2;
if (ret == QUERY_STYLE_NOTHING) {
ret = QUERY_STYLE_SINGLE;
@@ -209,9 +208,9 @@ Glib::ustring GrDrag::makeStopSafeColor( gchar const *str, bool &isNull )
Glib::ustring::size_type pos = colorStr.find("url(#");
if ( pos != Glib::ustring::npos ) {
Glib::ustring targetName = colorStr.substr(pos + 5, colorStr.length() - 6);
- const GSList *gradients = desktop->doc()->getResourceList("gradient");
- for (const GSList *item = gradients; item; item = item->next) {
- SPGradient* grad = SP_GRADIENT(item->data);
+ std::set<SPObject *> gradients = desktop->doc()->getResourceList("gradient");
+ for (std::set<SPObject *>::const_iterator it = gradients.begin(); it != gradients.end(); ++it) {
+ SPGradient* grad = SP_GRADIENT(*it);
if ( targetName == grad->getId() ) {
SPGradient *vect = grad->getVector();
SPStop *firstStop = (vect) ? vect->getFirstStop() : grad->getFirstStop();
@@ -239,7 +238,7 @@ Glib::ustring GrDrag::makeStopSafeColor( gchar const *str, bool &isNull )
bool GrDrag::styleSet( const SPCSSAttr *css )
{
- if (!selected) {
+ if (selected.empty()) {
return false;
}
@@ -307,11 +306,10 @@ bool GrDrag::styleSet( const SPCSSAttr *css )
return false;
}
- for (GList const* sel = selected; sel != NULL; sel = sel->next) { // for all selected draggers
- GrDragger* dragger = reinterpret_cast<GrDragger*>(sel->data);
- for (GSList const* i = dragger->draggables; i != NULL; i = i->next) { // for all draggables of dragger
- GrDraggable *draggable = reinterpret_cast<GrDraggable *>(i->data);
-
+ for(std::set<GrDragger *>::const_iterator it = selected.begin(); it != selected.end(); ++it) { //for all selected draggers
+ GrDragger *d = *it;
+ for(std::vector<GrDraggable *>::const_iterator it2 = d->draggables.begin(); it2 != d->draggables.end(); ++it2 ) { //for all draggables of dragger
+ GrDraggable *draggable = *it2;
local_change = true;
sp_item_gradient_stop_set_style(draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke, stop);
}
@@ -324,17 +322,17 @@ bool GrDrag::styleSet( const SPCSSAttr *css )
guint32 GrDrag::getColor()
{
- if (!selected) return 0;
+ if (selected.empty()) return 0;
float cf[4];
cf[0] = cf[1] = cf[2] = cf[3] = 0;
int count = 0;
- for (GList *i = selected; i != NULL; i = i->next) { // for all selected draggers
- GrDragger *d = (GrDragger *) i->data;
- for (GSList const* j = d->draggables; j != NULL; j = j->next) { // for all draggables of dragger
- GrDraggable *draggable = (GrDraggable *) j->data;
+ for(std::set<GrDragger *>::const_iterator it = selected.begin(); it != selected.end(); ++it) { //for all selected draggers
+ GrDragger *d = *it;
+ for(std::vector<GrDraggable *>::const_iterator it2 = d->draggables.begin(); it2 != d->draggables.end(); ++it2 ) { //for all draggables of dragger
+ GrDraggable *draggable = *it2;
guint32 c = sp_item_gradient_stop_query_style (draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke);
cf[0] += SP_RGBA32_R_F (c);
@@ -580,15 +578,15 @@ bool GrDrag::dropColor(SPItem */*item*/, gchar const *c, Geom::Point p)
Glib::ustring toUse = makeStopSafeColor( c, stopIsNull );
// first, see if we can drop onto one of the existing draggers
- for (GList *i = draggers; i != NULL; i = i->next) { // for all draggables of dragger
- GrDragger *d = (GrDragger *) i->data;
+ for(std::vector<GrDragger *>::const_iterator i = draggers.begin(); i != draggers.end(); ++i) { //for all draggers
+ GrDragger *d = *i ;
if (Geom::L2(p - d->point)*desktop->current_zoom() < 5) {
SPCSSAttr *stop = sp_repr_css_attr_new ();
sp_repr_css_set_property( stop, "stop-color", stopIsNull ? 0 : toUse.c_str() );
sp_repr_css_set_property( stop, "stop-opacity", "1" );
- for (GSList *j = d->draggables; j != NULL; j = j->next) { // for all draggables of dragger
- GrDraggable *draggable = (GrDraggable *) j->data;
+ for(std::vector<GrDraggable *>::const_iterator j = d->draggables.begin(); j != d->draggables.end(); ++j) { //for all draggables of dragger
+ GrDraggable *draggable = *j;
local_change = true;
sp_item_gradient_stop_set_style (draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke, stop);
}
@@ -599,9 +597,9 @@ bool GrDrag::dropColor(SPItem */*item*/, gchar const *c, Geom::Point p)
// now see if we're over line and create a new stop
bool over_line = false;
- if (lines) {
- for (GSList *l = lines; (l != NULL) && (!over_line); l = l->next) {
- SPCtrlLine *line = (SPCtrlLine*) l->data;
+ if (!lines.empty()) {
+ for (std::vector<SPCtrlLine *>::const_iterator l = lines.begin(); l != lines.end() && (!over_line); ++l) {
+ SPCtrlLine *line = *l;
Geom::LineSegment ls(line->s, line->e);
Geom::Point nearest = ls.pointAt(ls.nearestTime(p));
double dist_screen = Geom::L2(p - nearest) * desktop->current_zoom();
@@ -623,7 +621,6 @@ bool GrDrag::dropColor(SPItem */*item*/, gchar const *c, Geom::Point p)
GrDrag::GrDrag(SPDesktop *desktop) :
- selected(0),
keep_selection(false),
local_change(false),
desktop(desktop),
@@ -676,8 +673,8 @@ GrDrag::~GrDrag()
this->style_set_connection.disconnect();
this->style_query_connection.disconnect();
- if (this->selected) {
- GrDraggable *draggable = (GrDraggable *) ((GrDragger*)this->selected->data)->draggables->data;
+ if (! this->selected.empty()) {
+ GrDraggable *draggable = (*(this->selected.begin()))->draggables[0];
desktop->gr_item = draggable->item;
desktop->gr_point_type = draggable->point_type;
desktop->gr_point_i = draggable->point_i;
@@ -690,18 +687,16 @@ GrDrag::~GrDrag()
}
deselect_all();
- for (GList *l = this->draggers; l != NULL; l = l->next) {
- delete ((GrDragger *) l->data);
+ for (std::vector<GrDragger *>::const_iterator it = this->draggers.begin(); it != this->draggers.end(); ++it) {
+ delete (*it);
}
- g_list_free (this->draggers);
- this->draggers = NULL;
- this->selected = NULL;
+ this->draggers.clear();
+ this->selected.clear();
- for (GSList *l = this->lines; l != NULL; l = l->next) {
- sp_canvas_item_destroy(SP_CANVAS_ITEM(l->data));
+ for (std::vector<SPCtrlLine *>::const_iterator it = this->lines.begin(); it != this->lines.end(); ++it) {
+ sp_canvas_item_destroy(SP_CANVAS_ITEM(*it));
}
- g_slist_free (this->lines);
- this->lines = NULL;
+ this->lines.clear();
}
GrDraggable::GrDraggable(SPItem *item, GrPointType point_type, guint point_i, Inkscape::PaintTarget fill_or_stroke) :
@@ -751,39 +746,43 @@ static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, gui
if (state & GDK_SHIFT_MASK) {
// with Shift; unsnap if we carry more than one draggable
- if (dragger->draggables && dragger->draggables->next) {
+ if (dragger->draggables.size()>1) {
// create a new dragger
GrDragger *dr_new = new GrDragger (dragger->parent, dragger->point, NULL);
- dragger->parent->draggers = g_list_prepend (dragger->parent->draggers, dr_new);
+ dragger->parent->draggers.insert(dragger->parent->draggers.begin(), dr_new);
// relink to it all but the first draggable in the list
- for (GSList const* i = dragger->draggables->next; i != NULL; i = i->next) {
- GrDraggable *draggable = (GrDraggable *) i->data;
+ std::vector<GrDraggable *>::const_iterator i = dragger->draggables.begin();
+ for ( ++i ; i != dragger->draggables.end(); ++i ) {
+ GrDraggable *draggable = *i;
dr_new->addDraggable (draggable);
}
dr_new->updateKnotShape();
- g_slist_free (dragger->draggables->next);
- dragger->draggables->next = NULL;
+ if(dragger->draggables.size()>1){
+ GrDraggable *tmp = dragger->draggables[0];
+ dragger->draggables.clear();
+ dragger->draggables.push_back(tmp);
+ }
dragger->updateKnotShape();
dragger->updateTip();
}
} else if (!(state & GDK_CONTROL_MASK)) {
// without Shift or Ctrl; see if we need to snap to another dragger
- for (GList *di = dragger->parent->draggers; di != NULL; di = di->next) {
- GrDragger *d_new = (GrDragger *) di->data;
+ for (std::vector<GrDragger *>::const_iterator di = dragger->parent->draggers.begin(); di != dragger->parent->draggers.end() ; ++di) {
+ GrDragger *d_new = *di;
if (dragger->mayMerge(d_new) && Geom::L2 (d_new->point - p) < snap_dist) {
// Merge draggers:
- for (GSList const* i = dragger->draggables; i != NULL; i = i->next) { // for all draggables of dragger
- GrDraggable *draggable = (GrDraggable *) i->data;
+ for (std::vector<GrDraggable *>::const_iterator i = dragger->draggables.begin(); i != dragger->draggables.end(); ++i) {
+ GrDraggable *draggable = *i;
// copy draggable to d_new:
GrDraggable *da_new = new GrDraggable (draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke);
d_new->addDraggable (da_new);
}
// unlink and delete this dragger
- dragger->parent->draggers = g_list_remove (dragger->parent->draggers, dragger);
- d_new->parent->draggers = g_list_remove (d_new->parent->draggers, dragger);
- d_new->parent->selected = g_list_remove (d_new->parent->selected, dragger);
+ dragger->parent->draggers.erase(std::remove(dragger->parent->draggers.begin(),dragger->parent->draggers.end(), dragger),dragger->parent->draggers.end());
+ d_new->parent->draggers.erase(std::remove(d_new->parent->draggers.begin(),d_new->parent->draggers.end(), dragger),d_new->parent->draggers.end());
+ d_new->parent->selected.erase(dragger);
delete dragger;
// throw out delayed snap context
@@ -817,14 +816,14 @@ static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, gui
unsigned snaps = abs(prefs->getInt("/options/rotationsnapsperpi/value", 12));
/* 0 means no snapping. */
- for (GSList const* i = dragger->draggables; i != NULL; i = i->next) {
- GrDraggable *draggable = (GrDraggable *) i->data;
+ for (std::vector<GrDraggable *>::const_iterator i = dragger->draggables.begin(); i != dragger->draggables.end(); ++i) {
+ GrDraggable *draggable = *i;
Geom::Point dr_snap(Geom::infinity(), Geom::infinity());
if (draggable->point_type == POINT_LG_BEGIN || draggable->point_type == POINT_LG_END) {
- for (GList *di = dragger->parent->draggers; di != NULL; di = di->next) {
- GrDragger *d_new = (GrDragger *) di->data;
+ for (std::vector<GrDragger *>::const_iterator di = dragger->parent->draggers.begin() ; di != dragger->parent->draggers.end() ; ++di) {
+ GrDragger *d_new = *di;
if (d_new == dragger)
continue;
if (d_new->isA (draggable->item,
@@ -842,8 +841,8 @@ static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, gui
}
}
} else if (draggable->point_type == POINT_RG_R1 || draggable->point_type == POINT_RG_R2 || draggable->point_type == POINT_RG_FOCUS) {
- for (GList *di = dragger->parent->draggers; di != NULL; di = di->next) {
- GrDragger *d_new = (GrDragger *) di->data;
+ for (std::vector<GrDragger *>::const_iterator di = dragger->parent->draggers.begin(); di != dragger->parent->draggers.end(); ++di) {
+ GrDragger *d_new = *di;
if (d_new == dragger)
continue;
if (d_new->isA (draggable->item,
@@ -896,7 +895,7 @@ static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, gui
knot->moveto(p);
}
- drag->keep_selection = (bool) g_list_find(drag->selected, dragger);
+ drag->keep_selection = (drag->selected.find(dragger)!=drag->selected.end());
bool scale_radial = (state & GDK_CONTROL_MASK) && (state & GDK_SHIFT_MASK);
if (drag->keep_selection) {
@@ -912,16 +911,16 @@ static void gr_knot_moved_handler(SPKnot *knot, Geom::Point const &ppointer, gui
}
-static void gr_midpoint_limits(GrDragger *dragger, SPObject *server, Geom::Point *begin, Geom::Point *end, Geom::Point *low_lim, Geom::Point *high_lim, GSList **moving)
+static void gr_midpoint_limits(GrDragger *dragger, SPObject *server, Geom::Point *begin, Geom::Point *end, Geom::Point *low_lim, Geom::Point *high_lim, std::vector<GrDragger *> &moving)
{
GrDrag *drag = dragger->parent;
// a midpoint dragger can (logically) only contain one GrDraggable
- GrDraggable *draggable = (GrDraggable *) dragger->draggables->data;
+ GrDraggable *draggable = dragger->draggables[0];
// get begin and end points between which dragging is allowed:
// the draglimits are between knot(lowest_i - 1) and knot(highest_i + 1)
- *moving = g_slist_append(*moving, dragger);
+ moving.push_back(dragger);
guint lowest_i = draggable->point_i;
guint highest_i = draggable->point_i;
@@ -932,9 +931,9 @@ static void gr_midpoint_limits(GrDragger *dragger, SPObject *server, Geom::Point
while ( true )
{
d_add = drag->getDraggerFor(draggable->item, draggable->point_type, lowest_i - 1, draggable->fill_or_stroke);
- if ( d_add && g_list_find(drag->selected, d_add) ) {
+ if ( d_add && drag->selected.find(d_add)!=drag->selected.end() ) {
lowest_i = lowest_i - 1;
- *moving = g_slist_prepend(*moving, d_add);
+ moving.insert(moving.begin(),d_add);
lowest_dragger = d_add;
} else {
break;
@@ -944,9 +943,9 @@ static void gr_midpoint_limits(GrDragger *dragger, SPObject *server, Geom::Point
while ( true )
{
d_add = drag->getDraggerFor(draggable->item, draggable->point_type, highest_i + 1, draggable->fill_or_stroke);
- if ( d_add && g_list_find(drag->selected, d_add) ) {
+ if ( d_add && drag->selected.find(d_add)!=drag->selected.end() ) {
highest_i = highest_i + 1;
- *moving = g_slist_append(*moving, d_add);
+ moving.push_back(d_add);
highest_dragger = d_add;
} else {
break;
@@ -1002,7 +1001,7 @@ static void gr_knot_moved_midpoint_handler(SPKnot */*knot*/, Geom::Point const &
GrDragger *dragger = (GrDragger *) data;
GrDrag *drag = dragger->parent;
// a midpoint dragger can (logically) only contain one GrDraggable
- GrDraggable *draggable = (GrDraggable *) dragger->draggables->data;
+ GrDraggable *draggable = dragger->draggables[0];
// FIXME: take from prefs
double snap_fraction = 0.1;
@@ -1013,8 +1012,8 @@ static void gr_knot_moved_midpoint_handler(SPKnot */*knot*/, Geom::Point const &
SPObject *server = draggable->getServer();
- GSList *moving = NULL;
- gr_midpoint_limits(dragger, server, &begin, &end, &low_lim, &high_lim, &moving);
+ std::vector<GrDragger *> moving;
+ gr_midpoint_limits(dragger, server, &begin, &end, &low_lim, &high_lim, moving);
if (state & GDK_CONTROL_MASK) {
Geom::LineSegment ls(low_lim, high_lim);
@@ -1033,8 +1032,8 @@ static void gr_knot_moved_midpoint_handler(SPKnot */*knot*/, Geom::Point const &
}
Geom::Point displacement = p - dragger->point;
- for (GSList const* i = moving; i != NULL; i = i->next) {
- GrDragger *drg = (GrDragger*) i->data;
+ for (std::vector<GrDragger *>::const_iterator i = moving.begin(); i!= moving.end(); ++i ) {
+ GrDragger *drg = *i;
SPKnot *drgknot = drg->knot;
Geom::Point this_move = displacement;
if (state & GDK_MOD1_MASK) {
@@ -1054,8 +1053,6 @@ static void gr_knot_moved_midpoint_handler(SPKnot */*knot*/, Geom::Point const &
drg->updateDependencies(false);
}
- g_slist_free(moving);
-
drag->keep_selection = dragger->isSelected();
}
@@ -1085,12 +1082,11 @@ static void gr_knot_ungrabbed_handler(SPKnot *knot, unsigned int state, gpointer
dragger->fireDraggables (true);
}
dragger->updateHandles( dragger->point_original, MG_NODE_NO_SCALE );
-
- for (GList *i = dragger->parent->selected; i != NULL; i = i->next) {
- GrDragger *d = (GrDragger *) i->data;
- if (d == dragger)
+
+ for (std::set<GrDragger *>::const_iterator it = dragger->parent->selected.begin(); it != dragger->parent->selected.end() ; ++it ) {
+ if (*it == dragger)
continue;
- d->fireDraggables (true);
+ (*it)->fireDraggables (true);
}
// make this dragger selected
@@ -1112,7 +1108,7 @@ static void gr_knot_ungrabbed_handler(SPKnot *knot, unsigned int state, gpointer
static void gr_knot_clicked_handler(SPKnot */*knot*/, guint state, gpointer data)
{
GrDragger *dragger = (GrDragger *) data;
- GrDraggable *draggable = (GrDraggable *) dragger->draggables->data;
+ GrDraggable *draggable = dragger->draggables[0];
if (!draggable) return;
if ( (state & GDK_CONTROL_MASK) && (state & GDK_MOD1_MASK ) ) {
@@ -1185,7 +1181,7 @@ static void gr_knot_doubleclicked_handler(SPKnot */*knot*/, guint /*state*/, gpo
dragger->point_original = dragger->point;
- if (dragger->draggables == NULL)
+ if (dragger->draggables.empty())
return;
/*
@@ -1200,8 +1196,8 @@ static void gr_knot_doubleclicked_handler(SPKnot */*knot*/, guint /*state*/, gpo
*/
void GrDragger::fireDraggables(bool write_repr, bool scale_radial, bool merging_focus)
{
- for (GSList const* i = this->draggables; i != NULL; i = i->next) {
- GrDraggable *draggable = (GrDraggable *) i->data;
+ for (std::vector<GrDraggable *>::const_iterator i = this->draggables.begin(); i != this->draggables.end(); ++i) {
+ GrDraggable *draggable = *i;
// set local_change flag so that selection_changed callback does not regenerate draggers
this->parent->local_change = true;
@@ -1221,8 +1217,8 @@ void GrDragger::fireDraggables(bool write_repr, bool scale_radial, bool merging_
*/
bool GrDragger::isA(GrPointType point_type)
{
- for (GSList const* i = this->draggables; i != NULL; i = i->next) {
- GrDraggable *draggable = reinterpret_cast<GrDraggable *>(i->data);
+ for (std::vector<GrDraggable *>::const_iterator i = this->draggables.begin(); i != this->draggables.end(); ++i) {
+ GrDraggable *draggable = *i;
if (draggable->point_type == point_type) {
return true;
}
@@ -1235,8 +1231,8 @@ bool GrDragger::isA(GrPointType point_type)
*/
bool GrDragger::isA(SPItem *item, GrPointType point_type, gint point_i, Inkscape::PaintTarget fill_or_stroke)
{
- for (GSList const* i = this->draggables; i != NULL; i = i->next) {
- GrDraggable *draggable = (GrDraggable *) i->data;
+ for (std::vector<GrDraggable *>::const_iterator i = this->draggables.begin(); i != this->draggables.end(); ++i) {
+ GrDraggable *draggable = *i;
if ( (draggable->point_type == point_type) && (draggable->point_i == point_i) && (draggable->item == item) && (draggable->fill_or_stroke == fill_or_stroke) ) {
return true;
}
@@ -1249,8 +1245,8 @@ bool GrDragger::isA(SPItem *item, GrPointType point_type, gint point_i, Inkscape
*/
bool GrDragger::isA(SPItem *item, GrPointType point_type, Inkscape::PaintTarget fill_or_stroke)
{
- for (GSList const* i = this->draggables; i != NULL; i = i->next) {
- GrDraggable *draggable = (GrDraggable *) i->data;
+ for (std::vector<GrDraggable *>::const_iterator i = this->draggables.begin(); i != this->draggables.end(); ++i) {
+ GrDraggable *draggable = *i;
if ( (draggable->point_type == point_type) && (draggable->item == item) && (draggable->fill_or_stroke == fill_or_stroke) ) {
return true;
}
@@ -1282,10 +1278,10 @@ bool GrDragger::mayMerge(GrDragger *other)
if (this == other)
return false;
- for (GSList const* i = this->draggables; i != NULL; i = i->next) { // for all draggables of this
- GrDraggable *da1 = (GrDraggable *) i->data;
- for (GSList const* j = other->draggables; j != NULL; j = j->next) { // for all draggables of other
- GrDraggable *da2 = (GrDraggable *) j->data;
+ for (std::vector<GrDraggable *>::const_iterator i = this->draggables.begin(); i != this->draggables.end(); ++i) {
+ GrDraggable *da1 = *i;
+ for (std::vector<GrDraggable *>::const_iterator j = other->draggables.begin(); j != other->draggables.end(); ++j) {
+ GrDraggable *da2 = *j;
if (!da1->mayMerge(da2))
return false;
}
@@ -1295,8 +1291,8 @@ bool GrDragger::mayMerge(GrDragger *other)
bool GrDragger::mayMerge(GrDraggable *da2)
{
- for (GSList const* i = this->draggables; i != NULL; i = i->next) { // for all draggables of this
- GrDraggable *da1 = (GrDraggable *) i->data;
+ for (std::vector<GrDraggable *>::const_iterator i = this->draggables.begin(); i != this->draggables.end(); ++i) {
+ GrDraggable *da1 = *i;
if (!da1->mayMerge(da2))
return false;
}
@@ -1339,10 +1335,10 @@ GrDragger::updateHandles ( Geom::Point pc_old, MeshNodeOperation op )
bool scale = false;
if( scale == true ) {
- for ( GList *i = drag->selected; i != NULL; i = i->next ) {
- GrDragger *dragger = (GrDragger *) i->data;
- for ( GSList *j = dragger->draggables; j != NULL; j = j->next ) {
- GrDraggable *draggable = (GrDraggable *) j->data;
+ for( std::set<GrDragger *>::const_iterator it = drag->selected.begin(); it != drag->selected.end(); ++it ) {
+ GrDragger *dragger = *it;
+ for (std::vector<GrDraggable *>::const_iterator it2 = dragger->draggables.begin(); it2 != dragger->draggables.end(); ++it2 ) {
+ GrDraggable *draggable = *it2;
// Check draggable is of type POINT_MG_CORNER (don't allow selection of POINT_MG_HANDLE)
if( draggable->point_type != POINT_MG_CORNER ) continue;
@@ -1360,8 +1356,8 @@ GrDragger::updateHandles ( Geom::Point pc_old, MeshNodeOperation op )
// Loop over all draggables in moved corner
std::map<SPGradient*, std::vector<guint> > dragger_corners;
- for ( GSList *j = draggables; j != NULL; j = j->next ) {
- GrDraggable *draggable = (GrDraggable *) j->data;
+ for (std::vector<GrDraggable *>::const_iterator j = draggables.begin(); j != draggables.end(); ++j ) {
+ GrDraggable *draggable = *j;
SPItem *item = draggable->item;
gint point_type = draggable->point_type;
@@ -1417,8 +1413,8 @@ void GrDragger::updateTip()
this->knot->tip = NULL;
}
- if (g_slist_length (this->draggables) == 1) {
- GrDraggable *draggable = (GrDraggable *) this->draggables->data;
+ if (this->draggables.size() == 1) {
+ GrDraggable *draggable = this->draggables[0];
char *item_desc = draggable->item->detailedDescription();
switch (draggable->point_type) {
case POINT_LG_MID:
@@ -1439,10 +1435,10 @@ void GrDragger::updateTip()
break;
}
g_free(item_desc);
- } else if (g_slist_length (draggables) == 2 && isA (POINT_RG_CENTER) && isA (POINT_RG_FOCUS)) {
+ } else if (draggables.size() == 2 && isA (POINT_RG_CENTER) && isA (POINT_RG_FOCUS)) {
this->knot->tip = g_strdup_printf ("%s", _("Radial gradient <b>center</b> and <b>focus</b>; drag with <b>Shift</b> to separate focus"));
} else {
- int length = g_slist_length (this->draggables);
+ int length = this->draggables.size();
this->knot->tip = g_strdup_printf (ngettext("Gradient point shared by <b>%d</b> gradient; drag with <b>Shift</b> to separate",
"Gradient point shared by <b>%d</b> gradients; drag with <b>Shift</b> to separate",
length),
@@ -1455,9 +1451,9 @@ void GrDragger::updateTip()
*/
void GrDragger::updateKnotShape()
{
- if (!draggables)
+ if (draggables.empty())
return;
- GrDraggable *last = (GrDraggable *) g_slist_last(draggables)->data;
+ GrDraggable *last = draggables.back();
g_object_set (G_OBJECT (this->knot->item), "shape", gr_knot_shapes[last->point_type], NULL);
}
@@ -1466,7 +1462,7 @@ void GrDragger::updateKnotShape()
*/
void GrDragger::addDraggable(GrDraggable *draggable)
{
- this->draggables = g_slist_prepend (this->draggables, draggable);
+ this->draggables.insert(this->draggables.begin(), draggable);
this->updateTip();
}
@@ -1477,18 +1473,18 @@ void GrDragger::addDraggable(GrDraggable *draggable)
*/
void GrDragger::moveThisToDraggable(SPItem *item, GrPointType point_type, gint point_i, Inkscape::PaintTarget fill_or_stroke, bool write_repr)
{
- GrDraggable *dr_first = reinterpret_cast<GrDraggable *>(draggables->data);
- if (!dr_first) {
+ if (draggables.empty())
return;
- }
+
+ GrDraggable *dr_first = draggables[0];
this->point = getGradientCoords(dr_first->item, dr_first->point_type, dr_first->point_i, dr_first->fill_or_stroke);
this->point_original = this->point;
this->knot->moveto(this->point);
- for (GSList const* i = draggables; i != NULL; i = i->next) {
- GrDraggable *da = (GrDraggable *) i->data;
+ for (std::vector<GrDraggable *>::const_iterator j = draggables.begin(); j != draggables.end(); ++j ) {
+ GrDraggable *da = *j;
if ( (da->item == item) &&
(point_type == -1 || da->point_type == point_type) &&
(point_i == -1 || da->point_i == point_i) &&
@@ -1531,8 +1527,8 @@ void GrDragger::updateMidstopDependencies(GrDraggable *draggable, bool write_rep
*/
void GrDragger::updateDependencies(bool write_repr)
{
- for (GSList const* i = this->draggables; i != NULL; i = i->next) {
- GrDraggable *draggable = (GrDraggable *) i->data;
+ for (std::vector<GrDraggable *>::const_iterator j = draggables.begin(); j != draggables.end(); ++j ) {
+ GrDraggable *draggable = *j;
switch (draggable->point_type) {
case POINT_LG_BEGIN:
{
@@ -1590,7 +1586,7 @@ GrDragger::GrDragger(GrDrag *parent, Geom::Point p, GrDraggable *draggable)
: point(p),
point_original(p)
{
- this->draggables = NULL;
+ this->draggables.clear();
this->parent = parent;
@@ -1649,12 +1645,10 @@ GrDragger::~GrDragger()
knot_unref(this->knot);
// delete all draggables
- for (GSList const* i = this->draggables; i != NULL; i = i->next) {
- delete ((GrDraggable *) i->data);
+ for (std::vector<GrDraggable *>::const_iterator j = this->draggables.begin(); j != this->draggables.end(); ++j ) {
+ delete (*j);
}
-
- g_slist_free (this->draggables);
- this->draggables = NULL;
+ this->draggables.clear();
}
/**
@@ -1662,10 +1656,10 @@ GrDragger::~GrDragger()
*/
GrDragger *GrDrag::getDraggerFor(SPItem *item, GrPointType point_type, gint point_i, Inkscape::PaintTarget fill_or_stroke)
{
- for (GList const* i = this->draggers; i != NULL; i = i->next) {
- GrDragger *dragger = (GrDragger *) i->data;
- for (GSList const* j = dragger->draggables; j != NULL; j = j->next) {
- GrDraggable *da2 = (GrDraggable *) j->data;
+ for (std::vector<GrDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i ) {
+ GrDragger *dragger = *i;
+ for (std::vector<GrDraggable *>::const_iterator j = dragger->draggables.begin(); j != dragger->draggables.end(); ++j ) {
+ GrDraggable *da2 = *j;
if ( (da2->item == item) &&
(point_type == -1 || da2->point_type == point_type) && // -1 means this does not matter
(point_i == -1 || da2->point_i == point_i) && // -1 means this does not matter
@@ -1716,7 +1710,7 @@ void GrDragger::deselect()
bool
GrDragger::isSelected()
{
- return g_list_find (parent->selected, this);
+ return parent->selected.find(this) != parent->selected.end();
}
/**
@@ -1724,10 +1718,9 @@ GrDragger::isSelected()
*/
void GrDrag::deselect_all()
{
- while (selected) {
- ( (GrDragger*) selected->data)->deselect();
- selected = g_list_remove(selected, selected->data);
- }
+ for (std::set<GrDragger *>::const_iterator it = selected.begin(); it != selected.end(); ++it )
+ (*it)->deselect();
+ selected.clear();
}
/**
@@ -1744,8 +1737,8 @@ void GrDrag::deselectAll()
*/
void GrDrag::selectAll()
{
- for (GList *l = this->draggers; l != NULL; l = l->next) {
- GrDragger *d = ((GrDragger *) l->data);
+ for (std::vector<GrDragger *>::const_iterator l = this->draggers.begin(); l != this->draggers.end(); ++l) {
+ GrDragger *d = *l;
setSelected (d, true, true);
}
}
@@ -1755,8 +1748,8 @@ void GrDrag::selectAll()
*/
void GrDrag::selectByCoords(std::vector<Geom::Point> coords)
{
- for (GList *l = this->draggers; l != NULL; l = l->next) {
- GrDragger *d = ((GrDragger *) l->data);
+ for (std::vector<GrDragger *>::const_iterator l = this->draggers.begin(); l != this->draggers.end(); ++l) {
+ GrDragger *d = *l;
for (guint k = 0; k < coords.size(); k++) {
if (Geom::L2 (d->point - coords[k]) < 1e-4) {
setSelected (d, true, true);
@@ -1770,12 +1763,12 @@ void GrDrag::selectByCoords(std::vector<Geom::Point> coords)
*/
void GrDrag::selectByStop(SPStop *stop, bool add_to_selection, bool override )
{
- for (GList *i = this->draggers; i != NULL; i = i->next) {
+ for (std::vector<GrDragger *>::const_iterator l = this->draggers.begin(); l != this->draggers.end(); ++l) {
- GrDragger *dragger = (GrDragger *) i->data;
- for (GSList const* j = dragger->draggables; j != NULL; j = j->next) {
+ GrDragger *dragger = *l;
+ for (std::vector<GrDraggable *>::const_iterator j = dragger->draggables.begin(); j != dragger->draggables.end(); ++j) {
- GrDraggable *d = (GrDraggable *) j->data;
+ GrDraggable *d = *j;
SPGradient *gradient = getGradient(d->item, d->fill_or_stroke);
SPGradient *vector = gradient->getVector(false);
SPStop *stop_i = sp_get_stop_i(vector, d->point_i);
@@ -1791,8 +1784,8 @@ void GrDrag::selectByStop(SPStop *stop, bool add_to_selection, bool override )
*/
void GrDrag::selectRect(Geom::Rect const &r)
{
- for (GList *l = this->draggers; l != NULL; l = l->next) {
- GrDragger *d = ((GrDragger *) l->data);
+ for (std::vector<GrDragger *>::const_iterator l = this->draggers.begin(); l != this->draggers.end(); ++l) {
+ GrDragger *d = *l;
if (r.contains(d->point)) {
setSelected (d, true, true);
}
@@ -1816,20 +1809,18 @@ void GrDrag::setSelected(GrDragger *dragger, bool add_to_selection, bool overrid
if (add_to_selection) {
if (!dragger) return;
if (override) {
- if (!g_list_find(selected, dragger)) {
- selected = g_list_prepend(selected, dragger);
- }
+ selected.insert(dragger);
dragger->select();
seldragger = dragger;
} else { // toggle
- if (g_list_find(selected, dragger)) {
- selected = g_list_remove(selected, dragger);
+ if(selected.find(dragger)!=selected.end()) {
+ selected.erase(dragger);
dragger->deselect();
- if (selected) {
- seldragger = (GrDragger*) selected->data; // select the dragger that is first in the list
+ if (!selected.empty()) {
+ seldragger = *(selected.begin()); // select the dragger that is first in the list
}
} else {
- selected = g_list_prepend(selected, dragger);
+ selected.insert(dragger);
dragger->select();
seldragger = dragger;
}
@@ -1837,7 +1828,7 @@ void GrDrag::setSelected(GrDragger *dragger, bool add_to_selection, bool overrid
} else {
deselect_all();
if (dragger) {
- selected = g_list_prepend(selected, dragger);
+ selected.insert(dragger);
dragger->select();
seldragger = dragger;
}
@@ -1853,11 +1844,11 @@ void GrDrag::setSelected(GrDragger *dragger, bool add_to_selection, bool overrid
*/
void GrDrag::setDeselected(GrDragger *dragger)
{
- if (g_list_find(selected, dragger)) {
- selected = g_list_remove(selected, dragger);
+ if (selected.find(dragger) != selected.end()) {
+ selected.erase(dragger);
dragger->deselect();
}
- this->desktop->emitToolSubselectionChanged((gpointer) (selected ? selected->data : NULL ));
+ this->desktop->emitToolSubselectionChanged((gpointer) (selected.empty() ? NULL :*(selected.begin())));
}
@@ -1873,7 +1864,7 @@ void GrDrag::addLine(SPItem *item, Geom::Point p1, Geom::Point p2, Inkscape::Pai
sp_canvas_item_move_to_z(line, 0);
line->item = item;
sp_canvas_item_show(line);
- this->lines = g_slist_append(this->lines, line);
+ this->lines.push_back(line);
}
@@ -1889,7 +1880,7 @@ void GrDrag::addCurve(SPItem *item, Geom::Point p0, Geom::Point p1, Geom::Point
sp_canvas_item_move_to_z(line, 0);
line->item = item;
sp_canvas_item_show (line);
- this->lines = g_slist_append (this->lines, line);
+ this->lines.push_back(line);
}
@@ -1901,8 +1892,8 @@ void GrDrag::addDragger(GrDraggable *draggable)
{
Geom::Point p = getGradientCoords(draggable->item, draggable->point_type, draggable->point_i, draggable->fill_or_stroke);
- for (GList *i = this->draggers; i != NULL; i = i->next) {
- GrDragger *dragger = (GrDragger *) i->data;
+ for (std::vector<GrDragger *>::const_iterator l = this->draggers.begin(); l != this->draggers.end(); ++l) {
+ GrDragger *dragger = *l;
if (dragger->mayMerge (draggable) && Geom::L2 (dragger->point - p) < MERGE_DIST) {
// distance is small, merge this draggable into dragger, no need to create new dragger
dragger->addDraggable (draggable);
@@ -1913,7 +1904,7 @@ void GrDrag::addDragger(GrDraggable *draggable)
GrDragger *new_dragger = new GrDragger(this, p, draggable);
// fixme: draggers should be added AFTER the last one: this way tabbing through them will be from begin to end.
- this->draggers = g_list_append (this->draggers, new_dragger);
+ this->draggers.push_back(new_dragger);
}
/**
@@ -2071,19 +2062,16 @@ void GrDrag::grabKnot(SPItem *item, GrPointType point_type, gint point_i, Inksca
*/
void GrDrag::updateDraggers()
{
- while (selected) {
- selected = g_list_remove(selected, selected->data);
- }
+ selected.clear();
// delete old draggers
- for (GList const* i = this->draggers; i != NULL; i = i->next) {
- delete static_cast<GrDragger *>(i->data);
+ for (std::vector<GrDragger *>::const_iterator l = this->draggers.begin(); l != this->draggers.end(); ++l) {
+ delete (*l);
}
- g_list_free(this->draggers);
- this->draggers = NULL;
+ this->draggers.clear();
g_return_if_fail(this->selection != NULL);
std::vector<SPItem*> list = this->selection->itemList();
- for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); ++i) {
SPItem *item = *i;
SPStyle *style = item->style;
@@ -2127,8 +2115,8 @@ void GrDrag::updateDraggers()
*/
bool GrDrag::mouseOver()
{
- for (GList const* i = this->draggers; i != NULL; i = i->next) {
- GrDragger *d = (GrDragger *) i->data;
+ for (std::vector<GrDragger *>::const_iterator l = this->draggers.begin(); l != this->draggers.end(); ++l) {
+ GrDragger *d = *l;
if (d->knot && (d->knot->flags & SP_KNOT_MOUSEOVER)) {
return true;
}
@@ -2143,16 +2131,15 @@ bool GrDrag::mouseOver()
void GrDrag::updateLines()
{
// delete old lines
- for (GSList const *i = this->lines; i != NULL; i = i->next) {
- sp_canvas_item_destroy(SP_CANVAS_ITEM(i->data));
+ for (std::vector<SPCtrlLine *>::const_iterator i = this->lines.begin(); i != this->lines.end(); ++i) {
+ sp_canvas_item_destroy(SP_CANVAS_ITEM(*i));
}
- g_slist_free(this->lines);
- this->lines = NULL;
+ this->lines.clear();
g_return_if_fail(this->selection != NULL);
std::vector<SPItem*> list = this->selection->itemList();
- for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); ++i) {
SPItem *item = *i;
SPStyle *style = item->style;
@@ -2296,7 +2283,7 @@ void GrDrag::updateLevels()
g_return_if_fail (this->selection != NULL);
std::vector<SPItem*> list = this->selection->itemList();
- for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = list.begin(); i != list.end(); ++i) {
SPItem *item = *i;
Geom::OptRect rect = item->desktopVisualBounds();
if (rect) {
@@ -2313,13 +2300,11 @@ void GrDrag::updateLevels()
void GrDrag::selected_reverse_vector()
{
- if (selected == NULL)
+ if (selected.empty())
return;
- for (GSList const* i = ( (GrDragger*) selected->data )->draggables; i != NULL; i = i->next) {
- GrDraggable *draggable = (GrDraggable *) i->data;
-
- sp_item_gradient_reverse_vector (draggable->item, draggable->fill_or_stroke);
+ for(std::vector<GrDraggable *>::const_iterator it = (*(selected.begin()))->draggables.begin(); it != (*(selected.begin()))->draggables.end(); ++it) {
+ sp_item_gradient_reverse_vector ((*it)->item, (*it)->fill_or_stroke);
}
}
@@ -2330,13 +2315,13 @@ void GrDrag::selected_move_nowrite(double x, double y, bool scale_radial)
void GrDrag::selected_move(double x, double y, bool write_repr, bool scale_radial)
{
- if (selected == NULL)
+ if (selected.empty())
return;
bool did = false;
- for (GList *i = selected; i != NULL; i = i->next) {
- GrDragger *d = (GrDragger *) i->data;
+ for(std::set<GrDragger *>::const_iterator it = selected.begin(); it != selected.end(); ++it) {
+ GrDragger *d = *it;
if (!d->isA(POINT_LG_MID) && !d->isA(POINT_RG_MID1) && !d->isA(POINT_RG_MID2)) {
// if this is an endpoint,
@@ -2347,12 +2332,12 @@ void GrDrag::selected_move(double x, double y, bool write_repr, bool scale_radia
if (d->isA(POINT_RG_R1) || d->isA(POINT_RG_R2) ||
(d->isA(POINT_RG_FOCUS) && !d->isA(POINT_RG_CENTER))) {
bool skip_radius_with_center = false;
- for (GList *di = selected; di != NULL; di = di->next) {
- GrDragger *d_new = (GrDragger *) di->data;
- if (d_new->isA (((GrDraggable *) d->draggables->data)->item,
+ for(std::set<GrDragger *>::const_iterator di = selected.begin(); di != selected.end(); ++di) {
+ GrDragger *d_new = *di;
+ if (d_new->isA (( d->draggables[0])->item,
POINT_RG_CENTER,
0,
- ((GrDraggable *) d->draggables->data)->fill_or_stroke)) {
+ (d->draggables[0])->fill_or_stroke)) {
// FIXME: here we take into account only the first draggable!
skip_radius_with_center = true;
}
@@ -2382,23 +2367,23 @@ void GrDrag::selected_move(double x, double y, bool write_repr, bool scale_radia
if (!did) { // none of the end draggers are selected, so let's try to move the mids
- GrDragger *dragger = (GrDragger *) selected->data;
+ GrDragger *dragger = *(selected.begin());
// a midpoint dragger can (logically) only contain one GrDraggable
- GrDraggable *draggable = (GrDraggable *) dragger->draggables->data;
+ GrDraggable *draggable = dragger->draggables[0];
Geom::Point begin(0,0), end(0,0);
Geom::Point low_lim(0,0), high_lim(0,0);
SPObject *server = draggable->getServer();
- GSList *moving = NULL;
- gr_midpoint_limits(dragger, server, &begin, &end, &low_lim, &high_lim, &moving);
+ std::vector<GrDragger *> moving;
+ gr_midpoint_limits(dragger, server, &begin, &end, &low_lim, &high_lim, moving);
Geom::LineSegment ls(low_lim, high_lim);
Geom::Point p = ls.pointAt(ls.nearestTime(dragger->point + Geom::Point(x,y)));
Geom::Point displacement = p - dragger->point;
- for (GSList const* i = moving; i != NULL; i = i->next) {
- GrDragger *drg = (GrDragger*) i->data;
+ for(std::vector<GrDragger *>::const_iterator i = moving.begin(); i!= moving.end();++i) {
+ GrDragger *drg = *i;
SPKnot *drgknot = drg->knot;
drg->point += displacement;
drgknot->moveto(drg->point);
@@ -2407,8 +2392,6 @@ void GrDrag::selected_move(double x, double y, bool write_repr, bool scale_radia
did = true;
}
- g_slist_free(moving);
-
if (write_repr && did) {
// we did an undoable action
DocumentUndo::maybeDone(desktop->getDocument(), "grmovem", SP_VERB_CONTEXT_GRADIENT,
@@ -2432,11 +2415,11 @@ void GrDrag::selected_move_screen(double x, double y)
GrDragger *GrDrag::select_next()
{
GrDragger *d = NULL;
- if (selected == NULL || g_list_find(draggers, selected->data)->next == NULL) {
- if (draggers)
- d = (GrDragger *) draggers->data;
+ if (selected.empty() || (++find(draggers.begin(),draggers.end(),*(selected.begin())))==draggers.end()) {
+ if (!draggers.empty())
+ d = draggers[0];
} else {
- d = (GrDragger *) g_list_find(draggers, selected->data)->next->data;
+ d = *(++find(draggers.begin(),draggers.end(),*(selected.begin())));
}
if (d)
setSelected (d);
@@ -2449,11 +2432,11 @@ GrDragger *GrDrag::select_next()
GrDragger *GrDrag::select_prev()
{
GrDragger *d = NULL;
- if (selected == NULL || g_list_find(draggers, selected->data)->prev == NULL) {
- if (draggers)
- d = (GrDragger *) g_list_last (draggers)->data;
+ if (selected.empty() || draggers[0] == (*(selected.begin()))) {
+ if (!draggers.empty())
+ d = draggers[draggers.size()-1];
} else {
- d = (GrDragger *) g_list_find(draggers, selected->data)->prev->data;
+ d = *(--find(draggers.begin(),draggers.end(),*(selected.begin())));
}
if (d)
setSelected (d);
@@ -2464,7 +2447,7 @@ GrDragger *GrDrag::select_prev()
// FIXME: i.m.o. an ugly function that I just made to work, but... aargh! (Johan)
void GrDrag::deleteSelected(bool just_one)
{
- if (!selected) return;
+ if (selected.empty()) return;
SPDocument *document = NULL;
@@ -2477,10 +2460,10 @@ void GrDrag::deleteSelected(bool just_one)
GSList *midstoplist = NULL; // list of stops that must be deleted (will be deleted first)
GSList *endstoplist = NULL; // list of stops that must be deleted
- while (selected) {
- GrDragger *dragger = (GrDragger*) selected->data;
- for (GSList * drgble = dragger->draggables; drgble != NULL; drgble = drgble->next) {
- GrDraggable *draggable = (GrDraggable*) drgble->data;
+ while (!selected.empty()) {
+ GrDragger *dragger = *(selected.begin());
+ for(std::vector<GrDraggable *>::const_iterator drgble = dragger->draggables.begin(); drgble != dragger->draggables.end(); ++drgble) {
+ GrDraggable *draggable = *drgble;
SPGradient *gradient = getGradient(draggable->item, draggable->fill_or_stroke);
SPGradient *vector = sp_gradient_get_forked_vector_if_necessary (gradient, false);
@@ -2538,7 +2521,7 @@ void GrDrag::deleteSelected(bool just_one)
break;
}
}
- selected = g_list_remove(selected, dragger);
+ selected.erase(dragger);
if ( just_one ) break; // iterate once if just_one is set.
}
while (midstoplist) {
diff --git a/src/gradient-drag.h b/src/gradient-drag.h
index da264b4bb..b07f748a7 100644
--- a/src/gradient-drag.h
+++ b/src/gradient-drag.h
@@ -20,6 +20,7 @@
#include <stddef.h>
#include <sigc++/sigc++.h>
#include <vector>
+#include <set>
#include <glib.h>
#include <glibmm/ustring.h>
@@ -86,7 +87,7 @@ struct GrDragger {
// position of the knot before it began to drag; updated when released
Geom::Point point_original;
- GSList *draggables;
+ std::vector<GrDraggable *> draggables;
void addDraggable(GrDraggable *draggable);
@@ -123,6 +124,7 @@ private:
sigc::connection _ungrabbed_connection;
};
+struct SPCtrlLine;
/**
This is the root class of the gradient dragging machinery. It holds lists of GrDraggers
and of lines (simple canvas items). It also remembers one of the draggers as selected.
@@ -133,20 +135,21 @@ public: // FIXME: make more of this private!
GrDrag(SPDesktop *desktop);
virtual ~GrDrag();
- bool isNonEmpty() {return (draggers != NULL);}
- bool hasSelection() {return (selected != NULL);}
- guint numSelected() {return (selected? g_list_length(selected) : 0);}
- guint numDraggers() {return (draggers? g_list_length(draggers) : 0);}
+ bool isNonEmpty() {return !draggers.empty();}
+ bool hasSelection() {return !selected.empty();}
+ guint numSelected() {return selected.size();}
+ guint numDraggers() {return draggers.size();}
guint singleSelectedDraggerNumDraggables() {
- return (selected? g_slist_length(( static_cast<GrDragger *>(selected->data))->draggables) : 0);
+ return (selected.empty()? 0 : (*(selected.begin()))->draggables.size() );
}
guint singleSelectedDraggerSingleDraggableType() {
- return (selected? (static_cast<GrDraggable*>((static_cast<GrDragger*>(selected->data))->draggables->data))->point_type : 0);}
+ return (selected.empty() ? 0 : ((*(selected.begin()))->draggables[0]->point_type));
+ }
// especially the selection must be private, fix gradient-context to remove direct access to it
- GList *selected; // list of GrDragger*
+ std::set<GrDragger *> selected; // list of GrDragger*
void setSelected(GrDragger *dragger, bool add_to_selection = false, bool override = true);
void setDeselected(GrDragger *dragger);
void deselectAll();
@@ -178,8 +181,8 @@ public: // FIXME: make more of this private!
std::vector<double> hor_levels;
std::vector<double> vert_levels;
- GList *draggers;
- GSList *lines;
+ std::vector<GrDragger *> draggers;
+ std::vector<SPCtrlLine *> lines;
void updateDraggers();
void updateLines();
diff --git a/src/graphlayout.cpp b/src/graphlayout.cpp
index 40994347c..3956b39fe 100644
--- a/src/graphlayout.cpp
+++ b/src/graphlayout.cpp
@@ -25,7 +25,6 @@
#include "desktop.h"
#include "inkscape.h"
#include "sp-namedview.h"
-#include "util/glib-list-iterators.h"
#include "graphlayout.h"
#include "sp-path.h"
#include "sp-item.h"
@@ -89,7 +88,7 @@ struct CheckProgress : TestConvergence {
* not connectors in filtered
*/
void filterConnectors(std::vector<SPItem*> const &items, list<SPItem *> &filtered) {
- for(std::vector<SPItem*>::const_iterator i = items.begin();i !=items.end(); i++){
+ for(std::vector<SPItem*>::const_iterator i = items.begin();i !=items.end(); ++i){
SPItem *item = *i;
if(!isConnector(item)) {
filtered.push_back(item);
@@ -106,7 +105,6 @@ void graphlayout(std::vector<SPItem*> const &items) {
return;
}
- using Inkscape::Util::GSListIterator;
list<SPItem *> selected;
filterConnectors(items,selected);
if (selected.empty()) return;
@@ -164,10 +162,11 @@ void graphlayout(std::vector<SPItem*> const &items) {
continue;
}
unsigned u=i_iter->second;
- GSList *nlist=iu->avoidRef->getAttachedConnectors(Avoid::runningFrom);
+ std::vector<SPItem *> nlist=iu->avoidRef->getAttachedConnectors(Avoid::runningFrom);
list<SPItem *> connectors;
- connectors.insert<GSListIterator<SPItem *> >(connectors.end(),nlist,NULL);
+ connectors.insert(connectors.end(), nlist.begin(), nlist.end());
+
for (list<SPItem *>::iterator j(connectors.begin());
j != connectors.end();
++j) {
@@ -203,9 +202,6 @@ void graphlayout(std::vector<SPItem*> const &items) {
}
}
}
- if(nlist) {
- g_slist_free(nlist);
- }
}
const unsigned E = es.size();
double eweights[E];
diff --git a/src/graphlayout.h b/src/graphlayout.h
index 9794dd6b5..dfef45359 100644
--- a/src/graphlayout.h
+++ b/src/graphlayout.h
@@ -16,7 +16,6 @@
#include <list>
-typedef struct _GSList GSList;
class SPItem;
void graphlayout(std::vector<SPItem*> const &items);
diff --git a/src/guide-snapper.cpp b/src/guide-snapper.cpp
index 960caed67..17f2d9583 100644
--- a/src/guide-snapper.cpp
+++ b/src/guide-snapper.cpp
@@ -44,11 +44,10 @@ Inkscape::GuideSnapper::LineList Inkscape::GuideSnapper::_getSnapLines(Geom::Poi
}
SPGuide const *guide_to_ignore = _snapmanager->getGuideToIgnore();
-
- for (GSList const *l = _snapmanager->getNamedView()->guides; l != NULL; l = l->next) {
- SPGuide const *g = SP_GUIDE(l->data);
- if (g != guide_to_ignore) {
- s.push_back(std::pair<Geom::Point, Geom::Point>(g->getNormal(), g->getPoint()));
+ std::vector<SPGuide *> guides = _snapmanager->getNamedView()->guides;
+ for(std::vector<SPGuide *>::const_iterator it = guides.begin() ; it != guides.end(); ++it) {
+ if ((*it) != guide_to_ignore) {
+ s.push_back(std::pair<Geom::Point, Geom::Point>((*it)->getNormal(), (*it)->getPoint()));
}
}
diff --git a/src/helper/geom-pathstroke.cpp b/src/helper/geom-pathstroke.cpp
index c73a9e9e7..d2e9f9a1b 100644
--- a/src/helper/geom-pathstroke.cpp
+++ b/src/helper/geom-pathstroke.cpp
@@ -15,6 +15,7 @@
#include <2geom/sbasis-to-bezier.h> // cubicbezierpath_from_sbasis
#include <2geom/path-intersection.h>
#include <2geom/circle.h>
+#include <math.h>
#include "helper/geom-pathstroke.h"
@@ -55,6 +56,53 @@ static Circle touching_circle( D2<SBasis> const &curve, double t, double tol=0.0
return Geom::Circle(center, fabs(radius));
}
+
+// Area of triangle given three corner points
+static double area( Geom::Point a, Geom::Point b, Geom::Point c ) {
+
+ using Geom::X;
+ using Geom::Y;
+ return( 0.5 * fabs( ( a[X]*(b[Y]-c[Y]) + b[X]*(c[Y]-a[Y]) + c[X]*(a[Y]-b[Y]) ) ) );
+}
+
+// Alternative touching circle routine directly using Beziers. Works only at end points.
+static Circle touching_circle( CubicBezier const &curve, bool start ) {
+
+ double k = 0;
+ Geom::Point p;
+ Geom::Point normal;
+ if ( start ) {
+ double distance = Geom::distance( curve[1], curve[0] );
+ k = 4.0/3.0 * area( curve[0], curve[1], curve[2] ) /
+ (distance * distance * distance);
+ if( Geom::cross(curve[0]-curve[1], curve[1]-curve[2]) < 0 ) {
+ k = -k;
+ }
+ p = curve[0];
+ normal = Geom::Point(curve[1] - curve[0]).cw();
+ normal.normalize();
+ // std::cout << "Start k: " << k << " d: " << distance << " normal: " << normal << std::endl;
+ } else {
+ double distance = Geom::distance( curve[3], curve[2] );
+ k = 4.0/3.0 * area( curve[1], curve[2], curve[3] ) /
+ (distance * distance * distance);
+ if( Geom::cross(curve[1]-curve[2], curve[2]-curve[3]) < 0 ) {
+ k = -k;
+ }
+ p = curve[3];
+ normal = Geom::Point(curve[3] - curve[2]).cw();
+ normal.normalize();
+ // std::cout << "End k: " << k << " d: " << distance << " normal: " << normal << std::endl;
+ }
+ if( k == 0 ) {
+ return Geom::Circle( Geom::Point(0,std::numeric_limits<float>::infinity()),
+ std::numeric_limits<float>::infinity());
+ } else {
+ double radius = 1/k;
+ Geom::Point center = p + normal * radius;
+ return Geom::Circle( center, fabs(radius) );
+ }
+}
}
namespace {
@@ -77,7 +125,7 @@ struct join_data {
// line parameters
double miter;
- double width;
+ double width; // half stroke width
};
// Join functions must append the outgoing path
@@ -115,7 +163,9 @@ void miter_join_internal(join_data jd, bool clip)
if (p.isFinite()) {
// check size of miter
Point point_on_path = incoming.finalPoint() + rot90(tang1)*width;
- satisfied = distance(p, point_on_path) <= miter * 2.0 * width;
+ // SVG defines miter length as distance between inner intersection and outer intersection,
+ // which is twice the distance from p to point_on_path but width is half stroke width.
+ satisfied = distance(p, point_on_path) <= miter * width;
if (satisfied) {
// miter OK, check to see if we can do a relocation
if (inc_ls) {
@@ -124,13 +174,16 @@ void miter_join_internal(join_data jd, bool clip)
res.appendNew<LineSegment>(p);
}
} else if (clip) {
+ // std::cout << " Clipping ------------ " << std::endl;
// miter needs clipping, find two points
Point bisector_versor = Line(point_on_path, p).versor();
- Point point_limit = point_on_path + miter * 2.0 * width * bisector_versor;
-
+ Point point_limit = point_on_path + miter * width * bisector_versor;
+ // std::cout << " bisector_versor: " << bisector_versor << std::endl;
+ // std::cout << " point_limit: " << point_limit << std::endl;
Point p1 = intersection_point(incoming.finalPoint(), tang1, point_limit, bisector_versor.cw());
Point p2 = intersection_point(outgoing.initialPoint(), tang2, point_limit, bisector_versor.cw());
-
+ // std::cout << " p1: " << p1 << std::endl;
+ // std::cout << " p2: " << p2 << std::endl;
if (inc_ls) {
res.setFinal(p1);
} else {
@@ -176,8 +229,132 @@ Geom::Point pick_solution(std::vector<Geom::ShapeIntersection> points, Geom::Poi
return sol;
}
-void extrapolate_join(join_data jd)
+// Arcs line join. If two circles don't intersect, expand inner circle.
+Geom::Point expand_circle( Geom::Circle &inner_circle, Geom::Circle const &outer_circle, Geom::Point const &start_pt, Geom::Point const &start_tangent ) {
+ // std::cout << "expand_circle:" << std::endl;
+ // std::cout << " outer_circle: radius: " << outer_circle.radius() << " center: " << outer_circle.center() << std::endl;
+ // std::cout << " start: point: " << start_pt << " tangent: " << start_tangent << std::endl;
+
+ if( !(outer_circle.contains(start_pt) ) ) {
+ // std::cout << " WARNING: Outer circle does not contain starting point!" << std::endl;
+ return Geom::Point(0,0);
+ }
+
+ Geom::Line secant1(start_pt, start_pt + start_tangent);
+ std::vector<Geom::ShapeIntersection> chord1_pts = outer_circle.intersect(secant1);
+ // std::cout << " chord1: " << chord1_pts[0].point() << ", " << chord1_pts[1].point() << std::endl;
+ Geom::LineSegment chord1(chord1_pts[0].point(), chord1_pts[1].point());
+
+ Geom::Line bisector = make_bisector_line( chord1 );
+ std::vector<Geom::ShapeIntersection> chord2_pts = outer_circle.intersect(bisector);
+ // std::cout << " chord2: " << chord2_pts[0].point() << ", " << chord2_pts[1].point() << std::endl;
+ Geom::LineSegment chord2(chord2_pts[0].point(), chord2_pts[1].point());
+
+ // Find D, point on chord2 and on circle closest to start point
+ Geom::Coord d0 = Geom::distance(chord2_pts[0].point(),start_pt);
+ Geom::Coord d1 = Geom::distance(chord2_pts[1].point(),start_pt);
+ // std::cout << " d0: " << d0 << " d1: " << d1 << std::endl;
+ Geom::Point d = (d0 < d1) ? chord2_pts[0].point() : chord2_pts[1].point();
+ Geom::Line da(d,start_pt);
+
+ // Chord through start point and point D
+ std::vector<Geom::ShapeIntersection> chord3_pts = outer_circle.intersect(da);
+ // std::cout << " chord3: " << chord3_pts[0].point() << ", " << chord3_pts[1].point() << std::endl;
+
+ // Find farthest point on chord3 and on circle (could be more robust)
+ Geom::Coord d2 = Geom::distance(chord3_pts[0].point(),d);
+ Geom::Coord d3 = Geom::distance(chord3_pts[1].point(),d);
+ // std::cout << " d2: " << d2 << " d3: " << d3 << std::endl;
+
+ // Find point P, the intersection of outer circle and new inner circle
+ Geom::Point p = (d2 > d3) ? chord3_pts[0].point() : chord3_pts[1].point();
+
+ // Find center of new circle: it is at the intersection of the bisector
+ // of the chord defined by the start point and point P and a line through
+ // the start point and parallel to the first bisector.
+ Geom::LineSegment chord4(start_pt,p);
+ Geom::Line bisector2 = make_bisector_line( chord4 );
+ Geom::Line diameter = make_parallel_line( start_pt, bisector );
+ std::vector<Geom::ShapeIntersection> center_new = bisector2.intersect( diameter );
+ // std::cout << " center_new: " << center_new[0].point() << std::endl;
+ Geom::Coord r_new = Geom::distance( center_new[0].point(), start_pt );
+ // std::cout << " r_new: " << r_new << std::endl;
+
+ inner_circle.setCenter( center_new[0].point() );
+ inner_circle.setRadius( r_new );
+ return p;
+}
+
+// Arcs line join. If two circles don't intersect, adjust both circles so they just touch.
+// Increase (decrease) the radius of circle 1 and decrease (increase) of circle 2 by the same amount keeping the given points and tangents fixed.
+Geom::Point adjust_circles( Geom::Circle &circle1, Geom::Circle &circle2, Geom::Point const &point1, Geom::Point const &point2, Geom::Point const &tan1, Geom::Point const &tan2 ) {
+
+ Geom::Point n1 = (circle1.center() - point1).normalized(); // Always points towards center
+ Geom::Point n2 = (circle2.center() - point2).normalized();
+ Geom::Point sum_n = n1 + n2;
+
+ double r1 = circle1.radius();
+ double r2 = circle2.radius();
+ double delta_r = r2 - r1;
+ Geom::Point c1 = circle1.center();
+ Geom::Point c2 = circle2.center();
+ Geom::Point delta_c = c2 - c1;
+
+ // std::cout << "adjust_circles:" << std::endl;
+ // std::cout << " norm: " << n1 << "; " << n2 << std::endl;
+ // std::cout << " sum_n: " << sum_n << std::endl;
+ // std::cout << " delta_r: " << delta_r << std::endl;
+ // std::cout << " delta_c: " << delta_c << std::endl;
+
+ // Quadratic equation
+ double A = 4 - sum_n.length() * sum_n.length();
+ double B = 4.0 * delta_r - 2.0 * Geom::dot( delta_c, sum_n );
+ double C = delta_r * delta_r - delta_c.length() * delta_c.length();
+
+ double s1 = 0;
+ double s2 = 0;
+
+ if( fabs(A) < 0.01 ) {
+ // std::cout << " A near zero! $$$$$$$$$$$$$$$$$$" << std::endl;
+ if( B != 0 ) {
+ s1 = -C/B;
+ s2 = -s1;
+ }
+ } else {
+ s1 = (-B + sqrt(B*B - 4*A*C))/(2*A);
+ s2 = (-B - sqrt(B*B - 4*A*C))/(2*A);
+ }
+
+ double dr = (fabs(s1)<=fabs(s2)?s1:s2);
+
+ // std::cout << " A: " << A << std::endl;
+ // std::cout << " B: " << B << std::endl;
+ // std::cout << " C: " << C << std::endl;
+ // std::cout << " s1: " << s1 << " s2: " << s2 << " dr: " << dr << std::endl;
+
+ circle1 = Geom::Circle( c1 - dr*n1, r1-dr );
+ circle2 = Geom::Circle( c2 + dr*n2, r2+dr );
+
+ // std::cout << " C1: " << circle1 << std::endl;
+ // std::cout << " C2: " << circle2 << std::endl;
+ // std::cout << " d': " << Geom::Point( circle1.center() - circle2.center() ).length() << std::endl;
+
+ Geom::Line bisector( circle1.center(), circle2.center() );
+ std::vector<Geom::ShapeIntersection> points = circle1.intersect( bisector );
+ Geom::Point p0 = points[0].point();
+ Geom::Point p1 = points[1].point();
+ // std::cout << " points: " << p0 << "; " << p1 << std::endl;
+ if( abs( Geom::distance( p0, circle2.center() ) - circle2.radius() ) <
+ abs( Geom::distance( p1, circle2.center() ) - circle2.radius() ) ) {
+ return p0;
+ } else {
+ return p1;
+ }
+}
+
+void extrapolate_join_internal(join_data jd, int alternative)
{
+ // std::cout << "\nextrapolate_join: entrance: alternative: " << alternative << std::endl;
using namespace Geom;
Geom::Path &res = jd.res;
@@ -187,10 +364,40 @@ void extrapolate_join(join_data jd)
Geom::Point endPt = outgoing.initialPoint();
Geom::Point tang1 = jd.in_tang;
Geom::Point tang2 = jd.out_tang;
+ // width is half stroke-width
double width = jd.width, miter = jd.miter;
- Geom::Circle circle1 = Geom::touching_circle(Geom::reverse(incoming.toSBasis()), 0.);
- Geom::Circle circle2 = Geom::touching_circle(outgoing.toSBasis(), 0);
+ // std::cout << " startPt: " << startPt << " endPt: " << endPt << std::endl;
+ // std::cout << " tang1: " << tang1 << " tang2: " << tang2 << std::endl;
+ // std::cout << " dot product: " << Geom::dot( tang1, tang2 ) << std::endl;
+ // std::cout << " width: " << width << std::endl;
+
+ // CIRCLE CALCULATION TESTING
+ Geom::Circle circle1 = touching_circle(Geom::reverse(incoming.toSBasis()), 0.);
+ Geom::Circle circle2 = touching_circle(outgoing.toSBasis(), 0);
+ // std::cout << " circle1: " << circle1 << std::endl;
+ // std::cout << " circle2: " << circle2 << std::endl;
+ if( Geom::CubicBezier const * in_bezier = dynamic_cast<Geom::CubicBezier const*>(&incoming) ) {
+ Geom::Circle circle_test1 = touching_circle(*in_bezier, false);
+ if( !Geom::are_near( circle1, circle_test1, 0.01 ) ) {
+ // std::cout << " Circle 1 error!!!!!!!!!!!!!!!!!" << std::endl;
+ // std::cout << " " << circle_test1 << std::endl;
+ }
+ }
+ if( Geom::CubicBezier const * out_bezier = dynamic_cast<Geom::CubicBezier const*>(&outgoing) ) {
+ Geom::Circle circle_test2 = touching_circle(*out_bezier, true);
+ if( !Geom::are_near( circle2, circle_test2, 0.01 ) ) {
+ // std::cout << " Circle 2 error!!!!!!!!!!!!!!!!!" << std::endl;
+ // std::cout << " " << circle_test2 << std::endl;
+ }
+ }
+ // END TESTING
+
+ Geom::Point center1 = circle1.center();
+ Geom::Point center2 = circle2.center();
+ double side1 = tang1[Geom::X]*(startPt[Geom::Y]-center1[Geom::Y]) - tang1[Geom::Y]*(startPt[Geom::X]-center1[Geom::X]);
+ double side2 = tang2[Geom::X]*( endPt[Geom::Y]-center2[Geom::Y]) - tang2[Geom::Y]*( endPt[Geom::X]-center2[Geom::X]);
+ // std::cout << " side1: " << side1 << " side2: " << side2 << std::endl;
bool inc_ls = !circle1.center().isFinite();
bool out_ls = !circle2.center().isFinite();
@@ -199,20 +406,120 @@ void extrapolate_join(join_data jd)
Geom::EllipticalArc *arc1 = NULL;
Geom::EllipticalArc *arc2 = NULL;
+ Geom::LineSegment *seg1 = NULL;
+ Geom::LineSegment *seg2 = NULL;
Geom::Point sol;
Geom::Point p1;
Geom::Point p2;
if (!inc_ls && !out_ls) {
+ // std::cout << " two circles" << std::endl;
+
+ // See if tangent is backwards (radius < width/2 and circle is inside stroke).
+ Geom::Point node_on_path = startPt + Geom::rot90(tang1)*width;
+ // std::cout << " node_on_path: " << node_on_path << " -------------- " << std::endl;
+ bool b1 = false;
+ bool b2 = false;
+ if (circle1.radius() < width && distance( circle1.center(), node_on_path ) < width) {
+ b1 = true;
+ }
+ if (circle2.radius() < width && distance( circle2.center(), node_on_path ) < width) {
+ b2 = true;
+ }
+ // std::cout << " b1: " << (b1?"true":"false")
+ // << " b2: " << (b2?"true":"false") << std::endl;
+
// Two circles
points = circle1.intersect(circle2);
+
+ if (points.size() != 2) {
+ // std::cout << " Circles do not intersect, do backup" << std::endl;
+ switch (alternative) {
+ case 1:
+ {
+ // Fallback to round if one path has radius smaller than half line width.
+ if(b1 || b2) {
+ // std::cout << "At one least path has radius smaller than half line width." << std::endl;
+ return( round_join(jd) );
+ }
+
+ Point p;
+ if( circle2.contains( startPt ) && !circle1.contains( endPt ) ) {
+ // std::cout << "Expand circle1" << std::endl;
+ p = expand_circle( circle1, circle2, startPt, tang1 );
+ points.push_back( ShapeIntersection( 0, 0, p) );
+ points.push_back( ShapeIntersection( 0, 0, p) );
+ } else if( circle1.contains( endPt ) && !circle2.contains( startPt ) ) {
+ // std::cout << "Expand circle2" << std::endl;
+ p = expand_circle( circle2, circle1, endPt, tang2 );
+ points.push_back( ShapeIntersection( 0, 0, p) );
+ points.push_back( ShapeIntersection( 0, 0, p) );
+ } else {
+ // std::cout << "Either both points inside or both outside" << std::endl;
+ return( miter_clip_join(jd) );
+ }
+ break;
+
+ }
+ case 2:
+ {
+ // Fallback to round if one path has radius smaller than half line width.
+ if(b1 || b2) {
+ // std::cout << "At one least path has radius smaller than half line width." << std::endl;
+ return( round_join(jd) );
+ }
+
+ if( ( circle2.contains( startPt ) && !circle1.contains( endPt ) ) ||
+ ( circle1.contains( endPt ) && !circle2.contains( startPt ) ) ) {
+
+ Geom::Point apex = adjust_circles( circle1, circle2, startPt, endPt, tang1, tang2 );
+ points.push_back( ShapeIntersection( 0, 0, apex) );
+ points.push_back( ShapeIntersection( 0, 0, apex) );
+ } else {
+ // std::cout << "Either both points inside or both outside" << std::endl;
+ return( miter_clip_join(jd) );
+ }
+
+ break;
+ }
+ case 3:
+ if( side1 > 0 ) {
+ Geom::Line secant(startPt, startPt + tang1);
+ points = circle2.intersect(secant);
+ circle1.setRadius(std::numeric_limits<float>::infinity());
+ circle1.setCenter(Geom::Point(0,std::numeric_limits<float>::infinity()));
+ } else {
+ Geom::Line secant(endPt, endPt + tang2);
+ points = circle1.intersect(secant);
+ circle2.setRadius(std::numeric_limits<float>::infinity());
+ circle2.setCenter(Geom::Point(0,std::numeric_limits<float>::infinity()));
+ }
+ break;
+
+
+ case 0:
+ default:
+ // Do nothing
+ break;
+ }
+ }
+
if (points.size() == 2) {
sol = pick_solution(points, tang2, endPt);
- arc1 = circle1.arc(startPt, 0.5*(startPt+sol), sol);
- arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt);
+ if( circle1.radius() != std::numeric_limits<float>::infinity() ) {
+ arc1 = circle1.arc(startPt, 0.5*(startPt+sol), sol);
+ } else {
+ seg1 = new Geom::LineSegment(startPt, sol);
+ }
+ if( circle2.radius() != std::numeric_limits<float>::infinity() ) {
+ arc2 = circle2.arc(sol, 0.5*(sol+endPt), endPt);
+ } else {
+ seg2 = new Geom::LineSegment(sol, endPt);
+ }
}
} else if (inc_ls && !out_ls) {
// Line and circle
+ // std::cout << " line circle" << std::endl;
points = circle2.intersect(Line(incoming.initialPoint(), incoming.finalPoint()));
if (points.size() == 2) {
sol = pick_solution(points, tang2, endPt);
@@ -220,16 +527,18 @@ void extrapolate_join(join_data jd)
}
} else if (!inc_ls && out_ls) {
// Circle and line
+ // std::cout << " circle line" << std::endl;
points = circle1.intersect(Line(outgoing.initialPoint(), outgoing.finalPoint()));
if (points.size() == 2) {
sol = pick_solution(points, tang2, endPt);
arc1 = circle1.arc(startPt, 0.5*(sol+startPt), sol);
}
}
-
- if (points.size() != 2)
+ if (points.size() != 2) {
+ // std::cout << " no solutions" << std::endl;
// no solutions available, fall back to miter
- return miter_clip_join(jd);
+ return miter_join(jd);
+ }
// We have a solution, thus sol is defined.
p1 = sol;
@@ -248,14 +557,15 @@ void extrapolate_join(join_data jd)
Geom::Line bisector_chord = make_bisector_line(chord);
Geom::Line limit_line;
- double miter_limit = 2.0 * width * miter;
+ double miter_limit = width * miter;
bool clipped = false;
-
+
if (are_parallel(bisector_chord, ortho)) {
// No intersection (can happen if curvatures are equal but opposite)
if (Geom::distance(point_on_path, sol) > miter_limit) {
clipped = true;
- Geom::Point limit_point = point_on_path + miter_limit * bisector.versor();
+ Geom::Point temp = bisector.versor();
+ Geom::Point limit_point = point_on_path + miter_limit * temp;
limit_line = make_parallel_line( limit_point, ortho );
}
} else {
@@ -311,6 +621,8 @@ void extrapolate_join(join_data jd)
// Add initial
if (arc1) {
res.append(*arc1);
+ } else if (seg1 ) {
+ res.append(*seg1);
} else {
// Straight line segment: move last point
res.setFinal(p1);
@@ -324,6 +636,9 @@ void extrapolate_join(join_data jd)
if (arc2) {
res.append(*arc2);
res.append(outgoing);
+ } else if (seg2 ) {
+ res.append(*seg2);
+ res.append(outgoing);
} else {
// Straight line segment:
res.appendNew<Geom::LineSegment>(outgoing.finalPoint());
@@ -334,8 +649,16 @@ void extrapolate_join(join_data jd)
delete arc1;
delete arc2;
+ delete seg1;
+ delete seg2;
}
+void extrapolate_join( join_data jd) { extrapolate_join_internal(jd, 0); }
+void extrapolate_join_alt1(join_data jd) { extrapolate_join_internal(jd, 1); }
+void extrapolate_join_alt2(join_data jd) { extrapolate_join_internal(jd, 2); }
+void extrapolate_join_alt3(join_data jd) { extrapolate_join_internal(jd, 3); }
+
+
void join_inside(join_data jd)
{
Geom::Path &res = jd.res;
@@ -716,6 +1039,15 @@ void outline_join(Geom::Path &res, Geom::Path const& temp, Geom::Point in_tang,
case Inkscape::JOIN_EXTRAPOLATE:
jf = &extrapolate_join;
break;
+ case Inkscape::JOIN_EXTRAPOLATE1:
+ jf = &extrapolate_join_alt1;
+ break;
+ case Inkscape::JOIN_EXTRAPOLATE2:
+ jf = &extrapolate_join_alt2;
+ break;
+ case Inkscape::JOIN_EXTRAPOLATE3:
+ jf = &extrapolate_join_alt3;
+ break;
case Inkscape::JOIN_MITER_CLIP:
jf = &miter_clip_join;
break;
diff --git a/src/helper/geom-pathstroke.h b/src/helper/geom-pathstroke.h
index 6697273cf..6a753a6fd 100644
--- a/src/helper/geom-pathstroke.h
+++ b/src/helper/geom-pathstroke.h
@@ -21,6 +21,9 @@ enum LineJoinType {
JOIN_MITER,
JOIN_MITER_CLIP,
JOIN_EXTRAPOLATE,
+ JOIN_EXTRAPOLATE1,
+ JOIN_EXTRAPOLATE2,
+ JOIN_EXTRAPOLATE3,
};
enum LineCapType {
diff --git a/src/helper/png-write.cpp b/src/helper/png-write.cpp
index fc365c435..9430feeff 100644
--- a/src/helper/png-write.cpp
+++ b/src/helper/png-write.cpp
@@ -128,6 +128,9 @@ sp_png_write_rgba_striped(SPDocument *doc,
int (* get_rows)(guchar const **rows, void **to_free, int row, int num_rows, void *data),
void *data)
{
+ g_return_val_if_fail(filename != NULL, false);
+ g_return_val_if_fail(data != NULL, false);
+
struct SPEBP *ebp = (struct SPEBP *) data;
FILE *fp;
png_structp png_ptr;
@@ -135,9 +138,6 @@ sp_png_write_rgba_striped(SPDocument *doc,
png_color_8 sig_bit;
png_uint_32 r;
- g_return_val_if_fail(filename != NULL, false);
- g_return_val_if_fail(data != NULL, false);
-
/* open the file */
Inkscape::IO::dump_fopen_call(filename, "M");
diff --git a/src/inkgc/gc.cpp b/src/inkgc/gc.cpp
index 90c02d9c8..ffa94ea2a 100644
--- a/src/inkgc/gc.cpp
+++ b/src/inkgc/gc.cpp
@@ -28,9 +28,9 @@ void display_warning(char *msg, GC_word arg) {
}
void do_init() {
- GC_no_dls = 1;
- GC_all_interior_pointers = 1;
- GC_finalize_on_demand = 0;
+ GC_set_no_dls(1);
+ GC_set_all_interior_pointers(1);
+ GC_set_finalize_on_demand(0);
GC_INIT();
diff --git a/src/inkview.cpp b/src/inkview.cpp
index 8b7492798..3fcd9ed8a 100644
--- a/src/inkview.cpp
+++ b/src/inkview.cpp
@@ -30,10 +30,6 @@
# include "config.h"
#endif
-#ifdef HAVE_GETOPT_H
-#include <getopt.h>
-#endif
-
#include <cstring>
#include <sys/stat.h>
#include <locale.h>
@@ -106,70 +102,67 @@ static GtkWidget *ctrlwin = NULL;
int sp_main_gui (int, char const**) { return 0; }
int sp_main_console (int, char const**) { return 0; }
-static int
-sp_svgview_main_delete (GtkWidget */*widget*/, GdkEvent */*event*/, struct SPSlideShow */*ss*/)
+static int sp_svgview_main_delete (GtkWidget */*widget*/,
+ GdkEvent */*event*/,
+ struct SPSlideShow */*ss*/)
{
gtk_main_quit ();
return FALSE;
}
-static int
-sp_svgview_main_key_press (GtkWidget */*widget*/, GdkEventKey *event, struct SPSlideShow *ss)
+static int sp_svgview_main_key_press (GtkWidget */*widget*/,
+ GdkEventKey *event,
+ struct SPSlideShow *ss)
{
switch (event->keyval) {
- case GDK_KEY_Up:
- case GDK_KEY_Home:
- sp_svgview_goto_first(ss);
- break;
- case GDK_KEY_Down:
- case GDK_KEY_End:
- sp_svgview_goto_last(ss);
- break;
- case GDK_KEY_F11:
-#ifdef HAVE_GTK_WINDOW_FULLSCREEN
- if (ss->fullscreen) {
- gtk_window_unfullscreen (GTK_WINDOW(ss->window));
- ss->fullscreen = false;
- } else {
- gtk_window_fullscreen (GTK_WINDOW(ss->window));
- ss->fullscreen = true;
- }
-#else
- std::cout<<"Your GTK+ does not support fullscreen mode. Upgrade to 2.2."<<std::endl;
-#endif
- break;
- case GDK_KEY_Return:
- sp_svgview_control_show (ss);
- break;
- case GDK_KEY_KP_Page_Down:
- case GDK_KEY_Page_Down:
- case GDK_KEY_Right:
- case GDK_KEY_space:
- sp_svgview_show_next (ss);
- break;
- case GDK_KEY_KP_Page_Up:
- case GDK_KEY_Page_Up:
- case GDK_KEY_Left:
- case GDK_KEY_BackSpace:
- sp_svgview_show_prev (ss);
- break;
- case GDK_KEY_Escape:
- case GDK_KEY_q:
- case GDK_KEY_Q:
- gtk_main_quit();
- break;
- default:
- break;
+ case GDK_KEY_Up:
+ case GDK_KEY_Home:
+ sp_svgview_goto_first(ss);
+ break;
+ case GDK_KEY_Down:
+ case GDK_KEY_End:
+ sp_svgview_goto_last(ss);
+ break;
+ case GDK_KEY_F11:
+ if (ss->fullscreen) {
+ gtk_window_unfullscreen (GTK_WINDOW(ss->window));
+ ss->fullscreen = false;
+ } else {
+ gtk_window_fullscreen (GTK_WINDOW(ss->window));
+ ss->fullscreen = true;
+ }
+ break;
+ case GDK_KEY_Return:
+ sp_svgview_control_show (ss);
+ break;
+ case GDK_KEY_KP_Page_Down:
+ case GDK_KEY_Page_Down:
+ case GDK_KEY_Right:
+ case GDK_KEY_space:
+ sp_svgview_show_next (ss);
+ break;
+ case GDK_KEY_KP_Page_Up:
+ case GDK_KEY_Page_Up:
+ case GDK_KEY_Left:
+ case GDK_KEY_BackSpace:
+ sp_svgview_show_prev (ss);
+ break;
+ case GDK_KEY_Escape:
+ case GDK_KEY_q:
+ case GDK_KEY_Q:
+ gtk_main_quit();
+ break;
+ default:
+ break;
}
gtk_window_set_title(GTK_WINDOW(ss->window), ss->doc->getName());
return TRUE;
}
-int
-main (int argc, const char **argv)
+int main (int argc, const char **argv)
{
if (argc == 1) {
- usage();
+ usage();
}
// Prevents errors like "Unable to wrap GdkPixbuf..." (in nr-filter-image.cpp for example)
@@ -179,21 +172,25 @@ main (int argc, const char **argv)
struct SPSlideShow ss;
- int option,
- num_parsed_options = 0;
+ int num_parsed_options = 0;
// the list of arguments is in the net line
- while ((option = getopt(argc, (char* const* )argv, "t:")) != -1)
- {
- switch(option) {
- case 't': // for timer
- // fprintf(stderr, "set timer arg %s\n", optarg );
- ss.timer = atoi(optarg);
- num_parsed_options += 2; // 2 because of flag + option
+ for (int i = 1; i < argc; i++) {
+ if ((argv[i][0] == '-')) {
+ if (!strcmp(argv[i], "--")) {
break;
- case '?':
- default:
- usage();
+ }
+ else if ((!strcmp(argv[i], "-t"))) {
+ if (i + 1 >= argc) {
+ usage();
+ }
+ ss.timer = atoi(argv[i+1]);
+ num_parsed_options = i+1;
+ i++;
+ }
+ else {
+ usage();
+ }
}
}
@@ -236,82 +233,84 @@ main (int argc, const char **argv)
// starting at where the commandline options stopped parsing because
// we want all the files to be in the list
for (i = num_parsed_options + 1 ; i < argc; i++) {
- struct stat st;
- if (stat (argv[i], &st)
- || !S_ISREG (st.st_mode)
- || (st.st_size < 64)) {
- fprintf(stderr, "could not open file %s\n", argv[i]);
- } else {
-
-#ifdef WITH_INKJAR
- if (is_jar(argv[i])) {
- Inkjar::JarFileReader jar_file_reader(argv[i]);
- for (;;) {
- GByteArray *gba = jar_file_reader.get_next_file();
- if (gba == NULL) {
- char *c_ptr;
- gchar *last_filename = jar_file_reader.get_last_filename();
- if (last_filename == NULL)
- break;
- if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) {
- if (*(++c_ptr) == '\0') {
- g_free(last_filename);
- continue;
- }
- }
- } else if (gba->len > 0) {
- //::write(1, gba->data, gba->len);
- /* Append to list */
- if (ss.length >= ss.size) {
- /* Expand */
- ss.size <<= 1;
- ss.slides = g_renew (char *, ss.slides, ss.size);
- }
-
- ss.doc = SPDocument::createNewDocFromMem ((const gchar *)gba->data,
- gba->len,
- TRUE);
- gchar *last_filename = jar_file_reader.get_last_filename();
- if (ss.doc) {
- ss.slides[ss.length++] = strdup (last_filename);
- (ss.doc)->setUri (last_filename);
- }
- g_byte_array_free(gba, TRUE);
- g_free(last_filename);
- } else
- break;
- }
- } else {
-#endif /* WITH_INKJAR */
- /* Append to list */
- if (ss.length >= ss.size) {
- /* Expand */
- ss.size <<= 1;
- ss.slides = g_renew (char *, ss.slides, ss.size);
-
- }
-
- ss.slides[ss.length++] = strdup (argv[i]);
-
+ struct stat st;
+ if (stat (argv[i], &st)
+ || !S_ISREG (st.st_mode)
+ || (st.st_size < 64)) {
+ fprintf(stderr, "could not open file %s\n", argv[i]);
+ } else {
+
+ #ifdef WITH_INKJAR
+ if (is_jar(argv[i])) {
+ Inkjar::JarFileReader jar_file_reader(argv[i]);
+ for (;;) {
+ GByteArray *gba = jar_file_reader.get_next_file();
+ if (gba == NULL) {
+ char *c_ptr;
+ gchar *last_filename = jar_file_reader.get_last_filename();
+ if (last_filename == NULL)
+ break;
+ if ((c_ptr = std::strrchr(last_filename, '/')) != NULL) {
+ if (*(++c_ptr) == '\0') {
+ g_free(last_filename);
+ continue;
+ }
+ }
+ } else if (gba->len > 0) {
+ //::write(1, gba->data, gba->len);
+ /* Append to list */
+ if (ss.length >= ss.size) {
+ /* Expand */
+ ss.size <<= 1;
+ ss.slides = g_renew (char *, ss.slides, ss.size);
+ }
+
+ ss.doc = SPDocument::createNewDocFromMem ((const gchar *)gba->data,
+ gba->len,
+ TRUE);
+ gchar *last_filename = jar_file_reader.get_last_filename();
+ if (ss.doc) {
+ ss.slides[ss.length++] = strdup (last_filename);
+ (ss.doc)->setUri (last_filename);
+ }
+ g_byte_array_free(gba, TRUE);
+ g_free(last_filename);
+ } else {
+ break;
+ }
+ }
+ } else {
+ #endif /* WITH_INKJAR */
+ /* Append to list */
+ if (ss.length >= ss.size) {
+ /* Expand */
+ ss.size <<= 1;
+ ss.slides = g_renew (char *, ss.slides, ss.size);
+ }
+
+ ss.slides[ss.length++] = strdup (argv[i]);
+
+ if (!ss.doc) {
+ ss.doc = SPDocument::createNewDoc (ss.slides[ss.current], TRUE, false);
if (!ss.doc) {
- ss.doc = SPDocument::createNewDoc (ss.slides[ss.current], TRUE, false);
- if (!ss.doc)
- ++ss.current;
- }
-#ifdef WITH_INKJAR
- }
-#endif
- }
+ ++ss.current;
+ }
+ }
+ #ifdef WITH_INKJAR
+ }
+ #endif
+ }
}
- if(!ss.doc)
+ if(!ss.doc) {
return 1; /* none of the slides loadable */
-
+ }
+
w = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title( GTK_WINDOW(w), ss.doc->getName() );
gtk_window_set_default_size (GTK_WINDOW (w),
- MIN ((int)(ss.doc)->getWidth().value("px"), (int)gdk_screen_width() - 64),
- MIN ((int)(ss.doc)->getHeight().value("px"), (int)gdk_screen_height() - 64));
+ MIN ((int)(ss.doc)->getWidth().value("px"), (int)gdk_screen_width() - 64),
+ MIN ((int)(ss.doc)->getHeight().value("px"), (int)gdk_screen_height() - 64));
ss.window = w;
g_signal_connect (G_OBJECT (w), "delete_event", (GCallback) sp_svgview_main_delete, &ss);
@@ -331,8 +330,9 @@ main (int argc, const char **argv)
return 0;
}
-static int
-sp_svgview_ctrlwin_delete (GtkWidget */*widget*/, GdkEvent */*event*/, void */*data*/)
+static int sp_svgview_ctrlwin_delete (GtkWidget */*widget*/,
+ GdkEvent */*event*/,
+ void */*data*/)
{
ctrlwin = NULL;
return FALSE;
@@ -341,97 +341,92 @@ sp_svgview_ctrlwin_delete (GtkWidget */*widget*/, GdkEvent */*event*/, void */*d
static GtkWidget* sp_svgview_control_show(struct SPSlideShow *ss)
{
if (!ctrlwin) {
- ctrlwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ ctrlwin = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_resizable(GTK_WINDOW(ctrlwin), FALSE);
gtk_window_set_transient_for(GTK_WINDOW(ctrlwin), GTK_WINDOW(ss->window));
g_signal_connect(G_OBJECT (ctrlwin), "key_press_event", (GCallback) sp_svgview_main_key_press, ss);
g_signal_connect(G_OBJECT (ctrlwin), "delete_event", (GCallback) sp_svgview_ctrlwin_delete, NULL);
#if GTK_CHECK_VERSION(3,0,0)
- GtkWidget *t = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
+ GtkWidget *t = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL);
#else
- GtkWidget *t = gtk_hbutton_box_new();
+ GtkWidget *t = gtk_hbutton_box_new();
#endif
- gtk_container_add(GTK_CONTAINER(ctrlwin), t);
+ gtk_container_add(GTK_CONTAINER(ctrlwin), t);
#if GTK_CHECK_VERSION(3,10,0)
GtkWidget *b = gtk_button_new_from_icon_name(INKSCAPE_ICON("go-first"), GTK_ICON_SIZE_BUTTON);
#else
- GtkWidget *b = gtk_button_new();
+ GtkWidget *b = gtk_button_new();
GtkWidget *img = gtk_image_new_from_icon_name(INKSCAPE_ICON("go-first"), GTK_ICON_SIZE_BUTTON);
gtk_button_set_image(GTK_BUTTON(b), img);
#endif
- gtk_container_add(GTK_CONTAINER(t), b);
+ gtk_container_add(GTK_CONTAINER(t), b);
- g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_first_cb, ss);
+ g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_first_cb, ss);
#if GTK_CHECK_VERSION(3,10,0)
b = gtk_button_new_from_icon_name(INKSCAPE_ICON("go-previous"), GTK_ICON_SIZE_BUTTON);
#else
- b = gtk_button_new();
+ b = gtk_button_new();
img = gtk_image_new_from_icon_name(INKSCAPE_ICON("go-previous"), GTK_ICON_SIZE_BUTTON);
gtk_button_set_image(GTK_BUTTON(b), img);
#endif
- gtk_container_add(GTK_CONTAINER(t), b);
+ gtk_container_add(GTK_CONTAINER(t), b);
- g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_prev_cb, ss);
+ g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_prev_cb, ss);
#if GTK_CHECK_VERSION(3,10,0)
b = gtk_button_new_from_icon_name(INKSCAPE_ICON("go-next"), GTK_ICON_SIZE_BUTTON);
#else
- b = gtk_button_new();
+ b = gtk_button_new();
img = gtk_image_new_from_icon_name(INKSCAPE_ICON("go-next"), GTK_ICON_SIZE_BUTTON);
gtk_button_set_image(GTK_BUTTON(b), img);
#endif
- gtk_container_add(GTK_CONTAINER(t), b);
+ gtk_container_add(GTK_CONTAINER(t), b);
- g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_next_cb, ss);
+ g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_show_next_cb, ss);
#if GTK_CHECK_VERSION(3,10,0)
b = gtk_button_new_from_icon_name(INKSCAPE_ICON("go-last"), GTK_ICON_SIZE_BUTTON);
#else
- b = gtk_button_new();
+ b = gtk_button_new();
img = gtk_image_new_from_icon_name(INKSCAPE_ICON("go-last"), GTK_ICON_SIZE_BUTTON);
gtk_button_set_image(GTK_BUTTON(b), img);
#endif
- gtk_container_add(GTK_CONTAINER(t), b);
- g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_last_cb, ss);
- gtk_widget_show_all(ctrlwin);
+ gtk_container_add(GTK_CONTAINER(t), b);
+ g_signal_connect(G_OBJECT(b), "clicked", (GCallback) sp_svgview_goto_last_cb, ss);
+ gtk_widget_show_all(ctrlwin);
} else {
- gtk_window_present(GTK_WINDOW(ctrlwin));
+ gtk_window_present(GTK_WINDOW(ctrlwin));
}
return NULL;
}
-static int
-sp_svgview_show_next_cb (GtkWidget */*widget*/, void *data)
+static int sp_svgview_show_next_cb (GtkWidget */*widget*/, void *data)
{
sp_svgview_show_next(static_cast<struct SPSlideShow *>(data));
return FALSE;
}
-static int
-sp_svgview_show_prev_cb (GtkWidget */*widget*/, void *data)
+static int sp_svgview_show_prev_cb (GtkWidget */*widget*/, void *data)
{
sp_svgview_show_prev(static_cast<struct SPSlideShow *>(data));
return FALSE;
}
-static int
-sp_svgview_goto_first_cb (GtkWidget */*widget*/, void *data)
+static int sp_svgview_goto_first_cb (GtkWidget */*widget*/, void *data)
{
sp_svgview_goto_first(static_cast<struct SPSlideShow *>(data));
return FALSE;
}
-static int
-sp_svgview_goto_last_cb (GtkWidget */*widget*/, void *data)
+static int sp_svgview_goto_last_cb (GtkWidget */*widget*/, void *data)
{
sp_svgview_goto_last(static_cast<struct SPSlideShow *>(data));
return FALSE;
}
-static void
-sp_svgview_waiting_cursor(struct SPSlideShow *ss)
+static void sp_svgview_waiting_cursor(struct SPSlideShow *ss)
{
GdkCursor *waiting = gdk_cursor_new(GDK_WATCH);
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(ss->window)), waiting);
@@ -449,12 +444,12 @@ sp_svgview_waiting_cursor(struct SPSlideShow *ss)
gdk_cursor_unref(waiting);
#endif
}
- while(gtk_events_pending())
+ while(gtk_events_pending()) {
gtk_main_iteration();
+ }
}
-static void
-sp_svgview_normal_cursor(struct SPSlideShow *ss)
+static void sp_svgview_normal_cursor(struct SPSlideShow *ss)
{
gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(ss->window)), NULL);
if (ctrlwin) {
@@ -462,8 +457,9 @@ sp_svgview_normal_cursor(struct SPSlideShow *ss)
}
}
-static void
-sp_svgview_set_document(struct SPSlideShow *ss, SPDocument *doc, int current)
+static void sp_svgview_set_document(struct SPSlideShow *ss,
+ SPDocument *doc,
+ int current)
{
if (doc && doc != ss->doc) {
doc->ensureUpToDate();
@@ -473,8 +469,7 @@ sp_svgview_set_document(struct SPSlideShow *ss, SPDocument *doc, int current)
}
}
-static void
-sp_svgview_show_next (struct SPSlideShow *ss)
+static void sp_svgview_show_next (struct SPSlideShow *ss)
{
sp_svgview_waiting_cursor(ss);
@@ -489,8 +484,7 @@ sp_svgview_show_next (struct SPSlideShow *ss)
sp_svgview_normal_cursor(ss);
}
-static void
-sp_svgview_show_prev (struct SPSlideShow *ss)
+static void sp_svgview_show_prev (struct SPSlideShow *ss)
{
sp_svgview_waiting_cursor(ss);
@@ -505,16 +499,16 @@ sp_svgview_show_prev (struct SPSlideShow *ss)
sp_svgview_normal_cursor(ss);
}
-static void
-sp_svgview_goto_first (struct SPSlideShow *ss)
+static void sp_svgview_goto_first (struct SPSlideShow *ss)
{
sp_svgview_waiting_cursor(ss);
SPDocument *doc = NULL;
int current = 0;
while ( !doc && (current < ss->length - 1)) {
- if (current == ss->current)
+ if (current == ss->current) {
break;
+ }
doc = SPDocument::createNewDoc (ss->slides[current++], TRUE, false);
}
@@ -523,16 +517,16 @@ sp_svgview_goto_first (struct SPSlideShow *ss)
sp_svgview_normal_cursor(ss);
}
-static void
-sp_svgview_goto_last (struct SPSlideShow *ss)
+static void sp_svgview_goto_last (struct SPSlideShow *ss)
{
sp_svgview_waiting_cursor(ss);
SPDocument *doc = NULL;
int current = ss->length - 1;
while (!doc && (current >= 0)) {
- if (current == ss->current)
+ if (current == ss->current) {
break;
+ }
doc = SPDocument::createNewDoc (ss->slides[current--], TRUE, false);
}
@@ -542,8 +536,7 @@ sp_svgview_goto_last (struct SPSlideShow *ss)
}
#ifdef WITH_INKJAR
-static bool
-is_jar(char const *filename)
+static bool is_jar(char const *filename)
{
/* fixme: Check MIME type or something. /usr/share/misc/file/magic suggests that checking for
initial string "PK\003\004" in content should suffice. */
@@ -560,12 +553,12 @@ is_jar(char const *filename)
static void usage()
{
fprintf(stderr,
- "Usage: inkview [OPTIONS...] [FILES ...]\n"
- "\twhere FILES are SVG (.svg or .svgz)"
+ "Usage: inkview [OPTIONS...] [FILES ...]\n"
+ "\twhere FILES are SVG (.svg or .svgz)"
#ifdef WITH_INKJAR
- " or archives of SVGs (.sxw, .jar)"
+ " or archives of SVGs (.sxw, .jar)"
#endif
- "\n");
+ "\n");
exit(1);
}
diff --git a/src/io/inkjar.cpp b/src/io/inkjar.cpp
index fb1fedf55..345455c4a 100644
--- a/src/io/inkjar.cpp
+++ b/src/io/inkjar.cpp
@@ -103,14 +103,19 @@ bool JarFile::init_inflation()
bool JarFile::open()
{
+ if (_file != NULL) {
+ fclose(_file);
+ }
if ((_file = fopen(_filename, "r")) == NULL) {
- fprintf(stderr, "open failed.\n");
- return false;
+ fprintf(stderr, "open failed.\n");
+ return false;
+ }
+ if (!init_inflation()) {
+ return false;
+ }
+ else {
+ return true;
}
- if (!init_inflation())
- return false;
-
- return true;
}
bool JarFile::close()
diff --git a/src/io/streamtest.cpp b/src/io/streamtest.cpp
index 2030e6a85..ec59ac4a6 100644
--- a/src/io/streamtest.cpp
+++ b/src/io/streamtest.cpp
@@ -202,6 +202,7 @@ void path_init(char *path, char *name)
exit(1);
}
strncpy(ptr+1,name,strlen(name)+1);
+ path[PATH_MAX-1] = '\0';
printf("'%s'\n",path);
}
diff --git a/src/knot-holder-entity.h b/src/knot-holder-entity.h
index 43ab25e5c..63a068cab 100644
--- a/src/knot-holder-entity.h
+++ b/src/knot-holder-entity.h
@@ -44,7 +44,10 @@ public:
item(NULL),
desktop(NULL),
parent_holder(NULL),
- my_counter(0)
+ my_counter(0),
+ handler_id(0),
+ _click_handler_id(0),
+ _ungrab_handler_id(0)
{}
virtual ~KnotHolderEntity();
diff --git a/src/knot.cpp b/src/knot.cpp
index b3813ab53..bfc0c4f0b 100644
--- a/src/knot.cpp
+++ b/src/knot.cpp
@@ -206,6 +206,8 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
return true;
}
+ bool key_press_event_unconsumed = FALSE;
+
knot_ref(knot);
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -213,158 +215,163 @@ static int sp_knot_handler(SPCanvasItem */*item*/, GdkEvent *event, SPKnot *knot
switch (event->type) {
case GDK_2BUTTON_PRESS:
- if (event->button.button == 1) {
- knot->doubleclicked_signal.emit(knot, event->button.state);
+ if (event->button.button == 1) {
+ knot->doubleclicked_signal.emit(knot, event->button.state);
- grabbed = FALSE;
- moved = FALSE;
- consumed = TRUE;
- }
- break;
+ grabbed = FALSE;
+ moved = FALSE;
+ consumed = TRUE;
+ }
+ break;
case GDK_BUTTON_PRESS:
- if ((event->button.button == 1) && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) {
- Geom::Point const p = knot->desktop->w2d(Geom::Point(event->button.x, event->button.y));
- knot->startDragging(p, (gint) event->button.x, (gint) event->button.y, event->button.time);
+ if ((event->button.button == 1) && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) {
+ Geom::Point const p = knot->desktop->w2d(Geom::Point(event->button.x, event->button.y));
+ knot->startDragging(p, (gint) event->button.x, (gint) event->button.y, event->button.time);
- consumed = TRUE;
- }
- break;
+ consumed = TRUE;
+ }
+ break;
case GDK_BUTTON_RELEASE:
- if (event->button.button == 1 && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) {
- // If we have any pending snap event, then invoke it now
- if (knot->desktop->event_context->_delayed_snap_event) {
- sp_event_context_snap_watchdog_callback(knot->desktop->event_context->_delayed_snap_event);
- }
-
- sp_event_context_discard_delayed_snap_event(knot->desktop->event_context);
-
- knot->pressure = 0;
-
- if (transform_escaped) {
- transform_escaped = false;
- consumed = TRUE;
- } else {
- knot->setFlag(SP_KNOT_GRABBED, FALSE);
-
- if (!nograb) {
- sp_canvas_item_ungrab(knot->item, event->button.time);
- }
+ if (event->button.button == 1 && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) {
+ // If we have any pending snap event, then invoke it now
+ if (knot->desktop->event_context->_delayed_snap_event) {
+ sp_event_context_snap_watchdog_callback(knot->desktop->event_context->_delayed_snap_event);
+ }
- if (moved) {
- knot->setFlag(SP_KNOT_DRAGGING, FALSE);
+ sp_event_context_discard_delayed_snap_event(knot->desktop->event_context);
- knot->ungrabbed_signal.emit(knot, event->button.state);
- } else {
- knot->click_signal.emit(knot, event->button.state);
- }
+ knot->pressure = 0;
- grabbed = FALSE;
- moved = FALSE;
- consumed = TRUE;
- }
- }
- if (tools_isactive(knot->desktop, TOOLS_NODES)) {
- Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(knot->desktop->event_context);
- nt->update_helperpath();
- }
- break;
- case GDK_MOTION_NOTIFY:
- if (grabbed && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) {
+ if (transform_escaped) {
+ transform_escaped = false;
consumed = TRUE;
+ } else {
+ knot->setFlag(SP_KNOT_GRABBED, FALSE);
- if ( within_tolerance
- && ( abs( (gint) event->motion.x - xp ) < tolerance )
- && ( abs( (gint) event->motion.y - yp ) < tolerance ) ) {
- break; // do not drag if we're within tolerance from origin
+ if (!nograb) {
+ sp_canvas_item_ungrab(knot->item, event->button.time);
}
- // Once the user has moved farther than tolerance from the original location
- // (indicating they intend to move the object, not click), then always process the
- // motion notify coordinates as given (no snapping back to origin)
- within_tolerance = false;
+ if (moved) {
+ knot->setFlag(SP_KNOT_DRAGGING, FALSE);
- if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &knot->pressure)) {
- knot->pressure = CLAMP (knot->pressure, 0, 1);
+ knot->ungrabbed_signal.emit(knot, event->button.state);
} else {
- knot->pressure = 0.5;
+ knot->click_signal.emit(knot, event->button.state);
}
- if (!moved) {
- knot->grabbed_signal.emit(knot, event->motion.state);
+ grabbed = FALSE;
+ moved = FALSE;
+ consumed = TRUE;
+ }
+ }
+ if (tools_isactive(knot->desktop, TOOLS_NODES)) {
+ Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(knot->desktop->event_context);
+ nt->update_helperpath();
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if (grabbed && knot->desktop && knot->desktop->event_context && !knot->desktop->event_context->space_panning) {
+ consumed = TRUE;
- knot->setFlag(SP_KNOT_DRAGGING, TRUE);
- }
+ if ( within_tolerance
+ && ( abs( (gint) event->motion.x - xp ) < tolerance )
+ && ( abs( (gint) event->motion.y - yp ) < tolerance ) ) {
+ break; // do not drag if we're within tolerance from origin
+ }
+
+ // Once the user has moved farther than tolerance from the original location
+ // (indicating they intend to move the object, not click), then always process the
+ // motion notify coordinates as given (no snapping back to origin)
+ within_tolerance = false;
- sp_event_context_snap_delay_handler(knot->desktop->event_context, NULL, knot, (GdkEventMotion *)event, Inkscape::UI::Tools::DelayedSnapEvent::KNOT_HANDLER);
- sp_knot_handler_request_position(event, knot);
- moved = TRUE;
+ if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &knot->pressure)) {
+ knot->pressure = CLAMP (knot->pressure, 0, 1);
+ } else {
+ knot->pressure = 0.5;
}
- if (tools_isactive(knot->desktop, TOOLS_NODES)) {
- Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(knot->desktop->event_context);
- nt->update_helperpath();
+
+ if (!moved) {
+ knot->grabbed_signal.emit(knot, event->motion.state);
+
+ knot->setFlag(SP_KNOT_DRAGGING, TRUE);
}
- break;
+
+ sp_event_context_snap_delay_handler(knot->desktop->event_context, NULL, knot, (GdkEventMotion *)event, Inkscape::UI::Tools::DelayedSnapEvent::KNOT_HANDLER);
+ sp_knot_handler_request_position(event, knot);
+ moved = TRUE;
+ }
+ if (tools_isactive(knot->desktop, TOOLS_NODES)) {
+ Inkscape::UI::Tools::NodeTool *nt = static_cast<Inkscape::UI::Tools::NodeTool*>(knot->desktop->event_context);
+ nt->update_helperpath();
+ }
+ break;
case GDK_ENTER_NOTIFY:
- knot->setFlag(SP_KNOT_MOUSEOVER, TRUE);
- knot->setFlag(SP_KNOT_GRABBED, FALSE);
+ knot->setFlag(SP_KNOT_MOUSEOVER, TRUE);
+ knot->setFlag(SP_KNOT_GRABBED, FALSE);
- if (knot->tip && knot->desktop && knot->desktop->event_context) {
- knot->desktop->event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, knot->tip);
- }
+ if (knot->tip && knot->desktop && knot->desktop->event_context) {
+ knot->desktop->event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, knot->tip);
+ }
- grabbed = FALSE;
- moved = FALSE;
- consumed = TRUE;
- break;
+ grabbed = FALSE;
+ moved = FALSE;
+ consumed = TRUE;
+ break;
case GDK_LEAVE_NOTIFY:
- knot->setFlag(SP_KNOT_MOUSEOVER, FALSE);
- knot->setFlag(SP_KNOT_GRABBED, FALSE);
+ knot->setFlag(SP_KNOT_MOUSEOVER, FALSE);
+ knot->setFlag(SP_KNOT_GRABBED, FALSE);
- if (knot->tip && knot->desktop && knot->desktop->event_context) {
- knot->desktop->event_context->defaultMessageContext()->clear();
- }
+ if (knot->tip && knot->desktop && knot->desktop->event_context) {
+ knot->desktop->event_context->defaultMessageContext()->clear();
+ }
- grabbed = FALSE;
- moved = FALSE;
- consumed = TRUE;
- break;
+ grabbed = FALSE;
+ moved = FALSE;
+ consumed = TRUE;
+ break;
case GDK_KEY_PRESS: // keybindings for knot
- switch (Inkscape::UI::Tools::get_group0_keyval(&event->key)) {
- case GDK_KEY_Escape:
- knot->setFlag(SP_KNOT_GRABBED, FALSE);
-
- if (!nograb) {
- sp_canvas_item_ungrab(knot->item, event->button.time);
- }
-
- if (moved) {
- knot->setFlag(SP_KNOT_DRAGGING, FALSE);
-
- knot->ungrabbed_signal.emit(knot, event->button.state);
-
- DocumentUndo::undo(knot->desktop->getDocument());
- knot->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Node or handle drag canceled."));
- transform_escaped = true;
- consumed = TRUE;
- }
-
- grabbed = FALSE;
- moved = FALSE;
-
- sp_event_context_discard_delayed_snap_event(knot->desktop->event_context);
- break;
- default:
- consumed = FALSE;
- break;
- }
- break;
+ switch (Inkscape::UI::Tools::get_group0_keyval(&event->key)) {
+ case GDK_KEY_Escape:
+ knot->setFlag(SP_KNOT_GRABBED, FALSE);
+
+ if (!nograb) {
+ sp_canvas_item_ungrab(knot->item, event->button.time);
+ }
+
+ if (moved) {
+ knot->setFlag(SP_KNOT_DRAGGING, FALSE);
+
+ knot->ungrabbed_signal.emit(knot, event->button.state);
+
+ DocumentUndo::undo(knot->desktop->getDocument());
+ knot->desktop->messageStack()->flash(Inkscape::NORMAL_MESSAGE, _("Node or handle drag canceled."));
+ transform_escaped = true;
+ consumed = TRUE;
+ }
+
+ grabbed = FALSE;
+ moved = FALSE;
+
+ sp_event_context_discard_delayed_snap_event(knot->desktop->event_context);
+ break;
+ default:
+ consumed = FALSE;
+ key_press_event_unconsumed = TRUE;
+ break;
+ }
+ break;
default:
- break;
+ break;
}
knot_unref(knot);
- return consumed || grabbed;
+ if (key_press_event_unconsumed) {
+ return false; // e.g. in case "%" was pressed to toggle snapping, or Q for quick zoom (while dragging a handle)
+ } else {
+ return consumed || grabbed;
+ }
}
void sp_knot_handler_request_position(GdkEvent *event, SPKnot *knot) {
diff --git a/src/layer-manager.cpp b/src/layer-manager.cpp
index 3bbc831d5..c0fe95dd7 100644
--- a/src/layer-manager.cpp
+++ b/src/layer-manager.cpp
@@ -191,14 +191,12 @@ Glib::ustring LayerManager::getNextLayerName( SPObject* obj, gchar const *label)
}
std::set<Glib::ustring> currentNames;
- GSList const *layers=_document->getResourceList("layer");
+ std::set<SPObject *> layers = _document->getResourceList("layer");
SPObject *root=_desktop->currentRoot();
if ( root ) {
- for ( GSList const *iter=layers ; iter ; iter = iter->next ) {
- SPObject *layer=static_cast<SPObject *>(iter->data);
- if ( layer != obj ) {
- currentNames.insert( layer->label() ? Glib::ustring(layer->label()) : Glib::ustring() );
- }
+ for (std::set<SPObject *>::const_iterator iter = layers.begin(); iter != layers.end(); ++iter) {
+ if (*iter != obj)
+ currentNames.insert( (*iter)->label() ? Glib::ustring((*iter)->label()) : Glib::ustring() );
}
}
@@ -262,15 +260,16 @@ void LayerManager::_rebuild() {
if (!_document) // http://sourceforge.net/mailarchive/forum.php?thread_name=5747bce9a7ed077c1b4fc9f0f4f8a5e0%40localhost&forum_name=inkscape-devel
return;
- GSList const *layers = _document->getResourceList("layer");
+ std::set<SPObject *> layers = _document->getResourceList("layer");
+
SPObject *root=_desktop->currentRoot();
if ( root ) {
_addOne(root);
std::set<SPGroup*> layersToAdd;
- for ( GSList const *iter = layers; iter; iter = iter->next ) {
- SPObject *layer = static_cast<SPObject *>(iter->data);
+ for ( std::set<SPObject *>::const_iterator iter = layers.begin(); iter != layers.end(); ++iter ) {
+ SPObject *layer = *iter;
// Debug::EventTracker<DebugLayerNote> tracker(Util::format("Examining %s", layer->label()));
bool needsAdd = false;
std::set<SPGroup*> additional;
@@ -282,7 +281,7 @@ void LayerManager::_rebuild() {
SPGroup* group = SP_GROUP(curr);
if ( group->layerMode() == SPGroup::LAYER ) {
// If we have a layer-group as the one or a parent, ensure it is listed as a valid layer.
- needsAdd &= ( g_slist_find(const_cast<GSList *>(layers), curr) != NULL );
+ needsAdd &= ( layers.find(curr) != layers.end() );
// XML Tree being used here directly while it shouldn't be...
if ( (!(group->getRepr())) || (!(group->getRepr()->parent())) ) {
needsAdd = false;
diff --git a/src/libcroco/cr-additional-sel.c b/src/libcroco/cr-additional-sel.c
index 5a37eba6c..c34b8d243 100644
--- a/src/libcroco/cr-additional-sel.c
+++ b/src/libcroco/cr-additional-sel.c
@@ -247,7 +247,7 @@ cr_additional_sel_to_string (CRAdditionalSel const * a_this)
guchar *name = NULL;
if (cur->content.class_name) {
- name = g_strndup
+ name = (guchar *) g_strndup
(cur->content.class_name->stryng->str,
cur->content.class_name->stryng->len);
@@ -266,8 +266,8 @@ cr_additional_sel_to_string (CRAdditionalSel const * a_this)
{
guchar *name = NULL;
- if (cur->content.class_name) {
- name = g_strndup
+ if (cur->content.id_name) {
+ name = (guchar *) g_strndup
(cur->content.id_name->stryng->str,
cur->content.id_name->stryng->len);
@@ -323,7 +323,7 @@ cr_additional_sel_to_string (CRAdditionalSel const * a_this)
}
if (str_buf) {
- result = str_buf->str;
+ result = (guchar *) str_buf->str;
g_string_free (str_buf, FALSE);
str_buf = NULL;
}
@@ -347,7 +347,7 @@ cr_additional_sel_one_to_string (CRAdditionalSel const *a_this)
guchar *name = NULL;
if (a_this->content.class_name) {
- name = g_strndup
+ name = (guchar *) g_strndup
(a_this->content.class_name->stryng->str,
a_this->content.class_name->stryng->len);
@@ -366,8 +366,8 @@ cr_additional_sel_one_to_string (CRAdditionalSel const *a_this)
{
guchar *name = NULL;
- if (a_this->content.class_name) {
- name = g_strndup
+ if (a_this->content.id_name) {
+ name = (guchar *) g_strndup
(a_this->content.id_name->stryng->str,
a_this->content.id_name->stryng->len);
@@ -422,7 +422,7 @@ cr_additional_sel_one_to_string (CRAdditionalSel const *a_this)
}
if (str_buf) {
- result = str_buf->str;
+ result = (guchar *) str_buf->str;
g_string_free (str_buf, FALSE);
str_buf = NULL;
}
diff --git a/src/libcroco/cr-attr-sel.c b/src/libcroco/cr-attr-sel.c
index 7976ff1f8..31d9da579 100644
--- a/src/libcroco/cr-attr-sel.c
+++ b/src/libcroco/cr-attr-sel.c
@@ -123,10 +123,10 @@ cr_attr_sel_to_string (CRAttrSel const * a_this)
if (cur->name) {
guchar *name = NULL;
- name = g_strndup (cur->name->stryng->str,
+ name = (guchar *) g_strndup (cur->name->stryng->str,
cur->name->stryng->len);
if (name) {
- g_string_append (str_buf, name);
+ g_string_append (str_buf, (const gchar *) name);
g_free (name);
name = NULL;
}
@@ -135,7 +135,7 @@ cr_attr_sel_to_string (CRAttrSel const * a_this)
if (cur->value) {
guchar *value = NULL;
- value = g_strndup (cur->value->stryng->str,
+ value = (guchar *) g_strndup (cur->value->stryng->str,
cur->value->stryng->len);
if (value) {
switch (cur->match_way) {
@@ -168,7 +168,7 @@ cr_attr_sel_to_string (CRAttrSel const * a_this)
}
if (str_buf) {
- result = str_buf->str;
+ result = (guchar *) str_buf->str;
g_string_free (str_buf, FALSE);
}
diff --git a/src/libcroco/cr-cascade.c b/src/libcroco/cr-cascade.c
index 31e938bb7..9f8dbdf8d 100644
--- a/src/libcroco/cr-cascade.c
+++ b/src/libcroco/cr-cascade.c
@@ -75,8 +75,8 @@ cr_cascade_new (CRStyleSheet * a_author_sheet,
PRIVATE (result) = g_try_malloc (sizeof (CRCascadePriv));
if (!PRIVATE (result)) {
- g_free(result);
cr_utils_trace_info ("Out of memory");
+ g_free (result);
return NULL;
}
memset (PRIVATE (result), 0, sizeof (CRCascadePriv));
diff --git a/src/libcroco/cr-declaration.c b/src/libcroco/cr-declaration.c
index ab150a9e4..69c24b376 100644
--- a/src/libcroco/cr-declaration.c
+++ b/src/libcroco/cr-declaration.c
@@ -48,7 +48,7 @@ dump (CRDeclaration const * a_this, FILE * a_fp, glong a_indent)
g_return_if_fail (a_this);
- str = cr_declaration_to_string (a_this, a_indent);
+ str = (guchar *) cr_declaration_to_string (a_this, a_indent);
if (str) {
fprintf (a_fp, "%s", str);
g_free (str);
@@ -130,7 +130,7 @@ cr_declaration_parse_from_buf (CRStatement * a_statement,
g_return_val_if_fail (a_statement->type == RULESET_STMT,
NULL);
- parser = cr_parser_new_from_buf ((guchar*)a_str, strlen (a_str), a_enc, FALSE);
+ parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE);
g_return_val_if_fail (parser, NULL);
status = cr_parser_try_to_skip_spaces_and_comments (parser);
@@ -194,7 +194,7 @@ cr_declaration_parse_list_from_buf (const guchar * a_str,
g_return_val_if_fail (a_str, NULL);
- parser = cr_parser_new_from_buf ((guchar*)a_str, strlen (a_str), a_enc, FALSE);
+ parser = cr_parser_new_from_buf ((guchar*)a_str, strlen ((const char *) a_str), a_enc, FALSE);
g_return_val_if_fail (parser, NULL);
status = cr_parser_get_tknzr (parser, &tokenizer);
if (status != CR_OK || !tokenizer) {
@@ -243,10 +243,10 @@ cr_declaration_parse_list_from_buf (const guchar * a_str,
if (status != CR_OK || !property) {
if (status == CR_END_OF_INPUT_ERROR) {
status = CR_OK; // simply the end of input, do not delete what we got so far, just finish
- break;
+ break;
} else {
continue; // even if one declaration is broken, it's no reason to discard others (see http://www.w3.org/TR/CSS21/syndata.html#declaration)
- }
+ }
}
cur_decl = cr_declaration_new (NULL, property, value);
if (cur_decl) {
@@ -504,7 +504,7 @@ cr_declaration_to_string (CRDeclaration const * a_this, gulong a_indent)
{
GString *stringue = NULL;
- guchar *str = NULL,
+ gchar *str = NULL,
*result = NULL;
g_return_val_if_fail (a_this, NULL);
@@ -581,7 +581,7 @@ cr_declaration_list_to_string (CRDeclaration const * a_this, gulong a_indent)
stringue = g_string_new (NULL);
for (cur = a_this; cur; cur = cur->next) {
- str = cr_declaration_to_string (cur, a_indent);
+ str = (guchar *) cr_declaration_to_string (cur, a_indent);
if (str) {
g_string_append_printf (stringue, "%s;", str);
g_free (str);
@@ -589,7 +589,7 @@ cr_declaration_list_to_string (CRDeclaration const * a_this, gulong a_indent)
break;
}
if (stringue && stringue->str) {
- result = stringue->str;
+ result = (guchar *) stringue->str;
g_string_free (stringue, FALSE);
}
@@ -620,7 +620,7 @@ cr_declaration_list_to_string2 (CRDeclaration const * a_this,
stringue = g_string_new (NULL);
for (cur = a_this; cur; cur = cur->next) {
- str = cr_declaration_to_string (cur, a_indent);
+ str = (guchar *) cr_declaration_to_string (cur, a_indent);
if (str) {
if (a_one_decl_per_line == TRUE) {
if (cur->next)
@@ -628,21 +628,21 @@ cr_declaration_list_to_string2 (CRDeclaration const * a_this,
"%s;\n", str);
else
g_string_append (stringue,
- str);
+ (const gchar *) str);
} else {
if (cur->next)
g_string_append_printf (stringue,
"%s;", str);
else
g_string_append (stringue,
- str);
+ (const gchar *) str);
}
g_free (str);
} else
break;
}
if (stringue && stringue->str) {
- result = stringue->str;
+ result = (guchar *) stringue->str;
g_string_free (stringue, FALSE);
}
@@ -714,7 +714,7 @@ cr_declaration_get_by_prop_name (CRDeclaration * a_this,
&& cur->property->stryng
&& cur->property->stryng->str) {
if (!strcmp (cur->property->stryng->str,
- a_prop)) {
+ (const char *) a_prop)) {
return cur;
}
}
diff --git a/src/libcroco/cr-enc-handler.c b/src/libcroco/cr-enc-handler.c
index b3e5b7eba..a7c4269ad 100644
--- a/src/libcroco/cr-enc-handler.c
+++ b/src/libcroco/cr-enc-handler.c
@@ -89,8 +89,7 @@ cr_enc_handler_get_instance (enum CREncoding a_enc)
for (i = 0; gv_default_enc_handlers[i].encoding; i++) {
if (gv_default_enc_handlers[i].encoding == a_enc) {
- return (CREncHandler *)
- & gv_default_enc_handlers[i].encoding;
+ return (CREncHandler *) & gv_default_enc_handlers[i];
}
}
@@ -118,11 +117,10 @@ cr_enc_handler_resolve_enc_alias (const guchar * a_alias_name,
g_return_val_if_fail (a_alias_name != NULL, CR_BAD_PARAM_ERROR);
- alias_name_up = g_strdup (a_alias_name);
- g_ascii_strup (alias_name_up, -1);
+ alias_name_up = (guchar *) g_ascii_strup ((const gchar *) a_alias_name, -1);
for (i = 0; gv_default_aliases[i].name; i++) {
- if (!strcmp (gv_default_aliases[i].name, alias_name_up)) {
+ if (!strcmp (gv_default_aliases[i].name, (const gchar *) alias_name_up)) {
*a_enc = gv_default_aliases[i].encoding;
status = CR_OK;
break;
diff --git a/src/libcroco/cr-fonts.c b/src/libcroco/cr-fonts.c
index 10f26c99c..78e261149 100644
--- a/src/libcroco/cr-fonts.c
+++ b/src/libcroco/cr-fonts.c
@@ -78,7 +78,7 @@ cr_font_family_to_string_real (CRFontFamily const * a_this,
if (a_this->prev) {
g_string_append_printf (*a_string, ", %s", name);
} else {
- g_string_append (*a_string, name);
+ g_string_append (*a_string, (const gchar *) name);
}
}
if (a_walk_list == TRUE && a_this->next) {
@@ -187,7 +187,7 @@ cr_font_family_to_string (CRFontFamily const * a_this,
GString *stringue = NULL;
if (!a_this) {
- result = g_strdup ("NULL");
+ result = (guchar *) g_strdup ("NULL");
g_return_val_if_fail (result, NULL);
return result;
}
@@ -196,7 +196,7 @@ cr_font_family_to_string (CRFontFamily const * a_this,
&stringue);
if (status == CR_OK && stringue) {
- result = stringue->str;
+ result = (guchar *) stringue->str;
g_string_free (stringue, FALSE);
stringue = NULL;
@@ -420,7 +420,7 @@ cr_font_size_set_predefined_absolute_font_size (CRFontSize *a_this,
enum CRPredefinedAbsoluteFontSize a_predefined)
{
g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR) ;
- g_return_val_if_fail ((unsigned)a_predefined < NB_FONT_SIZE_TYPE,
+ g_return_val_if_fail ((unsigned)a_predefined < NB_PREDEFINED_ABSOLUTE_FONT_SIZES,
CR_BAD_PARAM_ERROR) ;
a_this->type = PREDEFINED_ABSOLUTE_FONT_SIZE ;
@@ -526,7 +526,7 @@ cr_font_size_to_string (CRFontSize const * a_this)
(a_this->value.predefined));
break;
case ABSOLUTE_FONT_SIZE:
- str = cr_num_to_string (&a_this->value.absolute);
+ str = (gchar *) cr_num_to_string (&a_this->value.absolute);
break;
case RELATIVE_FONT_SIZE:
str = g_strdup (cr_relative_font_size_to_string
@@ -683,7 +683,7 @@ cr_font_size_adjust_to_string (CRFontSizeAdjust const * a_this)
break;
case FONT_SIZE_ADJUST_NUMBER:
if (a_this->num)
- str = cr_num_to_string (a_this->num);
+ str = (gchar *) cr_num_to_string (a_this->num);
else
str = g_strdup ("unknow font-size-adjust property value"); /* Should raise an error no?*/
break;
diff --git a/src/libcroco/cr-input.c b/src/libcroco/cr-input.c
index 3cc283e01..732068aff 100644
--- a/src/libcroco/cr-input.c
+++ b/src/libcroco/cr-input.c
@@ -722,6 +722,8 @@ cr_input_consume_white_spaces (CRInput * a_this, gulong * a_nb_chars)
}
+ *a_nb_chars = (gulong) nb_consumed;
+
if (nb_consumed && status == CR_END_OF_INPUT_ERROR) {
status = CR_OK;
}
@@ -746,7 +748,7 @@ enum CRStatus
cr_input_peek_char (CRInput const * a_this, guint32 * a_char)
{
enum CRStatus status = CR_OK;
- glong consumed = 0,
+ gulong consumed = 0,
nb_bytes_left = 0;
g_return_val_if_fail (a_this && PRIVATE (a_this)
diff --git a/src/libcroco/cr-num.c b/src/libcroco/cr-num.c
index a5c320bf2..6cc5150a1 100644
--- a/src/libcroco/cr-num.c
+++ b/src/libcroco/cr-num.c
@@ -105,7 +105,7 @@ cr_num_to_string (CRNum const * a_this)
test_val = a_this->val - (glong) a_this->val;
if (!test_val) {
- tmp_char1 = g_strdup_printf ("%ld", (glong) a_this->val);
+ tmp_char1 = (guchar *) g_strdup_printf ("%ld", (glong) a_this->val);
} else {
/* We can't use g_ascii_dtostr, because that sometimes uses
e notation (which wouldn't be a valid number in CSS). */
@@ -195,7 +195,7 @@ cr_num_to_string (CRNum const * a_this)
}
if (tmp_char2) {
- result = g_strconcat (tmp_char1, tmp_char2, NULL);
+ result = (guchar *) g_strconcat ((gchar *) tmp_char1, tmp_char2, NULL);
g_free (tmp_char1);
} else {
result = tmp_char1;
diff --git a/src/libcroco/cr-om-parser.c b/src/libcroco/cr-om-parser.c
index c1acb855c..596cd6e6b 100644
--- a/src/libcroco/cr-om-parser.c
+++ b/src/libcroco/cr-om-parser.c
@@ -39,9 +39,6 @@ struct _CROMParserPriv {
#define PRIVATE(a_this) ((a_this)->priv)
-// Unfortunately, C does not allow unnamed function arguments, so use this macro instead...
-#define UNUSED(x) (void)(x)
-
/*
*Forward declaration of a type defined later
*in this file.
@@ -210,12 +207,12 @@ static void
start_font_face (CRDocHandler * a_this,
CRParsingLocation *a_location)
{
- UNUSED(a_location);
-
enum CRStatus status = CR_OK;
ParsingContext *ctxt = NULL;
ParsingContext **ctxtptr = NULL;
+ (void) a_location;
+
g_return_if_fail (a_this);
g_return_if_fail (a_this);
@@ -307,8 +304,6 @@ static void
charset (CRDocHandler * a_this, CRString * a_charset,
CRParsingLocation *a_location)
{
- UNUSED(a_location);
-
enum CRStatus status = CR_OK;
CRStatement *stmt = NULL,
*stmt2 = NULL;
@@ -317,6 +312,8 @@ charset (CRDocHandler * a_this, CRString * a_charset,
ParsingContext *ctxt = NULL;
ParsingContext **ctxtptr = NULL;
+ (void) a_location;
+
g_return_if_fail (a_this);
ctxtptr = &ctxt;
status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
@@ -347,12 +344,12 @@ start_page (CRDocHandler * a_this,
CRString * a_pseudo,
CRParsingLocation *a_location)
{
- UNUSED(a_location);
-
enum CRStatus status = CR_OK;
ParsingContext *ctxt = NULL;
ParsingContext **ctxtptr = NULL;
+ (void) a_location;
+
g_return_if_fail (a_this);
ctxtptr = &ctxt;
status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
@@ -390,18 +387,21 @@ end_page (CRDocHandler * a_this,
CRString * a_page,
CRString * a_pseudo_page)
{
- UNUSED(a_page);
- UNUSED(a_pseudo_page);
-
enum CRStatus status = CR_OK;
ParsingContext *ctxt = NULL;
ParsingContext **ctxtptr = NULL;
CRStatement *stmt = NULL;
+ (void) a_page;
+ (void) a_pseudo_page;
+
g_return_if_fail (a_this);
+
ctxtptr = &ctxt;
status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
g_return_if_fail (status == CR_OK && ctxt);
+
g_return_if_fail (ctxt->cur_stmt
&& ctxt->cur_stmt->type == AT_PAGE_RULE_STMT
&& ctxt->stylesheet);
@@ -419,6 +419,8 @@ end_page (CRDocHandler * a_this,
cr_statement_destroy (ctxt->cur_stmt);
ctxt->cur_stmt = NULL;
}
+ a_page = NULL; /*keep compiler happy */
+ a_pseudo_page = NULL; /*keep compiler happy */
}
static void
@@ -426,13 +428,13 @@ start_media (CRDocHandler * a_this,
GList * a_media_list,
CRParsingLocation *a_location)
{
- UNUSED(a_location);
-
enum CRStatus status = CR_OK;
ParsingContext *ctxt = NULL;
ParsingContext **ctxtptr = NULL;
GList *media_list = NULL;
+ (void) a_location;
+
g_return_if_fail (a_this);
ctxtptr = &ctxt;
status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
@@ -456,17 +458,20 @@ start_media (CRDocHandler * a_this,
static void
end_media (CRDocHandler * a_this, GList * a_media_list)
{
- UNUSED(a_media_list);
-
enum CRStatus status = CR_OK;
ParsingContext *ctxt = NULL;
ParsingContext **ctxtptr = NULL;
CRStatement *stmts = NULL;
+ (void) a_media_list;
+
g_return_if_fail (a_this);
+
ctxtptr = &ctxt;
status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
g_return_if_fail (status == CR_OK && ctxt);
+
g_return_if_fail (ctxt
&& ctxt->cur_media_stmt
&& ctxt->cur_media_stmt->type == AT_MEDIA_RULE_STMT
@@ -474,6 +479,7 @@ end_media (CRDocHandler * a_this, GList * a_media_list)
stmts = cr_statement_append (ctxt->stylesheet->statements,
ctxt->cur_media_stmt);
+
if (!stmts) {
cr_statement_destroy (ctxt->cur_media_stmt);
ctxt->cur_media_stmt = NULL;
@@ -484,6 +490,7 @@ end_media (CRDocHandler * a_this, GList * a_media_list)
ctxt->cur_stmt = NULL ;
ctxt->cur_media_stmt = NULL ;
+ a_media_list = NULL;
}
static void
@@ -493,9 +500,6 @@ import_style (CRDocHandler * a_this,
CRString * a_uri_default_ns,
CRParsingLocation *a_location)
{
- UNUSED(a_uri_default_ns);
- UNUSED(a_location);
-
enum CRStatus status = CR_OK;
CRString *uri = NULL;
CRStatement *stmt = NULL,
@@ -504,17 +508,26 @@ import_style (CRDocHandler * a_this,
ParsingContext **ctxtptr = NULL;
GList *media_list = NULL ;
+ (void) a_uri_default_ns;
+ (void) a_location;
+
g_return_if_fail (a_this);
+
ctxtptr = &ctxt;
status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
g_return_if_fail (status == CR_OK && ctxt);
+
g_return_if_fail (ctxt->stylesheet);
uri = cr_string_dup (a_uri) ;
+
if (a_media_list)
media_list = cr_utils_dup_glist_of_cr_string (a_media_list) ;
+
stmt = cr_statement_new_at_import_rule
(ctxt->stylesheet, uri, media_list, NULL);
+
if (!stmt)
goto error;
@@ -546,6 +559,7 @@ import_style (CRDocHandler * a_this,
cr_statement_destroy (stmt);
stmt = NULL;
}
+ a_uri_default_ns = NULL; /*keep compiler happy */
}
static void
@@ -572,16 +586,19 @@ start_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
static void
end_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
{
- UNUSED(a_selector_list);
-
enum CRStatus status = CR_OK;
ParsingContext *ctxt = NULL;
ParsingContext **ctxtptr = NULL;
+ (void) a_selector_list;
+
g_return_if_fail (a_this);
+
ctxtptr = &ctxt;
status = cr_doc_handler_get_ctxt (a_this, (gpointer *) ctxtptr);
+
g_return_if_fail (status == CR_OK && ctxt);
+
g_return_if_fail (ctxt->cur_stmt && ctxt->stylesheet);
if (ctxt->cur_stmt) {
@@ -621,6 +638,8 @@ end_selector (CRDocHandler * a_this, CRSelector * a_selector_list)
}
}
+
+ a_selector_list = NULL; /*keep compiler happy */
}
static void
diff --git a/src/libcroco/cr-parser.c b/src/libcroco/cr-parser.c
index 69b521496..544b35ab0 100644
--- a/src/libcroco/cr-parser.c
+++ b/src/libcroco/cr-parser.c
@@ -78,7 +78,7 @@ typedef struct _CRParserError CRParserError;
*parsing routines.
*/
struct _CRParserError {
- gchar *msg;
+ guchar *msg;
enum CRStatus status;
glong line;
glong column;
@@ -197,9 +197,9 @@ if ((a_status) != CR_OK) \
*/
#define PEEK_NEXT_CHAR(a_this, a_to_char) \
{\
-enum CRStatus status ; \
-status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
-CHECK_PARSING_STATUS (status, TRUE) \
+enum CRStatus pnc_status ; \
+pnc_status = cr_tknzr_peek_char (PRIVATE (a_this)->tknzr, a_to_char) ; \
+CHECK_PARSING_STATUS (pnc_status, TRUE) \
}
/**
@@ -374,11 +374,11 @@ static enum CRStatus cr_parser_parse_simple_selector (CRParser * a_this,
static enum CRStatus cr_parser_parse_simple_sels (CRParser * a_this,
CRSimpleSel ** a_sel);
-static CRParserError *cr_parser_error_new (const gchar * a_msg,
+static CRParserError *cr_parser_error_new (const guchar * a_msg,
enum CRStatus);
static void cr_parser_error_set_msg (CRParserError * a_this,
- const gchar * a_msg);
+ const guchar * a_msg);
static void cr_parser_error_dump (CRParserError * a_this);
@@ -392,7 +392,7 @@ static void
cr_parser_error_destroy (CRParserError * a_this);
static enum CRStatus cr_parser_push_error (CRParser * a_this,
- const gchar * a_msg,
+ const guchar * a_msg,
enum CRStatus a_status);
static enum CRStatus cr_parser_dump_err_stack (CRParser * a_this,
@@ -411,7 +411,7 @@ static enum CRStatus
*@return the newly built instance of #CRParserError.
*/
static CRParserError *
-cr_parser_error_new (const gchar * a_msg, enum CRStatus a_status)
+cr_parser_error_new (const guchar * a_msg, enum CRStatus a_status)
{
CRParserError *result = NULL;
@@ -436,7 +436,7 @@ cr_parser_error_new (const gchar * a_msg, enum CRStatus a_status)
*@param a_msg the new message.
*/
static void
-cr_parser_error_set_msg (CRParserError * a_this, const gchar * a_msg)
+cr_parser_error_set_msg (CRParserError * a_this, const guchar * a_msg)
{
g_return_if_fail (a_this);
@@ -444,7 +444,7 @@ cr_parser_error_set_msg (CRParserError * a_this, const gchar * a_msg)
g_free (a_this->msg);
}
- a_this->msg = g_strdup (a_msg);
+ a_this->msg = (guchar *) g_strdup ((const gchar *) a_msg);
}
/**
@@ -515,7 +515,7 @@ cr_parser_error_destroy (CRParserError * a_this)
*/
static enum CRStatus
cr_parser_push_error (CRParser * a_this,
- const gchar * a_msg, enum CRStatus a_status)
+ const guchar * a_msg, enum CRStatus a_status)
{
enum CRStatus status = CR_OK;
@@ -733,7 +733,7 @@ cr_parser_parse_stylesheet_core (CRParser * a_this)
error:
cr_parser_push_error
- (a_this, "could not recognize next production", CR_ERROR);
+ (a_this, (const guchar *) "could not recognize next production", CR_ERROR);
cr_parser_dump_err_stack (a_this, TRUE);
@@ -1688,14 +1688,12 @@ cr_parser_parse_simple_selector (CRParser * a_this, CRSimpleSel ** a_sel)
&& token->u.unichar == '*') {
int comb = (int)sel->type_mask | (int) UNIVERSAL_SELECTOR;
sel->type_mask = (enum SimpleSelectorType)comb;
- //sel->type_mask |= UNIVERSAL_SELECTOR;
sel->name = cr_string_new_from_string ("*");
found_sel = TRUE;
} else if (token && token->type == IDENT_TK) {
sel->name = token->u.str;
int comb = (int)sel->type_mask | (int) TYPE_SELECTOR;
sel->type_mask = (enum SimpleSelectorType)comb;
- //sel->type_mask |= TYPE_SELECTOR;
token->u.str = NULL;
found_sel = TRUE;
} else {
@@ -2707,7 +2705,7 @@ cr_parser_parse_stylesheet (CRParser * a_this)
}
cr_parser_push_error
- (a_this, "could not recognize next production", CR_ERROR);
+ (a_this, (const guchar *) "could not recognize next production", CR_ERROR);
if (PRIVATE (a_this)->sac_handler
&& PRIVATE (a_this)->sac_handler->unrecoverable_error) {
@@ -3193,7 +3191,7 @@ cr_parser_parse_declaration (CRParser * a_this,
CHECK_PARSING_STATUS_ERR
(a_this, status, FALSE,
- "while parsing declaration: next property is malformed",
+ (const guchar *) "while parsing declaration: next property is malformed",
CR_SYNTAX_ERROR);
READ_NEXT_CHAR (a_this, &cur_char);
@@ -3202,7 +3200,7 @@ cr_parser_parse_declaration (CRParser * a_this,
status = CR_PARSING_ERROR;
cr_parser_push_error
(a_this,
- "while parsing declaration: this char must be ':'",
+ (const guchar *) "while parsing declaration: this char must be ':'",
CR_SYNTAX_ERROR);
goto error;
}
@@ -3213,7 +3211,7 @@ cr_parser_parse_declaration (CRParser * a_this,
CHECK_PARSING_STATUS_ERR
(a_this, status, FALSE,
- "while parsing declaration: next expression is malformed",
+ (const guchar *) "while parsing declaration: next expression is malformed",
CR_SYNTAX_ERROR);
cr_parser_try_to_skip_spaces_and_comments (a_this);
@@ -3353,7 +3351,7 @@ cr_parser_parse_ruleset (CRParser * a_this)
ENSURE_PARSING_COND_ERR
(a_this, cur_char == '{',
- "while parsing rulset: current char should be '{'",
+ (const guchar *) "while parsing rulset: current char should be '{'",
CR_SYNTAX_ERROR);
if (PRIVATE (a_this)->sac_handler
@@ -3417,7 +3415,7 @@ cr_parser_parse_ruleset (CRParser * a_this)
}
CHECK_PARSING_STATUS_ERR
(a_this, status, FALSE,
- "while parsing ruleset: next construction should be a declaration",
+ (const guchar *) "while parsing ruleset: next construction should be a declaration",
CR_SYNTAX_ERROR);
for (;;) {
@@ -3459,7 +3457,7 @@ cr_parser_parse_ruleset (CRParser * a_this)
READ_NEXT_CHAR (a_this, &cur_char);
ENSURE_PARSING_COND_ERR
(a_this, cur_char == '}',
- "while parsing rulset: current char must be a '}'",
+ (const guchar *) "while parsing rulset: current char must be a '}'",
CR_SYNTAX_ERROR);
selector->location = end_parsing_location;
diff --git a/src/libcroco/cr-pseudo.c b/src/libcroco/cr-pseudo.c
index a46e69ed0..cee3fc869 100644
--- a/src/libcroco/cr-pseudo.c
+++ b/src/libcroco/cr-pseudo.c
@@ -68,11 +68,11 @@ cr_pseudo_to_string (CRPseudo const * a_this)
goto error;
}
- name = g_strndup (a_this->name->stryng->str,
+ name = (guchar *) g_strndup (a_this->name->stryng->str,
a_this->name->stryng->len);
if (name) {
- g_string_append (str_buf, name);
+ g_string_append (str_buf, (const gchar *) name);
g_free (name);
name = NULL;
}
@@ -83,11 +83,11 @@ cr_pseudo_to_string (CRPseudo const * a_this)
if (a_this->name == NULL)
goto error;
- name = g_strndup (a_this->name->stryng->str,
+ name = (guchar *) g_strndup (a_this->name->stryng->str,
a_this->name->stryng->len);
if (a_this->extra) {
- arg = g_strndup (a_this->extra->stryng->str,
+ arg = (guchar *) g_strndup (a_this->extra->stryng->str,
a_this->extra->stryng->len);
}
@@ -97,7 +97,7 @@ cr_pseudo_to_string (CRPseudo const * a_this)
name = NULL;
if (arg) {
- g_string_append (str_buf, arg);
+ g_string_append (str_buf, (const gchar *) arg);
g_free (arg);
arg = NULL;
}
@@ -107,7 +107,7 @@ cr_pseudo_to_string (CRPseudo const * a_this)
}
if (str_buf) {
- result = str_buf->str;
+ result = (guchar *) str_buf->str;
g_string_free (str_buf, FALSE);
str_buf = NULL;
}
diff --git a/src/libcroco/cr-rgb.c b/src/libcroco/cr-rgb.c
index 537343579..889f248b6 100644
--- a/src/libcroco/cr-rgb.c
+++ b/src/libcroco/cr-rgb.c
@@ -275,7 +275,7 @@ cr_rgb_to_string (CRRgb const * a_this)
}
if (str_buf) {
- result = str_buf->str;
+ result = (guchar *) str_buf->str;
g_string_free (str_buf, FALSE);
}
@@ -507,7 +507,7 @@ cr_rgb_set_from_hex_str (CRRgb * a_this, const guchar * a_hex)
g_return_val_if_fail (a_this && a_hex, CR_BAD_PARAM_ERROR);
- if (strlen (a_hex) == 3) {
+ if (strlen ((const char *) a_hex) == 3) {
for (i = 0; i < 3; i++) {
if (a_hex[i] >= '0' && a_hex[i] <= '9') {
colors[i] = a_hex[i] - '0';
@@ -522,7 +522,7 @@ cr_rgb_set_from_hex_str (CRRgb * a_this, const guchar * a_hex)
status = CR_UNKNOWN_TYPE_ERROR;
}
}
- } else if (strlen (a_hex) == 6) {
+ } else if (strlen ((const char *) a_hex) == 6) {
for (i = 0; i < 6; i++) {
if (a_hex[i] >= '0' && a_hex[i] <= '9') {
colors[i / 2] <<= 4;
@@ -587,7 +587,7 @@ cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value)
} else {
status = cr_rgb_set_from_name
(a_this,
- a_value->content.str->stryng->str) ;
+ (const guchar *) a_value->content.str->stryng->str) ;
}
} else {
cr_utils_trace_info
@@ -600,7 +600,7 @@ cr_rgb_set_from_term (CRRgb *a_this, const struct _CRTerm *a_value)
&& a_value->content.str->stryng->str) {
status = cr_rgb_set_from_hex_str
(a_this,
- a_value->content.str->stryng->str) ;
+ (const guchar *) a_value->content.str->stryng->str) ;
} else {
cr_utils_trace_info
("a_value has NULL string value") ;
@@ -656,8 +656,7 @@ cr_rgb_parse_from_buf (const guchar *a_str,
g_return_val_if_fail (a_str, NULL);
- parser = cr_parser_new_from_buf ((guchar*)a_str, strlen (a_str),
- a_enc, FALSE) ;
+ parser = cr_parser_new_from_buf ((guchar *) a_str, strlen ((const char *) a_str), a_enc, FALSE);
g_return_val_if_fail (parser, NULL);
diff --git a/src/libcroco/cr-sel-eng.c b/src/libcroco/cr-sel-eng.c
index 4f501ee05..6f496df2f 100644
--- a/src/libcroco/cr-sel-eng.c
+++ b/src/libcroco/cr-sel-eng.c
@@ -37,7 +37,7 @@
#define PRIVATE(a_this) (a_this)->priv
struct CRPseudoClassSelHandlerEntry {
- char *name;
+ guchar *name;
enum CRPseudoType type;
CRPseudoClassSelectorHandler handler;
};
@@ -139,7 +139,7 @@ lang_pseudo_class_handler (CRSelEng *const a_this,
/* "xml:lang" needed for SVG */
if ( (strqcmp (a_sel->content.pseudo->name->stryng->str, "lang", 4 ) &&
(strqcmp (a_sel->content.pseudo->name->stryng->str, "xml:lang", 8 ) ) )
- || !a_sel->content.pseudo->type == FUNCTION_PSEUDO) {
+ || a_sel->content.pseudo->type != FUNCTION_PSEUDO) {
cr_utils_trace_info ("This handler is for :lang only");
return FALSE;
}
@@ -149,8 +149,8 @@ lang_pseudo_class_handler (CRSelEng *const a_this,
|| a_sel->content.pseudo->extra->stryng->len < 2)
return FALSE;
for (; node; node = get_next_parent_element_node (node_iface, node)) {
- char *val = node_iface->getProp (node, "lang");
- if (!val) val = node_iface->getProp (node, "xml:lang");
+ char *val = node_iface->getProp (node, (const xmlChar *) "lang");
+ if (!val) val = node_iface->getProp (node, (const xmlChar *) "xml:lang");
if (val) {
if (!strcasecmp(val, a_sel->content.pseudo->extra->stryng->str)) {
result = TRUE;
@@ -180,7 +180,7 @@ first_child_pseudo_class_handler (CRSelEng *const a_this,
if (strcmp (a_sel->content.pseudo->name->stryng->str,
"first-child")
- || !a_sel->content.pseudo->type == IDENT_PSEUDO) {
+ || a_sel->content.pseudo->type != IDENT_PSEUDO) {
cr_utils_trace_info ("This handler is for :first-child only");
return FALSE;
}
@@ -209,7 +209,7 @@ pseudo_class_add_sel_matches_node (CRSelEng * a_this,
&& a_node, FALSE);
status = cr_sel_eng_get_pseudo_class_selector_handler
- (a_this, a_add_sel->content.pseudo->name->stryng->str,
+ (a_this, (guchar *) a_add_sel->content.pseudo->name->stryng->str,
a_add_sel->content.pseudo->type, &handler);
if (status != CR_OK || !handler)
return FALSE;
@@ -237,7 +237,7 @@ class_add_sel_matches_node (CRAdditionalSel * a_add_sel,
&& a_add_sel->content.class_name->stryng->str
&& a_node, FALSE);
- klass = a_node_iface->getProp (a_node, "class");
+ klass = a_node_iface->getProp (a_node, (const xmlChar *) "class");
if (klass) {
char const *cur;
for (cur = klass; cur && *cur; cur++) {
@@ -246,7 +246,7 @@ class_add_sel_matches_node (CRAdditionalSel * a_add_sel,
== TRUE)
cur++;
- if (!strncmp (cur,
+ if (!strncmp ((const char *) cur,
a_add_sel->content.class_name->stryng->str,
a_add_sel->content.class_name->stryng->len)) {
cur += a_add_sel->content.class_name->stryng->len;
@@ -291,9 +291,9 @@ id_add_sel_matches_node (CRAdditionalSel * a_add_sel,
&& a_add_sel->type == ID_ADD_SELECTOR
&& a_node, FALSE);
- id = a_node_iface->getProp (a_node, "id");
+ id = a_node_iface->getProp (a_node, (const xmlChar *) "id");
if (id) {
- if (!strqcmp (id, a_add_sel->content.id_name->stryng->str,
+ if (!strqcmp ((const char *) id, a_add_sel->content.id_name->stryng->str,
a_add_sel->content.id_name->stryng->len)) {
result = TRUE;
}
@@ -324,7 +324,7 @@ attr_add_sel_matches_node (CRAdditionalSel * a_add_sel,
for (cur_sel = a_add_sel->content.attr_sel;
cur_sel; cur_sel = cur_sel->next) {
- if (!cur_sel->name
+ if (!cur_sel->name
|| !cur_sel->name->stryng
|| !cur_sel->name->stryng->str)
return FALSE;
@@ -384,7 +384,7 @@ attr_add_sel_matches_node (CRAdditionalSel * a_add_sel,
ptr2 = cur;
if (!strncmp
- (ptr1,
+ ((const char *) ptr1,
cur_sel->value->stryng->str,
ptr2 - ptr1 + 1)) {
found = TRUE;
@@ -422,7 +422,7 @@ attr_add_sel_matches_node (CRAdditionalSel * a_add_sel,
ptr2 = cur;
if (g_strstr_len
- (ptr1, ptr2 - ptr1 + 1,
+ ((const gchar *) ptr1, ptr2 - ptr1 + 1,
cur_sel->value->stryng->str)
== ptr1) {
found = TRUE;
@@ -635,7 +635,7 @@ sel_matches_node_real (CRSelEng * a_this, CRSimpleSel * a_sel,
&& cur_sel->name->stryng
&& cur_sel->name->stryng->str)
&& (!strcmp (cur_sel->name->stryng->str,
- node_iface->getLocalName(cur_node))))
+ (const char *) node_iface->getLocalName(cur_node))))
|| (cur_sel->type_mask & UNIVERSAL_SELECTOR)) {
/*
*this simple selector
@@ -1121,11 +1121,11 @@ cr_sel_eng_new (void)
}
memset (PRIVATE (result), 0, sizeof (CRSelEngPriv));
cr_sel_eng_register_pseudo_class_sel_handler
- (result, "first-child",
+ (result, (guchar *) "first-child",
IDENT_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
first_child_pseudo_class_handler);
cr_sel_eng_register_pseudo_class_sel_handler
- (result, "lang",
+ (result, (guchar *) "lang",
FUNCTION_PSEUDO, /*(CRPseudoClassSelectorHandler)*/
lang_pseudo_class_handler);
@@ -1146,7 +1146,7 @@ cr_sel_eng_new (void)
*/
enum CRStatus
cr_sel_eng_register_pseudo_class_sel_handler (CRSelEng * a_this,
- char * a_name,
+ guchar * a_name,
enum CRPseudoType a_type,
CRPseudoClassSelectorHandler
a_handler)
@@ -1164,7 +1164,7 @@ cr_sel_eng_register_pseudo_class_sel_handler (CRSelEng * a_this,
}
memset (handler_entry, 0,
sizeof (struct CRPseudoClassSelHandlerEntry));
- handler_entry->name = g_strdup (a_name);
+ handler_entry->name = (guchar *) g_strdup ((const gchar *) a_name);
handler_entry->type = a_type;
handler_entry->handler = a_handler;
list = g_list_append (PRIVATE (a_this)->pcs_handlers, handler_entry);
@@ -1177,7 +1177,7 @@ cr_sel_eng_register_pseudo_class_sel_handler (CRSelEng * a_this,
enum CRStatus
cr_sel_eng_unregister_pseudo_class_sel_handler (CRSelEng * a_this,
- char * a_name,
+ guchar * a_name,
enum CRPseudoType a_type)
{
GList *elem = NULL,
@@ -1190,7 +1190,7 @@ cr_sel_eng_unregister_pseudo_class_sel_handler (CRSelEng * a_this,
for (elem = PRIVATE (a_this)->pcs_handlers;
elem; elem = g_list_next (elem)) {
entry = (struct CRPseudoClassSelHandlerEntry *) elem->data;
- if (!strcmp (entry->name, a_name)
+ if (!strcmp ((const char *) entry->name, (const char *) a_name)
&& entry->type == a_type) {
found = TRUE;
break;
@@ -1250,7 +1250,7 @@ cr_sel_eng_unregister_all_pseudo_class_sel_handlers (CRSelEng * a_this)
enum CRStatus
cr_sel_eng_get_pseudo_class_selector_handler (CRSelEng * a_this,
- char * a_name,
+ guchar * a_name,
enum CRPseudoType a_type,
CRPseudoClassSelectorHandler *
a_handler)
@@ -1265,7 +1265,7 @@ cr_sel_eng_get_pseudo_class_selector_handler (CRSelEng * a_this,
for (elem = PRIVATE (a_this)->pcs_handlers;
elem; elem = g_list_next (elem)) {
entry = (struct CRPseudoClassSelHandlerEntry *) elem->data;
- if (!strcmp (a_name, entry->name)
+ if (!strcmp ((const char *) a_name, (const char *) entry->name)
&& entry->type == a_type) {
found = TRUE;
break;
diff --git a/src/libcroco/cr-sel-eng.h b/src/libcroco/cr-sel-eng.h
index 4d09f9c95..564debc8d 100644
--- a/src/libcroco/cr-sel-eng.h
+++ b/src/libcroco/cr-sel-eng.h
@@ -65,18 +65,18 @@ typedef gboolean (*CRPseudoClassSelectorHandler) (CRSelEng* a_this,
CRSelEng * cr_sel_eng_new (void) ;
enum CRStatus cr_sel_eng_register_pseudo_class_sel_handler (CRSelEng *a_this,
- char *a_pseudo_class_sel_name,
+ guchar *a_pseudo_class_sel_name,
enum CRPseudoType a_pseudo_class_type,
CRPseudoClassSelectorHandler a_handler) ;
enum CRStatus cr_sel_eng_unregister_pseudo_class_sel_handler (CRSelEng *a_this,
- char *a_pseudo_class_sel_name,
+ guchar *a_pseudo_class_sel_name,
enum CRPseudoType a_pseudo_class_type) ;
enum CRStatus cr_sel_eng_unregister_all_pseudo_class_sel_handlers (CRSelEng *a_this) ;
enum CRStatus cr_sel_eng_get_pseudo_class_selector_handler (CRSelEng *a_this,
- char *a_pseudo_class_sel_name,
+ guchar *a_pseudo_class_sel_name,
enum CRPseudoType a_pseudo_class_type,
CRPseudoClassSelectorHandler *a_handler) ;
diff --git a/src/libcroco/cr-selector.c b/src/libcroco/cr-selector.c
index 43a3bd914..c56c43fda 100644
--- a/src/libcroco/cr-selector.c
+++ b/src/libcroco/cr-selector.c
@@ -38,7 +38,10 @@
CRSelector *
cr_selector_new (CRSimpleSel * a_simple_sel)
{
- CRSelector *result = (CRSelector *)g_try_malloc (sizeof (CRSelector));
+ CRSelector *result = NULL;
+
+ result = (CRSelector *) g_try_malloc (sizeof (CRSelector));
+
if (!result) {
cr_utils_trace_info ("Out of memory");
return NULL;
@@ -55,8 +58,7 @@ cr_selector_parse_from_buf (const guchar * a_char_buf, enum CREncoding a_enc)
g_return_val_if_fail (a_char_buf, NULL);
- parser = cr_parser_new_from_buf ((guchar*)a_char_buf,
- strlen ((char *)a_char_buf),
+ parser = cr_parser_new_from_buf ((guchar*)a_char_buf, strlen ((const char *) a_char_buf),
a_enc, FALSE);
g_return_val_if_fail (parser, NULL);
@@ -140,8 +142,9 @@ guchar *
cr_selector_to_string (CRSelector const * a_this)
{
guchar *result = NULL;
+ GString *str_buf = NULL;
- GString *str_buf = (GString *)g_string_new (NULL);
+ str_buf = (GString *) g_string_new (NULL);
g_return_val_if_fail (str_buf, NULL);
if (a_this) {
@@ -159,7 +162,7 @@ cr_selector_to_string (CRSelector const * a_this)
g_string_append (str_buf,
", ");
- g_string_append (str_buf, (gchar *)tmp_str);
+ g_string_append (str_buf, (const gchar *) tmp_str);
g_free (tmp_str);
tmp_str = NULL;
@@ -169,7 +172,7 @@ cr_selector_to_string (CRSelector const * a_this)
}
if (str_buf) {
- result = (guchar *)str_buf->str;
+ result = (guchar *) str_buf->str;
g_string_free (str_buf, FALSE);
str_buf = NULL;
}
diff --git a/src/libcroco/cr-simple-sel.c b/src/libcroco/cr-simple-sel.c
index 4f5ac965a..4df93fa77 100644
--- a/src/libcroco/cr-simple-sel.c
+++ b/src/libcroco/cr-simple-sel.c
@@ -35,7 +35,9 @@
CRSimpleSel *
cr_simple_sel_new (void)
{
- CRSimpleSel *result = (CRSimpleSel *)g_try_malloc (sizeof (CRSimpleSel));
+ CRSimpleSel *result = NULL;
+
+ result = (CRSimpleSel *) g_try_malloc (sizeof (CRSimpleSel));
if (!result) {
cr_utils_trace_info ("Out of memory");
return NULL;
@@ -110,7 +112,7 @@ cr_simple_sel_to_string (CRSimpleSel const * a_this)
str_buf = g_string_new (NULL);
for (cur = a_this; cur; cur = cur->next) {
if (cur->name) {
- gchar *str = g_strndup (cur->name->stryng->str,
+ guchar *str = (guchar *) g_strndup (cur->name->stryng->str,
cur->name->stryng->len);
if (str) {
@@ -131,17 +133,18 @@ cr_simple_sel_to_string (CRSimpleSel const * a_this)
break;
}
- g_string_append (str_buf, str);
+ g_string_append (str_buf, (const gchar *) str);
g_free (str);
str = NULL;
}
}
if (cur->add_sel) {
+ guchar *tmp_str = NULL;
- gchar *tmp_str = (gchar *)cr_additional_sel_to_string (cur->add_sel);
+ tmp_str = cr_additional_sel_to_string (cur->add_sel);
if (tmp_str) {
- g_string_append (str_buf, tmp_str);
+ g_string_append (str_buf, (const gchar *) tmp_str);
g_free (tmp_str);
tmp_str = NULL;
}
@@ -149,7 +152,7 @@ cr_simple_sel_to_string (CRSimpleSel const * a_this)
}
if (str_buf) {
- result = (guchar *)str_buf->str;
+ result = (guchar *) str_buf->str;
g_string_free (str_buf, FALSE);
str_buf = NULL;
}
@@ -168,7 +171,7 @@ cr_simple_sel_one_to_string (CRSimpleSel const * a_this)
str_buf = g_string_new (NULL);
if (a_this->name) {
- gchar *str = g_strndup (a_this->name->stryng->str,
+ guchar *str = (guchar *) g_strndup (a_this->name->stryng->str,
a_this->name->stryng->len);
if (str) {
@@ -179,8 +182,9 @@ cr_simple_sel_one_to_string (CRSimpleSel const * a_this)
}
if (a_this->add_sel) {
+ guchar *tmp_str = NULL;
- gchar *tmp_str = (gchar *)cr_additional_sel_to_string (a_this->add_sel);
+ tmp_str = cr_additional_sel_to_string (a_this->add_sel);
if (tmp_str) {
g_string_append_printf
(str_buf, "%s", tmp_str);
@@ -190,7 +194,7 @@ cr_simple_sel_one_to_string (CRSimpleSel const * a_this)
}
if (str_buf) {
- result = (guchar *)str_buf->str;
+ result = (guchar *) str_buf->str;
g_string_free (str_buf, FALSE);
str_buf = NULL;
}
@@ -250,7 +254,7 @@ cr_simple_sel_compute_specificity (CRSimpleSel * a_this)
g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
for (cur_sel = a_this; cur_sel; cur_sel = cur_sel->next) {
- if (cur_sel->type_mask | TYPE_SELECTOR) {
+ if (cur_sel->type_mask & TYPE_SELECTOR) {
c++; /*hmmh, is this a new language ? */
} else if (!cur_sel->name
|| !cur_sel->name->stryng
diff --git a/src/libcroco/cr-statement.c b/src/libcroco/cr-statement.c
index 4666f26ec..e31123aec 100644
--- a/src/libcroco/cr-statement.c
+++ b/src/libcroco/cr-statement.c
@@ -25,8 +25,6 @@
#include "cr-statement.h"
#include "cr-parser.h"
-#define UNUSED(_param) ((void)(_param))
-
/**
*@file
*Definition of the #CRStatement class.
@@ -38,12 +36,12 @@ static void cr_statement_clear (CRStatement * a_this);
static void
parse_font_face_start_font_face_cb (CRDocHandler * a_this,
- CRParsingLocation * a_location)
+ CRParsingLocation *a_location)
{
CRStatement *stmt = NULL;
enum CRStatus status = CR_OK;
- UNUSED(a_location);
+ (void) a_location;
stmt = cr_statement_new_at_font_face_rule (NULL, NULL);
g_return_if_fail (stmt);
@@ -86,7 +84,7 @@ parse_font_face_property_cb (CRDocHandler * a_this,
CRStatement *stmt = NULL;
CRStatement **stmtptr = NULL;
- UNUSED(a_important);
+ (void) a_important;
g_return_if_fail (a_this && a_name);
@@ -144,13 +142,13 @@ static void
parse_page_start_page_cb (CRDocHandler * a_this,
CRString * a_name,
CRString * a_pseudo_page,
- CRParsingLocation * a_location)
+ CRParsingLocation *a_location)
{
CRStatement *stmt = NULL;
enum CRStatus status = CR_OK;
CRString *page_name = NULL, *pseudo_name = NULL ;
- UNUSED(a_location);
+ (void) a_location;
if (a_name)
page_name = cr_string_dup (a_name) ;
@@ -225,8 +223,8 @@ parse_page_end_page_cb (CRDocHandler * a_this,
CRStatement *stmt = NULL;
CRStatement **stmtptr = NULL;
- UNUSED(a_name);
- UNUSED(a_pseudo_page);
+ (void) a_name;
+ (void) a_pseudo_page;
stmtptr = &stmt;
status = cr_doc_handler_get_ctxt (a_this, (gpointer *) stmtptr);
@@ -240,13 +238,13 @@ parse_page_end_page_cb (CRDocHandler * a_this,
static void
parse_at_media_start_media_cb (CRDocHandler * a_this,
GList * a_media_list,
- CRParsingLocation * a_location)
+ CRParsingLocation *a_location)
{
enum CRStatus status = CR_OK;
CRStatement *at_media = NULL;
GList *media_list = NULL;
- UNUSED(a_location);
+ (void) a_location;
g_return_if_fail (a_this && a_this->priv);
@@ -380,7 +378,7 @@ parse_at_media_end_media_cb (CRDocHandler * a_this,
CRStatement *at_media = NULL;
CRStatement **at_media_ptr = NULL;
- UNUSED(a_media_list);
+ (void) a_media_list;
g_return_if_fail (a_this && a_this->priv);
@@ -603,12 +601,13 @@ cr_statement_clear (CRStatement * a_this)
static gchar *
cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent)
{
+ GString *stringue = NULL;
gchar *tmp_str = NULL,
*result = NULL;
g_return_val_if_fail (a_this && a_this->type == RULESET_STMT, NULL);
- GString * stringue = (GString *)g_string_new (NULL);
+ stringue = (GString *) g_string_new (NULL);
if (!stringue) {
return result;
}
@@ -617,8 +616,8 @@ cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent)
if (a_indent)
cr_utils_dump_n_chars2 (' ', stringue, a_indent);
- tmp_str = (gchar *)
- cr_selector_to_string (a_this->kind.ruleset->
+ tmp_str =
+ (gchar *) cr_selector_to_string (a_this->kind.ruleset->
sel_list);
if (tmp_str) {
g_string_append (stringue, tmp_str);
@@ -628,7 +627,7 @@ cr_statement_ruleset_to_string (CRStatement const * a_this, glong a_indent)
}
g_string_append (stringue, " {\n");
if (a_this->kind.ruleset->decl_list) {
- tmp_str = (gchar *)cr_declaration_list_to_string2
+ tmp_str = (gchar *) cr_declaration_list_to_string2
(a_this->kind.ruleset->decl_list,
a_indent + DECLARATION_INDENT_NB, TRUE);
if (tmp_str) {
@@ -677,13 +676,13 @@ cr_statement_font_face_rule_to_string (CRStatement const * a_this,
NULL);
if (a_this->kind.font_face_rule->decl_list) {
- stringue = (GString *)g_string_new (NULL) ;
+ stringue = (GString *) g_string_new (NULL) ;
g_return_val_if_fail (stringue, NULL) ;
if (a_indent)
cr_utils_dump_n_chars2 (' ', stringue,
a_indent);
g_string_append (stringue, "@font-face {\n");
- tmp_str = (gchar *)cr_declaration_list_to_string2
+ tmp_str = (gchar *) cr_declaration_list_to_string2
(a_this->kind.font_face_rule->decl_list,
a_indent + DECLARATION_INDENT_NB, TRUE) ;
if (tmp_str) {
@@ -762,9 +761,10 @@ static gchar *
cr_statement_at_page_rule_to_string (CRStatement const *a_this,
gulong a_indent)
{
+ GString *stringue = NULL;
gchar *result = NULL ;
- GString *stringue = (GString *)g_string_new (NULL) ;
+ stringue = (GString *) g_string_new (NULL) ;
cr_utils_dump_n_chars2 (' ', stringue, a_indent) ;
g_string_append (stringue, "@page");
@@ -785,7 +785,7 @@ cr_statement_at_page_rule_to_string (CRStatement const *a_this,
if (a_this->kind.page_rule->decl_list) {
gchar *str = NULL ;
g_string_append (stringue, " {\n");
- str = (gchar *)cr_declaration_list_to_string2
+ str = (gchar *) cr_declaration_list_to_string2
(a_this->kind.page_rule->decl_list,
a_indent + DECLARATION_INDENT_NB, TRUE) ;
if (str) {
@@ -821,17 +821,17 @@ cr_statement_media_rule_to_string (CRStatement const *a_this,
NULL);
if (a_this->kind.media_rule) {
- stringue = (GString *)g_string_new (NULL) ;
+ stringue = (GString *) g_string_new (NULL) ;
cr_utils_dump_n_chars2 (' ', stringue, a_indent);
g_string_append (stringue, "@media");
for (cur = a_this->kind.media_rule->media_list; cur;
cur = cur->next) {
if (cur->data) {
- gchar *str = cr_string_dup2
+ gchar *str2 = cr_string_dup2
((CRString const *) cur->data);
- if (str) {
+ if (str2) {
if (cur->prev) {
g_string_append
(stringue,
@@ -839,9 +839,9 @@ cr_statement_media_rule_to_string (CRStatement const *a_this,
}
g_string_append_printf
(stringue,
- " %s", str);
- g_free (str);
- str = NULL;
+ " %s", str2);
+ g_free (str2);
+ str2 = NULL;
}
}
}
@@ -878,7 +878,7 @@ cr_statement_import_rule_to_string (CRStatement const *a_this,
if (a_this->kind.import_rule->url
&& a_this->kind.import_rule->url->stryng) {
- stringue = (GString *)g_string_new (NULL) ;
+ stringue = (GString *) g_string_new (NULL) ;
g_return_val_if_fail (stringue, NULL) ;
str = g_strndup (a_this->kind.import_rule->url->stryng->str,
a_this->kind.import_rule->url->stryng->len);
@@ -950,8 +950,7 @@ cr_statement_does_buf_parses_against_core (const guchar * a_buf,
enum CRStatus status = CR_OK;
gboolean result = FALSE;
- parser = cr_parser_new_from_buf ((guchar*)a_buf,
- strlen ((char *)a_buf),
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
a_encoding, FALSE);
g_return_val_if_fail (parser, FALSE);
@@ -1071,8 +1070,7 @@ cr_statement_ruleset_parse_from_buf (const guchar * a_buf,
g_return_val_if_fail (a_buf, NULL);
- parser = cr_parser_new_from_buf ((guchar*)a_buf,
- strlen ((char *)a_buf),
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
a_enc, FALSE);
g_return_val_if_fail (parser, NULL);
@@ -1138,6 +1136,8 @@ cr_statement_new_ruleset (CRStyleSheet * a_sheet,
CRDeclaration * a_decl_list,
CRStatement * a_parent_media_rule)
{
+ CRStatement *result = NULL;
+
g_return_val_if_fail (a_sel_list, NULL);
if (a_parent_media_rule) {
@@ -1148,7 +1148,7 @@ cr_statement_new_ruleset (CRStyleSheet * a_sheet,
NULL);
}
- CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
if (!result) {
cr_utils_trace_info ("Out of memory");
@@ -1157,7 +1157,7 @@ cr_statement_new_ruleset (CRStyleSheet * a_sheet,
memset (result, 0, sizeof (CRStatement));
result->type = RULESET_STMT;
- result->kind.ruleset = (CRRuleSet *)g_try_malloc (sizeof (CRRuleSet));
+ result->kind.ruleset = (CRRuleSet *) g_try_malloc (sizeof (CRRuleSet));
if (!result->kind.ruleset) {
cr_utils_trace_info ("Out of memory");
@@ -1207,8 +1207,7 @@ cr_statement_at_media_rule_parse_from_buf (const guchar * a_buf,
CRDocHandler *sac_handler = NULL;
enum CRStatus status = CR_OK;
- parser = cr_parser_new_from_buf ((guchar*)a_buf,
- strlen ((char *)a_buf),
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
a_enc, FALSE);
if (!parser) {
cr_utils_trace_info ("Instanciation of the parser failed");
@@ -1278,12 +1277,13 @@ CRStatement *
cr_statement_new_at_media_rule (CRStyleSheet * a_sheet,
CRStatement * a_rulesets, GList * a_media)
{
- CRStatement *cur = NULL;
+ CRStatement *result = NULL,
+ *cur = NULL;
if (a_rulesets)
g_return_val_if_fail (a_rulesets->type == RULESET_STMT, NULL);
- CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
if (!result) {
cr_utils_trace_info ("Out of memory");
@@ -1293,7 +1293,7 @@ cr_statement_new_at_media_rule (CRStyleSheet * a_sheet,
memset (result, 0, sizeof (CRStatement));
result->type = AT_MEDIA_RULE_STMT;
- result->kind.media_rule = (CRAtMediaRule *)g_try_malloc (sizeof (CRAtMediaRule));
+ result->kind.media_rule = (CRAtMediaRule *) g_try_malloc (sizeof (CRAtMediaRule));
if (!result->kind.media_rule) {
cr_utils_trace_info ("Out of memory");
g_free (result);
@@ -1340,7 +1340,9 @@ cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet,
GList * a_media_list,
CRStyleSheet * a_imported_sheet)
{
- CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
+ CRStatement *result = NULL;
+
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
if (!result) {
cr_utils_trace_info ("Out of memory");
@@ -1350,7 +1352,7 @@ cr_statement_new_at_import_rule (CRStyleSheet * a_container_sheet,
memset (result, 0, sizeof (CRStatement));
result->type = AT_IMPORT_RULE_STMT;
- result->kind.import_rule = (CRAtImportRule *)g_try_malloc (sizeof (CRAtImportRule));
+ result->kind.import_rule = (CRAtImportRule *) g_try_malloc (sizeof (CRAtImportRule));
if (!result->kind.import_rule) {
cr_utils_trace_info ("Out of memory");
@@ -1391,8 +1393,7 @@ cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf,
CRString *import_string = NULL;
CRParsingLocation location = {0,0,0} ;
- parser = cr_parser_new_from_buf ((guchar*)a_buf,
- strlen ((char *)a_buf),
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
a_encoding, FALSE);
if (!parser) {
cr_utils_trace_info ("Instanciation of parser failed.");
@@ -1425,8 +1426,7 @@ cr_statement_at_import_rule_parse_from_buf (const guchar * a_buf,
parser = NULL;
}
if (media_list) {
- GList *cur = NULL;
- for (cur = media_list; media_list;
+ for (; media_list;
media_list = g_list_next (media_list)) {
if (media_list->data) {
cr_string_destroy ((CRString*)media_list->data);
@@ -1463,7 +1463,9 @@ cr_statement_new_at_page_rule (CRStyleSheet * a_sheet,
CRDeclaration * a_decl_list,
CRString * a_name, CRString * a_pseudo)
{
- CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
+ CRStatement *result = NULL;
+
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
if (!result) {
cr_utils_trace_info ("Out of memory");
@@ -1473,7 +1475,7 @@ cr_statement_new_at_page_rule (CRStyleSheet * a_sheet,
memset (result, 0, sizeof (CRStatement));
result->type = AT_PAGE_RULE_STMT;
- result->kind.page_rule = (CRAtPageRule *)g_try_malloc (sizeof (CRAtPageRule));
+ result->kind.page_rule = (CRAtPageRule *) g_try_malloc (sizeof (CRAtPageRule));
if (!result->kind.page_rule) {
cr_utils_trace_info ("Out of memory");
@@ -1511,14 +1513,14 @@ cr_statement_at_page_rule_parse_from_buf (const guchar * a_buf,
enum CREncoding a_encoding)
{
enum CRStatus status = CR_OK;
+ CRParser *parser = NULL;
CRDocHandler *sac_handler = NULL;
CRStatement *result = NULL;
CRStatement **resultptr = NULL;
g_return_val_if_fail (a_buf, NULL);
- CRParser *parser = cr_parser_new_from_buf ((guchar*)a_buf,
- strlen ((char *)a_buf),
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
a_encoding, FALSE);
if (!parser) {
cr_utils_trace_info ("Instanciation of the parser failed.");
@@ -1584,9 +1586,11 @@ CRStatement *
cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet,
CRString * a_charset)
{
+ CRStatement *result = NULL;
+
g_return_val_if_fail (a_charset, NULL);
- CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
if (!result) {
cr_utils_trace_info ("Out of memory");
@@ -1596,7 +1600,7 @@ cr_statement_new_at_charset_rule (CRStyleSheet * a_sheet,
memset (result, 0, sizeof (CRStatement));
result->type = AT_CHARSET_RULE_STMT;
- result->kind.charset_rule = (CRAtCharsetRule *)g_try_malloc (sizeof (CRAtCharsetRule));
+ result->kind.charset_rule = (CRAtCharsetRule *) g_try_malloc (sizeof (CRAtCharsetRule));
if (!result->kind.charset_rule) {
cr_utils_trace_info ("Out of memory");
@@ -1626,13 +1630,13 @@ cr_statement_at_charset_rule_parse_from_buf (const guchar * a_buf,
enum CREncoding a_encoding)
{
enum CRStatus status = CR_OK;
+ CRParser *parser = NULL;
CRStatement *result = NULL;
CRString *charset = NULL;
g_return_val_if_fail (a_buf, NULL);
- CRParser *parser = cr_parser_new_from_buf ((guchar*)a_buf,
- strlen ((char *)a_buf),
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
a_encoding, FALSE);
if (!parser) {
cr_utils_trace_info ("Instanciation of the parser failed.");
@@ -1678,7 +1682,9 @@ CRStatement *
cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet,
CRDeclaration * a_font_decls)
{
- CRStatement *result = (CRStatement *)g_try_malloc (sizeof (CRStatement));
+ CRStatement *result = NULL;
+
+ result = (CRStatement *) g_try_malloc (sizeof (CRStatement));
if (!result) {
cr_utils_trace_info ("Out of memory");
@@ -1687,7 +1693,7 @@ cr_statement_new_at_font_face_rule (CRStyleSheet * a_sheet,
memset (result, 0, sizeof (CRStatement));
result->type = AT_FONT_FACE_RULE_STMT;
- result->kind.font_face_rule = (CRAtFontFaceRule *)g_try_malloc
+ result->kind.font_face_rule = (CRAtFontFaceRule *) g_try_malloc
(sizeof (CRAtFontFaceRule));
if (!result->kind.font_face_rule) {
@@ -1723,12 +1729,11 @@ cr_statement_font_face_rule_parse_from_buf (const guchar * a_buf,
{
CRStatement *result = NULL;
CRStatement **resultptr = NULL;
+ CRParser *parser = NULL;
CRDocHandler *sac_handler = NULL;
enum CRStatus status = CR_OK;
- CRParser *parser = (CRParser *)cr_parser_new_from_buf (
- (guchar*)a_buf,
- strlen ((char *)a_buf),
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
a_encoding, FALSE);
if (!parser)
goto cleanup;
@@ -2614,8 +2619,10 @@ cr_statement_dump (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
void
cr_statement_dump_ruleset (CRStatement const * a_this, FILE * a_fp, glong a_indent)
{
+ gchar *str = NULL;
+
g_return_if_fail (a_fp && a_this);
- gchar *str = cr_statement_ruleset_to_string (a_this, a_indent);
+ str = cr_statement_ruleset_to_string (a_this, a_indent);
if (str) {
fprintf (a_fp, "%s", str);
g_free (str);
@@ -2661,9 +2668,11 @@ cr_statement_dump_font_face_rule (CRStatement const * a_this, FILE * a_fp,
void
cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
{
+ gchar *str = NULL;
+
g_return_if_fail (a_this && a_this->type == AT_CHARSET_RULE_STMT);
- gchar *str = cr_statement_charset_to_string (a_this,
+ str = cr_statement_charset_to_string (a_this,
a_indent) ;
if (str) {
fprintf (a_fp, "%s", str) ;
@@ -2685,11 +2694,13 @@ cr_statement_dump_charset (CRStatement const * a_this, FILE * a_fp, gulong a_ind
void
cr_statement_dump_page (CRStatement const * a_this, FILE * a_fp, gulong a_indent)
{
+ gchar *str = NULL;
+
g_return_if_fail (a_this
&& a_this->type == AT_PAGE_RULE_STMT
&& a_this->kind.page_rule);
- gchar *str = cr_statement_at_page_rule_to_string (a_this, a_indent) ;
+ str = cr_statement_at_page_rule_to_string (a_this, a_indent) ;
if (str) {
fprintf (a_fp, "%s", str);
g_free (str) ;
diff --git a/src/libcroco/cr-string.c b/src/libcroco/cr-string.c
index 47d557d5b..86ad3432c 100644
--- a/src/libcroco/cr-string.c
+++ b/src/libcroco/cr-string.c
@@ -32,7 +32,9 @@
CRString *
cr_string_new (void)
{
- CRString *result = (CRString *)g_try_malloc (sizeof (CRString)) ;
+ CRString *result = NULL ;
+
+ result = (CRString *) g_try_malloc (sizeof (CRString)) ;
if (!result) {
cr_utils_trace_info ("Out of memory") ;
return NULL ;
@@ -51,7 +53,9 @@ cr_string_new (void)
CRString *
cr_string_new_from_string (const gchar * a_string)
{
- CRString *result = cr_string_new () ;
+ CRString *result = NULL ;
+
+ result = cr_string_new () ;
if (!result) {
cr_utils_trace_info ("Out of memory") ;
return NULL ;
@@ -70,7 +74,9 @@ cr_string_new_from_string (const gchar * a_string)
CRString *
cr_string_new_from_gstring (GString const *a_string)
{
- CRString *result = cr_string_new () ;
+ CRString *result = NULL ;
+
+ result = cr_string_new () ;
if (!result) {
cr_utils_trace_info ("Out of memory") ;
return NULL ;
@@ -87,9 +93,10 @@ cr_string_new_from_gstring (GString const *a_string)
CRString *
cr_string_dup (CRString const *a_this)
{
+ CRString *result = NULL ;
g_return_val_if_fail (a_this, NULL) ;
- CRString *result = cr_string_new_from_gstring (a_this->stryng) ;
+ result = cr_string_new_from_gstring (a_this->stryng) ;
if (!result) {
cr_utils_trace_info ("Out of memory") ;
return NULL ;
diff --git a/src/libcroco/cr-style.c b/src/libcroco/cr-style.c
index a9c5a5cec..2b865c248 100644
--- a/src/libcroco/cr-style.c
+++ b/src/libcroco/cr-style.c
@@ -140,9 +140,9 @@ static CRPropertyDesc gv_prop_table[] = {
{"font-size", PROP_ID_FONT_SIZE},
{"font-style", PROP_ID_FONT_STYLE},
{"font-weight", PROP_ID_FONT_WEIGHT},
- {"white-space", PROP_ID_WHITE_SPACE},
+ {"white-space", PROP_ID_WHITE_SPACE},
/*must be the last one */
- {NULL, (enum CRPropertyID)0}
+ {NULL, (enum CRPropertyID) 0}
};
/**
@@ -185,7 +185,7 @@ static struct CRNumPropEnumDumpInfo gv_num_props_dump_infos[] = {
{NUM_PROP_MARGIN_BOTTOM, "margin-bottom"},
{NUM_PROP_MARGIN_LEFT, "margin-left"},
{NUM_PROP_WIDTH, "width"},
- {(enum CRNumProp)0, NULL}
+ {(enum CRNumProp) 0, NULL}
};
struct CRRgbPropEnumDumpInfo {
@@ -200,7 +200,7 @@ static struct CRRgbPropEnumDumpInfo gv_rgb_props_dump_infos[] = {
{RGB_PROP_BORDER_LEFT_COLOR, "left-color"},
{RGB_PROP_COLOR, "color"},
{RGB_PROP_BACKGROUND_COLOR, "background-color"},
- {(enum CRRgbProp)0, NULL}
+ {(enum CRRgbProp) 0, NULL}
};
struct CRBorderStylePropEnumDumpInfo {
@@ -215,7 +215,7 @@ static struct CRBorderStylePropEnumDumpInfo gv_border_style_props_dump_infos[]
{BORDER_STYLE_PROP_RIGHT, "border-style-right"},
{BORDER_STYLE_PROP_BOTTOM, "boder-style-bottom"},
{BORDER_STYLE_PROP_LEFT, "border-style-left"},
- {(enum CRBorderStyleProp)0, NULL}
+ {(enum CRBorderStyleProp) 0, NULL}
};
static enum CRStatus
@@ -319,9 +319,9 @@ set_prop_font_weight_from_value (CRStyle * a_style, CRTerm * a_value);
static const gchar *
num_prop_code_to_string (enum CRNumProp a_code)
{
- int len = sizeof (gv_num_props_dump_infos) /
+ guint len = sizeof (gv_num_props_dump_infos) /
sizeof (struct CRNumPropEnumDumpInfo);
- if ((int)a_code >= len) {
+ if (a_code >= len) {
cr_utils_trace_info ("A field has been added "
"to 'enum CRNumProp' and no matching"
" entry has been "
@@ -342,10 +342,10 @@ num_prop_code_to_string (enum CRNumProp a_code)
static const gchar *
rgb_prop_code_to_string (enum CRRgbProp a_code)
{
- int len = sizeof (gv_rgb_props_dump_infos) /
+ guint len = sizeof (gv_rgb_props_dump_infos) /
sizeof (struct CRRgbPropEnumDumpInfo);
- if ((int)a_code >= len) {
+ if (a_code >= len) {
cr_utils_trace_info ("A field has been added "
"to 'enum CRRgbProp' and no matching"
" entry has been "
@@ -366,10 +366,10 @@ rgb_prop_code_to_string (enum CRRgbProp a_code)
static const gchar *
border_style_prop_code_to_string (enum CRBorderStyleProp a_code)
{
- int len = sizeof (gv_border_style_props_dump_infos) /
+ guint len = sizeof (gv_border_style_props_dump_infos) /
sizeof (struct CRBorderStylePropEnumDumpInfo);
- if ((int)a_code >= len) {
+ if (a_code >= len) {
cr_utils_trace_info ("A field has been added "
"to 'enum CRBorderStyleProp' and no matching"
" entry has been "
@@ -421,7 +421,7 @@ cr_style_get_prop_id (const guchar * a_prop)
cr_style_init_properties ();
}
- raw_id = (gpointer *)g_hash_table_lookup (gv_prop_hash, a_prop);
+ raw_id = (gpointer *) g_hash_table_lookup (gv_prop_hash, a_prop);
if (!raw_id) {
return PROP_ID_NOT_KNOWN;
}
@@ -465,7 +465,7 @@ set_prop_padding_x_from_value (CRStyle * a_style,
if (a_value->content.str
&& a_value->content.str->stryng
&& a_value->content.str->stryng->str
- && !strncmp ("inherit",
+ && !strncmp ((const char *) "inherit",
a_value->content.str->stryng->str,
sizeof ("inherit")-1)) {
status = cr_num_set (num_val, 0.0, NUM_INHERIT);
@@ -569,9 +569,10 @@ static enum CRStatus
set_prop_border_width_from_value (CRStyle *a_style,
CRTerm *a_value)
{
+ CRTerm *cur_term = NULL ;
g_return_val_if_fail (a_style && a_value,
CR_BAD_PARAM_ERROR) ;
- CRTerm *cur_term = a_value ;
+ cur_term = a_value ;
if (!cur_term)
return CR_ERROR ;
@@ -579,7 +580,7 @@ set_prop_border_width_from_value (CRStyle *a_style,
int dir;
for (dir = (int) DIR_TOP ; dir < (int)NB_DIRS ; dir++) {
enum CRDirection direction = (enum CRDirection)dir;
- set_prop_border_x_width_from_value (a_style,
+ set_prop_border_x_width_from_value (a_style,
cur_term,
direction) ;
}
@@ -696,16 +697,18 @@ static enum CRStatus
set_prop_border_style_from_value (CRStyle *a_style,
CRTerm *a_value)
{
+ CRTerm *cur_term = NULL ;
+
g_return_val_if_fail (a_style && a_value,
CR_BAD_PARAM_ERROR) ;
- CRTerm *cur_term = a_value ;
+ cur_term = a_value ;
if (!cur_term || cur_term->type != TERM_IDENT) {
return CR_ERROR ;
}
int dir;
- for (dir = (int)DIR_TOP ; dir < (int)NB_DIRS ; dir++) {
+ for (dir = (int)DIR_TOP ; dir < (int)NB_DIRS ; dir++) {
enum CRDirection direction = (enum CRDirection)dir;
set_prop_border_x_style_from_value (a_style,
cur_term,
@@ -908,7 +911,7 @@ set_prop_position_from_value (CRStyle * a_style, CRTerm * a_value)
break;
}
- return CR_OK;
+ return status;
}
static enum CRStatus
@@ -1115,11 +1118,11 @@ set_prop_border_x_color_from_value (CRStyle * a_style, CRTerm * a_value,
&& a_value->content.str->stryng->str) {
status = cr_rgb_set_from_name
(rgb_color,
- (guchar *)a_value->content.str->stryng->str);
+ (const guchar *) a_value->content.str->stryng->str);
}
if (status != CR_OK) {
- cr_rgb_set_from_name (rgb_color, (guchar *)"black");
+ cr_rgb_set_from_name (rgb_color, (const guchar *) "black");
}
} else if (a_value->type == TERM_RGB) {
if (a_value->content.rgb) {
@@ -1354,7 +1357,7 @@ set_prop_font_family_from_value (CRStyle * a_style, CRTerm * a_value)
&& cur_term->content.str->stryng->str) {
cur_ff = cr_font_family_new
(FONT_FAMILY_NON_GENERIC,
- (guchar *)cur_term->content.str->stryng->str);
+ (guchar *) cur_term->content.str->stryng->str);
}
}
break;
@@ -1707,7 +1710,9 @@ set_prop_white_space_from_value (CRStyle * a_style, CRTerm * a_value)
CRStyle *
cr_style_new (gboolean a_set_props_to_initial_values)
{
- CRStyle *result = (CRStyle *)g_try_malloc (sizeof (CRStyle));
+ CRStyle *result = NULL;
+
+ result = (CRStyle *) g_try_malloc (sizeof (CRStyle));
if (!result) {
cr_utils_trace_info ("Out of memory");
return NULL;
@@ -2018,7 +2023,7 @@ cr_style_set_style_from_decl (CRStyle * a_this, CRDeclaration * a_decl)
CR_BAD_PARAM_ERROR);
prop_id = cr_style_get_prop_id
- ((guchar *)a_decl->property->stryng->str);
+ ((const guchar *) a_decl->property->stryng->str);
value = a_decl->value;
switch (prop_id) {
@@ -2676,7 +2681,7 @@ cr_style_to_string (CRStyle * a_this, GString ** a_str, guint a_nb_indent)
*before outputing it value
*/
cr_utils_dump_n_chars2 (' ', str, indent);
- tmp_str = (gchar *) num_prop_code_to_string ((enum CRNumProp)i);
+ tmp_str = (gchar *) num_prop_code_to_string ((enum CRNumProp) i);
if (tmp_str) {
g_string_append_printf (str, "%s: ", tmp_str);
} else {
@@ -2690,7 +2695,7 @@ cr_style_to_string (CRStyle * a_this, GString ** a_str, guint a_nb_indent)
}
/*loop over the rgb_props and to_string() them all */
for (i = RGB_PROP_BORDER_TOP_COLOR; i < NB_RGB_PROPS; i++) {
- tmp_str = (gchar *) rgb_prop_code_to_string ((enum CRRgbProp)i);
+ tmp_str = (gchar *) rgb_prop_code_to_string ((enum CRRgbProp) i);
cr_utils_dump_n_chars2 (' ', str, indent);
if (tmp_str) {
g_string_append_printf (str, "%s: ", tmp_str);
@@ -2705,8 +2710,7 @@ cr_style_to_string (CRStyle * a_this, GString ** a_str, guint a_nb_indent)
}
/*loop over the border_style_props and to_string() them */
for (i = BORDER_STYLE_PROP_TOP; i < NB_BORDER_STYLE_PROPS; i++) {
- tmp_str = (gchar *)
- border_style_prop_code_to_string ((enum CRBorderStyleProp)i);
+ tmp_str = (gchar *) border_style_prop_code_to_string ((enum CRBorderStyleProp) i);
cr_utils_dump_n_chars2 (' ', str, indent);
if (tmp_str) {
g_string_append_printf (str, "%s: ", tmp_str);
@@ -2741,7 +2745,7 @@ cr_style_to_string (CRStyle * a_this, GString ** a_str, guint a_nb_indent)
cr_utils_dump_n_chars2 (' ', str, indent);
g_string_append (str, "font-family: ");
- tmp_str = (gchar *)cr_font_family_to_string (a_this->font_family, TRUE);
+ tmp_str = (gchar *) cr_font_family_to_string (a_this->font_family, TRUE);
if (tmp_str) {
g_string_append (str, tmp_str);
g_free (tmp_str);
diff --git a/src/libcroco/cr-stylesheet.c b/src/libcroco/cr-stylesheet.c
index 1b26c64bf..cb5de6958 100644
--- a/src/libcroco/cr-stylesheet.c
+++ b/src/libcroco/cr-stylesheet.c
@@ -36,7 +36,9 @@
CRStyleSheet *
cr_stylesheet_new (CRStatement * a_stmts)
{
- CRStyleSheet *result = (CRStyleSheet *)g_try_malloc (sizeof (CRStyleSheet));
+ CRStyleSheet *result;
+
+ result = (CRStyleSheet *) g_try_malloc (sizeof (CRStyleSheet));
if (!result) {
cr_utils_trace_info ("Out of memory");
return NULL;
diff --git a/src/libcroco/cr-term.c b/src/libcroco/cr-term.c
index 09b6354db..1c50aed2a 100644
--- a/src/libcroco/cr-term.c
+++ b/src/libcroco/cr-term.c
@@ -84,7 +84,9 @@ cr_term_clear (CRTerm * a_this)
CRTerm *
cr_term_new (void)
{
- CRTerm *result = (CRTerm *)g_try_malloc (sizeof (CRTerm));
+ CRTerm *result = NULL;
+
+ result = (CRTerm *) g_try_malloc (sizeof (CRTerm));
if (!result) {
cr_utils_trace_info ("Out of memory");
return NULL;
@@ -104,15 +106,14 @@ CRTerm *
cr_term_parse_expression_from_buf (const guchar * a_buf,
enum CREncoding a_encoding)
{
+ CRParser *parser = NULL;
CRTerm *result = NULL;
enum CRStatus status = CR_OK;
g_return_val_if_fail (a_buf, NULL);
- CRParser *parser = cr_parser_new_from_buf (
- (guchar*)a_buf,
- strlen ((char *)a_buf),
- a_encoding, FALSE);
+ parser = cr_parser_new_from_buf ((guchar*)a_buf, strlen ((const char *) a_buf),
+ a_encoding, FALSE);
g_return_val_if_fail (parser, NULL);
status = cr_parser_try_to_skip_spaces_and_comments (parser);
@@ -279,8 +280,8 @@ cr_term_to_string (CRTerm const * a_this)
{
GString *str_buf = NULL;
CRTerm const *cur = NULL;
- guchar *result = NULL;
- gchar *content = NULL;
+ guchar *result = NULL,
+ *content = NULL;
g_return_val_if_fail (a_this, NULL);
@@ -329,11 +330,11 @@ cr_term_to_string (CRTerm const * a_this)
switch (cur->type) {
case TERM_NUMBER:
if (cur->content.num) {
- content = (gchar *)cr_num_to_string (cur->content.num);
+ content = cr_num_to_string (cur->content.num);
}
if (content) {
- g_string_append (str_buf, content);
+ g_string_append (str_buf, (const gchar *) content);
g_free (content);
content = NULL;
}
@@ -342,7 +343,7 @@ cr_term_to_string (CRTerm const * a_this)
case TERM_FUNCTION:
if (cur->content.str) {
- content = g_strndup
+ content = (guchar *) g_strndup
(cur->content.str->stryng->str,
cur->content.str->stryng->len);
}
@@ -360,22 +361,21 @@ cr_term_to_string (CRTerm const * a_this)
if (tmp_str) {
g_string_append (str_buf,
- (gchar *)tmp_str);
+ (const gchar *) tmp_str);
g_free (tmp_str);
tmp_str = NULL;
}
-
}
+ g_string_append (str_buf, ")");
g_free (content);
content = NULL;
- g_string_append (str_buf, ")");
}
break;
case TERM_STRING:
if (cur->content.str) {
- content = g_strndup
+ content = (guchar *) g_strndup
(cur->content.str->stryng->str,
cur->content.str->stryng->len);
}
@@ -390,13 +390,13 @@ cr_term_to_string (CRTerm const * a_this)
case TERM_IDENT:
if (cur->content.str) {
- content = g_strndup
+ content = (guchar *) g_strndup
(cur->content.str->stryng->str,
cur->content.str->stryng->len);
}
if (content) {
- g_string_append (str_buf, content);
+ g_string_append (str_buf, (const gchar *) content);
g_free (content);
content = NULL;
}
@@ -404,9 +404,9 @@ cr_term_to_string (CRTerm const * a_this)
case TERM_URI:
if (cur->content.str) {
- content = g_strndup
- (cur->content.str->stryng->str,
- cur->content.str->stryng->len);
+ content = (guchar *) g_strndup
+ (cur->content.str->stryng->str,
+ cur->content.str->stryng->len);
}
if (content) {
@@ -425,7 +425,7 @@ cr_term_to_string (CRTerm const * a_this)
tmp_str = cr_rgb_to_string (cur->content.rgb);
if (tmp_str) {
- g_string_append (str_buf, (gchar *)tmp_str);
+ g_string_append (str_buf, (const gchar *) tmp_str);
g_free (tmp_str);
tmp_str = NULL;
}
@@ -442,7 +442,7 @@ cr_term_to_string (CRTerm const * a_this)
case TERM_HASH:
if (cur->content.str) {
- content = g_strndup
+ content = (guchar *) g_strndup
(cur->content.str->stryng->str,
cur->content.str->stryng->len);
}
@@ -463,7 +463,7 @@ cr_term_to_string (CRTerm const * a_this)
}
if (str_buf) {
- result = (guchar *)str_buf->str;
+ result =(guchar *) str_buf->str;
g_string_free (str_buf, FALSE);
str_buf = NULL;
}
@@ -475,8 +475,8 @@ guchar *
cr_term_one_to_string (CRTerm const * a_this)
{
GString *str_buf = NULL;
- guchar *result = NULL;
- gchar *content = NULL;
+ guchar *result = NULL,
+ *content = NULL;
g_return_val_if_fail (a_this, NULL);
@@ -524,11 +524,11 @@ cr_term_one_to_string (CRTerm const * a_this)
switch (a_this->type) {
case TERM_NUMBER:
if (a_this->content.num) {
- content = (gchar *)cr_num_to_string (a_this->content.num);
+ content = cr_num_to_string (a_this->content.num);
}
if (content) {
- g_string_append (str_buf, content);
+ g_string_append (str_buf, (const gchar *) content);
g_free (content);
content = NULL;
}
@@ -537,7 +537,7 @@ cr_term_one_to_string (CRTerm const * a_this)
case TERM_FUNCTION:
if (a_this->content.str) {
- content = g_strndup
+ content = (guchar *) g_strndup
(a_this->content.str->stryng->str,
a_this->content.str->stryng->len);
}
@@ -571,7 +571,7 @@ cr_term_one_to_string (CRTerm const * a_this)
case TERM_STRING:
if (a_this->content.str) {
- content = g_strndup
+ content = (guchar *) g_strndup
(a_this->content.str->stryng->str,
a_this->content.str->stryng->len);
}
@@ -586,13 +586,13 @@ cr_term_one_to_string (CRTerm const * a_this)
case TERM_IDENT:
if (a_this->content.str) {
- content = g_strndup
+ content = (guchar *) g_strndup
(a_this->content.str->stryng->str,
a_this->content.str->stryng->len);
}
if (content) {
- g_string_append (str_buf, content);
+ g_string_append (str_buf, (const gchar *) content);
g_free (content);
content = NULL;
}
@@ -600,7 +600,7 @@ cr_term_one_to_string (CRTerm const * a_this)
case TERM_URI:
if (a_this->content.str) {
- content = g_strndup
+ content = (guchar *) g_strndup
(a_this->content.str->stryng->str,
a_this->content.str->stryng->len);
}
@@ -615,12 +615,13 @@ cr_term_one_to_string (CRTerm const * a_this)
case TERM_RGB:
if (a_this->content.rgb) {
+ guchar *tmp_str = NULL;
g_string_append_printf (str_buf, "rgb(");
- gchar *tmp_str = (gchar *)cr_rgb_to_string (a_this->content.rgb);
+ tmp_str = cr_rgb_to_string (a_this->content.rgb);
if (tmp_str) {
- g_string_append (str_buf, tmp_str);
+ g_string_append (str_buf, (const gchar *) tmp_str);
g_free (tmp_str);
tmp_str = NULL;
}
@@ -637,7 +638,7 @@ cr_term_one_to_string (CRTerm const * a_this)
case TERM_HASH:
if (a_this->content.str) {
- content = g_strndup
+ content = (guchar *) g_strndup
(a_this->content.str->stryng->str,
a_this->content.str->stryng->len);
}
@@ -658,7 +659,7 @@ cr_term_one_to_string (CRTerm const * a_this)
}
if (str_buf) {
- result = (guchar *)str_buf->str;
+ result = (guchar *) str_buf->str;
g_string_free (str_buf, FALSE);
str_buf = NULL;
}
diff --git a/src/libcroco/cr-tknzr.c b/src/libcroco/cr-tknzr.c
index 1f762b5c5..83f6ab3c0 100644
--- a/src/libcroco/cr-tknzr.c
+++ b/src/libcroco/cr-tknzr.c
@@ -1586,7 +1586,9 @@ cr_tknzr_parse_num (CRTknzr * a_this,
CRTknzr *
cr_tknzr_new (CRInput * a_input)
{
- CRTknzr *result = (CRTknzr *)g_try_malloc (sizeof (CRTknzr));
+ CRTknzr *result = NULL;
+
+ result = (CRTknzr *) g_try_malloc (sizeof (CRTknzr));
if (result == NULL) {
cr_utils_trace_info ("Out of memory");
@@ -1636,7 +1638,9 @@ cr_tknzr_new_from_uri (const guchar * a_file_uri,
enum CREncoding a_enc)
{
CRTknzr *result = NULL;
- CRInput *input = cr_input_new_from_uri ((gchar *)a_file_uri, a_enc);
+ CRInput *input = NULL;
+
+ input = cr_input_new_from_uri ((const gchar *) a_file_uri, a_enc);
g_return_val_if_fail (input != NULL, NULL);
result = cr_tknzr_new (input);
@@ -1898,6 +1902,8 @@ cr_tknzr_seek_index (CRTknzr * a_this, enum CRSeekPos a_origin, gint a_pos)
enum CRStatus
cr_tknzr_consume_chars (CRTknzr * a_this, guint32 a_char, glong * a_nb_char)
{
+ gulong consumed = *(gulong *) a_nb_char;
+ enum CRStatus status;
g_return_val_if_fail (a_this && PRIVATE (a_this)
&& PRIVATE (a_this)->input, CR_BAD_PARAM_ERROR);
@@ -1908,8 +1914,10 @@ cr_tknzr_consume_chars (CRTknzr * a_this, guint32 a_char, glong * a_nb_char)
PRIVATE (a_this)->token_cache = NULL;
}
- return cr_input_consume_chars (PRIVATE (a_this)->input,
- a_char, (gulong *)a_nb_char);
+ status = cr_input_consume_chars (PRIVATE (a_this)->input,
+ a_char, &consumed);
+ *a_nb_char = (glong) consumed;
+ return status;
}
enum CRStatus
@@ -2097,15 +2105,15 @@ cr_tknzr_get_next_token (CRTknzr * a_this, CRToken ** a_tk)
if (BYTE (input, 2, NULL) == 'r'
&& BYTE (input, 3, NULL) == 'l'
&& BYTE (input, 4, NULL) == '(') {
- CRString *str = NULL;
+ CRString *str2 = NULL;
- status = cr_tknzr_parse_uri (a_this, &str);
+ status = cr_tknzr_parse_uri (a_this, &str2);
if (status == CR_OK) {
- status = cr_token_set_uri (token, str);
+ status = cr_token_set_uri (token, str2);
CHECK_PARSING_STATUS (status, TRUE);
- if (str) {
+ if (str2) {
cr_parsing_location_copy (&token->location,
- &str->location) ;
+ &str2->location) ;
}
goto done;
}
diff --git a/src/libcroco/cr-token.c b/src/libcroco/cr-token.c
index 3dd73ac3e..dfe83e221 100644
--- a/src/libcroco/cr-token.c
+++ b/src/libcroco/cr-token.c
@@ -133,7 +133,9 @@ cr_token_clear (CRToken * a_this)
CRToken *
cr_token_new (void)
{
- CRToken *result = (CRToken *)g_try_malloc (sizeof (CRToken));
+ CRToken *result = NULL;
+
+ result = (CRToken *) g_try_malloc (sizeof (CRToken));
if (result == NULL) {
cr_utils_trace_info ("Out of memory");
diff --git a/src/libcroco/cr-utils.c b/src/libcroco/cr-utils.c
index a51c76920..bfb587017 100644
--- a/src/libcroco/cr-utils.c
+++ b/src/libcroco/cr-utils.c
@@ -429,9 +429,8 @@ cr_utils_read_char_from_utf8_buf (const guchar * a_in,
gulong a_in_len,
guint32 * a_out, gulong * a_consumed)
{
- gulong in_len = 0,
- in_index = 0,
- nb_bytes_2_decode = 0;
+ gulong in_index = 0,
+ nb_bytes_2_decode = 0;
enum CRStatus status = CR_OK;
/*
@@ -448,8 +447,6 @@ cr_utils_read_char_from_utf8_buf (const guchar * a_in,
goto end;
}
- in_len = a_in_len;
-
if (*a_in <= 0x7F) {
/*
*7 bits long char
@@ -901,15 +898,10 @@ cr_utils_ucs1_to_utf8 (const guchar * a_in,
if (*a_in_len == 0) {
*a_out_len = 0 ;
- return CR_OK ;
+ return status;
}
g_return_val_if_fail (a_out, CR_BAD_PARAM_ERROR) ;
- if (*a_in_len < 1) {
- status = CR_OK;
- goto end;
- }
-
in_len = *a_in_len;
out_len = *a_out_len;
@@ -930,11 +922,10 @@ cr_utils_ucs1_to_utf8 (const guchar * a_in,
}
} /*end for */
- end:
*a_in_len = in_index;
*a_out_len = out_index;
- return CR_OK;
+ return status;
}
/**
@@ -951,8 +942,7 @@ cr_utils_ucs1_str_to_utf8 (const guchar * a_in,
gulong * a_in_len,
guchar ** a_out, gulong * a_out_len)
{
- gulong in_len = 0,
- out_len = 0;
+ gulong out_len = 0;
enum CRStatus status = CR_OK;
g_return_val_if_fail (a_in && a_in_len && a_out
@@ -969,8 +959,6 @@ cr_utils_ucs1_str_to_utf8 (const guchar * a_in,
g_return_val_if_fail (status == CR_OK, status);
- in_len = *a_in_len;
-
*a_out = (guchar *) g_malloc0 (out_len);
status = cr_utils_ucs1_to_utf8 (a_in, a_in_len, *a_out, &out_len);
@@ -1023,7 +1011,6 @@ cr_utils_utf8_to_ucs1 (const guchar * a_in,
&& a_out && a_out_len, CR_BAD_PARAM_ERROR);
if (*a_in_len < 1) {
- status = CR_OK;
goto end;
}
@@ -1102,7 +1089,6 @@ cr_utils_utf8_to_ucs1 (const guchar * a_in,
*(if any) to get the current character.
*/
if (in_index + nb_bytes_2_decode - 1 >= in_len) {
- status = CR_OK;
goto end;
}
@@ -1136,7 +1122,7 @@ cr_utils_utf8_to_ucs1 (const guchar * a_in,
*a_out_len = out_index;
*a_in_len = in_index;
- return CR_OK;
+ return status;
}
/**
diff --git a/src/libgdl/CMakeLists.txt b/src/libgdl/CMakeLists.txt
index d59d017f0..a452320f7 100644
--- a/src/libgdl/CMakeLists.txt
+++ b/src/libgdl/CMakeLists.txt
@@ -1,47 +1,50 @@
+if (NOT "${WITH_EXT_GDL}")
-set(libgdl_SRC
- gdl-dock-bar.c
- gdl-dock-item-button-image.c
- gdl-dock-item-grip.c
- gdl-dock-item.c
- gdl-dock-master.c
- gdl-dock-notebook.c
- gdl-dock-object.c
- gdl-dock-paned.c
- gdl-dock-placeholder.c
- gdl-dock-tablabel.c
- gdl-dock.c
- gdl-i18n.c
- gdl-switcher.c
- libgdlmarshal.c
- libgdltypebuiltins.c
+ set(libgdl_SRC
+ gdl-dock-bar.c
+ gdl-dock-item-button-image.c
+ gdl-dock-item-grip.c
+ gdl-dock-item.c
+ gdl-dock-master.c
+ gdl-dock-notebook.c
+ gdl-dock-object.c
+ gdl-dock-paned.c
+ gdl-dock-placeholder.c
+ gdl-dock-tablabel.c
+ gdl-dock.c
+ gdl-i18n.c
+ gdl-switcher.c
+ libgdlmarshal.c
+ libgdltypebuiltins.c
- # -------
- # Headers
- gdl-dock-bar.h
- gdl-dock-item-button-image.h
- gdl-dock-item-grip.h
- gdl-dock-item.h
- gdl-dock-master.h
- gdl-dock-notebook.h
- gdl-dock-object.h
- gdl-dock-paned.h
- gdl-dock-placeholder.h
- gdl-dock-tablabel.h
- gdl-dock.h
- gdl-i18n.h
- gdl-switcher.h
- gdl.h
- libgdlmarshal.h
- libgdltypebuiltins.h
-)
+ # -------
+ # Headers
+ gdl-dock-bar.h
+ gdl-dock-item-button-image.h
+ gdl-dock-item-grip.h
+ gdl-dock-item.h
+ gdl-dock-master.h
+ gdl-dock-notebook.h
+ gdl-dock-object.h
+ gdl-dock-paned.h
+ gdl-dock-placeholder.h
+ gdl-dock-tablabel.h
+ gdl-dock.h
+ gdl-i18n.h
+ gdl-switcher.h
+ gdl.h
+ libgdlmarshal.h
+ libgdltypebuiltins.h
+ )
-if(WIN32)
- list(APPEND libgdl_SRC
- gdl-win32.c
- gdl-win32.h
- )
-endif()
+ if(WIN32)
+ list(APPEND libgdl_SRC
+ gdl-win32.c
+ gdl-win32.h
+ )
+ endif()
+
+ add_inkscape_lib(gdl_LIB "${libgdl_SRC}")
-add_inkscape_lib(gdl_LIB "${libgdl_SRC}")
+endif()
diff --git a/src/libgdl/gdl-dock-item-grip.c b/src/libgdl/gdl-dock-item-grip.c
index d23eb7f98..9b3810c20 100644
--- a/src/libgdl/gdl-dock-item-grip.c
+++ b/src/libgdl/gdl-dock-item-grip.c
@@ -149,6 +149,8 @@ gdl_dock_item_grip_expose (GtkWidget *widget,
}
+/* see bug #950556: may contribute to regression with GTK2/Quartz */
+#if !defined(GDK_WINDOWING_QUARTZ)
if (gdl_dock_item_or_child_has_focus(grip->item)) {
gtk_paint_focus (gtk_widget_get_style (widget),
@@ -157,6 +159,7 @@ gdl_dock_item_grip_expose (GtkWidget *widget,
&event->area, widget,
NULL, 0, 0, -1, -1);
}
+#endif //GDK_WINDOWING_QUARTZ
return GTK_WIDGET_CLASS (gdl_dock_item_grip_parent_class)->expose_event (widget, event);
}
diff --git a/src/libgdl/gdl-dock-item.c b/src/libgdl/gdl-dock-item.c
index afcd4dfcb..af630e681 100644
--- a/src/libgdl/gdl-dock-item.c
+++ b/src/libgdl/gdl-dock-item.c
@@ -1064,8 +1064,11 @@ gdl_dock_item_paint (GtkWidget *widget,
"dockitem",
0, 0, -1, -1);
+/* see bug #950556: avoid regression with GTK2/Quartz */
+#if !defined(GDK_WINDOWING_QUARTZ)
if (GTK_IS_WIDGET(item->_priv->grip))
gtk_widget_queue_draw (GTK_WIDGET(item->_priv->grip));
+#endif
}
static gint
diff --git a/src/libnrtype/FontInstance.cpp b/src/libnrtype/FontInstance.cpp
index a5572c517..7a16fc0c3 100644
--- a/src/libnrtype/FontInstance.cpp
+++ b/src/libnrtype/FontInstance.cpp
@@ -21,6 +21,7 @@
#include FT_BBOX_H
#include FT_TRUETYPE_TAGS_H
#include FT_TRUETYPE_TABLES_H
+#include FT_GLYPH_H
#include <pango/pangoft2.h>
#include <2geom/pathvector.h>
#include <2geom/path-sink.h>
@@ -183,6 +184,20 @@ font_instance::font_instance(void) :
theFace(0)
{
//printf("font instance born\n");
+ _ascent = _ascent_max = 0.8;
+ _descent = _descent_max = 0.2;
+ _xheight = 0.5;
+
+ // Default baseline values, alphabetic is reference
+ _baselines[ SP_CSS_BASELINE_AUTO ] = 0.0;
+ _baselines[ SP_CSS_BASELINE_ALPHABETIC ] = 0.0;
+ _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] = -_descent;
+ _baselines[ SP_CSS_BASELINE_HANGING ] = 0.8 * _ascent;
+ _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = 0.8 * _xheight;
+ _baselines[ SP_CSS_BASELINE_CENTRAL ] = 0.5 - _descent;
+ _baselines[ SP_CSS_BASELINE_MIDDLE ] = 0.5 * _xheight;
+ _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] = _ascent;
+ _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] = -_descent;
}
font_instance::~font_instance(void)
@@ -259,6 +274,7 @@ void font_instance::InitTheFace()
FT_Select_Charmap(theFace,ft_encoding_unicode) && FT_Select_Charmap(theFace,ft_encoding_symbol);
}
#endif
+ FindFontMetrics();
}
}
@@ -374,10 +390,10 @@ void font_instance::LoadGlyph(int glyph_id)
GLYPHMETRICS metrics;
DWORD bufferSize=GetGlyphOutline (parent->hScreenDC, glyph_id, GGO_GLYPH_INDEX | GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity);
double scale=1.0/parent->fontSize;
- n_g.h_advance=metrics.gmCellIncX*scale;
- n_g.v_advance=otm.otmTextMetrics.tmHeight*scale;
- n_g.h_width=metrics.gmBlackBoxX*scale;
- n_g.v_width=metrics.gmBlackBoxY*scale;
+ n_g.h_advance = metrics.gmCellIncX * scale;
+ n_g.v_advance = otm.otmTextMetrics.tmHeight * scale;
+ n_g.h_width = metrics.gmBlackBoxX * scale;
+ n_g.v_width = metrics.gmBlackBoxY * scale;
if ( bufferSize == GDI_ERROR) {
// shit happened
} else if ( bufferSize == 0) {
@@ -459,7 +475,13 @@ void font_instance::LoadGlyph(int glyph_id)
n_g.v_advance=((double)theFace->glyph->metrics.vertAdvance)/((double)theFace->units_per_EM);
n_g.v_width=((double)theFace->glyph->metrics.height)/((double)theFace->units_per_EM);
} else {
- n_g.v_width=n_g.v_advance=((double)theFace->height)/((double)theFace->units_per_EM);
+ // CSS3 Writing modes dictates that if vertical font metrics are missing we must
+ // synthisize them. No method is specified. The SVG 1.1 spec suggests using the em
+ // height (which is not theFace->height as that includes leading). The em height
+ // is ascender + descender (descender positive). Note: The "Requirements for
+ // Japanese Text Layout" W3C document says that Japanese kanji should be "set
+ // solid" which implies that vertical (and horizontal) advance should be 1em.
+ n_g.v_width=n_g.v_advance= 1.0;
}
if ( theFace->glyph->format == ft_glyph_format_outline ) {
FT_Outline_Funcs ft2_outline_funcs = {
@@ -501,7 +523,7 @@ void font_instance::LoadGlyph(int glyph_id)
}
}
-bool font_instance::FontMetrics(double &ascent,double &descent,double &leading)
+bool font_instance::FontMetrics(double &ascent,double &descent,double &xheight)
{
if ( pFont == NULL ) {
return false;
@@ -510,32 +532,17 @@ bool font_instance::FontMetrics(double &ascent,double &descent,double &leading)
if ( theFace == NULL ) {
return false;
}
-#ifdef USE_PANGO_WIN32
- OUTLINETEXTMETRIC otm;
- if ( !GetOutlineTextMetrics(parent->hScreenDC,sizeof(otm),&otm) ) {
- return false;
- }
- double scale=1.0/parent->fontSize;
- ascent=fabs(otm.otmAscent*scale);
- descent=fabs(otm.otmDescent*scale);
- leading=fabs(otm.otmLineGap*scale);
- //otmSubscriptSize, otmSubscriptOffset, otmSuperscriptSize, otmSuperscriptOffset,
-#else
- if ( theFace->units_per_EM == 0 ) {
- return false; // bitmap font
- }
- ascent=fabs(((double)theFace->ascender)/((double)theFace->units_per_EM));
- descent=fabs(((double)theFace->descender)/((double)theFace->units_per_EM));
- leading=fabs(((double)theFace->height)/((double)theFace->units_per_EM));
- leading-=ascent+descent;
-#endif
+
+ ascent = _ascent;
+ descent = _descent;
+ xheight = _xheight;
+
return true;
}
-bool font_instance::FontDecoration(
- double &underline_position, double &underline_thickness,
- double &linethrough_position, double &linethrough_thickness
-){
+bool font_instance::FontDecoration( double &underline_position, double &underline_thickness,
+ double &linethrough_position, double &linethrough_thickness)
+{
if ( pFont == NULL ) {
return false;
}
@@ -662,6 +669,179 @@ double font_instance::Advance(int glyph_id,bool vertical)
return 0;
}
+// Internal function to find baselines
+void font_instance::FindFontMetrics() {
+
+ // CSS2 recommends using the OS/2 values sTypoAscender and sTypoDescender for the Typographic
+ // ascender and descender values:
+ // http://www.w3.org/TR/CSS2/visudet.html#sTypoAscender
+ // On Windows, the typographic ascender and descender are taken from the otmMacAscent and
+ // otmMacDescent values:
+ // http://microsoft.public.win32.programmer.gdi.narkive.com/LV6k4BDh/msdn-documentation-outlinetextmetrics-clarification
+ // The otmAscent and otmDescent values are the maxiumum ascent and maxiumum descent of all the
+ // glyphs in a font.
+ if ( theFace ) {
+
+#ifdef USE_PANGO_WIN32
+
+ if ( GetOutlineTextMetrics(parent->hScreenDC,sizeof(otm),&otm) ) {
+ double scale=1.0/parent->fontSize;
+ _ascent = fabs(otm.otmMacAscent * scale);
+ _descent = fabs(otm.otmMacDescent * scale);
+ _xheight = fabs(otm.otmXHeight * scale);
+ _ascent_max = fabs(otm.otmAscent * scale);
+ _descent_max = fabs(otm.otmDescent * scale);
+
+ // In CSS em size is ascent + descent... which should be 1. If not,
+ // adjust so it is.
+ double em = _ascent + _descent;
+ if( em > 0 ) {
+ _ascent /= em;
+ _descent /= em;
+ }
+
+ // May not be necessary but if OS/2 table missing or not version 2 or higher,
+ // xheight might be zero.
+ if( _xheight == 0.0 ) {
+ _xheight = 0.5;
+ }
+
+ // Baselines defined relative to alphabetic.
+ _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] = -_descent; // Recommendation
+ _baselines[ SP_CSS_BASELINE_HANGING ] = 0.8 * _ascent; // Guess
+ _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = 0.8 * _xheight; // Guess
+ _baselines[ SP_CSS_BASELINE_CENTRAL ] = 0.5 - _descent; // Definition
+ _baselines[ SP_CSS_BASELINE_MIDDLE ] = 0.5 * _xheight; // Definition
+ _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] = _ascent; // Definition
+ _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] = -_descent; // Definition
+
+
+ MAT2 identity = {{0,1},{0,0},{0,0},{0,1}};
+ GLYPHMETRICS metrics;
+ int retval;
+
+ // Better math baseline:
+ // Try center of minus sign
+ retval = GetGlyphOutline (parent->hScreenDC, 0x2212, GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity);
+ // If no minus sign, try hyphen
+ if( retval <= 0 )
+ retval = GetGlyphOutline (parent->hScreenDC, '-', GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity);
+
+ if( retval > 0 ) {
+ double math = (metrics.gmptGlyphOrigin.y + 0.5 * metrics.gmBlackBoxY) * scale;
+ _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = math;
+ }
+
+ // Find hanging baseline... assume it is at top of 'म'.
+ retval = GetGlyphOutline (parent->hScreenDC, 0x092E, GGO_NATIVE | GGO_UNHINTED, &metrics, 0, NULL, &identity);
+ if( retval > 0 ) {
+ double hanging = metrics.gmptGlyphOrigin.y * scale;
+ _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = hanging;
+ }
+ }
+
+#else
+
+ if ( theFace->units_per_EM != 0 ) { // If zero then it's a bitmap font.
+
+ TT_OS2* os2 = (TT_OS2*)FT_Get_Sfnt_Table( theFace, ft_sfnt_os2 );
+ if( os2 ) {
+ _ascent = fabs(((double)os2->sTypoAscender) / ((double)theFace->units_per_EM));
+ _descent = fabs(((double)os2->sTypoDescender)/ ((double)theFace->units_per_EM));
+ } else {
+ _ascent = fabs(((double)theFace->ascender) / ((double)theFace->units_per_EM));
+ _descent = fabs(((double)theFace->descender) / ((double)theFace->units_per_EM));
+ }
+ _ascent_max = fabs(((double)theFace->ascender) / ((double)theFace->units_per_EM));
+ _descent_max = fabs(((double)theFace->descender) / ((double)theFace->units_per_EM));
+
+ // In CSS em size is ascent + descent... which should be 1. If not,
+ // adjust so it is.
+ double em = _ascent + _descent;
+ if( em > 0 ) {
+ _ascent /= em;
+ _descent /= em;
+ }
+
+ // x-height
+ if( os2 && os2->version >= 0x0002 && os2->version != 0xffffu ) {
+ // Only os/2 version 2 and above have sxHeight, 0xffff marks "old Mac fonts" without table
+ _xheight = fabs(((double)os2->sxHeight) / ((double)theFace->units_per_EM));
+ } else {
+ // Measure 'x' height in font. Recommended option by XSL standard if no sxHeight.
+ FT_UInt index = FT_Get_Char_Index( theFace, 'x' );
+ if( index != 0 ) {
+ FT_Load_Glyph( theFace, index, FT_LOAD_NO_SCALE );
+ _xheight = (fabs)(((double)theFace->glyph->metrics.height/(double)theFace->units_per_EM));
+ } else {
+ // No 'x' in font!
+ _xheight = 0.5;
+ }
+ }
+
+ // Baselines defined relative to alphabetic.
+ _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] = -_descent; // Recommendation
+ _baselines[ SP_CSS_BASELINE_HANGING ] = 0.8 * _ascent; // Guess
+ _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = 0.8 * _xheight; // Guess
+ _baselines[ SP_CSS_BASELINE_CENTRAL ] = 0.5 - _descent; // Definition
+ _baselines[ SP_CSS_BASELINE_MIDDLE ] = 0.5 * _xheight; // Definition
+ _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] = _ascent; // Definition
+ _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] = -_descent; // Definition
+
+ // Better math baseline:
+ // Try center of minus sign
+ FT_UInt index = FT_Get_Char_Index( theFace, 0x2212 ); //'−'
+ // If no minus sign, try hyphen
+ if( index == 0 )
+ index = FT_Get_Char_Index( theFace, '-' );
+
+ if( index != 0 ) {
+ FT_Load_Glyph( theFace, index, FT_LOAD_NO_SCALE );
+ FT_Glyph aglyph;
+ FT_Get_Glyph( theFace->glyph, &aglyph );
+ FT_BBox acbox;
+ FT_Glyph_Get_CBox( aglyph, FT_GLYPH_BBOX_UNSCALED, &acbox );
+ double math = (acbox.yMin + acbox.yMax)/2.0/(double)theFace->units_per_EM;
+ _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] = math;
+ // std::cout << "Math baseline: - bbox: y_min: " << acbox.yMin
+ // << " y_max: " << acbox.yMax
+ // << " math: " << math << std::endl;
+ }
+
+ // Find hanging baseline... assume it is at top of 'म'.
+ index = FT_Get_Char_Index( theFace, 0x092E ); // 'म'
+ if( index != 0 ) {
+ FT_Load_Glyph( theFace, index, FT_LOAD_NO_SCALE );
+ FT_Glyph aglyph;
+ FT_Get_Glyph( theFace->glyph, &aglyph );
+ FT_BBox acbox;
+ FT_Glyph_Get_CBox( aglyph, FT_GLYPH_BBOX_UNSCALED, &acbox );
+ double hanging = (double)acbox.yMax/(double)theFace->units_per_EM;
+ _baselines[ SP_CSS_BASELINE_HANGING ] = hanging;
+ // std::cout << "Hanging baseline: प: " << hanging << std::endl;
+ }
+ }
+#endif
+ // const gchar *family = pango_font_description_get_family(descr);
+ // std::cout << "Font: " << (family?family:"null") << std::endl;
+ // std::cout << " ascent: " << _ascent << std::endl;
+ // std::cout << " descent: " << _descent << std::endl;
+ // std::cout << " x-height: " << _xheight << std::endl;
+ // std::cout << " max ascent: " << _ascent_max << std::endl;
+ // std::cout << " max descent: " << _descent_max << std::endl;
+ // std::cout << " Baselines:" << std::endl;
+ // std::cout << " alphabetic: " << _baselines[ SP_CSS_BASELINE_ALPHABETIC ] << std::endl;
+ // std::cout << " ideographic: " << _baselines[ SP_CSS_BASELINE_IDEOGRAPHIC ] << std::endl;
+ // std::cout << " hanging: " << _baselines[ SP_CSS_BASELINE_HANGING ] << std::endl;
+ // std::cout << " math: " << _baselines[ SP_CSS_BASELINE_MATHEMATICAL ] << std::endl;
+ // std::cout << " central: " << _baselines[ SP_CSS_BASELINE_CENTRAL ] << std::endl;
+ // std::cout << " middle: " << _baselines[ SP_CSS_BASELINE_MIDDLE ] << std::endl;
+ // std::cout << " text_before: " << _baselines[ SP_CSS_BASELINE_TEXT_BEFORE_EDGE ] << std::endl;
+ // std::cout << " text_after: " << _baselines[ SP_CSS_BASELINE_TEXT_AFTER_EDGE ] << std::endl;
+ }
+}
+
+
/*
Local Variables:
mode:c++
diff --git a/src/libnrtype/Layout-TNG-Compute.cpp b/src/libnrtype/Layout-TNG-Compute.cpp
index d81e1b6b4..e862f0657 100644
--- a/src/libnrtype/Layout-TNG-Compute.cpp
+++ b/src/libnrtype/Layout-TNG-Compute.cpp
@@ -23,17 +23,6 @@ namespace Text {
#define TRACE(_args) IFTRACE(g_print _args)
-// ******* enum conversion tables
-static Layout::EnumConversionItem const enum_convert_spstyle_direction_to_pango_direction[] = {
- {SP_CSS_WRITING_MODE_LR_TB, PANGO_DIRECTION_LTR},
- {SP_CSS_WRITING_MODE_RL_TB, PANGO_DIRECTION_RTL},
- {SP_CSS_WRITING_MODE_TB_LR, PANGO_DIRECTION_LTR}}; // this is correct
-
-static Layout::EnumConversionItem const enum_convert_spstyle_direction_to_my_direction[] = {
- {SP_CSS_WRITING_MODE_LR_TB, Layout::LEFT_TO_RIGHT},
- {SP_CSS_WRITING_MODE_RL_TB, Layout::RIGHT_TO_LEFT},
- {SP_CSS_WRITING_MODE_TB_LR, Layout::LEFT_TO_RIGHT}}; // this is correct
-
/** \brief private to Layout. Does the real work of text flowing.
This class does a standard greedy paragraph wrapping algorithm.
@@ -124,9 +113,10 @@ class Layout::Calculator
unsigned input_index; /// index into Layout::_input_stream
Glib::ustring::const_iterator input_stream_first_character;
double font_size;
- LineHeight line_height; /// This is not the CSS line-height attribute!
+ FontMetrics line_height; /// This is not the CSS line-height attribute!
double line_height_multiplier; /// calculated from the font-height css property
double baseline_shift; /// calculated from the baseline-shift css property
+ SPCSSTextOrientation text_orientation;
unsigned text_bytes;
unsigned char_index_in_para; /// the index of the first character in this span in the paragraph, for looking up char_attributes
SVGLength x, y, dx, dy, rotate; // these are reoriented copies of the <tspan> attributes. We change span when we encounter one.
@@ -204,9 +194,8 @@ class Layout::Calculator
void _buildPangoItemizationForPara(ParagraphInfo *para) const;
- static void _computeFontLineHeight(font_instance *font, double font_size,
- SPStyle const *style, LineHeight *line_height,
- double *line_height_multiplier);
+ // Returns line_height_multiplier
+ static double _computeFontLineHeight( SPStyle const *style );
unsigned _buildSpansForPara(ParagraphInfo *para) const;
@@ -254,7 +243,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
bool _goToNextWrapShape();
bool _findChunksForLine(ParagraphInfo const &para, UnbrokenSpanPosition *start_span_pos,
- std::vector<ChunkInfo> *chunk_info, LineHeight *line_height);
+ std::vector<ChunkInfo> *chunk_info, FontMetrics *line_box_height);
static inline PangoLogAttr const &_charAttributes(ParagraphInfo const &para,
UnbrokenSpanPosition const &span_pos)
@@ -266,7 +255,8 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
UnbrokenSpanPosition const &start_span_pos,
ScanlineMaker::ScanRun const &scan_run,
std::vector<ChunkInfo> *chunk_info,
- LineHeight *line_height) const;
+ FontMetrics *line_height,
+ FontMetrics const *strut_height) const;
/** computes the width of a single UnbrokenSpan (pointed to by span->start.iter_span)
and outputs its vital statistics into the other fields of \a span.
@@ -281,11 +271,15 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
or will be unaltered if there is none. */
bool _measureUnbrokenSpan(ParagraphInfo const &para, BrokenSpan *span, BrokenSpan *last_break_span, BrokenSpan *last_emergency_break_span, double maximum_width) const
{
+ TRACE((" start _measureUnbrokenSpan %g\n", maximum_width));
span->setZero();
if (span->start.iter_span->dx._set && span->start.char_byte == 0){
- if(para.direction == RIGHT_TO_LEFT){ span->width -= span->start.iter_span->dx.computed; }
- else { span->width += span->start.iter_span->dx.computed; }
+ if(para.direction == RIGHT_TO_LEFT){
+ span->width -= span->start.iter_span->dx.computed;
+ } else {
+ span->width += span->start.iter_span->dx.computed;
+ }
}
if (span->start.iter_span->pango_item_index == -1) {
@@ -304,7 +298,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
if (control_code->code == ARBITRARY_GAP) {
if (span->width + control_code->width > maximum_width)
return false;
- TRACE(("fitted control code, width = %f\n", control_code->width));
+ TRACE((" fitted control code, width = %f\n", control_code->width));
span->width += control_code->width;
span->end.increment();
}
@@ -343,12 +337,14 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
PangoLogAttr const &char_attributes = _charAttributes(para, span->end);
if (char_attributes.is_mandatory_break && span->end != span->start) {
+ TRACE((" is_mandatory_break ************\n"));
*last_emergency_break_span = *last_break_span = *span;
- TRACE(("span %ld end of para; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count));
+ TRACE((" span %ld end of para; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count));
return false;
}
if (char_attributes.is_line_break) {
+ TRACE((" is_line_break ************\n"));
// a suitable position to break at, record where we are
*last_emergency_break_span = *last_break_span = *span;
if (soft_hyphen_in_word) {
@@ -366,10 +362,22 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
double char_width = 0.0;
while (span->end_glyph_index < (unsigned)span->end.iter_span->glyph_string->num_glyphs
&& span->end.iter_span->glyph_string->log_clusters[span->end_glyph_index] <= (int)span->end.char_byte) {
- if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT)
- char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, true);
- else
+ if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) {
+ // Vertical text
+
+ if( text_source->style->text_orientation.computed == SP_CSS_TEXT_ORIENTATION_SIDEWAYS ||
+ (text_source->style->text_orientation.computed == SP_CSS_TEXT_ORIENTATION_MIXED &&
+ para.pango_items[span->end.iter_span->pango_item_index].item->analysis.gravity == 0) ) {
+ // Sideways orientation
+ char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, false);
+ } else {
+ // Upright orientation
+ char_width += span->start.iter_span->font_size * para.pango_items[span->end.iter_span->pango_item_index].font->Advance(span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].glyph, true);
+ }
+ } else {
+ // Horizontal text
char_width += font_size_multiplier * span->end.iter_span->glyph_string->glyphs[span->end_glyph_index].geometry.width;
+ }
span->end_glyph_index++;
}
if (char_attributes.is_cursor_position)
@@ -401,13 +409,14 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
span->word_spacing = text_source->style->word_spacing.computed;
if (test_width > maximum_width && !char_attributes.is_white) { // whitespaces don't matter, we can put as many as we want at eol
- TRACE(("span %ld exceeded scanrun; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count));
+ TRACE((" span %ld exceeded scanrun; width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count));
return false;
}
} while (span->end.char_byte != 0); // while we haven't wrapped to the next span
- TRACE(("fitted span %ld width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count));
+ TRACE((" fitted span %ld width = %f chars = %d\n", span->start.iter_span - para.unbroken_spans.begin(), span->width, char_count));
+ TRACE((" end _measureUnbrokenSpan %g\n", maximum_width));
return true;
}
@@ -458,19 +467,33 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
are ready to output the final result to #_flow. This method takes its
input parameters and does that.
*/
- void _outputLine(ParagraphInfo const &para, LineHeight const &line_height, std::vector<ChunkInfo> const &chunk_info)
+ void _outputLine(ParagraphInfo const &para, FontMetrics const &line_height, std::vector<ChunkInfo> const &chunk_info)
{
- TRACE(("Start _outputLine\n"));
+ TRACE((" Start _outputLine: ascent %f, descent %f, top of box %f\n", line_height.ascent, line_height.descent, _scanline_maker->yCoordinate() ));
if (chunk_info.empty()) {
- TRACE(("line too short to fit anything on it, go to next\n"));
+ TRACE((" line too short to fit anything on it, go to next\n"));
return;
}
// we've finished fiddling about with ascents and descents: create the output
- TRACE(("found line fit; creating output\n"));
+ TRACE((" found line fit; creating output\n"));
Layout::Line new_line;
new_line.in_paragraph = _flow._paragraphs.size() - 1;
- new_line.baseline_y = _scanline_maker->yCoordinate() + line_height.ascent;
+ new_line.baseline_y = _scanline_maker->yCoordinate();
+
+ // The y coordinate is at the beginning edge of the line box (top for horizontal text, left
+ // edge for vertical lr text, right edge for vertical rl text. We align, by default to the
+ // alphabetic baseline for horizontal text and the central baseline for vertical text.
+ if( _block_progression == RIGHT_TO_LEFT ) {
+ // Vertical text, use em box center as baseline
+ new_line.baseline_y -= 0.5 * line_height.emSize();
+ } else if ( _block_progression == LEFT_TO_RIGHT ) {
+ // Vertical text, use em box center as baseline
+ new_line.baseline_y += 0.5 * line_height.emSize();
+ } else {
+ new_line.baseline_y += line_height.getTypoAscent();
+ }
+
new_line.in_shape = _current_shape_index;
_flow._lines.push_back(new_line);
@@ -480,7 +503,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
// add the chunk to the list
Layout::Chunk new_chunk;
new_chunk.in_line = _flow._lines.size() - 1;
- TRACE((" New chunk: in_line: %d\n", new_chunk.in_line));
+ TRACE((" New chunk: in_line: %d\n", new_chunk.in_line));
new_chunk.left_x = _getChunkLeftWithAlignment(para, it_chunk, &add_to_each_whitespace);
// we may also have y move orders to deal with here (dx, dy and rotate are done per span)
@@ -511,17 +534,27 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
// If <tspan> "y" attribute is set, use it (initial "y" attributes in
// <tspans> other than the first have already been stripped for <tspans>
// marked with role="line", see sp-text.cpp: SPText::_buildLayoutInput).
+ // NOTE: for vertical text, "y" is the user-space "x" value.
if( it_chunk->broken_spans.front().start.iter_span->y._set ) {
// Use set "y" attribute
new_line.baseline_y = it_chunk->broken_spans.front().start.iter_span->y.computed;
-
// Save baseline
_flow._lines.back().baseline_y = new_line.baseline_y;
- // Save new <tspan> y coordinate
- _scanline_maker->setNewYCoordinate(new_line.baseline_y - line_height.ascent);
-
+ double top_of_line_box = new_line.baseline_y;
+ if( _block_progression == RIGHT_TO_LEFT ) {
+ // Vertical text, use em box center as baseline
+ top_of_line_box += 0.5 * line_height.emSize();
+ } else if (_block_progression == LEFT_TO_RIGHT ) {
+ // Vertical text, use em box center as baseline
+ top_of_line_box -= 0.5 * line_height.emSize();
+ } else {
+ top_of_line_box -= line_height.getTypoAscent();
+ }
+ TRACE((" y attribute set, next line top_of_line_box: %f\n", top_of_line_box ));
+ // Set the initial y coordinate of the next line (see above).
+ _scanline_maker->setNewYCoordinate(top_of_line_box);
}
// Reset relative y_offset ("dy" attribute is relative but should be reset at
@@ -540,21 +573,21 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
}
_flow._chunks.push_back(new_chunk);
- double x;
+ double current_x;
double direction_sign;
Direction previous_direction = para.direction;
double counter_directional_width_remaining = 0.0;
float glyph_rotate = 0.0;
if (para.direction == LEFT_TO_RIGHT) {
direction_sign = +1.0;
- x = 0.0;
+ current_x = 0.0;
} else {
direction_sign = -1.0;
if (para.alignment == FULL && !_flow._input_wrap_shapes.empty()){
- x = it_chunk->scanrun_width;
+ current_x = it_chunk->scanrun_width;
}
else {
- x = it_chunk->text_width;
+ current_x = it_chunk->text_width;
}
}
@@ -567,7 +600,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
if (it_span->start.char_byte == 0) {
// Start of an unbroken span, we might have dx, dy or rotate still to process
// (x and y are done per chunk)
- if (unbroken_span.dx._set) x += unbroken_span.dx.computed;
+ if (unbroken_span.dx._set) current_x += unbroken_span.dx.computed;
if (unbroken_span.dy._set) _y_offset += unbroken_span.dy.computed;
if (unbroken_span.rotate._set) glyph_rotate = unbroken_span.rotate.computed * (M_PI/180);
}
@@ -585,6 +618,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
new_span.in_input_stream_item = unbroken_span.input_index;
new_span.baseline_shift = 0.0;
new_span.block_progression = _block_progression;
+ new_span.text_orientation = unbroken_span.text_orientation;
if ((_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) && (new_span.font = para.pango_items[unbroken_span.pango_item_index].font))
{
new_span.font->Ref();
@@ -593,12 +627,12 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
new_span.input_stream_first_character = Glib::ustring::const_iterator(unbroken_span.input_stream_first_character.base() + it_span->start.char_byte);
} else { // a control code
new_span.font = NULL;
- new_span.font_size = new_span.line_height.ascent + new_span.line_height.descent;
+ new_span.font_size = new_span.line_height.emSize();
new_span.direction = para.direction;
}
if (new_span.direction == para.direction) {
- x -= counter_directional_width_remaining;
+ current_x -= counter_directional_width_remaining;
counter_directional_width_remaining = 0.0;
} else if (new_span.direction != previous_direction) {
// measure width of spans we need to switch round
@@ -614,10 +648,10 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
}
counter_directional_width_remaining += direction_sign * (it_following_span->width + it_following_span->whitespace_count * add_to_each_whitespace);
}
- x += counter_directional_width_remaining;
+ current_x += counter_directional_width_remaining;
counter_directional_width_remaining = 0.0; // we want to go increasingly negative
}
- new_span.x_start = x;
+ new_span.x_start = current_x;
if (_flow._input_stream[unbroken_span.input_index]->Type() == TEXT_SOURCE) {
// the span is set up, push the glyphs and chars
@@ -657,10 +691,12 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
}
// create the Layout::Glyph
+ PangoGlyphInfo *unbroken_span_glyph_info = &unbroken_span.glyph_string->glyphs[glyph_index];
Layout::Glyph new_glyph;
- new_glyph.glyph = unbroken_span.glyph_string->glyphs[glyph_index].glyph;
+ new_glyph.glyph = unbroken_span_glyph_info->glyph;
new_glyph.in_character = _flow._characters.size();
new_glyph.rotation = glyph_rotate;
+ new_glyph.orientation = ORIENTATION_UPRIGHT; // Only effects vertical text
// We may have scaled font size to fit textLength; now, if
// @lengthAdjust=spacingAndGlyphs, this scaling must be only horizontal,
@@ -670,30 +706,68 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
else
new_glyph.vertical_scale = 1.0;
- /* put something like this back in when we do glyph-rotation-horizontal/vertical
- if (new_span.block_progression == LEFT_TO_RIGHT || new_span.block_progression == RIGHT_TO_LEFT) {
- new_glyph.x += new_span.line_height.ascent;
- new_glyph.y -= unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * font_size_multiplier * 0.5;
- new_glyph.width = new_span.line_height.ascent + new_span.line_height.descent;
- } else */
+ // Position glyph --------------------
+ new_glyph.x = current_x + unbroken_span_glyph_info->geometry.x_offset * font_size_multiplier;
+ new_glyph.y =_y_offset;
+
+ // y-coordinate is flipped between vertical and horizontal text... delta_y is common offset but applied with opposite sign
+ double delta_y = unbroken_span_glyph_info->geometry.y_offset * font_size_multiplier + unbroken_span.baseline_shift;
+ SPCSSBaseline dominant_baseline = _flow._blockBaseline();
if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT) {
- new_glyph.x = x + unbroken_span.glyph_string->glyphs[glyph_index].geometry.x_offset * font_size_multiplier + new_span.line_height.ascent;
- new_glyph.y = _y_offset -
- unbroken_span.baseline_shift +
- (unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset -
- unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * 0.5) * font_size_multiplier;
- new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[glyph_index].glyph, true);
+ // Vertical text
+
+ // Default dominant baseline is determined by overall block (i.e. <text>) 'text-orientation' value.
+ if( _flow._blockTextOrientation() != SP_CSS_TEXT_ORIENTATION_SIDEWAYS ) {
+ if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_CENTRAL;
+ } else {
+ if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_ALPHABETIC;
+ }
+
+ new_glyph.y += delta_y;
+
+ // TODO: Should also check 'glyph_orientation_vertical' if 'text-orientation' is unset...
+ if( new_span.text_orientation == SP_CSS_TEXT_ORIENTATION_SIDEWAYS ||
+ (new_span.text_orientation == SP_CSS_TEXT_ORIENTATION_MIXED &&
+ para.pango_items[unbroken_span.pango_item_index].item->analysis.gravity == 0) ) {
+
+ // Sideways orientation (Latin characters, CJK punctuation), 90deg rotation done at output stage. zzzzzzz
+ new_glyph.orientation = ORIENTATION_SIDEWAYS;
+
+ new_glyph.y -= new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ];
+ new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, false);
+
+ } else {
+ // Upright orientation
+
+ new_glyph.x += new_span.line_height.ascent;
+
+ // Glyph reference point is center (shift: left edge to center glyph)
+ new_glyph.y -= unbroken_span_glyph_info->geometry.width * 0.5 * font_size_multiplier;
+ new_glyph.y -= new_span.font_size * (para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ] -
+ para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ SP_CSS_BASELINE_CENTRAL ] );
+
+ new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, true);
+ if( new_glyph.width == 0 ) {
+ new_glyph.width = unbroken_span_glyph_info->geometry.width * font_size_multiplier;
+ }
+
+ }
} else {
- new_glyph.x = x + unbroken_span.glyph_string->glyphs[glyph_index].geometry.x_offset * font_size_multiplier;
- new_glyph.y = _y_offset -
- unbroken_span.baseline_shift +
- unbroken_span.glyph_string->glyphs[glyph_index].geometry.y_offset * font_size_multiplier;
- new_glyph.width = unbroken_span.glyph_string->glyphs[glyph_index].geometry.width * font_size_multiplier;
+ // Horizontal text
+
+ if( dominant_baseline == SP_CSS_BASELINE_AUTO ) dominant_baseline = SP_CSS_BASELINE_ALPHABETIC;
+
+ new_glyph.y -= delta_y;
+ new_glyph.y += new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->GetBaselines()[ dominant_baseline ];
+
+ new_glyph.width = unbroken_span_glyph_info->geometry.width * font_size_multiplier;
if ((new_glyph.width == 0) && (para.pango_items[unbroken_span.pango_item_index].font))
- new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[glyph_index].glyph, false);
+ new_glyph.width = new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span_glyph_info->glyph, false);
// for some reason pango returns zero width for invalid glyph characters (those empty boxes), so go to freetype for the info
}
+
+
if (new_span.direction == RIGHT_TO_LEFT) {
// pango wanted to give us glyphs in visual order but we refused, so we need to work
// out where the cluster start is ourselves
@@ -702,13 +776,15 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
if (unbroken_span.glyph_string->glyphs[rtl_index].attr.is_cluster_start && rtl_index != glyph_index)
break;
if (_block_progression == LEFT_TO_RIGHT || _block_progression == RIGHT_TO_LEFT)
+ // Vertical text
cluster_width += new_span.font_size * para.pango_items[unbroken_span.pango_item_index].font->Advance(unbroken_span.glyph_string->glyphs[rtl_index].glyph, true);
else
+ // Horizontal text
cluster_width += font_size_multiplier * unbroken_span.glyph_string->glyphs[rtl_index].geometry.width;
}
new_glyph.x -= cluster_width;
}
- _flow._glyphs.push_back(new_glyph);
+ _flow._glyphs.push_back(new_glyph);
// create the Layout::Character(s)
double advance_width = new_glyph.width;
@@ -765,15 +841,15 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
advance_width *= direction_sign;
if (new_span.direction != para.direction) {
counter_directional_width_remaining -= advance_width;
- x -= advance_width;
+ current_x -= advance_width;
x_in_span_last -= advance_width;
} else {
- x += advance_width;
+ current_x += advance_width;
x_in_span_last += advance_width;
}
}
} else if (_flow._input_stream[unbroken_span.input_index]->Type() == CONTROL_CODE) {
- x += static_cast<InputStreamControlCode const *>(_flow._input_stream[unbroken_span.input_index])->width;
+ current_x += static_cast<InputStreamControlCode const *>(_flow._input_stream[unbroken_span.input_index])->width;
}
new_span.x_end = new_span.x_start + x_in_span_last;
@@ -782,7 +858,7 @@ static void dumpUnbrokenSpans(ParagraphInfo *para){
}
// end adding spans to the list, on to the next chunk...
}
- TRACE(("output done\n"));
+ TRACE((" End _outputLine\n"));
}
/* *********************************************************************************************************/
@@ -962,6 +1038,7 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) con
#if PANGO_VERSION_CHECK(1,37,1)
TRACE((" ... compiled for font features\n"));
#endif
+
Glib::ustring para_text;
PangoAttrList *attributes_list;
unsigned input_index;
@@ -983,10 +1060,10 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) con
} else if (_flow._input_stream[input_index]->Type() == TEXT_SOURCE) {
Layout::InputStreamTextSource *text_source = static_cast<Layout::InputStreamTextSource *>(_flow._input_stream[input_index]);
- // create the font_instance
- font_instance *font = text_source->styleGetFontInstance();
- if (font == NULL)
- continue; // bad news: we'll have to ignore all this text because we know of no font to render it
+ // create the font_instance
+ font_instance *font = text_source->styleGetFontInstance();
+ if (font == NULL)
+ continue; // bad news: we'll have to ignore all this text because we know of no font to render it
PangoAttribute *attribute_font_description = pango_attr_font_desc_new(font->descr);
attribute_font_description->start_index = para_text.bytes();
@@ -1012,25 +1089,22 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) con
TRACE(("whole para: \"%s\"\n", para_text.data()));
TRACE(("%d input sources used\n", input_index - para->first_input_index));
-
// do the pango_itemize()
GList *pango_items_glist = NULL;
+ para->direction = LEFT_TO_RIGHT; // CSS default
if (_flow._input_stream[para->first_input_index]->Type() == TEXT_SOURCE) {
Layout::InputStreamTextSource const *text_source = static_cast<Layout::InputStreamTextSource *>(_flow._input_stream[para->first_input_index]);
- if (text_source->style->direction.set) {
- PangoDirection pango_direction = (PangoDirection)_enum_converter(text_source->style->direction.computed, enum_convert_spstyle_direction_to_pango_direction, sizeof(enum_convert_spstyle_direction_to_pango_direction)/sizeof(enum_convert_spstyle_direction_to_pango_direction[0]));
- pango_items_glist = pango_itemize_with_base_dir(_pango_context, pango_direction, para_text.data(), 0, para_text.bytes(), attributes_list, NULL);
- para->direction = (Layout::Direction)_enum_converter(text_source->style->direction.computed, enum_convert_spstyle_direction_to_my_direction, sizeof(enum_convert_spstyle_direction_to_my_direction)/sizeof(enum_convert_spstyle_direction_to_my_direction[0]));
- }
+
+ para->direction = (text_source->style->direction.computed == SP_CSS_DIRECTION_LTR) ? LEFT_TO_RIGHT : RIGHT_TO_LEFT;
+ PangoDirection pango_direction = (text_source->style->direction.computed == SP_CSS_DIRECTION_LTR) ? PANGO_DIRECTION_LTR : PANGO_DIRECTION_RTL;
+ pango_items_glist = pango_itemize_with_base_dir(_pango_context, pango_direction, para_text.data(), 0, para_text.bytes(), attributes_list, NULL);
}
- if (pango_items_glist == NULL) { // no direction specified, guess it
- pango_items_glist = pango_itemize(_pango_context, para_text.data(), 0, para_text.bytes(), attributes_list, NULL);
- // I think according to the css spec this is wrong and we're never allowed to guess the directionality
- // of a paragraph. Need to talk to an rtl speaker.
- if (pango_items_glist == NULL || pango_items_glist->data == NULL) para->direction = LEFT_TO_RIGHT;
- else para->direction = (((PangoItem*)pango_items_glist->data)->analysis.level & 1) ? RIGHT_TO_LEFT : LEFT_TO_RIGHT;
+ if( pango_items_glist == NULL ) {
+ // Type wasn't TEXT_SOURCE or direction was not set.
+ pango_items_glist = pango_itemize(_pango_context, para_text.data(), 0, para_text.bytes(), attributes_list, NULL);
}
+
pango_attr_list_unref(attributes_list);
// convert the GList to our vector<> and make the font_instance for each PangoItem at the same time
@@ -1054,44 +1128,32 @@ void Layout::Calculator::_buildPangoItemizationForPara(ParagraphInfo *para) con
}
/**
- * Gets the ascent, descent and leading for a font and the alteration that has to be performed
- * according to the value specified by the line-height css property. The result of multiplying
- * \a line_height by \a line_height_multiplier is the inline box height as specified in css2
- * section 10.8.
+ * Finds the value of line_height_multiplier given the 'line-height' property. The result of
+ * multiplying \a l by \a line_height_multiplier is the inline box height as specified in css2
+ * section 10.8. http://www.w3.org/TR/CSS2/visudet.html#line-height
+ *
+ * The 'computed' value of 'line-height' does not have a consistent meaning. We need to find the
+ * 'used' value and divide that by the font size.
*/
-void Layout::Calculator::_computeFontLineHeight(font_instance *font, double font_size,
- SPStyle const *style, LineHeight *line_height,
- double *line_height_multiplier)
+double Layout::Calculator::_computeFontLineHeight( SPStyle const *style )
{
- if (font == NULL) {
- line_height->setZero();
- *line_height_multiplier = 1.0;
- }
- else {
- font->FontMetrics(line_height->ascent, line_height->descent, line_height->leading);
- }
- *line_height *= font_size;
-
// yet another borked SPStyle member that we're going to have to fix ourselves
+ // We shouldn't need to climb the element tree...
for ( ; ; ) {
if (style->line_height.set && !style->line_height.inherit) {
if (style->line_height.normal)
break;
switch (style->line_height.unit) {
case SP_CSS_UNIT_NONE:
- *line_height_multiplier = style->line_height.computed * font_size / line_height->total();
- return;
+ return style->line_height.computed;
case SP_CSS_UNIT_EX:
- *line_height_multiplier = style->line_height.value * 0.5 * font_size / line_height->total();
+ return style->line_height.value * 0.5;
// 0.5 is an approximation of the x-height. Fixme.
- return;
case SP_CSS_UNIT_EM:
case SP_CSS_UNIT_PERCENT:
- *line_height_multiplier = style->line_height.value * font_size / line_height->total();
- return;
+ return style->line_height.value;
default: // absolute values
- *line_height_multiplier = style->line_height.computed / line_height->total();
- return;
+ return style->line_height.computed / style->font_size.computed;
}
break;
}
@@ -1099,7 +1161,7 @@ void Layout::Calculator::_computeFontLineHeight(font_instance *font, double font
style = style->object->parent->style;
if (style == NULL) break;
}
- *line_height_multiplier = LINE_HEIGHT_NORMAL * font_size / line_height->total();
+ return (LINE_HEIGHT_NORMAL);
}
bool compareGlyphWidth(const PangoGlyphInfo &a, const PangoGlyphInfo &b)
@@ -1139,7 +1201,6 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
new_span.input_index = input_index;
new_span.line_height.ascent = control_code->ascent * _flow.getTextLengthMultiplierDue();
new_span.line_height.descent = control_code->descent * _flow.getTextLengthMultiplierDue();
- new_span.line_height.leading = 0.0;
new_span.text_bytes = 0;
new_span.char_index_in_para = char_index_in_para;
para->unbroken_spans.push_back(new_span);
@@ -1178,11 +1239,13 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
new_span.dy._set = false;
new_span.rotate._set = false;
if (_block_progression == TOP_TO_BOTTOM || _block_progression == BOTTOM_TO_TOP) {
+ // Horizontal text
if (text_source->x.size() > char_index_in_source) new_span.x = text_source->x[char_index_in_source];
if (text_source->y.size() > char_index_in_source) new_span.y = text_source->y[char_index_in_source];
if (text_source->dx.size() > char_index_in_source) new_span.dx = text_source->dx[char_index_in_source].computed * _flow.getTextLengthMultiplierDue();
if (text_source->dy.size() > char_index_in_source) new_span.dy = text_source->dy[char_index_in_source].computed * _flow.getTextLengthMultiplierDue();
} else {
+ // Vertical text
if (text_source->x.size() > char_index_in_source) new_span.y = text_source->x[char_index_in_source];
if (text_source->y.size() > char_index_in_source) new_span.x = text_source->y[char_index_in_source];
if (text_source->dx.size() > char_index_in_source) new_span.dy = text_source->dx[char_index_in_source].computed * _flow.getTextLengthMultiplierDue();
@@ -1215,7 +1278,7 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
}
// now we know the length, do some final calculations and add the UnbrokenSpan to the list
- new_span.font_size = text_source->styleComputeFontSize() * _flow.getTextLengthMultiplierDue();
+ new_span.font_size = text_source->style->font_size.computed * _flow.getTextLengthMultiplierDue();
if (new_span.text_bytes) {
new_span.glyph_string = pango_glyph_string_new();
/* Some assertions intended to help diagnose bug #1277746. */
@@ -1224,6 +1287,7 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
g_assert( span_start_byte_in_source + new_span.text_bytes <= text_source->text->bytes() );
g_assert( memchr(text_source->text->data() + span_start_byte_in_source, '\0', static_cast<size_t>(new_span.text_bytes))
== NULL );
+
/* Notes as of 4/29/13. Pango_shape is not generating English language ligatures, but it is generating
them for Hebrew (and probably other similar languages). In the case observed 3 unicode characters (a base
and 2 Mark, nonspacings) are merged into two glyphs (the base + first Mn, the 2nd Mn). All of these map
@@ -1231,6 +1295,8 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
characters and glyphs. A big chunk of the conditional code which immediately follows this call
is there to clean up the resulting mess.
*/
+
+ // Convert characters to glyphs
pango_shape(text_source->text->data() + span_start_byte_in_source,
new_span.text_bytes,
&para->pango_items[pango_item_index].item->analysis,
@@ -1308,11 +1374,14 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
/* glyphs[].x_offset values may be out of order within any log_clusters, apparently harmless */
}
new_span.pango_item_index = pango_item_index;
- _computeFontLineHeight(para->pango_items[pango_item_index].font, new_span.font_size, text_source->style, &new_span.line_height, &new_span.line_height_multiplier);
+ new_span.line_height_multiplier = _computeFontLineHeight( text_source->style );
+ new_span.line_height.set( para->pango_items[pango_item_index].font );
+ new_span.line_height *= new_span.font_size;
// At some point we may want to calculate baseline_shift here (to take advantage
// of otm features like superscript baseline), but for now we use style baseline_shift.
new_span.baseline_shift = text_source->style->baseline_shift.computed;
+ new_span.text_orientation = (SPCSSTextOrientation)text_source->style->text_orientation.computed;
// TODO: metrics for vertical text
TRACE(("add text span %lu \"%s\"\n", para->unbroken_spans.size(), text_source->text->raw().substr(span_start_byte_in_source, new_span.text_bytes).c_str()));
@@ -1322,11 +1391,13 @@ unsigned Layout::Calculator::_buildSpansForPara(ParagraphInfo *para) const
new_span.pango_item_index = -1;
font_instance *font = text_source->styleGetFontInstance();
if (font) {
- _computeFontLineHeight(font, new_span.font_size, text_source->style, &new_span.line_height, &new_span.line_height_multiplier);
+ new_span.line_height_multiplier = _computeFontLineHeight( text_source->style );
+ new_span.line_height.set( font );
+ new_span.line_height *= new_span.font_size;
font->Unref();
} else {
- new_span.line_height.setZero();
- new_span.line_height_multiplier = 1.0;
+ new_span.line_height *= 0.0; // Set all to zero
+ new_span.line_height_multiplier = LINE_HEIGHT_NORMAL;
}
TRACE(("add style init span %lu\n", para->unbroken_spans.size()));
}
@@ -1376,60 +1447,54 @@ bool Layout::Calculator::_goToNextWrapShape()
* bits of information that will prove useful when we come to output the
* line to #_flow. Returns with \a start_span_pos set to the end of the
* text that was fitted, \a chunk_info completely filled out and
- * \a line_height set to the largest line box on the line. The return
+ * \a line_box_height set with the largest ascent and the largest
+ * descent (individually per CSS) on the line. The return
* value is false only if we've run out of shapes to wrap inside (and
* hence couldn't create any chunks).
*/
bool Layout::Calculator::_findChunksForLine(ParagraphInfo const &para,
UnbrokenSpanPosition *start_span_pos,
std::vector<ChunkInfo> *chunk_info,
- LineHeight *line_height)
+ FontMetrics *line_box_height)
{
- // init the initial line_height
- if (start_span_pos->iter_span == para.unbroken_spans.end()) {
- if (_flow._spans.empty()) {
- // empty first para: create a font for the sole purpose of measuring it
- InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_flow._input_stream.front());
- font_instance *font = text_source->styleGetFontInstance();
- if (font) {
- double font_size = text_source->styleComputeFontSize();
- double multiplier;
- _computeFontLineHeight(font, font_size, text_source->style, line_height, &multiplier);
- font->Unref();
- *line_height *= multiplier;
- _scanline_maker->setNewYCoordinate(_scanline_maker->yCoordinate() - line_height->ascent);
- }
- }
- // else empty subsequent para: keep the old line height
+ TRACE((" begin _findChunksForLine: chunks: %lu, em size: %f\n", chunk_info->size(), line_box_height->emSize() ));
+
+ // CSS 2.1 dictates that the minimum line height (i.e. the strut height) is found from the block element. This,
+ // however, is not what the browsers seem to be doing. Instead, find the height from the first text source.
+ InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_flow._input_stream.front());
+ font_instance *font = text_source->styleGetFontInstance();
+ if (font) {
+ double multiplier = _computeFontLineHeight(text_source->style);
+ line_box_height->set( font );
+ *line_box_height *= text_source->style->font_size.computed;
+ font->Unref();
+ line_box_height->computeEffective( multiplier );
} else {
- if (_flow._input_wrap_shapes.empty()) {
- // if we're not wrapping set the line_height big and negative so we can use negative line height
- line_height->ascent = -1.0e10;
- line_height->descent = -1.0e10;
- line_height->leading = -1.0e10;
- }
- else
- line_height->setZero();
+ std::cerr << "Layout::Calculator::_findChunksForLine: Font not found." << std::endl;
}
+ TRACE((" initial line_box_height (em size): %f\n", line_box_height->emSize() ));
+
+ // Save strut height for use when recalculating line height after backing out chunks that don't fit.
+ FontMetrics strut_height = *line_box_height;
UnbrokenSpanPosition span_pos;
for( ; ; ) {
std::vector<ScanlineMaker::ScanRun> scan_runs;
- scan_runs = _scanline_maker->makeScanline(*line_height); // Only one line with "InfiniteScanlineMaker
+ scan_runs = _scanline_maker->makeScanline(*line_box_height); // Only one line with "InfiniteScanlineMaker
while (scan_runs.empty()) {
// Only used by ShapeScanlineMaker
if (!_goToNextWrapShape()) return false; // no more shapes to wrap in to
- scan_runs = _scanline_maker->makeScanline(*line_height);
+ scan_runs = _scanline_maker->makeScanline(*line_box_height);
}
- TRACE(("finding line fit y=%f, %lu scan runs\n", scan_runs.front().y, scan_runs.size()));
+ TRACE((" finding line fit y=%f, %lu scan runs\n", scan_runs.front().y, scan_runs.size()));
chunk_info->clear();
chunk_info->reserve(scan_runs.size());
if (para.direction == RIGHT_TO_LEFT) std::reverse(scan_runs.begin(), scan_runs.end());
unsigned scan_run_index;
span_pos = *start_span_pos;
for (scan_run_index = 0 ; scan_run_index < scan_runs.size() ; scan_run_index++) {
- if (!_buildChunksInScanRun(para, span_pos, scan_runs[scan_run_index], chunk_info, line_height))
+ if (!_buildChunksInScanRun(para, span_pos, scan_runs[scan_run_index], chunk_info, line_box_height, &strut_height))
break;
if (!chunk_info->empty() && !chunk_info->back().broken_spans.empty())
span_pos = chunk_info->back().broken_spans.back().end;
@@ -1437,6 +1502,8 @@ bool Layout::Calculator::_findChunksForLine(ParagraphInfo const &para,
if (scan_run_index == scan_runs.size()) break; // ie when buildChunksInScanRun() succeeded
}
*start_span_pos = span_pos;
+ TRACE((" final line_box_height: %f\n", line_box_height->emSize() ));
+ TRACE((" end _findChunksForLine: chunks: %lu\n", chunk_info->size()));
return true;
}
@@ -1458,8 +1525,11 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const &para,
UnbrokenSpanPosition const &start_span_pos,
ScanlineMaker::ScanRun const &scan_run,
std::vector<ChunkInfo> *chunk_info,
- LineHeight *line_height) const
+ FontMetrics *line_height,
+ FontMetrics const *strut_height) const
{
+ TRACE((" begin _buildChunksInScanRun: chunks: %lu, em size: %f\n", chunk_info->size(), line_height->emSize() ));
+
ChunkInfo new_chunk;
new_chunk.text_width = 0.0;
new_chunk.whitespace_count = 0;
@@ -1473,7 +1543,7 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const &para,
last_span_at_emergency_break.start = start_span_pos;
last_span_at_emergency_break.setZero();
- TRACE(("trying chunk from %f to %g\n", scan_run.x_start, scan_run.x_end));
+ TRACE((" trying chunk from %f to %g\n", scan_run.x_start, scan_run.x_end));
BrokenSpan new_span;
new_span.end = start_span_pos;
while (new_span.end.iter_span != para.unbroken_spans.end()) { // this loops once for each UnbrokenSpan
@@ -1495,16 +1565,17 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const &para,
}
// see if this span is too tall to fit on the current line
- LineHeight total_height = new_span.start.iter_span->line_height;
- total_height *= new_span.start.iter_span->line_height_multiplier;
+ FontMetrics new_span_height = new_span.start.iter_span->line_height;
+ new_span_height.computeEffective( new_span.start.iter_span->line_height_multiplier );
/* floating point 80-bit/64-bit rounding problems require epsilon. See
discussion http://inkscape.gristle.org/2005-03-16.txt around 22:00 */
- if ( total_height.ascent > line_height->ascent + FLT_EPSILON
- || total_height.descent > line_height->descent + FLT_EPSILON
- || total_height.leading > line_height->leading + FLT_EPSILON) {
- line_height->max(total_height);
- if (!_scanline_maker->canExtendCurrentScanline(*line_height))
+ if ( new_span_height.ascent > line_height->ascent + FLT_EPSILON ||
+ new_span_height.descent > line_height->descent + FLT_EPSILON) {
+ // Take larger of each of the two ascents and two descents per CSS
+ line_height->max(new_span_height);
+ if (!_scanline_maker->canExtendCurrentScanline(*line_height)) {
return false;
+ }
}
bool span_fitted = _measureUnbrokenSpan(para, &new_span, &last_span_at_break, &last_span_at_emergency_break, new_chunk.scanrun_width - new_chunk.text_width);
@@ -1521,10 +1592,10 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const &para,
}
}
- TRACE(("chunk complete, used %f width (%d whitespaces, %lu brokenspans)\n", new_chunk.text_width, new_chunk.whitespace_count, new_chunk.broken_spans.size()));
+ TRACE((" chunk complete, used %f width (%d whitespaces, %lu brokenspans)\n", new_chunk.text_width, new_chunk.whitespace_count, new_chunk.broken_spans.size()));
chunk_info->push_back(new_chunk);
- if (scan_run.width() >= 4.0 * line_height->total() && last_span_at_break.end == start_span_pos) {
+ if (scan_run.width() >= 4.0 * line_height->emSize() && last_span_at_break.end == start_span_pos) {
/* **non-SVG spec bit**: See bug #1191102
If the user types a very long line with no spaces, the way the spec
is written at the moment means that when the length of the text
@@ -1559,12 +1630,25 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const &para,
chunk_info->back().text_width += last_span_at_break.width;
chunk_info->back().whitespace_count += last_span_at_break.whitespace_count;
}
- TRACE(("correction: fitted span %lu width = %f\n", last_span_at_break.start.iter_span - para.unbroken_spans.begin(), last_span_at_break.width));
+ TRACE((" correction: fitted span %lu width = %f\n", last_span_at_break.start.iter_span - para.unbroken_spans.begin(), last_span_at_break.width));
+ }
+ }
+
+ // Recalculate line_box_height after backing out chunks
+ *line_height = *strut_height;
+ for (std::vector<ChunkInfo>::const_iterator it_chunk = chunk_info->begin() ; it_chunk != chunk_info->end() ; it_chunk++) {
+ for (std::vector<BrokenSpan>::const_iterator it_span = it_chunk->broken_spans.begin() ; it_span != it_chunk->broken_spans.end() ; it_span++) {
+ TRACE((" brokenspan line_height: %f\n", it_span->start.iter_span->line_height.emSize() ));
+ FontMetrics span_height = it_span->start.iter_span->line_height;
+ span_height.computeEffective( it_span->start.iter_span->line_height_multiplier );
+ line_height->max( span_height );
}
}
+ TRACE((" line_box_height: %f\n", line_height->emSize()));
if (!chunk_info->empty() && !chunk_info->back().broken_spans.empty() && chunk_info->back().broken_spans.back().ends_with_whitespace) {
// for justification we need to discard space occupied by the single whitespace at the end of the chunk
+ TRACE((" backing out whitespace\n"));
chunk_info->back().broken_spans.back().ends_with_whitespace = false;
chunk_info->back().broken_spans.back().width -= chunk_info->back().broken_spans.back().each_whitespace_width;
chunk_info->back().broken_spans.back().whitespace_count--;
@@ -1576,9 +1660,10 @@ bool Layout::Calculator::_buildChunksInScanRun(ParagraphInfo const &para,
// for justification we need to discard line-spacing and word-spacing at end of the chunk
chunk_info->back().broken_spans.back().width -= chunk_info->back().broken_spans.back().letter_spacing;
chunk_info->back().text_width -= chunk_info->back().broken_spans.back().letter_spacing;
- TRACE(("width after subtracting last letter_spacing: %f\n", chunk_info->back().broken_spans.back().width));
+ TRACE((" width after subtracting last letter_spacing: %f\n", chunk_info->back().broken_spans.back().width));
}
+ TRACE((" end _buildChunksInScanRun: chunks: %lu\n", chunk_info->size()));
return true;
}
@@ -1598,19 +1683,32 @@ bool Layout::Calculator::calculate()
g_warning("flow text is not of type TEXT_SOURCE. Abort.");
return false;
}
- TRACE(("begin calculateFlow()\n"));
+ TRACE(("begin calculate()\n"));
_flow._clearOutputObjects();
_pango_context = (font_factory::Default())->fontContext;
+
_font_factory_size_multiplier = (font_factory::Default())->fontSize;
+ // Reset gravity hint in case it was changed via previous use of 'text-orientation'
+ // (scripts take their natural gravity given base gravity).
+ pango_context_set_gravity_hint(_pango_context, PANGO_GRAVITY_HINT_NATURAL);
+
_block_progression = _flow._blockProgression();
+ if( _block_progression == RIGHT_TO_LEFT || _block_progression == LEFT_TO_RIGHT ) {
+ // Vertical text, CJK
+ pango_context_set_base_gravity(_pango_context, PANGO_GRAVITY_EAST);
+ } else {
+ // Horizontal text
+ pango_context_set_base_gravity(_pango_context, PANGO_GRAVITY_AUTO);
+ }
+
_y_offset = 0.0;
_createFirstScanlineMaker();
ParagraphInfo para;
- LineHeight line_height; // needs to be maintained across paragraphs to be able to deal with blank paras
+ FontMetrics line_box_height; // needs to be maintained across paragraphs to be able to deal with blank paras
for(para.first_input_index = 0 ; para.first_input_index < _flow._input_stream.size() ; ) {
// jump to the next wrap shape if this is a SHAPE_BREAK control code
if (_flow._input_stream[para.first_input_index]->Type() == CONTROL_CODE) {
@@ -1624,7 +1722,10 @@ bool Layout::Calculator::calculate()
if (_scanline_maker == NULL)
break; // we're trying to flow past the last wrap shape
- _buildPangoItemizationForPara(&para);
+ // Break things up into little pango units with unique direction, gravity, etc.
+ _buildPangoItemizationForPara(&para);
+
+ // Do shaping (convert characters to glyphs)
unsigned para_end_input_index = _buildSpansForPara(&para);
if (_flow._input_stream[para.first_input_index]->Type() == TEXT_SOURCE)
@@ -1647,11 +1748,13 @@ bool Layout::Calculator::calculate()
do { // for each line in the paragraph
TRACE(("begin line\n"));
std::vector<ChunkInfo> line_chunk_info;
- if (!_findChunksForLine(para, &span_pos, &line_chunk_info, &line_height))
+ if (!_findChunksForLine(para, &span_pos, &line_chunk_info, &line_box_height))
break; // out of shapes to wrap in to
- _outputLine(para, line_height, line_chunk_info);
+ _outputLine(para, line_box_height, line_chunk_info);
+ _scanline_maker->setLineHeight( line_box_height );
_scanline_maker->completeLine(); // Increments y by line height
+ TRACE(("end line\n"));
} while (span_pos.iter_span != para.unbroken_spans.end());
TRACE(("para %lu end\n\n", _flow._paragraphs.size() - 1));
@@ -1663,8 +1766,8 @@ bool Layout::Calculator::calculate()
Layout::Span new_span;
if (_flow._spans.empty()) {
new_span.font = NULL;
- new_span.font_size = line_height.ascent + line_height.descent;
- new_span.line_height = line_height;
+ new_span.font_size = line_box_height.emSize();
+ new_span.line_height = line_box_height;
new_span.x_end = 0.0;
} else {
new_span = _flow._spans.back();
@@ -1739,19 +1842,16 @@ void Layout::_calculateCursorShapeForEmpty()
InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream.front());
font_instance *font = text_source->styleGetFontInstance();
- double font_size = text_source->styleComputeFontSize();
+ double font_size = text_source->style->font_size.computed;
double caret_slope_run = 0.0, caret_slope_rise = 1.0;
- LineHeight line_height;
+ FontMetrics line_height;
if (font) {
const_cast<font_instance*>(font)->FontSlope(caret_slope_run, caret_slope_rise);
- font->FontMetrics(line_height.ascent, line_height.descent, line_height.leading);
+ font->FontMetrics(line_height.ascent, line_height.descent, line_height.xheight);
line_height *= font_size;
font->Unref();
- } else {
- line_height.ascent = font_size * 0.85; // random guesses
- line_height.descent = font_size * 0.15;
- line_height.leading = 0.0;
}
+
double caret_slope = atan2(caret_slope_run, caret_slope_rise);
_empty_cursor_shape.height = font_size / cos(caret_slope);
_empty_cursor_shape.rotation = caret_slope;
@@ -1764,16 +1864,20 @@ void Layout::_calculateCursorShapeForEmpty()
ShapeScanlineMaker scanline_maker(_input_wrap_shapes.front().shape, block_progression);
std::vector<ScanlineMaker::ScanRun> scan_runs = scanline_maker.makeScanline(line_height);
if (!scan_runs.empty()) {
- if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT)
+ if (block_progression == LEFT_TO_RIGHT || block_progression == RIGHT_TO_LEFT) {
+ // Vertical text
_empty_cursor_shape.position = Geom::Point(scan_runs.front().y + font_size, scan_runs.front().x_start);
- else
+ } else {
+ // Horizontal text
_empty_cursor_shape.position = Geom::Point(scan_runs.front().x_start, scan_runs.front().y + font_size);
+ }
}
}
}
bool Layout::calculateFlow()
{
+ TRACE(("begin calculateFlow()\n"));
Layout::Calculator calc = Calculator(this);
bool result = calc.calculate();
if (textLengthIncrement != 0) {
diff --git a/src/libnrtype/Layout-TNG-Input.cpp b/src/libnrtype/Layout-TNG-Input.cpp
index 84f3f260e..6f5d4e5f8 100644
--- a/src/libnrtype/Layout-TNG-Input.cpp
+++ b/src/libnrtype/Layout-TNG-Input.cpp
@@ -126,89 +126,43 @@ int Layout::_enum_converter(int input, EnumConversionItem const *conversion_tabl
return conversion_table[0].output;
}
-// ***** the style format interface
-// this doesn't include all accesses to SPStyle, only the ones that are non-trivial
-
-static const float medium_font_size = 12.0; // more of a default if all else fails than anything else
-float Layout::InputStreamTextSource::styleComputeFontSize() const
+Layout::Direction Layout::InputStreamTextSource::styleGetBlockProgression() const
{
- return style->font_size.computed;
-
- // in case the computed value's not good enough, here's some manual code held in reserve:
- SPStyle const *this_style = style;
- float inherit_multiplier = 1.0;
+ switch( style->writing_mode.computed ) {
- for ( ; ; ) {
- if (this_style->font_size.set && !this_style->font_size.inherit) {
- switch (this_style->font_size.type) {
- case SP_FONT_SIZE_LITERAL: {
- switch(this_style->font_size.literal) { // these multipliers are straight out of the CSS spec
- case SP_CSS_FONT_SIZE_XX_SMALL: return medium_font_size * inherit_multiplier * (3.0/5.0);
- case SP_CSS_FONT_SIZE_X_SMALL: return medium_font_size * inherit_multiplier * (3.0/4.0);
- case SP_CSS_FONT_SIZE_SMALL: return medium_font_size * inherit_multiplier * (8.0/9.0);
- default:
- case SP_CSS_FONT_SIZE_MEDIUM: return medium_font_size * inherit_multiplier;
- case SP_CSS_FONT_SIZE_LARGE: return medium_font_size * inherit_multiplier * (6.0/5.0);
- case SP_CSS_FONT_SIZE_X_LARGE: return medium_font_size * inherit_multiplier * (3.0/2.0);
- case SP_CSS_FONT_SIZE_XX_LARGE: return medium_font_size * inherit_multiplier * 2.0;
- case SP_CSS_FONT_SIZE_SMALLER: inherit_multiplier *= 0.84; break; //not exactly according to spec
- case SP_CSS_FONT_SIZE_LARGER: inherit_multiplier *= 1.26; break; //not exactly according to spec
- }
- break;
- }
- case SP_FONT_SIZE_PERCENTAGE: { // 'em' units should be in here, but aren't. Fix in style.cpp.
- inherit_multiplier *= this_style->font_size.value;
- break;
- }
- case SP_FONT_SIZE_LENGTH: {
- return this_style->font_size.value * inherit_multiplier;
- }
- }
- }
- if (this_style->object == NULL || this_style->object->parent == NULL) break;
- this_style = this_style->object->parent->style;
- if (this_style == NULL) break;
- }
- return medium_font_size * inherit_multiplier;
-}
+ case SP_CSS_WRITING_MODE_LR_TB:
+ case SP_CSS_WRITING_MODE_RL_TB:
+ return TOP_TO_BOTTOM;
+
+ case SP_CSS_WRITING_MODE_TB_RL:
+ return RIGHT_TO_LEFT;
-static const Layout::EnumConversionItem enum_convert_spstyle_block_progression_to_direction[] = {
- {SP_CSS_BLOCK_PROGRESSION_TB, Layout::TOP_TO_BOTTOM},
- {SP_CSS_BLOCK_PROGRESSION_LR, Layout::LEFT_TO_RIGHT},
- {SP_CSS_BLOCK_PROGRESSION_RL, Layout::RIGHT_TO_LEFT}};
+ case SP_CSS_WRITING_MODE_TB_LR:
+ return LEFT_TO_RIGHT;
-static const Layout::EnumConversionItem enum_convert_spstyle_writing_mode_to_direction[] = {
- {SP_CSS_WRITING_MODE_LR_TB, Layout::TOP_TO_BOTTOM},
- {SP_CSS_WRITING_MODE_RL_TB, Layout::TOP_TO_BOTTOM},
- {SP_CSS_WRITING_MODE_TB_RL, Layout::RIGHT_TO_LEFT},
- {SP_CSS_WRITING_MODE_TB_LR, Layout::LEFT_TO_RIGHT}};
+ default:
+ std::cerr << "Layout::InputTextStream::styleGetBlockProgression: invalid writing mode." << std::endl;
+ }
+ return TOP_TO_BOTTOM;
+}
-Layout::Direction Layout::InputStreamTextSource::styleGetBlockProgression() const
+SPCSSTextOrientation Layout::InputStreamTextSource::styleGetTextOrientation() const
{
- // this function shouldn't be necessary, but since style.cpp doesn't support
- // shorthand properties yet, it is.
- SPStyle const *this_style = style;
-
- for ( ; ; ) {
- if (this_style->block_progression.set)
- return (Layout::Direction)_enum_converter(this_style->block_progression.computed, enum_convert_spstyle_block_progression_to_direction, sizeof(enum_convert_spstyle_block_progression_to_direction)/sizeof(enum_convert_spstyle_block_progression_to_direction[0]));
- if (this_style->writing_mode.set)
- return (Layout::Direction)_enum_converter(this_style->writing_mode.computed, enum_convert_spstyle_writing_mode_to_direction, sizeof(enum_convert_spstyle_writing_mode_to_direction)/sizeof(enum_convert_spstyle_writing_mode_to_direction[0]));
- if (this_style->object == NULL || this_style->object->parent == NULL) break;
- this_style = this_style->object->parent->style;
- if (this_style == NULL) break;
- }
- return TOP_TO_BOTTOM;
+ return ((SPCSSTextOrientation)style->text_orientation.computed);
+}
+SPCSSBaseline Layout::InputStreamTextSource::styleGetDominantBaseline() const
+{
+ return ((SPCSSBaseline)style->dominant_baseline.computed);
}
-static Layout::Alignment text_anchor_to_alignment(unsigned anchor, Layout::Direction /*para_direction*/)
+static Layout::Alignment text_anchor_to_alignment(unsigned anchor, Layout::Direction para_direction)
{
switch (anchor) {
default:
- case SP_CSS_TEXT_ANCHOR_START: return Layout::LEFT;
+ case SP_CSS_TEXT_ANCHOR_START: return para_direction == Layout::LEFT_TO_RIGHT ? Layout::LEFT : Layout::RIGHT;
case SP_CSS_TEXT_ANCHOR_MIDDLE: return Layout::CENTER;
- case SP_CSS_TEXT_ANCHOR_END: return Layout::RIGHT;
+ case SP_CSS_TEXT_ANCHOR_END: return para_direction == Layout::LEFT_TO_RIGHT ? Layout::RIGHT : Layout::LEFT;
}
}
diff --git a/src/libnrtype/Layout-TNG-OutIter.cpp b/src/libnrtype/Layout-TNG-OutIter.cpp
index 707897f50..8c29b7dbc 100644
--- a/src/libnrtype/Layout-TNG-OutIter.cpp
+++ b/src/libnrtype/Layout-TNG-OutIter.cpp
@@ -120,7 +120,8 @@ Layout::iterator Layout::getNearestCursorPositionTo(double x, double y) const
double best_y_range = DBL_MAX;
double best_x_range = DBL_MAX;
for (chunk_index = 0 ; chunk_index < _chunks.size() ; chunk_index++) {
- LineHeight line_height = {0.0, 0.0, 0.0};
+ FontMetrics line_height;
+ line_height *= 0.0; // Set all metrics to zero.
double chunk_width = 0.0;
for ( ; span_index < _spans.size() && _spans[span_index].in_chunk == chunk_index ; span_index++) {
line_height.max(_spans[span_index].line_height);
@@ -340,8 +341,8 @@ Geom::Rect Layout::characterBoundingBox(iterator const &it, double *rotation) co
double baseline_y = _characters[char_index].line(this).baseline_y + _characters[char_index].span(this).baseline_shift;
if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) {
- double span_height = _spans[_characters[char_index].in_span].line_height.ascent + _spans[_characters[char_index].in_span].line_height.descent;
- top_left[Geom::Y] = top_left[Geom::X];
+ double span_height = _spans[_characters[char_index].in_span].line_height.emSize();
+ top_left[Geom::Y] = top_left[Geom::X];
top_left[Geom::X] = baseline_y - span_height * 0.5;
bottom_right[Geom::Y] = bottom_right[Geom::X];
bottom_right[Geom::X] = baseline_y + span_height * 0.5;
@@ -404,7 +405,7 @@ std::vector<Geom::Point> Layout::createSelectionShape(iterator const &it_start,
double vertical_scale = _glyphs.back().vertical_scale;
if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) {
- double span_height = vertical_scale * (_spans[span_index].line_height.ascent + _spans[span_index].line_height.descent);
+ double span_height = vertical_scale * _spans[span_index].line_height.emSize();
top_left[Geom::Y] = top_left[Geom::X];
top_left[Geom::X] = baseline_y - span_height * 0.5;
bottom_right[Geom::Y] = bottom_right[Geom::X];
@@ -507,20 +508,22 @@ void Layout::queryCursorShape(iterator const &it, Geom::Point &position, double
position[Geom::Y] = span->line(this).baseline_y + span->baseline_shift;
}
// up to now *position is the baseline point, not the final point which will be the bottom of the descent
- double vertical_scale = _glyphs.back().vertical_scale;
+ double vertical_scale = _glyphs.empty() ? 1.0 : _glyphs.back().vertical_scale;
if (_directions_are_orthogonal(_blockProgression(), TOP_TO_BOTTOM)) {
- height = vertical_scale * span->line_height.ascent + span->line_height.descent;
+ // Vertical text
+ height = vertical_scale * span->line_height.emSize();
rotation += M_PI / 2;
std::swap(position[Geom::X], position[Geom::Y]);
position[Geom::X] -= vertical_scale * sin(rotation) * height * 0.5;
position[Geom::Y] += vertical_scale * cos(rotation) * height * 0.5;
} else {
+ // Horizontal text
double caret_slope_run = 0.0, caret_slope_rise = 1.0;
if (span->font)
const_cast<font_instance*>(span->font)->FontSlope(caret_slope_run, caret_slope_rise);
double caret_slope = atan2(caret_slope_run, caret_slope_rise);
- height = vertical_scale * (span->line_height.ascent + span->line_height.descent) / cos(caret_slope);
+ height = vertical_scale * (span->line_height.emSize()) / cos(caret_slope);
rotation += caret_slope;
position[Geom::X] -= sin(rotation) * vertical_scale * span->line_height.descent;
position[Geom::Y] += cos(rotation) * vertical_scale * span->line_height.descent;
diff --git a/src/libnrtype/Layout-TNG-Output.cpp b/src/libnrtype/Layout-TNG-Output.cpp
index 6e3faf33b..526319f35 100644
--- a/src/libnrtype/Layout-TNG-Output.cpp
+++ b/src/libnrtype/Layout-TNG-Output.cpp
@@ -93,26 +93,55 @@ void Layout::_clearOutputObjects()
_path_fitted = NULL;
}
-void Layout::LineHeight::max(LineHeight const &other)
+void Layout::FontMetrics::set(font_instance *font)
{
- if (other.ascent > ascent) ascent = other.ascent;
- if (other.descent > descent) descent = other.descent;
- if (other.leading > leading) leading = other.leading;
+ if( font != NULL ) {
+ ascent = font->GetTypoAscent();
+ descent = font->GetTypoDescent();
+ xheight = font->GetXHeight();
+ ascent_max = font->GetMaxAscent();
+ descent_max = font->GetMaxDescent();
+ }
+}
+
+void Layout::FontMetrics::max(FontMetrics const &other)
+{
+ if (other.ascent > ascent ) ascent = other.ascent;
+ if (other.descent > descent ) descent = other.descent;
+ if( other.xheight > xheight ) xheight = other.xheight;
+ if( other.ascent_max > ascent_max ) ascent_max = other.ascent_max;
+ if( other.descent_max > descent_max ) descent_max = other.descent_max;
+}
+
+void Layout::FontMetrics::computeEffective( const double &line_height_multiplier ) {
+ double half_leading = 0.5 * (line_height_multiplier - 1.0) * emSize();
+ ascent += half_leading;
+ descent += half_leading;
}
void Layout::_getGlyphTransformMatrix(int glyph_index, Geom::Affine *matrix) const
{
Span const &span = _glyphs[glyph_index].span(this);
- double sin_rotation = sin(_glyphs[glyph_index].rotation);
- double cos_rotation = cos(_glyphs[glyph_index].rotation);
+ double rotation = _glyphs[glyph_index].rotation;
+ if ( (span.block_progression == LEFT_TO_RIGHT || span.block_progression == RIGHT_TO_LEFT) &&
+ _glyphs[glyph_index].orientation == ORIENTATION_SIDEWAYS ) {
+ // Vertical sideways text
+ rotation += M_PI/2.0;
+ }
+ double sin_rotation = sin(rotation);
+ double cos_rotation = cos(rotation);
(*matrix)[0] = span.font_size * cos_rotation;
(*matrix)[1] = span.font_size * sin_rotation;
(*matrix)[2] = span.font_size * sin_rotation;
(*matrix)[3] = -span.font_size * cos_rotation * (_glyphs[glyph_index].vertical_scale); // unscale vertically so the specified text height is preserved if lengthAdjust=spacingAndGlyphs
if (span.block_progression == LEFT_TO_RIGHT || span.block_progression == RIGHT_TO_LEFT) {
+ // Vertical text
+ // This effectively swaps x for y which changes handedness of coordinate system. This is a bit strange
+ // and not what one would expect but the compute code already reverses y so OK.
(*matrix)[4] = _lines[_chunks[span.in_chunk].in_line].baseline_y + _glyphs[glyph_index].y;
(*matrix)[5] = _chunks[span.in_chunk].left_x + _glyphs[glyph_index].x;
} else {
+ // Horizontal text
(*matrix)[4] = _chunks[span.in_chunk].left_x + _glyphs[glyph_index].x;
(*matrix)[5] = _lines[_chunks[span.in_chunk].in_line].baseline_y + _glyphs[glyph_index].y;
}
@@ -127,9 +156,9 @@ void Layout::show(DrawingGroup *in_arena, Geom::OptRect const &paintbox) const
InputStreamTextSource const *text_source = static_cast<InputStreamTextSource const *>(_input_stream[_spans[span_index].in_input_stream_item]);
text_source->style->text_decoration_data.tspan_width = _spans[span_index].width();
- text_source->style->text_decoration_data.ascender = _spans[span_index].line_height.getAscent();
- text_source->style->text_decoration_data.descender = _spans[span_index].line_height.getDescent();
- text_source->style->text_decoration_data.line_gap = _spans[span_index].line_height.getLeading();
+ text_source->style->text_decoration_data.ascender = _spans[span_index].line_height.getTypoAscent();
+ text_source->style->text_decoration_data.descender = _spans[span_index].line_height.getTypoDescent();
+
if(!span_index ||
(_chunks[_spans[span_index].in_chunk].in_line != _chunks[_spans[span_index-1].in_chunk].in_line)){
text_source->style->text_decoration_data.tspan_line_start = true;
@@ -170,11 +199,14 @@ void Layout::show(DrawingGroup *in_arena, Geom::OptRect const &paintbox) const
first_line_glyph = false;
phase0 = glyph_matrix.translation()[Geom::X];
}
- // save the starting coordinates for the line - these are needed for figuring out dot/dash/wave phase
+ // Save the starting coordinates for the line - these are needed for figuring out
+ // dot/dash/wave phase.
+ // Use maximum ascent and descent to ensure glpyhs that extend outside the embox
+ // are fully drawn.
(void) nr_text->addComponent(_spans[span_index].font, _glyphs[glyph_index].glyph, glyph_matrix,
_glyphs[glyph_index].width,
- _spans[span_index].line_height.getAscent(),
- _spans[span_index].line_height.getDescent(),
+ _spans[span_index].line_height.getMaxAscent(),
+ _spans[span_index].line_height.getMaxDescent(),
glyph_matrix.translation()[Geom::X] - phase0
);
}
@@ -580,7 +612,7 @@ Glib::ustring Layout::dumpAsText() const
result += Glib::ustring::compose(" font '%1' %2 %3 %4\n", sp_font_description_get_family(_spans[span_index].font->descr), _spans[span_index].font_size, style_to_text(pango_font_description_get_style(_spans[span_index].font->descr)), weight_to_text(pango_font_description_get_weight(_spans[span_index].font->descr)));
}
result += Glib::ustring::compose(" x_start = %1, x_end = %2\n", _spans[span_index].x_start, _spans[span_index].x_end)
- + Glib::ustring::compose(" line height: ascent %1, descent %2 leading %3\n", _spans[span_index].line_height.ascent, _spans[span_index].line_height.descent, _spans[span_index].line_height.leading)
+ + Glib::ustring::compose(" line height: ascent %1, descent %2\n", _spans[span_index].line_height.ascent, _spans[span_index].line_height.descent)
+ Glib::ustring::compose(" direction %1, block-progression %2\n", direction_to_text(_spans[span_index].direction), direction_to_text(_spans[span_index].block_progression))
+ " ** characters:\n";
Glib::ustring::const_iterator iter_char = _spans[span_index].input_stream_first_character;
diff --git a/src/libnrtype/Layout-TNG-Scanline-Maker.h b/src/libnrtype/Layout-TNG-Scanline-Maker.h
index d513d7cc1..7c90ea8cc 100644
--- a/src/libnrtype/Layout-TNG-Scanline-Maker.h
+++ b/src/libnrtype/Layout-TNG-Scanline-Maker.h
@@ -47,7 +47,7 @@ public:
between calls if the new height too big to fit in the space remaining in
this shape. Returns an empty vector if there is no space left in the
current shape. */
- virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height) =0;
+ virtual std::vector<ScanRun> makeScanline(Layout::FontMetrics const &line_height) =0;
/** Indicates that the caller has successfully filled the current line
and hence that the next call to makeScanline() should return lines on
@@ -71,7 +71,12 @@ public:
The metrics given here are considered to be the ones that are being
used now, and hence is the line advance height used by completeLine().
*/
- virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height) =0;
+ virtual bool canExtendCurrentScanline(Layout::FontMetrics const &line_height) =0;
+
+ /** Sets current line block height. Call before completeLine() to correct for
+ actually used line height (in case some chunks with larger font-size rolled back).
+ */
+ virtual void setLineHeight(Layout::FontMetrics const &line_height) =0;
};
/** \brief private to Layout. Generates infinite scanlines for when you don't want wrapping
@@ -90,7 +95,7 @@ public:
virtual ~InfiniteScanlineMaker();
/** Returns a single infinite run at the current location */
- virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height);
+ virtual std::vector<ScanRun> makeScanline(Layout::FontMetrics const &line_height);
/** Increments the current y by the current line height */
virtual void completeLine();
@@ -102,11 +107,16 @@ public:
virtual void setNewYCoordinate(double new_y);
/** Always true, but has to save the new height */
- virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height);
+ virtual bool canExtendCurrentScanline(Layout::FontMetrics const &line_height);
+
+ /** Sets current line block height. Call before completeLine() to correct for
+ actually used line height (in case some chunks with larger font-size rolled back).
+ */
+ virtual void setLineHeight(Layout::FontMetrics const &line_height);
private:
double _x, _y;
- Layout::LineHeight _current_line_height;
+ Layout::FontMetrics _current_line_height;
bool _negative_block_progression; /// if true, indicates that completeLine() should decrement rather than increment, ie block-progression is either rl or bt
};
@@ -122,7 +132,7 @@ public:
ShapeScanlineMaker(Shape const *shape, Layout::Direction block_progression);
virtual ~ShapeScanlineMaker();
- virtual std::vector<ScanRun> makeScanline(Layout::LineHeight const &line_height);
+ virtual std::vector<ScanRun> makeScanline(Layout::FontMetrics const &line_height);
virtual void completeLine();
@@ -131,7 +141,13 @@ public:
virtual void setNewYCoordinate(double new_y);
/** never true */
- virtual bool canExtendCurrentScanline(Layout::LineHeight const &line_height);
+ virtual bool canExtendCurrentScanline(Layout::FontMetrics const &line_height);
+
+ /** Sets current line block height. Call before completeLine() to correct for
+ actually used line height (in case some chunks with larger font-size rolled back).
+ */
+ virtual void setLineHeight(Layout::FontMetrics const &line_height);
+
private:
/** To generate scanlines for top-to-bottom text it is easiest if we
simply rotate the given shape by a multiple of 90 degrees. This stores
diff --git a/src/libnrtype/Layout-TNG-Scanline-Makers.cpp b/src/libnrtype/Layout-TNG-Scanline-Makers.cpp
index 7144f3876..dcc973a24 100644
--- a/src/libnrtype/Layout-TNG-Scanline-Makers.cpp
+++ b/src/libnrtype/Layout-TNG-Scanline-Makers.cpp
@@ -19,9 +19,7 @@ namespace Text {
Layout::InfiniteScanlineMaker::InfiniteScanlineMaker(double initial_x, double initial_y, Layout::Direction block_progression)
{
- _current_line_height.ascent = 0.0;
- _current_line_height.descent = 0.0;
- _current_line_height.leading = 0.0;
+ _current_line_height.setZero();
switch (block_progression) {
case LEFT_TO_RIGHT:
case RIGHT_TO_LEFT:
@@ -41,7 +39,7 @@ Layout::InfiniteScanlineMaker::~InfiniteScanlineMaker()
{
}
-std::vector<Layout::ScanlineMaker::ScanRun> Layout::InfiniteScanlineMaker::makeScanline(Layout::LineHeight const &line_height)
+std::vector<Layout::ScanlineMaker::ScanRun> Layout::InfiniteScanlineMaker::makeScanline(Layout::FontMetrics const &line_height)
{
std::vector<ScanRun> runs(1);
runs[0].x_start = _x;
@@ -54,12 +52,10 @@ std::vector<Layout::ScanlineMaker::ScanRun> Layout::InfiniteScanlineMaker::makeS
void Layout::InfiniteScanlineMaker::completeLine()
{
if (_negative_block_progression)
- _y -= _current_line_height.total();
+ _y -= _current_line_height.emSize();
else
- _y += _current_line_height.total();
- _current_line_height.ascent = 0.0;
- _current_line_height.descent = 0.0;
- _current_line_height.leading = 0.0;
+ _y += _current_line_height.emSize();
+ _current_line_height.setZero();
}
void Layout::InfiniteScanlineMaker::setNewYCoordinate(double new_y)
@@ -67,12 +63,17 @@ void Layout::InfiniteScanlineMaker::setNewYCoordinate(double new_y)
_y = new_y;
}
-bool Layout::InfiniteScanlineMaker::canExtendCurrentScanline(Layout::LineHeight const &line_height)
+bool Layout::InfiniteScanlineMaker::canExtendCurrentScanline(Layout::FontMetrics const &line_height)
{
_current_line_height = line_height;
return true;
}
+void Layout::InfiniteScanlineMaker::setLineHeight(Layout::FontMetrics const &line_height)
+{
+ _current_line_height = line_height;
+}
+
// *********************** real shapes version
Layout::ShapeScanlineMaker::ShapeScanlineMaker(Shape const *shape, Layout::Direction block_progression)
@@ -111,29 +112,29 @@ Layout::ShapeScanlineMaker::~ShapeScanlineMaker()
delete _rotated_shape;
}
-std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScanline(Layout::LineHeight const &line_height)
+std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScanline(Layout::FontMetrics const &line_height)
{
- FloatLigne line_rasterization;
- FloatLigne line_decent_length_runs;
- float line_text_height = (float)(line_height.ascent + line_height.descent);
-
if (_y > _bounding_box_bottom)
return std::vector<ScanRun>();
if (_y < _bounding_box_top)
_y = _bounding_box_top;
+ FloatLigne line_rasterization;
+ FloatLigne line_decent_length_runs;
+ float line_text_height = (float)(line_height.emSize());
if (line_text_height == 0.0)
line_text_height = 0.001; // Scan() doesn't work for zero height so this will have to do
- _current_line_height = (float)line_height.total();
+ _current_line_height = (float)line_height.emSize();
// I think what's going on here is that we're moving the top of the scanline to the given position...
_rotated_shape->Scan(_rasterizer_y, _current_rasterization_point, _y, line_text_height);
// ...then actually retreiving the scanline (which alters the first two parameters)
_rotated_shape->Scan(_rasterizer_y, _current_rasterization_point, _y + line_text_height , &line_rasterization, true, line_text_height);
- // sanitise the raw rasterisation, which could have weird overlaps
+ // sanitise the raw rasterisation, which could have weird overlaps
line_rasterization.Flatten();
+ // line_rasterization.Affiche();
// cut out runs that cover less than 90% of the line
line_decent_length_runs.Over(&line_rasterization, 0.9 * line_text_height);
@@ -145,7 +146,7 @@ std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScan
std::vector<ScanRun> result(1);
result[0].x_start = line_rasterization.runs[0].st;
result[0].x_end = line_rasterization.runs[0].st;
- result[0].y = _negative_block_progression ? -_current_line_height - _y : _y;
+ result[0].y = _negative_block_progression ? - _y : _y;
return result;
}
@@ -154,7 +155,7 @@ std::vector<Layout::ScanlineMaker::ScanRun> Layout::ShapeScanlineMaker::makeScan
for (unsigned i = 0 ; i < result.size() ; i++) {
result[i].x_start = line_decent_length_runs.runs[i].st;
result[i].x_end = line_decent_length_runs.runs[i].en;
- result[i].y = _negative_block_progression ? -_current_line_height - _y : _y;
+ result[i].y = _negative_block_progression ? - _y : _y;
}
return result;
@@ -167,23 +168,28 @@ void Layout::ShapeScanlineMaker::completeLine()
double Layout::ShapeScanlineMaker::yCoordinate()
{
- if (_negative_block_progression) return -_current_line_height - _y;
+ if (_negative_block_progression) return - _y;
return _y;
}
void Layout::ShapeScanlineMaker::setNewYCoordinate(double new_y)
{
_y = (float)new_y;
- if (_negative_block_progression) _y = -_current_line_height - _y;
+ if (_negative_block_progression) _y = - _y;
// what will happen with the rasteriser if we move off the shape?
// it's not an important question because <flowSpan> doesn't have a y attribute
}
-bool Layout::ShapeScanlineMaker::canExtendCurrentScanline(Layout::LineHeight const &/*line_height*/)
+bool Layout::ShapeScanlineMaker::canExtendCurrentScanline(Layout::FontMetrics const &/*line_height*/)
{
//we actually could return true if only the leading changed, but that's too much effort for something that rarely happens
return false;
}
+void Layout::ShapeScanlineMaker::setLineHeight(Layout::FontMetrics const &line_height)
+{
+ _current_line_height = line_height.emSize();
+}
+
}//namespace Text
}//namespace Inkscape
diff --git a/src/libnrtype/Layout-TNG.cpp b/src/libnrtype/Layout-TNG.cpp
index 8b0889188..ec488b584 100644
--- a/src/libnrtype/Layout-TNG.cpp
+++ b/src/libnrtype/Layout-TNG.cpp
@@ -14,7 +14,7 @@ namespace Inkscape {
namespace Text {
const gunichar Layout::UNICODE_SOFT_HYPHEN = 0x00AD;
-const double Layout::LINE_HEIGHT_NORMAL = 1.25;
+const double Layout::LINE_HEIGHT_NORMAL = 125;
Layout::Layout() :
_input_truncated(0),
diff --git a/src/libnrtype/Layout-TNG.h b/src/libnrtype/Layout-TNG.h
index 26db1fad9..97a05bde8 100644
--- a/src/libnrtype/Layout-TNG.h
+++ b/src/libnrtype/Layout-TNG.h
@@ -22,6 +22,7 @@
#include <vector>
#include <boost/optional.hpp>
#include <svg/svg-length.h>
+#include "style-enums.h"
#ifdef HAVE_CAIRO_PDF
namespace Inkscape {
@@ -157,6 +158,9 @@ public:
both the 'direction' and 'block-progression' CSS attributes. */
enum Direction {LEFT_TO_RIGHT, RIGHT_TO_LEFT, TOP_TO_BOTTOM, BOTTOM_TO_TOP};
+ /** Used to specify orientation of glyphs in vertical text. */
+ enum Orientation {ORIENTATION_UPRIGHT, ORIENTATION_SIDEWAYS};
+
/** Display alignment for shapes. See appendWrapShape(). */
enum DisplayAlign {DISPLAY_ALIGN_BEFORE, DISPLAY_ALIGN_CENTER, DISPLAY_ALIGN_AFTER};
@@ -603,19 +607,69 @@ public:
//@}
- /// it's useful for this to be public so that ScanlineMaker can use it
- struct LineHeight {
- double ascent;
- double descent;
- double leading;
- inline double total() const {return ascent + descent + leading;}
- inline void setZero() {ascent = descent = leading = 0.0;}
- inline LineHeight& operator*=(double x) {ascent *= x; descent *= x; leading *= x; return *this;}
- void max(LineHeight const &other); /// makes this object contain the largest of all three members between this object and other
- inline double getAscent() const {return ascent; }
- inline double getDescent() const {return descent; }
- inline double getLeading() const {return leading; }
- };
+
+ /**
+ * Keep track of font metrics. Two use cases:
+ * 1. Keep track of ascent, descent, and x-height of an individual font.
+ * 2. Keep track of effective ascent and descent that includes half-leading.
+ *
+ * Note: Leading refers to the "external" leading which is added (subtracted) due to
+ * a computed value of 'line-height' that differs from 'font-size'. "Internal" leading
+ * which is specified inside a font is not used in CSS. The 'font-size' is based on
+ * the font's em size which is 'ascent' + 'descent'.
+ *
+ * This structure was renamed (and modified) from "LineHeight".
+ *
+ * It's useful for this to be public so that ScanlineMaker can use it.
+ */
+ class FontMetrics {
+
+ public:
+ FontMetrics() { reset(); }
+
+ void reset() {
+ ascent = 0.8;
+ descent = -0.2;
+ xheight = 0.5;
+ ascent_max = 0.8;
+ descent_max = 0.2;
+ }
+
+ void set( font_instance *font );
+
+ // CSS 2.1 dictates that font-size is based on em-size which is defined as ascent + descent
+ inline double emSize() const {return ascent + descent;}
+ // Alternatively name function for use 2.
+ inline double lineSize() const { return ascent + descent; }
+ inline void setZero() {ascent = descent = xheight = ascent_max = descent_max = 0.0;}
+
+ // For scaling for 'font-size'.
+ inline FontMetrics& operator*=(double x) {
+ ascent *= x; descent *= x; xheight *= x; ascent_max *= x; descent_max *= x;
+ return *this;
+ }
+
+ /// Save the larger values of ascent and descent between this and other. Needed for laying
+ /// out a line with mixed font-sizes, fonts, or line spacings.
+ void max(FontMetrics const &other);
+
+ /// Calculate the effective ascent and descent including half "leading".
+ void computeEffective( const double &line_height );
+
+ inline double getTypoAscent() const {return ascent; }
+ inline double getTypoDescent() const {return descent; }
+ inline double getXHeight() const {return xheight; }
+ inline double getMaxAscent() const {return ascent_max; }
+ inline double getMaxDescent() const {return descent_max; }
+
+ // private:
+ double ascent; // Typographic ascent.
+ double descent; // Typographic descent.
+ double xheight; // Height of 'x' measured from alphabetic baseline.
+ double ascent_max; // Maximum ascent of all glyphs in font.
+ double descent_max; // Maximum descent of all glyphs in font.
+
+ }; // End FontMetrics
/// see _enum_converter()
struct EnumConversionItem {
@@ -664,11 +718,12 @@ private:
LengthAdjust lengthAdjust;
// a few functions for some of the more complicated style accesses
- float styleComputeFontSize() const;
/// The return value must be freed with pango_font_description_free()
PangoFontDescription *styleGetFontDescription() const;
font_instance *styleGetFontInstance() const;
Direction styleGetBlockProgression() const;
+ SPCSSTextOrientation styleGetTextOrientation() const;
+ SPCSSBaseline styleGetDominantBaseline() const;
Alignment styleGetAlignment(Direction para_direction, bool try_text_align) const;
};
@@ -707,6 +762,22 @@ private:
return TOP_TO_BOTTOM;
}
+ /** The overall text-orientation of the whole flow. */
+ inline SPCSSTextOrientation _blockTextOrientation() const
+ {
+ if(!_input_stream.empty())
+ return static_cast<InputStreamTextSource*>(_input_stream.front())->styleGetTextOrientation();
+ return SP_CSS_TEXT_ORIENTATION_MIXED;
+ }
+
+ /** The overall text-orientation of the whole flow. */
+ inline SPCSSBaseline _blockBaseline() const
+ {
+ if(!_input_stream.empty())
+ return static_cast<InputStreamTextSource*>(_input_stream.front())->styleGetDominantBaseline();
+ return SP_CSS_BASELINE_AUTO;
+ }
+
/** so that LEFT_TO_RIGHT == RIGHT_TO_LEFT but != TOP_TO_BOTTOM */
static bool _directions_are_orthogonal(Direction d1, Direction d2);
@@ -748,6 +819,7 @@ private:
float x; /// relative to the start of the chunk
float y; /// relative to the current line's baseline
float rotation; /// absolute, modulo any object transforms, which we don't know about
+ Orientation orientation; /// Orientation of glyph in vertical text
float width;
float vertical_scale; /// to implement lengthAdjust="spacingAndGlyphs" that must scale glyphs only horizontally; instead we change font size and then undo that change vertically only
inline Span const & span(Layout const *l) const {return l->_spans[l->_characters[in_character].in_span];}
@@ -772,8 +844,9 @@ private:
float x_start; /// relative to the start of the chunk
float x_end; /// relative to the start of the chunk
inline float width() const {return std::abs(x_start - x_end);}
- LineHeight line_height;
+ FontMetrics line_height;
double baseline_shift; /// relative to the line's baseline
+ SPCSSTextOrientation text_orientation;
Direction direction; /// See CSS3 section 3.2. Either rtl or ltr
Direction block_progression; /// See CSS3 section 3.2. The direction in which lines go.
unsigned in_input_stream_item;
diff --git a/src/libnrtype/TextWrapper.cpp b/src/libnrtype/TextWrapper.cpp
index 380e9ba3f..124f3f7b4 100644
--- a/src/libnrtype/TextWrapper.cpp
+++ b/src/libnrtype/TextWrapper.cpp
@@ -862,7 +862,7 @@ void text_wrapper::MeasureBoxes(void)
for (int i = 0; i < nbBox; i++) {
boxes[i].ascent = 0;
boxes[i].descent = 0;
- boxes[i].leading = 0;
+ boxes[i].xheight = 0;
boxes[i].width = 0;
PangoFont *curPF = glyph_text[boxes[i].g_st].font;
@@ -870,7 +870,7 @@ void text_wrapper::MeasureBoxes(void)
PangoFontDescription *pfd = pango_font_describe(curPF);
font_instance *curF = f_src->Face(pfd);
if ( curF ) {
- curF->FontMetrics(boxes[i].ascent, boxes[i].descent, boxes[i].leading);
+ curF->FontMetrics(boxes[i].ascent, boxes[i].descent, boxes[i].xheight);
curF->Unref();
}
pango_font_description_free(pfd);
diff --git a/src/libnrtype/font-instance.h b/src/libnrtype/font-instance.h
index 5a71e353b..2fac7c19b 100644
--- a/src/libnrtype/font-instance.h
+++ b/src/libnrtype/font-instance.h
@@ -57,19 +57,31 @@ public:
// nota: all coordinates returned by these functions are on a [0..1] scale; you need to multiply
// by the fontsize to get the real sizes
+
+ // Return 2geom pathvector for glyph. Deallocated when font instance dies.
Geom::PathVector* PathVector(int glyph_id);
- // returns the 2geom-type pathvector for this glyph. no refcounting needed, it's deallocated when the font_instance dies
+
+ // Horizontal advance if 'vertical' is false, vertical advance if true.
double Advance(int glyph_id, bool vertical);
- // nominal advance of the font.
+
+ double GetTypoAscent() { return _ascent; }
+ double GetTypoDescent() { return _descent; }
+ double GetXHeight() { return _xheight; }
+ double GetMaxAscent() { return _ascent_max; }
+ double GetMaxDescent() { return _descent_max; }
+ const double* GetBaselines() { return _baselines; }
+
bool FontMetrics(double &ascent, double &descent, double &leading);
- bool FontDecoration(double &underline_position, double &underline_thickness,
- double &linethrough_position, double &linethrough_thickness);
+ bool FontDecoration(double &underline_position, double &underline_thickness,
+ double &linethrough_position, double &linethrough_thickness);
bool FontSlope(double &run, double &rise);
// for generating slanted cursors for oblique fonts
- Geom::OptRect BBox(int glyph_id);
+ Geom::OptRect BBox(int glyph_id);
private:
void FreeTheFace();
+ // Find ascent, descent, x-height, and baselines.
+ void FindFontMetrics();
// Temp: make public
public:
@@ -81,6 +93,17 @@ public:
// as long as pFont is valid, theFace is too
#endif
+private:
+
+ // Font metrics in em-box units
+ double _ascent; // Typographic ascent.
+ double _descent; // Typographic descent.
+ double _xheight; // x-height of font.
+ double _ascent_max; // Maxiumum ascent of all glyphs in font.
+ double _descent_max; // Maxiumum descent of all glyphs in font.
+
+ // Baselines
+ double _baselines[SP_CSS_BASELINE_SIZE];
};
diff --git a/src/libnrtype/font-lister.cpp b/src/libnrtype/font-lister.cpp
index 70374864a..568a7c8cc 100644
--- a/src/libnrtype/font-lister.cpp
+++ b/src/libnrtype/font-lister.cpp
@@ -6,7 +6,6 @@
#include <gtkmm/treemodel.h>
#include <libnrtype/font-instance.h>
-#include <libnrtype/TextWrapper.h>
#include <libnrtype/one-glyph.h>
#include "font-lister.h"
diff --git a/src/libnrtype/one-box.h b/src/libnrtype/one-box.h
index c868cf23f..c3b36a3ce 100644
--- a/src/libnrtype/one-box.h
+++ b/src/libnrtype/one-box.h
@@ -9,7 +9,7 @@
// this time for sp-typeset
struct one_box {
int g_st, g_en; ///< First and last glyph of this word.
- double ascent, descent, leading;
+ double ascent, descent, xheight;
double width;
bool word_start, word_end;
};
diff --git a/src/libuemf/uemf.c b/src/libuemf/uemf.c
index 3180c757c..fa7689bb6 100644
--- a/src/libuemf/uemf.c
+++ b/src/libuemf/uemf.c
@@ -16,11 +16,11 @@
/*
File: uemf.c
-Version: 0.0.30
-Date: 20-MAR-2015
+Version: 0.0.31
+Date: 26-JAN-2016
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
-Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
*/
#ifdef __cplusplus
@@ -1858,8 +1858,8 @@ U_LOGCOLORSPACEA logcolorspacea_set(
lcsa.lcsIntent = lcsIntent;
lcsa.lcsEndpoints = lcsEndpoints;
lcsa.lcsGammaRGB = lcsGammaRGB;
- memset(lcsa.lcsFilename,0,U_MAX_PATH); // zero out the Filename field
strncpy(lcsa.lcsFilename,lcsFilename,U_MAX_PATH);
+ lcsa.lcsFilename[U_MAX_PATH-1] = '\0';
return(lcsa);
}
@@ -1889,6 +1889,7 @@ U_LOGCOLORSPACEW logcolorspacew_set(
lcsa.lcsEndpoints = lcsEndpoints;
lcsa.lcsGammaRGB = lcsGammaRGB;
wchar16strncpypad(lcsa.lcsFilename,lcsFilename,U_MAX_PATH);
+ lcsa.lcsFilename[U_MAX_PATH-1] = '\0';
return(lcsa);
}
@@ -1983,6 +1984,7 @@ U_LOGFONT logfont_set(
lf.lfQuality = lfQuality;
lf.lfPitchAndFamily = lfPitchAndFamily;
wchar16strncpypad(lf.lfFaceName, lfFaceName, U_LF_FACESIZE); // pad this one as the intial structure was not set to zero
+ lf.lfFaceName[U_LF_FACESIZE-1] = '\0';
return(lf);
}
@@ -2006,7 +2008,9 @@ U_LOGFONT_PANOSE logfont_panose_set(
U_LOGFONT_PANOSE lfp;
memset(&lfp,0,sizeof(U_LOGFONT_PANOSE)); // all fields zero unless needed. Many should be ignored or must be 0.
wchar16strncpy(lfp.elfFullName, elfFullName, U_LF_FULLFACESIZE);
+ lfp.elfFullName[U_LF_FULLFACESIZE-1] = '\0';
wchar16strncpy(lfp.elfStyle, elfStyle, U_LF_FACESIZE);
+ lfp.elfStyle[U_LF_FACESIZE-1] = '\0';
lfp.elfLogFont = elfLogFont;
lfp.elfStyleSize = elfStyleSize;
lfp.elfPanose = elfPanose;
diff --git a/src/libuemf/uemf.h b/src/libuemf/uemf.h
index f6ed7da03..82fd0990c 100644
--- a/src/libuemf/uemf.h
+++ b/src/libuemf/uemf.h
@@ -95,11 +95,11 @@ these WMF enumerations is by referencing the following table:
/*
File: uemf.h
-Version: 0.0.32
-Date: 28-APR-2015
+Version: 0.0.33
+Date: 27-JAN-2016
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
-Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
*/
#ifndef _UEMF_
@@ -426,6 +426,7 @@ typedef struct {
uint32_t biClrImportant; //!< Number of bmciColors needed (0 means all).
} U_BITMAPINFOHEADER,
*PU_BITMAPINFOHEADER; //!< WMF manual 2.2.2.3
+#define U_SIZE_BITMAPINFOHEADER (sizeof(U_BITMAPINFOHEADER))
/** WMF manual 2.2.2.6
\brief For U_CIEXYZTRIPLE (all) fields
@@ -1678,6 +1679,7 @@ typedef struct {
U_FNTAXES Values[1]; //!< Optional. Array of font axes for opentype font
} U_DESIGNVECTOR,
*PU_DESIGNVECTOR; //!< EMF manual 2.2.3
+#define U_SIZE_DESIGNVECTOR (sizeof(uint32_t) + sizeof(U_NUM_FNTAXES))
/**
\brief For U_EMR_COMMENT_MULTIFORMATS record, where an array of these is used
@@ -1901,6 +1903,7 @@ typedef struct {
U_LOGPLTNTRY palPalEntry[1]; //!< PC_Entry Enumeration
} U_LOGPALETTE,
*PU_LOGPALETTE; //!< EMF manual 2.2.17
+#define U_SIZE_LOGPALETTE (2*sizeof(uint16_t))
// Microsoft name: LogPaletteEntry Object, EMF manual 2.2.18, defined above, before 2.2.17
@@ -1970,6 +1973,7 @@ typedef struct {
U_RECTL rclBounds; //!< Region bounds
} U_RGNDATAHEADER,
*PU_RGNDATAHEADER; //!< EMF manual 2.2.25
+#define U_SIZE_RGNDATAHEADER (sizeof(U_RGNDATAHEADER))
/**
\brief For U_EMRFILLRGN RgnData field(s)
@@ -1982,6 +1986,7 @@ typedef struct {
U_RECTL Buffer[1]; //!< Array of U_RECTL elements
} U_RGNDATA,
*PU_RGNDATA; //!< EMF manual 2.2.24
+#define U_SIZE_RGNDATA U_SIZE_RGNDATAHEADER
// Microsoft name: RegionDataHeader Object. EMF manual 2.2.25, defined above, before 2.2.24
// Microsoft name: TriVertex Object. EMF manual 2.2.26, defined above, before 2.2.7
@@ -2017,6 +2022,7 @@ typedef struct {
U_STYLEENTRY elpStyleEntry[1]; //!< Array of StyleEntry (For user specified dot/dash patterns)
} U_EXTLOGPEN,
*PU_EXTLOGPEN; //!< EMF manual 2.2.20
+#define U_SIZE_EXTLOGPEN (sizeof(U_EXTLOGPEN) - sizeof(U_STYLEENTRY)) // there may not be any style entries
/**
\brief For U_EMR_* OffBmi* fields
@@ -2030,6 +2036,7 @@ typedef struct {
U_RGBQUAD bmiColors[1]; //!< Color table. 24 bit images do not use color table values.
} U_BITMAPINFO,
*PU_BITMAPINFO; //!< WMF Manual 2.2.2.9
+#define U_SIZE_BITMAPINFO U_SIZE_BITMAPINFOHEADER
/**
\brief U_EMRALPHABLEND Blend field
@@ -2056,6 +2063,7 @@ typedef struct {
uint32_t dParm[1]; //!< Data in record
} U_ENHMETARECORD,
*PU_ENHMETARECORD; //!< General form of an EMF record.
+#define U_SIZE_ENHMETARECORD (2*sizeof(uint32_t))
/** First two fields of all EMF records,
First two fields of all EMF+ records (1 or more within an EMF comment)
@@ -2171,7 +2179,7 @@ typedef struct {
U_EMRPOLYPOLYGON, //!< EMF manual 2.3.5.28
*PU_EMRPOLYPOLYLINE, //!< EMF manual 2.3.5.30
*PU_EMRPOLYPOLYGON; //!< EMF manual 2.3.5.28
-#define U_SIZE_EMRPOLYPOLYLINE (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POLYCOUNTS) + sizeof(U_POLYCOUNTS))
+#define U_SIZE_EMRPOLYPOLYLINE (sizeof(U_EMR) + sizeof(U_RECTL) + sizeof(U_NUM_POLYCOUNTS) + sizeof(U_NUM_POINTL))
#define U_SIZE_EMRPOLYPOLYGON U_SIZE_EMRPOLYPOLYLINE
/* Index 9,11 (numbers interleave with next one) */
@@ -2535,10 +2543,10 @@ typedef struct {
typedef struct {
U_EMR emr; //!< U_EMR
uint32_t ihPal; //!< Index to place object in EMF object table (this entry must not yet exist)
- U_LOGPALETTE lgpl; //!< Palette properties
+ U_LOGPALETTE lgpl; //!< Palette properties (variable size)
} U_EMRCREATEPALETTE,
*PU_EMRCREATEPALETTE; //!< EMF manual 2.3.7.6
-#define U_SIZE_EMRCREATEPALETTE (sizeof(U_EMRCREATEPALETTE))
+#define U_SIZE_EMRCREATEPALETTE (sizeof(U_EMR) + sizeof(uint32_t) + U_SIZE_LOGPALETTE)
/* Index 50 */
/** EMF manual 2.3.8.8
@@ -3029,7 +3037,7 @@ typedef struct {
//!< Record may include optional DIB bitmap
} U_EMREXTCREATEPEN,
*PU_EMREXTCREATEPEN; //!< EMF manual 2.3.7.9
-#define U_SIZE_EMREXTCREATEPEN (sizeof(U_EMREXTCREATEPEN))
+#define U_SIZE_EMREXTCREATEPEN (sizeof(U_EMREXTCREATEPEN) - sizeof(U_EXTLOGPEN) + U_SIZE_EXTLOGPEN)
/* Index 96.97 */
/** EMF manual 2.3.5.32
@@ -3084,7 +3092,7 @@ typedef struct {
U_DATA Data[1]; //!< OpenGL data
} U_EMRGLSRECORD,
*PU_EMRGLSRECORD; //!< EMF manual 2.3.9.2
-#define U_SIZE_EMRGLSRECORD (sizeof(U_EMRGLSRECORD))
+#define U_SIZE_EMRGLSRECORD (sizeof(U_EMR) + sizeof(U_CBDATA))
/* Index 103 */
/** EMF manual 2.3.9.1
@@ -3167,7 +3175,7 @@ typedef struct {
uint16_t Driver[1]; //!< Driver name in uint16_t characters, null terminated
} U_EMRNAMEDESCAPE,
*PU_EMRNAMEDESCAPE; //!< EMF manual 2.3.6.3
-#define U_SIZE_EMRNAMEDESCAPE (sizeof(U_EMRNAMEDESCAPE))
+#define U_SIZE_EMRNAMEDESCAPE (sizeof(U_EMR) + 2*sizeof(U_CBDATA))
/* Index 111-113 (not implemented )
EMF manual 2.3.8.1
diff --git a/src/libuemf/uemf_print.c b/src/libuemf/uemf_print.c
index 4bc9f0206..28fe0b7c3 100644
--- a/src/libuemf/uemf_print.c
+++ b/src/libuemf/uemf_print.c
@@ -6,11 +6,11 @@
/*
File: uemf_print.c
-Version: 0.0.20
-Date: 21-MAY-2015
+Version: 0.0.21
+Date: 26-JAN-2016
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
-Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
*/
#ifdef __cplusplus
@@ -1884,15 +1884,21 @@ void U_EMRPAINTRGN_print(const char *contents){
*/
void U_EMREXTSELECTCLIPRGN_print(const char *contents){
PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN) (contents);
- if(pEmr->emr.nSize < sizeof(U_EMREXTSELECTCLIPRGN)){
+ if(pEmr->emr.nSize < U_SIZE_EMREXTSELECTCLIPRGN){
printf(" record corruption HERE\n");
return;
}
const char *blimit = contents + pEmr->emr.nSize;
printf(" cbRgnData: %u\n",pEmr->cbRgnData);
printf(" iMode: %u\n",pEmr->iMode);
- const char *minptr = MAKE_MIN_PTR(((const char *) &pEmr->RgnData + pEmr->cbRgnData),blimit);
- printf(" RegionData: "); rgndata_print(pEmr->RgnData, minptr); printf("\n");
+ if(pEmr->iMode == U_RGN_COPY && !pEmr->cbRgnData){
+ printf(" RegionData: none (Clip region becomes NULL)\n");
+ }
+ else {
+ const char *minptr = MAKE_MIN_PTR(((const char *) &pEmr->RgnData + pEmr->cbRgnData),blimit);
+ printf(" RegionData: "); rgndata_print(pEmr->RgnData, minptr); printf("\n");
+ }
+
}
// U_EMRBITBLT 76
diff --git a/src/libuemf/uemf_safe.c b/src/libuemf/uemf_safe.c
index 36284d60e..a3e050282 100644
--- a/src/libuemf/uemf_safe.c
+++ b/src/libuemf/uemf_safe.c
@@ -15,11 +15,11 @@
/*
File: uemf_safe.c
-Version: 0.0.4
-Date: 23-APR-2015
+Version: 0.0.5
+Date: 26-JAN-2016
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
-Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
*/
#ifdef __cplusplus
@@ -740,6 +740,8 @@ int U_EMREXTSELECTCLIPRGN_safe(const char *record){
if(!core5_safe(record, U_SIZE_EMREXTSELECTCLIPRGN))return(0);
PU_EMREXTSELECTCLIPRGN pEmr = (PU_EMREXTSELECTCLIPRGN)(record);
int cbRgnData = pEmr->cbRgnData;
+ /* data size can be 0 with COPY mode, it means clear the clip region. */
+ if(pEmr->iMode == U_RGN_COPY && !cbRgnData)return(1);
const char *blimit = record + pEmr->emr.nSize;
if(IS_MEM_UNSAFE(pEmr->RgnData, cbRgnData, blimit))return(0);
return(rgndata_safe(pEmr->RgnData, cbRgnData));
diff --git a/src/libuemf/upmf.c b/src/libuemf/upmf.c
index fe929e443..5cb558ac6 100644
--- a/src/libuemf/upmf.c
+++ b/src/libuemf/upmf.c
@@ -21,11 +21,11 @@
/*
File: upmf.c
-Version: 0.0.11
-Date: 28-MAY-2015
+Version: 0.0.12
+Date: 26-JAN-2016
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
-Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
*/
#ifdef __cplusplus
@@ -4125,7 +4125,6 @@ U_PSEUDO_OBJ *U_PMR_DRAWCURVE_set(uint32_t PenID, U_FLOAT Tension, uint32_t Offs
\brief Create and set a U_PMR_DRAWDRIVERSTRING PseudoObject
\return Pointer to PseudoObject, NULL on error
\param FontID U_PMF_FONT object in the EMF+ object table (0-63, inclusive)
- \param Tension Controls splines, 0 is straight line, >0 is curved
\param BrushID U_PSEUDO_OBJ containing a U_PMF_ARGB or a U_PMF_4NUM. Color or U_PMF_BRUSH object in the EMF+ object table (0-63, inclusive)
\param DSOFlags DriverStringOptions flags
\param HasMatrix If 1 record contains a TransformMatrix field, if 0 it does not.
@@ -4137,7 +4136,7 @@ U_PSEUDO_OBJ *U_PMR_DRAWCURVE_set(uint32_t PenID, U_FLOAT Tension, uint32_t Offs
EMF+ manual 2.3.4.6, Microsoft name: EmfPlusDrawDriverString Record, Index 0x36
*/
-U_PSEUDO_OBJ *U_PMR_DRAWDRIVERSTRING_set(uint32_t FontID, U_FLOAT Tension, const U_PSEUDO_OBJ *BrushID,
+U_PSEUDO_OBJ *U_PMR_DRAWDRIVERSTRING_set(uint32_t FontID, const U_PSEUDO_OBJ *BrushID,
uint32_t DSOFlags, uint32_t HasMatrix, uint32_t GlyphCount,
const uint16_t *Glyphs, const U_PSEUDO_OBJ *Points, const U_PSEUDO_OBJ *Tm){
int btype;
@@ -4163,7 +4162,6 @@ U_PSEUDO_OBJ *U_PMR_DRAWDRIVERSTRING_set(uint32_t FontID, U_FLOAT Tension, const
U_PSEUDO_OBJ *ph = U_PMR_CMN_HDR_set(U_PMR_DRAWDRIVERSTRING,utmp16,Size);
const U_SERIAL_DESC List[] = {
{ph->Data,ph->Used, 1, U_XE},
- {&Tension, 4, 1, U_LE},
{BrushID->Data, BrushID->Used, 1, U_XE},
{&DSOFlags, 4, 1, U_LE},
{&HasMatrix, 4, 1, U_LE},
@@ -7469,7 +7467,6 @@ int U_PMR_DRAWCURVE_get(const char *contents, U_PMF_CMN_HDR *Header,
\param Header Common header
\param FontID U_PMF_FONT object in the EMF+ object table (0-63, inclusive)
\param btype Set: BrushID is an U_PFM_ARGB; Clear: index of U_PMF_BRUSH object in EMF+ object table.
- \param Tension Controls splines, 0 is straight line, >0 is curved
\param BrushID Color or index of U_PMF_BRUSH object in the EMF+ object table, depends on Flags bit0
\param DSOFlags DriverStringOptions flags
\param HasMatrix If 1 record contains a TransformMatrix field, if 0 it does not.
@@ -7482,9 +7479,9 @@ int U_PMR_DRAWCURVE_get(const char *contents, U_PMF_CMN_HDR *Header,
*/
int U_PMR_DRAWDRIVERSTRING_get(const char *contents, U_PMF_CMN_HDR *Header,
uint32_t *FontID, int *btype,
- U_FLOAT *Tension, uint32_t *BrushID, uint32_t *DSOFlags, uint32_t *HasMatrix, uint32_t *Elements,
+ uint32_t *BrushID, uint32_t *DSOFlags, uint32_t *HasMatrix, uint32_t *Elements,
uint16_t **Glyphs, U_PMF_POINTF **Points, U_PMF_TRANSFORMMATRIX **Matrix){
- if(!contents || !FontID || !btype || !Tension || !BrushID ||
+ if(!contents || !FontID || !btype || !BrushID ||
!DSOFlags || !HasMatrix || !Elements || !Glyphs || !Points || !Matrix){ return(0); }
const char *blimit = contents;
@@ -7496,7 +7493,6 @@ int U_PMR_DRAWDRIVERSTRING_get(const char *contents, U_PMF_CMN_HDR *Header,
*btype = (lclHeader.Flags & U_PPF_B ? 1 : 0 );
*FontID = (lclHeader.Flags >> U_FF_SHFT_OID8) & U_FF_MASK_OID8;
- U_PMF_SERIAL_get(&contents, Tension, 4, 1, U_LE);
U_PMF_SERIAL_get(&contents, BrushID, 4, 1, (*btype ? U_XE : U_LE)); /* color is not byte swapped, ID integer is */
U_PMF_SERIAL_get(&contents, DSOFlags, 4, 1, U_LE);
U_PMF_SERIAL_get(&contents, HasMatrix, 4, 1, U_LE);
diff --git a/src/libuemf/upmf.h b/src/libuemf/upmf.h
index dbda02ba7..4fb7ad492 100644
--- a/src/libuemf/upmf.h
+++ b/src/libuemf/upmf.h
@@ -27,11 +27,11 @@
/*
File: upmf.h
-Version: 0.0.4
-Date: 17-MAR-2015
+Version: 0.0.5
+Date: 26-JAN-2016
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
-Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
*/
#ifndef _UPMF_
@@ -2289,7 +2289,6 @@ typedef struct {
*/
typedef struct {
U_PMF_CMN_HDR Header; //!< Common header
- U_FLOAT Tension; //!< Controls splines, 0 is straight line, >0 is curved
uint32_t BrushID; //!< Color or index to Brush object, depends on Flags bit0
uint32_t DSOFlags; //!< DriverStringOptions flags
uint32_t HasMatrix; //!< If 1 record contains a TransformMatrix field, if 0 it does not.
@@ -2987,7 +2986,7 @@ U_PSEUDO_OBJ *U_PMR_DRAWARC_set(uint32_t PenID, U_FLOAT Start, U_FLOAT Sweep, co
U_PSEUDO_OBJ *U_PMR_DRAWBEZIERS_set(uint32_t PenID, const U_PSEUDO_OBJ *Points);
U_PSEUDO_OBJ *U_PMR_DRAWCLOSEDCURVE_set(uint32_t PenID, U_FLOAT Tension, const U_PSEUDO_OBJ *Points);
U_PSEUDO_OBJ *U_PMR_DRAWCURVE_set(uint32_t PenID, U_FLOAT Tension,uint32_t Offset, uint32_t NSegs, const U_PSEUDO_OBJ *Points);
-U_PSEUDO_OBJ *U_PMR_DRAWDRIVERSTRING_set(uint32_t FontID, U_FLOAT Tension, const U_PSEUDO_OBJ *BrushID,
+U_PSEUDO_OBJ *U_PMR_DRAWDRIVERSTRING_set(uint32_t FontID, const U_PSEUDO_OBJ *BrushID,
uint32_t DSOFlags, uint32_t HasMatrix, uint32_t GlyphCount,
const uint16_t *Glyphs, const U_PSEUDO_OBJ *Points, const U_PSEUDO_OBJ *Tm);
U_PSEUDO_OBJ *U_PMR_DRAWELLIPSE_set(uint32_t PenID, const U_PSEUDO_OBJ *Rect);
@@ -3125,7 +3124,7 @@ int U_PMR_DRAWARC_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *Pen
int U_PMR_DRAWBEZIERS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, int *RelAbs, uint32_t *Elements, U_PMF_POINTF **Points);
int U_PMR_DRAWCLOSEDCURVE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, int *RelAbs, U_FLOAT *Tension, uint32_t *Elements, U_PMF_POINTF **Points);
int U_PMR_DRAWCURVE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, U_FLOAT *Tension, uint32_t *Offset, uint32_t *NSegs, uint32_t *Elements, U_PMF_POINTF **Points);
-int U_PMR_DRAWDRIVERSTRING_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *FontID, int *btype, U_FLOAT *Tension, uint32_t *BrushID, uint32_t *DSOFlags, uint32_t *HasMatrix, uint32_t *Elements, uint16_t **Glyphs, U_PMF_POINTF **Points, U_PMF_TRANSFORMMATRIX **Matrix);
+int U_PMR_DRAWDRIVERSTRING_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *FontID, int *btype, uint32_t *BrushID, uint32_t *DSOFlags, uint32_t *HasMatrix, uint32_t *Elements, uint16_t **Glyphs, U_PMF_POINTF **Points, U_PMF_TRANSFORMMATRIX **Matrix);
int U_PMR_DRAWELLIPSE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *PenID, int *ctype, U_PMF_RECTF *Rect);
int U_PMR_DRAWIMAGE_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *ImgID, int *ctype, uint32_t *ImgAttrID, int32_t *SrcUnit, U_PMF_RECTF *SrcRect, U_PMF_RECTF *DstRect);
int U_PMR_DRAWIMAGEPOINTS_get(const char *contents, U_PMF_CMN_HDR *Header, uint32_t *ImgID, int *ctype, int *etype, int *RelAbs, uint32_t *ImgAttrID, int32_t *SrcUnit, U_PMF_RECTF *SrcRect, uint32_t *Elements, U_PMF_POINTF **Points);
diff --git a/src/libuemf/upmf_print.c b/src/libuemf/upmf_print.c
index 58ff4edd0..69fad3691 100644
--- a/src/libuemf/upmf_print.c
+++ b/src/libuemf/upmf_print.c
@@ -6,11 +6,11 @@
/*
File: upmf_print.c
-Version: 0.0.7
-Date: 21-MAY-2015
+Version: 0.0.8
+Date: 26-JAN-2016
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
-Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
*/
/* compiler options:
@@ -2379,19 +2379,19 @@ int U_PMR_DRAWDRIVERSTRING_print(const char *contents){
unsigned int i;
uint32_t FontID;
int btype;
- U_FLOAT Tension;
uint32_t BrushID, DSOFlags, HasMatrix, Elements;
uint16_t *Glyphs;
+ uint16_t *GlyphsIter;
U_PMF_POINTF *Points;
U_PMF_TRANSFORMMATRIX *Matrix;
int status = U_PMR_DRAWDRIVERSTRING_get(contents, NULL, &FontID, &btype,
- &Tension, &BrushID, &DSOFlags, &HasMatrix, &Elements,&Glyphs, &Points, &Matrix);
+ &BrushID, &DSOFlags, &HasMatrix, &Elements,&Glyphs, &Points, &Matrix);
if(status){
- printf(" + FontID:%u btype:%d Tension:%f BrushID:%u DSOFlags:%X Elements:%u\n", FontID,btype,Tension, BrushID, DSOFlags, Elements);
+ printf(" + FontID:%u btype:%d BrushID:%u DSOFlags:%X Elements:%u\n", FontID,btype, BrushID, DSOFlags, Elements);
printf(" + Glyphs:");
if(*Glyphs){
- for(i=0; i<Elements;i++, Glyphs++){ printf(" %u",*Glyphs); }
+ for(GlyphsIter=Glyphs, i=0; i<Elements;i++, GlyphsIter++){ printf(" %u",*GlyphsIter); }
free(Glyphs);
}
else {
diff --git a/src/libuemf/uwmf.h b/src/libuemf/uwmf.h
index 027de8e06..138ffab37 100644
--- a/src/libuemf/uwmf.h
+++ b/src/libuemf/uwmf.h
@@ -36,11 +36,11 @@
/*
File: uwmf.h
-Version: 0.0.12
-Date: 28-APR-2015
+Version: 0.0.13
+Date: 26-JAN-2016
Author: David Mathog, Biology Division, Caltech
email: mathog@caltech.edu
-Copyright: 2015 David Mathog and California Institute of Technology (Caltech)
+Copyright: 2016 David Mathog and California Institute of Technology (Caltech)
*/
#ifndef _UWMF_
@@ -643,7 +643,8 @@ enum U_WMR_TYPES{
#define U_SIZE_REGION 20 /**< X 22 20 is minums the variable part */
#define U_SIZE_BITMAP16 10 /**< + 10 */
#define U_SIZE_BITMAPCOREHEADER 12 /**< + 12 */
-#define U_SIZE_BITMAPINFOHEADER 40 /**< + 40 */
+// also defined in uemf.h, avoid redefining. Same value in both places, of course.
+// # define U_SIZE_BITMAPINFOHEADER 40 /**< + 40 */
#define U_SIZE_BITMAPV4HEADER 108 /**< ? 108 not tested */
#define U_SIZE_BITMAPV5HEADER 124 /**< ? 124 not tested */
#define U_SIZE_WLOGBRUSH 8 /**< + 8 */
diff --git a/src/live_effects/CMakeLists.txt b/src/live_effects/CMakeLists.txt
index 8a097590a..9a2f06a76 100644
--- a/src/live_effects/CMakeLists.txt
+++ b/src/live_effects/CMakeLists.txt
@@ -6,6 +6,7 @@ set(live_effects_SRC
lpe-bounding-box.cpp
lpe-bspline.cpp
lpe-circle_3pts.cpp
+ lpe-transform_2pts.cpp
lpe-circle_with_radius.cpp
lpe-clone-original.cpp
lpe-constructgrid.cpp
@@ -83,6 +84,7 @@ set(live_effects_SRC
lpe-bounding-box.h
lpe-bspline.h
lpe-circle_3pts.h
+ lpe-transform_2pts.h
lpe-circle_with_radius.h
lpe-clone-original.h
lpe-constructgrid.h
diff --git a/src/live_effects/Makefile_insert b/src/live_effects/Makefile_insert
index c2c2ce93c..b5bee55c8 100644
--- a/src/live_effects/Makefile_insert
+++ b/src/live_effects/Makefile_insert
@@ -74,6 +74,8 @@ ink_common_sources += \
live_effects/lpe-mirror_symmetry.h \
live_effects/lpe-circle_3pts.cpp \
live_effects/lpe-circle_3pts.h \
+ live_effects/lpe-transform_2pts.cpp \
+ live_effects/lpe-transform_2pts.h \
live_effects/lpe-angle_bisector.cpp \
live_effects/lpe-angle_bisector.h \
live_effects/lpe-parallel.cpp \
diff --git a/src/live_effects/effect-enum.h b/src/live_effects/effect-enum.h
index 383eec19e..eea26184c 100644
--- a/src/live_effects/effect-enum.h
+++ b/src/live_effects/effect-enum.h
@@ -38,6 +38,7 @@ enum EffectType {
TANGENT_TO_CURVE,
MIRROR_SYMMETRY,
CIRCLE_3PTS,
+ TRANSFORM_2PTS,
ANGLE_BISECTOR,
PARALLEL,
COPY_ROTATE,
diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp
index b65678f0a..2a6edaafb 100644
--- a/src/live_effects/effect.cpp
+++ b/src/live_effects/effect.cpp
@@ -57,6 +57,7 @@
#include "live_effects/lpe-sketch.h"
#include "live_effects/lpe-spiro.h"
#include "live_effects/lpe-tangent_to_curve.h"
+#include "live_effects/lpe-transform_2pts.h"
#include "live_effects/lpe-taperstroke.h"
#include "live_effects/lpe-test-doEffect-stack.h"
#include "live_effects/lpe-text_label.h"
@@ -144,13 +145,14 @@ const Util::EnumData<EffectType> LPETypeData[] = {
{ELLIPSE_5PTS, N_("Ellipse by 5 points"), "ellipse_5pts"},
{BOUNDING_BOX, N_("Bounding Box"), "bounding_box"},
/* 0.91 */
- {SIMPLIFY, N_("Simplify"), "simplify"},
- {LATTICE2, N_("Lattice Deformation 2"), "lattice2"},
- {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"},
+ {SIMPLIFY, N_("Simplify"), "simplify"},
+ {LATTICE2, N_("Lattice Deformation 2"), "lattice2"},
+ {PERSPECTIVE_ENVELOPE, N_("Perspective/Envelope"), "perspective-envelope"},
{FILLET_CHAMFER, N_("Fillet/Chamfer"), "fillet-chamfer"},
{INTERPOLATE_POINTS, N_("Interpolate points"), "interpolate_points"},
/* 0.92 */
{COPY_ROTATE, N_("Rotate copies"), "copy_rotate"},
+ {TRANSFORM_2PTS, N_("Transform by 2 points"), "transform_2pts"},
};
const Util::EnumDataConverter<EffectType> LPETypeConverter(LPETypeData, sizeof(LPETypeData)/sizeof(*LPETypeData));
@@ -316,6 +318,9 @@ Effect::New(EffectType lpenr, LivePathEffectObject *lpeobj)
case SHOW_HANDLES:
neweffect = static_cast<Effect*> ( new LPEShowHandles(lpeobj) );
break;
+ case TRANSFORM_2PTS:
+ neweffect = static_cast<Effect*> ( new LPETransform2Pts(lpeobj) );
+ break;
default:
g_warning("LivePathEffect::Effect::New called with invalid patheffect type (%d)", lpenr);
neweffect = NULL;
@@ -352,7 +357,8 @@ Effect::createAndApply(EffectType type, SPDocument *doc, SPItem *item)
}
Effect::Effect(LivePathEffectObject *lpeobject)
- : _provides_knotholder_entities(false),
+ : apply_to_clippath_and_mask(false),
+ _provides_knotholder_entities(false),
oncanvasedit_it(0),
is_visible(_("Is visible?"), _("If unchecked, the effect remains applied to the object but is temporarily disabled on canvas"), "is_visible", &wr, this, true),
show_orig_path(false),
diff --git a/src/live_effects/effect.h b/src/live_effects/effect.h
index ea57ff243..898e089b7 100644
--- a/src/live_effects/effect.h
+++ b/src/live_effects/effect.h
@@ -121,6 +121,7 @@ public:
inline bool isVisible() const { return is_visible; }
void editNextParamOncanvas(SPItem * item, SPDesktop * desktop);
+ bool apply_to_clippath_and_mask;
protected:
Effect(LivePathEffectObject *lpeobject);
@@ -144,6 +145,7 @@ protected:
std::vector<Parameter *> param_vector;
bool _provides_knotholder_entities;
+
int oncanvasedit_it;
BoolParam is_visible;
diff --git a/src/live_effects/lpe-angle_bisector.cpp b/src/live_effects/lpe-angle_bisector.cpp
index 95a81c763..900d29e3a 100644
--- a/src/live_effects/lpe-angle_bisector.cpp
+++ b/src/live_effects/lpe-angle_bisector.cpp
@@ -38,7 +38,7 @@ public:
virtual Geom::Point knot_get() const;
};
-} // namespace TtC
+} // namespace AB
LPEAngleBisector::LPEAngleBisector(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
diff --git a/src/live_effects/lpe-bendpath.cpp b/src/live_effects/lpe-bendpath.cpp
index 33171b184..bc112285f 100644
--- a/src/live_effects/lpe-bendpath.cpp
+++ b/src/live_effects/lpe-bendpath.cpp
@@ -20,7 +20,13 @@
#include <2geom/d2.h>
#include <2geom/piecewise.h>
+#include "knot-holder-entity.h"
+#include "knotholder.h"
+
+#include <glibmm/i18n.h>
+
#include <algorithm>
+
using std::vector;
@@ -48,10 +54,21 @@ first) but I think we can first forget about them.
namespace Inkscape {
namespace LivePathEffect {
+Geom::PathVector bp_helper_path;
+namespace BeP {
+class KnotHolderEntityWidthBendPath : public LPEKnotHolderEntity {
+ public:
+ KnotHolderEntityWidthBendPath(LPEBendPath * effect) : LPEKnotHolderEntity(effect) {}
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
+ virtual Geom::Point knot_get() const;
+ };
+} // BeP
+
LPEBendPath::LPEBendPath(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
bend_path(_("Bend path:"), _("Path along which to bend the original path"), "bendpath", &wr, this, "M0,0 L1,0"),
- prop_scale(_("_Width:"), _("Width of the path"), "prop_scale", &wr, this, 1),
+ original_height(0.0),
+ prop_scale(_("_Width:"), _("Width of the path"), "prop_scale", &wr, this, 1.0),
scale_y_rel(_("W_idth in units of length"), _("Scale the width of the path in units of its length"), "scale_y_rel", &wr, this, false),
vertical_pattern(_("_Original path is vertical"), _("Rotates the original 90 degrees, before bending it along the bend path"), "vertical", &wr, this, false)
{
@@ -63,6 +80,8 @@ LPEBendPath::LPEBendPath(LivePathEffectObject *lpeobject) :
prop_scale.param_set_digits(3);
prop_scale.param_set_increments(0.01, 0.10);
+ _provides_knotholder_entities = true;
+ apply_to_clippath_and_mask = true;
concatenate_before_pwd2 = true;
}
@@ -76,9 +95,7 @@ LPEBendPath::doBeforeEffect (SPLPEItem const* lpeitem)
{
// get the item bounding box
original_bbox(lpeitem);
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
+ original_height = boundingbox_Y.max() - boundingbox_Y.min();
}
Geom::Piecewise<Geom::D2<Geom::SBasis> >
@@ -148,7 +165,75 @@ LPEBendPath::resetDefaults(SPItem const* item)
bend_path.set_new_value( path.toPwSb(), true );
}
+void
+LPEBendPath::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+ hp_vec.push_back(bp_helper_path);
+}
+
+void
+LPEBendPath::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+{
+ KnotHolderEntity *e = new BeP::KnotHolderEntityWidthBendPath(this);
+ e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Change the width"), SP_KNOT_SHAPE_CIRCLE);
+ knotholder->add(e);
+}
+
+namespace BeP {
+void
+KnotHolderEntityWidthBendPath::knot_set(Geom::Point const &p, Geom::Point const& /*origin*/, guint state)
+{
+ LPEBendPath *lpe = dynamic_cast<LPEBendPath *> (_effect);
+
+ Geom::Point const s = snap_knot_position(p, state);
+ Geom::Path path_in = lpe->bend_path.get_pathvector().pathAt(Geom::PathVectorTime(0, 0, 0.0));
+ Geom::Point ptA = path_in.pointAt(Geom::PathTime(0, 0.0));
+ Geom::Point B = path_in.pointAt(Geom::PathTime(1, 0.0));
+ Geom::Curve const *first_curve = &path_in.curveAt(Geom::PathTime(0, 0.0));
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*first_curve);
+ Geom::Ray ray(ptA, B);
+ if (cubic) {
+ ray.setPoints(ptA, (*cubic)[1]);
+ }
+ ray.setAngle(ray.angle() + Geom::rad_from_deg(90));
+ Geom::Point knot_pos = this->knot->pos * item->i2dt_affine().inverse();
+ Geom::Coord nearest_to_ray = ray.nearestTime(knot_pos);
+ if(nearest_to_ray == 0){
+ lpe->prop_scale.param_set_value(-Geom::distance(s , ptA)/(lpe->original_height/2.0));
+ } else {
+ lpe->prop_scale.param_set_value(Geom::distance(s , ptA)/(lpe->original_height/2.0));
+ }
+
+ sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
+}
+
+Geom::Point
+KnotHolderEntityWidthBendPath::knot_get() const
+{
+ LPEBendPath *lpe = dynamic_cast<LPEBendPath *> (_effect);
+
+ Geom::Path path_in = lpe->bend_path.get_pathvector().pathAt(Geom::PathVectorTime(0, 0, 0.0));
+ Geom::Point ptA = path_in.pointAt(Geom::PathTime(0, 0.0));
+ Geom::Point B = path_in.pointAt(Geom::PathTime(1, 0.0));
+ Geom::Curve const *first_curve = &path_in.curveAt(Geom::PathTime(0, 0.0));
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*first_curve);
+ Geom::Ray ray(ptA, B);
+ if (cubic) {
+ ray.setPoints(ptA,(*cubic)[1]);
+ }
+ ray.setAngle(ray.angle() + Geom::rad_from_deg(90));
+ Geom::Point result_point = Geom::Point::polar(ray.angle(), (lpe->original_height/2.0) * lpe->prop_scale) + ptA;
+
+ bp_helper_path.clear();
+ Geom::Path hp(result_point);
+ hp.appendNew<Geom::LineSegment>(ptA);
+ bp_helper_path.push_back(hp);
+ hp.clear();
+
+ return result_point;
+}
+} // namespace BeP
} // namespace LivePathEffect
} /* namespace Inkscape */
diff --git a/src/live_effects/lpe-bendpath.h b/src/live_effects/lpe-bendpath.h
index 16b8c6137..eeda86a5e 100644
--- a/src/live_effects/lpe-bendpath.h
+++ b/src/live_effects/lpe-bendpath.h
@@ -27,6 +27,10 @@
namespace Inkscape {
namespace LivePathEffect {
+namespace BeP {
+class KnotHolderEntityWidthBendPath;
+}
+
//for Bend path on group : we need information concerning the group Bounding box
class LPEBendPath : public Effect, GroupBBoxEffect {
public:
@@ -39,13 +43,19 @@ public:
virtual void resetDefaults(SPItem const* item);
+ void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec);
+
+ virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item);
+ PathParam bend_path;
+
+ friend class BeP::KnotHolderEntityWidthBendPath;
+protected:
+ double original_height;
+ ScalarParam prop_scale;
private:
- PathParam bend_path;
- ScalarParam prop_scale;
BoolParam scale_y_rel;
- BoolParam vertical_pattern;
-
+ BoolParam vertical_pattern;
Geom::Piecewise<Geom::D2<Geom::SBasis> > uskeleton;
Geom::Piecewise<Geom::D2<Geom::SBasis> > n;
diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp
index c2a2d080e..1423e670a 100644
--- a/src/live_effects/lpe-bspline.cpp
+++ b/src/live_effects/lpe-bspline.cpp
@@ -10,38 +10,46 @@
#include "svg/svg.h"
#include "xml/repr.h"
#include "preferences.h"
+#include "document-undo.h"
+#include "verbs.h"
// TODO due to internal breakage in glibmm headers, this must be last:
#include <glibmm/i18n.h>
namespace Inkscape {
namespace LivePathEffect {
-const double HANDLE_CUBIC_GAP = 0.01;
+const double HANDLE_CUBIC_GAP = 0.001;
const double NO_POWER = 0.0;
-const double DEFAULT_START_POWER = 0.3334;
-const double DEFAULT_END_POWER = 0.6667;
+const double DEFAULT_START_POWER = 1.0/3.0;
+const double DEFAULT_END_POWER = 2.0/3.0;
+Geom::PathVector hp;
+void sp_bspline_drawHandle(Geom::Point p, double helper_size);
LPEBSpline::LPEBSpline(LivePathEffectObject *lpeobject)
: Effect(lpeobject),
steps(_("Steps with CTRL:"), _("Change number of steps with CTRL pressed"), "steps", &wr, this, 2),
helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 0),
- ignore_cusp(_("Ignore cusp nodes"), _("Change ignoring cusp nodes"), "ignore_cusp", &wr, this, true),
+ apply_no_weight(_("Apply changes if weight = 0%"), _("Apply changes if weight = 0%"), "apply_no_weight", &wr, this, true),
+ apply_with_weight(_("Apply changes if weight > 0%"), _("Apply changes if weight > 0%"), "apply_with_weight", &wr, this, true),
only_selected(_("Change only selected nodes"), _("Change only selected nodes"), "only_selected", &wr, this, false),
- weight(_("Change weight:"), _("Change weight of the effect"), "weight", &wr, this, DEFAULT_START_POWER)
+ weight(_("Change weight %:"), _("Change weight percent of the effect"), "weight", &wr, this, DEFAULT_START_POWER * 100)
{
registerParameter(&weight);
registerParameter(&steps);
registerParameter(&helper_size);
- registerParameter(&ignore_cusp);
+ registerParameter(&apply_no_weight);
+ registerParameter(&apply_with_weight);
registerParameter(&only_selected);
- weight.param_set_range(NO_POWER, 1);
+ weight.param_set_range(NO_POWER, 100.0);
weight.param_set_increments(0.1, 0.1);
weight.param_set_digits(4);
+ weight.param_overwrite_widget(true);
steps.param_set_range(1, 10);
steps.param_set_increments(1, 1);
steps.param_set_digits(0);
+ steps.param_overwrite_widget(true);
helper_size.param_set_range(0.0, 999.0);
helper_size.param_set_increments(1, 1);
@@ -67,15 +75,113 @@ void LPEBSpline::doOnApply(SPLPEItem const* lpeitem)
}
}
+void
+LPEBSpline::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+ hp_vec.push_back(hp);
+}
+
+Gtk::Widget *LPEBSpline::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);
+ std::vector<Parameter *>::iterator it = param_vector.begin();
+ while (it != param_vector.end()) {
+ if ((*it)->widget_is_visible) {
+ Parameter *param = *it;
+ Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
+ if (param->param_key == "weight") {
+ Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0));
+ Gtk::Button *default_weight =
+ Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight"))));
+ default_weight->signal_clicked()
+ .connect(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight));
+ buttons->pack_start(*default_weight, true, true, 2);
+ Gtk::Button *make_cusp =
+ Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp"))));
+ make_cusp->signal_clicked()
+ .connect(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp));
+ buttons->pack_start(*make_cusp, true, true, 2);
+ vbox->pack_start(*buttons, true, true, 2);
+ }
+ if (param->param_key == "weight" || param->param_key == "steps") {
+ Inkscape::UI::Widget::Scalar *widg_registered =
+ Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
+ widg_registered->signal_value_changed()
+ .connect(sigc::mem_fun(*this, &LPEBSpline::toWeight));
+ widg = dynamic_cast<Gtk::Widget *>(widg_registered);
+ if (widg) {
+ Gtk::HBox * hbox_weight_steps = dynamic_cast<Gtk::HBox *>(widg);
+ std::vector< Gtk::Widget* > childList = hbox_weight_steps->get_children();
+ Gtk::Entry* entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]);
+ entry_widget->set_width_chars(9);
+ }
+ }
+ if (param->param_key == "only_selected" || param->param_key == "apply_no_weight" || param->param_key == "apply_with_weight") {
+ Gtk::CheckButton *widg_registered =
+ Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
+ widg = dynamic_cast<Gtk::Widget *>(widg_registered);
+ }
+ Glib::ustring *tip = param->param_getTooltip();
+ if (widg) {
+ vbox->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+
+ ++it;
+ }
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+void LPEBSpline::toDefaultWeight()
+{
+ changeWeight(DEFAULT_START_POWER * 100);
+ DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change to default weight"));
+}
+
+void LPEBSpline::toMakeCusp()
+{
+ changeWeight(NO_POWER);
+ DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change to 0 weight"));
+}
+
+void LPEBSpline::toWeight()
+{
+ changeWeight(weight);
+ DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));
+}
+
+void LPEBSpline::changeWeight(double weight_ammount)
+{
+ SPPath *path = dynamic_cast<SPPath *>(sp_lpe_item);
+ if(path) {
+ SPCurve *curve = path->get_curve_for_edit();
+ doBSplineFromWidget(curve, weight_ammount/100.0);
+ gchar *str = sp_svg_write_path(curve->get_pathvector());
+ path->getRepr()->setAttribute("inkscape:original-d", str);
+ }
+}
+
void LPEBSpline::doEffect(SPCurve *curve)
{
+ sp_bspline_do_effect(curve, helper_size);
+}
+void sp_bspline_do_effect(SPCurve *curve, double helper_size)
+{
if (curve->get_segment_count() < 1) {
return;
}
- // Make copy of old path as it is changed during processing
Geom::PathVector const original_pathv = curve->get_pathvector();
-
curve->reset();
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
for (Geom::PathVector::const_iterator path_it = original_pathv.begin();
@@ -99,21 +205,19 @@ void LPEBSpline::doEffect(SPCurve *curve)
Geom::D2<Geom::SBasis> sbasis_out;
Geom::D2<Geom::SBasis> sbasis_helper;
Geom::CubicBezier const *cubic = NULL;
+ curve_n->moveto(curve_it1->initialPoint());
if (path_it->closed()) {
- // if the path is closed, maybe we have to stop a bit earlier because the
- // closing line segment has zerolength.
- const Geom::Curve &closingline =
- path_it->back_closed(); // the closing line segment is always of type
- // Geom::LineSegment.
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- // closingline.isDegenerate() did not work, because it only checks for
- // *exact* zero length, which goes wrong for relative coordinates and
- // rounding errors...
- // the closing line segment has zero-length. So stop before that one!
- curve_endit = path_it->end_open();
- }
+ const Geom::Curve &closingline = path_it->back_closed();
+ // the closing line segment is always of type
+ // Geom::LineSegment.
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ // closingline.isDegenerate() did not work, because it only checks for
+ // *exact* zero length, which goes wrong for relative coordinates and
+ // rounding errors...
+ // the closing line segment has zero-length. So stop before that one!
+ curve_endit = path_it->end_open();
+ }
}
- curve_n->moveto(curve_it1->initialPoint());
while (curve_it1 != curve_endit) {
SPCurve *in = new SPCurve();
in->moveto(curve_it1->initialPoint());
@@ -209,12 +313,11 @@ void LPEBSpline::doEffect(SPCurve *curve)
curve_n->curveto(point_at1, point_at2, node);
}
if(!are_near(node,curve_it1->finalPoint()) && helper_size > 0.0) {
- drawHandle(node, helper_size);
+ sp_bspline_drawHandle(node, helper_size);
}
++curve_it1;
++curve_it2;
}
- //y cerramos la curva
if (path_it->closed()) {
curve_n->closepath_current();
}
@@ -228,8 +331,8 @@ void LPEBSpline::doEffect(SPCurve *curve)
}
}
-void
-LPEBSpline::drawHandle(Geom::Point p, double helper_size)
+
+void sp_bspline_drawHandle(Geom::Point p, double helper_size)
{
char const * svgd = "M 1,0.5 A 0.5,0.5 0 0 1 0.5,1 0.5,0.5 0 0 1 0,0.5 0.5,0.5 0 0 1 0.5,0 0.5,0.5 0 0 1 1,0.5 Z";
Geom::PathVector pathv = sp_svg_read_pathv(svgd);
@@ -240,103 +343,6 @@ LPEBSpline::drawHandle(Geom::Point p, double helper_size)
hp.push_back(pathv[0]);
}
-void
-LPEBSpline::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
-{
- hp_vec.push_back(hp);
-}
-Gtk::Widget *LPEBSpline::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);
- std::vector<Parameter *>::iterator it = param_vector.begin();
- while (it != param_vector.end()) {
- if ((*it)->widget_is_visible) {
- Parameter *param = *it;
- Gtk::Widget *widg = dynamic_cast<Gtk::Widget *>(param->param_newWidget());
- if (param->param_key == "weight") {
- Gtk::HBox * buttons = Gtk::manage(new Gtk::HBox(true,0));
- Gtk::Button *default_weight =
- Gtk::manage(new Gtk::Button(Glib::ustring(_("Default weight"))));
- default_weight->signal_clicked()
- .connect(sigc::mem_fun(*this, &LPEBSpline::toDefaultWeight));
- buttons->pack_start(*default_weight, true, true, 2);
- Gtk::Button *make_cusp =
- Gtk::manage(new Gtk::Button(Glib::ustring(_("Make cusp"))));
- make_cusp->signal_clicked()
- .connect(sigc::mem_fun(*this, &LPEBSpline::toMakeCusp));
- buttons->pack_start(*make_cusp, true, true, 2);
- vbox->pack_start(*buttons, true, true, 2);
- }
- if (param->param_key == "weight" || param->param_key == "steps") {
- Inkscape::UI::Widget::Scalar *widg_registered =
- Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
- widg_registered->signal_value_changed()
- .connect(sigc::mem_fun(*this, &LPEBSpline::toWeight));
- widg = dynamic_cast<Gtk::Widget *>(widg_registered);
- if (widg) {
- Gtk::HBox * hbox_weight_steps = dynamic_cast<Gtk::HBox *>(widg);
- std::vector< Gtk::Widget* > childList = hbox_weight_steps->get_children();
- Gtk::Entry* entry_widget = dynamic_cast<Gtk::Entry *>(childList[1]);
- entry_widget->set_width_chars(6);
- }
- }
- if (param->param_key == "only_selected") {
- Gtk::CheckButton *widg_registered =
- Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
- widg = dynamic_cast<Gtk::Widget *>(widg_registered);
- }
- if (param->param_key == "ignore_cusp") {
- Gtk::CheckButton *widg_registered =
- Gtk::manage(dynamic_cast<Gtk::CheckButton *>(widg));
- widg = dynamic_cast<Gtk::Widget *>(widg_registered);
- }
- Glib::ustring *tip = param->param_getTooltip();
- if (widg) {
- vbox->pack_start(*widg, true, true, 2);
- if (tip) {
- widg->set_tooltip_text(*tip);
- } else {
- widg->set_tooltip_text("");
- widg->set_has_tooltip(false);
- }
- }
- }
-
- ++it;
- }
- return dynamic_cast<Gtk::Widget *>(vbox);
-}
-
-void LPEBSpline::toDefaultWeight()
-{
- changeWeight(DEFAULT_START_POWER);
-}
-
-void LPEBSpline::toMakeCusp()
-{
- changeWeight(NO_POWER);
-}
-
-void LPEBSpline::toWeight()
-{
- changeWeight(weight);
-}
-
-void LPEBSpline::changeWeight(double weight_ammount)
-{
- SPPath *path = dynamic_cast<SPPath *>(sp_lpe_item);
- if(path) {
- SPCurve *curve = path->get_curve_for_edit();
- doBSplineFromWidget(curve, weight_ammount);
- gchar *str = sp_svg_write_path(curve->get_pathvector());
- path->getRepr()->setAttribute("inkscape:original-d", str);
- }
-}
-
void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weight_ammount)
{
using Geom::X;
@@ -366,21 +372,19 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weight_ammount)
Geom::D2<Geom::SBasis> sbasis_in;
Geom::D2<Geom::SBasis> sbasis_out;
Geom::CubicBezier const *cubic = NULL;
+ curve_n->moveto(curve_it1->initialPoint());
if (path_it->closed()) {
- // if the path is closed, maybe we have to stop a bit earlier because the
- // closing line segment has zerolength.
- const Geom::Curve &closingline =
- path_it->back_closed(); // the closing line segment is always of type
- // Geom::LineSegment.
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- // closingline.isDegenerate() did not work, because it only checks for
- // *exact* zero length, which goes wrong for relative coordinates and
- // rounding errors...
- // the closing line segment has zero-length. So stop before that one!
- curve_endit = path_it->end_open();
- }
+ const Geom::Curve &closingline = path_it->back_closed();
+ // the closing line segment is always of type
+ // Geom::LineSegment.
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ // closingline.isDegenerate() did not work, because it only checks for
+ // *exact* zero length, which goes wrong for relative coordinates and
+ // rounding errors...
+ // the closing line segment has zero-length. So stop before that one!
+ curve_endit = path_it->end_open();
+ }
}
- curve_n->moveto(curve_it1->initialPoint());
while (curve_it1 != curve_endit) {
SPCurve *in = new SPCurve();
in->moveto(curve_it1->initialPoint());
@@ -389,91 +393,61 @@ void LPEBSpline::doBSplineFromWidget(SPCurve *curve, double weight_ammount)
point_at0 = in->first_segment()->initialPoint();
point_at3 = in->first_segment()->finalPoint();
sbasis_in = in->first_segment()->toSBasis();
- if (!only_selected) {
- if (cubic) {
- if (!ignore_cusp || !Geom::are_near((*cubic)[1], point_at0)) {
+ if (cubic) {
+ if ((apply_no_weight && apply_with_weight) ||
+ (apply_no_weight && Geom::are_near((*cubic)[1], point_at0)) ||
+ (apply_with_weight && !Geom::are_near((*cubic)[1], point_at0)))
+ {
+ if (isNodePointSelected(point_at0) || !only_selected) {
point_at1 = sbasis_in.valueAt(weight_ammount);
if (weight_ammount != NO_POWER) {
point_at1 =
Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP);
}
} else {
- point_at1 = in->first_segment()->initialPoint();
- }
- if (!ignore_cusp || !Geom::are_near((*cubic)[2], point_at3)) {
- point_at2 = sbasis_in.valueAt(1 - weight_ammount);
- if (weight_ammount != NO_POWER) {
- point_at2 =
- Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP);
- }
- } else {
- point_at2 = in->first_segment()->finalPoint();
+ point_at1 = (*cubic)[1];
}
} else {
- if (!ignore_cusp && weight_ammount != NO_POWER) {
- point_at1 = sbasis_in.valueAt(weight_ammount);
- if (weight_ammount != NO_POWER) {
- point_at1 =
- Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP);
- }
+ point_at1 = (*cubic)[1];
+ }
+ if ((apply_no_weight && apply_with_weight) ||
+ (apply_no_weight && Geom::are_near((*cubic)[2], point_at3)) ||
+ (apply_with_weight && !Geom::are_near((*cubic)[2], point_at3)))
+ {
+ if (isNodePointSelected(point_at3) || !only_selected) {
point_at2 = sbasis_in.valueAt(1 - weight_ammount);
if (weight_ammount != NO_POWER) {
point_at2 =
Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP);
}
} else {
- point_at1 = in->first_segment()->initialPoint();
- point_at2 = in->first_segment()->finalPoint();
+ point_at2 = (*cubic)[2];
}
+ } else {
+ point_at2 = (*cubic)[2];
}
} else {
- if (cubic) {
- if (!ignore_cusp || !Geom::are_near((*cubic)[1], point_at0)) {
- if (isNodePointSelected(point_at0)) {
- point_at1 = sbasis_in.valueAt(weight_ammount);
- if (weight_ammount != NO_POWER) {
- point_at1 =
- Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP);
- }
- } else {
- point_at1 = (*cubic)[1];
- }
+ if ((apply_no_weight && apply_with_weight) ||
+ (apply_no_weight && weight_ammount == NO_POWER) ||
+ (apply_with_weight && weight_ammount != NO_POWER))
+ {
+ if (isNodePointSelected(point_at0) || !only_selected) {
+ point_at1 = sbasis_in.valueAt(weight_ammount);
+ point_at1 =
+ Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP);
} else {
point_at1 = in->first_segment()->initialPoint();
}
- if (!ignore_cusp || !Geom::are_near((*cubic)[2], point_at3)) {
- if (isNodePointSelected(point_at3)) {
- point_at2 = sbasis_in.valueAt(1 - weight_ammount);
- if (weight_ammount != NO_POWER) {
- point_at2 =
- Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP);
- }
- } else {
- point_at2 = (*cubic)[2];
- }
+ if (isNodePointSelected(point_at3) || !only_selected) {
+ point_at2 = sbasis_in.valueAt(1 - weight_ammount);
+ point_at2 =
+ Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP);
} else {
point_at2 = in->first_segment()->finalPoint();
}
} else {
- if (!ignore_cusp && weight_ammount != NO_POWER) {
- if (isNodePointSelected(point_at0)) {
- point_at1 = sbasis_in.valueAt(weight_ammount);
- point_at1 =
- Geom::Point(point_at1[X] + HANDLE_CUBIC_GAP, point_at1[Y] + HANDLE_CUBIC_GAP);
- } else {
- point_at1 = in->first_segment()->initialPoint();
- }
- if (isNodePointSelected(point_at3)) {
- point_at2 = sbasis_in.valueAt(weight_ammount);
- point_at2 =
- Geom::Point(point_at2[X] + HANDLE_CUBIC_GAP, point_at2[Y] + HANDLE_CUBIC_GAP);
- } else {
- point_at2 = in->first_segment()->finalPoint();
- }
- } else {
- point_at1 = in->first_segment()->initialPoint();
- point_at2 = in->first_segment()->finalPoint();
- }
+ point_at1 = in->first_segment()->initialPoint();
+ point_at2 = in->first_segment()->finalPoint();
}
}
in->reset();
diff --git a/src/live_effects/lpe-bspline.h b/src/live_effects/lpe-bspline.h
index fc0f66353..7823f00f0 100644
--- a/src/live_effects/lpe-bspline.h
+++ b/src/live_effects/lpe-bspline.h
@@ -25,29 +25,29 @@ public:
virtual void doOnApply(SPLPEItem const* lpeitem);
virtual void doEffect(SPCurve *curve);
virtual void doBeforeEffect (SPLPEItem const* lpeitem);
- void drawHandle(Geom::Point p, double radiusHelperNodes);
- virtual void doBSplineFromWidget(SPCurve *curve, double value);
+ void doBSplineFromWidget(SPCurve *curve, double value);
void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec);
virtual Gtk::Widget *newWidget();
- virtual void changeWeight(double weightValue);
- virtual void toDefaultWeight();
- virtual void toMakeCusp();
- virtual void toWeight();
+ void changeWeight(double weightValue);
+ void toDefaultWeight();
+ void toMakeCusp();
+ void toWeight();
// TODO make this private
ScalarParam steps;
private:
ScalarParam helper_size;
- BoolParam ignore_cusp;
+ BoolParam apply_no_weight;
+ BoolParam apply_with_weight;
BoolParam only_selected;
ScalarParam weight;
- Geom::PathVector hp;
LPEBSpline(const LPEBSpline &);
LPEBSpline &operator=(const LPEBSpline &);
};
+void sp_bspline_do_effect(SPCurve *curve, double helper_size);
} //namespace LivePathEffect
} //namespace Inkscape
diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp
index 083f56be8..c60de961d 100644
--- a/src/live_effects/lpe-copy_rotate.cpp
+++ b/src/live_effects/lpe-copy_rotate.cpp
@@ -18,7 +18,6 @@
#include "live_effects/lpe-copy_rotate.h"
#include <2geom/path.h>
#include <2geom/transforms.h>
-#include <2geom/d2-sbasis.h>
#include <2geom/angle.h>
#include "knot-holder-entity.h"
@@ -57,6 +56,7 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) :
{
show_orig_path = true;
_provides_knotholder_entities = true;
+ apply_to_clippath_and_mask = true;
// register all your parameters here, so Inkscape knows which parameters this effect has:
registerParameter(&copies_to_360);
@@ -133,8 +133,8 @@ LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem)
dir = unit_vector(B - A);
// I first suspected the minus sign to be a bug in 2geom but it is
// likely due to SVG's choice of coordinate system orientation (max)
- start_pos = origin + dir * Rotate(-deg_to_rad(starting_angle)) * dist_angle_handle;
- rot_pos = origin + dir * Rotate(-deg_to_rad(rotation_angle+starting_angle)) * dist_angle_handle;
+ start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * dist_angle_handle;
+ rot_pos = origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle;
if( fusion_paths || copies_to_360 ) {
rot_pos = origin;
}
@@ -351,7 +351,7 @@ LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & p
divider.appendNew<Geom::LineSegment>((Geom::Point)origin);
divider.appendNew<Geom::LineSegment>(line_end);
Piecewise<D2<SBasis> > output;
- Affine pre = Translate(-origin) * Rotate(-deg_to_rad(starting_angle));
+ Affine pre = Translate(-origin) * Rotate(-rad_from_deg(starting_angle));
if(fusion_paths) {
Geom::PathVector path_out;
Geom::PathVector tmp_path;
@@ -399,7 +399,7 @@ LPECopyRotate::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geo
Geom::Path hp;
hp.start(start_pos);
hp.appendNew<Geom::LineSegment>((Geom::Point)origin);
- hp.appendNew<Geom::LineSegment>(origin + dir * Rotate(-deg_to_rad(rotation_angle+starting_angle)) * dist_angle_handle);
+ hp.appendNew<Geom::LineSegment>(origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle);
Geom::PathVector pathv;
pathv.push_back(hp);
hp_vec.push_back(pathv);
@@ -442,7 +442,7 @@ KnotHolderEntityStartingAngle::knot_set(Geom::Point const &p, Geom::Point const
// I first suspected the minus sign to be a bug in 2geom but it is
// likely due to SVG's choice of coordinate system orientation (max)
- lpe->starting_angle.param_set_value(rad_to_deg(-angle_between(lpe->dir, s - lpe->origin)));
+ lpe->starting_angle.param_set_value(deg_from_rad(-angle_between(lpe->dir, s - lpe->origin)));
if (state & GDK_SHIFT_MASK) {
lpe->dist_angle_handle = L2(lpe->B - lpe->A);
} else {
@@ -462,7 +462,7 @@ KnotHolderEntityRotationAngle::knot_set(Geom::Point const &p, Geom::Point const
// I first suspected the minus sign to be a bug in 2geom but it is
// likely due to SVG's choice of coordinate system orientation (max)
- lpe->rotation_angle.param_set_value(rad_to_deg(-angle_between(lpe->dir, s - lpe->origin)) - lpe->starting_angle);
+ lpe->rotation_angle.param_set_value(deg_from_rad(-angle_between(lpe->dir, s - lpe->origin)) - lpe->starting_angle);
if (state & GDK_SHIFT_MASK) {
lpe->dist_angle_handle = L2(lpe->B - lpe->A);
} else {
diff --git a/src/live_effects/lpe-dynastroke.cpp b/src/live_effects/lpe-dynastroke.cpp
index c60db4fc4..aeecd5d5c 100644
--- a/src/live_effects/lpe-dynastroke.cpp
+++ b/src/live_effects/lpe-dynastroke.cpp
@@ -20,7 +20,6 @@
#include <2geom/bezier-to-sbasis.h>
#include <2geom/sbasis-to-bezier.h>
#include <2geom/d2.h>
-#include <2geom/d2-sbasis.h>
#include <2geom/sbasis-math.h>
#include <2geom/piecewise.h>
diff --git a/src/live_effects/lpe-envelope.cpp b/src/live_effects/lpe-envelope.cpp
index 05a672ae8..e873c0b15 100644
--- a/src/live_effects/lpe-envelope.cpp
+++ b/src/live_effects/lpe-envelope.cpp
@@ -42,6 +42,7 @@ LPEEnvelope::LPEEnvelope(LivePathEffectObject *lpeobject) :
registerParameter( dynamic_cast<Parameter *>(&bend_path3) );
registerParameter( dynamic_cast<Parameter *>(&bend_path4) );
concatenate_before_pwd2 = true;
+ apply_to_clippath_and_mask = true;
}
LPEEnvelope::~LPEEnvelope()
@@ -54,9 +55,6 @@ LPEEnvelope::doBeforeEffect (SPLPEItem const* lpeitem)
{
// get the item bounding box
original_bbox(lpeitem);
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
}
Geom::Piecewise<Geom::D2<Geom::SBasis> >
diff --git a/src/live_effects/lpe-fill-between-many.cpp b/src/live_effects/lpe-fill-between-many.cpp
index 3e0810cfc..574ec3580 100644
--- a/src/live_effects/lpe-fill-between-many.cpp
+++ b/src/live_effects/lpe-fill-between-many.cpp
@@ -37,7 +37,7 @@ void LPEFillBetweenMany::doEffect (SPCurve * curve)
{
Geom::PathVector res_pathv;
SPItem * firstObj = NULL;
- for (std::vector<PathAndDirection*>::iterator iter = linked_paths._vector.begin(); iter != linked_paths._vector.end(); iter++) {
+ for (std::vector<PathAndDirection*>::iterator iter = linked_paths._vector.begin(); iter != linked_paths._vector.end(); ++iter) {
SPObject *obj;
if ((*iter)->ref.isAttached() && (obj = (*iter)->ref.getObject()) && SP_IS_ITEM(obj) && !(*iter)->_pathvector.empty()) {
Geom::Path linked_path;
diff --git a/src/live_effects/lpe-fillet-chamfer.cpp b/src/live_effects/lpe-fillet-chamfer.cpp
index a9a96864a..07760b172 100644
--- a/src/live_effects/lpe-fillet-chamfer.cpp
+++ b/src/live_effects/lpe-fillet-chamfer.cpp
@@ -76,12 +76,15 @@ LPEFilletChamfer::LPEFilletChamfer(LivePathEffectObject *lpeobject) :
radius.param_set_range(0., infinity());
radius.param_set_increments(1, 1);
radius.param_set_digits(4);
+ radius.param_overwrite_widget(true);
chamfer_steps.param_set_range(1, 999);
chamfer_steps.param_set_increments(1, 1);
chamfer_steps.param_set_digits(0);
+ chamfer_steps.param_overwrite_widget(true);
helper_size.param_set_range(0, infinity());
helper_size.param_set_increments(5, 5);
helper_size.param_set_digits(0);
+ helper_size.param_overwrite_widget(true);
fillet_chamfer_values.set_chamfer_steps(3);
}
@@ -96,6 +99,14 @@ Gtk::Widget *LPEFilletChamfer::newWidget()
vbox->set_border_width(5);
vbox->set_homogeneous(false);
vbox->set_spacing(2);
+ Gtk::HBox *advertaising = Gtk::manage(new Gtk::HBox(true, 0));
+ Gtk::Button *advert = Gtk::manage(new Gtk::Button(Glib::ustring(_("IMPORTANT! New version soon..."))));
+ advertaising->pack_start(*advert, true, true, 2);
+ vbox->pack_start(*advertaising, true, true, 2);
+ Gtk::HBox *advertaising2 = Gtk::manage(new Gtk::HBox(true, 0));
+ Gtk::Button *advert2 = Gtk::manage(new Gtk::Button(Glib::ustring(_("Not compatible. Convert to path after."))));
+ advertaising2->pack_start(*advert2, true, true, 2);
+ vbox->pack_start(*advertaising2, true, true, 2);
std::vector<Parameter *>::iterator it = param_vector.begin();
while (it != param_vector.end()) {
if ((*it)->widget_is_visible) {
@@ -226,18 +237,21 @@ void LPEFilletChamfer::updateFillet()
}
Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
doUpdateFillet(path_from_piecewise(pwd2, tolerance), power);
+ DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));
}
void LPEFilletChamfer::fillet()
{
Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
doChangeType(path_from_piecewise(pwd2, tolerance), 1);
+ DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to fillet"));
}
void LPEFilletChamfer::inverseFillet()
{
Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
doChangeType(path_from_piecewise(pwd2, tolerance), 2);
+ DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet"));
}
void LPEFilletChamfer::chamferSubdivisions()
@@ -245,6 +259,7 @@ void LPEFilletChamfer::chamferSubdivisions()
fillet_chamfer_values.set_chamfer_steps(chamfer_steps);
Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 5000);
+ DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));
}
void LPEFilletChamfer::chamfer()
@@ -252,6 +267,7 @@ void LPEFilletChamfer::chamfer()
fillet_chamfer_values.set_chamfer_steps(chamfer_steps);
Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 3000);
+ DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to chamfer"));
}
void LPEFilletChamfer::inverseChamfer()
@@ -259,6 +275,7 @@ void LPEFilletChamfer::inverseChamfer()
fillet_chamfer_values.set_chamfer_steps(chamfer_steps);
Piecewise<D2<SBasis> > const &pwd2 = fillet_chamfer_values.get_pwd2();
doChangeType(path_from_piecewise(pwd2, tolerance), chamfer_steps + 4000);
+ DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Convert to inverse fillet"));
}
void LPEFilletChamfer::refreshKnots()
@@ -270,6 +287,7 @@ void LPEFilletChamfer::refreshKnots()
tools_switch(desktop, TOOLS_SELECT);
tools_switch(desktop, TOOLS_NODES);
}
+ DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Knots and helper paths refreshed"));
}
void LPEFilletChamfer::doUpdateFillet(Geom::PathVector const &original_pathv, double power)
diff --git a/src/live_effects/lpe-interpolate.cpp b/src/live_effects/lpe-interpolate.cpp
index b1ad07d23..74c7efd90 100644
--- a/src/live_effects/lpe-interpolate.cpp
+++ b/src/live_effects/lpe-interpolate.cpp
@@ -16,7 +16,6 @@
#include <2geom/path.h>
#include <2geom/sbasis-to-bezier.h>
-#include <2geom/d2-sbasis.h>
#include <2geom/piecewise.h>
#include <2geom/sbasis-geometric.h>
diff --git a/src/live_effects/lpe-interpolate_points.cpp b/src/live_effects/lpe-interpolate_points.cpp
index 4ac139752..cf70832ee 100644
--- a/src/live_effects/lpe-interpolate_points.cpp
+++ b/src/live_effects/lpe-interpolate_points.cpp
@@ -52,8 +52,11 @@ Geom::PathVector
LPEInterpolatePoints::doEffect_path (Geom::PathVector const & path_in)
{
Geom::PathVector path_out;
-
+#if __cplusplus <= 199711L
std::auto_ptr<Geom::Interpolate::Interpolator> interpolator( Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value())) );
+#else
+ std::unique_ptr<Geom::Interpolate::Interpolator> interpolator( Geom::Interpolate::Interpolator::create(static_cast<Geom::Interpolate::InterpolatorType>(interpolator_type.get_value())) );
+#endif
for(Geom::PathVector::const_iterator path_it = path_in.begin(); path_it != path_in.end(); ++path_it) {
if (path_it->empty())
diff --git a/src/live_effects/lpe-jointype.cpp b/src/live_effects/lpe-jointype.cpp
index 28f99eb94..2eef315dd 100644
--- a/src/live_effects/lpe-jointype.cpp
+++ b/src/live_effects/lpe-jointype.cpp
@@ -33,6 +33,9 @@ static const Util::EnumData<unsigned> JoinTypeData[] = {
{JOIN_MITER, N_("Miter"), "miter"},
{JOIN_MITER_CLIP, N_("Miter Clip"), "miter-clip"},
{JOIN_EXTRAPOLATE, N_("Extrapolated arc"), "extrp_arc"},
+ {JOIN_EXTRAPOLATE1, N_("Extrapolated arc Alt1"), "extrp_arc1"},
+ {JOIN_EXTRAPOLATE2, N_("Extrapolated arc Alt2"), "extrp_arc2"},
+ {JOIN_EXTRAPOLATE3, N_("Extrapolated arc Alt3"), "extrp_arc3"},
};
static const Util::EnumData<unsigned> CapTypeData[] = {
diff --git a/src/live_effects/lpe-knot.cpp b/src/live_effects/lpe-knot.cpp
index c3000fe0d..a033a6c4a 100644
--- a/src/live_effects/lpe-knot.cpp
+++ b/src/live_effects/lpe-knot.cpp
@@ -27,7 +27,6 @@
#include <2geom/sbasis-to-bezier.h>
#include <2geom/sbasis.h>
#include <2geom/d2.h>
-#include <2geom/d2-sbasis.h>
#include <2geom/path.h>
#include <2geom/bezier-to-sbasis.h>
#include <2geom/basic-intersection.h>
@@ -507,7 +506,7 @@ static void
collectPathsAndWidths (SPLPEItem const *lpeitem, Geom::PathVector &paths, std::vector<double> &stroke_widths){
if (SP_IS_GROUP(lpeitem)) {
std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
- for ( std::vector<SPItem*>::const_iterator iter = item_list.begin(); iter != item_list.end(); iter++) {
+ for ( std::vector<SPItem*>::const_iterator iter = item_list.begin(); iter != item_list.end(); ++iter) {
SPObject *subitem = *iter;
if (SP_IS_LPE_ITEM(subitem)) {
collectPathsAndWidths(SP_LPE_ITEM(subitem), paths, stroke_widths);
diff --git a/src/live_effects/lpe-lattice.cpp b/src/live_effects/lpe-lattice.cpp
index c05bae7e1..3c23e349e 100644
--- a/src/live_effects/lpe-lattice.cpp
+++ b/src/live_effects/lpe-lattice.cpp
@@ -78,7 +78,7 @@ LPELattice::LPELattice(LivePathEffectObject *lpeobject) :
registerParameter( dynamic_cast<Parameter *>(&grid_point14) );
registerParameter( dynamic_cast<Parameter *>(&grid_point15) );
-
+ apply_to_clippath_and_mask = true;
}
LPELattice::~LPELattice()
@@ -176,9 +176,6 @@ void
LPELattice::doBeforeEffect (SPLPEItem const* lpeitem)
{
original_bbox(lpeitem);
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
}
void
diff --git a/src/live_effects/lpe-lattice2.cpp b/src/live_effects/lpe-lattice2.cpp
index 8c7f46cbd..0c403daec 100644
--- a/src/live_effects/lpe-lattice2.cpp
+++ b/src/live_effects/lpe-lattice2.cpp
@@ -46,6 +46,7 @@ LPELattice2::LPELattice2(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
horizontal_mirror(_("Mirror movements in horizontal"), _("Mirror movements in horizontal"), "horizontal_mirror", &wr, this, false),
vertical_mirror(_("Mirror movements in vertical"), _("Mirror movements in vertical"), "vertical_mirror", &wr, this, false),
+ live_update(_("Update while moving knots (maybe slow)"), _("Update while moving knots (maybe slow)"), "live_update", &wr, this, true),
grid_point_0(_("Control 0:"), _("Control 0 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint0", &wr, this),
grid_point_1(_("Control 1:"), _("Control 1 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint1", &wr, this),
grid_point_2(_("Control 2:"), _("Control 2 - <b>Ctrl+Alt+Click</b>: reset, <b>Ctrl</b>: move along axes"), "gridpoint2", &wr, this),
@@ -76,6 +77,7 @@ LPELattice2::LPELattice2(LivePathEffectObject *lpeobject) :
// register all your parameters here, so Inkscape knows which parameters this effect has:
registerParameter(&horizontal_mirror);
registerParameter(&vertical_mirror);
+ registerParameter(&live_update);
registerParameter(&grid_point_0);
registerParameter(&grid_point_1);
registerParameter(&grid_point_2);
@@ -101,6 +103,7 @@ LPELattice2::LPELattice2(LivePathEffectObject *lpeobject) :
registerParameter(&grid_point_28x30);
registerParameter(&grid_point_29x31);
registerParameter(&grid_point_32x33x34x35);
+ apply_to_clippath_and_mask = true;
}
LPELattice2::~LPELattice2()
@@ -248,7 +251,7 @@ LPELattice2::newWidget()
}
Glib::ustring * tip = param->param_getTooltip();
if (widg) {
- if (param->param_key == "horizontal_mirror" || param->param_key == "vertical_mirror") {
+ if (param->param_key == "horizontal_mirror" || param->param_key == "vertical_mirror" || param->param_key == "live_update") {
vbox->pack_start(*widg, true, true, 2);
} else {
vbox_expander->pack_start(*widg, true, true, 2);
@@ -300,8 +303,8 @@ LPELattice2::vertical(PointParam &param_one, PointParam &param_two, Geom::Line v
}
A[Geom::X] = nearest[Geom::X] - distance_middle;
B[Geom::X] = nearest[Geom::X] + distance_middle;
- param_one.param_setValue(A, true);
- param_two.param_setValue(B, true);
+ param_one.param_setValue(A, live_update);
+ param_two.param_setValue(B, live_update);
}
void
@@ -321,8 +324,8 @@ LPELattice2::horizontal(PointParam &param_one, PointParam &param_two, Geom::Line
}
A[Geom::Y] = nearest[Geom::Y] - distance_middle;
B[Geom::Y] = nearest[Geom::Y] + distance_middle;
- param_one.param_setValue(A, true);
- param_two.param_setValue(B, true);
+ param_one.param_setValue(A, live_update);
+ param_two.param_setValue(B, live_update);
}
void
@@ -356,9 +359,6 @@ LPELattice2::doBeforeEffect (SPLPEItem const* lpeitem)
horizontal(grid_point_17, grid_point_19,horiz);
horizontal(grid_point_20x21, grid_point_22x23,horiz);
}
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
}
void
@@ -464,6 +464,31 @@ LPELattice2::setDefaults()
grid_point_28x30.param_update_default(gp28x30);
grid_point_29x31.param_update_default(gp29x31);
grid_point_32x33x34x35.param_update_default(gp32x33x34x35);
+ grid_point_0.param_set_liveupdate(live_update);
+ grid_point_1.param_set_liveupdate(live_update);
+ grid_point_2.param_set_liveupdate(live_update);
+ grid_point_3.param_set_liveupdate(live_update);
+ grid_point_4.param_set_liveupdate(live_update);
+ grid_point_5.param_set_liveupdate(live_update);
+ grid_point_6.param_set_liveupdate(live_update);
+ grid_point_7.param_set_liveupdate(live_update);
+ grid_point_8x9.param_set_liveupdate(live_update);
+ grid_point_10x11.param_set_liveupdate(live_update);
+ grid_point_12.param_set_liveupdate(live_update);
+ grid_point_13.param_set_liveupdate(live_update);
+ grid_point_14.param_set_liveupdate(live_update);
+ grid_point_15.param_set_liveupdate(live_update);
+ grid_point_16.param_set_liveupdate(live_update);
+ grid_point_17.param_set_liveupdate(live_update);
+ grid_point_18.param_set_liveupdate(live_update);
+ grid_point_19.param_set_liveupdate(live_update);
+ grid_point_20x21.param_set_liveupdate(live_update);
+ grid_point_22x23.param_set_liveupdate(live_update);
+ grid_point_24x26.param_set_liveupdate(live_update);
+ grid_point_25x27.param_set_liveupdate(live_update);
+ grid_point_28x30.param_set_liveupdate(live_update);
+ grid_point_29x31.param_set_liveupdate(live_update);
+ grid_point_32x33x34x35.param_set_liveupdate(live_update);
}
void
diff --git a/src/live_effects/lpe-lattice2.h b/src/live_effects/lpe-lattice2.h
index b32903c9e..8d0c18a3a 100644
--- a/src/live_effects/lpe-lattice2.h
+++ b/src/live_effects/lpe-lattice2.h
@@ -63,6 +63,7 @@ private:
BoolParam horizontal_mirror;
BoolParam vertical_mirror;
+ BoolParam live_update;
PointParam grid_point_0;
PointParam grid_point_1;
PointParam grid_point_2;
diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp
index 783053df2..c13cffb6a 100644
--- a/src/live_effects/lpe-mirror_symmetry.cpp
+++ b/src/live_effects/lpe-mirror_symmetry.cpp
@@ -33,7 +33,7 @@ LPEMirrorSymmetry::LPEMirrorSymmetry(LivePathEffectObject *lpeobject) :
reflection_line(_("Reflection line:"), _("Line which serves as 'mirror' for the reflection"), "reflection_line", &wr, this, "M0,0 L100,100")
{
show_orig_path = true;
-
+ apply_to_clippath_and_mask = true;
registerParameter( dynamic_cast<Parameter *>(&discard_orig_path) );
registerParameter( dynamic_cast<Parameter *>(&reflection_line) );
}
@@ -43,14 +43,6 @@ LPEMirrorSymmetry::~LPEMirrorSymmetry()
}
void
-LPEMirrorSymmetry::doBeforeEffect (SPLPEItem const* lpeitem)
-{
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
-}
-
-void
LPEMirrorSymmetry::doOnApply (SPLPEItem const* lpeitem)
{
using namespace Geom;
diff --git a/src/live_effects/lpe-mirror_symmetry.h b/src/live_effects/lpe-mirror_symmetry.h
index 7a484a473..64a72d7b3 100644
--- a/src/live_effects/lpe-mirror_symmetry.h
+++ b/src/live_effects/lpe-mirror_symmetry.h
@@ -30,8 +30,6 @@ public:
virtual void doOnApply (SPLPEItem const* lpeitem);
- virtual void doBeforeEffect (SPLPEItem const* lpeitem);
-
virtual Geom::PathVector doEffect_path (Geom::PathVector const & path_in);
private:
diff --git a/src/live_effects/lpe-offset.cpp b/src/live_effects/lpe-offset.cpp
index dd7af92a2..d611b88a1 100644
--- a/src/live_effects/lpe-offset.cpp
+++ b/src/live_effects/lpe-offset.cpp
@@ -31,7 +31,7 @@ LPEOffset::LPEOffset(LivePathEffectObject *lpeobject) :
offset_pt(_("Offset"), _("Handle to control the distance of the offset from the curve"), "offset_pt", &wr, this)
{
show_orig_path = true;
-
+ apply_to_clippath_and_mask = true;
registerParameter(dynamic_cast<Parameter *>(&offset_pt));
}
@@ -57,14 +57,6 @@ static void append_half_circle(Geom::Piecewise<Geom::D2<Geom::SBasis> > &pwd2,
pwd2.continuousConcat(cap_pwd2);
}
-void
-LPEOffset::doBeforeEffect (SPLPEItem const* lpeitem)
-{
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
-}
-
Geom::Piecewise<Geom::D2<Geom::SBasis> >
LPEOffset::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
{
diff --git a/src/live_effects/lpe-offset.h b/src/live_effects/lpe-offset.h
index 997311c7d..9966fd45d 100644
--- a/src/live_effects/lpe-offset.h
+++ b/src/live_effects/lpe-offset.h
@@ -28,8 +28,6 @@ public:
virtual void doOnApply (SPLPEItem const* lpeitem);
- virtual void doBeforeEffect (SPLPEItem const* lpeitem);
-
virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);
private:
diff --git a/src/live_effects/lpe-patternalongpath.cpp b/src/live_effects/lpe-patternalongpath.cpp
index ed65a0d50..9397d848f 100644
--- a/src/live_effects/lpe-patternalongpath.cpp
+++ b/src/live_effects/lpe-patternalongpath.cpp
@@ -18,6 +18,9 @@
#include <2geom/d2.h>
#include <2geom/piecewise.h>
+#include "knot-holder-entity.h"
+#include "knotholder.h"
+
#include <algorithm>
using std::vector;
@@ -45,6 +48,16 @@ first) but I think we can first forget about them.
namespace Inkscape {
namespace LivePathEffect {
+Geom::PathVector pap_helper_path;
+
+namespace WPAP {
+ class KnotHolderEntityWidthPatternAlongPath : public LPEKnotHolderEntity {
+ public:
+ KnotHolderEntityWidthPatternAlongPath(LPEPatternAlongPath * effect) : LPEKnotHolderEntity(effect) {}
+ virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state);
+ virtual Geom::Point knot_get() const;
+ };
+} // WPAP
static const Util::EnumData<PAPCopyType> PAPCopyTypeData[PAPCT_END] = {
{PAPCT_SINGLE, N_("Single"), "single"},
@@ -57,9 +70,10 @@ static const Util::EnumDataConverter<PAPCopyType> PAPCopyTypeConverter(PAPCopyTy
LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) :
Effect(lpeobject),
pattern(_("Pattern source:"), _("Path to put along the skeleton path"), "pattern", &wr, this, "M0,0 L1,0"),
+ original_height(0),
+ prop_scale(_("_Width:"), _("Width of the pattern"), "prop_scale", &wr, this, 1.0),
copytype(_("Pattern copies:"), _("How many pattern copies to place along the skeleton path"),
"copytype", PAPCopyTypeConverter, &wr, this, PAPCT_SINGLE_STRETCHED),
- prop_scale(_("_Width:"), _("Width of the pattern"), "prop_scale", &wr, this, 1),
scale_y_rel(_("Wid_th in units of length"),
_("Scale the width of the pattern in units of its length"),
"scale_y_rel", &wr, this, false),
@@ -87,9 +101,11 @@ LPEPatternAlongPath::LPEPatternAlongPath(LivePathEffectObject *lpeobject) :
registerParameter( dynamic_cast<Parameter *>(&prop_units) );
registerParameter( dynamic_cast<Parameter *>(&vertical_pattern) );
registerParameter( dynamic_cast<Parameter *>(&fuse_tolerance) );
-
prop_scale.param_set_digits(3);
prop_scale.param_set_increments(0.01, 0.10);
+
+ _provides_knotholder_entities = true;
+
}
LPEPatternAlongPath::~LPEPatternAlongPath()
@@ -97,6 +113,16 @@ LPEPatternAlongPath::~LPEPatternAlongPath()
}
+void
+LPEPatternAlongPath::doBeforeEffect (SPLPEItem const* lpeitem)
+{
+ // get the pattern bounding box
+ Geom::OptRect bbox = pattern.get_pathvector().boundsFast();
+ if (bbox) {
+ original_height = (*bbox)[Geom::Y].max() - (*bbox)[Geom::Y].min();
+ }
+}
+
Geom::Piecewise<Geom::D2<Geom::SBasis> >
LPEPatternAlongPath::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
{
@@ -238,6 +264,83 @@ LPEPatternAlongPath::transform_multiply(Geom::Affine const& postmul, bool set)
}
}
+void
+LPEPatternAlongPath::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+ hp_vec.push_back(pap_helper_path);
+}
+
+
+void
+LPEPatternAlongPath::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item)
+{
+ KnotHolderEntity *e = new WPAP::KnotHolderEntityWidthPatternAlongPath(this);
+ e->create(desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, _("Change the width"), SP_KNOT_SHAPE_CIRCLE);
+ knotholder->add(e);
+}
+
+namespace WPAP {
+
+void
+KnotHolderEntityWidthPatternAlongPath::knot_set(Geom::Point const &p, Geom::Point const& /*origin*/, guint state)
+{
+ LPEPatternAlongPath *lpe = dynamic_cast<LPEPatternAlongPath *> (_effect);
+
+ Geom::Point const s = snap_knot_position(p, state);
+ SPShape const *sp_shape = dynamic_cast<SPShape const *>(SP_LPE_ITEM(item));
+ if (sp_shape) {
+ Geom::Path const *path_in = sp_shape->getCurveBeforeLPE()->first_path();
+ Geom::Point ptA = path_in->pointAt(Geom::PathTime(0, 0.0));
+ Geom::Point B = path_in->pointAt(Geom::PathTime(1, 0.0));
+ Geom::Curve const *first_curve = &path_in->curveAt(Geom::PathTime(0, 0.0));
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*first_curve);
+ Geom::Ray ray(ptA, B);
+ if (cubic) {
+ ray.setPoints(ptA, (*cubic)[1]);
+ }
+ ray.setAngle(ray.angle() + Geom::rad_from_deg(90));
+ Geom::Point knot_pos = this->knot->pos * item->i2dt_affine().inverse();
+ Geom::Coord nearest_to_ray = ray.nearestTime(knot_pos);
+ if(nearest_to_ray == 0){
+ lpe->prop_scale.param_set_value(-Geom::distance(s , ptA)/(lpe->original_height/2.0));
+ } else {
+ lpe->prop_scale.param_set_value(Geom::distance(s , ptA)/(lpe->original_height/2.0));
+ }
+
+ }
+ sp_lpe_item_update_patheffect (SP_LPE_ITEM(item), false, true);
+}
+
+Geom::Point
+KnotHolderEntityWidthPatternAlongPath::knot_get() const
+{
+ LPEPatternAlongPath *lpe = dynamic_cast<LPEPatternAlongPath *> (_effect);
+
+ SPShape const *sp_shape = dynamic_cast<SPShape const *>(SP_LPE_ITEM(item));
+ if (sp_shape) {
+ Geom::Path const *path_in = sp_shape->getCurveBeforeLPE()->first_path();
+ Geom::Point ptA = path_in->pointAt(Geom::PathTime(0, 0.0));
+ Geom::Point B = path_in->pointAt(Geom::PathTime(1, 0.0));
+ Geom::Curve const *first_curve = &path_in->curveAt(Geom::PathTime(0, 0.0));
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*first_curve);
+ Geom::Ray ray(ptA, B);
+ if (cubic) {
+ ray.setPoints(ptA, (*cubic)[1]);
+ }
+ ray.setAngle(ray.angle() + Geom::rad_from_deg(90));
+ Geom::Point result_point = Geom::Point::polar(ray.angle(), (lpe->original_height/2.0) * lpe->prop_scale) + ptA;
+
+ pap_helper_path.clear();
+ Geom::Path hp(result_point);
+ hp.appendNew<Geom::LineSegment>(ptA);
+ pap_helper_path.push_back(hp);
+ hp.clear();
+
+ return result_point;
+ }
+ return Geom::Point();
+}
+} // namespace WPAP
} // namespace LivePathEffect
} /* namespace Inkscape */
diff --git a/src/live_effects/lpe-patternalongpath.h b/src/live_effects/lpe-patternalongpath.h
index be2197ddb..3b9a17ab0 100644
--- a/src/live_effects/lpe-patternalongpath.h
+++ b/src/live_effects/lpe-patternalongpath.h
@@ -13,10 +13,15 @@
#include "live_effects/effect.h"
#include "live_effects/parameter/path.h"
#include "live_effects/parameter/bool.h"
+#include "live_effects/parameter/point.h"
namespace Inkscape {
namespace LivePathEffect {
+namespace WPAP {
+class KnotHolderEntityWidthPatternAlongPath;
+}
+
enum PAPCopyType {
PAPCT_SINGLE = 0,
PAPCT_SINGLE_STRETCHED,
@@ -30,14 +35,25 @@ public:
LPEPatternAlongPath(LivePathEffectObject *lpeobject);
virtual ~LPEPatternAlongPath();
+ virtual void doBeforeEffect (SPLPEItem const* lpeitem);
+
virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);
virtual void transform_multiply(Geom::Affine const& postmul, bool set);
+ void addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec);
+
+ virtual void addKnotHolderEntities(KnotHolder * knotholder, SPDesktop * desktop, SPItem * item);
+
PathParam pattern;
+
+ friend class WPAP::KnotHolderEntityWidthPatternAlongPath;
+protected:
+ double original_height;
+ ScalarParam prop_scale;
+
private:
EnumParam<PAPCopyType> copytype;
- ScalarParam prop_scale;
BoolParam scale_y_rel;
ScalarParam spacing;
ScalarParam normal_offset;
@@ -45,7 +61,6 @@ private:
BoolParam prop_units;
BoolParam vertical_pattern;
ScalarParam fuse_tolerance;
-
void on_pattern_pasted();
LPEPatternAlongPath(const LPEPatternAlongPath&);
diff --git a/src/live_effects/lpe-perspective-envelope.cpp b/src/live_effects/lpe-perspective-envelope.cpp
index 72c1b0e99..5b29df4a7 100644
--- a/src/live_effects/lpe-perspective-envelope.cpp
+++ b/src/live_effects/lpe-perspective-envelope.cpp
@@ -56,6 +56,7 @@ LPEPerspectiveEnvelope::LPEPerspectiveEnvelope(LivePathEffectObject *lpeobject)
registerParameter(&up_right_point);
registerParameter(&down_left_point);
registerParameter(&down_right_point);
+ apply_to_clippath_and_mask = true;
}
LPEPerspectiveEnvelope::~LPEPerspectiveEnvelope()
@@ -371,9 +372,6 @@ LPEPerspectiveEnvelope::doBeforeEffect (SPLPEItem const* lpeitem)
horizontal(up_left_point, down_left_point,horiz);
horizontal(up_right_point, down_right_point,horiz);
}
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
setDefaults();
}
diff --git a/src/live_effects/lpe-perspective_path.cpp b/src/live_effects/lpe-perspective_path.cpp
index 901519b4f..c8cdd7912 100644
--- a/src/live_effects/lpe-perspective_path.cpp
+++ b/src/live_effects/lpe-perspective_path.cpp
@@ -64,6 +64,7 @@ LPEPerspectivePath::LPEPerspectivePath(LivePathEffectObject *lpeobject) :
concatenate_before_pwd2 = true; // don't split the path into its subpaths
_provides_knotholder_entities = true;
+ apply_to_clippath_and_mask = true;
}
LPEPerspectivePath::~LPEPerspectivePath()
@@ -100,8 +101,6 @@ LPEPerspectivePath::doBeforeEffect (SPLPEItem const* lpeitem)
Geom::Affine doc2d = Geom::Scale(1, -1) * Geom::Translate(0, item->document->getHeight().value("px"));
pmat = pmat * doc2d;
pmat.copy_tmat(tmat);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
}
void LPEPerspectivePath::refresh(Gtk::Entry* perspective) {
diff --git a/src/live_effects/lpe-powerstroke.cpp b/src/live_effects/lpe-powerstroke.cpp
index f90d67d4e..03102a84a 100644
--- a/src/live_effects/lpe-powerstroke.cpp
+++ b/src/live_effects/lpe-powerstroke.cpp
@@ -102,12 +102,15 @@ static Circle touching_circle( D2<SBasis> const &curve, double t, double tol=0.0
{
//Piecewise<SBasis> k = curvature(curve, tol);
D2<SBasis> dM=derivative(curve);
- if ( are_near(L2sq(dM(t)),0.) ) {
+ if ( are_near(L2sq(dM(t)),0.) && (dM[0].size() > 1) && (dM[1].size() > 1) ) {
dM=derivative(dM);
}
- if ( are_near(L2sq(dM(t)),0.) ) { // try second time
+ if ( are_near(L2sq(dM(t)),0.) && (dM[0].size() > 1) && (dM[1].size() > 1) ) { // try second time
dM=derivative(dM);
}
+ if ( are_near(L2sq(dM(t)),0.) && (dM[0].size() > 1) && (dM[1].size() > 1) ) { // admit defeat
+ return Geom::Circle(Geom::Point(0., 0.), 0.);
+ }
Piecewise<D2<SBasis> > unitv = unitVector(dM,tol);
Piecewise<SBasis> dMlength = dot(Piecewise<D2<SBasis> >(dM),unitv);
Piecewise<SBasis> k = cross(derivative(unitv),unitv);
diff --git a/src/live_effects/lpe-roughen.cpp b/src/live_effects/lpe-roughen.cpp
index 33ffd96d6..105fe2fc4 100644
--- a/src/live_effects/lpe-roughen.cpp
+++ b/src/live_effects/lpe-roughen.cpp
@@ -18,7 +18,9 @@
#include "live_effects/lpe-roughen.h"
#include "display/curve.h"
#include "live_effects/parameter/parameter.h"
+#include <boost/functional/hash.hpp>
#include "helper/geom.h"
+#include "sp-item-group.h"
#include <glibmm/i18n.h>
#include <cmath>
@@ -32,13 +34,22 @@ static const Util::EnumData<DivisionMethod> DivisionMethodData[DM_END] = {
static const Util::EnumDataConverter<DivisionMethod>
DMConverter(DivisionMethodData, DM_END);
+static const Util::EnumData<HandlesMethod> HandlesMethodData[HM_END] = {
+ { HM_ALONG_NODES, N_("Along nodes"), "along" },
+ { HM_RAND, N_("Rand"), "rand" },
+ { HM_RETRACT, N_("Retract"), "retract" },
+ { HM_SMOOTH, N_("Smooth"), "smooth" }
+};
+static const Util::EnumDataConverter<HandlesMethod>
+HMConverter(HandlesMethodData, HM_END);
+
LPERoughen::LPERoughen(LivePathEffectObject *lpeobject)
: Effect(lpeobject),
// initialise your parameters here:
method(_("Method"), _("Division method"), "method", DMConverter, &wr,
this, DM_SEGMENTS),
max_segment_size(_("Max. segment size"), _("Max. segment size"),
- "max_segment_size", &wr, this, 10.),
+ "max_segment_size", &wr, this, 10),
segments(_("Number of segments"), _("Number of segments"), "segments",
&wr, this, 2),
displace_x(_("Max. displacement in X"), _("Max. displacement in X"),
@@ -47,10 +58,14 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject)
"displace_y", &wr, this, 10.),
global_randomize(_("Global randomize"), _("Global randomize"),
"global_randomize", &wr, this, 1.),
+ handles(_("Handles"), _("Handles options"), "handles", HMConverter, &wr,
+ this, HM_ALONG_NODES),
shift_nodes(_("Shift nodes"), _("Shift nodes"), "shift_nodes", &wr, this,
true),
- shift_node_handles(_("Shift node handles"), _("Shift node handles"),
- "shift_node_handles", &wr, this, true)
+ fixed_displacement(_("Fixed displacement"), _("Fixed displacement, 1/3 of segment length"),
+ "fixed_displacement", &wr, this, false),
+ spray_tool_friendly(_("Spray Tool friendly"), _("For use with spray tool in copy mode"),
+ "spray_tool_friendly", &wr, this, false)
{
registerParameter(&method);
registerParameter(&max_segment_size);
@@ -58,8 +73,10 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject)
registerParameter(&displace_x);
registerParameter(&displace_y);
registerParameter(&global_randomize);
+ registerParameter(&handles);
registerParameter(&shift_nodes);
- registerParameter(&shift_node_handles);
+ registerParameter(&fixed_displacement);
+ registerParameter(&spray_tool_friendly);
displace_x.param_set_range(0., Geom::infinity());
displace_y.param_set_range(0., Geom::infinity());
global_randomize.param_set_range(0., Geom::infinity());
@@ -69,19 +86,23 @@ LPERoughen::LPERoughen(LivePathEffectObject *lpeobject)
segments.param_set_range(1, Geom::infinity());
segments.param_set_increments(1, 1);
segments.param_set_digits(0);
+ seed = 0;
+ apply_to_clippath_and_mask = true;
}
LPERoughen::~LPERoughen() {}
void LPERoughen::doBeforeEffect(SPLPEItem const *lpeitem)
{
+ if(spray_tool_friendly && seed == 0 && SP_OBJECT(lpeitem)->getId()){
+ std::string id_item(SP_OBJECT(lpeitem)->getId());
+ long seed = static_cast<long>(boost::hash_value(id_item));
+ global_randomize.param_set_value(global_randomize.get_value(), seed);
+ }
displace_x.resetRandomizer();
displace_y.resetRandomizer();
global_randomize.resetRandomizer();
srand(1);
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
}
Gtk::Widget *LPERoughen::newWidget()
@@ -122,6 +143,15 @@ Gtk::Widget *LPERoughen::newWidget()
vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
Gtk::PACK_EXPAND_WIDGET);
}
+ if (param->param_key == "handles") {
+ Gtk::Label *options = Gtk::manage(new Gtk::Label(
+ Glib::ustring(_("<b>Options</b> Modify options to rough")),
+ Gtk::ALIGN_START));
+ options->set_use_markup(true);
+ vbox->pack_start(*options, false, false, 2);
+ vbox->pack_start(*Gtk::manage(new Gtk::HSeparator()),
+ Gtk::PACK_EXPAND_WIDGET);
+ }
Glib::ustring *tip = param->param_getTooltip();
if (widg) {
vbox->pack_start(*widg, true, true, 2);
@@ -133,7 +163,6 @@ Gtk::Widget *LPERoughen::newWidget()
}
}
}
-
++it;
}
return dynamic_cast<Gtk::Widget *>(vbox);
@@ -147,19 +176,25 @@ double LPERoughen::sign(double random_number)
return random_number;
}
-Geom::Point LPERoughen::randomize()
+Geom::Point LPERoughen::randomize(double max_lenght, bool is_node)
{
- double displace_x_parsed = displace_x * global_randomize;
- double displace_y_parsed = displace_y * global_randomize;
-
+ double factor = 1.0/3.0;
+ if(is_node){
+ factor = 1.0;
+ }
+ double displace_x_parsed = displace_x * global_randomize * factor;
+ double displace_y_parsed = displace_y * global_randomize * factor;
Geom::Point output = Geom::Point(sign(displace_x_parsed), sign(displace_y_parsed));
+ if( fixed_displacement ){
+ Geom::Ray ray(Geom::Point(0,0),output);
+ output = Geom::Point::polar(ray.angle(), max_lenght);
+ }
return output;
}
void LPERoughen::doEffect(SPCurve *curve)
{
- Geom::PathVector const original_pathv =
- pathv_to_linear_and_cubic_beziers(curve->get_pathvector());
+ Geom::PathVector const original_pathv = pathv_to_linear_and_cubic_beziers(curve->get_pathvector());
curve->reset();
for (Geom::PathVector::const_iterator path_it = original_pathv.begin();
path_it != original_pathv.end(); ++path_it) {
@@ -170,41 +205,30 @@ void LPERoughen::doEffect(SPCurve *curve)
Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
Geom::Path::const_iterator curve_endit = path_it->end_default();
SPCurve *nCurve = new SPCurve();
+ Geom::Point prev(0, 0);
+ Geom::Point last_move(0, 0);
+ nCurve->moveto(curve_it1->initialPoint());
if (path_it->closed()) {
- const Geom::Curve &closingline =
- path_it->back_closed();
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- curve_endit = path_it->end_open();
- }
- }
- Geom::Point initialMove(0, 0);
- if (shift_nodes) {
- initialMove = randomize();
+ const Geom::Curve &closingline = path_it->back_closed();
+ // the closing line segment is always of type
+ // Geom::LineSegment.
+ if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
+ // closingline.isDegenerate() did not work, because it only checks for
+ // *exact* zero length, which goes wrong for relative coordinates and
+ // rounding errors...
+ // the closing line segment has zero-length. So stop before that one!
+ curve_endit = path_it->end_open();
+ }
}
- Geom::Point initialPoint = curve_it1->initialPoint() + initialMove;
- nCurve->moveto(initialPoint);
- Geom::Point point0(0, 0);
- Geom::Point point1(0, 0);
- Geom::Point point2(0, 0);
- Geom::Point point3(0, 0);
- bool first = true;
while (curve_it1 != curve_endit) {
Geom::CubicBezier const *cubic = NULL;
- point0 = curve_it1->initialPoint();
- point1 = curve_it1->initialPoint();
- point2 = curve_it1->finalPoint();
- point3 = curve_it1->finalPoint();
cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
if (cubic) {
- point1 = (*cubic)[1];
- if (shift_nodes && first) {
- point1 = (*cubic)[1] + initialMove;
- }
- point2 = (*cubic)[2];
- nCurve->curveto(point1, point2, point3);
+ nCurve->curveto((*cubic)[1] + last_move, (*cubic)[2], curve_it1->finalPoint());
} else {
- nCurve->lineto(point3);
+ nCurve->lineto(curve_it1->finalPoint());
}
+ last_move = Geom::Point(0, 0);
double length = curve_it1->length(0.001);
std::size_t splits = 0;
if (method == DM_SEGMENTS) {
@@ -212,15 +236,21 @@ void LPERoughen::doEffect(SPCurve *curve)
} else {
splits = ceil(length / max_segment_size);
}
- for (unsigned int t = splits; t >= 1; t--) {
- if (t == 1 && splits != 1) {
+ Geom::Curve const * original = nCurve->last_segment()->duplicate() ;
+ for (unsigned int t = 1; t <= splits; t++) {
+ if(t == splits && splits != 1){
continue;
}
- const SPCurve *tmp;
+ SPCurve const * tmp;
if (splits == 1) {
- tmp = jitter(nCurve->last_segment());
+ tmp = jitter(nCurve->last_segment(), prev, last_move);
} else {
- tmp = addNodesAndJitter(nCurve->last_segment(), 1. / t);
+ bool last = false;
+ if(t == splits-1){
+ last = true;
+ }
+ double time = Geom::nearest_time(original->pointAt((1. / (double)splits) * t), *nCurve->last_segment());
+ tmp = addNodesAndJitter(nCurve->last_segment(), prev, last_move, time, last);
}
if (nCurve->get_segment_count() > 1) {
nCurve->backspace();
@@ -231,12 +261,44 @@ void LPERoughen::doEffect(SPCurve *curve)
delete tmp;
}
++curve_it1;
- if(curve_it2 != curve_endit) {
- ++curve_it2;
- }
- first = false;
+ ++curve_it2;
}
if (path_it->closed()) {
+ if(handles == HM_SMOOTH && curve_it1 == curve_endit){
+ SPCurve *out = new SPCurve();
+ nCurve = nCurve->create_reverse();
+ Geom::CubicBezier const *cubic_start = dynamic_cast<Geom::CubicBezier const *>(nCurve->first_segment());
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment());
+ Geom::Point oposite = nCurve->first_segment()->pointAt(1.0/3.0);
+ if(cubic_start){
+ Geom::Ray ray((*cubic_start)[1], (*cubic_start)[0]);
+ double dist = Geom::distance((*cubic_start)[1], (*cubic_start)[0]);
+ oposite = Geom::Point::polar(ray.angle(),dist) + (*cubic_start)[0];
+ }
+ if(cubic){
+ out->moveto((*cubic)[0]);
+ out->curveto((*cubic)[1], oposite, (*cubic)[3]);
+ } else {
+ out->moveto(nCurve->last_segment()->initialPoint());
+ out->curveto(nCurve->last_segment()->initialPoint(), oposite, nCurve->last_segment()->finalPoint());
+ }
+ nCurve->backspace();
+ nCurve->append_continuous(out, 0.001);
+ nCurve = nCurve->create_reverse();
+ }
+ if(handles == HM_ALONG_NODES && curve_it1 == curve_endit){
+ SPCurve *out = new SPCurve();
+ nCurve = nCurve->create_reverse();
+ Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment());
+ if(cubic){
+ out->moveto((*cubic)[0]);
+ out->curveto((*cubic)[1], (*cubic)[2] - ((*cubic)[3] - nCurve->first_segment()->initialPoint()) , (*cubic)[3]);
+ nCurve->backspace();
+ nCurve->append_continuous(out, 0.001);
+ }
+ nCurve = nCurve->create_reverse();
+ }
+ nCurve->move_endpoints(nCurve->last_segment()->finalPoint(), nCurve->last_segment()->finalPoint());
nCurve->closepath_current();
}
curve->append(nCurve, false);
@@ -245,77 +307,211 @@ void LPERoughen::doEffect(SPCurve *curve)
}
}
-SPCurve *LPERoughen::addNodesAndJitter(const Geom::Curve *A, double t)
+SPCurve const * LPERoughen::addNodesAndJitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move, double t, bool last)
{
SPCurve *out = new SPCurve();
Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A);
- Geom::Point point1(0, 0);
- Geom::Point point2(0, 0);
- Geom::Point point3(0, 0);
+ double max_lenght = Geom::distance(A->initialPoint(),A->pointAt(t)) / 3.0;
+ Geom::Point point_a1(0, 0);
+ Geom::Point point_a2(0, 0);
+ Geom::Point point_a3(0, 0);
Geom::Point point_b1(0, 0);
Geom::Point point_b2(0, 0);
Geom::Point point_b3(0, 0);
if (shift_nodes) {
- point3 = randomize();
- point_b3 = randomize();
+ point_a3 = randomize(max_lenght, true);
+ if(last){
+ point_b3 = randomize(max_lenght, true);
+ }
}
- if (shift_node_handles) {
- point1 = randomize();
- point2 = randomize();
- point_b1 = randomize();
- point_b2 = randomize();
+ if (handles == HM_RAND || handles == HM_SMOOTH) {
+ point_a1 = randomize(max_lenght);
+ point_a2 = randomize(max_lenght);
+ point_b1 = randomize(max_lenght);
+ if(last){
+ point_b2 = randomize(max_lenght);
+ }
} else {
- point2 = point3;
- point_b1 = point3;
- point_b2 = point_b3;
+ point_a2 = point_a3;
+ point_b1 = point_a3;
+ if(last){
+ point_b2 = point_b3;
+ }
}
- if (cubic) {
- std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
- std::vector<Geom::Point> seg1 = div.first.controlPoints(),
- seg2 = div.second.controlPoints();
- out->moveto(seg1[0]);
- out->curveto(seg1[1] + point1, seg1[2] + point2, seg1[3] + point3);
- out->curveto(seg2[1] + point_b1, seg2[2], seg2[3]);
- } else if (shift_node_handles) {
- out->moveto(A->initialPoint());
- out->curveto(A->pointAt(t / 3) + point1, A->pointAt((t / 3) * 2) + point2,
- A->pointAt(t) + point3);
- out->curveto(A->pointAt(t + (t / 3)) + point_b1, A->pointAt(t + ((t / 3) * 2)),
- A->finalPoint());
- } else {
+ if(handles == HM_SMOOTH){
+ if(cubic) {
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
+ std::vector<Geom::Point> seg1 = div.first.controlPoints(),
+ seg2 = div.second.controlPoints();
+ Geom::Ray ray(seg1[3] + point_a3, seg2[1] + point_a3);
+ double lenght = max_lenght;
+ if(!fixed_displacement ){
+ lenght = Geom::distance(seg1[3] + point_a3, seg2[1] + point_a3);
+ }
+ point_b1 = seg1[3] + point_a3 + Geom::Point::polar(ray.angle() , lenght);
+ point_b2 = seg2[2];
+ point_b3 = seg2[3] + point_b3;
+ point_a3 = seg1[3] + point_a3;
+ ray.setPoints(prev,A->initialPoint());
+ point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght);
+ if(prev == Geom::Point(0,0)){
+ point_a1 = randomize(max_lenght);
+ }
+ if(last){
+ Geom::Path b2(point_b3);
+ b2.appendNew<Geom::LineSegment>(point_a3);
+ lenght = max_lenght;
+ ray.setPoints(point_b3, point_b2);
+ if(!fixed_displacement ){
+ lenght = Geom::distance(b2.pointAt(1.0/3.0), point_b3);
+ }
+ point_b2 = point_b3 + Geom::Point::polar(ray.angle() , lenght);
+ }
+ ray.setPoints(point_b1, point_a3);
+ point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_lenght);
+ if(last){
+ prev = point_b2;
+ } else {
+ prev = point_a2;
+ }
+ out->moveto(seg1[0]);
+ out->curveto(point_a1,point_a2,point_a3);
+ out->curveto(point_b1, point_b2, point_b3);
+ } else {
+ Geom::Ray ray(A->pointAt(t) + point_a3, A->pointAt(t + (t / 3)));
+ double lenght = max_lenght;
+ if(!fixed_displacement ){
+ lenght = Geom::distance(A->pointAt(t) + point_a3, A->pointAt(t + (t / 3)));
+ }
+ point_b1 = A->pointAt(t) + point_a3 + Geom::Point::polar(ray.angle() , lenght);
+ point_b2 = A->pointAt(t +((t / 3) * 2));
+ point_b3 = A->finalPoint() + point_b3;
+ point_a3 = A->pointAt(t) + point_a3;
+ ray.setPoints(prev,A->initialPoint());
+ point_a1 = A->initialPoint() + Geom::Point::polar(ray.angle(), max_lenght);
+ if(prev == Geom::Point(0,0)){
+ point_a1 = randomize(max_lenght);
+ }
+ if(last){
+ Geom::Path b2(point_b3);
+ b2.appendNew<Geom::LineSegment>(point_a3);
+ lenght = max_lenght;
+ ray.setPoints(point_b3, point_b2);
+ if(!fixed_displacement ){
+ lenght = Geom::distance(b2.pointAt(1.0/3.0), point_b3);
+ }
+ point_b2 = point_b3 + Geom::Point::polar(ray.angle() , lenght);
+ }
+ ray.setPoints(point_b1, point_a3);
+ point_a2 = point_a3 + Geom::Point::polar(ray.angle(), max_lenght);
+ if(last){
+ prev = point_b2;
+ } else {
+ prev = point_a2;
+ }
+ out->moveto(A->initialPoint());
+ out->curveto(point_a1,point_a2,point_a3);
+ out->curveto(point_b1, point_b2, point_b3);
+ }
+ } else if(handles == HM_RETRACT){
out->moveto(A->initialPoint());
- out->lineto(A->pointAt(t) + point3);
- out->lineto(A->finalPoint());
+ out->lineto(A->pointAt(t) + point_a3);
+ if(cubic && !last){
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
+ std::vector<Geom::Point> seg2 = div.second.controlPoints();
+ out->curveto(seg2[1], seg2[2], seg2[3]);
+ } else {
+ out->lineto(A->finalPoint() + point_b3);
+ }
+ } else if(handles == HM_ALONG_NODES){
+ if (cubic) {
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
+ std::vector<Geom::Point> seg1 = div.first.controlPoints(),
+ seg2 = div.second.controlPoints();
+ out->moveto(seg1[0]);
+ out->curveto(seg1[1] + last_move, seg1[2] + point_a3, seg1[3] + point_a3);
+ last_move = point_a3;
+ if(last){
+ last_move = point_b3;
+ }
+ out->curveto(seg2[1] + point_a3, seg2[2] + point_b3, seg2[3] + point_b3);
+ } else {
+ out->moveto(A->initialPoint());
+ out->lineto(A->pointAt(t) + point_a3);
+ out->lineto(A->finalPoint() + point_b3);
+ }
+ } else if(handles == HM_RAND) {
+ if (cubic) {
+ std::pair<Geom::CubicBezier, Geom::CubicBezier> div = cubic->subdivide(t);
+ std::vector<Geom::Point> seg1 = div.first.controlPoints(),
+ seg2 = div.second.controlPoints();
+ out->moveto(seg1[0]);
+ out->curveto(seg1[1] + point_a1, seg1[2] + point_a2 + point_a3, seg1[3] + point_a3);
+ out->curveto(seg2[1] + point_a3 + point_b1, seg2[2] + point_b2 + point_b3, seg2[3] + point_b3);
+ } else {
+ out->moveto(A->initialPoint());
+ out->lineto(A->pointAt(t) + point_a3);
+ out->lineto(A->finalPoint() + point_b3);
+ }
}
return out;
}
-SPCurve *LPERoughen::jitter(const Geom::Curve *A)
+SPCurve *LPERoughen::jitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move)
{
SPCurve *out = new SPCurve();
Geom::CubicBezier const *cubic = dynamic_cast<Geom::CubicBezier const *>(&*A);
- Geom::Point point1(0, 0);
- Geom::Point point2(0, 0);
- Geom::Point point3(0, 0);
+ double max_lenght = Geom::distance(A->initialPoint(),A->finalPoint()) / 3.0;
+ Geom::Point point_a1(0, 0);
+ Geom::Point point_a2(0, 0);
+ Geom::Point point_a3(0, 0);
if (shift_nodes) {
- point3 = randomize();
+ point_a3 = randomize(max_lenght, true);
}
- if (shift_node_handles) {
- point1 = randomize();
- point2 = randomize();
- } else {
- point2 = point3;
+ if (handles == HM_RAND || handles == HM_SMOOTH) {
+ point_a1 = randomize(max_lenght);
+ point_a2 = randomize(max_lenght);
}
- if (cubic) {
- out->moveto((*cubic)[0]);
- out->curveto((*cubic)[1] + point1, (*cubic)[2] + point2, (*cubic)[3] + point3);
- } else if (shift_node_handles) {
+ if(handles == HM_SMOOTH) {
+ if (cubic) {
+ Geom::Ray ray(prev,A->initialPoint());
+ point_a1 = Geom::Point::polar(ray.angle(), max_lenght);
+ if(prev == Geom::Point(0,0)){
+ point_a1 = A->pointAt(1.0/3.0) + randomize(max_lenght);
+ }
+ ray.setPoints((*cubic)[3] + point_a3, (*cubic)[2] + point_a3);
+ point_a2 = randomize(max_lenght, ray.angle());
+ prev = (*cubic)[2] + point_a2;
+ out->moveto((*cubic)[0]);
+ out->curveto((*cubic)[0] + point_a1, (*cubic)[2] + point_a2 + point_a3, (*cubic)[3] + point_a3);
+ } else {
+ Geom::Ray ray(prev,A->initialPoint());
+ point_a1 = Geom::Point::polar(ray.angle(), max_lenght);
+ if(prev==Geom::Point(0,0)){
+ point_a1 = A->pointAt(1.0/3.0) + randomize(max_lenght);
+ }
+ ray.setPoints(A->finalPoint() + point_a3, A->pointAt((1.0/3.0) * 2) + point_a3);
+ point_a2 = randomize(max_lenght, ray.angle());
+ prev = A->pointAt((1.0/3.0) * 2) + point_a2 + point_a3;
+ out->moveto(A->initialPoint());
+ out->curveto(A->initialPoint() + point_a1, A->pointAt((1.0/3.0) * 2) + point_a2 + point_a3, A->finalPoint() + point_a3);
+ }
+ } else if(handles == HM_RETRACT){
out->moveto(A->initialPoint());
- out->curveto(A->pointAt(0.3333) + point1, A->pointAt(0.6666) + point2,
- A->finalPoint() + point3);
- } else {
+ out->lineto(A->finalPoint() + point_a3);
+ } else if (handles == HM_ALONG_NODES) {
+ if(cubic){
+ out->moveto((*cubic)[0]);
+ out->curveto((*cubic)[1] + last_move, (*cubic)[2] + point_a3, (*cubic)[3] + point_a3);
+ last_move = point_a3;
+ } else {
+ out->moveto(A->initialPoint());
+ out->lineto(A->finalPoint() + point_a3);
+ }
+ } else if (handles == HM_RAND) {
out->moveto(A->initialPoint());
- out->lineto(A->finalPoint() + point3);
+ out->curveto(A->pointAt(0.3333) + point_a1, A->pointAt(0.6666) + point_a2 + point_a3,
+ A->finalPoint() + point_a3);
}
return out;
}
diff --git a/src/live_effects/lpe-roughen.h b/src/live_effects/lpe-roughen.h
index 2b285cd40..44a723c89 100644
--- a/src/live_effects/lpe-roughen.h
+++ b/src/live_effects/lpe-roughen.h
@@ -28,6 +28,15 @@ enum DivisionMethod {
DM_END
};
+enum HandlesMethod {
+ HM_ALONG_NODES,
+ HM_RAND,
+ HM_RETRACT,
+ HM_SMOOTH,
+ HM_END
+};
+
+
class LPERoughen : public Effect {
public:
@@ -36,10 +45,10 @@ public:
virtual void doEffect(SPCurve *curve);
virtual double sign(double randNumber);
- virtual Geom::Point randomize();
+ virtual Geom::Point randomize(double max_lenght, bool is_node = false);
virtual void doBeforeEffect(SPLPEItem const * lpeitem);
- virtual SPCurve *addNodesAndJitter(const Geom::Curve *A, double t);
- virtual SPCurve *jitter(const Geom::Curve *A);
+ virtual SPCurve const * addNodesAndJitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move, double t, bool last);
+ virtual SPCurve *jitter(Geom::Curve const * A, Geom::Point &prev, Geom::Point &last_move);
virtual Geom::Point tPoint(Geom::Point A, Geom::Point B, double t = 0.5);
virtual Gtk::Widget *newWidget();
@@ -50,9 +59,11 @@ private:
RandomParam displace_x;
RandomParam displace_y;
RandomParam global_randomize;
+ EnumParam<HandlesMethod> handles;
BoolParam shift_nodes;
- BoolParam shift_node_handles;
-
+ BoolParam fixed_displacement;
+ BoolParam spray_tool_friendly;
+ long seed;
LPERoughen(const LPERoughen &);
LPERoughen &operator=(const LPERoughen &);
diff --git a/src/live_effects/lpe-simplify.cpp b/src/live_effects/lpe-simplify.cpp
index 265192a17..f807bdc8d 100644
--- a/src/live_effects/lpe-simplify.cpp
+++ b/src/live_effects/lpe-simplify.cpp
@@ -28,8 +28,8 @@ namespace LivePathEffect {
LPESimplify::LPESimplify(LivePathEffectObject *lpeobject)
: Effect(lpeobject),
steps(_("Steps:"),_("Change number of simplify steps "), "steps", &wr, this,1),
- threshold(_("Roughly threshold:"), _("Roughly threshold:"), "threshold", &wr, this, 0.003),
- smooth_angles(_("Smooth angles:"), _("Max degree difference on handles to preform a smooth"), "smooth_angles", &wr, this, 20.),
+ threshold(_("Roughly threshold:"), _("Roughly threshold:"), "threshold", &wr, this, 0.002),
+ smooth_angles(_("Smooth angles:"), _("Max degree difference on handles to perform a smooth"), "smooth_angles", &wr, this, 0.),
helper_size(_("Helper size:"), _("Helper size"), "helper_size", &wr, this, 5),
simplify_individual_paths(_("Paths separately"), _("Simplifying paths (separately)"), "simplify_individual_paths", &wr, this, false,
"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")),
@@ -51,7 +51,7 @@ LPESimplify::LPESimplify(LivePathEffectObject *lpeobject)
steps.param_set_increments(1, 1);
steps.param_set_digits(0);
- smooth_angles.param_set_range(0.0, 365.0);
+ smooth_angles.param_set_range(0.0, 360.0);
smooth_angles.param_set_increments(10, 10);
smooth_angles.param_set_digits(2);
@@ -60,6 +60,7 @@ LPESimplify::LPESimplify(LivePathEffectObject *lpeobject)
helper_size.param_set_digits(2);
radius_helper_nodes = 6.0;
+ apply_to_clippath_and_mask = true;
}
LPESimplify::~LPESimplify() {}
@@ -71,10 +72,7 @@ LPESimplify::doBeforeEffect (SPLPEItem const* lpeitem)
hp.clear();
}
bbox = SP_ITEM(lpeitem)->visualBounds();
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
radius_helper_nodes = helper_size;
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
}
Gtk::Widget *
@@ -82,6 +80,7 @@ LPESimplify::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);
@@ -137,6 +136,7 @@ LPESimplify::doEffect(SPCurve *curve)
if(simplify_individual_paths) {
size = Geom::L2(Geom::bounds_fast(original_pathv)->dimensions());
}
+ size /= sp_lpe_item->i2doc_affine().descrim();
for (int unsigned i = 0; i < steps; i++) {
if ( simplify_just_coalesce ) {
pathliv->Coalesce(threshold * size);
@@ -197,13 +197,15 @@ LPESimplify::generateHelperPathAndSmooth(Geom::PathVector &result)
Geom::Point point_at2 = curve_it1->finalPoint();
Geom::Point point_at3 = curve_it1->finalPoint();
Geom::Point point_at4 = curve_it1->finalPoint();
+
+ if(start == Geom::Point(0,0)) {
+ start = point_at1;
+ }
+
if (cubic) {
point_at1 = (*cubic)[1];
point_at2 = (*cubic)[2];
}
- if(start == Geom::Point(0,0)) {
- start = point_at1;
- }
if(path_it->closed() && curve_it2 == curve_endit) {
point_at4 = start;
@@ -216,13 +218,13 @@ LPESimplify::generateHelperPathAndSmooth(Geom::PathVector &result)
}
Geom::Ray ray1(point_at2, point_at3);
Geom::Ray ray2(point_at3, point_at4);
- double angle1 = Geom::rad_to_deg(ray1.angle());
- double angle2 = Geom::rad_to_deg(ray2.angle());
- if((smooth_angles >= angle2 - angle1) && !are_near(point_at4,point_at3) && !are_near(point_at2,point_at3)) {
+ double angle1 = Geom::deg_from_rad(ray1.angle());
+ double angle2 = Geom::deg_from_rad(ray2.angle());
+ if((smooth_angles >= std::abs(angle2 - angle1)) && !are_near(point_at4,point_at3) && !are_near(point_at2,point_at3)) {
double dist = Geom::distance(point_at2,point_at3);
Geom::Angle angleFixed = ray2.angle();
angleFixed -= Geom::Angle::from_degrees(180.0);
- point_at2 = Geom::Point::polar(angleFixed,dist) + point_at3;
+ point_at2 = Geom::Point::polar(angleFixed, dist) + point_at3;
}
nCurve->curveto(point_at1, point_at2, curve_it1->finalPoint());
cubic = dynamic_cast<Geom::CubicBezier const *>(nCurve->last_segment());
diff --git a/src/live_effects/lpe-spiro.cpp b/src/live_effects/lpe-spiro.cpp
index eefd25c7d..0d42596b2 100644
--- a/src/live_effects/lpe-spiro.cpp
+++ b/src/live_effects/lpe-spiro.cpp
@@ -37,6 +37,10 @@ LPESpiro::~LPESpiro()
void
LPESpiro::doEffect(SPCurve * curve)
{
+ sp_spiro_do_effect(curve);
+}
+
+void sp_spiro_do_effect(SPCurve *curve){
using Geom::X;
using Geom::Y;
@@ -54,7 +58,7 @@ LPESpiro::doEffect(SPCurve * curve)
// start of path
{
- Geom::Point p = path_it->front().pointAt(0);
+ Geom::Point p = path_it->initialPoint();
path[ip].x = p[X];
path[ip].y = p[Y];
path[ip].ty = '{' ; // for closed paths, this is overwritten
@@ -64,17 +68,7 @@ LPESpiro::doEffect(SPCurve * curve)
// midpoints
Geom::Path::const_iterator curve_it1 = path_it->begin(); // incoming curve
Geom::Path::const_iterator curve_it2 = ++(path_it->begin()); // outgoing curve
-
Geom::Path::const_iterator curve_endit = path_it->end_default(); // this determines when the loop has to stop
- if (path_it->closed()) {
- // if the path is closed, maybe we have to stop a bit earlier because the closing line segment has zerolength.
- const Geom::Curve &closingline = path_it->back_closed(); // the closing line segment is always of type Geom::LineSegment.
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- // closingline.isDegenerate() did not work, because it only checks for *exact* zero length, which goes wrong for relative coordinates and rounding errors...
- // the closing line segment has zero-length. So stop before that one!
- curve_endit = path_it->end_open();
- }
- }
while ( curve_it2 != curve_endit )
{
diff --git a/src/live_effects/lpe-spiro.h b/src/live_effects/lpe-spiro.h
index edce42280..c8aba53d9 100644
--- a/src/live_effects/lpe-spiro.h
+++ b/src/live_effects/lpe-spiro.h
@@ -27,6 +27,8 @@ private:
LPESpiro& operator=(const LPESpiro&);
};
+void sp_spiro_do_effect(SPCurve *curve);
+
}; //namespace LivePathEffect
}; //namespace Inkscape
diff --git a/src/live_effects/lpe-taperstroke.cpp b/src/live_effects/lpe-taperstroke.cpp
index ef616f802..f2ddd4929 100644
--- a/src/live_effects/lpe-taperstroke.cpp
+++ b/src/live_effects/lpe-taperstroke.cpp
@@ -408,9 +408,8 @@ Piecewise<D2<SBasis> > stretch_along(Piecewise<D2<SBasis> > pwd2_in, Geom::Path
n = force_continuity(remove_short_cuts(n,.1));
int nbCopies = 0;
- double scaling = 1;
+ double scaling = (uskeleton.domain().extent() - toffset)/pattBndsX->extent();
nbCopies = 1;
- scaling = (uskeleton.domain().extent() - toffset)/pattBndsX->extent();
double pattWidth = pattBndsX->extent() * scaling;
diff --git a/src/live_effects/lpe-transform_2pts.cpp b/src/live_effects/lpe-transform_2pts.cpp
new file mode 100644
index 000000000..1cd59b7fa
--- /dev/null
+++ b/src/live_effects/lpe-transform_2pts.cpp
@@ -0,0 +1,461 @@
+/** \file
+ * LPE "Transform through 2 points" implementation
+ */
+
+/*
+ * Authors:
+ * Jabier Arraiza Cenoz<jabier.arraiza@marker.es>
+ *
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include <gtkmm.h>
+
+#include "live_effects/lpe-transform_2pts.h"
+#include "display/curve.h"
+#include <2geom/transforms.h>
+#include <2geom/pathvector.h>
+#include "sp-path.h"
+#include "ui/icon-names.h"
+#include "svg/svg.h"
+#include "verbs.h"
+// TODO due to internal breakage in glibmm headers, this must be last:
+#include <glibmm/i18n.h>
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+LPETransform2Pts::LPETransform2Pts(LivePathEffectObject *lpeobject) :
+ Effect(lpeobject),
+ elastic(_("Elastic"), _("Elastic transform mode"), "elastic", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")),
+ from_original_width(_("From original width"), _("From original width"), "from_original_width", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")),
+ lock_lenght(_("Lock length"), _("Lock length to current distance"), "lock_lenght", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")),
+ lock_angle(_("Lock angle"), _("Lock angle"), "lock_angle", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")),
+ flip_horizontal(_("Flip horizontal"), _("Flip horizontal"), "flip_horizontal", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")),
+ flip_vertical(_("Flip vertical"), _("Flip vertical"), "flip_vertical", &wr, this, false,"", INKSCAPE_ICON("on"), INKSCAPE_ICON("off")),
+ start(_("Start"), _("Start point"), "start", &wr, this, "Start point"),
+ end(_("End"), _("End point"), "end", &wr, this, "End point"),
+ strech(_("Stretch"), _("Stretch the result"), "strech", &wr, this, 1),
+ offset(_("Offset"), _("Offset from knots"), "offset", &wr, this, 0),
+ first_knot(_("First Knot"), _("First Knot"), "first_knot", &wr, this, 1),
+ last_knot(_("Last Knot"), _("Last Knot"), "last_knot", &wr, this, 1),
+ helper_size(_("Helper size:"), _("Rotation helper size"), "helper_size", &wr, this, 3),
+ from_original_width_toggler(false),
+ point_a(Geom::Point()),
+ point_b(Geom::Point()),
+ pathvector(),
+ append_path(false),
+ previous_angle(Geom::rad_from_deg(0)),
+ previous_start(Geom::Point()),
+ previous_lenght(-1)
+{
+
+ registerParameter(&first_knot);
+ registerParameter(&last_knot);
+ registerParameter(&helper_size);
+ registerParameter(&strech);
+ registerParameter(&offset);
+ registerParameter(&start);
+ registerParameter(&end);
+ registerParameter(&elastic);
+ registerParameter(&from_original_width);
+ registerParameter(&flip_vertical);
+ registerParameter(&flip_horizontal);
+ registerParameter(&lock_lenght);
+ registerParameter(&lock_angle);
+
+ first_knot.param_make_integer(true);
+ first_knot.param_overwrite_widget(true);
+ last_knot.param_make_integer(true);
+ last_knot.param_overwrite_widget(true);
+ helper_size.param_set_range(0, 999);
+ helper_size.param_set_increments(1, 1);
+ helper_size.param_set_digits(0);
+ offset.param_set_range(-999999.0, 999999.0);
+ offset.param_set_increments(1, 1);
+ offset.param_set_digits(2);
+ strech.param_set_range(0, 999.0);
+ strech.param_set_increments(0.01, 0.01);
+ strech.param_set_digits(4);
+ apply_to_clippath_and_mask = true;
+}
+
+LPETransform2Pts::~LPETransform2Pts()
+{
+}
+
+void
+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);
+ SPPath *sp_path = dynamic_cast<SPPath *>(splpeitem);
+ if (sp_path) {
+ pathvector = sp_path->get_original_curve()->get_pathvector();
+ }
+ if(!pathvector.empty()) {
+ point_a = pathvector.initialPoint();
+ point_b = pathvector.finalPoint();
+ if(are_near(point_a,point_b)) {
+ point_b = pathvector.back().finalCurve().initialPoint();
+ }
+ size_t nnodes = nodeCount(pathvector);
+ last_knot.param_set_value(nnodes);
+ }
+
+ previous_lenght = Geom::distance(point_a,point_b);
+ Geom::Ray transformed(point_a,point_b);
+ previous_angle = transformed.angle();
+ start.param_update_default(point_a);
+ start.param_set_default();
+ end.param_update_default(point_b);
+ end.param_set_default();
+}
+
+void
+LPETransform2Pts::doBeforeEffect (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);
+ SPPath *sp_path = dynamic_cast<SPPath *>(splpeitem);
+ if (sp_path) {
+ pathvector = sp_path->get_original_curve()->get_pathvector();
+ }
+ if(from_original_width_toggler != from_original_width) {
+ from_original_width_toggler = from_original_width;
+ reset();
+ }
+ if(!pathvector.empty() && !from_original_width) {
+ append_path = false;
+ point_a = pointAtNodeIndex(pathvector,(size_t)first_knot-1);
+ point_b = pointAtNodeIndex(pathvector,(size_t)last_knot-1);
+ size_t nnodes = nodeCount(pathvector);
+ first_knot.param_set_range(1, last_knot-1);
+ last_knot.param_set_range(first_knot+1, nnodes);
+ from_original_width.param_setValue(false);
+ } else {
+ first_knot.param_set_value(1);
+ last_knot.param_set_value(2);
+ first_knot.param_set_range(1,1);
+ last_knot.param_set_range(2,2);
+ from_original_width.param_setValue(true);
+ append_path = false;
+ }
+ if(lock_lenght && !lock_angle && previous_lenght != -1) {
+ Geom::Ray transformed((Geom::Point)start,(Geom::Point)end);
+ if(previous_start == start || previous_angle == Geom::rad_from_deg(0)) {
+ previous_angle = transformed.angle();
+ }
+ } else if(lock_angle && !lock_lenght && previous_angle != Geom::rad_from_deg(0)) {
+ if(previous_start == start){
+ previous_lenght = Geom::distance((Geom::Point)start, (Geom::Point)end);
+ }
+ }
+ if(lock_lenght || lock_angle ) {
+ Geom::Point end_point = Geom::Point::polar(previous_angle, previous_lenght) + (Geom::Point)start;
+ end.param_setValue(end_point);
+ }
+ Geom::Ray transformed((Geom::Point)start,(Geom::Point)end);
+ previous_angle = transformed.angle();
+ previous_lenght = Geom::distance((Geom::Point)start, (Geom::Point)end);
+ previous_start = start;
+}
+
+void
+LPETransform2Pts::updateIndex()
+{
+ SPLPEItem * splpeitem = const_cast<SPLPEItem *>(sp_lpe_item);
+ SPPath *sp_path = dynamic_cast<SPPath *>(splpeitem);
+ if (sp_path) {
+ pathvector = sp_path->get_original_curve()->get_pathvector();
+ }
+ if(pathvector.empty()) {
+ return;
+ }
+ if(!from_original_width) {
+ point_a = pointAtNodeIndex(pathvector,(size_t)first_knot-1);
+ point_b = pointAtNodeIndex(pathvector,(size_t)last_knot-1);
+ start.param_update_default(point_a);
+ start.param_set_default();
+ end.param_update_default(point_b);
+ end.param_set_default();
+ start.param_update_default(point_a);
+ end.param_update_default(point_b);
+ start.param_set_default();
+ end.param_set_default();
+ }
+ DocumentUndo::done(getSPDoc(), SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change index of knot"));
+}
+//todo migrate to PathVector class?
+size_t
+LPETransform2Pts::nodeCount(Geom::PathVector pathvector) const
+{
+ size_t n = 0;
+ for (Geom::PathVector::iterator it = pathvector.begin(); it != pathvector.end(); ++it) {
+ n += it->size_closed();
+ }
+ return n;
+}
+//todo migrate to PathVector class?
+Geom::Point
+LPETransform2Pts::pointAtNodeIndex(Geom::PathVector pathvector, size_t index) const
+{
+ size_t n = 0;
+ for (Geom::PathVector::iterator pv_it = pathvector.begin(); pv_it != pathvector.end(); ++pv_it) {
+ for (Geom::Path::iterator curve_it = pv_it->begin(); curve_it != pv_it->end_closed(); ++curve_it) {
+ if(index == n) {
+ return curve_it->initialPoint();
+ }
+ n++;
+ }
+ }
+ return Geom::Point();
+}
+//todo migrate to PathVector class? Not used
+Geom::Path
+LPETransform2Pts::pathAtNodeIndex(Geom::PathVector pathvector, size_t index) const
+{
+ size_t n = 0;
+ for (Geom::PathVector::iterator pv_it = pathvector.begin(); pv_it != pathvector.end(); ++pv_it) {
+ for (Geom::Path::iterator curve_it = pv_it->begin(); curve_it != pv_it->end_closed(); ++curve_it) {
+ if(index == n) {
+ return *pv_it;
+ }
+ n++;
+ }
+ }
+ return Geom::Path();
+}
+
+
+void
+LPETransform2Pts::reset()
+{
+ point_a = Geom::Point(boundingbox_X.min(), boundingbox_Y.middle());
+ point_b = Geom::Point(boundingbox_X.max(), boundingbox_Y.middle());
+ if(!pathvector.empty() && !from_original_width) {
+ size_t nnodes = nodeCount(pathvector);
+ first_knot.param_set_range(1, last_knot-1);
+ last_knot.param_set_range(first_knot+1, nnodes);
+ first_knot.param_set_value(1);
+ last_knot.param_set_value(nnodes);
+ point_a = pathvector.initialPoint();
+ point_b = pathvector.finalPoint();
+ } else {
+ first_knot.param_set_value(1);
+ last_knot.param_set_value(2);
+ }
+ Geom::Ray transformed(point_a, point_b);
+ previous_angle = transformed.angle();
+ previous_lenght = Geom::distance(point_a, point_b);
+ start.param_update_default(point_a);
+ end.param_update_default(point_b);
+ start.param_set_default();
+ end.param_set_default();
+}
+
+Gtk::Widget *LPETransform2Pts::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(6);
+
+ 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::HBox * button3 = Gtk::manage(new Gtk::HBox(true,0));
+ Gtk::HBox * button4 = Gtk::manage(new Gtk::HBox(true,0));
+ 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 (param->param_key == "first_knot" || param->param_key == "last_knot") {
+ Inkscape::UI::Widget::Scalar *registered_widget = Gtk::manage(dynamic_cast<Inkscape::UI::Widget::Scalar *>(widg));
+ registered_widget->signal_value_changed().connect(sigc::mem_fun(*this, &LPETransform2Pts::updateIndex));
+ widg = registered_widget;
+ if (widg) {
+ Gtk::HBox *hbox_scalar = dynamic_cast<Gtk::HBox *>(widg);
+ std::vector<Gtk::Widget *> child_list = hbox_scalar->get_children();
+ Gtk::Entry *entry_widget = dynamic_cast<Gtk::Entry *>(child_list[1]);
+ entry_widget->set_width_chars(3);
+ vbox->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ } else if (param->param_key == "from_original_width" || param->param_key == "elastic") {
+ Glib::ustring * tip = param->param_getTooltip();
+ if (widg) {
+ button1->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ } else if (param->param_key == "flip_horizontal" || param->param_key == "flip_vertical") {
+ Glib::ustring * tip = param->param_getTooltip();
+ if (widg) {
+ button2->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ } else if (param->param_key == "lock_angle" || param->param_key == "lock_lenght") {
+ Glib::ustring * tip = param->param_getTooltip();
+ if (widg) {
+ button3->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ } else if (widg) {
+ vbox->pack_start(*widg, true, true, 2);
+ if (tip) {
+ widg->set_tooltip_text(*tip);
+ } else {
+ widg->set_tooltip_text("");
+ widg->set_has_tooltip(false);
+ }
+ }
+ }
+
+ ++it;
+ }
+ Gtk::Button *reset = Gtk::manage(new Gtk::Button(Glib::ustring(_("Reset"))));
+ reset->signal_clicked().connect(sigc::mem_fun(*this, &LPETransform2Pts::reset));
+ button4->pack_start(*reset, true, true, 2);
+ vbox->pack_start(*button1, true, true, 2);
+ vbox->pack_start(*button2, true, true, 2);
+ vbox->pack_start(*button3, true, true, 2);
+ vbox->pack_start(*button4, true, true, 2);
+ return dynamic_cast<Gtk::Widget *>(vbox);
+}
+
+Geom::Piecewise<Geom::D2<Geom::SBasis> >
+LPETransform2Pts::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in)
+{
+ Geom::Piecewise<Geom::D2<Geom::SBasis> > output;
+ double sca = Geom::distance((Geom::Point)start,(Geom::Point)end)/Geom::distance(point_a,point_b);
+ Geom::Ray original(point_a,point_b);
+ Geom::Ray transformed((Geom::Point)start,(Geom::Point)end);
+ double rot = transformed.angle() - original.angle();
+ Geom::Path helper;
+ helper.start(point_a);
+ helper.appendNew<Geom::LineSegment>(point_b);
+ Geom::Affine m;
+ Geom::Angle original_angle = original.angle();
+ if(flip_horizontal && flip_vertical){
+ m *= Geom::Rotate(-original_angle);
+ m *= Geom::Scale(-1,-1);
+ m *= Geom::Rotate(original_angle);
+ } else if(flip_vertical){
+ m *= Geom::Rotate(-original_angle);
+ m *= Geom::Scale(1,-1);
+ m *= Geom::Rotate(original_angle);
+ } else if(flip_horizontal){
+ m *= Geom::Rotate(-original_angle);
+ m *= Geom::Scale(-1,1);
+ m *= Geom::Rotate(original_angle);
+ }
+ if(strech != 1){
+ m *= Geom::Rotate(-original_angle);
+ m *= Geom::Scale(1,strech);
+ m *= Geom::Rotate(original_angle);
+ }
+ if(elastic) {
+ m *= Geom::Rotate(-original_angle);
+ if(sca > 1){
+ m *= Geom::Scale(sca, 1.0);
+ } else {
+ m *= Geom::Scale(sca, 1.0-((1.0-sca)/2.0));
+ }
+ m *= Geom::Rotate(transformed.angle());
+ } else {
+ m *= Geom::Scale(sca);
+ m *= Geom::Rotate(rot);
+ }
+ helper *= m;
+ Geom::Point trans = (Geom::Point)start - helper.initialPoint();
+ if(flip_horizontal){
+ trans = (Geom::Point)end - helper.initialPoint();
+ }
+ if(offset != 0){
+ trans = Geom::Point::polar(transformed.angle() + Geom::rad_from_deg(-90),offset) + trans;
+ }
+ m *= Geom::Translate(trans);
+
+ output.concat(pwd2_in * m);
+
+ return output;
+}
+
+void
+LPETransform2Pts::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geom::PathVector> &hp_vec)
+{
+ using namespace Geom;
+ hp_vec.clear();
+ Geom::Path hp;
+ hp.start((Geom::Point)start);
+ hp.appendNew<Geom::LineSegment>((Geom::Point)end);
+ Geom::PathVector pathv;
+ pathv.push_back(hp);
+ double r = helper_size*.1;
+ if(lock_lenght || lock_angle ) {
+ char const * svgd;
+ svgd = "M -5.39,8.78 -9.13,5.29 -10.38,10.28 Z M -7.22,7.07 -3.43,3.37 m -1.95,-12.16 -3.74,3.5 -1.26,-5 z m -1.83,1.71 3.78,3.7 M 5.24,8.78 8.98,5.29 10.24,10.28 Z M 7.07,7.07 3.29,3.37 M 5.24,-8.78 l 3.74,3.5 1.26,-5 z M 7.07,-7.07 3.29,-3.37";
+ PathVector pathv_move = sp_svg_read_pathv(svgd);
+ pathv_move *= Affine(r,0,0,r,0,0) * Translate(Geom::Point(start));
+ hp_vec.push_back(pathv_move);
+ }
+ if(!lock_angle && lock_lenght) {
+ char const * svgd;
+ svgd = "m 7.07,7.07 c -3.9,3.91 -10.24,3.91 -14.14,0 -3.91,-3.9 -3.91,-10.24 0,-14.14 3.9,-3.91 10.24,-3.91 14.14,0 l -2.83,-4.24 -0.7,2.12";
+ PathVector pathv_turn = sp_svg_read_pathv(svgd);
+ pathv_turn *= Geom::Rotate(previous_angle);
+ pathv_turn *= Affine(r,0,0,r,0,0) * Translate(Geom::Point(end));
+ hp_vec.push_back(pathv_turn);
+ }
+ hp_vec.push_back(pathv);
+}
+
+
+/* ######################## */
+
+} //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/lpe-transform_2pts.h b/src/live_effects/lpe-transform_2pts.h
new file mode 100644
index 000000000..c20d56206
--- /dev/null
+++ b/src/live_effects/lpe-transform_2pts.h
@@ -0,0 +1,91 @@
+#ifndef INKSCAPE_LPE_TRANSFORM_2PTS_H
+#define INKSCAPE_LPE_TRANSFORM_2PTS_H
+
+/** \file
+ * LPE "Transform through 2 points" implementation
+ */
+
+/*
+ * Authors:
+ *
+ *
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "live_effects/effect.h"
+#include "live_effects/lpegroupbbox.h"
+#include "live_effects/parameter/parameter.h"
+#include "live_effects/parameter/togglebutton.h"
+#include "live_effects/parameter/point.h"
+
+namespace Inkscape {
+namespace LivePathEffect {
+
+class LPETransform2Pts : public Effect, GroupBBoxEffect {
+public:
+ LPETransform2Pts(LivePathEffectObject *lpeobject);
+ virtual ~LPETransform2Pts();
+
+ virtual void doOnApply (SPLPEItem const* lpeitem);
+
+ virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in);
+
+ virtual void doBeforeEffect (SPLPEItem const* lpeitem);
+
+ virtual Gtk::Widget *newWidget();
+
+ void updateIndex();
+
+ size_t nodeCount(Geom::PathVector pathvector) const;
+
+ Geom::Point pointAtNodeIndex(Geom::PathVector pathvector, size_t index) const;
+
+ Geom::Path pathAtNodeIndex(Geom::PathVector pathvector, size_t index) const;
+
+ void reset();
+
+protected:
+ virtual void addCanvasIndicators(SPLPEItem const *lpeitem, std::vector<Geom::PathVector> &hp_vec);
+
+private:
+ ToggleButtonParam elastic;
+ ToggleButtonParam from_original_width;
+ ToggleButtonParam lock_lenght;
+ ToggleButtonParam lock_angle;
+ ToggleButtonParam flip_horizontal;
+ ToggleButtonParam flip_vertical;
+ PointParam start;
+ PointParam end;
+ ScalarParam strech;
+ ScalarParam offset;
+ ScalarParam first_knot;
+ ScalarParam last_knot;
+ ScalarParam helper_size;
+ bool from_original_width_toggler;
+ Geom::Point point_a;
+ Geom::Point point_b;
+ Geom::PathVector pathvector;
+ bool append_path;
+ Geom::Angle previous_angle;
+ Geom::Point previous_start;
+ double previous_lenght;
+ LPETransform2Pts(const LPETransform2Pts&);
+ LPETransform2Pts& operator=(const LPETransform2Pts&);
+};
+
+} //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-vonkoch.cpp b/src/live_effects/lpe-vonkoch.cpp
index 7b424e019..7eda7446e 100644
--- a/src/live_effects/lpe-vonkoch.cpp
+++ b/src/live_effects/lpe-vonkoch.cpp
@@ -64,7 +64,7 @@ LPEVonKoch::LPEVonKoch(LivePathEffectObject *lpeobject) :
registerParameter( dynamic_cast<Parameter *>(&drawall) );
registerParameter( dynamic_cast<Parameter *>(&maxComplexity) );
//registerParameter( dynamic_cast<Parameter *>(&draw_boxes) );
-
+ apply_to_clippath_and_mask = true;
nbgenerations.param_make_integer();
nbgenerations.param_set_range(0, Geom::infinity());
maxComplexity.param_make_integer();
@@ -262,9 +262,6 @@ LPEVonKoch::doBeforeEffect (SPLPEItem const* lpeitem)
tmp_pathv.push_back(tmp_path);
ref_path.set_new_value(tmp_pathv,true);
}
- SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem);
- item->apply_to_clippath(item);
- item->apply_to_mask(item);
}
diff --git a/src/live_effects/parameter/bool.cpp b/src/live_effects/parameter/bool.cpp
index c1e8f8a7b..9ecadbdeb 100644
--- a/src/live_effects/parameter/bool.cpp
+++ b/src/live_effects/parameter/bool.cpp
@@ -21,8 +21,8 @@ namespace LivePathEffect {
BoolParam::BoolParam( const Glib::ustring& label, const Glib::ustring& tip,
const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
- Effect* effect, bool default_value )
- : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value)
+ Effect* effect, bool default_value , bool no_widget)
+ : Parameter(label, tip, key, wr, effect), value(default_value), defvalue(default_value), hide_widget(no_widget)
{
}
@@ -53,20 +53,24 @@ BoolParam::param_getSVGValue() const
Gtk::Widget *
BoolParam::param_newWidget()
{
- Inkscape::UI::Widget::RegisteredCheckButton * checkwdg = Gtk::manage(
- new Inkscape::UI::Widget::RegisteredCheckButton( param_label,
- param_tooltip,
- param_key,
- *param_wr,
- false,
- param_effect->getRepr(),
- param_effect->getSPDoc()) );
+ if(!hide_widget){
+ Inkscape::UI::Widget::RegisteredCheckButton * checkwdg = Gtk::manage(
+ new Inkscape::UI::Widget::RegisteredCheckButton( param_label,
+ param_tooltip,
+ param_key,
+ *param_wr,
+ false,
+ param_effect->getRepr(),
+ param_effect->getSPDoc()) );
- checkwdg->setActive(value);
- checkwdg->setProgrammatically = false;
- checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change bool parameter"));
+ checkwdg->setActive(value);
+ checkwdg->setProgrammatically = false;
+ checkwdg->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change bool parameter"));
- return dynamic_cast<Gtk::Widget *> (checkwdg);
+ return dynamic_cast<Gtk::Widget *> (checkwdg);
+ } else {
+ return NULL;
+ }
}
void
diff --git a/src/live_effects/parameter/bool.h b/src/live_effects/parameter/bool.h
index b45eeb0b3..403dd0b87 100644
--- a/src/live_effects/parameter/bool.h
+++ b/src/live_effects/parameter/bool.h
@@ -25,7 +25,8 @@ public:
const Glib::ustring& key,
Inkscape::UI::Widget::Registry* wr,
Effect* effect,
- bool default_value = false);
+ bool default_value = false,
+ bool no_widget = false);
virtual ~BoolParam();
virtual Gtk::Widget * param_newWidget();
@@ -46,6 +47,7 @@ private:
bool value;
bool defvalue;
+ bool hide_widget;
};
diff --git a/src/live_effects/parameter/filletchamferpointarray.cpp b/src/live_effects/parameter/filletchamferpointarray.cpp
index b089213fd..117d57460 100644
--- a/src/live_effects/parameter/filletchamferpointarray.cpp
+++ b/src/live_effects/parameter/filletchamferpointarray.cpp
@@ -159,9 +159,8 @@ void FilletChamferPointArrayParam::recalculate_controlpoints_for_new_pwd2(
//todo: if the path remove some nodes whith the result of a straight
//line but with handles, the node inserted into dont fire the knot
// because is not handle as cusp node by get_nodetype function
- bool this_is_line = true;
bool next_is_line = is_straight_curve(*curve_it1);
- this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
+ bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1);
if (this_is_line || next_is_line) {
nodetype = NODE_CUSP;
@@ -307,9 +306,8 @@ void FilletChamferPointArrayParam::recalculate_knots(
nodetype = NODE_NONE;
}
} else {
- bool this_is_line = true;
bool next_is_line = is_straight_curve(*curve_it1);
- this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
+ bool this_is_line = is_straight_curve((*path_it)[counterCurves - 1]);
nodetype = get_nodetype((*path_it)[counterCurves - 1], *curve_it1);
if (this_is_line || next_is_line) {
nodetype = NODE_CUSP;
@@ -394,7 +392,7 @@ void FilletChamferPointArrayParam::updateCanvasIndicators()
Geom::PathVector pathv = sp_svg_read_pathv(svgd);
Geom::Affine aff = Geom::Affine();
aff *= Geom::Scale(helper_size);
- aff *= Geom::Rotate(ray1.angle() - deg_to_rad(270));
+ aff *= Geom::Rotate(ray1.angle() - rad_from_deg(270));
aff *= Geom::Translate(last_pwd2[i].valueAt(Xvalue));
pathv *= aff;
hp.push_back(pathv[0]);
@@ -467,12 +465,12 @@ double FilletChamferPointArrayParam::len_to_rad(int index, double len)
Geom::Point endArcPoint = B->toSBasis().valueAt(times[2]);
Curve *knotCurve1 = A->portion(times[0], times[1]);
Curve *knotCurve2 = B->portion(times[2], 1);
- Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve1);
+ Geom::CubicBezier const *cubic1 = dynamic_cast<Geom::CubicBezier const *>(knotCurve1);
Ray ray1(startArcPoint, A->finalPoint());
if (cubic1) {
ray1.setPoints((*cubic1)[2], startArcPoint);
}
- Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*knotCurve2);
+ Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(knotCurve2);
Ray ray2(B->initialPoint(), endArcPoint);
if (cubic2) {
ray2.setPoints(endArcPoint, (*cubic2)[1]);
diff --git a/src/live_effects/parameter/originalpatharray.cpp b/src/live_effects/parameter/originalpatharray.cpp
index 78e061e66..7e3a6f5fe 100644
--- a/src/live_effects/parameter/originalpatharray.cpp
+++ b/src/live_effects/parameter/originalpatharray.cpp
@@ -215,7 +215,7 @@ void OriginalPathArrayParam::on_up_button_click()
int i = -1;
std::vector<PathAndDirection*>::iterator piter = _vector.begin();
- for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); piter = iter, i++, iter++) {
+ for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); piter = iter, i++, ++iter) {
if (*iter == row[_model->_colObject]) {
_vector.erase(iter);
_vector.insert(piter, row[_model->_colObject]);
@@ -241,11 +241,11 @@ void OriginalPathArrayParam::on_down_button_click()
Gtk::TreeModel::Row row = *iter;
int i = 0;
- for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); i++, iter++) {
+ for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); i++, ++iter) {
if (*iter == row[_model->_colObject]) {
std::vector<PathAndDirection*>::iterator niter = _vector.erase(iter);
if (niter != _vector.end()) {
- niter++;
+ ++niter;
i++;
}
_vector.insert(niter, row[_model->_colObject]);
@@ -295,7 +295,7 @@ OriginalPathArrayParam::on_link_button_click()
Inkscape::SVGOStringStream os;
bool foundOne = false;
- for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); iter++) {
+ for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); ++iter) {
if (foundOne) {
os << "|";
} else {
@@ -330,7 +330,7 @@ void OriginalPathArrayParam::unlink(PathAndDirection* to)
void OriginalPathArrayParam::remove_link(PathAndDirection* to)
{
unlink(to);
- for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); iter++) {
+ for (std::vector<PathAndDirection*>::iterator iter = _vector.begin(); iter != _vector.end(); ++iter) {
if (*iter == to) {
PathAndDirection *w = *iter;
_vector.erase(iter);
@@ -455,7 +455,7 @@ gchar * OriginalPathArrayParam::param_getSVGValue() const
{
Inkscape::SVGOStringStream os;
bool foundOne = false;
- for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); iter++) {
+ for (std::vector<PathAndDirection*>::const_iterator iter = _vector.begin(); iter != _vector.end(); ++iter) {
if (foundOne) {
os << "|";
} else {
diff --git a/src/live_effects/parameter/parameter.cpp b/src/live_effects/parameter/parameter.cpp
index 527bc06fe..d4e213948 100644
--- a/src/live_effects/parameter/parameter.cpp
+++ b/src/live_effects/parameter/parameter.cpp
@@ -54,7 +54,7 @@ void Parameter::write_to_SVG(void)
*/
ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip,
const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
- Effect* effect, gdouble default_value)
+ Effect* effect, gdouble default_value, bool no_widget)
: Parameter(label, tip, key, wr, effect),
value(default_value),
min(-SCALARPARAM_G_MAXDOUBLE),
@@ -64,7 +64,9 @@ ScalarParam::ScalarParam( const Glib::ustring& label, const Glib::ustring& tip,
digits(2),
inc_step(0.1),
inc_page(1),
- add_slider(false)
+ add_slider(false),
+ overwrite_widget(false),
+ hide_widget(no_widget)
{
}
@@ -143,24 +145,34 @@ ScalarParam::param_make_integer(bool yes)
inc_page = 10;
}
+void
+ScalarParam::param_overwrite_widget(bool overwrite_widget)
+{
+ this->overwrite_widget = overwrite_widget;
+}
+
Gtk::Widget *
ScalarParam::param_newWidget()
{
- Inkscape::UI::Widget::RegisteredScalar *rsu = Gtk::manage( new Inkscape::UI::Widget::RegisteredScalar(
- param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) );
-
- rsu->setValue(value);
- rsu->setDigits(digits);
- rsu->setIncrements(inc_step, inc_page);
- rsu->setRange(min, max);
- rsu->setProgrammatically = false;
- if (add_slider) {
- rsu->addSlider();
+ if(!hide_widget){
+ Inkscape::UI::Widget::RegisteredScalar *rsu = Gtk::manage( new Inkscape::UI::Widget::RegisteredScalar(
+ param_label, param_tooltip, param_key, *param_wr, param_effect->getRepr(), param_effect->getSPDoc() ) );
+
+ rsu->setValue(value);
+ rsu->setDigits(digits);
+ rsu->setIncrements(inc_step, inc_page);
+ rsu->setRange(min, max);
+ rsu->setProgrammatically = false;
+ if (add_slider) {
+ rsu->addSlider();
+ }
+ if(!overwrite_widget){
+ rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));
+ }
+ return dynamic_cast<Gtk::Widget *> (rsu);
+ } else {
+ return NULL;
}
-
- rsu->set_undo_parameters(SP_VERB_DIALOG_LIVE_PATH_EFFECT, _("Change scalar parameter"));
-
- return dynamic_cast<Gtk::Widget *> (rsu);
}
void
diff --git a/src/live_effects/parameter/parameter.h b/src/live_effects/parameter/parameter.h
index cc2c4f3d6..0ef28650a 100644
--- a/src/live_effects/parameter/parameter.h
+++ b/src/live_effects/parameter/parameter.h
@@ -102,7 +102,8 @@ public:
const Glib::ustring& key,
Inkscape::UI::Widget::Registry* wr,
Effect* effect,
- gdouble default_value = 1.0);
+ gdouble default_value = 1.0,
+ bool no_widget = false);
virtual ~ScalarParam();
virtual bool param_readSVGValue(const gchar * strvalue);
@@ -117,6 +118,7 @@ public:
void addSlider(bool add_slider_widget) { add_slider = add_slider_widget; };
+ void param_overwrite_widget(bool overwrite_widget);
virtual Gtk::Widget * param_newWidget();
inline operator gdouble() const { return value; };
@@ -131,6 +133,8 @@ protected:
double inc_step;
double inc_page;
bool add_slider;
+ bool overwrite_widget;
+ bool hide_widget;
private:
ScalarParam(const ScalarParam&);
diff --git a/src/live_effects/parameter/point.cpp b/src/live_effects/parameter/point.cpp
index 4c4d2cd9c..ca3471b29 100644
--- a/src/live_effects/parameter/point.cpp
+++ b/src/live_effects/parameter/point.cpp
@@ -25,9 +25,11 @@ namespace LivePathEffect {
PointParam::PointParam( const Glib::ustring& label, const Glib::ustring& tip,
const Glib::ustring& key, Inkscape::UI::Widget::Registry* wr,
- Effect* effect, const gchar *htip, Geom::Point default_value)
+ Effect* effect, const gchar *htip, Geom::Point default_value,
+ bool live_update )
: Parameter(label, tip, key, wr, effect),
defvalue(default_value),
+ liveupdate(live_update),
knoth(NULL)
{
knot_shape = SP_KNOT_SHAPE_DIAMOND;
@@ -48,6 +50,12 @@ PointParam::param_set_default()
param_setValue(defvalue,true);
}
+void
+PointParam::param_set_liveupdate( bool live_update)
+{
+ liveupdate = live_update;
+}
+
Geom::Point
PointParam::param_get_default() const{
return defvalue;
@@ -70,7 +78,7 @@ PointParam::param_setValue(Geom::Point newpoint, bool write)
param_write_to_repr(str);
g_free(str);
}
- if(knoth){
+ if(knoth && liveupdate){
knoth->update_knots();
}
}
@@ -166,9 +174,9 @@ PointParamKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &or
s = A;
}
}
- pparam->param_setValue(s, true);
+ pparam->param_setValue(s, this->pparam->liveupdate);
SPLPEItem * splpeitem = dynamic_cast<SPLPEItem *>(item);
- if(splpeitem){
+ if(splpeitem && this->pparam->liveupdate){
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 471fbc993..4329e0bcd 100644
--- a/src/live_effects/parameter/point.h
+++ b/src/live_effects/parameter/point.h
@@ -29,8 +29,9 @@ public:
const Glib::ustring& key,
Inkscape::UI::Widget::Registry* wr,
Effect* effect,
- const gchar *handle_tip = NULL,
- Geom::Point default_value = Geom::Point(0,0) ); // tip for automatically associated on-canvas handle
+ const gchar *handle_tip = NULL,// tip for automatically associated on-canvas handle
+ Geom::Point default_value = Geom::Point(0,0),
+ bool live_update = true );
virtual ~PointParam();
virtual Gtk::Widget * param_newWidget();
@@ -41,6 +42,7 @@ public:
void param_setValue(Geom::Point newpoint, bool write = false);
void param_set_default();
Geom::Point param_get_default() const;
+ void param_set_liveupdate(bool live_update);
void param_update_default(Geom::Point newpoint);
virtual void param_transform_multiply(Geom::Affine const& /*postmul*/, bool /*set*/);
@@ -54,6 +56,7 @@ private:
PointParam(const PointParam&);
PointParam& operator=(const PointParam&);
Geom::Point defvalue;
+ bool liveupdate;
KnotHolder *knoth;
SPKnotShapeType knot_shape;
SPKnotModeType knot_mode;
diff --git a/src/live_effects/parameter/togglebutton.cpp b/src/live_effects/parameter/togglebutton.cpp
index c5da8b858..47a8b5615 100644
--- a/src/live_effects/parameter/togglebutton.cpp
+++ b/src/live_effects/parameter/togglebutton.cpp
@@ -119,6 +119,10 @@ ToggleButtonParam::param_newWidget()
void
ToggleButtonParam::refresh_button()
{
+ if (!_toggled_connection.connected()) {
+ return;
+ }
+
if(!checkwdg){
return;
}
diff --git a/src/live_effects/spiro-converters.cpp b/src/live_effects/spiro-converters.cpp
index f116d5256..ee214704c 100644
--- a/src/live_effects/spiro-converters.cpp
+++ b/src/live_effects/spiro-converters.cpp
@@ -21,43 +21,49 @@
namespace Spiro {
void
-ConverterSPCurve::moveto(double x, double y, bool is_open)
+ConverterSPCurve::moveto(double x, double y)
{
if ( IS_FINITE(x) && IS_FINITE(y) ) {
_curve.moveto(x, y);
- if (!is_open) {
- _curve.closepath();
- }
} else {
SPIRO_G_MESSAGE("Spiro: moveto not finite");
}
}
void
-ConverterSPCurve::lineto(double x, double y)
+ConverterSPCurve::lineto(double x, double y, bool close_last)
{
if ( IS_FINITE(x) && IS_FINITE(y) ) {
_curve.lineto(x, y);
+ if (close_last) {
+ _curve.closepath();
+ }
} else {
SPIRO_G_MESSAGE("Spiro: lineto not finite");
}
}
void
-ConverterSPCurve::quadto(double xm, double ym, double x3, double y3)
+ConverterSPCurve::quadto(double xm, double ym, double x3, double y3, bool close_last)
{
if ( IS_FINITE(xm) && IS_FINITE(ym) && IS_FINITE(x3) && IS_FINITE(y3) ) {
_curve.quadto(xm, ym, x3, y3);
+ if (close_last) {
+ _curve.closepath();
+ }
} else {
SPIRO_G_MESSAGE("Spiro: quadto not finite");
}
}
void
-ConverterSPCurve::curveto(double x1, double y1, double x2, double y2, double x3, double y3)
+ConverterSPCurve::curveto(double x1, double y1, double x2, double y2, double x3, double y3, bool close_last)
{
if ( IS_FINITE(x1) && IS_FINITE(y1) && IS_FINITE(x2) && IS_FINITE(y2) ) {
_curve.curveto(x1, y1, x2, y2, x3, y3);
+ if (close_last) {
+ _curve.closepath();
+ }
} else {
SPIRO_G_MESSAGE("Spiro: curveto not finite");
}
@@ -71,41 +77,43 @@ ConverterPath::ConverterPath(Geom::Path &path)
}
void
-ConverterPath::moveto(double x, double y, bool is_open)
+ConverterPath::moveto(double x, double y)
{
if ( IS_FINITE(x) && IS_FINITE(y) ) {
_path.start(Geom::Point(x, y));
- _path.close(!is_open);
} else {
SPIRO_G_MESSAGE("spiro moveto not finite");
}
}
void
-ConverterPath::lineto(double x, double y)
+ConverterPath::lineto(double x, double y, bool close_last)
{
if ( IS_FINITE(x) && IS_FINITE(y) ) {
_path.appendNew<Geom::LineSegment>( Geom::Point(x, y) );
+ _path.close(close_last);
} else {
SPIRO_G_MESSAGE("spiro lineto not finite");
}
}
void
-ConverterPath::quadto(double xm, double ym, double x3, double y3)
+ConverterPath::quadto(double xm, double ym, double x3, double y3, bool close_last)
{
if ( IS_FINITE(xm) && IS_FINITE(ym) && IS_FINITE(x3) && IS_FINITE(y3) ) {
_path.appendNew<Geom::QuadraticBezier>(Geom::Point(xm, ym), Geom::Point(x3, y3));
+ _path.close(close_last);
} else {
SPIRO_G_MESSAGE("spiro quadto not finite");
}
}
void
-ConverterPath::curveto(double x1, double y1, double x2, double y2, double x3, double y3)
+ConverterPath::curveto(double x1, double y1, double x2, double y2, double x3, double y3, bool close_last)
{
if ( IS_FINITE(x1) && IS_FINITE(y1) && IS_FINITE(x2) && IS_FINITE(y2) ) {
_path.appendNew<Geom::CubicBezier>(Geom::Point(x1, y1), Geom::Point(x2, y2), Geom::Point(x3, y3));
+ _path.close(close_last);
} else {
SPIRO_G_MESSAGE("spiro curveto not finite");
}
diff --git a/src/live_effects/spiro-converters.h b/src/live_effects/spiro-converters.h
index 90855d2d6..6182a5dcd 100644
--- a/src/live_effects/spiro-converters.h
+++ b/src/live_effects/spiro-converters.h
@@ -11,10 +11,10 @@ public:
ConverterBase() {};
virtual ~ConverterBase() {};
- virtual void moveto(double x, double y, bool is_open) = 0;
- virtual void lineto(double x, double y) = 0;
- virtual void quadto(double x1, double y1, double x2, double y2) = 0;
- virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3) = 0;
+ virtual void moveto(double x, double y) = 0;
+ virtual void lineto(double x, double y, bool close_last) = 0;
+ virtual void quadto(double x1, double y1, double x2, double y2, bool close_last) = 0;
+ virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3, bool close_last) = 0;
};
@@ -27,10 +27,10 @@ public:
: _curve(curve)
{}
- virtual void moveto(double x, double y, bool is_open);
- virtual void lineto(double x, double y);
- virtual void quadto(double x1, double y1, double x2, double y2);
- virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3);
+ virtual void moveto(double x, double y);
+ virtual void lineto(double x, double y, bool close_last);
+ virtual void quadto(double x1, double y1, double x2, double y2, bool close_last);
+ virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3, bool close_last);
private:
SPCurve &_curve;
@@ -47,10 +47,10 @@ class ConverterPath : public ConverterBase {
public:
ConverterPath(Geom::Path &path);
- virtual void moveto(double x, double y, bool is_open);
- virtual void lineto(double x, double y);
- virtual void quadto(double x1, double y1, double x2, double y2);
- virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3);
+ virtual void moveto(double x, double y);
+ virtual void lineto(double x, double y, bool close_last);
+ virtual void quadto(double x1, double y1, double x2, double y2, bool close_last);
+ virtual void curveto(double x1, double y1, double x2, double y2, double x3, double y3, bool close_last);
private:
Geom::Path &_path;
diff --git a/src/live_effects/spiro.cpp b/src/live_effects/spiro.cpp
index 46e53a0da..0ac2815bf 100644
--- a/src/live_effects/spiro.cpp
+++ b/src/live_effects/spiro.cpp
@@ -847,13 +847,13 @@ solve_spiro(spiro_seg *s, const int nseg)
static void
spiro_seg_to_otherpath(const double ks[4],
double x0, double y0, double x1, double y1,
- ConverterBase &bc, int depth)
+ ConverterBase &bc, int depth, bool close_last)
{
double bend = fabs(ks[0]) + fabs(.5 * ks[1]) + fabs(.125 * ks[2]) +
fabs((1./48) * ks[3]);
if (!(bend > 1e-8)) {
- bc.lineto(x1, y1);
+ bc.lineto(x1, y1, close_last);
} else {
double seg_ch = hypot(x1 - x0, y1 - y0);
double seg_th = atan2(y1 - y0, x1 - x0);
@@ -876,7 +876,7 @@ spiro_seg_to_otherpath(const double ks[4],
vl = (scale * (1./3)) * sin(th_even - th_odd);
ur = (scale * (1./3)) * cos(th_even + th_odd);
vr = (scale * (1./3)) * sin(th_even + th_odd);
- bc.curveto(x0 + ul, y0 + vl, x1 - ur, y1 - vr, x1, y1);
+ bc.curveto(x0 + ul, y0 + vl, x1 - ur, y1 - vr, x1, y1, close_last);
} else {
/* subdivide */
double ksub[4];
@@ -895,11 +895,11 @@ spiro_seg_to_otherpath(const double ks[4],
integrate_spiro(ksub, xysub);
xmid = x0 + cth * xysub[0] - sth * xysub[1];
ymid = y0 + cth * xysub[1] + sth * xysub[0];
- spiro_seg_to_otherpath(ksub, x0, y0, xmid, ymid, bc, depth + 1);
+ spiro_seg_to_otherpath(ksub, x0, y0, xmid, ymid, bc, depth + 1, false);
ksub[0] += .25 * ks[1] + (1./384) * ks[3];
ksub[1] += .125 * ks[2];
ksub[2] += (1./16) * ks[3];
- spiro_seg_to_otherpath(ksub, xmid, ymid, x1, y1, bc, depth + 1);
+ spiro_seg_to_otherpath(ksub, xmid, ymid, x1, y1, bc, depth + 1, close_last);
}
}
}
@@ -933,9 +933,10 @@ spiro_to_otherpath(const spiro_seg *s, int n, ConverterBase &bc)
double y1 = s[i + 1].y;
if (i == 0) {
- bc.moveto(x0, y0, s[0].ty == '{');
+ bc.moveto(x0, y0);
}
- spiro_seg_to_otherpath(s[i].ks, x0, y0, x1, y1, bc, 0);
+ // on the last segment, set the 'close_last' flag if path is closed
+ spiro_seg_to_otherpath(s[i].ks, x0, y0, x1, y1, bc, 0, (nsegs == n) && (i == n - 1));
}
}
diff --git a/src/main.cpp b/src/main.cpp
index 26c25af02..840643a90 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -212,7 +212,7 @@ static gboolean sp_export_id_only = FALSE;
static gchar *sp_export_svg = NULL;
static gchar *sp_export_ps = NULL;
static gchar *sp_export_eps = NULL;
-static gint sp_export_ps_level = 2;
+static gint sp_export_ps_level = 3;
static gchar *sp_export_pdf = NULL;
static gchar *sp_export_pdf_version = NULL;
static gchar *sp_export_emf = NULL;
@@ -260,7 +260,7 @@ static void resetCommandlineGlobals() {
sp_export_svg = NULL;
sp_export_ps = NULL;
sp_export_eps = NULL;
- sp_export_ps_level = 2;
+ sp_export_ps_level = 3;
sp_export_pdf = NULL;
sp_export_pdf_version = NULL;
sp_export_emf = NULL;
@@ -405,7 +405,7 @@ struct poptOption options[] = {
{"export-ps-level", 0,
POPT_ARG_INT, &sp_export_ps_level, SP_ARG_EXPORT_PS_LEVEL,
N_("Choose the PostScript Level used to export. Possible choices are"
- " 2 (the default) and 3"),
+ " 2 and 3 (the default)"),
N_("PS Level")},
{"export-pdf", 'A',
@@ -1045,6 +1045,10 @@ sp_main_gui(int argc, char const **argv)
gchar *usericondir = Inkscape::Application::profile_path("icons");
gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), usericondir);
gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), INKSCAPE_PIXMAPDIR);
+#ifdef INKSCAPE_THEMEDIR
+ gtk_icon_theme_append_search_path(gtk_icon_theme_get_default(), INKSCAPE_THEMEDIR);
+ gtk_icon_theme_rescan_if_needed (gtk_icon_theme_get_default());
+#endif
g_free(usericondir);
gdk_event_handler_set((GdkEventFunc)snooper, NULL, NULL);
diff --git a/src/menus-skeleton.h b/src/menus-skeleton.h
index f5e815bf6..8cdfbeb05 100644
--- a/src/menus-skeleton.h
+++ b/src/menus-skeleton.h
@@ -1,7 +1,9 @@
#ifndef SEEN_MENUS_SKELETON_H
#define SEEN_MENUS_SKELETON_H
-#include "config.h"
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
#ifdef __cplusplus
#undef N_
@@ -85,6 +87,7 @@ static char const menus_skeleton[] =
" <verb verb-id=\"EditDeselect\" />\n"
" <separator/>\n"
" <verb verb-id=\"EditGuidesAroundPage\" />\n"
+" <verb verb-id=\"EditGuidesToggleLock\" check=\"yes\" />\n"
" <verb verb-id=\"EditRemoveAllGuides\" />\n"
" <separator/>\n"
" <verb verb-id=\"DialogXMLEditor\" />\n"
@@ -221,7 +224,11 @@ static char const menus_skeleton[] =
" <submenu name=\"" N_("_Path") "\">\n"
" <verb verb-id=\"ObjectToPath\" />\n"
" <verb verb-id=\"StrokeToPath\" />\n"
+
+#if HAVE_POTRACE
" <verb verb-id=\"SelectionTrace\" />\n"
+#endif
+
" <verb verb-id=\"SelectionPixelArt\" />\n"
" <separator/>\n"
" <verb verb-id=\"SelectionUnion\" />\n"
@@ -284,7 +291,9 @@ static char const menus_skeleton[] =
" <verb verb-id=\"TutorialsBasic\" />\n"
" <verb verb-id=\"TutorialsShapes\" />\n"
" <verb verb-id=\"TutorialsAdvanced\" />\n"
+#if HAVE_POTRACE
" <verb verb-id=\"TutorialsTracing\" />\n"
+#endif
" <verb verb-id=\"TutorialsTracingPixelArt\" />\n"
" <verb verb-id=\"TutorialsCalligraphy\" />\n"
" <verb verb-id=\"TutorialsInterpolate\" />\n"
diff --git a/src/object-snapper.cpp b/src/object-snapper.cpp
index 634d56aa6..3e559ee7a 100644
--- a/src/object-snapper.cpp
+++ b/src/object-snapper.cpp
@@ -239,7 +239,7 @@ void Inkscape::ObjectSnapper::_collectNodes(SnapSourceType const &t,
bool old_pref2 = _snapmanager->snapprefs.isTargetSnappable(SNAPTARGET_ROTATION_CENTER);
if (old_pref2) {
std::vector<SPItem*> rotationSource=_snapmanager->getRotationCenterSource();
- for ( std::vector<SPItem*>::const_iterator itemlist = rotationSource.begin(); itemlist != rotationSource.end(); itemlist++) {
+ for ( std::vector<SPItem*>::const_iterator itemlist = rotationSource.begin(); itemlist != rotationSource.end(); ++itemlist) {
if ((*i).item == *itemlist) {
// don't snap to this item's rotation center
_snapmanager->snapprefs.setTargetSnappable(SNAPTARGET_ROTATION_CENTER, false);
@@ -637,54 +637,22 @@ void Inkscape::ObjectSnapper::_snapPathsConstrained(IntermSnapResults &isr,
constraint_line.appendNew<Geom::LineSegment>(p_max_on_cl);
constraint_path.push_back(constraint_line);
}
- // Length of constraint_path will always be one
bool strict_snapping = _snapmanager->snapprefs.getStrictSnapping();
// Find all intersections of the constrained path with the snap target candidates
- std::vector<Geom::Point> intersections;
for (std::vector<SnapCandidatePath >::const_iterator k = _paths_to_snap_to->begin(); k != _paths_to_snap_to->end(); ++k) {
if (k->path_vector && _allowSourceToSnapToTarget(p.getSourceType(), (*k).target_type, strict_snapping)) {
// Do the intersection math
- Geom::CrossingSet cs = Geom::crossings(constraint_path, *(k->path_vector));
- // Store the results as intersection points
- unsigned int index = 0;
- for (Geom::CrossingSet::const_iterator i = cs.begin(); i != cs.end(); ++i) {
- if (index >= constraint_path.size()) {
- break;
- }
- // Reconstruct and store the points of intersection
- for (Geom::Crossings::const_iterator m = (*i).begin(); m != (*i).end(); ++m) {
- intersections.push_back(constraint_path[index].pointAt((*m).ta));
- }
- index++;
- }
-
- //Geom::crossings will not consider the closing segment apparently, so we'll handle that separately here
- //TODO: This should have been fixed in rev. #9859, which makes this workaround obsolete
- for(Geom::PathVector::iterator it_pv = k->path_vector->begin(); it_pv != k->path_vector->end(); ++it_pv) {
- if (it_pv->closed()) {
- // Get the closing linesegment and convert it to a path
- Geom::Path cls;
- cls.close(false);
- cls.append(it_pv->back_closed());
- // Intersect that closing path with the constrained path
- Geom::Crossings cs = Geom::crossings(constraint_path.front(), cls);
- // Reconstruct and store the points of intersection
- index = 0; // assuming the constraint path vector has only one path
- for (Geom::Crossings::const_iterator m = cs.begin(); m != cs.end(); ++m) {
- intersections.push_back(constraint_path[index].pointAt((*m).ta));
- }
- }
- }
+ std::vector<Geom::PVIntersection> inters = constraint_path.intersect(*(k->path_vector));
- // Convert the collected points of intersection to snapped points
- for (std::vector<Geom::Point>::iterator p_inters = intersections.begin(); p_inters != intersections.end(); ++p_inters) {
+ // Convert the collected intersections to snapped points
+ for (std::vector<Geom::PVIntersection>::const_iterator i = inters.begin(); i != inters.end(); ++i) {
// Convert to desktop coordinates
- (*p_inters) = dt->doc2dt(*p_inters);
+ Geom::Point p_inters = dt->doc2dt(i->point());
// Construct a snapped point
- Geom::Coord dist = Geom::L2(p.getPoint() - *p_inters);
- SnappedPoint s = SnappedPoint(*p_inters, p.getSourceType(), p.getSourceNum(), k->target_type, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, false, k->target_bbox);
+ Geom::Coord dist = Geom::L2(p.getPoint() - p_inters);
+ SnappedPoint s = SnappedPoint(p_inters, p.getSourceType(), p.getSourceNum(), k->target_type, dist, getSnapperTolerance(), getSnapperAlwaysSnap(), true, false, k->target_bbox);
// Store the snapped point
if (dist <= tolerance) { // If the intersection is within snapping range, then we might snap to it
isr.points.push_back(s);
diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp
index 7bd5b6298..15d3f0f99 100644
--- a/src/path-chemistry.cpp
+++ b/src/path-chemistry.cpp
@@ -52,7 +52,7 @@ inline bool less_than_items(SPItem const *first, SPItem const *second)
}
void
-sp_selected_path_combine(SPDesktop *desktop)
+sp_selected_path_combine(SPDesktop *desktop, bool skip_undo)
{
Inkscape::Selection *selection = desktop->getSelection();
SPDocument *doc = desktop->getDocument();
@@ -71,14 +71,14 @@ sp_selected_path_combine(SPDesktop *desktop)
items = sp_degroup_list (items); // descend into any groups in selection
std::vector<SPItem*> to_paths;
- for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); i++) {
+ for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); ++i) {
if (!dynamic_cast<SPPath *>(*i) && !dynamic_cast<SPGroup *>(*i)) {
to_paths.push_back(*i);
}
}
std::vector<Inkscape::XML::Node*> converted;
bool did = sp_item_list_to_curves(to_paths, items, converted);
- for (std::vector<Inkscape::XML::Node*>::const_iterator i = converted.begin(); i != converted.end(); i++)
+ for (std::vector<Inkscape::XML::Node*>::const_iterator i = converted.begin(); i != converted.end(); ++i)
items.push_back((SPItem*)doc->getObjectByRepr(*i));
items = sp_degroup_list (items); // converting to path may have added more groups, descend again
@@ -101,7 +101,7 @@ sp_selected_path_combine(SPDesktop *desktop)
selection->clear();
}
- for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); i++){
+ for (std::vector<SPItem*>::const_reverse_iterator i = items.rbegin(); i != items.rend(); ++i){
SPItem *item = *i;
SPPath *path = dynamic_cast<SPPath *>(item);
@@ -172,10 +172,10 @@ sp_selected_path_combine(SPDesktop *desktop)
// move to the position of the topmost, reduced by the number of deleted items
repr->setPosition(position > 0 ? position : 0);
-
- DocumentUndo::done(desktop->getDocument(), SP_VERB_SELECTION_COMBINE,
- _("Combine"));
-
+ if ( !skip_undo ) {
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_SELECTION_COMBINE,
+ _("Combine"));
+ }
selection->set(repr);
Inkscape::GC::release(repr);
@@ -188,7 +188,7 @@ sp_selected_path_combine(SPDesktop *desktop)
}
void
-sp_selected_path_break_apart(SPDesktop *desktop)
+sp_selected_path_break_apart(SPDesktop *desktop, bool skip_undo)
{
Inkscape::Selection *selection = desktop->getSelection();
@@ -204,7 +204,7 @@ sp_selected_path_break_apart(SPDesktop *desktop)
bool did = false;
std::vector<SPItem*> itemlist(selection->itemList());
- for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i != itemlist.end(); i++){
+ for (std::vector<SPItem*>::const_iterator i = itemlist.begin(); i != itemlist.end(); ++i){
SPItem *item = *i;
@@ -283,8 +283,10 @@ sp_selected_path_break_apart(SPDesktop *desktop)
desktop->clearWaitingCursor();
if (did) {
- DocumentUndo::done(desktop->getDocument(), SP_VERB_SELECTION_BREAK_APART,
- _("Break apart"));
+ if ( !skip_undo ) {
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_SELECTION_BREAK_APART,
+ _("Break apart"));
+ }
} else {
desktop->getMessageStack()->flash(Inkscape::ERROR_MESSAGE, _("<b>No path(s)</b> to break apart in the selection."));
}
@@ -354,7 +356,7 @@ bool
sp_item_list_to_curves(const std::vector<SPItem*> &items, std::vector<SPItem*>& selected, std::vector<Inkscape::XML::Node*> &to_select, bool skip_all_lpeitems)
{
bool did = false;
- for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++){
+ for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); ++i){
SPItem *item = *i;
g_assert(item != NULL);
SPDocument *document = item->document;
@@ -474,7 +476,13 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/)
// Special treatment for text: convert each glyph to separate path, then group the paths
Inkscape::XML::Node *g_repr = xml_doc->createElement("svg:g");
- Glib::ustring original_text; // To save original text of accessibility.
+ // Save original text for accessibility.
+ Glib::ustring original_text = sp_te_get_string_multiline( item,
+ te_get_layout(item)->begin(),
+ te_get_layout(item)->end() );
+ if( original_text.size() > 0 ) {
+ g_repr->setAttribute("aria-label", original_text.c_str() );
+ }
g_repr->setAttribute("transform", item->getRepr()->attribute("transform"));
/* Mask */
@@ -494,10 +502,8 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/)
item->style->write( SP_STYLE_FLAG_IFDIFF, item->parent ? item->parent->style : NULL); // TODO investigate posibility
g_repr->setAttribute("style", style_str.c_str());
- Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin();
+ Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin();
do {
- original_text += (gunichar)te_get_layout(item)->characterAt( iter );
-
Inkscape::Text::Layout::iterator iter_next = iter;
iter_next.nextGlyph(); // iter_next is one glyph ahead from iter
if (iter == iter_next)
@@ -538,10 +544,6 @@ sp_selected_item_to_curved_repr(SPItem *item, guint32 /*text_grouping_policy*/)
g_repr->appendChild(p_repr);
- // For accessibility, store original string
- if( original_text.size() > 0 ) {
- g_repr->setAttribute("aria-label", original_text.c_str() );
- }
Inkscape::GC::release(p_repr);
if (iter == te_get_layout(item)->end())
@@ -621,7 +623,7 @@ sp_selected_path_reverse(SPDesktop *desktop)
bool did = false;
desktop->messageStack()->flash(Inkscape::IMMEDIATE_MESSAGE, _("Reversing paths..."));
- for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++){
+ for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); ++i){
SPPath *path = dynamic_cast<SPPath *>(*i);
if (!path) {
diff --git a/src/path-chemistry.h b/src/path-chemistry.h
index f454167a9..7b9beaed8 100644
--- a/src/path-chemistry.h
+++ b/src/path-chemistry.h
@@ -24,10 +24,9 @@ class Node;
} // namespace Inkscape
typedef unsigned int guint32;
-typedef struct _GSList GSList;
-void sp_selected_path_combine (SPDesktop *desktop);
-void sp_selected_path_break_apart (SPDesktop *desktop);
+void sp_selected_path_combine (SPDesktop *desktop, bool skip_undo = false);
+void sp_selected_path_break_apart (SPDesktop *desktop, bool skip_undo = false);
// interactive=true only has an effect if desktop != NULL, i.e. if a GUI is available
void sp_selected_path_to_curves (Inkscape::Selection *selection, SPDesktop *desktop, bool interactive = true);
void sp_selected_to_lpeitems(SPDesktop *desktop);
diff --git a/src/path-prefix.h b/src/path-prefix.h
index 7042d5124..7f9bcec51 100644
--- a/src/path-prefix.h
+++ b/src/path-prefix.h
@@ -35,6 +35,7 @@
# define INKSCAPE_PATTERNSDIR BR_DATADIR( "/inkscape/patterns" )
# define INKSCAPE_SCREENSDIR BR_DATADIR( "/inkscape/screens" )
# define INKSCAPE_SYMBOLSDIR BR_DATADIR( "/inkscape/symbols" )
+# define INKSCAPE_THEMEDIR BR_DATADIR( "/icons" )
# define INKSCAPE_TUTORIALSDIR BR_DATADIR( "/inkscape/tutorials" )
# define INKSCAPE_TEMPLATESDIR BR_DATADIR( "/inkscape/templates" )
# define INKSCAPE_UIDIR BR_DATADIR( "/inkscape/ui" )
@@ -102,6 +103,7 @@
# define INKSCAPE_PATTERNSDIR INKSCAPE_DATADIR "/inkscape/patterns"
# define INKSCAPE_SCREENSDIR INKSCAPE_DATADIR "/inkscape/screens"
# define INKSCAPE_SYMBOLSDIR INKSCAPE_DATADIR "/inkscape/symbols"
+# define INKSCAPE_THEMEDIR INKSCAPE_DATADIR "/icons"
# define INKSCAPE_TUTORIALSDIR INKSCAPE_DATADIR "/inkscape/tutorials"
# define INKSCAPE_TEMPLATESDIR INKSCAPE_DATADIR "/inkscape/templates"
# define INKSCAPE_UIDIR INKSCAPE_DATADIR "/inkscape/ui"
diff --git a/src/persp3d.cpp b/src/persp3d.cpp
index dc0975d12..a48481145 100644
--- a/src/persp3d.cpp
+++ b/src/persp3d.cpp
@@ -36,10 +36,10 @@ static int global_counter = 0;
/* Constructor/destructor for the internal class */
-Persp3DImpl::Persp3DImpl() {
- tmat = Proj::TransfMat3x4 ();
- document = NULL;
-
+Persp3DImpl::Persp3DImpl() :
+ tmat (Proj::TransfMat3x4 ()),
+ document (NULL)
+{
my_counter = global_counter++;
}
diff --git a/src/pixmaps/cursor-select.xpm b/src/pixmaps/cursor-select.xpm
new file mode 100644
index 000000000..569573618
--- /dev/null
+++ b/src/pixmaps/cursor-select.xpm
@@ -0,0 +1,38 @@
+/* XPM */
+static char const *cursor_select_xpm[] = {
+"32 32 3 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+". ",
+".. ",
+".+. ",
+".++. ",
+".+++. ",
+".++++. ",
+".+++++. ",
+".++++++. ",
+".+++++++. ",
+".++++++++. ",
+".+++++++++. ",
+".++++++..... ",
+".++++++. ",
+".++..++. ",
+".+. .+++. ",
+".. .++. ",
+". .+++. ",
+" .+. ",
+" .. ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" ",
+" "};
diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h
index f4a08b928..b428cbe7a 100644
--- a/src/preferences-skeleton.h
+++ b/src/preferences-skeleton.h
@@ -269,7 +269,7 @@ static char const preferences_skeleton[] =
" <group id=\"zoomcorrection\" value=\"1.0\" unit=\"mm\"/>\n"
" <group id=\"keyscroll\" value=\"15\"/>\n"
" <group id=\"wheelscroll\" value=\"40\"/>\n"
-" <group id=\"spacepans\" value=\"0\"/>\n"
+" <group id=\"spacebarpans\" value=\"1\"/>\n"
" <group id=\"wheelzooms\" value=\"0\"/>\n"
" <group id=\"transientpolicy\" value=\"1\"/>\n"
" <group id=\"scrollingacceleration\" value=\"0.4\"/>\n"
diff --git a/src/profile-manager.cpp b/src/profile-manager.cpp
index 90b124195..035aa6051 100644
--- a/src/profile-manager.cpp
+++ b/src/profile-manager.cpp
@@ -34,11 +34,9 @@ void ProfileManager::_resourcesChanged()
{
std::vector<SPObject*> newList;
if (_doc) {
- const GSList *current = _doc->getResourceList( "iccprofile" );
- while ( current ) {
- newList.push_back(SP_OBJECT(current->data));
- current = g_slist_next(current);
- }
+ std::set<SPObject *> current = _doc->getResourceList( "iccprofile" );
+ for (std::set<SPObject *>::const_iterator i = current.begin(); i != current.end(); ++i)
+ newList.push_back(*i);
}
sort( newList.begin(), newList.end() );
diff --git a/src/pure-transform.cpp b/src/pure-transform.cpp
new file mode 100644
index 000000000..9c7054b9f
--- /dev/null
+++ b/src/pure-transform.cpp
@@ -0,0 +1,359 @@
+/*
+ * Class for pure transformations, such as translating, scaling, stretching, skewing, and rotating
+ *
+ * Authors:
+ * Diederik van Lierop <mail@diedenrezi.nl>
+ *
+ * Copyright (C) 2015 Diederik van Lierop
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "pure-transform.h"
+#include "snap.h"
+
+namespace Inkscape
+
+{
+
+void PureTransform::snap(::SnapManager *sm, std::vector<Inkscape::SnapCandidatePoint> const &points, Geom::Point const &pointer) {
+ std::vector<Inkscape::SnapCandidatePoint> transformed_points;
+ Geom::Rect bbox;
+
+ long source_num = 0;
+ for (std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); ++i) {
+
+ /* Work out the transformed version of this point */
+ Geom::Point transformed = getTransformedPoint(*i); // _transformPoint(*i, transformation_type, transformation, origin, dim, uniform);
+
+ // add the current transformed point to the box hulling all transformed points
+ if (i == points.begin()) {
+ bbox = Geom::Rect(transformed, transformed);
+ } else {
+ bbox.expandTo(transformed);
+ }
+
+ transformed_points.push_back(Inkscape::SnapCandidatePoint(transformed, (*i).getSourceType(), source_num, Inkscape::SNAPTARGET_UNDEFINED, Geom::OptRect()));
+ source_num++;
+ }
+
+ /* The current best metric for the best transformation; lower is better, whereas Geom::infinity()
+ ** means that we haven't snapped anything.
+ */
+ Inkscape::SnapCandidatePoint best_original_point;
+ g_assert(best_snapped_point.getAlwaysSnap() == false); // Check initialization of snapped point
+ g_assert(best_snapped_point.getAtIntersection() == false);
+ g_assert(best_snapped_point.getSnapped() == false); // Check initialization to catch any regression
+
+ std::vector<Inkscape::SnapCandidatePoint>::iterator j = transformed_points.begin();
+
+ // std::cout << std::endl;
+ bool first_free_snap = true;
+
+ for (std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); ++i) {
+
+ // If we have a collection of SnapCandidatePoints, with mixed constrained snapping and free snapping
+ // requirements (this can happen when scaling, see PureScale::snap()), then freeSnap might never see the
+ // SnapCandidatePoint with source_num == 0. The freeSnap() method in the object snapper depends on this,
+ // because only for source-num == 0 the target nodes will be collected. Therefore we enforce that the first
+ // SnapCandidatePoint that is to be freeSnapped always has source_num == 0;
+ // TODO: This is a bit ugly so fix this; do we need sourcenum for anything else? if we don't then get rid
+ // of it and explicitly communicate to the object snapper that this is a first point
+ if (first_free_snap) {
+ (*j).setSourceNum(0);
+ first_free_snap = false;
+ }
+ Inkscape::SnappedPoint snapped_point = snap(sm, *j, (*i).getPoint(), bbox); // Calls the snap() method of the derived classes
+
+ // std::cout << "dist = " << snapped_point.getSnapDistance() << std::endl;
+ snapped_point.setPointerDistance(Geom::L2(pointer - (*i).getPoint()));
+
+ /*Find the transformation that describes where the snapped point has
+ ** ended up, and also the metric for this transformation.
+ */
+
+ bool store_best_snap = false;
+ if (snapped_point.getSnapped()) {
+ // We snapped; keep track of the best snap
+ if (best_snapped_point.isOtherSnapBetter(snapped_point, true)) {
+ store_best_snap = true;
+ }
+ } else {
+ // So we didn't snap for this point
+ if (!best_snapped_point.getSnapped()) {
+ // ... and none of the points before snapped either
+ // We might still need to apply a constraint though, if we tried a constrained snap. And
+ // in case of a free snap we might have use for the transformed point, so let's return that
+ // point, whether it's constrained or not
+ if (best_snapped_point.isOtherSnapBetter(snapped_point, true) || points.size() == 1) {
+ // .. so we must keep track of the best non-snapped constrained point
+ store_best_snap = true;
+ }
+ }
+ }
+
+ if (store_best_snap) {
+ best_original_point = (*i);
+ best_snapped_point = snapped_point;
+ }
+
+ ++j;
+ }
+
+ /* The current best transformation */
+ //Geom::Point best_transformation = getResult(best_original_point, best_snapped_point);
+ storeTransform(best_original_point, best_snapped_point);
+
+ Geom::Coord best_metric = best_snapped_point.getSnapDistance();
+
+ // Using " < 1e6" instead of " < Geom::infinity()" for catching some rounding errors
+ // These rounding errors might be caused by NRRects, see bug #1584301
+ best_snapped_point.setSnapDistance(best_metric < 1e6 ? best_metric : Geom::infinity());
+}
+
+
+
+
+
+Geom::Point PureTranslate::getTransformedPoint(SnapCandidatePoint const &p) const {
+ return p.getPoint() + _vector;
+}
+
+void PureTranslate::storeTransform(SnapCandidatePoint const original_point, SnappedPoint const snapped_point) {
+ /* Consider the case in which a box is almost aligned with a grid in both
+ * horizontal and vertical directions. The distance to the intersection of
+ * the grid lines will always be larger then the distance to a single grid
+ * line. If we prefer snapping to an intersection over to a single
+ * grid line, then we cannot use "metric = Geom::L2(result)". Therefore the
+ * snapped distance will be used as a metric. Please note that the snapped
+ * distance to an intersection is defined as the distance to the nearest line
+ * of the intersection, and not to the intersection itself!
+ */
+ // Only for translations, the relevant metric will be the real snapped distance,
+ // so we don't have to do anything special here
+ _vector_snapped = snapped_point.getPoint() - original_point.getPoint();
+}
+
+SnappedPoint PureTranslate::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point /*pt_orig*/, Geom::OptRect const &bbox_to_snap) const {
+ return sm->freeSnap(p, bbox_to_snap);
+}
+
+SnappedPoint PureTranslateConstrained::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const {
+ // Calculate a constraint dedicated for this specific point
+ // When doing a constrained translation, all points will move in the same direction, i.e.
+ // either horizontally or vertically. The lines along which they move are therefore all
+ // parallel, but might not be co-linear. Therefore we will have to specify the point through
+ // which the constraint-line runs here, for each point individually.
+ Snapper::SnapConstraint dedicated_constraint = Snapper::SnapConstraint(pt_orig, _direction);
+ return sm->constrainedSnap(p, dedicated_constraint, bbox_to_snap);
+}
+
+
+
+
+
+Geom::Point PureScale::getTransformedPoint(SnapCandidatePoint const &p) const {
+ return (p.getPoint() - _origin) * _scale + _origin;
+}
+
+void PureScale::storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point) {
+ _scale_snapped = Geom::Scale(Geom::infinity(), Geom::infinity());
+ // If this point *i is horizontally or vertically aligned with
+ // the origin of the scaling, then it will scale purely in X or Y
+ // We can therefore only calculate the scaling in this direction
+ // and the scaling factor for the other direction should remain
+ // untouched (unless scaling is uniform of course)
+ Geom::Point const a = snapped_point.getPoint() - _origin; // vector to snapped point
+ Geom::Point const b = original_point.getPoint() - _origin; // vector to original point (not the transformed point!)
+ for (int index = 0; index < 2; index++) {
+ if (fabs(b[index]) > 1e-4) { // if SCALING CAN occur in this direction
+ if (fabs(fabs(a[index]/b[index]) - fabs(_scale[index])) > 1e-7) { // if SNAPPING DID occur in this direction
+ _scale_snapped[index] = a[index] / b[index]; // then calculate it!
+ // _scale_snapped will be (1,1) if we haven't snapped, because the snapped point equals the original point
+ }
+ // we might have left result[1-index] = Geom::infinity() if scaling didn't occur in the other direction
+ }
+ }
+ if (_uniform) {
+ // Lock the scaling the be uniform, but keep the sign such that we don't change which quadrant we have dragged into
+ if (fabs(_scale_snapped[0]) < fabs(_scale_snapped[1])) {
+ _scale_snapped[1] = fabs(_scale_snapped[0]) * Geom::sgn(_scale[1]);
+ } else {
+ _scale_snapped[0] = fabs(_scale_snapped[1]) * Geom::sgn(_scale[0]);
+ }
+ }
+
+ // Don't ever exit with one of scaling components uninitialized
+ for (int index = 0; index < 2; index++) {
+ if (_scale_snapped[index] == Geom::infinity()) {
+ _scale_snapped[index] = _scale[index];
+ }
+ }
+
+ // Compare the resulting scaling with the desired scaling
+ Geom::Point scale_metric = _scale_snapped.vector() - _scale.vector();
+ snapped_point.setSnapDistance(Geom::L2(scale_metric));
+ snapped_point.setSecondSnapDistance(Geom::infinity());
+}
+
+// When scaling, a point aligned either horizontally or vertically with the origin can only
+// move in that specific direction; therefore it should only snap in that direction, so this
+// then becomes a constrained snap; otherwise we can use a free snap;
+SnappedPoint PureScale::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const {
+ Geom::Point const b = (pt_orig - _origin); // vector to original point (not the transformed point!)
+ bool const c1 = fabs(b[Geom::X]) < 1e-6;
+ bool const c2 = fabs(b[Geom::Y]) < 1e-6;
+ if ((c1 || c2) && !(c1 && c2)) {
+ Geom::Point cvec; cvec[c1] = 1.;
+ Snapper::SnapConstraint dedicated_constraint = Inkscape::Snapper::SnapConstraint(_origin, cvec);
+ return sm->constrainedSnap(p, dedicated_constraint, bbox_to_snap);
+ } else {
+ return sm->freeSnap(p, bbox_to_snap);
+ }
+}
+
+SnappedPoint PureScaleConstrained::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const {
+ // When constrained scaling, only uniform scaling is supported.
+ // When uniformly scaling, each point will have its own unique constraint line,
+ // running from the scaling origin to the original untransformed point. We will
+ // calculate that line here as a dedicated constraint
+ Geom::Point b = pt_orig - _origin;
+ Snapper::SnapConstraint dedicated_constraint = Inkscape::Snapper::SnapConstraint(_origin, b);
+ return sm->constrainedSnap(p, dedicated_constraint, bbox_to_snap);
+}
+
+
+
+
+
+Geom::Point PureStretchConstrained::getTransformedPoint(SnapCandidatePoint const &p) const {
+ Geom::Scale s(1, 1);
+ if (_uniform)
+ s[Geom::X] = s[Geom::Y] = _magnitude;
+ else {
+ s[_direction] = _magnitude;
+ s[1 - _direction] = 1;
+ }
+ return ((p.getPoint() - _origin) * s) + _origin;
+}
+
+SnappedPoint PureStretchConstrained::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const {
+ Snapper::SnapConstraint dedicated_constraint;
+ if (_uniform) {
+ // When uniformly stretching, each point will have its own unique constraint line,
+ // running from the scaling origin to the original untransformed point. We will
+ // calculate that line here
+ Geom::Point b = pt_orig - _origin;
+ dedicated_constraint = Inkscape::Snapper::SnapConstraint(_origin, b); // dedicated constraint
+ } else {
+ Geom::Point cvec; cvec[_direction] = 1.;
+ dedicated_constraint = Inkscape::Snapper::SnapConstraint(pt_orig, cvec);
+ }
+
+ return sm->constrainedSnap(p, dedicated_constraint, bbox_to_snap);
+}
+
+void PureStretchConstrained::storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point) {
+ Geom::Point const a = snapped_point.getPoint() - _origin; // vector to snapped point
+ Geom::Point const b = original_point.getPoint() - _origin; // vector to original point (not the transformed point!)
+
+ _stretch_snapped = Geom::Scale(Geom::infinity(), Geom::infinity());
+ if (fabs(b[_direction]) > 1e-6) { // if STRETCHING will occur for this point
+ _stretch_snapped[_direction] = a[_direction] / b[_direction];
+ _stretch_snapped[1-_direction] = _uniform ? _stretch_snapped[_direction] : 1;
+ } else { // STRETCHING might occur for this point, but only when the stretching is uniform
+ if (_uniform && fabs(b[1-_direction]) > 1e-6) {
+ _stretch_snapped[1-_direction] = a[1-_direction] / b[1-_direction];
+ _stretch_snapped[_direction] = _stretch_snapped[1-_direction];
+ }
+ }
+
+ // _stretch_snapped might have one or both components at infinity!
+
+ // Store the metric for this transformation as a virtual distance
+ snapped_point.setSnapDistance(std::abs(_stretch_snapped[_direction] - _magnitude));
+ snapped_point.setSecondSnapDistance(Geom::infinity());
+}
+
+
+
+
+
+Geom::Point PureSkewConstrained::getTransformedPoint(SnapCandidatePoint const &p) const {
+ Geom::Point transformed;
+ // Apply the skew factor
+ transformed[_direction] = (p.getPoint())[_direction] + _skew * ((p.getPoint())[1 - _direction] - _origin[1 - _direction]);
+ // While skewing, mirroring and scaling (by integer multiples) in the opposite direction is also allowed.
+ // Apply that scale factor here
+ transformed[1-_direction] = (p.getPoint() - _origin)[1 - _direction] * _scale + _origin[1 - _direction];
+ return transformed;
+}
+
+SnappedPoint PureSkewConstrained::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const {
+ // Snapping the nodes of the bounding box of a selection that is being transformed, will only work if
+ // the transformation of the bounding box is equal to the transformation of the individual nodes. This is
+ // NOT the case for example when rotating or skewing. The bounding box itself cannot possibly rotate or skew,
+ // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping
+ // of bounding boxes is not allowed here.
+ g_assert(!(p.getSourceType() & Inkscape::SNAPSOURCE_BBOX_CATEGORY));
+
+ Geom::Point constraint_vector;
+ constraint_vector[1-_direction] = 0.0;
+ constraint_vector[_direction] = 1.0;
+
+ return sm->constrainedSnap(p, Inkscape::Snapper::SnapConstraint(constraint_vector), bbox_to_snap);
+}
+
+void PureSkewConstrained::storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point) {
+ Geom::Point const b = original_point.getPoint() - _origin; // vector to original point (not the transformed point!)
+ _skew_snapped = (snapped_point.getPoint()[_direction] - (original_point.getPoint())[_direction]) / b[1 - _direction]; // skew factor
+
+ // Store the metric for this transformation as a virtual distance
+ snapped_point.setSnapDistance(std::abs(_skew_snapped - _skew));
+ snapped_point.setSecondSnapDistance(Geom::infinity());
+}
+
+
+
+
+Geom::Point PureRotateConstrained::getTransformedPoint(SnapCandidatePoint const &p) const {
+ return (p.getPoint() - _origin) * Geom::Rotate(_angle) + _origin;
+}
+
+SnappedPoint PureRotateConstrained::snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const {
+ // Snapping the nodes of the bounding box of a selection that is being transformed, will only work if
+ // the transformation of the bounding box is equal to the transformation of the individual nodes. This is
+ // NOT the case for example when rotating or skewing. The bounding box itself cannot possibly rotate or skew,
+ // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping
+ // of bounding boxes is not allowed here.
+ g_assert(!(p.getSourceType() & Inkscape::SNAPSOURCE_BBOX_CATEGORY));
+
+ // Calculate a constraint dedicated for this specific point
+ Geom::Point b = pt_orig - _origin;
+ Geom::Coord r = Geom::L2(b); // the radius of the circular constraint
+ Snapper::SnapConstraint dedicated_constraint = Inkscape::Snapper::SnapConstraint(_origin, b, r);
+ return sm->constrainedSnap(p, dedicated_constraint, bbox_to_snap);
+}
+
+void PureRotateConstrained::storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point) {
+ Geom::Point const a = snapped_point.getPoint() - _origin; // vector to snapped point
+ Geom::Point const b = (original_point.getPoint() - _origin); // vector to original point (not the transformed point!)
+ // a is vector to snapped point; b is vector to original point; now lets calculate angle between a and b
+ _angle_snapped = atan2(Geom::dot(Geom::rot90(b), a), Geom::dot(b, a));
+ if (Geom::L2(b) < 1e-9) { // points too close to the rotation center will not move. Don't try to snap these
+ // as they will always yield a perfect snap result if they're already snapped beforehand (e.g.
+ // when the transformation center has been snapped to a grid intersection in the selector tool)
+ snapped_point.setSnapDistance(Geom::infinity());
+ // PS1: Apparently we don't have to do this for skewing, but why?
+ // PS2: We cannot easily filter these points upstream, e.g. in the grab() method (seltrans.cpp)
+ // because the rotation center will change when pressing shift, and grab() won't be recalled.
+ // Filtering could be done in handleRequest() (again in seltrans.cpp), by iterating through
+ // the snap candidates. But hey, we're iterating here anyway.
+ } else {
+ snapped_point.setSnapDistance(fabs(_angle_snapped - _angle));
+ }
+ snapped_point.setSecondSnapDistance(Geom::infinity());
+
+}
+
+}
diff --git a/src/pure-transform.h b/src/pure-transform.h
new file mode 100644
index 000000000..f973a95b1
--- /dev/null
+++ b/src/pure-transform.h
@@ -0,0 +1,228 @@
+/*
+ * Class for pure transformations, such as translating, scaling, stretching, skewing, and rotating. Pure means that they cannot
+ * be combined. This is what makes them different from affine transformations. Pure transformations are being used in the selector
+ * tool and node tool
+ *
+ * Authors:
+ * Diederik van Lierop <mail@diedenrezi.nl>
+ *
+ * Copyright (C) 2015 Diederik van Lierop
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_PURE_TRANSFORM_H
+#define SEEN_PURE_TRANSFORM_H
+
+#include <glib.h> // for g_warning
+#include "snapper.h" // for SnapConstraint
+
+class SnapManager;
+
+namespace Inkscape {
+
+class PureTransform {
+
+protected:
+ virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const = 0;
+ virtual Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const = 0;
+ virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point) = 0;
+
+public:
+ //PureTransform();
+ virtual ~PureTransform() {};
+// virtual PureTransform * clone () const = 0; // https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Virtual_Constructor
+
+ // Snap a group of points
+ SnappedPoint best_snapped_point;
+ void snap(::SnapManager *sm, std::vector<Inkscape::SnapCandidatePoint> const &points, Geom::Point const &pointer);
+};
+
+// **************************************************************************************************************
+
+class PureTranslate: public PureTransform {
+
+protected:
+ Geom::Point _vector;
+ Geom::Point _vector_snapped;
+
+ virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const;
+ virtual Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const;
+ virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point);
+
+public:
+// PureTranslate(); // Default constructor
+// PureTranslate(PureTranslate const &); // Copy constructor
+ virtual ~PureTranslate() {};
+ PureTranslate(Geom::Point vector = Geom::Point()) : _vector(vector), _vector_snapped(vector) {}
+
+ Geom::Point getTranslationSnapped() {return _vector_snapped;}
+// PureTranslate * clone () const {return new PureTranslate(*this);}
+};
+
+
+class PureTranslateConstrained: public PureTranslate {
+
+protected:
+ Geom::Dim2 _direction;
+ virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const;
+
+public:
+ virtual ~PureTranslateConstrained() {};
+ PureTranslateConstrained(Geom::Coord displacement, Geom::Dim2 direction):
+ PureTranslate() {
+ _vector[direction] = displacement;
+ _vector[1-direction] = 0.0;
+ _direction = direction;
+ }
+ // PureTranslateConstrained * clone () const {return new PureTranslateConstrained(*this);}
+};
+
+// **************************************************************************************************************
+
+class PureScale: public PureTransform {
+
+protected:
+ Geom::Scale _scale;
+ Geom::Scale _scale_snapped;
+ Geom::Point _origin;
+ bool _uniform;
+
+ virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const;
+ virtual Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const;
+ virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point);
+
+public:
+// PureScale(); // Default constructor
+// PureScale(PureScale const &); // Copy constructor
+ virtual ~PureScale() {};
+
+ PureScale(Geom::Scale scale, Geom::Point origin, bool uniform) :
+ _scale (scale),
+ _scale_snapped (scale),
+ _origin (origin),
+ _uniform (uniform)
+ {}
+
+ Geom::Scale getScaleSnapped() {return _scale_snapped;}
+// PureScale * clone () const {return new PureScale (*this);}
+};
+
+class PureScaleConstrained: public PureScale {
+//Magnitude of the scale components will be the same, but the sign could still be different ()
+protected:
+ virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const;
+
+public:
+ virtual ~PureScaleConstrained() {};
+ PureScaleConstrained(Geom::Scale scale, Geom::Point origin):
+ PureScale(scale, origin, true) {}; // Non-uniform constrained scaling is not supported
+
+// PureScaleConstrained * clone () const {return new PureScaleConstrained(*this);}
+};
+
+// **************************************************************************************************************
+
+class PureStretchConstrained: public PureTransform {
+// A stretch is always implicitly constrained
+
+protected:
+ Geom::Coord _magnitude;
+ Geom::Scale _stretch_snapped;
+ Geom::Point _origin;
+ Geom::Dim2 _direction;
+ bool _uniform;
+
+ virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const;
+ virtual Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const;
+ virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point);
+
+public:
+ virtual ~PureStretchConstrained() {};
+ PureStretchConstrained(Geom::Coord magnitude, Geom::Point origin, Geom::Dim2 direction, bool uniform) :
+ _magnitude (magnitude),
+ _stretch_snapped (Geom::Scale(magnitude, magnitude)),
+ _origin (origin),
+ _direction (direction),
+ _uniform (uniform)
+ {
+ if (not uniform) {
+ _stretch_snapped[1-direction] = 1.0;
+ }
+ }
+
+ Geom::Scale getStretchSnapped() {return _stretch_snapped;}
+ Geom::Coord getMagnitude() {return _magnitude;}
+ Geom::Coord getMagnitudeSnapped() {return _stretch_snapped[_direction];}
+
+// PureStretchConstrained * clone () const {return new PureStretchConstrained(*this);}
+};
+
+// **************************************************************************************************************
+
+class PureSkewConstrained: public PureTransform {
+// A skew is always implicitly constrained
+
+protected:
+ Geom::Coord _skew;
+ Geom::Coord _skew_snapped;
+ Geom::Coord _scale;
+ Geom::Point _origin;
+ Geom::Dim2 _direction;
+
+ virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const;
+ Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const;
+ virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point);
+
+public:
+ virtual ~PureSkewConstrained() {};
+ PureSkewConstrained(Geom::Coord skew, Geom::Coord scale, Geom::Point origin, Geom::Dim2 direction) :
+ _skew (skew),
+ _skew_snapped (skew),
+ _scale (scale),
+ _origin (origin),
+ _direction (direction)
+ {};
+
+ Geom::Coord getSkewSnapped() {return _skew_snapped;}
+
+// PureSkewConstrained * clone () const {return new PureSkewConstrained(*this);}
+};
+
+// **************************************************************************************************************
+
+class PureRotateConstrained: public PureTransform {
+// A rotation is always implicitly constrained, so we will hide the constructor by making it protected; devs should use PureRotateConstrained instead
+// It's _constraint member variable though will be empty
+
+protected:
+ double _angle; // in radians
+ double _angle_snapped;
+ Geom::Point _origin;
+ bool _uniform;
+
+ virtual SnappedPoint snap(::SnapManager *sm, SnapCandidatePoint const &p, Geom::Point pt_orig, Geom::OptRect const &bbox_to_snap) const;
+ virtual Geom::Point getTransformedPoint(SnapCandidatePoint const &p) const;
+ virtual void storeTransform(SnapCandidatePoint const original_point, SnappedPoint snapped_point);
+
+public:
+// PureRotate(); // Default constructor
+// PureRotate(PureRotate const &); // Copy constructor
+ virtual ~PureRotateConstrained() {};
+
+ PureRotateConstrained(double angle, Geom::Point origin) :
+ _angle (angle), // in radians!
+ _angle_snapped (angle),
+ _origin (origin),
+ _uniform (true) // We do not yet allow for simultaneous rotation and scaling
+ {}
+
+ double getAngleSnapped() {return _angle_snapped;}
+
+// PureRotate * clone () const {return new PureRotate(*this);}
+};
+
+}
+
+#endif // !SEEN_PURE_TRANSFORM_H
+
diff --git a/src/removeoverlap.cpp b/src/removeoverlap.cpp
index 9ea75de0d..138577fb8 100644
--- a/src/removeoverlap.cpp
+++ b/src/removeoverlap.cpp
@@ -12,7 +12,6 @@
*/
#include <utility>
#include <2geom/transforms.h>
-#include "util/glib-list-iterators.h"
#include "sp-item.h"
#include "sp-item-transform.h"
#include "libvpsc/generate-constraints.h"
diff --git a/src/removeoverlap.h b/src/removeoverlap.h
index d873663d1..cc0c7d9b7 100644
--- a/src/removeoverlap.h
+++ b/src/removeoverlap.h
@@ -13,8 +13,6 @@
#ifndef SEEN_REMOVEOVERLAP_H
#define SEEN_REMOVEOVERLAP_H
-typedef struct _GSList GSList;
-
void removeoverlap(std::vector<SPItem*> const &items, double xGap, double yGap);
#endif // SEEN_REMOVEOVERLAP_H
diff --git a/src/resource-manager.cpp b/src/resource-manager.cpp
index fe53eca4f..18d7c6ba2 100644
--- a/src/resource-manager.cpp
+++ b/src/resource-manager.cpp
@@ -179,9 +179,9 @@ std::vector<Glib::ustring> ResourceManagerImpl::findBrokenLinks( SPDocument *doc
std::set<Glib::ustring> uniques;
if ( doc ) {
- GSList const *images = doc->getResourceList("image");
- for (GSList const *it = images; it; it = it->next) {
- Inkscape::XML::Node *ir = static_cast<SPObject *>(it->data)->getRepr();
+ std::set<SPObject *> images = doc->getResourceList("image");
+ for (std::set<SPObject *>::const_iterator it = images.begin(); it != images.end(); ++it) {
+ Inkscape::XML::Node *ir = (*it)->getRepr();
gchar const *href = ir->attribute("xlink:href");
if ( href && ( uniques.find(href) == uniques.end() ) ) {
@@ -222,11 +222,15 @@ std::map<Glib::ustring, Glib::ustring> ResourceManagerImpl::locateLinks(Glib::us
Glib::ustring uri = (*it)->get_uri();
std::string scheme = Glib::uri_parse_scheme(uri);
if ( scheme == "file" ) {
- std::string path = Glib::filename_from_uri(uri);
- path = Glib::path_get_dirname(path);
- if ( std::find(priorLocations.begin(), priorLocations.end(), path) == priorLocations.end() ) {
- // TODO debug g_message(" ==>[%s]", path.c_str());
- priorLocations.push_back(path);
+ try {
+ std::string path = Glib::filename_from_uri(uri);
+ path = Glib::path_get_dirname(path);
+ if ( std::find(priorLocations.begin(), priorLocations.end(), path) == priorLocations.end() ) {
+ // TODO debug g_message(" ==>[%s]", path.c_str());
+ priorLocations.push_back(path);
+ }
+ } catch (Glib::ConvertError e) {
+ g_warning("Bad URL ignored [%s]", uri.c_str());
}
}
}
@@ -301,10 +305,10 @@ bool ResourceManagerImpl::fixupBrokenLinks(SPDocument *doc)
bool savedUndoState = DocumentUndo::getUndoSensitive(doc);
DocumentUndo::setUndoSensitive(doc, true);
-
- GSList const *images = doc->getResourceList("image");
- for (GSList const *it = images; it; it = it->next) {
- Inkscape::XML::Node *ir = static_cast<SPObject *>(it->data)->getRepr();
+
+ std::set<SPObject *> images = doc->getResourceList("image");
+ for (std::set<SPObject *>::const_iterator it = images.begin(); it != images.end(); ++it) {
+ Inkscape::XML::Node *ir = (*it)->getRepr();
gchar const *href = ir->attribute("xlink:href");
if ( href ) {
diff --git a/src/satisfied-guide-cns.cpp b/src/satisfied-guide-cns.cpp
index 028a22405..a83417865 100644
--- a/src/satisfied-guide-cns.cpp
+++ b/src/satisfied-guide-cns.cpp
@@ -10,8 +10,8 @@ void satisfied_guide_cns(SPDesktop const &desktop,
std::vector<SPGuideConstraint> &cns)
{
SPNamedView const &nv = *desktop.getNamedView();
- for (GSList const *l = nv.guides; l != NULL; l = l->next) {
- SPGuide &g = *SP_GUIDE(l->data);
+ for(std::vector<SPGuide *>::const_iterator it = nv.guides.begin(); it != nv.guides.end(); ++it) {
+ SPGuide &g = *(*it);
for (unsigned int i = 0; i < snappoints.size(); ++i) {
if (Geom::are_near(g.getDistanceFrom(snappoints[i].getPoint()), 0, 1e-2)) {
cns.push_back(SPGuideConstraint(&g, i));
diff --git a/src/selcue.cpp b/src/selcue.cpp
index c73219b7d..297b9fffc 100644
--- a/src/selcue.cpp
+++ b/src/selcue.cpp
@@ -104,7 +104,7 @@ void Inkscape::SelCue::_updateItemBboxes(gint mode, int prefs_bbox)
int bcount = 0;
std::vector<SPItem*> ll=_selection->itemList();
- for (std::vector<SPItem*>::const_iterator l = ll.begin(); l != ll.end(); l++) {
+ for (std::vector<SPItem*>::const_iterator l = ll.begin(); l != ll.end(); ++l) {
SPItem *item = *l;
SPCanvasItem* box = _item_bboxes[bcount ++];
@@ -147,7 +147,7 @@ void Inkscape::SelCue::_newItemBboxes()
int prefs_bbox = prefs->getBool("/tools/bounding_box");
std::vector<SPItem*> ll=_selection->itemList();
- for (std::vector<SPItem*>::const_iterator l = ll.begin(); l != ll.end(); l++) {
+ for (std::vector<SPItem*>::const_iterator l = ll.begin(); l != ll.end(); ++l) {
SPItem *item = *l;
Geom::OptRect const b = (prefs_bbox == 0) ?
@@ -202,7 +202,7 @@ void Inkscape::SelCue::_newTextBaselines()
_text_baselines.clear();
std::vector<SPItem*> ll = _selection->itemList();
- for (std::vector<SPItem*>::const_iterator l=ll.begin();l!=ll.end();l++) {
+ for (std::vector<SPItem*>::const_iterator l=ll.begin();l!=ll.end();++l) {
SPItem *item = *l;
SPCanvasItem* baseline_point = NULL;
diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp
index 3999156db..e6d5f174e 100644
--- a/src/selection-chemistry.cpp
+++ b/src/selection-chemistry.cpp
@@ -284,7 +284,7 @@ void SelectionHelper::fixSelection(SPDesktop *dt)
std::vector<SPItem*> const selList = selection->itemList();
- for( std::vector<SPItem*>::const_reverse_iterator i = selList.rbegin(); i != selList.rend(); i++ ) {
+ for( std::vector<SPItem*>::const_reverse_iterator i = selList.rbegin(); i != selList.rend(); ++i ) {
SPItem *item = *i;
if( item &&
!dt->isLayer(item) &&
@@ -330,7 +330,7 @@ static void sp_selection_copy_impl(std::vector<SPItem*> const &items, std::vecto
sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position_bool);
// Copy item reprs:
- for (std::vector<SPItem*>::const_iterator i = sorted_items.begin(); i != sorted_items.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = sorted_items.begin(); i != sorted_items.end(); ++i) {
SPItem *item = *i;
if (item) {
sp_selection_copy_one(item->getRepr(), item->i2doc_affine(), clip, xml_doc);
@@ -351,7 +351,7 @@ static std::vector<Inkscape::XML::Node*> sp_selection_paste_impl(SPDocument *doc
std::vector<Inkscape::XML::Node*> copied;
// add objects to document
- for (std::vector<Inkscape::XML::Node*>::const_iterator l = clip.begin(); l != clip.end(); l++) {
+ for (std::vector<Inkscape::XML::Node*>::const_iterator l = clip.begin(); l != clip.end(); ++l) {
Inkscape::XML::Node *repr = *l;
Inkscape::XML::Node *copy = repr->duplicate(xml_doc);
@@ -378,10 +378,10 @@ static std::vector<Inkscape::XML::Node*> sp_selection_paste_impl(SPDocument *doc
static void sp_selection_delete_impl(std::vector<SPItem*> const &items, bool propagate = true, bool propagate_descendants = true)
{
- for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); ++i) {
sp_object_ref(*i, NULL);
}
- for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); ++i) {
SPItem *item = *i;
item->deleteObject(propagate, propagate_descendants);
sp_object_unref(item, NULL);
@@ -475,7 +475,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone, bool duplicat
bool relink_clones = prefs->getBool("/options/relinkclonesonduplicate/value");
const bool fork_livepatheffects = prefs->getBool("/options/forklpeonduplicate/value", true);
- for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();i++){
+ for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();++i){
Inkscape::XML::Node *old_repr = *i;
Inkscape::XML::Node *parent = old_repr->parent();
Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
@@ -483,7 +483,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone, bool duplicat
if(! duplicateLayer)
parent->appendChild(copy);
else
- parent->addChild(copy, old_repr);
+ parent->addChild(copy, old_repr);
if (relink_clones) {
SPObject *old_obj = doc->getObjectByRepr(old_repr);
@@ -547,7 +547,7 @@ void sp_selection_duplicate(SPDesktop *desktop, bool suppressDone, bool duplicat
if(!duplicateLayer)
selection->setReprList(newsel);
else{
- SPObject* new_layer = doc->getObjectByRepr(newsel[0]);
+ SPObject* new_layer = doc->getObjectByRepr(newsel[0]);
gchar* name = g_strdup_printf(_("%s copy"), new_layer->label());
desktop->layer_manager->renameLayer( new_layer, name, TRUE );
g_free(name);
@@ -638,7 +638,7 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i
std::vector<SPItem*> all_items = sp_item_group_item_list(dynamic_cast<SPGroup *>(dt->currentLayer()));
- for (std::vector<SPItem*>::const_reverse_iterator i=all_items.rbegin();i!=all_items.rend();i++) {
+ for (std::vector<SPItem*>::const_reverse_iterator i=all_items.rbegin();i!=all_items.rend();++i) {
SPItem *item = *i;
if (item && (!onlysensitive || !item->isLocked())) {
@@ -655,7 +655,7 @@ static void sp_edit_select_all_full(SPDesktop *dt, bool force_all_layers, bool i
break;
}
case PREFS_SELECTION_LAYER_RECURSIVE: {
- std::vector<SPItem*> x;
+ std::vector<SPItem*> x;
items = get_all_items(x, dt->currentLayer(), dt, onlyvisible, onlysensitive, FALSE, exclude);
break;
}
@@ -698,7 +698,7 @@ static void sp_selection_group_impl(std::vector<Inkscape::XML::Node*> p, Inkscap
gint topmost = p.back()->position();
Inkscape::XML::Node *topmost_parent = p.back()->parent();
- for(std::vector<Inkscape::XML::Node*>::const_iterator i = p.begin(); i != p.end(); i++){
+ for(std::vector<Inkscape::XML::Node*>::const_iterator i = p.begin(); i != p.end(); ++i){
Inkscape::XML::Node *current = *i;
if (current->parent() == topmost_parent) {
@@ -802,7 +802,7 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop)
std::vector<SPItem*> old_select = selection->itemList();
std::vector<SPItem*> new_select;
GSList *groups = NULL;
- for (std::vector<SPItem*>::const_iterator item = old_select.begin(); item!=old_select.end(); item++) {
+ for (std::vector<SPItem*>::const_iterator item = old_select.begin(); item!=old_select.end(); ++item) {
SPItem *obj = *item;
if (dynamic_cast<SPGroup *>(obj)) {
groups = g_slist_prepend(groups, obj);
@@ -821,7 +821,7 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop)
// If any of the clones refer to the groups, unlink them and replace them with successors
// in the items list.
GSList *clones_to_unlink = NULL;
- for (std::vector<SPItem*>::const_iterator item = items.begin(); item != items.end(); item++) {
+ for (std::vector<SPItem*>::const_iterator item = items.begin(); item != items.end(); ++item) {
SPUse *use = dynamic_cast<SPUse *>(*item);
SPItem *original = use;
@@ -847,12 +847,12 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop)
g_slist_free(clones_to_unlink);
// do the actual work
- for (std::vector<SPItem*>::iterator item = items.begin(); item != items.end(); item++) {
+ for (std::vector<SPItem*>::iterator item = items.begin(); item != items.end(); ++item) {
SPItem *obj = *item;
// ungroup only the groups marked earlier
if (g_slist_find(groups, *item) != NULL) {
- std::vector<SPItem*> children;
+ std::vector<SPItem*> children;
sp_item_group_ungroup(dynamic_cast<SPGroup *>(obj), children, false);
// add the items resulting from ungrouping to the selection
new_select.insert(new_select.end(),children.begin(),children.end());
@@ -873,16 +873,16 @@ void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop)
std::vector<SPItem*>
sp_degroup_list(std::vector<SPItem*> &items)
{
- std::vector<SPItem*> out;
+ std::vector<SPItem*> out;
bool has_groups = false;
- for (std::vector<SPItem*>::const_iterator item=items.begin();item!=items.end();item++) {
+ for (std::vector<SPItem*>::const_iterator item=items.begin();item!=items.end();++item) {
SPGroup *group = dynamic_cast<SPGroup *>(*item);
if (!group) {
out.push_back(*item);
} else {
has_groups = true;
std::vector<SPItem*> members = sp_item_group_item_list(group);
- for (std::vector<SPItem*>::const_iterator member=members.begin();member!=members.end();member++) {
+ for (std::vector<SPItem*>::const_iterator member=members.begin();member!=members.end();++member) {
out.push_back(*member);
}
members.clear();
@@ -899,7 +899,7 @@ sp_degroup_list(std::vector<SPItem*> &items)
/** If items in the list have a common parent, return it, otherwise return NULL */
static SPGroup *
-sp_item_list_common_parent_group(std::vector<SPItem*> const items)
+sp_item_list_common_parent_group(std::vector<SPItem*> const &items)
{
if (items.empty()) {
return NULL;
@@ -909,8 +909,8 @@ sp_item_list_common_parent_group(std::vector<SPItem*> const items)
if (!dynamic_cast<SPGroup *>(parent)) {
return NULL;
}
- for (std::vector<SPItem*>::const_iterator item=items.begin();item!=items.end();item++) {
- if((*item)==items[0])continue;
+ for (std::vector<SPItem*>::const_iterator item=items.begin();item!=items.end();++item) {
+ if((*item)==items[0])continue;
if ((*item)->parent != parent) {
return NULL;
}
@@ -926,7 +926,7 @@ enclose_items(std::vector<SPItem*> const &items)
g_assert(!items.empty());
Geom::OptRect r;
- for (std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();++i) {
r.unionWith((*i)->desktopVisualBounds());
}
return r;
@@ -945,7 +945,7 @@ static SPObject *prev_sibling(SPObject *child)
bool sp_item_repr_compare_position_bool(SPObject const *first, SPObject const *second)
{
return sp_repr_compare_position(((SPItem*)first)->getRepr(),
- ((SPItem*)second)->getRepr())<0;
+ ((SPItem*)second)->getRepr())<0;
}
void
@@ -974,7 +974,7 @@ sp_selection_raise(Inkscape::Selection *selection, SPDesktop *desktop)
// Iterate over all objects in the selection (starting from top).
if (selected) {
- for (std::vector<SPItem*>::const_iterator item=rev.begin();item!=rev.end();item++) {
+ for (std::vector<SPItem*>::const_iterator item=rev.begin();item!=rev.end();++item) {
SPObject *child = *item;
// for each selected object, find the next sibling
for (SPObject *newref = child->next; newref; newref = newref->next) {
@@ -1019,7 +1019,7 @@ void sp_selection_raise_to_top(Inkscape::Selection *selection, SPDesktop *deskto
std::vector<Inkscape::XML::Node*> rl(selection->reprList());
sort(rl.begin(),rl.end(),sp_repr_compare_position_bool);
- for (std::vector<Inkscape::XML::Node*>::const_iterator l=rl.begin(); l!=rl.end();l++) {
+ for (std::vector<Inkscape::XML::Node*>::const_iterator l=rl.begin(); l!=rl.end();++l) {
Inkscape::XML::Node *repr =(*l);
repr->setPosition(-1);
}
@@ -1053,7 +1053,7 @@ void sp_selection_lower(Inkscape::Selection *selection, SPDesktop *desktop)
// Iterate over all objects in the selection (starting from top).
if (selected) {
- for (std::vector<SPItem*>::const_reverse_iterator item=rev.rbegin();item!=rev.rend();item++) {
+ for (std::vector<SPItem*>::const_reverse_iterator item=rev.rbegin();item!=rev.rend();++item) {
SPObject *child = *item;
// for each selected object, find the prev sibling
for (SPObject *newref = prev_sibling(child); newref; newref = prev_sibling(newref)) {
@@ -1103,7 +1103,7 @@ void sp_selection_lower_to_bottom(Inkscape::Selection *selection, SPDesktop *des
std::vector<Inkscape::XML::Node*> rl(selection->reprList());
sort(rl.begin(),rl.end(),sp_repr_compare_position_bool);
- for (std::vector<Inkscape::XML::Node*>::const_reverse_iterator l=rl.rbegin();l!=rl.rend();l++) {
+ for (std::vector<Inkscape::XML::Node*>::const_reverse_iterator l=rl.rbegin();l!=rl.rend();++l) {
gint minpos;
SPObject *pp, *pc;
Inkscape::XML::Node *repr = (*l);
@@ -1256,7 +1256,7 @@ void sp_selection_remove_livepatheffect(SPDesktop *desktop)
return;
}
std::vector<SPItem*> list=selection->itemList();
- for ( std::vector<SPItem*>::const_iterator itemlist=list.begin();itemlist!=list.end();itemlist++) {
+ for ( std::vector<SPItem*>::const_iterator itemlist=list.begin();itemlist!=list.end();++itemlist) {
SPItem *item = *itemlist;
sp_selection_remove_livepatheffect_impl(item);
@@ -1313,7 +1313,7 @@ void sp_selection_paste_size_separately(SPDesktop *desktop, bool apply_x, bool a
*/
void sp_selection_change_layer_maintain_clones(std::vector<SPItem*> const &items,SPObject *where)
{
- for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end(); ++i) {
SPItem *item = *i;
if (item) {
SPItem *oldparent = dynamic_cast<SPItem *>(item->parent);
@@ -1341,6 +1341,7 @@ void sp_selection_to_next_layer(SPDesktop *dt, bool suppressDone)
bool no_more = false; // Set to true, if no more layers above
SPObject *next=Inkscape::next_layer(dt->currentRoot(), dt->currentLayer());
if (next) {
+ selection->clear();
sp_selection_change_layer_maintain_clones(items,next);
std::vector<Inkscape::XML::Node*> temp_clip;
sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc());
@@ -1384,6 +1385,7 @@ void sp_selection_to_prev_layer(SPDesktop *dt, bool suppressDone)
bool no_more = false; // Set to true, if no more layers below
SPObject *next=Inkscape::previous_layer(dt->currentRoot(), dt->currentLayer());
if (next) {
+ selection->clear();
sp_selection_change_layer_maintain_clones(items,next);
std::vector<Inkscape::XML::Node*> temp_clip;
sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs
@@ -1424,6 +1426,7 @@ void sp_selection_to_layer(SPDesktop *dt, SPObject *moveto, bool suppressDone)
std::vector<SPItem*> items(selection->itemList());
if (moveto) {
+ selection->clear();
sp_selection_change_layer_maintain_clones(items,moveto);
std::vector<Inkscape::XML::Node*> temp_clip;
sp_selection_copy_impl(items, temp_clip, dt->doc()->getReprDoc()); // we're in the same doc, so no need to copy defs
@@ -1472,7 +1475,7 @@ selection_contains_both_clone_and_original(Inkscape::Selection *selection)
{
bool clone_with_original = false;
std::vector<SPItem*> items = selection->itemList();
- for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;l++) {
+ for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;++l) {
SPItem *item = *l;
if (item) {
clone_with_original |= selection_contains_original(item, selection);
@@ -1517,7 +1520,7 @@ void sp_selection_apply_affine(Inkscape::Selection *selection, Geom::Affine cons
persp3d_apply_affine_transformation(transf_persp, affine);
}
std::vector<SPItem*> items = selection->itemList();
- for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;l++) {
+ for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;++l) {
SPItem *item = *l;
if( dynamic_cast<SPRoot *>(item) ) {
@@ -1688,7 +1691,7 @@ void sp_selection_remove_transform(SPDesktop *desktop)
Inkscape::Selection *selection = desktop->getSelection();
std::vector<Inkscape::XML::Node*> items = selection->reprList();
- for (std::vector<Inkscape::XML::Node*>::const_iterator l=items.begin();l!=items.end() ;l++) {
+ for (std::vector<Inkscape::XML::Node*>::const_iterator l=items.begin();l!=items.end() ;++l) {
(*l)->setAttribute("transform", NULL, false);
}
@@ -1789,7 +1792,7 @@ void sp_selection_rotate_90(SPDesktop *desktop, bool ccw)
std::vector<SPItem*> items = selection->itemList();
Geom::Rotate const rot_90(Geom::Point(0, ccw ? 1 : -1)); // pos. or neg. rotation, depending on the value of ccw
- for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;l++) {
+ for (std::vector<SPItem*>::const_iterator l=items.begin();l!=items.end() ;++l) {
SPItem *item = *l;
if (item) {
sp_item_rotate_rel(item, rot_90);
@@ -1854,14 +1857,14 @@ void sp_select_same_fill_stroke_style(SPDesktop *desktop, gboolean fill, gboolea
std::vector<SPItem*> items = selection->itemList();
std::vector<SPItem*> tmp;
- for (std::vector<SPItem*>::const_iterator iter=all_list.begin();iter!=all_list.end();iter++) {
+ for (std::vector<SPItem*>::const_iterator iter=all_list.begin();iter!=all_list.end();++iter) {
if(!SP_IS_GROUP(*iter)){
tmp.push_back(*iter);
}
}
all_list=tmp;
- for (std::vector<SPItem*>::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) {
+ for (std::vector<SPItem*>::const_iterator sel_iter=items.begin();sel_iter!=items.end();++sel_iter) {
SPItem *sel = *sel_iter;
std::vector<SPItem*> matches = all_list;
if (fill && stroke && style) {
@@ -1909,7 +1912,7 @@ void sp_select_same_object_type(SPDesktop *desktop)
Inkscape::Selection *selection = desktop->getSelection();
std::vector<SPItem*> items=selection->itemList();
- for (std::vector<SPItem*>::const_iterator sel_iter=items.begin();sel_iter!=items.end();sel_iter++) {
+ for (std::vector<SPItem*>::const_iterator sel_iter=items.begin();sel_iter!=items.end();++sel_iter) {
SPItem *sel = *sel_iter;
if (sel) {
matches = sp_get_same_object_type(sel, matches);
@@ -1936,7 +1939,7 @@ std::vector<SPItem*> sp_get_same_fill_or_stroke_color(SPItem *sel, std::vector<S
SPIPaint *sel_paint = (type == SP_FILL_COLOR) ? &(sel->style->fill) : &(sel->style->stroke);
- for (std::vector<SPItem*>::const_reverse_iterator i=src.rbegin();i!=src.rend();i++) {
+ for (std::vector<SPItem*>::const_reverse_iterator i=src.rbegin();i!=src.rend();++i) {
SPItem *iter = *i;
if (iter) {
SPIPaint *iter_paint = (type == SP_FILL_COLOR) ? &(iter->style->fill) : &(iter->style->stroke);
@@ -2031,7 +2034,7 @@ std::vector<SPItem*> sp_get_same_object_type(SPItem *sel, std::vector<SPItem*> &
{
std::vector<SPItem*> matches;
- for (std::vector<SPItem*>::const_reverse_iterator i=src.rbegin();i!=src.rend();i++) {
+ for (std::vector<SPItem*>::const_reverse_iterator i=src.rbegin();i!=src.rend();++i) {
SPItem *item = *i;
if (item && item_type_match(sel, item) && !item->cloned) {
matches.push_back(item);
@@ -2072,7 +2075,7 @@ std::vector<SPItem*> sp_get_same_style(SPItem *sel, std::vector<SPItem*> &src, S
objects_query_strokewidth (objects, sel_style_for_width);
}
bool match_g;
- for (std::vector<SPItem*>::const_iterator i=src.begin();i!=src.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i=src.begin();i!=src.end();++i) {
SPItem *iter = *i;
if (iter) {
match_g=true;
@@ -2112,7 +2115,7 @@ std::vector<SPItem*> sp_get_same_style(SPItem *sel, std::vector<SPItem*> &src, S
}
}
}
- match_g = match_g && match;
+ match_g = match_g && match;
if (match_g) {
while (iter->cloned) iter=dynamic_cast<SPItem *>(iter->parent);
matches.insert(matches.begin(),iter);
@@ -2371,11 +2374,11 @@ SPItem *next_item(SPDesktop *desktop, GSList *path, SPObject *root,
template <typename D>
-SPItem *next_item_from_list(SPDesktop *desktop, std::vector<SPItem*> const items,
+SPItem *next_item_from_list(SPDesktop *desktop, std::vector<SPItem*> const &items,
SPObject *root, bool only_in_viewport, PrefsSelectionContext inlayer, bool onlyvisible, bool onlysensitive)
{
SPObject *current=root;
- for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++) {
+ for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();++i) {
SPItem *item = *i;
if ( root->isAncestorOf(item) &&
( !only_in_viewport || desktop->isWithinViewport(item) ) )
@@ -2577,8 +2580,8 @@ void sp_selection_clone(SPDesktop *desktop)
std::vector<Inkscape::XML::Node*> newsel;
- for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();i++){
- Inkscape::XML::Node *sel_repr = *i;
+ for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();++i){
+ Inkscape::XML::Node *sel_repr = *i;
Inkscape::XML::Node *parent = sel_repr->parent();
Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");
@@ -2628,7 +2631,7 @@ sp_selection_relink(SPDesktop *desktop)
// Get a copy of current selection.
bool relinked = false;
std::vector<SPItem*> items=selection->itemList();
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
SPItem *item = *i;
if (dynamic_cast<SPUse *>(item)) {
@@ -2666,7 +2669,7 @@ sp_selection_unlink(SPDesktop *desktop)
std::vector<SPItem*> new_select;
bool unlinked = false;
std::vector<SPItem*> items=selection->itemList();
- for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){
+ for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();++i){
SPItem *item = *i;
if (dynamic_cast<SPText *>(item)) {
@@ -2831,7 +2834,7 @@ void sp_selection_clone_original_path_lpe(SPDesktop *desktop)
Inkscape::SVGOStringStream os;
SPObject * firstItem = NULL;
std::vector<SPItem*> items=selection->itemList();
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
if (SP_IS_SHAPE(*i) || SP_IS_TEXT(*i)) {
if (firstItem) {
os << "|";
@@ -2934,7 +2937,7 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply)
// Create a list of duplicates, to be pasted inside marker element.
std::vector<Inkscape::XML::Node*> repr_copies;
- for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){
+ for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();++i){
Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc);
repr_copies.push_back(dup);
}
@@ -2944,7 +2947,7 @@ void sp_selection_to_marker(SPDesktop *desktop, bool apply)
if (apply) {
// Delete objects so that their clones don't get alerted;
// the objects will be restored inside the marker element.
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
SPObject *item = *i;
item->deleteObject(false);
}
@@ -2973,7 +2976,7 @@ static void sp_selection_to_guides_recursive(SPItem *item, bool wholegroups) {
SPGroup *group = dynamic_cast<SPGroup *>(item);
if (group && !dynamic_cast<SPBox3D *>(item) && !wholegroups) {
std::vector<SPItem*> items=sp_item_group_item_list(group);
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
sp_selection_to_guides_recursive(*i, wholegroups);
}
} else {
@@ -3004,7 +3007,7 @@ void sp_selection_to_guides(SPDesktop *desktop)
// and its entry in the selection list is invalid (crash).
// Therefore: first convert all, then delete all.
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
sp_selection_to_guides_recursive(*i, wholegroups);
}
@@ -3056,6 +3059,7 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ )
doc->ensureUpToDate();
std::vector<SPObject*> items(selection->list());
+ sort(items.begin(),items.end(),sp_object_compare_position_bool);
// Keep track of parent, this is where <use> will be inserted.
Inkscape::XML::Node *the_first_repr = items[0]->getRepr();
@@ -3105,7 +3109,9 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ )
symbol_repr->setAttribute("style", the_group->getAttribute("style"));
symbol_repr->setAttribute("class", the_group->getAttribute("class"));
- symbol_repr->setAttribute("id", the_group->getAttribute("id") );
+ Glib::ustring id = the_group->getAttribute("id");
+ the_group->setAttribute("id", id + "_transform");
+ symbol_repr->setAttribute("id", id);
// This should eventually be replaced by 'refX' and 'refY' once SVG WG approves it.
// It is done here for round-tripping
@@ -3115,14 +3121,11 @@ void sp_selection_symbol(SPDesktop *desktop, bool /*apply*/ )
the_group->getAttribute("inkscape:transform-center-y"));
the_group->setAttribute("style", NULL);
- Glib::ustring id = symbol_repr->attribute("id");
- id += "_transform";
- the_group->setAttribute("id", id);
}
// Move selected items to new <symbol>
- for (std::vector<SPObject*>::const_iterator i=items.begin();i!=items.end();i++){
+ for (std::vector<SPObject*>::const_reverse_iterator i=items.rbegin();i!=items.rend();++i){
Inkscape::XML::Node *repr = (*i)->getRepr();
repr->parent()->removeChild(repr);
symbol_repr->addChild(repr,NULL);
@@ -3206,7 +3209,7 @@ void sp_selection_unsymbol(SPDesktop *desktop)
}
}
- for (std::vector<SPObject*>::const_reverse_iterator i=children.rbegin();i!=children.rend();i++){
+ for (std::vector<SPObject*>::const_reverse_iterator i=children.rbegin();i!=children.rend();++i){
Inkscape::XML::Node *repr = (*i)->getRepr();
repr->parent()->removeChild(repr);
group->addChild(repr,NULL);
@@ -3290,7 +3293,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply)
// create a list of duplicates
std::vector<Inkscape::XML::Node*> repr_copies;
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc);
repr_copies.push_back(dup);
}
@@ -3299,7 +3302,7 @@ sp_selection_tile(SPDesktop *desktop, bool apply)
if (apply) {
// delete objects so that their clones don't get alerted; this object will be restored shortly
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
SPObject *item = *i;
item->deleteObject(false);
}
@@ -3373,7 +3376,7 @@ void sp_selection_untile(SPDesktop *desktop)
bool did = false;
std::vector<SPItem*> items(selection->itemList());
- for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();i++){
+ for (std::vector<SPItem*>::const_reverse_iterator i=items.rbegin();i!=items.rend();++i){
SPItem *item = *i;
SPStyle *style = item->style;
@@ -3442,7 +3445,7 @@ void sp_selection_get_export_hints(Inkscape::Selection *selection, Glib::ustring
bool xdpi_search = TRUE;
bool ydpi_search = TRUE;
- for (std::vector<Inkscape::XML::Node*>::const_iterator i=reprlst.begin();filename_search&&xdpi_search&&ydpi_search&&i!=reprlst.end();i++){
+ for (std::vector<Inkscape::XML::Node*>::const_iterator i=reprlst.begin();filename_search&&xdpi_search&&ydpi_search&&i!=reprlst.end();++i){
gchar const *dpi_string;
Inkscape::XML::Node *repr = *i;
@@ -3493,7 +3496,6 @@ void sp_document_get_export_hints(SPDocument *doc, Glib::ustring &filename, floa
*xdpi = atof(dpi_string);
}
- dpi_string = NULL;
dpi_string = repr->attribute("inkscape:export-ydpi");
if (dpi_string != NULL) {
*ydpi = atof(dpi_string);
@@ -3743,8 +3745,8 @@ void sp_selection_set_clipgroup(SPDesktop *desktop)
Inkscape::XML::Node *inner = xml_doc->createElement("svg:g");
inner->setAttribute("inkscape:label", "Clip");
- for(std::vector<Inkscape::XML::Node*>::const_iterator i=p.begin();i!=p.end();i++){
- Inkscape::XML::Node *current = *i;
+ for(std::vector<Inkscape::XML::Node*>::const_iterator i=p.begin();i!=p.end();++i){
+ Inkscape::XML::Node *current = *i;
if (current->parent() == topmost_parent) {
Inkscape::XML::Node *spnew = current->duplicate(xml_doc);
@@ -3879,12 +3881,12 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_
apply_to_items.push_back(SP_ITEM(desktop->currentLayer()));
}
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i) {
if((!topmost && !apply_to_layer && *i == items.front())
|| (topmost && !apply_to_layer && *i == items.back())
- || apply_to_layer){
+ || apply_to_layer){
- Geom::Affine oldtr=(*i)->transform;
+ Geom::Affine oldtr=(*i)->transform;
(*i)->doWriteTransform((*i)->getRepr(), (*i)->i2doc_affine());
Inkscape::XML::Node *dup = (*i)->getRepr()->duplicate(xml_doc);
(*i)->doWriteTransform((*i)->getRepr(), oldtr);
@@ -3896,7 +3898,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_
else {
items_to_select.push_back(*i);
}
- continue;
+ continue;
}else{
apply_to_items.push_back(*i);
items_to_select.push_back(*i);
@@ -3914,7 +3916,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_
group->setAttribute("inkscape:groupmode", "maskhelper");
std::vector<Inkscape::XML::Node*> reprs_to_group;
- for (std::vector<SPItem*>::const_iterator i = apply_to_items.begin(); i != apply_to_items.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = apply_to_items.begin(); i != apply_to_items.end(); ++i) {
reprs_to_group.push_back(static_cast<SPObject*>(*i)->getRepr());
}
items_to_select.clear();
@@ -3935,13 +3937,13 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_
gchar const *attributeName = apply_clip_path ? "clip-path" : "mask";
- for (std::vector<SPItem*>::const_reverse_iterator i = apply_to_items.rbegin(); i != apply_to_items.rend(); i++) {
+ for (std::vector<SPItem*>::const_reverse_iterator i = apply_to_items.rbegin(); i != apply_to_items.rend(); ++i) {
SPItem *item = reinterpret_cast<SPItem *>(*i);
// inverted object transform should be applied to a mask object,
// as mask is calculated in user space (after applying transform)
std::vector<Inkscape::XML::Node*> mask_items_dup;
- for(std::vector<Inkscape::XML::Node*>::const_iterator it=mask_items.begin();it!=mask_items.end();it++)
- mask_items_dup.push_back((*it)->duplicate(xml_doc));
+ for(std::vector<Inkscape::XML::Node*>::const_iterator it=mask_items.begin();it!=mask_items.end();++it)
+ mask_items_dup.push_back((*it)->duplicate(xml_doc));
Inkscape::XML::Node *current = SP_OBJECT(*i)->getRepr();
// Node to apply mask to
Inkscape::XML::Node *apply_mask_to = current;
@@ -3980,7 +3982,7 @@ void sp_selection_set_mask(SPDesktop *desktop, bool apply_clip_path, bool apply_
}
- for (std::vector<SPItem*>::const_iterator i = items_to_delete.begin(); i != items_to_delete.end(); i++) {
+ for (std::vector<SPItem*>::const_iterator i = items_to_delete.begin(); i != items_to_delete.end(); ++i) {
SPObject *item = reinterpret_cast<SPObject*>(*i);
item->deleteObject(false);
items_to_select.erase(remove(items_to_select.begin(), items_to_select.end(), item), items_to_select.end());
@@ -4027,7 +4029,7 @@ void sp_selection_unset_mask(SPDesktop *desktop, bool apply_clip_path) {
// SPObject* refers to a group containing the clipped path or mask itself,
// whereas SPItem* refers to the item being clipped or masked
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
if (remove_original) {
// remember referenced mask/clippath, so orphaned masks can be moved back to document
SPItem *item = *i;
diff --git a/src/selection-chemistry.h b/src/selection-chemistry.h
index 5bcc5b1ea..4bfa2c0aa 100644
--- a/src/selection-chemistry.h
+++ b/src/selection-chemistry.h
@@ -22,7 +22,6 @@
class SPCSSAttr;
class SPDesktop;
-typedef struct _GSList GSList;
namespace Inkscape {
@@ -75,7 +74,6 @@ void sp_selection_unsymbol(SPDesktop *desktop);
void sp_selection_tile(SPDesktop *desktop, bool apply = true);
void sp_selection_untile(SPDesktop *desktop);
-//void sp_selection_group_impl(GSList const *reprs_to_group, Inkscape::XML::Node *group, Inkscape::XML::Document *xml_doc, SPDocument *doc);
void sp_selection_group(Inkscape::Selection *selection, SPDesktop *desktop);
void sp_selection_ungroup(Inkscape::Selection *selection, SPDesktop *desktop);
diff --git a/src/selection-describer.cpp b/src/selection-describer.cpp
index 8304db684..ddc7a0d10 100644
--- a/src/selection-describer.cpp
+++ b/src/selection-describer.cpp
@@ -46,7 +46,7 @@ char* collect_terms (const std::vector<SPItem*> &items)
std::stringstream ss;
bool first = true;
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();++iter ) {
SPItem *item = *iter;
if (item) {
const char *term = item->displayName();
@@ -65,7 +65,7 @@ static int count_terms (const std::vector<SPItem*> &items)
{
GSList *check = NULL;
int count=0;
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();++iter ) {
SPItem *item = *iter;
if (item) {
const char *term = item->displayName();
@@ -82,7 +82,7 @@ static int count_terms (const std::vector<SPItem*> &items)
static int count_filtered (const std::vector<SPItem*> &items)
{
int count=0;
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();++iter ) {
SPItem *item = *iter;
if (item) {
count += item->isFiltered();
diff --git a/src/selection.cpp b/src/selection.cpp
index 77a507eec..6fc426be7 100644
--- a/src/selection.cpp
+++ b/src/selection.cpp
@@ -255,7 +255,7 @@ void Selection::addList(std::vector<SPItem*> const &list) {
_invalidateCachedLists();
- for ( std::vector<SPItem*>::const_iterator iter=list.begin();iter!=list.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=list.begin();iter!=list.end(); ++iter) {
SPObject *obj = *iter;
if (includes(obj)) continue;
_add (obj);
@@ -267,7 +267,7 @@ void Selection::addList(std::vector<SPItem*> const &list) {
void Selection::setReprList(std::vector<XML::Node*> const &list) {
_clear();
- for ( std::vector<XML::Node*>::const_reverse_iterator iter=list.rbegin();iter!=list.rend();iter++ ) {
+ for ( std::vector<XML::Node*>::const_reverse_iterator iter=list.rbegin();iter!=list.rend(); ++iter) {
SPObject *obj=_objectForXMLNode(*iter);
if (obj) {
_add(obj);
@@ -286,7 +286,7 @@ std::vector<SPObject*> const &Selection::list() {
if(!_objs_vector.empty())
return _objs_vector;
- for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) {
+ for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end(); ++iter) {
_objs_vector.push_back(*iter);
}
return _objs_vector;
@@ -298,7 +298,7 @@ std::vector<SPItem*> const &Selection::itemList() {
return _items;
}
- for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) {
+ for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end(); ++iter) {
SPObject *obj=*iter;
if (SP_IS_ITEM(obj)) {
_items.push_back(SP_ITEM(obj));
@@ -310,7 +310,7 @@ std::vector<SPItem*> const &Selection::itemList() {
std::vector<XML::Node*> const &Selection::reprList() {
if (!_reprs.empty()) { return _reprs; }
std::vector<SPItem*> list = itemList();
- for ( std::vector<SPItem*>::const_iterator iter=list.begin();iter!=list.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=list.begin();iter!=list.end(); ++iter) {
SPObject *obj = *iter;
_reprs.push_back(obj->getRepr());
}
@@ -372,9 +372,9 @@ SPItem *Selection::_sizeistItem(bool sml, Selection::CompareSize compare) {
gdouble max = sml ? 1e18 : 0;
SPItem *ist = NULL;
- for ( std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++ ) {
+ for ( std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i) {
Geom::OptRect obox = SP_ITEM(*i)->desktopPreferredBounds();
- if (!obox || obox.isEmpty()) continue;
+ if (!obox || obox.empty()) continue;
Geom::Rect bbox = *obox;
gdouble size = compare == 2 ? bbox.area() :
@@ -404,7 +404,7 @@ Geom::OptRect Selection::geometricBounds() const
std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList();
Geom::OptRect bbox;
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
bbox.unionWith(SP_ITEM(*iter)->desktopGeometricBounds());
}
return bbox;
@@ -415,7 +415,7 @@ Geom::OptRect Selection::visualBounds() const
std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList();
Geom::OptRect bbox;
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
bbox.unionWith(SP_ITEM(*iter)->desktopVisualBounds());
}
return bbox;
@@ -436,7 +436,7 @@ Geom::OptRect Selection::documentBounds(SPItem::BBoxType type) const
std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList();
if (items.empty()) return bbox;
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
SPItem *item = SP_ITEM(*iter);
bbox |= item->documentBounds(type);
}
@@ -463,19 +463,21 @@ boost::optional<Geom::Point> Selection::center() const {
}
std::vector<Inkscape::SnapCandidatePoint> Selection::getSnapPoints(SnapPreferences const *snapprefs) const {
- std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList();
-
- SnapPreferences snapprefs_dummy = *snapprefs; // create a local copy of the snapping prefs
- snapprefs_dummy.setTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER, false); // locally disable snapping to the item center
std::vector<Inkscape::SnapCandidatePoint> p;
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
- SPItem *this_item = *iter;
- this_item->getSnappoints(p, &snapprefs_dummy);
-
- //Include the transformation origin for snapping
- //For a selection or group only the overall center is considered, not for each item individually
- if (snapprefs != NULL && snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER)) {
- p.push_back(Inkscape::SnapCandidatePoint(this_item->getCenter(), SNAPSOURCE_ROTATION_CENTER));
+
+ if (snapprefs != NULL){
+ SnapPreferences snapprefs_dummy = *snapprefs; // create a local copy of the snapping prefs
+ snapprefs_dummy.setTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER, false); // locally disable snapping to the item center
+ std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList();
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
+ SPItem *this_item = *iter;
+ this_item->getSnappoints(p, &snapprefs_dummy);
+
+ //Include the transformation origin for snapping
+ //For a selection or group only the overall center is considered, not for each item individually
+ if (snapprefs->isTargetSnappable(Inkscape::SNAPTARGET_ROTATION_CENTER)) {
+ p.push_back(Inkscape::SnapCandidatePoint(this_item->getCenter(), SNAPSOURCE_ROTATION_CENTER));
+ }
}
}
@@ -484,7 +486,7 @@ std::vector<Inkscape::SnapCandidatePoint> Selection::getSnapPoints(SnapPreferenc
void Selection::_removeObjectDescendants(SPObject *obj) {
std::vector<SPObject*> toremove;
- for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end();iter++ ) {
+ for ( std::list<SPObject*>::const_iterator iter=_objs.begin();iter!=_objs.end(); ++iter) {
SPObject *sel_obj= dynamic_cast<SPObject*>(*iter);
SPObject *parent = sel_obj->parent;
while (parent) {
@@ -495,7 +497,7 @@ void Selection::_removeObjectDescendants(SPObject *obj) {
parent = parent->parent;
}
}
- for ( std::vector<SPObject*>::const_iterator iter=toremove.begin();iter!=toremove.end();iter++ ) {
+ for ( std::vector<SPObject*>::const_iterator iter=toremove.begin();iter!=toremove.end(); ++iter) {
_remove(*iter);
}
}
@@ -522,7 +524,7 @@ SPObject *Selection::_objectForXMLNode(Inkscape::XML::Node *repr) const {
size_t Selection::numberOfLayers() {
std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList();
std::set<SPObject*> layers;
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
SPObject *layer = _layers->layerForObject(*iter);
layers.insert(layer);
}
@@ -532,7 +534,7 @@ size_t Selection::numberOfLayers() {
size_t Selection::numberOfParents() {
std::vector<SPItem*> const items = const_cast<Selection *>(this)->itemList();
std::set<SPObject*> parents;
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
SPObject *parent = (*iter)->parent;
parents.insert(parent);
}
diff --git a/src/seltrans.cpp b/src/seltrans.cpp
index f7562923f..b54525610 100644
--- a/src/seltrans.cpp
+++ b/src/seltrans.cpp
@@ -31,6 +31,7 @@
#include "knot.h"
#include "message-stack.h"
#include "snap.h"
+#include "pure-transform.h"
#include "selection.h"
#include "ui/tools/select-tool.h"
#include "sp-item.h"
@@ -240,7 +241,7 @@ void Inkscape::SelTrans::setCenter(Geom::Point const &p)
// Write the new center position into all selected items
std::vector<SPItem*> items=_desktop->selection->itemList();
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
SPItem *it = SP_ITEM(*iter);
it->setCenter(p);
// only set the value; updating repr and document_done will be done once, on ungrab
@@ -270,7 +271,7 @@ void Inkscape::SelTrans::grab(Geom::Point const &p, gdouble x, gdouble y, bool s
}
std::vector<SPItem*> items=_desktop->selection->itemList();
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
SPItem *it = static_cast<SPItem*>(sp_object_ref(*iter, NULL));
_items.push_back(it);
_items_const.push_back(it);
@@ -492,7 +493,7 @@ void Inkscape::SelTrans::ungrab()
if (_center_is_set) {
// we were dragging center; update reprs and commit undoable action
std::vector<SPItem*> items=_desktop->selection->itemList();
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
SPItem *it = *iter;
it->updateRepr();
}
@@ -533,7 +534,7 @@ void Inkscape::SelTrans::stamp()
_stamp_cache = l;
}
- for(std::vector<SPItem*>::const_iterator x=l.begin();x!=l.end();x++) {
+ for(std::vector<SPItem*>::const_iterator x=l.begin();x!=l.end(); ++x) {
SPItem *original_item = *x;
Inkscape::XML::Node *original_repr = original_item->getRepr();
@@ -711,7 +712,7 @@ void Inkscape::SelTrans::handleClick(SPKnot */*knot*/, guint state, SPSelTransHa
if (state & GDK_SHIFT_MASK) {
// Unset the center position for all selected items
std::vector<SPItem*> items=_desktop->selection->itemList();
- for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end();iter++ ) {
+ for ( std::vector<SPItem*>::const_iterator iter=items.begin();iter!=items.end(); ++iter) {
SPItem *it = *iter;
it->unsetCenter();
it->updateRepr();
@@ -897,10 +898,7 @@ gboolean Inkscape::SelTrans::scaleRequest(Geom::Point &pt, guint state)
// When scaling by an integer, snapping is not needed
} else {
// In all other cases we should try to snap now
- SnapManager &m = _desktop->namedview->snap_manager;
- m.setup(_desktop, false, _items_const);
-
- Inkscape::SnappedPoint bb, sn;
+ Inkscape::PureScale *bb, *sn;
if ((state & GDK_CONTROL_MASK) || _desktop->isToolboxButtonActive ("lock")) {
// Scale is locked to a 1:1 aspect ratio, so that s[X] must be made to equal s[Y].
@@ -915,30 +913,37 @@ gboolean Inkscape::SelTrans::scaleRequest(Geom::Point &pt, guint state)
}
// Snap along a suitable constraint vector from the origin.
- bb = m.constrainedSnapScale(_bbox_points, _point, default_scale, _origin_for_bboxpoints);
- sn = m.constrainedSnapScale(_snap_points, _point, geom_scale, _origin_for_specpoints);
+
+ bb = new Inkscape::PureScaleConstrained(default_scale, _origin_for_bboxpoints);
+ sn = new Inkscape::PureScaleConstrained(geom_scale, _origin_for_specpoints);
} else {
/* Scale aspect ratio is unlocked */
- bb = m.freeSnapScale(_bbox_points, _point, default_scale, _origin_for_bboxpoints);
- sn = m.freeSnapScale(_snap_points, _point, geom_scale, _origin_for_specpoints);
+ bb = new Inkscape::PureScale(default_scale, _origin_for_bboxpoints, false);
+ sn = new Inkscape::PureScale(geom_scale, _origin_for_specpoints, false);
}
+ SnapManager &m = _desktop->namedview->snap_manager;
+ m.setup(_desktop, false, _items_const);
+ m.snapTransformed(_bbox_points, _point, (*bb));
+ m.snapTransformed(_snap_points, _point, (*sn));
+ m.unSetup();
// These lines below are duplicated in stretchRequest
- if (bb.getSnapped() || sn.getSnapped()) {
- if (bb.getSnapped()) {
- if (!bb.isOtherSnapBetter(sn, false)) {
+ //TODO: Eliminate this code duplication
+ if (bb->best_snapped_point.getSnapped() || sn->best_snapped_point.getSnapped()) {
+ if (bb->best_snapped_point.getSnapped()) {
+ if (!bb->best_snapped_point.isOtherSnapBetter(sn->best_snapped_point, false)) {
// We snapped the bbox (which is either visual or geometric)
- _desktop->snapindicator->set_new_snaptarget(bb);
- default_scale = Geom::Scale(bb.getTransformation());
+ _desktop->snapindicator->set_new_snaptarget(bb->best_snapped_point);
+ default_scale = bb->getScaleSnapped();
// Calculate the new transformation and update the handle position
pt = _calcAbsAffineDefault(default_scale);
}
- } else if (sn.getSnapped()) {
- _desktop->snapindicator->set_new_snaptarget(sn);
+ } else if (sn->best_snapped_point.getSnapped()) {
+ _desktop->snapindicator->set_new_snaptarget(sn->best_snapped_point);
// We snapped the special points (e.g. nodes), which are not at the visual bbox
// The handle location however (pt) might however be at the visual bbox, so we
// will have to calculate pt taking the stroke width into account
- geom_scale = Geom::Scale(sn.getTransformation());
+ geom_scale = sn->getScaleSnapped();
pt = _calcAbsAffineGeom(geom_scale);
}
} else {
@@ -946,7 +951,9 @@ gboolean Inkscape::SelTrans::scaleRequest(Geom::Point &pt, guint state)
_calcAbsAffineDefault(default_scale);
_desktop->snapindicator->remove_snaptarget();
}
- m.unSetup();
+
+ delete bb;
+ delete sn;
}
/* Status text */
@@ -1003,21 +1010,22 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, Geom
SnapManager &m = _desktop->namedview->snap_manager;
m.setup(_desktop, false, _items_const);
- Inkscape::SnappedPoint bb, sn;
- g_assert(bb.getSnapped() == false); // Check initialization to catch any regression
-
bool symmetrical = state & GDK_CONTROL_MASK;
- bb = m.constrainedSnapStretch(_bbox_points, _point, Geom::Coord(default_scale[axis]), _origin_for_bboxpoints, Geom::Dim2(axis), symmetrical);
- sn = m.constrainedSnapStretch(_snap_points, _point, Geom::Coord(geom_scale[axis]), _origin_for_specpoints, Geom::Dim2(axis), symmetrical);
+ Inkscape::PureStretchConstrained bb = Inkscape::PureStretchConstrained(Geom::Coord(default_scale[axis]), _origin_for_bboxpoints, Geom::Dim2(axis), symmetrical);
+ Inkscape::PureStretchConstrained sn = Inkscape::PureStretchConstrained(Geom::Coord(geom_scale[axis]), _origin_for_specpoints, Geom::Dim2(axis), symmetrical);
- if (bb.getSnapped()) {
+ m.snapTransformed(_bbox_points, _point, bb);
+ m.snapTransformed(_snap_points, _point, sn);
+ m.unSetup();
+
+ if (bb.best_snapped_point.getSnapped()) {
// We snapped the bbox (which is either visual or geometric)
- default_scale[axis] = bb.getTransformation()[axis];
+ default_scale[axis] = bb.getMagnitude();
}
- if (sn.getSnapped()) {
- geom_scale[axis] = sn.getTransformation()[axis];
+ if (sn.best_snapped_point.getSnapped()) {
+ geom_scale[axis] = sn.getMagnitude();
}
if (symmetrical) {
@@ -1028,21 +1036,21 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, Geom
}
// These lines below are duplicated in scaleRequest
- if (bb.getSnapped() || sn.getSnapped()) {
- if (bb.getSnapped()) {
- if (!bb.isOtherSnapBetter(sn, false)) {
+ if (bb.best_snapped_point.getSnapped() || sn.best_snapped_point.getSnapped()) {
+ if (bb.best_snapped_point.getSnapped()) {
+ if (!bb.best_snapped_point.isOtherSnapBetter(sn.best_snapped_point, false)) {
// We snapped the bbox (which is either visual or geometric)
- _desktop->snapindicator->set_new_snaptarget(bb);
- default_scale = Geom::Scale(bb.getTransformation());
+ _desktop->snapindicator->set_new_snaptarget(bb.best_snapped_point);
+ default_scale = bb.getStretchSnapped();
// Calculate the new transformation and update the handle position
pt = _calcAbsAffineDefault(default_scale);
}
- } else if (sn.getSnapped()) {
- _desktop->snapindicator->set_new_snaptarget(sn);
+ } else if (sn.best_snapped_point.getSnapped()) {
+ _desktop->snapindicator->set_new_snaptarget(sn.best_snapped_point);
// We snapped the special points (e.g. nodes), which are not at the visual bbox
// The handle location however (pt) might however be at the visual bbox, so we
// will have to calculate pt taking the stroke width into account
- geom_scale = Geom::Scale(sn.getTransformation());
+ geom_scale = sn.getStretchSnapped();
pt = _calcAbsAffineGeom(geom_scale);
}
} else {
@@ -1050,8 +1058,6 @@ gboolean Inkscape::SelTrans::stretchRequest(SPSelTransHandle const &handle, Geom
_calcAbsAffineDefault(default_scale);
_desktop->snapindicator->remove_snaptarget();
}
-
- m.unSetup();
}
// status text
@@ -1156,16 +1162,14 @@ gboolean Inkscape::SelTrans::skewRequest(SPSelTransHandle const &handle, Geom::P
SnapManager &m = _desktop->namedview->snap_manager;
m.setup(_desktop, false, _items_const);
- Geom::Point cvec; cvec[dim_b] = 1.;
- Inkscape::Snapper::SnapConstraint const constraint(cvec);
- // When skewing, we cannot snap the corners of the bounding box, see the comment in "constrainedSnapSkew" for details
- Geom::Point const s(skew[dim_a], scale[dim_a]);
- Inkscape::SnappedPoint sn = m.constrainedSnapSkew(_snap_points, _point, constraint, s, _origin, Geom::Dim2(dim_b));
+ // When skewing, we cannot snap the corners of the bounding box, see the comment in PureSkewConstrained for details
+ Inkscape::PureSkewConstrained sn = Inkscape::PureSkewConstrained(skew[dim_a], scale[dim_a], _origin, Geom::Dim2(dim_b));
+ m.snapTransformed(_snap_points, _point, sn);
- if (sn.getSnapped()) {
+ if (sn.best_snapped_point.getSnapped()) {
// We snapped something, so change the skew to reflect it
- skew[dim_a] = sn.getTransformation()[0];
- _desktop->snapindicator->set_new_snaptarget(sn);
+ skew[dim_a] = sn.getSkewSnapped();
+ _desktop->snapindicator->set_new_snaptarget(sn.best_snapped_point);
} else {
_desktop->snapindicator->remove_snaptarget();
}
@@ -1191,7 +1195,7 @@ gboolean Inkscape::SelTrans::skewRequest(SPSelTransHandle const &handle, Geom::P
}
// Update the status text
- double degrees = mod360symm(Geom::rad_to_deg(radians));
+ double degrees = mod360symm(Geom::deg_from_rad(radians));
_message_context.setF(Inkscape::IMMEDIATE_MESSAGE,
// TRANSLATORS: don't modify the first ";"
// (it will NOT be displayed as ";" - only the second one will be)
@@ -1243,13 +1247,14 @@ gboolean Inkscape::SelTrans::rotateRequest(Geom::Point &pt, guint state)
SnapManager &m = _desktop->namedview->snap_manager;
m.setup(_desktop, false, _items_const);
// When rotating, we cannot snap the corners of the bounding box, see the comment in "constrainedSnapRotate" for details
- Inkscape::SnappedPoint sn = m.constrainedSnapRotate(_snap_points, _point, radians, _origin);
+ Inkscape::PureRotateConstrained sn = Inkscape::PureRotateConstrained(radians, _origin);
+ m.snapTransformed(_snap_points, _point, sn);
m.unSetup();
- if (sn.getSnapped()) {
- _desktop->snapindicator->set_new_snaptarget(sn);
+ if (sn.best_snapped_point.getSnapped()) {
+ _desktop->snapindicator->set_new_snaptarget(sn.best_snapped_point);
// We snapped something, so change the rotation to reflect it
- radians = sn.getTransformation()[0];
+ radians = sn.getAngleSnapped();
r1 = Geom::Rotate(0);
r2 = Geom::Rotate(radians);
} else {
@@ -1266,7 +1271,7 @@ gboolean Inkscape::SelTrans::rotateRequest(Geom::Point &pt, guint state)
pt = _point * Geom::Translate(-_origin) * _relative_affine * Geom::Translate(_origin);
// Update the status text
- double degrees = mod360symm(Geom::rad_to_deg(radians));
+ double degrees = mod360symm(Geom::deg_from_rad(radians));
_message_context.setF(Inkscape::IMMEDIATE_MESSAGE,
// TRANSLATORS: don't modify the first ";"
// (it will NOT be displayed as ";" - only the second one will be)
@@ -1352,30 +1357,19 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state)
bool const control = (state & GDK_CONTROL_MASK);
bool const shift = (state & GDK_SHIFT_MASK);
- if (alt) {
-
- // Alt pressed means: move only by integer multiples of the grid spacing
-
- if (control) { // ... if also constrained to the orthogonal axes
- if (fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y])) {
- dxy[Geom::Y] = 0;
- } else {
- dxy[Geom::X] = 0;
- }
+ if (control) { // constrained to the orthogonal axes
+ if (fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y])) {
+ dxy[Geom::Y] = 0;
+ } else {
+ dxy[Geom::X] = 0;
}
+ }
+
+ if (alt) {// Alt pressed means: move only by integer multiples of the grid spacing
m.setup(_desktop, true, _items_const);
dxy = m.multipleOfGridPitch(dxy, _point);
m.unSetup();
- } else if (shift) {
- if (control) { // shift & control: constrained movement without snapping
- if (fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y])) {
- dxy[Geom::Y] = 0;
- } else {
- dxy[Geom::X] = 0;
- }
- }
- } else { //!shift: with snapping
-
+ } else if (!shift) { //!shift: with snapping
/* We're snapping to things, possibly with a constraint to horizontal or
** vertical movement. Obtain a list of possible translations and then
** pick the smallest.
@@ -1386,52 +1380,55 @@ void Inkscape::SelTrans::moveTo(Geom::Point const &xy, guint state)
/* This will be our list of possible translations */
std::list<Inkscape::SnappedPoint> s;
+ Inkscape::PureTranslate *bb, *sn;
+
if (control) { // constrained movement with snapping
/* Snap to things, and also constrain to horizontal or vertical movement */
- unsigned int dim = fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y]) ? Geom::X : Geom::Y;
+ Geom::Dim2 dim = fabs(dxy[Geom::X]) > fabs(dxy[Geom::Y]) ? Geom::X : Geom::Y;
// When doing a constrained translation, all points will move in the same direction, i.e.
// either horizontally or vertically. Therefore we only have to specify the direction of
// the constraint-line once. The constraint lines are parallel, but might not be colinear.
// Therefore we will have to set the point through which the constraint-line runs
- // individually for each point to be snapped; this will be handled however by _snapTransformed()
- Geom::Point cvec; cvec[dim] = 1.;
- s.push_back(m.constrainedSnapTranslate(_bbox_points,
- _point,
- Inkscape::Snapper::SnapConstraint(cvec),
- dxy));
-
- s.push_back(m.constrainedSnapTranslate(_snap_points,
- _point,
- Inkscape::Snapper::SnapConstraint(cvec),
- dxy));
+ // individually for each point to be snapped; this will be handled however by snapTransformed()
+ bb = new Inkscape::PureTranslateConstrained(dxy[dim], dim);
+ sn = new Inkscape::PureTranslateConstrained(dxy[dim], dim);
} else { // !control
-
- // Let's leave this timer code here for a while. I'll probably need it in the near future (Diederik van Lierop)
- /* GTimeVal starttime;
- GTimeVal endtime;
- g_get_current_time(&starttime); */
-
/* Snap to things with no constraint */
- s.push_back(m.freeSnapTranslate(_bbox_points, _point, dxy));
- s.push_back(m.freeSnapTranslate(_snap_points, _point, dxy));
-
- /*g_get_current_time(&endtime);
- double elapsed = ((((double)endtime.tv_sec - starttime.tv_sec) * G_USEC_PER_SEC + (endtime.tv_usec - starttime.tv_usec))) / 1000.0;
- std::cout << "Time spent snapping: " << elapsed << std::endl; */
+ bb = new Inkscape::PureTranslate(dxy);
+ sn = new Inkscape::PureTranslate(dxy);
}
+ // Let's leave this timer code here for a while. I'll probably need it in the near future (Diederik van Lierop)
+ /* GTimeVal starttime;
+ GTimeVal endtime;
+ g_get_current_time(&starttime); */
+
+ m.snapTransformed(_bbox_points, _point, (*bb));
+ m.snapTransformed(_snap_points, _point, (*sn));
m.unSetup();
+ /*g_get_current_time(&endtime);
+ double elapsed = ((((double)endtime.tv_sec - starttime.tv_sec) * G_USEC_PER_SEC + (endtime.tv_usec - starttime.tv_usec))) / 1000.0;
+ std::cout << "Time spent snapping: " << elapsed << std::endl; */
+
/* Pick one */
Inkscape::SnappedPoint best_snapped_point;
- for (std::list<Inkscape::SnappedPoint>::const_iterator i = s.begin(); i != s.end(); ++i) {
- if (i->getSnapped()) {
- if (best_snapped_point.isOtherSnapBetter(*i, true)) {
- best_snapped_point = *i;
- dxy = i->getTransformation();
- }
- }
+
+ bool sn_is_best = sn->best_snapped_point.getSnapped();
+ bool bb_is_best = bb->best_snapped_point.getSnapped();
+
+ if (bb_is_best && sn_is_best) {
+ sn_is_best = bb->best_snapped_point.isOtherSnapBetter(sn->best_snapped_point, true);
+ bb_is_best = !sn_is_best;
+ }
+
+ if (sn_is_best) {
+ best_snapped_point = sn->best_snapped_point;
+ dxy = sn->getTranslationSnapped();
+ } else if (bb_is_best) {
+ best_snapped_point = bb->best_snapped_point;
+ dxy = bb->getTranslationSnapped();
}
if (best_snapped_point.getSnapped()) {
@@ -1609,7 +1606,7 @@ void Inkscape::SelTrans::_keepClosestPointOnly(Geom::Point const &p)
}
}
-
+// TODO: This code is duplicated in transform-handle-set.cpp; fix this!
void Inkscape::SelTrans::getNextClosestPoint(bool reverse)
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -1635,6 +1632,12 @@ void Inkscape::SelTrans::getNextClosestPoint(bool reverse)
} else {
_snap_points.push_back(*_all_snap_sources_iter);
}
+
+ // Show the updated snap source now; otherwise it won't be shown until the selection is being moved again
+ SnapManager &m = _desktop->namedview->snap_manager;
+ m.setup(_desktop);
+ m.displaySnapsource(*_all_snap_sources_iter);
+ m.unSetup();
}
}
}
diff --git a/src/seltrans.h b/src/seltrans.h
index 26c2e9cd9..f756cc77a 100644
--- a/src/seltrans.h
+++ b/src/seltrans.h
@@ -34,7 +34,6 @@ class SPDesktop;
struct SPCanvasItem;
struct SPCtrlLine;
struct SPSelTransHandle;
-typedef struct _GSList GSList;
namespace Inkscape {
diff --git a/src/shortcuts.cpp b/src/shortcuts.cpp
index e72c16de0..194d4d2a4 100644
--- a/src/shortcuts.cpp
+++ b/src/shortcuts.cpp
@@ -575,7 +575,14 @@ static void read_shortcuts_file(char const *filename, bool const is_user_set) {
}
Inkscape::Verb *verb=Inkscape::Verb::getbyid(verb_name);
- if (!verb) {
+ if (!verb
+#if !HAVE_POTRACE
+ // Squash warning about disabled features
+ && strcmp(verb_name, "ToolPaintBucket") != 0
+ && strcmp(verb_name, "SelectionTrace") != 0
+ && strcmp(verb_name, "PaintBucketPrefs") != 0
+#endif
+ ) {
g_warning("Unknown verb name: %s", verb_name);
continue;
}
diff --git a/src/snap.cpp b/src/snap.cpp
index 5a308777c..7f0e8d9dc 100644
--- a/src/snap.cpp
+++ b/src/snap.cpp
@@ -23,6 +23,7 @@
#include "snap-enums.h"
#include "snapped-line.h"
#include "snapped-curve.h"
+#include "pure-transform.h"
#include "display/canvas-grid.h"
#include "display/snap-indicator.h"
@@ -68,9 +69,8 @@ SnapManager::SnapperList SnapManager::getGridSnappers() const
SnapperList s;
if (_desktop && _desktop->gridsEnabled() && snapprefs.isTargetSnappable(Inkscape::SNAPTARGET_GRID)) {
- for ( GSList const *l = _named_view->grids; l != NULL; l = l->next) {
- Inkscape::CanvasGrid *grid = (Inkscape::CanvasGrid*) l->data;
- s.push_back(grid->snapper);
+ for(std::vector<Inkscape::CanvasGrid *>::const_iterator it = _named_view->grids.begin(); it != _named_view->grids.end(); ++it) {
+ s.push_back((*it)->snapper);
}
}
@@ -172,8 +172,8 @@ Geom::Point SnapManager::multipleOfGridPitch(Geom::Point const &t, Geom::Point c
// Cannot use getGridSnappers() because we need both the grids AND their snappers
// Therefore we iterate through all grids manually
- for (GSList const *l = _named_view->grids; l != NULL; l = l->next) {
- Inkscape::CanvasGrid *grid = (Inkscape::CanvasGrid*) l->data;
+ for (std::vector<Inkscape::CanvasGrid *>::const_iterator it = _named_view->grids.begin(); it != _named_view->grids.end(); ++it) {
+ Inkscape::CanvasGrid *grid = (*it);
const Inkscape::Snapper* snapper = grid->snapper;
if (snapper && snapper->ThisSnapperMightSnap()) {
// To find the nearest multiple of the grid pitch for a given translation t, we
@@ -442,16 +442,11 @@ void SnapManager::guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline)
s.getPointIfSnapped(p);
}
-Inkscape::SnappedPoint SnapManager::_snapTransformed(
+void SnapManager::snapTransformed(
std::vector<Inkscape::SnapCandidatePoint> const &points,
Geom::Point const &pointer,
- bool constrained,
- Inkscape::Snapper::SnapConstraint const &constraint,
- Transformation transformation_type,
- Geom::Point const &transformation,
- Geom::Point const &origin,
- Geom::Dim2 dim,
- bool uniform)
+ Inkscape::PureTransform &transform
+ )
{
/* We have a list of points, which we are proposing to transform in some way. We need to see
** if any of these points, when transformed, snap to anything. If they do, we return the
@@ -459,47 +454,8 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
*/
if (points.size() == 0) {
- return Inkscape::SnappedPoint(pointer);
- }
-
- std::vector<Inkscape::SnapCandidatePoint> transformed_points;
- Geom::Rect bbox;
-
- long source_num = 0;
- for (std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); ++i) {
-
- /* Work out the transformed version of this point */
- Geom::Point transformed = _transformPoint(*i, transformation_type, transformation, origin, dim, uniform);
-
- // add the current transformed point to the box hulling all transformed points
- if (i == points.begin()) {
- bbox = Geom::Rect(transformed, transformed);
- } else {
- bbox.expandTo(transformed);
- }
-
- transformed_points.push_back(Inkscape::SnapCandidatePoint(transformed, (*i).getSourceType(), source_num, Inkscape::SNAPTARGET_UNDEFINED, Geom::OptRect()));
- source_num++;
- }
-
- /* The current best transformation */
- Geom::Point best_transformation = transformation;
-
- /* The current best metric for the best transformation; lower is better, Geom::infinity()
- ** means that we haven't snapped anything.
- */
- Inkscape::SnappedPoint best_snapped_point;
- g_assert(best_snapped_point.getAlwaysSnap() == false); // Check initialization of snapped point
- g_assert(best_snapped_point.getAtIntersection() == false);
-
- // Warnings for the devs
- if (constrained && transformation_type == SCALE && !uniform) {
- g_warning("Non-uniform constrained scaling is not supported!");
- }
-
- if (!constrained && transformation_type == ROTATE) {
- // We do not yet allow for simultaneous rotation and scaling
- g_warning("Unconstrained rotation is not supported!");
+ transform.best_snapped_point = Inkscape::SnappedPoint(pointer);
+ return;
}
// We will try to snap a set of points, but we don't want to have a snap indicator displayed
@@ -508,349 +464,22 @@ Inkscape::SnappedPoint SnapManager::_snapTransformed(
bool _orig_snapindicator_status = _snapindicator;
_snapindicator = false;
- std::vector<Inkscape::SnapCandidatePoint>::iterator j = transformed_points.begin();
-
- // std::cout << std::endl;
- bool first_free_snap = true;
-
- for (std::vector<Inkscape::SnapCandidatePoint>::const_iterator i = points.begin(); i != points.end(); ++i) {
-
- /* Snap it */
- Inkscape::SnappedPoint snapped_point;
- Inkscape::Snapper::SnapConstraint dedicated_constraint = constraint;
- Geom::Point const b = ((*i).getPoint() - origin); // vector to original point (not the transformed point! required for rotations!)
-
- if (constrained) {
- if (((transformation_type == SCALE || transformation_type == STRETCH) && uniform)) {
- // When uniformly scaling, each point will have its own unique constraint line,
- // running from the scaling origin to the original untransformed point. We will
- // calculate that line here
- dedicated_constraint = Inkscape::Snapper::SnapConstraint(origin, b);
- } else if (transformation_type == ROTATE) {
- Geom::Coord r = Geom::L2(b); // the radius of the circular constraint
- dedicated_constraint = Inkscape::Snapper::SnapConstraint(origin, b, r);
- } else if (transformation_type == STRETCH) { // when non-uniform stretching {
- Geom::Point cvec; cvec[dim] = 1.;
- dedicated_constraint = Inkscape::Snapper::SnapConstraint((*i).getPoint(), cvec);
- } else if (transformation_type == TRANSLATE) {
- // When doing a constrained translation, all points will move in the same direction, i.e.
- // either horizontally or vertically. The lines along which they move are therefore all
- // parallel, but might not be colinear. Therefore we will have to specify the point through
- // which the constraint-line runs here, for each point individually. (we could also have done this
- // earlier on, e.g. in seltrans.cpp but we're being lazy there and don't want to add an iteration loop)
- dedicated_constraint = Inkscape::Snapper::SnapConstraint((*i).getPoint(), constraint.getDirection());
- } // else: leave the original constraint, e.g. for skewing
- snapped_point = constrainedSnap(*j, dedicated_constraint, bbox);
- } else {
- bool const c1 = fabs(b[Geom::X]) < 1e-6;
- bool const c2 = fabs(b[Geom::Y]) < 1e-6;
- if (transformation_type == SCALE && (c1 || c2) && !(c1 && c2)) {
- // When scaling, a point aligned either horizontally or vertically with the origin can only
- // move in that specific direction; therefore it should only snap in that direction, otherwise
- // we will get snapped points with an invalid transformation
- Geom::Point cvec; cvec[c1] = 1.;
- dedicated_constraint = Inkscape::Snapper::SnapConstraint(origin, cvec);
- snapped_point = constrainedSnap(*j, dedicated_constraint, bbox);
- } else {
- // If we have a collection of SnapCandidatePoints, with mixed constrained snapping and free snapping
- // requirements, then freeSnap might never see the SnapCandidatePoint with source_num == 0. The freeSnap()
- // method in the object snapper depends on this, because only for source-num == 0 the target nodes will
- // be collected. Therefore we enforce that the first SnapCandidatePoint that is to be freeSnapped always
- // has source_num == 0;
- // TODO: This is a bit ugly so fix this; do we need sourcenum for anything else? if we don't then get rid
- // of it and explicitly communicate to the object snapper that this is a first point
- if (first_free_snap) {
- (*j).setSourceNum(0);
- first_free_snap = false;
- }
- snapped_point = freeSnap(*j, bbox);
- }
- }
- // std::cout << "dist = " << snapped_point.getSnapDistance() << std::endl;
- snapped_point.setPointerDistance(Geom::L2(pointer - (*i).getPoint()));
-
- // Allow the snapindicator to be displayed again
- _snapindicator = _orig_snapindicator_status;
-
- Geom::Point result;
-
- /*Find the transformation that describes where the snapped point has
- ** ended up, and also the metric for this transformation.
- */
- Geom::Point const a = snapped_point.getPoint() - origin; // vector to snapped point
- //Geom::Point const b = (*i - origin); // vector to original point
-
- switch (transformation_type) {
- case TRANSLATE:
- result = snapped_point.getPoint() - (*i).getPoint();
- /* Consider the case in which a box is almost aligned with a grid in both
- * horizontal and vertical directions. The distance to the intersection of
- * the grid lines will always be larger then the distance to a single grid
- * line. If we prefer snapping to an intersection over to a single
- * grid line, then we cannot use "metric = Geom::L2(result)". Therefore the
- * snapped distance will be used as a metric. Please note that the snapped
- * distance to an intersection is defined as the distance to the nearest line
- * of the intersection, and not to the intersection itself!
- */
- // Only for translations, the relevant metric will be the real snapped distance,
- // so we don't have to do anything special here
- break;
- case SCALE:
- {
- result = Geom::Point(Geom::infinity(), Geom::infinity());
- // If this point *i is horizontally or vertically aligned with
- // the origin of the scaling, then it will scale purely in X or Y
- // We can therefore only calculate the scaling in this direction
- // and the scaling factor for the other direction should remain
- // untouched (unless scaling is uniform of course)
- for (int index = 0; index < 2; index++) {
- if (fabs(b[index]) > 1e-4) { // if SCALING CAN occur in this direction
- if (fabs(fabs(a[index]/b[index]) - fabs(transformation[index])) > 1e-7) { // if SNAPPING DID occur in this direction
- result[index] = a[index] / b[index]; // then calculate it!
- }
- // we might have left result[1-index] = Geom::infinity()
- // if scaling didn't occur in the other direction
- }
- }
- if (uniform) {
- if (fabs(result[0]) < fabs(result[1])) {
- result[1] = result[0];
- } else {
- result[0] = result[1];
- }
- }
-
- // Compare the resulting scaling with the desired scaling
- Geom::Point scale_metric = result - transformation; // One or both of its components might be Geom::infinity()
- scale_metric[0] = fabs(scale_metric[0]);
- scale_metric[1] = fabs(scale_metric[1]);
- if (scale_metric[0] == Geom::infinity() || scale_metric[1] == Geom::infinity()) {
- snapped_point.setSnapDistance(std::min(scale_metric[0], scale_metric[1]));
- } else {
- snapped_point.setSnapDistance(Geom::L2(scale_metric));
- }
- snapped_point.setSecondSnapDistance(Geom::infinity());
- break;
- }
- case STRETCH:
- result = Geom::Point(Geom::infinity(), Geom::infinity());
- if (fabs(b[dim]) > 1e-6) { // if STRETCHING will occur for this point
- result[dim] = a[dim] / b[dim];
- result[1-dim] = uniform ? result[dim] : 1;
- } else { // STRETCHING might occur for this point, but only when the stretching is uniform
- if (uniform && fabs(b[1-dim]) > 1e-6) {
- result[1-dim] = a[1-dim] / b[1-dim];
- result[dim] = result[1-dim];
- }
- }
- // Store the metric for this transformation as a virtual distance
- snapped_point.setSnapDistance(std::abs(result[dim] - transformation[dim]));
- snapped_point.setSecondSnapDistance(Geom::infinity());
- break;
- case SKEW:
- result[0] = (snapped_point.getPoint()[dim] - ((*i).getPoint())[dim]) / b[1 - dim]; // skew factor
- result[1] = transformation[1]; // scale factor
- // Store the metric for this transformation as a virtual distance
- snapped_point.setSnapDistance(std::abs(result[0] - transformation[0]));
- snapped_point.setSecondSnapDistance(Geom::infinity());
- break;
- case ROTATE:
- // a is vector to snapped point; b is vector to original point; now lets calculate angle between a and b
- result[0] = atan2(Geom::dot(Geom::rot90(b), a), Geom::dot(b, a));
- result[1] = result[0]; // dummy value; how else should we store an angle in a point ;-)
- if (Geom::L2(b) < 1e-9) { // points too close to the rotation center will not move. Don't try to snap these
- // as they will always yield a perfect snap result if they're already snapped beforehand (e.g.
- // when the transformation center has been snapped to a grid intersection in the selector tool)
- snapped_point.setSnapDistance(Geom::infinity());
- // PS1: Apparently we don't have to do this for skewing, but why?
- // PS2: We cannot easily filter these points upstream, e.g. in the grab() method (seltrans.cpp)
- // because the rotation center will change when pressing shift, and grab() won't be recalled.
- // Filtering could be done in handleRequest() (again in seltrans.cpp), by iterating through
- // the snap candidates. But hey, we're iterating here anyway.
- } else {
- snapped_point.setSnapDistance(std::abs(result[0] - transformation[0]));
- }
- snapped_point.setSecondSnapDistance(Geom::infinity());
- break;
- default:
- g_assert_not_reached();
- }
-
- if (snapped_point.getSnapped()) {
- // We snapped; keep track of the best snap
- if (best_snapped_point.isOtherSnapBetter(snapped_point, true)) {
- best_transformation = result;
- best_snapped_point = snapped_point;
- }
- } else {
- // So we didn't snap for this point
- if (!best_snapped_point.getSnapped()) {
- // ... and none of the points before snapped either
- // We might still need to apply a constraint though, if we tried a constrained snap. And
- // in case of a free snap we might have use for the transformed point, so let's return that
- // point, whether it's constrained or not
- if (best_snapped_point.isOtherSnapBetter(snapped_point, true) || points.size() == 1) {
- // .. so we must keep track of the best non-snapped constrained point
- best_transformation = result;
- best_snapped_point = snapped_point;
- }
- }
- }
-
- ++j;
- }
-
- Geom::Coord best_metric;
- if (transformation_type == SCALE) {
- // When scaling, don't ever exit with one of scaling components uninitialized
- for (int index = 0; index < 2; index++) {
- if (fabs(best_transformation[index]) == Geom::infinity()) {
- if (uniform && fabs(best_transformation[1-index]) < Geom::infinity()) {
- best_transformation[index] = best_transformation[1-index];
- } else {
- best_transformation[index] = transformation[index];
- }
- }
- }
- }
+ transform.snap(this, points, pointer);
- best_metric = best_snapped_point.getSnapDistance();
- best_snapped_point.setTransformation(best_transformation);
- // Using " < 1e6" instead of " < Geom::infinity()" for catching some rounding errors
- // These rounding errors might be caused by NRRects, see bug #1584301
- best_snapped_point.setSnapDistance(best_metric < 1e6 ? best_metric : Geom::infinity());
+ // Allow the snapindicator to be displayed again
+ _snapindicator = _orig_snapindicator_status;
if (_snapindicator) {
- if (best_snapped_point.getSnapped()) {
- _desktop->snapindicator->set_new_snaptarget(best_snapped_point);
+ if (transform.best_snapped_point.getSnapped()) {
+ _desktop->snapindicator->set_new_snaptarget(transform.best_snapped_point);
} else {
_desktop->snapindicator->remove_snaptarget();
}
}
- return best_snapped_point;
-}
-
-
-Inkscape::SnappedPoint SnapManager::freeSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Geom::Point const &tr)
-{
- Inkscape::SnappedPoint result = _snapTransformed(p, pointer, false, Geom::Point(0,0), TRANSLATE, tr, Geom::Point(0,0), Geom::X, false);
-
- if (p.size() == 1) {
- displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType()));
- }
- return result;
-}
-
-Inkscape::SnappedPoint SnapManager::constrainedSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Inkscape::Snapper::SnapConstraint const &constraint,
- Geom::Point const &tr)
-{
- Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, constraint, TRANSLATE, tr, Geom::Point(0,0), Geom::X, false);
-
- if (p.size() == 1) {
- displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType()));
- }
-
- return result;
-}
-
-
-Inkscape::SnappedPoint SnapManager::freeSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Geom::Scale const &s,
- Geom::Point const &o)
-{
- Inkscape::SnappedPoint result = _snapTransformed(p, pointer, false, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, false);
-
- if (p.size() == 1) {
- displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType()));
- }
-
- return result;
-}
-
-
-Inkscape::SnappedPoint SnapManager::constrainedSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Geom::Scale const &s,
- Geom::Point const &o)
-{
- // When constrained scaling, only uniform scaling is supported.
- Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, Geom::Point(0,0), SCALE, Geom::Point(s[Geom::X], s[Geom::Y]), o, Geom::X, true);
-
- if (p.size() == 1) {
- displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType()));
- }
-
- return result;
-}
-
-Inkscape::SnappedPoint SnapManager::constrainedSnapStretch(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Geom::Coord const &s,
- Geom::Point const &o,
- Geom::Dim2 d,
- bool u)
-{
- Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, Geom::Point(0,0), STRETCH, Geom::Point(s, s), o, d, u);
-
- if (p.size() == 1) {
- displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType()));
- }
-
- return result;
-}
-
-Inkscape::SnappedPoint SnapManager::constrainedSnapSkew(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Inkscape::Snapper::SnapConstraint const &constraint,
- Geom::Point const &s,
- Geom::Point const &o,
- Geom::Dim2 d)
-{
- // "s" contains skew factor in s[0], and scale factor in s[1]
-
- // Snapping the nodes of the bounding box of a selection that is being transformed, will only work if
- // the transformation of the bounding box is equal to the transformation of the individual nodes. This is
- // NOT the case for example when rotating or skewing. The bounding box itself cannot possibly rotate or skew,
- // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping
- // of bounding boxes is not allowed here.
- if (!p.empty()) {
- g_assert(!(p.at(0).getSourceType() & Inkscape::SNAPSOURCE_BBOX_CATEGORY));
- }
-
- Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, constraint, SKEW, s, o, d, false);
-
- if (p.size() == 1) {
- displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType()));
- }
-
- return result;
-}
-
-Inkscape::SnappedPoint SnapManager::constrainedSnapRotate(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Geom::Coord const &angle,
- Geom::Point const &o)
-{
- // Snapping the nodes of the bounding box of a selection that is being transformed, will only work if
- // the transformation of the bounding box is equal to the transformation of the individual nodes. This is
- // NOT the case for example when rotating or skewing. The bounding box itself cannot possibly rotate or skew,
- // so it's corners have a different transformation. The snappers cannot handle this, therefore snapping
- // of bounding boxes is not allowed here.
-
- Inkscape::SnappedPoint result = _snapTransformed(p, pointer, true, Geom::Point(0,0), ROTATE, Geom::Point(angle, angle), o, Geom::X, false);
-
- if (p.size() == 1) {
- displaySnapsource(Inkscape::SnapCandidatePoint(result.getPoint(), p.at(0).getSourceType()));
+ if (points.size() == 1) {
+ displaySnapsource(Inkscape::SnapCandidatePoint(transform.best_snapped_point.getPoint(), points.at(0).getSourceType()));
}
-
- return result;
-
}
Inkscape::SnappedPoint SnapManager::findBestSnap(Inkscape::SnapCandidatePoint const &p,
@@ -1080,7 +709,7 @@ void SnapManager::setupIgnoreSelection(SPDesktop const *desktop,
Inkscape::Selection *sel = _desktop->selection;
std::vector<SPItem*> const items = sel->itemList();
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i) {
_items_to_ignore.push_back(*i);
}
}
@@ -1090,51 +719,51 @@ SPDocument *SnapManager::getDocument() const
return _named_view->document;
}
-Geom::Point SnapManager::_transformPoint(Inkscape::SnapCandidatePoint const &p,
- Transformation const transformation_type,
- Geom::Point const &transformation,
- Geom::Point const &origin,
- Geom::Dim2 const dim,
- bool const uniform) const
-{
- /* Work out the transformed version of this point */
- Geom::Point transformed;
- switch (transformation_type) {
- case TRANSLATE:
- transformed = p.getPoint() + transformation;
- break;
- case SCALE:
- transformed = (p.getPoint() - origin) * Geom::Scale(transformation[Geom::X], transformation[Geom::Y]) + origin;
- break;
- case STRETCH:
- {
- Geom::Scale s(1, 1);
- if (uniform)
- s[Geom::X] = s[Geom::Y] = transformation[dim];
- else {
- s[dim] = transformation[dim];
- s[1 - dim] = 1;
- }
- transformed = ((p.getPoint() - origin) * s) + origin;
- break;
- }
- case SKEW:
- // Apply the skew factor
- transformed[dim] = (p.getPoint())[dim] + transformation[0] * ((p.getPoint())[1 - dim] - origin[1 - dim]);
- // While skewing, mirroring and scaling (by integer multiples) in the opposite direction is also allowed.
- // Apply that scale factor here
- transformed[1-dim] = (p.getPoint() - origin)[1 - dim] * transformation[1] + origin[1 - dim];
- break;
- case ROTATE:
- // for rotations: transformation[0] stores the angle in radians
- transformed = (p.getPoint() - origin) * Geom::Rotate(transformation[0]) + origin;
- break;
- default:
- g_assert_not_reached();
- }
-
- return transformed;
-}
+//Geom::Point SnapManager::_transformPoint(Inkscape::SnapCandidatePoint const &p,
+// Transformation const transformation_type,
+// Geom::Point const &transformation,
+// Geom::Point const &origin,
+// Geom::Dim2 const dim,
+// bool const uniform) const
+//{
+// /* Work out the transformed version of this point */
+// Geom::Point transformed;
+// switch (transformation_type) {
+// case TRANSLATE:
+// transformed = p.getPoint() + transformation;
+// break;
+// case SCALE:
+// transformed = (p.getPoint() - origin) * Geom::Scale(transformation[Geom::X], transformation[Geom::Y]) + origin;
+// break;
+// case STRETCH:
+// {
+// Geom::Scale s(1, 1);
+// if (uniform)
+// s[Geom::X] = s[Geom::Y] = transformation[dim];
+// else {
+// s[dim] = transformation[dim];
+// s[1 - dim] = 1;
+// }
+// transformed = ((p.getPoint() - origin) * s) + origin;
+// break;
+// }
+// case SKEW:
+// // Apply the skew factor
+// transformed[dim] = (p.getPoint())[dim] + transformation[0] * ((p.getPoint())[1 - dim] - origin[1 - dim]);
+// // While skewing, mirroring and scaling (by integer multiples) in the opposite direction is also allowed.
+// // Apply that scale factor here
+// transformed[1-dim] = (p.getPoint() - origin)[1 - dim] * transformation[1] + origin[1 - dim];
+// break;
+// case ROTATE:
+// // for rotations: transformation[0] stores the angle in radians
+// transformed = (p.getPoint() - origin) * Geom::Rotate(transformation[0]) + origin;
+// break;
+// default:
+// g_assert_not_reached();
+// }
+//
+// return transformed;
+//}
/**
* Mark the location of the snap source (not the snap target!) on the canvas by drawing a symbol.
diff --git a/src/snap.h b/src/snap.h
index 944c49b3e..41d21b1b2 100644
--- a/src/snap.h
+++ b/src/snap.h
@@ -21,6 +21,8 @@
#include "guide-snapper.h"
#include "object-snapper.h"
#include "snap-preferences.h"
+//#include "pure-transform.h"
+
// Guides
enum SPGuideDragType { // used both here and in desktop-events.cpp
@@ -32,7 +34,11 @@ enum SPGuideDragType { // used both here and in desktop-events.cpp
class SPGuide;
class SPNamedView;
-typedef struct _GSList GSList;
+
+namespace Inkscape {
+ class PureTransform;
+}
+
/**
* Class to coordinate snapping operations.
@@ -327,110 +333,6 @@ public:
*/
void guideConstrainedSnap(Geom::Point &p, SPGuide const &guideline) const;
- /**
- * Apply a translation to a set of points and try to snap freely in 2 degrees-of-freedom.
- *
- * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
- * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
- * @param tr Proposed translation; the final translation can only be calculated after snapping has occurred.
- * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
- */
- Inkscape::SnappedPoint freeSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Geom::Point const &tr);
-
- /**
- * Apply a translation to a set of points and try to snap along a constraint.
- *
- * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
- * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
- * @param constraint The direction or line along which snapping must occur.
- * @param tr Proposed translation; the final translation can only be calculated after snapping has occurred.
- * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
- */
- Inkscape::SnappedPoint constrainedSnapTranslate(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Inkscape::Snapper::SnapConstraint const &constraint,
- Geom::Point const &tr);
-
- /**
- * Apply a scaling to a set of points and try to snap freely in 2 degrees-of-freedom.
- *
- * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
- * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
- * @param s Proposed scaling; the final scaling can only be calculated after snapping has occurred.
- * @param o Origin of the scaling.
- * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
- */
- Inkscape::SnappedPoint freeSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Geom::Scale const &s,
- Geom::Point const &o);
-
- /**
- * Apply a scaling to a set of points and snap such that the aspect ratio of the selection is preserved.
- *
- * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
- * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
- * @param s Proposed scaling; the final scaling can only be calculated after snapping has occurred.
- * @param o Origin of the scaling.
- * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
- */
- Inkscape::SnappedPoint constrainedSnapScale(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Geom::Scale const &s,
- Geom::Point const &o);
-
- /**
- * Apply a stretch to a set of points and snap such that the direction of the stretch is preserved.
- *
- * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
- * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
- * @param s Proposed stretch; the final stretch can only be calculated after snapping has occurred.
- * @param o Origin of the stretching.
- * @param d Dimension in which to apply proposed stretch.
- * @param u true if the stretch should be uniform (i.e. to be applied equally in both dimensions).
- * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
- */
- Inkscape::SnappedPoint constrainedSnapStretch(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Geom::Coord const &s,
- Geom::Point const &o,
- Geom::Dim2 d,
- bool uniform);
-
- /**
- * Apply a skew to a set of points and snap such that the direction of the skew is preserved.
- *
- * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
- * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
- * @param constraint The direction or line along which snapping must occur.
- * @param s Proposed skew; the final skew can only be calculated after snapping has occurred.
- * @param o Origin of the proposed skew.
- * @param d Dimension in which to apply proposed skew.
- * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
- */
- Inkscape::SnappedPoint constrainedSnapSkew(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Inkscape::Snapper::SnapConstraint const &constraint,
- Geom::Point const &s, // s[0] = skew factor, s[1] = scale factor
- Geom::Point const &o,
- Geom::Dim2 d);
-
- /**
- * Apply a rotation to a set of points and snap, without scaling.
- *
- * @param p Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
- * @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
- * @param angle Proposed rotation (in radians); the final rotation can only be calculated after snapping has occurred.
- * @param o Origin of the rotation.
- * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
- */
- Inkscape::SnappedPoint constrainedSnapRotate(std::vector<Inkscape::SnapCandidatePoint> const &p,
- Geom::Point const &pointer,
- Geom::Coord const &angle,
- Geom::Point const &o);
-
Inkscape::GuideSnapper guide; ///< guide snapper
Inkscape::ObjectSnapper object; ///< snapper to other objects
Inkscape::SnapPreferences snapprefs;
@@ -490,17 +392,6 @@ public:
*/
void displaySnapsource(Inkscape::SnapCandidatePoint const &p) const;
-protected:
- SPNamedView const *_named_view;
-
-private:
- std::vector<SPItem const *> _items_to_ignore; ///< Items that should not be snapped to, for example the items that are currently being dragged. Set using the setup() method
- std::vector<SPItem*> _rotation_center_source_items; // to avoid snapping a rotation center to itself
- SPGuide *_guide_to_ignore; ///< A guide that should not be snapped to, e.g. the guide that is currently being dragged
- SPDesktop const *_desktop;
- bool _snapindicator; ///< When true, an indicator will be drawn at the position that was being snapped to
- std::vector<Inkscape::SnapCandidatePoint> *_unselected_nodes; ///< Nodes of the path that is currently being edited and which have not been selected and which will therefore be stationary. Only these nodes will be considered for snapping to. Of each unselected node both the position (Geom::Point) and the type (Inkscape::SnapTargetType) will be stored
-
/**
* Method for snapping sets of points while they are being transformed.
*
@@ -518,42 +409,22 @@ private:
*
* @param points Collection of points to snap (snap sources), at their untransformed position, all points undergoing the same transformation. Paired with an identifier of the type of the snap source.
* @param pointer Location of the mouse pointer at the time dragging started (i.e. when the selection was still untransformed).
- * @param constrained true if the snap is constrained, e.g. for stretching or for purely horizontal translation.
- * @param constraint The direction or line along which snapping must occur, if 'constrained' is true; otherwise undefined.
- * @param transformation_type Type of transformation to apply to points before trying to snap them.
- * @param transformation Description of the transformation; details depend on the type.
- * @param origin Origin of the transformation, if applicable.
- * @param dim Dimension to which the transformation applies, if applicable.
- * @param uniform true if the transformation should be uniform; only applicable for stretching and scaling.
- * @return An instance of the SnappedPoint class, which holds data on the snap source, snap target, and various metrics.
+ * @param transform Describes the type of transformation, it's parameters, and any additional constraints
*/
- Inkscape::SnappedPoint _snapTransformed(std::vector<Inkscape::SnapCandidatePoint> const &points,
+ void snapTransformed(std::vector<Inkscape::SnapCandidatePoint> const &points,
Geom::Point const &pointer,
- bool constrained,
- Inkscape::Snapper::SnapConstraint const &constraint,
- Transformation transformation_type,
- Geom::Point const &transformation,
- Geom::Point const &origin,
- Geom::Dim2 dim,
- bool uniform);
+ Inkscape::PureTransform &transform);
- /**
- * Takes an untransformed point, applies the given transformation, and returns the transformed point. Eliminates lots of duplicated code.
- *
- * @param p The untransformed position of the point, paired with an identifier of the type of the snap source.
- * @param transformation_type Type of transformation to apply.
- * @param transformation Mathematical description of the transformation; details depend on the type.
- * @param origin Origin of the transformation, if applicable.
- * @param dim Dimension to which the transformation applies, if applicable.
- * @param uniform true if the transformation should be uniform; only applicable for stretching and scaling.
- * @return The position of the point after transformation.
- */
- Geom::Point _transformPoint(Inkscape::SnapCandidatePoint const &p,
- Transformation const transformation_type,
- Geom::Point const &transformation,
- Geom::Point const &origin,
- Geom::Dim2 const dim,
- bool const uniform) const;
+protected:
+ SPNamedView const *_named_view;
+
+private:
+ std::vector<SPItem const *> _items_to_ignore; ///< Items that should not be snapped to, for example the items that are currently being dragged. Set using the setup() method
+ std::vector<SPItem*> _rotation_center_source_items; // to avoid snapping a rotation center to itself
+ SPGuide *_guide_to_ignore; ///< A guide that should not be snapped to, e.g. the guide that is currently being dragged
+ SPDesktop const *_desktop;
+ bool _snapindicator; ///< When true, an indicator will be drawn at the position that was being snapped to
+ std::vector<Inkscape::SnapCandidatePoint> *_unselected_nodes; ///< Nodes of the path that is currently being edited and which have not been selected and which will therefore be stationary. Only these nodes will be considered for snapping to. Of each unselected node both the position (Geom::Point) and the type (Inkscape::SnapTargetType) will be stored
};
diff --git a/src/snapped-point.cpp b/src/snapped-point.cpp
index ab545bd5f..f826211fa 100644
--- a/src/snapped-point.cpp
+++ b/src/snapped-point.cpp
@@ -29,7 +29,6 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const
_second_distance (Geom::infinity()),
_second_tolerance (1),
_second_always_snap (false),
- _transformation (Geom::Point(1,1)),
_target_bbox(target_bbox),
_pointer_distance (Geom::infinity())
{
@@ -50,7 +49,6 @@ Inkscape::SnappedPoint::SnappedPoint(Inkscape::SnapCandidatePoint const &p, Snap
_second_distance (Geom::infinity()),
_second_tolerance (1),
_second_always_snap (false),
- _transformation (Geom::Point(1,1)),
_target_bbox (p.getTargetBBox()),
_pointer_distance (Geom::infinity())
{
@@ -73,7 +71,6 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p, SnapSourceType const
_second_always_snap(a2),
// tolerance should never be smaller than 1 px, as it is used for normalization in
// isOtherSnapBetter. We don't want a division by zero.
- _transformation (Geom::Point(1,1)),
_target_bbox (Geom::OptRect()),
_pointer_distance (Geom::infinity())
{
@@ -94,7 +91,6 @@ Inkscape::SnappedPoint::SnappedPoint():
_second_distance (Geom::infinity()),
_second_tolerance (1),
_second_always_snap (false),
- _transformation (Geom::Point(1,1)),
_target_bbox (Geom::OptRect()),
_pointer_distance (Geom::infinity())
{
@@ -115,7 +111,6 @@ Inkscape::SnappedPoint::SnappedPoint(Geom::Point const &p):
_second_distance (Geom::infinity()),
_second_tolerance (1),
_second_always_snap (false),
- _transformation (Geom::Point(1,1)),
_target_bbox (Geom::OptRect()),
_pointer_distance (Geom::infinity())
{
diff --git a/src/snapped-point.h b/src/snapped-point.h
index 9d77ab162..cf3a15c3b 100644
--- a/src/snapped-point.h
+++ b/src/snapped-point.h
@@ -66,8 +66,6 @@ public:
bool getFullyConstrained() const {return _fully_constrained;}
bool getConstrainedSnap() const {return _constrained_snap;}
bool getSnapped() const {return _distance < Geom::infinity();}
- Geom::Point getTransformation() const {return _transformation;}
- void setTransformation(Geom::Point const &t) {_transformation = t;}
void setTarget(SnapTargetType const target) {_target = target;}
SnapTargetType getTarget() const {return _target;}
void setTargetBBox(Geom::OptRect const target) {_target_bbox = target;}
@@ -122,8 +120,6 @@ protected:
Geom::Coord _second_tolerance;
/* If true then "Always snap" is on */
bool _second_always_snap;
- /* The transformation (translation, scale, skew, or stretch) from the original point to the snapped point */
- Geom::Point _transformation;
/* The bounding box we've snapped to (when applicable); will be used by the snapindicator */
Geom::OptRect _target_bbox;
/* Distance from the un-transformed point to the mouse pointer, measured at the point in time when dragging started */
diff --git a/src/snapper.h b/src/snapper.h
index 9616d0954..6c7995045 100644
--- a/src/snapper.h
+++ b/src/snapper.h
@@ -76,6 +76,8 @@ public:
SnapConstraint(Geom::Point const &d) : _point(), _direction(d), _radius(0), _type(DIRECTION) {}
// Constructs a linear constraint
SnapConstraint(Geom::Point const &p, Geom::Point const &d) : _point(p), _direction(d), _radius(0), _type(LINE) {}
+ // Orthogonal version
+ SnapConstraint(Geom::Point const &p, Geom::Dim2 const &d) : _point(p), _direction(), _radius(0), _type(LINE) {_direction[d] = 1.;}
SnapConstraint(Geom::Line const &l) : _point(l.origin()), _direction(l.versor()), _radius(0), _type(LINE) {}
// Constructs a circular constraint
SnapConstraint(Geom::Point const &p, Geom::Point const &d, Geom::Coord const &r) : _point(p), _direction(d), _radius(r), _type(CIRCLE) {}
diff --git a/src/sp-clippath.cpp b/src/sp-clippath.cpp
index d66508eae..0c07d1b3d 100644
--- a/src/sp-clippath.cpp
+++ b/src/sp-clippath.cpp
@@ -308,7 +308,7 @@ const gchar *SPClipPath::create (std::vector<Inkscape::XML::Node*> &reprs, SPDoc
const gchar *id = repr->attribute("id");
SPObject *clip_path_object = document->getObjectById(id);
- for (std::vector<Inkscape::XML::Node*>::const_iterator it = reprs.begin(); it != reprs.end(); it++) {
+ for (std::vector<Inkscape::XML::Node*>::const_iterator it = reprs.begin(); it != reprs.end(); ++it) {
Inkscape::XML::Node *node = (*it);
SPItem *item = SP_ITEM(clip_path_object->appendChildRepr(node));
diff --git a/src/sp-clippath.h b/src/sp-clippath.h
index c9a8c68df..7b1c83356 100644
--- a/src/sp-clippath.h
+++ b/src/sp-clippath.h
@@ -19,7 +19,6 @@
#define SP_IS_CLIPPATH(obj) (dynamic_cast<const SPClipPath*>((SPObject*)obj) != NULL)
struct SPClipPathView;
-typedef struct _GSList GSList;
#include <cstdio>
@@ -93,10 +92,10 @@ protected:
Inkscape::XML::Node * const owner_repr = owner->getRepr();
//XML Tree being used directly here while it shouldn't be...
Inkscape::XML::Node * const obj_repr = obj->getRepr();
- char const * owner_name = NULL;
- char const * owner_clippath = NULL;
- char const * obj_name = NULL;
- char const * obj_id = NULL;
+ char const * owner_name = "";
+ char const * owner_clippath = "";
+ char const * obj_name = "";
+ char const * obj_id = "";
if (owner_repr != NULL) {
owner_name = owner_repr->name();
owner_clippath = owner_repr->attribute("clippath");
diff --git a/src/sp-conn-end.cpp b/src/sp-conn-end.cpp
index fa5a57529..75cce4374 100644
--- a/src/sp-conn-end.cpp
+++ b/src/sp-conn-end.cpp
@@ -51,7 +51,7 @@ static bool try_get_intersect_point_with_item_recursive(Geom::PathVector& conn_p
// consider all first-order children
double child_pos = 0.0;
std::vector<SPItem*> g = sp_item_group_item_list(group);
- for (std::vector<SPItem*>::const_iterator i = g.begin();i!=g.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i = g.begin();i!=g.end();++i) {
SPItem* child_item = *i;
try_get_intersect_point_with_item_recursive(conn_pv, child_item,
item_transform * child_item->transform, child_pos);
diff --git a/src/sp-defs.cpp b/src/sp-defs.cpp
index 2e341d3c6..dd779c0da 100644
--- a/src/sp-defs.cpp
+++ b/src/sp-defs.cpp
@@ -37,7 +37,7 @@ void SPDefs::update(SPCtx *ctx, guint flags) {
flags &= SP_OBJECT_MODIFIED_CASCADE;
std::vector<SPObject*> l(this->childList(true));
- for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){
+ for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){
SPObject *child = *i;
if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
child->updateDisplay(ctx, flags);
diff --git a/src/sp-factory.cpp b/src/sp-factory.cpp
index 55e673c4a..20472d425 100644
--- a/src/sp-factory.cpp
+++ b/src/sp-factory.cpp
@@ -294,10 +294,12 @@ SPObject *SPFactory::createObject(std::string const& id)
{}
else if (id == "inkscape:clipboard") // SP node not necessary
{}
+ else if (id == "inkscape:_templateinfo") // ?
+ {}
else if (id.empty()) // comments
{}
else {
- fprintf(stderr, "WARNING: unknown type: %s", id.c_str());
+ fprintf(stderr, "WARNING: unknown type: %s\n", id.c_str());
}
return ret;
diff --git a/src/sp-filter-primitive.cpp b/src/sp-filter-primitive.cpp
index 1f85c8193..b18850914 100644
--- a/src/sp-filter-primitive.cpp
+++ b/src/sp-filter-primitive.cpp
@@ -194,7 +194,9 @@ Inkscape::XML::Node* SPFilterPrimitive::write(Inkscape::XML::Document *doc, Inks
int sp_filter_primitive_read_in(SPFilterPrimitive *prim, gchar const *name)
{
- if (!name) return Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
+ if (!name || !prim){
+ return Inkscape::Filters::NR_FILTER_SLOT_NOT_SET;
+ }
// TODO: are these case sensitive or not? (assumed yes)
switch (name[0]) {
case 'S':
diff --git a/src/sp-filter.cpp b/src/sp-filter.cpp
index 1bde69dd1..c17c67fc5 100644
--- a/src/sp-filter.cpp
+++ b/src/sp-filter.cpp
@@ -246,7 +246,7 @@ void SPFilter::update(SPCtx *ctx, guint flags) {
}
childflags &= SP_OBJECT_MODIFIED_CASCADE;
std::vector<SPObject*> l(this->childList(true, SPObject::ActionUpdate));
- for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){
+ for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){
SPObject *child = *i;
if( SP_IS_FILTER_PRIMITIVE( child ) ) {
child->updateDisplay(ctx, childflags);
diff --git a/src/sp-flowtext.cpp b/src/sp-flowtext.cpp
index cac3cc61d..b87507e18 100644
--- a/src/sp-flowtext.cpp
+++ b/src/sp-flowtext.cpp
@@ -34,8 +34,10 @@
#include "display/drawing-text.h"
-SPFlowtext::SPFlowtext() : SPItem() {
- this->par_indent = 0;
+SPFlowtext::SPFlowtext() : SPItem(),
+ par_indent(0),
+ _optimizeScaledText(false)
+{
}
SPFlowtext::~SPFlowtext() {
diff --git a/src/sp-guide.cpp b/src/sp-guide.cpp
index 4e1c5913d..17a1a9ff1 100644
--- a/src/sp-guide.cpp
+++ b/src/sp-guide.cpp
@@ -26,6 +26,7 @@
#include "display/sp-canvas.h"
#include "display/guideline.h"
#include "svg/svg.h"
+#include "svg/svg-color.h"
#include "svg/stringstream.h"
#include "attributes.h"
#include "sp-guide.h"
@@ -42,6 +43,7 @@
#include <2geom/angle.h>
#include "document.h"
#include "document-undo.h"
+#include "helper-fns.h"
#include "verbs.h"
using Inkscape::DocumentUndo;
@@ -50,7 +52,7 @@ using std::vector;
SPGuide::SPGuide()
: SPObject()
, label(NULL)
- , views(NULL)
+ , locked(0)
, normal_to_line(Geom::Point(0.,1.))
, point_on_line(Geom::Point(0.,0.))
, color(0x0000ff7f)
@@ -61,8 +63,8 @@ void SPGuide::setColor(guint32 c)
{
color = c;
- for (GSList *l = this->views; l != NULL; l = l->next) {
- sp_guideline_set_color(SP_GUIDELINE(l->data), this->color);
+ for(std::vector<SPGuideLine *>::const_iterator it = this->views.begin(); it != this->views.end(); ++it) {
+ sp_guideline_set_color(*it, this->color);
}
}
@@ -70,7 +72,9 @@ void SPGuide::build(SPDocument *document, Inkscape::XML::Node *repr)
{
SPObject::build(document, repr);
+ this->readAttr( "inkscape:color" );
this->readAttr( "inkscape:label" );
+ this->readAttr( "inkscape:locked" );
this->readAttr( "orientation" );
this->readAttr( "position" );
@@ -80,10 +84,10 @@ void SPGuide::build(SPDocument *document, Inkscape::XML::Node *repr)
void SPGuide::release()
{
- while (this->views) {
- sp_guideline_delete(SP_GUIDELINE(this->views->data));
- this->views = g_slist_remove(this->views, this->views->data);
+ for(std::vector<SPGuideLine *>::const_iterator it = this->views.begin(); it != this->views.end(); ++it) {
+ sp_guideline_delete(*it);
}
+ this->views.clear();
if (this->document) {
// Unregister ourselves
@@ -95,9 +99,14 @@ void SPGuide::release()
void SPGuide::set(unsigned int key, const gchar *value) {
switch (key) {
+ case SP_ATTR_INKSCAPE_COLOR:
+ if (value) {
+ this->setColor(sp_svg_read_color(value, 0x0000ff00) | 0x7f);
+ }
+ break;
case SP_ATTR_INKSCAPE_LABEL:
- if (this->label) g_free(this->label);
-
+ // this->label already freed in sp_guideline_set_label (src/display/guideline.cpp)
+ // see bug #1498444, bug #1469514
if (value) {
this->label = g_strdup(value);
} else {
@@ -106,6 +115,12 @@ void SPGuide::set(unsigned int key, const gchar *value) {
this->set_label(this->label, false);
break;
+ case SP_ATTR_INKSCAPE_LOCKED:
+ this->locked = helperfns_read_bool(value, false);
+ if (value) {
+ this->set_locked(this->locked, false);
+ }
+ break;
case SP_ATTR_ORIENTATION:
{
if (value && !strcmp(value, "horizontal")) {
@@ -249,10 +264,11 @@ void sp_guide_create_guides_around_page(SPDesktop *dt)
void sp_guide_delete_all_guides(SPDesktop *dt)
{
SPDocument *doc=dt->getDocument();
- const GSList *current;
- while ( (current = doc->getResourceList("guide")) ) {
- SPGuide* guide = SP_GUIDE(current->data);
+ std::set<SPObject *> current = doc->getResourceList("guide");
+ while (!current.empty()){
+ SPGuide* guide = SP_GUIDE(*(current.begin()));
sp_guide_remove(guide);
+ current = doc->getResourceList("guide");
}
DocumentUndo::done(doc, SP_VERB_NONE, _("Delete All Guides"));
@@ -265,14 +281,19 @@ void SPGuide::showSPGuide(SPCanvasGroup *group, GCallback handler)
g_signal_connect(G_OBJECT(item), "event", G_CALLBACK(handler), this);
- views = g_slist_prepend(views, item);
+ views.push_back(SP_GUIDELINE(item));
}
void SPGuide::showSPGuide()
{
- for (GSList *v = views; v != NULL; v = v->next) {
- sp_canvas_item_show(SP_CANVAS_ITEM(v->data));
- sp_canvas_item_show(SP_CANVAS_ITEM(SP_GUIDELINE(v->data)->origin));
+ for(std::vector<SPGuideLine *>::const_iterator it = this->views.begin(); it != this->views.end(); ++it) {
+ sp_canvas_item_show(SP_CANVAS_ITEM(*it));
+ if((*it)->origin) {
+ sp_canvas_item_show(SP_CANVAS_ITEM((*it)->origin));
+ } else {
+ //reposition to same place to show knots
+ sp_guideline_set_position(*it, point_on_line);
+ }
}
}
@@ -280,11 +301,10 @@ void SPGuide::hideSPGuide(SPCanvas *canvas)
{
g_assert(canvas != NULL);
g_assert(SP_IS_CANVAS(canvas));
-
- for (GSList *l = views; l != NULL; l = l->next) {
- if (canvas == SP_CANVAS_ITEM(l->data)->canvas) {
- sp_guideline_delete(SP_GUIDELINE(l->data));
- views = g_slist_remove(views, l->data);
+ for(std::vector<SPGuideLine *>::iterator it = this->views.begin(); it != this->views.end(); ++it) {
+ if (canvas == SP_CANVAS_ITEM(*it)->canvas) {
+ sp_guideline_delete(*it);
+ views.erase(it);
return;
}
}
@@ -294,9 +314,11 @@ void SPGuide::hideSPGuide(SPCanvas *canvas)
void SPGuide::hideSPGuide()
{
- for (GSList *v = views; v != NULL; v = v->next) {
- sp_canvas_item_hide(SP_CANVAS_ITEM(v->data));
- sp_canvas_item_hide(SP_CANVAS_ITEM(SP_GUIDELINE(v->data)->origin));
+ for(std::vector<SPGuideLine *>::const_iterator it = this->views.begin(); it != this->views.end(); ++it) {
+ sp_canvas_item_hide(SP_CANVAS_ITEM(*it));
+ if ((*it)->origin) {
+ sp_canvas_item_hide(SP_CANVAS_ITEM((*it)->origin));
+ }
}
}
@@ -305,9 +327,9 @@ void SPGuide::sensitize(SPCanvas *canvas, bool sensitive)
g_assert(canvas != NULL);
g_assert(SP_IS_CANVAS(canvas));
- for (GSList *l = views; l != NULL; l = l->next) {
- if (canvas == SP_CANVAS_ITEM(l->data)->canvas) {
- sp_guideline_set_sensitive(SP_GUIDELINE(l->data), sensitive);
+ for(std::vector<SPGuideLine *>::const_iterator it = this->views.begin(); it != this->views.end(); ++it) {
+ if (canvas == SP_CANVAS_ITEM(*it)->canvas) {
+ sp_guideline_set_sensitive(*it, sensitive);
return;
}
}
@@ -332,8 +354,11 @@ double SPGuide::getDistanceFrom(Geom::Point const &pt) const
*/
void SPGuide::moveto(Geom::Point const point_on_line, bool const commit)
{
- for (GSList *l = views; l != NULL; l = l->next) {
- sp_guideline_set_position(SP_GUIDELINE(l->data), point_on_line);
+ if(this->locked) {
+ return;
+ }
+ for(std::vector<SPGuideLine *>::const_iterator it = this->views.begin(); it != this->views.end(); ++it) {
+ sp_guideline_set_position(*it, point_on_line);
}
/* Calling sp_repr_set_point must precede calling sp_item_notify_moveto in the commit
@@ -378,8 +403,11 @@ void SPGuide::moveto(Geom::Point const point_on_line, bool const commit)
*/
void SPGuide::set_normal(Geom::Point const normal_to_line, bool const commit)
{
- for (GSList *l = this->views; l != NULL; l = l->next) {
- sp_guideline_set_normal(SP_GUIDELINE(l->data), normal_to_line);
+ if(this->locked) {
+ return;
+ }
+ for(std::vector<SPGuideLine *>::const_iterator it = this->views.begin(); it != this->views.end(); ++it) {
+ sp_guideline_set_normal(*it, normal_to_line);
}
/* Calling sp_repr_set_svg_point must precede calling sp_item_notify_moveto in the commit
@@ -404,8 +432,8 @@ void SPGuide::set_color(const unsigned r, const unsigned g, const unsigned b, bo
{
this->color = (r << 24) | (g << 16) | (b << 8) | 0x7f;
- if (views) {
- sp_guideline_set_color(SP_GUIDELINE(views->data), this->color);
+ if (! views.empty()) {
+ sp_guideline_set_color(views[0], this->color);
}
if (commit) {
@@ -416,10 +444,22 @@ void SPGuide::set_color(const unsigned r, const unsigned g, const unsigned b, bo
}
}
+void SPGuide::set_locked(const bool locked, bool const commit)
+{
+ this->locked = locked;
+ if ( !views.empty() ) {
+ sp_guideline_set_locked(views[0], locked);
+ }
+
+ if (commit) {
+ getRepr()->setAttribute("inkscape:locked", g_strdup(locked ? "true" : "false"));
+ }
+}
+
void SPGuide::set_label(const char* label, bool const commit)
{
- if (views) {
- sp_guideline_set_label(SP_GUIDELINE(views->data), label);
+ if (!views.empty()) {
+ sp_guideline_set_label(views[0], label);
}
if (commit) {
@@ -461,7 +501,7 @@ char* SPGuide::description(bool const verbose) const
descr = g_strdup_printf(_("horizontal, at %s"), position_string_y->str);
} else {
double const radians = this->angle();
- double const degrees = Geom::rad_to_deg(radians);
+ double const degrees = Geom::deg_from_rad(radians);
int const degrees_int = (int) round(degrees);
descr = g_strdup_printf(_("at %d degrees, through (%s,%s)"),
degrees_int, position_string_x->str, position_string_y->str);
@@ -475,6 +515,7 @@ char* SPGuide::description(bool const verbose) const
descr = g_strconcat(oldDescr, shortcuts, NULL);
g_free(oldDescr);
}
+
g_free(shortcuts);
}
diff --git a/src/sp-guide.h b/src/sp-guide.h
index 382ea56f0..25a0e5af8 100644
--- a/src/sp-guide.h
+++ b/src/sp-guide.h
@@ -22,13 +22,12 @@
typedef unsigned int guint32;
extern "C" {
typedef void (*GCallback) (void);
- typedef struct _GSList GSList;
}
class SPDesktop;
struct SPCanvas;
struct SPCanvasGroup;
-
+struct SPGuideLine;
#define SP_GUIDE(obj) (dynamic_cast<SPGuide*>((SPObject*)obj))
#define SP_IS_GUIDE(obj) (dynamic_cast<const SPGuide*>((SPObject*)obj) != NULL)
@@ -53,6 +52,9 @@ public:
void set_label(const char* label, bool const commit);
char const* getLabel() const { return label; }
+ void set_locked(const bool locked, bool const commit);
+ bool getLocked() const { return locked; }
+
static SPGuide *createSPGuide(SPDocument *doc, Geom::Point const &pt1, Geom::Point const &pt2);
void showSPGuide(SPCanvasGroup *group, GCallback handler);
@@ -77,7 +79,8 @@ protected:
virtual void set(unsigned int key, const char* value);
char* label;
- GSList *views; // contains an object of type SPGuideline (see display/guideline.cpp for definition)
+ std::vector<SPGuideLine *> views; // contains an object of type SPGuideline (see display/guideline.cpp for definition)
+ bool locked;
Geom::Point normal_to_line;
Geom::Point point_on_line;
diff --git a/src/sp-hatch.cpp b/src/sp-hatch.cpp
index ea4c5865a..2d938618c 100644
--- a/src/sp-hatch.cpp
+++ b/src/sp-hatch.cpp
@@ -113,7 +113,7 @@ void SPHatch::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref)
SPHatchPath *path_child = dynamic_cast<SPHatchPath *>(document->getObjectByRepr(child));
if (path_child) {
- for (ViewIterator iter = _display.begin(); iter != _display.end(); iter++) {
+ for (ViewIterator iter = _display.begin(); iter != _display.end(); ++iter) {
Geom::OptInterval extents = _calculateStripExtents(iter->bbox);
Inkscape::DrawingItem *ac = path_child->show(iter->arenaitem->drawing(), iter->key, extents);
diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp
index 72cd5d7fa..83d67cf5a 100644
--- a/src/sp-item-group.cpp
+++ b/src/sp-item-group.cpp
@@ -58,8 +58,11 @@ using Inkscape::DocumentUndo;
static void sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write);
-SPGroup::SPGroup() : SPLPEItem() {
- this->_layer_mode = SPGroup::GROUP;
+SPGroup::SPGroup() : SPLPEItem(),
+ _expanded(false),
+ _insertBottom(false),
+ _layer_mode(SPGroup::GROUP)
+{
}
SPGroup::~SPGroup() {
@@ -90,10 +93,9 @@ void SPGroup::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref)
if ( item ) {
/* TODO: this should be moved into SPItem somehow */
SPItemView *v;
- Inkscape::DrawingItem *ac;
for (v = this->display; v != NULL; v = v->next) {
- ac = item->invoke_show (v->arenaitem->drawing(), v->key, v->flags);
+ Inkscape::DrawingItem *ac = item->invoke_show (v->arenaitem->drawing(), v->key, v->flags);
if (ac) {
v->arenaitem->appendChild(ac);
@@ -105,12 +107,10 @@ void SPGroup::child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref)
if ( item ) {
/* TODO: this should be moved into SPItem somehow */
SPItemView *v;
- Inkscape::DrawingItem *ac;
-
unsigned position = item->pos_in_parent();
for (v = this->display; v != NULL; v = v->next) {
- ac = item->invoke_show (v->arenaitem->drawing(), v->key, v->flags);
+ Inkscape::DrawingItem *ac = item->invoke_show (v->arenaitem->drawing(), v->key, v->flags);
if (ac) {
v->arenaitem->prependChild(ac);
@@ -162,7 +162,7 @@ void SPGroup::update(SPCtx *ctx, unsigned int flags) {
}
childflags &= SP_OBJECT_MODIFIED_CASCADE;
std::vector<SPObject*> l=this->childList(true, SPObject::ActionUpdate);
- for(std::vector<SPObject*> ::const_iterator i=l.begin();i!=l.end();i++){
+ for(std::vector<SPObject*> ::const_iterator i=l.begin();i!=l.end();++i){
SPObject *child = *i;
if (childflags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
@@ -206,7 +206,7 @@ void SPGroup::modified(guint flags) {
flags &= SP_OBJECT_MODIFIED_CASCADE;
std::vector<SPObject*> l=this->childList(true);
- for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){
+ for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){
SPObject *child = *i;
if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
@@ -280,7 +280,7 @@ Geom::OptRect SPGroup::bbox(Geom::Affine const &transform, SPItem::BBoxType bbox
// TODO CPPIFY: replace this const_cast later
std::vector<SPObject*> l = const_cast<SPGroup*>(this)->childList(false, SPObject::ActionBBox);
- for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){
+ for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){
SPObject *o = *i;
SPItem *item = dynamic_cast<SPItem *>(o);
if (item && !item->isHidden()) {
@@ -294,7 +294,7 @@ Geom::OptRect SPGroup::bbox(Geom::Affine const &transform, SPItem::BBoxType bbox
void SPGroup::print(SPPrintContext *ctx) {
std::vector<SPObject*> l=this->childList(false);
- for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){
+ for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){
SPObject *o = *i;
SPItem *item = dynamic_cast<SPItem *>(o);
if (item) {
@@ -348,7 +348,7 @@ Inkscape::DrawingItem *SPGroup::show (Inkscape::Drawing &drawing, unsigned int k
void SPGroup::hide (unsigned int key) {
std::vector<SPObject*> l=this->childList(false, SPObject::ActionShow);
- for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){
+ for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){
SPObject *o = *i;
SPItem *item = dynamic_cast<SPItem *>(o);
@@ -373,7 +373,7 @@ void SPGroup::snappoints(std::vector<Inkscape::SnapCandidatePoint> &p, Inkscape:
void sp_item_group_ungroup_handle_clones(SPItem *parent, Geom::Affine const g)
{
- for(std::list<SPObject*>::const_iterator refd=parent->hrefList.begin();refd!=parent->hrefList.end();refd++){
+ for(std::list<SPObject*>::const_iterator refd=parent->hrefList.begin();refd!=parent->hrefList.end();++refd){
SPItem *citem = dynamic_cast<SPItem *>(*refd);
if (citem && !citem->cloned) {
SPUse *useitem = dynamic_cast<SPUse *>(citem);
@@ -465,7 +465,7 @@ sp_item_group_ungroup (SPGroup *group, std::vector<SPItem*> &children, bool do_d
Inkscape::XML::Node *nrepr = child->getRepr()->duplicate(prepr->document());
// Merging transform
- Geom::Affine ctrans;
+ Geom::Affine ctrans = citem->transform * g;
// We should not apply the group's transformation to both a linked offset AND to its source
if (dynamic_cast<SPOffset *>(citem)) { // Do we have an offset at hand (whether it's dynamic or linked)?
SPItem *source = sp_offset_get_source(dynamic_cast<SPOffset *>(citem));
@@ -476,13 +476,9 @@ sp_item_group_ungroup (SPGroup *group, std::vector<SPItem*> &children, bool do_d
source = sp_offset_get_source(dynamic_cast<SPOffset *>(source));
}
if (source != NULL && // If true then we must be dealing with a linked offset ...
- group->isAncestorOf(source) == false) { // ... of which the source is not in the same group
- ctrans = citem->transform * g; // then we should apply the transformation of the group to the offset
- } else {
- ctrans = citem->transform;
+ group->isAncestorOf(source) ) { // ... of which the source is in the same group
+ ctrans = citem->transform; // then we should apply the transformation of the group to the offset
}
- } else {
- ctrans = citem->transform * g;
}
// FIXME: constructing a transform that would fully preserve the appearance of a
@@ -785,7 +781,7 @@ gint SPGroup::getItemCount() const {
void SPGroup::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem *ai, unsigned int key, unsigned int flags) {
Inkscape::DrawingItem *ac = NULL;
std::vector<SPObject*> l=this->childList(false, SPObject::ActionShow);
- for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();i++){
+ for(std::vector<SPObject*>::const_iterator i=l.begin();i!=l.end();++i){
SPObject *o = *i;
SPItem * child = dynamic_cast<SPItem *>(o);
if (child) {
@@ -804,7 +800,7 @@ void SPGroup::update_patheffect(bool write) {
std::vector<SPItem*> const item_list = sp_item_group_item_list(this);
- for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) {
+ for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) {
SPObject *subitem = *iter;
SPLPEItem *lpeItem = dynamic_cast<SPLPEItem *>(subitem);
@@ -814,7 +810,7 @@ void SPGroup::update_patheffect(bool write) {
}
if (hasPathEffect() && pathEffectsEnabled()) {
- for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); it++)
+ for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); ++it)
{
LivePathEffectObject *lpeobj = (*it)->lpeobject;
@@ -832,7 +828,7 @@ sp_group_perform_patheffect(SPGroup *group, SPGroup *topgroup, bool write)
{
std::vector<SPItem*> const item_list = sp_item_group_item_list(group);
- for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) {
+ for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) {
SPObject *subitem = *iter;
SPGroup *subGroup = dynamic_cast<SPGroup *>(subitem);
diff --git a/src/sp-item-group.h b/src/sp-item-group.h
index fc0b6382f..0c74c3dc3 100644
--- a/src/sp-item-group.h
+++ b/src/sp-item-group.h
@@ -25,7 +25,6 @@ namespace Inkscape {
class Drawing;
class DrawingItem;
-typedef struct _GSList GSList;
} // namespace Inkscape
diff --git a/src/sp-item.cpp b/src/sp-item.cpp
index 410fd9b37..4937e6c76 100644
--- a/src/sp-item.cpp
+++ b/src/sp-item.cpp
@@ -351,8 +351,8 @@ void SPItem::lowerToBottom() {
SPObject * bottom=parent->firstChild();
while(dynamic_cast<SPObject*>(bottom) && dynamic_cast<SPObject*>(bottom->next) && bottom!=this && !is_item(*(bottom->next))) bottom=bottom->next;
- if (bottom) {
- Inkscape::XML::Node *ref = ( bottom ? bottom->getRepr() : NULL );
+ if (bottom && bottom != this) {
+ Inkscape::XML::Node *ref = bottom->getRepr() ;
parent->getRepr()->changeOrder(getRepr(), ref);
}
}
diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp
index 9befd2a2b..e2afbb55b 100644
--- a/src/sp-lpe-item.cpp
+++ b/src/sp-lpe-item.cpp
@@ -209,7 +209,7 @@ Inkscape::XML::Node* SPLPEItem::write(Inkscape::XML::Document *xml_doc, Inkscape
/**
* returns true when LPE was successful.
*/
-bool SPLPEItem::performPathEffect(SPCurve *curve) {
+bool SPLPEItem::performPathEffect(SPCurve *curve, bool clip_paths) {
if (!this) {
return false;
}
@@ -217,7 +217,7 @@ bool SPLPEItem::performPathEffect(SPCurve *curve) {
if (!curve) {
return false;
}
-
+ bool apply_to_clippath_and_mask = false;
if (this->hasPathEffect() && this->pathEffectsEnabled()) {
for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); ++it)
{
@@ -239,35 +239,42 @@ bool SPLPEItem::performPathEffect(SPCurve *curve) {
}
if (lpe->isVisible()) {
+ if(lpe->apply_to_clippath_and_mask){
+ apply_to_clippath_and_mask = true;
+ }
if (lpe->acceptsNumClicks() > 0 && !lpe->isReady()) {
// if the effect expects mouse input before being applied and the input is not finished
// yet, we don't alter the path
return false;
}
+ if (clip_paths || lpe->apply_to_clippath_and_mask) {
+ // Groups have their doBeforeEffect called elsewhere
+ if (!SP_IS_GROUP(this)) {
+ lpe->doBeforeEffect_impl(this);
+ }
- // Groups have their doBeforeEffect called elsewhere
- if (!SP_IS_GROUP(this)) {
- lpe->doBeforeEffect_impl(this);
- }
-
- try {
- lpe->doEffect(curve);
- }
- catch (std::exception & e) {
- g_warning("Exception during LPE %s execution. \n %s", lpe->getName().c_str(), e.what());
- if (SP_ACTIVE_DESKTOP && SP_ACTIVE_DESKTOP->messageStack()) {
- SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE,
- _("An exception occurred during execution of the Path Effect.") );
+ try {
+ lpe->doEffect(curve);
+ }
+ catch (std::exception & e) {
+ g_warning("Exception during LPE %s execution. \n %s", lpe->getName().c_str(), e.what());
+ if (SP_ACTIVE_DESKTOP && SP_ACTIVE_DESKTOP->messageStack()) {
+ SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE,
+ _("An exception occurred during execution of the Path Effect.") );
+ }
+ return false;
+ }
+ if (!SP_IS_GROUP(this)) {
+ lpe->doAfterEffect(this);
}
- return false;
- }
- if (!SP_IS_GROUP(this)) {
- lpe->doAfterEffect(this);
}
}
}
}
-
+ if(apply_to_clippath_and_mask && clip_paths){
+ this->apply_to_clippath((SPItem *)this);
+ this->apply_to_mask((SPItem *)this);
+ }
return true;
}
@@ -354,7 +361,7 @@ sp_lpe_item_create_original_path_recursive(SPLPEItem *lpeitem)
}
if (SP_IS_GROUP(lpeitem)) {
std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
- for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) {
+ for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) {
SPObject *subitem = *iter;
if (SP_IS_LPE_ITEM(subitem)) {
sp_lpe_item_create_original_path_recursive(SP_LPE_ITEM(subitem));
@@ -388,7 +395,7 @@ sp_lpe_item_cleanup_original_path_recursive(SPLPEItem *lpeitem)
}
}
std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(lpeitem));
- for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) {
+ for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) {
SPObject *subitem = *iter;
if (SP_IS_LPE_ITEM(subitem)) {
sp_lpe_item_cleanup_original_path_recursive(SP_LPE_ITEM(subitem));
@@ -641,47 +648,11 @@ SPLPEItem::apply_to_clippath(SPItem *item)
SPClipPath *clipPath = item->clip_ref->getObject();
if(clipPath) {
SPObject * clip_data = clipPath->firstChild();
- SPCurve * clip_curve = NULL;
-
- if (SP_IS_PATH(clip_data)) {
- clip_curve = SP_PATH(clip_data)->get_original_curve();
- } else if(SP_IS_SHAPE(clip_data)) {
- clip_curve = SP_SHAPE(clip_data)->getCurve();
- } else if(SP_IS_GROUP(clip_data)) {
- apply_to_clip_or_mask_group(SP_ITEM(clip_data), item);
- return;
- }
- if(clip_curve) {
- bool success = false;
- if(SP_IS_GROUP(this)){
- clip_curve->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)));
- success = this->performPathEffect(clip_curve);
- clip_curve->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)).inverse());
- } else {
- success = this->performPathEffect(clip_curve);
- }
- Inkscape::XML::Node *reprClip = clip_data->getRepr();
- if (success) {
- gchar *str = sp_svg_write_path(clip_curve->get_pathvector());
- reprClip->setAttribute("d", str);
- g_free(str);
- } else {
- // LPE was unsuccesfull. Read the old 'd'-attribute.
- if (gchar const * value = reprClip->attribute("d")) {
- Geom::PathVector pv = sp_svg_read_pathv(value);
- SPCurve *oldcurve = new SPCurve(pv);
- if (oldcurve) {
- SP_SHAPE(clip_data)->setCurve(oldcurve, TRUE);
- oldcurve->unref();
- }
- }
- }
- clip_curve->unref();
- }
+ apply_to_clip_or_mask(SP_ITEM(clip_data), item);
}
if(SP_IS_GROUP(item)){
std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(item));
- for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) {
+ for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) {
SPObject *subitem = *iter;
apply_to_clippath(SP_ITEM(subitem));
}
@@ -694,46 +665,11 @@ SPLPEItem::apply_to_mask(SPItem *item)
SPMask *mask = item->mask_ref->getObject();
if(mask) {
SPObject *mask_data = mask->firstChild();
- SPCurve * mask_curve = NULL;
- if (SP_IS_PATH(mask_data)) {
- mask_curve = SP_PATH(mask_data)->get_original_curve();
- } else if(SP_IS_SHAPE(mask_data)) {
- mask_curve = SP_SHAPE(mask_data)->getCurve();
- } else if(SP_IS_GROUP(mask_data)) {
- apply_to_clip_or_mask_group(SP_ITEM(mask_data), item);
- return;
- }
- if(mask_curve) {
- bool success = false;
- if(SP_IS_GROUP(this)){
- mask_curve->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)));
- success = this->performPathEffect(mask_curve);
- mask_curve->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)).inverse());
- } else {
- success = this->performPathEffect(mask_curve);
- }
- Inkscape::XML::Node *reprmask = mask_data->getRepr();
- if (success) {
- gchar *str = sp_svg_write_path(mask_curve->get_pathvector());
- reprmask->setAttribute("d", str);
- g_free(str);
- } else {
- // LPE was unsuccesfull. Read the old 'd'-attribute.
- if (gchar const * value = reprmask->attribute("d")) {
- Geom::PathVector pv = sp_svg_read_pathv(value);
- SPCurve *oldcurve = new SPCurve(pv);
- if (oldcurve) {
- SP_SHAPE(mask_data)->setCurve(oldcurve, TRUE);
- oldcurve->unref();
- }
- }
- }
- mask_curve->unref();
- }
+ apply_to_clip_or_mask(SP_ITEM(mask_data), item);
}
if(SP_IS_GROUP(item)){
std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(item));
- for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) {
+ for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) {
SPObject *subitem = *iter;
apply_to_mask(SP_ITEM(subitem));
}
@@ -741,51 +677,57 @@ SPLPEItem::apply_to_mask(SPItem *item)
}
void
-SPLPEItem::apply_to_clip_or_mask_group(SPItem *group, SPItem *item)
+SPLPEItem::apply_to_clip_or_mask(SPItem *clip_mask, SPItem *item)
{
- if (!SP_IS_GROUP(group)) {
- return;
- }
- std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(group));
- for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();iter++) {
- SPObject *subitem = *iter;
- if (SP_IS_GROUP(subitem)) {
- apply_to_clip_or_mask_group(SP_ITEM(subitem), item);
- } else if (SP_IS_SHAPE(subitem)) {
- SPCurve * c = NULL;
-
- if (SP_IS_PATH(subitem)) {
- c = SP_PATH(subitem)->get_original_curve();
- } else {
- c = SP_SHAPE(subitem)->getCurve();
- }
- if (c) {
- bool success = false;
- if(SP_IS_GROUP(group)){
+ if (SP_IS_GROUP(clip_mask)) {
+ std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(clip_mask));
+ for ( std::vector<SPItem*>::const_iterator iter=item_list.begin();iter!=item_list.end();++iter) {
+ SPItem *subitem = *iter;
+ apply_to_clip_or_mask(subitem, item);
+ }
+ } else if (SP_IS_SHAPE(clip_mask)) {
+ SPCurve * c = NULL;
+
+ if (SP_IS_PATH(clip_mask)) {
+ c = SP_PATH(clip_mask)->get_original_curve();
+ } else {
+ c = SP_SHAPE(clip_mask)->getCurve();
+ }
+ if (c) {
+ bool success = false;
+ try {
+ if(SP_IS_GROUP(this)){
c->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)));
- success = this->performPathEffect(c);
+ success = this->performPathEffect(c, false);
c->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)).inverse());
} else {
- success = this->performPathEffect(c);
+ success = this->performPathEffect(c, false);
}
- Inkscape::XML::Node *repr = subitem->getRepr();
- if (success) {
- gchar *str = sp_svg_write_path(c->get_pathvector());
- repr->setAttribute("d", str);
- g_free(str);
- } else {
- // LPE was unsuccesfull. Read the old 'd'-attribute.
- if (gchar const * value = repr->attribute("d")) {
- Geom::PathVector pv = sp_svg_read_pathv(value);
- SPCurve *oldcurve = new SPCurve(pv);
- if (oldcurve) {
- SP_SHAPE(subitem)->setCurve(oldcurve, TRUE);
- oldcurve->unref();
- }
+ } catch (std::exception & e) {
+ g_warning("Exception during LPE execution. \n %s", e.what());
+ if (SP_ACTIVE_DESKTOP && SP_ACTIVE_DESKTOP->messageStack()) {
+ SP_ACTIVE_DESKTOP->messageStack()->flash( Inkscape::WARNING_MESSAGE,
+ _("An exception occurred during execution of the Path Effect.") );
+ }
+ success = false;
+ }
+ Inkscape::XML::Node *repr = clip_mask->getRepr();
+ if (success) {
+ gchar *str = sp_svg_write_path(c->get_pathvector());
+ repr->setAttribute("d", str);
+ g_free(str);
+ } else {
+ // LPE was unsuccesfull. Read the old 'd'-attribute.
+ if (gchar const * value = repr->attribute("d")) {
+ Geom::PathVector pv = sp_svg_read_pathv(value);
+ SPCurve *oldcurve = new SPCurve(pv);
+ if (oldcurve) {
+ SP_SHAPE(clip_mask)->setCurve(oldcurve, TRUE);
+ oldcurve->unref();
}
}
- c->unref();
}
+ c->unref();
}
}
}
diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h
index 902271430..d5e868b2e 100644
--- a/src/sp-lpe-item.h
+++ b/src/sp-lpe-item.h
@@ -26,21 +26,21 @@ class SPCurve;
class SPDesktop;
namespace Inkscape{
-namespace Display {
- class TemporaryItem;
-}
-namespace LivePathEffect{
- class LPEObjectReference;
- class Effect;
-}
+ namespace Display {
+ class TemporaryItem;
+ }
+ namespace LivePathEffect{
+ class LPEObjectReference;
+ class Effect;
+ }
}
typedef std::list<Inkscape::LivePathEffect::LPEObjectReference *> PathEffectList;
class SPLPEItem : public SPItem {
public:
- SPLPEItem();
- virtual ~SPLPEItem();
+ SPLPEItem();
+ virtual ~SPLPEItem();
int path_effects_enabled;
@@ -54,22 +54,22 @@ public:
std::vector<LivePathEffectObject const *> const &new_lpeobjs );
- virtual void build(SPDocument* doc, Inkscape::XML::Node* repr);
- virtual void release();
+ virtual void build(SPDocument* doc, Inkscape::XML::Node* repr);
+ virtual void release();
- virtual void set(unsigned int key, char const* value);
+ virtual void set(unsigned int key, char const* value);
- virtual void update(SPCtx* ctx, unsigned int flags);
- virtual void modified(unsigned int flags);
+ virtual void update(SPCtx* ctx, unsigned int flags);
+ virtual void modified(unsigned int flags);
- virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref);
- virtual void remove_child(Inkscape::XML::Node* child);
+ virtual void child_added(Inkscape::XML::Node* child, Inkscape::XML::Node* ref);
+ virtual void remove_child(Inkscape::XML::Node* child);
- virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags);
+ virtual Inkscape::XML::Node* write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, unsigned int flags);
- virtual void update_patheffect(bool write);
+ virtual void update_patheffect(bool write);
- bool performPathEffect(SPCurve *curve);
+ bool performPathEffect(SPCurve *curve, bool clip_paths = true);
bool pathEffectsEnabled() const;
bool hasPathEffect() const;
@@ -93,7 +93,7 @@ public:
void addPathEffect(LivePathEffectObject * new_lpeobj);
void apply_to_mask(SPItem * item);
void apply_to_clippath(SPItem * item);
- void apply_to_clip_or_mask_group(SPItem * group, SPItem * item);
+ void apply_to_clip_or_mask(SPItem * clip_mask, SPItem * item);
bool forkPathEffectsIfNecessary(unsigned int nr_of_allowed_users = 1);
void editNextParamOncanvas(SPDesktop *dt);
diff --git a/src/sp-marker.cpp b/src/sp-marker.cpp
index 9334614dc..3505e2fe8 100644
--- a/src/sp-marker.cpp
+++ b/src/sp-marker.cpp
@@ -43,14 +43,18 @@ public:
std::vector<Inkscape::DrawingItem *> items;
};
-SPMarker::SPMarker() : SPGroup(), SPViewBox() {
-
- this->markerUnits = 0;
- this->markerUnits_set = 0;
-
- this->orient_mode = MARKER_ORIENT_ANGLE;
- this->orient_set = 0;
- this->orient = 0;
+SPMarker::SPMarker() : SPGroup(), SPViewBox(),
+ markerUnits_set(0),
+ markerUnits(0),
+ refX(),
+ refY(),
+ markerWidth(),
+ markerHeight(),
+ orient_set(0),
+ orient_mode(MARKER_ORIENT_ANGLE)
+{
+ // cppcheck-suppress useInitializationList
+ orient = 0;
}
/**
@@ -390,7 +394,8 @@ sp_marker_show_instance ( SPMarker *marker, Inkscape::DrawingItem *parent,
if (marker->orient_mode == MARKER_ORIENT_AUTO) {
m = base;
} else if (marker->orient_mode == MARKER_ORIENT_AUTO_START_REVERSE) {
- m = Geom::Rotate::from_degrees( 180.0 ) * base;
+ // m = Geom::Rotate::from_degrees( 180.0 ) * base;
+ // Rotating is done at rendering time if necessary
m = base;
} else {
/* fixme: Orient units (Lauris) */
@@ -442,7 +447,7 @@ const gchar *generate_marker(std::vector<Inkscape::XML::Node*> &reprs, Geom::Rec
const gchar *mark_id = repr->attribute("id");
SPObject *mark_object = document->getObjectById(mark_id);
- for (std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();i++){
+ for (std::vector<Inkscape::XML::Node*>::const_iterator i=reprs.begin();i!=reprs.end();++i){
Inkscape::XML::Node *node = *i;
SPItem *copy = SP_ITEM(mark_object->appendChildRepr(node));
diff --git a/src/sp-mask.cpp b/src/sp-mask.cpp
index f8fb7aff4..3537c7bac 100644
--- a/src/sp-mask.cpp
+++ b/src/sp-mask.cpp
@@ -138,23 +138,18 @@ void SPMask::update(SPCtx* ctx, unsigned int flags) {
flags &= SP_OBJECT_MODIFIED_CASCADE;
- GSList *l = NULL;
- for (SPObject *child = this->firstChild(); child; child = child->getNext()) {
- sp_object_ref(child);
- l = g_slist_prepend (l, child);
+ std::vector<SPObject *> children = this->childList(false);
+ for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();++child) {
+ sp_object_ref(*child);
}
- l = g_slist_reverse (l);
- while (l) {
- SPObject *child = SP_OBJECT(l->data);
- l = g_slist_remove(l, child);
-
- if (flags || (child->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
- child->updateDisplay(ctx, flags);
+ for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();++child) {
+ if (flags || ((*child)->uflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
+ (*child)->updateDisplay(ctx, flags);
}
- sp_object_unref(child);
+ sp_object_unref(*child);
}
for (SPMaskView *v = this->display; v != NULL; v = v->next) {
@@ -177,23 +172,17 @@ void SPMask::modified(unsigned int flags) {
flags &= SP_OBJECT_MODIFIED_CASCADE;
- GSList *l = NULL;
- for (SPObject *child = this->firstChild(); child; child = child->getNext()) {
- sp_object_ref(child);
- l = g_slist_prepend(l, child);
+ std::vector<SPObject *> children = this->childList(false);
+ for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();++child) {
+ sp_object_ref(*child);
}
- l = g_slist_reverse(l);
-
- while (l) {
- SPObject *child = SP_OBJECT(l->data);
- l = g_slist_remove(l, child);
-
- if (flags || (child->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
- child->emitModified(flags);
+ for (std::vector<SPObject *>::const_iterator child = children.begin();child != children.end();++child) {
+ if (flags || ((*child)->mflags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG))) {
+ (*child)->emitModified(flags);
}
- sp_object_unref(child);
+ sp_object_unref(*child);
}
}
@@ -221,7 +210,7 @@ sp_mask_create (std::vector<Inkscape::XML::Node*> &reprs, SPDocument *document,
const gchar *mask_id = repr->attribute("id");
SPObject *mask_object = document->getObjectById(mask_id);
- for (std::vector<Inkscape::XML::Node*>::const_iterator it = reprs.begin(); it != reprs.end(); it++) {
+ for (std::vector<Inkscape::XML::Node*>::const_iterator it = reprs.begin(); it != reprs.end(); ++it) {
Inkscape::XML::Node *node = (*it);
SPItem *item = SP_ITEM(mask_object->appendChildRepr(node));
diff --git a/src/sp-mask.h b/src/sp-mask.h
index 74bd4d66e..19786b1fd 100644
--- a/src/sp-mask.h
+++ b/src/sp-mask.h
@@ -86,10 +86,10 @@ protected:
Inkscape::XML::Node * const owner_repr = owner->getRepr();
//XML Tree being used directly here while it shouldn't be...
Inkscape::XML::Node * const obj_repr = obj->getRepr();
- char const * owner_name = NULL;
- char const * owner_mask = NULL;
- char const * obj_name = NULL;
- char const * obj_id = NULL;
+ char const * owner_name = "";
+ char const * owner_mask = "";
+ char const * obj_name = "";
+ char const * obj_id = "";
if (owner_repr != NULL) {
owner_name = owner_repr->name();
owner_mask = owner_repr->attribute("mask");
diff --git a/src/sp-mesh-array.cpp b/src/sp-mesh-array.cpp
index 445c9a8f6..355150893 100644
--- a/src/sp-mesh-array.cpp
+++ b/src/sp-mesh-array.cpp
@@ -313,7 +313,7 @@ bool SPMeshPatchI::tensorIsSet( unsigned int i ) {
/**
Return tensor control point for "corner" i.
- If not sest, returns calculated (Coons) point.
+ If not set, returns calculated (Coons) point.
*/
Geom::Point SPMeshPatchI::getTensorPoint( guint k ) {
@@ -1058,11 +1058,11 @@ void SPMeshNodeArray::create( SPMesh *mg, SPItem *item, Geom::OptRect bbox ) {
Geom::Point center = bbox->midpoint();
// Must keep repr and array in sync. We have two choices:
- // Build the repr first and the "read" it.
- // Construct the array and the "write" it.
+ // Build the repr first and then "read" it.
+ // Construct the array and then "write" it.
// We'll do the second.
- // Remove any existing mesh. We could chose to simply scale an existing mesh...
+ // Remove any existing mesh. We could choose to simply scale an existing mesh...
//clear();
// We get called twice when a new mesh is created...WHY?
@@ -2265,10 +2265,12 @@ guint SPMeshNodeArray::color_pick( std::vector<guint> icorners, SPItem* item ) {
// Region to average over
Geom::Point p = n->p;
- // std::cout << " p: " << p << std::endl;
+ // std::cout << " before transform: p: " << p << std::endl;
p *= gr->gradientTransform;
- // std::cout << " p: " << p << std::endl;
-
+ // std::cout << " after transform: p: " << p << std::endl;
+ p *= item->i2doc_affine();
+ // std::cout << " after transform: p: " << p << std::endl;
+
// If on edge, move inward
guint cols = patch_columns()+1;
guint rows = patch_rows()+1;
@@ -2277,7 +2279,7 @@ guint SPMeshNodeArray::color_pick( std::vector<guint> icorners, SPItem* item ) {
guint ncol = col * 3;
guint nrow = row * 3;
- double size = 3.0;
+ const double size = 3.0;
// Top edge
if( row == 0 ) {
@@ -2328,6 +2330,7 @@ guint SPMeshNodeArray::color_pick( std::vector<guint> icorners, SPItem* item ) {
pick_doc->getRoot()->invoke_hide(pick_visionkey);
delete pick_drawing;
+ picked = 1; // Picking always happens
if( picked > 0 ) built = false;
return picked;
}
diff --git a/src/sp-namedview.cpp b/src/sp-namedview.cpp
index 12c2cdf8e..9598a14ec 100644
--- a/src/sp-namedview.cpp
+++ b/src/sp-namedview.cpp
@@ -51,7 +51,9 @@ using Inkscape::Util::unit_table;
#define DEFAULTPAGECOLOR 0xffffff00
static void sp_namedview_setup_guides(SPNamedView * nv);
+static void sp_namedview_lock_guides(SPNamedView * nv);
static void sp_namedview_show_single_guide(SPGuide* guide, bool show);
+static void sp_namedview_lock_single_guide(SPGuide* guide, bool show);
static gboolean sp_str_to_bool(const gchar *str);
static gboolean sp_nv_read_opacity(const gchar *str, guint32 *color);
@@ -60,7 +62,7 @@ SPNamedView::SPNamedView() : SPObjectGroup(), snap_manager(this) {
this->zoom = 0;
this->guidecolor = 0;
this->guidehicolor = 0;
- this->views = NULL;
+ this->views.clear();
this->borderlayer = 0;
this->page_size_units = NULL;
this->window_x = 0;
@@ -79,13 +81,15 @@ SPNamedView::SPNamedView() : SPObjectGroup(), snap_manager(this) {
this->editable = TRUE;
this->showguides = TRUE;
+ this->lockguides = false;
this->grids_visible = false;
this->showborder = TRUE;
+ this->pagecheckerboard = FALSE;
this->showpageshadow = TRUE;
- this->guides = NULL;
+ this->guides.clear();
this->viewcount = 0;
- this->grids = NULL;
+ this->grids.clear();
this->default_layer_id = 0;
@@ -204,6 +208,7 @@ void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) {
this->readAttr( "bordercolor" );
this->readAttr( "borderopacity" );
this->readAttr( "pagecolor" );
+ this->readAttr( "inkscape:pagecheckerboard" );
this->readAttr( "inkscape:pageopacity" );
this->readAttr( "inkscape:pageshadow" );
this->readAttr( "inkscape:zoom" );
@@ -240,15 +245,17 @@ void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) {
this->readAttr( "inkscape:snap-page" );
this->readAttr( "inkscape:current-layer" );
this->readAttr( "inkscape:connector-spacing" );
+ this->readAttr( "inkscape:lockguides" );
/* Construct guideline list */
for (SPObject *o = this->firstChild() ; o; o = o->getNext() ) {
if (SP_IS_GUIDE(o)) {
SPGuide * g = SP_GUIDE(o);
- this->guides = g_slist_prepend(this->guides, g);
+ this->guides.push_back(g);
//g_object_set(G_OBJECT(g), "color", nv->guidecolor, "hicolor", nv->guidehicolor, NULL);
g->setColor(this->guidecolor);
g->setHiColor(this->guidehicolor);
+ g->readAttr( "inkscape:color" );
}
}
@@ -267,18 +274,12 @@ void SPNamedView::build(SPDocument *document, Inkscape::XML::Node *repr) {
}
void SPNamedView::release() {
- if (this->guides) {
- g_slist_free(this->guides);
- this->guides = NULL;
- }
+ this->guides.clear();
// delete grids:
- while ( this->grids ) {
- Inkscape::CanvasGrid *gr = (Inkscape::CanvasGrid *)this->grids->data; // get first entry
- delete gr;
- this->grids = g_slist_remove_link(this->grids, this->grids); // deletes first entry
- }
-
+ for(std::vector<Inkscape::CanvasGrid *>::const_iterator it=this->grids.begin();it!=this->grids.end();++it )
+ delete *it;
+ this->grids.clear();
SPObjectGroup::release();
}
@@ -324,9 +325,9 @@ void SPNamedView::set(unsigned int key, const gchar* value) {
this->guidecolor = (this->guidecolor & 0xff) | sp_svg_read_color(value, this->guidecolor);
}
- for (GSList *l = this->guides; l != NULL; l = l->next) {
- //g_object_set(G_OBJECT(l->data), "color", nv->guidecolor, NULL);
- SP_GUIDE(l->data)->setColor(this->guidecolor);
+ for(std::vector<SPGuide *>::const_iterator it=this->guides.begin();it!=this->guides.end();++it ) {
+ (*it)->setColor(this->guidecolor);
+ (*it)->readAttr("inkscape:color");
}
this->requestModified(SP_OBJECT_MODIFIED_FLAG);
@@ -335,9 +336,9 @@ void SPNamedView::set(unsigned int key, const gchar* value) {
this->guidecolor = (this->guidecolor & 0xffffff00) | (DEFAULTGUIDECOLOR & 0xff);
sp_nv_read_opacity(value, &this->guidecolor);
- for (GSList *l = this->guides; l != NULL; l = l->next) {
- //g_object_set(G_OBJECT(l->data), "color", nv->guidecolor, NULL);
- SP_GUIDE(l->data)->setColor(this->guidecolor);
+ for(std::vector<SPGuide *>::const_iterator it=this->guides.begin();it!=this->guides.end();++it ) {
+ (*it)->setColor(this->guidecolor);
+ (*it)->readAttr("inkscape:color");
}
this->requestModified(SP_OBJECT_MODIFIED_FLAG);
@@ -348,10 +349,8 @@ void SPNamedView::set(unsigned int key, const gchar* value) {
if (value) {
this->guidehicolor = (this->guidehicolor & 0xff) | sp_svg_read_color(value, this->guidehicolor);
}
-
- for (GSList *l = this->guides; l != NULL; l = l->next) {
- //g_object_set(G_OBJECT(l->data), "hicolor", nv->guidehicolor, NULL);
- SP_GUIDE(l->data)->setHiColor(this->guidehicolor);
+ for(std::vector<SPGuide *>::const_iterator it=this->guides.begin();it!=this->guides.end();++it ) {
+ (*it)->setHiColor(this->guidehicolor);
}
this->requestModified(SP_OBJECT_MODIFIED_FLAG);
@@ -359,10 +358,8 @@ void SPNamedView::set(unsigned int key, const gchar* value) {
case SP_ATTR_GUIDEHIOPACITY:
this->guidehicolor = (this->guidehicolor & 0xffffff00) | (DEFAULTGUIDEHICOLOR & 0xff);
sp_nv_read_opacity(value, &this->guidehicolor);
-
- for (GSList *l = this->guides; l != NULL; l = l->next) {
- //g_object_set(G_OBJECT(l->data), "hicolor", nv->guidehicolor, NULL);
- SP_GUIDE(l->data)->setHiColor(this->guidehicolor);
+ for(std::vector<SPGuide *>::const_iterator it=this->guides.begin();it!=this->guides.end();++it ) {
+ (*it)->setHiColor(this->guidehicolor);
}
this->requestModified(SP_OBJECT_MODIFIED_FLAG);
@@ -395,6 +392,10 @@ void SPNamedView::set(unsigned int key, const gchar* value) {
}
this->requestModified(SP_OBJECT_MODIFIED_FLAG);
break;
+ case SP_ATTR_INKSCAPE_PAGECHECKERBOARD:
+ this->pagecheckerboard = (value) ? sp_str_to_bool (value) : false;
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
case SP_ATTR_INKSCAPE_PAGEOPACITY:
this->pagecolor = (this->pagecolor & 0xffffff00) | (DEFAULTPAGECOLOR & 0xff);
sp_nv_read_opacity(value, &this->pagecolor);
@@ -597,6 +598,11 @@ void SPNamedView::set(unsigned int key, const gchar* value) {
this->requestModified(SP_OBJECT_MODIFIED_FLAG);
break;
}
+ case SP_ATTR_INKSCAPE_LOCKGUIDES:
+ this->lockguides = value ? sp_str_to_bool(value) : FALSE;
+ sp_namedview_lock_guides(this);
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
default:
SPObjectGroup::set(key, value);
break;
@@ -611,10 +617,9 @@ static Inkscape::CanvasGrid*
sp_namedview_add_grid(SPNamedView *nv, Inkscape::XML::Node *repr, SPDesktop *desktop) {
Inkscape::CanvasGrid* grid = NULL;
//check if namedview already has an object for this grid
- for (GSList *l = nv->grids; l != NULL; l = l->next) {
- Inkscape::CanvasGrid* g = (Inkscape::CanvasGrid*) l->data;
- if (repr == g->repr) {
- grid = g;
+ for(std::vector<Inkscape::CanvasGrid *>::const_iterator it=nv->grids.begin();it!=nv->grids.end();++it ) {
+ if (repr == (*it)->repr) {
+ grid = (*it);
break;
}
}
@@ -627,14 +632,13 @@ sp_namedview_add_grid(SPNamedView *nv, Inkscape::XML::Node *repr, SPDesktop *des
return NULL;
}
grid = Inkscape::CanvasGrid::NewGrid(nv, repr, nv->document, gridtype);
- nv->grids = g_slist_append(nv->grids, grid);
+ nv->grids.push_back(grid);
}
if (!desktop) {
//add canvasitem to all desktops
- for (GSList *l = nv->views; l != NULL; l = l->next) {
- SPDesktop *dt = static_cast<SPDesktop*>(l->data);
- grid->createCanvasItem(dt);
+ for(std::vector<SPDesktop *>::const_iterator it=nv->views.begin();it!=nv->views.end();++it ) {
+ grid->createCanvasItem(*it);
}
} else {
//add canvasitem only for specified desktop
@@ -657,21 +661,23 @@ void SPNamedView::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *r
if (SP_IS_GUIDE(no)) {
SPGuide *g = (SPGuide *) no;
- this->guides = g_slist_prepend(this->guides, g);
+ this->guides.push_back(g);
//g_object_set(G_OBJECT(g), "color", this->guidecolor, "hicolor", this->guidehicolor, NULL);
g->setColor(this->guidecolor);
g->setHiColor(this->guidehicolor);
+ g->readAttr("inkscape:color");
if (this->editable) {
- for (GSList *l = this->views; l != NULL; l = l->next) {
- g->SPGuide::showSPGuide(static_cast<SPDesktop*>(l->data)->guides, (GCallback) sp_dt_guide_event);
+ for(std::vector<SPDesktop *>::const_iterator it=this->views.begin();it!=this->views.end();++it ) {
+ g->SPGuide::showSPGuide((*it)->guides, (GCallback) sp_dt_guide_event);
- if (static_cast<SPDesktop*>(l->data)->guides_active) {
- g->sensitize((static_cast<SPDesktop*> (l->data))->getCanvas(), TRUE);
+ if ((*it)->guides_active) {
+ g->sensitize((*it)->getCanvas(), TRUE);
}
sp_namedview_show_single_guide(SP_GUIDE(g), this->showguides);
+ sp_namedview_lock_single_guide(SP_GUIDE(g), this->lockguides);
}
}
}
@@ -680,27 +686,19 @@ void SPNamedView::child_added(Inkscape::XML::Node *child, Inkscape::XML::Node *r
void SPNamedView::remove_child(Inkscape::XML::Node *child) {
if (!strcmp(child->name(), "inkscape:grid")) {
- for ( GSList *iter = this->grids ; iter ; iter = iter->next ) {
- Inkscape::CanvasGrid *gr = (Inkscape::CanvasGrid *)iter->data;
-
- if ( gr->repr == child ) {
- delete gr;
- this->grids = g_slist_remove_link(this->grids, iter);
+ for(std::vector<Inkscape::CanvasGrid *>::iterator it=this->grids.begin();it!=this->grids.end();++it ) {
+ if ( (*it)->repr == child ) {
+ delete (*it);
+ this->grids.erase(it);
break;
}
}
} else {
- GSList **ref = &this->guides;
- for ( GSList *iter = this->guides ; iter ; iter = iter->next ) {
-
- if ( reinterpret_cast<SPObject *>(iter->data)->getRepr() == child ) {
- *ref = iter->next;
- iter->next = NULL;
- g_slist_free_1(iter);
+ for(std::vector<SPGuide *>::iterator it=this->guides.begin();it!=this->guides.end();++it ) {
+ if ( (*it)->getRepr() == child ) {
+ this->guides.erase(it);
break;
- }
-
- ref = &iter->next;
+ }
}
}
@@ -723,15 +721,16 @@ Inkscape::XML::Node* SPNamedView::write(Inkscape::XML::Document *xml_doc, Inksca
void SPNamedView::show(SPDesktop *desktop)
{
- for (GSList *l = guides; l != NULL; l = l->next) {
- SP_GUIDE(l->data)->showSPGuide( desktop->guides, (GCallback) sp_dt_guide_event);
+ for(std::vector<SPGuide *>::const_iterator it=this->guides.begin();it!=this->guides.end();++it ) {
+ (*it)->showSPGuide( desktop->guides, (GCallback) sp_dt_guide_event);
if (desktop->guides_active) {
- SP_GUIDE(l->data)->sensitize(desktop->getCanvas(), TRUE);
+ (*it)->sensitize(desktop->getCanvas(), TRUE);
}
- sp_namedview_show_single_guide(SP_GUIDE(l->data), showguides);
+ sp_namedview_show_single_guide((*it), showguides);
+ sp_namedview_lock_single_guide((*it), lockguides);
}
- views = g_slist_prepend(views, desktop);
+ views.push_back(desktop);
// generate grids specified in SVG:
Inkscape::XML::Node *repr = this->getRepr();
@@ -920,31 +919,35 @@ void sp_namedview_document_from_window(SPDesktop *desktop)
void SPNamedView::hide(SPDesktop const *desktop)
{
g_assert(desktop != NULL);
- g_assert(g_slist_find(views, desktop));
-
- for (GSList *l = guides; l != NULL; l = l->next) {
- SP_GUIDE(l->data)->hideSPGuide(desktop->getCanvas());
+ g_assert(std::find(views.begin(),views.end(),desktop)!=views.end());
+ for(std::vector<SPGuide *>::iterator it=this->guides.begin();it!=this->guides.end();++it ) {
+ (*it)->hideSPGuide(desktop->getCanvas());
}
-
- views = g_slist_remove(views, desktop);
+ views.erase(std::remove(views.begin(),views.end(),desktop),views.end());
}
void SPNamedView::activateGuides(void* desktop, bool active)
{
g_assert(desktop != NULL);
- g_assert(g_slist_find(views, desktop));
+ g_assert(std::find(views.begin(),views.end(),desktop)!=views.end());
SPDesktop *dt = static_cast<SPDesktop*>(desktop);
-
- for (GSList *l = guides; l != NULL; l = l->next) {
- SP_GUIDE(l->data)->sensitize(dt->getCanvas(), active);
+ for(std::vector<SPGuide *>::iterator it=this->guides.begin();it!=this->guides.end();++it ) {
+ (*it)->sensitize(dt->getCanvas(), active);
}
}
static void sp_namedview_setup_guides(SPNamedView *nv)
{
- for (GSList *l = nv->guides; l != NULL; l = l->next) {
- sp_namedview_show_single_guide(SP_GUIDE(l->data), nv->showguides);
+ for(std::vector<SPGuide *>::iterator it=nv->guides.begin();it!=nv->guides.end();++it ) {
+ sp_namedview_show_single_guide(*it, nv->showguides);
+ }
+}
+
+static void sp_namedview_lock_guides(SPNamedView *nv)
+{
+ for(std::vector<SPGuide *>::iterator it=nv->guides.begin();it!=nv->guides.end();++it ) {
+ sp_namedview_lock_single_guide(*it, nv->lockguides);
}
}
@@ -957,6 +960,11 @@ static void sp_namedview_show_single_guide(SPGuide* guide, bool show)
}
}
+static void sp_namedview_lock_single_guide(SPGuide* guide, bool locked)
+{
+ guide->set_locked(locked, true);
+}
+
void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr)
{
unsigned int v;
@@ -975,6 +983,23 @@ void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr)
doc->setModifiedSinceSave();
}
+void sp_namedview_guides_toggle_lock(SPDocument *doc, Inkscape::XML::Node *repr)
+{
+ unsigned int v;
+ unsigned int set = sp_repr_get_boolean(repr, "inkscape:lockguides", &v);
+ if (!set) { // hide guides if not specified, for backwards compatibility
+ v = true;
+ } else {
+ v = !v;
+ }
+
+ bool saved = DocumentUndo::getUndoSensitive(doc);
+ DocumentUndo::setUndoSensitive(doc, false);
+ sp_repr_set_boolean(repr, "inkscape:lockguides", v);
+ DocumentUndo::setUndoSensitive(doc, saved);
+ doc->setModifiedSinceSave();
+}
+
void sp_namedview_show_grids(SPNamedView * namedview, bool show, bool dirty_document)
{
namedview->grids_visible = show;
@@ -1006,7 +1031,7 @@ guint SPNamedView::getViewCount()
return ++viewcount;
}
-GSList const *SPNamedView::getViewList() const
+std::vector<SPDesktop *> const SPNamedView::getViewList() const
{
return views;
}
@@ -1073,6 +1098,7 @@ void SPNamedView::setGuides(bool v)
g_assert(this->getRepr() != NULL);
sp_repr_set_boolean(this->getRepr(), "showguides", v);
sp_repr_set_boolean(this->getRepr(), "inkscape:guide-bbox", v);
+ sp_repr_set_boolean(this->getRepr(), "inkscape:locked", false);
}
bool SPNamedView::getGuides()
@@ -1140,18 +1166,17 @@ Inkscape::Util::Unit const & SPNamedView::getSVGUnit() const
*/
Inkscape::CanvasGrid * sp_namedview_get_first_enabled_grid(SPNamedView *namedview)
{
- for (GSList const * l = namedview->grids; l != NULL; l = l->next) {
- Inkscape::CanvasGrid * grid = (Inkscape::CanvasGrid*) l->data;
- if (grid->isEnabled())
- return grid;
+ for(std::vector<Inkscape::CanvasGrid *>::const_iterator it=namedview->grids.begin();it!=namedview->grids.end();++it ) {
+ if ((*it)->isEnabled())
+ return (*it);
}
return NULL;
}
void SPNamedView::translateGuides(Geom::Translate const &tr) {
- for (GSList *l = guides; l != NULL; l = l->next) {
- SPGuide &guide = *SP_GUIDE(l->data);
+ for(std::vector<SPGuide *>::iterator it=this->guides.begin();it!=this->guides.end();++it ) {
+ SPGuide &guide = *(*it);
Geom::Point point_on_line = guide.getPoint();
point_on_line *= tr;
guide.moveto(point_on_line, true);
@@ -1159,19 +1184,15 @@ void SPNamedView::translateGuides(Geom::Translate const &tr) {
}
void SPNamedView::translateGrids(Geom::Translate const &tr) {
- for (GSList *l = grids; l != NULL; l = l->next) {
- Inkscape::CanvasGrid* g = reinterpret_cast<Inkscape::CanvasGrid*>(l->data);
- if (g) {
- g->setOrigin(g->origin * tr);
- }
+ for(std::vector<Inkscape::CanvasGrid *>::iterator it=this->grids.begin();it!=this->grids.end();++it ) {
+ (*it)->setOrigin((*it)->origin * tr);
}
}
void SPNamedView::scrollAllDesktops(double dx, double dy, bool is_scrolling) {
- for(GSList *l = views; l; l = l->next) {
- SPDesktop *desktop = static_cast<SPDesktop *>(l->data);
- desktop->scroll_world_in_svg_coords(dx, dy, is_scrolling);
- }
+ for(std::vector<SPDesktop *>::iterator it=this->views.begin();it!=this->views.end();++it ) {
+ (*it)->scroll_world_in_svg_coords(dx, dy, is_scrolling);
+ }
}
diff --git a/src/sp-namedview.h b/src/sp-namedview.h
index f1ecc12d3..3d63f2b97 100644
--- a/src/sp-namedview.h
+++ b/src/sp-namedview.h
@@ -21,6 +21,7 @@
#include "snap.h"
#include "document.h"
#include "util/units.h"
+#include <vector>
namespace Inkscape {
class CanvasGrid;
@@ -44,6 +45,8 @@ public:
unsigned int editable : 1;
unsigned int showguides : 1;
+ unsigned int lockguides : 1;
+ unsigned int pagecheckerboard : 1;
unsigned int showborder : 1;
unsigned int showpageshadow : 1;
unsigned int borderlayer : 2;
@@ -58,7 +61,7 @@ public:
int window_maximized;
SnapManager snap_manager;
- GSList * grids;
+ std::vector<Inkscape::CanvasGrid *> grids;
bool grids_visible;
Inkscape::Util::Unit const *svg_units; // Units used for the values in SVG
@@ -75,8 +78,8 @@ public:
guint32 pagecolor;
guint32 pageshadow;
- GSList *guides;
- GSList *views;
+ std::vector<SPGuide *> guides;
+ std::vector<SPDesktop *> views;
int viewcount;
@@ -85,7 +88,7 @@ public:
void activateGuides(void* desktop, bool active);
char const *getName() const;
unsigned int getViewCount();
- GSList const *getViewList() const;
+ std::vector<SPDesktop *> const getViewList() const;
Inkscape::Util::Unit const * getDisplayUnit() const;
Inkscape::Util::Unit const & getSVGUnit() const;
@@ -122,6 +125,7 @@ void sp_namedview_document_from_window(SPDesktop *desktop);
void sp_namedview_update_layers_from_document (SPDesktop *desktop);
void sp_namedview_toggle_guides(SPDocument *doc, Inkscape::XML::Node *repr);
+void sp_namedview_guides_toggle_lock(SPDocument *doc, Inkscape::XML::Node *repr);
void sp_namedview_show_grids(SPNamedView *namedview, bool show, bool dirty_document);
Inkscape::CanvasGrid * sp_namedview_get_first_enabled_grid(SPNamedView *namedview);
diff --git a/src/sp-object.h b/src/sp-object.h
index 7bc02fad5..70d3e5df5 100644
--- a/src/sp-object.h
+++ b/src/sp-object.h
@@ -59,7 +59,6 @@ class SPObject;
class SPCSSAttr;
class SPStyle;
-typedef struct _GSList GSList;
namespace Inkscape {
namespace XML {
diff --git a/src/sp-paint-server.cpp b/src/sp-paint-server.cpp
index c3416c6c8..d445ca0a7 100644
--- a/src/sp-paint-server.cpp
+++ b/src/sp-paint-server.cpp
@@ -39,7 +39,9 @@ SPPaintServer::~SPPaintServer() {
bool SPPaintServer::isSwatch() const
{
- return swatch;
+ if( this ) // Protect against assumption that "vector" always exists.
+ return swatch;
+ return( false );
}
diff --git a/src/sp-path.cpp b/src/sp-path.cpp
index cabed0467..c4d24c503 100644
--- a/src/sp-path.cpp
+++ b/src/sp-path.cpp
@@ -294,8 +294,9 @@ Geom::Affine SPPath::set_transform(Geom::Affine const &transform) {
// Transform the original-d path if this is a valid LPE this, other else the (ordinary) path
if (_curve_before_lpe && hasPathEffectRecursive()) {
- if (this->hasPathEffectOfType(Inkscape::LivePathEffect::CLONE_ORIGINAL)) {
+ if (this->hasPathEffectOfType(Inkscape::LivePathEffect::CLONE_ORIGINAL) || this->hasPathEffectOfType(Inkscape::LivePathEffect::BEND_PATH)) {
// if path has the CLONE_ORIGINAL LPE applied, don't write the transform to the pathdata, but write it 'unoptimized'
+ // also if the effect is type BEND PATH to fix bug #179842
return transform;
} else {
_curve_before_lpe->transform(transform);
diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp
index 755d3d162..55110f3c5 100644
--- a/src/sp-pattern.cpp
+++ b/src/sp-pattern.cpp
@@ -244,7 +244,7 @@ void SPPattern::update(SPCtx *ctx, unsigned int flags)
std::list<SPObject *> l;
_getChildren(l);
- for (SPObjectIterator it = l.begin(); it != l.end(); it++) {
+ for (SPObjectIterator it = l.begin(); it != l.end(); ++it) {
SPObject *child = *it;
sp_object_ref(child, NULL);
@@ -270,7 +270,7 @@ void SPPattern::modified(unsigned int flags)
std::list<SPObject *> l;
_getChildren(l);
- for (SPObjectIterator it = l.begin(); it != l.end(); it++) {
+ for (SPObjectIterator it = l.begin(); it != l.end(); ++it) {
SPObject *child = *it;
sp_object_ref(child, NULL);
@@ -390,15 +390,16 @@ const gchar *SPPattern::produce(const std::vector<Inkscape::XML::Node *> &reprs,
repr->setAttribute("patternUnits", "userSpaceOnUse");
sp_repr_set_svg_double(repr, "width", bounds.dimensions()[Geom::X]);
sp_repr_set_svg_double(repr, "height", bounds.dimensions()[Geom::Y]);
-
- Glib::ustring t = sp_svg_transform_write(transform);
- repr->setAttribute("patternTransform", t);
-
+ //TODO: Maybe is better handle it in sp_svg_transform_write
+ if(transform != Geom::Affine()){
+ Glib::ustring t = sp_svg_transform_write(transform);
+ repr->setAttribute("patternTransform", t);
+ }
defsrepr->appendChild(repr);
const gchar *pat_id = repr->attribute("id");
SPObject *pat_object = document->getObjectById(pat_id);
- for (NodePtrIterator i = reprs.begin(); i != reprs.end(); i++) {
+ for (NodePtrIterator i = reprs.begin(); i != reprs.end(); ++i) {
Inkscape::XML::Node *node = *i;
SPItem *copy = SP_ITEM(pat_object->appendChildRepr(node));
diff --git a/src/sp-radial-gradient.cpp b/src/sp-radial-gradient.cpp
index 8fb230ba7..fa6355478 100644
--- a/src/sp-radial-gradient.cpp
+++ b/src/sp-radial-gradient.cpp
@@ -16,6 +16,7 @@ SPRadialGradient::SPRadialGradient() : SPGradient() {
this->r.unset(SVGLength::PERCENT, 0.5, 0.5);
this->fx.unset(SVGLength::PERCENT, 0.5, 0.5);
this->fy.unset(SVGLength::PERCENT, 0.5, 0.5);
+ this->fr.unset(SVGLength::PERCENT, 0.5, 0.5);
}
SPRadialGradient::~SPRadialGradient() {
@@ -32,6 +33,7 @@ void SPRadialGradient::build(SPDocument *document, Inkscape::XML::Node *repr) {
this->readAttr( "r" );
this->readAttr( "fx" );
this->readAttr( "fy" );
+ this->readAttr( "fr" );
}
/**
@@ -89,6 +91,13 @@ void SPRadialGradient::set(unsigned key, gchar const *value) {
this->requestModified(SP_OBJECT_MODIFIED_FLAG);
break;
+ case SP_ATTR_FR:
+ if (!this->fr.read(value)) {
+ this->fr.unset(SVGLength::PERCENT, 0.0, 0.0);
+ }
+ this->requestModified(SP_OBJECT_MODIFIED_FLAG);
+ break;
+
default:
SPGradient::set(key, value);
break;
@@ -123,6 +132,10 @@ Inkscape::XML::Node* SPRadialGradient::write(Inkscape::XML::Document *xml_doc, I
sp_repr_set_svg_double(repr, "fy", this->fy.computed);
}
+ if ((flags & SP_OBJECT_WRITE_ALL) || this->fr._set) {
+ sp_repr_set_svg_double(repr, "fr", this->fr.computed);
+ }
+
SPGradient::write(xml_doc, repr, flags);
return repr;
@@ -135,6 +148,7 @@ cairo_pattern_t* SPRadialGradient::pattern_new(cairo_t *ct, Geom::OptRect const
Geom::Point center(this->cx.computed, this->cy.computed);
double radius = this->r.computed;
+ double focusr = this->fr.computed;
double scale = 1.0;
double tolerance = cairo_get_tolerance(ct);
@@ -159,8 +173,10 @@ cairo_pattern_t* SPRadialGradient::pattern_new(cairo_t *ct, Geom::OptRect const
Geom::Point d(focus - center);
Geom::Point d_user(d.length(), 0);
Geom::Point r_user(radius, 0);
+ Geom::Point fr_user(focusr, 0);
d_user *= gs2user.withoutTranslation();
r_user *= gs2user.withoutTranslation();
+ fr_user *= gs2user.withoutTranslation();
double dx = d_user.x(), dy = d_user.y();
cairo_user_to_device_distance(ct, &dx, &dy);
@@ -181,7 +197,7 @@ cairo_pattern_t* SPRadialGradient::pattern_new(cairo_t *ct, Geom::OptRect const
}
cairo_pattern_t *cp = cairo_pattern_create_radial(
- scale * d.x() + center.x(), scale * d.y() + center.y(), 0,
+ scale * d.x() + center.x(), scale * d.y() + center.y(), focusr,
center.x(), center.y(), radius);
sp_gradient_pattern_common_setup(cp, this, bbox, opacity);
diff --git a/src/sp-radial-gradient.h b/src/sp-radial-gradient.h
index f753623b7..f90c8c7a9 100644
--- a/src/sp-radial-gradient.h
+++ b/src/sp-radial-gradient.h
@@ -25,6 +25,7 @@ public:
SVGLength r;
SVGLength fx;
SVGLength fy;
+ SVGLength fr; // Focus radius. Added in SVG 2
virtual cairo_pattern_t* pattern_new(cairo_t *ct, Geom::OptRect const &bbox, double opacity);
diff --git a/src/sp-rect.cpp b/src/sp-rect.cpp
index e17d7373c..2ba9a7023 100644
--- a/src/sp-rect.cpp
+++ b/src/sp-rect.cpp
@@ -61,13 +61,13 @@ void SPRect::set(unsigned key, gchar const *value) {
switch (key) {
case SP_ATTR_X:
this->x.readOrUnset(value);
- this->x.update( ex, em, w );
+ this->x.update( em, ex, w );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
case SP_ATTR_Y:
this->y.readOrUnset(value);
- this->y.update( ex, em, h );
+ this->y.update( em, ex, h );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
@@ -75,7 +75,7 @@ void SPRect::set(unsigned key, gchar const *value) {
if (!this->width.read(value) || this->width.value < 0.0) {
this->width.unset();
}
- this->width.update( ex, em, w );
+ this->width.update( em, ex, w );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
@@ -83,7 +83,7 @@ void SPRect::set(unsigned key, gchar const *value) {
if (!this->height.read(value) || this->height.value < 0.0) {
this->height.unset();
}
- this->height.update( ex, em, h );
+ this->height.update( em, ex, h );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
@@ -91,7 +91,7 @@ void SPRect::set(unsigned key, gchar const *value) {
if (!this->rx.read(value) || this->rx.value <= 0.0) {
this->rx.unset();
}
- this->rx.update( ex, em, w );
+ this->rx.update( em, ex, w );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
@@ -99,7 +99,7 @@ void SPRect::set(unsigned key, gchar const *value) {
if (!this->ry.read(value) || this->ry.value <= 0.0) {
this->ry.unset();
}
- this->ry.update( ex, em, h );
+ this->ry.update( em, ex, h );
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
break;
diff --git a/src/sp-star.cpp b/src/sp-star.cpp
index 51d5e6254..8a1956e3b 100644
--- a/src/sp-star.cpp
+++ b/src/sp-star.cpp
@@ -32,15 +32,16 @@
#include "sp-star.h"
-SPStar::SPStar() : SPPolygon() {
- this->sides = 5;
- this->center = Geom::Point(0, 0);
+SPStar::SPStar() : SPPolygon() ,
+ sides(5),
+ center(0, 0),
+ flatsided(0),
+ rounded(0.0),
+ randomized(0.0)
+{
this->r[0] = 1.0;
this->r[1] = 0.001;
this->arg[0] = this->arg[1] = 0.0;
- this->flatsided = 0;
- this->rounded = 0.0;
- this->randomized = 0.0;
}
SPStar::~SPStar() {
diff --git a/src/sp-switch.cpp b/src/sp-switch.cpp
index cfc0e7d8b..d2dcde15d 100644
--- a/src/sp-switch.cpp
+++ b/src/sp-switch.cpp
@@ -97,7 +97,7 @@ void SPSwitch::_reevaluate(bool /*add_to_drawing*/) {
_releaseLastItem(_cached_item);
std::vector<SPObject*> item_list = _childList(false, SPObject::ActionShow);
- for ( std::vector<SPObject*>::const_reverse_iterator iter=item_list.rbegin();iter!=item_list.rend();iter++) {
+ for ( std::vector<SPObject*>::const_reverse_iterator iter=item_list.rbegin();iter!=item_list.rend();++iter) {
SPObject *o = *iter;
if ( !SP_IS_ITEM (o) ) {
continue;
@@ -132,7 +132,7 @@ void SPSwitch::_showChildren (Inkscape::Drawing &drawing, Inkscape::DrawingItem
std::vector<SPObject*> l = this->_childList(false, SPObject::ActionShow);
- for ( std::vector<SPObject*>::const_reverse_iterator iter=l.rbegin();iter!=l.rend();iter++) {
+ for ( std::vector<SPObject*>::const_reverse_iterator iter=l.rbegin();iter!=l.rend();++iter) {
SPObject *o = *iter;
if (SP_IS_ITEM (o)) {
diff --git a/src/sp-switch.h b/src/sp-switch.h
index 7152e1b82..57ce8b236 100644
--- a/src/sp-switch.h
+++ b/src/sp-switch.h
@@ -17,7 +17,6 @@
#include "sp-item-group.h"
-typedef struct _GSList GSList;
#define SP_SWITCH(obj) (dynamic_cast<SPSwitch*>((SPObject*)obj))
#define SP_IS_SWITCH(obj) (dynamic_cast<const SPSwitch*>((SPObject*)obj) != NULL)
diff --git a/src/sp-text.cpp b/src/sp-text.cpp
index d351e58e3..4a5b1b1d6 100644
--- a/src/sp-text.cpp
+++ b/src/sp-text.cpp
@@ -93,7 +93,7 @@ void SPText::release() {
void SPText::set(unsigned int key, const gchar* value) {
//std::cout << "SPText::set: " << sp_attribute_name( key ) << ": " << (value?value:"Null") << std::endl;
- if (this->attributes.readSingleAttribute(key, value)) {
+ if (this->attributes.readSingleAttribute(key, value, style, &viewport)) {
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
} else {
switch (key) {
@@ -181,6 +181,16 @@ void SPText::update(SPCtx *ctx, guint flags) {
SP_OBJECT_CHILD_MODIFIED_FLAG |
SP_TEXT_LAYOUT_MODIFIED_FLAG ) )
{
+
+ SPItemCtx const *ictx = reinterpret_cast<SPItemCtx const *>(ctx);
+
+ double const w = ictx->viewport.width();
+ double const h = ictx->viewport.height();
+ double const em = style->font_size.computed;
+ double const ex = 0.5 * em; // fixme: get x height from pango or libnrtype.
+
+ attributes.update( em, ex, w, h );
+
/* fixme: It is not nice to have it here, but otherwise children content changes does not work */
/* fixme: Even now it may not work, as we are delayed */
/* fixme: So check modification flag everywhere immediate state is used */
@@ -292,15 +302,6 @@ Inkscape::XML::Node *SPText::write(Inkscape::XML::Document *xml_doc, Inkscape::X
this->attributes.writeTo(repr);
this->rebuildLayout(); // copied from update(), see LP Bug 1339305
- // deprecated attribute, but keep it around for backwards compatibility
- if (this->style->line_height.set && !this->style->line_height.inherit && !this->style->line_height.normal && this->style->line_height.unit == SP_CSS_UNIT_PERCENT) {
- Inkscape::SVGOStringStream os;
- os << (this->style->line_height.value * 100.0) << "%";
- this->getRepr()->setAttribute("sodipodi:linespacing", os.str().c_str());
- } else {
- this->getRepr()->setAttribute("sodipodi:linespacing", NULL);
- }
-
// SVG 2 Auto-wrapped text
if( this->width.computed > 0.0 ) {
sp_repr_set_svg_double(repr, "width", this->width.computed);
@@ -357,8 +358,11 @@ gchar* SPText::description() const {
char *n = xml_quote_strdup( style->font_family.value );
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int unit = prefs->getInt("/options/font/unitType", SP_CSS_UNIT_PT);
Inkscape::Util::Quantity q = Inkscape::Util::Quantity(style->font_size.computed, "px");
- GString *xs = g_string_new(q.string(SP_ACTIVE_DESKTOP->getNamedView()->display_units).c_str());
+ q.quantity *= this->i2doc_affine().descrim();
+ GString *xs = g_string_new(q.string(sp_style_get_css_unit_string(unit)).c_str());
char const *trunc = "";
Inkscape::Text::Layout const *layout = te_get_layout((SPItem *) this);
@@ -576,7 +580,7 @@ unsigned SPText::_buildLayoutInput(SPObject *root, Inkscape::Text::Layout::Optio
SPString *str = dynamic_cast<SPString *>(child);
if (str) {
Glib::ustring const &string = str->string;
- // std::cout << " Appending: " << string << std::endl;
+ // std::cout << " Appending: >" << string << "<" << std::endl;
layout.appendText(string, root->style, child, &optional_attrs, child_attrs_offset + length);
length += string.length();
} else if (!sp_repr_is_meta_element(child->getRepr())) {
@@ -671,25 +675,30 @@ void SPText::_clearFlow(Inkscape::DrawingGroup *in_arena)
* TextTagAttributes implementation
*/
-void TextTagAttributes::readFrom(Inkscape::XML::Node const *node)
-{
- readSingleAttribute(SP_ATTR_X, node->attribute("x"));
- readSingleAttribute(SP_ATTR_Y, node->attribute("y"));
- readSingleAttribute(SP_ATTR_DX, node->attribute("dx"));
- readSingleAttribute(SP_ATTR_DY, node->attribute("dy"));
- readSingleAttribute(SP_ATTR_ROTATE, node->attribute("rotate"));
- readSingleAttribute(SP_ATTR_TEXTLENGTH, node->attribute("textLength"));
- readSingleAttribute(SP_ATTR_LENGTHADJUST, node->attribute("lengthAdjust"));
-}
-
-bool TextTagAttributes::readSingleAttribute(unsigned key, gchar const *value)
+// Not used.
+// void TextTagAttributes::readFrom(Inkscape::XML::Node const *node)
+// {
+// readSingleAttribute(SP_ATTR_X, node->attribute("x"));
+// readSingleAttribute(SP_ATTR_Y, node->attribute("y"));
+// readSingleAttribute(SP_ATTR_DX, node->attribute("dx"));
+// readSingleAttribute(SP_ATTR_DY, node->attribute("dy"));
+// readSingleAttribute(SP_ATTR_ROTATE, node->attribute("rotate"));
+// readSingleAttribute(SP_ATTR_TEXTLENGTH, node->attribute("textLength"));
+// readSingleAttribute(SP_ATTR_LENGTHADJUST, node->attribute("lengthAdjust"));
+// }
+
+bool TextTagAttributes::readSingleAttribute(unsigned key, gchar const *value, SPStyle const *style, Geom::Rect const *viewport)
{
+ // std::cout << "TextTagAttributes::readSingleAttribute: key: " << key
+ // << " value: " << (value?value:"Null") << std::endl;
std::vector<SVGLength> *attr_vector;
+ bool update_x = false;
+ bool update_y = false;
switch (key) {
- case SP_ATTR_X: attr_vector = &attributes.x; break;
- case SP_ATTR_Y: attr_vector = &attributes.y; break;
- case SP_ATTR_DX: attr_vector = &attributes.dx; break;
- case SP_ATTR_DY: attr_vector = &attributes.dy; break;
+ case SP_ATTR_X: attr_vector = &attributes.x; update_x = true; break;
+ case SP_ATTR_Y: attr_vector = &attributes.y; update_y = true; break;
+ case SP_ATTR_DX: attr_vector = &attributes.dx; update_x = true; break;
+ case SP_ATTR_DY: attr_vector = &attributes.dy; update_y = true; break;
case SP_ATTR_ROTATE: attr_vector = &attributes.rotate; break;
case SP_ATTR_TEXTLENGTH:
attributes.textLength.readOrUnset(value);
@@ -706,6 +715,19 @@ bool TextTagAttributes::readSingleAttribute(unsigned key, gchar const *value)
// FIXME: sp_svg_length_list_read() amalgamates repeated separators. This prevents unset values.
*attr_vector = sp_svg_length_list_read(value);
+
+ if( (update_x || update_y) && style != NULL && viewport != NULL ) {
+ double const w = viewport->width();
+ double const h = viewport->height();
+ double const em = style->font_size.computed;
+ double const ex = em * 0.5;
+ for(std::vector<SVGLength>::iterator it = attr_vector->begin(); it != attr_vector->end(); ++it) {
+ if( update_x )
+ it->update( em, ex, w );
+ if( update_y )
+ it->update( em, ex, h );
+ }
+ }
return true;
}
@@ -728,12 +750,26 @@ void TextTagAttributes::writeTo(Inkscape::XML::Node *node) const
}
}
+void TextTagAttributes::update( double em, double ex, double w, double h )
+{
+ for(std::vector<SVGLength>::iterator it = attributes.x.begin(); it != attributes.x.end(); ++it) {
+ it->update( em, ex, w );
+ }
+ for(std::vector<SVGLength>::iterator it = attributes.y.begin(); it != attributes.y.end(); ++it) {
+ it->update( em, ex, h );
+ }
+ for(std::vector<SVGLength>::iterator it = attributes.dx.begin(); it != attributes.dx.end(); ++it) {
+ it->update( em, ex, w );
+ }
+ for(std::vector<SVGLength>::iterator it = attributes.dy.begin(); it != attributes.dy.end(); ++it) {
+ it->update( em, ex, h );
+ }
+}
+
void TextTagAttributes::writeSingleAttributeLength(Inkscape::XML::Node *node, gchar const *key, const SVGLength &length)
{
if (length._set) {
- gchar single_value_string[32];
- g_ascii_formatd(single_value_string, sizeof (single_value_string), "%.8g", length.computed);
- node->setAttribute(key, single_value_string);
+ node->setAttribute(key, length.write().c_str());
} else
node->setAttribute(key, NULL);
}
@@ -744,13 +780,11 @@ void TextTagAttributes::writeSingleAttributeVector(Inkscape::XML::Node *node, gc
node->setAttribute(key, NULL);
else {
Glib::ustring string;
- gchar single_value_string[32];
// FIXME: this has no concept of unset values because sp_svg_length_list_read() can't read them back in
for (std::vector<SVGLength>::const_iterator it = attr_vector.begin() ; it != attr_vector.end() ; ++it) {
- g_ascii_formatd(single_value_string, sizeof (single_value_string), "%.8g", it->computed);
if (!string.empty()) string += ' ';
- string += single_value_string;
+ string += it->write();
}
node->setAttribute(key, string.c_str());
}
diff --git a/src/sp-tref.cpp b/src/sp-tref.cpp
index aef18462a..ba592058b 100644
--- a/src/sp-tref.cpp
+++ b/src/sp-tref.cpp
@@ -92,7 +92,7 @@ void SPTRef::set(unsigned int key, const gchar* value) {
debug("0x%p %s(%u): '%s'",this,
sp_attribute_name(key),key,value ? value : "<no value>");
- if (this->attributes.readSingleAttribute(key, value)) { // x, y, dx, dy, rotate
+ if (this->attributes.readSingleAttribute(key, value, style, &viewport)) { // x, y, dx, dy, rotate
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
} else if (key == SP_ATTR_XLINK_HREF) { // xlink:href
if ( !value ) {
diff --git a/src/sp-tspan.cpp b/src/sp-tspan.cpp
index 7582cb9e6..05f8430ba 100644
--- a/src/sp-tspan.cpp
+++ b/src/sp-tspan.cpp
@@ -70,7 +70,7 @@ void SPTSpan::release() {
}
void SPTSpan::set(unsigned int key, const gchar* value) {
- if (this->attributes.readSingleAttribute(key, value)) {
+ if (this->attributes.readSingleAttribute(key, value, style, &viewport)) {
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
} else {
switch (key) {
@@ -103,6 +103,20 @@ void SPTSpan::update(SPCtx *ctx, guint flags) {
}
SPItem::update(ctx, flags);
+
+ if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_CHILD_MODIFIED_FLAG |
+ SP_TEXT_LAYOUT_MODIFIED_FLAG ) )
+ {
+ SPItemCtx const *ictx = reinterpret_cast<SPItemCtx const *>(ctx);
+
+ double const w = ictx->viewport.width();
+ double const h = ictx->viewport.height();
+ double const em = style->font_size.computed;
+ double const ex = 0.5 * em; // fixme: get x height from pango or libnrtype.
+
+ attributes.update( em, ex, w, h );
+ }
}
void SPTSpan::modified(unsigned int flags) {
@@ -264,7 +278,7 @@ void SPTextPath::release() {
}
void SPTextPath::set(unsigned int key, const gchar* value) {
- if (this->attributes.readSingleAttribute(key, value)) {
+ if (this->attributes.readSingleAttribute(key, value, style, &viewport)) {
this->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
} else {
switch (key) {
@@ -304,6 +318,20 @@ void SPTextPath::update(SPCtx *ctx, guint flags) {
ochild->updateDisplay(ctx, flags);
}
}
+
+ if (flags & ( SP_OBJECT_STYLE_MODIFIED_FLAG |
+ SP_OBJECT_CHILD_MODIFIED_FLAG |
+ SP_TEXT_LAYOUT_MODIFIED_FLAG ) )
+ {
+ SPItemCtx const *ictx = reinterpret_cast<SPItemCtx const *>(ctx);
+
+ double const w = ictx->viewport.width();
+ double const h = ictx->viewport.height();
+ double const em = style->font_size.computed;
+ double const ex = 0.5 * em; // fixme: get x height from pango or libnrtype.
+
+ attributes.update( em, ex, w, h );
+ }
}
diff --git a/src/splivarot.cpp b/src/splivarot.cpp
index 726df6e20..461445ee0 100644
--- a/src/splivarot.cpp
+++ b/src/splivarot.cpp
@@ -105,6 +105,13 @@ sp_selected_path_cut(Inkscape::Selection *selection, SPDesktop *desktop)
{
sp_selected_path_boolop(selection, desktop, bool_op_cut, SP_VERB_SELECTION_CUT, _("Division"));
}
+
+void
+sp_selected_path_cut_skip_undo(Inkscape::Selection *selection, SPDesktop *desktop)
+{
+ sp_selected_path_boolop(selection, desktop, bool_op_cut, SP_VERB_NONE, _("Division"));
+}
+
void
sp_selected_path_slice(Inkscape::Selection *selection, SPDesktop *desktop)
{
@@ -342,13 +349,6 @@ sp_selected_path_boolop(Inkscape::Selection *selection, SPDesktop *desktop, bool
g_assert(!il.empty());
- if (il.size() > 2) {
- if (bop == bool_op_diff || bop == bool_op_cut || bop == bool_op_slice ) {
- boolop_display_error_message(desktop, _("Select <b>exactly 2 paths</b> to perform difference, division, or path cut."));
- return;
- }
- }
-
// reverseOrderForOp marks whether the order of the list is the top->down order
// it's only used when there are 2 objects, and for operations who need to know the
// topmost object (differences, cuts)
diff --git a/src/splivarot.h b/src/splivarot.h
index ba314399f..421c9c4b8 100644
--- a/src/splivarot.h
+++ b/src/splivarot.h
@@ -33,6 +33,7 @@ void sp_selected_path_diff (Inkscape::Selection *selection, SPDesktop *desktop);
void sp_selected_path_diff_skip_undo (Inkscape::Selection *selection, SPDesktop *desktop);
void sp_selected_path_symdiff (Inkscape::Selection *selection, SPDesktop *desktop);
void sp_selected_path_cut (Inkscape::Selection *selection, SPDesktop *desktop);
+void sp_selected_path_cut_skip_undo (Inkscape::Selection *selection, SPDesktop *desktop);
void sp_selected_path_slice (Inkscape::Selection *selection, SPDesktop *desktop);
// offset/inset of a curve
diff --git a/src/style-enums.h b/src/style-enums.h
index dfc99282c..06207852c 100644
--- a/src/style-enums.h
+++ b/src/style-enums.h
@@ -163,12 +163,6 @@ enum SPCSSDirection {
SP_CSS_DIRECTION_RTL
};
-enum SPCSSBlockProgression {
- SP_CSS_BLOCK_PROGRESSION_TB,
- SP_CSS_BLOCK_PROGRESSION_RL,
- SP_CSS_BLOCK_PROGRESSION_LR
-};
-
enum SPCSSWritingMode {
SP_CSS_WRITING_MODE_LR_TB,
SP_CSS_WRITING_MODE_RL_TB,
@@ -176,6 +170,13 @@ enum SPCSSWritingMode {
SP_CSS_WRITING_MODE_TB_LR
};
+// CSS WRITING MODES 3
+enum SPCSSTextOrientation {
+ SP_CSS_TEXT_ORIENTATION_MIXED,
+ SP_CSS_TEXT_ORIENTATION_UPRIGHT,
+ SP_CSS_TEXT_ORIENTATION_SIDEWAYS
+};
+
enum SPTextAnchor {
SP_CSS_TEXT_ANCHOR_START,
SP_CSS_TEXT_ANCHOR_MIDDLE,
@@ -190,10 +191,24 @@ enum SPWhiteSpace {
SP_CSS_WHITE_SPACE_PRELINE
};
+// Not complete list
+enum SPCSSBaseline {
+ SP_CSS_BASELINE_AUTO,
+ SP_CSS_BASELINE_ALPHABETIC,
+ SP_CSS_BASELINE_IDEOGRAPHIC,
+ SP_CSS_BASELINE_HANGING,
+ SP_CSS_BASELINE_MATHEMATICAL,
+ SP_CSS_BASELINE_CENTRAL,
+ SP_CSS_BASELINE_MIDDLE,
+ SP_CSS_BASELINE_TEXT_BEFORE_EDGE,
+ SP_CSS_BASELINE_TEXT_AFTER_EDGE,
+ SP_CSS_BASELINE_SIZE // Size of enum, keep last.
+};
+
enum SPCSSBaselineShift {
- SP_CSS_BASELINE_SHIFT_BASELINE,
- SP_CSS_BASELINE_SHIFT_SUB,
- SP_CSS_BASELINE_SHIFT_SUPER
+ SP_CSS_BASELINE_SHIFT_BASELINE,
+ SP_CSS_BASELINE_SHIFT_SUB,
+ SP_CSS_BASELINE_SHIFT_SUPER
};
enum SPVisibility {
@@ -489,13 +504,6 @@ static SPStyleEnum const enum_direction[] = {
{NULL, -1}
};
-static SPStyleEnum const enum_block_progression[] = {
- {"tb", SP_CSS_BLOCK_PROGRESSION_TB},
- {"rl", SP_CSS_BLOCK_PROGRESSION_RL},
- {"lr", SP_CSS_BLOCK_PROGRESSION_LR},
- {NULL, -1}
-};
-
static SPStyleEnum const enum_writing_mode[] = {
/* Note that using the same enumerator for lr as lr-tb means we write as lr-tb even if the
* input file said lr. We prefer writing lr-tb on the grounds that the spec says the initial
@@ -504,12 +512,38 @@ static SPStyleEnum const enum_writing_mode[] = {
* ECMA scripts may be surprised to find tb-rl in DOM if they set the attribute to rl, so
* sharing enumerators for different strings may be a bug (once we support ecma script).
*/
+ // SVG 1.1 Deprecated but still must be supported in SVG 2.
{"lr-tb", SP_CSS_WRITING_MODE_LR_TB},
{"rl-tb", SP_CSS_WRITING_MODE_RL_TB},
{"tb-rl", SP_CSS_WRITING_MODE_TB_RL},
{"lr", SP_CSS_WRITING_MODE_LR_TB},
{"rl", SP_CSS_WRITING_MODE_RL_TB},
{"tb", SP_CSS_WRITING_MODE_TB_RL},
+ // SVG 2 & CSS 3 Writing Modes
+ {"horizontal-tb", SP_CSS_WRITING_MODE_LR_TB}, // This is correct, 'direction' distinguishes between 'lr' and 'rl'.
+ {"vertical-rl", SP_CSS_WRITING_MODE_TB_RL},
+ {"vertical-lr", SP_CSS_WRITING_MODE_TB_LR},
+ {NULL, -1}
+};
+
+// CSS WRITING MODES 3
+static SPStyleEnum const enum_text_orientation[] = {
+ {"mixed", SP_CSS_TEXT_ORIENTATION_MIXED}, // Default
+ {"upright", SP_CSS_TEXT_ORIENTATION_UPRIGHT},
+ {"sideways", SP_CSS_TEXT_ORIENTATION_SIDEWAYS},
+ {NULL, -1}
+};
+
+static SPStyleEnum const enum_baseline[] = {
+ {"auto", SP_CSS_BASELINE_AUTO}, // Default
+ {"alphabetic", SP_CSS_BASELINE_ALPHABETIC},
+ {"ideographic", SP_CSS_BASELINE_IDEOGRAPHIC},
+ {"hanging", SP_CSS_BASELINE_HANGING},
+ {"mathematical", SP_CSS_BASELINE_MATHEMATICAL},
+ {"central", SP_CSS_BASELINE_CENTRAL},
+ {"middle", SP_CSS_BASELINE_MIDDLE},
+ {"text-before-edge", SP_CSS_BASELINE_TEXT_BEFORE_EDGE},
+ {"text-after-edge", SP_CSS_BASELINE_TEXT_AFTER_EDGE},
{NULL, -1}
};
diff --git a/src/style-internal.cpp b/src/style-internal.cpp
index c117a97f9..b425a1c80 100644
--- a/src/style-internal.cpp
+++ b/src/style-internal.cpp
@@ -709,7 +709,8 @@ SPIEnumBits::write( guint const flags, SPIBase const *const base) const {
unsigned j = 1;
for (unsigned i = 0; enums[i].key; ++i) {
if (j & this->value ) {
- return_string += enums[i].value + " ";
+ return_string += enums[i].key;
+ return_string += " ";
}
j *= 2;
}
diff --git a/src/style-internal.h b/src/style-internal.h
index 1ddab30f1..767552784 100644
--- a/src/style-internal.h
+++ b/src/style-internal.h
@@ -342,7 +342,7 @@ public:
computed(0)
{}
- SPILength( Glib::ustring const &name, unsigned value = 0 )
+ SPILength( Glib::ustring const &name, float value = 0 )
: SPIBase( name ),
unit(SP_CSS_UNIT_NONE),
value(value),
@@ -401,7 +401,7 @@ public:
normal(true)
{}
- SPILengthOrNormal( Glib::ustring const &name, unsigned value = 0 )
+ SPILengthOrNormal( Glib::ustring const &name, float value = 0 )
: SPILength( name, value ),
normal(true)
{}
@@ -1260,7 +1260,6 @@ struct SPITextDecorationData {
float tspan_width; // from libnrtype, when it calculates spans
float ascender; // the rest from tspan's font
float descender;
- float line_gap;
float underline_thickness;
float underline_position;
float line_through_thickness;
diff --git a/src/style.cpp b/src/style.cpp
index d8402e08a..99beaed22 100644
--- a/src/style.cpp
+++ b/src/style.cpp
@@ -113,7 +113,7 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) :
font_weight( "font-weight", enum_font_weight, SP_CSS_FONT_WEIGHT_NORMAL, SP_CSS_FONT_WEIGHT_400 ),
font_stretch( "font-stretch", enum_font_stretch, SP_CSS_FONT_STRETCH_NORMAL ),
font_size(),
- line_height( "line-height", 1.0 ), // SPILengthOrNormal
+ line_height( "line-height", 125 ), // SPILengthOrNormal
font_family( "font-family", "sans-serif" ), // SPIString w/default
font(), // SPIFont
font_specification( "-inkscape-font-specification" ), // SPIString
@@ -136,8 +136,9 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) :
text_transform( "text-transform", enum_text_transform, SP_CSS_TEXT_TRANSFORM_NONE ),
direction( "direction", enum_direction, SP_CSS_DIRECTION_LTR ),
- block_progression("block-progression", enum_block_progression, SP_CSS_BLOCK_PROGRESSION_TB),
writing_mode( "writing-mode", enum_writing_mode, SP_CSS_WRITING_MODE_LR_TB ),
+ text_orientation( "text-orientation",enum_text_orientation,SP_CSS_TEXT_ORIENTATION_MIXED ),
+ dominant_baseline("dominant-baseline",enum_baseline, SP_CSS_BASELINE_AUTO ),
baseline_shift(),
text_anchor( "text-anchor", enum_text_anchor, SP_CSS_TEXT_ANCHOR_START ),
white_space( "white-space", enum_white_space, SP_CSS_WHITE_SPACE_NORMAL ),
@@ -286,7 +287,7 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) :
_properties.push_back( &color );
// 'font-size'/'font' must be before properties that need to know em, ex size (SPILength,
- // SPILenghtOrNormal)
+ // SPILengthOrNormal)
_properties.push_back( &font_style );
_properties.push_back( &font_variant );
_properties.push_back( &font_weight );
@@ -318,9 +319,10 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) :
_properties.push_back( &word_spacing );
_properties.push_back( &text_transform );
- _properties.push_back( &direction );
- _properties.push_back( &block_progression );
_properties.push_back( &writing_mode );
+ _properties.push_back( &direction );
+ _properties.push_back( &text_orientation );
+ _properties.push_back( &dominant_baseline );
_properties.push_back( &baseline_shift );
_properties.push_back( &text_anchor );
_properties.push_back( &white_space );
@@ -381,7 +383,7 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) :
// // 'color' must be before 'fill', 'stroke', 'text-decoration-color', ...
// _propmap.insert( std::make_pair( color.name, reinterpret_cast<SPIBasePtr>(&SPStyle::color ) ) );
- // // 'font-size' must be before properties that need to know em, ex size (SPILength, SPILenghtOrNormal)
+ // // 'font-size' must be before properties that need to know em, ex size (SPILength, SPILengthOrNormal)
// _propmap.insert( std::make_pair( font_style.name, reinterpret_cast<SPIBasePtr>(&SPStyle::font_style ) ) );
// _propmap.insert( std::make_pair( font_variant.name, reinterpret_cast<SPIBasePtr>(&SPStyle::font_variant ) ) );
// _propmap.insert( std::make_pair( font_weight.name, reinterpret_cast<SPIBasePtr>(&SPStyle::font_weight ) ) );
@@ -413,8 +415,9 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) :
// _propmap.insert( std::make_pair( text_transform.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_transform ) ) );
// _propmap.insert( std::make_pair( direction.name, reinterpret_cast<SPIBasePtr>(&SPStyle::direction ) ) );
- // _propmap.insert( std::make_pair( block_progression.name, reinterpret_cast<SPIBasePtr>(&SPStyle::block_progression ) ) );
// _propmap.insert( std::make_pair( writing_mode.name, reinterpret_cast<SPIBasePtr>(&SPStyle::writing_mode ) ) );
+ // _propmap.insert( std::make_pair( text_orientation.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_orientation ) ) );
+ // _propmap.insert( std::make_pair( dominant_baseline.name, reinterpret_cast<SPIBasePtr>(&SPStyle::dominant_baseline ) ) );
// _propmap.insert( std::make_pair( baseline_shift.name, reinterpret_cast<SPIBasePtr>(&SPStyle::baseline_shift ) ) );
// _propmap.insert( std::make_pair( text_anchor.name, reinterpret_cast<SPIBasePtr>(&SPStyle::text_anchor ) ) );
// _propmap.insert( std::make_pair( white_space.name, reinterpret_cast<SPIBasePtr>(&SPStyle::white_space ) ) );
@@ -778,12 +781,12 @@ SPStyle::readIfUnset( gint id, gchar const *val ) {
case SP_PROP_DIRECTION:
direction.readIfUnset( val );
break;
- case SP_PROP_BLOCK_PROGRESSION:
- block_progression.readIfUnset( val );
- break;
case SP_PROP_WRITING_MODE:
writing_mode.readIfUnset( val );
break;
+ case SP_PROP_TEXT_ORIENTATION:
+ text_orientation.readIfUnset( val );
+ break;
case SP_PROP_TEXT_ANCHOR:
text_anchor.readIfUnset( val );
break;
@@ -796,6 +799,9 @@ SPStyle::readIfUnset( gint id, gchar const *val ) {
case SP_PROP_SHAPE_PADDING:
shape_padding.readIfUnset( val );
break;
+ case SP_PROP_DOMINANT_BASELINE:
+ dominant_baseline.readIfUnset( val );
+ break;
case SP_PROP_BASELINE_SHIFT:
baseline_shift.readIfUnset( val );
break;
@@ -805,9 +811,6 @@ SPStyle::readIfUnset( gint id, gchar const *val ) {
case SP_PROP_ALIGNMENT_BASELINE:
g_warning("Unimplemented style property SP_PROP_ALIGNMENT_BASELINE: value: %s", val);
break;
- case SP_PROP_DOMINANT_BASELINE:
- g_warning("Unimplemented style property SP_PROP_DOMINANT_BASELINE: value: %s", val);
- break;
case SP_PROP_GLYPH_ORIENTATION_HORIZONTAL:
g_warning("Unimplemented style property SP_PROP_ORIENTATION_HORIZONTAL: value: %s", val);
break;
@@ -1258,7 +1261,7 @@ SPStyle::getFontFeatureString() {
if( font_variant_east_asian.value & SP_CSS_FONT_VARIANT_EAST_ASIAN_RUBY )
feature_string += "ruby, ";
- if ( strcmp( font_feature_settings.value, "normal") ) {
+ if ( font_feature_settings.value && strcmp( font_feature_settings.value, "normal") ) {
// We do no sanity checking...
feature_string += font_feature_settings.value;
feature_string += ", ";
@@ -1689,16 +1692,19 @@ sp_style_unset_property_attrs(SPObject *o)
repr->setAttribute("text-anchor", NULL);
}
if (style->white_space.set) {
- repr->setAttribute("white_space", NULL);
+ repr->setAttribute("white-space", NULL);
}
if (style->shape_inside.set) {
- repr->setAttribute("shape_inside", NULL);
+ repr->setAttribute("shape-inside", NULL);
}
if (style->shape_padding.set) {
- repr->setAttribute("shape_padding", NULL);
+ repr->setAttribute("shape-padding", NULL);
}
if (style->writing_mode.set) {
- repr->setAttribute("writing_mode", NULL);
+ repr->setAttribute("writing-mode", NULL);
+ }
+ if (style->text_orientation.set) {
+ repr->setAttribute("text-orientation", NULL);
}
if (style->filter.set) {
repr->setAttribute("filter", NULL);
@@ -1781,8 +1787,8 @@ sp_css_attr_unset_text(SPCSSAttr *css)
sp_repr_css_set_property(css, "word-spacing", NULL);
sp_repr_css_set_property(css, "text-transform", NULL);
sp_repr_css_set_property(css, "direction", NULL);
- sp_repr_css_set_property(css, "block-progression", NULL);
sp_repr_css_set_property(css, "writing-mode", NULL);
+ sp_repr_css_set_property(css, "text-orientation", NULL);
sp_repr_css_set_property(css, "text-anchor", NULL);
sp_repr_css_set_property(css, "white-space", NULL);
sp_repr_css_set_property(css, "shape-inside", NULL);
@@ -1951,7 +1957,7 @@ sp_css_attr_scale(SPCSSAttr *css, double ex)
sp_css_attr_scale_property_single(css, "kerning", ex);
sp_css_attr_scale_property_single(css, "letter-spacing", ex);
sp_css_attr_scale_property_single(css, "word-spacing", ex);
- sp_css_attr_scale_property_single(css, "line-height", ex, true);
+ //sp_css_attr_scale_property_single(css, "line-height", ex, true);
return css;
}
diff --git a/src/style.h b/src/style.h
index 02432d3e7..0e8e34145 100644
--- a/src/style.h
+++ b/src/style.h
@@ -142,12 +142,14 @@ public:
SPIEnum text_transform;
/* CSS3 Text */
- /** text direction (css3 text 3.2) */
+ /** text direction (svg1.1) */
SPIEnum direction;
- /** block progression (css3 text 3.2) */
- SPIEnum block_progression;
- /** Writing mode (css3 text 3.2 and svg1.1 10.7.2) */
+ /** Writing mode (svg1.1 10.7.2, CSS Writing Modes 3) */
SPIEnum writing_mode;
+ /** Text orientation (CSS Writing Modes 3) */
+ SPIEnum text_orientation;
+ /** Dominant baseline (svg1.1) */
+ SPIEnum dominant_baseline;
/** Baseline shift (svg1.1 10.9.2) */
SPIBaselineShift baseline_shift;
diff --git a/src/svg/CMakeLists.txt b/src/svg/CMakeLists.txt
index f9d0bc52d..ff4bb63ab 100644
--- a/src/svg/CMakeLists.txt
+++ b/src/svg/CMakeLists.txt
@@ -2,7 +2,7 @@
set(svg_SRC
css-ostringstream.cpp
path-string.cpp
- sp-svg.def
+ #sp-svg.def
stringstream.cpp
strip-trailing-zeros.cpp
svg-affine.cpp
diff --git a/src/svg/svg-affine.cpp b/src/svg/svg-affine.cpp
index c853f9930..d9d79bba5 100644
--- a/src/svg/svg-affine.cpp
+++ b/src/svg/svg-affine.cpp
@@ -119,7 +119,7 @@ sp_svg_transform_read(gchar const *str, Geom::Affine *transform)
if (n_args != 1 && n_args != 3) {
return false;
}
- Geom::Rotate const rot(Geom::deg_to_rad(args[0]));
+ Geom::Rotate const rot(Geom::rad_from_deg(args[0]));
if (n_args == 3) {
a = ( Geom::Translate(-args[1], -args[2])
* rot
diff --git a/src/svg/svg-length.cpp b/src/svg/svg-length.cpp
index edbc59c36..cd995582d 100644
--- a/src/svg/svg-length.cpp
+++ b/src/svg/svg-length.cpp
@@ -463,7 +463,7 @@ unsigned int sp_svg_length_read_ldd(gchar const *str, SVGLength::Unit *unit, dou
return r;
}
-std::string const SVGLength::write()
+std::string SVGLength::write() const
{
return sp_svg_length_write_with_units(*this);
}
diff --git a/src/svg/svg-length.h b/src/svg/svg-length.h
index 84056dd5f..2aaf248b1 100644
--- a/src/svg/svg-length.h
+++ b/src/svg/svg-length.h
@@ -57,7 +57,7 @@ public:
bool read(char const *str);
void readOrUnset(char const *str, Unit u = NONE, float v = 0, float c = 0);
bool readAbsolute(char const *str);
- std::string const write();
+ std::string write() const;
// To set 'v' use '='
void set(Unit u, float v); // Sets computed value based on u and v.
void set(Unit u, float v, float c); // Sets all three values.
diff --git a/src/svg/svg-path.cpp b/src/svg/svg-path.cpp
index ba9e11452..7bb58fc9c 100644
--- a/src/svg/svg-path.cpp
+++ b/src/svg/svg-path.cpp
@@ -84,7 +84,7 @@ static void sp_svg_write_curve(Inkscape::SVG::PathString & str, Geom::Curve cons
}
else if(Geom::EllipticalArc const *elliptical_arc = dynamic_cast<Geom::EllipticalArc const *>(c)) {
str.arcTo( elliptical_arc->ray(Geom::X), elliptical_arc->ray(Geom::Y),
- Geom::rad_to_deg(elliptical_arc->rotationAngle()),
+ Geom::deg_from_rad(elliptical_arc->rotationAngle()),
elliptical_arc->largeArc(), elliptical_arc->sweep(),
elliptical_arc->finalPoint() );
} else {
diff --git a/src/text-chemistry.cpp b/src/text-chemistry.cpp
index 9fc862ad2..fbbbe5807 100644
--- a/src/text-chemistry.cpp
+++ b/src/text-chemistry.cpp
@@ -44,7 +44,7 @@ static SPItem *
flowtext_in_selection(Inkscape::Selection *selection)
{
std::vector<SPItem*> items = selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
if (SP_IS_FLOWTEXT(*i))
return *i;
}
@@ -55,7 +55,7 @@ static SPItem *
text_or_flowtext_in_selection(Inkscape::Selection *selection)
{
std::vector<SPItem*> items = selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i))
return *i;
}
@@ -66,7 +66,7 @@ static SPItem *
shape_in_selection(Inkscape::Selection *selection)
{
std::vector<SPItem*> items = selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
if (SP_IS_SHAPE(*i))
return *i;
}
@@ -197,7 +197,7 @@ text_remove_from_path()
bool did = false;
std::vector<SPItem*> items(selection->itemList());
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
SPObject *obj = *i;
if (SP_IS_TEXT_TEXTPATH(obj)) {
@@ -261,7 +261,7 @@ text_remove_all_kerns()
bool did = false;
std::vector<SPItem*> items = selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
SPObject *obj = *i;
if (!SP_IS_TEXT(obj) && !SP_IS_TSPAN(obj) && !SP_IS_FLOWTEXT(obj)) {
@@ -321,7 +321,7 @@ text_flow_into_shape()
/* Add clones */
std::vector<SPItem*> items = selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
SPItem *item = *i;
if (SP_IS_SHAPE(item)){
Inkscape::XML::Node *clone = xml_doc->createElement("svg:use");
@@ -396,7 +396,7 @@ text_unflow ()
GSList *old_objs = NULL;
std::vector<SPItem*> items = selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
if (!SP_IS_FLOWTEXT(*i)) {
continue;
@@ -481,7 +481,7 @@ flowtext_to_text()
std::vector<Inkscape::XML::Node*> reprs;
std::vector<SPItem*> items(selection->itemList());
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
SPItem *item = *i;
diff --git a/src/text-editing.cpp b/src/text-editing.cpp
index 050e223eb..057523b1e 100644
--- a/src/text-editing.cpp
+++ b/src/text-editing.cpp
@@ -68,7 +68,7 @@ void te_update_layout_now_recursive(SPItem *item)
{
if (SP_IS_GROUP(item)) {
std::vector<SPItem*> item_list = sp_item_group_item_list(SP_GROUP(item));
- for(std::vector<SPItem*>::const_iterator i=item_list.begin();i!=item_list.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=item_list.begin();i!=item_list.end();++i){
SPItem* list_item = *i;
te_update_layout_now_recursive(list_item);
}
@@ -1805,6 +1805,14 @@ static bool tidy_operator_redundant_semi_nesting(SPObject **item, bool /*has_tex
return false;
}
+
+/* tidy_operator_styled_whitespace commented out: not only did it have bugs,
+ * but it did *not* preserve the rendering: spaces in different font sizes,
+ * for instance, have different width, so moving them out of tspans changes
+ * the document. cf https://bugs.launchpad.net/inkscape/+bug/1477723
+*/
+
+#if 0
/** helper for tidy_operator_styled_whitespace(), finds the last string object
in a paragraph which is not \a not_obj. */
static SPString* find_last_string_child_not_equal_to(SPObject *root, SPObject *not_obj)
@@ -1883,6 +1891,7 @@ static bool tidy_operator_styled_whitespace(SPObject **item, bool has_text_decor
delete_obj->deleteObject();
return true;
}
+#endif
/* possible tidy operators that are not yet implemented, either because
they are difficult, occur infrequently, or because I'm not sure that the
@@ -1917,8 +1926,7 @@ static bool tidy_xml_tree_recursively(SPObject *root, bool has_text_decoration)
tidy_operator_repeated_spans,
tidy_operator_excessive_nesting,
tidy_operator_redundant_double_nesting,
- tidy_operator_redundant_semi_nesting,
- tidy_operator_styled_whitespace
+ tidy_operator_redundant_semi_nesting
};
bool changes = false;
diff --git a/src/text-tag-attributes.h b/src/text-tag-attributes.h
index 7a389ed39..2cf7a8bde 100644
--- a/src/text-tag-attributes.h
+++ b/src/text-tag-attributes.h
@@ -31,11 +31,14 @@ public:
/** Process the parameters from the set() function of SPObject.
Returns true if \a key was a recognised attribute. */
- bool readSingleAttribute(unsigned key, gchar const *value);
+ bool readSingleAttribute(unsigned key, gchar const *value, SPStyle const *style, Geom::Rect const *viewport);
/// Write out all the contents of #attributes to the given node.
void writeTo(Inkscape::XML::Node *node) const;
+ /// Update relative values
+ void update( double em, double ex, double w, double h );
+
/** For tspan role=line elements we should not use the set x,y
coordinates since that would overrule the values calculated by the
text layout engine, however if there are more than one element in
diff --git a/src/trace/CMakeLists.txt b/src/trace/CMakeLists.txt
index bf7cfa276..12cf495f6 100644
--- a/src/trace/CMakeLists.txt
+++ b/src/trace/CMakeLists.txt
@@ -1,3 +1,4 @@
+if (${HAVE_POTRACE})
set(trace_SRC
filterset.cpp
@@ -7,14 +8,7 @@ set(trace_SRC
siox.cpp
trace.cpp
- potrace/curve.cpp
- potrace/decompose.cpp
- potrace/greymap.cpp
potrace/inkscape-potrace.cpp
- potrace/potracelib.cpp
- potrace/render.cpp
- potrace/trace.cpp
-
# -------
# Headers
@@ -26,19 +20,11 @@ set(trace_SRC
siox.h
trace.h
- potrace/auxiliary.h
potrace/bitmap.h
- potrace/bitops.h
- potrace/curve.h
- potrace/decompose.h
- potrace/greymap.h
potrace/inkscape-potrace.h
- potrace/lists.h
- potrace/potracelib.h
- potrace/progress.h
- potrace/render.h
- potrace/trace.h
)
# add_inkscape_lib(trace_LIB "${trace_SRC}")
add_inkscape_source("${trace_SRC}")
+
+endif()
diff --git a/src/trace/Makefile_insert b/src/trace/Makefile_insert
index 21ec4ac0c..27353df15 100644
--- a/src/trace/Makefile_insert
+++ b/src/trace/Makefile_insert
@@ -1,5 +1,7 @@
## Makefile.am fragment sourced by src/Makefile.am.
+if HAVE_POTRACE
+
ink_common_sources += \
trace/pool.h \
trace/trace.h \
@@ -14,21 +16,8 @@ ink_common_sources += \
trace/filterset.cpp \
trace/siox.h \
trace/siox.cpp \
- trace/potrace/auxiliary.h \
- trace/potrace/bitmap.h \
- trace/potrace/curve.cpp \
- trace/potrace/curve.h \
- trace/potrace/decompose.cpp \
- trace/potrace/decompose.h \
- trace/potrace/greymap.cpp \
- trace/potrace/greymap.h \
- trace/potrace/lists.h \
- trace/potrace/potracelib.cpp \
- trace/potrace/potracelib.h \
- trace/potrace/progress.h \
- trace/potrace/render.cpp \
- trace/potrace/render.h \
- trace/potrace/trace.cpp \
- trace/potrace/trace.h \
+ trace/potrace/bitmap.h \
trace/potrace/inkscape-potrace.cpp \
trace/potrace/inkscape-potrace.h
+
+endif
diff --git a/src/trace/potrace/auxiliary.h b/src/trace/potrace/auxiliary.h
deleted file mode 100644
index dbf124d7c..000000000
--- a/src/trace/potrace/auxiliary.h
+++ /dev/null
@@ -1,80 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-/* This header file collects some general-purpose macros (and static
- inline functions) that are used in various places. */
-
-#ifndef AUXILIARY_H
-#define AUXILIARY_H
-
-#include <stdlib.h>
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* ---------------------------------------------------------------------- */
-/* point arithmetic */
-
-#include "potracelib.h"
-
-struct point_s {
- long x;
- long y;
-};
-typedef struct point_s point_t;
-
-typedef potrace_dpoint_t dpoint_t;
-
-/* convert point_t to dpoint_t */
-static inline dpoint_t dpoint(point_t p) {
- dpoint_t res;
- res.x = p.x;
- res.y = p.y;
- return res;
-}
-
-/* range over the straight line segment [a,b] when lambda ranges over [0,1] */
-static inline dpoint_t interval(double lambda, dpoint_t a, dpoint_t b) {
- dpoint_t res;
-
- res.x = a.x + lambda * (b.x - a.x);
- res.y = a.y + lambda * (b.y - a.y);
- return res;
-}
-
-/* ---------------------------------------------------------------------- */
-/* some useful macros. Note: the "mod" macro works correctly for
- negative a. Also note that the test for a>=n, while redundant,
- speeds up the mod function by 70% in the average case (significant
- since the program spends about 16% of its time here - or 40%
- without the test). The "floordiv" macro returns the largest integer
- <= a/n, and again this works correctly for negative a, as long as
- a,n are integers and n>0. */
-
-/* integer arithmetic */
-
-static inline int mod(int a, int n) {
- return a>=n ? a%n : a>=0 ? a : n-1-(-1-a)%n;
-}
-
-static inline int floordiv(int a, int n) {
- return a>=0 ? a/n : -1-(-1-a)/n;
-}
-
-/* Note: the following work for integers and other numeric types. */
-#undef sign
-#undef abs
-#undef min
-#undef max
-#undef sq
-#undef cu
-#define sign(x) ((x)>0 ? 1 : (x)<0 ? -1 : 0)
-#define abs(a) ((a)>0 ? (a) : -(a))
-#define min(a,b) ((a)<(b) ? (a) : (b))
-#define max(a,b) ((a)>(b) ? (a) : (b))
-#define sq(a) ((a)*(a))
-#define cu(a) ((a)*(a)*(a))
-
-#endif /* AUXILIARY_H */
diff --git a/src/trace/potrace/bitmap.h b/src/trace/potrace/bitmap.h
index 086bbb046..7b5a94bb1 100644
--- a/src/trace/potrace/bitmap.h
+++ b/src/trace/potrace/bitmap.h
@@ -8,6 +8,7 @@
#include <string.h>
#include <stdlib.h>
#include <errno.h>
+#include <stddef.h>
/* The bitmap type is defined in potracelib.h */
#include "potracelib.h"
@@ -28,7 +29,7 @@
/* macros for accessing pixel at index (x,y). U* macros omit the
bounds check. */
-#define bm_scanline(bm, y) ((bm)->map + (ssize_t)(y)*(ssize_t)(bm)->dy)
+#define bm_scanline(bm, y) ((bm)->map + (ptrdiff_t)(y)*(ptrdiff_t)(bm)->dy)
#define bm_index(bm, x, y) (&bm_scanline(bm, y)[(x)/BM_WORDBITS])
#define bm_mask(x) (BM_HIBIT >> ((x) & (BM_WORDBITS-1)))
#define bm_range(x, a) ((int)(x) >= 0 && (int)(x) < (a))
@@ -57,10 +58,10 @@ static inline void bm_free(potrace_bitmap_t *bm) {
static inline potrace_bitmap_t *bm_new(int w, int h) {
potrace_bitmap_t *bm;
int dy = w == 0 ? 0 : (w - 1) / BM_WORDBITS + 1;
- ssize_t size = (ssize_t)dy * (ssize_t)h * (ssize_t)BM_WORDSIZE;
+ ptrdiff_t size = (ptrdiff_t)dy * (ptrdiff_t)h * (ptrdiff_t)BM_WORDSIZE;
/* check for overflow error */
- if (size < 0 || size / h / dy != BM_WORDSIZE) {
+ if (size < 0 || (h != 0 && dy != 0 && size / h / dy != BM_WORDSIZE)) {
errno = ENOMEM;
return NULL;
}
@@ -83,15 +84,15 @@ static inline potrace_bitmap_t *bm_new(int w, int h) {
/* clear the given bitmap. Set all bits to c. */
static inline void bm_clear(potrace_bitmap_t *bm, int c) {
/* Note: if the bitmap was created with bm_new, then it is
- guaranteed that size will fit into the ssize_t type. */
- ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h * (ssize_t)BM_WORDSIZE;
+ guaranteed that size will fit into the ptrdiff_t type. */
+ ptrdiff_t size = (ptrdiff_t)bm->dy * (ptrdiff_t)bm->h * (ptrdiff_t)BM_WORDSIZE;
memset(bm->map, c ? -1 : 0, size);
}
/* duplicate the given bitmap. Return NULL on error with errno set. */
static inline potrace_bitmap_t *bm_dup(const potrace_bitmap_t *bm) {
potrace_bitmap_t *bm1 = bm_new(bm->w, bm->h);
- ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h * (ssize_t)BM_WORDSIZE;
+ ptrdiff_t size = (ptrdiff_t)bm->dy * (ptrdiff_t)bm->h * (ptrdiff_t)BM_WORDSIZE;
if (!bm1) {
return NULL;
}
@@ -101,8 +102,8 @@ static inline potrace_bitmap_t *bm_dup(const potrace_bitmap_t *bm) {
/* invert the given bitmap. */
static inline void bm_invert(potrace_bitmap_t *bm) {
- ssize_t i;
- ssize_t size = (ssize_t)bm->dy * (ssize_t)bm->h;
+ ptrdiff_t i;
+ ptrdiff_t size = (ptrdiff_t)bm->dy * (ptrdiff_t)bm->h;
for (i = 0; i < size; i++) {
bm->map[i] ^= BM_ALLBITS;
diff --git a/src/trace/potrace/bitops.h b/src/trace/potrace/bitops.h
deleted file mode 100644
index cff734a46..000000000
--- a/src/trace/potrace/bitops.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-
-/* bits.h: this file defines some macros for bit manipulations. We
- provide a generic implementation, as well as machine- and
- compiler-specific fast implementations */
-
-/* lobit: return the position of the rightmost "1" bit of an int, or
- 32 if none. hibit: return 1 + the position of the leftmost "1" bit
- of an int, or 0 if none. Note: these functions work on 32-bit
- integers. */
-
-#ifndef BITOPS_H
-#define BITOPS_H
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* ---------------------------------------------------------------------- */
-/* machine specific macros */
-
-#if defined(HAVE_I386)
-
-static inline unsigned int lobit(unsigned int x) {
- unsigned int res;
- asm ("bsf %1,%0\n\t"
- "jnz 0f\n\t"
- "movl $32,%0\n"
- "0:"
- : "=r" (res)
- : "r" (x)
- : "cc");
- return res;
-}
-
-static inline unsigned int hibit(unsigned int x) {
- unsigned int res;
-
- asm ("bsr %1,%0\n\t"
- "jnz 0f\n\t"
- "movl $-1,%0\n"
- "0:"
- : "=r" (res)
- : "r" (x)
- : "cc");
- return res+1;
-}
-
-/* ---------------------------------------------------------------------- */
-#else /* generic macros */
-
-static inline unsigned int lobit(unsigned int x) {
- unsigned int res = 32;
- while (x & 0xffffff) {
- x <<= 8;
- res -= 8;
- }
- while (x) {
- x <<= 1;
- res -= 1;
- }
- return res;
-}
-
-static inline unsigned int hibit(unsigned int x) {
- unsigned int res = 0;
- while (x > 0xff) {
- x >>= 8;
- res += 8;
- }
- while (x) {
- x >>= 1;
- res += 1;
- }
- return res;
-}
-
-#endif
-
-#endif /* BITOPS_H */
diff --git a/src/trace/potrace/curve.cpp b/src/trace/potrace/curve.cpp
deleted file mode 100644
index e6a9a4721..000000000
--- a/src/trace/potrace/curve.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-/* private part of the path and curve data structures */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "potracelib.h"
-#include "lists.h"
-#include "curve.h"
-
-#define SAFE_CALLOC(var, n, typ) \
- if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error
-
-/* ---------------------------------------------------------------------- */
-/* allocate and free path objects */
-
-path_t *path_new(void) {
- path_t *p = NULL;
- privpath_t *priv = NULL;
-
- SAFE_CALLOC(p, 1, path_t);
- memset(p, 0, sizeof(path_t));
- SAFE_CALLOC(priv, 1, privpath_t);
- memset(priv, 0, sizeof(privpath_t));
- p->priv = priv;
- return p;
-
- calloc_error:
- free(p);
- free(priv);
- return NULL;
-}
-
-/* free the members of the given curve structure. Leave errno unchanged. */
-static void privcurve_free_members(privcurve_t *curve) {
- free(curve->tag);
- free(curve->c);
- free(curve->vertex);
- free(curve->alpha);
- free(curve->alpha0);
- free(curve->beta);
-}
-
-/* free a path. Leave errno untouched. */
-void path_free(path_t *p) {
- if (p) {
- if (p->priv) {
- free(p->priv->pt);
- free(p->priv->lon);
- free(p->priv->sums);
- free(p->priv->po);
- privcurve_free_members(&p->priv->curve);
- privcurve_free_members(&p->priv->ocurve);
- }
- free(p->priv);
- /* do not free p->fcurve ! */
- }
- free(p);
-}
-
-/* free a pathlist, leaving errno untouched. */
-void pathlist_free(path_t *plist) {
- path_t *p;
-
- list_forall_unlink(p, plist) {
- path_free(p);
- }
-}
-
-/* ---------------------------------------------------------------------- */
-/* initialize and finalize curve structures */
-
-typedef dpoint_t dpoint3_t[3];
-
-/* initialize the members of the given curve structure to size m.
- Return 0 on success, 1 on error with errno set. */
-int privcurve_init(privcurve_t *curve, int n) {
- memset(curve, 0, sizeof(privcurve_t));
- curve->n = n;
- SAFE_CALLOC(curve->tag, n, int);
- SAFE_CALLOC(curve->c, n, dpoint3_t);
- SAFE_CALLOC(curve->vertex, n, dpoint_t);
- SAFE_CALLOC(curve->alpha, n, double);
- SAFE_CALLOC(curve->alpha0, n, double);
- SAFE_CALLOC(curve->beta, n, double);
- return 0;
-
- calloc_error:
- free(curve->tag);
- free(curve->c);
- free(curve->vertex);
- free(curve->alpha);
- free(curve->alpha0);
- free(curve->beta);
- return 1;
-}
-
-/* copy private to public curve structure */
-void privcurve_to_curve(privcurve_t *pc, potrace_curve_t *c) {
- c->n = pc->n;
- c->tag = pc->tag;
- c->c = pc->c;
-}
-
diff --git a/src/trace/potrace/curve.h b/src/trace/potrace/curve.h
deleted file mode 100644
index feb95b39b..000000000
--- a/src/trace/potrace/curve.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-#ifndef CURVE_H
-#define CURVE_H
-
-#include "auxiliary.h"
-
-/* vertex is c[1] for tag=POTRACE_CORNER, and the intersection of
- .c[-1][2]..c[0] and c[1]..c[2] for tag=POTRACE_CURVETO. alpha is only
- defined for tag=POTRACE_CURVETO and is the alpha parameter of the curve:
- .c[-1][2]..c[0] = alpha*(.c[-1][2]..vertex), and
- c[2]..c[1] = alpha*(c[2]..vertex).
- Beta is so that (.beta[i])[.vertex[i],.vertex[i+1]] = .c[i][2].
-*/
-
-struct privcurve_s {
- int n; /* number of segments */
- int *tag; /* tag[n]: POTRACE_CORNER or POTRACE_CURVETO */
- dpoint_t (*c)[3]; /* c[n][i]: control points.
- c[n][0] is unused for tag[n]=POTRACE_CORNER */
- /* the remainder of this structure is special to privcurve, and is
- used in EPS debug output and special EPS "short coding". These
- fields are valid only if "alphacurve" is set. */
- int alphacurve; /* have the following fields been initialized? */
- dpoint_t *vertex; /* for POTRACE_CORNER, this equals c[1] */
- double *alpha; /* only for POTRACE_CURVETO */
- double *alpha0; /* "uncropped" alpha parameter - for debug output only */
- double *beta;
-};
-typedef struct privcurve_s privcurve_t;
-
-struct sums_s {
- double x;
- double y;
- double x2;
- double xy;
- double y2;
-};
-typedef struct sums_s sums_t;
-
-/* the path structure is filled in with information about a given path
- as it is accumulated and passed through the different stages of the
- Potrace algorithm. Backends only need to read the fcurve and fm
- fields of this data structure, but debugging backends may read
- other fields. */
-struct potrace_privpath_s {
- int len;
- point_t *pt; /* pt[len]: path as extracted from bitmap */
- int *lon; /* lon[len]: (i,lon[i]) = longest straight line from i */
-
- int x0, y0; /* origin for sums */
- sums_t *sums; /* sums[len+1]: cache for fast summing */
-
- int m; /* length of optimal polygon */
- int *po; /* po[m]: optimal polygon */
-
- privcurve_t curve; /* curve[m]: array of curve elements */
- privcurve_t ocurve; /* ocurve[om]: array of curve elements */
- privcurve_t *fcurve; /* final curve: this points to either curve or
- ocurve. Do not free this separately. */
-};
-typedef struct potrace_privpath_s potrace_privpath_t;
-
-/* shorter names */
-typedef potrace_privpath_t privpath_t;
-typedef potrace_path_t path_t;
-
-path_t *path_new(void);
-void path_free(path_t *p);
-void pathlist_free(path_t *plist);
-int privcurve_init(privcurve_t *curve, int n);
-void privcurve_to_curve(privcurve_t *pc, potrace_curve_t *c);
-
-#endif /* CURVE_H */
-
diff --git a/src/trace/potrace/decompose.cpp b/src/trace/potrace/decompose.cpp
deleted file mode 100644
index 7628b202d..000000000
--- a/src/trace/potrace/decompose.cpp
+++ /dev/null
@@ -1,511 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-
-#include "potracelib.h"
-#include "curve.h"
-#include "lists.h"
-#include "bitmap.h"
-#include "decompose.h"
-#include "progress.h"
-
-/* ---------------------------------------------------------------------- */
-/* deterministically and efficiently hash (x,y) into a pseudo-random bit */
-
-static inline int detrand(int x, int y) {
- unsigned int z;
- static const unsigned char t[256] = {
- /* non-linear sequence: constant term of inverse in GF(8),
- mod x^8+x^4+x^3+x+1 */
- 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1,
- 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
- 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1,
- 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1,
- 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0,
- 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0,
- 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0,
- 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1,
- 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0,
- 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1,
- 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
- };
-
- /* 0x04b3e375 and 0x05a8ef93 are chosen to contain every possible
- 5-bit sequence */
- z = ((0x04b3e375 * x) ^ y) * 0x05a8ef93;
- z = t[z & 0xff] ^ t[(z>>8) & 0xff] ^ t[(z>>16) & 0xff] ^ t[(z>>24) & 0xff];
- return z;
-}
-
-/* ---------------------------------------------------------------------- */
-/* auxiliary bitmap manipulations */
-
-/* set the excess padding to 0 */
-static void bm_clearexcess(potrace_bitmap_t *bm) {
- if (bm->w % BM_WORDBITS != 0) {
- potrace_word mask = BM_ALLBITS << (BM_WORDBITS - (bm->w % BM_WORDBITS));
- for (int y=0; y<bm->h; y++) {
- *bm_index(bm, bm->w, y) &= mask;
- }
- }
-}
-
-struct bbox_s {
- int x0, x1, y0, y1; /* bounding box */
-};
-typedef struct bbox_s bbox_t;
-
-/* clear the bm, assuming the bounding box is set correctly (faster
- than clearing the whole bitmap) */
-static void clear_bm_with_bbox(potrace_bitmap_t *bm, bbox_t *bbox) {
- int imin = (bbox->x0 / BM_WORDBITS);
- int imax = ((bbox->x1 + BM_WORDBITS-1) / BM_WORDBITS);
- int i, y;
-
- for (y=bbox->y0; y<bbox->y1; y++) {
- for (i=imin; i<imax; i++) {
- bm_scanline(bm, y)[i] = 0;
- }
- }
-}
-
-/* ---------------------------------------------------------------------- */
-/* auxiliary functions */
-
-/* return the "majority" value of bitmap bm at intersection (x,y). We
- assume that the bitmap is balanced at "radius" 1. */
-static int majority(potrace_bitmap_t *bm, int x, int y) {
- int i, a, ct;
-
- for (i=2; i<5; i++) { /* check at "radius" i */
- ct = 0;
- for (a=-i+1; a<=i-1; a++) {
- ct += BM_GET(bm, x+a, y+i-1) ? 1 : -1;
- ct += BM_GET(bm, x+i-1, y+a-1) ? 1 : -1;
- ct += BM_GET(bm, x+a-1, y-i) ? 1 : -1;
- ct += BM_GET(bm, x-i, y+a) ? 1 : -1;
- }
- if (ct>0) {
- return 1;
- } else if (ct<0) {
- return 0;
- }
- }
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-/* decompose image into paths */
-
-/* efficiently invert bits [x,infty) and [xa,infty) in line y. Here xa
- must be a multiple of BM_WORDBITS. */
-static void xor_to_ref(potrace_bitmap_t *bm, int x, int y, int xa) {
- int xhi = x & -BM_WORDBITS;
- int xlo = x & (BM_WORDBITS-1); /* = x % BM_WORDBITS */
- int i;
-
- if (xhi<xa) {
- for (i = xhi; i < xa; i+=BM_WORDBITS) {
- *bm_index(bm, i, y) ^= BM_ALLBITS;
- }
- } else {
- for (i = xa; i < xhi; i+=BM_WORDBITS) {
- *bm_index(bm, i, y) ^= BM_ALLBITS;
- }
- }
- /* note: the following "if" is needed because x86 treats a<<b as
- a<<(b&31). I spent hours looking for this bug. */
- if (xlo) {
- *bm_index(bm, xhi, y) ^= (BM_ALLBITS << (BM_WORDBITS - xlo));
- }
-}
-
-/* a path is represented as an array of points, which are thought to
- lie on the corners of pixels (not on their centers). The path point
- (x,y) is the lower left corner of the pixel (x,y). Paths are
- represented by the len/pt components of a path_t object (which
- also stores other information about the path) */
-
-/* xor the given pixmap with the interior of the given path. Note: the
- path must be within the dimensions of the pixmap. */
-static void xor_path(potrace_bitmap_t *bm, path_t *p) {
- int xa, x, y, k, y1;
-
- if (p->priv->len <= 0) { /* a path of length 0 is silly, but legal */
- return;
- }
-
- y1 = p->priv->pt[p->priv->len-1].y;
-
- xa = p->priv->pt[0].x & -BM_WORDBITS;
- for (k=0; k<p->priv->len; k++) {
- x = p->priv->pt[k].x;
- y = p->priv->pt[k].y;
-
- if (y != y1) {
- /* efficiently invert the rectangle [x,xa] x [y,y1] */
- xor_to_ref(bm, x, min(y,y1), xa);
- y1 = y;
- }
- }
-}
-
-/* Find the bounding box of a given path. Path is assumed to be of
- non-zero length. */
-static void setbbox_path(bbox_t *bbox, path_t *p) {
- int x, y;
- int k;
-
- bbox->y0 = INT_MAX;
- bbox->y1 = 0;
- bbox->x0 = INT_MAX;
- bbox->x1 = 0;
-
- for (k=0; k<p->priv->len; k++) {
- x = p->priv->pt[k].x;
- y = p->priv->pt[k].y;
-
- if (x < bbox->x0) {
- bbox->x0 = x;
- }
- if (x > bbox->x1) {
- bbox->x1 = x;
- }
- if (y < bbox->y0) {
- bbox->y0 = y;
- }
- if (y > bbox->y1) {
- bbox->y1 = y;
- }
- }
-}
-
-/* compute a path in the given pixmap, separating black from white.
- Start path at the point (x0,x1), which must be an upper left corner
- of the path. Also compute the area enclosed by the path. Return a
- new path_t object, or NULL on error (note that a legitimate path
- cannot have length 0). Sign is required for correct interpretation
- of turnpolicies. */
-static path_t *findpath(potrace_bitmap_t *bm, int x0, int y0, int sign, int turnpolicy) {
- int x, y, dirx, diry, len, size, area;
- int c, d, tmp;
- point_t *pt, *pt1;
- path_t *p = NULL;
-
- x = x0;
- y = y0;
- dirx = 0;
- diry = -1;
-
- len = size = 0;
- pt = NULL;
- area = 0;
-
- while (1) {
- /* add point to path */
- if (len>=size) {
- size += 100;
- size = (int)(1.3 * size);
- pt1 = (point_t *)realloc(pt, size * sizeof(point_t));
- if (!pt1) {
- goto error;
- }
- pt = pt1;
- }
- pt[len].x = x;
- pt[len].y = y;
- len++;
-
- /* move to next point */
- x += dirx;
- y += diry;
- area += x*diry;
-
- /* path complete? */
- if (x==x0 && y==y0) {
- break;
- }
-
- /* determine next direction */
- c = BM_GET(bm, x + (dirx+diry-1)/2, y + (diry-dirx-1)/2);
- d = BM_GET(bm, x + (dirx-diry-1)/2, y + (diry+dirx-1)/2);
-
- if (c && !d) { /* ambiguous turn */
- if (turnpolicy == POTRACE_TURNPOLICY_RIGHT
- || (turnpolicy == POTRACE_TURNPOLICY_BLACK && sign == '+')
- || (turnpolicy == POTRACE_TURNPOLICY_WHITE && sign == '-')
- || (turnpolicy == POTRACE_TURNPOLICY_RANDOM && detrand(x,y))
- || (turnpolicy == POTRACE_TURNPOLICY_MAJORITY && majority(bm, x, y))
- || (turnpolicy == POTRACE_TURNPOLICY_MINORITY && !majority(bm, x, y))) {
- tmp = dirx; /* right turn */
- dirx = diry;
- diry = -tmp;
- } else {
- tmp = dirx; /* left turn */
- dirx = -diry;
- diry = tmp;
- }
- } else if (c) { /* right turn */
- tmp = dirx;
- dirx = diry;
- diry = -tmp;
- } else if (!d) { /* left turn */
- tmp = dirx;
- dirx = -diry;
- diry = tmp;
- }
- } /* while this path */
-
- /* allocate new path object */
- p = path_new();
- if (!p) {
- goto error;
- }
-
- p->priv->pt = pt;
- p->priv->len = len;
- p->area = area;
- p->sign = sign;
-
- return p;
-
- error:
- free(pt);
- return NULL;
-}
-
-/* Give a tree structure to the given path list, based on "insideness"
- testing. I.e., path A is considered "below" path B if it is inside
- path B. The input pathlist is assumed to be ordered so that "outer"
- paths occur before "inner" paths. The tree structure is stored in
- the "childlist" and "sibling" components of the path_t
- structure. The linked list structure is also changed so that
- negative path components are listed immediately after their
- positive parent. Note: some backends may ignore the tree
- structure, others may use it e.g. to group path components. We
- assume that in the input, point 0 of each path is an "upper left"
- corner of the path, as returned by bm_to_pathlist. This makes it
- easy to find an "interior" point. The bm argument should be a
- bitmap of the correct size (large enough to hold all the paths),
- and will be used as scratch space. Return 0 on success or -1 on
- error with errno set. */
-
-static void pathlist_to_tree(path_t *plist, potrace_bitmap_t *bm) {
- path_t *p, *p1;
- path_t *heap, *heap1;
- path_t *cur;
- path_t *head;
- path_t **plist_hook; /* for fast appending to linked list */
- path_t **hook_in, **hook_out; /* for fast appending to linked list */
- bbox_t bbox;
-
- bm_clear(bm, 0);
-
- /* save original "next" pointers */
- list_forall(p, plist) {
- p->sibling = p->next;
- p->childlist = NULL;
- }
-
- heap = plist;
-
- /* the heap holds a list of lists of paths. Use "childlist" field
- for outer list, "next" field for inner list. Each of the sublists
- is to be turned into a tree. This code is messy, but it is
- actually fast. Each path is rendered exactly once. We use the
- heap to get a tail recursive algorithm: the heap holds a list of
- pathlists which still need to be transformed. */
-
- while (heap) {
- /* unlink first sublist */
- cur = heap;
- heap = heap->childlist;
- cur->childlist = NULL;
-
- /* unlink first path */
- head = cur;
- cur = cur->next;
- head->next = NULL;
-
- /* render path */
- xor_path(bm, head);
- setbbox_path(&bbox, head);
-
- /* now do insideness test for each element of cur; append it to
- head->childlist if it's inside head, else append it to
- head->next. */
- hook_in=&head->childlist;
- hook_out=&head->next;
- list_forall_unlink(p, cur) {
- if (p->priv->pt[0].y <= bbox.y0) {
- list_insert_beforehook(p, hook_out);
- /* append the remainder of the list to hook_out */
- *hook_out = cur;
- break;
- }
- if (BM_GET(bm, p->priv->pt[0].x, p->priv->pt[0].y-1)) {
- list_insert_beforehook(p, hook_in);
- } else {
- list_insert_beforehook(p, hook_out);
- }
- }
-
- /* clear bm */
- clear_bm_with_bbox(bm, &bbox);
-
- /* now schedule head->childlist and head->next for further
- processing */
- if (head->next) {
- head->next->childlist = heap;
- heap = head->next;
- }
- if (head->childlist) {
- head->childlist->childlist = heap;
- heap = head->childlist;
- }
- }
-
- /* copy sibling structure from "next" to "sibling" component */
- p = plist;
- while (p) {
- p1 = p->sibling;
- p->sibling = p->next;
- p = p1;
- }
-
- /* reconstruct a new linked list ("next") structure from tree
- ("childlist", "sibling") structure. This code is slightly messy,
- because we use a heap to make it tail recursive: the heap
- contains a list of childlists which still need to be
- processed. */
- heap = plist;
- if (heap) {
- heap->next = NULL; /* heap is a linked list of childlists */
- }
- plist = NULL;
- plist_hook = &plist;
- while (heap) {
- heap1 = heap->next;
- for (p=heap; p; p=p->sibling) {
- /* p is a positive path */
- /* append to linked list */
- list_insert_beforehook(p, plist_hook);
-
- /* go through its children */
- for (p1=p->childlist; p1; p1=p1->sibling) {
- /* append to linked list */
- list_insert_beforehook(p1, plist_hook);
- /* append its childlist to heap, if non-empty */
- if (p1->childlist) {
- list_append(path_t, heap1, p1->childlist);
- }
- }
- }
- heap = heap1;
- }
-
- return;
-}
-
-/* find the next set pixel in a row <= y. Pixels are searched first
- left-to-right, then top-down. In other words, (x,y)<(x',y') if y>y'
- or y=y' and x<x'. If found, return 0 and store pixel in
- (*xp,*yp). Else return 1. Note that this function assumes that
- excess bytes have been cleared with bm_clearexcess. */
-static int findnext(potrace_bitmap_t *bm, int *xp, int *yp) {
- int x;
- int y;
- int x0;
-
- x0 = (*xp) & ~(BM_WORDBITS-1);
-
- for (y=*yp; y>=0; y--) {
- for (x=x0; x<bm->w; x+=BM_WORDBITS) {
- if (*bm_index(bm, x, y)) {
- while (!BM_GET(bm, x, y)) {
- x++;
- }
- /* found */
- *xp = x;
- *yp = y;
- return 0;
- }
- }
- x0 = 0;
- }
- /* not found */
- return 1;
-}
-
-/* Decompose the given bitmap into paths. Returns a linked list of
- path_t objects with the fields len, pt, area, sign filled
- in. Returns 0 on success with plistp set, or -1 on error with errno
- set. */
-
-int bm_to_pathlist(const potrace_bitmap_t *bm, path_t **plistp, const potrace_param_t *param, progress_t *progress) {
- int x;
- int y;
- path_t *p;
- path_t *plist = NULL; /* linked list of path objects */
- path_t **plist_hook = &plist; /* used to speed up appending to linked list */
- potrace_bitmap_t *bm1 = NULL;
- int sign;
-
- bm1 = bm_dup(bm);
- if (!bm1) {
- goto error;
- }
-
- /* be sure the byte padding on the right is set to 0, as the fast
- pixel search below relies on it */
- bm_clearexcess(bm1);
-
- /* iterate through components */
- x = 0;
- y = bm1->h - 1;
- while (findnext(bm1, &x, &y) == 0) {
- /* calculate the sign by looking at the original */
- sign = BM_GET(bm, x, y) ? '+' : '-';
-
- /* calculate the path */
- p = findpath(bm1, x, y+1, sign, param->turnpolicy);
- if (p==NULL) {
- goto error;
- }
-
- /* update buffered image */
- xor_path(bm1, p);
-
- /* if it's a turd, eliminate it, else append it to the list */
- if (p->area <= param->turdsize) {
- path_free(p);
- } else {
- list_insert_beforehook(p, plist_hook);
- }
-
- if (bm1->h > 0) { /* to be sure */
- progress_update(1-y/(double)bm1->h, progress);
- }
- }
-
- pathlist_to_tree(plist, bm1);
- bm_free(bm1);
- *plistp = plist;
-
- progress_update(1.0, progress);
-
- return 0;
-
- error:
- bm_free(bm1);
- list_forall_unlink(p, plist) {
- path_free(p);
- }
- return -1;
-}
diff --git a/src/trace/potrace/decompose.h b/src/trace/potrace/decompose.h
deleted file mode 100644
index 8ae89b8ad..000000000
--- a/src/trace/potrace/decompose.h
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-
-#ifndef DECOMPOSE_H
-#define DECOMPOSE_H
-
-#include "potracelib.h"
-#include "progress.h"
-#include "curve.h"
-
-int bm_to_pathlist(const potrace_bitmap_t *bm, path_t **plistp, const potrace_param_t *param, progress_t *progress);
-
-#endif /* DECOMPOSE_H */
-
diff --git a/src/trace/potrace/greymap.cpp b/src/trace/potrace/greymap.cpp
deleted file mode 100644
index 4ef2ec8df..000000000
--- a/src/trace/potrace/greymap.cpp
+++ /dev/null
@@ -1,941 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-
-/* Routines for manipulating greymaps, including reading pgm files. We
- only deal with greymaps of depth 8 bits. */
-
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <errno.h>
-
-#include "greymap.h"
-#include "bitops.h"
-
-#define INTBITS (8*sizeof(int))
-
-#define mod(a,n) ((a)>=(n) ? (a)%(n) : (a)>=0 ? (a) : (n)-1-(-1-(a))%(n))
-
-static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic);
-static int gm_readbody_bmp(FILE *f, greymap_t **gmp);
-
-/* ---------------------------------------------------------------------- */
-/* basic greymap routines */
-
-/* return new un-initialized greymap. NULL with errno on error.
- Assumes w, h >= 0. */
-greymap_t *gm_new(int w, int h) {
- greymap_t *gm;
- ssize_t size = (ssize_t)w * (ssize_t)h * (ssize_t)sizeof(signed short int);
-
- /* check for overflow error */
- if (size < 0 || size / w / h != sizeof(signed short int)) {
- errno = ENOMEM;
- return NULL;
- }
-
- gm = (greymap_t *) malloc(sizeof(greymap_t));
- if (!gm) {
- return NULL;
- }
- gm->w = w;
- gm->h = h;
- gm->map = (signed short int *) malloc(size);
- if (!gm->map) {
- free(gm);
- return NULL;
- }
- return gm;
-}
-
-/* free the given greymap */
-void gm_free(greymap_t *gm) {
- if (gm) {
- free(gm->map);
- }
- free(gm);
-}
-
-/* duplicate the given greymap. Return NULL on error with errno set. */
-greymap_t *gm_dup(greymap_t *gm) {
- greymap_t *gm1 = gm_new(gm->w, gm->h);
- if (!gm1) {
- return NULL;
- }
- memcpy(gm1->map, gm->map, gm->w*gm->h*sizeof(signed short int));
- return gm1;
-}
-
-/* clear the given greymap to color b. */
-void gm_clear(greymap_t *gm, int b) {
- if (b==0) {
- memset(gm->map, 0, gm->w*gm->h*sizeof(signed short int));
- } else {
- for (int i=0; i<gm->w*gm->h; i++) {
- gm->map[i] = b;
- }
- }
-}
-
-/* ---------------------------------------------------------------------- */
-/* routines for reading pnm streams */
-
-/* read next character after whitespace and comments. Return EOF on
- end of file or error. */
-static int fgetc_ws(FILE *f) {
- int c;
-
- while (1) {
- c = fgetc(f);
- if (c=='#') {
- while (1) {
- c = fgetc(f);
- if (c=='\n' || c==EOF) {
- break;
- }
- }
- }
- /* space, tab, line feed, carriage return, form-feed */
- if (c!=' ' && c!='\t' && c!='\r' && c!='\n' && c!=12) {
- return c;
- }
- }
-}
-
-/* skip whitespace and comments, then read a non-negative decimal
- number from a stream. Return -1 on EOF. Tolerate other errors (skip
- bad characters). Do not the read any characters following the
- number (put next character back into the stream) */
-
-static int readnum(FILE *f) {
- int c;
- int acc;
-
- /* skip whitespace and comments */
- while (1) {
- c = fgetc_ws(f);
- if (c==EOF) {
- return -1;
- }
- if (c>='0' && c<='9') {
- break;
- }
- }
-
- /* first digit is already in c */
- acc = c-'0';
- while (1) {
- c = fgetc(f);
- if (c==EOF) {
- break;
- }
- if (c<'0' || c>'9') {
- ungetc(c, f);
- break;
- }
- acc *= 10;
- acc += c-'0';
- }
- return acc;
-}
-
-/* similar to readnum, but read only a single 0 or 1, and do not read
- any characters after it. */
-
-static int readbit(FILE *f) {
- int c;
-
- /* skip whitespace and comments */
- while (1) {
- c = fgetc_ws(f);
- if (c==EOF) {
- return -1;
- }
- if (c>='0' && c<='1') {
- break;
- }
- }
-
- return c-'0';
-}
-
-/* ---------------------------------------------------------------------- */
-
-/* read a PNM stream: P1-P6 format (see pnm(5)), or a BMP stream, and
- convert the output to a greymap. Return greymap in *gmp. Return 0
- on success, -1 on error with errno set, -2 on bad file format (with
- error message in gm_read_error), and 1 on premature end of file, -3
- on empty file (including files with only whitespace and comments),
- -4 if wrong magic number. If the return value is >=0, *gmp is
- valid. */
-
-char const *gm_read_error = NULL;
-
-int gm_read(FILE *f, greymap_t **gmp) {
- int magic[2];
-
- /* read magic number. We ignore whitespace and comments before the
- magic, for the benefit of concatenated files in P1-P3 format.
- Multiple P1-P3 images in a single file are not formally allowed
- by the PNM standard, but there is no harm in being lenient. */
-
- magic[0] = fgetc_ws(f);
- if (magic[0] == EOF) {
- /* files which contain only comments and whitespace count as "empty" */
- return -3;
- }
- magic[1] = fgetc(f);
- if (magic[0] == 'P' && magic[1] >= '1' && magic[1] <= '6') {
- return gm_readbody_pnm(f, gmp, magic[1]);
- }
- if (magic[0] == 'B' && magic[1] == 'M') {
- return gm_readbody_bmp(f, gmp);
- }
- return -4;
-}
-
-/* ---------------------------------------------------------------------- */
-/* read PNM format */
-
-/* read PNM stream after magic number. Return values as for gm_read */
-static int gm_readbody_pnm(FILE *f, greymap_t **gmp, int magic) {
- greymap_t *gm;
- int x, y, i, j, b, b1, sum;
- int bpr; /* bytes per row (as opposed to 4*gm->c) */
- int w, h, max;
-
- gm = NULL;
-
- w = readnum(f);
- if (w<0) {
- goto format_error;
- }
-
- h = readnum(f);
- if (h<0) {
- goto format_error;
- }
-
- /* allocate greymap */
- gm = gm_new(w, h);
- if (!gm) {
- return -1;
- }
-
- /* zero it out */
- gm_clear(gm, 0);
-
- switch (magic) {
- default:
- /* not reached */
- goto format_error;
-
- case '1':
- /* read P1 format: PBM ascii */
-
- for (y=h-1; y>=0; y--) {
- for (x=0; x<w; x++) {
- b = readbit(f);
- if (b<0) {
- goto eof;
- }
- GM_UPUT(gm, x, y, b ? 0 : 255);
- }
- }
- break;
-
- case '2':
- /* read P2 format: PGM ascii */
-
- max = readnum(f);
- if (max<1) {
- goto format_error;
- }
-
- for (y=h-1; y>=0; y--) {
- for (x=0; x<w; x++) {
- b = readnum(f);
- if (b<0) {
- goto eof;
- }
- GM_UPUT(gm, x, y, b*255/max);
- }
- }
- break;
-
- case '3':
- /* read P3 format: PPM ascii */
-
- max = readnum(f);
- if (max<1) {
- goto format_error;
- }
-
- for (y=h-1; y>=0; y--) {
- for (x=0; x<w; x++) {
- sum = 0;
- for (i=0; i<3; i++) {
- b = readnum(f);
- if (b<0) {
- goto eof;
- }
- sum += b;
- }
- GM_UPUT(gm, x, y, sum*(255/3)/max);
- }
- }
- break;
-
- case '4':
- /* read P4 format: PBM raw */
-
- b = fgetc(f); /* read single white-space character after height */
- if (b==EOF) {
- goto format_error;
- }
-
- bpr = (w+7)/8;
-
- for (y=h-1; y>=0; y--) {
- for (i=0; i<bpr; i++) {
- b = fgetc(f);
- if (b==EOF) {
- goto eof;
- }
- for (j=0; j<8; j++) {
- GM_PUT(gm, i*8+j, y, b & (0x80 >> j) ? 0 : 255);
- }
- }
- }
- break;
-
- case '5':
- /* read P5 format: PGM raw */
-
- max = readnum(f);
- if (max<1) {
- goto format_error;
- }
-
- b = fgetc(f); /* read single white-space character after max */
- if (b==EOF) {
- goto format_error;
- }
-
- for (y=h-1; y>=0; y--) {
- for (x=0; x<w; x++) {
- b = fgetc(f);
- if (b==EOF)
- goto eof;
- if (max>=256) {
- b <<= 8;
- b1 = fgetc(f);
- if (b1==EOF)
- goto eof;
- b |= b1;
- }
- GM_UPUT(gm, x, y, b*255/max);
- }
- }
- break;
-
- case '6':
- /* read P6 format: PPM raw */
-
- max = readnum(f);
- if (max<1) {
- goto format_error;
- }
-
- b = fgetc(f); /* read single white-space character after max */
- if (b==EOF) {
- goto format_error;
- }
-
- for (y=h-1; y>=0; y--) {
- for (x=0; x<w; x++) {
- sum = 0;
- for (i=0; i<3; i++) {
- b = fgetc(f);
- if (b==EOF) {
- goto eof;
- }
- if (max>=256) {
- b <<= 8;
- b1 = fgetc(f);
- if (b1==EOF)
- goto eof;
- b |= b1;
- }
- sum += b;
- }
- GM_UPUT(gm, x, y, sum*(255/3)/max);
- }
- }
- break;
- }
-
- *gmp = gm;
- return 0;
-
- eof:
- *gmp = gm;
- return 1;
-
- format_error:
- gm_free(gm);
- if (magic == '1' || magic == '4') {
- gm_read_error = "invalid pbm file";
- } else if (magic == '2' || magic == '5') {
- gm_read_error = "invalid pgm file";
- } else {
- gm_read_error = "invalid ppm file";
- }
- return -2;
-}
-
-/* ---------------------------------------------------------------------- */
-/* read BMP format */
-
-struct bmp_info_s {
- unsigned int FileSize;
- unsigned int reserved;
- unsigned int DataOffset;
- unsigned int InfoSize;
- unsigned int w; /* width */
- unsigned int h; /* height */
- unsigned int Planes;
- unsigned int bits; /* bits per sample */
- unsigned int comp; /* compression mode */
- unsigned int ImageSize;
- unsigned int XpixelsPerM;
- unsigned int YpixelsPerM;
- unsigned int ncolors; /* number of colors in palette */
- unsigned int ColorsImportant;
- unsigned int RedMask;
- unsigned int GreenMask;
- unsigned int BlueMask;
- unsigned int AlphaMask;
- unsigned int ctbits; /* sample size for color table */
- int topdown; /* top-down mode? */
-};
-typedef struct bmp_info_s bmp_info_t;
-
-/* auxiliary */
-
-static int bmp_count = 0; /* counter for byte padding */
-static int bmp_pos = 0; /* counter from start of BMP data */
-
-/* read n-byte little-endian integer. Return 1 on EOF or error, else
- 0. Assume n<=4. */
-static int bmp_readint(FILE *f, int n, unsigned int *p) {
- int i;
- unsigned int sum = 0;
- int b;
-
- for (i=0; i<n; i++) {
- b = fgetc(f);
- if (b==EOF) {
- return 1;
- }
- sum += b << (8*i);
- }
- bmp_count += n;
- bmp_pos += n;
- *p = sum;
- return 0;
-}
-
-/* reset padding boundary */
-static void bmp_pad_reset(void) {
- bmp_count = 0;
-}
-
-/* read padding bytes to 4-byte boundary. Return 1 on EOF or error,
- else 0. */
-static int bmp_pad(FILE *f) {
- int c, i, b;
-
- c = (-bmp_count) & 3;
- for (i=0; i<c; i++) {
- b = fgetc(f);
- if (b==EOF) {
- return 1;
- }
- }
- bmp_pos += c;
- bmp_count = 0;
- return 0;
-}
-
-/* forward to the new file position. Return 1 on EOF or error, else 0 */
-static int bmp_forward(FILE *f, int pos) {
- int b;
-
- while (bmp_pos < pos) {
- b = fgetc(f);
- if (b==EOF) {
- return 1;
- }
- bmp_pos++;
- bmp_count++;
- }
- return 0;
-}
-
-#define TRY(x) if (x) goto try_error
-#define TRY_EOF(x) if (x) goto eof
-
-/* correct y-coordinate for top-down format */
-#define ycorr(y) (bmpinfo.topdown ? bmpinfo.h-1-y : y)
-
-/* read BMP stream after magic number. Return values as for gm_read.
- We choose to be as permissive as possible, since there are many
- programs out there which produce BMP. For instance, ppmtobmp can
- produce codings with anywhere from 1-8 or 24 bits per sample,
- although most specifications only allow 1,4,8,24,32. We can also
- read both the old and new OS/2 BMP formats in addition to the
- Windows BMP format. */
-static int gm_readbody_bmp(FILE *f, greymap_t **gmp) {
- bmp_info_t bmpinfo;
- int *coltable;
- unsigned int b, c;
- unsigned int i, j;
- greymap_t *gm;
- unsigned int x, y;
- int col[2];
- unsigned int bitbuf;
- unsigned int n;
- unsigned int redshift, greenshift, blueshift;
-
- gm_read_error = NULL;
- gm = NULL;
- coltable = NULL;
-
- bmp_pos = 2; /* set file position */
-
- /* file header (minus magic number) */
- TRY(bmp_readint(f, 4, &bmpinfo.FileSize));
- TRY(bmp_readint(f, 4, &bmpinfo.reserved));
- TRY(bmp_readint(f, 4, &bmpinfo.DataOffset));
-
- /* info header */
- TRY(bmp_readint(f, 4, &bmpinfo.InfoSize));
- if (bmpinfo.InfoSize == 40 || bmpinfo.InfoSize == 64
- || bmpinfo.InfoSize == 108 || bmpinfo.InfoSize == 124) {
- /* Windows or new OS/2 format */
- bmpinfo.ctbits = 32; /* sample size in color table */
- TRY(bmp_readint(f, 4, &bmpinfo.w));
- TRY(bmp_readint(f, 4, &bmpinfo.h));
- TRY(bmp_readint(f, 2, &bmpinfo.Planes));
- TRY(bmp_readint(f, 2, &bmpinfo.bits));
- TRY(bmp_readint(f, 4, &bmpinfo.comp));
- TRY(bmp_readint(f, 4, &bmpinfo.ImageSize));
- TRY(bmp_readint(f, 4, &bmpinfo.XpixelsPerM));
- TRY(bmp_readint(f, 4, &bmpinfo.YpixelsPerM));
- TRY(bmp_readint(f, 4, &bmpinfo.ncolors));
- TRY(bmp_readint(f, 4, &bmpinfo.ColorsImportant));
- if (bmpinfo.InfoSize >= 108) { /* V4 and V5 bitmaps */
- TRY(bmp_readint(f, 4, &bmpinfo.RedMask));
- TRY(bmp_readint(f, 4, &bmpinfo.GreenMask));
- TRY(bmp_readint(f, 4, &bmpinfo.BlueMask));
- TRY(bmp_readint(f, 4, &bmpinfo.AlphaMask));
- }
- if (bmpinfo.w > 0x7fffffff) {
- goto format_error;
- }
- if (bmpinfo.h > 0x7fffffff) {
- bmpinfo.h = (-bmpinfo.h) & 0xffffffff;
- bmpinfo.topdown = 1;
- } else {
- bmpinfo.topdown = 0;
- }
- if (bmpinfo.h > 0x7fffffff) {
- goto format_error;
- }
- } else if (bmpinfo.InfoSize == 12) {
- /* old OS/2 format */
- bmpinfo.ctbits = 24; /* sample size in color table */
- TRY(bmp_readint(f, 2, &bmpinfo.w));
- TRY(bmp_readint(f, 2, &bmpinfo.h));
- TRY(bmp_readint(f, 2, &bmpinfo.Planes));
- TRY(bmp_readint(f, 2, &bmpinfo.bits));
- bmpinfo.comp = 0;
- bmpinfo.ncolors = 0;
- bmpinfo.topdown = 0;
- } else {
- goto format_error;
- }
-
- if (bmpinfo.comp == 3 && bmpinfo.InfoSize < 108) {
- /* bitfield feature is only understood with V4 and V5 format */
- goto format_error;
- }
-
- /* forward to color table (e.g., if bmpinfo.InfoSize == 64) */
- TRY(bmp_forward(f, 14+bmpinfo.InfoSize));
-
- if (bmpinfo.Planes != 1) {
- gm_read_error = "cannot handle bmp planes";
- goto format_error; /* can't handle planes */
- }
-
- if (bmpinfo.ncolors == 0) {
- bmpinfo.ncolors = 1 << bmpinfo.bits;
- }
-
- /* color table, present only if bmpinfo.bits <= 8. */
- if (bmpinfo.bits <= 8) {
- coltable = (int *) calloc(bmpinfo.ncolors, sizeof(int));
- if (!coltable) {
- goto std_error;
- }
- /* NOTE: since we are reading a greymap, we can immediately convert
- the color table entries to grey values. */
- for (i=0; i<bmpinfo.ncolors; i++) {
- TRY(bmp_readint(f, bmpinfo.ctbits/8, &c));
- c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
- coltable[i] = c/3;
- }
- }
-
- /* forward to data */
- if (bmpinfo.InfoSize != 12) { /* not old OS/2 format */
- TRY(bmp_forward(f, bmpinfo.DataOffset));
- }
-
- /* allocate greymap */
- gm = gm_new(bmpinfo.w, bmpinfo.h);
- if (!gm) {
- goto std_error;
- }
-
- /* zero it out */
- gm_clear(gm, 0);
-
- switch (bmpinfo.bits + 0x100*bmpinfo.comp) {
-
- default:
- goto format_error;
- break;
-
- case 0x001: /* monochrome palette */
-
- /* raster data */
- for (y=0; y<bmpinfo.h; y++) {
- bmp_pad_reset();
- for (i=0; 8*i<bmpinfo.w; i++) {
- TRY_EOF(bmp_readint(f, 1, &b));
- for (j=0; j<8; j++) {
- GM_PUT(gm, i*8+j, ycorr(y), b & (0x80 >> j) ? coltable[1] : coltable[0]);
- }
- }
- TRY(bmp_pad(f));
- }
- break;
-
- case 0x002: /* 2-bit to 8-bit palettes */
- case 0x003:
- case 0x004:
- case 0x005:
- case 0x006:
- case 0x007:
- case 0x008:
- for (y=0; y<bmpinfo.h; y++) {
- bmp_pad_reset();
- bitbuf = 0; /* bit buffer: bits in buffer are high-aligned */
- n = 0; /* number of bits currently in bitbuffer */
- for (x=0; x<bmpinfo.w; x++) {
- if (n < bmpinfo.bits) {
- TRY_EOF(bmp_readint(f, 1, &b));
- bitbuf |= b << (INTBITS - 8 - n);
- n += 8;
- }
- b = bitbuf >> (INTBITS - bmpinfo.bits);
- bitbuf <<= bmpinfo.bits;
- n -= bmpinfo.bits;
- GM_UPUT(gm, x, ycorr(y), coltable[b]);
- }
- TRY(bmp_pad(f));
- }
- break;
-
- case 0x010: /* 16-bit encoding */
- /* can't do this format because it is not well-documented and I
- don't have any samples */
- gm_read_error = "cannot handle bmp 16-bit coding";
- goto format_error;
- break;
-
- case 0x018: /* 24-bit encoding */
- case 0x020: /* 32-bit encoding */
- for (y=0; y<bmpinfo.h; y++) {
- bmp_pad_reset();
- for (x=0; x<bmpinfo.w; x++) {
- TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
- c = ((c>>16) & 0xff) + ((c>>8) & 0xff) + (c & 0xff);
- GM_UPUT(gm, x, ycorr(y), c/3);
- }
- TRY(bmp_pad(f));
- }
- break;
-
- case 0x320: /* 32-bit encoding with bitfields */
- redshift = lobit(bmpinfo.RedMask);
- greenshift = lobit(bmpinfo.GreenMask);
- blueshift = lobit(bmpinfo.BlueMask);
-
- for (y=0; y<bmpinfo.h; y++) {
- bmp_pad_reset();
- for (x=0; x<bmpinfo.w; x++) {
- TRY_EOF(bmp_readint(f, bmpinfo.bits/8, &c));
- c = ((c & bmpinfo.RedMask) >> redshift) + ((c & bmpinfo.GreenMask) >> greenshift) + ((c & bmpinfo.BlueMask) >> blueshift);
- GM_UPUT(gm, x, ycorr(y), c/3);
- }
- TRY(bmp_pad(f));
- }
- break;
-
- case 0x204: /* 4-bit runlength compressed encoding (RLE4) */
- x = 0;
- y = 0;
- while (1) {
- TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
- TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
- if (b>0) {
- /* repeat count */
- col[0] = coltable[(c>>4) & 0xf];
- col[1] = coltable[c & 0xf];
- for (i=0; i<b && x<bmpinfo.w; i++) {
- if (x>=bmpinfo.w) {
- x=0;
- y++;
- }
- if (y>=bmpinfo.h) {
- break;
- }
- GM_UPUT(gm, x, ycorr(y), col[i&1]);
- x++;
- }
- } else if (c == 0) {
- /* end of line */
- y++;
- x = 0;
- } else if (c == 1) {
- /* end of greymap */
- break;
- } else if (c == 2) {
- /* "delta": skip pixels in x and y directions */
- TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
- TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
- x += b;
- y += c;
- } else {
- /* verbatim segment */
- for (i=0; i<c; i++) {
- if ((i&1)==0) {
- TRY_EOF(bmp_readint(f, 1, &b));
- }
- if (x>=bmpinfo.w) {
- x=0;
- y++;
- }
- if (y>=bmpinfo.h) {
- break;
- }
- GM_PUT(gm, x, ycorr(y), coltable[(b>>(4-4*(i&1))) & 0xf]);
- x++;
- }
- if ((c+1) & 2) {
- /* pad to 16-bit boundary */
- TRY_EOF(bmp_readint(f, 1, &b));
- }
- }
- }
- break;
-
- case 0x108: /* 8-bit runlength compressed encoding (RLE8) */
- x = 0;
- y = 0;
- while (1) {
- TRY_EOF(bmp_readint(f, 1, &b)); /* opcode */
- TRY_EOF(bmp_readint(f, 1, &c)); /* argument */
- if (b>0) {
- /* repeat count */
- for (i=0; i<b; i++) {
- if (x>=bmpinfo.w) {
- x=0;
- y++;
- }
- if (y>=bmpinfo.h) {
- break;
- }
- GM_UPUT(gm, x, ycorr(y), coltable[c]);
- x++;
- }
- } else if (c == 0) {
- /* end of line */
- y++;
- x = 0;
- } else if (c == 1) {
- /* end of greymap */
- break;
- } else if (c == 2) {
- /* "delta": skip pixels in x and y directions */
- TRY_EOF(bmp_readint(f, 1, &b)); /* x offset */
- TRY_EOF(bmp_readint(f, 1, &c)); /* y offset */
- x += b;
- y += c;
- } else {
- /* verbatim segment */
- for (i=0; i<c; i++) {
- TRY_EOF(bmp_readint(f, 1, &b));
- if (x>=bmpinfo.w) {
- x=0;
- y++;
- }
- if (y>=bmpinfo.h) {
- break;
- }
- GM_PUT(gm, x, ycorr(y), coltable[b]);
- x++;
- }
- if (c & 1) {
- /* pad input to 16-bit boundary */
- TRY_EOF(bmp_readint(f, 1, &b));
- }
- }
- }
- break;
-
- } /* switch */
-
- /* skip any potential junk after the data section, but don't
- complain in case EOF is encountered */
- bmp_forward(f, bmpinfo.FileSize);
-
- free(coltable);
- *gmp = gm;
- return 0;
-
- eof:
- free(coltable);
- *gmp = gm;
- return 1;
-
- format_error:
- try_error:
- free(coltable);
- free(gm);
- if (!gm_read_error) {
- gm_read_error = "invalid bmp file";
- }
- return -2;
-
- std_error:
- free(coltable);
- free(gm);
- return -1;
-}
-
-/* ---------------------------------------------------------------------- */
-
-/* write a pgm stream, either P2 or (if raw != 0) P5 format. Include
- one-line comment if non-NULL. Mode determines how out-of-range
- color values are converted. Gamma is the desired gamma correction,
- if any (set to 2.2 if the image is to look optimal on a CRT monitor,
- 2.8 for LCD). Set to 1.0 for no gamma correction */
-
-int gm_writepgm(FILE *f, greymap_t *gm, char *comment, int raw, int mode, double gamma) {
- int x, y, v;
- int gammatable[256];
-
- /* prepare gamma correction lookup table */
- if (gamma != 1.0) {
- gammatable[0] = 0;
- for (v=1; v<256; v++) {
- gammatable[v] = (int)(255 * exp(log(v/255.0)/gamma) + 0.5);
- }
- } else {
- for (v=0; v<256; v++) {
- gammatable[v] = v;
- }
- }
-
- fprintf(f, raw ? "P5\n" : "P2\n");
- if (comment && *comment) {
- fprintf(f, "# %s\n", comment);
- }
- fprintf(f, "%d %d 255\n", gm->w, gm->h);
- for (y=gm->h-1; y>=0; y--) {
- for (x=0; x<gm->w; x++) {
- v = GM_UGET(gm, x, y);
- if (mode == GM_MODE_NONZERO) {
- if (v > 255) {
- v = 510 - v;
- }
- if (v < 0) {
- v = 0;
- }
- } else if (mode == GM_MODE_ODD) {
- v = mod(v, 510);
- if (v > 255) {
- v = 510 - v;
- }
- } else if (mode == GM_MODE_POSITIVE) {
- if (v < 0) {
- v = 0;
- } else if (v > 255) {
- v = 255;
- }
- } else if (mode == GM_MODE_NEGATIVE) {
- v = 510 - v;
- if (v < 0) {
- v = 0;
- } else if (v > 255) {
- v = 255;
- }
- }
- v = gammatable[v];
-
- if (raw) {
- fputc(v, f);
- } else {
- fprintf(f, x == gm->w-1 ? "%d\n" : "%d ", v);
- }
- }
- }
- return 0;
-}
-
-/* ---------------------------------------------------------------------- */
-/* output - for primitive debugging purposes only! */
-
-/* print greymap to screen */
-int gm_print(FILE *f, greymap_t *gm) {
- int x, y;
- int xx, yy;
- int d, t;
- int sw, sh;
-
- sw = gm->w < 79 ? gm->w : 79;
- sh = gm->w < 79 ? gm->h : gm->h*sw*44/(79*gm->w);
-
- for (yy=sh-1; yy>=0; yy--) {
- for (xx=0; xx<sw; xx++) {
- d=0;
- t=0;
- for (x=xx*gm->w/sw; x<(xx+1)*gm->w/sw; x++) {
- for (y=yy*gm->h/sh; y<(yy+1)*gm->h/sh; y++) {
- d += GM_GET(gm, x, y);
- t += 256;
- }
- }
- fputc("*#=- "[5*d/t], f); /* what a cute trick :) */
- }
- fputc('\n', f);
- }
- return 0;
-}
diff --git a/src/trace/potrace/greymap.h b/src/trace/potrace/greymap.h
deleted file mode 100644
index 8c9db9bbf..000000000
--- a/src/trace/potrace/greymap.h
+++ /dev/null
@@ -1,58 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-
-#ifndef GREYMAP_H
-#define GREYMAP_H
-
-#include <stdio.h>
-#include <stdlib.h>
-
-/* internal format for greymaps. Note: in this format, rows are
- ordered from bottom to top. The pixels in each row are given from
- left to right. */
-
-struct greymap_s {
- int w; /* width, in pixels */
- int h; /* height, in pixels */
- signed short int *map; /* raw data, w*h values */
-};
-typedef struct greymap_s greymap_t;
-
-/* macros for accessing pixel at index (x,y). Note that the origin is
- in the *lower* left corner. U* macros omit the bounds check. */
-
-#define gm_index(gm, x, y) (&(gm)->map[(x)+(y)*(ssize_t)(gm)->w])
-#define gm_safe(gm, x, y) ((int)(x)>=0 && (int)(x)<(gm)->w && (int)(y)>=0 && (int)(y)<(gm)->h)
-#define gm_bound(x, m) ((x)<0 ? 0 : (x)>=(m) ? (m)-1 : (x))
-#define GM_UGET(gm, x, y) (*gm_index(gm, x, y))
-#define GM_UINC(gm, x, y, b) (*gm_index(gm, x, y) += (short int)(b))
-#define GM_UINV(gm, x, y) (*gm_index(gm, x, y) = 255 - *gm_index(gm, x, y))
-#define GM_UPUT(gm, x, y, b) (*gm_index(gm, x, y) = (short int)(b))
-#define GM_GET(gm, x, y) (gm_safe(gm, x, y) ? GM_UGET(gm, x, y) : 0)
-#define GM_INC(gm, x, y, b) (gm_safe(gm, x, y) ? GM_UINC(gm, x, y, b) : 0)
-#define GM_INV(gm, x, y) (gm_safe(gm, x, y) ? GM_UINV(gm, x, y) : 0)
-#define GM_PUT(gm, x, y, b) (gm_safe(gm, x, y) ? GM_UPUT(gm, x, y, b) : 0)
-#define GM_BGET(gm, x, y) GM_UGET(gm, gm_bound(x, gm->w), gm_bound(y, gm->h))
-
-/* modes for cutting off out-of-range values. The following names
- refer to winding numbers. I.e., make a pixel black if winding
- number is nonzero, odd, or positive, respectively. We assume that 0
- winding number corresponds to white (255). */
-#define GM_MODE_NONZERO 1
-#define GM_MODE_ODD 2
-#define GM_MODE_POSITIVE 3
-#define GM_MODE_NEGATIVE 4
-
-extern char const *gm_read_error;
-
-greymap_t *gm_new(int w, int h);
-greymap_t *gm_dup(greymap_t *gm);
-void gm_free(greymap_t *gm);
-void gm_clear(greymap_t *gm, int b);
-int gm_read(FILE *f, greymap_t **gmp);
-int gm_writepgm(FILE *f, greymap_t *gm, char *comment, int raw, int mode, double gamma);
-int gm_print(FILE *f, greymap_t *gm);
-
-#endif /* GREYMAP_H */
diff --git a/src/trace/potrace/inkscape-potrace.cpp b/src/trace/potrace/inkscape-potrace.cpp
index 8f3bb7bdf..a0b0df1f6 100644
--- a/src/trace/potrace/inkscape-potrace.cpp
+++ b/src/trace/potrace/inkscape-potrace.cpp
@@ -29,7 +29,6 @@
#include "message-stack.h"
#include <sp-path.h>
#include <svg/path-string.h>
-#include "curve.h"
#include "bitmap.h"
using Glib::ustring;
@@ -128,7 +127,7 @@ static bool hasPoint(std::vector<Point> &points, double x, double y)
/**
- * Recursively descend the path_t node tree, writing paths in SVG
+ * Recursively descend the potrace_path_t node tree, writing paths in SVG
* format into the output stream. The Point vector is used to prevent
* redundant paths. Returns number of paths processed.
*/
@@ -144,7 +143,7 @@ static long writePaths(PotraceTracingEngine *engine, potrace_path_t *plist,
//g_message("node->fm:%d\n", node->fm);
if (!curve->n)
continue;
- dpoint_t *pt = curve->c[curve->n - 1];
+ const potrace_dpoint_t *pt = curve->c[curve->n - 1];
double x0 = 0.0;
double y0 = 0.0;
double x1 = 0.0;
@@ -192,7 +191,7 @@ static long writePaths(PotraceTracingEngine *engine, potrace_path_t *plist,
}
data.closePath();
- for (path_t *child=node->childlist; child ; child=child->sibling)
+ for (potrace_path_t *child=node->childlist; child ; child=child->sibling)
{
nodeCount += writePaths(engine, child, data, points);
}
diff --git a/src/trace/potrace/inkscape-potrace.h b/src/trace/potrace/inkscape-potrace.h
index 88da56abb..e8e654973 100644
--- a/src/trace/potrace/inkscape-potrace.h
+++ b/src/trace/potrace/inkscape-potrace.h
@@ -18,7 +18,7 @@
#define __INKSCAPE_POTRACE_H__
#include <trace/trace.h>
-#include "potracelib.h"
+#include <potracelib.h>
struct GrayMap_def;
typedef GrayMap_def GrayMap;
diff --git a/src/trace/potrace/lists.h b/src/trace/potrace/lists.h
deleted file mode 100644
index 394262c23..000000000
--- a/src/trace/potrace/lists.h
+++ /dev/null
@@ -1,285 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-
-#ifndef _PS_LISTS_H
-#define _PS_LISTS_H
-
-/* here we define some general list macros. Because they are macros,
- they should work on any datatype with a "->next" component. Some of
- them use a "hook". If elt and list are of type t* then hook is of
- type t**. A hook stands for an insertion point in the list, i.e.,
- either before the first element, or between two elements, or after
- the last element. If an operation "sets the hook" for an element,
- then the hook is set to just before the element. One can insert
- something at a hook. One can also unlink at a hook: this means,
- unlink the element just after the hook. By "to unlink", we mean the
- element is removed from the list, but not deleted. Thus, it and its
- components still need to be freed. */
-
-/* Note: these macros are somewhat experimental. Only the ones that
- are actually *used* have been tested. So be careful to test any
- that you use. Looking at the output of the preprocessor, "gcc -E"
- (possibly piped though "indent"), might help too. Also: these
- macros define some internal (local) variables that start with
- "_". */
-
-/* we enclose macro definitions whose body consists of more than one
- statement in MACRO_BEGIN and MACRO_END, rather than '{' and '}'. The
- reason is that we want to be able to use the macro in a context
- such as "if (...) macro(...); else ...". If we didn't use this obscure
- trick, we'd have to omit the ";" in such cases. */
-
-#define MACRO_BEGIN do {
-#define MACRO_END } while (0)
-
-/* ---------------------------------------------------------------------- */
-/* macros for singly-linked lists */
-
-/* traverse list. At the end, elt is set to NULL. */
-#define list_forall(elt, list) for (elt=list; elt!=NULL; elt=elt->next)
-
-/* set elt to the first element of list satisfying boolean condition
- c, or NULL if not found */
-#define list_find(elt, list, c) \
- MACRO_BEGIN list_forall(elt, list) if (c) break; MACRO_END
-
-/* like forall, except also set hook for elt. */
-#define list_forall2(elt, list, hook) \
- for (elt=list, hook=&list; elt!=NULL; hook=&elt->next, elt=elt->next)
-
-/* same as list_find, except also set hook for elt. */
-#define list_find2(elt, list, c, hook) \
- MACRO_BEGIN list_forall2(elt, list, hook) if (c) break; MACRO_END
-
-/* same, except only use hook. */
-#define _list_forall_hook(list, hook) \
- for (hook=&list; *hook!=NULL; hook=&(*hook)->next)
-
-/* same, except only use hook. Note: c may only refer to *hook, not elt. */
-#define _list_find_hook(list, c, hook) \
- MACRO_BEGIN _list_forall_hook(list, hook) if (c) break; MACRO_END
-
-/* insert element after hook */
-#define list_insert_athook(elt, hook) \
- MACRO_BEGIN elt->next = *hook; *hook = elt; MACRO_END
-
-/* insert element before hook */
-#define list_insert_beforehook(elt, hook) \
- MACRO_BEGIN elt->next = *hook; *hook = elt; hook=&elt->next; MACRO_END
-
-/* unlink element after hook, let elt be unlinked element, or NULL.
- hook remains. */
-#define list_unlink_athook(list, elt, hook) \
- MACRO_BEGIN \
- elt = hook ? *hook : NULL; if (elt) { *hook = elt->next; elt->next = NULL; }\
- MACRO_END
-
-/* unlink the specific element, if it is in the list. Otherwise, set
- elt to NULL */
-#define list_unlink(listtype, list, elt) \
- MACRO_BEGIN \
- listtype **_hook; \
- _list_find_hook(list, *_hook==elt, _hook); \
- list_unlink_athook(list, elt, _hook); \
- MACRO_END
-
-/* prepend elt to list */
-#define list_prepend(list, elt) \
- MACRO_BEGIN elt->next = list; list = elt; MACRO_END
-
-/* append elt to list. */
-#define list_append(listtype, list, elt) \
- MACRO_BEGIN \
- listtype **_hook; \
- _list_forall_hook(list, _hook) {} \
- list_insert_athook(elt, _hook); \
- MACRO_END
-
-/* unlink the first element that satisfies the condition. */
-#define list_unlink_cond(listtype, list, elt, c) \
- MACRO_BEGIN \
- listtype **_hook; \
- list_find2(elt, list, c, _hook); \
- list_unlink_athook(list, elt, _hook); \
- MACRO_END
-
-/* let elt be the nth element of the list, starting to count from 0.
- Return NULL if out of bounds. */
-#define list_nth(elt, list, n) \
- MACRO_BEGIN \
- int _x; /* only evaluate n once */ \
- for (_x=(n), elt=list; _x && elt; _x--, elt=elt->next) {} \
- MACRO_END
-
-/* let elt be the nth element of the list, starting to count from 0.
- Return NULL if out of bounds. */
-#define list_nth_hook(elt, list, n, hook) \
- MACRO_BEGIN \
- int _x; /* only evaluate n once */ \
- for (_x=(n), elt=list, hook=&list; _x && elt; _x--, hook=&elt->next, elt=elt->next) {} \
- MACRO_END
-
-/* set n to the length of the list */
-#define list_length(listtype, list, n) \
- MACRO_BEGIN \
- listtype *_elt; \
- n=0; \
- list_forall(_elt, list) \
- n++; \
- MACRO_END
-
-/* set n to the index of the first element satisfying cond, or -1 if
- none found. Also set elt to the element, or NULL if none found. */
-#define list_index(list, n, elt, c) \
- MACRO_BEGIN \
- n=0; \
- list_forall(elt, list) { \
- if (c) break; \
- n++; \
- } \
- if (!elt) \
- n=-1; \
- MACRO_END
-
-/* set n to the number of elements in the list that satisfy condition c */
-#define list_count(list, n, elt, c) \
- MACRO_BEGIN \
- n=0; \
- list_forall(elt, list) { \
- if (c) n++; \
- } \
- MACRO_END
-
-/* let elt be each element of the list, unlinked. At the end, set list=NULL. */
-#define list_forall_unlink(elt, list) \
- for (elt=list; elt ? (list=elt->next, elt->next=NULL), 1 : 0; elt=list)
-
-/* reverse a list (efficient) */
-#define list_reverse(listtype, list) \
- MACRO_BEGIN \
- listtype *_list1=NULL, *elt; \
- list_forall_unlink(elt, list) \
- list_prepend(_list1, elt); \
- list = _list1; \
- MACRO_END
-
-/* insert the element ELT just before the first element TMP of the
- list for which COND holds. Here COND must be a condition of ELT and
- TMP. Typical usage is to insert an element into an ordered list:
- for instance, list_insert_ordered(listtype, list, elt, tmp,
- elt->size <= tmp->size). Note: if we give a "less than or equal"
- condition, the new element will be inserted just before a sequence
- of equal elements. If we give a "less than" condition, the new
- element will be inserted just after a list of equal elements.
- Note: it is much more efficient to construct a list with
- list_prepend and then order it with list_merge_sort, than to
- construct it with list_insert_ordered. */
-#define list_insert_ordered(listtype, list, elt, tmp, cond) \
- MACRO_BEGIN \
- listtype **_hook; \
- _list_find_hook(list, (tmp=*_hook, (cond)), _hook); \
- list_insert_athook(elt, _hook); \
- MACRO_END
-
-/* sort the given list, according to the comparison condition.
- Typical usage is list_sort(listtype, list, a, b, a->size <
- b->size). Note: if we give "less than or equal" condition, each
- segment of equal elements will be reversed in order. If we give a
- "less than" condition, each segment of equal elements will retain
- the original order. The latter is slower but sometimes
- prettier. Average running time: n*n/2. */
-#define list_sort(listtype, list, a, b, cond) \
- MACRO_BEGIN \
- listtype *_newlist=NULL; \
- list_forall_unlink(a, list) \
- list_insert_ordered(listtype, _newlist, a, b, cond); \
- list = _newlist; \
- MACRO_END
-
-/* a much faster sort algorithm (merge sort, n log n worst case). It
- is required that the list type has an additional, unused next1
- component. Note there is no curious reversal of order of equal
- elements as for list_sort. */
-
-#define list_mergesort(listtype, list, a, b, cond) \
- MACRO_BEGIN \
- listtype *_elt, **_hook1; \
- \
- for (_elt=list; _elt; _elt=_elt->next1) { \
- _elt->next1 = _elt->next; \
- _elt->next = NULL; \
- } \
- do { \
- _hook1 = &(list); \
- while ((a = *_hook1) != NULL && (b = a->next1) != NULL ) { \
- _elt = b->next1; \
- _list_merge_cond(listtype, a, b, cond, *_hook1); \
- _hook1 = &((*_hook1)->next1); \
- *_hook1 = _elt; \
- } \
- } while (_hook1 != &(list)); \
- MACRO_END
-
-/* merge two sorted lists. Store result at &result */
-#define _list_merge_cond(listtype, a, b, cond, result) \
- MACRO_BEGIN \
- listtype **_hook; \
- _hook = &(result); \
- while (1) { \
- if (a==NULL) { \
- *_hook = b; \
- break; \
- } else if (b==NULL) { \
- *_hook = a; \
- break; \
- } else if (cond) { \
- *_hook = a; \
- _hook = &(a->next); \
- a = a->next; \
- } else { \
- *_hook = b; \
- _hook = &(b->next); \
- b = b->next; \
- } \
- } \
- MACRO_END
-
-/* ---------------------------------------------------------------------- */
-/* macros for doubly-linked lists */
-
-#define dlist_append(head, end, elt) \
- MACRO_BEGIN \
- elt->prev = end; \
- elt->next = NULL; \
- if (end) { \
- end->next = elt; \
- } else { \
- head = elt; \
- } \
- end = elt; \
- MACRO_END
-
-/* let elt be each element of the list, unlinked. At the end, set list=NULL. */
-#define dlist_forall_unlink(elt, head, end) \
- for (elt=head; elt ? (head=elt->next, elt->next=NULL, elt->prev=NULL), 1 : (end=NULL, 0); elt=head)
-
-/* unlink the first element of the list */
-#define dlist_unlink_first(head, end, elt) \
- MACRO_BEGIN \
- elt = head; \
- if (head) { \
- head = head->next; \
- if (head) { \
- head->prev = NULL; \
- } else { \
- end = NULL; \
- } \
- elt->prev = NULL; \
- elt->next = NULL; \
- } \
- MACRO_END
-
-#endif /* _PS_LISTS_H */
-
diff --git a/src/trace/potrace/potracelib.cpp b/src/trace/potrace/potracelib.cpp
deleted file mode 100644
index b5463d676..000000000
--- a/src/trace/potrace/potracelib.cpp
+++ /dev/null
@@ -1,128 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-#include <stdlib.h>
-#include <string.h>
-#include <glib.h>
-
-#include "potracelib.h"
-#include "inkscape-version.h"
-#include "curve.h"
-#include "decompose.h"
-#include "trace.h"
-#include "progress.h"
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-/* default parameters */
-static const potrace_param_t param_default = {
- 2, /* turdsize */
- POTRACE_TURNPOLICY_MINORITY, /* turnpolicy */
- 1.0, /* alphamax */
- 1, /* opticurve */
- 0.2, /* opttolerance */
- {
- NULL, /* callback function */
- NULL, /* callback data */
- 0.0, 1.0, /* progress range */
- 0.0, /* granularity */
- },
-};
-
-/* Return a fresh copy of the set of default parameters, or NULL on
- failure with errno set. */
-potrace_param_t *potrace_param_default(void) {
- potrace_param_t *p;
-
- p = (potrace_param_t *) malloc(sizeof(potrace_param_t));
- if (!p) {
- return NULL;
- }
- memcpy(p, &param_default, sizeof(potrace_param_t));
- return p;
-}
-
-/* On success, returns a Potrace state st with st->status ==
- POTRACE_STATUS_OK. On failure, returns NULL if no Potrace state
- could be created (with errno set), or returns an incomplete Potrace
- state (with st->status == POTRACE_STATUS_INCOMPLETE, and with errno
- set). Complete or incomplete Potrace state can be freed with
- potrace_state_free(). */
-potrace_state_t *potrace_trace(const potrace_param_t *param, const potrace_bitmap_t *bm) {
- int r;
- path_t *plist = NULL;
- potrace_state_t *st;
- progress_t prog;
- progress_t subprog;
-
- /* prepare private progress bar state */
- prog.callback = param->progress.callback;
- prog.data = param->progress.data;
- prog.min = param->progress.min;
- prog.max = param->progress.max;
- prog.epsilon = param->progress.epsilon;
- prog.d_prev = param->progress.min;
-
- /* allocate state object */
- st = (potrace_state_t *)malloc(sizeof(potrace_state_t));
- if (!st) {
- return NULL;
- }
-
- progress_subrange_start(0.0, 0.1, &prog, &subprog);
-
- /* process the image */
- r = bm_to_pathlist(bm, &plist, param, &subprog);
- if (r) {
- free(st);
- return NULL;
- }
-
- st->status = POTRACE_STATUS_OK;
- st->plist = plist;
- st->priv = NULL; /* private state currently unused */
-
- progress_subrange_end(&prog, &subprog);
-
- progress_subrange_start(0.1, 1.0, &prog, &subprog);
-
- /* partial success. */
- r = process_path(plist, param, &subprog);
- if (r) {
- st->status = POTRACE_STATUS_INCOMPLETE;
- }
-
- progress_subrange_end(&prog, &subprog);
-
- return st;
-}
-
-/* free a Potrace state, without disturbing errno. */
-void potrace_state_free(potrace_state_t *st) {
- pathlist_free(st->plist);
- free(st);
-}
-
-/* free a parameter list, without disturbing errno. */
-void potrace_param_free(potrace_param_t *p) {
- free(p);
-}
-
-char *potrace_version(void) {
- static char *ver = g_strdup_printf("potracelib %s", Inkscape::version_string);
- return ver;
-}
-
-/*
- 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/trace/potrace/potracelib.h b/src/trace/potrace/potracelib.h
deleted file mode 100644
index 0a6ddbf1f..000000000
--- a/src/trace/potrace/potracelib.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-#ifndef POTRACELIB_H
-#define POTRACELIB_H
-
-/* this file defines the API for the core Potrace library. For a more
- detailed description of the API, see potracelib.pdf */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* ---------------------------------------------------------------------- */
-/* tracing parameters */
-
-/* turn policies */
-#define POTRACE_TURNPOLICY_BLACK 0
-#define POTRACE_TURNPOLICY_WHITE 1
-#define POTRACE_TURNPOLICY_LEFT 2
-#define POTRACE_TURNPOLICY_RIGHT 3
-#define POTRACE_TURNPOLICY_MINORITY 4
-#define POTRACE_TURNPOLICY_MAJORITY 5
-#define POTRACE_TURNPOLICY_RANDOM 6
-
-/* structure to hold progress bar callback data */
-struct potrace_progress_s {
- void (*callback)(double progress, void *privdata); /* callback fn */
- void *data; /* callback function's private data */
- double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */
- double epsilon; /* granularity: can skip smaller increments */
-};
-typedef struct potrace_progress_s potrace_progress_t;
-
-/* structure to hold tracing parameters */
-struct potrace_param_s {
- int turdsize; /* area of largest path to be ignored */
- int turnpolicy; /* resolves ambiguous turns in path decomposition */
- double alphamax; /* corner threshold */
- int opticurve; /* use curve optimization? */
- double opttolerance; /* curve optimization tolerance */
- potrace_progress_t progress; /* progress callback function */
-};
-typedef struct potrace_param_s potrace_param_t;
-
-/* ---------------------------------------------------------------------- */
-/* bitmaps */
-
-/* native word size */
-typedef unsigned long potrace_word;
-
-/* Internal bitmap format. The n-th scanline starts at scanline(n) =
- (map + n*dy). Raster data is stored as a sequence of potrace_words
- (NOT bytes). The leftmost bit of scanline n is the most significant
- bit of scanline(n)[0]. */
-struct potrace_bitmap_s {
- int w, h; /* width and height, in pixels */
- int dy; /* words per scanline (not bytes) */
- potrace_word *map; /* raw data, dy*h words */
-};
-typedef struct potrace_bitmap_s potrace_bitmap_t;
-
-/* ---------------------------------------------------------------------- */
-/* curves */
-
-/* point */
-struct potrace_dpoint_s {
- double x, y;
-};
-typedef struct potrace_dpoint_s potrace_dpoint_t;
-
-/* segment tags */
-#define POTRACE_CURVETO 1
-#define POTRACE_CORNER 2
-
-/* closed curve segment */
-struct potrace_curve_s {
- int n; /* number of segments */
- int *tag; /* tag[n]: POTRACE_CURVETO or POTRACE_CORNER */
- potrace_dpoint_t (*c)[3]; /* c[n][3]: control points.
- c[n][0] is unused for tag[n]=POTRACE_CORNER */
-};
-typedef struct potrace_curve_s potrace_curve_t;
-
-/* Linked list of signed curve segments. Also carries a tree structure. */
-struct potrace_path_s {
- int area; /* area of the bitmap path */
- int sign; /* '+' or '-', depending on orientation */
- potrace_curve_t curve; /* this path's vector data */
-
- struct potrace_path_s *next; /* linked list structure */
-
- struct potrace_path_s *childlist; /* tree structure */
- struct potrace_path_s *sibling; /* tree structure */
-
- struct potrace_privpath_s *priv; /* private state */
-};
-typedef struct potrace_path_s potrace_path_t;
-
-/* ---------------------------------------------------------------------- */
-/* Potrace state */
-
-#define POTRACE_STATUS_OK 0
-#define POTRACE_STATUS_INCOMPLETE 1
-
-struct potrace_state_s {
- int status;
- potrace_path_t *plist; /* vector data */
-
- struct potrace_privstate_s *priv; /* private state */
-};
-typedef struct potrace_state_s potrace_state_t;
-
-/* ---------------------------------------------------------------------- */
-/* API functions */
-
-/* get default parameters */
-potrace_param_t *potrace_param_default(void);
-
-/* free parameter set */
-void potrace_param_free(potrace_param_t *p);
-
-/* trace a bitmap*/
-potrace_state_t *potrace_trace(const potrace_param_t *param,
- const potrace_bitmap_t *bm);
-
-/* free a Potrace state */
-void potrace_state_free(potrace_state_t *st);
-
-/* return a static plain text version string identifying this version
- of potracelib */
-char *potrace_version(void);
-
-#ifdef __cplusplus
-} /* end of extern "C" */
-#endif
-
-#endif /* POTRACELIB_H */
diff --git a/src/trace/potrace/progress.h b/src/trace/potrace/progress.h
deleted file mode 100644
index ecc2ba217..000000000
--- a/src/trace/potrace/progress.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-/* operations on potrace_progress_t objects, which are defined in
- potracelib.h. Note: the code attempts to minimize runtime overhead
- when no progress monitoring was requested. It also tries to
- minimize excessive progress calculations beneath the "epsilon"
- threshold. */
-
-#ifndef PROGRESS_H
-#define PROGRESS_H
-
-/* structure to hold progress bar callback data */
-struct progress_s {
- void (*callback)(double progress, void *privdata); /* callback fn */
- void *data; /* callback function's private data */
- double min, max; /* desired range of progress, e.g. 0.0 to 1.0 */
- double epsilon; /* granularity: can skip smaller increments */
- double b; /* upper limit of subrange in superrange units */
- double d_prev; /* previous value of d */
-};
-typedef struct progress_s progress_t;
-
-/* notify given progress object of current progress. Note that d is
- given in the 0.0-1.0 range, which will be scaled and translated to
- the progress object's range. */
-static inline void progress_update(double d, progress_t *prog) {
- if (prog != NULL && prog->callback != NULL) {
- double d_scaled = prog->min * (1-d) + prog->max * d;
- if (d == 1.0 || d_scaled >= prog->d_prev + prog->epsilon) {
- prog->callback(prog->min * (1-d) + prog->max * d, prog->data);
- prog->d_prev = d_scaled;
- }
- }
-}
-
-/* start a subrange of the given progress object. The range is
- narrowed to [a..b], relative to 0.0-1.0 coordinates. If new range
- is below granularity threshold, disable further subdivisions. */
-static inline void progress_subrange_start(double a, double b, const progress_t *prog, progress_t *sub) {
- double min, max;
-
- if (prog == NULL || prog->callback == NULL) {
- sub->callback = NULL;
- return;
- }
-
- min = prog->min * (1-a) + prog->max * a;
- max = prog->min * (1-b) + prog->max * b;
-
- if (max - min < prog->epsilon) {
- sub->callback = NULL; /* no further progress info in subrange */
- sub->b = b;
- return;
- }
- sub->callback = prog->callback;
- sub->data = prog->data;
- sub->epsilon = prog->epsilon;
- sub->min = min;
- sub->max = max;
- sub->d_prev = prog->d_prev;
- return;
-}
-
-static inline void progress_subrange_end(progress_t *prog, progress_t *sub) {
- if (prog != NULL && prog->callback != NULL) {
- if (sub->callback == NULL) {
- progress_update(sub->b, prog);
- } else {
- prog->d_prev = sub->d_prev;
- }
- }
-}
-
-#endif /* PROGRESS_H */
-
diff --git a/src/trace/potrace/render.cpp b/src/trace/potrace/render.cpp
deleted file mode 100644
index 4f44ae6a6..000000000
--- a/src/trace/potrace/render.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <math.h>
-#include <string.h>
-
-#include "render.h"
-#include "greymap.h"
-#include "auxiliary.h"
-
-/* ---------------------------------------------------------------------- */
-/* routines for anti-aliased rendering of curves */
-
-/* we use the following method. Given a point (x,y) (with real-valued
- coordinates) in the plane, let (xi,yi) be the integer part of the
- coordinates, i.e., xi=floor(x), yi=floor(y). Define a path from
- (x,y) to infinity as follows: path(x,y) =
- (x,y)--(xi+1,y)--(xi+1,yi)--(+infty,yi). Now as the point (x,y)
- moves smoothly across the plane, the path path(x,y) sweeps
- (non-smoothly) across a certain area. We proportionately blacken
- the area as the path moves "downward", and we whiten the area as
- the path moves "upward". This way, after the point has traversed a
- closed curve, the interior of the curve has been darkened
- (counterclockwise movement) or lightened (clockwise movement). (The
- "grey shift" is actually proportional to the winding number). By
- choosing the above path with mostly integer coordinates, we achieve
- that only pixels close to (x,y) receive grey values and are subject
- to round-off errors. The grey value of pixels far away from (x,y)
- is always in "integer" (where 0=black, 1=white). As a special
- trick, we keep an accumulator rm->a1, which holds a double value to
- be added to the grey value to be added to the current pixel
- (xi,yi). Only when changing "current" pixels, we convert this
- double value to an integer. This way we avoid round-off errors at
- the meeting points of line segments. Another speedup measure is
- that we sometimes use the rm->incrow_buf array to postpone
- incrementing or decrementing an entire row. If incrow_buf[y]=x+1!=0,
- then all the pixels (x,y),(x+1,y),(x+2,y),... are scheduled to be
- incremented/decremented (which one is the case will be clear from
- context). This keeps the greymap operations reasonably local. */
-
-/* allocate a new rendering state */
-render_t *render_new(greymap_t *gm) {
- render_t *rm;
-
- rm = (render_t *) malloc(sizeof(render_t));
- if (!rm) {
- return NULL;
- }
- memset(rm, 0, sizeof(render_t));
- rm->gm = gm;
- rm->incrow_buf = (int *) calloc(gm->h, sizeof(int));
- if (!rm->incrow_buf) {
- free(rm);
- return NULL;
- }
- memset(rm->incrow_buf, 0, gm->h * sizeof(int));
- return rm;
-}
-
-/* free a given rendering state. Note: this does not free the
- underlying greymap. */
-void render_free(render_t *rm) {
- free(rm->incrow_buf);
- free(rm);
-}
-
-/* close path */
-void render_close(render_t *rm) {
- if (rm->x0 != rm->x1 || rm->y0 != rm->y1) {
- render_lineto(rm, rm->x0, rm->y0);
- }
- GM_INC(rm->gm, rm->x0i, rm->y0i, (rm->a0+rm->a1)*255);
-
- /* assert (rm->x0i != rm->x1i || rm->y0i != rm->y1i); */
-
- /* the persistent state is now undefined */
-}
-
-/* move point */
-void render_moveto(render_t *rm, double x, double y) {
- /* close the previous path */
- render_close(rm);
-
- rm->x0 = rm->x1 = x;
- rm->y0 = rm->y1 = y;
- rm->x0i = (int)floor(rm->x0);
- rm->x1i = (int)floor(rm->x1);
- rm->y0i = (int)floor(rm->y0);
- rm->y1i = (int)floor(rm->y1);
- rm->a0 = rm->a1 = 0;
-}
-
-/* add b to pixels (x,y) and all pixels to the right of it. However,
- use rm->incrow_buf as a buffer to economize on multiple calls */
-static void incrow(render_t *rm, int x, int y, int b) {
- int i, x0;
-
- if (y < 0 || y >= rm->gm->h) {
- return;
- }
-
- if (x < 0) {
- x = 0;
- } else if (x > rm->gm->w) {
- x = rm->gm->w;
- }
- if (rm->incrow_buf[y] == 0) {
- rm->incrow_buf[y] = x+1; /* store x+1 so that we can use 0 for "vacant" */
- return;
- }
- x0 = rm->incrow_buf[y]-1;
- rm->incrow_buf[y] = 0;
- if (x0 < x) {
- for (i=x0; i<x; i++) {
- GM_INC(rm->gm, i, y, -b);
- }
- } else {
- for (i=x; i<x0; i++) {
- GM_INC(rm->gm, i, y, b);
- }
- }
-}
-
-/* render a straight line */
-void render_lineto(render_t *rm, double x2, double y2) {
- int x2i, y2i;
- double t0=2, s0=2;
- int sn, tn;
- double ss=2, ts=2;
- double r0, r1;
- int i, j;
- int rxi, ryi;
- int s;
-
- x2i = (int)floor(x2);
- y2i = (int)floor(y2);
-
- sn = abs(x2i - rm->x1i);
- tn = abs(y2i - rm->y1i);
-
- if (sn) {
- s0 = ((x2>rm->x1 ? rm->x1i+1 : rm->x1i) - rm->x1)/(x2-rm->x1);
- ss = fabs(1.0/(x2-rm->x1));
- }
- if (tn) {
- t0 = ((y2>rm->y1 ? rm->y1i+1 : rm->y1i) - rm->y1)/(y2-rm->y1);
- ts = fabs(1.0/(y2-rm->y1));
- }
-
- r0 = 0;
-
- i = 0;
- j = 0;
-
- rxi = rm->x1i;
- ryi = rm->y1i;
-
- while (i<sn || j<tn) {
- if (j>=tn || (i<sn && s0+i*ss < t0+j*ts)) {
- r1 = s0+i*ss;
- i++;
- s = 1;
- } else {
- r1 = t0+j*ts;
- j++;
- s = 0;
- }
- /* render line from r0 to r1 segment of (rm->x1,rm->y1)..(x2,y2) */
-
- /* move point to r1 */
- rm->a1 += (r1-r0)*(y2-rm->y1)*(rxi+1-((r0+r1)/2.0*(x2-rm->x1)+rm->x1));
-
- /* move point across pixel boundary */
- if (s && x2>rm->x1) {
- GM_INC(rm->gm, rxi, ryi, rm->a1*255);
- rm->a1 = 0;
- rxi++;
- rm->a1 += rm->y1+r1*(y2-rm->y1)-ryi;
- } else if (!s && y2>rm->y1) {
- GM_INC(rm->gm, rxi, ryi, rm->a1*255);
- rm->a1 = 0;
- incrow(rm, rxi+1, ryi, 255);
- ryi++;
- } else if (s && x2<=rm->x1) {
- rm->a1 -= rm->y1+r1*(y2-rm->y1)-ryi;
- GM_INC(rm->gm, rxi, ryi, rm->a1*255);
- rm->a1 = 0;
- rxi--;
- } else if (!s && y2<=rm->y1) {
- GM_INC(rm->gm, rxi, ryi, rm->a1*255);
- rm->a1 = 0;
- ryi--;
- incrow(rm, rxi+1, ryi, -255);
- }
-
- r0 = r1;
- }
-
- /* move point to (x2,y2) */
-
- r1 = 1;
- rm->a1 += (r1-r0)*(y2-rm->y1)*(rxi+1-((r0+r1)/2.0*(x2-rm->x1)+rm->x1));
-
- rm->x1i = x2i;
- rm->y1i = y2i;
- rm->x1 = x2;
- rm->y1 = y2;
-
- /* assert (rxi != rm->x1i || ryi != rm->y1i); */
-}
-
-/* render a Bezier curve. */
-void render_curveto(render_t *rm, double x2, double y2, double x3, double y3, double x4, double y4) {
- double x1, y1, dd0, dd1, dd, delta, e2, epsilon, t;
-
- x1 = rm->x1; /* starting point */
- y1 = rm->y1;
-
- /* we approximate the curve by small line segments. The interval
- size, epsilon, is determined on the fly so that the distance
- between the true curve and its approximation does not exceed the
- desired accuracy delta. */
-
- delta = .1; /* desired accuracy, in pixels */
-
- /* let dd = maximal value of 2nd derivative over curve - this must
- occur at an endpoint. */
- dd0 = sq(x1-2*x2+x3) + sq(y1-2*y2+y3);
- dd1 = sq(x2-2*x3+x4) + sq(y2-2*y3+y4);
- dd = 6*sqrt(max(dd0, dd1));
- e2 = 8*delta <= dd ? 8*delta/dd : 1;
- epsilon = sqrt(e2); /* necessary interval size */
-
- for (t=epsilon; t<1; t+=epsilon) {
- render_lineto(rm, x1*cu(1-t)+3*x2*sq(1-t)*t+3*x3*(1-t)*sq(t)+x4*cu(t),
- y1*cu(1-t)+3*y2*sq(1-t)*t+3*y3*(1-t)*sq(t)+y4*cu(t));
- }
- render_lineto(rm, x4, y4);
-}
diff --git a/src/trace/potrace/render.h b/src/trace/potrace/render.h
deleted file mode 100644
index 0caaedff6..000000000
--- a/src/trace/potrace/render.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-
-#ifndef RENDER_H
-#define RENDER_H
-
-#include "greymap.h"
-
-struct render_s {
- greymap_t *gm;
- double x0, y0, x1, y1;
- int x0i, y0i, x1i, y1i;
- double a0, a1;
- int *incrow_buf;
-};
-typedef struct render_s render_t;
-
-render_t *render_new(greymap_t *gm);
-void render_free(render_t *rm);
-void render_close(render_t *rm);
-void render_moveto(render_t *rm, double x, double y);
-void render_lineto(render_t *rm, double x, double y);
-void render_curveto(render_t *rm, double x2, double y2, double x3, double y3, double x4, double y4);
-
-#endif /* RENDER_H */
diff --git a/src/trace/potrace/trace.cpp b/src/trace/potrace/trace.cpp
deleted file mode 100644
index 469262b67..000000000
--- a/src/trace/potrace/trace.cpp
+++ /dev/null
@@ -1,1245 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-/* transform jaggy paths into smooth curves */
-
-#include <stdio.h>
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "potracelib.h"
-#include "curve.h"
-#include "lists.h"
-#include "auxiliary.h"
-#include "trace.h"
-#include "progress.h"
-
-#define INFTY 10000000 /* it suffices that this is longer than any
- path; it need not be really infinite */
-#define COS179 -0.999847695156 /* the cosine of 179 degrees */
-
-/* ---------------------------------------------------------------------- */
-#define SAFE_CALLOC(var, n, typ) \
- if ((var = (typ *)calloc(n, sizeof(typ))) == NULL) goto calloc_error
-
-/* ---------------------------------------------------------------------- */
-/* auxiliary functions */
-
-/* return a direction that is 90 degrees counterclockwise from p2-p0,
- but then restricted to one of the major wind directions (n, nw, w, etc) */
-static inline point_t dorth_infty(dpoint_t p0, dpoint_t p2) {
- point_t r;
-
- r.y = sign(p2.x-p0.x);
- r.x = -sign(p2.y-p0.y);
-
- return r;
-}
-
-/* return (p1-p0)x(p2-p0), the area of the parallelogram */
-static inline double dpara(dpoint_t p0, dpoint_t p1, dpoint_t p2) {
- double x1, y1, x2, y2;
-
- x1 = p1.x-p0.x;
- y1 = p1.y-p0.y;
- x2 = p2.x-p0.x;
- y2 = p2.y-p0.y;
-
- return x1*y2 - x2*y1;
-}
-
-/* ddenom/dpara have the property that the square of radius 1 centered
- at p1 intersects the line p0p2 iff |dpara(p0,p1,p2)| <= ddenom(p0,p2) */
-static inline double ddenom(dpoint_t p0, dpoint_t p2) {
- point_t r = dorth_infty(p0, p2);
-
- return r.y*(p2.x-p0.x) - r.x*(p2.y-p0.y);
-}
-
-/* return 1 if a <= b < c < a, in a cyclic sense (mod n) */
-static inline int cyclic(int a, int b, int c) {
- if (a<=c) {
- return (a<=b && b<c);
- } else {
- return (a<=b || b<c);
- }
-}
-
-/* determine the center and slope of the line i..j. Assume i<j. Needs
- "sum" components of p to be set. */
-static void pointslope(privpath_t *pp, int i, int j, dpoint_t *ctr, dpoint_t *dir) {
- /* assume i<j */
-
- int n = pp->len;
- sums_t *sums = pp->sums;
-
- double x, y, x2, xy, y2;
- double k;
- double a, b, c, lambda2, l;
- int r=0; /* rotations from i to j */
-
- while (j>=n) {
- j-=n;
- r+=1;
- }
- while (i>=n) {
- i-=n;
- r-=1;
- }
- while (j<0) {
- j+=n;
- r-=1;
- }
- while (i<0) {
- i+=n;
- r+=1;
- }
-
- x = sums[j+1].x-sums[i].x+r*sums[n].x;
- y = sums[j+1].y-sums[i].y+r*sums[n].y;
- x2 = sums[j+1].x2-sums[i].x2+r*sums[n].x2;
- xy = sums[j+1].xy-sums[i].xy+r*sums[n].xy;
- y2 = sums[j+1].y2-sums[i].y2+r*sums[n].y2;
- k = j+1-i+r*n;
-
- ctr->x = x/k;
- ctr->y = y/k;
-
- a = (x2-(double)x*x/k)/k;
- b = (xy-(double)x*y/k)/k;
- c = (y2-(double)y*y/k)/k;
-
- lambda2 = (a+c+sqrt((a-c)*(a-c)+4*b*b))/2; /* larger e.value */
-
- /* now find e.vector for lambda2 */
- a -= lambda2;
- c -= lambda2;
-
- if (fabs(a) >= fabs(c)) {
- l = sqrt(a*a+b*b);
- if (l!=0) {
- dir->x = -b/l;
- dir->y = a/l;
- }
- } else {
- l = sqrt(c*c+b*b);
- if (l!=0) {
- dir->x = -c/l;
- dir->y = b/l;
- }
- }
- if (l==0) {
- dir->x = dir->y = 0; /* sometimes this can happen when k=4:
- the two eigenvalues coincide */
- }
-}
-
-/* the type of (affine) quadratic forms, represented as symmetric 3x3
- matrices. The value of the quadratic form at a vector (x,y) is v^t
- Q v, where v = (x,y,1)^t. */
-typedef double quadform_t[3][3];
-
-/* Apply quadratic form Q to vector w = (w.x,w.y) */
-static inline double quadform(quadform_t Q, dpoint_t w) {
- double v[3];
- int i, j;
- double sum;
-
- v[0] = w.x;
- v[1] = w.y;
- v[2] = 1;
- sum = 0.0;
-
- for (i=0; i<3; i++) {
- for (j=0; j<3; j++) {
- sum += v[i] * Q[i][j] * v[j];
- }
- }
- return sum;
-}
-
-/* calculate p1 x p2 */
-static inline int xprod(point_t p1, point_t p2) {
- return p1.x*p2.y - p1.y*p2.x;
-}
-
-/* calculate (p1-p0)x(p3-p2) */
-static inline double cprod(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) {
- double x1, y1, x2, y2;
-
- x1 = p1.x - p0.x;
- y1 = p1.y - p0.y;
- x2 = p3.x - p2.x;
- y2 = p3.y - p2.y;
-
- return x1*y2 - x2*y1;
-}
-
-/* calculate (p1-p0)*(p2-p0) */
-static inline double iprod(dpoint_t p0, dpoint_t p1, dpoint_t p2) {
- double x1, y1, x2, y2;
-
- x1 = p1.x - p0.x;
- y1 = p1.y - p0.y;
- x2 = p2.x - p0.x;
- y2 = p2.y - p0.y;
-
- return x1*x2 + y1*y2;
-}
-
-/* calculate (p1-p0)*(p3-p2) */
-static inline double iprod1(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) {
- double x1, y1, x2, y2;
-
- x1 = p1.x - p0.x;
- y1 = p1.y - p0.y;
- x2 = p3.x - p2.x;
- y2 = p3.y - p2.y;
-
- return x1*x2 + y1*y2;
-}
-
-/* calculate distance between two points */
-static inline double ddist(dpoint_t p, dpoint_t q) {
- return sqrt(sq(p.x-q.x)+sq(p.y-q.y));
-}
-
-/* calculate point of a bezier curve */
-static inline dpoint_t bezier(double t, dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3) {
- double s = 1-t;
- dpoint_t res;
-
- /* Note: a good optimizing compiler (such as gcc-3) reduces the
- following to 16 multiplications, using common subexpression
- elimination. */
-
- res.x = s*s*s*p0.x + 3*(s*s*t)*p1.x + 3*(t*t*s)*p2.x + t*t*t*p3.x;
- res.y = s*s*s*p0.y + 3*(s*s*t)*p1.y + 3*(t*t*s)*p2.y + t*t*t*p3.y;
-
- return res;
-}
-
-/* calculate the point t in [0..1] on the (convex) bezier curve
- (p0,p1,p2,p3) which is tangent to q1-q0. Return -1.0 if there is no
- solution in [0..1]. */
-static double tangent(dpoint_t p0, dpoint_t p1, dpoint_t p2, dpoint_t p3, dpoint_t q0, dpoint_t q1) {
- double A, B, C; /* (1-t)^2 A + 2(1-t)t B + t^2 C = 0 */
- double a, b, c; /* a t^2 + b t + c = 0 */
- double d, s, r1, r2;
-
- A = cprod(p0, p1, q0, q1);
- B = cprod(p1, p2, q0, q1);
- C = cprod(p2, p3, q0, q1);
-
- a = A - 2*B + C;
- b = -2*A + 2*B;
- c = A;
-
- d = b*b - 4*a*c;
-
- if (a==0 || d<0) {
- return -1.0;
- }
-
- s = sqrt(d);
-
- r1 = (-b + s) / (2 * a);
- r2 = (-b - s) / (2 * a);
-
- if (r1 >= 0 && r1 <= 1) {
- return r1;
- } else if (r2 >= 0 && r2 <= 1) {
- return r2;
- } else {
- return -1.0;
- }
-}
-
-/* ---------------------------------------------------------------------- */
-/* Preparation: fill in the sum* fields of a path (used for later
- rapid summing). Return 0 on success, 1 with errno set on
- failure. */
-static int calc_sums(privpath_t *pp) {
- int i, x, y;
- int n = pp->len;
-
- SAFE_CALLOC(pp->sums, pp->len+1, sums_t);
-
- /* origin */
- pp->x0 = pp->pt[0].x;
- pp->y0 = pp->pt[0].y;
-
- /* preparatory computation for later fast summing */
- pp->sums[0].x2 = pp->sums[0].xy = pp->sums[0].y2 = pp->sums[0].x = pp->sums[0].y = 0;
- for (i=0; i<n; i++) {
- x = pp->pt[i].x - pp->x0;
- y = pp->pt[i].y - pp->y0;
- pp->sums[i+1].x = pp->sums[i].x + x;
- pp->sums[i+1].y = pp->sums[i].y + y;
- pp->sums[i+1].x2 = pp->sums[i].x2 + x*x;
- pp->sums[i+1].xy = pp->sums[i].xy + x*y;
- pp->sums[i+1].y2 = pp->sums[i].y2 + y*y;
- }
- return 0;
-
- calloc_error:
- return 1;
-}
-
-/* ---------------------------------------------------------------------- */
-/* Stage 1: determine the straight subpaths (Sec. 2.2.1). Fill in the
- "lon" component of a path object (based on pt/len). For each i,
- lon[i] is the furthest index such that a straight line can be drawn
- from i to lon[i]. Return 1 on error with errno set, else 0. */
-
-/* this algorithm depends on the fact that the existence of straight
- subpaths is a triplewise property. I.e., there exists a straight
- line through squares i0,...,in iff there exists a straight line
- through i,j,k, for all i0<=i<j<k<=in. (Proof?) */
-
-/* this implementation of calc_lon is O(n^2). It replaces an older
- O(n^3) version. A "constraint" means that future points must
- satisfy xprod(constraint[0], cur) >= 0 and xprod(constraint[1],
- cur) <= 0. */
-
-/* Remark for Potrace 1.1: the current implementation of calc_lon is
- more complex than the implementation found in Potrace 1.0, but it
- is considerably faster. The introduction of the "nc" data structure
- means that we only have to test the constraints for "corner"
- points. On a typical input file, this speeds up the calc_lon
- function by a factor of 31.2, thereby decreasing its time share
- within the overall Potrace algorithm from 72.6% to 7.82%, and
- speeding up the overall algorithm by a factor of 3.36. On another
- input file, calc_lon was sped up by a factor of 6.7, decreasing its
- time share from 51.4% to 13.61%, and speeding up the overall
- algorithm by a factor of 1.78. In any case, the savings are
- substantial. */
-
-/* returns 0 on success, 1 on error with errno set */
-static int calc_lon(privpath_t *pp) {
- point_t *pt = pp->pt;
- int n = pp->len;
- int i, j, k, k1;
- int ct[4], dir;
- point_t constraint[2];
- point_t cur;
- point_t off;
- int *pivk = NULL; /* pivk[n] */
- int *nc = NULL; /* nc[n]: next corner */
- point_t dk; /* direction of k-k1 */
- int a, b, c, d;
-
- SAFE_CALLOC(pivk, n, int);
- SAFE_CALLOC(nc, n, int);
-
- /* initialize the nc data structure. Point from each point to the
- furthest future point to which it is connected by a vertical or
- horizontal segment. We take advantage of the fact that there is
- always a direction change at 0 (due to the path decomposition
- algorithm). But even if this were not so, there is no harm, as
- in practice, correctness does not depend on the word "furthest"
- above. */
- k = 0;
- for (i=n-1; i>=0; i--) {
- if (pt[i].x != pt[k].x && pt[i].y != pt[k].y) {
- k = i+1; /* necessarily i<n-1 in this case */
- }
- nc[i] = k;
- }
-
- SAFE_CALLOC(pp->lon, n, int);
-
- /* determine pivot points: for each i, let pivk[i] be the furthest k
- such that all j with i<j<k lie on a line connecting i,k. */
-
- for (i=n-1; i>=0; i--) {
- ct[0] = ct[1] = ct[2] = ct[3] = 0;
-
- /* keep track of "directions" that have occurred */
- dir = (3+3*(pt[mod(i+1,n)].x-pt[i].x)+(pt[mod(i+1,n)].y-pt[i].y))/2;
- ct[dir]++;
-
- constraint[0].x = 0;
- constraint[0].y = 0;
- constraint[1].x = 0;
- constraint[1].y = 0;
-
- /* find the next k such that no straight line from i to k */
- k = nc[i];
- k1 = i;
- while (1) {
-
- dir = (3+3*sign(pt[k].x-pt[k1].x)+sign(pt[k].y-pt[k1].y))/2;
- ct[dir]++;
-
- /* if all four "directions" have occurred, cut this path */
- if (ct[0] && ct[1] && ct[2] && ct[3]) {
- pivk[i] = k1;
- goto foundk;
- }
-
- cur.x = pt[k].x - pt[i].x;
- cur.y = pt[k].y - pt[i].y;
-
- /* see if current constraint is violated */
- if (xprod(constraint[0], cur) < 0 || xprod(constraint[1], cur) > 0) {
- goto constraint_viol;
- }
-
- /* else, update constraint */
- if (abs(cur.x) <= 1 && abs(cur.y) <= 1) {
- /* no constraint */
- } else {
- off.x = cur.x + ((cur.y>=0 && (cur.y>0 || cur.x<0)) ? 1 : -1);
- off.y = cur.y + ((cur.x<=0 && (cur.x<0 || cur.y<0)) ? 1 : -1);
- if (xprod(constraint[0], off) >= 0) {
- constraint[0] = off;
- }
- off.x = cur.x + ((cur.y<=0 && (cur.y<0 || cur.x<0)) ? 1 : -1);
- off.y = cur.y + ((cur.x>=0 && (cur.x>0 || cur.y<0)) ? 1 : -1);
- if (xprod(constraint[1], off) <= 0) {
- constraint[1] = off;
- }
- }
- k1 = k;
- k = nc[k1];
- if (!cyclic(k,i,k1)) {
- break;
- }
- }
- constraint_viol:
- /* k1 was the last "corner" satisfying the current constraint, and
- k is the first one violating it. We now need to find the last
- point along k1..k which satisfied the constraint. */
- dk.x = sign(pt[k].x-pt[k1].x);
- dk.y = sign(pt[k].y-pt[k1].y);
- cur.x = pt[k1].x - pt[i].x;
- cur.y = pt[k1].y - pt[i].y;
- /* find largest integer j such that xprod(constraint[0], cur+j*dk)
- >= 0 and xprod(constraint[1], cur+j*dk) <= 0. Use bilinearity
- of xprod. */
- a = xprod(constraint[0], cur);
- b = xprod(constraint[0], dk);
- c = xprod(constraint[1], cur);
- d = xprod(constraint[1], dk);
- /* find largest integer j such that a+j*b>=0 and c+j*d<=0. This
- can be solved with integer arithmetic. */
- j = INFTY;
- if (b<0) {
- j = floordiv(a,-b);
- }
- if (d>0) {
- j = min(j, floordiv(-c,d));
- }
- pivk[i] = mod(k1+j,n);
- foundk:
- ;
- } /* for i */
-
- /* clean up: for each i, let lon[i] be the largest k such that for
- all i' with i<=i'<k, i'<k<=pivk[i']. */
-
- j=pivk[n-1];
- pp->lon[n-1]=j;
- for (i=n-2; i>=0; i--) {
- if (cyclic(i+1,pivk[i],j)) {
- j=pivk[i];
- }
- pp->lon[i]=j;
- }
-
- for (i=n-1; cyclic(mod(i+1,n),j,pp->lon[i]); i--) {
- pp->lon[i] = j;
- }
-
- free(pivk);
- free(nc);
- return 0;
-
- calloc_error:
- free(pivk);
- free(nc);
- return 1;
-}
-
-
-/* ---------------------------------------------------------------------- */
-/* Stage 2: calculate the optimal polygon (Sec. 2.2.2-2.2.4). */
-
-/* Auxiliary function: calculate the penalty of an edge from i to j in
- the given path. This needs the "lon" and "sum*" data. */
-
-static double penalty3(privpath_t *pp, int i, int j) {
- int n = pp->len;
- point_t *pt = pp->pt;
- sums_t *sums = pp->sums;
-
- /* assume 0<=i<j<=n */
- double x, y, x2, xy, y2;
- double k;
- double a, b, c, s;
- double px, py, ex, ey;
-
- int r = 0; /* rotations from i to j */
-
- if (j>=n) {
- j -= n;
- r = 1;
- }
-
- /* critical inner loop: the "if" gives a 4.6 percent speedup */
- if (r == 0) {
- x = sums[j+1].x - sums[i].x;
- y = sums[j+1].y - sums[i].y;
- x2 = sums[j+1].x2 - sums[i].x2;
- xy = sums[j+1].xy - sums[i].xy;
- y2 = sums[j+1].y2 - sums[i].y2;
- k = j+1 - i;
- } else {
- x = sums[j+1].x - sums[i].x + sums[n].x;
- y = sums[j+1].y - sums[i].y + sums[n].y;
- x2 = sums[j+1].x2 - sums[i].x2 + sums[n].x2;
- xy = sums[j+1].xy - sums[i].xy + sums[n].xy;
- y2 = sums[j+1].y2 - sums[i].y2 + sums[n].y2;
- k = j+1 - i + n;
- }
-
- px = (pt[i].x + pt[j].x) / 2.0 - pt[0].x;
- py = (pt[i].y + pt[j].y) / 2.0 - pt[0].y;
- ey = (pt[j].x - pt[i].x);
- ex = -(pt[j].y - pt[i].y);
-
- a = ((x2 - 2*x*px) / k + px*px);
- b = ((xy - x*py - y*px) / k + px*py);
- c = ((y2 - 2*y*py) / k + py*py);
-
- s = ex*ex*a + 2*ex*ey*b + ey*ey*c;
-
- return sqrt(s);
-}
-
-/* find the optimal polygon. Fill in the m and po components. Return 1
- on failure with errno set, else 0. Non-cyclic version: assumes i=0
- is in the polygon. Fixme: implement cyclic version. */
-static int bestpolygon(privpath_t *pp)
-{
- int i, j, m, k;
- int n = pp->len;
- double *pen = NULL; /* pen[n+1]: penalty vector */
- int *prev = NULL; /* prev[n+1]: best path pointer vector */
- int *clip0 = NULL; /* clip0[n]: longest segment pointer, non-cyclic */
- int *clip1 = NULL; /* clip1[n+1]: backwards segment pointer, non-cyclic */
- int *seg0 = NULL; /* seg0[m+1]: forward segment bounds, m<=n */
- int *seg1 = NULL; /* seg1[m+1]: backward segment bounds, m<=n */
- double thispen;
- double best;
- int c;
-
- SAFE_CALLOC(pen, n+1, double);
- SAFE_CALLOC(prev, n+1, int);
- SAFE_CALLOC(clip0, n, int);
- SAFE_CALLOC(clip1, n+1, int);
- SAFE_CALLOC(seg0, n+1, int);
- SAFE_CALLOC(seg1, n+1, int);
-
- /* calculate clipped paths */
- for (i=0; i<n; i++) {
- c = mod(pp->lon[mod(i-1,n)]-1,n);
- if (c == i) {
- c = mod(i+1,n);
- }
- if (c < i) {
- clip0[i] = n;
- } else {
- clip0[i] = c;
- }
- }
-
- /* calculate backwards path clipping, non-cyclic. j <= clip0[i] iff
- clip1[j] <= i, for i,j=0..n. */
- j = 1;
- for (i=0; i<n; i++) {
- while (j <= clip0[i]) {
- clip1[j] = i;
- j++;
- }
- }
-
- /* calculate seg0[j] = longest path from 0 with j segments */
- i = 0;
- for (j=0; i<n; j++) {
- seg0[j] = i;
- i = clip0[i];
- }
- seg0[j] = n;
- m = j;
-
- /* calculate seg1[j] = longest path to n with m-j segments */
- i = n;
- for (j=m; j>0; j--) {
- seg1[j] = i;
- i = clip1[i];
- }
- seg1[0] = 0;
-
- /* now find the shortest path with m segments, based on penalty3 */
- /* note: the outer 2 loops jointly have at most n iterations, thus
- the worst-case behavior here is quadratic. In practice, it is
- close to linear since the inner loop tends to be short. */
- pen[0]=0;
- for (j=1; j<=m; j++) {
- for (i=seg1[j]; i<=seg0[j]; i++) {
- best = -1;
- for (k=seg0[j-1]; k>=clip1[i]; k--) {
- thispen = penalty3(pp, k, i) + pen[k];
- if (best < 0 || thispen < best) {
- prev[i] = k;
- best = thispen;
- }
- }
- pen[i] = best;
- }
- }
-
- pp->m = m;
- SAFE_CALLOC(pp->po, m, int);
-
- /* read off shortest path */
- for (i=n, j=m-1; i>0; j--) {
- i = prev[i];
- pp->po[j] = i;
- }
-
- free(pen);
- free(prev);
- free(clip0);
- free(clip1);
- free(seg0);
- free(seg1);
- return 0;
-
- calloc_error:
- free(pen);
- free(prev);
- free(clip0);
- free(clip1);
- free(seg0);
- free(seg1);
- return 1;
-}
-
-/* ---------------------------------------------------------------------- */
-/* Stage 3: vertex adjustment (Sec. 2.3.1). */
-
-/* Adjust vertices of optimal polygon: calculate the intersection of
- the two "optimal" line segments, then move it into the unit square
- if it lies outside. Return 1 with errno set on error; 0 on
- success. */
-
-static int adjust_vertices(privpath_t *pp) {
- int m = pp->m;
- int *po = pp->po;
- int n = pp->len;
- point_t *pt = pp->pt;
- int x0 = pp->x0;
- int y0 = pp->y0;
-
- dpoint_t *ctr = NULL; /* ctr[m] */
- dpoint_t *dir = NULL; /* dir[m] */
- quadform_t *q = NULL; /* q[m] */
- double v[3];
- double d;
- int i, j, k, l;
- dpoint_t s;
- int r;
-
- SAFE_CALLOC(ctr, m, dpoint_t);
- SAFE_CALLOC(dir, m, dpoint_t);
- SAFE_CALLOC(q, m, quadform_t);
-
- r = privcurve_init(&pp->curve, m);
- if (r) {
- goto calloc_error;
- }
-
- /* calculate "optimal" point-slope representation for each line
- segment */
- for (i=0; i<m; i++) {
- j = po[mod(i+1,m)];
- j = mod(j-po[i],n)+po[i];
- pointslope(pp, po[i], j, &ctr[i], &dir[i]);
- }
-
- /* represent each line segment as a singular quadratic form; the
- distance of a point (x,y) from the line segment will be
- (x,y,1)Q(x,y,1)^t, where Q=q[i]. */
- for (i=0; i<m; i++) {
- d = sq(dir[i].x) + sq(dir[i].y);
- if (d == 0.0) {
- for (j=0; j<3; j++) {
- for (k=0; k<3; k++) {
- q[i][j][k] = 0;
- }
- }
- } else {
- v[0] = dir[i].y;
- v[1] = -dir[i].x;
- v[2] = - v[1] * ctr[i].y - v[0] * ctr[i].x;
- for (l=0; l<3; l++) {
- for (k=0; k<3; k++) {
- q[i][l][k] = v[l] * v[k] / d;
- }
- }
- }
- }
-
- /* now calculate the "intersections" of consecutive segments.
- Instead of using the actual intersection, we find the point
- within a given unit square which minimizes the square distance to
- the two lines. */
- for (i=0; i<m; i++) {
- quadform_t Q;
- dpoint_t w;
- double dx, dy;
- double det;
- double min, cand; /* minimum and candidate for minimum of quad. form */
- double xmin, ymin; /* coordinates of minimum */
- int z;
-
- /* let s be the vertex, in coordinates relative to x0/y0 */
- s.x = pt[po[i]].x-x0;
- s.y = pt[po[i]].y-y0;
-
- /* intersect segments i-1 and i */
-
- j = mod(i-1,m);
-
- /* add quadratic forms */
- for (l=0; l<3; l++) {
- for (k=0; k<3; k++) {
- Q[l][k] = q[j][l][k] + q[i][l][k];
- }
- }
-
- while(1) {
- /* minimize the quadratic form Q on the unit square */
- /* find intersection */
-
-#ifdef HAVE_GCC_LOOP_BUG
- /* work around gcc bug #12243 */
- free(NULL);
-#endif
-
- det = Q[0][0]*Q[1][1] - Q[0][1]*Q[1][0];
- if (det != 0.0) {
- w.x = (-Q[0][2]*Q[1][1] + Q[1][2]*Q[0][1]) / det;
- w.y = ( Q[0][2]*Q[1][0] - Q[1][2]*Q[0][0]) / det;
- break;
- }
-
- /* matrix is singular - lines are parallel. Add another,
- orthogonal axis, through the center of the unit square */
- if (Q[0][0]>Q[1][1]) {
- v[0] = -Q[0][1];
- v[1] = Q[0][0];
- } else if (Q[1][1]) {
- v[0] = -Q[1][1];
- v[1] = Q[1][0];
- } else {
- v[0] = 1;
- v[1] = 0;
- }
- d = sq(v[0]) + sq(v[1]);
- v[2] = - v[1] * s.y - v[0] * s.x;
- for (l=0; l<3; l++) {
- for (k=0; k<3; k++) {
- Q[l][k] += v[l] * v[k] / d;
- }
- }
- }
- dx = fabs(w.x-s.x);
- dy = fabs(w.y-s.y);
- if (dx <= .5 && dy <= .5) {
- pp->curve.vertex[i].x = w.x+x0;
- pp->curve.vertex[i].y = w.y+y0;
- continue;
- }
-
- /* the minimum was not in the unit square; now minimize quadratic
- on boundary of square */
- min = quadform(Q, s);
- xmin = s.x;
- ymin = s.y;
-
- if (Q[0][0] == 0.0) {
- goto fixx;
- }
- for (z=0; z<2; z++) { /* value of the y-coordinate */
- w.y = s.y-0.5+z;
- w.x = - (Q[0][1] * w.y + Q[0][2]) / Q[0][0];
- dx = fabs(w.x-s.x);
- cand = quadform(Q, w);
- if (dx <= .5 && cand < min) {
- min = cand;
- xmin = w.x;
- ymin = w.y;
- }
- }
- fixx:
- if (Q[1][1] == 0.0) {
- goto corners;
- }
- for (z=0; z<2; z++) { /* value of the x-coordinate */
- w.x = s.x-0.5+z;
- w.y = - (Q[1][0] * w.x + Q[1][2]) / Q[1][1];
- dy = fabs(w.y-s.y);
- cand = quadform(Q, w);
- if (dy <= .5 && cand < min) {
- min = cand;
- xmin = w.x;
- ymin = w.y;
- }
- }
- corners:
- /* check four corners */
- for (l=0; l<2; l++) {
- for (k=0; k<2; k++) {
- w.x = s.x-0.5+l;
- w.y = s.y-0.5+k;
- cand = quadform(Q, w);
- if (cand < min) {
- min = cand;
- xmin = w.x;
- ymin = w.y;
- }
- }
- }
-
- pp->curve.vertex[i].x = xmin + x0;
- pp->curve.vertex[i].y = ymin + y0;
- continue;
- }
-
- free(ctr);
- free(dir);
- free(q);
- return 0;
-
- calloc_error:
- free(ctr);
- free(dir);
- free(q);
- return 1;
-}
-
-/* ---------------------------------------------------------------------- */
-/* Stage 4: smoothing and corner analysis (Sec. 2.3.3) */
-
-/* reverse orientation of a path */
-static void reverse(privcurve_t *curve) {
- int m = curve->n;
- int i, j;
- dpoint_t tmp;
-
- for (i=0, j=m-1; i<j; i++, j--) {
- tmp = curve->vertex[i];
- curve->vertex[i] = curve->vertex[j];
- curve->vertex[j] = tmp;
- }
-}
-
-/* Always succeeds */
-static void smooth(privcurve_t *curve, double alphamax) {
- int m = curve->n;
-
- int i, j, k;
- double dd, denom, alpha;
- dpoint_t p2, p3, p4;
-
- /* examine each vertex and find its best fit */
- for (i=0; i<m; i++) {
- j = mod(i+1, m);
- k = mod(i+2, m);
- p4 = interval(1/2.0, curve->vertex[k], curve->vertex[j]);
-
- denom = ddenom(curve->vertex[i], curve->vertex[k]);
- if (denom != 0.0) {
- dd = dpara(curve->vertex[i], curve->vertex[j], curve->vertex[k]) / denom;
- dd = fabs(dd);
- alpha = dd>1 ? (1 - 1.0/dd) : 0;
- alpha = alpha / 0.75;
- } else {
- alpha = 4/3.0;
- }
- curve->alpha0[j] = alpha; /* remember "original" value of alpha */
-
- if (alpha >= alphamax) { /* pointed corner */
- curve->tag[j] = POTRACE_CORNER;
- curve->c[j][1] = curve->vertex[j];
- curve->c[j][2] = p4;
- } else {
- if (alpha < 0.55) {
- alpha = 0.55;
- } else if (alpha > 1) {
- alpha = 1;
- }
- p2 = interval(.5+.5*alpha, curve->vertex[i], curve->vertex[j]);
- p3 = interval(.5+.5*alpha, curve->vertex[k], curve->vertex[j]);
- curve->tag[j] = POTRACE_CURVETO;
- curve->c[j][0] = p2;
- curve->c[j][1] = p3;
- curve->c[j][2] = p4;
- }
- curve->alpha[j] = alpha; /* store the "cropped" value of alpha */
- curve->beta[j] = 0.5;
- }
- curve->alphacurve = 1;
-
- return;
-}
-
-/* ---------------------------------------------------------------------- */
-/* Stage 5: Curve optimization (Sec. 2.4) */
-
-/* a private type for the result of opti_penalty */
-struct opti_s {
- double pen; /* penalty */
- dpoint_t c[2]; /* curve parameters */
- double t, s; /* curve parameters */
- double alpha; /* curve parameter */
-};
-typedef struct opti_s opti_t;
-
-/* calculate best fit from i+.5 to j+.5. Assume i<j (cyclically).
- Return 0 and set badness and parameters (alpha, beta), if
- possible. Return 1 if impossible. */
-static int opti_penalty(privpath_t *pp, int i, int j, opti_t *res, double opttolerance, int *convc, double *areac) {
- int m = pp->curve.n;
- int k, k1, k2, conv, i1;
- double area, alpha, d, d1, d2;
- dpoint_t p0, p1, p2, p3, pt;
- double A, R, A1, A2, A3, A4;
- double s, t;
-
- /* check convexity, corner-freeness, and maximum bend < 179 degrees */
-
- if (i==j) { /* sanity - a full loop can never be an opticurve */
- return 1;
- }
-
- k = i;
- i1 = mod(i+1, m);
- k1 = mod(k+1, m);
- conv = convc[k1];
- if (conv == 0) {
- return 1;
- }
- d = ddist(pp->curve.vertex[i], pp->curve.vertex[i1]);
- for (k=k1; k!=j; k=k1) {
- k1 = mod(k+1, m);
- k2 = mod(k+2, m);
- if (convc[k1] != conv) {
- return 1;
- }
- if (sign(cprod(pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], pp->curve.vertex[k2])) != conv) {
- return 1;
- }
- if (iprod1(pp->curve.vertex[i], pp->curve.vertex[i1], pp->curve.vertex[k1], pp->curve.vertex[k2]) < d * ddist(pp->curve.vertex[k1], pp->curve.vertex[k2]) * COS179) {
- return 1;
- }
- }
-
- /* the curve we're working in: */
- p0 = pp->curve.c[mod(i,m)][2];
- p1 = pp->curve.vertex[mod(i+1,m)];
- p2 = pp->curve.vertex[mod(j,m)];
- p3 = pp->curve.c[mod(j,m)][2];
-
- /* determine its area */
- area = areac[j] - areac[i];
- area -= dpara(pp->curve.vertex[0], pp->curve.c[i][2], pp->curve.c[j][2])/2;
- if (i>=j) {
- area += areac[m];
- }
-
- /* find intersection o of p0p1 and p2p3. Let t,s such that o =
- interval(t,p0,p1) = interval(s,p3,p2). Let A be the area of the
- triangle (p0,o,p3). */
-
- A1 = dpara(p0, p1, p2);
- A2 = dpara(p0, p1, p3);
- A3 = dpara(p0, p2, p3);
- /* A4 = dpara(p1, p2, p3); */
- A4 = A1+A3-A2;
-
- if (A2 == A1) { /* this should never happen */
- return 1;
- }
-
- t = A3/(A3-A4);
- s = A2/(A2-A1);
- A = A2 * t / 2.0;
-
- if (A == 0.0) { /* this should never happen */
- return 1;
- }
-
- R = area / A; /* relative area */
- alpha = 2 - sqrt(4 - R / 0.3); /* overall alpha for p0-o-p3 curve */
-
- res->c[0] = interval(t * alpha, p0, p1);
- res->c[1] = interval(s * alpha, p3, p2);
- res->alpha = alpha;
- res->t = t;
- res->s = s;
-
- p1 = res->c[0];
- p2 = res->c[1]; /* the proposed curve is now (p0,p1,p2,p3) */
-
- res->pen = 0;
-
- /* calculate penalty */
- /* check tangency with edges */
- for (k=mod(i+1,m); k!=j; k=k1) {
- k1 = mod(k+1,m);
- t = tangent(p0, p1, p2, p3, pp->curve.vertex[k], pp->curve.vertex[k1]);
- if (t<-.5) {
- return 1;
- }
- pt = bezier(t, p0, p1, p2, p3);
- d = ddist(pp->curve.vertex[k], pp->curve.vertex[k1]);
- if (d == 0.0) { /* this should never happen */
- return 1;
- }
- d1 = dpara(pp->curve.vertex[k], pp->curve.vertex[k1], pt) / d;
- if (fabs(d1) > opttolerance) {
- return 1;
- }
- if (iprod(pp->curve.vertex[k], pp->curve.vertex[k1], pt) < 0 || iprod(pp->curve.vertex[k1], pp->curve.vertex[k], pt) < 0) {
- return 1;
- }
- res->pen += sq(d1);
- }
-
- /* check corners */
- for (k=i; k!=j; k=k1) {
- k1 = mod(k+1,m);
- t = tangent(p0, p1, p2, p3, pp->curve.c[k][2], pp->curve.c[k1][2]);
- if (t<-.5) {
- return 1;
- }
- pt = bezier(t, p0, p1, p2, p3);
- d = ddist(pp->curve.c[k][2], pp->curve.c[k1][2]);
- if (d == 0.0) { /* this should never happen */
- return 1;
- }
- d1 = dpara(pp->curve.c[k][2], pp->curve.c[k1][2], pt) / d;
- d2 = dpara(pp->curve.c[k][2], pp->curve.c[k1][2], pp->curve.vertex[k1]) / d;
- d2 *= 0.75 * pp->curve.alpha[k1];
- if (d2 < 0) {
- d1 = -d1;
- d2 = -d2;
- }
- if (d1 < d2 - opttolerance) {
- return 1;
- }
- if (d1 < d2) {
- res->pen += sq(d1 - d2);
- }
- }
-
- return 0;
-}
-
-/* optimize the path p, replacing sequences of Bezier segments by a
- single segment when possible. Return 0 on success, 1 with errno set
- on failure. */
-static int opticurve(privpath_t *pp, double opttolerance) {
- int m = pp->curve.n;
- int *pt = NULL; /* pt[m+1] */
- double *pen = NULL; /* pen[m+1] */
- int *len = NULL; /* len[m+1] */
- opti_t *opt = NULL; /* opt[m+1] */
- int om;
- int i,j,r;
- opti_t o;
- dpoint_t p0;
- int i1;
- double area;
- double alpha;
- double *s = NULL;
- double *t = NULL;
-
- int *convc = NULL; /* conv[m]: pre-computed convexities */
- double *areac = NULL; /* cumarea[m+1]: cache for fast area computation */
-
- SAFE_CALLOC(pt, m+1, int);
- SAFE_CALLOC(pen, m+1, double);
- SAFE_CALLOC(len, m+1, int);
- SAFE_CALLOC(opt, m+1, opti_t);
- SAFE_CALLOC(convc, m, int);
- SAFE_CALLOC(areac, m+1, double);
-
- /* pre-calculate convexity: +1 = right turn, -1 = left turn, 0 = corner */
- for (i=0; i<m; i++) {
- if (pp->curve.tag[i] == POTRACE_CURVETO) {
- convc[i] = sign(dpara(pp->curve.vertex[mod(i-1,m)], pp->curve.vertex[i], pp->curve.vertex[mod(i+1,m)]));
- } else {
- convc[i] = 0;
- }
- }
-
- /* pre-calculate areas */
- area = 0.0;
- areac[0] = 0.0;
- p0 = pp->curve.vertex[0];
- for (i=0; i<m; i++) {
- i1 = mod(i+1, m);
- if (pp->curve.tag[i1] == POTRACE_CURVETO) {
- alpha = pp->curve.alpha[i1];
- area += 0.3*alpha*(4-alpha)*dpara(pp->curve.c[i][2], pp->curve.vertex[i1], pp->curve.c[i1][2])/2;
- area += dpara(p0, pp->curve.c[i][2], pp->curve.c[i1][2])/2;
- }
- areac[i+1] = area;
- }
-
- pt[0] = -1;
- pen[0] = 0;
- len[0] = 0;
-
- /* Fixme: we always start from a fixed point -- should find the best
- curve cyclically */
-
- for (j=1; j<=m; j++) {
- /* calculate best path from 0 to j */
- pt[j] = j-1;
- pen[j] = pen[j-1];
- len[j] = len[j-1]+1;
-
- for (i=j-2; i>=0; i--) {
- r = opti_penalty(pp, i, mod(j,m), &o, opttolerance, convc, areac);
- if (r) {
- break;
- }
- if (len[j] > len[i]+1 || (len[j] == len[i]+1 && pen[j] > pen[i] + o.pen)) {
- pt[j] = i;
- pen[j] = pen[i] + o.pen;
- len[j] = len[i] + 1;
- opt[j] = o;
- }
- }
- }
- om = len[m];
- r = privcurve_init(&pp->ocurve, om);
- if (r) {
- goto calloc_error;
- }
- SAFE_CALLOC(s, om, double);
- SAFE_CALLOC(t, om, double);
-
- j = m;
- for (i=om-1; i>=0; i--) {
- if (pt[j]==j-1) {
- pp->ocurve.tag[i] = pp->curve.tag[mod(j,m)];
- pp->ocurve.c[i][0] = pp->curve.c[mod(j,m)][0];
- pp->ocurve.c[i][1] = pp->curve.c[mod(j,m)][1];
- pp->ocurve.c[i][2] = pp->curve.c[mod(j,m)][2];
- pp->ocurve.vertex[i] = pp->curve.vertex[mod(j,m)];
- pp->ocurve.alpha[i] = pp->curve.alpha[mod(j,m)];
- pp->ocurve.alpha0[i] = pp->curve.alpha0[mod(j,m)];
- pp->ocurve.beta[i] = pp->curve.beta[mod(j,m)];
- s[i] = t[i] = 1.0;
- } else {
- pp->ocurve.tag[i] = POTRACE_CURVETO;
- pp->ocurve.c[i][0] = opt[j].c[0];
- pp->ocurve.c[i][1] = opt[j].c[1];
- pp->ocurve.c[i][2] = pp->curve.c[mod(j,m)][2];
- pp->ocurve.vertex[i] = interval(opt[j].s, pp->curve.c[mod(j,m)][2], pp->curve.vertex[mod(j,m)]);
- pp->ocurve.alpha[i] = opt[j].alpha;
- pp->ocurve.alpha0[i] = opt[j].alpha;
- s[i] = opt[j].s;
- t[i] = opt[j].t;
- }
- j = pt[j];
- }
-
- /* calculate beta parameters */
- for (i=0; i<om; i++) {
- i1 = mod(i+1,om);
- pp->ocurve.beta[i] = s[i] / (s[i] + t[i1]);
- }
- pp->ocurve.alphacurve = 1;
-
- free(pt);
- free(pen);
- free(len);
- free(opt);
- free(s);
- free(t);
- free(convc);
- free(areac);
- return 0;
-
- calloc_error:
- free(pt);
- free(pen);
- free(len);
- free(opt);
- free(s);
- free(t);
- free(convc);
- free(areac);
- return 1;
-}
-
-/* ---------------------------------------------------------------------- */
-
-#define TRY(x) if (x) goto try_error
-
-/* return 0 on success, 1 on error with errno set. */
-int process_path(path_t *plist, const potrace_param_t *param, progress_t *progress) {
- path_t *p;
- double nn = 0, cn = 0;
-
- if (progress->callback) {
- /* precompute task size for progress estimates */
- nn = 0;
- list_forall (p, plist) {
- nn += p->priv->len;
- }
- cn = 0;
- }
-
- /* call downstream function with each path */
- list_forall (p, plist) {
- TRY(calc_sums(p->priv));
- TRY(calc_lon(p->priv));
- TRY(bestpolygon(p->priv));
- TRY(adjust_vertices(p->priv));
- if (p->sign == '-') { /* reverse orientation of negative paths */
- reverse(&p->priv->curve);
- }
- smooth(&p->priv->curve, param->alphamax);
- if (param->opticurve) {
- TRY(opticurve(p->priv, param->opttolerance));
- p->priv->fcurve = &p->priv->ocurve;
- } else {
- p->priv->fcurve = &p->priv->curve;
- }
- privcurve_to_curve(p->priv->fcurve, &p->curve);
-
- if (progress->callback) {
- cn += p->priv->len;
- progress_update(cn/nn, progress);
- }
- }
-
- progress_update(1.0, progress);
-
- return 0;
-
- try_error:
- return 1;
-}
diff --git a/src/trace/potrace/trace.h b/src/trace/potrace/trace.h
deleted file mode 100644
index c53cdd10f..000000000
--- a/src/trace/potrace/trace.h
+++ /dev/null
@@ -1,15 +0,0 @@
-/* Copyright (C) 2001-2015 Peter Selinger.
- This file is part of Potrace. It is free software and it is covered
- by the GNU General Public License. See the file COPYING for details. */
-
-
-#ifndef TRACE_H
-#define TRACE_H
-
-#include "potracelib.h"
-#include "progress.h"
-#include "curve.h"
-
-int process_path(path_t *plist, const potrace_param_t *param, progress_t *progress);
-
-#endif /* TRACE_H */
diff --git a/src/trace/trace.cpp b/src/trace/trace.cpp
index 91c230920..18f03aa1b 100644
--- a/src/trace/trace.cpp
+++ b/src/trace/trace.cpp
@@ -74,7 +74,7 @@ SPImage *Tracer::getSelectedSPImage()
them as bottom-to-top so that we can discover the image and any
SPItems above it
*/
- for (std::vector<SPItem*>::const_iterator i=list.begin() ; list.end()!=i ; i++)
+ for (std::vector<SPItem*>::const_iterator i=list.begin() ; list.end()!=i ; ++i)
{
if (!SP_IS_ITEM(*i))
{
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 58af7d935..587974b90 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -34,7 +34,6 @@ set(ui_SRC
tools/dropper-tool.cpp
tools/dynamic-base.cpp
tools/eraser-tool.cpp
- tools/flood-tool.cpp
tools/freehand-base.cpp
tools/gradient-tool.cpp
tools/lpe-tool.cpp
@@ -81,6 +80,7 @@ set(ui_SRC
dialog/icon-preview.cpp
dialog/inkscape-preferences.cpp
dialog/input.cpp
+ dialog/knot-properties.cpp
dialog/layer-properties.cpp
dialog/layers.cpp
dialog/livepatheffect-add.cpp
@@ -107,7 +107,6 @@ set(ui_SRC
dialog/template-widget.cpp
dialog/text-edit.cpp
dialog/tile.cpp
- dialog/tracedialog.cpp
dialog/transformation.cpp
dialog/undo-history.cpp
dialog/xml-tree.cpp
@@ -221,6 +220,7 @@ set(ui_SRC
dialog/icon-preview.h
dialog/inkscape-preferences.h
dialog/input.h
+ dialog/knot-properties.h
dialog/layer-properties.h
dialog/layers.h
dialog/livepatheffect-add.h
@@ -248,7 +248,6 @@ set(ui_SRC
dialog/template-widget.h
dialog/text-edit.h
dialog/tile.h
- dialog/tracedialog.h
dialog/transformation.h
dialog/undo-history.h
dialog/xml-tree.h
@@ -276,7 +275,6 @@ set(ui_SRC
tools/dropper-tool.h
tools/dynamic-base.h
tools/eraser-tool.h
- tools/flood-tool.h
tools/freehand-base.h
tools/gradient-tool.h
tools/lpe-tool.h
@@ -364,3 +362,14 @@ endif()
# add_inkscape_lib(ui_LIB "${ui_SRC}")
add_inkscape_source("${ui_SRC}")
+
+set ( ui_flood_and_trace_SRC
+ tools/flood-tool.h
+ tools/flood-tool.cpp
+ dialog/tracedialog.cpp
+ dialog/tracedialog.h
+)
+
+if ("${HAVE_POTRACE}")
+ add_inkscape_source("${ui_flood_and_trace_SRC}")
+endif()
diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp
index d6cf1f980..f04d8a591 100644
--- a/src/ui/clipboard.cpp
+++ b/src/ui/clipboard.cpp
@@ -154,6 +154,7 @@ private:
Inkscape::XML::Node *_root; ///< Reference to the clipboard's root node
Inkscape::XML::Node *_clipnode; ///< The node that holds extra information
Inkscape::XML::Document *_doc; ///< Reference to the clipboard's Inkscape::XML::Document
+ std::set<SPItem*> cloned_elements;
// we need a way to copy plain text AND remember its style;
// the standard _clipnode is only available in an SVG tree, hence this special storage
@@ -239,7 +240,7 @@ void ClipboardManagerImpl::copy(SPDesktop *desktop)
// Special case for when the color picker ("dropper") is active - copies color under cursor
if (tools_isactive(desktop, TOOLS_DROPPER)) {
//_setClipboardColor(sp_dropper_context_get_color(desktop->event_context));
- _setClipboardColor(SP_DROPPER_CONTEXT(desktop->event_context)->get_color());
+ _setClipboardColor(SP_DROPPER_CONTEXT(desktop->event_context)->get_color());
_discardInternalClipboard();
return;
}
@@ -523,8 +524,8 @@ bool ClipboardManagerImpl::pasteSize(SPDesktop *desktop, bool separately, bool a
// resize each object in the selection
if (separately) {
- std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ std::vector<SPItem*> itemlist=selection->itemList();
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (item) {
Geom::OptRect obj_size = item->desktopVisualBounds();
@@ -564,7 +565,7 @@ bool ClipboardManagerImpl::pastePathEffect(SPDesktop *desktop)
}
Inkscape::Selection *selection = desktop->getSelection();
- if (selection && selection->isEmpty()) {
+ if (!selection || selection->isEmpty()) {
_userWarn(desktop, _("Select <b>object(s)</b> to paste live path effect to."));
return false;
}
@@ -580,7 +581,7 @@ bool ClipboardManagerImpl::pastePathEffect(SPDesktop *desktop)
// make sure all selected items are converted to paths first (i.e. rectangles)
sp_selected_to_lpeitems(desktop);
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
_applyPathEffect(item, effectstack);
}
@@ -630,7 +631,7 @@ Glib::ustring ClipboardManagerImpl::getShapeOrTextObjectId(SPDesktop *desktop)
// at the first object to be <svg:path> or <svg:text>.
// but that could then return the id of the object's
// clip path or mask, not the original path!
-
+
SPDocument *tempdoc = _retrieveClipboard(); // any target will do here
if ( tempdoc == NULL ) {
_userWarn(desktop, _("Nothing on the clipboard."));
@@ -662,8 +663,9 @@ Glib::ustring ClipboardManagerImpl::getShapeOrTextObjectId(SPDesktop *desktop)
void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection)
{
// copy the defs used by all items
- std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ std::vector<SPItem*> itemlist=selection->itemList();
+ cloned_elements.clear();
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (item) {
_copyUsedDefs(item);
@@ -673,14 +675,33 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection)
}
// copy the representation of the items
- std::vector<SPItem*> sorted_items(itemlist);
+ std::vector<SPObject*> sorted_items;
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i)
+ sorted_items.push_back(*i);
sort(sorted_items.begin(),sorted_items.end(),sp_object_compare_position_bool);
- for(std::vector<SPItem*>::const_iterator i=sorted_items.begin();i!=sorted_items.end();i++){
- SPItem *item = *i;
+ //remove already copied elements from cloned_elements
+ std::vector<SPItem*>tr;
+ for(std::set<SPItem*>::iterator it = cloned_elements.begin();it!=cloned_elements.end();++it){
+ if(std::find(sorted_items.begin(),sorted_items.end(),*it)!=sorted_items.end())
+ tr.push_back(*it);
+ }
+ for(std::vector<SPItem*>::iterator it = tr.begin();it!=tr.end();++it){
+ cloned_elements.erase(*it);
+ }
+
+ sorted_items.insert(sorted_items.end(),cloned_elements.begin(),cloned_elements.end());
+
+ for(std::vector<SPObject*>::const_iterator i=sorted_items.begin();i!=sorted_items.end();++i){
+ SPItem *item = dynamic_cast<SPItem*>(*i);
if (item) {
Inkscape::XML::Node *obj = item->getRepr();
- Inkscape::XML::Node *obj_copy = _copyNode(obj, _doc, _root);
+ Inkscape::XML::Node *obj_copy;
+ if(cloned_elements.find(item)==cloned_elements.end())
+ obj_copy = _copyNode(obj, _doc, _root);
+ else
+ obj_copy = _copyNode(obj, _doc, _clipnode);
+
// copy complete inherited style
SPCSSAttr *css = sp_repr_css_attr_inherited(obj, "style");
@@ -737,6 +758,12 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection)
*/
void ClipboardManagerImpl::_copyUsedDefs(SPItem *item)
{
+ SPUse *use=dynamic_cast<SPUse *>(item);
+ if(use){
+ if(cloned_elements.insert(use->get_original()).second)
+ _copyUsedDefs(use->get_original());
+ }
+
// copy fill and stroke styles (patterns and gradients)
SPStyle *style = item->style;
diff --git a/src/ui/control-manager.cpp b/src/ui/control-manager.cpp
index 5a3c5a496..cedaea405 100644
--- a/src/ui/control-manager.cpp
+++ b/src/ui/control-manager.cpp
@@ -20,7 +20,6 @@
#include "display/sp-canvas-item.h"
#include "display/sp-ctrlline.h"
#include "display/sp-ctrlcurve.h"
-#include "display/sp-ctrlpoint.h"
#include "preferences.h"
using Inkscape::ControlFlags;
@@ -139,8 +138,6 @@ ControlManagerImpl::ControlManagerImpl(ControlManager &manager) :
_typeTable[CTRL_TYPE_NODE_SMOOTH] = SP_TYPE_CTRL;
_typeTable[CTRL_TYPE_NODE_SYMETRICAL] = SP_TYPE_CTRL;
- _typeTable[CTRL_TYPE_ORIGIN] = SP_TYPE_CTRLPOINT;
-
_typeTable[CTRL_TYPE_LINE] = SP_TYPE_CTRLLINE;
@@ -183,10 +180,6 @@ ControlManagerImpl::ControlManagerImpl(ControlManager &manager) :
_sizeTable[CTRL_TYPE_SHAPER] = std::vector<int>(sizes, sizes + (sizeof(sizes) / sizeof(sizes[0])));
}
{
- int sizes[] = {2, 3, 4, 7, 8, 9, 10};
- _sizeTable[CTRL_TYPE_ORIGIN] = std::vector<int>(sizes, sizes + (sizeof(sizes) / sizeof(sizes[0])));
- }
- {
int sizes[] = {5, 7, 9, 10, 11, 12, 13};
_sizeTable[CTRL_TYPE_NODE_AUTO] = std::vector<int>(sizes, sizes + (sizeof(sizes) / sizeof(sizes[0])));
_sizeTable[CTRL_TYPE_NODE_CUSP] = std::vector<int>(sizes, sizes + (sizeof(sizes) / sizeof(sizes[0])));
@@ -258,10 +251,6 @@ SPCanvasItem *ControlManagerImpl::createControl(SPCanvasGroup *parent, ControlTy
NULL);
break;
}
- case CTRL_TYPE_ORIGIN:
- item = sp_canvas_item_new(parent, SP_TYPE_CTRLPOINT,
- NULL);
- break;
case CTRL_TYPE_INVISIPOINT:
item = sp_canvas_item_new(parent, SP_TYPE_CTRL,
"shape", SP_CTRL_SHAPE_SQUARE,
@@ -297,14 +286,11 @@ void ControlManagerImpl::updateItem(SPCanvasItem *item)
if (item) {
double target = _sizeTable[item->ctrlType][_size - 1];
- if ((item->ctrlType == CTRL_TYPE_ORIGIN) && SP_IS_CTRLPOINT(item)) {
- sp_ctrlpoint_set_radius(SP_CTRLPOINT(item), target / 2.0);
- } else {
- if (_sizeChangers.count(item->ctrlType) && _manager.isSelected(item)) {
- target += 2;
- }
- g_object_set(item, "size", target, NULL);
+ if (_sizeChangers.count(item->ctrlType) && _manager.isSelected(item)) {
+ target += 2;
}
+ g_object_set(item, "size", target, NULL);
+
sp_canvas_item_request_update(item);
}
}
diff --git a/src/ui/control-manager.h b/src/ui/control-manager.h
index 05a53f6a0..964ad0a29 100644
--- a/src/ui/control-manager.h
+++ b/src/ui/control-manager.h
@@ -74,9 +74,11 @@ public:
private:
ControlManager();
-
+#if __cplusplus <= 199711L
std::auto_ptr<ControlManagerImpl> _impl;
-
+#else
+ std::unique_ptr<ControlManagerImpl> _impl;
+#endif
friend class ControlManagerImpl;
};
diff --git a/src/ui/control-types.h b/src/ui/control-types.h
index 0bbf31144..1a0230324 100644
--- a/src/ui/control-types.h
+++ b/src/ui/control-types.h
@@ -26,7 +26,6 @@ enum ControlType {
CTRL_TYPE_ROTATE,
CTRL_TYPE_SIZER,
CTRL_TYPE_SHAPER,
- CTRL_TYPE_ORIGIN,
CTRL_TYPE_LINE,
CTRL_TYPE_NODE_AUTO,
CTRL_TYPE_NODE_CUSP,
diff --git a/src/ui/dialog/Makefile_insert b/src/ui/dialog/Makefile_insert
index cbdae1cb0..71628973e 100644
--- a/src/ui/dialog/Makefile_insert
+++ b/src/ui/dialog/Makefile_insert
@@ -61,6 +61,8 @@ ink_common_sources += \
ui/dialog/inkscape-preferences.h \
ui/dialog/input.cpp \
ui/dialog/input.h \
+ ui/dialog/knot-properties.cpp \
+ ui/dialog/knot-properties.h \
ui/dialog/layer-properties.cpp \
ui/dialog/layer-properties.h \
ui/dialog/layers.cpp \
@@ -106,8 +108,6 @@ ink_common_sources += \
ui/dialog/text-edit.h \
ui/dialog/tile.cpp \
ui/dialog/tile.h \
- ui/dialog/tracedialog.cpp \
- ui/dialog/tracedialog.h \
ui/dialog/pixelartdialog.cpp \
ui/dialog/pixelartdialog.h \
ui/dialog/transformation.cpp \
@@ -123,3 +123,11 @@ ink_common_sources += \
ui/dialog/lpe-fillet-chamfer-properties.cpp \
ui/dialog/lpe-fillet-chamfer-properties.h \
$(inkboard_dialogs)
+
+if HAVE_POTRACE
+
+ink_common_sources += \
+ ui/dialog/tracedialog.cpp \
+ ui/dialog/tracedialog.h
+
+endif
diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp
index 882427912..8f87932b8 100644
--- a/src/ui/dialog/align-and-distribute.cpp
+++ b/src/ui/dialog/align-and-distribute.cpp
@@ -42,7 +42,7 @@
#include "ui/icon-names.h"
#include "ui/tools/node-tool.h"
#include "ui/tool/multi-path-manipulator.h"
-#include "util/glib-list-iterators.h"
+#include "ui/tool/control-point-selection.h"
#include "verbs.h"
#include "widgets/icon.h"
#include "sp-root.h"
@@ -89,6 +89,42 @@ Action::Action(const Glib::ustring &id,
}
+void ActionAlign::do_node_action(Inkscape::UI::Tools::NodeTool *nt, int verb)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int prev_pref = prefs->getInt("/dialogs/align/align-nodes-to");
+ switch(verb){
+ case SP_VERB_ALIGN_HORIZONTAL_LEFT:
+ prefs->setInt("/dialogs/align/align-nodes-to", MIN_NODE );
+ nt->_multipath->alignNodes(Geom::Y);
+ break;
+ case SP_VERB_ALIGN_HORIZONTAL_CENTER:
+ nt->_multipath->alignNodes(Geom::Y);
+ break;
+ case SP_VERB_ALIGN_HORIZONTAL_RIGHT:
+ prefs->setInt("/dialogs/align/align-nodes-to", MAX_NODE );
+ nt->_multipath->alignNodes(Geom::Y);
+ break;
+ case SP_VERB_ALIGN_VERTICAL_TOP:
+ prefs->setInt("/dialogs/align/align-nodes-to", MAX_NODE );
+ nt->_multipath->alignNodes(Geom::X);
+ break;
+ case SP_VERB_ALIGN_VERTICAL_CENTER:
+ nt->_multipath->alignNodes(Geom::X);
+ break;
+ case SP_VERB_ALIGN_VERTICAL_BOTTOM:
+ prefs->setInt("/dialogs/align/align-nodes-to", MIN_NODE );
+ nt->_multipath->alignNodes(Geom::X);
+ break;
+ case SP_VERB_ALIGN_VERTICAL_HORIZONTAL_CENTER:
+ nt->_multipath->alignNodes(Geom::X);
+ nt->_multipath->alignNodes(Geom::Y);
+ break;
+ default:return;
+ }
+ prefs->setInt("/dialogs/align/align-nodes-to", prev_pref );
+}
+
void ActionAlign::do_action(SPDesktop *desktop, int index)
{
Inkscape::Selection *selection = desktop->getSelection();
@@ -188,6 +224,14 @@ ActionAlign::Coeffs const ActionAlign::_allCoeffs[11] = {
void ActionAlign::do_verb_action(SPDesktop *desktop, int verb)
{
+ Inkscape::UI::Tools::ToolBase *event_context = desktop->getEventContext();
+ if (INK_IS_NODE_TOOL(event_context)) {
+ Inkscape::UI::Tools::NodeTool *nt = INK_NODE_TOOL(event_context);
+ if(!nt->_selected_nodes->empty()){
+ do_node_action(nt, verb);
+ return;
+ }
+ }
do_action(desktop, verb_to_coeff(verb));
}
@@ -535,7 +579,7 @@ private :
if (length_a != length_b) return (length_a > length_b);
}
// Last criteria: Sort according to the z-coordinate
- return (a->isSiblingOf(b));
+ return sp_item_repr_compare_position(a,b)<0;
}
virtual void on_button_click()
@@ -742,7 +786,6 @@ private :
if (!selection) return;
std::vector<SPItem*> selected(selection->itemList());
- if (selected.empty()) return;
//Check 2 or more selected objects
if (selected.size() < 2) return;
@@ -795,7 +838,51 @@ private :
_("Distribute text baselines"));
}
- } else {
+ } else { //align
+ Geom::Point ref_point;
+ SPItem *focus = NULL;
+ Geom::OptRect b = Geom::OptRect();
+
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
+ switch (AlignTarget(prefs->getInt("/dialogs/align/align-to", 6)))
+ {
+ case LAST:
+ focus = SP_ITEM(*selected.begin());
+ break;
+ case FIRST:
+ focus = SP_ITEM(*--(selected.end()));
+ break;
+ case BIGGEST:
+ focus = selection->largestItem(Selection::AREA);
+ break;
+ case SMALLEST:
+ focus = selection->smallestItem(Selection::AREA);
+ break;
+ case PAGE:
+ b = desktop->getDocument()->preferredBounds();
+ break;
+ case DRAWING:
+ b = desktop->getDocument()->getRoot()->desktopPreferredBounds();
+ break;
+ case SELECTION:
+ b = selection->preferredBounds();
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ };
+
+ if(focus) {
+ if (SP_IS_TEXT (focus) || SP_IS_FLOWTEXT (focus)) {
+ ref_point = *(te_get_layout(focus)->baselineAnchorPoint())*(focus->i2dt_affine());
+ } else {
+ ref_point = focus->desktopPreferredBounds()->min();
+ }
+ } else {
+ ref_point = b->min();
+ }
+
for (std::vector<SPItem*>::iterator it(selected.begin());
it != selected.end();
++it)
@@ -807,7 +894,7 @@ private :
if (pt) {
Geom::Point base = *pt * (item)->i2dt_affine();
Geom::Point t(0.0, 0.0);
- t[_orientation] = b_min[_orientation] - base[_orientation];
+ t[_orientation] = ref_point[_orientation] - base[_orientation];
sp_item_move_rel(item, Geom::Translate(t));
changed = true;
}
@@ -829,6 +916,9 @@ static void on_tool_changed(AlignAndDistribute *daad)
SPDesktop *desktop = SP_ACTIVE_DESKTOP;
if (desktop && desktop->getEventContext())
daad->setMode(tools_active(desktop) == TOOLS_NODES);
+ else
+ daad->setMode(false);
+
}
static void on_selection_changed(AlignAndDistribute *daad)
@@ -863,6 +953,7 @@ AlignAndDistribute::AlignAndDistribute()
_nodesTable(1, 4, true),
#endif
_anchorLabel(_("Relative to: ")),
+ _anchorLabelNode(_("Relative to: ")),
_selgrpLabel(_("_Treat selection as group: "), 1)
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -1001,9 +1092,20 @@ AlignAndDistribute::AlignAndDistribute()
_combo.set_active(prefs->getInt("/dialogs/align/align-to", 6));
_combo.signal_changed().connect(sigc::mem_fun(*this, &AlignAndDistribute::on_ref_change));
+ _comboNode.append(_("Last selected"));
+ _comboNode.append(_("First selected"));
+ _comboNode.append(_("Middle of selection"));
+ _comboNode.append(_("Min value"));
+ _comboNode.append(_("Max value"));
+ _comboNode.set_active(prefs->getInt("/dialogs/align/align-nodes-to", 2));
+ _comboNode.signal_changed().connect(sigc::mem_fun(*this, &AlignAndDistribute::on_node_ref_change));
+
_anchorBox.pack_end(_combo, false, false);
_anchorBox.pack_end(_anchorLabel, false, false);
+ _anchorBoxNode.pack_end(_comboNode, false, false);
+ _anchorBoxNode.pack_end(_anchorLabelNode, false, false);
+
_selgrpLabel.set_mnemonic_widget(_selgrp);
_selgrpBox.pack_end(_selgrp, false, false);
_selgrpBox.pack_end(_selgrpLabel, false, false);
@@ -1021,11 +1123,15 @@ AlignAndDistribute::AlignAndDistribute()
_alignBox.pack_start(_selgrpBox);
_alignBox.pack_start(_alignTableBox);
+ _alignBoxNode.pack_start(_anchorBoxNode, false, false);
+ _alignBoxNode.pack_start(_nodesTableBox);
+
+
_alignFrame.add(_alignBox);
_distributeFrame.add(_distributeTableBox);
_rearrangeFrame.add(_rearrangeTableBox);
_removeOverlapFrame.add(_removeOverlapTableBox);
- _nodesFrame.add(_nodesTableBox);
+ _nodesFrame.add(_alignBoxNode);
Gtk::Box *contents = _getContents();
contents->set_spacing(4);
@@ -1036,7 +1142,7 @@ AlignAndDistribute::AlignAndDistribute()
contents->pack_start(_distributeFrame, true, true);
contents->pack_start(_rearrangeFrame, true, true);
contents->pack_start(_removeOverlapFrame, true, true);
- contents->pack_start(_nodesFrame, true, true);
+ contents->pack_start(_nodesFrame, true, false);
//Connect to the global tool change signal
_toolChangeConn = INKSCAPE.signal_eventcontext_set.connect(sigc::hide<0>(sigc::bind(sigc::ptr_fun(&on_tool_changed), this)));
@@ -1082,6 +1188,13 @@ void AlignAndDistribute::on_ref_change(){
//Make blink the master
}
+void AlignAndDistribute::on_node_ref_change(){
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setInt("/dialogs/align/align-nodes-to", _comboNode.get_active_row_number());
+
+ //Make blink the master
+}
+
void AlignAndDistribute::on_selgrp_toggled(){
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
prefs->setInt("/dialogs/align/sel-as-groups", _selgrp.get_active());
@@ -1107,6 +1220,7 @@ void AlignAndDistribute::setMode(bool nodeEdit)
((_rearrangeFrame).*(mSel))();
((_removeOverlapFrame).*(mSel))();
((_nodesFrame).*(mNode))();
+ _getContents()->queue_resize();
}
void AlignAndDistribute::addAlignButton(const Glib::ustring &id, const Glib::ustring tiptext,
diff --git a/src/ui/dialog/align-and-distribute.h b/src/ui/dialog/align-and-distribute.h
index eecc30ff8..f8cc61af2 100644
--- a/src/ui/dialog/align-and-distribute.h
+++ b/src/ui/dialog/align-and-distribute.h
@@ -18,6 +18,7 @@
#include <list>
#include "ui/widget/panel.h"
#include "ui/widget/frame.h"
+
#include <gtkmm/frame.h>
#include <gtkmm/comboboxtext.h>
#include <gtkmm/label.h>
@@ -35,6 +36,9 @@ class SPItem;
namespace Inkscape {
namespace UI {
+namespace Tools{
+class NodeTool;
+}
namespace Dialog {
class Action;
@@ -68,6 +72,7 @@ public:
protected:
void on_ref_change();
+ void on_node_ref_change();
void on_selgrp_toggled();
void addDistributeButton(const Glib::ustring &id, const Glib::ustring tiptext,
guint row, guint col, bool onInterSpace,
@@ -114,15 +119,19 @@ protected:
Gtk::HBox _anchorBox;
Gtk::HBox _selgrpBox;
Gtk::VBox _alignBox;
+ Gtk::VBox _alignBoxNode;
Gtk::HBox _alignTableBox;
Gtk::HBox _distributeTableBox;
Gtk::HBox _rearrangeTableBox;
Gtk::HBox _removeOverlapTableBox;
Gtk::HBox _nodesTableBox;
Gtk::Label _anchorLabel;
+ Gtk::Label _anchorLabelNode;
Gtk::Label _selgrpLabel;
Gtk::CheckButton _selgrp;
Gtk::ComboBoxText _combo;
+ Gtk::HBox _anchorBoxNode;
+ Gtk::ComboBoxText _comboNode;
SPDesktop *_desktop;
DesktopTracker _deskTrack;
@@ -149,6 +158,8 @@ bool operator< (const BBoxSort &a, const BBoxSort &b);
class Action {
public :
+ enum AlignTarget { LAST=0, FIRST, BIGGEST, SMALLEST, PAGE, DRAWING, SELECTION };
+ enum AlignTargetNode { LAST_NODE=0, FIRST_NODE, MID_NODE, MIN_NODE, MAX_NODE };
Action(const Glib::ustring &id,
const Glib::ustring &tiptext,
guint row, guint column,
@@ -183,7 +194,6 @@ public :
double sx0, sx1, sy0, sy1;
int verb_id;
};
- enum AlignTarget { LAST=0, FIRST, BIGGEST, SMALLEST, PAGE, DRAWING, SELECTION };
ActionAlign(const Glib::ustring &id,
const Glib::ustring &tiptext,
guint row, guint column,
@@ -213,6 +223,7 @@ private :
}
static void do_action(SPDesktop *desktop, int index);
+ static void do_node_action(Inkscape::UI::Tools::NodeTool *nt, int index);
guint _index;
AlignAndDistribute &_dialog;
diff --git a/src/ui/dialog/clonetiler.cpp b/src/ui/dialog/clonetiler.cpp
index f84a2ffd6..fbd050f8e 100644
--- a/src/ui/dialog/clonetiler.cpp
+++ b/src/ui/dialog/clonetiler.cpp
@@ -85,7 +85,7 @@ CloneTiler::CloneTiler () :
{
Gtk::Box *contents = _getContents();
contents->set_spacing(0);
-
+
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -101,7 +101,7 @@ CloneTiler::CloneTiler () :
contents->pack_start (*Gtk::manage(Glib::wrap(mainbox)), true, true, 0);
- GtkWidget *nb = gtk_notebook_new ();
+ nb = gtk_notebook_new ();
gtk_box_pack_start (GTK_BOX (mainbox), nb, FALSE, FALSE, 0);
@@ -662,7 +662,7 @@ CloneTiler::CloneTiler () :
gtk_box_pack_start (GTK_BOX (hb), l, FALSE, FALSE, 0);
guint32 rgba = 0x000000ff | sp_svg_read_color (prefs->getString(prefs_path + "initial_color").data(), 0x000000ff);
- color_picker = new Inkscape::UI::Widget::ColorPicker (*new Glib::ustring(_("Initial color of tiled clones")), *new Glib::ustring(_("Initial color for clones (works only if the original has unset fill or stroke)")), rgba, false);
+ color_picker = new Inkscape::UI::Widget::ColorPicker (*new Glib::ustring(_("Initial color of tiled clones")), *new Glib::ustring(_("Initial color for clones (works only if the original has unset fill or stroke or on spray tool in copy mode)")), rgba, false);
color_changed_connection = color_picker->connectChanged (sigc::ptr_fun(on_picker_color_changed));
gtk_box_pack_start (GTK_BOX (hb), reinterpret_cast<GtkWidget*>(color_picker->gobj()), FALSE, FALSE, 0);
@@ -776,8 +776,6 @@ CloneTiler::CloneTiler () :
// Trace
{
GtkWidget *vb = clonetiler_new_tab (nb, _("_Trace"));
-
-
{
#if GTK_CHECK_VERSION(3,0,0)
GtkWidget *hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, VB_MARGIN);
@@ -787,11 +785,11 @@ CloneTiler::CloneTiler () :
#endif
gtk_box_pack_start (GTK_BOX (vb), hb, FALSE, FALSE, 0);
- GtkWidget *b = gtk_check_button_new_with_label (_("Trace the drawing under the tiles"));
+ b = gtk_check_button_new_with_label (_("Trace the drawing under the clones/sprayed items"));
g_object_set_data (G_OBJECT(b), "uncheckable", GINT_TO_POINTER(TRUE));
bool old = prefs->getBool(prefs_path + "dotrace");
gtk_toggle_button_set_active ((GtkToggleButton *) b, old);
- gtk_widget_set_tooltip_text (b, _("For each clone, pick a value from the drawing in that clone's location and apply it to the clone"));
+ gtk_widget_set_tooltip_text (b, _("For each clone/sprayed item, pick a value from the drawing in its location and apply it"));
gtk_box_pack_start (GTK_BOX (hb), b, FALSE, FALSE, 0);
g_signal_connect(G_OBJECT(b), "toggled",
@@ -1001,6 +999,18 @@ CloneTiler::CloneTiler () :
}
}
+ {
+#if GTK_CHECK_VERSION(3,0,0)
+ GtkWidget *hb = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, VB_MARGIN);
+ gtk_box_set_homogeneous(GTK_BOX(hb), FALSE);
+#else
+ GtkWidget *hb = gtk_hbox_new(FALSE, VB_MARGIN);
+#endif
+ gtk_box_pack_start (GTK_BOX (mainbox), hb, FALSE, FALSE, 0);
+ GtkWidget *l = gtk_label_new(_(""));
+ gtk_label_set_markup (GTK_LABEL(l), _("Apply to tiled clones:"));
+ gtk_box_pack_start (GTK_BOX (hb), l, FALSE, FALSE, 0);
+ }
// Rows/columns, width/height
{
#if GTK_CHECK_VERSION(3,0,0)
@@ -1289,7 +1299,6 @@ CloneTiler::CloneTiler () :
}
gtk_widget_show_all (mainbox);
-
}
show_all();
@@ -2479,7 +2488,7 @@ void CloneTiler::clonetiler_apply(GtkWidget */*widget*/, GtkWidget *dlg)
// Trace tab
if (dotrace) {
- Geom::Rect bbox_t = transform_rect (bbox_original, t);
+ Geom::Rect bbox_t = transform_rect (bbox_original, t*Geom::Scale(1.0/scale_units));
guint32 rgba = clonetiler_trace_pick (bbox_t);
float r = SP_RGBA32_R_F(rgba);
@@ -3005,6 +3014,13 @@ void CloneTiler::clonetiler_do_pick_toggled(GtkToggleButton *tb, GtkWidget *dlg)
}
}
+void CloneTiler::show_page_trace()
+{
+ gtk_notebook_set_current_page(GTK_NOTEBOOK(nb),6);
+ gtk_toggle_button_set_active ((GtkToggleButton *) b, false);
+}
+
+
}
}
}
diff --git a/src/ui/dialog/clonetiler.h b/src/ui/dialog/clonetiler.h
index e5f5638b2..a8f1df0a0 100644
--- a/src/ui/dialog/clonetiler.h
+++ b/src/ui/dialog/clonetiler.h
@@ -31,7 +31,7 @@ public:
virtual ~CloneTiler();
static CloneTiler &getInstance() { return *new CloneTiler(); }
-
+ void show_page_trace();
protected:
GtkWidget * clonetiler_new_tab(GtkWidget *nb, const gchar *label);
@@ -113,6 +113,8 @@ private:
CloneTiler& operator=(CloneTiler const &d);
GtkWidget *dlg;
+ GtkWidget *nb;
+ GtkWidget *b;
SPDesktop *desktop;
DesktopTracker deskTrack;
Inkscape::UI::Widget::ColorPicker *color_picker;
diff --git a/src/ui/dialog/dialog-manager.cpp b/src/ui/dialog/dialog-manager.cpp
index 7b1b36908..49853277c 100644
--- a/src/ui/dialog/dialog-manager.cpp
+++ b/src/ui/dialog/dialog-manager.cpp
@@ -34,7 +34,11 @@
#include "ui/dialog/messages.h"
#include "ui/dialog/symbols.h"
#include "ui/dialog/tile.h"
-#include "ui/dialog/tracedialog.h"
+
+#if HAVE_POTRACE
+# include "ui/dialog/tracedialog.h"
+#endif
+
#include "ui/dialog/pixelartdialog.h"
#include "ui/dialog/transformation.h"
#include "ui/dialog/undo-history.h"
@@ -124,7 +128,11 @@ DialogManager::DialogManager() {
registerFactory("Swatches", &create<SwatchesPanel, FloatingBehavior>);
registerFactory("TileDialog", &create<ArrangeDialog, FloatingBehavior>);
registerFactory("Symbols", &create<SymbolsDialog, FloatingBehavior>);
+
+#if HAVE_POTRACE
registerFactory("Trace", &create<TraceDialog, FloatingBehavior>);
+#endif
+
registerFactory("PixelArt", &create<PixelArtDialog, FloatingBehavior>);
registerFactory("Transformation", &create<Transformation, FloatingBehavior>);
registerFactory("UndoHistory", &create<UndoHistory, FloatingBehavior>);
@@ -159,7 +167,11 @@ DialogManager::DialogManager() {
registerFactory("Swatches", &create<SwatchesPanel, DockBehavior>);
registerFactory("TileDialog", &create<ArrangeDialog, DockBehavior>);
registerFactory("Symbols", &create<SymbolsDialog, DockBehavior>);
+
+#if HAVE_POTRACE
registerFactory("Trace", &create<TraceDialog, DockBehavior>);
+#endif
+
registerFactory("PixelArt", &create<PixelArtDialog, DockBehavior>);
registerFactory("Transformation", &create<Transformation, DockBehavior>);
registerFactory("UndoHistory", &create<UndoHistory, DockBehavior>);
diff --git a/src/ui/dialog/document-properties.cpp b/src/ui/dialog/document-properties.cpp
index b04e8ecc1..c2c5c5005 100644
--- a/src/ui/dialog/document-properties.cpp
+++ b/src/ui/dialog/document-properties.cpp
@@ -116,10 +116,11 @@ DocumentProperties::DocumentProperties()
_page_metadata2(Gtk::manage(new UI::Widget::NotebookPage(1, 1))),
//---------------------------------------------------------------
_rcb_antialias(_("Use antialiasing"), _("If unset, no antialiasing will be done on the drawing"), "shape-rendering", _wr, false, NULL, NULL, NULL, "crispEdges"),
+ _rcb_checkerboard(_("Checkerboard background"), _("If set, use checkerboard for background, otherwise use background color at full opacity."), "inkscape:pagecheckerboard", _wr, false),
_rcb_canb(_("Show page _border"), _("If set, rectangular page border is shown"), "showborder", _wr, false),
_rcb_bord(_("Border on _top of drawing"), _("If set, border is always on top of the drawing"), "borderlayer", _wr, false),
_rcb_shad(_("_Show border shadow"), _("If set, page border shows a shadow on its right and lower side"), "inkscape:showpageshadow", _wr, false),
- _rcp_bg(_("Back_ground color:"), _("Background color"), _("Color of the page background. Note: transparency setting ignored while editing but used when exporting to bitmap."), "pagecolor", "inkscape:pageopacity", _wr),
+ _rcp_bg(_("Back_ground color:"), _("Background color"), _("Color of the page background. Note: transparency setting ignored while editing if 'Checkerboard background' unset (but used when exporting to bitmap)."), "pagecolor", "inkscape:pageopacity", _wr),
_rcp_bord(_("Border _color:"), _("Page border color"), _("Color of the page border"), "bordercolor", "borderopacity", _wr),
_rum_deflt(_("Display _units:"), "inkscape:document-units", _wr),
_page_sizer(_wr),
@@ -327,10 +328,19 @@ void DocumentProperties::build_page()
Gtk::Label* label_gen = Gtk::manage (new Gtk::Label);
label_gen->set_markup (_("<b>General</b>"));
+
Gtk::Label *label_for = Gtk::manage (new Gtk::Label);
label_for->set_markup (_("<b>Page Size</b>"));
+
+ Gtk::Label* label_bkg = Gtk::manage (new Gtk::Label);
+ label_bkg->set_markup (_("<b>Background</b>"));
+
+ Gtk::Label* label_bdr = Gtk::manage (new Gtk::Label);
+ label_bdr->set_markup (_("<b>Border</b>"));
+
Gtk::Label* label_dsp = Gtk::manage (new Gtk::Label);
label_dsp->set_markup (_("<b>Display</b>"));
+
_page_sizer.init();
Gtk::Widget *const widget_array[] =
@@ -343,13 +353,16 @@ void DocumentProperties::build_page()
label_for, 0,
0, &_page_sizer,
0, 0,
- label_dsp, 0,
+ label_bkg, 0,
+ 0, &_rcb_checkerboard,
+ _rcp_bg._label, &_rcp_bg,
+ label_bdr, 0,
0, &_rcb_canb,
0, &_rcb_bord,
0, &_rcb_shad,
- 0, &_rcb_antialias,
- _rcp_bg._label, &_rcp_bg,
_rcp_bord._label, &_rcp_bord,
+ label_dsp, 0,
+ 0, &_rcb_antialias,
};
std::list<Gtk::Widget*> _slaveList;
@@ -435,13 +448,13 @@ void DocumentProperties::populate_available_profiles(){
*/
static void sanitizeName( Glib::ustring& str )
{
- if (str.size() > 1) {
+ if (str.size() > 0) {
char val = str.at(0);
if (((val < 'A') || (val > 'Z'))
&& ((val < 'a') || (val > 'z'))
&& (val != '_')
&& (val != ':')) {
- str.replace(0, 1, "-");
+ str.insert(0, "_");
}
for (Glib::ustring::size_type i = 1; i < str.size(); i++) {
char val = str.at(i);
@@ -479,7 +492,13 @@ void DocumentProperties::linkSelectedProfile()
std::vector<std::pair<Glib::ustring, Glib::ustring> > pairs = ColorProfile::getProfileFilesWithNames();
Glib::ustring file = pairs[row].first;
Glib::ustring name = pairs[row].second;
-
+ std::set<SPObject *> current = SP_ACTIVE_DOCUMENT->getResourceList( "iccprofile" );
+ for (std::set<SPObject *>::const_iterator it = current.begin(); it != current.end(); ++it) {
+ SPObject* obj = *it;
+ Inkscape::ColorProfile* prof = reinterpret_cast<Inkscape::ColorProfile*>(obj);
+ if (!strcmp(prof->href, file.c_str()))
+ return;
+ }
Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
Inkscape::XML::Node *cprofRepr = xml_doc->createElement("svg:color-profile");
gchar* tmp = g_strdup(name.c_str());
@@ -487,6 +506,8 @@ void DocumentProperties::linkSelectedProfile()
sanitizeName(nameStr);
cprofRepr->setAttribute("name", nameStr.c_str());
cprofRepr->setAttribute("xlink:href", (gchar*) file.c_str());
+ cprofRepr->setAttribute("id", (gchar*) file.c_str());
+
// Checks whether there is a defs element. Creates it when needed
Inkscape::XML::Node *defsRepr = sp_repr_lookup_name(xml_doc, "svg:defs");
@@ -511,17 +532,16 @@ void DocumentProperties::linkSelectedProfile()
void DocumentProperties::populate_linked_profiles_box()
{
_LinkedProfilesListStore->clear();
- const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "iccprofile" );
- if (current) {
- _emb_profiles_observer.set(SP_OBJECT(current->data)->parent);
+ std::set<SPObject *> current = SP_ACTIVE_DOCUMENT->getResourceList( "iccprofile" );
+ if (! current.empty()) {
+ _emb_profiles_observer.set((*(current.begin()))->parent);
}
- while ( current ) {
- SPObject* obj = SP_OBJECT(current->data);
+ for (std::set<SPObject *>::const_iterator it = current.begin(); it != current.end(); ++it) {
+ SPObject* obj = *it;
Inkscape::ColorProfile* prof = reinterpret_cast<Inkscape::ColorProfile*>(obj);
Gtk::TreeModel::Row row = *(_LinkedProfilesListStore->append());
row[_LinkedProfilesListColumns.nameColumn] = prof->name;
// row[_LinkedProfilesListColumns.previewColumn] = "Color Preview";
- current = g_slist_next(current);
}
}
@@ -594,19 +614,15 @@ void DocumentProperties::removeSelectedProfile(){
return;
}
}
-
- const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "iccprofile" );
- while ( current ) {
- SPObject* obj = SP_OBJECT(current->data);
+ std::set<SPObject *> current = SP_ACTIVE_DOCUMENT->getResourceList( "iccprofile" );
+ for (std::set<SPObject *>::const_iterator it = current.begin(); it != current.end(); ++it) {
+ SPObject* obj = *it;
Inkscape::ColorProfile* prof = reinterpret_cast<Inkscape::ColorProfile*>(obj);
if (!name.compare(prof->name)){
-
- //XML Tree being used directly here while it shouldn't be.
- sp_repr_unparent(obj->getRepr());
+ prof->deleteObject(true, false);
DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_EDIT_REMOVE_COLOR_PROFILE, _("Remove linked color profile"));
break; // removing the color profile likely invalidates part of the traversed list, stop traversing here.
}
- current = g_slist_next(current);
}
populate_linked_profiles_box();
@@ -722,9 +738,9 @@ void DocumentProperties::build_cms()
_LinkedProfilesList.signal_button_release_event().connect_notify(sigc::mem_fun(*this, &DocumentProperties::linked_profiles_list_button_release));
cms_create_popup_menu(_LinkedProfilesList, sigc::mem_fun(*this, &DocumentProperties::removeSelectedProfile));
- const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "defs" );
- if (current) {
- _emb_profiles_observer.set(SP_OBJECT(current->data)->parent);
+ std::set<SPObject *> current = SP_ACTIVE_DOCUMENT->getResourceList( "defs" );
+ if (!current.empty()) {
+ _emb_profiles_observer.set((*(current.begin()))->parent);
}
_emb_profiles_observer.signal_changed().connect(sigc::mem_fun(*this, &DocumentProperties::populate_linked_profiles_box));
onColorProfileSelectRow();
@@ -959,9 +975,9 @@ void DocumentProperties::build_scripting()
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
//TODO: review this observers code:
- const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
- if (current) {
- _scripts_observer.set(SP_OBJECT(current->data)->parent);
+ std::set<SPObject *> current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
+ if (! current.empty()) {
+ _scripts_observer.set((*(current.begin()))->parent);
}
_scripts_observer.signal_changed().connect(sigc::mem_fun(*this, &DocumentProperties::populate_script_lists));
onEmbeddedScriptSelectRow();
@@ -1174,9 +1190,9 @@ void DocumentProperties::removeExternalScript(){
}
}
- const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
- while ( current ) {
- SPObject* obj = reinterpret_cast<SPObject *>(current->data);
+ std::set<SPObject *> current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
+ for (std::set<SPObject *>::const_iterator it = current.begin(); it != current.end(); ++it) {
+ SPObject* obj = *it;
if (obj) {
SPScript* script = dynamic_cast<SPScript *>(obj);
if (script && (name == script->xlinkhref)) {
@@ -1191,7 +1207,6 @@ void DocumentProperties::removeExternalScript(){
}
}
}
- current = g_slist_next(current);
}
populate_script_lists();
@@ -1253,9 +1268,9 @@ void DocumentProperties::changeEmbeddedScript(){
}
bool voidscript=true;
- const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
- while ( current ) {
- SPObject* obj = SP_OBJECT(current->data);
+ std::set<SPObject *> current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
+ for (std::set<SPObject *>::const_iterator it = current.begin(); it != current.end(); ++it) {
+ SPObject* obj = *it;
if (id == obj->getId()){
int count=0;
@@ -1279,7 +1294,6 @@ void DocumentProperties::changeEmbeddedScript(){
}
}
}
- current = g_slist_next(current);
}
if (voidscript)
@@ -1299,9 +1313,9 @@ void DocumentProperties::editEmbeddedScript(){
}
Inkscape::XML::Document *xml_doc = SP_ACTIVE_DOCUMENT->getReprDoc();
- const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
- while ( current ) {
- SPObject* obj = SP_OBJECT(current->data);
+ std::set<SPObject *> current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
+ for (std::set<SPObject *>::const_iterator it = current.begin(); it != current.end(); ++it) {
+ SPObject* obj = *it;
if (id == obj->getId()){
//XML Tree being used directly here while it shouldn't be.
@@ -1317,21 +1331,20 @@ void DocumentProperties::editEmbeddedScript(){
DocumentUndo::done(SP_ACTIVE_DOCUMENT, SP_VERB_EDIT_EMBEDDED_SCRIPT, _("Edit embedded script"));
}
}
- current = g_slist_next(current);
}
}
void DocumentProperties::populate_script_lists(){
_ExternalScriptsListStore->clear();
_EmbeddedScriptsListStore->clear();
- const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
- if (current) {
- SPObject *obj = reinterpret_cast<SPObject *>(current->data);
+ std::set<SPObject *> current = SP_ACTIVE_DOCUMENT->getResourceList( "script" );
+ if (!current.empty()) {
+ SPObject *obj = *(current.begin());
g_assert(obj != NULL);
_scripts_observer.set(obj->parent);
}
- while ( current ) {
- SPObject* obj = reinterpret_cast<SPObject *>(current->data);
+ for (std::set<SPObject *>::const_iterator it = current.begin(); it != current.end(); ++it) {
+ SPObject* obj = *it;
SPScript* script = dynamic_cast<SPScript *>(obj);
g_assert(script != NULL);
if (script->xlinkhref)
@@ -1344,8 +1357,6 @@ void DocumentProperties::populate_script_lists(){
Gtk::TreeModel::Row row = *(_EmbeddedScriptsListStore->append());
row[_EmbeddedScriptsListColumns.idColumn] = obj->getId();
}
-
- current = g_slist_next(current);
}
}
@@ -1364,12 +1375,11 @@ void DocumentProperties::update_gridspage()
//add tabs
bool grids_present = false;
- for (GSList const * l = nv->grids; l != NULL; l = l->next) {
- Inkscape::CanvasGrid * grid = (Inkscape::CanvasGrid*) l->data;
- if (!grid->repr->attribute("id")) continue; // update_gridspage is called again when "id" is added
- Glib::ustring name(grid->repr->attribute("id"));
+ for(std::vector<Inkscape::CanvasGrid *>::const_iterator it = nv->grids.begin(); it != nv->grids.end(); ++it) {
+ if (!(*it)->repr->attribute("id")) continue; // update_gridspage is called again when "id" is added
+ Glib::ustring name((*it)->repr->attribute("id"));
const char *icon = NULL;
- switch (grid->getGridType()) {
+ switch ((*it)->getGridType()) {
case GRID_RECTANGULAR:
icon = "grid-rectangular";
break;
@@ -1379,7 +1389,7 @@ void DocumentProperties::update_gridspage()
default:
break;
}
- _grids_notebook.append_page(*grid->newWidget(), _createPageTabLabel(name, icon));
+ _grids_notebook.append_page(*(*it)->newWidget(), _createPageTabLabel(name, icon));
grids_present = true;
}
_grids_notebook.show_all();
@@ -1441,6 +1451,7 @@ void DocumentProperties::update()
set_sensitive (true);
//-----------------------------------------------------------page page
+ _rcb_checkerboard.setActive (nv->pagecheckerboard);
_rcp_bg.setRgba32 (nv->pagecolor);
_rcb_canb.setActive (nv->showborder);
_rcb_bord.setActive (nv->borderlayer == SP_BORDER_LAYER_TOP);
@@ -1639,14 +1650,9 @@ void DocumentProperties::onRemoveGrid()
SPDesktop *dt = getDesktop();
SPNamedView *nv = dt->getNamedView();
Inkscape::CanvasGrid * found_grid = NULL;
- int i = 0;
- for (GSList const * l = nv->grids; l != NULL; l = l->next, i++) { // not a very nice fix, but works.
- Inkscape::CanvasGrid * grid = (Inkscape::CanvasGrid*) l->data;
- if (pagenum == i) {
- found_grid = grid;
- break; // break out of for-loop
- }
- }
+ if( pagenum < (gint)nv->grids.size())
+ found_grid = nv->grids[pagenum];
+
if (found_grid) {
// delete the grid that corresponds with the selected tab
// when the grid is deleted from SVG, the SPNamedview handler automatically deletes the object, so found_grid becomes an invalid pointer!
diff --git a/src/ui/dialog/document-properties.h b/src/ui/dialog/document-properties.h
index b1f90b4b7..7340b67f5 100644
--- a/src/ui/dialog/document-properties.h
+++ b/src/ui/dialog/document-properties.h
@@ -118,6 +118,7 @@ protected:
UI::Widget::Registry _wr;
//---------------------------------------------------------------
UI::Widget::RegisteredCheckButton _rcb_antialias;
+ UI::Widget::RegisteredCheckButton _rcb_checkerboard;
UI::Widget::RegisteredCheckButton _rcb_canb;
UI::Widget::RegisteredCheckButton _rcb_bord;
UI::Widget::RegisteredCheckButton _rcb_shad;
diff --git a/src/ui/dialog/export.cpp b/src/ui/dialog/export.cpp
index 1edfdfe80..2fb5f9e3b 100644
--- a/src/ui/dialog/export.cpp
+++ b/src/ui/dialog/export.cpp
@@ -474,7 +474,14 @@ void Export::set_default_filename () {
doc_export_name = filename_entry.get_text();
}
+ else if ( SP_ACTIVE_DOCUMENT )
+ {
+ Glib::ustring filename = create_filepath_from_id (_("bitmap"), filename_entry.get_text());
+ filename_entry.set_text(filename);
+ filename_entry.set_position(filename.length());
+ doc_export_name = filename_entry.get_text();
+ }
}
#if WITH_GTKMM_3_0
@@ -814,7 +821,7 @@ void Export::onAreaToggled ()
if (filename.empty()) {
const gchar * id = "object";
const std::vector<XML::Node*> reprlst = SP_ACTIVE_DESKTOP->getSelection()->reprList();
- for(std::vector<XML::Node*>::const_iterator i=reprlst.begin(); reprlst.end() != i; i++) {
+ for(std::vector<XML::Node*>::const_iterator i=reprlst.begin(); reprlst.end() != i; ++i) {
Inkscape::XML::Node * repr = *i;
if (repr->attribute("id")) {
id = repr->attribute("id");
@@ -1023,7 +1030,7 @@ void Export::onExport ()
gint export_count = 0;
std::vector<SPItem*> itemlist=desktop->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator i = itemlist.begin();i!=itemlist.end() && !interrupted ;i++){
+ for(std::vector<SPItem*>::const_iterator i = itemlist.begin();i!=itemlist.end() && !interrupted ;++i){
SPItem *item = *i;
prog_dlg->set_data("current", GINT_TO_POINTER(n));
@@ -1232,7 +1239,7 @@ void Export::onExport ()
DocumentUndo::setUndoSensitive(doc, false);
reprlst = desktop->getSelection()->reprList();
- for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprlst.begin(); reprlst.end() != i; i++) {
+ for(std::vector<Inkscape::XML::Node*>::const_iterator i=reprlst.begin(); reprlst.end() != i; ++i) {
Inkscape::XML::Node * repr = *i;
const gchar * temp_string;
Glib::ustring dir = Glib::path_get_dirname(filename.c_str());
diff --git a/src/ui/dialog/filedialogimpl-gtkmm.cpp b/src/ui/dialog/filedialogimpl-gtkmm.cpp
index 17cf835cd..042637d22 100644
--- a/src/ui/dialog/filedialogimpl-gtkmm.cpp
+++ b/src/ui/dialog/filedialogimpl-gtkmm.cpp
@@ -199,37 +199,9 @@ void SVGPreview::showImage(Glib::ustring &theFileName)
// files so we assume they are well formed.
// std::cout << "SVGPreview::showImage: " << theFileName << std::endl;
- std::ifstream input(theFileName.c_str());
-
std::string width;
std::string height;
- if( !input ) {
- std::cerr << "SVGPreview::showImage: Failed to open file: " << theFileName << std::endl;
- } else {
-
- std::string token;
-
- Glib::MatchInfo match_info;
- Glib::RefPtr<Glib::Regex> regex1 = Glib::Regex::create("width=\"(.*)\"");
- Glib::RefPtr<Glib::Regex> regex2 = Glib::Regex::create("height=\"(.*)\"");
-
- while( !input.eof() && (height.empty() || width.empty()) ) {
-
- input >> token;
- // std::cout << "|" << token << "|" << std::endl;
-
- if (regex1->match(token, match_info)) {
- width = match_info.fetch(1).raw();
- }
-
- if (regex2->match(token, match_info)) {
- height = match_info.fetch(1).raw();
- }
-
- }
- }
-
/*#####################################
# LET'S HAVE SOME FUN WITH SVG!
# Instead of just loading an image, why
@@ -265,6 +237,46 @@ void SVGPreview::showImage(Glib::ustring &theFileName)
gint imgWidth = img->get_width();
gint imgHeight = img->get_height();
+
+ Glib::ustring svg = ".svg";
+ if (hasSuffix(fileName, svg)) {
+ std::ifstream input(theFileName.c_str());
+ if( !input ) {
+ std::cerr << "SVGPreview::showImage: Failed to open file: " << theFileName << std::endl;
+ } else {
+
+ std::string token;
+
+ Glib::MatchInfo match_info;
+ Glib::RefPtr<Glib::Regex> regex1 = Glib::Regex::create("width=\"(.*)\"");
+ Glib::RefPtr<Glib::Regex> regex2 = Glib::Regex::create("height=\"(.*)\"");
+
+ while( !input.eof() && (height.empty() || width.empty()) ) {
+
+ input >> token;
+ // std::cout << "|" << token << "|" << std::endl;
+
+ if (regex1->match(token, match_info)) {
+ width = match_info.fetch(1).raw();
+ }
+
+ if (regex2->match(token, match_info)) {
+ height = match_info.fetch(1).raw();
+ }
+
+ }
+ }
+ }
+
+ // TODO: replace int to string conversion with std::to_string when fully C++11 compliant
+ if (height.empty() || width.empty()) {
+ std::ostringstream s_width;
+ std::ostringstream s_height;
+ s_width << imgWidth;
+ s_height << imgHeight;
+ width = s_width.str();
+ height = s_height.str();
+ }
// Find the minimum scale to fit the image inside the preview area
double scaleFactorX = (0.9 * (double)previewWidth) / ((double)imgWidth);
diff --git a/src/ui/dialog/filter-effects-dialog.cpp b/src/ui/dialog/filter-effects-dialog.cpp
index 1ff9e4a1b..7e9d8481a 100644
--- a/src/ui/dialog/filter-effects-dialog.cpp
+++ b/src/ui/dialog/filter-effects-dialog.cpp
@@ -1474,7 +1474,7 @@ void FilterEffectsDialog::FilterModifier::update_selection(Selection *sel)
std::set<SPObject*> used;
std::vector<SPItem*> itemlist=sel->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) {
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; ++i) {
SPObject *obj = *i;
SPStyle *style = obj->style;
if (!style || !SP_IS_ITEM(obj)) {
@@ -1555,7 +1555,7 @@ void FilterEffectsDialog::FilterModifier::on_selection_toggled(const Glib::ustri
filter = 0;
std::vector<SPItem*> itemlist=sel->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) {
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; ++i) {
SPItem * item = *i;
SPStyle *style = item->style;
g_assert(style != NULL);
@@ -1589,13 +1589,14 @@ void FilterEffectsDialog::FilterModifier::update_filters()
{
SPDesktop* desktop = _dialog.getDesktop();
SPDocument* document = desktop->getDocument();
- const GSList* filters = document->getResourceList("filter");
+
+ std::set<SPObject *> filters = document->getResourceList( "filter" );
_model->clear();
- for(const GSList *l = filters; l; l = l->next) {
+ for (std::set<SPObject *>::const_iterator it = filters.begin(); it != filters.end(); ++it) {
Gtk::TreeModel::Row row = *_model->append();
- SPFilter* f = SP_FILTER(l->data);
+ SPFilter* f = SP_FILTER(*it);
row[_columns.filter] = f;
const gchar* lbl = f->label();
const gchar* id = f->getId();
@@ -1669,7 +1670,7 @@ void FilterEffectsDialog::FilterModifier::remove_filter()
// Delete all references to this filter
std::vector<SPItem*> x,y;
std::vector<SPItem*> all = get_all_items(x, _desktop->currentRoot(), _desktop, false, false, true, y);
- for(std::vector<SPItem*>::const_iterator i=all.begin(); all.end() != i; i++) {
+ for(std::vector<SPItem*>::const_iterator i=all.begin(); all.end() != i; ++i) {
if (!SP_IS_ITEM(*i)) {
continue;
}
@@ -2756,8 +2757,6 @@ FilterEffectsDialog::FilterEffectsDialog()
_sizegroup = Gtk::SizeGroup::create(Gtk::SIZE_GROUP_HORIZONTAL);
_sizegroup->set_ignore_hidden();
- _add_primitive_type.remove_row(NR_FILTER_TILE);
-
// Initialize widget hierarchy
#if WITH_GTKMM_3_0
Gtk::Paned* hpaned = Gtk::manage(new Gtk::Paned);
@@ -2900,7 +2899,7 @@ void FilterEffectsDialog::init_settings_widgets()
_settings->add_spinscale(1, SP_PROP_FLOOD_OPACITY, _("Opacity:"), 0, 1, 0.1, 0.01, 2);
_settings->type(NR_FILTER_GAUSSIANBLUR);
- _settings->add_dualspinscale(SP_ATTR_STDDEVIATION, _("Standard Deviation:"), 0.01, 100, 1, 0.01, 1, _("The standard deviation for the blur operation."));
+ _settings->add_dualspinscale(SP_ATTR_STDDEVIATION, _("Standard Deviation:"), 0.01, 100, 1, 0.01, 2, _("The standard deviation for the blur operation."));
_settings->type(NR_FILTER_MERGE);
_settings->add_no_params();
@@ -2925,7 +2924,7 @@ void FilterEffectsDialog::init_settings_widgets()
_settings->add_lightsource();
_settings->type(NR_FILTER_TILE);
- _settings->add_notimplemented();
+ _settings->add_no_params();
_settings->type(NR_FILTER_TURBULENCE);
// _settings->add_checkbutton(false, SP_ATTR_STITCHTILES, _("Stitch Tiles"), "stitch", "noStitch");
@@ -3017,7 +3016,7 @@ void FilterEffectsDialog::update_primitive_infobox()
break;
case(NR_FILTER_TILE):
_infobox_icon.set_from_icon_name("feTile-icon", Gtk::ICON_SIZE_DIALOG);
- _infobox_desc.set_markup(_("The <b>feTile</b> filter primitive tiles a region with its input graphic"));
+ _infobox_desc.set_markup(_("The <b>feTile</b> filter primitive tiles a region with an input graphic. The source tile is defined by the filter primitive subregion of the input."));
break;
case(NR_FILTER_TURBULENCE):
_infobox_icon.set_from_icon_name("feTurbulence-icon", Gtk::ICON_SIZE_DIALOG);
diff --git a/src/ui/dialog/filter-effects-dialog.h b/src/ui/dialog/filter-effects-dialog.h
index a067cd70c..283abb5b0 100644
--- a/src/ui/dialog/filter-effects-dialog.h
+++ b/src/ui/dialog/filter-effects-dialog.h
@@ -127,7 +127,11 @@ private:
Gtk::Button _add;
Glib::RefPtr<Gtk::Menu> _menu;
sigc::signal<void> _signal_filter_changed;
+#if __cplusplus <= 199711L
std::auto_ptr<Inkscape::XML::SignalObserver> _observer;
+#else
+ std::unique_ptr<Inkscape::XML::SignalObserver> _observer;
+#endif
};
class PrimitiveColumns : public Gtk::TreeModel::ColumnRecord
@@ -243,7 +247,11 @@ private:
sigc::connection _scroll_connection;
int _autoscroll_y;
int _autoscroll_x;
+#if __cplusplus <= 199711L
std::auto_ptr<Inkscape::XML::SignalObserver> _observer;
+#else
+ std::unique_ptr<Inkscape::XML::SignalObserver> _observer;
+#endif
int _input_type_width;
int _input_type_height;
};
diff --git a/src/ui/dialog/find.cpp b/src/ui/dialog/find.cpp
index a8ac42a1b..0f368c5ac 100644
--- a/src/ui/dialog/find.cpp
+++ b/src/ui/dialog/find.cpp
@@ -561,7 +561,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b
std::vector<SPItem*> out;
if (check_searchin_text.get_active()) {
- for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) {
+ for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) {
SPObject *obj = *i;
SPItem *item = dynamic_cast<SPItem *>(obj);
g_assert(item != NULL);
@@ -584,7 +584,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b
bool attrvalue = check_attributevalue.get_active();
if (ids) {
- for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) {
+ for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) {
SPObject *obj = *i;
SPItem *item = dynamic_cast<SPItem *>(obj);
if (item_id_match(item, text, exact, casematch)) {
@@ -600,7 +600,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b
if (style) {
- for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) {
+ for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) {
SPObject *obj = *i;
SPItem *item = dynamic_cast<SPItem *>(obj);
g_assert(item != NULL);
@@ -617,7 +617,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b
if (attrname) {
- for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) {
+ for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) {
SPObject *obj = *i;
SPItem *item = dynamic_cast<SPItem *>(obj);
g_assert(item != NULL);
@@ -634,7 +634,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b
if (attrvalue) {
- for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) {
+ for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) {
SPObject *obj = *i;
SPItem *item = dynamic_cast<SPItem *>(obj);
g_assert(item != NULL);
@@ -651,7 +651,7 @@ std::vector<SPItem*> Find::filter_fields (std::vector<SPItem*> &l, bool exact, b
if (font) {
- for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; i++) {
+ for(std::vector<SPItem*>::const_reverse_iterator i=in.rbegin(); in.rend() != i; ++i) {
SPObject *obj = *i;
SPItem *item = dynamic_cast<SPItem *>(obj);
g_assert(item != NULL);
@@ -718,7 +718,7 @@ bool Find::item_type_match (SPItem *item)
std::vector<SPItem*> Find::filter_types (std::vector<SPItem*> &l)
{
std::vector<SPItem*> n;
- for(std::vector<SPItem*>::const_reverse_iterator i=l.rbegin(); l.rend() != i; i++) {
+ for(std::vector<SPItem*>::const_reverse_iterator i=l.rbegin(); l.rend() != i; ++i) {
SPObject *obj = *i;
SPItem *item = dynamic_cast<SPItem *>(obj);
g_assert(item != NULL);
@@ -762,7 +762,7 @@ std::vector<SPItem*> &Find::all_items (SPObject *r, std::vector<SPItem*> &l, boo
std::vector<SPItem*> &Find::all_selection_items (Inkscape::Selection *s, std::vector<SPItem*> &l, SPObject *ancestor, bool hidden, bool locked)
{
std::vector<SPItem*> itemlist=s->itemList();
- for(std::vector<SPItem*>::const_reverse_iterator i=itemlist.rbegin(); itemlist.rend() != i; i++) {
+ for(std::vector<SPItem*>::const_reverse_iterator i=itemlist.rbegin(); itemlist.rend() != i; ++i) {
SPObject *obj = *i;
SPItem *item = dynamic_cast<SPItem *>(obj);
g_assert(item != NULL);
diff --git a/src/ui/dialog/font-substitution.cpp b/src/ui/dialog/font-substitution.cpp
index 19506c6a3..f219f3db6 100644
--- a/src/ui/dialog/font-substitution.cpp
+++ b/src/ui/dialog/font-substitution.cpp
@@ -154,7 +154,7 @@ std::vector<SPItem*> FontSubstitution::getFontReplacedItems(SPDocument* doc, Gli
std::map<SPItem *, Glib::ustring> mapFontStyles;
allList = get_all_items(x, doc->getRoot(), desktop, false, false, true, y);
- for(std::vector<SPItem*>::const_iterator i = allList.begin();i!=allList.end();i++){
+ for(std::vector<SPItem*>::const_iterator i = allList.begin();i!=allList.end();++i){
SPItem *item = *i;
SPStyle *style = item->style;
Glib::ustring family = "";
diff --git a/src/ui/dialog/glyphs.cpp b/src/ui/dialog/glyphs.cpp
index 7ca277ea2..56b001291 100644
--- a/src/ui/dialog/glyphs.cpp
+++ b/src/ui/dialog/glyphs.cpp
@@ -579,7 +579,7 @@ void GlyphsPanel::insertText()
{
SPItem *textItem = 0;
std::vector<SPItem*> itemlist=targetDesktop->selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) {
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; ++i) {
if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) {
textItem = *i;
break;
@@ -689,7 +689,7 @@ void GlyphsPanel::calcCanInsert()
{
int items = 0;
std::vector<SPItem*> itemlist=targetDesktop->selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; i++) {
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin(); itemlist.end() != i; ++i) {
if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i)) {
++items;
}
diff --git a/src/ui/dialog/grid-arrange-tab.cpp b/src/ui/dialog/grid-arrange-tab.cpp
index ccd23a572..639e463ea 100644
--- a/src/ui/dialog/grid-arrange-tab.cpp
+++ b/src/ui/dialog/grid-arrange-tab.cpp
@@ -75,16 +75,10 @@ static bool sp_compare_x_position(SPItem *first, SPItem *second)
a_in_b_vert = false;
}
- if (!a_in_b_vert) {
- return true;
- }
- if (a_in_b_vert && a->min()[X] > b->min()[X]) {
- return false;
+ if (!a_in_b_vert) { // a and b are not in the same row
+ return (a->min()[Y] < b->min()[Y]);
}
- if (a_in_b_vert && a->min()[X] < b->min()[X]) {
- return true;
- }
- return false;
+ return (a->min()[X] < b->min()[X]);
}
/*
@@ -170,7 +164,7 @@ void GridArrangeTab::arrange()
Inkscape::Selection *selection = desktop->getSelection();
const std::vector<SPItem*> items = selection ? selection->itemList() : std::vector<SPItem*>();
- for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end(); ++i){
SPItem *item = *i;
Geom::OptRect b = item->documentVisualBounds();
if (!b) {
@@ -208,7 +202,7 @@ void GridArrangeTab::arrange()
cnt=0;
const std::vector<SPItem*> sizes(sorted);
- for (std::vector<SPItem*>::const_iterator i = sizes.begin();i!=sizes.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i = sizes.begin();i!=sizes.end(); ++i) {
SPItem *item = *i;
Geom::OptRect b = item->documentVisualBounds();
if (b) {
@@ -307,11 +301,11 @@ g_print("\n row = %f col = %f selection x= %f selection y = %f", total_row_h
cnt=0;
std::vector<SPItem*>::iterator it = sorted.begin();
- for (row_cnt=0; ((it != sorted.end()) && (row_cnt<NoOfRows)); row_cnt++) {
+ for (row_cnt=0; ((it != sorted.end()) && (row_cnt<NoOfRows)); ++row_cnt) {
GSList *current_row = NULL;
col_cnt = 0;
- for(;it!=sorted.end()&&col_cnt<NoOfCols;it++) {
+ for(;it!=sorted.end()&&col_cnt<NoOfCols;++it) {
current_row = g_slist_append (current_row, *it);
col_cnt++;
}
diff --git a/src/ui/dialog/guides.cpp b/src/ui/dialog/guides.cpp
index af8e2cc31..556d77a28 100644
--- a/src/ui/dialog/guides.cpp
+++ b/src/ui/dialog/guides.cpp
@@ -44,6 +44,7 @@ namespace Dialogs {
GuidelinePropertiesDialog::GuidelinePropertiesDialog(SPGuide *guide, SPDesktop *desktop)
: _desktop(desktop), _guide(guide),
+ _locked_toggle(_("Lo_cked"), _("Lock the movement of guides")),
_relative_toggle(_("Rela_tive change"), _("Move and/or rotate the guide relative to current settings")),
_spin_button_x(C_("Guides", "_X:"), "", UNIT_TYPE_LINEAR, "", "", &_unit_menu),
_spin_button_y(C_("Guides", "_Y:"), "", UNIT_TYPE_LINEAR, "", "", &_unit_menu),
@@ -97,9 +98,12 @@ void GuidelinePropertiesDialog::_onOK()
} else if ( deg_angle == 0. || deg_angle == 180. || deg_angle == -180.) {
normal = Geom::Point(0.,1.);
} else {
- double rad_angle = Geom::deg_to_rad( deg_angle );
+ double rad_angle = Geom::rad_from_deg( deg_angle );
normal = Geom::rot90(Geom::Point::polar(rad_angle, 1.0));
}
+ //To allow reposition from dialog
+ _guide->set_locked(false, true);
+
_guide->set_normal(normal, true);
double const points_x = _spin_button_x.getValue("px");
@@ -113,6 +117,11 @@ void GuidelinePropertiesDialog::_onOK()
const gchar* name = g_strdup( _label_entry.getEntry()->get_text().c_str() );
_guide->set_label(name, true);
+
+ const bool locked = _locked_toggle.get_active();
+
+ _guide->set_locked(locked, true);
+
g_free((gpointer) name);
#if WITH_GTKMM_3_0
@@ -269,6 +278,12 @@ void GuidelinePropertiesDialog::_setup() {
_relative_toggle.set_valign(Gtk::ALIGN_FILL);
_relative_toggle.set_hexpand();
_layout_table.attach(_relative_toggle, 1, 7, 2, 1);
+
+ // locked radio button
+ _locked_toggle.set_halign(Gtk::ALIGN_FILL);
+ _locked_toggle.set_valign(Gtk::ALIGN_FILL);
+ _locked_toggle.set_hexpand();
+ _layout_table.attach(_locked_toggle, 1, 8, 2, 1);
#else
_layout_table.attach(_spin_angle,
1, 3, 6, 7, Gtk::EXPAND | Gtk::FILL, Gtk::FILL);
@@ -276,11 +291,21 @@ void GuidelinePropertiesDialog::_setup() {
// mode radio button
_layout_table.attach(_relative_toggle,
1, 3, 7, 8, Gtk::EXPAND | Gtk::FILL, Gtk::FILL);
+
+ // locked radio button
+ _layout_table.attach(_locked_toggle,
+ 1, 3, 8, 9, Gtk::EXPAND | Gtk::FILL, Gtk::FILL);
#endif
_relative_toggle.signal_toggled().connect(sigc::mem_fun(*this, &GuidelinePropertiesDialog::_modeChanged));
_relative_toggle.set_active(_relative_toggle_status);
+ bool global_guides_lock = _desktop->namedview->lockguides;
+ if(global_guides_lock){
+ _locked_toggle.set_sensitive(false);
+ }
+ _locked_toggle.set_active(_guide->getLocked());
+
// don't know what this exactly does, but it results in that the dialog closes when entering a value and pressing enter (see LP bug 484187)
g_signal_connect_swapped(G_OBJECT(_spin_button_x.getWidget()->gobj()), "activate",
G_CALLBACK(gtk_window_activate_default), gobj());
@@ -301,7 +326,7 @@ void GuidelinePropertiesDialog::_setup() {
} else if (_guide->isHorizontal()) {
_oldangle = 0;
} else {
- _oldangle = Geom::rad_to_deg( std::atan2( - _guide->getNormal()[Geom::X], _guide->getNormal()[Geom::Y] ) );
+ _oldangle = Geom::deg_from_rad( std::atan2( - _guide->getNormal()[Geom::X], _guide->getNormal()[Geom::Y] ) );
}
{
diff --git a/src/ui/dialog/guides.h b/src/ui/dialog/guides.h
index 4ff7b4fde..5dce0d6ed 100644
--- a/src/ui/dialog/guides.h
+++ b/src/ui/dialog/guides.h
@@ -79,6 +79,7 @@ private:
Gtk::Label _label_name;
Gtk::Label _label_descr;
+ Inkscape::UI::Widget::CheckButton _locked_toggle;
Inkscape::UI::Widget::CheckButton _relative_toggle;
static bool _relative_toggle_status; // remember the status of the _relative_toggle_status button across instances
Inkscape::UI::Widget::UnitMenu _unit_menu;
diff --git a/src/ui/dialog/icon-preview.cpp b/src/ui/dialog/icon-preview.cpp
index 77f120e1a..83656a1f2 100644
--- a/src/ui/dialog/icon-preview.cpp
+++ b/src/ui/dialog/icon-preview.cpp
@@ -363,7 +363,7 @@ void IconPreviewPanel::refreshPreview()
//g_message("found a selection to play with");
std::vector<SPItem*> const items = sel->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();!target && i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();!target && i!=items.end();++i){
SPItem* item = *i;
gchar const *id = item->getId();
if ( id ) {
diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp
index 3b0731953..b20f71a6a 100644
--- a/src/ui/dialog/inkscape-preferences.cpp
+++ b/src/ui/dialog/inkscape-preferences.cpp
@@ -206,6 +206,15 @@ void InkscapePreferences::AddDotSizeSpinbutton(DialogPage &p, Glib::ustring cons
false );
}
+void InkscapePreferences::AddBaseSimplifySpinbutton(DialogPage &p, Glib::ustring const &prefs_path, double def_value)
+{
+ PrefSpinButton* sb = Gtk::manage( new PrefSpinButton);
+ sb->init ( prefs_path + "/base-simplify", 0.0, 100.0, 1.0, 10.0, def_value, false, false);
+ p.add_line( false, _("Base simplify:"), *sb, _("on dinamic LPE simplify"),
+ _("Base simplify of dinamic LPE based simplify"),
+ false );
+}
+
static void StyleFromSelectionToTool(Glib::ustring const &prefs_path, StyleSwatch *swatch)
{
@@ -425,6 +434,7 @@ void InkscapePreferences::initPageTools()
this->AddSelcueCheckbox(_page_pencil, "/tools/freehand/pencil", true);
this->AddNewObjectsStyle(_page_pencil, "/tools/freehand/pencil");
this->AddDotSizeSpinbutton(_page_pencil, "/tools/freehand/pencil", 3.0);
+ this->AddBaseSimplifySpinbutton(_page_pencil, "/tools/freehand/pencil", 25.0);
_page_pencil.add_group_header( _("Sketch mode"));
_page_pencil.add_line( true, "", _pencil_average_all_sketches, "",
_("If on, the sketch result will be the normal average of all sketches made, instead of averaging the old result with the new sketch"));
@@ -478,10 +488,12 @@ void InkscapePreferences::initPageTools()
this->AddPage(_page_eraser, _("Eraser"), iter_tools, PREFS_PAGE_TOOLS_ERASER);
this->AddNewObjectsStyle(_page_eraser, "/tools/eraser");
+#if HAVE_POTRACE
//Paint Bucket
this->AddPage(_page_paintbucket, _("Paint Bucket"), iter_tools, PREFS_PAGE_TOOLS_PAINTBUCKET);
this->AddSelcueCheckbox(_page_paintbucket, "/tools/paintbucket", false);
this->AddNewObjectsStyle(_page_paintbucket, "/tools/paintbucket");
+#endif
//Gradient
this->AddPage(_page_gradient, _("Gradient"), iter_tools, PREFS_PAGE_TOOLS_GRADIENT);
@@ -522,22 +534,54 @@ void InkscapePreferences::initPageUI()
Gtk::TreeModel::iterator iter_ui = this->AddPage(_page_ui, _("Interface"), PREFS_PAGE_UI);
_path_ui = _page_list.get_model()->get_path(iter_ui);
- Glib::ustring languages[] = {_("System default"), _("Albanian (sq)"), _("Amharic (am)"), _("Arabic (ar)"), _("Armenian (hy)"),_("Azerbaijani (az)"), _("Basque (eu)"), _("Belarusian (be)"),
- _("Bulgarian (bg)"), _("Bengali (bn)"), _("Bengali/Bangladesh (bn_BD)"), _("Breton (br)"), _("Catalan (ca)"), _("Valencian Catalan (ca@valencia)"), _("Chinese/China (zh_CN)"),
- _("Chinese/Taiwan (zh_TW)"), _("Croatian (hr)"), _("Czech (cs)"),
- _("Danish (da)"), _("Dutch (nl)"), _("Dzongkha (dz)"), _("German (de)"), _("Greek (el)"), _("English (en)"), _("English/Australia (en_AU)"),
- _("English/Canada (en_CA)"), _("English/Great Britain (en_GB)"), _("Pig Latin (en_US@piglatin)"),
- _("Esperanto (eo)"), _("Estonian (et)"), _("Farsi (fa)"), _("Finnish (fi)"),
- _("French (fr)"), _("Irish (ga)"), _("Galician (gl)"), _("Hebrew (he)"), _("Hungarian (hu)"),
- _("Indonesian (id)"), _("Icelandic (is)"), _("Italian (it)"), _("Japanese (ja)"), _("Khmer (km)"), _("Kinyarwanda (rw)"), _("Korean (ko)"), _("Lithuanian (lt)"), _("Latvian (lv)"), _("Macedonian (mk)"),
- _("Mongolian (mn)"), _("Nepali (ne)"), _("Norwegian Bokmål (nb)"), _("Norwegian Nynorsk (nn)"), _("Panjabi (pa)"),
- _("Polish (pl)"), _("Portuguese (pt)"), _("Portuguese/Brazil (pt_BR)"), _("Romanian (ro)"), _("Russian (ru)"),
- _("Serbian (sr)"), _("Serbian in Latin script (sr@latin)"), _("Slovak (sk)"), _("Slovenian (sl)"), _("Spanish (es)"), _("Spanish/Mexico (es_MX)"),
- _("Swedish (sv)"),_("Telugu (te)"), _("Thai (th)"), _("Turkish (tr)"), _("Ukrainian (uk)"), _("Vietnamese (vi)")};
- Glib::ustring langValues[] = {"", "sq", "am", "ar", "hy", "az", "eu", "be", "bg", "bn", "bn_BD", "br", "ca", "ca@valencia", "zh_CN", "zh_TW", "hr", "cs", "da", "nl",
- "dz", "de", "el", "en", "en_AU", "en_CA", "en_GB", "en_US@piglatin", "eo", "et", "fa", "fi", "fr", "ga",
- "gl", "he", "hu", "id", "is", "it", "ja", "km", "rw", "ko", "lt", "lv", "mk", "mn", "ne", "nb", "nn", "pa",
- "pl", "pt", "pt_BR", "ro", "ru", "sr", "sr@latin", "sk", "sl", "es", "es_MX", "sv", "te", "th", "tr", "uk", "vi" };
+ Glib::ustring languages[] = {_("System default"),
+ _("Albanian (sq)"), _("Amharic (am)"), _("Arabic (ar)"), _("Armenian (hy)"), _("Assamese (as)"), _("Azerbaijani (az)"),
+ _("Basque (eu)"), _("Belarusian (be)"), _("Bulgarian (bg)"), _("Bengali (bn)"), _("Bengali/Bangladesh (bn_BD)"), _("Bodo (brx)"), _("Breton (br)"),
+ _("Catalan (ca)"), _("Valencian Catalan (ca@valencia)"), _("Chinese/China (zh_CN)"), _("Chinese/Taiwan (zh_TW)"), _("Croatian (hr)"), _("Czech (cs)"),
+ _("Danish (da)"), _("Dogri (doi)"), _("Dutch (nl)"), _("Dzongkha (dz)"),
+ _("German (de)"), _("Greek (el)"),
+ _("English (en)"), _("English/Australia (en_AU)"), _("English/Canada (en_CA)"), _("English/Great Britain (en_GB)"), _("Pig Latin (en_US@piglatin)"), _("Esperanto (eo)"), _("Estonian (et)"),
+ _("Farsi (fa)"), _("Finnish (fi)"), _("French (fr)"),
+ _("Galician (gl)"), _("Gujarati (gu)"),
+ _("Hebrew (he)"), _("Hindi (hi)"), _("Hungarian (hu)"),
+ _("Icelandic (is)"), _("Indonesian (id)"), _("Irish (ga)"), _("Italian (it)"),
+ _("Japanese (ja)"),
+ _("Kannada (kn)"), _("Kashmiri in Peso-Arabic script (ks@aran)"), _("Kashmiri in Devanagari script (ks@deva)"), _("Khmer (km)"), _("Kinyarwanda (rw)"), _("Konkani (kok)"), _("Konkani in Latin script (kok@latin)"), _("Korean (ko)"),
+ _("Latvian (lv)"), _("Lithuanian (lt)"),
+ _("Macedonian (mk)"), _("Maithili (mai)"), _("Malayalam (ml)"), _("Manipuri (mni)"), _("Manipuri in Bengali script (mni@beng)"), _("Marathi (mr)"), _("Mongolian (mn)"),
+ _("Nepali (ne)"), _("Norwegian Bokmål (nb)"), _("Norwegian Nynorsk (nn)"),
+ _("Odia (or)"),
+ _("Panjabi (pa)"), _("Polish (pl)"), _("Portuguese (pt)"), _("Portuguese/Brazil (pt_BR)"),
+ _("Romanian (ro)"), _("Russian (ru)"),
+ _("Sanskrit (sa)"), _("Santali (sat)"), _("Santali in Devanagari script (sat@deva)"), _("Serbian (sr)"), _("Serbian in Latin script (sr@latin)"),
+ _("Sindhi (sd)"), _("Sindhi in Devanagari script (sd@deva)"), _("Slovak (sk)"), _("Slovenian (sl)"), _("Spanish (es)"), _("Spanish/Mexico (es_MX)"), _("Swedish (sv)"),
+ _("Tamil (ta)"), _("Telugu (te)"), _("Thai (th)"), _("Turkish (tr)"),
+ _("Ukrainian (uk)"), _("Urdu (ur)"),
+ _("Vietnamese (vi)")};
+ Glib::ustring langValues[] = {"",
+ "sq", "am", "ar", "hy", "as", "az",
+ "eu", "be", "bg", "bn", "bn_BD", "brx", "br",
+ "ca", "ca@valencia", "zh_CN", "zh_TW", "hr", "cs",
+ "da", "doi", "nl", "dz",
+ "de", "el",
+ "en", "en_AU", "en_CA", "en_GB", "en_US@piglatin", "eo", "et",
+ "fa", "fi", "fr",
+ "gl", "gu",
+ "he", "hi", "hu",
+ "is", "id", "ga", "it",
+ "ja",
+ "kn", "ks@aran", "ks@deva", "km", "rw", "kok", "kok@latin", "ko",
+ "lv", "lt",
+ "mk", "mai", "ml", "mni", "mni@beng", "mr", "mn",
+ "ne", "nb", "nn",
+ "or",
+ "pa", "pl", "pt", "pt_BR",
+ "ro", "ru",
+ "sa", "sat", "sat@deva", "sr", "sr@latin",
+ "sd", "sd@deva", "sk", "sl", "es", "es_MX", "sv",
+ "ta", "te", "th", "tr",
+ "uk", "ur",
+ "vi" };
{
// sorting languages according to translated name
@@ -569,7 +613,7 @@ void InkscapePreferences::initPageUI()
_("Set the language for menus and number formats"), false);
{
- Glib::ustring sizeLabels[] = {_("Large"), _("Small"), _("Smaller")};
+ Glib::ustring sizeLabels[] = {C_("Icon size", "Large"), C_("Icon size", "Small"), C_("Icon size", "Smaller")};
int sizeValues[] = {0, 1, 2};
_misc_small_tools.init( "/toolbox/tools/small", sizeLabels, sizeValues, G_N_ELEMENTS(sizeLabels), 0 );
@@ -654,7 +698,7 @@ void InkscapePreferences::initPageUI()
_win_ontop_agressive.init ( _("Aggressive"), "/options/transientpolicy/value", 2, false, &_win_ontop_none);
{
- Glib::ustring defaultSizeLabels[] = {_("Small"), _("Large"), _("Maximized")};
+ Glib::ustring defaultSizeLabels[] = {C_("Window size", "Small"), C_("Window size", "Large"), C_("Window size", "Maximized")};
int defaultSizeValues[] = {0, 1, 2};
_win_default_size.init( "/options/defaultwindowsize/value", defaultSizeLabels, defaultSizeValues, G_N_ELEMENTS(defaultSizeLabels), 1 );
@@ -1218,37 +1262,47 @@ void InkscapePreferences::initPageBehavior()
_scroll_auto_thres.init ( "/options/autoscrolldistance/value", -600.0, 600.0, 1.0, 1.0, -10.0, true, false);
_page_scrolling.add_line( true, _("_Threshold:"), _scroll_auto_thres, _("pixels"),
_("How far (in screen pixels) you need to be from the canvas edge to trigger autoscroll; positive is outside the canvas, negative is within the canvas"), false);
-/*
- _scroll_space.init ( _("Left mouse button pans when Space is pressed"), "/options/spacepans/value", false);
- _page_scrolling.add_line( false, "", _scroll_space, "",
- _("When on, pressing and holding Space and dragging with left mouse button pans canvas (as in Adobe Illustrator); when off, Space temporarily switches to Selector tool (default)"));
-*/
+ _scroll_space.init ( _("Mouse move pans when Space is pressed"), "/options/spacebarpans/value", true);
+ _page_scrolling.add_line( true, "", _scroll_space, "",
+ _("When on, pressing and holding Space and dragging pans canvas"));
_wheel_zoom.init ( _("Mouse wheel zooms by default"), "/options/wheelzooms/value", false);
_page_scrolling.add_line( false, "", _wheel_zoom, "",
_("When on, mouse wheel zooms without Ctrl and scrolls canvas with Ctrl; when off, it zooms with Ctrl and scrolls without Ctrl"));
this->AddPage(_page_scrolling, _("Scrolling"), iter_behavior, PREFS_PAGE_BEHAVIOR_SCROLLING);
// Snapping options
+ _page_snapping.add_group_header( _("Snap indicator"));
+
_snap_indicator.init( _("Enable snap indicator"), "/options/snapindicator/value", true);
- _page_snapping.add_line( false, "", _snap_indicator, "",
+ _page_snapping.add_line( true, "", _snap_indicator, "",
_("After snapping, a symbol is drawn at the point that has snapped"));
- _snap_delay.init("/options/snapdelay/value", 0, 1000, 50, 100, 300, 0);
- _page_snapping.add_line( false, _("_Delay (in ms):"), _snap_delay, "",
- _("Postpone snapping as long as the mouse is moving, and then wait an additional fraction of a second. This additional delay is specified here. When set to zero or to a very small number, snapping will be immediate."), true);
+ _snap_indicator.changed_signal.connect( sigc::mem_fun(_snap_persistence, &Gtk::Widget::set_sensitive) );
+
+ _snap_persistence.init("/options/snapindicatorpersistence/value", 0.1, 10, 0.1, 1, 2, 1);
+ _page_snapping.add_line( true, _("Snap indicator persistence (in seconds):"), _snap_persistence, "",
+ _("Controls how long the snap indicator message will be shown, before it disappears"), true);
+
+ _page_snapping.add_group_header( _("What should snap"));
_snap_closest_only.init( _("Only snap the node closest to the pointer"), "/options/snapclosestonly/value", false);
- _page_snapping.add_line( false, "", _snap_closest_only, "",
+ _page_snapping.add_line( true, "", _snap_closest_only, "",
_("Only try to snap the node that is initially closest to the mouse pointer"));
_snap_weight.init("/options/snapweight/value", 0, 1, 0.1, 0.2, 0.5, 1);
- _page_snapping.add_line( false, _("_Weight factor:"), _snap_weight, "",
+ _page_snapping.add_line( true, _("_Weight factor:"), _snap_weight, "",
_("When multiple snap solutions are found, then Inkscape can either prefer the closest transformation (when set to 0), or prefer the node that was initially the closest to the pointer (when set to 1)"), true);
_snap_mouse_pointer.init( _("Snap the mouse pointer when dragging a constrained knot"), "/options/snapmousepointer/value", false);
- _page_snapping.add_line( false, "", _snap_mouse_pointer, "",
+ _page_snapping.add_line( true, "", _snap_mouse_pointer, "",
_("When dragging a knot along a constraint line, then snap the position of the mouse pointer instead of snapping the projection of the knot onto the constraint line"));
+ _page_snapping.add_group_header( _("Delayed snap"));
+
+ _snap_delay.init("/options/snapdelay/value", 0, 1, 0.1, 0.2, 0.3, 1);
+ _page_snapping.add_line( true, _("Delay (in seconds):"), _snap_delay, "",
+ _("Postpone snapping as long as the mouse is moving, and then wait an additional fraction of a second. This additional delay is specified here. When set to zero or to a very small number, snapping will be immediate."), true);
+
this->AddPage(_page_snapping, _("Snapping"), iter_behavior, PREFS_PAGE_BEHAVIOR_SNAPPING);
// Steps options
diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h
index dcea91741..d1abcfc58 100644
--- a/src/ui/dialog/inkscape-preferences.h
+++ b/src/ui/dialog/inkscape-preferences.h
@@ -15,6 +15,10 @@
#ifndef INKSCAPE_UI_DIALOG_INKSCAPE_PREFERENCES_H
#define INKSCAPE_UI_DIALOG_INKSCAPE_PREFERENCES_H
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
#include <iostream>
#include <vector>
#include "ui/widget/preferences-widget.h"
@@ -56,7 +60,11 @@ enum {
PREFS_PAGE_TOOLS_TEXT,
PREFS_PAGE_TOOLS_SPRAY,
PREFS_PAGE_TOOLS_ERASER,
+
+#if HAVE_POTRACE
PREFS_PAGE_TOOLS_PAINTBUCKET,
+#endif
+
PREFS_PAGE_TOOLS_GRADIENT,
PREFS_PAGE_TOOLS_DROPPER,
PREFS_PAGE_TOOLS_CONNECTOR,
@@ -322,6 +330,7 @@ protected:
UI::Widget::PrefCheckButton _importexport_import_res_override;
UI::Widget::PrefSlider _snap_delay;
UI::Widget::PrefSlider _snap_weight;
+ UI::Widget::PrefSlider _snap_persistence;
UI::Widget::PrefCheckButton _font_dialog;
UI::Widget::PrefCombo _font_unit_type;
UI::Widget::PrefCheckButton _font_output_px;
@@ -493,6 +502,7 @@ protected:
static void AddConvertGuidesCheckbox(UI::Widget::DialogPage& p, Glib::ustring const &prefs_path, bool def_value);
static void AddFirstAndLastCheckbox(UI::Widget::DialogPage& p, Glib::ustring const &prefs_path, bool def_value);
static void AddDotSizeSpinbutton(UI::Widget::DialogPage& p, Glib::ustring const &prefs_path, double def_value);
+ static void AddBaseSimplifySpinbutton(UI::Widget::DialogPage& p, Glib::ustring const &prefs_path, double def_value);
static void AddNewObjectsStyle(UI::Widget::DialogPage& p, Glib::ustring const &prefs_path, const gchar* banner = NULL);
void on_pagelist_selection_changed();
diff --git a/src/ui/dialog/knot-properties.cpp b/src/ui/dialog/knot-properties.cpp
new file mode 100644
index 000000000..9c23c33e1
--- /dev/null
+++ b/src/ui/dialog/knot-properties.cpp
@@ -0,0 +1,213 @@
+/**
+ * @file
+ * Dialog for renaming layers.
+ */
+/* Author:
+ * Bryce W. Harrington <bryce@bryceharrington.com>
+ * Andrius R. <knutux@gmail.com>
+ * Abhishek Sharma
+ *
+ * Copyright (C) 2004 Bryce Harrington
+ * Copyright (C) 2006 Andrius R.
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "ui/dialog/knot-properties.h"
+#include <boost/lexical_cast.hpp>
+#include <gtkmm/stock.h>
+#include <glibmm/main.h>
+#include <glibmm/i18n.h>
+#include "inkscape.h"
+#include "util/units.h"
+#include "desktop.h"
+#include "document.h"
+#include "document-undo.h"
+#include "layer-manager.h"
+#include "message-stack.h"
+
+#include "sp-object.h"
+#include "sp-item.h"
+#include "verbs.h"
+#include "selection.h"
+#include "selection-chemistry.h"
+#include "ui/icon-names.h"
+#include "ui/widget/imagetoggler.h"
+
+//#include "event-context.h"
+
+namespace Inkscape {
+namespace UI {
+namespace Dialogs {
+
+KnotPropertiesDialog::KnotPropertiesDialog()
+: _desktop(NULL), _knotpoint(NULL), _position_visible(false)
+{
+ Gtk::Box *mainVBox = get_vbox();
+
+ _layout_table.set_spacings(4);
+ _layout_table.resize (2, 2);
+ _unit_name = "";
+ // Layer name widgets
+ _knot_x_entry.set_activates_default(true);
+ _knot_x_entry.set_digits(4);
+ _knot_x_entry.set_increments(1,1);
+ _knot_x_entry.set_range(-G_MAXDOUBLE, G_MAXDOUBLE);
+ _knot_x_label.set_label(_("Position X:"));
+ _knot_x_label.set_alignment(1.0, 0.5);
+
+ _knot_y_entry.set_activates_default(true);
+ _knot_y_entry.set_digits(4);
+ _knot_y_entry.set_increments(1,1);
+ _knot_y_entry.set_range(-G_MAXDOUBLE, G_MAXDOUBLE);
+ _knot_y_label.set_label(_("Position Y:"));
+ _knot_y_label.set_alignment(1.0, 0.5);
+
+ _layout_table.attach(_knot_x_label,
+ 0, 1, 0, 1, Gtk::FILL, Gtk::FILL);
+ _layout_table.attach(_knot_x_entry,
+ 1, 2, 0, 1, Gtk::FILL | Gtk::EXPAND, Gtk::FILL);
+
+ _layout_table.attach(_knot_y_label, 0, 1, 1, 2, Gtk::FILL, Gtk::FILL);
+ _layout_table.attach(_knot_y_entry, 1, 2, 1, 2, Gtk::FILL | Gtk::EXPAND, Gtk::FILL);
+
+ mainVBox->pack_start(_layout_table, true, true, 4);
+
+ // Buttons
+ _close_button.set_use_stock(true);
+ _close_button.set_label(Gtk::Stock::CANCEL.id);
+ _close_button.set_can_default();
+
+ _apply_button.set_use_underline(true);
+ _apply_button.set_can_default();
+
+ _close_button.signal_clicked()
+ .connect(sigc::mem_fun(*this, &KnotPropertiesDialog::_close));
+ _apply_button.signal_clicked()
+ .connect(sigc::mem_fun(*this, &KnotPropertiesDialog::_apply));
+
+ signal_delete_event().connect(
+ sigc::bind_return(
+ sigc::hide(sigc::mem_fun(*this, &KnotPropertiesDialog::_close)),
+ true
+ )
+ );
+ add_action_widget(_close_button, Gtk::RESPONSE_CLOSE);
+ add_action_widget(_apply_button, Gtk::RESPONSE_APPLY);
+
+ _apply_button.grab_default();
+
+ show_all_children();
+
+ set_focus(_knot_y_entry);
+}
+
+KnotPropertiesDialog::~KnotPropertiesDialog() {
+
+ _setDesktop(NULL);
+}
+
+void KnotPropertiesDialog::showDialog(SPDesktop *desktop, const SPKnot *pt, Glib::ustring const unit_name)
+{
+ KnotPropertiesDialog *dialog = new KnotPropertiesDialog();
+ dialog->_setDesktop(desktop);
+ dialog->_setKnotPoint(pt->position(), unit_name);
+ dialog->_setPt(pt);
+
+ dialog->set_title(_("Modify Knot Position"));
+ dialog->_apply_button.set_label(_("_Move"));
+
+ dialog->set_modal(true);
+ desktop->setWindowTransient (dialog->gobj());
+ dialog->property_destroy_with_parent() = true;
+
+ dialog->show();
+ dialog->present();
+}
+
+void
+KnotPropertiesDialog::_apply()
+{
+ double d_x = Inkscape::Util::Quantity::convert(_knot_x_entry.get_value(), _unit_name, "px");
+ double d_y = Inkscape::Util::Quantity::convert(_knot_y_entry.get_value(), _unit_name, "px");
+ _knotpoint->moveto(Geom::Point(d_x, d_y));
+ _knotpoint->moved_signal.emit(_knotpoint, _knotpoint->position(), 0);
+ _close();
+}
+
+void
+KnotPropertiesDialog::_close()
+{
+ _setDesktop(NULL);
+ destroy_();
+ Glib::signal_idle().connect(
+ sigc::bind_return(
+ sigc::bind(sigc::ptr_fun(&::operator delete), this),
+ false
+ )
+ );
+}
+
+bool KnotPropertiesDialog::_handleKeyEvent(GdkEventKey * /*event*/)
+{
+
+ /*switch (get_group0_keyval(event)) {
+ case GDK_KEY_Return:
+ case GDK_KEY_KP_Enter: {
+ _apply();
+ return true;
+ }
+ break;
+ }*/
+ return false;
+}
+
+void KnotPropertiesDialog::_handleButtonEvent(GdkEventButton* event)
+{
+ if ( (event->type == GDK_2BUTTON_PRESS) && (event->button == 1) ) {
+ _apply();
+ }
+}
+
+void KnotPropertiesDialog::_setKnotPoint(Geom::Point knotpoint, Glib::ustring const unit_name)
+{
+ _unit_name = unit_name;
+ _knot_x_entry.set_value( Inkscape::Util::Quantity::convert(knotpoint.x(), "px", _unit_name));
+ _knot_y_entry.set_value( Inkscape::Util::Quantity::convert(knotpoint.y(), "px", _unit_name));
+ _knot_x_label.set_label(g_strdup_printf(_("Position X (%s):"), _unit_name.c_str()));
+ _knot_y_label.set_label(g_strdup_printf(_("Position Y (%s):"), _unit_name.c_str()));
+}
+
+void KnotPropertiesDialog::_setPt(const SPKnot *pt)
+{
+ _knotpoint = const_cast<SPKnot *>(pt);
+}
+
+void KnotPropertiesDialog::_setDesktop(SPDesktop *desktop) {
+ if (desktop) {
+ Inkscape::GC::anchor (desktop);
+ }
+ if (_desktop) {
+ Inkscape::GC::release (_desktop);
+ }
+ _desktop = desktop;
+}
+
+} // namespace
+} // namespace
+} // namespace
+
+
+/*
+ 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/dialog/knot-properties.h b/src/ui/dialog/knot-properties.h
new file mode 100644
index 000000000..fd87df03d
--- /dev/null
+++ b/src/ui/dialog/knot-properties.h
@@ -0,0 +1,97 @@
+/** @file
+ * @brief
+ */
+/* Author:
+ * Bryce W. Harrington <bryce@bryceharrington.com>
+ *
+ * Copyright (C) 2004 Bryce Harrington
+ *
+ * Released under GNU GPL. Read the file 'COPYING' for more information
+ */
+
+#ifndef INKSCAPE_DIALOG_KNOT_PROPERTIES_H
+#define INKSCAPE_DIALOG_KNOT_PROPERTIES_H
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <gtkmm.h>
+#include <2geom/point.h>
+#include "knot.h"
+#include "ui/tools/measure-tool.h"
+
+class SPDesktop;
+
+namespace Inkscape {
+namespace UI {
+namespace Dialogs {
+
+
+class KnotPropertiesDialog : public Gtk::Dialog {
+ public:
+ KnotPropertiesDialog();
+ virtual ~KnotPropertiesDialog();
+
+ Glib::ustring getName() const { return "LayerPropertiesDialog"; }
+
+ static void showDialog(SPDesktop *desktop, const SPKnot *pt, Glib::ustring const unit_name);
+
+protected:
+
+ SPDesktop *_desktop;
+ SPKnot *_knotpoint;
+
+ Gtk::Label _knot_x_label;
+ Gtk::SpinButton _knot_x_entry;
+ Gtk::Label _knot_y_label;
+ Gtk::SpinButton _knot_y_entry;
+ Gtk::Table _layout_table;
+ bool _position_visible;
+
+ Gtk::Button _close_button;
+ Gtk::Button _apply_button;
+ Glib::ustring _unit_name;
+
+ sigc::connection _destroy_connection;
+
+ static KnotPropertiesDialog &_instance() {
+ static KnotPropertiesDialog instance;
+ return instance;
+ }
+
+ void _setDesktop(SPDesktop *desktop);
+ void _setPt(const SPKnot *pt);
+
+ void _apply();
+ void _close();
+
+ void _setKnotPoint(Geom::Point knotpoint, Glib::ustring const unit_name);
+ void _prepareLabelRenderer(Gtk::TreeModel::const_iterator const &row);
+
+ bool _handleKeyEvent(GdkEventKey *event);
+ void _handleButtonEvent(GdkEventButton* event);
+ friend class Inkscape::UI::Tools::MeasureTool;
+
+private:
+ KnotPropertiesDialog(KnotPropertiesDialog const &); // no copy
+ KnotPropertiesDialog &operator=(KnotPropertiesDialog const &); // no assign
+};
+
+} // namespace
+} // namespace
+} // namespace
+
+
+#endif //INKSCAPE_DIALOG_LAYER_PROPERTIES_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/dialog/layers.cpp b/src/ui/dialog/layers.cpp
index 3f5e80f8d..1c022ecad 100644
--- a/src/ui/dialog/layers.cpp
+++ b/src/ui/dialog/layers.cpp
@@ -715,11 +715,11 @@ void LayersPanel::_doTreeMove( )
{
if (_dnd_source && _dnd_source->getRepr() ) {
if(!_dnd_target){
- _dnd_source->doWriteTransform(_dnd_source->getRepr(), _dnd_source->document->getRoot()->i2doc_affine().inverse() * _dnd_source->i2doc_affine());
+ _dnd_source->doWriteTransform(_dnd_source->getRepr(), _dnd_source->i2doc_affine() * _dnd_source->document->getRoot()->i2doc_affine().inverse());
}else{
SPItem* parent = _dnd_into ? _dnd_target : dynamic_cast<SPItem*>(_dnd_target->parent);
if(parent){
- Geom::Affine move = parent->i2doc_affine().inverse() * _dnd_source->i2doc_affine();
+ Geom::Affine move = _dnd_source->i2doc_affine() * parent->i2doc_affine().inverse();
_dnd_source->doWriteTransform(_dnd_source->getRepr(), move);
}
}
@@ -1040,14 +1040,6 @@ void LayersPanel::setDesktop( SPDesktop* desktop )
_layersChanged();
}
}
-/*
- GSList const *layers = _desktop->doc()->getResourceList( "layer" );
- g_message( "layers list starts at %p", layers );
- for ( GSList const *iter=layers ; iter ; iter = iter->next ) {
- SPObject *layer=static_cast<SPObject *>(iter->data);
- g_message(" {%s} [%s]", layer->id, layer->label() );
- }
-*/
deskTrack.setBase(desktop);
}
diff --git a/src/ui/dialog/new-from-template.cpp b/src/ui/dialog/new-from-template.cpp
index e30b148bb..74ec7111e 100644
--- a/src/ui/dialog/new-from-template.cpp
+++ b/src/ui/dialog/new-from-template.cpp
@@ -29,10 +29,12 @@ NewFromTemplate::NewFromTemplate()
set_title(_("New From Template"));
resize(400, 400);
+ _main_widget = new TemplateLoadTab(this);
+
#if WITH_GTKMM_3_0
- get_content_area()->pack_start(_main_widget);
+ get_content_area()->pack_start(*_main_widget);
#else
- get_vbox()->pack_start(_main_widget);
+ get_vbox()->pack_start(*_main_widget);
#endif
Gtk::Alignment *align;
@@ -49,14 +51,24 @@ NewFromTemplate::NewFromTemplate()
_create_template_button.signal_clicked().connect(
sigc::mem_fun(*this, &NewFromTemplate::_createFromTemplate));
+ _create_template_button.set_sensitive(false);
show_all();
}
+NewFromTemplate::~NewFromTemplate()
+{
+ delete _main_widget;
+}
+
+void NewFromTemplate::setCreateButtonSensitive(bool value)
+{
+ _create_template_button.set_sensitive(value);
+}
void NewFromTemplate::_createFromTemplate()
{
- _main_widget.createTemplate();
+ _main_widget->createTemplate();
_onClose();
}
diff --git a/src/ui/dialog/new-from-template.h b/src/ui/dialog/new-from-template.h
index 2b40af2a6..c0b65affb 100644
--- a/src/ui/dialog/new-from-template.h
+++ b/src/ui/dialog/new-from-template.h
@@ -27,11 +27,13 @@ class NewFromTemplate : public Gtk::Dialog
friend class TemplateLoadTab;
public:
static void load_new_from_template();
-
+ void setCreateButtonSensitive(bool value);
+ virtual ~NewFromTemplate();
+
private:
NewFromTemplate();
Gtk::Button _create_template_button;
- TemplateLoadTab _main_widget;
+ TemplateLoadTab* _main_widget;
void _createFromTemplate();
void _onClose();
diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp
index 835ecf35b..891048beb 100644
--- a/src/ui/dialog/objects.cpp
+++ b/src/ui/dialog/objects.cpp
@@ -479,7 +479,7 @@ void ObjectsPanel::_objectsSelected( Selection *sel ) {
_tree.get_selection()->unselect_all();
SPItem *item = NULL;
std::vector<SPItem*> const items = sel->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin(); i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin(); i!=items.end(); ++i){
item = *i;
if (setOpacity)
{
@@ -1583,6 +1583,10 @@ void ObjectsPanel::_blurChangedIter(const Gtk::TreeIter& iter, double blur)
}
if (radius != 0) {
+ // The modify function expects radius to be in display pixels.
+ Geom::Affine i2d (item->i2dt_affine());
+ double expansion = i2d.descrim();
+ radius *= expansion;
SPFilter *filter = modify_filter_gaussian_blur_from_item(_document, item, radius);
sp_style_set_property_url(item, "filter", filter, false);
} else if (item->style->filter.set && item->style->getFilter()) {
@@ -1614,11 +1618,11 @@ ObjectsPanel::ObjectsPanel() :
_pending(0),
_toggleEvent(0),
_defer_target(),
- _visibleHeader(_("V")),
- _lockHeader(_("L")),
- _typeHeader(_("T")),
- _clipmaskHeader(_("CM")),
- _highlightHeader(_("HL")),
+ _visibleHeader(C_("Visibility", "V")),
+ _lockHeader(C_("Lock", "L")),
+ _typeHeader(C_("Type", "T")),
+ _clipmaskHeader(C_("Clip and mask", "CM")),
+ _highlightHeader(C_("Highlight", "HL")),
_nameHeader(_("Label")),
_composite_vbox(false, 0),
_opacity_vbox(false, 0),
diff --git a/src/ui/dialog/pixelartdialog.cpp b/src/ui/dialog/pixelartdialog.cpp
index 760391df6..f557ff0fc 100644
--- a/src/ui/dialog/pixelartdialog.cpp
+++ b/src/ui/dialog/pixelartdialog.cpp
@@ -373,7 +373,7 @@ void PixelArtDialogImpl::vectorize()
}
std::vector<SPItem*> const items = desktop->selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin(); i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin(); i!=items.end();++i){
if ( !SP_IS_IMAGE(*i) )
continue;
diff --git a/src/ui/dialog/polar-arrange-tab.cpp b/src/ui/dialog/polar-arrange-tab.cpp
index af1386e27..5ec1285c1 100644
--- a/src/ui/dialog/polar-arrange-tab.cpp
+++ b/src/ui/dialog/polar-arrange-tab.cpp
@@ -304,7 +304,7 @@ void PolarArrangeTab::arrange()
bool arrangeOnFirstEllipse = arrangeOnEllipse && arrangeOnFirstCircleRadio.get_active();
int count = 0;
- for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++)
+ for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i)
{
if(arrangeOnEllipse)
{
@@ -373,7 +373,7 @@ void PolarArrangeTab::arrange()
Geom::Point realCenter = Geom::Point(cx, cy) * transformation;
int i = 0;
- for(std::vector<SPItem*>::const_iterator it=tmp.begin();it!=tmp.end();it++)
+ for(std::vector<SPItem*>::const_iterator it=tmp.begin();it!=tmp.end(); ++it)
{
SPItem *item = *it;
diff --git a/src/ui/dialog/svg-fonts-dialog.cpp b/src/ui/dialog/svg-fonts-dialog.cpp
index 12b423602..46e045c14 100644
--- a/src/ui/dialog/svg-fonts-dialog.cpp
+++ b/src/ui/dialog/svg-fonts-dialog.cpp
@@ -266,12 +266,12 @@ void SvgFontsDialog::update_fonts()
{
SPDesktop* desktop = this->getDesktop();
SPDocument* document = desktop->getDocument();
- const GSList* fonts = document->getResourceList("font");
+ std::set<SPObject *> fonts = document->getResourceList( "fonts" );
_model->clear();
- for(const GSList *l = fonts; l; l = l->next) {
+ for (std::set<SPObject *>::const_iterator it = fonts.begin(); it != fonts.end(); ++it) {
Gtk::TreeModel::Row row = *_model->append();
- SPFont* f = SP_FONT(l->data);
+ SPFont* f = SP_FONT(*it);
row[_columns.spfont] = f;
row[_columns.svgfont] = new SvgFont(f);
const gchar* lbl = f->label();
diff --git a/src/ui/dialog/swatches.cpp b/src/ui/dialog/swatches.cpp
index 72677c07e..924ebe03d 100644
--- a/src/ui/dialog/swatches.cpp
+++ b/src/ui/dialog/swatches.cpp
@@ -171,9 +171,9 @@ static void editGradient( GtkMenuItem */*menuitem*/, gpointer /*user_data*/ )
SPDocument *doc = desktop ? desktop->doc() : 0;
if (doc) {
std::string targetName(bounceTarget->def.descr);
- const GSList *gradients = doc->getResourceList("gradient");
- for (const GSList *item = gradients; item; item = item->next) {
- SPGradient* grad = SP_GRADIENT(item->data);
+ std::set<SPObject *> gradients = doc->getResourceList("gradient");
+ for (std::set<SPObject *>::const_iterator item = gradients.begin(); item != gradients.end(); ++item) {
+ SPGradient* grad = SP_GRADIENT(*item);
if ( targetName == grad->getId() ) {
editGradientImpl( desktop, grad );
break;
@@ -192,10 +192,10 @@ void SwatchesPanelHook::convertGradient( GtkMenuItem * /*menuitem*/, gpointer us
gint index = GPOINTER_TO_INT(userData);
if ( doc && (index >= 0) && (static_cast<guint>(index) < popupItems.size()) ) {
Glib::ustring targetName = popupItems[index];
+ std::set<SPObject *> gradients = doc->getResourceList("gradient");
+ for (std::set<SPObject *>::const_iterator item = gradients.begin(); item != gradients.end(); ++item) {
+ SPGradient* grad = SP_GRADIENT(*item);
- const GSList *gradients = doc->getResourceList("gradient");
- for (const GSList *item = gradients; item; item = item->next) {
- SPGradient* grad = SP_GRADIENT(item->data);
if ( targetName == grad->getId() ) {
grad->setSwatch();
DocumentUndo::done(doc, SP_VERB_CONTEXT_GRADIENT,
@@ -326,10 +326,10 @@ gboolean colorItemHandleButtonPress( GtkWidget* widget, GdkEventButton* event, g
SPDesktopWidget *dtw = SP_DESKTOP_WIDGET(wdgt);
if ( dtw && dtw->desktop ) {
// Pick up all gradients with vectors
- const GSList *gradients = (dtw->desktop->doc())->getResourceList("gradient");
+ std::set<SPObject *> gradients = (dtw->desktop->doc())->getResourceList("gradient");
gint index = 0;
- for (const GSList *curr = gradients; curr; curr = curr->next) {
- SPGradient* grad = SP_GRADIENT(curr->data);
+ for (std::set<SPObject *>::const_iterator item = gradients.begin(); item != gradients.end(); ++item) {
+ SPGradient* grad = SP_GRADIENT(*item);
if ( grad->hasStops() && !grad->isSwatch() ) {
//gl = g_slist_prepend(gl, curr->data);
processed = true;
@@ -393,10 +393,10 @@ static bool parseNum( char*& str, int& val ) {
}
-void _loadPaletteFile( gchar const *filename, gboolean user/*=FALSE*/ )
+void _loadPaletteFile( gchar const *filename, gchar const *path, gboolean user/*=FALSE*/ )
{
char block[1024];
- FILE *f = Inkscape::IO::fopen_utf8name( filename, "r" );
+ FILE *f = Inkscape::IO::fopen_utf8name(path, "r" );
if ( f ) {
char* result = fgets( block, sizeof(block), f );
if ( result ) {
@@ -405,6 +405,7 @@ void _loadPaletteFile( gchar const *filename, gboolean user/*=FALSE*/ )
bool hasErr = false;
SwatchPage *onceMore = new SwatchPage();
+ onceMore->_name = filename;
do {
result = fgets( block, sizeof(block), f );
@@ -521,7 +522,7 @@ compare_swatch_names(SwatchPage const *a, SwatchPage const *b) {
static void loadEmUp()
{
static bool beenHere = false;
- gboolean userPalete = true;
+ gboolean userPalette = true;
if ( !beenHere ) {
beenHere = true;
@@ -549,7 +550,7 @@ static void loadEmUp()
if ( !g_str_has_suffix(lower, "~") ) {
gchar* full = g_build_filename(dirname, filename, NULL);
if ( !Inkscape::IO::file_test( full, G_FILE_TEST_IS_DIR ) ) {
- _loadPaletteFile(full, userPalete);
+ _loadPaletteFile(filename, full, userPalette);
}
g_free(full);
}
@@ -563,7 +564,7 @@ static void loadEmUp()
// toss the dirname
g_free(dirname);
sources.pop_front();
- userPalete = false;
+ userPalette = false;
}
}
@@ -923,12 +924,11 @@ static void recalcSwatchContents(SPDocument* doc,
std::map<ColorItem*, SPGradient*> &gradMappings)
{
std::vector<SPGradient*> newList;
-
- const GSList *gradients = doc->getResourceList("gradient");
- for (const GSList *item = gradients; item; item = item->next) {
- SPGradient* grad = SP_GRADIENT(item->data);
+ std::set<SPObject *> gradients = doc->getResourceList("gradient");
+ for (std::set<SPObject *>::const_iterator item = gradients.begin(); item != gradients.end(); ++item) {
+ SPGradient* grad = SP_GRADIENT(*item);
if ( grad->isSwatch() ) {
- newList.push_back(SP_GRADIENT(item->data));
+ newList.push_back(SP_GRADIENT(*item));
}
}
diff --git a/src/ui/dialog/tags.cpp b/src/ui/dialog/tags.cpp
index f36e3f18d..cbb2fb953 100644
--- a/src/ui/dialog/tags.cpp
+++ b/src/ui/dialog/tags.cpp
@@ -13,10 +13,6 @@
# include <config.h>
#endif
-#if WITH_GLIBMM_2_32
-# include <glibmm/threads.h>
-#endif
-
#include "tags.h"
#include <gtkmm/widget.h>
#include <gtkmm/icontheme.h>
@@ -353,7 +349,7 @@ void TagsPanel::_objectsSelected( Selection *sel ) {
_selectedConnection.block();
_tree.get_selection()->unselect_all();
std::vector<SPObject*> tmp=sel->list();
- for(std::vector<SPObject*>::const_iterator i=tmp.begin();i!=tmp.end();i++)
+ for(std::vector<SPObject*>::const_iterator i=tmp.begin();i!=tmp.end();++i)
{
SPObject *obj = *i;
_store->foreach(sigc::bind<SPObject *>( sigc::mem_fun(*this, &TagsPanel::_checkForSelected), obj));
@@ -651,7 +647,7 @@ bool TagsPanel::_handleButtonEvent(GdkEventButton* event)
if (SP_IS_TAG(obj)) {
bool wasadded = false;
std::vector<SPItem*> items=_desktop->selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
SPObject *newobj = *i;
bool addchild = true;
for ( SPObject *child = obj->children; child != NULL; child = child->next) {
diff --git a/src/ui/dialog/template-load-tab.cpp b/src/ui/dialog/template-load-tab.cpp
index fca1f7b30..7eb04ff79 100644
--- a/src/ui/dialog/template-load-tab.cpp
+++ b/src/ui/dialog/template-load-tab.cpp
@@ -35,10 +35,11 @@
namespace Inkscape {
namespace UI {
-TemplateLoadTab::TemplateLoadTab()
+TemplateLoadTab::TemplateLoadTab(NewFromTemplate* parent)
: _current_keyword("")
, _keywords_combo(true)
, _current_search_type(ALL)
+ , _parent_widget(parent)
{
set_border_width(10);
@@ -94,7 +95,8 @@ void TemplateLoadTab::_displayTemplateInfo()
if (templateSelectionRef->get_selected()) {
_current_template = (*templateSelectionRef->get_selected())[_columns.textValue];
- _info_widget->display(_tdata[_current_template]);
+ _info_widget->display(_tdata[_current_template]);
+ _parent_widget->setCreateButtonSensitive(true);
}
}
@@ -148,11 +150,10 @@ void TemplateLoadTab::_keywordSelected()
void TemplateLoadTab::_refreshTemplatesList()
{
- _tlist_store->clear();
-
+ _tlist_store->clear();
+
switch (_current_search_type){
case ALL :{
-
for (std::map<Glib::ustring, TemplateData>::iterator it = _tdata.begin() ; it != _tdata.end() ; ++it) {
Gtk::TreeModel::iterator iter = _tlist_store->append();
Gtk::TreeModel::Row row = *iter;
@@ -160,7 +161,7 @@ void TemplateLoadTab::_refreshTemplatesList()
}
break;
}
-
+
case LIST_KEYWORD: {
for (std::map<Glib::ustring, TemplateData>::iterator it = _tdata.begin() ; it != _tdata.end() ; ++it) {
if (it->second.keywords.count(_current_keyword.lowercase()) != 0){
@@ -171,10 +172,10 @@ void TemplateLoadTab::_refreshTemplatesList()
}
break;
}
-
+
case USER_SPECIFIED : {
for (std::map<Glib::ustring, TemplateData>::iterator it = _tdata.begin() ; it != _tdata.end() ; ++it) {
- if (it->second.keywords.count(_current_keyword.lowercase()) != 0 ||
+ if (it->second.keywords.count(_current_keyword.lowercase()) != 0 ||
it->second.display_name.lowercase().find(_current_keyword.lowercase()) != Glib::ustring::npos ||
it->second.author.lowercase().find(_current_keyword.lowercase()) != Glib::ustring::npos ||
it->second.short_description.lowercase().find(_current_keyword.lowercase()) != Glib::ustring::npos ||
@@ -188,6 +189,27 @@ void TemplateLoadTab::_refreshTemplatesList()
break;
}
}
+
+ // reselect item
+ Gtk::TreeIter* item_to_select = NULL;
+ for (Gtk::TreeModel::Children::iterator it = _tlist_store->children().begin(); it != _tlist_store->children().end(); ++it) {
+ Gtk::TreeModel::Row row = *it;
+ if (_current_template == row[_columns.textValue]) {
+ item_to_select = new Gtk::TreeIter(it);
+ break;
+ }
+ }
+ if (_tlist_store->children().size() == 1) {
+ item_to_select = new Gtk::TreeIter(_tlist_store->children().begin());
+ }
+ if (item_to_select) {
+ _tlist_view.get_selection()->select(*item_to_select);
+ delete item_to_select;
+ } else {
+ _current_template = "";
+ _info_widget->clear();
+ _parent_widget->setCreateButtonSensitive(false);
+ }
}
diff --git a/src/ui/dialog/template-load-tab.h b/src/ui/dialog/template-load-tab.h
index 920ae6ca2..d11c4c77f 100644
--- a/src/ui/dialog/template-load-tab.h
+++ b/src/ui/dialog/template-load-tab.h
@@ -28,6 +28,7 @@ namespace Inkscape {
namespace UI {
class TemplateWidget;
+class NewFromTemplate;
class TemplateLoadTab : public Gtk::HBox
{
@@ -47,7 +48,7 @@ public:
Inkscape::Extension::Effect *tpl_effect;
};
- TemplateLoadTab();
+ TemplateLoadTab(NewFromTemplate* parent);
virtual ~TemplateLoadTab();
virtual void createTemplate();
@@ -95,6 +96,7 @@ private:
};
SearchType _current_search_type;
+ NewFromTemplate* _parent_widget;
void _getDataFromNode(Inkscape::XML::Node *, TemplateData &);
void _getProceduralTemplates();
diff --git a/src/ui/dialog/template-widget.cpp b/src/ui/dialog/template-widget.cpp
index eff75b311..0d110d853 100644
--- a/src/ui/dialog/template-widget.cpp
+++ b/src/ui/dialog/template-widget.cpp
@@ -56,6 +56,7 @@ TemplateWidget::TemplateWidget()
_more_info_button.signal_clicked().connect(
sigc::mem_fun(*this, &TemplateWidget::_displayTemplateDetails));
+ _more_info_button.set_sensitive(false);
}
@@ -85,14 +86,12 @@ void TemplateWidget::create()
void TemplateWidget::display(TemplateLoadTab::TemplateData data)
{
+ clear();
_current_template = data;
_template_name_label.set_text(_current_template.display_name);
_short_description_label.set_text(_current_template.short_description);
-
- _preview_render.hide();
- _preview_image.hide();
-
+
std::string imagePath = Glib::build_filename(Glib::path_get_dirname(_current_template.path), _current_template.preview_name);
if (data.preview_name != ""){
_preview_image.set(imagePath);
@@ -103,17 +102,26 @@ void TemplateWidget::display(TemplateLoadTab::TemplateData data)
_preview_render.showImage(gPath);
_preview_render.show();
}
-
- if (_effect_prefs != NULL){
- remove (*_effect_prefs);
- _effect_prefs = NULL;
- }
+
if (data.is_procedural){
_effect_prefs = data.tpl_effect->get_imp()->prefs_effect(data.tpl_effect, SP_ACTIVE_DESKTOP, NULL, NULL);
pack_start(*_effect_prefs);
}
+ _more_info_button.set_sensitive(true);
}
+void TemplateWidget::clear()
+{
+ _template_name_label.set_text("");
+ _short_description_label.set_text("");
+ _preview_render.hide();
+ _preview_image.hide();
+ if (_effect_prefs != NULL){
+ remove (*_effect_prefs);
+ _effect_prefs = NULL;
+ }
+ _more_info_button.set_sensitive(false);
+}
void TemplateWidget::_displayTemplateDetails()
{
diff --git a/src/ui/dialog/template-widget.h b/src/ui/dialog/template-widget.h
index bb35d26a0..13488089c 100644
--- a/src/ui/dialog/template-widget.h
+++ b/src/ui/dialog/template-widget.h
@@ -28,6 +28,7 @@ public:
TemplateWidget ();
void create();
void display(TemplateLoadTab::TemplateData);
+ void clear();
private:
TemplateLoadTab::TemplateData _current_template;
diff --git a/src/ui/dialog/text-edit.cpp b/src/ui/dialog/text-edit.cpp
index 7575cc854..c01da8864 100644
--- a/src/ui/dialog/text-edit.cpp
+++ b/src/ui/dialog/text-edit.cpp
@@ -127,8 +127,8 @@ TextEdit::TextEdit()
gtk_combo_box_text_append_text((GtkComboBoxText *) spacing_combo, spacings[i]);
}
- gtk_widget_set_tooltip_text (px, _("Spacing between lines (percent of font size)"));
- gtk_widget_set_tooltip_text (spacing_combo, _("Spacing between lines (percent of font size)"));
+ gtk_widget_set_tooltip_text (px, _("Spacing between baselines (percent of font size)"));
+ gtk_widget_set_tooltip_text (spacing_combo, _("Spacing between baselines (percent of font size)"));
layout_hbox.pack_start(*Gtk::manage(Glib::wrap(spacing_combo)), false, false);
layout_frame.set_padding(4,4,4,4);
layout_frame.add(layout_hbox);
@@ -175,6 +175,19 @@ TextEdit::TextEdit()
gtk_text_view_set_wrap_mode ((GtkTextView *) text_view, GTK_WRAP_WORD);
#ifdef WITH_GTKSPELL
+#ifdef WITH_GTKMM_3_0
+/*
+ TODO: Use computed xml:lang attribute of relevant element, if present, to specify the
+ language (either as 2nd arg of gtkspell_new_attach, or with explicit
+ gtkspell_set_language call in; see advanced.c example in gtkspell docs).
+ onReadSelection looks like a suitable place.
+*/
+ GtkSpellChecker * speller = gtk_spell_checker_new();
+
+ if (! gtk_spell_checker_attach(speller, GTK_TEXT_VIEW(text_view))) {
+ g_print("gtkspell error:\n");
+ }
+#else
GError *error = NULL;
/*
@@ -188,6 +201,7 @@ TextEdit::TextEdit()
g_error_free(error);
}
#endif
+#endif
gtk_widget_set_size_request (text_view, -1, 64);
gtk_text_view_set_editable (GTK_TEXT_VIEW (text_view), TRUE);
@@ -430,7 +444,7 @@ SPItem *TextEdit::getSelectedTextItem (void)
return NULL;
std::vector<SPItem*> tmp=SP_ACTIVE_DESKTOP->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++)
+ for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i)
{
if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i))
return *i;
@@ -448,7 +462,7 @@ unsigned TextEdit::getSelectedTextCount (void)
unsigned int items = 0;
std::vector<SPItem*> tmp=SP_ACTIVE_DESKTOP->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++)
+ for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i)
{
if (SP_IS_TEXT(*i) || SP_IS_FLOWTEXT(*i))
++items;
@@ -558,7 +572,7 @@ void TextEdit::onApply()
SPCSSAttr *css = fillTextStyle ();
sp_desktop_set_style(desktop, css, true);
- for(std::vector<SPItem*>::const_iterator i=item_list.begin();i!=item_list.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=item_list.begin();i!=item_list.end();++i){
// apply style to the reprs of all text objects in the selection
if (SP_IS_TEXT (*i)) {
diff --git a/src/ui/dialog/transformation.cpp b/src/ui/dialog/transformation.cpp
index 498ad7822..b7638e8c1 100644
--- a/src/ui/dialog/transformation.cpp
+++ b/src/ui/dialog/transformation.cpp
@@ -35,7 +35,6 @@
#include "sp-item-transform.h"
#include "macros.h"
#include "sp-item.h"
-#include "util/glib-list-iterators.h"
#include "ui/icon-names.h"
#include "widgets/icon.h"
@@ -812,7 +811,7 @@ void Transformation::applyPageScale(Inkscape::Selection *selection)
bool preserve = prefs->getBool("/options/preservetransform/value", false);
if (prefs->getBool("/dialogs/transformation/applyseparately")) {
std::vector<SPItem*> tmp=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i){
SPItem *item = *i;
Geom::OptRect bbox_pref = item->desktopPreferredBounds();
Geom::OptRect bbox_geom = item->desktopGeometricBounds();
@@ -876,7 +875,7 @@ void Transformation::applyPageRotate(Inkscape::Selection *selection)
if (prefs->getBool("/dialogs/transformation/applyseparately")) {
std::vector<SPItem*> tmp=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i){
SPItem *item = *i;
sp_item_rotate_rel(item, Geom::Rotate (angle*M_PI/180.0));
}
@@ -896,7 +895,7 @@ void Transformation::applyPageSkew(Inkscape::Selection *selection)
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
if (prefs->getBool("/dialogs/transformation/applyseparately")) {
std::vector<SPItem*> items=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();++i){
SPItem *item = *i;
if (!_units_skew.isAbsolute()) { // percentage
@@ -998,7 +997,7 @@ void Transformation::applyPageTransform(Inkscape::Selection *selection)
if (_check_replace_matrix.get_active()) {
std::vector<SPItem*> tmp=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=tmp.begin();i!=tmp.end();++i){
SPItem *item = *i;
item->set_item_transform(displayed);
item->updateRepr();
@@ -1170,6 +1169,9 @@ void Transformation::onReplaceMatrixToggled()
void Transformation::onScaleProportionalToggled()
{
onScaleXValueChanged();
+ if (_scalar_scale_vertical.setProgrammatically) {
+ _scalar_scale_vertical.setProgrammatically = false;
+ }
}
diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp
index a129d4b92..69b229519 100644
--- a/src/ui/interface.cpp
+++ b/src/ui/interface.cpp
@@ -239,7 +239,7 @@ sp_create_window(SPViewWidget *vw, bool editable)
}
int pos = nui_drop_target_entries;
- for (std::vector<gchar*>::iterator it = types.begin() ; it != types.end() ; it++) {
+ for (std::vector<gchar*>::iterator it = types.begin() ; it != types.end() ; ++it) {
completeDropTargets[pos].target = *it;
completeDropTargets[pos].flags = 0;
completeDropTargets[pos].info = IMAGE_DATA;
@@ -577,6 +577,9 @@ static gboolean checkitem_update(GtkWidget *widget, GdkEventExpose * /*event*/,
if (!strcmp(action->id, "ToggleGrid")) {
ison = dt->gridsEnabled();
}
+ else if (!strcmp(action->id, "EditGuidesToggleLock")) {
+ ison = dt->namedview->lockguides;
+ }
else if (!strcmp(action->id, "ToggleGuides")) {
ison = dt->namedview->getGuides();
}
@@ -846,13 +849,11 @@ static void sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, I
#endif
}
} else if (menu_pntr->attribute("check") != NULL) {
- SPAction *action = NULL;
if (verb->get_code() != SP_VERB_NONE) {
- action = verb->get_action(Inkscape::ActionContext(view));
- }
- sp_ui_menu_append_check_item_from_verb(GTK_MENU(menu), view, action->name, action->tip, NULL,
+ SPAction *action = verb->get_action(Inkscape::ActionContext(view));
+ sp_ui_menu_append_check_item_from_verb(GTK_MENU(menu), view, action->name, action->tip, NULL,
checkitem_toggled, checkitem_update, verb);
-
+ }
} else {
sp_ui_menu_append_item_from_verb(GTK_MENU(menu), verb, view);
group = NULL;
@@ -868,11 +869,7 @@ static void sp_ui_build_dyn_menus(Inkscape::XML::Node *menus, GtkWidget *menu, I
}
continue;
}
- if (!strcmp(menu_pntr->name(), "separator")
- // This was spelt wrong in the original version
- // and so this is for backward compatibility. It can
- // probably be dropped after the 0.44 release.
- || !strcmp(menu_pntr->name(), "seperator")) {
+ if (!strcmp(menu_pntr->name(), "separator")) {
GtkWidget *item = gtk_separator_menu_item_new();
gtk_widget_show(item);
gtk_menu_shell_append(GTK_MENU_SHELL(menu), item);
@@ -1119,9 +1116,9 @@ sp_ui_drag_data_received(GtkWidget *widget,
unsigned int b = color.getB();
SPGradient* matches = 0;
- const GSList *gradients = doc->getResourceList("gradient");
- for (const GSList *item = gradients; item; item = item->next) {
- SPGradient* grad = SP_GRADIENT(item->data);
+ std::set<SPObject *> gradients = doc->getResourceList("gradient");
+ for (std::set<SPObject *>::const_iterator item = gradients.begin(); item != gradients.end(); ++item) {
+ SPGradient* grad = SP_GRADIENT(*item);
if ( color.descr == grad->getId() ) {
if ( grad->hasStops() ) {
matches = grad;
@@ -2076,7 +2073,7 @@ void ContextMenu::ImageEdit(void)
#endif
std::vector<SPItem*> itemlist=_desktop->selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
Inkscape::XML::Node *ir = (*i)->getRepr();
const gchar *href = ir->attribute("xlink:href");
diff --git a/src/ui/object-edit.cpp b/src/ui/object-edit.cpp
index 0a6c792dc..459acf002 100644
--- a/src/ui/object-edit.cpp
+++ b/src/ui/object-edit.cpp
@@ -1364,13 +1364,15 @@ public:
};
void
-OffsetKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int /*state*/)
+OffsetKnotHolderEntity::knot_set(Geom::Point const &p, Geom::Point const &/*origin*/, unsigned int state)
{
SPOffset *offset = dynamic_cast<SPOffset *>(item);
g_assert(offset != NULL);
- offset->rad = sp_offset_distance_to_original(offset, p);
- offset->knot = p;
+ Geom::Point const p_snapped = snap_knot_position(p, state);
+
+ offset->rad = sp_offset_distance_to_original(offset, p_snapped);
+ offset->knot = p_snapped;
offset->knotSet = true;
offset->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
diff --git a/src/ui/tool-factory.cpp b/src/ui/tool-factory.cpp
index 700bd40ce..c6c579c9e 100644
--- a/src/ui/tool-factory.cpp
+++ b/src/ui/tool-factory.cpp
@@ -16,7 +16,11 @@
#include "ui/tools/connector-tool.h"
#include "ui/tools/dropper-tool.h"
#include "ui/tools/eraser-tool.h"
-#include "ui/tools/flood-tool.h"
+
+#if HAVE_POTRACE
+# include "ui/tools/flood-tool.h"
+#endif
+
#include "ui/tools/gradient-tool.h"
#include "ui/tools/lpe-tool.h"
#include "ui/tools/measure-tool.h"
@@ -52,8 +56,10 @@ ToolBase *ToolFactory::createObject(std::string const& id)
tool = new DropperTool;
else if (id == "/tools/eraser")
tool = new EraserTool;
+#if HAVE_POTRACE
else if (id == "/tools/paintbucket")
tool = new FloodTool;
+#endif
else if (id == "/tools/gradient")
tool = new GradientTool;
else if (id == "/tools/lpetool")
diff --git a/src/ui/tool/control-point-selection.cpp b/src/ui/tool/control-point-selection.cpp
index 998f74ee0..f36ad7374 100644
--- a/src/ui/tool/control-point-selection.cpp
+++ b/src/ui/tool/control-point-selection.cpp
@@ -19,6 +19,8 @@
#include "ui/tool/transform-handle-set.h"
#include "ui/tool/node.h"
+
+
#include <gdk/gdkkeysyms.h>
namespace Inkscape {
@@ -82,6 +84,7 @@ std::pair<ControlPointSelection::iterator, bool> ControlPointSelection::insert(c
}
found = _points.insert(x).first;
+ _points_list.push_back(x);
x->updateState();
_pointChanged(x, true);
@@ -97,6 +100,7 @@ std::pair<ControlPointSelection::iterator, bool> ControlPointSelection::insert(c
void ControlPointSelection::erase(iterator pos)
{
SelectableControlPoint *erased = *pos;
+ _points_list.remove(*pos);
_points.erase(pos);
erased->updateState();
_pointChanged(erased, false);
@@ -219,8 +223,11 @@ void ControlPointSelection::transform(Geom::Affine const &m)
/** Align control points on the specified axis. */
void ControlPointSelection::align(Geom::Dim2 axis)
{
+ enum AlignTargetNode { LAST_NODE=0, FIRST_NODE, MID_NODE, MIN_NODE, MAX_NODE };
if (empty()) return;
Geom::Dim2 d = static_cast<Geom::Dim2>((axis + 1) % 2);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+
Geom::OptInterval bound;
for (iterator i = _points.begin(); i != _points.end(); ++i) {
@@ -229,7 +236,27 @@ void ControlPointSelection::align(Geom::Dim2 axis)
if (!bound) { return; }
- double new_coord = bound->middle();
+ double new_coord;
+ switch (AlignTargetNode(prefs->getInt("/dialogs/align/align-nodes-to", 2))){
+ case FIRST_NODE:
+ new_coord=(_points_list.front())->position()[d];
+ break;
+ case LAST_NODE:
+ new_coord=(_points_list.back())->position()[d];
+ break;
+ case MID_NODE:
+ new_coord=bound->middle();
+ break;
+ case MIN_NODE:
+ new_coord=bound->min();
+ break;
+ case MAX_NODE:
+ new_coord=bound->max();
+ break;
+ default:
+ return;
+ }
+
for (iterator i = _points.begin(); i != _points.end(); ++i) {
Geom::Point pos = (*i)->position();
pos[d] = new_coord;
diff --git a/src/ui/tool/control-point-selection.h b/src/ui/tool/control-point-selection.h
index 2d812c0a3..f122a468d 100644
--- a/src/ui/tool/control-point-selection.h
+++ b/src/ui/tool/control-point-selection.h
@@ -12,6 +12,7 @@
#ifndef SEEN_UI_TOOL_CONTROL_POINT_SELECTION_H
#define SEEN_UI_TOOL_CONTROL_POINT_SELECTION_H
+#include <list>
#include <memory>
#include <boost/optional.hpp>
#include <stddef.h>
@@ -140,6 +141,8 @@ private:
double _rotationRadius(Geom::Point const &);
set_type _points;
+ //the purpose of this list is to keep track of first and last selected
+ std::list<SelectableControlPoint *> _points_list;
set_type _all_points;
INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Point> _original_positions;
INK_UNORDERED_MAP<SelectableControlPoint *, Geom::Affine> _last_trans;
diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp
index 46c6246a1..9ec6f733f 100644
--- a/src/ui/tool/multi-path-manipulator.cpp
+++ b/src/ui/tool/multi-path-manipulator.cpp
@@ -683,13 +683,14 @@ bool MultiPathManipulator::event(Inkscape::UI::Tools::ToolBase *event_context, G
//if the trace is bspline ( mode 2)
if(mode==2){
// is this correct ?
- if(del_preserves_shape ^ held_control(event->key))
+ if(del_preserves_shape ^ held_control(event->key)){
deleteNodes(false);
- else
+ } else {
deleteNodes(true);
- }
- else
+ }
+ } else {
deleteNodes(del_preserves_shape ^ held_control(event->key));
+ }
// Delete any selected gradient nodes as well
event_context->deleteSelectedDrag(held_control(event->key));
diff --git a/src/ui/tool/node.cpp b/src/ui/tool/node.cpp
index ca6f5abb1..d70147f80 100644
--- a/src/ui/tool/node.cpp
+++ b/src/ui/tool/node.cpp
@@ -60,10 +60,8 @@ Inkscape::ControlType nodeTypeToCtrlType(Inkscape::UI::NodeType type)
namespace Inkscape {
namespace UI {
-/*const double handleCubicGap = 0.01;*/
-const double noPower = 0.0;
-const double defaultStartPower = 0.3334;
-/*const double defaultEndPower = 0.6667;*/
+const double NO_POWER = 0.0;
+const double DEFAULT_START_POWER = 1.0/3.0;
ControlPoint::ColorSet Node::node_colors = {
{0xbfbfbf00, 0x000000ff}, // normal fill, stroke
@@ -142,6 +140,7 @@ void Handle::move(Geom::Point const &new_pos)
Node *node_away = _parent->nodeAwayFrom(this); // node in the opposite direction
Handle *towards = node_towards ? node_towards->handleAwayFrom(_parent) : NULL;
Handle *towards_second = node_towards ? node_towards->handleToward(_parent) : NULL;
+ double bspline_weight = 0.0;
if (Geom::are_near(new_pos, _parent->position())) {
// The handle becomes degenerate.
@@ -176,8 +175,9 @@ void Handle::move(Geom::Point const &new_pos)
//move the handler and its oposite the same proportion
if(_pm()._isBSpline()){
- setPosition(_pm()._bsplineHandleReposition(this,this));
- this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),this));
+ setPosition(_pm()._bsplineHandleReposition(this, false));
+ bspline_weight = _pm()._bsplineHandlePosition(this, false);
+ this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(), bspline_weight));
}
return;
}
@@ -193,8 +193,9 @@ void Handle::move(Geom::Point const &new_pos)
//move the handler and its oposite the same proportion
if(_pm()._isBSpline()){
- setPosition(_pm()._bsplineHandleReposition(this,this));
- this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),this));
+ setPosition(_pm()._bsplineHandleReposition(this, false));
+ bspline_weight = _pm()._bsplineHandlePosition(this, false);
+ this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(), bspline_weight));
}
return;
@@ -219,8 +220,9 @@ void Handle::move(Geom::Point const &new_pos)
// moves the handler and its oposite the same proportion
if(_pm()._isBSpline()){
- setPosition(_pm()._bsplineHandleReposition(this,this));
- this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),this));
+ setPosition(_pm()._bsplineHandleReposition(this, false));
+ bspline_weight = _pm()._bsplineHandlePosition(this, false);
+ this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(), bspline_weight));
}
}
@@ -299,7 +301,7 @@ bool Handle::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEven
default: break;
}
break;
- // new double click event to set the handlers of a node to the default proportion, defaultStartPower%
+ // new double click event to set the handlers of a node to the default proportion, DEFAULT_START_POWER%
case GDK_2BUTTON_PRESS:
handle_2button_press();
break;
@@ -310,11 +312,11 @@ bool Handle::_eventHandler(Inkscape::UI::Tools::ToolBase *event_context, GdkEven
return ControlPoint::_eventHandler(event_context, event);
}
-//this function moves the handler and its oposite to the default proportion of defaultStartPower
+//this function moves the handler and its oposite to the default proportion of DEFAULT_START_POWER
void Handle::handle_2button_press(){
if(_pm()._isBSpline()){
- setPosition(_pm()._bsplineHandleReposition(this,defaultStartPower));
- this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(),defaultStartPower));
+ setPosition(_pm()._bsplineHandleReposition(this, DEFAULT_START_POWER));
+ this->other()->setPosition(_pm()._bsplineHandleReposition(this->other(), DEFAULT_START_POWER));
_pm().update();
}
}
@@ -375,7 +377,7 @@ void Handle::dragged(Geom::Point &new_pos, GdkEventMotion *event)
if(_pm()._isBSpline()){
setPosition(new_pos);
int steps = _pm()._bsplineGetSteps();
- new_pos=_pm()._bsplineHandleReposition(this,ceilf(_pm()._bsplineHandlePosition(this,this)*steps)/steps);
+ new_pos=_pm()._bsplineHandleReposition(this,ceilf(_pm()._bsplineHandlePosition(this, false)*steps)/steps);
}
}
@@ -549,7 +551,7 @@ Glib::ustring Handle::_getTip(unsigned state) const
"<b>Auto node handle</b>: drag to convert to smooth node (%s)"), more);
}else{
return format_tip(C_("Path handle tip",
- "<b>BSpline node handle</b>: Shift to drag, double click to reset (%s). %g power"),more,_pm()._bsplineHandlePosition(h,NULL));
+ "<b>BSpline node handle</b>: Shift to drag, double click to reset (%s). %g power"),more,_pm()._bsplineHandlePosition(h));
}
}
}
@@ -627,22 +629,18 @@ void Node::move(Geom::Point const &new_pos)
Geom::Point delta = new_pos - position();
// save the previous nodes strength to apply it again once the node is moved
- double nodeWeight = noPower;
- double nextNodeWeight = noPower;
- double prevNodeWeight = noPower;
+ double nodeWeight = NO_POWER;
+ double nextNodeWeight = NO_POWER;
+ double prevNodeWeight = NO_POWER;
Node *n = this;
Node * nextNode = n->nodeToward(n->front());
Node * prevNode = n->nodeToward(n->back());
- nodeWeight = fmax(_pm()._bsplineHandlePosition(n->front()),_pm()._bsplineHandlePosition(n->back()));
+ nodeWeight = fmax(_pm()._bsplineHandlePosition(n->front(), false),_pm()._bsplineHandlePosition(n->back(), false));
if(prevNode){
- if(prevNode->isEndNode()){
- prevNodeWeight = _pm()._bsplineHandlePosition(prevNode->front(),prevNode->front());
- }
+ prevNodeWeight = _pm()._bsplineHandlePosition(prevNode->front());
}
if(nextNode){
- if(nextNode->isEndNode()){
- nextNodeWeight = _pm()._bsplineHandlePosition(nextNode->back(),nextNode->back());
- }
+ nextNodeWeight = _pm()._bsplineHandlePosition(nextNode->back());
}
setPosition(new_pos);
@@ -659,18 +657,10 @@ void Node::move(Geom::Point const &new_pos)
_front.setPosition(_pm()._bsplineHandleReposition(this->front(),nodeWeight));
_back.setPosition(_pm()._bsplineHandleReposition(this->back(),nodeWeight));
if(prevNode){
- if(prevNode->isEndNode()){
- prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNodeWeight));
- }else{
- prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNode->back()));
- }
+ prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(), prevNodeWeight));
}
if(nextNode){
- if(nextNode->isEndNode()){
- nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNodeWeight));
- }else{
- nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNode->front()));
- }
+ nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(), nextNodeWeight));
}
}
}
@@ -681,22 +671,18 @@ void Node::transform(Geom::Affine const &m)
Geom::Point old_pos = position();
// save the previous nodes strength to apply it again once the node is moved
- double nodeWeight = noPower;
- double nextNodeWeight = noPower;
- double prevNodeWeight = noPower;
+ double nodeWeight = NO_POWER;
+ double nextNodeWeight = NO_POWER;
+ double prevNodeWeight = NO_POWER;
Node *n = this;
Node * nextNode = n->nodeToward(n->front());
Node * prevNode = n->nodeToward(n->back());
nodeWeight = _pm()._bsplineHandlePosition(n->front());
if(prevNode){
- if(prevNode->isEndNode()){
- prevNodeWeight = _pm()._bsplineHandlePosition(prevNode->front(),prevNode->front());
- }
+ prevNodeWeight = _pm()._bsplineHandlePosition(prevNode->front());
}
if(nextNode){
- if(nextNode->isEndNode()){
- nextNodeWeight = _pm()._bsplineHandlePosition(nextNode->back(),nextNode->back());
- }
+ nextNodeWeight = _pm()._bsplineHandlePosition(nextNode->back());
}
setPosition(position() * m);
@@ -709,21 +695,13 @@ void Node::transform(Geom::Affine const &m)
// move the involved handlers, first the node ones, later the adjoining ones
if(_pm()._isBSpline()){
- _front.setPosition(_pm()._bsplineHandleReposition(this->front(),nodeWeight));
- _back.setPosition(_pm()._bsplineHandleReposition(this->back(),nodeWeight));
+ _front.setPosition(_pm()._bsplineHandleReposition(this->front(), nodeWeight));
+ _back.setPosition(_pm()._bsplineHandleReposition(this->back(), nodeWeight));
if(prevNode){
- if(prevNode->isEndNode()){
- prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNodeWeight));
- }else{
- prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(),prevNode->back()));
- }
+ prevNode->front()->setPosition(_pm()._bsplineHandleReposition(prevNode->front(), prevNodeWeight));
}
if(nextNode){
- if(nextNode->isEndNode()){
- nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNodeWeight));
- }else{
- nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(),nextNode->front()));
- }
+ nextNode->back()->setPosition(_pm()._bsplineHandleReposition(nextNode->back(), nextNodeWeight));
}
}
}
@@ -913,15 +891,15 @@ void Node::setType(NodeType type, bool update_handles)
break;
default: break;
}
- /* in node type changes, about bspline traces, we can mantain them with noPower power in border mode,
+ /* in node type changes, about bspline traces, we can mantain them with NO_POWER power in border mode,
or we give them the default power in curve mode */
if(_pm()._isBSpline()){
- double weight = noPower;
- if(_pm()._bsplineHandlePosition(this->front()) != noPower ){
- weight = defaultStartPower;
+ double weight = NO_POWER;
+ if(_pm()._bsplineHandlePosition(this->front()) != NO_POWER ){
+ weight = DEFAULT_START_POWER;
}
- _front.setPosition(_pm()._bsplineHandleReposition(this->front(),weight));
- _back.setPosition(_pm()._bsplineHandleReposition(this->back(),weight));
+ _front.setPosition(_pm()._bsplineHandleReposition(this->front(), weight));
+ _back.setPosition(_pm()._bsplineHandleReposition(this->back(), weight));
}
}
_type = type;
@@ -1435,7 +1413,6 @@ Glib::ustring Node::_getTip(unsigned state) const
{
bool isBSpline = _pm()._isBSpline();
Handle *h = const_cast<Handle *>(&_front);
- Handle *h2 = const_cast<Handle *>(&_back);
if (state_held_shift(state)) {
bool can_drag_out = (_next() && _front.isDegenerate()) || (_prev() && _back.isDegenerate());
if (can_drag_out) {
@@ -1464,7 +1441,7 @@ Glib::ustring Node::_getTip(unsigned state) const
// No modifiers: assemble tip from node type
char const *nodetype = node_type_to_localized_string(_type);
- double power = _pm()._bsplineHandlePosition(h,h2);
+ double power = _pm()._bsplineHandlePosition(h);
if (_selection.transformHandlesEnabled() && selected()) {
if (_selection.size() == 1 && !isBSpline) {
return format_tip(C_("Path node tip",
diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp
index 848b10373..f4790c317 100644
--- a/src/ui/tool/path-manipulator.cpp
+++ b/src/ui/tool/path-manipulator.cpp
@@ -56,9 +56,9 @@ enum PathChange {
};
} // anonymous namespace
-const double HANDLE_CUBIC_GAP = 0.01;
+const double HANDLE_CUBIC_GAP = 0.001;
const double NO_POWER = 0.0;
-const double defaultStartPower = 0.3334;
+const double DEFAULT_START_POWER = 1.0/3.0;
/**
@@ -695,10 +695,12 @@ unsigned PathManipulator::_deleteStretch(NodeList::iterator start, NodeList::ite
// if we are removing, we readjust the handlers
if(_isBSpline()){
if(start.prev()){
- start.prev()->front()->setPosition(_bsplineHandleReposition(start.prev()->front(),start.prev()->back()));
+ double bspline_weight = _bsplineHandlePosition(start.prev()->back(), false);
+ start.prev()->front()->setPosition(_bsplineHandleReposition(start.prev()->front(), bspline_weight));
}
if(end){
- end->back()->setPosition(_bsplineHandleReposition(end->back(),end->front()));
+ double bspline_weight = _bsplineHandlePosition(end->front(), false);
+ end->back()->setPosition(_bsplineHandleReposition(end->back(),bspline_weight));
}
}
@@ -1033,7 +1035,7 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d
line_inside_nodes->moveto(n->position());
line_inside_nodes->lineto(second->position());
sbasis_inside_nodes = line_inside_nodes->first_segment()->toSBasis();
- Geom::Point next = sbasis_inside_nodes.valueAt(defaultStartPower);
+ Geom::Point next = sbasis_inside_nodes.valueAt(DEFAULT_START_POWER);
next = Geom::Point(next[Geom::X] + HANDLE_CUBIC_GAP,next[Geom::Y] + HANDLE_CUBIC_GAP);
line_inside_nodes->reset();
n->front()->setPosition(next);
@@ -1044,7 +1046,7 @@ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, d
line_inside_nodes->moveto(n->position());
line_inside_nodes->lineto(first->position());
sbasis_inside_nodes = line_inside_nodes->first_segment()->toSBasis();
- Geom::Point previous = sbasis_inside_nodes.valueAt(defaultStartPower);
+ Geom::Point previous = sbasis_inside_nodes.valueAt(DEFAULT_START_POWER);
previous = Geom::Point(previous[Geom::X] + HANDLE_CUBIC_GAP,previous[Geom::Y] + HANDLE_CUBIC_GAP);
n->back()->setPosition(previous);
}else{
@@ -1277,13 +1279,10 @@ bool PathManipulator::_isBSpline() const {
}
// returns the corresponding strength to the position of the handlers
-double PathManipulator::_bsplineHandlePosition(Handle *h, Handle *h2)
+double PathManipulator::_bsplineHandlePosition(Handle *h, bool check_other)
{
using Geom::X;
using Geom::Y;
- if(h2){
- h = h2;
- }
double pos = NO_POWER;
Node *n = h->parent();
Node * next_node = NULL;
@@ -1293,19 +1292,19 @@ double PathManipulator::_bsplineHandlePosition(Handle *h, Handle *h2)
line_inside_nodes->moveto(n->position());
line_inside_nodes->lineto(next_node->position());
if(!are_near(h->position(), n->position())){
- pos = Geom::nearest_time(Geom::Point(h->position()[X] - HANDLE_CUBIC_GAP, h->position()[Y] - HANDLE_CUBIC_GAP), *line_inside_nodes->first_segment());
+ pos = Geom::nearest_time(Geom::Point(h->position()[X] - HANDLE_CUBIC_GAP, h->position()[Y] + HANDLE_CUBIC_GAP), *line_inside_nodes->first_segment());
}
}
- if (pos == NO_POWER && !h2){
- return _bsplineHandlePosition(h, h->other());
+ if (pos == NO_POWER && check_other){
+ return _bsplineHandlePosition(h->other(), false);
}
return pos;
}
// give the location for the handler in the corresponding position
-Geom::Point PathManipulator::_bsplineHandleReposition(Handle *h, Handle *h2)
+Geom::Point PathManipulator::_bsplineHandleReposition(Handle *h, bool check_other)
{
- double pos = this->_bsplineHandlePosition(h, h2);
+ double pos = this->_bsplineHandlePosition(h, check_other);
return _bsplineHandleReposition(h,pos);
}
diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h
index 4c6f74ba4..283cb610a 100644
--- a/src/ui/tool/path-manipulator.h
+++ b/src/ui/tool/path-manipulator.h
@@ -111,8 +111,8 @@ private:
void _recalculateIsBSpline();
bool _isBSpline() const;
- double _bsplineHandlePosition(Handle *h, Handle *h2 = NULL);
- Geom::Point _bsplineHandleReposition(Handle *h, Handle *h2 = NULL);
+ double _bsplineHandlePosition(Handle *h, bool check_other = true);
+ Geom::Point _bsplineHandleReposition(Handle *h, bool check_other = true);
Geom::Point _bsplineHandleReposition(Handle *h, double pos);
void _createGeometryFromControlPoints(bool alert_LPE = false);
unsigned _deleteStretch(NodeList::iterator first, NodeList::iterator last, bool keep_shape);
diff --git a/src/ui/tool/selector.cpp b/src/ui/tool/selector.cpp
index 051cb41ae..9acf7de88 100644
--- a/src/ui/tool/selector.cpp
+++ b/src/ui/tool/selector.cpp
@@ -39,6 +39,7 @@ public:
setVisible(false);
_rubber = static_cast<CtrlRect*>(sp_canvas_item_new(_desktop->getControls(),
SP_TYPE_CTRLRECT, NULL));
+ _rubber->setShadow(1, 0xffffffff);
sp_canvas_item_hide(_rubber);
}
diff --git a/src/ui/tool/transform-handle-set.cpp b/src/ui/tool/transform-handle-set.cpp
index da2a54989..748b9d4cc 100644
--- a/src/ui/tool/transform-handle-set.cpp
+++ b/src/ui/tool/transform-handle-set.cpp
@@ -15,9 +15,11 @@
#include <glib/gi18n.h>
#include <2geom/transforms.h>
#include "desktop.h"
+#include "sp-namedview.h"
#include "display/sodipodi-ctrlrect.h"
#include "preferences.h"
+#include "pure-transform.h"
#include "snap.h"
#include "snap-candidate.h"
#include "sp-namedview.h"
@@ -93,6 +95,7 @@ TransformHandle::TransformHandle(TransformHandleSet &th, SPAnchorType anchor, Gl
setVisible(false);
}
+// TODO: This code is duplicated in seltrans.cpp; fix this!
void TransformHandle::getNextClosestPoint(bool reverse)
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -113,6 +116,11 @@ void TransformHandle::getNextClosestPoint(bool reverse)
_snap_points.clear();
_snap_points.push_back(*_all_snap_sources_iter);
+ // Show the updated snap source now; otherwise it won't be shown until the selection is being moved again
+ SnapManager &m = _desktop->namedview->snap_manager;
+ m.setup(_desktop);
+ m.displaySnapsource(*_all_snap_sources_iter);
+ m.unSetup();
}
}
}
@@ -247,7 +255,7 @@ protected:
if (Geom::are_near(vold[Geom::X], 0) || Geom::are_near(vold[Geom::Y], 0))
return Geom::identity();
- double scale[2] = { vnew[Geom::X] / vold[Geom::X], vnew[Geom::Y] / vold[Geom::Y] };
+ Geom::Scale scale = Geom::Scale(vnew[Geom::X] / vold[Geom::X], vnew[Geom::Y] / vold[Geom::Y]);
if (held_alt(*event)) {
for (unsigned i = 0; i < 2; ++i) {
@@ -261,20 +269,21 @@ protected:
SnapManager &m = _th._desktop->namedview->snap_manager;
m.setupIgnoreSelection(_th._desktop, true, &_unselected_points);
- Inkscape::SnappedPoint sp;
+ Inkscape::PureScale *ptr;
if (held_control(*event)) {
scale[0] = scale[1] = std::min(scale[0], scale[1]);
- sp = m.constrainedSnapScale(_snap_points, _origin, Geom::Scale(scale[0], scale[1]), scc);
+ ptr = new Inkscape::PureScaleConstrained(Geom::Scale(scale[0], scale[1]), scc);
} else {
- sp = m.freeSnapScale(_snap_points, _origin, Geom::Scale(scale[0], scale[1]), scc);
+ ptr = new Inkscape::PureScale(Geom::Scale(scale[0], scale[1]), scc, false);
}
+ m.snapTransformed(_snap_points, _origin, (*ptr));
m.unSetup();
- if (sp.getSnapped()) {
- Geom::Point result = sp.getTransformation();
- scale[0] = result[0];
- scale[1] = result[1];
+ if (ptr->best_snapped_point.getSnapped()) {
+ scale = ptr->getScaleSnapped();
}
+
+ delete ptr;
}
_last_scale_x = scale[0];
@@ -349,11 +358,12 @@ protected:
m.setupIgnoreSelection(_th._desktop, true, &_unselected_points);
bool uniform = held_control(*event);
- Inkscape::SnappedPoint sp = m.constrainedSnapStretch(_snap_points, _origin, vs[d1], scc, d1, uniform);
+ Inkscape::PureStretchConstrained psc = Inkscape::PureStretchConstrained(vs[d1], scc, d1, uniform);
+ m.snapTransformed(_snap_points, _origin, psc);
m.unSetup();
- if (sp.getSnapped()) {
- Geom::Point result = sp.getTransformation();
+ if (psc.best_snapped_point.getSnapped()) {
+ Geom::Point result = psc.getStretchSnapped().vector(); //best_snapped_point.getTransformation();
vs[d1] = result[d1];
vs[d2] = result[d2];
} else {
@@ -414,11 +424,12 @@ protected:
} else {
SnapManager &m = _th._desktop->namedview->snap_manager;
m.setupIgnoreSelection(_th._desktop, true, &_unselected_points);
- Inkscape::SnappedPoint sp = m.constrainedSnapRotate(_snap_points, _origin, angle, rotc);
+ Inkscape::PureRotateConstrained prc = Inkscape::PureRotateConstrained(angle, rotc);
+ m.snapTransformed(_snap_points, _origin, prc);
m.unSetup();
- if (sp.getSnapped()) {
- angle = sp.getTransformation()[0];
+ if (prc.best_snapped_point.getSnapped()) {
+ angle = prc.getAngleSnapped(); //best_snapped_point.getTransformation()[0];
}
}
@@ -528,13 +539,12 @@ protected:
SnapManager &m = _th._desktop->namedview->snap_manager;
m.setupIgnoreSelection(_th._desktop, true, &_unselected_points);
- Geom::Point cvec; cvec[d2] = 1.0;
- Inkscape::Snapper::SnapConstraint const constraint(cvec);
- Inkscape::SnappedPoint sp = m.constrainedSnapSkew(_snap_points, _origin, constraint, Geom::Point(skew[d1], scale[d1]), scc, d2);
+ Inkscape::PureSkewConstrained psc = Inkscape::PureSkewConstrained(skew[d1], scale[d1], scc, d2);
+ m.snapTransformed(_snap_points, _origin, psc);
m.unSetup();
- if (sp.getSnapped()) {
- skew[d1] = sp.getTransformation()[0];
+ if (psc.best_snapped_point.getSnapped()) {
+ skew[d1] = psc.getSkewSnapped(); //best_snapped_point.getTransformation()[0];
}
}
diff --git a/src/ui/tools-switch.cpp b/src/ui/tools-switch.cpp
index 11313f550..ea0431b0a 100644
--- a/src/ui/tools-switch.cpp
+++ b/src/ui/tools-switch.cpp
@@ -42,7 +42,11 @@
#include "ui/tools/connector-tool.h"
#include "ui/tools/dropper-tool.h"
#include "ui/tools/eraser-tool.h"
+
+#if HAVE_POTRACE
#include "ui/tools/flood-tool.h"
+#endif
+
#include "ui/tools/gradient-tool.h"
#include "ui/tools/lpe-tool.h"
#include "ui/tools/measure-tool.h"
@@ -83,7 +87,9 @@ static char const *const tool_names[] = {
"/tools/measure",
"/tools/dropper",
"/tools/connector",
+#if HAVE_POTRACE
"/tools/paintbucket",
+#endif
"/tools/eraser",
"/tools/lpetool",
NULL
@@ -111,7 +117,9 @@ static char const *const tool_msg[] = {
N_("<b>Drag</b> to measure the dimensions of objects."),
N_("<b>Click</b> to set fill, <b>Shift+click</b> to set stroke; <b>drag</b> to average color in area; with <b>Alt</b> to pick inverse color; <b>Ctrl+C</b> to copy the color under mouse to clipboard"),
N_("<b>Click and drag</b> between shapes to create a connector."),
+#if HAVE_POTRACE
N_("<b>Click</b> to paint a bounded area, <b>Shift+click</b> to union the new fill with the current selection, <b>Ctrl+click</b> to change the clicked object's fill and stroke to the current setting."),
+#endif
N_("<b>Drag</b> to erase."),
N_("Choose a subtool from the toolbar"),
};
diff --git a/src/ui/tools-switch.h b/src/ui/tools-switch.h
index 280837e87..d396597ca 100644
--- a/src/ui/tools-switch.h
+++ b/src/ui/tools-switch.h
@@ -12,6 +12,10 @@
#ifndef SEEN_TOOLS_SWITCH_H
#define SEEN_TOOLS_SWITCH_H
+#if HAVE_CONFIG_H
+# include "config.h"
+#endif
+
class SPDesktop;
class SPItem;
namespace Geom {
@@ -40,7 +44,11 @@ enum {
TOOLS_MEASURE,
TOOLS_DROPPER,
TOOLS_CONNECTOR,
+
+#if HAVE_POTRACE
TOOLS_PAINTBUCKET,
+#endif
+
TOOLS_ERASER,
TOOLS_LPETOOL
};
diff --git a/src/ui/tools/Makefile_insert b/src/ui/tools/Makefile_insert
index cd09a3230..686dfedd8 100644
--- a/src/ui/tools/Makefile_insert
+++ b/src/ui/tools/Makefile_insert
@@ -8,7 +8,6 @@ ink_common_sources += \
ui/tools/dropper-tool.cpp ui/tools/dropper-tool.h \
ui/tools/dynamic-base.cpp ui/tools/dynamic-base.h \
ui/tools/eraser-tool.cpp ui/tools/eraser-tool.h \
- ui/tools/flood-tool.cpp ui/tools/flood-tool.h \
ui/tools/freehand-base.cpp ui/tools/freehand-base.h \
ui/tools/gradient-tool.cpp ui/tools/gradient-tool.h \
ui/tools/lpe-tool.cpp ui/tools/lpe-tool.h \
@@ -25,4 +24,11 @@ ink_common_sources += \
ui/tools/text-tool.cpp ui/tools/text-tool.h \
ui/tools/tool-base.cpp ui/tools/tool-base.h \
ui/tools/tweak-tool.cpp ui/tools/tweak-tool.h \
- ui/tools/zoom-tool.cpp ui/tools/zoom-tool.h \ No newline at end of file
+ ui/tools/zoom-tool.cpp ui/tools/zoom-tool.h
+
+if HAVE_POTRACE
+
+ink_common_sources += \
+ ui/tools/flood-tool.cpp ui/tools/flood-tool.h
+
+endif
diff --git a/src/ui/tools/connector-tool.cpp b/src/ui/tools/connector-tool.cpp
index 0a36877ff..b84d16686 100644
--- a/src/ui/tools/connector-tool.cpp
+++ b/src/ui/tools/connector-tool.cpp
@@ -1307,7 +1307,7 @@ void cc_selection_set_avoid(bool const set_avoid)
int changes = 0;
std::vector<SPItem*> l = selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=l.begin();i!=l.end();i++) {
+ for(std::vector<SPItem*>::const_iterator i=l.begin();i!=l.end(); ++i) {
SPItem *item = *i;
char const *value = (set_avoid) ? "true" : NULL;
diff --git a/src/ui/tools/eraser-tool.cpp b/src/ui/tools/eraser-tool.cpp
index e416fd7ef..6b32b5901 100644
--- a/src/ui/tools/eraser-tool.cpp
+++ b/src/ui/tools/eraser-tool.cpp
@@ -64,8 +64,11 @@
#include "livarot/Shape.h"
#include "document-undo.h"
#include "verbs.h"
+#include "style.h"
+#include "style-enums.h"
#include <2geom/math-utils.h>
#include <2geom/pathvector.h>
+#include "path-chemistry.h"
#include "display/curve.h"
#include "ui/tools/eraser-tool.h"
@@ -96,6 +99,7 @@ const std::string EraserTool::prefsPath = "/tools/eraser";
EraserTool::EraserTool()
: DynamicBase(cursor_eraser_xpm, 4, 4)
+ , nowidth(false)
{
}
@@ -145,6 +149,7 @@ static ProfileFloatElement f_profile[PROFILE_FLOAT_SIZE] = {
sp_event_context_read(this, "cap_rounding");
this->is_drawing = false;
+ //TODO not sure why get 0.01 if slider width == 0, maybe a double/int problem
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
if (prefs->getBool("/tools/eraser/selcue", 0) != 0) {
@@ -339,7 +344,10 @@ void EraserTool::brush() {
this->point1[this->npoints] = brush + del_left;
this->point2[this->npoints] = brush - del_right;
-
+
+ if (this->nowidth) {
+ this->point1[this->npoints] = Geom::middle_point(this->point1[this->npoints],this->point2[this->npoints]);
+ }
this->del = 0.5*(del_left + del_right);
this->npoints++;
@@ -371,7 +379,8 @@ void EraserTool::cancel() {
bool EraserTool::root_handler(GdkEvent* event) {
gint ret = FALSE;
-
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
switch (event->type) {
case GDK_BUTTON_PRESS:
if (event->button.button == 1 && !this->space_panning) {
@@ -391,10 +400,10 @@ bool EraserTool::root_handler(GdkEvent* event) {
if (this->repr) {
this->repr = NULL;
}
-
- Inkscape::Rubberband::get(desktop)->start(desktop, button_dt);
- Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_TOUCHPATH);
-
+ if ( ! eraserMode ) {
+ Inkscape::Rubberband::get(desktop)->start(desktop, button_dt);
+ Inkscape::Rubberband::get(desktop)->setMode(RUBBERBAND_MODE_TOUCHPATH);
+ }
/* initialize first point */
this->npoints = 0;
@@ -439,8 +448,10 @@ bool EraserTool::root_handler(GdkEvent* event) {
ret = TRUE;
}
-
- Inkscape::Rubberband::get(desktop)->move(motion_dt);
+ if ( !eraserMode ) {
+ this->accumulated->reset();
+ Inkscape::Rubberband::get(desktop)->move(motion_dt);
+ }
}
break;
@@ -480,7 +491,7 @@ bool EraserTool::root_handler(GdkEvent* event) {
ret = TRUE;
}
- if (Inkscape::Rubberband::get(desktop)->is_started()) {
+ if (!eraserMode && Inkscape::Rubberband::get(desktop)->is_started()) {
Inkscape::Rubberband::get(desktop)->stop();
}
@@ -489,33 +500,32 @@ bool EraserTool::root_handler(GdkEvent* event) {
case GDK_KEY_PRESS:
switch (get_group0_keyval (&event->key)) {
- case GDK_KEY_Up:
- case GDK_KEY_KP_Up:
- if (!MOD__CTRL_ONLY(event)) {
- this->angle += 5.0;
-
- if (this->angle > 90.0) {
- this->angle = 90.0;
- }
-
- sp_erc_update_toolbox (desktop, "eraser-angle", this->angle);
- ret = TRUE;
- }
- break;
-
- case GDK_KEY_Down:
- case GDK_KEY_KP_Down:
- if (!MOD__CTRL_ONLY(event)) {
- this->angle -= 5.0;
-
- if (this->angle < -90.0) {
- this->angle = -90.0;
- }
-
- sp_erc_update_toolbox (desktop, "eraser-angle", this->angle);
- ret = TRUE;
- }
- break;
+// case GDK_KEY_Up:
+// case GDK_KEY_KP_Up:
+// if (!MOD__CTRL_ONLY(event)) {
+// this->angle += 5.0;
+
+// if (this->angle > 90.0) {
+// this->angle = 90.0;
+// }
+// sp_erc_update_toolbox (desktop, "eraser-angle", this->angle);
+// ret = TRUE;
+// }
+// break;
+
+// case GDK_KEY_Down:
+// case GDK_KEY_KP_Down:
+// if (!MOD__CTRL_ONLY(event)) {
+// this->angle -= 5.0;
+
+// if (this->angle < -90.0) {
+// this->angle = -90.0;
+// }
+
+// sp_erc_update_toolbox (desktop, "eraser-angle", this->angle);
+// ret = TRUE;
+// }
+// break;
case GDK_KEY_Right:
case GDK_KEY_KP_Right:
@@ -568,8 +578,9 @@ bool EraserTool::root_handler(GdkEvent* event) {
break;
case GDK_KEY_Escape:
- Inkscape::Rubberband::get(desktop)->stop();
-
+ if ( !eraserMode ) {
+ Inkscape::Rubberband::get(desktop)->stop();
+ }
if (this->is_drawing) {
// if drawing, cancel, otherwise pass it up for deselecting
this->cancel();
@@ -640,15 +651,12 @@ void EraserTool::set_to_accumulated() {
sp_desktop_apply_style_tool (desktop, repr, "/tools/eraser", false);
this->repr = repr;
-
- SPItem *item=SP_ITEM(desktop->currentLayer()->appendChildRepr(this->repr));
- Inkscape::GC::release(this->repr);
-
- item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
- item->updateRepr();
}
-
+ SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr(this->repr));
+ Inkscape::GC::release(this->repr);
+ item->updateRepr();
Geom::PathVector pathv = this->accumulated->get_pathvector() * desktop->dt2doc();
+ pathv *= item->i2doc_affine().inverse();
gchar *str = sp_svg_write_path(pathv);
g_assert( str != NULL );
this->repr->setAttribute("d", str);
@@ -658,50 +666,87 @@ void EraserTool::set_to_accumulated() {
bool wasSelection = false;
Inkscape::Selection *selection = desktop->getSelection();
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-
gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
SPItem* acid = SP_ITEM(desktop->doc()->getObjectByRepr(this->repr));
- Geom::OptRect eraserBbox = acid->visualBounds();
- Geom::Rect bounds = (*eraserBbox) * desktop->doc2dt();
+ Geom::OptRect eraserBbox = acid->desktopVisualBounds();
std::vector<SPItem*> remainingItems;
std::vector<SPItem*> toWorkOn;
if (selection->isEmpty()) {
if ( eraserMode ) {
- toWorkOn = desktop->getDocument()->getItemsPartiallyInBox(desktop->dkey, bounds);
+ toWorkOn = desktop->getDocument()->getItemsPartiallyInBox(desktop->dkey, *eraserBbox);
} else {
Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
toWorkOn = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints());
}
toWorkOn.erase(std::remove(toWorkOn.begin(), toWorkOn.end(), acid), toWorkOn.end());
} else {
- toWorkOn= selection->itemList();
+ if ( !eraserMode ) {
+ Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
+ std::vector<SPItem*> touched;
+ touched = desktop->getDocument()->getItemsAtPoints(desktop->dkey, r->getPoints());
+ for (std::vector<SPItem*>::const_iterator i = touched.begin();i!=touched.end();++i) {
+ if(selection->includes(*i)){
+ toWorkOn.push_back((*i));
+ }
+ }
+ } else {
+ toWorkOn = selection->itemList();
+ }
wasSelection = true;
}
if ( !toWorkOn.empty() ) {
if ( eraserMode ) {
- for (std::vector<SPItem*>::const_iterator i = toWorkOn.begin(); i != toWorkOn.end(); i++){
- SPItem *item = *i;
-
- if ( eraserMode ) {
- Geom::OptRect bbox = item->visualBounds();
-
+ for (std::vector<SPItem*>::const_iterator i = toWorkOn.begin(); i != toWorkOn.end(); ++i){
+ SPItem *item = *i;
+ SPUse *use = dynamic_cast<SPUse *>(item);
+ if (SP_IS_PATH(item) && SP_PATH(item)->nodesInPath () == 2){
+ sp_object_ref( *i, 0 );
+ SPItem *item = *i;
+ item->deleteObject(true);
+ sp_object_unref(item);
+ workDone = true;
+ workDone = true;
+ } else if (SP_IS_GROUP(item) || use ) {
+ /*Do nothing*/
+ } else {
+ Geom::OptRect bbox = item->desktopVisualBounds();
if (bbox && bbox->intersects(*eraserBbox)) {
Inkscape::XML::Node* dup = this->repr->duplicate(xml_doc);
this->repr->parent()->appendChild(dup);
Inkscape::GC::release(dup); // parent takes over
-
- selection->set(item);
- selection->add(dup);
- sp_selected_path_diff_skip_undo(selection, desktop);
+ selection->set(dup);
+ if (!this->nowidth) {
+ sp_selected_path_union_skip_undo(selection, desktop);
+ }
+ selection->add(item);
+ if(item->style->fill_rule.value == SP_WIND_RULE_EVENODD){
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property(css, "fill-rule", "evenodd");
+ sp_desktop_set_style(desktop, css);
+ sp_repr_css_attr_unref(css);
+ css = 0;
+ }
+ if (this->nowidth) {
+ sp_selected_path_cut_skip_undo(selection, desktop);
+ } else {
+ sp_selected_path_diff_skip_undo(selection, desktop);
+ }
workDone = true; // TODO set this only if something was cut.
-
+ bool break_apart = prefs->getBool("/tools/eraser/break_apart", false);
+ if(!break_apart){
+ sp_selected_path_combine(desktop, true);
+ } else {
+ if(!this->nowidth){
+ sp_selected_path_break_apart(desktop, true);
+ }
+ }
if ( !selection->isEmpty() ) {
// If the item was not completely erased, track the new remainder.
- std::vector<SPItem*> nowSel(selection->itemList());
- for (std::vector<SPItem*>::const_iterator i2 = nowSel.begin();i2!=nowSel.end();i2++) {
+ std::vector<SPItem*> nowSel(selection->itemList());
+ for (std::vector<SPItem*>::const_iterator i2 = nowSel.begin();i2!=nowSel.end();++i2) {
remainingItems.push_back(*i2);
}
}
@@ -711,11 +756,11 @@ void EraserTool::set_to_accumulated() {
}
}
} else {
- for (std::vector<SPItem*> ::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) {
+ for (std::vector<SPItem*> ::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();++i) {
sp_object_ref( *i, 0 );
}
- for (std::vector<SPItem*>::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i = toWorkOn.begin();i!=toWorkOn.end();++i) {
SPItem *item = *i;
item->deleteObject(true);
sp_object_unref(item);
@@ -736,7 +781,6 @@ void EraserTool::set_to_accumulated() {
}
}
}
-
// Remove the eraser stroke itself:
sp_repr_unparent( this->repr );
this->repr = 0;
@@ -811,24 +855,25 @@ void EraserTool::accumulate() {
g_assert( rev_cal2_lastseg );
this->accumulated->append(this->cal1, FALSE);
-
- add_cap(this->accumulated,
- dc_cal1_lastseg->finalPoint() - dc_cal1_lastseg->unitTangentAt(1),
- dc_cal1_lastseg->finalPoint(),
- rev_cal2_firstseg->initialPoint(),
- rev_cal2_firstseg->initialPoint() + rev_cal2_firstseg->unitTangentAt(0),
- this->cap_rounding);
-
- this->accumulated->append(rev_cal2, TRUE);
-
- add_cap(this->accumulated,
- rev_cal2_lastseg->finalPoint() - rev_cal2_lastseg->unitTangentAt(1),
- rev_cal2_lastseg->finalPoint(),
- dc_cal1_firstseg->initialPoint(),
- dc_cal1_firstseg->initialPoint() + dc_cal1_firstseg->unitTangentAt(0),
- this->cap_rounding);
-
- this->accumulated->closepath();
+ if(!this->nowidth) {
+ add_cap(this->accumulated,
+ dc_cal1_lastseg->finalPoint() - dc_cal1_lastseg->unitTangentAt(1),
+ dc_cal1_lastseg->finalPoint(),
+ rev_cal2_firstseg->initialPoint(),
+ rev_cal2_firstseg->initialPoint() + rev_cal2_firstseg->unitTangentAt(0),
+ this->cap_rounding);
+
+ this->accumulated->append(rev_cal2, TRUE);
+
+ add_cap(this->accumulated,
+ rev_cal2_lastseg->finalPoint() - rev_cal2_lastseg->unitTangentAt(1),
+ rev_cal2_lastseg->finalPoint(),
+ dc_cal1_firstseg->initialPoint(),
+ dc_cal1_firstseg->initialPoint() + dc_cal1_firstseg->unitTangentAt(0),
+ this->cap_rounding);
+
+ this->accumulated->closepath();
+ }
rev_cal2->unref();
@@ -844,6 +889,8 @@ static double square(double const x)
void EraserTool::fit_and_split(bool release) {
double const tolerance_sq = square( desktop->w2d().descrim() * TOLERANCE_ERASER );
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ this->nowidth = prefs->getDouble( "/tools/eraser/width", 1) == 0;
#ifdef ERASER_VERBOSE
g_print("[F&S:R=%c]", release?'T':'F');
@@ -940,7 +987,6 @@ void EraserTool::fit_and_split(bool release) {
g_print("[%d]Yup\n", this->npoints);
#endif
if (!release) {
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
g_assert(!this->currentcurve->is_empty());
diff --git a/src/ui/tools/eraser-tool.h b/src/ui/tools/eraser-tool.h
index 110f57ba3..50ce6b6e3 100644
--- a/src/ui/tools/eraser-tool.h
+++ b/src/ui/tools/eraser-tool.h
@@ -58,6 +58,7 @@ private:
void accumulate();
void fit_and_split(bool release);
void draw_temporary_box();
+ bool nowidth;
};
}
diff --git a/src/ui/tools/freehand-base.cpp b/src/ui/tools/freehand-base.cpp
index e8cbfcdbf..613857626 100644
--- a/src/ui/tools/freehand-base.cpp
+++ b/src/ui/tools/freehand-base.cpp
@@ -20,7 +20,9 @@
# include "config.h"
#endif
+#include "live_effects/lpe-bendpath.h"
#include "live_effects/lpe-patternalongpath.h"
+#include "live_effects/lpe-simplify.h"
#include "display/canvas-bpath.h"
#include "xml/repr.h"
#include "svg/svg.h"
@@ -40,10 +42,12 @@
#include "selection-chemistry.h"
#include "snap.h"
#include "sp-path.h"
+#include "sp-use.h"
#include "sp-namedview.h"
#include "live_effects/lpe-powerstroke.h"
#include "style.h"
#include "ui/control-manager.h"
+#include "util/units.h"
// clipboard support
#include "ui/clipboard.h"
#include "ui/tools/freehand-base.h"
@@ -212,7 +216,7 @@ static Glib::ustring const tool_name(FreehandBase *dc)
: "/tools/freehand/pencil" );
}
-static void spdc_paste_curve_as_freehand_shape(const SPCurve *c, FreehandBase *dc, SPItem *item)
+static void spdc_paste_curve_as_freehand_shape(Geom::PathVector const &newpath, FreehandBase *dc, SPItem *item)
{
using namespace Inkscape::LivePathEffect;
@@ -220,8 +224,7 @@ static void spdc_paste_curve_as_freehand_shape(const SPCurve *c, FreehandBase *d
Effect::createAndApply(PATTERN_ALONG_PATH, dc->desktop->doc(), item);
Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE();
- gchar *svgd = sp_svg_write_path(c->get_pathvector());
- static_cast<LPEPatternAlongPath*>(lpe)->pattern.paste_param_path(svgd);
+ static_cast<LPEPatternAlongPath*>(lpe)->pattern.set_new_value(newpath,true);
}
static void spdc_apply_powerstroke_shape(const std::vector<Geom::Point> & points, FreehandBase *dc, SPItem *item)
@@ -266,37 +269,87 @@ static void spdc_apply_powerstroke_shape(const std::vector<Geom::Point> & points
lpe->getRepr()->setAttribute("offset_points", s.str().c_str());
}
+static void spdc_apply_bend_shape(gchar const *svgd, FreehandBase *dc, SPItem *item)
+{
+ using namespace Inkscape::LivePathEffect;
+ SPUse *use = dynamic_cast<SPUse *>(item);
+ if ( use ) {
+ return;
+ }
+ if(!SP_IS_LPE_ITEM(item) || !SP_LPE_ITEM(item)->hasPathEffectOfType(BEND_PATH)){
+ Effect::createAndApply(BEND_PATH, dc->desktop->doc(), item);
+ }
+ Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE();
+
+ // write bend parameters:
+ lpe->getRepr()->setAttribute("prop_scale", "1");
+ lpe->getRepr()->setAttribute("scale_y_rel", "false");
+ lpe->getRepr()->setAttribute("vertical", "false");
+ static_cast<LPEBendPath*>(lpe)->bend_path.paste_param_path(svgd);
+}
+
+static void spdc_apply_simplify(std::string threshold, FreehandBase *dc, SPItem *item)
+{
+ using namespace Inkscape::LivePathEffect;
+
+ Effect::createAndApply(SIMPLIFY, dc->desktop->doc(), item);
+ Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE();
+ // write simplify parameters:
+ lpe->getRepr()->setAttribute("steps", "1");
+ lpe->getRepr()->setAttribute("threshold", threshold);
+ lpe->getRepr()->setAttribute("smooth_angles", "360");
+ lpe->getRepr()->setAttribute("helper_size", "0");
+ lpe->getRepr()->setAttribute("simplifyindividualpaths", "false");
+ lpe->getRepr()->setAttribute("simplifyJustCoalesce", "false");
+}
+
+enum shapeType { NONE, TRIANGLE_IN, TRIANGLE_OUT, ELLIPSE, CLIPBOARD, BEND_CLIPBOARD, LAST_APPLIED };
+static shapeType previous_shape_type = NONE;
+
static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item, SPCurve *curve)
{
using namespace Inkscape::LivePathEffect;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
if (item && SP_IS_LPE_ITEM(item)) {
+ bool simplify = prefs->getInt(tool_name(dc) + "/simplify", 0);
+ if(simplify){
+ double tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0);
+ tol = tol/(100.0*(102.0-tol));
+ std::ostringstream ss;
+ ss << tol;
+ spdc_apply_simplify(ss.str(), dc, item);
+ sp_lpe_item_update_patheffect(SP_LPE_ITEM(item), false, false);
+ }
if (prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 1) {
Effect::createAndApply(SPIRO, dc->desktop->doc(), item);
}
- //add the bspline node in the waiting effects
+
if (prefs->getInt(tool_name(dc) + "/freehand-mode", 0) == 2) {
Effect::createAndApply(BSPLINE, dc->desktop->doc(), item);
}
+ SPShape *sp_shape = dynamic_cast<SPShape *>(item);
+ if (sp_shape) {
+ curve = sp_shape->getCurve();
+ }
//Store the clipboard path to apply in the future without the use of clipboard
static Geom::PathVector previous_shape_pathv;
- enum shapeType { NONE, TRIANGLE_IN, TRIANGLE_OUT, ELLIPSE, CLIPBOARD, LAST_APPLIED };
- static shapeType previous_shape_type = NONE;
-
shapeType shape = (shapeType)prefs->getInt(tool_name(dc) + "/shape", 0);
bool shape_applied = false;
SPCSSAttr *css_item = sp_css_attr_from_object(item, SP_STYLE_FLAG_ALWAYS);
const char *cstroke = sp_repr_css_property(css_item, "stroke", "none");
+ static SPItem *bend_item;
#define SHAPE_LENGTH 10
#define SHAPE_HEIGHT 10
+
if(shape == LAST_APPLIED){
+
shape = previous_shape_type;
- if(shape == CLIPBOARD){
+ if(shape == CLIPBOARD || shape == BEND_CLIPBOARD){
shape = LAST_APPLIED;
}
}
@@ -337,7 +390,7 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
c->curveto(SHAPE_LENGTH, (1 + C1) * SHAPE_HEIGHT/2, (1 + C1) * SHAPE_LENGTH/2, SHAPE_HEIGHT, SHAPE_LENGTH/2, SHAPE_HEIGHT);
c->curveto((1 - C1) * SHAPE_LENGTH/2, SHAPE_HEIGHT, 0, (1 + C1) * SHAPE_HEIGHT/2, 0, SHAPE_HEIGHT/2);
c->closepath();
- spdc_paste_curve_as_freehand_shape(c, dc, item);
+ spdc_paste_curve_as_freehand_shape(c->get_pathvector(), dc, item);
c->unref();
shape_applied = true;
@@ -345,26 +398,90 @@ static void spdc_check_for_and_apply_waiting_LPE(FreehandBase *dc, SPItem *item,
}
case CLIPBOARD:
{
- // take shape from clipboard; TODO: catch the case where clipboard is empty
- Effect::createAndApply(PATTERN_ALONG_PATH, dc->desktop->doc(), item);
- Effect* lpe = SP_LPE_ITEM(item)->getCurrentLPE();
- static_cast<LPEPatternAlongPath*>(lpe)->pattern.on_paste_button_click();
+ // take shape from clipboard;
Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
- Glib::ustring svgd = cm->getPathParameter(SP_ACTIVE_DESKTOP);
- previous_shape_pathv = sp_svg_read_pathv(svgd.data());
-
- shape_applied = true;
+ if(cm->paste(SP_ACTIVE_DESKTOP,true) == true){
+ SPItem * pasted_clipboard = dc->selection->singleItem();
+ if(pasted_clipboard){
+ Inkscape::XML::Node *pasted_clipboard_root = pasted_clipboard->getRepr();
+ Inkscape::XML::Node *path = sp_repr_lookup_name(pasted_clipboard_root, "svg:path", -1); // unlimited search depth
+ if ( path != NULL ) {
+ gchar const *svgd = path->attribute("d");
+ dc->selection->remove(SP_OBJECT(pasted_clipboard));
+ previous_shape_pathv = sp_svg_read_pathv(svgd);
+ previous_shape_pathv *= pasted_clipboard->transform;
+ spdc_paste_curve_as_freehand_shape(previous_shape_pathv, dc, item);
+
+ shape = CLIPBOARD;
+ shape_applied = true;
+ pasted_clipboard->deleteObject();
+ } else {
+ shape = NONE;
+ }
+ } else {
+ shape = NONE;
+ }
+ } else {
+ shape = NONE;
+ }
+ break;
+ }
+ case BEND_CLIPBOARD:
+ {
+ Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get();
+ if(cm->paste(SP_ACTIVE_DESKTOP,true) == true){
+ gchar const *svgd = item->getRepr()->attribute("d");
+ bend_item = dc->selection->singleItem();
+ if(bend_item){
+ bend_item->moveTo(item,false);
+ bend_item->transform.setTranslation(Geom::Point());
+ spdc_apply_bend_shape(svgd, dc, bend_item);
+ dc->selection->add(SP_OBJECT(bend_item));
+
+ shape = BEND_CLIPBOARD;
+ } else {
+ shape = NONE;
+ }
+ } else {
+ shape = NONE;
+ }
break;
}
case LAST_APPLIED:
{
- if(previous_shape_pathv.size() != 0){
- SPCurve * c = new SPCurve();
- c->set_pathvector(previous_shape_pathv);
- spdc_paste_curve_as_freehand_shape(c, dc, item);
- c->unref();
-
- shape_applied = true;
+ if(previous_shape_type == CLIPBOARD){
+ if(previous_shape_pathv.size() != 0){
+ spdc_paste_curve_as_freehand_shape(previous_shape_pathv, dc, item);
+
+ shape_applied = true;
+ shape = CLIPBOARD;
+ } else{
+ shape = NONE;
+ }
+ } else {
+ if(bend_item != NULL && bend_item->getRepr() != NULL){
+ gchar const *svgd = item->getRepr()->attribute("d");
+ dc->selection->add(SP_OBJECT(bend_item));
+ sp_selection_duplicate(dc->desktop);
+ dc->selection->remove(SP_OBJECT(bend_item));
+ bend_item = dc->selection->singleItem();
+ if(bend_item){
+ bend_item->moveTo(item,false);
+ Geom::Coord expansion_X = bend_item->transform.expansionX();
+ Geom::Coord expansion_Y = bend_item->transform.expansionY();
+ bend_item->transform = Geom::Affine(1,0,0,1,0,0);
+ bend_item->transform.setExpansionX(expansion_X);
+ bend_item->transform.setExpansionY(expansion_Y);
+ spdc_apply_bend_shape(svgd, dc, bend_item);
+ dc->selection->add(SP_OBJECT(bend_item));
+
+ shape = BEND_CLIPBOARD;
+ } else {
+ shape = NONE;
+ }
+ } else {
+ shape = NONE;
+ }
}
break;
}
@@ -643,7 +760,6 @@ void spdc_concat_colors_and_flush(FreehandBase *dc, gboolean forceclosed)
static void spdc_flush_white(FreehandBase *dc, SPCurve *gc)
{
SPCurve *c;
-
if (dc->white_curves) {
g_assert(dc->white_item);
c = SPCurve::concat(dc->white_curves);
@@ -695,14 +811,17 @@ static void spdc_flush_white(FreehandBase *dc, SPCurve *gc)
// Attach repr
SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr));
- // we finished the path; now apply any waiting LPEs or freehand shapes
spdc_check_for_and_apply_waiting_LPE(dc, item, c);
-
- dc->selection->set(repr);
+ if(previous_shape_type != BEND_CLIPBOARD){
+ dc->selection->set(repr);
+ }
Inkscape::GC::release(repr);
item->transform = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
item->updateRepr();
item->doWriteTransform(item->getRepr(), item->transform, NULL, true);
+ if(previous_shape_type == BEND_CLIPBOARD){
+ repr->parent()->removeChild(repr);
+ }
}
DocumentUndo::done(doc, SP_IS_PEN_CONTEXT(dc)? SP_VERB_CONTEXT_PEN : SP_VERB_CONTEXT_PENCIL,
diff --git a/src/ui/tools/gradient-tool.cpp b/src/ui/tools/gradient-tool.cpp
index 603458983..9d8101cc4 100644
--- a/src/ui/tools/gradient-tool.cpp
+++ b/src/ui/tools/gradient-tool.cpp
@@ -225,13 +225,13 @@ sp_gradient_context_get_stop_intervals (GrDrag *drag, GSList **these_stops, GSLi
std::vector<Geom::Point> coords;
// for all selected draggers
- for (GList *i = drag->selected; i != NULL; i = i->next) {
- GrDragger *dragger = (GrDragger *) i->data;
+ for (std::set<GrDragger *>::const_iterator i = drag->selected.begin(); i != drag->selected.end() ; ++i ) {
+ GrDragger *dragger = *i;
// remember the coord of the dragger to reselect it later
coords.push_back(dragger->point);
// for all draggables of dragger
- for (GSList const* j = dragger->draggables; j != NULL; j = j->next) {
- GrDraggable *d = (GrDraggable *) j->data;
+ for (std::vector<GrDraggable *>::const_iterator j = dragger->draggables.begin(); j != dragger->draggables.end(); ++j) {
+ GrDraggable *d = *j;
// find the gradient
SPGradient *gradient = getGradient(d->item, d->fill_or_stroke);
@@ -315,9 +315,9 @@ sp_gradient_context_add_stops_between_selected_stops (GradientTool *rc)
if (g_slist_length(these_stops) == 0 && drag->numSelected() == 1) {
// if a single stop is selected, add between that stop and the next one
- GrDragger *dragger = (GrDragger *) drag->selected->data;
- for (GSList const* j = dragger->draggables; j != NULL; j = j->next) {
- GrDraggable *d = (GrDraggable *) j->data;
+ GrDragger *dragger = *(drag->selected.begin());
+ for (std::vector<GrDraggable *>::const_iterator j = dragger->draggables.begin(); j != dragger->draggables.end(); ++j) {
+ GrDraggable *d = *j;
if (d->point_type == POINT_RG_FOCUS) {
/*
* There are 2 draggables at the center (start) of a radial gradient
@@ -482,9 +482,9 @@ bool GradientTool::root_handler(GdkEvent* event) {
bool over_line = false;
SPCtrlLine *line = NULL;
- if (drag->lines) {
- for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) {
- line = (SPCtrlLine*) l->data;
+ if (!drag->lines.empty()) {
+ for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) {
+ line = *l;
over_line |= sp_gradient_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y));
}
}
@@ -495,7 +495,7 @@ bool GradientTool::root_handler(GdkEvent* event) {
sp_gradient_context_add_stop_near_point(this, SP_ITEM(selection->itemList().front()), this->mousepoint_doc, event->button.time);
} else {
std::vector<SPItem*> items=selection->itemList();
- for (std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i = items.begin();i!=items.end();++i) {
SPItem *item = *i;
SPGradientType new_type = (SPGradientType) prefs->getInt("/tools/gradient/newgradient", SP_GRADIENT_TYPE_LINEAR);
Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
@@ -588,9 +588,9 @@ bool GradientTool::root_handler(GdkEvent* event) {
bool over_line = false;
- if (drag->lines) {
- for (GSList *l = drag->lines; l != NULL; l = l->next) {
- over_line |= sp_gradient_context_is_over_line (this, (SPItem*) l->data, Geom::Point(event->motion.x, event->motion.y));
+ if (!drag->lines.empty()) {
+ for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end(); ++l) {
+ over_line |= sp_gradient_context_is_over_line (this, (SPItem*) (*l), Geom::Point(event->motion.x, event->motion.y));
}
}
@@ -613,12 +613,10 @@ bool GradientTool::root_handler(GdkEvent* event) {
bool over_line = false;
SPCtrlLine *line = NULL;
- if (drag->lines) {
- for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) {
- line = (SPCtrlLine*) l->data;
+ if (!drag->lines.empty()) {
+ for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) {
+ line = *l;
over_line = sp_gradient_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y));
- if (over_line)
- break;
}
}
@@ -663,7 +661,7 @@ bool GradientTool::root_handler(GdkEvent* event) {
}
} else {
// click in an empty space; do the same as Esc
- if (drag->selected) {
+ if (!drag->selected.empty()) {
drag->deselectAll();
} else {
selection->clear();
@@ -719,7 +717,7 @@ bool GradientTool::root_handler(GdkEvent* event) {
break;
case GDK_KEY_Escape:
- if (drag->selected) {
+ if (!drag->selected.empty()) {
drag->deselectAll();
} else {
Inkscape::SelectionHelper::selectNone(desktop);
@@ -910,7 +908,7 @@ static void sp_gradient_drag(GradientTool &rc, Geom::Point const pt, guint /*sta
sp_repr_css_set_property(css, "fill-opacity", "1.0");
std::vector<SPItem*> itemlist = selection->itemList();
- for (std::vector<SPItem*>::const_iterator i = itemlist.begin();i!=itemlist.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i = itemlist.begin();i!=itemlist.end();++i) {
//FIXME: see above
sp_repr_css_change_recursive((*i)->getRepr(), css, "style");
diff --git a/src/ui/tools/lpe-tool.cpp b/src/ui/tools/lpe-tool.cpp
index 13e47f3a6..9bbc1ac20 100644
--- a/src/ui/tools/lpe-tool.cpp
+++ b/src/ui/tools/lpe-tool.cpp
@@ -397,7 +397,7 @@ lpetool_create_measuring_items(LpeTool *lc, Inkscape::Selection *selection)
gchar *arc_length;
double lengthval;
std::vector<SPItem*> items=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
if (SP_IS_PATH(*i)) {
path = SP_PATH(*i);
curve = path->getCurve();
diff --git a/src/ui/tools/measure-tool.cpp b/src/ui/tools/measure-tool.cpp
index 570f3e796..a2a440ef4 100644
--- a/src/ui/tools/measure-tool.cpp
+++ b/src/ui/tools/measure-tool.cpp
@@ -4,67 +4,86 @@
* Authors:
* Felipe Correa da Silva Sanches <juca@members.fsf.org>
* Jon A. Cruz <jon@joncruz.org>
+ * Jabiertxo Arraiza <jabier.arraiza@marker.es>
*
* Copyright (C) 2011 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
-
+#include <gtkmm.h>
#include <gdk/gdkkeysyms.h>
#include <boost/none_t.hpp>
#include "util/units.h"
-#include "macros.h"
#include "display/curve.h"
-#include "sp-shape.h"
-#include "sp-text.h"
-#include "sp-flowtext.h"
-#include "text-editing.h"
-#include "display/sp-ctrlline.h"
#include "display/sodipodi-ctrl.h"
+#include "display/sp-ctrlline.h"
+#include "display/sp-ctrlcurve.h"
+#include "display/sp-canvas.h"
#include "display/sp-canvas-item.h"
#include "display/sp-canvas-util.h"
-#include "desktop.h"
-#include "document.h"
-#include "pixmaps/cursor-measure.xpm"
-#include "preferences.h"
-#include "inkscape.h"
-
+#include "svg/svg.h"
+#include "svg/svg-color.h"
#include "ui/tools/measure-tool.h"
#include "ui/tools/freehand-base.h"
-#include "display/canvas-text.h"
-#include "path-chemistry.h"
-#include "2geom/line.h"
+#include <2geom/line.h>
#include <2geom/path-intersection.h>
#include <2geom/pathvector.h>
#include <2geom/crossing.h>
#include <2geom/angle.h>
-#include "snap.h"
+#include <2geom/transforms.h>
+#include "ui/dialog/knot-properties.h"
#include "sp-namedview.h"
+#include "sp-shape.h"
+#include "sp-text.h"
+#include "sp-flowtext.h"
+#include "sp-defs.h"
+#include "sp-item.h"
+#include "sp-root.h"
+#include "macros.h"
+#include "svg/stringstream.h"
+#include "rubberband.h"
+#include "path-chemistry.h"
+#include "desktop.h"
+#include "document.h"
+#include "document-undo.h"
+#include "viewbox.h"
+#include "snap.h"
+#include "knot.h"
+#include "text-editing.h"
+#include "pixmaps/cursor-measure.xpm"
+#include "preferences.h"
+#include "inkscape.h"
#include "enums.h"
-#include "ui/control-manager.h"
#include "knot-enums.h"
+#include "desktop-style.h"
+#include "verbs.h"
+#include <glibmm/i18n.h>
using Inkscape::ControlManager;
using Inkscape::CTLINE_SECONDARY;
using Inkscape::Util::unit_table;
+using Inkscape::DocumentUndo;
+
+#define MT_KNOT_COLOR_NORMAL 0xffffff00
+#define MT_KNOT_COLOR_MOUSEOVER 0xff000000
+
namespace Inkscape {
namespace UI {
namespace Tools {
-std::vector<Inkscape::Display::TemporaryItem*> measure_tmp_items;
-
-const std::string& MeasureTool::getPrefsPath() {
- return MeasureTool::prefsPath;
+const std::string& MeasureTool::getPrefsPath()
+{
+ return MeasureTool::prefsPath;
}
const std::string MeasureTool::prefsPath = "/tools/measure";
-namespace
-{
-
-gint const DIMENSION_OFFSET = 35;
+namespace {
/**
* Simple class to use for removing label overlap.
@@ -87,14 +106,16 @@ bool SortLabelPlacement(LabelPlacement const &first, LabelPlacement const &secon
}
}
-void repositionOverlappingLabels(std::vector<LabelPlacement> &placements, SPDesktop *desktop, Geom::Point const &normal, double fontsize)
+//precision is for give the number of decimal positions
+//of the label to calculate label width
+void repositionOverlappingLabels(std::vector<LabelPlacement> &placements, SPDesktop *desktop, Geom::Point const &normal, double fontsize, int precision)
{
std::sort(placements.begin(), placements.end(), SortLabelPlacement);
double border = 3;
Geom::Rect box;
{
- Geom::Point tmp(fontsize * 8 + (border * 2), fontsize + (border * 2));
+ Geom::Point tmp(fontsize * (6 + precision) + (border * 2), fontsize + (border * 2));
tmp = desktop->w2d(tmp);
box = Geom::Rect(-tmp[Geom::X] / 2, -tmp[Geom::Y] / 2, tmp[Geom::X] / 2, tmp[Geom::Y] / 2);
}
@@ -175,6 +196,76 @@ Geom::Point calcAngleDisplayAnchor(SPDesktop *desktop, double angle, double base
}
/**
+ * Create a measure iten in current document.
+ *
+ * @param pathv the path to create.
+ * @param markers, if the path resuts get markers.
+ * @param color of the stroke.
+ * @param measure_repr container element.
+ */
+void setMeasureItem(Geom::PathVector pathv, bool is_curve, bool markers, guint32 color, Inkscape::XML::Node *measure_repr)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop) {
+ return;
+ }
+ SPDocument *doc = desktop->getDocument();
+ Inkscape::XML::Document *xml_doc = doc->getReprDoc();
+ Inkscape::XML::Node *repr;
+ repr = xml_doc->createElement("svg:path");
+ gchar *str = sp_svg_write_path(pathv);
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ Geom::Coord strokewidth = SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse().expansionX();
+ std::stringstream stroke_width;
+ stroke_width.imbue(std::locale::classic());
+ if(measure_repr) {
+ stroke_width << strokewidth / desktop->current_zoom();
+ } else {
+ stroke_width << strokewidth;
+ }
+ sp_repr_css_set_property (css, "stroke-width", stroke_width.str().c_str());
+ sp_repr_css_set_property (css, "fill", "none");
+ if(color) {
+ gchar color_line[64];
+ sp_svg_write_color (color_line, sizeof(color_line), color);
+ sp_repr_css_set_property (css, "stroke", color_line);
+ } else {
+ sp_repr_css_set_property (css, "stroke", "#ff0000");
+ }
+ char const * stroke_linecap = is_curve ? "butt" : "square";
+ sp_repr_css_set_property (css, "stroke-linecap", stroke_linecap);
+ sp_repr_css_set_property (css, "stroke-linejoin", "miter");
+ sp_repr_css_set_property (css, "stroke-miterlimit", "4");
+ sp_repr_css_set_property (css, "stroke-dasharray", "none");
+ if(measure_repr) {
+ sp_repr_css_set_property (css, "stroke-opacity", "0.5");
+ } else {
+ sp_repr_css_set_property (css, "stroke-opacity", "1");
+ }
+ if(markers) {
+ sp_repr_css_set_property (css, "marker-start", "url(#Arrow2Sstart)");
+ sp_repr_css_set_property (css, "marker-end", "url(#Arrow2Send)");
+ }
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ repr->setAttribute("style", css_str.c_str());
+ sp_repr_css_attr_unref (css);
+ g_assert( str != NULL );
+ repr->setAttribute("d", str);
+ g_free(str);
+ if(measure_repr) {
+ measure_repr->addChild(repr, NULL);
+ Inkscape::GC::release(repr);
+ } else {
+ SPItem *item = SP_ITEM(desktop->currentLayer()->appendChildRepr(repr));
+ Inkscape::GC::release(repr);
+ item->updateRepr();
+ desktop->getSelection()->clear();
+ desktop->getSelection()->add(item);
+ }
+}
+
+/**
* Given an angle, the arc center and edge point, draw an arc segment centered around that edge point.
*
* @param desktop the desktop that is being used.
@@ -182,8 +273,9 @@ Geom::Point calcAngleDisplayAnchor(SPDesktop *desktop, double angle, double base
* @param end the point that ends at the edge of the arc segment.
* @param anchor the anchor point for displaying the text label.
* @param angle the angle of the arc segment to draw.
+ * @param measure_rpr the container of the curve if converted to items.
*/
-void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const &center, Geom::Point const &end, Geom::Point const &anchor, double angle)
+void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const &center, Geom::Point const &end, Geom::Point const &anchor, double angle, bool to_phantom, std::vector<SPCanvasItem *> &measure_phantom_items , std::vector<SPCanvasItem *> &measure_tmp_items , Inkscape::XML::Node *measure_repr = NULL)
{
// Given that we have a point on the arc's edge and the angle of the arc, we need to get the two endpoints.
@@ -191,7 +283,7 @@ void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const &center, Geom
double sideLen = std::abs((end - center).length());
if (sideLen > 0.0) {
double factor = std::min(1.0, textLen / sideLen);
-
+
// arc start
Geom::Point p1 = end * (Geom::Affine(Geom::Translate(-center))
* Geom::Affine(Geom::Scale(factor))
@@ -219,24 +311,212 @@ void createAngleDisplayCurve(SPDesktop *desktop, Geom::Point const &center, Geom
Geom::Point p3(xc + bx + (k2 * by),
yc + by - (k2 * bx));
SPCtrlCurve *curve = ControlManager::getManager().createControlCurve(desktop->getTempGroup(), p1, p2, p3, p4, CTLINE_SECONDARY);
-
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(SP_CANVAS_ITEM(curve), 0, true));
+ if(to_phantom){
+ curve->rgba = 0x8888887f;
+ measure_phantom_items.push_back(SP_CANVAS_ITEM(curve));
+ } else {
+ measure_tmp_items.push_back(SP_CANVAS_ITEM(curve));
+ }
+ sp_canvas_item_move_to_z(SP_CANVAS_ITEM(curve), 0);
+ sp_canvas_item_show(SP_CANVAS_ITEM(curve));
+ if(measure_repr) {
+ Geom::PathVector pathv;
+ Geom::Path path;
+ path.start(desktop->doc2dt(p1));
+ path.appendNew<Geom::CubicBezier>(desktop->doc2dt(p2),desktop->doc2dt(p3),desktop->doc2dt(p4));
+ pathv.push_back(path);
+ pathv *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ if(!pathv.empty()) {
+ setMeasureItem(pathv, true, false, 0xff00007f, measure_repr);
+ }
+ }
}
}
-} // namespace
+} // namespace
+boost::optional<Geom::Point> explicit_base_tmp = boost::none;
MeasureTool::MeasureTool()
: ToolBase(cursor_measure_xpm, 4, 4)
, grabbed(NULL)
{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ start_p = readMeasurePoint(true);
+ end_p = readMeasurePoint(false);
+ dimension_offset = 35;
+ // create the knots
+ this->knot_start = new SPKnot(desktop, N_("Measure start, <b>Shift+Click</b> for position dialog"));
+ this->knot_start->setMode(SP_KNOT_MODE_XOR);
+ this->knot_start->setFill(MT_KNOT_COLOR_NORMAL, MT_KNOT_COLOR_MOUSEOVER, MT_KNOT_COLOR_MOUSEOVER);
+ this->knot_start->setStroke(0x0000007f, 0x0000007f, 0x0000007f);
+ this->knot_start->setShape(SP_KNOT_SHAPE_CIRCLE);
+ this->knot_start->updateCtrl();
+ this->knot_end = new SPKnot(desktop, N_("Measure end, <b>Shift+Click</b> for position dialog"));
+ this->knot_end->setMode(SP_KNOT_MODE_XOR);
+ this->knot_end->setFill(MT_KNOT_COLOR_NORMAL, MT_KNOT_COLOR_MOUSEOVER, MT_KNOT_COLOR_MOUSEOVER);
+ this->knot_end->setStroke(0x0000007f, 0x0000007f, 0x0000007f);
+ this->knot_end->setShape(SP_KNOT_SHAPE_CIRCLE);
+ this->knot_end->updateCtrl();
+ Geom::Rect display_area = desktop->get_display_area();
+ if(display_area.interiorContains(start_p) && display_area.interiorContains(end_p) && end_p != Geom::Point()) {
+ this->knot_start->moveto(start_p);
+ this->knot_start->show();
+ this->knot_end->moveto(end_p);
+ this->knot_end->show();
+ showCanvasItems();
+ } else {
+ start_p = Geom::Point(0,0);
+ end_p = Geom::Point(0,0);
+ writeMeasurePoint(start_p, true);
+ writeMeasurePoint(end_p, false);
+ }
+ this->_knot_start_moved_connection = this->knot_start->moved_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotStartMovedHandler));
+ this->_knot_start_click_connection = this->knot_start->click_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotClickHandler));
+ this->_knot_start_ungrabbed_connection = this->knot_start->ungrabbed_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotUngrabbedHandler));
+ this->_knot_end_moved_connection = this->knot_end->moved_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotEndMovedHandler));
+ this->_knot_end_click_connection = this->knot_end->click_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotClickHandler));
+ this->_knot_end_ungrabbed_connection = this->knot_end->ungrabbed_signal.connect(sigc::mem_fun(*this, &MeasureTool::knotUngrabbedHandler));
+
}
-MeasureTool::~MeasureTool() {
+MeasureTool::~MeasureTool()
+{
+ this->_knot_start_moved_connection.disconnect();
+ this->_knot_start_ungrabbed_connection.disconnect();
+ this->_knot_end_moved_connection.disconnect();
+ this->_knot_end_ungrabbed_connection.disconnect();
+
+ /* unref should call destroy */
+ knot_unref(this->knot_start);
+ knot_unref(this->knot_end);
+ for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) {
+ sp_canvas_item_destroy(measure_tmp_items[idx]);
+ }
+ measure_tmp_items.clear();
+ for (size_t idx = 0; idx < measure_phantom_items.size(); ++idx) {
+ sp_canvas_item_destroy(measure_phantom_items[idx]);
+ }
+ measure_phantom_items.clear();
}
-void MeasureTool::finish() {
+Geom::Point MeasureTool::readMeasurePoint(bool is_start) {
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPNamedView *namedview = desktop->namedview;
+ if(!namedview) {
+ return Geom::Point(Geom::infinity(),Geom::infinity());
+ }
+ char const * measure_point = is_start ? "inkscape:measure-start" : "inkscape:measure-end";
+ char const * measure_point_data = namedview->getAttribute (measure_point);
+ if(!measure_point_data) {
+ measure_point_data = "0,0";
+ namedview->setAttribute (measure_point, measure_point_data);
+ }
+ gchar ** strarray = g_strsplit(measure_point_data, ",", 2);
+ double newx, newy;
+ unsigned int success = sp_svg_number_read_d(strarray[0], &newx);
+ success += sp_svg_number_read_d(strarray[1], &newy);
+ g_strfreev (strarray);
+ if (success == 2) {
+ Geom::Point point_data(newx, newy);
+ return point_data;
+ }
+ return Geom::Point(Geom::infinity(),Geom::infinity());
+
+}
+
+void MeasureTool::writeMeasurePoint(Geom::Point point, bool is_start) {
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPNamedView *namedview = desktop->namedview;
+ if(!namedview) {
+ return;
+ }
+ std::stringstream meassure_point_str;
+ meassure_point_str.imbue(std::locale::classic());
+ meassure_point_str << point[Geom::X] << "," << point[Geom::Y];
+ gchar const *measure_point = is_start ? "inkscape:measure-start" : "inkscape:measure-end";
+ namedview->setAttribute (measure_point, meassure_point_str.str().c_str());
+}
+
+//This function is used to reverse the Measure, I do it in two steps because when move the knot the
+//start_ or the end_p are overwrite so I need the original values.
+void MeasureTool::reverseKnots()
+{
+ Geom::Point start = start_p;
+ Geom::Point end = end_p;
+ this->knot_start->moveto(end);
+ this->knot_start->show();
+ this->knot_end->moveto(start);
+ this->knot_end->show();
+ start_p = end;
+ end_p = start;
+ this->showCanvasItems();
+}
+
+void MeasureTool::knotClickHandler(SPKnot *knot, guint state)
+{
+ if (state & GDK_SHIFT_MASK) {
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ Glib::ustring const unit_name = prefs->getString("/tools/measure/unit");
+ explicit_base = explicit_base_tmp;
+ Inkscape::UI::Dialogs::KnotPropertiesDialog::showDialog(desktop, knot, unit_name);
+ }
+}
+
+void MeasureTool::knotStartMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state)
+{
+ Geom::Point point = this->knot_start->position();
+ if (state & GDK_CONTROL_MASK) {
+ spdc_endpoint_snap_rotation(this, point, end_p, state);
+ } else if (!(state & GDK_SHIFT_MASK)) {
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
+ Inkscape::SnapCandidatePoint scp(point, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ scp.addOrigin(this->knot_end->position());
+ Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp);
+ point = sp.getPoint();
+ snap_manager.unSetup();
+ }
+ if(start_p != point) {
+ start_p = point;
+ this->knot_start->moveto(start_p);
+ }
+ showCanvasItems();
+}
+
+void MeasureTool::knotEndMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state)
+{
+ Geom::Point point = this->knot_end->position();
+ if (state & GDK_CONTROL_MASK) {
+ spdc_endpoint_snap_rotation(this, point, start_p, state);
+ } else if (!(state & GDK_SHIFT_MASK)) {
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
+ Inkscape::SnapCandidatePoint scp(point, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ scp.addOrigin(this->knot_start->position());
+ Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp);
+ point = sp.getPoint();
+ snap_manager.unSetup();
+ }
+ if(end_p != point) {
+ end_p = point;
+ this->knot_end->moveto(end_p);
+ }
+ showCanvasItems();
+}
+
+void MeasureTool::knotUngrabbedHandler(SPKnot */*knot*/, unsigned int state)
+{
+ this->knot_start->moveto(start_p);
+ this->knot_end->moveto(end_p);
+ showCanvasItems();
+}
+
+
+//todo: we need this function?
+void MeasureTool::finish()
+{
this->enableGrDrag(false);
if (this->grabbed) {
@@ -247,498 +527,816 @@ void MeasureTool::finish() {
ToolBase::finish();
}
-//void MeasureTool::setup() {
-// ToolBase* ec = this;
-//
-//// if (SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->setup) {
-//// SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->setup(ec);
-//// }
-// ToolBase::setup();
-//}
-
-//gint MeasureTool::item_handler(SPItem* item, GdkEvent* event) {
-// gint ret = FALSE;
-//
-//// if (SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->item_handler) {
-//// ret = SP_EVENT_CONTEXT_CLASS(sp_measure_context_parent_class)->item_handler(event_context, item, event);
-//// }
-// ret = ToolBase::item_handler(item, event);
-//
-// return ret;
-//}
-
static void calculate_intersections(SPDesktop * /*desktop*/, SPItem* item, Geom::PathVector const &lineseg, SPCurve *curve, std::vector<double> &intersections)
{
-
curve->transform(item->i2doc_affine());
// Find all intersections of the control-line with this shape
Geom::CrossingSet cs = Geom::crossings(lineseg, curve->get_pathvector());
Geom::delete_duplicates(cs[0]);
// Reconstruct and store the points of intersection
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool show_hidden = prefs->getBool("/tools/measure/show_hidden", true);
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
for (Geom::Crossings::const_iterator m = cs[0].begin(); m != cs[0].end(); ++m) {
-#if 0
-//TODO: consider only visible intersections
- Geom::Point intersection = lineseg[0].pointAt((*m).ta);
- double eps = 0.0001;
- SPDocument* doc = desktop->getDocument();
- if (((*m).ta > eps &&
- item == doc->getItemAtPoint(desktop->dkey, lineseg[0].pointAt((*m).ta - eps), false, NULL)) ||
+ if (!show_hidden) {
+ double eps = 0.0001;
+ if (((*m).ta > eps &&
+ item == desktop->getItemAtPoint(desktop->d2w(desktop->dt2doc(lineseg[0].pointAt((*m).ta - eps))), true, NULL)) ||
((*m).ta + eps < 1 &&
- item == doc->getItemAtPoint(desktop->dkey, lineseg[0].pointAt((*m).ta + eps), false, NULL)) ) {
+ item == desktop->getItemAtPoint(desktop->d2w(desktop->dt2doc(lineseg[0].pointAt((*m).ta + eps))), true, NULL))) {
+ intersections.push_back((*m).ta);
+ }
+ } else {
intersections.push_back((*m).ta);
}
-#else
- intersections.push_back((*m).ta);
-
-#endif
}
}
-bool MeasureTool::root_handler(GdkEvent* event) {
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
-
+bool MeasureTool::root_handler(GdkEvent* event)
+{
gint ret = FALSE;
switch (event->type) {
- case GDK_BUTTON_PRESS: {
- Geom::Point const button_w(event->button.x, event->button.y);
- explicitBase = boost::none;
- lastEnd = boost::none;
- start_point = desktop->w2d(button_w);
-
- if (event->button.button == 1 && !this->space_panning) {
- // save drag origin
- xp = static_cast<gint>(event->button.x);
- yp = static_cast<gint>(event->button.y);
- within_tolerance = true;
-
- ret = TRUE;
- }
+ case GDK_BUTTON_PRESS: {
+ this->knot_start->hide();
+ this->knot_end->hide();
+ Geom::Point const button_w(event->button.x, event->button.y);
+ explicit_base = boost::none;
+ explicit_base_tmp = boost::none;
+ last_end = boost::none;
+ start_p = desktop->w2d(button_w);
+
+ if (event->button.button == 1 && !this->space_panning) {
+ // save drag origin
+ start_p = desktop->w2d(Geom::Point(event->button.x, event->button.y));
+ within_tolerance = true;
+
+ ret = TRUE;
+ }
- SnapManager &m = desktop->namedview->snap_manager;
- m.setup(desktop);
- m.freeSnapReturnByRef(start_point, Inkscape::SNAPSOURCE_OTHER_HANDLE);
- m.unSetup();
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
+ snap_manager.freeSnapReturnByRef(start_p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ snap_manager.unSetup();
- sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
- GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK,
- NULL, event->button.time);
- this->grabbed = SP_CANVAS_ITEM(desktop->acetate);
- break;
- }
- case GDK_KEY_PRESS: {
- if ((event->key.keyval == GDK_KEY_Shift_L) || (event->key.keyval == GDK_KEY_Shift_R)) {
- if (lastEnd) {
- explicitBase = lastEnd;
- }
- }
- break;
+ sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
+ GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK,
+ NULL, event->button.time);
+ this->grabbed = SP_CANVAS_ITEM(desktop->acetate);
+ break;
+ }
+ case GDK_KEY_PRESS: {
+ if ((event->key.keyval == GDK_KEY_Shift_L) || (event->key.keyval == GDK_KEY_Shift_R)) {
+ explicit_base_tmp = explicit_base;
+ explicit_base = end_p;
}
- case GDK_MOTION_NOTIFY: {
- if (!((event->motion.state & GDK_BUTTON1_MASK) && !this->space_panning)) {
- if (!(event->motion.state & GDK_SHIFT_MASK)) {
- Geom::Point const motion_w(event->motion.x, event->motion.y);
- Geom::Point const motion_dt(desktop->w2d(motion_w));
-
- SnapManager &m = desktop->namedview->snap_manager;
- m.setup(desktop);
+ break;
+ }
+ case GDK_MOTION_NOTIFY: {
+ if (!(event->motion.state & GDK_BUTTON1_MASK)) {
+ if(!(event->motion.state & GDK_SHIFT_MASK)) {
+ Geom::Point const motion_w(event->motion.x, event->motion.y);
+ Geom::Point const motion_dt(desktop->w2d(motion_w));
- Inkscape::SnapCandidatePoint scp(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE);
- scp.addOrigin(start_point);
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
- m.preSnap(scp);
- m.unSetup();
- }
- } else {
- ret = TRUE;
+ Inkscape::SnapCandidatePoint scp(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ scp.addOrigin(start_p);
- if ( within_tolerance
- && ( abs( static_cast<gint>(event->motion.x) - xp ) < tolerance )
- && ( abs( static_cast<gint>(event->motion.y) - yp ) < tolerance ) ) {
- break; // do not drag if we're within tolerance from origin
- }
- // Once the user has moved farther than tolerance from the original location
- // (indicating they intend to move the object, not click), then always process the
- // motion notify coordinates as given (no snapping back to origin)
- within_tolerance = false;
-
- //clear previous temporary canvas items, we'll draw new ones
- for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) {
- desktop->remove_temporary_canvasitem(measure_tmp_items[idx]);
+ snap_manager.preSnap(scp);
+ snap_manager.unSetup();
+ }
+ } else {
+ ret = TRUE;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
+ Geom::Point const motion_w(event->motion.x, event->motion.y);
+ if ( within_tolerance) {
+ if ( Geom::LInfty( motion_w - start_p ) < tolerance) {
+ return FALSE; // Do not drag if we're within tolerance from origin.
}
-
- measure_tmp_items.clear();
-
- Geom::Point const motion_w(event->motion.x, event->motion.y);
+ }
+ // Once the user has moved farther than tolerance from the original location
+ // (indicating they intend to move the object, not click), then always process the
+ // motion notify coordinates as given (no snapping back to origin)
+ within_tolerance = false;
+ if(event->motion.time == 0 || !last_end || Geom::LInfty( motion_w - *last_end ) > (tolerance/4.0)) {
Geom::Point const motion_dt(desktop->w2d(motion_w));
- Geom::Point end_point = motion_dt;
+ end_p = motion_dt;
if (event->motion.state & GDK_CONTROL_MASK) {
- spdc_endpoint_snap_rotation(this, end_point, start_point, event->motion.state);
- } else {
- if (!(event->motion.state & GDK_SHIFT_MASK)) {
- SnapManager &m = desktop->namedview->snap_manager;
- m.setup(desktop);
- Inkscape::SnapCandidatePoint scp(end_point, Inkscape::SNAPSOURCE_OTHER_HANDLE);
- scp.addOrigin(start_point);
- Inkscape::SnappedPoint sp = m.freeSnap(scp);
- end_point = sp.getPoint();
- m.unSetup();
- }
+ spdc_endpoint_snap_rotation(this, end_p, start_p, event->motion.state);
+ } else if (!(event->motion.state & GDK_SHIFT_MASK)) {
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
+ Inkscape::SnapCandidatePoint scp(end_p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ scp.addOrigin(start_p);
+ Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp);
+ end_p = sp.getPoint();
+ snap_manager.unSetup();
}
+ showCanvasItems();
+ last_end = motion_w ;
+ }
+ gobble_motion_events(GDK_BUTTON1_MASK);
+ }
+ break;
+ }
+ case GDK_BUTTON_RELEASE: {
+ this->knot_start->moveto(start_p);
+ this->knot_start->show();
+ if(last_end) {
+ end_p = desktop->w2d(*last_end);
+ if (event->button.state & GDK_CONTROL_MASK) {
+ spdc_endpoint_snap_rotation(this, end_p, start_p, event->motion.state);
+ } else if (!(event->button.state & GDK_SHIFT_MASK)) {
+ SnapManager &snap_manager = desktop->namedview->snap_manager;
+ snap_manager.setup(desktop);
+ Inkscape::SnapCandidatePoint scp(end_p, Inkscape::SNAPSOURCE_OTHER_HANDLE);
+ scp.addOrigin(start_p);
+ Inkscape::SnappedPoint sp = snap_manager.freeSnap(scp);
+ end_p = sp.getPoint();
+ snap_manager.unSetup();
+ }
+ }
+ this->knot_end->moveto(end_p);
+ this->knot_end->show();
+ showCanvasItems();
- Geom::PathVector lineseg;
- Geom::Path p;
- p.start(desktop->dt2doc(start_point));
- p.appendNew<Geom::LineSegment>(desktop->dt2doc(end_point));
- lineseg.push_back(p);
-
- double deltax = end_point[Geom::X] - start_point[Geom::X];
- double deltay = end_point[Geom::Y] - start_point[Geom::Y];
- double angle = atan2(deltay, deltax);
- double baseAngle = 0;
-
- if (explicitBase) {
- double deltax2 = explicitBase.get()[Geom::X] - start_point[Geom::X];
- double deltay2 = explicitBase.get()[Geom::Y] - start_point[Geom::Y];
-
- baseAngle = atan2(deltay2, deltax2);
- angle -= baseAngle;
-
- if (angle < -M_PI) {
- angle += 2 * M_PI;
- } else if (angle > M_PI) {
- angle -= 2 * M_PI;
- }
- }
+ if (this->grabbed) {
+ sp_canvas_item_ungrab(this->grabbed, event->button.time);
+ this->grabbed = NULL;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ if (!ret) {
+ ret = ToolBase::root_handler(event);
+ }
-//TODO: calculate NPOINTS
-//800 seems to be a good value for 800x600 resolution
-#define NPOINTS 800
+ return ret;
+}
- std::vector<Geom::Point> points;
+void MeasureTool::setMarkers()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPDocument *doc = desktop->getDocument();
+ SPObject *arrowStart = doc->getObjectById("Arrow2Sstart");
+ SPObject *arrowEnd = doc->getObjectById("Arrow2Send");
+ if (!arrowStart) {
+ setMarker(true);
+ }
+ if(!arrowEnd) {
+ setMarker(false);
+ }
+}
+void MeasureTool::setMarker(bool isStart)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPDocument *doc = desktop->getDocument();
+ SPDefs *defs = doc->getDefs();
+ Inkscape::XML::Node *rmarker;
+ Inkscape::XML::Document *xml_doc = doc->getReprDoc();
+ rmarker = xml_doc->createElement("svg:marker");
+ rmarker->setAttribute("id", isStart ? "Arrow2Sstart" : "Arrow2Send");
+ rmarker->setAttribute("inkscape:isstock", "true");
+ rmarker->setAttribute("inkscape:stockid", isStart ? "Arrow2Sstart" : "Arrow2Send");
+ rmarker->setAttribute("orient", "auto");
+ rmarker->setAttribute("refX", "0.0");
+ rmarker->setAttribute("refY", "0.0");
+ rmarker->setAttribute("style", "overflow:visible;");
+ SPItem *marker = SP_ITEM(defs->appendChildRepr(rmarker));
+ Inkscape::GC::release(rmarker);
+ marker->updateRepr();
+ Inkscape::XML::Node *rpath;
+ rpath = xml_doc->createElement("svg:path");
+ rpath->setAttribute("d", "M 8.72,4.03 L -2.21,0.02 L 8.72,-4.00 C 6.97,-1.63 6.98,1.62 8.72,4.03 z");
+ rpath->setAttribute("id", isStart ? "Arrow2SstartPath" : "Arrow2SendPath");
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ sp_repr_css_set_property (css, "stroke", "none");
+ sp_repr_css_set_property (css, "fill", "#000000");
+ sp_repr_css_set_property (css, "fill-opacity", "1");
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ rpath->setAttribute("style", css_str.c_str());
+ sp_repr_css_attr_unref (css);
+ rpath->setAttribute("transform", isStart ? "scale(0.3) translate(-2.3,0)" : "scale(0.3) rotate(180) translate(-2.3,0)");
+ SPItem *path = SP_ITEM(marker->appendChildRepr(rpath));
+ Inkscape::GC::release(rpath);
+ path->updateRepr();
+}
- for (double i = 0; i < NPOINTS; i++) {
- points.push_back(desktop->d2w(start_point + (i / NPOINTS) * (end_point - start_point)));
- }
+void MeasureTool::toGuides()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) {
+ return;
+ }
+ SPDocument *doc = desktop->getDocument();
+ Geom::Point start = desktop->doc2dt(start_p) * desktop->doc2dt();
+ Geom::Point end = desktop->doc2dt(end_p) * desktop->doc2dt();
+ Geom::Ray ray(start,end);
+ SPNamedView *namedview = desktop->namedview;
+ if(!namedview) {
+ return;
+ }
+ setGuide(start,ray.angle(), _("Measure"));
+ if(explicit_base) {
+ explicit_base = *explicit_base * SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ ray.setPoints(start, *explicit_base);
+ if(ray.angle() != 0) {
+ setGuide(start,ray.angle(), _("Base"));
+ }
+ }
+ setGuide(start,0,"");
+ setGuide(start,Geom::rad_from_deg(90),_("Start"));
+ setGuide(end,0,_("End"));
+ setGuide(end,Geom::rad_from_deg(90),"");
+ showCanvasItems(true);
+ doc->ensureUpToDate();
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MEASURE,_("Add guides from measure tool"));
+}
- // TODO: Felipe, why don't you simply iterate over all items, and test whether their bounding boxes intersect
- // with the measurement line, instead of interpolating over 800 points? E.g. bbox_of_measurement_line.intersects(*bbox_of_item).
- // That's also how the object-snapper works, see _findCandidates() in object-snapper.cpp.
-
- // TODO switch to a different variable name. The single letter 'l' is easy to misread.
-
- //select elements crossed by line segment:
- std::vector<SPItem*> items = desktop->getDocument()->getItemsAtPoints(desktop->dkey, points);
- std::vector<double> intersection_times;
- for (std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++) {
- SPItem *item = *i;
-
- if (SP_IS_SHAPE(item)) {
- calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersection_times);
- } else {
- if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
- Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin();
- do {
- Inkscape::Text::Layout::iterator iter_next = iter;
- iter_next.nextGlyph(); // iter_next is one glyph ahead from iter
- if (iter == iter_next) {
- break;
- }
-
- // get path from iter to iter_next:
- SPCurve *curve = te_get_layout(item)->convertToCurves(iter, iter_next);
- iter = iter_next; // shift to next glyph
- if (!curve) {
- continue; // error converting this glyph
- }
- if (curve->is_empty()) { // whitespace glyph?
- curve->unref();
- continue;
- }
-
- curve->transform(item->i2doc_affine());
-
- calculate_intersections(desktop, item, lineseg, curve, intersection_times);
-
- if (iter == te_get_layout(item)->end()) {
- break;
- }
- } while (true);
- }
- }
- }
+void MeasureTool::toPhantom()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) {
+ return;
+ }
+ SPDocument *doc = desktop->getDocument();
+ for (size_t idx = 0; idx < measure_phantom_items.size(); ++idx) {
+ sp_canvas_item_destroy(measure_phantom_items[idx]);
+ }
+ measure_phantom_items.clear();
+ for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) {
+ sp_canvas_item_destroy(measure_tmp_items[idx]);
+ }
+ measure_tmp_items.clear();
+ showCanvasItems(false, false, true);
+ doc->ensureUpToDate();
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MEASURE,_("Add Stored to measure tool"));
+}
- Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true)) {
- intersection_times.push_back(0);
- intersection_times.push_back(1);
- }
+void MeasureTool::toItem()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) {
+ return;
+ }
+ SPDocument *doc = desktop->getDocument();
+ Geom::Ray ray(start_p,end_p);
+ guint32 line_color_primary = 0x0000ff7f;
+ Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
+ Inkscape::XML::Node *rgroup = xml_doc->createElement("svg:g");
+ showCanvasItems(false, true, false, rgroup);
+ setLine(start_p,end_p, false, line_color_primary, rgroup);
+ SPItem *measure_item = SP_ITEM(desktop->currentLayer()->appendChildRepr(rgroup));
+ Inkscape::GC::release(rgroup);
+ measure_item->updateRepr();
+ doc->ensureUpToDate();
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MEASURE,_("Convert measure to items"));
+ reset();
+}
- Glib::ustring unit_name = prefs->getString("/tools/measure/unit");
- if (!unit_name.compare("")) {
- unit_name = "px";
- }
+void MeasureTool::toMarkDimension()
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) {
+ return;
+ }
+ SPDocument *doc = desktop->getDocument();
+ setMarkers();
+ Geom::Ray ray(start_p,end_p);
+ Geom::Point start = start_p + Geom::Point::polar(ray.angle(), 5);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ dimension_offset = prefs->getDouble("/tools/measure/offset", 5.0);
+ start = start + Geom::Point::polar(ray.angle() + Geom::rad_from_deg(90), -dimension_offset);
+ Geom::Point end = end_p + Geom::Point::polar(ray.angle(), -5);
+ end = end+ Geom::Point::polar(ray.angle() + Geom::rad_from_deg(90), -dimension_offset);
+ guint32 color = 0x000000ff;
+ setLine(start, end, true, color);
+ Glib::ustring unit_name = prefs->getString("/tools/measure/unit");
+ if (!unit_name.compare("")) {
+ unit_name = "px";
+ }
+ double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0);
+ int precision = prefs->getInt("/tools/measure/precision", 2);
+ std::stringstream precision_str;
+ precision_str.imbue(std::locale::classic());
+ precision_str << "%." << precision << "f %s";
+ Geom::Point middle = Geom::middle_point(start, end);
+ double totallengthval = (end_p - start_p).length();
+ totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name);
+ double scale = prefs->getDouble("/tools/measure/scale", 100.0) / 100.0;
+ gchar *totallength_str = g_strdup_printf(precision_str.str().c_str(), totallengthval * scale, unit_name.c_str());
+ setLabelText(totallength_str, middle, fontsize, Geom::rad_from_deg(180) - ray.angle(), color);
+ g_free(totallength_str);
+ doc->ensureUpToDate();
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MEASURE,_("Add global measure line"));
+}
- double fontsize = prefs->getInt("/tools/measure/fontsize");
+void MeasureTool::setGuide(Geom::Point origin,double angle, const char *label)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SPDocument *doc = desktop->getDocument();
+ Inkscape::XML::Document *xml_doc = doc->getReprDoc();
+ SPRoot const *root = doc->getRoot();
+ Geom::Affine affine(Geom::identity());
+ if(root) {
+ affine *= root->c2p.inverse();
+ }
+ SPNamedView *namedview = desktop->namedview;
+ if(!namedview) {
+ return;
+ }
+ origin *= affine;
+ //measure angle
+ Inkscape::XML::Node *guide;
+ guide = xml_doc->createElement("sodipodi:guide");
+ std::stringstream position;
+ position.imbue(std::locale::classic());
+ position << origin[Geom::X] << "," << origin[Geom::Y];
+ guide->setAttribute("position", position.str().c_str() );
+ guide->setAttribute("inkscape:color", "rgb(167,0,255)");
+ guide->setAttribute("inkscape:label", label);
+ Geom::Point unit_vector = Geom::rot90(origin.polar(angle));
+ std::stringstream angle_str;
+ angle_str.imbue(std::locale::classic());
+ angle_str << unit_vector[Geom::X] << "," << unit_vector[Geom::Y];
+ guide->setAttribute("orientation", angle_str.str().c_str());
+ namedview->appendChild(guide);
+ Inkscape::GC::release(guide);
+}
- // Normal will be used for lines and text
- Geom::Point windowNormal = Geom::unit_vector(Geom::rot90(desktop->d2w(end_point - start_point)));
- Geom::Point normal = desktop->w2d(windowNormal);
+void MeasureTool::setLine(Geom::Point start_point,Geom::Point end_point, bool markers, guint32 color, Inkscape::XML::Node *measure_repr)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !start_p.isFinite() || !end_p.isFinite()) {
+ return;
+ }
+ Geom::PathVector pathv;
+ Geom::Path path;
+ path.start(desktop->doc2dt(start_point));
+ path.appendNew<Geom::LineSegment>(desktop->doc2dt(end_point));
+ pathv.push_back(path);
+ pathv *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ if(!pathv.empty()) {
+ setMeasureItem(pathv, false, markers, color, measure_repr);
+ }
+}
- std::vector<Geom::Point> intersections;
- std::sort(intersection_times.begin(), intersection_times.end());
- for (std::vector<double>::iterator iter_t = intersection_times.begin(); iter_t != intersection_times.end(); iter_t++) {
- intersections.push_back(lineseg[0].pointAt(*iter_t));
- }
+void MeasureTool::setPoint(Geom::Point origin, Inkscape::XML::Node *measure_repr)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !origin.isFinite()) {
+ return;
+ }
+ char const * svgd;
+ svgd = "m 0.707,0.707 6.586,6.586 m 0,-6.586 -6.586,6.586";
+ Geom::PathVector pathv = sp_svg_read_pathv(svgd);
+ Geom::Scale scale = Geom::Scale(desktop->current_zoom()).inverse();
+ pathv *= Geom::Translate(Geom::Point(-3.5,-3.5));
+ pathv *= scale;
+ pathv *= Geom::Translate(Geom::Point() - (scale.vector() * 0.5));
+ pathv *= Geom::Translate(desktop->doc2dt(origin));
+ pathv *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ if (!pathv.empty()) {
+ guint32 line_color_secondary = 0xff0000ff;
+ setMeasureItem(pathv, false, false, line_color_secondary, measure_repr);
+ }
+}
- std::vector<LabelPlacement> placements;
- for (size_t idx = 1; idx < intersections.size(); ++idx) {
- LabelPlacement placement;
- placement.lengthVal = (intersections[idx] - intersections[idx - 1]).length();
- placement.lengthVal = Inkscape::Util::Quantity::convert(placement.lengthVal, "px", unit_name);
- placement.offset = DIMENSION_OFFSET;
- placement.start = desktop->doc2dt( (intersections[idx - 1] + intersections[idx]) / 2 );
- placement.end = placement.start - (normal * placement.offset);
+void MeasureTool::setLabelText(const char *value, Geom::Point pos, double fontsize, Geom::Coord angle, guint32 background, Inkscape::XML::Node *measure_repr, CanvasTextAnchorPositionEnum text_anchor)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ Inkscape::XML::Document *xml_doc = desktop->doc()->getReprDoc();
+ /* Create <text> */
+ pos = desktop->doc2dt(pos);
+ Inkscape::XML::Node *rtext = xml_doc->createElement("svg:text");
+ rtext->setAttribute("xml:space", "preserve");
+
+
+ /* Set style */
+ sp_desktop_apply_style_tool(desktop, rtext, "/tools/text", true);
+ if(measure_repr) {
+ sp_repr_set_svg_double(rtext, "x", 2);
+ sp_repr_set_svg_double(rtext, "y", 2);
+ } else {
+ sp_repr_set_svg_double(rtext, "x", 0);
+ sp_repr_set_svg_double(rtext, "y", 0);
+ }
- placements.push_back(placement);
- }
+ /* Create <tspan> */
+ Inkscape::XML::Node *rtspan = xml_doc->createElement("svg:tspan");
+ rtspan->setAttribute("sodipodi:role", "line");
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ std::stringstream font_size;
+ font_size.imbue(std::locale::classic());
+ if(measure_repr) {
+ font_size << fontsize;
+ } else {
+ font_size << fontsize << "pt";
+ }
+ sp_repr_css_set_property (css, "font-size", font_size.str().c_str());
+ sp_repr_css_set_property (css, "font-style", "normal");
+ sp_repr_css_set_property (css, "font-weight", "normal");
+ 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");
+ if(measure_repr) {
+ sp_repr_css_set_property (css, "fill", "#FFFFFF");
+ } else {
+ 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");
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ rtspan->setAttribute("style", css_str.c_str());
+ sp_repr_css_attr_unref (css);
+ rtext->addChild(rtspan, NULL);
+ Inkscape::GC::release(rtspan);
+ /* Create TEXT */
+ Inkscape::XML::Node *rstring = xml_doc->createTextNode(value);
+ rtspan->addChild(rstring, NULL);
+ Inkscape::GC::release(rstring);
+ SPItem *text_item = SP_ITEM(desktop->currentLayer()->appendChildRepr(rtext));
+ Inkscape::GC::release(rtext);
+ text_item->updateRepr();
+ Geom::OptRect bbox = text_item->geometricBounds();
+ if (!measure_repr && bbox) {
+ Geom::Point center = bbox->midpoint();
+ text_item->transform *= Geom::Translate(center).inverse();
+ pos += Geom::Point::polar(angle+ Geom::rad_from_deg(90), -bbox->height());
+ }
+ if(measure_repr) {
+ /* Create <group> */
+ Inkscape::XML::Node *rgroup = xml_doc->createElement("svg:g");
+ /* Create <rect> */
+ Inkscape::XML::Node *rrect = xml_doc->createElement("svg:rect");
+ SPCSSAttr *css = sp_repr_css_attr_new ();
+ gchar color_line[64];
+ sp_svg_write_color (color_line, sizeof(color_line), background);
+ sp_repr_css_set_property (css, "fill", color_line);
+ sp_repr_css_set_property (css, "fill-opacity", "0.5");
+ sp_repr_css_set_property (css, "stroke-width", "0");
+ Glib::ustring css_str;
+ sp_repr_css_write_string(css,css_str);
+ rrect->setAttribute("style", css_str.c_str());
+ sp_repr_css_attr_unref (css);
+ sp_repr_set_svg_double(rgroup, "x", 0);
+ sp_repr_set_svg_double(rgroup, "y", 0);
+ sp_repr_set_svg_double(rrect, "x", -bbox->width()/2.0);
+ sp_repr_set_svg_double(rrect, "y", -bbox->height());
+ sp_repr_set_svg_double(rrect, "width", bbox->width() + 6);
+ sp_repr_set_svg_double(rrect, "height", bbox->height() + 6);
+ Inkscape::XML::Node *rtextitem = text_item->getRepr();
+ text_item->deleteObject();
+ rgroup->addChild(rtextitem, NULL);
+ Inkscape::GC::release(rtextitem);
+ rgroup->addChild(rrect, NULL);
+ Inkscape::GC::release(rrect);
+ SPItem *text_item_box = SP_ITEM(desktop->currentLayer()->appendChildRepr(rgroup));
+ Geom::Scale scale = Geom::Scale(desktop->current_zoom()).inverse();
+ if(bbox && text_anchor == TEXT_ANCHOR_CENTER) {
+ text_item_box->transform *= Geom::Translate(bbox->midpoint() - Geom::Point(1.0,1.0)).inverse();
+ }
+ text_item_box->transform *= scale;
+ text_item_box->transform *= Geom::Translate(Geom::Point() - (scale.vector() * 0.5));
+ text_item_box->transform *= Geom::Translate(pos);
+ text_item_box->transform *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ text_item_box->updateRepr();
+ text_item_box->doWriteTransform(text_item_box->getRepr(), text_item_box->transform, NULL, true);
+ Inkscape::XML::Node *rlabel = text_item_box->getRepr();
+ text_item_box->deleteObject();
+ measure_repr->addChild(rlabel, NULL);
+ Inkscape::GC::release(rlabel);
+ } else {
+ text_item->transform *= Geom::Rotate(angle);
+ text_item->transform *= Geom::Translate(pos);
+ text_item->transform *= SP_ITEM(desktop->currentLayer())->i2doc_affine().inverse();
+ text_item->doWriteTransform(text_item->getRepr(), text_item->transform, NULL, true);
+ }
+}
- // Adjust positions
- repositionOverlappingLabels(placements, desktop, windowNormal, fontsize);
-
- for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it)
- {
- LabelPlacement &place = *it;
-
- // TODO cleanup memory, Glib::ustring, etc.:
- gchar *measure_str = g_strdup_printf("%.2f %s", place.lengthVal, unit_name.c_str());
- SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(),
- desktop,
- place.end,
- measure_str);
- sp_canvastext_set_fontsize(canvas_tooltip, fontsize);
- canvas_tooltip->rgba = 0xffffffff;
- canvas_tooltip->rgba_background = 0x0000007f;
- canvas_tooltip->outline = false;
- canvas_tooltip->background = true;
- canvas_tooltip->anchor_position = TEXT_ANCHOR_CENTER;
-
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0));
- g_free(measure_str);
- }
+void MeasureTool::reset()
+{
+ this->knot_start->hide();
+ this->knot_end->hide();
+ for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) {
+ sp_canvas_item_destroy(measure_tmp_items[idx]);
+ }
+ measure_tmp_items.clear();
+}
- Geom::Point angleDisplayPt = calcAngleDisplayAnchor(desktop, angle, baseAngle,
- start_point, end_point,
- fontsize);
-
- {
- // TODO cleanup memory, Glib::ustring, etc.:
- gchar *angle_str = g_strdup_printf("%.2f °", angle * 180/M_PI);
-
- SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(),
- desktop,
- angleDisplayPt,
- angle_str);
- sp_canvastext_set_fontsize(canvas_tooltip, fontsize);
- canvas_tooltip->rgba = 0xffffffff;
- canvas_tooltip->rgba_background = 0x337f337f;
- canvas_tooltip->outline = false;
- canvas_tooltip->background = true;
- canvas_tooltip->anchor_position = TEXT_ANCHOR_CENTER;
-
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0));
- g_free(angle_str);
- }
+void MeasureTool::setMeasureCanvasText(bool is_angle, double precision, double amount, double fontsize, Glib::ustring unit_name, Geom::Point position, guint32 background, CanvasTextAnchorPositionEnum text_anchor, bool to_item, bool to_phantom, Inkscape::XML::Node *measure_repr)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ std::stringstream precision_str;
+ precision_str.imbue(std::locale::classic());
+ if(is_angle){
+ precision_str << "%." << precision << "f °";
+ } else {
+ precision_str << "%." << precision << "f %s";
+ }
+ gchar *measure_str = g_strdup_printf(precision_str.str().c_str(), amount, unit_name.c_str());
+ SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(),
+ desktop,
+ position,
+ measure_str);
+ sp_canvastext_set_fontsize(canvas_tooltip, fontsize);
+ canvas_tooltip->rgba = 0xffffffff;
+ canvas_tooltip->rgba_background = background;
+ canvas_tooltip->outline = false;
+ canvas_tooltip->background = true;
+ canvas_tooltip->anchor_position = text_anchor;
+ if(to_phantom){
+ canvas_tooltip->rgba_background = 0x4444447f;
+ measure_phantom_items.push_back(SP_CANVAS_ITEM(canvas_tooltip));
+ sp_canvas_item_show(SP_CANVAS_ITEM(canvas_tooltip));
+ } else {
+ measure_tmp_items.push_back(SP_CANVAS_ITEM(canvas_tooltip));
+ sp_canvas_item_show(SP_CANVAS_ITEM(canvas_tooltip));
+ }
- {
- double totallengthval = (end_point - start_point).length();
- totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name);
-
- // TODO cleanup memory, Glib::ustring, etc.:
- gchar *totallength_str = g_strdup_printf("%.2f %s", totallengthval, unit_name.c_str());
- SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(),
- desktop,
- end_point + desktop->w2d(Geom::Point(3*fontsize, -fontsize)),
- totallength_str);
- sp_canvastext_set_fontsize(canvas_tooltip, fontsize);
- canvas_tooltip->rgba = 0xffffffff;
- canvas_tooltip->rgba_background = 0x3333337f;
- canvas_tooltip->outline = false;
- canvas_tooltip->background = true;
- canvas_tooltip->anchor_position = TEXT_ANCHOR_LEFT;
-
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0));
- g_free(totallength_str);
- }
+ if(to_item) {
+ setLabelText(measure_str, position, fontsize, 0, background, measure_repr);
+ }
+ g_free(measure_str);
+}
- if (intersections.size() > 2) {
- double totallengthval = (intersections[intersections.size()-1] - intersections[0]).length();
- totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name);
-
- // TODO cleanup memory, Glib::ustring, etc.:
- gchar *total_str = g_strdup_printf("%.2f %s", totallengthval, unit_name.c_str());
- SPCanvasText *canvas_tooltip = sp_canvastext_new(desktop->getTempGroup(),
- desktop,
- desktop->doc2dt((intersections[0] + intersections[intersections.size()-1])/2) + normal * 60,
- total_str);
- sp_canvastext_set_fontsize(canvas_tooltip, fontsize);
- canvas_tooltip->rgba = 0xffffffff;
- canvas_tooltip->rgba_background = 0x33337f7f;
- canvas_tooltip->outline = false;
- canvas_tooltip->background = true;
- canvas_tooltip->anchor_position = TEXT_ANCHOR_CENTER;
-
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvas_tooltip, 0));
- g_free(total_str);
- }
+void MeasureTool::setMeasureCanvasItem(Geom::Point position, bool to_item, bool to_phantom, Inkscape::XML::Node *measure_repr){
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ guint32 color = 0xff0000ff;
+ if(to_phantom){
+ color = 0x888888ff;
+ }
+ SPCanvasItem * canvasitem = sp_canvas_item_new(desktop->getTempGroup(),
+ SP_TYPE_CTRL,
+ "anchor", SP_ANCHOR_CENTER,
+ "size", 8.0,
+ "stroked", TRUE,
+ "stroke_color", color,
+ "mode", SP_KNOT_MODE_XOR,
+ "shape", SP_KNOT_SHAPE_CROSS,
+ NULL );
+
+ SP_CTRL(canvasitem)->moveto(position);
+ if(to_phantom){
+ measure_phantom_items.push_back(canvasitem);
+ } else {
+ measure_tmp_items.push_back(canvasitem);
+ }
+ sp_canvas_item_show(canvasitem);
+ sp_canvas_item_move_to_z(canvasitem, 0);
+
+ if(to_item) {
+ setPoint(position, measure_repr);
+ }
+}
- // Now that text has been added, we can add lines and controls so that they go underneath
-
- for (size_t idx = 0; idx < intersections.size(); ++idx) {
- // Display the intersection indicator (i.e. the cross)
- SPCanvasItem * canvasitem = sp_canvas_item_new(desktop->getTempGroup(),
- SP_TYPE_CTRL,
- "anchor", SP_ANCHOR_CENTER,
- "size", 8.0,
- "stroked", TRUE,
- "stroke_color", 0xff0000ff,
- "mode", SP_KNOT_MODE_XOR,
- "shape", SP_KNOT_SHAPE_CROSS,
- NULL );
-
- SP_CTRL(canvasitem)->moveto(desktop->doc2dt(intersections[idx]));
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvasitem, 0));
- }
+void MeasureTool::setMeasureCanvasControlLine(Geom::Point start, Geom::Point end, bool to_item, bool to_phantom, Inkscape::CtrlLineType ctrl_line_type, Inkscape::XML::Node *measure_repr){
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ gint32 color = ctrl_line_type == CTLINE_PRIMARY ? 0x0000ff7f : 0xff00007f;
+ if(to_phantom){
+ color = ctrl_line_type == CTLINE_PRIMARY ? 0x4444447f : 0x8888887f;
+ }
+ SPCtrlLine *control_line = ControlManager::getManager().createControlLine(desktop->getTempGroup(),
+ start,
+ end,
+ ctrl_line_type);
+ control_line->rgba = color;
+ if(to_phantom){
+ measure_phantom_items.push_back(SP_CANVAS_ITEM(control_line));
+ } else {
+ measure_tmp_items.push_back(SP_CANVAS_ITEM(control_line));
+ }
+ sp_canvas_item_move_to_z(SP_CANVAS_ITEM(control_line), 0);
+ sp_canvas_item_show(SP_CANVAS_ITEM(control_line));
+ if(to_item) {
+ setLine(start,
+ end,
+ false,
+ color,
+ measure_repr);
+ }
+}
+
+void MeasureTool::showCanvasItems(bool to_guides, bool to_item, bool to_phantom, Inkscape::XML::Node *measure_repr)
+{
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ if(!desktop || !start_p.isFinite() || !end_p.isFinite() || start_p == end_p) {
+ return;
+ }
+ writeMeasurePoint(start_p, true);
+ writeMeasurePoint(end_p, false);
+ //clear previous canvas items, we'll draw new ones
+ for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) {
+ sp_canvas_item_destroy(measure_tmp_items[idx]);
+ }
+ measure_tmp_items.clear();
+ //TODO:Calculate the measure area for current lenght and origin
+ // and use canvas->requestRedraw. In the calculation need a gap for outside text
+ // maybe this remove the trash lines on measure use
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ bool show_in_between = prefs->getBool("/tools/measure/show_in_between", true);
+ bool all_layers = prefs->getBool("/tools/measure/all_layers", true);
+ dimension_offset = 70;
+ Geom::PathVector lineseg;
+ Geom::Path p;
+ p.start(desktop->dt2doc(start_p));
+ p.appendNew<Geom::LineSegment>(desktop->dt2doc(end_p));
+ lineseg.push_back(p);
+
+ double angle = atan2(end_p - start_p);
+ double baseAngle = 0;
+
+ if (explicit_base) {
+ baseAngle = atan2(explicit_base.get() - start_p);
+ angle -= baseAngle;
+ }
- // Since adding goes to the bottom, do all lines last.
-
- // draw main control line
- {
- SPCtrlLine *control_line = ControlManager::getManager().createControlLine(desktop->getTempGroup(),
- start_point,
- end_point);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
-
- if ((end_point[Geom::X] != start_point[Geom::X]) && (end_point[Geom::Y] != start_point[Geom::Y])) {
- double length = std::abs((end_point - start_point).length());
- Geom::Point anchorEnd = start_point;
- anchorEnd[Geom::X] += length;
- if (explicitBase) {
- anchorEnd *= (Geom::Affine(Geom::Translate(-start_point))
- * Geom::Affine(Geom::Rotate(baseAngle))
- * Geom::Affine(Geom::Translate(start_point)));
+ std::vector<SPItem*> items;
+ SPDocument *doc = desktop->getDocument();
+ Geom::Rect rect(start_p, end_p);
+ items = doc->getItemsPartiallyInBox(desktop->dkey, rect, true);
+ Inkscape::LayerModel *layer_model = NULL;
+ SPObject *current_layer = NULL;
+ if(desktop){
+ layer_model = desktop->layers;
+ current_layer = desktop->currentLayer();
+ }
+ std::vector<double> intersection_times;
+ for (std::vector<SPItem*>::const_iterator i=items.begin(); i!=items.end(); ++i) {
+ SPItem *item = *i;
+ if(all_layers || (layer_model && layer_model->layerForObject(item) == current_layer)){
+ if (SP_IS_SHAPE(item)) {
+ calculate_intersections(desktop, item, lineseg, SP_SHAPE(item)->getCurve(), intersection_times);
+ } else {
+ if (SP_IS_TEXT(item) || SP_IS_FLOWTEXT(item)) {
+ Inkscape::Text::Layout::iterator iter = te_get_layout(item)->begin();
+ do {
+ Inkscape::Text::Layout::iterator iter_next = iter;
+ iter_next.nextGlyph(); // iter_next is one glyph ahead from iter
+ if (iter == iter_next) {
+ break;
}
- SPCtrlLine *control_line = ControlManager::getManager().createControlLine(desktop->getTempGroup(),
- start_point,
- anchorEnd,
- CTLINE_SECONDARY);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
+ // get path from iter to iter_next:
+ SPCurve *curve = te_get_layout(item)->convertToCurves(iter, iter_next);
+ iter = iter_next; // shift to next glyph
+ if (!curve) {
+ continue; // error converting this glyph
+ }
+ if (curve->is_empty()) { // whitespace glyph?
+ curve->unref();
+ continue;
+ }
- createAngleDisplayCurve(desktop, start_point, end_point, angleDisplayPt, angle);
- }
- }
+ curve->transform(item->i2doc_affine());
- if (intersections.size() > 2) {
- ControlManager &mgr = ControlManager::getManager();
- SPCtrlLine *control_line = 0;
- control_line = mgr.createControlLine(desktop->getTempGroup(),
- desktop->doc2dt(intersections[0]) + normal * 60,
- desktop->doc2dt(intersections[intersections.size() - 1]) + normal * 60);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
-
- control_line = mgr.createControlLine(desktop->getTempGroup(),
- desktop->doc2dt(intersections[0]),
- desktop->doc2dt(intersections[0]) + normal * 65);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
-
- control_line = mgr.createControlLine(desktop->getTempGroup(),
- desktop->doc2dt(intersections[intersections.size() - 1]),
- desktop->doc2dt(intersections[intersections.size() - 1]) + normal * 65);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
+ calculate_intersections(desktop, item, lineseg, curve, intersection_times);
+ if (iter == te_get_layout(item)->end()) {
+ break;
+ }
+ } while (true);
}
+ }
+ }
+ }
+ Glib::ustring unit_name = prefs->getString("/tools/measure/unit");
+ if (!unit_name.compare("")) {
+ unit_name = "px";
+ }
+ double scale = prefs->getDouble("/tools/measure/scale", 100.0) / 100.0;
+ double fontsize = prefs->getDouble("/tools/measure/fontsize", 10.0);
+ // Normal will be used for lines and text
+ Geom::Point windowNormal = Geom::unit_vector(Geom::rot90(desktop->d2w(end_p - start_p)));
+ Geom::Point normal = desktop->w2d(windowNormal);
+
+ std::vector<Geom::Point> intersections;
+ std::sort(intersection_times.begin(), intersection_times.end());
+ for (std::vector<double>::iterator iter_t = intersection_times.begin(); iter_t != intersection_times.end(); ++iter_t) {
+ intersections.push_back(lineseg[0].pointAt(*iter_t));
+ }
- // call-out lines
- for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it)
- {
- LabelPlacement &place = *it;
-
- ControlManager &mgr = ControlManager::getManager();
- SPCtrlLine *control_line = mgr.createControlLine(desktop->getTempGroup(),
- place.start,
- place.end,
- CTLINE_SECONDARY);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
- }
+ if(!show_in_between && intersection_times.size() > 1) {
+ Geom::Point start = lineseg[0].pointAt(intersection_times[0]);
+ Geom::Point end = lineseg[0].pointAt(intersection_times[intersection_times.size()-1]);
+ intersections.clear();
+ intersections.push_back(start);
+ intersections.push_back(end);
+ }
+ if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true)) {
+ intersections.insert(intersections.begin(),lineseg[0].pointAt(0));
+ intersections.push_back(lineseg[0].pointAt(1));
+ }
+ std::vector<LabelPlacement> placements;
+ for (size_t idx = 1; idx < intersections.size(); ++idx) {
+ LabelPlacement placement;
+ placement.lengthVal = (intersections[idx] - intersections[idx - 1]).length();
+ placement.lengthVal = Inkscape::Util::Quantity::convert(placement.lengthVal, "px", unit_name);
+ placement.offset = dimension_offset / 2;
+ placement.start = desktop->doc2dt( (intersections[idx - 1] + intersections[idx]) / 2 );
+ placement.end = placement.start - (normal * placement.offset);
+
+ placements.push_back(placement);
+ }
+ int precision = prefs->getInt("/tools/measure/precision", 2);
+ // Adjust positions
+ repositionOverlappingLabels(placements, desktop, windowNormal, fontsize, precision);
+ for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it) {
+ LabelPlacement &place = *it;
+
+ setMeasureCanvasText(false, precision, place.lengthVal * scale, fontsize, unit_name, place.end, 0x0000007f, TEXT_ANCHOR_CENTER, to_item, to_phantom, measure_repr);
+ }
+ Geom::Point angleDisplayPt = calcAngleDisplayAnchor(desktop, angle, baseAngle,
+ start_p, end_p,
+ fontsize);
+ {
+ setMeasureCanvasText(true, precision, Geom::deg_from_rad(angle), fontsize, unit_name, angleDisplayPt, 0x337f337f, TEXT_ANCHOR_CENTER, to_item, to_phantom, measure_repr);
+ }
- {
- for (size_t idx = 1; idx < intersections.size(); ++idx) {
- Geom::Point measure_text_pos = (intersections[idx - 1] + intersections[idx]) / 2;
-
- ControlManager &mgr = ControlManager::getManager();
- SPCtrlLine *control_line = mgr.createControlLine(desktop->getTempGroup(),
- desktop->doc2dt(measure_text_pos),
- desktop->doc2dt(measure_text_pos) - (normal * DIMENSION_OFFSET),
- CTLINE_SECONDARY);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(control_line, 0));
- }
- }
+ {
+ double totallengthval = (end_p - start_p).length();
+ totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name);
+ Geom::Point origin = end_p + desktop->w2d(Geom::Point(3*fontsize, -fontsize));
+ setMeasureCanvasText(false, precision, totallengthval * scale, fontsize, unit_name, origin, 0x3333337f, TEXT_ANCHOR_LEFT, to_item, to_phantom, measure_repr);
+ }
- // Initial point
- {
- SPCanvasItem * canvasitem = sp_canvas_item_new(desktop->getTempGroup(),
- SP_TYPE_CTRL,
- "anchor", SP_ANCHOR_CENTER,
- "size", 8.0,
- "stroked", TRUE,
- "stroke_color", 0xff0000ff,
- "mode", SP_KNOT_MODE_XOR,
- "shape", SP_KNOT_SHAPE_CROSS,
- NULL );
-
- SP_CTRL(canvasitem)->moveto(start_point);
- measure_tmp_items.push_back(desktop->add_temporary_canvasitem(canvasitem, 0));
- }
+ if (intersections.size() > 2) {
+ double totallengthval = (intersections[intersections.size()-1] - intersections[0]).length();
+ totallengthval = Inkscape::Util::Quantity::convert(totallengthval, "px", unit_name);
+ Geom::Point origin = desktop->doc2dt((intersections[0] + intersections[intersections.size()-1])/2) + normal * dimension_offset;
+ setMeasureCanvasText(false, precision, totallengthval * scale, fontsize, unit_name, origin, 0x33337f7f, TEXT_ANCHOR_CENTER, to_item, to_phantom, measure_repr);
+ }
- lastEnd = end_point; // track in case we get a anchoring key-press later
+ // Initial point
+ {
+ setMeasureCanvasItem(start_p, false, to_phantom, measure_repr);
+ }
- gobble_motion_events(GDK_BUTTON1_MASK);
+ // Now that text has been added, we can add lines and controls so that they go underneath
+ for (size_t idx = 0; idx < intersections.size(); ++idx) {
+ setMeasureCanvasItem(desktop->doc2dt(intersections[idx]), to_item, to_phantom, measure_repr);
+ if(to_guides) {
+ gchar *cross_number;
+ if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true)) {
+ cross_number= g_strdup_printf(_("Crossing %u"), idx);
+ } else {
+ cross_number= g_strdup_printf(_("Crossing %u"), idx + 1);
}
- break;
- }
- case GDK_BUTTON_RELEASE: {
- sp_event_context_discard_delayed_snap_event(this);
- explicitBase = boost::none;
- lastEnd = boost::none;
-
- //clear all temporary canvas items related to the measurement tool.
- for (size_t idx = 0; idx < measure_tmp_items.size(); ++idx) {
- desktop->remove_temporary_canvasitem(measure_tmp_items[idx]);
+ if (!prefs->getBool("/tools/measure/ignore_1st_and_last", true) && idx == 0) {
+ setGuide(desktop->doc2dt(intersections[idx]), angle + Geom::rad_from_deg(90), "");
+ } else {
+ setGuide(desktop->doc2dt(intersections[idx]), angle + Geom::rad_from_deg(90), cross_number);
}
+ g_free(cross_number);
+ }
+ }
+ // Since adding goes to the bottom, do all lines last.
- measure_tmp_items.clear();
+ // draw main control line
+ {
+ setMeasureCanvasControlLine(start_p, end_p, false, to_phantom, CTLINE_PRIMARY, measure_repr);
+ double length = std::abs((end_p - start_p).length());
+ Geom::Point anchorEnd = start_p;
+ anchorEnd[Geom::X] += length;
+ if (explicit_base) {
+ anchorEnd *= (Geom::Affine(Geom::Translate(-start_p))
+ * Geom::Affine(Geom::Rotate(baseAngle))
+ * Geom::Affine(Geom::Translate(start_p)));
+ }
+ setMeasureCanvasControlLine(start_p, anchorEnd, to_item, to_phantom, CTLINE_SECONDARY, measure_repr);
+ createAngleDisplayCurve(desktop, start_p, end_p, angleDisplayPt, angle, to_phantom, measure_phantom_items, measure_tmp_items, measure_repr);
+ }
- if (this->grabbed) {
- sp_canvas_item_ungrab(this->grabbed, event->button.time);
- this->grabbed = NULL;
- }
+ if (intersections.size() > 2) {
+ setMeasureCanvasControlLine(desktop->doc2dt(intersections[0]) + normal * dimension_offset, desktop->doc2dt(intersections[intersections.size() - 1]) + normal * dimension_offset, to_item, to_phantom, CTLINE_PRIMARY , measure_repr);
+
+ setMeasureCanvasControlLine(desktop->doc2dt(intersections[0]), desktop->doc2dt(intersections[0]) + normal * dimension_offset, to_item, to_phantom, CTLINE_PRIMARY , measure_repr);
- xp = 0;
- yp = 0;
- break;
- }
- default:
- break;
+ setMeasureCanvasControlLine(desktop->doc2dt(intersections[intersections.size() - 1]), desktop->doc2dt(intersections[intersections.size() - 1]) + normal * dimension_offset, to_item, to_phantom, CTLINE_PRIMARY , measure_repr);
}
- if (!ret) {
- ret = ToolBase::root_handler(event);
+ // call-out lines
+ for (std::vector<LabelPlacement>::iterator it = placements.begin(); it != placements.end(); ++it) {
+ LabelPlacement &place = *it;
+ setMeasureCanvasControlLine(place.start, place.end, to_item, to_phantom, CTLINE_SECONDARY, measure_repr);
}
- return ret;
+ {
+ for (size_t idx = 1; idx < intersections.size(); ++idx) {
+ Geom::Point measure_text_pos = (intersections[idx - 1] + intersections[idx]) / 2;
+ setMeasureCanvasControlLine(desktop->doc2dt(measure_text_pos), desktop->doc2dt(measure_text_pos) - (normal * dimension_offset / 2), to_item, to_phantom, CTLINE_SECONDARY, measure_repr);
+ }
+ }
}
}
diff --git a/src/ui/tools/measure-tool.h b/src/ui/tools/measure-tool.h
index 9701ba6ea..14fc9f81a 100644
--- a/src/ui/tools/measure-tool.h
+++ b/src/ui/tools/measure-tool.h
@@ -6,41 +6,83 @@
*
* Authors:
* Felipe Correa da Silva Sanches <juca@members.fsf.org>
- *
+ * Jabiertxo Arraiza <jabier.arraiza@marker.es>
* Copyright (C) 2011 Authors
*
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stddef.h>
+#include <sigc++/sigc++.h>
#include "ui/tools/tool-base.h"
#include <2geom/point.h>
+#include "display/canvas-text.h"
+#include "display/canvas-temporary-item.h"
+#include "ui/control-manager.h"
#include <boost/optional.hpp>
#define SP_MEASURE_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::MeasureTool*>((Inkscape::UI::Tools::ToolBase*)obj))
#define SP_IS_MEASURE_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::MeasureTool*>((const Inkscape::UI::Tools::ToolBase*)obj) != NULL)
+class SPKnot;
+
namespace Inkscape {
namespace UI {
namespace Tools {
class MeasureTool : public ToolBase {
public:
- MeasureTool();
- virtual ~MeasureTool();
-
- static const std::string prefsPath;
+ MeasureTool();
+ virtual ~MeasureTool();
- virtual void finish();
- virtual bool root_handler(GdkEvent* event);
-
- virtual const std::string& getPrefsPath();
+ static const std::string prefsPath;
+ virtual void finish();
+ virtual bool root_handler(GdkEvent* event);
+ virtual void showCanvasItems(bool to_guides = false, bool to_item = false, bool to_phantom = false, Inkscape::XML::Node *measure_repr = NULL);
+ virtual void reverseKnots();
+ virtual void toGuides();
+ virtual void toPhantom();
+ virtual void toMarkDimension();
+ virtual void toItem();
+ virtual void reset();
+ virtual void setMarkers();
+ virtual void setMarker(bool isStart);
+ virtual const std::string& getPrefsPath();
+ Geom::Point readMeasurePoint(bool is_start);
+ 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);
+ void setLine(Geom::Point start_point,Geom::Point end_point, bool markers, guint32 color, Inkscape::XML::Node *measure_repr = NULL);
+ void setMeasureCanvasText(bool is_angle, double precision, double amount, double fontsize, Glib::ustring unit_name, Geom::Point position, guint32 background, CanvasTextAnchorPositionEnum text_anchor, bool to_item, bool to_phantom, Inkscape::XML::Node *measure_repr);
+ void setMeasureCanvasItem(Geom::Point position, bool to_item, bool to_phantom, Inkscape::XML::Node *measure_repr);
+ void setMeasureCanvasControlLine(Geom::Point start, Geom::Point end, bool to_item, bool to_phantom, Inkscape::CtrlLineType ctrl_line_type, Inkscape::XML::Node *measure_repr);
+ void setLabelText(const char *value, Geom::Point pos, double fontsize, Geom::Coord angle, guint32 background , Inkscape::XML::Node *measure_repr = NULL, CanvasTextAnchorPositionEnum text_anchor = TEXT_ANCHOR_CENTER );
+ void knotStartMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state);
+ void knotEndMovedHandler(SPKnot */*knot*/, Geom::Point const &ppointer, guint state);
+ void knotClickHandler(SPKnot *knot, guint state);
+ void knotUngrabbedHandler(SPKnot */*knot*/, unsigned int /*state*/);
private:
- SPCanvasItem* grabbed;
-
- Geom::Point start_point;
- boost::optional<Geom::Point> explicitBase;
- boost::optional<Geom::Point> lastEnd;
+ SPCanvasItem* grabbed;
+ boost::optional<Geom::Point> explicit_base;
+ boost::optional<Geom::Point> last_end;
+ SPKnot *knot_start;
+ SPKnot *knot_end;
+ gint dimension_offset;
+ Geom::Point start_p;
+ Geom::Point end_p;
+ std::vector<SPCanvasItem *> measure_tmp_items;
+ std::vector<SPCanvasItem *> measure_phantom_items;
+ sigc::connection _knot_start_moved_connection;
+ sigc::connection _knot_start_ungrabbed_connection;
+ sigc::connection _knot_start_click_connection;
+ sigc::connection _knot_end_moved_connection;
+ sigc::connection _knot_end_click_connection;
+ sigc::connection _knot_end_ungrabbed_connection;
};
}
@@ -48,3 +90,14 @@ private:
}
#endif // SEEN_SP_MEASURING_CONTEXT_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/tools/mesh-tool.cpp b/src/ui/tools/mesh-tool.cpp
index 813d6ae5b..47927667c 100644
--- a/src/ui/tools/mesh-tool.cpp
+++ b/src/ui/tools/mesh-tool.cpp
@@ -57,7 +57,7 @@ namespace Inkscape {
namespace UI {
namespace Tools {
-static void sp_mesh_drag(MeshTool &rc, Geom::Point const pt, guint state, guint32 etime);
+static void sp_mesh_end_drag(MeshTool &rc);
const std::string& MeshTool::getPrefsPath() {
return MeshTool::prefsPath;
@@ -316,7 +316,7 @@ static void sp_mesh_context_split_near_point(MeshTool *rc, SPItem *item, Geom::
/**
Wrapper for various mesh operations that require a list of selected corner nodes.
*/
-static void
+void
sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation )
{
@@ -332,11 +332,11 @@ sp_mesh_context_corner_operation (MeshTool *rc, MeshCornerOperation operation )
// Get list of selected draggers for each mesh.
// For all selected draggers
- for (GList *i = drag->selected; i != NULL; i = i->next) {
- GrDragger *dragger = (GrDragger *) i->data;
+ for (std::set<GrDragger *>::const_iterator i = drag->selected.begin(); i != drag->selected.end(); ++i) {
+ GrDragger *dragger = *i;
// For all draggables of dragger
- for (GSList const* j = dragger->draggables; j != NULL; j = j->next) {
- GrDraggable *d = (GrDraggable *) j->data;
+ for (std::vector<GrDraggable *>::const_iterator j = dragger->draggables.begin(); j != dragger->draggables.end() ; ++j) {
+ GrDraggable *d = *j;
// Only mesh corners
if( d->point_type != POINT_MG_CORNER ) continue;
@@ -457,9 +457,9 @@ bool MeshTool::root_handler(GdkEvent* event) {
bool over_line = false;
SPCtrlCurve *line = NULL;
- if (drag->lines) {
- for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) {
- line = (SPCtrlCurve*) l->data;
+ if (! drag->lines.empty()) {
+ for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) {
+ line = (SPCtrlCurve*) (*l);
over_line |= sp_mesh_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y));
}
}
@@ -471,7 +471,7 @@ bool MeshTool::root_handler(GdkEvent* event) {
} else {
// Create a new gradient with default coordinates.
std::vector<SPItem*> items=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
SPItem *item = *i;
SPGradientType new_type = SP_GRADIENT_TYPE_MESH;
Inkscape::PaintTarget fsmode = (prefs->getInt("/tools/gradient/newfillorstroke", 1) != 0) ? Inkscape::FOR_FILL : Inkscape::FOR_STROKE;
@@ -560,8 +560,9 @@ bool MeshTool::root_handler(GdkEvent* event) {
Inkscape::Rubberband::get(desktop)->move(motion_dt);
this->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Draw around</b> handles to select them"));
} else {
- // Create new gradient with coordinates determined by drag.
- sp_mesh_drag(*this, motion_dt, event->motion.state, event->motion.time);
+ // Do nothing. For a linear/radial gradient we follow the drag, updating the
+ // gradient as the end node is dragged. For a mesh gradient, the gradient is always
+ // created to fill the object when the drag ends.
}
gobble_motion_events(GDK_BUTTON1_MASK);
@@ -592,9 +593,9 @@ bool MeshTool::root_handler(GdkEvent* event) {
// Change cursor shape if over line
bool over_line = false;
- if (drag->lines) {
- for (GSList *l = drag->lines; l != NULL; l = l->next) {
- over_line |= sp_mesh_context_is_over_line (this, (SPItem*) l->data, Geom::Point(event->motion.x, event->motion.y));
+ if (!drag->lines.empty()) {
+ for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() ; ++l) {
+ over_line |= sp_mesh_context_is_over_line (this, (SPItem*)(*l), Geom::Point(event->motion.x, event->motion.y));
}
}
@@ -623,9 +624,9 @@ bool MeshTool::root_handler(GdkEvent* event) {
bool over_line = false;
SPCtrlLine *line = NULL;
- if (drag->lines) {
- for (GSList *l = drag->lines; (l != NULL) && (!over_line); l = l->next) {
- line = (SPCtrlLine*) l->data;
+ if (!drag->lines.empty()) {
+ for (std::vector<SPCtrlLine *>::const_iterator l = drag->lines.begin(); l != drag->lines.end() && (!over_line); ++l) {
+ line = (SPCtrlLine*)(*l);
over_line = sp_mesh_context_is_over_line (this, (SPItem*) line, Geom::Point(event->motion.x, event->motion.y));
if (over_line) {
@@ -649,7 +650,7 @@ bool MeshTool::root_handler(GdkEvent* event) {
}
if (!this->within_tolerance) {
- // we've been dragging, either do nothing (grdrag handles that),
+ // we've been dragging, either create a new gradient
// or rubberband-select if we have rubberband
Inkscape::Rubberband *r = Inkscape::Rubberband::get(desktop);
@@ -659,6 +660,9 @@ bool MeshTool::root_handler(GdkEvent* event) {
Geom::OptRect const b = r->getRectangle();
drag->selectRect(*b);
}
+ } else {
+ // Create a new mesh gradient
+ sp_mesh_end_drag(*this);
}
} else if (this->item_to_select) {
if (over_line && line) {
@@ -674,7 +678,7 @@ bool MeshTool::root_handler(GdkEvent* event) {
}
} else {
// click in an empty space; do the same as Esc
- if (drag->selected) {
+ if (!drag->selected.empty()) {
drag->deselectAll();
} else {
selection->clear();
@@ -720,7 +724,7 @@ bool MeshTool::root_handler(GdkEvent* event) {
break;
case GDK_KEY_Escape:
- if (drag->selected) {
+ if (!drag->selected.empty()) {
drag->deselectAll();
} else {
selection->clear();
@@ -837,7 +841,7 @@ bool MeshTool::root_handler(GdkEvent* event) {
case GDK_KEY_Delete:
case GDK_KEY_KP_Delete:
case GDK_KEY_BackSpace:
- if ( drag->selected ) {
+ if ( !drag->selected.empty() ) {
std::cout << "Deleting mesh stops not implemented yet" << std::endl;
ret = TRUE;
}
@@ -922,7 +926,7 @@ bool MeshTool::root_handler(GdkEvent* event) {
return ret;
}
-static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/, guint32 /*etime*/) {
+static void sp_mesh_end_drag(MeshTool &rc) {
SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop;
Inkscape::Selection *selection = desktop->getSelection();
SPDocument *document = desktop->getDocument();
@@ -952,7 +956,7 @@ static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/
sp_repr_css_set_property(css, "fill-opacity", "1.0");
std::vector<SPItem*> items=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
//FIXME: see above
sp_repr_css_change_recursive((*i)->getRepr(), css, "style");
@@ -963,19 +967,8 @@ static void sp_mesh_drag(MeshTool &rc, Geom::Point const /*pt*/, guint /*state*/
(*i)->requestModified(SP_OBJECT_MODIFIED_FLAG);
}
- // if (ec->_grdrag) {
- // ec->_grdrag->updateDraggers();
- // // prevent regenerating draggers by selection modified signal, which sometimes
- // // comes too late and thus destroys the knot which we will now grab:
- // ec->_grdrag->local_change = true;
- // // give the grab out-of-bounds values of xp/yp because we're already dragging
- // // and therefore are already out of tolerance
- // ec->_grdrag->grabKnot (SP_ITEM(selection->itemList()->data),
- // type == SP_GRADIENT_TYPE_LINEAR? POINT_LG_END : POINT_RG_R1,
- // -1, // ignore number (though it is always 1)
- // fill_or_stroke, 99999, 99999, etime);
- // }
- // We did an undoable action, but SPDocumentUndo::done will be called by the knot when released
+
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MESH, _("Create mesh"));
// status text; we do not track coords because this branch is run once, not all the time
// during drag
diff --git a/src/ui/tools/mesh-tool.h b/src/ui/tools/mesh-tool.h
index d952c9010..91b35b3af 100644
--- a/src/ui/tools/mesh-tool.h
+++ b/src/ui/tools/mesh-tool.h
@@ -20,6 +20,7 @@
#include <stddef.h>
#include <sigc++/sigc++.h>
#include "ui/tools/tool-base.h"
+#include "sp-mesh-array.h"
#define SP_MESH_CONTEXT(obj) (dynamic_cast<Inkscape::UI::Tools::MeshTool*>((Inkscape::UI::Tools::ToolBase*)obj))
#define SP_IS_MESH_CONTEXT(obj) (dynamic_cast<const Inkscape::UI::Tools::MeshTool*>((const Inkscape::UI::Tools::ToolBase*)obj) != NULL)
@@ -57,6 +58,7 @@ private:
void sp_mesh_context_select_next(ToolBase *event_context);
void sp_mesh_context_select_prev(ToolBase *event_context);
+void sp_mesh_context_corner_operation(MeshTool *event_context, MeshCornerOperation operation );
}
}
diff --git a/src/ui/tools/node-tool.cpp b/src/ui/tools/node-tool.cpp
index 6a6ca0b26..4149403ea 100644
--- a/src/ui/tools/node-tool.cpp
+++ b/src/ui/tools/node-tool.cpp
@@ -413,7 +413,7 @@ void NodeTool::selection_changed(Inkscape::Selection *sel) {
std::set<ShapeRecord> shapes;
std::vector<SPItem*> items=sel->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
SPObject *obj = *i;
if (SP_IS_ITEM(obj)) {
@@ -495,7 +495,7 @@ bool NodeTool::root_handler(GdkEvent* event) {
// We will show a pre-snap indication for when the user adds a node through double-clicking
// Adding a node will only work when a path has been selected; if that's not the case then snapping is useless
- if (not this->desktop->selection->isEmpty()) {
+ if (!this->desktop->selection->isEmpty()) {
if (!(event->motion.state & GDK_SHIFT_MASK)) {
m.setup(this->desktop);
Inkscape::SnapCandidatePoint scp(motion_dt, Inkscape::SNAPSOURCE_OTHER_HANDLE);
@@ -678,7 +678,7 @@ void NodeTool::update_tip(GdkEvent *event) {
}
}
g_assert(positions.size() == 2);
- const double angle = Geom::rad_to_deg(Geom::Line(positions[0], positions[1]).angle());
+ const double angle = Geom::deg_from_rad(Geom::Line(positions[0], positions[1]).angle());
nodestring = g_strdup_printf("<b>%u of %u</b> nodes selected, angle: %.2f°.", sz, total, angle);
}
else {
diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp
index 827dbf5c3..2ed366a7d 100644
--- a/src/ui/tools/pen-tool.cpp
+++ b/src/ui/tools/pen-tool.cpp
@@ -84,7 +84,7 @@ namespace Tools {
static Geom::Point pen_drag_origin_w(0, 0);
static bool pen_within_tolerance = false;
static int pen_last_paraxial_dir = 0; // last used direction in horizontal/vertical mode; 0 = horizontal, 1 = vertical
-const double HANDLE_CUBIC_GAP = 0.01;
+const double HANDLE_CUBIC_GAP = 0.001;
const std::string& PenTool::getPrefsPath() {
return PenTool::prefsPath;
@@ -268,6 +268,9 @@ void PenTool::_endpointSnap(Geom::Point &p, guint const state) const {
if ((state & GDK_CONTROL_MASK) && !this->polylines_paraxial) { //CTRL enables angular snapping
if (this->npoints > 0) {
spdc_endpoint_snap_rotation(this, p, this->p[0], state);
+ } else {
+ boost::optional<Geom::Point> origin = boost::optional<Geom::Point>();
+ spdc_endpoint_snap_free(this, p, origin, state);
}
} else {
// We cannot use shift here to disable snapping because the shift-key is already used
@@ -379,11 +382,12 @@ bool PenTool::_handleButtonPress(GdkEventButton const &bevent) {
if( anchor && anchor == this->sa && this->green_curve->is_empty()){
//remove the following line to avoid having one node on top of another
_finishSegment(event_dt, bevent.state);
- _finish( false);
+ _finish(true);
return true;
}
return false;
}
+
bool ret = false;
if (bevent.button == 1 && !this->space_panning
// make sure this is not the last click for a waiting LPE (otherwise we want to finish the path)
@@ -857,7 +861,7 @@ bool PenTool::_handleButtonRelease(GdkEventButton const &revent) {
bool PenTool::_handle2ButtonPress(GdkEventButton const &bevent) {
bool ret = false;
// only end on LMB double click. Otherwise horizontal scrolling causes ending of the path
- if (this->npoints != 0 && bevent.button == 1) {
+ if (this->npoints != 0 && bevent.button == 1 && this->state != PenTool::CLOSE) {
this->_finish(false);
ret = true;
}
@@ -1714,9 +1718,9 @@ void PenTool::_bsplineSpiroBuild()
//Effect *spr = static_cast<Effect*> ( new LPEbspline(lpeobj) );
//spr->doEffect(curve);
if(this->bspline){
- this->_bsplineDoEffect(curve);
+ LivePathEffect::sp_bspline_do_effect(curve, 0);
}else{
- this->_spiroDoEffect(curve);
+ LivePathEffect::sp_spiro_do_effect(curve);
}
sp_canvas_bpath_set_bpath(SP_CANVAS_BPATH(this->blue_bpath), curve);
@@ -1740,257 +1744,6 @@ void PenTool::_bsplineSpiroBuild()
}
}
-//from LPE BSPLINE:
-void PenTool::_bsplineDoEffect(SPCurve * curve)
-{
- //const double NO_POWER = 0.0;
- const double DEFAULT_START_POWER = 0.3334;
- const double DEFAULT_END_POWER = 0.6667;
- if (curve->get_segment_count() < 1) {
- return;
- }
- // Make copy of old path as it is changed during processing
- Geom::PathVector const original_pathv = curve->get_pathvector();
-
- curve->reset();
-
- for (Geom::PathVector::const_iterator path_it = original_pathv.begin();
- path_it != original_pathv.end(); ++path_it) {
- if (path_it->empty()) {
- continue;
- }
- Geom::Path::const_iterator curve_it1 = path_it->begin();
- Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
- Geom::Path::const_iterator curve_endit = path_it->end_default();
- SPCurve *curve_n = new SPCurve();
- Geom::Point previousNode(0, 0);
- Geom::Point node(0, 0);
- Geom::Point point_at1(0, 0);
- Geom::Point point_at2(0, 0);
- Geom::Point next_point_at1(0, 0);
- Geom::D2<Geom::SBasis> sbasis_in;
- Geom::D2<Geom::SBasis> sbasis_out;
- Geom::D2<Geom::SBasis> sbasis_helper;
- Geom::CubicBezier const *cubic = NULL;
- if (path_it->closed()) {
- // if the path is closed, maybe we have to stop a bit earlier because the
- // closing line segment has zerolength.
- const Geom::Curve &closingline =
- path_it->back_closed(); // the closing line segment is always of type
- // Geom::LineSegment.
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- // closingline.isDegenerate() did not work, because it only checks for
- // *exact* zero length, which goes wrong for relative coordinates and
- // rounding errors...
- // the closing line segment has zero-length. So stop before that one!
- curve_endit = path_it->end_open();
- }
- }
- curve_n->moveto(curve_it1->initialPoint());
- while (curve_it1 != curve_endit) {
- SPCurve *in = new SPCurve();
- in->moveto(curve_it1->initialPoint());
- in->lineto(curve_it1->finalPoint());
- cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
- if (cubic) {
- sbasis_in = in->first_segment()->toSBasis();
- if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) {
- point_at1 = sbasis_in.valueAt(DEFAULT_START_POWER);
- } else {
- point_at1 = sbasis_in.valueAt(Geom::nearest_time((*cubic)[1], *in->first_segment()));
- }
- if(are_near((*cubic)[2],(*cubic)[3]) && !are_near((*cubic)[1],(*cubic)[0])) {
- point_at2 = sbasis_in.valueAt(DEFAULT_END_POWER);
- } else {
- point_at2 = sbasis_in.valueAt(Geom::nearest_time((*cubic)[2], *in->first_segment()));
- }
- } else {
- point_at1 = in->first_segment()->initialPoint();
- point_at2 = in->first_segment()->finalPoint();
- }
- in->reset();
- delete in;
- if ( curve_it2 != curve_endit ) {
- SPCurve *out = new SPCurve();
- out->moveto(curve_it2->initialPoint());
- out->lineto(curve_it2->finalPoint());
- cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it2);
- if (cubic) {
- sbasis_out = out->first_segment()->toSBasis();
- if(are_near((*cubic)[1],(*cubic)[0]) && !are_near((*cubic)[2],(*cubic)[3])) {
- next_point_at1 = sbasis_in.valueAt(DEFAULT_START_POWER);
- } else {
- next_point_at1 = sbasis_out.valueAt(Geom::nearest_time((*cubic)[1], *out->first_segment()));
- }
- } else {
- next_point_at1 = out->first_segment()->initialPoint();
- }
- out->reset();
- delete out;
- }
- if (path_it->closed() && curve_it2 == curve_endit) {
- SPCurve *start = new SPCurve();
- start->moveto(path_it->begin()->initialPoint());
- start->lineto(path_it->begin()->finalPoint());
- Geom::D2<Geom::SBasis> sbasis_start = start->first_segment()->toSBasis();
- SPCurve *line_helper = new SPCurve();
- cubic = dynamic_cast<Geom::CubicBezier const *>(&*path_it->begin());
- if (cubic) {
- line_helper->moveto(sbasis_start.valueAt(
- Geom::nearest_time((*cubic)[1], *start->first_segment())));
- } else {
- line_helper->moveto(start->first_segment()->initialPoint());
- }
- start->reset();
- delete start;
-
- SPCurve *end = new SPCurve();
- end->moveto(curve_it1->initialPoint());
- end->lineto(curve_it1->finalPoint());
- Geom::D2<Geom::SBasis> sbasis_end = end->first_segment()->toSBasis();
- cubic = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
- if (cubic) {
- line_helper->lineto(sbasis_end.valueAt(
- Geom::nearest_time((*cubic)[2], *end->first_segment())));
- } else {
- line_helper->lineto(end->first_segment()->finalPoint());
- }
- end->reset();
- delete end;
- sbasis_helper = line_helper->first_segment()->toSBasis();
- line_helper->reset();
- delete line_helper;
- node = sbasis_helper.valueAt(0.5);
- curve_n->curveto(point_at1, point_at2, node);
- curve_n->move_endpoints(node, node);
- } else if ( curve_it2 == curve_endit) {
- curve_n->curveto(point_at1, point_at2, curve_it1->finalPoint());
- curve_n->move_endpoints(path_it->begin()->initialPoint(), curve_it1->finalPoint());
- } else {
- SPCurve *line_helper = new SPCurve();
- line_helper->moveto(point_at2);
- line_helper->lineto(next_point_at1);
- sbasis_helper = line_helper->first_segment()->toSBasis();
- line_helper->reset();
- delete line_helper;
- previousNode = node;
- node = sbasis_helper.valueAt(0.5);
- Geom::CubicBezier const *cubic2 = dynamic_cast<Geom::CubicBezier const *>(&*curve_it1);
- if((cubic && are_near((*cubic)[0],(*cubic)[1])) || (cubic2 && are_near((*cubic2)[2],(*cubic2)[3]))) {
- node = curve_it1->finalPoint();
- }
- curve_n->curveto(point_at1, point_at2, node);
- }
- ++curve_it1;
- ++curve_it2;
- }
- //y cerramos la curva
- if (path_it->closed()) {
- curve_n->closepath_current();
- }
- curve->append(curve_n, false);
- curve_n->reset();
- delete curve_n;
- }
-}
-
-//Spiro function cloned from lpe-spiro.cpp
-// commenting the function "doEffect" from src/live_effects/lpe-spiro.cpp
-void PenTool::_spiroDoEffect(SPCurve * curve)
-{
- using Geom::X;
- using Geom::Y;
-
- Geom::PathVector const original_pathv = curve->get_pathvector();
- guint len = curve->get_segment_count() + 2;
-
- curve->reset();
- Spiro::spiro_cp *path = g_new (Spiro::spiro_cp, len);
- int ip = 0;
-
- for(Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) {
- if (path_it->empty())
- continue;
-
- {
- Geom::Point p = path_it->front().pointAt(0);
- path[ip].x = p[X];
- path[ip].y = p[Y];
- path[ip].ty = '{' ;
- ip++;
- }
-
- Geom::Path::const_iterator curve_it1 = path_it->begin();
- Geom::Path::const_iterator curve_it2 = ++(path_it->begin());
-
- Geom::Path::const_iterator curve_endit = path_it->end_default();
- if (path_it->closed()) {
- const Geom::Curve &closingline = path_it->back_closed();
- if (are_near(closingline.initialPoint(), closingline.finalPoint())) {
- curve_endit = path_it->end_open();
- }
- }
-
- while ( curve_it2 != curve_endit )
- {
- Geom::Point p = curve_it1->finalPoint();
- path[ip].x = p[X];
- path[ip].y = p[Y];
-
- bool this_is_line = is_straight_curve(*curve_it1);
- bool next_is_line = is_straight_curve(*curve_it2);
-
- Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, *curve_it2);
-
- if ( nodetype == Geom::NODE_SMOOTH || nodetype == Geom::NODE_SYMM )
- {
- if (this_is_line && !next_is_line) {
- path[ip].ty = ']';
- } else if (next_is_line && !this_is_line) {
- path[ip].ty = '[';
- } else {
- path[ip].ty = 'c';
- }
- } else {
- path[ip].ty = 'v';
- }
-
- ++curve_it1;
- ++curve_it2;
- ip++;
- }
-
- Geom::Point p = curve_it1->finalPoint();
- path[ip].x = p[X];
- path[ip].y = p[Y];
- if (path_it->closed()) {
- Geom::NodeType nodetype = Geom::get_nodetype(*curve_it1, path_it->front());
- switch (nodetype) {
- case Geom::NODE_NONE:
- path[ip].ty = '}';
- ip++;
- break;
- case Geom::NODE_CUSP:
- path[0].ty = path[ip].ty = 'v';
- break;
- case Geom::NODE_SMOOTH:
- case Geom::NODE_SYMM:
- path[0].ty = path[ip].ty = 'c';
- break;
- }
- } else {
- path[ip].ty = '}';
- ip++;
- }
-
- int sp_len = ip;
- Spiro::spiro_run(path, sp_len, *curve);
- ip = 0;
- }
-
- g_free (path);
-}
-
void PenTool::_setSubsequentPoint(Geom::Point const p, bool statusbar, guint status) {
g_assert( this->npoints != 0 );
diff --git a/src/ui/tools/pen-tool.h b/src/ui/tools/pen-tool.h
index 0ae16caf0..5a21e3bac 100644
--- a/src/ui/tools/pen-tool.h
+++ b/src/ui/tools/pen-tool.h
@@ -22,21 +22,21 @@ namespace Tools {
*/
class PenTool : public FreehandBase {
public:
- PenTool();
- PenTool(gchar const *const *cursor_shape, gint hot_x, gint hot_y);
- virtual ~PenTool();
-
- enum Mode {
- MODE_CLICK,
- MODE_DRAG
- };
-
- enum State {
- POINT,
- CONTROL,
- CLOSE,
- STOP
- };
+ PenTool();
+ PenTool(gchar const *const *cursor_shape, gint hot_x, gint hot_y);
+ virtual ~PenTool();
+
+ enum Mode {
+ MODE_CLICK,
+ MODE_DRAG
+ };
+
+ enum State {
+ POINT,
+ CONTROL,
+ CLOSE,
+ STOP
+ };
Geom::Point p[5];
@@ -66,28 +66,28 @@ public:
bool events_disabled;
- static const std::string prefsPath;
+ static const std::string prefsPath;
- virtual const std::string& getPrefsPath();
+ virtual const std::string& getPrefsPath();
- int nextParaxialDirection(Geom::Point const &pt, Geom::Point const &origin, guint state) const;
- void setPolylineMode();
- bool hasWaitingLPE();
+ int nextParaxialDirection(Geom::Point const &pt, Geom::Point const &origin, guint state) const;
+ void setPolylineMode();
+ bool hasWaitingLPE();
void waitForLPEMouseClicks(Inkscape::LivePathEffect::EffectType effect_type, unsigned int num_clicks, bool use_polylines = true);
protected:
- virtual void setup();
- virtual void finish();
- virtual void set(const Inkscape::Preferences::Entry& val);
- virtual bool root_handler(GdkEvent* event);
- virtual bool item_handler(SPItem* item, GdkEvent* event);
+ virtual void setup();
+ virtual void finish();
+ virtual void set(const Inkscape::Preferences::Entry& val);
+ virtual bool root_handler(GdkEvent* event);
+ virtual bool item_handler(SPItem* item, GdkEvent* event);
private:
- bool _handleButtonPress(GdkEventButton const &bevent);
- bool _handleMotionNotify(GdkEventMotion const &mevent);
- bool _handleButtonRelease(GdkEventButton const &revent);
- bool _handle2ButtonPress(GdkEventButton const &bevent);
- bool _handleKeyPress(GdkEvent *event);
+ bool _handleButtonPress(GdkEventButton const &bevent);
+ bool _handleMotionNotify(GdkEventMotion const &mevent);
+ bool _handleButtonRelease(GdkEventButton const &revent);
+ bool _handle2ButtonPress(GdkEventButton const &bevent);
+ bool _handleKeyPress(GdkEvent *event);
//adds spiro & bspline modes
void _penContextSetMode(guint mode);
//this function changes the colors red, green and blue making them transparent or not depending on if the function uses spiro
@@ -110,40 +110,36 @@ private:
void _bsplineSpiroEndAnchorOn();
//closes the curve with the last node in CUSP mode
void _bsplineSpiroEndAnchorOff();
- //CHECK: join all the curves "in game" and we call doEffect function
+ //apply the effect
void _bsplineSpiroBuild();
- //function bspline cloned from lpe-bspline.cpp
- void _bsplineDoEffect(SPCurve * curve);
- //function spiro cloned from lpe-spiro.cpp
- void _spiroDoEffect(SPCurve * curve);
-
- void _setInitialPoint(Geom::Point const p);
- void _setSubsequentPoint(Geom::Point const p, bool statusbar, guint status = 0);
- void _setCtrl(Geom::Point const p, guint state);
- void _finishSegment(Geom::Point p, guint state);
+
+ void _setInitialPoint(Geom::Point const p);
+ void _setSubsequentPoint(Geom::Point const p, bool statusbar, guint status = 0);
+ void _setCtrl(Geom::Point const p, guint state);
+ void _finishSegment(Geom::Point p, guint state);
bool _undoLastPoint();
- void _finish(gboolean closed);
+ void _finish(gboolean closed);
- void _resetColors();
+ void _resetColors();
- void _disableEvents();
- void _enableEvents();
+ void _disableEvents();
+ void _enableEvents();
- void _setToNearestHorizVert(Geom::Point &pt, guint const state, bool snap) const;
+ void _setToNearestHorizVert(Geom::Point &pt, guint const state, bool snap) const;
- void _setAngleDistanceStatusMessage(Geom::Point const p, int pc_point_to_compare, gchar const *message);
+ void _setAngleDistanceStatusMessage(Geom::Point const p, int pc_point_to_compare, gchar const *message);
- void _lastpointToLine();
- void _lastpointToCurve();
- void _lastpointMoveScreen(gdouble x, gdouble y);
- void _lastpointMove(gdouble x, gdouble y);
- void _redrawAll();
+ void _lastpointToLine();
+ void _lastpointToCurve();
+ void _lastpointMoveScreen(gdouble x, gdouble y);
+ void _lastpointMove(gdouble x, gdouble y);
+ void _redrawAll();
- void _endpointSnapHandle(Geom::Point &p, guint const state) const;
- void _endpointSnap(Geom::Point &p, guint const state) const;
+ void _endpointSnapHandle(Geom::Point &p, guint const state) const;
+ void _endpointSnap(Geom::Point &p, guint const state) const;
- void _cancel();
+ void _cancel();
};
}
diff --git a/src/ui/tools/pencil-tool.cpp b/src/ui/tools/pencil-tool.cpp
index 16c26546f..b029ca613 100644
--- a/src/ui/tools/pencil-tool.cpp
+++ b/src/ui/tools/pencil-tool.cpp
@@ -634,8 +634,13 @@ void PencilTool::_interpolate() {
using Geom::Y;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- double const tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0) * 0.4;
- double const tolerance_sq = 0.02 * square(this->desktop->w2d().descrim() * tol) * exp(0.2 * tol - 2);
+ double tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0) * 0.4;
+ bool simplify = prefs->getInt("/tools/freehand/pencil/simplify", 0);
+ if(simplify){
+ double tol2 = prefs->getDoubleLimited("/tools/freehand/pencil/base-simplify", 25.0, 1.0, 100.0) * 0.4;
+ tol = std::min(tol,tol2);
+ }
+ double tolerance_sq = 0.02 * square(this->desktop->w2d().descrim() * tol) * exp(0.2 * tol - 2);
g_assert(is_zero(this->req_tangent) || is_unit_vector(this->req_tangent));
@@ -702,9 +707,14 @@ void PencilTool::_sketchInterpolate() {
}
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- double const tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0) * 0.4;
- double const tolerance_sq = 0.02 * square(this->desktop->w2d().descrim() * tol) * exp(0.2 * tol - 2);
-
+ double tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0) * 0.4;
+ bool simplify = prefs->getInt("/tools/freehand/pencil/simplify", 0);
+ if(simplify){
+ double tol2 = prefs->getDoubleLimited("/tools/freehand/pencil/base-simplify", 25.0, 1.0, 100.0) * 0.4;
+ tol = std::min(tol,tol2);
+ }
+ double tolerance_sq = 0.02 * square(this->desktop->w2d().descrim() * tol) * exp(0.2 * tol - 2);
+
bool average_all_sketches = prefs->getBool("/tools/freehand/pencil/average_all_sketches", true);
g_assert(is_zero(this->req_tangent) || is_unit_vector(this->req_tangent));
diff --git a/src/ui/tools/select-tool.cpp b/src/ui/tools/select-tool.cpp
index f06b03d91..905e38f2b 100644
--- a/src/ui/tools/select-tool.cpp
+++ b/src/ui/tools/select-tool.cpp
@@ -89,10 +89,6 @@ SelectTool::SelectTool()
, button_press_shift(false)
, button_press_ctrl(false)
, button_press_alt(false)
- , cycling_items(NULL)
- , cycling_items_cmp(NULL)
- , cycling_items_selected_before(NULL)
- , cycling_cur_item(NULL)
, cycling_wrap(true)
, item(NULL)
, grabbed(NULL)
@@ -390,16 +386,16 @@ bool SelectTool::item_handler(SPItem* item, GdkEvent* event) {
}
void SelectTool::sp_select_context_cycle_through_items(Inkscape::Selection *selection, GdkEventScroll *scroll_event, bool shift_pressed) {
- if (!this->cycling_cur_item) {
+ if (this->cycling_cur_item == this->cycling_items.end()) {
return;
}
Inkscape::DrawingItem *arenaitem;
- SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(cycling_cur_item->data));
+ SPItem *item = *cycling_cur_item;
g_assert(item != NULL);
// Deactivate current item
- if (!g_list_find(this->cycling_items_selected_before, item) && selection->includes(item)) {
+ if (std::find(cycling_items_selected_before.begin(), cycling_items_selected_before.end(), item) == cycling_items_selected_before.end() && selection->includes(item)) {
selection->remove(item);
}
@@ -407,20 +403,22 @@ void SelectTool::sp_select_context_cycle_through_items(Inkscape::Selection *sele
arenaitem->setOpacity(0.3);
// Find next item and activate it
- GList *next;
+ std::vector<SPItem *>::iterator next = this->cycling_cur_item;
if (scroll_event->direction == GDK_SCROLL_UP) {
- next = this->cycling_cur_item->next;
- if (next == NULL && this->cycling_wrap)
- next = this->cycling_items;
+ ++next;
+ if (next == this->cycling_items.end() && this->cycling_wrap) {
+ next = this->cycling_items.begin();
+ }
} else {
- next = this->cycling_cur_item->prev;
- if (next == NULL && this->cycling_wrap)
- next = g_list_last(this->cycling_items);
+ if(next == this->cycling_items.begin()) {
+ next = this->cycling_items.end();
+ }
+ --next;
}
- if (next) {
+ if (next!=this->cycling_items.end()) {
this->cycling_cur_item = next;
- item = dynamic_cast<SPItem *>(static_cast<SPObject *>(this->cycling_cur_item->data));
+ item = *next;
g_assert(item != NULL);
}
@@ -435,8 +433,8 @@ void SelectTool::sp_select_context_cycle_through_items(Inkscape::Selection *sele
}
void SelectTool::sp_select_context_reset_opacities() {
- for (GList *l = this->cycling_items; l != NULL; l = g_list_next(l)) {
- SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(l->data));
+ for (std::vector<SPItem *>::const_iterator l = this->cycling_items.begin(); l != this->cycling_items.end(); ++l ) {
+ SPItem *item = *l;
if (item) {
Inkscape::DrawingItem *arenaitem = item->get_arenaitem(desktop->dkey);
arenaitem->setOpacity(SP_SCALE24_TO_FLOAT(item->style->opacity.value));
@@ -445,14 +443,10 @@ void SelectTool::sp_select_context_reset_opacities() {
}
}
- g_list_free(this->cycling_items);
- g_list_free(this->cycling_items_selected_before);
- g_list_free(this->cycling_items_cmp);
-
- this->cycling_items = NULL;
- this->cycling_items_selected_before = NULL;
- this->cycling_cur_item = NULL;
- this->cycling_items_cmp = NULL;
+ this->cycling_items.clear();
+ this->cycling_items_selected_before.clear();
+ this->cycling_cur_item = this->cycling_items.end();
+ this->cycling_items_cmp.clear();
}
bool SelectTool::root_handler(GdkEvent* event) {
@@ -819,70 +813,57 @@ bool SelectTool::root_handler(GdkEvent* event) {
SPItem *item = desktop->getItemAtPoint(p, true, NULL);
// Save pointer to current cycle-item so that we can find it again later, in the freshly built list
- SPItem *tmp_cur_item = this->cycling_cur_item ? dynamic_cast<SPItem *>(static_cast<SPObject *>(this->cycling_cur_item->data)) : NULL;
- g_list_free(this->cycling_items);
- this->cycling_items = NULL;
- this->cycling_cur_item = NULL;
-
+ SPItem *tmp_cur_item = this->cycling_cur_item!=this->cycling_items.end() ? (*(this->cycling_cur_item)) : NULL;
+ this->cycling_items.clear();
+ this->cycling_cur_item = this->cycling_items.end();
while(item != NULL) {
- this->cycling_items = g_list_append(this->cycling_items, item);
+ this->cycling_items.push_back(item);
item = desktop->getItemAtPoint(p, true, item);
}
/* Compare current item list with item list during previous scroll ... */
- GList *l1, *l2;
- bool item_lists_differ = false;
-
- // Note that we can do an 'or' comparison in the loop because it is safe to call g_list_next with a NULL pointer.
- for (l1 = this->cycling_items, l2 = this->cycling_items_cmp; l1 != NULL || l2 != NULL; l1 = g_list_next(l1), l2 = g_list_next(l2)) {
- if ((l1 !=NULL && l2 == NULL) || (l1 == NULL && l2 != NULL) || (l1->data != l2->data)) {
- item_lists_differ = true;
- break;
- }
- }
+ bool item_lists_differ = this->cycling_items != this->cycling_items_cmp;
/* If list of items under mouse pointer hasn't changed ... */
if (!item_lists_differ) {
// ... find current item in the freshly built list and continue cycling ...
// TODO: This wouldn't be necessary if cycling_cur_item pointed to an element of cycling_items_cmp instead
- this->cycling_cur_item = g_list_find(this->cycling_items, tmp_cur_item);
- g_assert(this->cycling_cur_item != NULL || this->cycling_items == NULL);
+ this->cycling_cur_item = std::find(this->cycling_items.begin(), this->cycling_items.end(), tmp_cur_item);
+ g_assert(this->cycling_cur_item != this->cycling_items.end() || this->cycling_items.empty());
} else {
// ... otherwise reset opacities for outdated items ...
Inkscape::DrawingItem *arenaitem;
- for(GList *l = this->cycling_items_cmp; l != NULL; l = l->next) {
- SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(l->data));
+ for (std::vector<SPItem *>::const_iterator l = this->cycling_items_cmp.begin(); l != this->cycling_items_cmp.end(); ++l) {
+ SPItem *item = *l;
if (item) {
arenaitem = item->get_arenaitem(desktop->dkey);
arenaitem->setOpacity(1.0);
//if (!shift_pressed && !g_list_find(this->cycling_items_selected_before, item) && selection->includes(item))
- if (!g_list_find(this->cycling_items_selected_before, item) && selection->includes(item)) {
+ if (std::find(this->cycling_items_selected_before.begin(),this->cycling_items_selected_before.end(), item)==this->cycling_items_selected_before.end() && selection->includes(item)) {
selection->remove(item);
}
}
}
// ... clear the lists ...
- g_list_free(this->cycling_items_cmp);
- g_list_free(this->cycling_items_selected_before);
- this->cycling_items_cmp = NULL;
- this->cycling_items_selected_before = NULL;
- this->cycling_cur_item = NULL;
+ this->cycling_items_cmp.clear();
+ this->cycling_items_selected_before.clear();
+ this->cycling_cur_item = this->cycling_items.end();
// ... and rebuild them with the new items.
- this->cycling_items_cmp = g_list_copy(this->cycling_items);
+ this->cycling_items_cmp = (this->cycling_items);
- for(GList *l = this->cycling_items; l != NULL; l = l->next) {
- SPItem *item = dynamic_cast<SPItem *>(static_cast<SPObject *>(l->data));
+ for(std::vector<SPItem *>::const_iterator l = this->cycling_items.begin(); l != this->cycling_items.end(); ++l) {
+ SPItem *item =*l;
if (item) {
arenaitem = item->get_arenaitem(desktop->dkey);
arenaitem->setOpacity(0.3);
if (selection->includes(item)) {
// already selected items are stored separately, too
- this->cycling_items_selected_before = g_list_append(this->cycling_items_selected_before, item);
+ this->cycling_items_selected_before.push_back(item);
}
} else {
g_assert_not_reached();
@@ -890,7 +871,8 @@ bool SelectTool::root_handler(GdkEvent* event) {
}
// set the current item to the bottommost one so that the cycling step below re-starts at the top
- this->cycling_cur_item = g_list_last(this->cycling_items);
+ this->cycling_cur_item = this->cycling_items.end();
+ this->cycling_cur_item--;
}
this->cycling_wrap = prefs->getBool("/options/selection/cycleWrap", true);
diff --git a/src/ui/tools/select-tool.h b/src/ui/tools/select-tool.h
index 5af99a56a..af183b1ca 100644
--- a/src/ui/tools/select-tool.h
+++ b/src/ui/tools/select-tool.h
@@ -40,10 +40,10 @@ public:
bool button_press_ctrl;
bool button_press_alt;
- GList *cycling_items;
- GList *cycling_items_cmp;
- GList *cycling_items_selected_before;
- GList *cycling_cur_item;
+ std::vector<SPItem *> cycling_items;
+ std::vector<SPItem *> cycling_items_cmp;
+ std::vector<SPItem *> cycling_items_selected_before;
+ std::vector<SPItem *>::iterator cycling_cur_item;
bool cycling_wrap;
SPItem *item;
diff --git a/src/ui/tools/spray-tool.cpp b/src/ui/tools/spray-tool.cpp
index e2be5ca4b..9adaf3879 100644
--- a/src/ui/tools/spray-tool.cpp
+++ b/src/ui/tools/spray-tool.cpp
@@ -12,6 +12,7 @@
* Steren GIANNINI (steren.giannini@gmail.com)
* Jon A. Cruz <jon@joncruz.org>
* Abhishek Sharma
+ * Jabiertxo Arraiza <jabier.arraiza@marker.es>
*
* Copyright (C) 2009 authors
*
@@ -48,7 +49,15 @@
#include "sp-path.h"
#include "path-chemistry.h"
+// For color picking
+#include "display/drawing.h"
+#include "display/drawing-context.h"
+#include "display/cairo-utils.h"
+#include "desktop-style.h"
+#include "svg/svg-color.h"
+
#include "sp-text.h"
+#include "sp-root.h"
#include "sp-flowtext.h"
#include "display/sp-canvas.h"
#include "display/canvas-bpath.h"
@@ -88,6 +97,17 @@ namespace Inkscape {
namespace UI {
namespace Tools {
+enum {
+ PICK_COLOR,
+ PICK_OPACITY,
+ PICK_R,
+ PICK_G,
+ PICK_B,
+ PICK_H,
+ PICK_S,
+ PICK_L
+};
+
const std::string& SprayTool::getPrefsPath() {
return SprayTool::prefsPath;
}
@@ -133,7 +153,9 @@ SprayTool::SprayTool()
: ToolBase(cursor_spray_xpm, 4, 4, false)
, pressure(TC_DEFAULT_PRESSURE)
, dragging(false)
- , usepressure(false)
+ , usepressurewidth(false)
+ , usepressurepopulation(false)
+ , usepressurescale(false)
, usetilt(false)
, usetext(false)
, width(0.2)
@@ -151,6 +173,25 @@ SprayTool::SprayTool()
, is_dilating(false)
, has_dilated(false)
, dilate_area(NULL)
+ , no_overlap(false)
+ , picker(false)
+ , pick_center(true)
+ , pick_inverse_value(false)
+ , pick_fill(false)
+ , pick_stroke(false)
+ , pick_no_overlap(false)
+ , over_transparent(true)
+ , over_no_transparent(true)
+ , offset(0)
+ , pick(0)
+ , do_trace(false)
+ , pick_to_size(false)
+ , pick_to_presence(false)
+ , pick_to_color(false)
+ , pick_to_opacity(false)
+ , invert_picked(false)
+ , gamma_picked(0)
+ , rand_picked(0)
{
}
@@ -211,6 +252,15 @@ void SprayTool::setup() {
this->is_drawing = false;
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setBool("/dialogs/clonetiler/dotrace", false);
+ if (prefs->getBool("/tools/spray/selcue")) {
+ this->enableSelectionCue();
+ }
+ if (prefs->getBool("/tools/spray/gradientdrag")) {
+ this->enableGrDrag();
+ }
+
sp_event_context_read(this, "distrib");
sp_event_context_read(this, "width");
sp_event_context_read(this, "ratio");
@@ -221,16 +271,33 @@ void SprayTool::setup() {
sp_event_context_read(this, "population");
sp_event_context_read(this, "mean");
sp_event_context_read(this, "standard_deviation");
- sp_event_context_read(this, "usepressure");
+ sp_event_context_read(this, "usepressurewidth");
+ sp_event_context_read(this, "usepressurepopulation");
+ sp_event_context_read(this, "usepressurescale");
sp_event_context_read(this, "Scale");
+ sp_event_context_read(this, "offset");
+ sp_event_context_read(this, "picker");
+ sp_event_context_read(this, "pick_center");
+ sp_event_context_read(this, "pick_inverse_value");
+ sp_event_context_read(this, "pick_fill");
+ sp_event_context_read(this, "pick_stroke");
+ sp_event_context_read(this, "pick_no_overlap");
+ sp_event_context_read(this, "over_no_transparent");
+ sp_event_context_read(this, "over_transparent");
+ sp_event_context_read(this, "no_overlap");
+}
+void SprayTool::setCloneTilerPrefs() {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- if (prefs->getBool("/tools/spray/selcue")) {
- this->enableSelectionCue();
- }
- if (prefs->getBool("/tools/spray/gradientdrag")) {
- this->enableGrDrag();
- }
+ this->do_trace = prefs->getBool("/dialogs/clonetiler/dotrace", false);
+ this->pick = prefs->getInt("/dialogs/clonetiler/pick");
+ this->pick_to_size = prefs->getBool("/dialogs/clonetiler/pick_to_size", false);
+ this->pick_to_presence = prefs->getBool("/dialogs/clonetiler/pick_to_presence", false);
+ this->pick_to_color = prefs->getBool("/dialogs/clonetiler/pick_to_color", false);
+ this->pick_to_opacity = prefs->getBool("/dialogs/clonetiler/pick_to_opacity", false);
+ this->rand_picked = 0.01 * prefs->getDoubleLimited("/dialogs/clonetiler/rand_picked", 0, 0, 100);
+ this->invert_picked = prefs->getBool("/dialogs/clonetiler/invert_picked", false);
+ this->gamma_picked = prefs->getDoubleLimited("/dialogs/clonetiler/gamma_picked", 0, -10, 10);
}
void SprayTool::set(const Inkscape::Preferences::Entry& val) {
@@ -241,8 +308,12 @@ void SprayTool::set(const Inkscape::Preferences::Entry& val) {
this->update_cursor(false);
} else if (path == "width") {
this->width = 0.01 * CLAMP(val.getInt(10), 1, 100);
- } else if (path == "usepressure") {
- this->usepressure = val.getBool();
+ } else if (path == "usepressurewidth") {
+ this->usepressurewidth = val.getBool();
+ } else if (path == "usepressurepopulation") {
+ this->usepressurepopulation = val.getBool();
+ } else if (path == "usepressurescale") {
+ this->usepressurescale = val.getBool();
} else if (path == "population") {
this->population = 0.01 * CLAMP(val.getInt(10), 1, 100);
} else if (path == "rotation_variation") {
@@ -260,6 +331,26 @@ void SprayTool::set(const Inkscape::Preferences::Entry& val) {
this->tilt = CLAMP(val.getDouble(0.1), 0, 1000.0);
} else if (path == "ratio") {
this->ratio = CLAMP(val.getDouble(), 0.0, 0.9);
+ } else if (path == "offset") {
+ this->offset = val.getDoubleLimited(100.0, 0, 1000.0);
+ } else if (path == "pick_center") {
+ this->pick_center = val.getBool(true);
+ } else if (path == "pick_inverse_value") {
+ this->pick_inverse_value = val.getBool(false);
+ } else if (path == "pick_fill") {
+ this->pick_fill = val.getBool(false);
+ } else if (path == "pick_stroke") {
+ this->pick_stroke = val.getBool(false);
+ } else if (path == "pick_no_overlap") {
+ this->pick_no_overlap = val.getBool(false);
+ } else if (path == "over_no_transparent") {
+ this->over_no_transparent = val.getBool(true);
+ } else if (path == "over_transparent") {
+ this->over_transparent = val.getBool(true);
+ } else if (path == "no_overlap") {
+ this->no_overlap = val.getBool(false);
+ } else if (path == "picker") {
+ this->picker = val.getBool(false);
}
}
@@ -272,9 +363,15 @@ static void sp_spray_extinput(SprayTool *tc, GdkEvent *event)
}
}
+static double get_width(SprayTool *tc)
+{
+ double pressure = (tc->usepressurewidth? tc->pressure / TC_DEFAULT_PRESSURE : 1);
+ return pressure * tc->width;
+}
+
static double get_dilate_radius(SprayTool *tc)
{
- return 250 * tc->width/SP_EVENT_CONTEXT(tc)->desktop->current_zoom();
+ return 250 * get_width(tc)/SP_EVENT_CONTEXT(tc)->desktop->current_zoom();
}
static double get_path_mean(SprayTool *tc)
@@ -289,11 +386,16 @@ static double get_path_standard_deviation(SprayTool *tc)
static double get_population(SprayTool *tc)
{
- double pressure = (tc->usepressure? tc->pressure / TC_DEFAULT_PRESSURE : 1);
- //g_warning("Pressure, population: %f, %f", pressure, pressure * tc->population);
+ double pressure = (tc->usepressurepopulation? tc->pressure / TC_DEFAULT_PRESSURE : 1);
return pressure * tc->population;
}
+static double get_pressure(SprayTool *tc)
+{
+ double pressure = tc->pressure / TC_DEFAULT_PRESSURE;
+ return pressure;
+}
+
static double get_move_mean(SprayTool *tc)
{
return tc->mean;
@@ -332,6 +434,433 @@ static void random_position(double &radius, double &angle, double &a, double &s,
}
+static void sp_spray_transform_path(SPItem * item, Geom::Path &path, Geom::Affine affine, Geom::Point center){
+ path *= i2anc_affine(static_cast<SPItem *>(item->parent), NULL).inverse();
+ path *= item->transform.inverse();
+ Geom::Affine dt2p;
+ if (item->parent) {
+ dt2p = static_cast<SPItem *>(item->parent)->i2dt_affine().inverse();
+ } else {
+ SPDesktop *dt = SP_ACTIVE_DESKTOP;
+ dt2p = dt->dt2doc();
+ }
+ Geom::Affine i2dt = item->i2dt_affine() * Geom::Translate(center).inverse() * affine * Geom::Translate(center);
+ path *= i2dt * dt2p;
+ path *= i2anc_affine(static_cast<SPItem *>(item->parent), NULL);
+}
+
+/**
+Randomizes \a val by \a rand, with 0 < val < 1 and all values (including 0, 1) having the same
+probability of being displaced.
+ */
+double randomize01(double val, double rand)
+{
+ double base = MIN (val - rand, 1 - 2*rand);
+ if (base < 0) {
+ base = 0;
+ }
+ val = base + g_random_double_range (0, MIN (2 * rand, 1 - base));
+ return CLAMP(val, 0, 1); // this should be unnecessary with the above provisions, but just in case...
+}
+
+guint32 getPickerData(Geom::IntRect area){
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ double R = 0, G = 0, B = 0, A = 0;
+ cairo_surface_t *s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, area.width(), area.height());
+ sp_canvas_arena_render_surface(SP_CANVAS_ARENA(desktop->getDrawing()), s, area);
+ ink_cairo_surface_average_color(s, R, G, B, A);
+ cairo_surface_destroy(s);
+ //this can fix the bug #1511998 if confirmed
+ if( A == 0 || A < 1e-6){
+ R = 1;
+ G = 1;
+ B = 1;
+ }
+ return SP_RGBA32_F_COMPOSE(R, G, B, A);
+}
+
+static void showHidden(std::vector<SPItem *> items_down){
+ for (std::vector<SPItem *>::const_iterator k=items_down.begin(); k!=items_down.end(); ++k) {
+ SPItem *item_hidden = *k;
+ item_hidden->setHidden(false);
+ item_hidden->updateRepr();
+ }
+}
+//todo: maybe move same parameter to preferences
+static bool fit_item(SPDesktop *desktop,
+ SPItem *item,
+ Geom::OptRect bbox,
+ Geom::Point &move,
+ Geom::Point center,
+ gint mode,
+ double angle,
+ double &_scale,
+ double scale,
+ bool picker,
+ bool pick_center,
+ bool pick_inverse_value,
+ bool pick_fill,
+ bool pick_stroke,
+ bool pick_no_overlap,
+ bool over_no_transparent,
+ bool over_transparent,
+ bool no_overlap,
+ double offset,
+ SPCSSAttr *css,
+ bool trace_scale,
+ int pick,
+ bool do_trace,
+ bool pick_to_size,
+ bool pick_to_presence,
+ bool pick_to_color,
+ bool pick_to_opacity,
+ bool invert_picked,
+ double gamma_picked ,
+ double rand_picked)
+{
+ SPDocument *doc = item->document;
+ double width = bbox->width();
+ double height = bbox->height();
+ double offset_width = (offset * width)/100.0 - (width);
+ if(offset_width < 0 ){
+ offset_width = 0;
+ }
+ double offset_height = (offset * height)/100.0 - (height);
+ if(offset_height < 0 ){
+ offset_height = 0;
+ }
+ if(picker && pick_to_size && !trace_scale && do_trace){
+ _scale = 0.1;
+ }
+ Geom::OptRect bbox_procesed = Geom::Rect(Geom::Point(bbox->left() - offset_width, bbox->top() - offset_height),Geom::Point(bbox->right() + offset_width, bbox->bottom() + offset_height));
+ Geom::Path path;
+ path.start(Geom::Point(bbox_procesed->left(), bbox_procesed->top()));
+ path.appendNew<Geom::LineSegment>(Geom::Point(bbox_procesed->right(), bbox_procesed->top()));
+ path.appendNew<Geom::LineSegment>(Geom::Point(bbox_procesed->right(), bbox_procesed->bottom()));
+ path.appendNew<Geom::LineSegment>(Geom::Point(bbox_procesed->left(), bbox_procesed->bottom()));
+ path.close(true);
+ sp_spray_transform_path(item, path, Geom::Scale(_scale), center);
+ sp_spray_transform_path(item, path, Geom::Scale(scale), center);
+ sp_spray_transform_path(item, path, Geom::Rotate(angle), center);
+ path *= Geom::Translate(move);
+ path *= desktop->doc2dt();
+ bbox_procesed = path.boundsFast();
+ double bbox_left_main = bbox_procesed->left();
+ double bbox_right_main = bbox_procesed->right();
+ double bbox_top_main = bbox_procesed->top();
+ double bbox_bottom_main = bbox_procesed->bottom();
+ double width_transformed = bbox_procesed->width();
+ double height_transformed = bbox_procesed->height();
+ Geom::Point mid_point = desktop->d2w(bbox_procesed->midpoint());
+ Geom::IntRect area = Geom::IntRect::from_xywh(floor(mid_point[Geom::X]), floor(mid_point[Geom::Y]), 1, 1);
+ guint32 rgba = getPickerData(area);
+ guint32 rgba2 = 0xffffff00;
+ Geom::Rect rect_sprayed(desktop->d2w(Geom::Point(bbox_left_main,bbox_top_main)), desktop->d2w(Geom::Point(bbox_right_main,bbox_bottom_main)));
+ if (!rect_sprayed.hasZeroArea()) {
+ rgba2 = getPickerData(rect_sprayed.roundOutwards());
+ }
+ if(pick_no_overlap) {
+ if(rgba != rgba2) {
+ if(mode != SPRAY_MODE_ERASER) {
+ return false;
+ }
+ }
+ }
+ if(!pick_center) {
+ rgba = rgba2;
+ }
+ if(!over_transparent && (SP_RGBA32_A_F(rgba) == 0 || SP_RGBA32_A_F(rgba) < 1e-6)) {
+ if(mode != SPRAY_MODE_ERASER) {
+ return false;
+ }
+ }
+ if(!over_no_transparent && SP_RGBA32_A_F(rgba) > 0) {
+ if(mode != SPRAY_MODE_ERASER) {
+ return false;
+ }
+ }
+ if(offset < 100 ) {
+ offset_width = ((99.0 - offset) * width_transformed)/100.0 - width_transformed;
+ offset_height = ((99.0 - offset) * height_transformed)/100.0 - height_transformed;
+ } else {
+ offset_width = 0;
+ offset_height = 0;
+ }
+ std::vector<SPItem*> items_down = desktop->getDocument()->getItemsPartiallyInBox(desktop->dkey, *bbox_procesed);
+ Inkscape::Selection *selection = desktop->getSelection();
+ if (selection->isEmpty()) {
+ return false;
+ }
+ std::vector<SPItem*> const items_selected(selection->itemList());
+ std::vector<SPItem*> items_down_erased;
+ for (std::vector<SPItem*>::const_iterator i=items_down.begin(); i!=items_down.end(); ++i) {
+ SPItem *item_down = *i;
+ Geom::OptRect bbox_down = item_down->documentVisualBounds();
+ double bbox_left = bbox_down->left();
+ double bbox_top = bbox_down->top();
+ gchar const * item_down_sharp = g_strdup_printf("#%s", item_down->getId());
+ items_down_erased.push_back(item_down);
+ for (std::vector<SPItem*>::const_iterator j=items_selected.begin(); j!=items_selected.end(); ++j) {
+ SPItem *item_selected = *j;
+ gchar const * spray_origin;
+ if(!item_selected->getAttribute("inkscape:spray-origin")){
+ spray_origin = g_strdup_printf("#%s", item_selected->getId());
+ } else {
+ spray_origin = item_selected->getAttribute("inkscape:spray-origin");
+ }
+ if(strcmp(item_down_sharp, spray_origin) == 0 ||
+ (item_down->getAttribute("inkscape:spray-origin") &&
+ strcmp(item_down->getAttribute("inkscape:spray-origin"),spray_origin) == 0 ))
+ {
+ if(mode == SPRAY_MODE_ERASER) {
+ if(strcmp(item_down_sharp, spray_origin) != 0 && !selection->includes(item_down) ){
+ item_down->deleteObject();
+ items_down_erased.pop_back();
+ break;
+ }
+ } else if(no_overlap) {
+ if(!(offset_width < 0 && offset_height < 0 && std::abs(bbox_left - bbox_left_main) > std::abs(offset_width) &&
+ std::abs(bbox_top - bbox_top_main) > std::abs(offset_height))){
+ if(!no_overlap && (picker || over_transparent || over_no_transparent)){
+ showHidden(items_down);
+ }
+ return false;
+ }
+ } else if(picker || over_transparent || over_no_transparent) {
+ item_down->setHidden(true);
+ item_down->updateRepr();
+ }
+ }
+ }
+ }
+ if(mode == SPRAY_MODE_ERASER){
+ if(!no_overlap && (picker || over_transparent || over_no_transparent)){
+ showHidden(items_down_erased);
+ }
+ return false;
+ }
+ if(picker || over_transparent || over_no_transparent){
+ if(!no_overlap){
+ doc->ensureUpToDate();
+ rgba = getPickerData(area);
+ if (!rect_sprayed.hasZeroArea()) {
+ rgba2 = getPickerData(rect_sprayed.roundOutwards());
+ }
+ }
+ if(pick_no_overlap){
+ if(rgba != rgba2){
+ if(!no_overlap && (picker || over_transparent || over_no_transparent)){
+ showHidden(items_down);
+ }
+ return false;
+ }
+ }
+ if(!pick_center){
+ rgba = rgba2;
+ }
+ double opacity = 1.0;
+ gchar color_string[32]; *color_string = 0;
+ float r = SP_RGBA32_R_F(rgba);
+ float g = SP_RGBA32_G_F(rgba);
+ float b = SP_RGBA32_B_F(rgba);
+ float a = SP_RGBA32_A_F(rgba);
+ if(!over_transparent && (a == 0 || a < 1e-6)){
+ if(!no_overlap && (picker || over_transparent || over_no_transparent)){
+ showHidden(items_down);
+ }
+ return false;
+ }
+ if(!over_no_transparent && a > 0){
+ if(!no_overlap && (picker || over_transparent || over_no_transparent)){
+ showHidden(items_down);
+ }
+ return false;
+ }
+
+ if(picker && do_trace){
+ float hsl[3];
+ sp_color_rgb_to_hsl_floatv (hsl, r, g, b);
+
+ gdouble val = 0;
+ switch (pick) {
+ case PICK_COLOR:
+ val = 1 - hsl[2]; // inverse lightness; to match other picks where black = max
+ break;
+ case PICK_OPACITY:
+ val = a;
+ break;
+ case PICK_R:
+ val = r;
+ break;
+ case PICK_G:
+ val = g;
+ break;
+ case PICK_B:
+ val = b;
+ break;
+ case PICK_H:
+ val = hsl[0];
+ break;
+ case PICK_S:
+ val = hsl[1];
+ break;
+ case PICK_L:
+ val = 1 - hsl[2];
+ break;
+ default:
+ break;
+ }
+
+ if (rand_picked > 0) {
+ val = randomize01 (val, rand_picked);
+ r = randomize01 (r, rand_picked);
+ g = randomize01 (g, rand_picked);
+ b = randomize01 (b, rand_picked);
+ }
+
+ if (gamma_picked != 0) {
+ double power;
+ if (gamma_picked > 0)
+ power = 1/(1 + fabs(gamma_picked));
+ else
+ power = 1 + fabs(gamma_picked);
+
+ val = pow (val, power);
+ r = pow ((double)r, (double)power);
+ g = pow ((double)g, (double)power);
+ b = pow ((double)b, (double)power);
+ }
+
+ if (invert_picked) {
+ val = 1 - val;
+ r = 1 - r;
+ g = 1 - g;
+ b = 1 - b;
+ }
+
+ val = CLAMP (val, 0, 1);
+ r = CLAMP (r, 0, 1);
+ g = CLAMP (g, 0, 1);
+ b = CLAMP (b, 0, 1);
+
+ // recompose tweaked color
+ rgba = SP_RGBA32_F_COMPOSE(r, g, b, a);
+ if (pick_to_size) {
+ if(!trace_scale){
+ if(pick_inverse_value) {
+ _scale = 1.0 - val;
+ } else {
+ _scale = val;
+ }
+ if(_scale == 0.0) {
+ if(!no_overlap && (picker || over_transparent || over_no_transparent)){
+ showHidden(items_down);
+ }
+ return false;
+ }
+ if(!fit_item(desktop
+ , item
+ , bbox
+ , move
+ , center
+ , mode
+ , angle
+ , _scale
+ , scale
+ , picker
+ , pick_center
+ , pick_inverse_value
+ , pick_fill
+ , pick_stroke
+ , pick_no_overlap
+ , over_no_transparent
+ , over_transparent
+ , no_overlap
+ , offset
+ , css
+ , true
+ , pick
+ , do_trace
+ , pick_to_size
+ , pick_to_presence
+ , pick_to_color
+ , pick_to_opacity
+ , invert_picked
+ , gamma_picked
+ , rand_picked)
+ )
+ {
+ if(!no_overlap && (picker || over_transparent || over_no_transparent)){
+ showHidden(items_down);
+ }
+ return false;
+ }
+ }
+ }
+
+ if (pick_to_opacity) {
+ if(pick_inverse_value) {
+ opacity *= 1.0 - val;
+ } else {
+ opacity *= val;
+ }
+ std::stringstream opacity_str;
+ opacity_str.imbue(std::locale::classic());
+ opacity_str << opacity;
+ sp_repr_css_set_property(css, "opacity", opacity_str.str().c_str());
+ }
+ if (pick_to_presence) {
+ if (g_random_double_range (0, 1) > val) {
+ //Hidding the element is a way to retain original
+ //behaviour of tiled clones for presence option.
+ sp_repr_css_set_property(css, "opacity", "0");
+ }
+ }
+ if (pick_to_color) {
+ sp_svg_write_color(color_string, sizeof(color_string), rgba);
+ if(pick_fill){
+ sp_repr_css_set_property(css, "fill", color_string);
+ }
+ if(pick_stroke){
+ sp_repr_css_set_property(css, "stroke", color_string);
+ }
+ }
+ if (opacity < 1e-6) { // invisibly transparent, skip
+ if(!no_overlap && (picker || over_transparent || over_no_transparent)){
+ showHidden(items_down);
+ }
+ return false;
+ }
+ }
+ if(!do_trace){
+ if(!pick_center){
+ rgba = rgba2;
+ }
+ if (pick_inverse_value) {
+ r = 1 - SP_RGBA32_R_F(rgba);
+ g = 1 - SP_RGBA32_G_F(rgba);
+ b = 1 - SP_RGBA32_B_F(rgba);
+ } else {
+ r = SP_RGBA32_R_F(rgba);
+ g = SP_RGBA32_G_F(rgba);
+ b = SP_RGBA32_B_F(rgba);
+ }
+ rgba = SP_RGBA32_F_COMPOSE(r, g, b, a);
+ sp_svg_write_color(color_string, sizeof(color_string), rgba);
+ if(pick_fill){
+ sp_repr_css_set_property(css, "fill", color_string);
+ }
+ if(pick_stroke){
+ sp_repr_css_set_property(css, "stroke", color_string);
+ }
+ }
+ if(!no_overlap && (picker || over_transparent || over_no_transparent)){
+ showHidden(items_down);
+ }
+ }
+ return true;
+}
+
static bool sp_spray_recursive(SPDesktop *desktop,
Inkscape::Selection *selection,
SPItem *item,
@@ -348,7 +877,28 @@ static bool sp_spray_recursive(SPDesktop *desktop,
double ratio,
double tilt,
double rotation_variation,
- gint _distrib)
+ gint _distrib,
+ bool no_overlap,
+ bool picker,
+ bool pick_center,
+ bool pick_inverse_value,
+ bool pick_fill,
+ bool pick_stroke,
+ bool pick_no_overlap,
+ bool over_no_transparent,
+ bool over_transparent,
+ double offset,
+ bool usepressurescale,
+ double pressure,
+ int pick,
+ bool do_trace,
+ bool pick_to_size,
+ bool pick_to_presence,
+ bool pick_to_color,
+ bool pick_to_opacity,
+ bool invert_picked,
+ double gamma_picked ,
+ double rand_picked)
{
bool did = false;
@@ -364,34 +914,83 @@ static bool sp_spray_recursive(SPDesktop *desktop,
double _fid = g_random_double_range(0, 1);
double angle = g_random_double_range( - rotation_variation / 100.0 * M_PI , rotation_variation / 100.0 * M_PI );
double _scale = g_random_double_range( 1.0 - scale_variation / 100.0, 1.0 + scale_variation / 100.0 );
+ if(usepressurescale){
+ _scale = pressure;
+ }
double dr; double dp;
random_position( dr, dp, mean, standard_deviation, _distrib );
dr=dr*radius;
- if (mode == SPRAY_MODE_COPY) {
+ if (mode == SPRAY_MODE_COPY || mode == SPRAY_MODE_ERASER) {
Geom::OptRect a = item->documentVisualBounds();
if (a) {
- SPItem *item_copied;
if(_fid <= population)
{
- // Duplicate
SPDocument *doc = item->document;
+ gchar const * spray_origin;
+ if(!item->getAttribute("inkscape:spray-origin")){
+ spray_origin = g_strdup_printf("#%s", item->getId());
+ } else {
+ spray_origin = item->getAttribute("inkscape:spray-origin");
+ }
+ Geom::Point center = item->getCenter();
+ Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ if(mode == SPRAY_MODE_ERASER || no_overlap || picker || !over_transparent || !over_no_transparent){
+ if(!fit_item(desktop
+ , item
+ , a
+ , move
+ , center
+ , mode
+ , angle
+ , _scale
+ , scale
+ , picker
+ , pick_center
+ , pick_inverse_value
+ , pick_fill
+ , pick_stroke
+ , pick_no_overlap
+ , over_no_transparent
+ , over_transparent
+ , no_overlap
+ , offset
+ , css
+ , false
+ , pick
+ , do_trace
+ , pick_to_size
+ , pick_to_presence
+ , pick_to_color
+ , pick_to_opacity
+ , invert_picked
+ , gamma_picked
+ , rand_picked)){
+ return false;
+ }
+ }
+ SPItem *item_copied;
+ // Duplicate
Inkscape::XML::Document* xml_doc = doc->getReprDoc();
Inkscape::XML::Node *old_repr = item->getRepr();
Inkscape::XML::Node *parent = old_repr->parent();
Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
+ if(!copy->attribute("inkscape:spray-origin")){
+ copy->setAttribute("inkscape:spray-origin", spray_origin);
+ }
parent->appendChild(copy);
-
SPObject *new_obj = doc->getObjectByRepr(copy);
item_copied = dynamic_cast<SPItem *>(new_obj); // Conversion object->item
- Geom::Point center=item->getCenter();
- sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(_scale,_scale));
- sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(scale,scale));
-
+ sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(_scale));
+ sp_spray_scale_rel(center,desktop, item_copied, Geom::Scale(scale));
sp_spray_rotate_rel(center,desktop,item_copied, Geom::Rotate(angle));
// Move the cursor p
- Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());
sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
+ Inkscape::GC::release(copy);
+ if(picker){
+ sp_desktop_apply_css_recursive(item_copied, css, true);
+ }
did = true;
}
}
@@ -404,7 +1003,7 @@ static bool sp_spray_recursive(SPDesktop *desktop,
int i=1;
std::vector<SPItem*> items=selection->itemList();
- for(std::vector<SPItem*>::const_iterator it=items.begin();it!=items.end();it++){
+ for(std::vector<SPItem*>::const_iterator it=items.begin();it!=items.end(); ++it){
SPItem *item1 = *it;
if (i == 1) {
parent_item = item1;
@@ -425,6 +1024,13 @@ static bool sp_spray_recursive(SPDesktop *desktop,
if (_fid <= population) { // Rules the population of objects sprayed
// Duplicates the parent item
Inkscape::XML::Node *copy = old_repr->duplicate(xml_doc);
+ gchar const * spray_origin;
+ if(!copy->attribute("inkscape:spray-origin")){
+ spray_origin = g_strdup_printf("#%s", old_repr->attribute("id"));
+ copy->setAttribute("inkscape:spray-origin", spray_origin);
+ } else {
+ spray_origin = copy->attribute("inkscape:spray-origin");
+ }
parent->appendChild(copy);
SPObject *new_obj = doc->getObjectByRepr(copy);
item_copied = dynamic_cast<SPItem *>(new_obj);
@@ -456,8 +1062,52 @@ static bool sp_spray_recursive(SPDesktop *desktop,
Geom::OptRect a = item->documentVisualBounds();
if (a) {
if(_fid <= population) {
- SPItem *item_copied;
SPDocument *doc = item->document;
+ gchar const * spray_origin;
+ if(!item->getAttribute("inkscape:spray-origin")){
+ spray_origin = g_strdup_printf("#%s", item->getId());
+ } else {
+ spray_origin = item->getAttribute("inkscape:spray-origin");
+ }
+ Geom::Point center=item->getCenter();
+ Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());
+ SPCSSAttr *css = sp_repr_css_attr_new();
+ if(mode == SPRAY_MODE_ERASER || no_overlap || picker || !over_transparent || !over_no_transparent){
+ if(!fit_item(desktop
+ , item
+ , a
+ , move
+ , center
+ , mode
+ , angle
+ , _scale
+ , scale
+ , picker
+ , pick_center
+ , pick_inverse_value
+ , pick_fill
+ , pick_stroke
+ , pick_no_overlap
+ , over_no_transparent
+ , over_transparent
+ , no_overlap
+ , offset
+ , css
+ , true
+ , pick
+ , do_trace
+ , pick_to_size
+ , pick_to_presence
+ , pick_to_color
+ , pick_to_opacity
+ , invert_picked
+ , gamma_picked
+ , rand_picked))
+ {
+ return false;
+ }
+ }
+ SPItem *item_copied;
Inkscape::XML::Document* xml_doc = doc->getReprDoc();
Inkscape::XML::Node *old_repr = item->getRepr();
Inkscape::XML::Node *parent = old_repr->parent();
@@ -467,6 +1117,9 @@ static bool sp_spray_recursive(SPDesktop *desktop,
// Ad the clone to the list of the parent's children
parent->appendChild(clone);
// Generates the link between parent and child attributes
+ if(!clone->attribute("inkscape:spray-origin")){
+ clone->setAttribute("inkscape:spray-origin", spray_origin);
+ }
gchar *href_str = g_strdup_printf("#%s", old_repr->attribute("id"));
clone->setAttribute("xlink:href", href_str, false);
g_free(href_str);
@@ -474,15 +1127,14 @@ static bool sp_spray_recursive(SPDesktop *desktop,
SPObject *clone_object = doc->getObjectByRepr(clone);
// Conversion object->item
item_copied = dynamic_cast<SPItem *>(clone_object);
- Geom::Point center = item->getCenter();
sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(_scale, _scale));
sp_spray_scale_rel(center, desktop, item_copied, Geom::Scale(scale, scale));
sp_spray_rotate_rel(center, desktop, item_copied, Geom::Rotate(angle));
- Geom::Point move = (Geom::Point(cos(tilt)*cos(dp)*dr/(1-ratio)+sin(tilt)*sin(dp)*dr/(1+ratio), -sin(tilt)*cos(dp)*dr/(1-ratio)+cos(tilt)*sin(dp)*dr/(1+ratio)))+(p-a->midpoint());
sp_item_move_rel(item_copied, Geom::Translate(move[Geom::X], -move[Geom::Y]));
-
+ if(picker){
+ sp_desktop_apply_css_recursive(item_copied, css, true);
+ }
Inkscape::GC::release(clone);
-
did = true;
}
}
@@ -520,22 +1172,57 @@ static bool sp_spray_dilate(SprayTool *tc, Geom::Point /*event_p*/, Geom::Point
{
std::vector<SPItem*> const items(selection->itemList());
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){
SPItem *item = *i;
g_assert(item != NULL);
sp_object_ref(item);
}
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){
SPItem *item = *i;
g_assert(item != NULL);
-
- if (sp_spray_recursive(desktop, selection, item, p, vector, tc->mode, radius, population, tc->scale, tc->scale_variation, reverse, move_mean, move_standard_deviation, tc->ratio, tc->tilt, tc->rotation_variation, tc->distrib)) {
+ if (sp_spray_recursive(desktop
+ , selection
+ , item
+ , p, vector
+ , tc->mode
+ , radius
+ , population
+ , tc->scale
+ , tc->scale_variation
+ , reverse
+ , move_mean
+ , move_standard_deviation
+ , tc->ratio
+ , tc->tilt
+ , tc->rotation_variation
+ , tc->distrib
+ , tc->no_overlap
+ , tc->picker
+ , tc->pick_center
+ , tc->pick_inverse_value
+ , tc->pick_fill
+ , tc->pick_stroke
+ , tc->pick_no_overlap
+ , tc->over_no_transparent
+ , tc->over_transparent
+ , tc->offset
+ , tc->usepressurescale
+ , get_pressure(tc)
+ , tc->pick
+ , tc->do_trace
+ , tc->pick_to_size
+ , tc->pick_to_presence
+ , tc->pick_to_color
+ , tc->pick_to_opacity
+ , tc->invert_picked
+ , tc->gamma_picked
+ , tc->rand_picked)) {
did = true;
}
}
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){
SPItem *item = *i;
g_assert(item != NULL);
sp_object_unref(item);
@@ -577,7 +1264,7 @@ bool SprayTool::root_handler(GdkEvent* event) {
if (Inkscape::have_viable_layer(desktop, this->message_context) == false) {
return TRUE;
}
-
+ this->setCloneTilerPrefs();
Geom::Point const motion_w(event->button.x, event->button.y);
Geom::Point const motion_dt(desktop->w2d(motion_w));
this->last_push = desktop->dt2doc(motion_dt);
diff --git a/src/ui/tools/spray-tool.h b/src/ui/tools/spray-tool.h
index 8df730201..c81110b37 100644
--- a/src/ui/tools/spray-tool.h
+++ b/src/ui/tools/spray-tool.h
@@ -12,6 +12,7 @@
* Benoît LAVORATA
* Vincent MONTAGNE
* Pierre BARBRY-BLOT
+ * Jabiertxo ARRAIZA
*
* Copyright (C) 2009 authors
*
@@ -46,7 +47,8 @@ namespace Tools {
enum {
SPRAY_MODE_COPY,
SPRAY_MODE_CLONE,
- SPRAY_MODE_SINGLE_PATH,
+ SPRAY_MODE_SINGLE_PATH,
+ SPRAY_MODE_ERASER,
SPRAY_OPTION,
};
@@ -62,7 +64,9 @@ public:
/* attributes */
bool dragging; /* mouse state: mouse is dragging */
- bool usepressure;
+ bool usepressurewidth;
+ bool usepressurepopulation;
+ bool usepressurescale;
bool usetilt;
bool usetext;
@@ -86,13 +90,32 @@ public:
bool has_dilated;
Geom::Point last_push;
SPCanvasItem *dilate_area;
-
+ bool no_overlap;
+ bool picker;
+ bool pick_center;
+ bool pick_inverse_value;
+ bool pick_fill;
+ bool pick_stroke;
+ bool pick_no_overlap;
+ bool over_transparent;
+ bool over_no_transparent;
+ double offset;
+ int pick;
+ bool do_trace;
+ bool pick_to_size;
+ bool pick_to_presence;
+ bool pick_to_color;
+ bool pick_to_opacity;
+ bool invert_picked;
+ double gamma_picked;
+ double rand_picked;
sigc::connection style_set_connection;
static const std::string prefsPath;
virtual void setup();
virtual void set(const Inkscape::Preferences::Entry& val);
+ virtual void setCloneTilerPrefs();
virtual bool root_handler(GdkEvent* event);
virtual const std::string& getPrefsPath();
diff --git a/src/ui/tools/tool-base.cpp b/src/ui/tools/tool-base.cpp
index 0f9b3ee7a..abac2c091 100644
--- a/src/ui/tools/tool-base.cpp
+++ b/src/ui/tools/tool-base.cpp
@@ -358,7 +358,7 @@ bool ToolBase::root_handler(GdkEvent* event) {
/// @todo REmove redundant /value in preference keys
tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100);
-
+ bool allow_panning = prefs->getBool("/options/spacebarpans/value");
gint ret = FALSE;
switch (event->type) {
@@ -582,7 +582,6 @@ bool ToolBase::root_handler(GdkEvent* event) {
case GDK_KEY_PRESS: {
double const acceleration = prefs->getDoubleLimited(
"/options/scrollingacceleration/value", 0, 0, 6);
-
int const key_scroll = prefs->getIntLimited("/options/keyscroll/value",
10, 0, 1000);
@@ -692,10 +691,10 @@ bool ToolBase::root_handler(GdkEvent* event) {
break;
case GDK_KEY_space:
- xp = yp = 0;
within_tolerance = true;
+ xp = yp = 0;
+ if (!allow_panning) break;
panning = 4;
-
this->space_panning = true;
this->message_context->set(Inkscape::INFORMATION_MESSAGE,
_("<b>Space+mouse move</b> to pan canvas"));
@@ -742,7 +741,7 @@ bool ToolBase::root_handler(GdkEvent* event) {
switch (get_group0_keyval(&event->key)) {
case GDK_KEY_space:
- if (within_tolerance == true) {
+ if (within_tolerance) {
// Space was pressed, but not panned
sp_toggle_selector(desktop);
@@ -925,7 +924,7 @@ void ToolBase::enableGrDrag(bool enable) {
*/
bool ToolBase::deleteSelectedDrag(bool just_one) {
- if (_grdrag && _grdrag->selected) {
+ if (_grdrag && !_grdrag->selected.empty()) {
_grdrag->deleteSelected(just_one);
return TRUE;
}
diff --git a/src/ui/tools/tool-base.h b/src/ui/tools/tool-base.h
index 7a6ab83e7..58eb6f88e 100644
--- a/src/ui/tools/tool-base.h
+++ b/src/ui/tools/tool-base.h
@@ -75,7 +75,12 @@ public:
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
double value = prefs->getDoubleLimited("/options/snapdelay/value", 0, 0, 1000);
- _timer_id = g_timeout_add(value, &sp_event_context_snap_watchdog_callback, this);
+ // We used to have this specified in milliseconds; this has changed to seconds now for consistency's sake
+ if (value > 1) { // Apparently we have an old preference file, this value must have been in milliseconds;
+ value = value / 1000.0; // now convert this value to seconds
+ }
+
+ _timer_id = g_timeout_add(value*1000.0, &sp_event_context_snap_watchdog_callback, this);
_event = gdk_event_copy((GdkEvent*) event);
((GdkEventMotion *)_event)->time = GDK_CURRENT_TIME;
diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp
index 94f7aa135..39a7a3f0b 100644
--- a/src/ui/tools/tweak-tool.cpp
+++ b/src/ui/tools/tweak-tool.cpp
@@ -1077,7 +1077,7 @@ sp_tweak_dilate (TweakTool *tc, Geom::Point event_p, Geom::Point p, Geom::Point
double color_force = MIN(sqrt(path_force)/20.0, 1);
std::vector<SPItem*> items=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){
SPItem *item = *i;
if (is_color_mode (tc->mode)) {
diff --git a/src/ui/tools/zoom-tool.cpp b/src/ui/tools/zoom-tool.cpp
index 6a4d4dbbd..13e097c18 100644
--- a/src/ui/tools/zoom-tool.cpp
+++ b/src/ui/tools/zoom-tool.cpp
@@ -142,7 +142,7 @@ bool ZoomTool::root_handler(GdkEvent* event) {
if ( event->button.button == 1 && !this->space_panning) {
Geom::OptRect const b = Inkscape::Rubberband::get(desktop)->getRectangle();
- if (b && !within_tolerance) {
+ if (b && !within_tolerance && !(GDK_SHIFT_MASK & event->button.state) ) {
desktop->set_display_area(*b, 10);
} else if (!escaped) {
double const zoom_rel( (event->button.state & GDK_SHIFT_MASK)
diff --git a/src/ui/uxmanager.cpp b/src/ui/uxmanager.cpp
index 051df691e..036659661 100644
--- a/src/ui/uxmanager.cpp
+++ b/src/ui/uxmanager.cpp
@@ -244,12 +244,13 @@ void UXManagerImpl::delTrack( SPDesktopWidget* dtw )
void UXManagerImpl::connectToDesktop( vector<GtkWidget *> const & toolboxes, SPDesktop *desktop )
{
- TrackItem &tracker = trackedBoxes[desktop];
- vector<GtkWidget*>& tracked = tracker.boxes;
- if (desktop)
+ if (!desktop)
{
- tracker.destroyConn = desktop->connectDestroy(&desktopDestructHandler);
+ return;
}
+ TrackItem &tracker = trackedBoxes[desktop];
+ vector<GtkWidget*>& tracked = tracker.boxes;
+ tracker.destroyConn = desktop->connectDestroy(&desktopDestructHandler);
for (vector<GtkWidget*>::const_iterator it = toolboxes.begin(); it != toolboxes.end(); ++it ) {
GtkWidget* toolbox = *it;
diff --git a/src/ui/view/edit-widget-interface.h b/src/ui/view/edit-widget-interface.h
index 55683871d..fcba0c6da 100644
--- a/src/ui/view/edit-widget-interface.h
+++ b/src/ui/view/edit-widget-interface.h
@@ -116,6 +116,9 @@ struct EditWidgetInterface
/// Toggle CMS on/off and set preference value accordingly
virtual void toggleColorProfAdjust() = 0;
+ /// Toggle lock guides on/off and set namedview value accordingly
+ virtual void toggleGuidesLock() = 0;
+
/// Is CMS on/off
virtual bool colorProfAdjustEnabled() = 0;
diff --git a/src/ui/widget/color-entry.h b/src/ui/widget/color-entry.h
index edabe1980..08537f26d 100644
--- a/src/ui/widget/color-entry.h
+++ b/src/ui/widget/color-entry.h
@@ -9,7 +9,7 @@
*/
#ifndef SEEN_COLOR_ENTRY_H
-#define SEEN_COLOR_ENTRY_H_
+#define SEEN_COLOR_ENTRY_H
#include <gtkmm/entry.h>
#include "ui/selected-color.h"
diff --git a/src/ui/widget/color-icc-selector.cpp b/src/ui/widget/color-icc-selector.cpp
index 1c31ae33a..2fe4a0704 100644
--- a/src/ui/widget/color-icc-selector.cpp
+++ b/src/ui/widget/color-icc-selector.cpp
@@ -676,9 +676,9 @@ void ColorICCSelectorImpl::_profilesChanged(std::string const &name)
gtk_combo_box_set_active(combo, 0);
int index = 1;
- const GSList *current = SP_ACTIVE_DOCUMENT->getResourceList("iccprofile");
- while (current) {
- SPObject *obj = SP_OBJECT(current->data);
+ std::set<SPObject *> current = SP_ACTIVE_DOCUMENT->getResourceList("iccprofile");
+ for (std::set<SPObject *>::const_iterator it = current.begin(); it != current.end(); ++it) {
+ SPObject *obj = *it;
Inkscape::ColorProfile *prof = reinterpret_cast<Inkscape::ColorProfile *>(obj);
gtk_list_store_append(store, &iter);
@@ -690,7 +690,6 @@ void ColorICCSelectorImpl::_profilesChanged(std::string const &name)
}
index++;
- current = g_slist_next(current);
}
g_signal_handler_unblock(G_OBJECT(_profileSel), _profChangedID);
diff --git a/src/ui/widget/font-variants.cpp b/src/ui/widget/font-variants.cpp
index 5d1e40971..62598dead 100644
--- a/src/ui/widget/font-variants.cpp
+++ b/src/ui/widget/font-variants.cpp
@@ -35,41 +35,41 @@ namespace Widget {
FontVariants::FontVariants () :
Gtk::VBox (),
- _ligatures_frame ( Glib::ustring(_("Ligatures" )) ),
- _ligatures_common ( Glib::ustring(_("Common" )) ),
- _ligatures_discretionary ( Glib::ustring(_("Discretionary")) ),
- _ligatures_historical ( Glib::ustring(_("Historical" )) ),
- _ligatures_contextual ( Glib::ustring(_("Contextual" )) ),
-
- _position_frame ( Glib::ustring(_("Position" )) ),
- _position_normal ( Glib::ustring(_("Normal" )) ),
- _position_sub ( Glib::ustring(_("Subscript" )) ),
- _position_super ( Glib::ustring(_("Superscript" )) ),
-
- _caps_frame ( Glib::ustring(_("Capitals" )) ),
- _caps_normal ( Glib::ustring(_("Normal" )) ),
- _caps_small ( Glib::ustring(_("Small" )) ),
- _caps_all_small ( Glib::ustring(_("All small" )) ),
- _caps_petite ( Glib::ustring(_("Petite" )) ),
- _caps_all_petite ( Glib::ustring(_("All petite" )) ),
- _caps_unicase ( Glib::ustring(_("Unicase" )) ),
- _caps_titling ( Glib::ustring(_("Titling" )) ),
-
- _numeric_frame ( Glib::ustring(_("Numeric" )) ),
- _numeric_lining ( Glib::ustring(_("Lining" )) ),
- _numeric_old_style ( Glib::ustring(_("Old Style" )) ),
- _numeric_default_style ( Glib::ustring(_("Default Style")) ),
- _numeric_proportional ( Glib::ustring(_("Proportional" )) ),
- _numeric_tabular ( Glib::ustring(_("Tabular" )) ),
- _numeric_default_width ( Glib::ustring(_("Default Width")) ),
- _numeric_diagonal ( Glib::ustring(_("Diagonal" )) ),
- _numeric_stacked ( Glib::ustring(_("Stacked" )) ),
- _numeric_default_fractions( Glib::ustring(_("Default Fractions")) ),
- _numeric_ordinal ( Glib::ustring(_("Ordinal" )) ),
- _numeric_slashed_zero ( Glib::ustring(_("Slashed Zero" )) ),
-
- _feature_frame ( Glib::ustring(_("Feature Settings")) ),
- _feature_label ( Glib::ustring(_("Selection has different Feature Settings!")) ),
+ _ligatures_frame ( Glib::ustring(C_("Font variant", "Ligatures" )) ),
+ _ligatures_common ( Glib::ustring(C_("Font variant", "Common" )) ),
+ _ligatures_discretionary ( Glib::ustring(C_("Font variant", "Discretionary")) ),
+ _ligatures_historical ( Glib::ustring(C_("Font variant", "Historical" )) ),
+ _ligatures_contextual ( Glib::ustring(C_("Font variant", "Contextual" )) ),
+
+ _position_frame ( Glib::ustring(C_("Font variant", "Position" )) ),
+ _position_normal ( Glib::ustring(C_("Font variant", "Normal" )) ),
+ _position_sub ( Glib::ustring(C_("Font variant", "Subscript" )) ),
+ _position_super ( Glib::ustring(C_("Font variant", "Superscript" )) ),
+
+ _caps_frame ( Glib::ustring(C_("Font variant", "Capitals" )) ),
+ _caps_normal ( Glib::ustring(C_("Font variant", "Normal" )) ),
+ _caps_small ( Glib::ustring(C_("Font variant", "Small" )) ),
+ _caps_all_small ( Glib::ustring(C_("Font variant", "All small" )) ),
+ _caps_petite ( Glib::ustring(C_("Font variant", "Petite" )) ),
+ _caps_all_petite ( Glib::ustring(C_("Font variant", "All petite" )) ),
+ _caps_unicase ( Glib::ustring(C_("Font variant", "Unicase" )) ),
+ _caps_titling ( Glib::ustring(C_("Font variant", "Titling" )) ),
+
+ _numeric_frame ( Glib::ustring(C_("Font variant", "Numeric" )) ),
+ _numeric_lining ( Glib::ustring(C_("Font variant", "Lining" )) ),
+ _numeric_old_style ( Glib::ustring(C_("Font variant", "Old Style" )) ),
+ _numeric_default_style ( Glib::ustring(C_("Font variant", "Default Style")) ),
+ _numeric_proportional ( Glib::ustring(C_("Font variant", "Proportional" )) ),
+ _numeric_tabular ( Glib::ustring(C_("Font variant", "Tabular" )) ),
+ _numeric_default_width ( Glib::ustring(C_("Font variant", "Default Width")) ),
+ _numeric_diagonal ( Glib::ustring(C_("Font variant", "Diagonal" )) ),
+ _numeric_stacked ( Glib::ustring(C_("Font variant", "Stacked" )) ),
+ _numeric_default_fractions( Glib::ustring(C_("Font variant", "Default Fractions")) ),
+ _numeric_ordinal ( Glib::ustring(C_("Font variant", "Ordinal" )) ),
+ _numeric_slashed_zero ( Glib::ustring(C_("Font variant", "Slashed Zero" )) ),
+
+ _feature_frame ( Glib::ustring(C_("Font variant", "Feature Settings")) ),
+ _feature_label ( Glib::ustring(C_("Font variant", "Selection has different Feature Settings!")) ),
_ligatures_changed( false ),
_position_changed( false ),
diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp
index 72597e4d9..e906762e3 100644
--- a/src/ui/widget/preferences-widget.cpp
+++ b/src/ui/widget/preferences-widget.cpp
@@ -205,6 +205,7 @@ void PrefCheckButton::init(Glib::ustring const &label, Glib::ustring const &pref
void PrefCheckButton::on_toggled()
{
+ this->changed_signal.emit(this->get_active());
if (this->get_visible()) //only take action if the user toggled it
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
diff --git a/src/ui/widget/preferences-widget.h b/src/ui/widget/preferences-widget.h
index 8b75b8368..1d2d77699 100644
--- a/src/ui/widget/preferences-widget.h
+++ b/src/ui/widget/preferences-widget.h
@@ -59,6 +59,7 @@ class PrefCheckButton : public Gtk::CheckButton
public:
void init(Glib::ustring const &label, Glib::ustring const &prefs_path,
bool default_value);
+ sigc::signal<void, bool> changed_signal;
protected:
Glib::ustring _prefs_path;
void on_toggled();
diff --git a/src/ui/widget/unit-tracker.cpp b/src/ui/widget/unit-tracker.cpp
index c6318db25..a1501c229 100644
--- a/src/ui/widget/unit-tracker.cpp
+++ b/src/ui/widget/unit-tracker.cpp
@@ -12,6 +12,7 @@
* Released under GNU GPL, read the file 'COPYING' for more information
*/
+#include "style-internal.h"
#include "unit-tracker.h"
#include "widgets/ege-select-one-action.h"
@@ -121,6 +122,15 @@ void UnitTracker::addUnit(Inkscape::Util::Unit const *u)
gtk_list_store_set(_store, &iter, COLUMN_STRING, u ? u->abbr.c_str() : "NULL", -1);
}
+void UnitTracker::prependUnit(Inkscape::Util::Unit const *u)
+{
+ GtkTreeIter iter;
+ gtk_list_store_prepend(_store, &iter);
+ gtk_list_store_set(_store, &iter, COLUMN_STRING, u ? u->abbr.c_str() : "NULL", -1);
+ /* Re-shuffle our default selection here (_active gets out of sync) */
+ setActiveUnit(_activeUnit);
+}
+
void UnitTracker::setFullVal(GtkAdjustment *adj, gdouble val)
{
_priorValues[adj] = val;
diff --git a/src/ui/widget/unit-tracker.h b/src/ui/widget/unit-tracker.h
index 06245930e..0fe5bda80 100644
--- a/src/ui/widget/unit-tracker.h
+++ b/src/ui/widget/unit-tracker.h
@@ -42,6 +42,7 @@ public:
Inkscape::Util::Unit const * getActiveUnit() const;
void addUnit(Inkscape::Util::Unit const *u);
+ void prependUnit(Inkscape::Util::Unit const *u);
void addAdjustment(GtkAdjustment *adj);
void setFullVal(GtkAdjustment *adj, gdouble val);
diff --git a/src/unclump.cpp b/src/unclump.cpp
index 81c958937..2c6840425 100644
--- a/src/unclump.cpp
+++ b/src/unclump.cpp
@@ -172,7 +172,7 @@ static double unclump_average (SPItem *item, std::list<SPItem*> &others)
{
int n = 0;
double sum = 0;
- for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();i++) {
+ for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();++i) {
SPItem *other = *i;
if (other == item)
@@ -196,7 +196,7 @@ static SPItem *unclump_closest (SPItem *item, std::list<SPItem*> &others)
double min = HUGE_VAL;
SPItem *closest = NULL;
- for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();i++) {
+ for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();++i) {
SPItem *other = *i;
if (other == item)
@@ -219,7 +219,7 @@ static SPItem *unclump_farest (SPItem *item, std::list<SPItem*> &others)
{
double max = -HUGE_VAL;
SPItem *farest = NULL;
- for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();i++) {
+ for (std::list<SPItem*>::const_iterator i = others.begin(); i != others.end();++i) {
SPItem *other = *i;
if (other == item)
@@ -259,7 +259,7 @@ unclump_remove_behind (SPItem *item, SPItem *closest, std::list<SPItem*> &rest)
double val_item = A * it[Geom::X] + B * it[Geom::Y] + C;
std::vector<SPItem*> out;
- for (std::list<SPItem*>::const_reverse_iterator i = rest.rbegin(); i != rest.rend();i++) {
+ for (std::list<SPItem*>::const_reverse_iterator i = rest.rbegin(); i != rest.rend();++i) {
SPItem *other = *i;
if (other == item)
@@ -336,7 +336,7 @@ unclump (std::vector<SPItem*> &items)
c_cache.clear();
wh_cache.clear();
- for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end();i++) { // for each original/clone x:
+ for (std::vector<SPItem*>::const_iterator i = items.begin(); i != items.end();++i) { // for each original/clone x:
SPItem *item = *i;
std::list<SPItem*> nei;
diff --git a/src/unclump.h b/src/unclump.h
index 461e99d0b..c6948f320 100644
--- a/src/unclump.h
+++ b/src/unclump.h
@@ -11,7 +11,6 @@
#ifndef SEEN_DIALOGS_UNCLUMP_H
#define SEEN_DIALOGS_UNCLUMP_H
-typedef struct _GSList GSList;
void unclump(std::vector<SPItem*> &items);
diff --git a/src/uri-references.cpp b/src/uri-references.cpp
index 04f904d39..db46a156f 100644
--- a/src/uri-references.cpp
+++ b/src/uri-references.cpp
@@ -19,80 +19,105 @@
#include "uri.h"
#include "uri-references.h"
#include "extract-uri.h"
-
+#include "sp-tag-use.h"
#include <glibmm/miscutils.h>
#include <sigc++/functors/mem_fun.h>
namespace Inkscape {
URIReference::URIReference(SPObject *owner)
- : _owner(owner), _owner_document(NULL), _obj(NULL), _uri(NULL)
+ : _owner(owner)
+ , _owner_document(NULL)
+ , _obj(NULL)
+ , _uri(NULL)
{
g_assert(_owner != NULL);
/* FIXME !!! attach to owner's destroy signal to clean up in case */
}
URIReference::URIReference(SPDocument *owner_document)
- : _owner(NULL), _owner_document(owner_document), _obj(NULL), _uri(NULL)
+ : _owner(NULL)
+ , _owner_document(owner_document)
+ , _obj(NULL)
+ , _uri(NULL)
{
g_assert(_owner_document != NULL);
}
-URIReference::~URIReference()
-{
- detach();
-}
+URIReference::~URIReference() { detach(); }
/*
* The main ideas here are:
* (1) "If we are inside a clone, then we can accept if and only if our "original thing" can accept the reference"
- * (this caused problems when there are clones because a change in ids triggers signals for the object hrefing this id, but also its cloned reprs
- * (descendants of <use> referencing an ancestor of the href'ing object)). The way it is done here is *atrocious*, but i could not find a better way.
+ * (this caused problems when there are clones because a change in ids triggers signals for the object hrefing this id,
+ *but also its cloned reprs
+ * (descendants of <use> referencing an ancestor of the href'ing object)). The way it is done here is *atrocious*, but i
+ *could not find a better way.
* FIXME: find a better and safer way to find the "original object" of anyone with the flag ->cloned
*
- * (2) Once we have an (potential owner) object, it can accept a href to obj, iff the graph of objects where directed edges are
+ * (2) Once we have an (potential owner) object, it can accept a href to obj, iff the graph of objects where directed
+ *edges are
* either parent->child relations , *** or href'ing to href'ed *** relations, stays acyclic.
- * We can go either from owner and up in the tree, or from obj and down, in either case this will be in the worst case linear in the number of objects.
- * There are no easy objects allowing to do the second proposition, while "hrefList" is a "list of objects href'ing us", so we'll take this.
+ * We can go either from owner and up in the tree, or from obj and down, in either case this will be in the worst case
+ *linear in the number of objects.
+ * There are no easy objects allowing to do the second proposition, while "hrefList" is a "list of objects href'ing us",
+ *so we'll take this.
* Then we keep a set of already visited elements, and do a DFS on this graph. if we find obj, then BOOM.
*/
-bool URIReference::_acceptObject(SPObject *obj) const {
- //we go back following hrefList and parent to find if the object already references ourselves indirectly
- std::set<SPObject*> done;
- SPObject * owner = getOwner();
- if(!owner)return true;
- while(owner->cloned){
- std::vector<int> positions;
- while(owner->cloned){
- int position=0;
- SPObject* c = owner->parent->firstChild();
- while(c != owner && dynamic_cast<SPObject*>(c) ){position++;c=c->next;}
- positions.push_back(position);
- owner=owner->parent;
- }
- owner = ((SPUse*)owner)->get_original();
- for(int i=positions.size()-2;i>=0;i--)owner=owner->childList(false)[positions[i]];
- }
- //once we have the "original" object (hopefully) we look at who is referencing it
- std::list<SPObject*> todo(owner->hrefList);
- todo.push_front(owner->parent);
- while(!todo.empty()){
- SPObject* e = todo.front();
- todo.pop_front();
- if(!dynamic_cast<SPObject*>(e))continue;
- if(done.insert(e).second){
- if(e==obj){return false;}
- todo.push_front(e->parent);
- todo.insert(todo.begin(),e->hrefList.begin(),e->hrefList.end());
- }
- }
+bool URIReference::_acceptObject(SPObject *obj) const
+{
+ // we go back following hrefList and parent to find if the object already references ourselves indirectly
+ std::set<SPObject *> done;
+ SPObject *owner = getOwner();
+ if (!owner)
+ return true;
+ while (owner->cloned) {
+ std::vector<int> positions;
+ while (owner->cloned) {
+ int position = 0;
+ SPObject *c = owner->parent->firstChild();
+ while (c != owner && dynamic_cast<SPObject *>(c)) {
+ position++;
+ c = c->next;
+ }
+ positions.push_back(position);
+ owner = owner->parent;
+ }
+ if (dynamic_cast<SPUse *>(owner))
+ owner = ((SPUse *)owner)->get_original();
+ else if (dynamic_cast<SPTagUse *>(owner))
+ owner = ((SPTagUse *)owner)->get_original();
+ else {
+ g_warning("cloned object with no known type\n");
+ return false;
+ }
+ for (int i = positions.size() - 2; i >= 0; i--)
+ owner = owner->childList(false)[positions[i]];
+ }
+ // once we have the "original" object (hopefully) we look at who is referencing it
+ if (obj == owner)
+ return false;
+ std::list<SPObject *> todo(owner->hrefList);
+ todo.push_front(owner->parent);
+ while (!todo.empty()) {
+ SPObject *e = todo.front();
+ todo.pop_front();
+ if (!dynamic_cast<SPObject *>(e))
+ continue;
+ if (done.insert(e).second) {
+ if (e == obj) {
+ return false;
+ }
+ todo.push_front(e->parent);
+ todo.insert(todo.begin(), e->hrefList.begin(), e->hrefList.end());
+ }
+ }
return true;
}
-
void URIReference::attach(const URI &uri) throw(BadURIException)
{
SPDocument *document = NULL;
@@ -108,32 +133,30 @@ void URIReference::attach(const URI &uri) throw(BadURIException)
// PNG and JPG files are allowed (in the case of feImage).
gchar *filename = uri.toString();
bool skip = false;
- if( g_str_has_suffix( filename, ".jpg" ) ||
- g_str_has_suffix( filename, ".JPG" ) ||
- g_str_has_suffix( filename, ".png" ) ||
- g_str_has_suffix( filename, ".PNG" ) ) {
+ if (g_str_has_suffix(filename, ".jpg") || g_str_has_suffix(filename, ".JPG") ||
+ g_str_has_suffix(filename, ".png") || g_str_has_suffix(filename, ".PNG")) {
skip = true;
}
-
+
// The path contains references to separate document files to load.
- if(document && uri.getPath() && !skip ) {
+ if (document && uri.getPath() && !skip) {
std::string base = document->getBase() ? document->getBase() : "";
std::string path = uri.getFullPath(base);
- if(!path.empty()) {
+ if (!path.empty()) {
document = document->createChildDoc(path);
} else {
document = NULL;
}
}
- if(!document) {
+ if (!document) {
g_warning("Can't get document for referenced URI: %s", filename);
- g_free( filename );
+ g_free(filename);
return;
}
- g_free( filename );
+ g_free(filename);
gchar const *fragment = uri.getFragment();
- if ( !uri.isRelative() || uri.getQuery() || !fragment ) {
+ if (!uri.isRelative() || uri.getQuery() || !fragment) {
throw UnsupportedURIException();
}
@@ -148,9 +171,9 @@ void URIReference::attach(const URI &uri) throw(BadURIException)
the strlen calculation and validity testing to before strdup, and copying just
the id without the "))". -- pjrm */
if (!strncmp(fragment, "xpointer(id(", 12)) {
- id = g_strdup(fragment+12);
+ id = g_strdup(fragment + 12);
size_t const len = strlen(id);
- if ( len < 3 || strcmp(id+len-2, "))") ) {
+ if (len < 3 || strcmp(id + len - 2, "))")) {
g_free(id);
throw MalformedURIException();
}
@@ -183,13 +206,14 @@ void URIReference::detach()
void URIReference::_setObject(SPObject *obj)
{
- if ( obj && !_acceptObject(obj) ) {
+ if (obj && !_acceptObject(obj)) {
obj = NULL;
}
- if ( obj == _obj ) return;
+ if (obj == _obj)
+ return;
- SPObject *old_obj=_obj;
+ SPObject *old_obj = _obj;
_obj = obj;
_release_connection.disconnect();
@@ -210,7 +234,7 @@ void URIReference::_setObject(SPObject *obj)
*/
void URIReference::_release(SPObject *obj)
{
- g_assert( _obj == obj );
+ g_assert(_obj == obj);
_setObject(NULL);
}
@@ -218,28 +242,27 @@ void URIReference::_release(SPObject *obj)
-SPObject* sp_css_uri_reference_resolve( SPDocument *document, const gchar *uri )
+SPObject *sp_css_uri_reference_resolve(SPDocument *document, const gchar *uri)
{
- SPObject* ref = NULL;
+ SPObject *ref = NULL;
- if ( document && uri && ( strncmp(uri, "url(", 4) == 0 ) ) {
- gchar *trimmed = extract_uri( uri );
- if ( trimmed ) {
- ref = sp_uri_reference_resolve( document, trimmed );
- g_free( trimmed );
+ if (document && uri && (strncmp(uri, "url(", 4) == 0)) {
+ gchar *trimmed = extract_uri(uri);
+ if (trimmed) {
+ ref = sp_uri_reference_resolve(document, trimmed);
+ g_free(trimmed);
}
}
return ref;
}
-SPObject *
-sp_uri_reference_resolve (SPDocument *document, const gchar *uri)
+SPObject *sp_uri_reference_resolve(SPDocument *document, const gchar *uri)
{
- SPObject* ref = NULL;
+ SPObject *ref = NULL;
- if ( uri && (*uri == '#') ) {
- ref = document->getObjectById( uri + 1 );
+ if (uri && (*uri == '#')) {
+ ref = document->getObjectById(uri + 1);
}
return ref;
diff --git a/src/uri.cpp b/src/uri.cpp
index 2eaf4ecc1..49bdab63c 100644
--- a/src/uri.cpp
+++ b/src/uri.cpp
@@ -148,7 +148,7 @@ gchar *URI::to_native_filename(gchar const* uri) throw(BadURIException)
* Does not check if the returned path is the local document's path (local)
* and thus redundent. Caller is expected to check against the document's path.
*/
-const std::string URI::getFullPath(std::string const base) const {
+const std::string URI::getFullPath(std::string const &base) const {
if (!_impl->getPath()) {
return "";
}
diff --git a/src/uri.h b/src/uri.h
index cee1baa09..bdf5f1baa 100644
--- a/src/uri.h
+++ b/src/uri.h
@@ -104,7 +104,7 @@ public:
static char *to_native_filename(char const* uri) throw(BadURIException);
- const std::string getFullPath(std::string const base) const;
+ const std::string getFullPath(std::string const &base) const;
char *toNativeFilename() const throw(BadURIException);
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index 8fd8c8c66..9680b6377 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -24,7 +24,6 @@ set(util_SRC
format.h
forward-pointer-iterator.h
function.h
- glib-list-iterators.h
list-container-test.h
list-container.h
list-copy.h
diff --git a/src/util/Makefile_insert b/src/util/Makefile_insert
index c23dffbca..2a778e660 100644
--- a/src/util/Makefile_insert
+++ b/src/util/Makefile_insert
@@ -25,7 +25,6 @@ util_libutil_a_SOURCES = \
util/format.h \
util/forward-pointer-iterator.h \
util/function.h \
- util/glib-list-iterators.h \
util/list.h \
util/list-container.h \
util/list-copy.h \
diff --git a/src/util/glib-list-iterators.h b/src/util/glib-list-iterators.h
deleted file mode 100644
index 6244e5b18..000000000
--- a/src/util/glib-list-iterators.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Inkscape::Util::GSListIterator - STL iterator for GSList
- * Inkscape::Util::GSListConstIterator - STL iterator for GSList
- * Inkscape::Util::GListIterator - STL iterator for GList
- * Inkscape::Util::GListConstIterator - STL iterator for GList
- *
- * Authors:
- * MenTaLguY <mental@rydia.net>
- *
- * Copyright (C) 2005 MenTaLguY
- *
- * Released under GNU GPL, read the file 'COPYING' for more information
- */
-
-#ifndef SEEN_INKSCAPE_GLIB_LIST_ITERATORS_H
-#define SEEN_INKSCAPE_GLIB_LIST_ITERATORS_H
-
-#include <cstddef>
-#include <iterator>
-#include <glib.h>
-
-namespace Inkscape {
-
-namespace Util {
-
-template <typename T> class GSListConstIterator;
-template <typename T> class GSListIterator;
-template <typename T> class GListConstIterator;
-template <typename T> class GListIterator;
-
-template <typename T>
-class GSListConstIterator<T *> {
-public:
- typedef std::forward_iterator_tag iterator_category;
- typedef T * const value_type G_GNUC_MAY_ALIAS;
- typedef std::ptrdiff_t difference_type;
- typedef value_type *pointer;
- typedef value_type &reference;
-
- GSListConstIterator(GSList const *list) : _list(list) {}
- // default copy
- // default assign
- GSList const *list() const { return _list; }
-
- reference operator*() const {
- return *reinterpret_cast<pointer>(&_list->data);
- }
-
- bool operator==(GSListConstIterator const &other) {
- return other._list == _list;
- }
- bool operator!=(GSListConstIterator const &other) {
- return other._list != _list;
- }
-
- GSListConstIterator &operator++() {
- _list = _list->next;
- return *this;
- }
- GSListConstIterator operator++(int) {
- GSListConstIterator saved=*this;
- _list = _list->next;
- return saved;
- }
-
-private:
- GSList const *_list;
-};
-
-template <typename T>
-class GSListIterator<T *> {
-public:
- typedef std::forward_iterator_tag iterator_category;
- typedef T *value_type G_GNUC_MAY_ALIAS;
- typedef std::ptrdiff_t difference_type;
- typedef value_type *pointer;
- typedef value_type &reference;
- typedef value_type const &const_reference;
-
- GSListIterator(GSList *list) : _list(list) {}
- // default copy
- // default assign
- operator GSListConstIterator<T *>() const { return _list; }
- GSList const *list() const { return _list; }
- GSList *list() { return _list; }
-
- const_reference operator*() const {
- return *reinterpret_cast<pointer>(&_list->data);
- }
- reference operator*() {
- return *reinterpret_cast<pointer>(&_list->data);
- }
-
- bool operator==(GSListIterator const &other) {
- return other._list == _list;
- }
- bool operator!=(GSListIterator const &other) {
- return other._list != _list;
- }
-
- GSListIterator &operator++() {
- _list = _list->next;
- return *this;
- }
- GSListIterator operator++(int) {
- GSListIterator saved=*this;
- _list = _list->next;
- return saved;
- }
-
-private:
- GSList *_list;
-};
-
-template <typename T>
-class GListConstIterator<T *> {
-public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef T * const value_type G_GNUC_MAY_ALIAS;
- typedef std::ptrdiff_t difference_type;
- typedef value_type *pointer;
- typedef value_type &reference;
-
- GListConstIterator(GList const *list) : _list(list) {}
- // default copy
- // default assign
- GList const *list() const { return _list; }
-
- reference operator*() const {
- return *reinterpret_cast<pointer>(&_list->data);
- }
-
- bool operator==(GListConstIterator const &other) {
- return other._list == _list;
- }
- bool operator!=(GListConstIterator const &other) {
- return other._list != _list;
- }
-
- GListConstIterator &operator++() {
- _list = _list->next;
- return *this;
- }
- GListConstIterator operator++(int) {
- GListConstIterator saved=*this;
- _list = _list->next;
- return saved;
- }
-
- GListConstIterator &operator--() {
- _list = _list->prev;
- return *this;
- }
- GListConstIterator operator--(int) {
- GListConstIterator saved=*this;
- _list = _list->prev;
- return saved;
- }
-
-private:
- GList const *_list;
-};
-
-template <typename T>
-class GListIterator<T *> {
-public:
- typedef std::bidirectional_iterator_tag iterator_category;
- typedef T *value_type G_GNUC_MAY_ALIAS;
- typedef std::ptrdiff_t difference_type;
- typedef value_type *pointer;
- typedef value_type &reference;
- typedef value_type const &const_reference;
-
- GListIterator(GList *list) : _list(list) {}
- // default copy
- // default assign
- operator GSListConstIterator<T *>() const {
- return reinterpret_cast<GSList *>(_list);
- }
- operator GSListIterator<T *>() const {
- return reinterpret_cast<GSList *>(_list);
- }
- operator GListConstIterator<T *>() const { return _list; }
- GList const *list() const { return _list; }
- GList *list() { return _list; }
-
- const_reference operator*() const {
- return *reinterpret_cast<pointer>(&_list->data);
- }
- reference operator*() { return *reinterpret_cast<pointer>(&_list->data); }
-
- bool operator==(GListIterator const &other) {
- return other._list == _list;
- }
- bool operator!=(GListIterator const &other) {
- return other._list != _list;
- }
-
- GListIterator &operator++() {
- _list = _list->next;
- return *this;
- }
- GListIterator operator++(int) {
- GListIterator saved=*this;
- _list = _list->next;
- return saved;
- }
-
- GListIterator &operator--() {
- _list = _list->prev;
- return *this;
- }
- GListIterator operator--(int) {
- GListIterator saved=*this;
- _list = _list->prev;
- return saved;
- }
-
-private:
- GList *_list;
-};
-
-}
-
-}
-
-#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:fileencoding=utf-8:textwidth=99 :
diff --git a/src/util/units.cpp b/src/util/units.cpp
index 2c72ec3ae..2e7a3b1d2 100644
--- a/src/util/units.cpp
+++ b/src/util/units.cpp
@@ -81,7 +81,21 @@ unsigned const svg_length_lookup[] = {
UNIT_CODE_PERCENT
};
-
+/* From SP_CSS_UNIT_* to unit */
+unsigned const sp_css_unit_lookup[] = {
+ 0,
+ UNIT_CODE_PX,
+ UNIT_CODE_PT,
+ UNIT_CODE_PC,
+ UNIT_CODE_MM,
+ UNIT_CODE_CM,
+ UNIT_CODE_IN,
+ UNIT_CODE_EM,
+ UNIT_CODE_EX,
+ UNIT_CODE_PERCENT
+ // UNIT_CODE_FT Missing,
+ // UNIT_CODE_MT Missing,
+};
// maps unit codes obtained from their abbreviations to their SVGLength unit indexes
typedef INK_UNORDERED_MAP<unsigned, SVGLength::Unit> UnitCodeLookup;
@@ -213,6 +227,10 @@ bool Unit::compatibleWith(Glib::ustring const &u) const
{
return compatibleWith(unit_table.getUnit(u));
}
+bool Unit::compatibleWith(char const *u) const
+{
+ return compatibleWith(unit_table.getUnit(u));
+}
bool Unit::operator==(Unit const &other) const
{
@@ -231,7 +249,29 @@ int Unit::svgUnit() const
return 0;
}
-
+double Unit::convert(double from_dist, Unit const *to) const
+{
+ // Percentage
+ if (to->type == UNIT_TYPE_DIMENSIONLESS) {
+ return from_dist * to->factor;
+ }
+
+ // Incompatible units
+ if (type != to->type) {
+ return -1;
+ }
+
+ // Compatible units
+ return from_dist * factor / to->factor;
+}
+double Unit::convert(double from_dist, Glib::ustring const &to) const
+{
+ return convert(from_dist, unit_table.getUnit(to));
+}
+double Unit::convert(double from_dist, char const *to) const
+{
+ return convert(from_dist, unit_table.getUnit(to));
+}
Unit UnitTable::_empty_unit;
@@ -283,6 +323,19 @@ Unit const *UnitTable::getUnit(SVGLength::Unit u) const
}
return &_empty_unit;
}
+/* SP_CSS_UNIT lookup */
+Unit const *UnitTable::getUnit(unsigned int u) const
+{
+ if (u == 0 || u > 9) {
+ return &_empty_unit;
+ }
+
+ UnitCodeMap::const_iterator f = _unit_map.find(sp_css_unit_lookup[u]);
+ if (f != _unit_map.end()) {
+ return &(*f->second);
+ }
+ return &_empty_unit;
+}
Unit const *UnitTable::findUnit(double factor, UnitType type) const
{
@@ -505,18 +558,7 @@ Glib::ustring Quantity::string() const {
double Quantity::convert(double from_dist, Unit const *from, Unit const *to)
{
- // Percentage
- if (to->type == UNIT_TYPE_DIMENSIONLESS) {
- return from_dist * to->factor;
- }
-
- // Incompatible units
- if (from->type != to->type) {
- return -1;
- }
-
- // Compatible units
- return from_dist * from->factor / to->factor;
+ return from->convert(from_dist, to);
}
double Quantity::convert(double from_dist, Glib::ustring const &from, Unit const *to)
{
diff --git a/src/util/units.h b/src/util/units.h
index 13777fd1b..a840a37ec 100644
--- a/src/util/units.h
+++ b/src/util/units.h
@@ -75,6 +75,11 @@ public:
/** Get SVG unit code. */
int svgUnit() const;
+
+ /** Convert value from this unit **/
+ double convert(double from_dist, Unit const *to) const;
+ double convert(double from_dist, Glib::ustring const &to) const;
+ double convert(double from_dist, char const *to) const;
};
class Quantity
@@ -147,6 +152,9 @@ public:
/** Retrieve a given unit based on its SVGLength unit */
Unit const *getUnit(SVGLength::Unit u) const;
+
+ /** Retrieve a given unit based on its SP_CSS_UNIT */
+ Unit const *getUnit(unsigned int u) const;
/** Retrieve a quantity based on its string identifier */
Quantity parseQuantity(Glib::ustring const &q) const;
diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp
index 46f895c06..32ccbad93 100644
--- a/src/vanishing-point.cpp
+++ b/src/vanishing-point.cpp
@@ -130,15 +130,15 @@ vp_knot_moved_handler (SPKnot *knot, Geom::Point const &ppointer, guint state, g
// FIXME: Do we need to create a new dragger as well?
dragger->updateZOrders ();
DocumentUndo::done(SP_ACTIVE_DESKTOP->getDocument(), SP_VERB_CONTEXT_3DBOX,
- _("Split vanishing points"));
+ _("Split vanishing points"));
return;
}
}
if (!(state & GDK_SHIFT_MASK)) {
// without Shift; see if we need to snap to another dragger
- for (GList *di = dragger->parent->draggers; di != NULL; di = di->next) {
- VPDragger *d_new = (VPDragger *) di->data;
+ for (std::vector<VPDragger *>::const_iterator di = dragger->parent->draggers.begin(); di != dragger->parent->draggers.end(); ++di) {
+ VPDragger *d_new = *di;
if ((d_new != dragger) && (Geom::L2 (d_new->point - p) < snap_dist)) {
if (have_VPs_of_same_perspective (dragger, d_new)) {
// this would result in degenerate boxes, which we disallow for the time being
@@ -155,7 +155,7 @@ vp_knot_moved_handler (SPKnot *knot, Geom::Point const &ppointer, guint state, g
d_new->vps.merge(dragger->vps);
// ... delete old dragger ...
- drag->draggers = g_list_remove (drag->draggers, dragger);
+ drag->draggers.erase(std::remove(drag->draggers.begin(), drag->draggers.end(), dragger),drag->draggers.end());
delete dragger;
dragger = NULL;
@@ -175,22 +175,24 @@ vp_knot_moved_handler (SPKnot *knot, Geom::Point const &ppointer, guint state, g
// as is currently the case.
DocumentUndo::done(SP_ACTIVE_DESKTOP->getDocument(), SP_VERB_CONTEXT_3DBOX,
- _("Merge vanishing points"));
+ _("Merge vanishing points"));
return;
}
}
+ }
- // We didn't snap to another dragger, so we'll try a regular snap
- SPDesktop *desktop = SP_ACTIVE_DESKTOP;
- SnapManager &m = desktop->namedview->snap_manager;
- m.setup(desktop);
- Inkscape::SnappedPoint s = m.freeSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_OTHER_HANDLE));
- m.unSetup();
- if (s.getSnapped()) {
- p = s.getPoint();
- knot->moveto(p);
- }
+ // We didn't hit the return statement above, so we didn't snap to another dragger. Therefore we'll now try a regular snap
+ // Regardless of the status of the SHIFT key, we will try to snap; Here SHIFT does not disable snapping, as the shift key
+ // has a different purpose in this context (see above)
+ SPDesktop *desktop = SP_ACTIVE_DESKTOP;
+ SnapManager &m = desktop->namedview->snap_manager;
+ m.setup(desktop);
+ Inkscape::SnappedPoint s = m.freeSnap(Inkscape::SnapCandidatePoint(p, Inkscape::SNAPSOURCE_OTHER_HANDLE));
+ m.unSetup();
+ if (s.getSnapped()) {
+ p = s.getPoint();
+ knot->moveto(p);
}
dragger->point = p; // FIXME: Is dragger->point being used at all?
@@ -241,7 +243,7 @@ vp_knot_ungrabbed_handler (SPKnot *knot, guint /*state*/, gpointer data)
g_return_if_fail (dragger->parent);
g_return_if_fail (dragger->parent->document);
DocumentUndo::done(dragger->parent->document, SP_VERB_CONTEXT_3DBOX,
- _("3D box: Move vanishing point"));
+ _("3D box: Move vanishing point"));
}
unsigned int VanishingPoint::global_counter = 0;
@@ -257,7 +259,7 @@ std::list<SPBox3D *>
VanishingPoint::selectedBoxes(Inkscape::Selection *sel) {
std::list<SPBox3D *> sel_boxes;
std::vector<SPItem*> itemlist=sel->itemList();
- for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i) {
SPItem *item = *i;
SPBox3D *box = dynamic_cast<SPBox3D *>(item);
if (box && this->hasBox(box)) {
@@ -267,15 +269,14 @@ VanishingPoint::selectedBoxes(Inkscape::Selection *sel) {
return sel_boxes;
}
-VPDragger::VPDragger(VPDrag *parent, Geom::Point p, VanishingPoint &vp)
+VPDragger::VPDragger(VPDrag *parent, Geom::Point p, VanishingPoint &vp) :
+ parent(parent),
+ knot(NULL),
+ point(p),
+ point_original(p),
+ dragging_started(false),
+ vps()
{
- this->parent = parent;
-
- this->point = p;
- this->point_original = p;
-
- this->dragging_started = false;
-
if (vp.is_finite()) {
// create the knot
this->knot = new SPKnot(SP_ACTIVE_DESKTOP, NULL);
@@ -397,7 +398,7 @@ VPDragger::VPsOfSelectedBoxes() {
// FIXME: Should we take the selection from the parent VPDrag? I guess it shouldn't make a difference.
Inkscape::Selection *sel = SP_ACTIVE_DESKTOP->getSelection();
std::vector<SPItem*> itemlist=sel->itemList();
- for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i) {
SPItem *item = *i;
SPBox3D *box = dynamic_cast<SPBox3D *>(item);
if (box) {
@@ -492,8 +493,6 @@ VPDrag::VPDrag (SPDocument *document)
this->document = document;
this->selection = SP_ACTIVE_DESKTOP->getSelection();
- this->draggers = NULL;
- this->lines = NULL;
this->show_lines = true;
this->front_or_rear_lines = 0x1;
@@ -520,17 +519,15 @@ VPDrag::~VPDrag()
this->sel_changed_connection.disconnect();
this->sel_modified_connection.disconnect();
- for (GList *l = this->draggers; l != NULL; l = l->next) {
- delete ((VPDragger *) l->data);
+ for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
+ delete (*i);
}
- g_list_free (this->draggers);
- this->draggers = NULL;
+ this->draggers.clear();
- for (GSList const *i = this->lines; i != NULL; i = i->next) {
- sp_canvas_item_destroy(SP_CANVAS_ITEM(i->data));
+ for (std::vector<SPCtrlLine *>::const_iterator i = this->lines.begin(); i != this->lines.end(); ++i) {
+ sp_canvas_item_destroy(SP_CANVAS_ITEM(*i));
}
- g_slist_free (this->lines);
- this->lines = NULL;
+ this->lines.clear();
}
/**
@@ -539,8 +536,8 @@ VPDrag::~VPDrag()
VPDragger *
VPDrag::getDraggerFor (VanishingPoint const &vp)
{
- for (GList const* i = this->draggers; i != NULL; i = i->next) {
- VPDragger *dragger = (VPDragger *) i->data;
+ for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
+ VPDragger *dragger = *i;
for (std::list<VanishingPoint>::iterator j = dragger->vps.begin(); j != dragger->vps.end(); ++j) {
// TODO: Should we compare the pointers or the VPs themselves!?!?!?!
if (*j == vp) {
@@ -555,8 +552,8 @@ void
VPDrag::printDraggers ()
{
g_print ("=== VPDrag info: =================================\n");
- for (GList const* i = this->draggers; i != NULL; i = i->next) {
- ((VPDragger *) i->data)->printVPs();
+ for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
+ (*i)->printVPs();
g_print ("========\n");
}
g_print ("=================================================\n");
@@ -571,16 +568,15 @@ VPDrag::updateDraggers ()
if (this->dragging)
return;
// delete old draggers
- for (GList const* i = this->draggers; i != NULL; i = i->next) {
- delete ((VPDragger *) i->data);
+ for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
+ delete (*i);
}
- g_list_free (this->draggers);
- this->draggers = NULL;
+ this->draggers.clear();
g_return_if_fail (this->selection != NULL);
std::vector<SPItem*> itemlist=this->selection->itemList();
- for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i) {
SPItem *item = *i;
SPBox3D *box = dynamic_cast<SPBox3D *>(item);
if (box) {
@@ -601,11 +597,10 @@ void
VPDrag::updateLines ()
{
// delete old lines
- for (GSList const *i = this->lines; i != NULL; i = i->next) {
- sp_canvas_item_destroy(SP_CANVAS_ITEM(i->data));
+ for (std::vector<SPCtrlLine *>::const_iterator i = this->lines.begin(); i != this->lines.end(); ++i) {
+ sp_canvas_item_destroy(SP_CANVAS_ITEM(*i));
}
- g_slist_free (this->lines);
- this->lines = NULL;
+ this->lines.clear();
// do nothing if perspective lines are currently disabled
if (this->show_lines == 0) return;
@@ -613,7 +608,7 @@ VPDrag::updateLines ()
g_return_if_fail (this->selection != NULL);
std::vector<SPItem*> itemlist=this->selection->itemList();
- for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++) {
+ for (std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i) {
SPItem *item = *i;
SPBox3D *box = dynamic_cast<SPBox3D *>(item);
if (box) {
@@ -630,7 +625,7 @@ VPDrag::updateBoxHandles ()
// FIXME: Is there a way to update the knots without accessing the
// (previously) statically linked function KnotHolder::update_knots?
- std::vector<SPItem*> sel = selection->itemList();
+ std::vector<SPItem*> sel = selection->itemList();
if (sel.empty())
return; // no selection
@@ -649,8 +644,8 @@ VPDrag::updateBoxHandles ()
void
VPDrag::updateBoxReprs ()
{
- for (GList *i = this->draggers; i != NULL; i = i->next) {
- VPDragger *dragger = (VPDragger *) i->data;
+ for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
+ VPDragger *dragger = *i;
for (std::list<VanishingPoint>::iterator i = dragger->vps.begin(); i != dragger->vps.end(); ++i) {
(*i).updateBoxReprs();
}
@@ -660,8 +655,8 @@ VPDrag::updateBoxReprs ()
void
VPDrag::updateBoxDisplays ()
{
- for (GList *i = this->draggers; i != NULL; i = i->next) {
- VPDragger *dragger = (VPDragger *) i->data;
+ for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
+ VPDragger *dragger = *i;
for (std::list<VanishingPoint>::iterator i = dragger->vps.begin(); i != dragger->vps.end(); ++i) {
(*i).updateBoxDisplays();
}
@@ -756,8 +751,8 @@ VPDrag::addDragger (VanishingPoint &vp)
}
Geom::Point p = vp.get_pos();
- for (GList *i = this->draggers; i != NULL; i = i->next) {
- VPDragger *dragger = (VPDragger *) i->data;
+ for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
+ VPDragger *dragger = *i;
if (Geom::L2 (dragger->point - p) < MERGE_DIST) {
// distance is small, merge this draggable into dragger, no need to create new dragger
dragger->addVP (vp);
@@ -767,16 +762,16 @@ VPDrag::addDragger (VanishingPoint &vp)
VPDragger *new_dragger = new VPDragger(this, p, vp);
// fixme: draggers should be added AFTER the last one: this way tabbing through them will be from begin to end.
- this->draggers = g_list_append (this->draggers, new_dragger);
+ this->draggers.push_back(new_dragger);
}
void
VPDrag::swap_perspectives_of_VPs(Persp3D *persp2, Persp3D *persp1)
{
// iterate over all VP in all draggers and replace persp2 with persp1
- for (GList *i = this->draggers; i != NULL; i = i->next) {
- for (std::list<VanishingPoint>::iterator j = ((VPDragger *) (i->data))->vps.begin();
- j != ((VPDragger *) (i->data))->vps.end(); ++j) {
+ for (std::vector<VPDragger *>::const_iterator i = this->draggers.begin(); i != this->draggers.end(); ++i) {
+ for (std::list<VanishingPoint>::iterator j = (*i)->vps.begin();
+ j != (*i)->vps.end(); ++j) {
if ((*j).get_perspective() == persp2) {
(*j).set_perspective(persp1);
}
@@ -788,7 +783,7 @@ void VPDrag::addLine(Geom::Point const &p1, Geom::Point const &p2, Inkscape::Ctr
{
SPCtrlLine *line = ControlManager::getManager().createControlLine(SP_ACTIVE_DESKTOP->getControls(), p1, p2, type);
sp_canvas_item_show(line);
- this->lines = g_slist_append(this->lines, line);
+ this->lines.push_back(line);
}
} // namespace Box3D
diff --git a/src/vanishing-point.h b/src/vanishing-point.h
index 7242a94ee..ae2a88d6e 100644
--- a/src/vanishing-point.h
+++ b/src/vanishing-point.h
@@ -23,8 +23,6 @@
#include "ui/control-manager.h" // TODO break enums out separately
class SPBox3D;
-typedef struct _GList GList;
-typedef struct _GSList GSList;
namespace Box3D {
@@ -48,6 +46,7 @@ public:
inline VanishingPoint &operator=(VanishingPoint const &rhs) {
_persp = rhs._persp;
_axis = rhs._axis;
+ my_counter = rhs.my_counter;
return *this;
}
inline bool operator==(VanishingPoint const &rhs) const {
@@ -173,8 +172,8 @@ public:
bool dragging;
SPDocument *document;
- GList *draggers;
- GSList *lines;
+ std::vector<VPDragger *> draggers;
+ std::vector<SPCtrlLine *> lines;
void printDraggers(); // convenience for debugging
/*
@@ -195,7 +194,6 @@ public:
inline bool hasEmptySelection() { return this->selection->isEmpty(); }
bool allBoxesAreSelected (VPDragger *dragger);
- GSList * selectedBoxesWithVPinDragger (VPDragger *dragger);
// FIXME: Should this be private? (It's the case with the corresponding function in gradient-drag.h)
// But vp_knot_grabbed_handler
diff --git a/src/verbs.cpp b/src/verbs.cpp
index e0ef27b0d..a78bde2f7 100644
--- a/src/verbs.cpp
+++ b/src/verbs.cpp
@@ -832,7 +832,14 @@ Verb *Verb::getbyid(gchar const *id)
verb = verb_found->second;
}
- if (verb == NULL)
+ if (verb == NULL
+#if !HAVE_POTRACE
+ // Squash warning about disabled features
+ && strcmp(id, "ToolPaintBucket") != 0
+ && strcmp(id, "SelectionTrace") != 0
+ && strcmp(id, "PaintBucketPrefs") != 0
+#endif
+ )
printf("Unable to find: %s\n", id);
return verb;
@@ -945,6 +952,10 @@ void EditVerb::perform(SPAction *action, void *data)
g_return_if_fail(ensure_desktop_valid(action));
SPDesktop *dt = sp_action_get_desktop(action);
+ SPDocument *doc = dt->getDocument();
+
+ Inkscape::XML::Node *repr = dt->namedview->getRepr();
+
switch (reinterpret_cast<std::size_t>(data)) {
case SP_VERB_EDIT_UNDO:
sp_undo(dt, dt->getDocument());
@@ -1072,10 +1083,12 @@ void EditVerb::perform(SPAction *action, void *data)
case SP_VERB_EDIT_DELETE_ALL_GUIDES:
sp_guide_delete_all_guides(dt);
break;
+ case SP_VERB_EDIT_GUIDES_TOGGLE_LOCK:
+ dt->toggleGuidesLock();
+ break;
case SP_VERB_EDIT_GUIDES_AROUND_PAGE:
sp_guide_create_guides_around_page(dt);
break;
-
case SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER:
sp_selection_next_patheffect_param(dt);
break;
@@ -1201,10 +1214,14 @@ void SelectionVerb::perform(SPAction *action, void *data)
case SP_VERB_SELECTION_REVERSE:
SelectionHelper::reverse(dt);
break;
+
+#if HAVE_POTRACE
case SP_VERB_SELECTION_TRACE:
INKSCAPE.dialogs_unhide();
dt->_dlg_mgr->showDialog("Trace");
break;
+#endif
+
case SP_VERB_SELECTION_PIXEL_ART:
INKSCAPE.dialogs_unhide();
dt->_dlg_mgr->showDialog("PixelArt");
@@ -1571,7 +1588,7 @@ void TagVerb::perform( SPAction *action, void *data)
id=NULL;
do {
g_free(id);
- id = g_strdup_printf("Set %d", tag_suffix++);
+ id = g_strdup_printf(_("Set %d"), tag_suffix++);
} while (dt->doc()->getObjectById(id));
doc = dt->doc()->getReprDoc();
@@ -1606,7 +1623,7 @@ void ContextVerb::perform(SPAction *action, void *data)
/** \todo !!! hopefully this can go away soon and actions can look after
* themselves
*/
- for (vidx = SP_VERB_CONTEXT_SELECT; vidx <= SP_VERB_CONTEXT_PAINTBUCKET_PREFS; vidx++)
+ for (vidx = SP_VERB_CONTEXT_SELECT; vidx <= SP_VERB_CONTEXT_LPETOOL_PREFS; vidx++)
{
SPAction *tool_action= get((sp_verb_t)vidx)->get_action(action->context);
if (tool_action) {
@@ -1673,9 +1690,13 @@ void ContextVerb::perform(SPAction *action, void *data)
case SP_VERB_CONTEXT_CONNECTOR:
tools_switch(dt, TOOLS_CONNECTOR);
break;
+
+#if HAVE_POTRACE
case SP_VERB_CONTEXT_PAINTBUCKET:
tools_switch(dt, TOOLS_PAINTBUCKET);
break;
+#endif
+
case SP_VERB_CONTEXT_ERASER:
tools_switch(dt, TOOLS_ERASER);
break;
@@ -1759,10 +1780,14 @@ void ContextVerb::perform(SPAction *action, void *data)
prefs->setInt("/dialogs/preferences/page", PREFS_PAGE_TOOLS_CONNECTOR);
dt->_dlg_mgr->showDialog("InkscapePreferences");
break;
+
+#if HAVE_POTRACE
case SP_VERB_CONTEXT_PAINTBUCKET_PREFS:
prefs->setInt("/dialogs/preferences/page", PREFS_PAGE_TOOLS_PAINTBUCKET);
dt->_dlg_mgr->showDialog("InkscapePreferences");
break;
+#endif
+
case SP_VERB_CONTEXT_ERASER_PREFS:
prefs->setInt("/dialogs/preferences/page", PREFS_PAGE_TOOLS_ERASER);
dt->_dlg_mgr->showDialog("InkscapePreferences");
@@ -1925,7 +1950,6 @@ void ZoomVerb::perform(SPAction *action, void *data)
case SP_VERB_TOGGLE_GRID:
dt->toggleGrids();
break;
-#ifdef HAVE_GTK_WINDOW_FULLSCREEN
case SP_VERB_FULLSCREEN:
dt->fullscreen();
break;
@@ -1933,7 +1957,6 @@ void ZoomVerb::perform(SPAction *action, void *data)
dt->fullscreen();
dt->focusMode(!dt->is_fullscreen());
break;
-#endif // HAVE_GTK_WINDOW_FULLSCREEN
case SP_VERB_FOCUSTOGGLE:
dt->focusMode(!dt->is_focusMode());
break;
@@ -2160,10 +2183,14 @@ void TutorialVerb::perform(SPAction *action, void *data)
// TRANSLATORS: See "tutorial-basic.svg" comment.
sp_help_open_tutorial(NULL, (gpointer)_("tutorial-advanced.svg"));
break;
+
+#if HAVE_POTRACE
case SP_VERB_TUTORIAL_TRACING:
// TRANSLATORS: See "tutorial-basic.svg" comment.
sp_help_open_tutorial(NULL, (gpointer)_("tutorial-tracing.svg"));
break;
+#endif
+
case SP_VERB_TUTORIAL_TRACING_PIXELART:
sp_help_open_tutorial(NULL, (gpointer)_("tutorial-tracing-pixelart.svg"));
break;
@@ -2517,6 +2544,7 @@ Verb *Verb::_base_verbs[] = {
N_("Deselect any selected objects or nodes"), INKSCAPE_ICON("edit-select-none")),
new EditVerb(SP_VERB_EDIT_DELETE_ALL_GUIDES, "EditRemoveAllGuides", N_("Delete All Guides"),
N_("Delete all the guides in the document"), NULL),
+ new EditVerb(SP_VERB_EDIT_GUIDES_TOGGLE_LOCK, "EditGuidesToggleLock", N_("Lock All Guides"), N_("Toggle lock of all guides in the document"), NULL),
new EditVerb(SP_VERB_EDIT_GUIDES_AROUND_PAGE, "EditGuidesAroundPage", N_("Create _Guides Around the Page"),
N_("Create four guides aligned with the page borders"), NULL),
new EditVerb(SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER, "EditNextPathEffectParameter", N_("Next path effect parameter"),
@@ -2593,9 +2621,13 @@ Verb *Verb::_base_verbs[] = {
N_("Simplify selected paths (remove extra nodes)"), INKSCAPE_ICON("path-simplify")),
new SelectionVerb(SP_VERB_SELECTION_REVERSE, "SelectionReverse", N_("_Reverse"),
N_("Reverse the direction of selected paths (useful for flipping markers)"), INKSCAPE_ICON("path-reverse")),
+
+#if HAVE_POTRACE
// TRANSLATORS: "to trace" means "to convert a bitmap to vector graphics" (to vectorize)
new SelectionVerb(SP_VERB_SELECTION_TRACE, "SelectionTrace", N_("_Trace Bitmap..."),
N_("Create one or more paths from a bitmap by tracing it"), INKSCAPE_ICON("bitmap-trace")),
+#endif
+
new SelectionVerb(SP_VERB_SELECTION_PIXEL_ART, "SelectionPixelArt", N_("Trace Pixel Art..."),
N_("Create paths using Kopf-Lischinski algorithm to vectorize pixel art"), INKSCAPE_ICON("pixelart-trace")),
new SelectionVerb(SP_VERB_SELECTION_CREATE_BITMAP, "SelectionCreateBitmap", N_("Make a _Bitmap Copy"),
@@ -2733,8 +2765,12 @@ Verb *Verb::_base_verbs[] = {
N_("Pick colors from image"), INKSCAPE_ICON("color-picker")),
new ContextVerb(SP_VERB_CONTEXT_CONNECTOR, "ToolConnector", NC_("ContextVerb", "Connector"),
N_("Create diagram connectors"), INKSCAPE_ICON("draw-connector")),
+
+#if HAVE_POTRACE
new ContextVerb(SP_VERB_CONTEXT_PAINTBUCKET, "ToolPaintBucket", NC_("ContextVerb", "Paint Bucket"),
N_("Fill bounded areas"), INKSCAPE_ICON("color-fill")),
+#endif
+
new ContextVerb(SP_VERB_CONTEXT_LPE, "ToolLPE", NC_("ContextVerb", "LPE Edit"),
N_("Edit Path Effect parameters"), NULL),
new ContextVerb(SP_VERB_CONTEXT_ERASER, "ToolEraser", NC_("ContextVerb", "Eraser"),
@@ -2780,8 +2816,12 @@ Verb *Verb::_base_verbs[] = {
N_("Open Preferences for the Dropper tool"), NULL),
new ContextVerb(SP_VERB_CONTEXT_CONNECTOR_PREFS, "ConnectorPrefs", N_("Connector Preferences"),
N_("Open Preferences for the Connector tool"), NULL),
+
+#if HAVE_POTRACE
new ContextVerb(SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "PaintBucketPrefs", N_("Paint Bucket Preferences"),
N_("Open Preferences for the Paint Bucket tool"), NULL),
+#endif
+
new ContextVerb(SP_VERB_CONTEXT_ERASER_PREFS, "EraserPrefs", N_("Eraser Preferences"),
N_("Open Preferences for the Eraser tool"), NULL),
new ContextVerb(SP_VERB_CONTEXT_LPETOOL_PREFS, "LPEToolPrefs", N_("LPE Tool Preferences"),
@@ -2810,12 +2850,10 @@ Verb *Verb::_base_verbs[] = {
INKSCAPE_ICON("zoom-half-size")),
new ZoomVerb(SP_VERB_ZOOM_2_1, "Zoom2:1", N_("_Zoom 2:1"), N_("Zoom to 2:1"),
INKSCAPE_ICON("zoom-double-size")),
-#ifdef HAVE_GTK_WINDOW_FULLSCREEN
new ZoomVerb(SP_VERB_FULLSCREEN, "FullScreen", N_("_Fullscreen"), N_("Stretch this document window to full screen"),
INKSCAPE_ICON("view-fullscreen")),
new ZoomVerb(SP_VERB_FULLSCREENFOCUS, "FullScreenFocus", N_("Fullscreen & Focus Mode"), N_("Stretch this document window to full screen"),
INKSCAPE_ICON("view-fullscreen")),
-#endif // HAVE_GTK_WINDOW_FULLSCREEN
new ZoomVerb(SP_VERB_FOCUSTOGGLE, "FocusToggle", N_("Toggle _Focus Mode"), N_("Remove excess toolbars to focus on drawing"),
NULL),
new ZoomVerb(SP_VERB_VIEW_NEW, "ViewNew", N_("Duplic_ate Window"), N_("Open a new window with the same document"),
@@ -2937,9 +2975,13 @@ Verb *Verb::_base_verbs[] = {
N_("Using shape tools to create and edit shapes"), NULL),
new TutorialVerb(SP_VERB_TUTORIAL_ADVANCED, "TutorialsAdvanced", N_("Inkscape: _Advanced"),
N_("Advanced Inkscape topics"), NULL/*"tutorial_advanced"*/),
+
+#if HAVE_POTRACE
// TRANSLATORS: "to trace" means "to convert a bitmap to vector graphics" (to vectorize)
new TutorialVerb(SP_VERB_TUTORIAL_TRACING, "TutorialsTracing", N_("Inkscape: T_racing"),
N_("Using bitmap tracing"), NULL/*"tutorial_tracing"*/),
+#endif
+
new TutorialVerb(SP_VERB_TUTORIAL_TRACING_PIXELART, "TutorialsTracingPixelArt", N_("Inkscape: Tracing Pixel Art"),
N_("Using Trace Pixel Art dialog"), NULL),
new TutorialVerb(SP_VERB_TUTORIAL_CALLIGRAPHY, "TutorialsCalligraphy", N_("Inkscape: _Calligraphy"),
diff --git a/src/verbs.h b/src/verbs.h
index 06fc4fb05..4f453761e 100644
--- a/src/verbs.h
+++ b/src/verbs.h
@@ -19,7 +19,6 @@
#include <cstring>
#include <string>
-//#include "require-config.h" /* HAVE_GTK_WINDOW_FULLSCREEN */
#include <glibmm/ustring.h>
struct SPAction;
@@ -107,6 +106,7 @@ enum {
SP_VERB_EDIT_SELECT_PREV,
SP_VERB_EDIT_DESELECT,
SP_VERB_EDIT_DELETE_ALL_GUIDES,
+ SP_VERB_EDIT_GUIDES_TOGGLE_LOCK,
SP_VERB_EDIT_GUIDES_AROUND_PAGE,
SP_VERB_EDIT_NEXT_PATHEFFECT_PARAMETER,
/* Selection */
@@ -136,7 +136,11 @@ enum {
SP_VERB_SELECTION_OUTLINE,
SP_VERB_SELECTION_SIMPLIFY,
SP_VERB_SELECTION_REVERSE,
+
+#if HAVE_POTRACE
SP_VERB_SELECTION_TRACE,
+#endif
+
SP_VERB_SELECTION_PIXEL_ART,
SP_VERB_SELECTION_CREATE_BITMAP,
SP_VERB_SELECTION_COMBINE,
@@ -203,7 +207,11 @@ enum {
SP_VERB_CONTEXT_MEASURE,
SP_VERB_CONTEXT_DROPPER,
SP_VERB_CONTEXT_CONNECTOR,
+
+#if HAVE_POTRACE
SP_VERB_CONTEXT_PAINTBUCKET,
+#endif
+
SP_VERB_CONTEXT_LPE, /* not really a tool but used for editing LPE parameters on-canvas for example */
SP_VERB_CONTEXT_ERASER,
SP_VERB_CONTEXT_LPETOOL, /* note that this is very different from SP_VERB_CONTEXT_LPE above! */
@@ -227,7 +235,11 @@ enum {
SP_VERB_CONTEXT_MEASURE_PREFS,
SP_VERB_CONTEXT_DROPPER_PREFS,
SP_VERB_CONTEXT_CONNECTOR_PREFS,
+
+#if HAVE_POTRACE
SP_VERB_CONTEXT_PAINTBUCKET_PREFS,
+#endif
+
SP_VERB_CONTEXT_ERASER_PREFS,
SP_VERB_CONTEXT_LPETOOL_PREFS,
/* Zooming and desktop settings */
@@ -249,10 +261,8 @@ enum {
SP_VERB_ZOOM_1_1,
SP_VERB_ZOOM_1_2,
SP_VERB_ZOOM_2_1,
-#ifdef HAVE_GTK_WINDOW_FULLSCREEN
SP_VERB_FULLSCREEN,
SP_VERB_FULLSCREENFOCUS,
-#endif /* HAVE_GTK_WINDOW_FULLSCREEN */
SP_VERB_FOCUSTOGGLE,
SP_VERB_VIEW_NEW,
SP_VERB_VIEW_NEW_PREVIEW,
@@ -311,7 +321,11 @@ enum {
SP_VERB_TUTORIAL_BASIC,
SP_VERB_TUTORIAL_SHAPES,
SP_VERB_TUTORIAL_ADVANCED,
+
+#if HAVE_POTRACE
SP_VERB_TUTORIAL_TRACING,
+#endif
+
SP_VERB_TUTORIAL_TRACING_PIXELART,
SP_VERB_TUTORIAL_CALLIGRAPHY,
SP_VERB_TUTORIAL_INTERPOLATE,
diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt
index a3e9e14d0..c38bde5cf 100644
--- a/src/widgets/CMakeLists.txt
+++ b/src/widgets/CMakeLists.txt
@@ -11,7 +11,6 @@ set(widgets_SRC
measure-toolbar.cpp
mesh-toolbar.cpp
node-toolbar.cpp
- paintbucket-toolbar.cpp
pencil-toolbar.cpp
rect-toolbar.cpp
spiral-toolbar.cpp
@@ -67,7 +66,6 @@ set(widgets_SRC
measure-toolbar.h
mesh-toolbar.h
node-toolbar.h
- paintbucket-toolbar.h
pencil-toolbar.h
rect-toolbar.h
spiral-toolbar.h
@@ -114,3 +112,12 @@ set(widgets_SRC
# add_inkscape_lib(widgets_LIB "${widgets_SRC}")
add_inkscape_source("${widgets_SRC}")
+
+set ( widgets_paintbucket_SRC
+ paintbucket-toolbar.cpp
+ paintbucket-toolbar.h
+)
+
+if ("${HAVE_POTRACE}")
+ add_inkscape_source("${widgets_paintbucket_SRC}")
+endif()
diff --git a/src/widgets/Makefile_insert b/src/widgets/Makefile_insert
index f66be66ed..6913f4a58 100644
--- a/src/widgets/Makefile_insert
+++ b/src/widgets/Makefile_insert
@@ -58,8 +58,6 @@ ink_common_sources += \
widgets/node-toolbar.h \
widgets/paint-selector.cpp \
widgets/paint-selector.h \
- widgets/paintbucket-toolbar.cpp \
- widgets/paintbucket-toolbar.h \
widgets/pencil-toolbar.cpp \
widgets/pencil-toolbar.h \
widgets/rect-toolbar.cpp \
@@ -109,5 +107,13 @@ ink_common_sources += \
widgets/zoom-toolbar.h \
widgets/widget-sizes.h
+if HAVE_POTRACE
+
+ink_common_sources += \
+ widgets/paintbucket-toolbar.cpp \
+ widgets/paintbucket-toolbar.h
+
+endif
+
widgets/button.$(OBJEXT): helper/sp-marshal.h
widgets/menu.$(OBJEXT): helper/sp-marshal.h
diff --git a/src/widgets/arc-toolbar.cpp b/src/widgets/arc-toolbar.cpp
index 71418e238..7b872e8b1 100644
--- a/src/widgets/arc-toolbar.cpp
+++ b/src/widgets/arc-toolbar.cpp
@@ -98,7 +98,7 @@ sp_arctb_startend_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *v
bool modmade = false;
std::vector<SPItem*> itemlist=desktop->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (SP_IS_GENERICELLIPSE(item)) {
@@ -164,7 +164,7 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
if ( ege_select_one_action_get_active(act) != 0 ) {
std::vector<SPItem*> itemlist=desktop->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (SP_IS_GENERICELLIPSE(item)) {
Inkscape::XML::Node *repr = item->getRepr();
@@ -175,7 +175,7 @@ static void sp_arctb_open_state_changed( EgeSelectOneAction *act, GObject *tbl )
}
} else {
std::vector<SPItem*> itemlist=desktop->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (SP_IS_GENERICELLIPSE(item)) {
Inkscape::XML::Node *repr = item->getRepr();
@@ -265,7 +265,7 @@ static void sp_arc_toolbox_selection_changed(Inkscape::Selection *selection, GOb
purge_repr_listener( tbl, tbl );
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (SP_IS_GENERICELLIPSE(item)) {
n_selected++;
diff --git a/src/widgets/connector-toolbar.cpp b/src/widgets/connector-toolbar.cpp
index 1c99f283d..733fb34e8 100644
--- a/src/widgets/connector-toolbar.cpp
+++ b/src/widgets/connector-toolbar.cpp
@@ -98,7 +98,7 @@ static void sp_connector_orthogonal_toggled( GtkToggleAction* act, GObject *tbl
bool modmade = false;
std::vector<SPItem*> itemlist=desktop->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (Inkscape::UI::Tools::cc_item_is_connector(item)) {
@@ -145,7 +145,7 @@ static void connector_curvature_changed(GtkAdjustment *adj, GObject* tbl)
bool modmade = false;
std::vector<SPItem*> itemlist=desktop->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (Inkscape::UI::Tools::cc_item_is_connector(item)) {
@@ -200,17 +200,15 @@ static void connector_spacing_changed(GtkAdjustment *adj, GObject* tbl)
desktop->namedview->updateRepr();
bool modmade = false;
- GSList *items = get_avoided_items(NULL, desktop->currentRoot(), desktop);
- for ( GSList const *iter = items ; iter != NULL ; iter = iter->next ) {
- SPItem *item = reinterpret_cast<SPItem *>(iter->data);
+ std::vector<SPItem *> items;
+ items = get_avoided_items(items, desktop->currentRoot(), desktop);
+ for (std::vector<SPItem *>::const_iterator iter = items.begin(); iter != items.end(); ++iter ) {
+ SPItem *item = *iter;
Geom::Affine m = Geom::identity();
avoid_item_move(&m, item);
modmade = true;
}
- if (items) {
- g_slist_free(items);
- }
if(modmade) {
DocumentUndo::done(doc, SP_VERB_CONTEXT_CONNECTOR,
_("Change connector spacing"));
diff --git a/src/widgets/desktop-widget.cpp b/src/widgets/desktop-widget.cpp
index e19f56e48..1fdd3ca6d 100644
--- a/src/widgets/desktop-widget.cpp
+++ b/src/widgets/desktop-widget.cpp
@@ -70,6 +70,9 @@
#include "widget-sizes.h"
#include "verbs.h"
+#if GTK_CHECK_VERSION(3,0,0)
+# include <gtkmm/cssprovider.h>
+#endif
#include <gtkmm/paned.h>
#include <gtkmm/messagedialog.h>
@@ -107,6 +110,7 @@ static void sp_desktop_widget_realize (GtkWidget *widget);
static gint sp_desktop_widget_event (GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dtw);
static void sp_dtw_color_profile_event(EgeColorProfTracker *widget, SPDesktopWidget *dtw);
+static void sp_update_guides_lock( GtkWidget *button, gpointer data );
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
static void cms_adjust_toggled( GtkWidget *button, gpointer data );
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
@@ -390,6 +394,19 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw )
dtw->tool_toolbox = ToolboxFactory::createToolToolbox();
ToolboxFactory::setOrientation( dtw->tool_toolbox, GTK_ORIENTATION_VERTICAL );
gtk_box_pack_start( GTK_BOX(dtw->hbox), dtw->tool_toolbox, FALSE, TRUE, 0 );
+ // Lock guides button
+ dtw->guides_lock = sp_button_new_from_data( Inkscape::ICON_SIZE_DECORATION,
+ SP_BUTTON_TYPE_TOGGLE,
+ NULL,
+ INKSCAPE_ICON("object-locked"),
+ _("Toggle lock of all guides in the document"));
+#if GTK_CHECK_VERSION(3,0,0)
+ Glib::RefPtr<Gtk::CssProvider> guides_lock_style_provider = Gtk::CssProvider::create();
+ guides_lock_style_provider->load_from_data("GtkWidget { padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0; }");
+ Gtk::Widget * wnd = Glib::wrap(dtw->guides_lock);
+ Glib::RefPtr<Gtk::StyleContext> context = wnd->get_style_context();
+ context->add_provider(guides_lock_style_provider, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
+#endif
/* Horizontal ruler */
GtkWidget *eventbox = gtk_event_box_new ();
@@ -407,23 +424,31 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw )
GtkWidget *tbl = gtk_grid_new();
dtw->canvas_tbl = gtk_grid_new();
+ gtk_grid_attach(GTK_GRID(dtw->canvas_tbl), dtw->guides_lock, 0, 0, 1, 1);
gtk_grid_attach(GTK_GRID(dtw->canvas_tbl), eventbox, 1, 0, 1, 1);
#else
GtkWidget *tbl = gtk_table_new(2, 3, FALSE);
dtw->canvas_tbl = gtk_table_new(3, 3, FALSE);
gtk_table_attach(GTK_TABLE(dtw->canvas_tbl),
- eventbox,
- 1, 2, 0, 1,
+ dtw->guides_lock,
+ 0, 1, 0, 1,
GTK_FILL, GTK_FILL,
0, 0);
+ gtk_table_attach(GTK_TABLE(dtw->canvas_tbl),
+ eventbox,
+ 1, 2, 0, 1,
+ GTK_FILL, GTK_FILL,
+ 0, 0);
#endif
-
+ g_signal_connect (G_OBJECT (dtw->guides_lock), "toggled", G_CALLBACK (sp_update_guides_lock), dtw);
gtk_box_pack_start( GTK_BOX(dtw->hbox), tbl, TRUE, TRUE, 1 );
/* Vertical ruler */
eventbox = gtk_event_box_new ();
dtw->vruler = sp_ruler_new(GTK_ORIENTATION_VERTICAL);
+
+ /* Vertical ruler */
dtw->vruler_box = eventbox;
sp_ruler_set_unit (SP_RULER (dtw->vruler), pt);
gtk_widget_set_tooltip_text (dtw->vruler_box, gettext(pt->name_plural.c_str()));
@@ -446,6 +471,9 @@ void SPDesktopWidget::init( SPDesktopWidget *dtw )
// Horizontal scrollbar
dtw->hadj = GTK_ADJUSTMENT(gtk_adjustment_new(0.0, -4000.0, 4000.0, 10.0, 100.0, 4.0));
+
+
+
#if GTK_CHECK_VERSION(3,0,0)
dtw->hscrollbar = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT (dtw->hadj));
gtk_grid_attach(GTK_GRID(dtw->canvas_tbl), dtw->hscrollbar, 1, 2, 1, 1);
@@ -1015,6 +1043,7 @@ sp_desktop_widget_event (GtkWidget *widget, GdkEvent *event, SPDesktopWidget *dt
return FALSE;
}
+
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
void sp_dtw_color_profile_event(EgeColorProfTracker */*tracker*/, SPDesktopWidget *dtw)
{
@@ -1036,6 +1065,27 @@ void sp_dtw_color_profile_event(EgeColorProfTracker */*tracker*/, SPDesktopWidge
}
#endif // defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
+void sp_update_guides_lock( GtkWidget */*button*/, gpointer data )
+{
+ SPDesktopWidget *dtw = SP_DESKTOP_WIDGET(data);
+
+ bool down = SP_BUTTON_IS_DOWN(dtw->guides_lock);
+
+ SPDocument *doc = dtw->desktop->getDocument();
+ SPNamedView *nv = dtw->desktop->getNamedView();
+ Inkscape::XML::Node *repr = nv->getRepr();
+
+ if ( down != nv->lockguides ) {
+ nv->lockguides = down;
+ sp_namedview_guides_toggle_lock(doc, repr);
+ if (down) {
+ dtw->setMessage (Inkscape::NORMAL_MESSAGE, _("Locked all guides"));
+ } else {
+ dtw->setMessage (Inkscape::NORMAL_MESSAGE, _("Unlocked all guides"));
+ }
+ }
+}
+
#if defined(HAVE_LIBLCMS1) || defined(HAVE_LIBLCMS2)
void cms_adjust_toggled( GtkWidget */*button*/, gpointer data )
{
@@ -1450,7 +1500,6 @@ sp_desktop_widget_maximize(SPDesktopWidget *dtw)
void
sp_desktop_widget_fullscreen(SPDesktopWidget *dtw)
{
-#ifdef HAVE_GTK_WINDOW_FULLSCREEN
GtkWindow *topw = GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(dtw->canvas)));
if (GTK_IS_WINDOW(topw)) {
if (dtw->desktop->is_fullscreen()) {
@@ -1474,7 +1523,6 @@ sp_desktop_widget_fullscreen(SPDesktopWidget *dtw)
// widget layout is triggered by the resulting window_state_event
}
}
-#endif /* HAVE_GTK_WINDOW_FULLSCREEN */
}
/**
@@ -1549,9 +1597,11 @@ void SPDesktopWidget::layoutWidgets()
}
if (!prefs->getBool(pref_root + "rulers/state", true)) {
+ gtk_widget_hide (dtw->guides_lock);
gtk_widget_hide (dtw->hruler);
gtk_widget_hide (dtw->vruler);
} else {
+ gtk_widget_show_all (dtw->guides_lock);
gtk_widget_show_all (dtw->hruler);
gtk_widget_show_all (dtw->vruler);
}
@@ -1684,6 +1734,7 @@ SPDesktopWidget* SPDesktopWidget::createInstance(SPNamedView *namedview)
/* Once desktop is set, we can update rulers */
sp_desktop_widget_update_rulers (dtw);
+ sp_button_toggle_set_down( SP_BUTTON(dtw->guides_lock), namedview->lockguides );
sp_view_widget_set_view (SP_VIEW_WIDGET (dtw), dtw->desktop);
@@ -1813,9 +1864,9 @@ bool SPDesktopWidget::onFocusInEvent(GdkEventFocus*)
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
if (prefs->getBool("/options/bitmapautoreload/value", true)) {
- GSList const *imageList = (desktop->doc())->getResourceList("image");
- for (GSList const *p = imageList; p; p = p->next) {
- SPImage* image = SP_IMAGE(p->data);
+ std::set<SPObject *> imageList = (desktop->doc())->getResourceList("image");
+ for (std::set<SPObject *>::const_iterator it = imageList.begin(); it != imageList.end(); ++it) {
+ SPImage* image = SP_IMAGE(*it);
sp_image_refresh_if_outdated( image );
}
}
@@ -2039,11 +2090,13 @@ void
sp_desktop_widget_toggle_rulers (SPDesktopWidget *dtw)
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- if (gtk_widget_get_visible (dtw->hruler)) {
+ if (gtk_widget_get_visible (dtw->guides_lock)) {
+ gtk_widget_hide (dtw->guides_lock);
gtk_widget_hide (dtw->hruler);
gtk_widget_hide (dtw->vruler);
prefs->setBool(dtw->desktop->is_fullscreen() ? "/fullscreen/rulers/state" : "/window/rulers/state", false);
} else {
+ gtk_widget_show_all (dtw->guides_lock);
gtk_widget_show_all (dtw->hruler);
gtk_widget_show_all (dtw->vruler);
prefs->setBool(dtw->desktop->is_fullscreen() ? "/fullscreen/rulers/state" : "/window/rulers/state", true);
@@ -2075,7 +2128,6 @@ bool sp_desktop_widget_color_prof_adj_enabled( SPDesktopWidget *dtw )
void sp_desktop_widget_toggle_color_prof_adj( SPDesktopWidget *dtw )
{
-
if ( gtk_widget_get_sensitive( dtw->cms_adjust ) ) {
if ( SP_BUTTON_IS_DOWN(dtw->cms_adjust) ) {
sp_button_toggle_set_down( SP_BUTTON(dtw->cms_adjust), FALSE );
@@ -2085,6 +2137,14 @@ void sp_desktop_widget_toggle_color_prof_adj( SPDesktopWidget *dtw )
}
}
+void sp_desktop_widget_toggle_guides_lock( SPDesktopWidget *dtw )
+{
+ if ( SP_BUTTON_IS_DOWN(dtw->guides_lock) ) {
+ sp_button_toggle_set_down( SP_BUTTON(dtw->guides_lock), FALSE );
+ } else {
+ sp_button_toggle_set_down( SP_BUTTON(dtw->guides_lock), TRUE );
+ }
+}
/* Unused
void
sp_spw_toggle_menubar (SPDesktopWidget *dtw, bool is_fullscreen)
diff --git a/src/widgets/desktop-widget.h b/src/widgets/desktop-widget.h
index 489217d9a..08966ad5f 100644
--- a/src/widgets/desktop-widget.h
+++ b/src/widgets/desktop-widget.h
@@ -49,6 +49,7 @@ void sp_desktop_widget_toggle_rulers (SPDesktopWidget *dtw);
void sp_desktop_widget_toggle_scrollbars (SPDesktopWidget *dtw);
void sp_desktop_widget_update_scrollbars (SPDesktopWidget *dtw, double scale);
void sp_desktop_widget_toggle_color_prof_adj( SPDesktopWidget *dtw );
+void sp_desktop_widget_toggle_guides_lock( SPDesktopWidget *dtw );
bool sp_desktop_widget_color_prof_adj_enabled( SPDesktopWidget *dtw );
void sp_dtw_desktop_activate (SPDesktopWidget *dtw);
@@ -87,6 +88,7 @@ struct SPDesktopWidget {
GtkWidget *hruler, *vruler;
GtkWidget *hruler_box, *vruler_box; // eventboxes for setting tooltips
+ GtkWidget *guides_lock;
GtkWidget *sticky_zoom;
GtkWidget *cms_adjust;
GtkWidget *coord_status;
@@ -181,6 +183,8 @@ struct SPDesktopWidget {
{ sp_desktop_widget_toggle_scrollbars (_dtw); }
virtual void toggleColorProfAdjust()
{ sp_desktop_widget_toggle_color_prof_adj(_dtw); }
+ virtual void toggleGuidesLock()
+ { sp_desktop_widget_toggle_guides_lock(_dtw); }
virtual bool colorProfAdjustEnabled()
{ return sp_desktop_widget_color_prof_adj_enabled(_dtw); }
virtual void updateZoom()
diff --git a/src/widgets/eraser-toolbar.cpp b/src/widgets/eraser-toolbar.cpp
index 1f79b50f2..45989936f 100644
--- a/src/widgets/eraser-toolbar.cpp
+++ b/src/widgets/eraser-toolbar.cpp
@@ -57,6 +57,13 @@ static void sp_erc_width_value_changed( GtkAdjustment *adj, GObject *tbl )
update_presets_list(tbl);
}
+static void sp_erc_mass_value_changed( GtkAdjustment *adj, GObject* tbl )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble( "/tools/eraser/mass", gtk_adjustment_get_value(adj) );
+ update_presets_list(tbl);
+}
+
static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl )
{
SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" ));
@@ -65,7 +72,18 @@ static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl )
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
prefs->setBool( "/tools/eraser/mode", eraserMode );
}
-
+ GtkAction *split = GTK_ACTION( g_object_get_data(tbl, "split") );
+ GtkAction *mass = GTK_ACTION( g_object_get_data(tbl, "mass") );
+ GtkAction *width = GTK_ACTION( g_object_get_data(tbl, "width") );
+ if(eraserMode == TRUE){
+ gtk_action_set_visible( split, TRUE );
+ gtk_action_set_visible( mass, TRUE );
+ gtk_action_set_visible( width, TRUE );
+ } else {
+ gtk_action_set_visible( split, FALSE );
+ gtk_action_set_visible( mass, FALSE );
+ gtk_action_set_visible( width, FALSE );
+ }
// only take action if run by the attr_changed listener
if (!g_object_get_data( tbl, "freeze" )) {
// in turn, prevent listener from responding
@@ -82,11 +100,20 @@ static void sp_erasertb_mode_changed( EgeSelectOneAction *act, GObject *tbl )
}
}
+static void sp_toogle_break_apart( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/eraser/break_apart", active);
+}
+
void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
{
+ Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gint eraserMode = FALSE;
{
GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
-
GtkTreeIter iter;
gtk_list_store_append( model, &iter );
gtk_list_store_set( model, &iter,
@@ -113,29 +140,70 @@ void sp_eraser_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb
ege_select_one_action_set_icon_column( act, 2 );
ege_select_one_action_set_tooltip_column( act, 1 );
- /// @todo Convert to boolean?
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- gint eraserMode = prefs->getBool("/tools/eraser/mode") ? 1 : 0;
+ eraserMode = prefs->getBool("/tools/eraser/mode") ? TRUE : FALSE;
ege_select_one_action_set_active( act, eraserMode );
g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_erasertb_mode_changed), holder );
}
{
/* Width */
- gchar const* labels[] = {_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
- gdouble values[] = {1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
+ gchar const* labels[] = {_("(no width)"),_("(hairline)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad stroke)")};
+ gdouble values[] = {0, 1, 3, 5, 10, 15, 20, 30, 50, 75, 100};
EgeAdjustmentAction *eact = create_adjustment_action( "EraserWidthAction",
_("Pen Width"), _("Width:"),
_("The width of the eraser pen (relative to the visible canvas area)"),
"/tools/eraser/width", 15,
GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-eraser",
- 1, 100, 1.0, 10.0,
+ 0, 100, 1.0, 10.0,
labels, values, G_N_ELEMENTS(labels),
sp_erc_width_value_changed, NULL /*unit tracker*/, 1, 0);
ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+ g_object_set_data( holder, "width", eact );
gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
}
+ {
+ /* Mass */
+ gchar const* labels[] = {_("(no inertia)"), _("(slight smoothing, default)"), _("(noticeable lagging)"), 0, 0, _("(maximum inertia)")};
+ gdouble values[] = {0.0, 2, 10, 20, 50, 100};
+ EgeAdjustmentAction* eact = create_adjustment_action( "EraserMassAction",
+ _("Eraser Mass"), _("Mass:"),
+ _("Increase to make the eraser drag behind, as if slowed by inertia"),
+ "/tools/eraser/mass", 10.0,
+ GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
+ 0.0, 100, 1, 10.0,
+ labels, values, G_N_ELEMENTS(labels),
+ sp_erc_mass_value_changed, NULL /*unit tracker*/, 1, 0);
+ ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
+ g_object_set_data( holder, "mass", eact );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+ gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+ }
+ /* Overlap */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "EraserBreakAppart",
+ _("Break appart cutted items"),
+ _("Break appart cutted itemss"),
+ INKSCAPE_ICON("distribute-randomize"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/eraser/break_apart", false) );
+ g_object_set_data( holder, "split", act );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toogle_break_apart), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ GtkAction *split = GTK_ACTION( g_object_get_data(holder, "split") );
+ GtkAction *mass = GTK_ACTION( g_object_get_data(holder, "mass") );
+ GtkAction *width = GTK_ACTION( g_object_get_data(holder, "width") );
+ if(eraserMode == TRUE){
+ gtk_action_set_visible( split, TRUE );
+ gtk_action_set_visible( mass, TRUE );
+ gtk_action_set_visible( width, TRUE );
+ } else {
+ gtk_action_set_visible( split, FALSE );
+ gtk_action_set_visible( mass, FALSE );
+ gtk_action_set_visible( width, FALSE );
+ }
}
diff --git a/src/widgets/fill-style.cpp b/src/widgets/fill-style.cpp
index fa5eabab4..a96776894 100644
--- a/src/widgets/fill-style.cpp
+++ b/src/widgets/fill-style.cpp
@@ -68,7 +68,7 @@ namespace Inkscape {
class FillNStroke : public Gtk::VBox
{
public:
- FillNStroke( FillOrStroke kind );
+ FillNStroke( FillOrStroke k );
~FillNStroke();
void setFillrule( SPPaintSelector::FillRule mode );
@@ -125,9 +125,9 @@ Gtk::Widget *Inkscape::Widgets::createStyleWidget( FillOrStroke kind )
return filler;
}
-FillNStroke::FillNStroke( FillOrStroke kind ) :
+FillNStroke::FillNStroke( FillOrStroke k ) :
Gtk::VBox(),
- kind(kind),
+ kind(k),
desktop(0),
psel(0),
lastDrag(0),
@@ -570,7 +570,7 @@ void FillNStroke::updateFromPaint()
}
}
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){
//FIXME: see above
if (kind == FILL) {
sp_repr_css_change_recursive((*i)->getRepr(), css, "style");
@@ -596,7 +596,7 @@ void FillNStroke::updateFromPaint()
// We have changed from another gradient type, or modified spread/units within
// this gradient type.
vector = sp_gradient_ensure_vector_normalized(vector);
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){
//FIXME: see above
if (kind == FILL) {
sp_repr_css_change_recursive((*i)->getRepr(), css, "style");
@@ -642,7 +642,7 @@ void FillNStroke::updateFromPaint()
// cannot just call sp_desktop_set_style, because we don't want to touch those
// objects who already have the same root pattern but through a different href
// chain. FIXME: move this to a sp_item_set_pattern
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end(); ++i){
Inkscape::XML::Node *selrepr = (*i)->getRepr();
if ( (kind == STROKE) && !selrepr) {
continue;
diff --git a/src/widgets/gradient-selector.cpp b/src/widgets/gradient-selector.cpp
index 402f30846..604ecd108 100644
--- a/src/widgets/gradient-selector.cpp
+++ b/src/widgets/gradient-selector.cpp
@@ -17,10 +17,6 @@
# include "config.h"
#endif
-#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
-#include <glibmm/threads.h>
-#endif
-
#include <gtkmm/treeview.h>
#include "gradient-vector.h"
@@ -555,6 +551,10 @@ sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *s
if (gr) {
repr = gr->getRepr()->duplicate(xml_doc);
+ // Rename the new gradients id to be similar to the cloned gradients
+ Glib::ustring old_id = gr->getId();
+ rename_id(gr, old_id);
+ doc->getDefs()->getRepr()->addChild(repr, NULL);
} else {
repr = xml_doc->createElement("svg:linearGradient");
Inkscape::XML::Node *stop = xml_doc->createElement("svg:stop");
@@ -567,17 +567,10 @@ sp_gradient_selector_add_vector_clicked (GtkWidget */*w*/, SPGradientSelector *s
stop->setAttribute("style", "stop-color:#fff;stop-opacity:1;");
repr->appendChild(stop);
Inkscape::GC::release(stop);
+ doc->getDefs()->getRepr()->addChild(repr, NULL);
+ gr = SP_GRADIENT(doc->getObjectByRepr(repr));
}
-
- doc->getDefs()->getRepr()->addChild(repr, NULL);
-
- Glib::ustring old_id = gr->getId();
-
- gr = SP_GRADIENT(doc->getObjectByRepr(repr));
-
- // Rename the new gradients id to be similar to the cloned gradients
- rename_id(gr, old_id);
-
+
sp_gradient_vector_selector_set_gradient( SP_GRADIENT_VECTOR_SELECTOR (sel->vectors), doc, gr);
sel->selectGradientInTree(gr);
diff --git a/src/widgets/gradient-toolbar.cpp b/src/widgets/gradient-toolbar.cpp
index 6743dd23a..858aa05db 100644
--- a/src/widgets/gradient-toolbar.cpp
+++ b/src/widgets/gradient-toolbar.cpp
@@ -106,10 +106,10 @@ void gr_apply_gradient(Inkscape::Selection *selection, GrDrag *drag, SPGradient
// GRADIENTFIXME: make this work for multiple selected draggers.
// First try selected dragger
- if (drag && drag->selected) {
- GrDragger *dragger = static_cast<GrDragger*>(drag->selected->data);
- for (GSList const* i = dragger->draggables; i != NULL; i = i->next) { // for all draggables of dragger
- GrDraggable *draggable = static_cast<GrDraggable*>(i->data);
+ if (drag && !drag->selected.empty()) {
+ GrDragger *dragger = *(drag->selected.begin());
+ for(std::vector<GrDraggable *>::const_iterator i = dragger->draggables.begin(); i != dragger->draggables.end(); ++i) { //for all draggables of dragger
+ GrDraggable *draggable = *i;
gr_apply_gradient_to_item(draggable->item, gr, initialType, initialMode, draggable->fill_or_stroke);
}
return;
@@ -117,7 +117,7 @@ void gr_apply_gradient(Inkscape::Selection *selection, GrDrag *drag, SPGradient
// If no drag or no dragger selected, act on selection
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
gr_apply_gradient_to_item(*i, gr, initialType, initialMode, initialMode);
}
}
@@ -139,19 +139,18 @@ gboolean gr_vector_list(GtkWidget *combo_box, SPDesktop *desktop, bool selection
/* Clear old list, if there is any */
gtk_list_store_clear(store);
- GSList *gl = NULL;
- const GSList *gradients = document->getResourceList("gradient");
- for (const GSList *i = gradients; i != NULL; i = i->next) {
- SPGradient *grad = SP_GRADIENT(i->data);
+ std::vector<SPObject *> gl;
+ std::set<SPObject *> gradients = document->getResourceList( "gradient" );
+ for (std::set<SPObject *>::const_iterator it = gradients.begin(); it != gradients.end(); ++it) {
+ SPGradient *grad = SP_GRADIENT(*it);
if ( grad->hasStops() && !grad->isSolid() ) {
- gl = g_slist_prepend(gl, i->data);
+ gl.push_back(*it);
}
}
- gl = g_slist_reverse(gl);
guint pos = 0;
- if (!gl) {
+ if (gl.empty()) {
// The document has no gradients
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, _("No gradient"), 1, NULL, 2, NULL, -1);
@@ -180,9 +179,8 @@ gboolean gr_vector_list(GtkWidget *combo_box, SPDesktop *desktop, bool selection
}
guint idx = 0;
- while (gl) {
- SPGradient *gradient = SP_GRADIENT(gl->data);
- gl = g_slist_remove(gl, gradient);
+ for (std::vector<SPObject *>::const_iterator it = gl.begin(); it != gl.end(); ++it) {
+ SPGradient *gradient = SP_GRADIENT(*it);
Glib::ustring label = gr_prepare_label(gradient);
GdkPixbuf *pixb = sp_gradient_to_pixbuf(gradient, 64, 16);
@@ -219,7 +217,7 @@ void gr_get_dt_selected_gradient(Inkscape::Selection *selection, SPGradient *&gr
SPGradient *gradient = 0;
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;// get the items gradient, not the getVector() version
SPStyle *style = item->style;
SPPaintServer *server = 0;
@@ -255,11 +253,11 @@ void gr_read_selection( Inkscape::Selection *selection,
SPGradientSpread &spr_selected,
bool &spr_multi )
{
- if (drag && drag->selected) {
+ if (drag && !drag->selected.empty()) {
// GRADIENTFIXME: make this work for more than one selected dragger?
- GrDragger *dragger = static_cast<GrDragger*>(drag->selected->data);
- for (GSList const* i = dragger->draggables; i; i = i->next) { // for all draggables of dragger
- GrDraggable *draggable = static_cast<GrDraggable *>(i->data);
+ GrDragger *dragger = *(drag->selected.begin());
+ for(std::vector<GrDraggable *>::const_iterator i = dragger->draggables.begin(); i != dragger->draggables.end(); ++i) { //for all draggables of dragger
+ GrDraggable *draggable = *i;
SPGradient *gradient = sp_item_gradient_get_vector(draggable->item, draggable->fill_or_stroke);
SPGradientSpread spread = sp_item_gradient_get_spread(draggable->item, draggable->fill_or_stroke);
@@ -287,7 +285,7 @@ void gr_read_selection( Inkscape::Selection *selection,
// If no selected dragger, read desktop selection
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
SPStyle *style = item->style;
@@ -394,10 +392,10 @@ static void gr_tb_selection_changed(Inkscape::Selection * /*selection*/, gpointe
}
InkAction *add = (InkAction *) g_object_get_data(G_OBJECT(widget), "gradient_stops_add_action");
- gtk_action_set_sensitive(GTK_ACTION(add), (gr_selected && !gr_multi && drag && drag->selected));
+ gtk_action_set_sensitive(GTK_ACTION(add), (gr_selected && !gr_multi && drag && !drag->selected.empty()));
InkAction *del = (InkAction *) g_object_get_data(G_OBJECT(widget), "gradient_stops_delete_action");
- gtk_action_set_sensitive(GTK_ACTION(del), (gr_selected && !gr_multi && drag && drag->selected));
+ gtk_action_set_sensitive(GTK_ACTION(del), (gr_selected && !gr_multi && drag && !drag->selected.empty()));
InkAction *reverse = (InkAction *) g_object_get_data(G_OBJECT(widget), "gradient_stops_reverse_action");
gtk_action_set_sensitive(GTK_ACTION(reverse), (gr_selected!= NULL));
@@ -649,7 +647,7 @@ static void select_stop_by_drag(GtkWidget *combo_box, SPGradient *gradient, Tool
GrDrag *drag = ev->get_drag();
- if (!drag || !drag->selected) {
+ if (!drag || drag->selected.empty()) {
blocked = TRUE;
gtk_combo_box_set_active(GTK_COMBO_BOX(combo_box) , 0);
gr_stop_set_offset(GTK_COMBO_BOX(combo_box), data);
@@ -660,11 +658,10 @@ static void select_stop_by_drag(GtkWidget *combo_box, SPGradient *gradient, Tool
gint n = 0;
// for all selected draggers
- for (GList *i = drag->selected; i != NULL; i = i->next) {
- GrDragger *dragger = static_cast<GrDragger*>(i->data);
- // for all draggables of dragger
- for (GSList const* j = dragger->draggables; j != NULL; j = j->next) {
- GrDraggable *draggable = static_cast<GrDraggable*>(j->data);
+ for(std::set<GrDragger *>::const_iterator i = drag->selected.begin(); i != drag->selected.end(); ++i) { //for all draggables of dragger
+ GrDragger *dragger = *i;
+ for(std::vector<GrDraggable *>::const_iterator j = dragger->draggables.begin(); j != dragger->draggables.end(); ++j) { //for all draggables of dragger
+ GrDraggable *draggable = *j;
if (draggable->point_type != POINT_RG_FOCUS) {
n++;
@@ -766,25 +763,25 @@ static gboolean update_stop_list( GtkWidget *stop_combo, SPGradient *gradient, S
}
/* Populate the combobox store */
- GSList *sl = NULL;
+ std::vector<SPObject *> sl;
if ( gradient->hasStops() ) {
for ( SPObject *ochild = gradient->firstChild() ; ochild ; ochild = ochild->getNext() ) {
if (SP_IS_STOP(ochild)) {
- sl = g_slist_append(sl, ochild);
+ sl.push_back(ochild);
}
}
}
- if (!sl) {
+ if (sl.empty()) {
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, _("No stops in gradient"), 1, NULL, 2, NULL, -1);
sensitive = FALSE;
} else {
- for (; sl != NULL; sl = sl->next){
- if (SP_IS_STOP(sl->data)){
- SPStop *stop = SP_STOP(sl->data);
- Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(sl->data)->getRepr();
+ for (std::vector<SPObject *>::const_iterator it = sl.begin(); it != sl.end(); ++it) {
+ if (SP_IS_STOP(*it)){
+ SPStop *stop = SP_STOP(*it);
+ Inkscape::XML::Node *repr = reinterpret_cast<SPItem *>(*it)->getRepr();
Inkscape::UI::Widget::ColorPreview *cpv = Gtk::manage(new Inkscape::UI::Widget::ColorPreview(stop->get_rgba32()));
GdkPixbuf *pb = cpv->toPixbuf(32, 16);
Glib::ustring label = gr_ellipsize_text(repr->attribute("id"), 25);
diff --git a/src/widgets/gradient-vector.cpp b/src/widgets/gradient-vector.cpp
index 259d4c9af..35c1e4a8d 100644
--- a/src/widgets/gradient-vector.cpp
+++ b/src/widgets/gradient-vector.cpp
@@ -298,11 +298,11 @@ static void sp_gvs_rebuild_gui_full(SPGradientVectorSelector *gvs)
/* Pick up all gradients with vectors */
GSList *gl = NULL;
if (gvs->gr) {
- const GSList *gradients = gvs->gr->document->getResourceList("gradient");
- for (const GSList *curr = gradients; curr; curr = curr->next) {
- SPGradient* grad = SP_GRADIENT(curr->data);
+ std::set<SPObject *> gradients = gvs->gr->document->getResourceList("gradient");
+ for (std::set<SPObject *>::const_iterator it = gradients.begin(); it != gradients.end(); ++it) {
+ SPGradient* grad = SP_GRADIENT(*it);
if ( grad->hasStops() && (grad->isSwatch() == gvs->swatched) ) {
- gl = g_slist_prepend(gl, curr->data);
+ gl = g_slist_prepend(gl, *it);
}
}
}
@@ -842,7 +842,8 @@ static GtkWidget * sp_gradient_vector_widget_new(SPGradient *gradient, SPStop *s
GtkWidget *vb, *w, *f;
- g_return_val_if_fail(!gradient || SP_IS_GRADIENT(gradient), NULL);
+ g_return_val_if_fail(gradient != NULL, NULL);
+ g_return_val_if_fail(SP_IS_GRADIENT(gradient), NULL);
#if GTK_CHECK_VERSION(3,0,0)
vb = gtk_box_new(GTK_ORIENTATION_VERTICAL, PAD);
diff --git a/src/widgets/measure-toolbar.cpp b/src/widgets/measure-toolbar.cpp
index 5a4785b1f..990989f4a 100644
--- a/src/widgets/measure-toolbar.cpp
+++ b/src/widgets/measure-toolbar.cpp
@@ -33,11 +33,16 @@
#include "measure-toolbar.h"
#include "desktop.h"
+#include "inkscape.h"
+#include "message-stack.h"
#include "document-undo.h"
#include "widgets/ege-adjustment-action.h"
#include "widgets/ege-output-action.h"
#include "preferences.h"
#include "toolbox.h"
+#include "widgets/ink-action.h"
+#include "ui/icon-names.h"
+#include "ui/tools/measure-tool.h"
#include "ui/widget/unit-tracker.h"
using Inkscape::UI::Widget::UnitTracker;
@@ -45,11 +50,26 @@ using Inkscape::Util::Unit;
using Inkscape::DocumentUndo;
using Inkscape::UI::ToolboxFactory;
using Inkscape::UI::PrefPusher;
+using Inkscape::UI::Tools::MeasureTool;
//########################
//## Measure Toolbox ##
//########################
+/** Temporary hack: Returns the node tool in the active desktop.
+ * Will go away during tool refactoring. */
+static MeasureTool *get_measure_tool()
+{
+ MeasureTool *tool = 0;
+ if (SP_ACTIVE_DESKTOP ) {
+ Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context;
+ if (SP_IS_MEASURE_CONTEXT(ec)) {
+ tool = static_cast<MeasureTool*>(ec);
+ }
+ }
+ return tool;
+}
+
static void
sp_measure_fontsize_value_changed(GtkAdjustment *adj, GObject *tbl)
{
@@ -57,17 +77,184 @@ sp_measure_fontsize_value_changed(GtkAdjustment *adj, GObject *tbl)
if (DocumentUndo::getUndoSensitive(desktop->getDocument())) {
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
- prefs->setInt(Glib::ustring("/tools/measure/fontsize"),
+ prefs->setDouble(Glib::ustring("/tools/measure/fontsize"),
+ gtk_adjustment_get_value(adj));
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+ }
+}
+
+static void
+sp_measure_offset_value_changed(GtkAdjustment *adj, GObject *tbl)
+{
+ SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" ));
+
+ if (DocumentUndo::getUndoSensitive(desktop->getDocument())) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble(Glib::ustring("/tools/measure/offset"),
gtk_adjustment_get_value(adj));
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
}
}
-static void measure_unit_changed(GtkAction* /*act*/, GObject* tbl)
+static void sp_measure_scale_value_changed(GtkAdjustment *adj, GObject *tbl)
+{
+ SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" ));
+
+ if (DocumentUndo::getUndoSensitive(desktop->getDocument())) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble(Glib::ustring("/tools/measure/scale"),
+ gtk_adjustment_get_value(adj));
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+ }
+}
+
+static void
+sp_measure_precision_value_changed(GtkAdjustment *adj, GObject *tbl)
+{
+ SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( tbl, "desktop" ));
+
+ if (DocumentUndo::getUndoSensitive(desktop->getDocument())) {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setInt(Glib::ustring("/tools/measure/precision"),
+ gtk_adjustment_get_value(adj));
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+ }
+}
+
+static void
+sp_measure_unit_changed(GtkAction* /*act*/, GObject* tbl)
{
UnitTracker* tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker"));
Glib::ustring const unit = tracker->getActiveUnit()->abbr;
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
prefs->setString("/tools/measure/unit", unit);
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+}
+
+static void
+sp_toggle_ignore_1st_and_last( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/measure/ignore_1st_and_last", active);
+ SPDesktop *desktop = static_cast<SPDesktop *>(data);
+ if ( active ) {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Start and end measures inactive."));
+ } else {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Start and end measures active."));
+ }
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+}
+
+static void
+sp_toggle_show_hidden( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/measure/show_hidden", active);
+ SPDesktop *desktop = static_cast<SPDesktop *>(data);
+ if ( active ) {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Show all crossings."));
+ } else {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Show visible crossings."));
+ }
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+}
+
+static void
+sp_toggle_all_layers( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/measure/all_layers", active);
+ SPDesktop *desktop = static_cast<SPDesktop *>(data);
+ if ( active ) {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Use all layers in the measure."));
+ } else {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Use current layer in the measure."));
+ }
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+}
+
+static void
+sp_toggle_show_in_between( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/measure/show_in_between", active);
+ SPDesktop *desktop = static_cast<SPDesktop *>(data);
+ if ( active ) {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Compute all elements."));
+ } else {
+ desktop->messageStack()->flash(Inkscape::INFORMATION_MESSAGE, _("Compute max length."));
+ }
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->showCanvasItems();
+ }
+}
+static void
+sp_reverse_knots(void){
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->reverseKnots();
+ }
+}
+
+static void
+sp_to_mark_dimension(void){
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->toMarkDimension();
+ }
+}
+
+static void
+sp_to_guides(void){
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->toGuides();
+ }
+}
+
+static void
+sp_to_phantom(void){
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->toPhantom();
+ }
+}
+
+static void
+sp_to_item(void){
+ MeasureTool *mt = get_measure_tool();
+ if (mt) {
+ mt->toItem();
+ }
}
void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObject* holder)
@@ -79,22 +266,22 @@ void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, G
g_object_set_data( holder, "tracker", tracker );
EgeAdjustmentAction *eact = 0;
+ Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
/* Font Size */
{
eact = create_adjustment_action( "MeasureFontSizeAction",
_("Font Size"), _("Font Size:"),
_("The font size to be used in the measurement labels"),
- "/tools/measure/fontsize", 0.0,
+ "/tools/measure/fontsize", 10.0,
GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
- 10, 36, 1.0, 4.0,
+ 1.0, 36.0, 1.0, 4.0,
0, 0, 0,
- sp_measure_fontsize_value_changed);
- gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+ sp_measure_fontsize_value_changed, NULL, 0 , 2);
+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact));
}
-
- // units label
+ /* units label */
{
EgeOutputAction* act = ege_output_action_new( "measure_units_label", _("Units:"), _("The units to be used for the measurements"), 0 );
ege_output_action_set_use_markup( act, TRUE );
@@ -102,12 +289,146 @@ void sp_measure_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, G
gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
}
- // units menu
+ /* units menu */
{
GtkAction* act = tracker->createAction( "MeasureUnitsAction", _("Units:"), _("The units to be used for the measurements") );
- g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(measure_unit_changed), holder );
+ g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_measure_unit_changed), holder );
gtk_action_group_add_action( mainActions, act );
}
+
+ /* Precission */
+ {
+ eact = create_adjustment_action( "MeasurePrecisionAction",
+ _("Precision"), _("Precision:"),
+ _("Decimal precision of measure"),
+ "/tools/measure/precision", 2,
+ GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
+ 0, 10, 1, 0,
+ 0, 0, 0,
+ sp_measure_precision_value_changed, NULL, 0 ,0);
+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact));
+ }
+
+ /* Scale */
+ {
+ eact = create_adjustment_action( "MeasureScaleAction",
+ _("Scale %"), _("Scale %:"),
+ _("Scale the results"),
+ "/tools/measure/scale", 100.0,
+ GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
+ 0.0, 90000.0, 1.0, 4.0,
+ 0, 0, 0,
+ sp_measure_scale_value_changed, NULL, 0 , 3);
+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+ }
+
+ /* Offset */
+ {
+ eact = create_adjustment_action( "MeasureOffsetAction",
+ _("Offset"), _("Offset:"),
+ _("The offset size"),
+ "/tools/measure/offset", 5.0,
+ GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
+ 0.0, 90000.0, 1.0, 4.0,
+ 0, 0, 0,
+ sp_measure_offset_value_changed, NULL, 0 , 2);
+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+ }
+
+ /* ignore_1st_and_last */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "MeasureIgnore1stAndLast",
+ _("Ignore first and last"),
+ _("Ignore first and last"),
+ INKSCAPE_ICON("draw-geometry-line-segment"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/ignore_1st_and_last", true) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_ignore_1st_and_last), desktop) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* only visible */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "MeasureShowHidden",
+ _("Show hidden intersections"),
+ _("Show hidden intersections"),
+ INKSCAPE_ICON("object-hidden"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/show_hidden", true) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_show_hidden), desktop) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* measure imbetweens */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "MeasureInBettween",
+ _("Show measures between items"),
+ _("Show measures between items"),
+ INKSCAPE_ICON("distribute-randomize"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/show_in_between", true) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_show_in_between), desktop) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* measure only current layer */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "MeasureAllLayers",
+ _("Measure all layers"),
+ _("Measure all layers"),
+ INKSCAPE_ICON("dialog-layers"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/measure/all_layers", true) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_all_layers), desktop) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* toogle start end */
+ {
+ InkAction* act = ink_action_new( "MeasureReverse",
+ _("Reverse measure"),
+ _("Reverse measure"),
+ INKSCAPE_ICON("draw-geometry-mirror"),
+ secondarySize );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_reverse_knots), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* phantom measure */
+ {
+ InkAction* act = ink_action_new( "MeasureToPhantom",
+ _("Phantom measure"),
+ _("Phantom measure"),
+ INKSCAPE_ICON("selection-make-bitmap-copy"),
+ secondarySize );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_to_phantom), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* to guides */
+ {
+ InkAction* act = ink_action_new( "MeasureToGuides",
+ _("To guides"),
+ _("To guides"),
+ INKSCAPE_ICON("guides"),
+ secondarySize );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_to_guides), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* to mark dimensions */
+ {
+ InkAction* act = ink_action_new( "MeasureMarkDimension",
+ _("Mark Dimension"),
+ _("Mark Dimension"),
+ INKSCAPE_ICON("tool-pointer"),
+ secondarySize );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_to_mark_dimension), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* to item */
+ {
+ InkAction* act = ink_action_new( "MeasureToItem",
+ _("Convert to item"),
+ _("Convert to item"),
+ INKSCAPE_ICON("path-reverse"),
+ secondarySize );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(sp_to_item), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
} // end of sp_measure_toolbox_prep()
diff --git a/src/widgets/mesh-toolbar.cpp b/src/widgets/mesh-toolbar.cpp
index 1af55d9cd..3643ce00c 100644
--- a/src/widgets/mesh-toolbar.cpp
+++ b/src/widgets/mesh-toolbar.cpp
@@ -34,6 +34,7 @@
#include "widgets/gradient-image.h"
#include "style.h"
+#include "inkscape.h"
#include "preferences.h"
#include "document-private.h"
#include "document-undo.h"
@@ -66,6 +67,7 @@
using Inkscape::DocumentUndo;
using Inkscape::UI::ToolboxFactory;
using Inkscape::UI::PrefPusher;
+using Inkscape::UI::Tools::MeshTool;
static bool blocked = false;
@@ -88,7 +90,7 @@ void ms_read_selection( Inkscape::Selection *selection,
ms_type = SP_MESH_TYPE_COONS;
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
SPStyle *style = item->style;
@@ -215,7 +217,7 @@ void ms_get_dt_selected_gradient(Inkscape::Selection *selection, SPMesh *&ms_sel
SPMesh *gradient = 0;
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;// get the items gradient, not the getVector() version
SPStyle *style = item->style;
SPPaintServer *server = 0;
@@ -290,6 +292,9 @@ static void ms_col_changed(GtkAdjustment *adj, GObject * /*tbl*/ )
blocked = FALSE;
}
+/**
+ * Sets mesh type: Coons, Bicubic
+ */
static void ms_type_changed(EgeSelectOneAction *act, GtkWidget *widget)
{
// std::cout << "ms_type_changed" << std::endl;
@@ -309,15 +314,54 @@ static void ms_type_changed(EgeSelectOneAction *act, GtkWidget *widget)
gradient->type_set = true;
gradient->updateRepr();
- DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_GRADIENT,
+ DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_MESH,
_("Set mesh type"));
}
}
+/** Temporary hack: Returns the mesh tool in the active desktop.
+ * Will go away during tool refactoring. */
+static MeshTool *get_mesh_tool()
+{
+ MeshTool *tool = 0;
+ if (SP_ACTIVE_DESKTOP ) {
+ Inkscape::UI::Tools::ToolBase *ec = SP_ACTIVE_DESKTOP->event_context;
+ if (SP_IS_MESH_CONTEXT(ec)) {
+ tool = static_cast<MeshTool*>(ec);
+ }
+ }
+ return tool;
+}
+
+static void ms_toggle_sides(void)
+{
+ MeshTool *mt = get_mesh_tool();
+ if (mt) {
+ sp_mesh_context_corner_operation( mt, MG_CORNER_SIDE_TOGGLE );
+ }
+}
+
+static void ms_make_elliptical(void)
+{
+ MeshTool *mt = get_mesh_tool();
+ if (mt) {
+ sp_mesh_context_corner_operation( mt, MG_CORNER_SIDE_ARC );
+ }
+}
+
+static void ms_pick_colors(void)
+{
+ MeshTool *mt = get_mesh_tool();
+ if (mt) {
+ sp_mesh_context_corner_operation( mt, MG_CORNER_COLOR_PICK );
+ }
+}
+
static void mesh_toolbox_watch_ec(SPDesktop* dt, Inkscape::UI::Tools::ToolBase* ec, GObject* holder);
/**
* Mesh auxiliary toolbar construction and setup.
+ * Don't forget to add to XML in widgets/toolbox.cpp!
*
*/
void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObject* holder)
@@ -389,14 +433,14 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj
/* Number of mesh rows */
{
- gchar const* labels[] = {};
+ gchar const** labels = NULL;
gdouble values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
eact = create_adjustment_action( "MeshRowAction",
_("Rows"), _("Rows:"), _("Number of rows in new mesh"),
"/tools/mesh/mesh_rows", 1,
GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
1, 20, 1, 1,
- labels, values, G_N_ELEMENTS(labels),
+ labels, values, 0,
ms_row_changed, NULL /*unit tracker*/,
1.0, 0 );
gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
@@ -405,14 +449,14 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj
/* Number of mesh columns */
{
- gchar const* labels[] = {};
+ gchar const** labels = NULL;
gdouble values[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
eact = create_adjustment_action( "MeshColumnAction",
_("Columns"), _("Columns:"), _("Number of columns in new mesh"),
"/tools/mesh/mesh_cols", 1,
GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
1, 20, 1, 1,
- labels, values, G_N_ELEMENTS(labels),
+ labels, values, 0,
ms_col_changed, NULL /*unit tracker*/,
1.0, 0 );
gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
@@ -466,7 +510,7 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj
gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
}
- /* Typeing method */
+ /* Type */
{
GtkListStore* model = gtk_list_store_new( 2, G_TYPE_STRING, G_TYPE_INT );
@@ -487,6 +531,41 @@ void sp_mesh_toolbox_prep(SPDesktop * desktop, GtkActionGroup* mainActions, GObj
gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
g_object_set_data( holder, "mesh_select_type_action", act );
}
+
+ {
+ InkAction* act = ink_action_new( "MeshToggleSidesAction",
+ _("Toggle Sides"),
+ _("Toggle selected sides between Beziers and lines."),
+ INKSCAPE_ICON("node-segment-line"),
+ secondarySize );
+ g_object_set( act, "short_label", _("Toggle side:"), NULL );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_toggle_sides), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+
+ {
+ InkAction* act = ink_action_new( "MeshMakeEllipticalAction",
+ _("Make elliptical"),
+ _("Make selected sides elliptical by changing length of handles. Works best if handles already approximate ellipse."),
+ INKSCAPE_ICON("node-segment-curve"),
+ secondarySize );
+ g_object_set( act, "short_label", _("Make elliptical:"), NULL );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_make_elliptical), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+
+ {
+ InkAction* act = ink_action_new( "MeshPickColorsAction",
+ _("Pick colors:"),
+ _("Pick colors for selected corner nodes from underneath mesh."),
+ INKSCAPE_ICON("color-picker"),
+ secondarySize );
+ g_object_set( act, "short_label", _("Pick Color"), NULL );
+ g_signal_connect_after( G_OBJECT(act), "activate", G_CALLBACK(ms_pick_colors), 0 );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+
+
}
static void mesh_toolbox_watch_ec(SPDesktop* desktop, Inkscape::UI::Tools::ToolBase* ec, GObject* holder)
diff --git a/src/widgets/paint-selector.cpp b/src/widgets/paint-selector.cpp
index 846ded511..602cad3c3 100644
--- a/src/widgets/paint-selector.cpp
+++ b/src/widgets/paint-selector.cpp
@@ -844,10 +844,10 @@ ink_pattern_list_get (SPDocument *source)
return NULL;
GSList *pl = NULL;
- GSList const *patterns = source->getResourceList("pattern");
- for (GSList *l = const_cast<GSList *>(patterns); l != NULL; l = l->next) {
- if (SP_PATTERN(l->data) == SP_PATTERN(l->data)->rootPattern()) { // only if this is a root pattern
- pl = g_slist_prepend(pl, l->data);
+ std::set<SPObject *> patterns = source->getResourceList("pattern");
+ for (std::set<SPObject *>::const_iterator it = patterns.begin(); it != patterns.end(); ++it) {
+ if (SP_PATTERN(*it) == SP_PATTERN(*it)->rootPattern()) { // only if this is a root pattern
+ pl = g_slist_prepend(pl, *it);
}
}
@@ -972,7 +972,7 @@ ink_pattern_menu(GtkWidget *combo)
}
- // Select the first item that is not a seperator
+ // Select the first item that is not a separator
if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL(store), &iter)) {
gboolean sep = false;
gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, COMBO_COL_SEP, &sep, -1);
diff --git a/src/widgets/pencil-toolbar.cpp b/src/widgets/pencil-toolbar.cpp
index 1214a378a..55127206c 100644
--- a/src/widgets/pencil-toolbar.cpp
+++ b/src/widgets/pencil-toolbar.cpp
@@ -28,11 +28,12 @@
# include "config.h"
#endif
+#include <gtkmm.h>
#include <glibmm/i18n.h>
+#include <list>
#include "pencil-toolbar.h"
#include "desktop.h"
-#include "document-undo.h"
#include "widgets/ege-adjustment-action.h"
#include "widgets/ege-select-one-action.h"
#include "widgets/ink-action.h"
@@ -43,9 +44,17 @@
#include "ui/tools/pen-tool.h"
#include "ui/uxmanager.h"
#include "widgets/spinbutton-events.h"
+#include <selection.h>
+#include "display/curve.h"
+#include "live_effects/effect.h"
+#include "live_effects/lpe-simplify.h"
+#include "live_effects/lpe-powerstroke.h"
+#include "live_effects/effect-enum.h"
+#include "live_effects/lpeobject.h"
+#include "live_effects/lpeobject-reference.h"
+#include "sp-lpe-item.h"
using Inkscape::UI::UXManager;
-using Inkscape::DocumentUndo;
using Inkscape::UI::ToolboxFactory;
using Inkscape::UI::PrefPusher;
@@ -151,6 +160,13 @@ static void freehand_change_shape(EgeSelectOneAction* act, GObject *dataKludge)
prefs->setInt(freehand_tool_name(dataKludge) + "/shape", shape);
}
+static void freehand_simplify_lpe(InkToggleAction* itact, GObject *dataKludge) {
+ gint simplify = gtk_toggle_action_get_active( GTK_TOGGLE_ACTION(itact) );
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setInt(freehand_tool_name(dataKludge) + "/simplify", simplify);
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(dataKludge, "flatten_simplify") ), simplify );
+}
+
/**
* Generate the list of freehand advanced shape option entries.
*/
@@ -162,6 +178,7 @@ static GList * freehand_shape_dropdown_items_list() {
glist = g_list_append (glist, _("Triangle out"));
glist = g_list_append (glist, _("Ellipse"));
glist = g_list_append (glist, _("From clipboard"));
+ glist = g_list_append (glist, _("Bend from clipboard"));
glist = g_list_append (glist, _("Last applied"));
return glist;
@@ -220,6 +237,41 @@ static void sp_pencil_tb_defaults(GtkWidget * /*widget*/, GObject *obj)
spinbutton_defocus(tbl);
}
+static void sp_simplify_flatten(GtkWidget * /*widget*/, GObject *obj)
+{
+ SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(obj, "desktop"));
+ std::vector<SPItem *> selected = desktop->getSelection()->itemList();
+ for (std::vector<SPItem *>::iterator it(selected.begin()); it != selected.end(); ++it){
+ SPLPEItem* lpeitem = dynamic_cast<SPLPEItem*>(*it);
+ if (lpeitem && lpeitem->hasPathEffect()){
+ PathEffectList lpelist = lpeitem->getEffectList();
+ std::list<Inkscape::LivePathEffect::LPEObjectReference *>::iterator i;
+ for (i = lpelist.begin(); i != lpelist.end(); ++i) {
+ LivePathEffectObject *lpeobj = (*i)->lpeobject;
+ if (lpeobj) {
+ Inkscape::LivePathEffect::Effect *lpe = lpeobj->get_lpe();
+ if (dynamic_cast<Inkscape::LivePathEffect::LPESimplify *>(lpe)) {
+ SPShape * shape = dynamic_cast<SPShape *>(lpeitem);
+ if(shape){
+ SPCurve * c = shape->getCurveBeforeLPE();
+ lpe->doEffect(c);
+ lpeitem->setCurrentPathEffect(*i);
+ if (lpelist.size() > 1){
+ lpeitem->removeCurrentPathEffect(true);
+ shape->setCurveBeforeLPE(c);
+ } else {
+ lpeitem->removeCurrentPathEffect(false);
+ shape->setCurve(c,0);
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
static void sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tbl)
{
// quit if run by the attr_changed listener
@@ -232,6 +284,51 @@ static void sp_pencil_tb_tolerance_value_changed(GtkAdjustment *adj, GObject *tb
prefs->setDouble("/tools/freehand/pencil/tolerance",
gtk_adjustment_get_value(adj));
g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
+ SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data(tbl, "desktop"));
+ std::vector<SPItem *> selected = desktop->getSelection()->itemList();
+ for (std::vector<SPItem *>::iterator it(selected.begin()); it != selected.end(); ++it){
+ SPLPEItem* lpeitem = dynamic_cast<SPLPEItem*>(*it);
+ if (lpeitem && lpeitem->hasPathEffect()){
+ Inkscape::LivePathEffect::Effect* simplify = lpeitem->getPathEffectOfType(Inkscape::LivePathEffect::SIMPLIFY);
+ if(simplify){
+ Inkscape::LivePathEffect::LPESimplify *lpe_simplify = dynamic_cast<Inkscape::LivePathEffect::LPESimplify*>(simplify->getLPEObj()->get_lpe());
+ if (lpe_simplify) {
+ double tol = prefs->getDoubleLimited("/tools/freehand/pencil/tolerance", 10.0, 1.0, 100.0);
+ tol = tol/(100.0*(102.0-tol));
+ std::ostringstream ss;
+ ss << tol;
+ Inkscape::LivePathEffect::Effect* powerstroke = lpeitem->getPathEffectOfType(Inkscape::LivePathEffect::POWERSTROKE);
+ bool simplified = false;
+ if(powerstroke){
+ Inkscape::LivePathEffect::LPEPowerStroke *lpe_powerstroke = dynamic_cast<Inkscape::LivePathEffect::LPEPowerStroke*>(powerstroke->getLPEObj()->get_lpe());
+ if(lpe_powerstroke){
+ lpe_powerstroke->getRepr()->setAttribute("is_visible", "false");
+ sp_lpe_item_update_patheffect(lpeitem, false, false);
+ SPShape *sp_shape = dynamic_cast<SPShape *>(lpeitem);
+ if (sp_shape) {
+ guint previous_curve_length = sp_shape->getCurve()->get_segment_count();
+ lpe_simplify->getRepr()->setAttribute("threshold", ss.str());
+ sp_lpe_item_update_patheffect(lpeitem, false, false);
+ simplified = true;
+ guint curve_length = sp_shape->getCurve()->get_segment_count();
+ std::vector<Geom::Point> ts = lpe_powerstroke->offset_points.data();
+ double factor = (double)curve_length/ (double)previous_curve_length;
+ for (size_t i = 0; i < ts.size(); i++) {
+ ts[i][Geom::X] = ts[i][Geom::X] * factor;
+ }
+ lpe_powerstroke->offset_points.param_setValue(ts);
+ }
+ lpe_powerstroke->getRepr()->setAttribute("is_visible", "true");
+ sp_lpe_item_update_patheffect(lpeitem, false, false);
+ }
+ }
+ if(!simplified){
+ lpe_simplify->getRepr()->setAttribute("threshold", ss.str());
+ }
+ }
+ }
+ }
+ }
}
/*
@@ -267,7 +364,7 @@ private:
void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
{
sp_add_freehand_mode_toggle(mainActions, holder, true);
-
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
EgeAdjustmentAction* eact = 0;
/* Tolerance */
@@ -303,6 +400,32 @@ void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb
g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_pencil_tb_defaults), holder );
gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
}
+ /* LPE simplify based tolerance */
+ {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ InkToggleAction* itact = ink_toggle_action_new( "PencilLpeSimplify",
+ _("LPE based interactive simplify"),
+ _("LPE based interactive simplify"),
+ INKSCAPE_ICON("interactive_simplify"),
+ Inkscape::ICON_SIZE_SMALL_TOOLBAR );
+ gtk_toggle_action_set_active(GTK_TOGGLE_ACTION(itact), prefs->getInt("/tools/freehand/pencil/simplify", 0) );
+ g_signal_connect_after( G_OBJECT(itact), "toggled", G_CALLBACK(freehand_simplify_lpe), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
+ }
+ /* LPE simplify flatten */
+ {
+ InkAction* inky = ink_action_new( "PencilLpeSimplifyFlatten",
+ _("LPE simplify flatten"),
+ _("LPE simplify flatten"),
+ INKSCAPE_ICON("flatten_simplify"),
+ Inkscape::ICON_SIZE_SMALL_TOOLBAR );
+ g_signal_connect_after( G_OBJECT(inky), "activate", G_CALLBACK(sp_simplify_flatten), holder );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(inky) );
+ g_object_set_data( holder, "flatten_simplify", inky );
+ if (!prefs->getInt("/tools/freehand/pencil/simplify", 0)) {
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(holder, "flatten_simplify") ), false );
+ }
+ }
g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
diff --git a/src/widgets/rect-toolbar.cpp b/src/widgets/rect-toolbar.cpp
index 96ba699dc..bc27d003c 100644
--- a/src/widgets/rect-toolbar.cpp
+++ b/src/widgets/rect-toolbar.cpp
@@ -107,7 +107,7 @@ static void sp_rtb_value_changed(GtkAdjustment *adj, GObject *tbl, gchar const *
bool modmade = false;
Inkscape::Selection *selection = desktop->getSelection();
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
if (SP_IS_RECT(*i)) {
if (gtk_adjustment_get_value(adj) != 0) {
(SP_RECT(*i)->*setter)(Quantity::convert(gtk_adjustment_get_value(adj), unit, "px"));
@@ -244,7 +244,7 @@ static void sp_rect_toolbox_selection_changed(Inkscape::Selection *selection, GO
purge_repr_listener( tbl, tbl );
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
if (SP_IS_RECT(*i)) {
n_selected++;
item = *i;
diff --git a/src/widgets/ruler.cpp b/src/widgets/ruler.cpp
index ab486eeeb..3a5e76277 100644
--- a/src/widgets/ruler.cpp
+++ b/src/widgets/ruler.cpp
@@ -41,8 +41,9 @@
#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB
-#define DEFAULT_RULER_FONT_SCALE PANGO_SCALE_X_SMALL
-#define MINIMUM_INCR 5
+#define DEFAULT_RULER_FONT_SCALE PANGO_SCALE_X_SMALL
+#define MINIMUM_INCR 5
+#define IMMEDIATE_REDRAW_THRESHOLD 20
using Inkscape::Util::unit_table;
@@ -71,11 +72,11 @@ typedef struct
GdkWindow *input_window;
cairo_surface_t *backing_store;
+ gboolean backing_store_valid;
+ GdkRectangle last_pos_rect;
+ guint pos_redraw_idle_id;
PangoLayout *layout;
gdouble font_scale;
-
- gint xsrc;
- gint ysrc;
GList *track_widgets;
} SPRulerPrivate;
@@ -132,18 +133,22 @@ static void sp_ruler_style_updated (GtkWidget *widget);
static void sp_ruler_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void sp_ruler_style_set (GtkWidget *widget,
- GtkStyle *prev_style);
+ GtkStyle *prev_style);
#endif
static gboolean sp_ruler_motion_notify (GtkWidget *widget,
GdkEventMotion *event);
static gboolean sp_ruler_draw (GtkWidget *widget,
- cairo_t *cr);
+ cairo_t *cr);
#if !GTK_CHECK_VERSION(3,0,0)
static gboolean sp_ruler_expose (GtkWidget *widget,
GdkEventExpose *event);
#endif
static void sp_ruler_draw_ticks (SPRuler *ruler);
+static GdkRectangle sp_ruler_get_pos_rect (SPRuler *ruler,
+ gdouble position);
+static gboolean sp_ruler_idle_queue_pos_redraw(gpointer data);
+static void sp_ruler_queue_pos_redraw (SPRuler *ruler);
static void sp_ruler_draw_pos (SPRuler *ruler,
cairo_t *cr);
static void sp_ruler_make_pixmap (SPRuler *ruler);
@@ -260,14 +265,23 @@ sp_ruler_init (SPRuler *ruler)
gtk_widget_set_has_window (GTK_WIDGET (ruler), FALSE);
- priv->orientation = GTK_ORIENTATION_HORIZONTAL;
- priv->unit = unit_table.getUnit("px");
- priv->lower = 0;
- priv->upper = 0;
- priv->position = 0;
- priv->max_size = 0;
- priv->backing_store = NULL;
- priv->font_scale = DEFAULT_RULER_FONT_SCALE;
+ priv->orientation = GTK_ORIENTATION_HORIZONTAL;
+ priv->unit = unit_table.getUnit("px");
+ priv->lower = 0;
+ priv->upper = 0;
+ priv->position = 0;
+ priv->max_size = 0;
+
+ priv->backing_store = NULL;
+ priv->backing_store_valid = FALSE;
+
+ priv->last_pos_rect.x = 0;
+ priv->last_pos_rect.y = 0;
+ priv->last_pos_rect.width = 0;
+ priv->last_pos_rect.height = 0;
+ priv->pos_redraw_idle_id = 0;
+
+ priv->font_scale = DEFAULT_RULER_FONT_SCALE;
#if GTK_CHECK_VERSION(3,0,0)
#if GTK_CHECK_VERSION(3,8,0)
@@ -299,6 +313,12 @@ sp_ruler_dispose (GObject *object)
while (priv->track_widgets)
sp_ruler_remove_track_widget (ruler, GTK_WIDGET(priv->track_widgets->data));
+ if (priv->pos_redraw_idle_id)
+ {
+ g_source_remove (priv->pos_redraw_idle_id);
+ priv->pos_redraw_idle_id = 0;
+ }
+
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -343,6 +363,7 @@ sp_ruler_set_range (SPRuler *ruler,
}
g_object_thaw_notify (G_OBJECT (ruler));
+ priv->backing_store_valid = FALSE;
gtk_widget_queue_draw (GTK_WIDGET (ruler));
}
@@ -513,7 +534,9 @@ sp_ruler_unrealize(GtkWidget *widget)
cairo_surface_destroy (priv->backing_store);
priv->backing_store = NULL;
}
-
+
+ priv->backing_store_valid = FALSE;
+
if (priv->layout)
{
g_object_unref (priv->layout);
@@ -689,7 +712,6 @@ sp_ruler_expose (GtkWidget *widget,
cairo_clip (cr);
gtk_widget_get_allocation (widget, &allocation);
- cairo_translate (cr, allocation.x, allocation.y);
gboolean result = sp_ruler_draw (widget, cr);
@@ -733,6 +755,8 @@ sp_ruler_make_pixmap (SPRuler *ruler)
CAIRO_CONTENT_COLOR,
allocation.width,
allocation.height);
+
+ priv->backing_store_valid = FALSE;
}
static void
@@ -743,118 +767,22 @@ sp_ruler_draw_pos (SPRuler *ruler,
#if GTK_CHECK_VERSION(3,0,0)
GtkStyleContext *context = gtk_widget_get_style_context (widget);
- GtkBorder border;
GdkRGBA color;
#else
GtkStyle *style = gtk_widget_get_style (widget);
GtkStateType state = gtk_widget_get_state (widget);
- gint xthickness;
- gint ythickness;
#endif
SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler);
- GtkAllocation allocation;
- gint x, y;
- gint width, height;
- gint bs_width, bs_height;
+ GdkRectangle pos_rect;
if (! gtk_widget_is_drawable (widget))
return;
- gtk_widget_get_allocation(widget, &allocation);
-
-#if GTK_CHECK_VERSION(3,0,0)
- gtk_style_context_get_border (context, static_cast<GtkStateFlags>(0), &border);
-#else
- xthickness = style->xthickness;
- ythickness = style->ythickness;
-#endif
-
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- width = allocation.width;
-#if GTK_CHECK_VERSION(3,0,0)
- height = allocation.height - (border.top + border.bottom);
-#else
- height = allocation.height - ythickness * 2;
-#endif
-
- bs_width = height / 2 + 2;
- bs_width |= 1; /* make sure it's odd */
- bs_height = bs_width / 2 + 1;
- }
- else
- {
-#if GTK_CHECK_VERSION(3,0,0)
- width = allocation.width - (border.left + border.right);
-#else
- width = allocation.width - xthickness * 2;
-#endif
- height = allocation.height;
-
- bs_height = width / 2 + 2;
- bs_height |= 1; /* make sure it's odd */
- bs_width = bs_height / 2 + 1;
- }
+ pos_rect = sp_ruler_get_pos_rect (ruler, sp_ruler_get_position (ruler));
- if ((bs_width > 0) && (bs_height > 0))
+ if ((pos_rect.width > 0) && (pos_rect.height > 0))
{
- gdouble lower;
- gdouble upper;
- gdouble position;
- gdouble increment;
-
- if (! cr)
- {
- cr = gdk_cairo_create (gtk_widget_get_window (widget));
- cairo_translate (cr, allocation.x, allocation.y);
- cairo_rectangle (cr, allocation.x, allocation.y, allocation.width, allocation.height);
- cairo_clip (cr);
-
- cairo_translate (cr, allocation.x, allocation.y);
-
- /* If a backing store exists, restore the ruler */
- if (priv->backing_store)
- {
- cairo_set_source_surface (cr, priv->backing_store, 0, 0);
- cairo_rectangle (cr, priv->xsrc, priv->ysrc, bs_width, bs_height);
- cairo_fill (cr);
- }
- }
- else
- {
- cairo_reference (cr);
- }
-
- position = sp_ruler_get_position (ruler);
-
- sp_ruler_get_range (ruler, &lower, &upper, NULL);
-
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- increment = (gdouble) width / (upper - lower);
-
-#if GTK_CHECK_VERSION(3,0,0)
- x = ROUND ((position - lower) * increment) + (border.left - bs_width) / 2 - 1;
- y = (height + bs_height) / 2 + border.top;
-#else
- x = ROUND ((position - lower) * increment) + (xthickness - bs_width) / 2 - 1;
- y = (height + bs_height) / 2 + ythickness;
-#endif
- }
- else
- {
- increment = (gdouble) height / (upper - lower);
-
-#if GTK_CHECK_VERSION(3,0,0)
- x = (width + bs_width) / 2 + border.left;
- y = ROUND ((position - lower) * increment) + (border.top - bs_height) / 2 - 1;
-#else
- x = (width + bs_width) / 2 + xthickness;
- y = ROUND ((position - lower) * increment) + (ythickness - bs_height) / 2 - 1;
-#endif
- }
-
#if GTK_CHECK_VERSION(3,0,0)
gtk_style_context_get_color (context, gtk_widget_get_state_flags (widget),
&color);
@@ -863,26 +791,28 @@ sp_ruler_draw_pos (SPRuler *ruler,
gdk_cairo_set_source_color (cr, &style->fg[state]);
#endif
- cairo_move_to (cr, x, y);
+ cairo_move_to (cr, pos_rect.x, pos_rect.y);
if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
{
- cairo_line_to (cr, x + bs_width / 2.0, y + bs_height);
- cairo_line_to (cr, x + bs_width, y);
+ cairo_line_to (cr, pos_rect.x + pos_rect.width / 2.0,
+ pos_rect.y + pos_rect.height);
+ cairo_line_to (cr, pos_rect.x + pos_rect.width,
+ pos_rect.y);
}
else
{
- cairo_line_to (cr, x + bs_width, y + bs_height / 2.0);
- cairo_line_to (cr, x, y + bs_height);
+ cairo_line_to (cr, pos_rect.x + pos_rect.width,
+
+ pos_rect.y + pos_rect.height / 2.0);
+ cairo_line_to (cr, pos_rect.x,
+ pos_rect.y + pos_rect.height);
}
cairo_fill (cr);
-
- cairo_destroy (cr);
-
- priv->xsrc = x;
- priv->ysrc = y;
}
+
+ priv->last_pos_rect = pos_rect;
}
/**
@@ -1096,6 +1026,7 @@ sp_ruler_set_unit (SPRuler *ruler,
priv->unit = unit;
g_object_notify(G_OBJECT(ruler), "unit");
+ priv->backing_store_valid = FALSE;
gtk_widget_queue_draw (GTK_WIDGET (ruler));
}
}
@@ -1131,10 +1062,39 @@ sp_ruler_set_position (SPRuler *ruler,
if (priv->position != position)
{
- priv->position = position;
- g_object_notify (G_OBJECT (ruler), "position");
-
- sp_ruler_draw_pos (ruler, NULL);
+ GdkRectangle rect;
+ gint xdiff, ydiff;
+
+ priv->position = position;
+ g_object_notify (G_OBJECT (ruler), "position");
+
+ rect = sp_ruler_get_pos_rect (ruler, priv->position);
+
+ xdiff = rect.x - priv->last_pos_rect.x;
+ ydiff = rect.y - priv->last_pos_rect.y;
+
+ /*
+ * If the position has changed far enough, queue a redraw immediately.
+ * Otherwise, we only queue a redraw in a low priority idle handler, to
+ * allow for other things (like updating the canvas) to run.
+ *
+ * TODO: This might not be necessary any more in GTK3 with the frame
+ * clock. Investigate this more after the port to GTK3.
+ */
+ if (priv->last_pos_rect.width != 0 &&
+ priv->last_pos_rect.height != 0 &&
+ (ABS (xdiff) > IMMEDIATE_REDRAW_THRESHOLD ||
+ ABS (ydiff) > IMMEDIATE_REDRAW_THRESHOLD))
+ {
+ sp_ruler_queue_pos_redraw (ruler);
+ }
+ else if (! priv->pos_redraw_idle_id)
+ {
+ priv->pos_redraw_idle_id =
+ g_idle_add_full (G_PRIORITY_LOW,
+ sp_ruler_idle_queue_pos_redraw,
+ ruler, NULL);
+ }
}
}
@@ -1154,7 +1114,7 @@ sp_ruler_get_position (SPRuler *ruler)
static gboolean
sp_ruler_motion_notify (GtkWidget *widget,
- GdkEventMotion *event)
+ GdkEventMotion *event)
{
SPRuler *ruler = SP_RULER(widget);
@@ -1347,7 +1307,7 @@ sp_ruler_draw_ticks (SPRuler *ruler)
if (ideal_length > ++length)
length = ideal_length;
- if (lower < upper)
+ if (lower < upper)
{
start = floor (lower / subd_incr) * subd_incr;
end = ceil (upper / subd_incr) * subd_incr;
@@ -1413,16 +1373,16 @@ sp_ruler_draw_ticks (SPRuler *ruler)
pango_layout_get_extents (layout, &logical_rect, NULL);
#if GTK_CHECK_VERSION(3,0,0)
- cairo_move_to (cr,
+ cairo_move_to (cr,
pos + 2,
border.top + PANGO_PIXELS (logical_rect.y - digit_offset));
#else
- cairo_move_to (cr,
+ cairo_move_to (cr,
pos + 2,
ythickness + PANGO_PIXELS (logical_rect.y - digit_offset));
#endif
- pango_cairo_show_layout(cr, layout);
+ pango_cairo_show_layout(cr, layout);
}
else
{
@@ -1435,15 +1395,15 @@ sp_ruler_draw_ticks (SPRuler *ruler)
pango_layout_get_extents (layout, NULL, &logical_rect);
#if GTK_CHECK_VERSION(3,0,0)
- cairo_move_to (cr,
+ cairo_move_to (cr,
border.left + 1,
pos + digit_height * j + 2 + PANGO_PIXELS (logical_rect.y - digit_offset));
#else
- cairo_move_to (cr,
+ cairo_move_to (cr,
xthickness + 1,
pos + digit_height * j + 2 + PANGO_PIXELS (logical_rect.y - digit_offset));
#endif
- pango_cairo_show_layout (cr, layout);
+ pango_cairo_show_layout (cr, layout);
}
}
}
@@ -1454,10 +1414,118 @@ sp_ruler_draw_ticks (SPRuler *ruler)
cairo_fill (cr);
+ priv->backing_store_valid = TRUE;
+
out:
cairo_destroy (cr);
}
+static GdkRectangle
+sp_ruler_get_pos_rect (SPRuler *ruler,
+ gdouble position)
+{
+ GtkWidget *widget = GTK_WIDGET (ruler);
+ GtkStyle *style = gtk_widget_get_style (widget);
+ SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler);
+ GtkAllocation allocation;
+ gint width, height;
+ gint xthickness;
+ gint ythickness;
+ gdouble upper, lower;
+ gdouble increment;
+ GdkRectangle rect = { 0, 0, 0, 0 };
+
+ if (! gtk_widget_is_drawable (widget))
+ return rect;
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ xthickness = style->xthickness;
+ ythickness = style->ythickness;
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ width = allocation.width;
+ height = allocation.height - ythickness * 2;
+
+ rect.width = height / 2 + 2;
+ rect.width |= 1; /* make sure it's odd */
+ rect.height = rect.width / 2 + 1;
+ }
+ else
+ {
+ width = allocation.width - xthickness * 2;
+ height = allocation.height;
+
+ rect.height = width / 2 + 2;
+ rect.height |= 1; /* make sure it's odd */
+ rect.width = rect.height / 2 + 1;
+ }
+
+ sp_ruler_get_range (ruler, &lower, &upper, NULL);
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ increment = (gdouble) width / (upper - lower);
+
+ rect.x = ROUND ((position - lower) * increment) + (xthickness - rect.width) / 2 - 1;
+ rect.y = (height + rect.height) / 2 + ythickness;
+ }
+ else
+ {
+ increment = (gdouble) height / (upper - lower);
+
+ rect.x = (width + rect.width) / 2 + xthickness;
+ rect.y = ROUND ((position - lower) * increment) + (ythickness - rect.height) / 2 - 1;
+ }
+
+ rect.x += allocation.x;
+ rect.y += allocation.y;
+
+ return rect;
+}
+
+static gboolean
+sp_ruler_idle_queue_pos_redraw (gpointer data)
+{
+ SPRuler *ruler = (SPRuler *)data;
+ SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler);
+
+ sp_ruler_queue_pos_redraw (ruler);
+
+ gboolean ret = g_source_remove(priv->pos_redraw_idle_id);
+ priv->pos_redraw_idle_id = 0;
+
+ return ret;
+}
+
+static void
+sp_ruler_queue_pos_redraw (SPRuler *ruler)
+{
+ SPRulerPrivate *priv = SP_RULER_GET_PRIVATE (ruler);
+ const GdkRectangle rect = sp_ruler_get_pos_rect (ruler, priv->position);
+
+ gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
+ rect.x,
+ rect.y,
+ rect.width,
+ rect.height);
+
+ if (priv->last_pos_rect.width != 0 || priv->last_pos_rect.height != 0)
+ {
+ gtk_widget_queue_draw_area (GTK_WIDGET(ruler),
+ priv->last_pos_rect.x,
+ priv->last_pos_rect.y,
+ priv->last_pos_rect.width,
+ priv->last_pos_rect.height);
+
+ priv->last_pos_rect.x = 0;
+ priv->last_pos_rect.y = 0;
+ priv->last_pos_rect.width = 0;
+ priv->last_pos_rect.height = 0;
+ }
+}
+
static PangoLayout*
sp_ruler_create_layout (GtkWidget *widget,
const gchar *text)
diff --git a/src/widgets/select-toolbar.cpp b/src/widgets/select-toolbar.cpp
index e49c4c00a..3cd6c0e28 100644
--- a/src/widgets/select-toolbar.cpp
+++ b/src/widgets/select-toolbar.cpp
@@ -136,13 +136,13 @@ sp_selection_layout_widget_change_selection(SPWidget *spw, Inkscape::Selection *
}
static void
-sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw)
+sp_object_layout_any_value_changed(GtkAdjustment *adj, GObject *tbl)
{
- if (g_object_get_data(G_OBJECT(spw), "update")) {
+ if (g_object_get_data(tbl, "update")) {
return;
}
- UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(G_OBJECT(spw), "tracker"));
+ UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker"));
if ( !tracker || tracker->isUpdating() ) {
/*
* When only units are being changed, don't treat changes
@@ -150,7 +150,7 @@ sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw)
*/
return;
}
- g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(TRUE));
+ g_object_set_data(tbl, "update", GINT_TO_POINTER(TRUE));
SPDesktop *desktop = SP_ACTIVE_DESKTOP;
Inkscape::Selection *selection = desktop->getSelection();
@@ -168,7 +168,7 @@ sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw)
Geom::OptRect bbox_user = selection->bounds(bbox_type);
if ( !bbox_user ) {
- g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE));
+ g_object_set_data(tbl, "update", GINT_TO_POINTER(FALSE));
return;
}
@@ -181,10 +181,10 @@ sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw)
Unit const *unit = tracker->getActiveUnit();
g_return_if_fail(unit != NULL);
- GtkAdjustment* a_x = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "X" ) );
- GtkAdjustment* a_y = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "Y" ) );
- GtkAdjustment* a_w = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "width" ) );
- GtkAdjustment* a_h = GTK_ADJUSTMENT( g_object_get_data( G_OBJECT(spw), "height" ) );
+ GtkAdjustment* a_x = GTK_ADJUSTMENT( g_object_get_data( tbl, "X" ) );
+ GtkAdjustment* a_y = GTK_ADJUSTMENT( g_object_get_data( tbl, "Y" ) );
+ GtkAdjustment* a_w = GTK_ADJUSTMENT( g_object_get_data( tbl, "width" ) );
+ GtkAdjustment* a_h = GTK_ADJUSTMENT( g_object_get_data( tbl, "height" ) );
if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) {
x0 = Quantity::convert(gtk_adjustment_get_value(a_x), unit, "px");
@@ -205,7 +205,7 @@ sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw)
}
// Keep proportions if lock is on
- GtkToggleAction *lock = GTK_TOGGLE_ACTION( g_object_get_data(G_OBJECT(spw), "lock") );
+ GtkToggleAction *lock = GTK_TOGGLE_ACTION( g_object_get_data(tbl, "lock") );
if ( gtk_toggle_action_get_active(lock) ) {
if (adj == a_h) {
x1 = x0 + yrel * bbox_user->dimensions()[Geom::X];
@@ -265,68 +265,7 @@ sp_object_layout_any_value_changed(GtkAdjustment *adj, SPWidget *spw)
desktop->getCanvas()->endForcedFullRedraws();
}
- g_object_set_data(G_OBJECT(spw), "update", GINT_TO_POINTER(FALSE));
-}
-
-static GtkWidget* createCustomSlider( GtkAdjustment *adjustment, gdouble climbRate, guint digits, Inkscape::UI::Widget::UnitTracker *unit_tracker )
-{
-#if WITH_GTKMM_3_0
- Glib::RefPtr<Gtk::Adjustment> adj = Glib::wrap(adjustment, true);
- Inkscape::UI::Widget::SpinButton *inkSpinner = new Inkscape::UI::Widget::SpinButton(adj, climbRate, digits);
-#else
- Inkscape::UI::Widget::SpinButton *inkSpinner = new Inkscape::UI::Widget::SpinButton(*Glib::wrap(adjustment, true), climbRate, digits);
-#endif
- inkSpinner->addUnitTracker(unit_tracker);
- inkSpinner = Gtk::manage( inkSpinner );
- GtkWidget *widget = GTK_WIDGET( inkSpinner->gobj() );
- return widget;
-}
-
-// TODO create_adjustment_action appears to be a rogue tile copy from toolbox.cpp. Resolve it to be unified:
-
-static EgeAdjustmentAction * create_adjustment_action( gchar const *name,
- gchar const *label,
- gchar const *shortLabel,
- gchar const *data,
- gdouble lower,
- GtkWidget* focusTarget,
- UnitTracker* tracker,
- GtkWidget* spw,
- gchar const *tooltip,
- gboolean altx )
-{
- static bool init = false;
- if ( !init ) {
- init = true;
- ege_adjustment_action_set_compact_tool_factory( createCustomSlider );
- }
-
- GtkAdjustment* adj = GTK_ADJUSTMENT( gtk_adjustment_new( 0.0, lower, 1e6, SPIN_STEP, SPIN_PAGE_STEP, 0 ) );
- if (tracker) {
- tracker->addAdjustment(adj);
- }
- if ( spw ) {
- g_object_set_data( G_OBJECT(spw), data, adj );
- }
-
- EgeAdjustmentAction* act = ege_adjustment_action_new( adj, name, Q_(label), tooltip, 0, SPIN_STEP, 3, tracker );
- if ( shortLabel ) {
- g_object_set( act, "short_label", Q_(shortLabel), NULL );
- }
-
- g_signal_connect( G_OBJECT(adj), "value_changed", G_CALLBACK(sp_object_layout_any_value_changed), spw );
- if ( focusTarget ) {
- ege_adjustment_action_set_focuswidget( act, focusTarget );
- }
-
- if ( altx ) { // this spinbutton will be activated by alt-x
- g_object_set( G_OBJECT(act), "self-id", "altx", NULL );
- }
-
- // Using a cast just to make sure we pass in the right kind of function pointer
- g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
-
- return act;
+ g_object_set_data(tbl, "update", GINT_TO_POINTER(FALSE));
}
// toggle button callbacks and updaters
@@ -497,21 +436,60 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb
// four spinbuttons
- eact = create_adjustment_action( "XAction", C_("Select toolbar", "X position"), C_("Select toolbar", "X:"), "X",
- -1e6, GTK_WIDGET(desktop->canvas), tracker, spw,
- _("Horizontal coordinate of selection"), TRUE );
+ eact = create_adjustment_action(
+ /* name= */ "XAction",
+ /* label= */ C_("Select toolbar", "X position"),
+ /* shortLabel= */ C_("Select toolbar", "X:"),
+ /* tooltip= */ C_("Select toolbar", "Horizontal coordinate of selection"),
+ /* path= */ "/tools/select/X",
+ /* def(default) */ 0.0,
+ /* focusTarget= */ GTK_WIDGET(desktop->canvas),
+ /* dataKludge= */ G_OBJECT(spw),
+ /* altx, altx_mark */ TRUE, "altx",
+ /* lower, uppper, step, page */ -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
+ /* descrLabels, descrValues, descrCount */ 0, 0, 0,
+ /* callback= */ sp_object_layout_any_value_changed,
+ /* unit_tracker= */ tracker,
+ /* climb, digits, factor */ SPIN_STEP, 3, 1);
+
gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) );
contextActions->push_back( GTK_ACTION(eact) );
- eact = create_adjustment_action( "YAction", C_("Select toolbar", "Y position"), C_("Select toolbar", "Y:"), "Y",
- -1e6, GTK_WIDGET(desktop->canvas), tracker, spw,
- _("Vertical coordinate of selection"), FALSE );
+ eact = create_adjustment_action(
+ /* name= */ "YAction",
+ /* label= */ C_("Select toolbar", "Y position"),
+ /* shortLabel= */ C_("Select toolbar", "Y:"),
+ /* tooltip= */ C_("Select toolbar", "Vertical coordinate of selection"),
+ /* path= */ "/tools/select/Y",
+ /* def(default) */ 0.0,
+ /* focusTarget= */ GTK_WIDGET(desktop->canvas),
+ /* dataKludge= */ G_OBJECT(spw),
+ /* altx, altx_mark */ TRUE, "altx",
+ /* lower, uppper, step, page */ -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
+ /* descrLabels, descrValues, descrCount */ 0, 0, 0,
+ /* callback= */ sp_object_layout_any_value_changed,
+ /* unit_tracker= */ tracker,
+ /* climb, digits, factor */ SPIN_STEP, 3, 1);
+
gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) );
contextActions->push_back( GTK_ACTION(eact) );
- eact = create_adjustment_action( "WidthAction", C_("Select toolbar", "Width"), C_("Select toolbar", "W:"), "width",
- 0.0, GTK_WIDGET(desktop->canvas), tracker, spw,
- _("Width of selection"), FALSE );
+ eact = create_adjustment_action(
+ /* name= */ "WidthAction",
+ /* label= */ C_("Select toolbar", "Width"),
+ /* shortLabel= */ C_("Select toolbar", "W:"),
+ /* tooltip= */ C_("Select toolbar", "Width of selection"),
+ /* path= */ "/tools/select/width",
+ /* def(default) */ 0.0,
+ /* focusTarget= */ GTK_WIDGET(desktop->canvas),
+ /* dataKludge= */ G_OBJECT(spw),
+ /* altx, altx_mark */ TRUE, "altx",
+ /* lower, uppper, step, page */ 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
+ /* descrLabels, descrValues, descrCount */ 0, 0, 0,
+ /* callback= */ sp_object_layout_any_value_changed,
+ /* unit_tracker= */ tracker,
+ /* climb, digits, factor */ SPIN_STEP, 3, 1);
+
gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) );
contextActions->push_back( GTK_ACTION(eact) );
@@ -528,9 +506,22 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb
gtk_action_group_add_action( mainActions, GTK_ACTION(itact) );
}
- eact = create_adjustment_action( "HeightAction", C_("Select toolbar", "Height"), C_("Select toolbar", "H:"), "height",
- 0.0, GTK_WIDGET(desktop->canvas), tracker, spw,
- _("Height of selection"), FALSE );
+ eact = create_adjustment_action(
+ /* name= */ "HeightAction",
+ /* label= */ C_("Select toolbar", "Height"),
+ /* shortLabel= */ C_("Select toolbar", "H:"),
+ /* tooltip= */ C_("Select toolbar", "Height of selection"),
+ /* path= */ "/tools/select/height",
+ /* def(default) */ 0.0,
+ /* focusTarget= */ GTK_WIDGET(desktop->canvas),
+ /* dataKludge= */ G_OBJECT(spw),
+ /* altx, altx_mark */ TRUE, "altx",
+ /* lower, uppper, step, page */ 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP,
+ /* descrLabels, descrValues, descrCount */ 0, 0, 0,
+ /* callback= */ sp_object_layout_any_value_changed,
+ /* unit_tracker= */ tracker,
+ /* climb, digits, factor */ SPIN_STEP, 3, 1);
+
gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) );
contextActions->push_back( GTK_ACTION(eact) );
diff --git a/src/widgets/sp-color-selector.cpp b/src/widgets/sp-color-selector.cpp
index dad0a18b0..93eaaee8b 100644
--- a/src/widgets/sp-color-selector.cpp
+++ b/src/widgets/sp-color-selector.cpp
@@ -7,10 +7,6 @@
# include "config.h"
#endif
-#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
-#include <glibmm/threads.h>
-#endif
-
#include <math.h>
#include <gtk/gtk.h>
#include <glibmm/i18n.h>
diff --git a/src/widgets/sp-color-selector.h b/src/widgets/sp-color-selector.h
index 308a5519c..75cb79b00 100644
--- a/src/widgets/sp-color-selector.h
+++ b/src/widgets/sp-color-selector.h
@@ -5,10 +5,6 @@
# include <config.h>
#endif
-#if GLIBMM_DISABLE_DEPRECATED && HAVE_GLIBMM_THREADS_H
-#include <glibmm/threads.h>
-#endif
-
#include <gtk/gtk.h>
#include "color.h"
diff --git a/src/widgets/sp-xmlview-attr-list.cpp b/src/widgets/sp-xmlview-attr-list.cpp
index dd763aea5..a4c00db7c 100644
--- a/src/widgets/sp-xmlview-attr-list.cpp
+++ b/src/widgets/sp-xmlview-attr-list.cpp
@@ -145,6 +145,7 @@ void sp_xmlview_attr_list_select_row_by_key(SPXMLViewAttrList * list, const gcha
break;
}
valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(list->store), &iter);
+ // cppcheck-suppress nullPointer // a string was copied in n by gtk_tree_model_get
if (n) {
g_free(n);
}
@@ -181,6 +182,7 @@ event_attr_changed (Inkscape::XML::Node * /*repr*/,
}
row++;
valid = gtk_tree_model_iter_next (GTK_TREE_MODEL(list->store), &iter);
+ // cppcheck-suppress nullPointer // a string was copied in n by gtk_tree_model_get
if (n) {
g_free(n);
}
diff --git a/src/widgets/spiral-toolbar.cpp b/src/widgets/spiral-toolbar.cpp
index 751a60f06..7e7398091 100644
--- a/src/widgets/spiral-toolbar.cpp
+++ b/src/widgets/spiral-toolbar.cpp
@@ -80,7 +80,7 @@ static void sp_spl_tb_value_changed(GtkAdjustment *adj, GObject *tbl, Glib::ustr
bool modmade = false;
std::vector<SPItem*> itemlist=desktop->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){
SPItem *item = *i;
if (SP_IS_SPIRAL(item)) {
Inkscape::XML::Node *repr = item->getRepr();
@@ -196,7 +196,7 @@ static void sp_spiral_toolbox_selection_changed(Inkscape::Selection *selection,
purge_repr_listener( tbl, tbl );
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){
SPItem *item = *i;
if (SP_IS_SPIRAL(item)) {
n_selected++;
diff --git a/src/widgets/spray-toolbar.cpp b/src/widgets/spray-toolbar.cpp
index 183814b7e..9e142a8db 100644
--- a/src/widgets/spray-toolbar.cpp
+++ b/src/widgets/spray-toolbar.cpp
@@ -15,10 +15,11 @@
* Tavmjong Bah <tavmjong@free.fr>
* Abhishek Sharma
* Kris De Gussem <Kris.DeGussem@gmail.com>
+ * Jabiertxo Arraiza <jabier.arraiza@marker.es>
*
* Copyright (C) 2004 David Turner
* Copyright (C) 2003 MenTaLguY
- * Copyright (C) 1999-2011 authors
+ * Copyright (C) 1999-2015 authors
* Copyright (C) 2001-2002 Ximian, Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -28,19 +29,23 @@
# include "config.h"
#endif
-#include <glibmm/i18n.h>
+#include <gtkmm.h>
#include "spray-toolbar.h"
#include "desktop.h"
-#include "document-undo.h"
+#include "inkscape.h"
#include "widgets/ege-adjustment-action.h"
#include "widgets/ege-select-one-action.h"
#include "widgets/ink-action.h"
#include "preferences.h"
#include "toolbox.h"
+#include "ui/dialog/clonetiler.h"
+#include "ui/dialog/dialog-manager.h"
+#include "ui/dialog/panel-dialog.h"
#include "ui/icon-names.h"
-using Inkscape::DocumentUndo;
+#include <glibmm/i18n.h>
+
using Inkscape::UI::ToolboxFactory;
using Inkscape::UI::PrefPusher;
@@ -53,6 +58,88 @@ using Inkscape::UI::PrefPusher;
//## Spray ##
//########################
+static void sp_stb_update_widgets( GObject *tbl )
+{
+ GtkAction* offset = GTK_ACTION( g_object_get_data(tbl, "offset") );
+ GtkAction* spray_scale = GTK_ACTION( g_object_get_data(tbl, "spray_scale") );
+ GtkAdjustment *adj_offset = ege_adjustment_action_get_adjustment( EGE_ADJUSTMENT_ACTION(offset) );
+ GtkAdjustment *adj_scale = ege_adjustment_action_get_adjustment( EGE_ADJUSTMENT_ACTION(spray_scale) );
+ GtkAction *no_overlap_action = GTK_ACTION( g_object_get_data(tbl, "no_overlap") );
+ GtkToggleAction *no_overlap = GTK_TOGGLE_ACTION( g_object_get_data(tbl, "no_overlap") );
+ GtkAction *picker_action = GTK_ACTION( g_object_get_data(tbl, "picker") );
+ GtkToggleAction *picker = GTK_TOGGLE_ACTION( g_object_get_data(tbl, "picker") );
+ GtkToggleAction *usepressurescale = GTK_TOGGLE_ACTION( g_object_get_data(tbl, "usepressurescale") );
+ GtkAction *pick_fill = GTK_ACTION( g_object_get_data(tbl, "pick_fill") );
+ GtkAction *pick_stroke = GTK_ACTION( g_object_get_data(tbl, "pick_stroke") );
+ GtkAction *pick_inverse_value = GTK_ACTION( g_object_get_data(tbl, "pick_inverse_value") );
+ GtkAction *pick_center = GTK_ACTION( g_object_get_data(tbl, "pick_center") );
+ gtk_adjustment_set_value( adj_offset, 100.0 );
+ if (gtk_toggle_action_get_active(no_overlap) && gtk_action_get_visible(no_overlap_action)) {
+ gtk_action_set_visible( offset, true );
+ } else {
+ gtk_action_set_visible( offset, false );
+ }
+ if (gtk_toggle_action_get_active(usepressurescale)) {
+ gtk_adjustment_set_value( adj_scale, 0.0 );
+ gtk_action_set_sensitive( spray_scale, false );
+ } else {
+ gtk_action_set_sensitive( spray_scale, true );
+ }
+ if(gtk_toggle_action_get_active(picker) && gtk_action_get_visible(picker_action)){
+ gtk_action_set_visible( pick_fill, true );
+ gtk_action_set_visible( pick_stroke, true );
+ gtk_action_set_visible( pick_inverse_value, true );
+ gtk_action_set_visible( pick_center, true );
+ } else {
+ gtk_action_set_visible( pick_fill, false );
+ gtk_action_set_visible( pick_stroke, false );
+ gtk_action_set_visible( pick_inverse_value, false );
+ gtk_action_set_visible( pick_center, false );
+ }
+}
+
+static void sp_spray_init( GObject *tbl){
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ int mode = prefs->getInt("/tools/spray/mode", 0);
+ bool show = true;
+ if(mode == 3 || mode == 2){
+ show = false;
+ }
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "no_overlap") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "over_no_transparent") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "over_transparent") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "pick_no_overlap") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "pick_stroke") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "pick_fill") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "pick_inverse_value") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "pick_center") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "picker") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "offset") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "pick_fill") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "pick_stroke") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "pick_inverse_value") ), show );
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "pick_center") ), show );
+ if(mode == 2){
+ show = true;
+ }
+ gtk_action_set_visible( GTK_ACTION( g_object_get_data(tbl, "spray_rotation") ), show );
+ sp_stb_update_widgets( tbl );
+}
+
+Inkscape::UI::Dialog::CloneTiler *get_clone_tiler_panel(SPDesktop *desktop)
+{
+ if (Inkscape::UI::Dialog::PanelDialogBase *panel_dialog =
+ dynamic_cast<Inkscape::UI::Dialog::PanelDialogBase *>(desktop->_dlg_mgr->getDialog("CloneTiler"))) {
+ try {
+ Inkscape::UI::Dialog::CloneTiler &clone_tiler =
+ dynamic_cast<Inkscape::UI::Dialog::CloneTiler &>(panel_dialog->getPanel());
+ return &clone_tiler;
+ } catch (std::exception &e) { }
+ }
+
+ return 0;
+}
+
static void sp_spray_width_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
{
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
@@ -74,11 +161,12 @@ static void sp_spray_standard_deviation_value_changed( GtkAdjustment *adj, GObje
gtk_adjustment_get_value(adj));
}
-static void sp_spray_mode_changed( EgeSelectOneAction *act, GObject * /*tbl*/ )
+static void sp_spray_mode_changed( EgeSelectOneAction *act, GObject * tbl )
{
int mode = ege_select_one_action_get_active( act );
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
prefs->setInt("/tools/spray/mode", mode);
+ sp_spray_init(tbl);
}
static void sp_spray_population_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
@@ -102,12 +190,105 @@ static void sp_spray_scale_value_changed( GtkAdjustment *adj, GObject * /*tbl*/
gtk_adjustment_get_value(adj));
}
+static void sp_spray_offset_value_changed( GtkAdjustment *adj, GObject * /*tbl*/ )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->setDouble( "/tools/spray/offset",
+ gtk_adjustment_get_value(adj));
+}
+
+static void sp_toggle_no_overlap( GtkToggleAction* act, gpointer data)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/spray/no_overlap", active);
+ GObject *tbl = G_OBJECT(data);
+ sp_stb_update_widgets(tbl);
+}
+
+static void sp_toggle_pressure_scale( GtkToggleAction* act, gpointer data)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/spray/usepressurescale", active);
+ if(active == true){
+ prefs->setDouble("/tools/spray/scale_variation", 0);
+ }
+ GObject *tbl = G_OBJECT(data);
+ sp_stb_update_widgets( tbl );
+}
+
+static void sp_toggle_over_no_transparent( GtkToggleAction* act, gpointer data)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/spray/over_no_transparent", active);
+}
+
+static void sp_toggle_over_transparent( GtkToggleAction* act, gpointer data)
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/spray/over_transparent", active);
+}
+
+
+static void sp_toggle_picker( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/spray/picker", active);
+ if(active == true){
+ prefs->setBool("/dialogs/clonetiler/dotrace", false);
+ SPDesktop *dt = SP_ACTIVE_DESKTOP;
+ if (Inkscape::UI::Dialog::CloneTiler *ct = get_clone_tiler_panel(dt)){
+ dt->_dlg_mgr->showDialog("CloneTiler");
+ ct->show_page_trace();
+ }
+ }
+ GObject *tbl = G_OBJECT(data);
+ sp_stb_update_widgets(tbl);
+}
+
+static void sp_toggle_pick_center( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/spray/pick_center", active);
+}
+
+static void sp_toggle_pick_fill( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/spray/pick_fill", active);
+}
+
+static void sp_toggle_pick_stroke( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/spray/pick_stroke", active);
+}
+
+static void sp_toggle_pick_no_overlap( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/spray/pick_no_overlap", active);
+}
+
+static void sp_toggle_pick_inverse_value( GtkToggleAction* act, gpointer data )
+{
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ gboolean active = gtk_toggle_action_get_active(act);
+ prefs->setBool("/tools/spray/pick_inverse_value", active);
+}
void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
{
Inkscape::IconSize secondarySize = ToolboxFactory::prefToSize("/toolbox/secondary", 1);
Inkscape::Preferences *prefs = Inkscape::Preferences::get();
-
{
/* Width */
gchar const* labels[] = {_("(narrow spray)"), 0, 0, 0, _("(default)"), 0, 0, 0, 0, _("(broad spray)")};
@@ -115,15 +296,28 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
EgeAdjustmentAction *eact = create_adjustment_action( "SprayWidthAction",
_("Width"), _("Width:"), _("The width of the spray area (relative to the visible canvas area)"),
"/tools/spray/width", 15,
- GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-spray",
+ GTK_WIDGET(desktop->canvas), holder, true, "altx-spray",
1, 100, 1.0, 10.0,
labels, values, G_N_ELEMENTS(labels),
sp_spray_width_value_changed, NULL /*unit tracker*/, 1, 0 );
ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
- gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+ gtk_action_set_sensitive( GTK_ACTION(eact), true );
}
+
+ /* Use Pressure Width button */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "SprayPressureWidthAction",
+ _("Pressure"),
+ _("Use the pressure of the input device to alter the width of spray area"),
+ INKSCAPE_ICON("draw-use-pressure"),
+ Inkscape::ICON_SIZE_DECORATION );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/spray/usepressurewidth");
+ g_signal_connect(holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
+ }
+
{
/* Mean */
gchar const* labels[] = {_("(default)"), 0, 0, 0, 0, 0, 0, _("(maximum mean)")};
@@ -131,13 +325,13 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
EgeAdjustmentAction *eact = create_adjustment_action( "SprayMeanAction",
_("Focus"), _("Focus:"), _("0 to spray a spot; increase to enlarge the ring radius"),
"/tools/spray/mean", 0,
- GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-mean",
+ GTK_WIDGET(desktop->canvas), holder, true, "spray-mean",
0, 100, 1.0, 10.0,
labels, values, G_N_ELEMENTS(labels),
sp_spray_mean_value_changed, NULL /*unit tracker*/, 1, 0 );
ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
- gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+ gtk_action_set_sensitive( GTK_ACTION(eact), true );
}
{
@@ -147,18 +341,18 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
EgeAdjustmentAction *eact = create_adjustment_action( "SprayStandard_deviationAction",
C_("Spray tool", "Scatter"), C_("Spray tool", "Scatter:"), _("Increase to scatter sprayed objects"),
"/tools/spray/standard_deviation", 70,
- GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-standard_deviation",
+ GTK_WIDGET(desktop->canvas), holder, true, "spray-standard_deviation",
1, 100, 1.0, 10.0,
labels, values, G_N_ELEMENTS(labels),
sp_spray_standard_deviation_value_changed, NULL /*unit tracker*/, 1, 0 );
ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
- gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+ gtk_action_set_sensitive( GTK_ACTION(eact), true );
}
/* Mode */
{
- GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
+ GtkListStore* model = gtk_list_store_new( 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
GtkTreeIter iter;
gtk_list_store_append( model, &iter );
@@ -174,6 +368,7 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
1, _("Spray clones of the initial selection"),
2, INKSCAPE_ICON("spray-mode-clone"),
-1 );
+
#ifdef ENABLE_SPRAY_MODE_SINGLE_PATH
gtk_list_store_append( model, &iter );
gtk_list_store_set( model, &iter,
@@ -182,6 +377,14 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
2, INKSCAPE_ICON("spray-mode-union"),
-1 );
#endif
+
+ gtk_list_store_append( model, &iter );
+ gtk_list_store_set( model, &iter,
+ 0, _("Delete sprayed items"),
+ 1, _("Delete sprayed items from selection"),
+ 2, INKSCAPE_ICON("draw-eraser"),
+ -1 );
+
EgeSelectOneAction* act = ege_select_one_action_new( "SprayModeAction", _("Mode"), (""), NULL, GTK_TREE_MODEL(model) );
g_object_set( act, "short_label", _("Mode:"), NULL );
gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
@@ -208,25 +411,25 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
_("Amount"), _("Amount:"),
_("Adjusts the number of items sprayed per click"),
"/tools/spray/population", 70,
- GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-population",
+ GTK_WIDGET(desktop->canvas), holder, true, "spray-population",
1, 100, 1.0, 10.0,
labels, values, G_N_ELEMENTS(labels),
sp_spray_population_value_changed, NULL /*unit tracker*/, 1, 0 );
ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
- gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+ gtk_action_set_sensitive( GTK_ACTION(eact), true );
g_object_set_data( holder, "spray_population", eact );
}
- /* Use Pressure button */
+ /* Use Pressure Population button */
{
- InkToggleAction* act = ink_toggle_action_new( "SprayPressureAction",
+ InkToggleAction* act = ink_toggle_action_new( "SprayPressurePopulationAction",
_("Pressure"),
_("Use the pressure of the input device to alter the amount of sprayed objects"),
INKSCAPE_ICON("draw-use-pressure"),
Inkscape::ICON_SIZE_DECORATION );
gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
- PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/spray/usepressure");
+ PrefPusher *pusher = new PrefPusher(GTK_TOGGLE_ACTION(act), "/tools/spray/usepressurepopulation");
g_signal_connect(holder, "destroy", G_CALLBACK(delete_prefspusher), pusher);
}
@@ -239,13 +442,13 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
// xgettext:no-c-format
_("Variation of the rotation of the sprayed objects; 0% for the same rotation than the original object"),
"/tools/spray/rotation_variation", 0,
- GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-rotation",
+ GTK_WIDGET(desktop->canvas), holder, true, "spray-rotation",
0, 100, 1.0, 10.0,
labels, values, G_N_ELEMENTS(labels),
sp_spray_rotation_value_changed, NULL /*unit tracker*/, 1, 0 );
ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
- gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+ gtk_action_set_sensitive( GTK_ACTION(eact), true );
g_object_set_data( holder, "spray_rotation", eact );
}
@@ -257,18 +460,162 @@ void sp_spray_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
// xgettext:no-c-format
_("Variation in the scale of the sprayed objects; 0% for the same scale than the original object"),
"/tools/spray/scale_variation", 0,
- GTK_WIDGET(desktop->canvas), holder, TRUE, "spray-scale",
+ GTK_WIDGET(desktop->canvas), holder, true, "spray-scale",
0, 100, 1.0, 10.0,
labels, values, G_N_ELEMENTS(labels),
sp_spray_scale_value_changed, NULL /*unit tracker*/, 1, 0 );
ege_adjustment_action_set_appearance( eact, TOOLBAR_SLIDER_HINT );
gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
- gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+ gtk_action_set_sensitive( GTK_ACTION(eact), true );
g_object_set_data( holder, "spray_scale", eact );
}
+ /* Use Pressure Scale button */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "SprayPressureScaleAction",
+ _("Pressure"),
+ _("Use the pressure of the input device to alter the scale of new items"),
+ INKSCAPE_ICON("draw-use-pressure"),
+ Inkscape::ICON_SIZE_DECORATION);
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/usepressurescale", false) );
+ g_object_set_data( holder, "usepressurescale", act );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pressure_scale), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* Picker */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "SprayPickColorAction",
+ _("Pick color from the drawing. You can use clonetiler trace dialog for advanced effects. In clone mode original fill or stroke colors must be unset."),
+ _("Pick color from the drawing. You can use clonetiler trace dialog for advanced effects. In clone mode original fill or stroke colors must be unset."),
+ INKSCAPE_ICON("color-picker"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/picker", false) );
+ g_object_set_data( holder, "picker", act );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_picker), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+
+ /* Pick from center */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "SprayPickCenterAction",
+ _("Pick from center instead average area."),
+ _("Pick from center instead average area."),
+ INKSCAPE_ICON("snap-bounding-box-center"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/pick_center", true) );
+ g_object_set_data( holder, "pick_center", act );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pick_center), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+ /* Inverse Value Size */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "SprayPickInverseValueAction",
+ _("Inverted pick value, retaining color in advanced trace mode"),
+ _("Inverted pick value, retaining color in advanced trace mode"),
+ INKSCAPE_ICON("object-tweak-shrink"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/pick_inverse_value", false) );
+ g_object_set_data( holder, "pick_inverse_value", act );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pick_inverse_value), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+
+ /* Pick Fill */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "SprayPickFillAction",
+ _("Apply picked color to fill"),
+ _("Apply picked color to fill"),
+ INKSCAPE_ICON("paint-solid"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/pick_fill", false) );
+ g_object_set_data( holder, "pick_fill", act );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pick_fill), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+
+ /* Pick Stroke */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "SprayPickStrokeAction",
+ _("Apply picked color to stroke"),
+ _("Apply picked color to stroke"),
+ INKSCAPE_ICON("no-marker"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/pick_stroke", false) );
+ g_object_set_data( holder, "pick_stroke", act );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pick_stroke), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+
+ /* Pick No Overlap */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "SprayPickNoOverlapAction",
+ _("No overlap between colors"),
+ _("No overlap between colors"),
+ INKSCAPE_ICON("symbol-bigger"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/pick_no_overlap", false) );
+ g_object_set_data( holder, "pick_no_overlap", act );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_pick_no_overlap), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+
+ /* Over Transparent */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "SprayOverTransparentAction",
+ _("Apply over transparent areas"),
+ _("Apply over transparent areas"),
+ INKSCAPE_ICON("object-hidden"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/over_transparent", true) );
+ g_object_set_data( holder, "over_transparent", act );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_over_transparent), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+
+ /* Over No Transparent */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "SprayOverNoTransparentAction",
+ _("Apply over no transparent areas"),
+ _("Apply over no transparent areas"),
+ INKSCAPE_ICON("object-visible"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/over_no_transparent", true) );
+ g_object_set_data( holder, "over_no_transparent", act );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_over_no_transparent), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+
+ /* Overlap */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "SprayNoOverlapAction",
+ _("Prevent overlapping objects"),
+ _("Prevent overlapping objects"),
+ INKSCAPE_ICON("distribute-randomize"),
+ secondarySize );
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/spray/no_overlap", false) );
+ g_object_set_data( holder, "no_overlap", act );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_toggle_no_overlap), holder) ;
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ }
+
+ /* Offset */
+ {
+ gchar const* labels[] = {_("(minimum offset)"), 0, 0, 0, _("(default)"), 0, 0, _("(maximum offset)")};
+ gdouble values[] = {0, 25, 50, 75, 100, 150, 200, 1000};
+ EgeAdjustmentAction *eact = create_adjustment_action( "SprayToolOffsetAction",
+ _("Offset %"), _("Offset %:"),
+ _("Increase to segregate objects more (value in percent)"),
+ "/tools/spray/offset", 100,
+ GTK_WIDGET(desktop->canvas), holder, FALSE, NULL,
+ 0, 1000, 1, 4,
+ labels, values, G_N_ELEMENTS(labels),
+ sp_spray_offset_value_changed, NULL, 0 , 0);
+ g_object_set_data( holder, "offset", eact );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
+ }
+ sp_spray_init(holder);
}
diff --git a/src/widgets/spray-toolbar.h b/src/widgets/spray-toolbar.h
index d1d5c7b4c..30d8233ca 100644
--- a/src/widgets/spray-toolbar.h
+++ b/src/widgets/spray-toolbar.h
@@ -21,7 +21,7 @@
*
* Copyright (C) 2004 David Turner
* Copyright (C) 2003 MenTaLguY
- * Copyright (C) 1999-2011 authors
+ * Copyright (C) 1999-2015 authors
* Copyright (C) 2001-2002 Ximian, Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
diff --git a/src/widgets/star-toolbar.cpp b/src/widgets/star-toolbar.cpp
index 96005d7df..982a3c854 100644
--- a/src/widgets/star-toolbar.cpp
+++ b/src/widgets/star-toolbar.cpp
@@ -84,7 +84,7 @@ static void sp_stb_magnitude_value_changed( GtkAdjustment *adj, GObject *dataKlu
Inkscape::Selection *selection = desktop->getSelection();
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (SP_IS_STAR(item)) {
Inkscape::XML::Node *repr = item->getRepr();
@@ -129,7 +129,7 @@ static void sp_stb_proportion_value_changed( GtkAdjustment *adj, GObject *dataKl
bool modmade = false;
Inkscape::Selection *selection = desktop->getSelection();
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (SP_IS_STAR(item)) {
Inkscape::XML::Node *repr = item->getRepr();
@@ -182,11 +182,11 @@ static void sp_stb_sides_flat_state_changed( EgeSelectOneAction *act, GObject *d
bool modmade = false;
if ( prop_action ) {
- gtk_action_set_sensitive( prop_action, !flat );
+ gtk_action_set_visible( prop_action, !flat );
}
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (SP_IS_STAR(item)) {
Inkscape::XML::Node *repr = item->getRepr();
@@ -225,7 +225,7 @@ static void sp_stb_rounded_value_changed( GtkAdjustment *adj, GObject *dataKludg
Inkscape::Selection *selection = desktop->getSelection();
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (SP_IS_STAR(item)) {
Inkscape::XML::Node *repr = item->getRepr();
@@ -265,7 +265,7 @@ static void sp_stb_randomized_value_changed( GtkAdjustment *adj, GObject *dataKl
Inkscape::Selection *selection = desktop->getSelection();
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (SP_IS_STAR(item)) {
Inkscape::XML::Node *repr = item->getRepr();
@@ -319,10 +319,10 @@ static void star_tb_event_attr_changed(Inkscape::XML::Node *repr, gchar const *n
EgeSelectOneAction* flat_action = EGE_SELECT_ONE_ACTION( g_object_get_data( G_OBJECT(tbl), "flat_action" ) );
if ( flatsides && !strcmp(flatsides,"false") ) {
ege_select_one_action_set_active( flat_action, 1 );
- gtk_action_set_sensitive( prop_action, TRUE );
+ gtk_action_set_visible( prop_action, TRUE );
} else {
ege_select_one_action_set_active( flat_action, 0 );
- gtk_action_set_sensitive( prop_action, FALSE );
+ gtk_action_set_visible( prop_action, FALSE );
}
} else if ((!strcmp(name, "sodipodi:r1") || !strcmp(name, "sodipodi:r2")) && (!isFlatSided) ) {
adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "proportion"));
@@ -368,7 +368,7 @@ sp_star_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl)
purge_repr_listener( tbl, tbl );
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (SP_IS_STAR(item)) {
n_selected++;
@@ -415,7 +415,7 @@ static void sp_stb_defaults( GtkWidget * /*widget*/, GObject *dataKludge )
ege_select_one_action_set_active( flat_action, flat ? 0 : 1 );
GtkAction* sb2 = GTK_ACTION( g_object_get_data( dataKludge, "prop_action" ) );
- gtk_action_set_sensitive( sb2, !flat );
+ gtk_action_set_visible( sb2, !flat );
adj = GTK_ADJUSTMENT( g_object_get_data( dataKludge, "magnitude" ) );
gtk_adjustment_set_value(adj, mag);
@@ -521,9 +521,9 @@ void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje
}
if ( !isFlatSided ) {
- gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+ gtk_action_set_visible( GTK_ACTION(eact), TRUE );
} else {
- gtk_action_set_sensitive( GTK_ACTION(eact), FALSE );
+ gtk_action_set_visible( GTK_ACTION(eact), FALSE );
}
/* Roundedness */
diff --git a/src/widgets/stroke-style.cpp b/src/widgets/stroke-style.cpp
index d05b3b994..84a6e77ad 100644
--- a/src/widgets/stroke-style.cpp
+++ b/src/widgets/stroke-style.cpp
@@ -221,6 +221,67 @@ StrokeStyle::StrokeStyle() :
#endif
i++;
+ /* Dash */
+ spw_label(table, _("Dashes:"), 0, i, NULL); //no mnemonic for now
+ //decide what to do:
+ // implement a set_mnemonic_source function in the
+ // SPDashSelector class, so that we do not have to
+ // expose any of the underlying widgets?
+ dashSelector = Gtk::manage(new SPDashSelector);
+
+ dashSelector->show();
+
+#if WITH_GTKMM_3_0
+ dashSelector->set_hexpand();
+ dashSelector->set_halign(Gtk::ALIGN_FILL);
+ dashSelector->set_valign(Gtk::ALIGN_CENTER);
+ table->attach(*dashSelector, 1, i, 3, 1);
+#else
+ table->attach(*dashSelector, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0);
+#endif
+
+ dashSelector->changed_signal.connect(sigc::mem_fun(*this, &StrokeStyle::lineDashChangedCB));
+
+ i++;
+
+ /* Drop down marker selectors*/
+ // TRANSLATORS: Path markers are an SVG feature that allows you to attach arbitrary shapes
+ // (arrowheads, bullets, faces, whatever) to the start, end, or middle nodes of a path.
+
+ spw_label(table, _("Markers:"), 0, i, NULL);
+
+ hb = spw_hbox(table, 1, 1, i);
+ i++;
+
+ startMarkerCombo = Gtk::manage(new MarkerComboBox("marker-start", SP_MARKER_LOC_START));
+ startMarkerCombo->set_tooltip_text(_("Start Markers are drawn on the first node of a path or shape"));
+ startMarkerConn = startMarkerCombo->signal_changed().connect(
+ sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>(
+ sigc::ptr_fun(&StrokeStyle::markerSelectCB), startMarkerCombo, this, SP_MARKER_LOC_START));
+ startMarkerCombo->show();
+
+ hb->pack_start(*startMarkerCombo, true, true, 0);
+
+ midMarkerCombo = Gtk::manage(new MarkerComboBox("marker-mid", SP_MARKER_LOC_MID));
+ midMarkerCombo->set_tooltip_text(_("Mid Markers are drawn on every node of a path or shape except the first and last nodes"));
+ midMarkerConn = midMarkerCombo->signal_changed().connect(
+ sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>(
+ sigc::ptr_fun(&StrokeStyle::markerSelectCB), midMarkerCombo, this, SP_MARKER_LOC_MID));
+ midMarkerCombo->show();
+
+ hb->pack_start(*midMarkerCombo, true, true, 0);
+
+ endMarkerCombo = Gtk::manage(new MarkerComboBox("marker-end", SP_MARKER_LOC_END));
+ endMarkerCombo->set_tooltip_text(_("End Markers are drawn on the last node of a path or shape"));
+ endMarkerConn = endMarkerCombo->signal_changed().connect(
+ sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>(
+ sigc::ptr_fun(&StrokeStyle::markerSelectCB), endMarkerCombo, this, SP_MARKER_LOC_END));
+ endMarkerCombo->show();
+
+ hb->pack_start(*endMarkerCombo, true, true, 0);
+
+ i++;
+
/* Join type */
// TRANSLATORS: The line join style specifies the shape to be used at the
// corners of paths. It can be "miter", "round" or "bevel".
@@ -230,14 +291,6 @@ StrokeStyle::StrokeStyle() :
Gtk::RadioButtonGroup joinGrp;
- joinMiter = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-miter"),
- hb, STROKE_STYLE_BUTTON_JOIN, "miter");
-
- // TRANSLATORS: Miter join: joining lines with a sharp (pointed) corner.
- // For an example, draw a triangle with a large stroke width and modify the
- // "Join" option (in the Fill and Stroke dialog).
- joinMiter->set_tooltip_text(_("Miter join"));
-
joinRound = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-round"),
hb, STROKE_STYLE_BUTTON_JOIN, "round");
@@ -254,7 +307,13 @@ StrokeStyle::StrokeStyle() :
// "Join" option (in the Fill and Stroke dialog).
joinBevel->set_tooltip_text(_("Bevel join"));
- i++;
+ joinMiter = makeRadioButton(joinGrp, INKSCAPE_ICON("stroke-join-miter"),
+ hb, STROKE_STYLE_BUTTON_JOIN, "miter");
+
+ // TRANSLATORS: Miter join: joining lines with a sharp (pointed) corner.
+ // For an example, draw a triangle with a large stroke width and modify the
+ // "Join" option (in the Fill and Stroke dialog).
+ joinMiter->set_tooltip_text(_("Miter join"));
/* Miterlimit */
// TRANSLATORS: Miter limit: only for "miter join", this limits the length
@@ -265,8 +324,6 @@ StrokeStyle::StrokeStyle() :
// when they become too long.
//spw_label(t, _("Miter _limit:"), 0, i);
- hb = spw_hbox(table, 3, 1, i);
-
#if WITH_GTKMM_3_0
miterLimitAdj = new Glib::RefPtr<Gtk::Adjustment>(Gtk::Adjustment::create(4.0, 0.0, 100.0, 0.1, 10.0, 0.0));
miterLimitSpin = new Inkscape::UI::Widget::SpinButton(*miterLimitAdj, 0.1, 2);
@@ -277,7 +334,6 @@ StrokeStyle::StrokeStyle() :
miterLimitSpin->set_tooltip_text(_("Maximum length of the miter (in units of stroke width)"));
miterLimitSpin->show();
- spw_label(table, _("Miter _limit:"), 0, i, miterLimitSpin);
sp_dialog_defocus_on_enter_cpp(miterLimitSpin);
hb->pack_start(*miterLimitSpin, false, false, 0);
@@ -288,6 +344,7 @@ StrokeStyle::StrokeStyle() :
#else
miterLimitAdj->signal_value_changed().connect(sigc::mem_fun(*this, &StrokeStyle::miterLimitChangedCB));
#endif
+
i++;
/* Cap type */
@@ -322,64 +379,43 @@ StrokeStyle::StrokeStyle() :
i++;
- /* Dash */
- spw_label(table, _("Dashes:"), 0, i, NULL); //no mnemonic for now
- //decide what to do:
- // implement a set_mnemonic_source function in the
- // SPDashSelector class, so that we do not have to
- // expose any of the underlying widgets?
- dashSelector = Gtk::manage(new SPDashSelector);
-
- dashSelector->show();
+ /* Paint order */
+ // TRANSLATORS: Paint order determines the order the 'fill', 'stroke', and 'markers are painted.
+ spw_label(table, _("Order:"), 0, i, NULL);
-#if WITH_GTKMM_3_0
- dashSelector->set_hexpand();
- dashSelector->set_halign(Gtk::ALIGN_FILL);
- dashSelector->set_valign(Gtk::ALIGN_CENTER);
- table->attach(*dashSelector, 1, i, 3, 1);
-#else
- table->attach(*dashSelector, 1, 4, i, i+1, (Gtk::EXPAND | Gtk::FILL), static_cast<Gtk::AttachOptions>(0), 0, 0);
-#endif
+ hb = spw_hbox(table, 4, 1, i);
- dashSelector->changed_signal.connect(sigc::mem_fun(*this, &StrokeStyle::lineDashChangedCB));
+ Gtk::RadioButtonGroup paintOrderGrp;
- i++;
+ paintOrderFSM = makeRadioButton(paintOrderGrp, INKSCAPE_ICON("paint-order-fsm"),
+ hb, STROKE_STYLE_BUTTON_ORDER, "normal");
+ paintOrderFSM->set_tooltip_text(_("Fill, Stroke, Markers"));
- /* Drop down marker selectors*/
- // TRANSLATORS: Path markers are an SVG feature that allows you to attach arbitrary shapes
- // (arrowheads, bullets, faces, whatever) to the start, end, or middle nodes of a path.
+ paintOrderSFM = makeRadioButton(paintOrderGrp, INKSCAPE_ICON("paint-order-sfm"),
+ hb, STROKE_STYLE_BUTTON_ORDER, "stroke fill markers");
+ paintOrderSFM->set_tooltip_text(_("Stroke, Fill, Markers"));
- spw_label(table, _("Markers:"), 0, i, NULL);
+ paintOrderFMS = makeRadioButton(paintOrderGrp, INKSCAPE_ICON("paint-order-fms"),
+ hb, STROKE_STYLE_BUTTON_ORDER, "fill markers stroke");
+ paintOrderFMS->set_tooltip_text(_("Fill, Markers, Stroke"));
- hb = spw_hbox(table, 1, 1, i);
i++;
- startMarkerCombo = Gtk::manage(new MarkerComboBox("marker-start", SP_MARKER_LOC_START));
- startMarkerCombo->set_tooltip_text(_("Start Markers are drawn on the first node of a path or shape"));
- startMarkerConn = startMarkerCombo->signal_changed().connect(
- sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>(
- sigc::ptr_fun(&StrokeStyle::markerSelectCB), startMarkerCombo, this, SP_MARKER_LOC_START));
- startMarkerCombo->show();
+ hb = spw_hbox(table, 4, 1, i);
- hb->pack_start(*startMarkerCombo, true, true, 0);
+ paintOrderMFS = makeRadioButton(paintOrderGrp, INKSCAPE_ICON("paint-order-mfs"),
+ hb, STROKE_STYLE_BUTTON_ORDER, "markers fill stroke");
+ paintOrderMFS->set_tooltip_text(_("Markers, Fill, Stroke"));
- midMarkerCombo = Gtk::manage(new MarkerComboBox("marker-mid", SP_MARKER_LOC_MID));
- midMarkerCombo->set_tooltip_text(_("Mid Markers are drawn on every node of a path or shape except the first and last nodes"));
- midMarkerConn = midMarkerCombo->signal_changed().connect(
- sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>(
- sigc::ptr_fun(&StrokeStyle::markerSelectCB), midMarkerCombo, this, SP_MARKER_LOC_MID));
- midMarkerCombo->show();
+ paintOrderSMF = makeRadioButton(paintOrderGrp, INKSCAPE_ICON("paint-order-smf"),
+ hb, STROKE_STYLE_BUTTON_ORDER, "stroke markers fill");
+ paintOrderSMF->set_tooltip_text(_("Stroke, Markers, Fill"));
- hb->pack_start(*midMarkerCombo, true, true, 0);
+ paintOrderMSF = makeRadioButton(paintOrderGrp, INKSCAPE_ICON("paint-order-msf"),
+ hb, STROKE_STYLE_BUTTON_ORDER, "markers stroke fill");
+ paintOrderMSF->set_tooltip_text(_("Markers, Stroke, Fill"));
- endMarkerCombo = Gtk::manage(new MarkerComboBox("marker-end", SP_MARKER_LOC_END));
- endMarkerCombo->set_tooltip_text(_("End Markers are drawn on the last node of a path or shape"));
- endMarkerConn = endMarkerCombo->signal_changed().connect(
- sigc::bind<MarkerComboBox *, StrokeStyle *, SPMarkerLoc>(
- sigc::ptr_fun(&StrokeStyle::markerSelectCB), endMarkerCombo, this, SP_MARKER_LOC_END));
- endMarkerCombo->show();
-
- hb->pack_start(*endMarkerCombo, true, true, 0);
+ i++;
setDesktop(desktop);
updateLine();
@@ -480,7 +516,7 @@ void StrokeStyle::markerSelectCB(MarkerComboBox *marker_combo, StrokeStyle *spw,
Inkscape::Selection *selection = spw->desktop->getSelection();
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();++i){
SPItem *item = *i;
if (!SP_IS_SHAPE(item) || SP_IS_RECT(item)) { // can't set marker to rect, until it's converted to using <path>
continue;
@@ -802,6 +838,43 @@ StrokeStyle::setCapType (unsigned const captype)
}
/**
+ * Sets the cap type for a line, and updates the stroke style widget's buttons
+ */
+void
+StrokeStyle::setPaintOrder (gchar const *paint_order)
+{
+ Gtk::RadioButton *tb = paintOrderFSM;
+
+ SPIPaintOrder temp;
+ temp.read( paint_order );
+
+ if (temp.layer[0] != SP_CSS_PAINT_ORDER_NORMAL) {
+
+ if (temp.layer[0] == SP_CSS_PAINT_ORDER_FILL) {
+ if (temp.layer[1] == SP_CSS_PAINT_ORDER_STROKE) {
+ tb = paintOrderFSM;
+ } else {
+ tb = paintOrderFMS;
+ }
+ } else if (temp.layer[0] == SP_CSS_PAINT_ORDER_STROKE) {
+ if (temp.layer[1] == SP_CSS_PAINT_ORDER_FILL) {
+ tb = paintOrderSFM;
+ } else {
+ tb = paintOrderSMF;
+ }
+ } else {
+ if (temp.layer[1] == SP_CSS_PAINT_ORDER_STROKE) {
+ tb = paintOrderMSF;
+ } else {
+ tb = paintOrderMFS;
+ }
+ }
+
+ }
+ setPaintOrderButtons(tb);
+}
+
+/**
* Callback for when stroke style widget is updated, including markers, cap type,
* join type, etc.
*/
@@ -825,6 +898,9 @@ StrokeStyle::updateLine()
int result_ml = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_STROKEMITERLIMIT);
int result_cap = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_STROKECAP);
int result_join = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_STROKEJOIN);
+
+ int result_order = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_PAINTORDER);
+
SPIPaint &targPaint = (kind == FILL) ? query.fill : query.stroke;
if (!sel || sel->isEmpty()) {
@@ -902,6 +978,13 @@ StrokeStyle::updateLine()
setCapButtons(NULL);
}
+ if (result_order != QUERY_STYLE_MULTIPLE_DIFFERENT &&
+ result_order != QUERY_STYLE_NOTHING ) {
+ setPaintOrder (query.paint_order.value);
+ } else {
+ setPaintOrder (NULL);
+ }
+
if (!sel || sel->isEmpty())
return;
@@ -981,7 +1064,7 @@ StrokeStyle::scaleLine()
int ndash;
dashSelector->get_dash(&ndash, &dash, &offset);
- for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=items.begin();i!=items.end();++i){
/* Set stroke width */
double width;
if (unit->type == Inkscape::Util::UNIT_TYPE_LINEAR) {
@@ -1109,6 +1192,11 @@ void StrokeStyle::buttonToggledCB(StrokeStyleButton *tb, StrokeStyle *spw)
sp_repr_css_set_property(css, "stroke-linecap", tb->get_stroke_style());
sp_desktop_set_style (spw->desktop, css);
spw->setCapButtons(tb);
+ break;
+ case STROKE_STYLE_BUTTON_ORDER:
+ sp_repr_css_set_property(css, "paint-order", tb->get_stroke_style());
+ sp_desktop_set_style (spw->desktop, css);
+ //spw->setPaintButtons(tb);
}
sp_repr_css_attr_unref(css);
@@ -1143,6 +1231,21 @@ StrokeStyle::setCapButtons(Gtk::ToggleButton *active)
/**
+ * Updates the paint order style toggle buttons
+ */
+void
+StrokeStyle::setPaintOrderButtons(Gtk::ToggleButton *active)
+{
+ paintOrderFSM->set_active(active == paintOrderFSM);
+ paintOrderSFM->set_active(active == paintOrderSFM);
+ paintOrderFMS->set_active(active == paintOrderFMS);
+ paintOrderMFS->set_active(active == paintOrderMFS);
+ paintOrderSMF->set_active(active == paintOrderSMF);
+ paintOrderMSF->set_active(active == paintOrderMSF);
+}
+
+
+/**
* Updates the marker combobox to highlight the appropriate marker and scroll to
* that marker.
*/
@@ -1156,7 +1259,7 @@ StrokeStyle::updateAllMarkers(std::vector<SPItem*> const &objects)
};
bool all_texts = true;
- for(std::vector<SPItem*>::const_iterator i=objects.begin();i!=objects.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=objects.begin();i!=objects.end();++i){
if (!SP_IS_TEXT (*i)) {
all_texts = false;
break;
diff --git a/src/widgets/stroke-style.h b/src/widgets/stroke-style.h
index 2605e1acf..d83067a4a 100644
--- a/src/widgets/stroke-style.h
+++ b/src/widgets/stroke-style.h
@@ -127,7 +127,8 @@ private:
/** List of valid types for the stroke-style radio-button widget */
enum StrokeStyleButtonType {
STROKE_STYLE_BUTTON_JOIN, ///< A button to set the line-join style
- STROKE_STYLE_BUTTON_CAP ///< A button to set the line-cap style
+ STROKE_STYLE_BUTTON_CAP, ///< A button to set the line-cap style
+ STROKE_STYLE_BUTTON_ORDER ///< A button to set the paint-order style
};
/**
@@ -158,8 +159,10 @@ private:
void setDashSelectorFromStyle(SPDashSelector *dsel, SPStyle *style);
void setJoinType (unsigned const jointype);
void setCapType (unsigned const captype);
+ void setPaintOrder (gchar const *paint_order);
void setJoinButtons(Gtk::ToggleButton *active);
void setCapButtons(Gtk::ToggleButton *active);
+ void setPaintOrderButtons(Gtk::ToggleButton *active);
void scaleLine();
void setScaledDash(SPCSSAttr *css, int ndash, double *dash, double offset, double scale);
void setMarkerColor(SPObject *marker, int loc, SPItem *item);
@@ -204,6 +207,12 @@ private:
StrokeStyleButton *capButt;
StrokeStyleButton *capRound;
StrokeStyleButton *capSquare;
+ StrokeStyleButton *paintOrderFSM;
+ StrokeStyleButton *paintOrderSFM;
+ StrokeStyleButton *paintOrderFMS;
+ StrokeStyleButton *paintOrderMFS;
+ StrokeStyleButton *paintOrderSMF;
+ StrokeStyleButton *paintOrderMSF;
SPDashSelector *dashSelector;
gboolean update;
diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp
index 7b22e4af7..c49f0bc05 100644
--- a/src/widgets/text-toolbar.cpp
+++ b/src/widgets/text-toolbar.cpp
@@ -54,12 +54,17 @@
#include "ui/icon-names.h"
#include "ui/tools/text-tool.h"
#include "ui/tools/tool-base.h"
+#include "ui/widget/unit-tracker.h"
+#include "util/units.h"
#include "verbs.h"
#include "xml/repr.h"
using Inkscape::DocumentUndo;
using Inkscape::UI::ToolboxFactory;
using Inkscape::UI::PrefPusher;
+using Inkscape::UI::Widget::UnitTracker;
+using Inkscape::Util::Unit;
+using Inkscape::Util::unit_table;
//#define DEBUG_TEXT
@@ -155,7 +160,7 @@ static void sp_text_fontfamily_value_changed( Ink_ComboBoxEntry_Action *act, GOb
act->active = 0; // New family is always at top of list.
}
- std::pair<Glib::ustring,Glib::ustring> ui = fontlister->set_font_family( act->active );
+ fontlister->set_font_family( act->active );
// active text set in sp_text_toolbox_selection_changed()
SPCSSAttr *css = sp_repr_css_attr_new ();
@@ -373,7 +378,7 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl )
// move the x of all texts to preserve the same bbox
Inkscape::Selection *selection = desktop->getSelection();
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){
if (SP_IS_TEXT(*i)) {
SPItem *item = *i;
@@ -504,8 +509,14 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl )
static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl )
{
- // quit if run by the _changed callbacks
- if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
+ UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker"));
+
+ if ( !tracker || tracker->isUpdating() || g_object_get_data(tbl, "freeze")) {
+ /*
+ * When only units are being changed, don't treat changes
+ * to adjuster values as object changes.
+ * or quit if run by the _changed callbacks
+ */
return;
}
g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
@@ -514,7 +525,18 @@ static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl )
// Set css line height.
SPCSSAttr *css = sp_repr_css_attr_new ();
Inkscape::CSSOStringStream osfs;
- osfs << gtk_adjustment_get_value(adj)*100 << "%";
+
+ gdouble value = gtk_adjustment_get_value(adj);
+
+ Unit const *unit = tracker->getActiveUnit();
+
+ // Value can only be in px or percent or naked pc (e.g. 0.7 for 70%)
+ if (unit->abbr != "%") {
+ value = unit->convert(value, "px");
+ unit = unit_table.getUnit("px");
+ }
+
+ osfs << value << unit->abbr;
sp_repr_css_set_property (css, "line-height", osfs.str().c_str());
// Apply line-height to selected objects.
@@ -526,7 +548,7 @@ static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl )
Inkscape::Selection *selection = desktop->getSelection();
bool modmade = false;
std::vector<SPItem*> itemlist=selection->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){
if (SP_IS_TEXT (*i)) {
(*i)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL));
modmade = true;
@@ -737,7 +759,7 @@ static void sp_text_rotation_value_changed( GtkAdjustment *adj, GObject *tbl )
g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
}
-static void sp_text_orientation_mode_changed( EgeSelectOneAction *act, GObject *tbl )
+static void sp_writing_mode_changed( EgeSelectOneAction *act, GObject *tbl )
{
// quit if run by the _changed callbacks
if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
@@ -752,13 +774,73 @@ static void sp_text_orientation_mode_changed( EgeSelectOneAction *act, GObject *
{
case 0:
{
- sp_repr_css_set_property (css, "writing-mode", "lr");
+ sp_repr_css_set_property (css, "writing-mode", "lr-tb");
break;
}
case 1:
{
- sp_repr_css_set_property (css, "writing-mode", "tb");
+ sp_repr_css_set_property (css, "writing-mode", "tb-rl");
+ break;
+ }
+
+ case 2:
+ {
+ sp_repr_css_set_property (css, "writing-mode", "vertical-lr");
+ break;
+ }
+}
+
+ SPStyle query(SP_ACTIVE_DOCUMENT);
+ int result_numbers =
+ sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
+
+ // If querying returned nothing, update default style.
+ if (result_numbers == QUERY_STYLE_NOTHING)
+ {
+ Inkscape::Preferences *prefs = Inkscape::Preferences::get();
+ prefs->mergeStyle("/tools/text/style", css);
+ }
+
+ sp_desktop_set_style (SP_ACTIVE_DESKTOP, css, true, true);
+ if(result_numbers != QUERY_STYLE_NOTHING)
+ {
+ DocumentUndo::done(SP_ACTIVE_DESKTOP->getDocument(), SP_VERB_CONTEXT_TEXT,
+ _("Text: Change writing mode"));
+ }
+ sp_repr_css_attr_unref (css);
+
+ g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) );
+}
+
+static void sp_text_orientation_changed( EgeSelectOneAction *act, GObject *tbl )
+{
+ // quit if run by the _changed callbacks
+ if (g_object_get_data(G_OBJECT(tbl), "freeze")) {
+ return;
+ }
+ g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) );
+
+ int mode = ege_select_one_action_get_active( act );
+
+ SPCSSAttr *css = sp_repr_css_attr_new ();
+ switch (mode)
+ {
+ case 0:
+ {
+ sp_repr_css_set_property (css, "text-orientation", "auto");
+ break;
+ }
+
+ case 1:
+ {
+ sp_repr_css_set_property (css, "text-orientation", "upright");
+ break;
+ }
+
+ case 2:
+ {
+ sp_repr_css_set_property (css, "text-orientation", "sideways");
break;
}
}
@@ -871,7 +953,7 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
// Find out if we have flowed text now so we can use it several places
gboolean isFlow = false;
std::vector<SPItem*> itemlist=SP_ACTIVE_DESKTOP->getSelection()->itemList();
- for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end();i++){
+ for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){
// const gchar* id = reinterpret_cast<SPItem *>(items->data)->getId();
// std::cout << " " << id << std::endl;
if( SP_IS_FLOWTEXT(*i)) {
@@ -893,13 +975,17 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
int result_style = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTSTYLE);
int result_numbers = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS);
int result_baseline = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_BASELINES);
+ int result_wmode = sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_WRITINGMODES);
/*
* If no text in selection (querying returned nothing), read the style from
* the /tools/text preferencess (default style for new texts). Return if
* tool bar already set to these preferences.
*/
- if (result_family == QUERY_STYLE_NOTHING || result_style == QUERY_STYLE_NOTHING || result_numbers == QUERY_STYLE_NOTHING) {
+ if (result_family == QUERY_STYLE_NOTHING ||
+ result_style == QUERY_STYLE_NOTHING ||
+ result_numbers == QUERY_STYLE_NOTHING ||
+ result_wmode == QUERY_STYLE_NOTHING ) {
// There are no texts in selection, read from preferences.
query.readFromPrefs("/tools/text");
#ifdef DEBUG_TEXT
@@ -1009,21 +1095,31 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
// Line height (spacing)
double height;
+
+ Unit const *lh_unit;
+ UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) );
+
if (query.line_height.normal) {
- height = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL;
+ lh_unit = unit_table.getUnit("%");
+ height = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL * 100;
+ } else if (query.line_height.unit == SP_CSS_UNIT_PERCENT) {
+ lh_unit = unit_table.getUnit("%");
+ height = query.line_height.value * 100;
} else {
- if (query.line_height.unit == SP_CSS_UNIT_PERCENT) {
- height = query.line_height.value;
- } else {
- height = query.line_height.computed;
- }
+ lh_unit = tracker->getActiveUnit();
+ // Can get unit like this: unit_table.getUnit(query.line_height.unit);
+ height = Inkscape::Util::Quantity::convert(query.line_height.computed, "px", lh_unit);
}
+ // Set before value is set
+ tracker->setActiveUnit(lh_unit);
+
GtkAction* lineHeightAction = GTK_ACTION( g_object_get_data( tbl, "TextLineHeightAction" ) );
GtkAdjustment *lineHeightAdjustment =
ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( lineHeightAction ));
gtk_adjustment_set_value( lineHeightAdjustment, height );
+ height = gtk_adjustment_get_value( lineHeightAdjustment );
// Word spacing
double wordSpacing;
@@ -1047,13 +1143,42 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/
gtk_adjustment_set_value( letterSpacingAdjustment, letterSpacing );
+ // Writing mode
+ int activeButton2 = 0;
+ if (query.writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB) activeButton2 = 0;
+ if (query.writing_mode.computed == SP_CSS_WRITING_MODE_TB_RL) activeButton2 = 1;
+ if (query.writing_mode.computed == SP_CSS_WRITING_MODE_TB_LR) activeButton2 = 2;
+
+ EgeSelectOneAction* writingModeAction =
+ EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextWritingModeAction" ) );
+ ege_select_one_action_set_active( writingModeAction, activeButton2 );
+
// Orientation
- int activeButton2 = (query.writing_mode.computed == SP_CSS_WRITING_MODE_LR_TB ? 0 : 1);
+ int activeButton3 = 0;
+ if (query.text_orientation.computed == SP_CSS_TEXT_ORIENTATION_MIXED ) activeButton3 = 0;
+ if (query.text_orientation.computed == SP_CSS_TEXT_ORIENTATION_UPRIGHT ) activeButton3 = 1;
+ if (query.text_orientation.computed == SP_CSS_TEXT_ORIENTATION_SIDEWAYS) activeButton3 = 2;
EgeSelectOneAction* textOrientationAction =
EGE_SELECT_ONE_ACTION( g_object_get_data( tbl, "TextOrientationAction" ) );
- ege_select_one_action_set_active( textOrientationAction, activeButton2 );
+ ege_select_one_action_set_active( textOrientationAction, activeButton3 );
+
+ // Disable text orientation for horizontal text.. See above for why this nonsense
+ model = GTK_LIST_STORE( ege_select_one_action_get_model( textOrientationAction ) );
+
+ path = gtk_tree_path_new_from_string("0");
+ gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path );
+ gtk_list_store_set( model, &iter, /* column */ 3, activeButton2 != 0, -1 );
+
+ path = gtk_tree_path_new_from_string("1");
+ gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path );
+ gtk_list_store_set( model, &iter, /* column */ 3, activeButton2 != 0, -1 );
+
+ path = gtk_tree_path_new_from_string("2");
+ gtk_tree_model_get_iter( GTK_TREE_MODEL (model), &iter, path );
+ gtk_list_store_set( model, &iter, /* column */ 3, activeButton2 != 0, -1 );
+ ege_select_one_action_update_sensitive( textOrientationAction );
}
@@ -1165,7 +1290,7 @@ static void sp_text_toolbox_select_cb( GtkEntry* entry, GtkEntryIconPosition /*p
SPDocument *document = desktop->getDocument();
std::vector<SPItem*> x,y;
std::vector<SPItem*> allList = get_all_items(x, document->getRoot(), desktop, false, false, true, y);
- for(std::vector<SPItem*>::const_reverse_iterator i=allList.rbegin();i!=allList.rend();i++){
+ for(std::vector<SPItem*>::const_reverse_iterator i=allList.rbegin();i!=allList.rend(); ++i){
SPItem *item = *i;
SPStyle *style = item->style;
@@ -1197,6 +1322,15 @@ static void sp_text_toolbox_select_cb( GtkEntry* entry, GtkEntryIconPosition /*p
static void text_toolbox_watch_ec(SPDesktop* dt, Inkscape::UI::Tools::ToolBase* ec, GObject* holder);
+static void destroy_tracker( GObject* obj, gpointer /*user_data*/ )
+{
+ UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(obj, "tracker"));
+ if ( tracker ) {
+ delete tracker;
+ g_object_set_data( obj, "tracker", 0 );
+ }
+}
+
// Define all the "widgets" in the toolbar.
void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
{
@@ -1387,7 +1521,7 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje
g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_align_mode_changed), holder );
}
- /* Orientation (Left to Right, Top to Bottom */
+ /* Writing mode (Horizontal, Vertical-LR, Vertical-RL) */
{
GtkListStore* model = gtk_list_store_new( 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING );
@@ -1402,14 +1536,73 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje
gtk_list_store_append( model, &iter );
gtk_list_store_set( model, &iter,
- 0, _("Vertical"),
- 1, _("Vertical text"),
+ 0, _("Vertical — RL"),
+ 1, _("Vertical text — lines: right to left"),
2, INKSCAPE_ICON("format-text-direction-vertical"),
-1 );
+ gtk_list_store_append( model, &iter );
+ gtk_list_store_set( model, &iter,
+ 0, _("Vertical — LR"),
+ 1, _("Vertical text — lines: left to right"), // Mongolian!
+ 2, INKSCAPE_ICON("format-text-direction-vertical-lr"),
+ -1 );
+
+ EgeSelectOneAction* act = ege_select_one_action_new( "TextWritingModeAction", // Name
+ _("Writing mode"), // Label
+ _("Block progression"), // Tooltip
+ NULL, // Icon name
+ GTK_TREE_MODEL(model) ); // Model
+
+ g_object_set( act, "short_label", "NotUsed", NULL );
+ gtk_action_group_add_action( mainActions, GTK_ACTION(act) );
+ g_object_set_data( holder, "TextWritingModeAction", act );
+
+ ege_select_one_action_set_appearance( act, "full" );
+ ege_select_one_action_set_radio_action_type( act, INK_RADIO_ACTION_TYPE );
+ g_object_set( G_OBJECT(act), "icon-property", "iconId", NULL );
+ ege_select_one_action_set_icon_column( act, 2 );
+ ege_select_one_action_set_icon_size( act, secondarySize );
+ ege_select_one_action_set_tooltip_column( act, 1 );
+
+ gint mode = prefs->getInt("/tools/text/writing_mode", 0);
+ ege_select_one_action_set_active( act, mode );
+ g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_writing_mode_changed), holder );
+ }
+
+ /* Text (glyph) orientation (Auto (mixed), Upright, Sideways) */
+ {
+ GtkListStore* model = gtk_list_store_new( 4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN );
+
+ GtkTreeIter iter;
+
+ gtk_list_store_append( model, &iter );
+ gtk_list_store_set( model, &iter,
+ 0, _("Auto"),
+ 1, _("Auto glyph orientation"),
+ 2, INKSCAPE_ICON("text-orientation-auto"),
+ 3, true,
+ -1 );
+
+ gtk_list_store_append( model, &iter );
+ gtk_list_store_set( model, &iter,
+ 0, _("Upright"),
+ 1, _("Upright glyph orientation"),
+ 2, INKSCAPE_ICON("text-orientation-upright"),
+ 3, true,
+ -1 );
+
+ gtk_list_store_append( model, &iter );
+ gtk_list_store_set( model, &iter,
+ 0, _("Sideways"),
+ 1, _("Sideways glyph orientation"),
+ 2, INKSCAPE_ICON("text-orientation-sideways"),
+ 3, true,
+ -1 );
+
EgeSelectOneAction* act = ege_select_one_action_new( "TextOrientationAction", // Name
- _("Orientation"), // Label
- _("Text orientation"), // Tooltip
+ _("Text orientation"), // Label
+ _("Text (glyph) orientation in vertical text."), // Tooltip
NULL, // Icon name
GTK_TREE_MODEL(model) ); // Model
@@ -1423,10 +1616,11 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje
ege_select_one_action_set_icon_column( act, 2 );
ege_select_one_action_set_icon_size( act, secondarySize );
ege_select_one_action_set_tooltip_column( act, 1 );
+ ege_select_one_action_set_sensitive_column( act, 3 );
- gint mode = prefs->getInt("/tools/text/orientation", 0);
+ gint mode = prefs->getInt("/tools/text/text_orientation", 0);
ege_select_one_action_set_active( act, mode );
- g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_orientation_mode_changed), holder );
+ g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_orientation_changed), holder );
}
/* Line height */
@@ -1435,22 +1629,29 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje
gchar const* labels[] = {_("Smaller spacing"), 0, 0, 0, 0, C_("Text tool", "Normal"), 0, 0, 0, 0, 0, _("Larger spacing")};
gdouble values[] = { 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1,2, 1.3, 1.4, 1.5, 2.0};
+ // Add the units menu.
+ UnitTracker* tracker = new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR);
+ tracker->prependUnit(unit_table.getUnit("%"));
+
+ g_object_set_data( holder, "tracker", tracker );
+ g_signal_connect( holder, "destroy", G_CALLBACK(destroy_tracker), holder );
+
EgeAdjustmentAction *eact = create_adjustment_action(
"TextLineHeightAction", /* name */
_("Line Height"), /* label */
_("Line:"), /* short label */
- _("Spacing between lines (times font size)"), /* tooltip */
+ _("Spacing between baselines"), /* tooltip */
"/tools/text/lineheight", /* preferences path */
- 0.0, /* default */
+ 125, /* default */
GTK_WIDGET(desktop->canvas), /* focusTarget */
holder, /* dataKludge */
FALSE, /* set alt-x keyboard shortcut? */
NULL, /* altx_mark */
- 0.0, 10.0, 0.01, 0.10, /* lower, upper, step (arrow up/down), page up/down */
+ 0.0, 1e6, 1.0, 10.0, /* lower, upper, step (arrow up/down), page up/down */
labels, values, G_N_ELEMENTS(labels), /* drop down menu */
sp_text_lineheight_value_changed, /* callback */
- NULL, /* unit tracker */
- 0.1, /* step (used?) */
+ tracker, /* unit tracker */
+ 1.0, /* step (used?) */
2, /* digits to show */
1.0 /* factor (multiplies default) */
);
@@ -1458,6 +1659,11 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje
gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
g_object_set_data( holder, "TextLineHeightAction", eact );
g_object_set( G_OBJECT(eact), "iconId", "text_line_spacing", NULL );
+
+ GtkAction* act = tracker->createAction( "TextLineHeightUnitAction", _("Units"), ("") );
+ gtk_action_group_add_action( mainActions, act );
+ g_object_set_data( holder, "TextLineHeightUnitAction", act );
+
}
/* Word spacing */
diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp
index d56b91f5e..f4d7ebf25 100644
--- a/src/widgets/toolbox.cpp
+++ b/src/widgets/toolbox.cpp
@@ -16,10 +16,11 @@
* Tavmjong Bah <tavmjong@free.fr>
* Abhishek Sharma
* Kris De Gussem <Kris.DeGussem@gmail.com>
+ * Jabiertxo Arraiza <jabier.arraiza@marker.es>
*
* Copyright (C) 2004 David Turner
* Copyright (C) 2003 MenTaLguY
- * Copyright (C) 1999-2011 authors
+ * Copyright (C) 1999-2015 authors
* Copyright (C) 2001-2002 Ximian, Inc.
*
* Released under GNU GPL, read the file 'COPYING' for more information
@@ -54,6 +55,7 @@
#include "ui/tools-switch.h"
#include "../ui/icon-names.h"
#include "../ui/widget/style-swatch.h"
+#include "../ui/widget/unit-tracker.h"
#include "../verbs.h"
#include "../widgets/button.h"
#include "../widgets/spinbutton-events.h"
@@ -78,7 +80,11 @@
#include "measure-toolbar.h"
#include "node-toolbar.h"
#include "rect-toolbar.h"
-#include "paintbucket-toolbar.h"
+
+#if HAVE_POTRACE
+# include "paintbucket-toolbar.h"
+#endif
+
#include "pencil-toolbar.h"
#include "select-toolbar.h"
#include "spray-toolbar.h"
@@ -150,7 +156,9 @@ static struct {
{ "/tools/calligraphic", "dyna_draw_tool", SP_VERB_CONTEXT_CALLIGRAPHIC, SP_VERB_CONTEXT_CALLIGRAPHIC_PREFS },
{ "/tools/lpetool", "lpetool_tool", SP_VERB_CONTEXT_LPETOOL, SP_VERB_CONTEXT_LPETOOL_PREFS },
{ "/tools/eraser", "eraser_tool", SP_VERB_CONTEXT_ERASER, SP_VERB_CONTEXT_ERASER_PREFS },
+#if HAVE_POTRACE
{ "/tools/paintbucket", "paintbucket_tool", SP_VERB_CONTEXT_PAINTBUCKET, SP_VERB_CONTEXT_PAINTBUCKET_PREFS },
+#endif
{ "/tools/text", "text_tool", SP_VERB_CONTEXT_TEXT, SP_VERB_CONTEXT_TEXT_PREFS },
{ "/tools/connector","connector_tool", SP_VERB_CONTEXT_CONNECTOR, SP_VERB_CONTEXT_CONNECTOR_PREFS },
{ "/tools/gradient", "gradient_tool", SP_VERB_CONTEXT_GRADIENT, SP_VERB_CONTEXT_GRADIENT_PREFS },
@@ -211,8 +219,10 @@ static struct {
SP_VERB_INVALID, 0, 0},
{ "/tools/mesh", "mesh_toolbox", 0, sp_mesh_toolbox_prep, "MeshToolbar",
SP_VERB_INVALID, 0, 0},
+#if HAVE_POTRACE
{ "/tools/paintbucket", "paintbucket_toolbox", 0, sp_paintbucket_toolbox_prep, "PaintbucketToolbar",
SP_VERB_CONTEXT_PAINTBUCKET_PREFS, "/tools/paintbucket", N_("Style of Paint Bucket fill objects")},
+#endif
{ NULL, NULL, NULL, NULL, NULL, SP_VERB_INVALID, NULL, NULL }
};
@@ -309,14 +319,28 @@ static gchar const * ui_descr =
" <toolitem action='SprayModeAction' />"
" <separator />"
" <toolitem action='SprayWidthAction' />"
+ " <toolitem action='SprayPressureWidthAction' />"
" <toolitem action='SprayPopulationAction' />"
- " <toolitem action='SprayPressureAction' />"
+ " <toolitem action='SprayPressurePopulationAction' />"
" <separator />"
" <toolitem action='SprayRotationAction' />"
" <toolitem action='SprayScaleAction' />"
+ " <toolitem action='SprayPressureScaleAction' />"
" <separator />"
" <toolitem action='SprayStandard_deviationAction' />"
" <toolitem action='SprayMeanAction' />"
+ " <separator />"
+ " <toolitem action='SprayOverNoTransparentAction' />"
+ " <toolitem action='SprayOverTransparentAction' />"
+ " <toolitem action='SprayPickNoOverlapAction' />"
+ " <toolitem action='SprayNoOverlapAction' />"
+ " <toolitem action='SprayToolOffsetAction' />"
+ " <separator />"
+ " <toolitem action='SprayPickColorAction' />"
+ " <toolitem action='SprayPickFillAction' />"
+ " <toolitem action='SprayPickStrokeAction' />"
+ " <toolitem action='SprayPickInverseValueAction' />"
+ " <toolitem action='SprayPickCenterAction' />"
" </toolbar>"
" <toolbar name='ZoomToolbar'>"
@@ -339,9 +363,24 @@ static gchar const * ui_descr =
" <toolbar name='MeasureToolbar'>"
" <toolitem action='MeasureFontSizeAction' />"
" <separator />"
+ " <toolitem action='MeasurePrecisionAction' />"
+ " <separator />"
+ " <toolitem action='MeasureScaleAction' />"
+ " <separator />"
+ " <toolitem action='MeasureOffsetAction' />"
+ " <separator />"
" <toolitem action='measure_units_label' />"
" <toolitem action='MeasureUnitsAction' />"
- " </toolbar>"
+ " <toolitem action='MeasureIgnore1stAndLast' />"
+ " <toolitem action='MeasureInBettween' />"
+ " <toolitem action='MeasureShowHidden' />"
+ " <toolitem action='MeasureAllLayers' />"
+ " <toolitem action='MeasureReverse' />"
+ " <toolitem action='MeasureToPhantom' />"
+ " <toolitem action='MeasureToGuides' />"
+ " <toolitem action='MeasureMarkDimension' />"
+ " <toolitem action='MeasureToItem' />"
+ " </toolbar>"
" <toolbar name='StarToolbar'>"
" <separator />"
@@ -398,6 +437,8 @@ static gchar const * ui_descr =
" <toolitem action='FreehandModeActionPencil' />"
" <separator />"
" <toolitem action='PencilToleranceAction' />"
+ " <toolitem action='PencilLpeSimplify' />"
+ " <toolitem action='PencilLpeSimplifyFlatten' />"
" <separator />"
" <toolitem action='PencilResetAction' />"
" <separator />"
@@ -438,6 +479,7 @@ static gchar const * ui_descr =
" <separator />"
" </toolbar>"
+#if HAVE_POTRACE
" <toolbar name='PaintbucketToolbar'>"
" <toolitem action='ChannelsAction' />"
" <separator />"
@@ -450,11 +492,15 @@ static gchar const * ui_descr =
" <separator />"
" <toolitem action='PaintbucketResetAction' />"
" </toolbar>"
+#endif
" <toolbar name='EraserToolbar'>"
" <toolitem action='EraserModeAction' />"
" <separator />"
" <toolitem action='EraserWidthAction' />"
+ " <toolitem action='EraserBreakAppart' />"
+ " <separator />"
+ " <toolitem action='EraserMassAction' />"
" </toolbar>"
" <toolbar name='TextToolbar'>"
@@ -470,12 +516,15 @@ static gchar const * ui_descr =
" <toolitem action='TextSubscriptAction' />"
" <separator />"
" <toolitem action='TextLineHeightAction' />"
+ " <toolitem action='TextLineHeightUnitAction' />"
" <toolitem action='TextLetterSpacingAction' />"
" <toolitem action='TextWordSpacingAction' />"
" <toolitem action='TextDxAction' />"
" <toolitem action='TextDyAction' />"
" <toolitem action='TextRotationAction' />"
" <separator />"
+ " <toolitem action='TextWritingModeAction' />"
+ " <separator />"
" <toolitem action='TextOrientationAction' />"
" </toolbar>"
@@ -517,9 +566,12 @@ static gchar const * ui_descr =
// " <toolitem action='MeshEditFillAction' />"
// " <toolitem action='MeshEditStrokeAction' />"
// " <toolitem action='MeshShowHandlesAction' />"
+ " <toolitem action='MeshToggleSidesAction' />"
+ " <toolitem action='MeshMakeEllipticalAction' />"
+ " <toolitem action='MeshPickColorsAction' />"
+ " <separator />"
" <toolitem action='MeshWarningAction' />"
" <toolitem action='MeshSmoothAction' />"
- " <separator />"
" </toolbar>"
" <toolbar name='DropperToolbar'>"
@@ -897,8 +949,12 @@ static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* deskto
};
Inkscape::IconSize toolboxSize = ToolboxFactory::prefToSize("/toolbox/small");
-
Glib::RefPtr<Gtk::ActionGroup> mainActions;
+ if (desktop == NULL)
+ {
+ return mainActions;
+ }
+
if ( groups.find(desktop) != groups.end() ) {
mainActions = groups[desktop];
}
@@ -906,10 +962,7 @@ static Glib::RefPtr<Gtk::ActionGroup> create_or_fetch_actions( SPDesktop* deskto
if ( !mainActions ) {
mainActions = Gtk::ActionGroup::create("main");
groups[desktop] = mainActions;
- if (desktop)
- {
- desktop->connectDestroy(&desktopDestructHandler);
- }
+ desktop->connectDestroy(&desktopDestructHandler);
}
for ( guint i = 0; i < G_N_ELEMENTS(verbsToUse); i++ ) {
@@ -1071,6 +1124,10 @@ EgeAdjustmentAction * create_adjustment_action( gchar const *name,
g_object_set_data( dataKludge, prefs->getEntry(path).getEntryName().data(), adj );
}
+ if (unit_tracker) {
+ unit_tracker->addAdjustment(adj);
+ }
+
// Using a cast just to make sure we pass in the right kind of function pointer
g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL );
@@ -1289,8 +1346,11 @@ void setup_tool_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
" <toolitem action='ToolSpray' />"
" <toolitem action='ToolEraser' />"
+#if HAVE_POTRACE
" <!-- Fill -->"
" <toolitem action='ToolPaintBucket' />"
+#endif
+
" <toolitem action='ToolGradient' />"
#ifdef WITH_MESH
" <toolitem action='ToolMesh' />"
@@ -1417,8 +1477,11 @@ void setup_aux_toolbox(GtkWidget *toolbox, SPDesktop *desktop)
gtk_table_attach( GTK_TABLE(holder), swatch_, 1, 2, 0, 1, (GtkAttachOptions)(GTK_SHRINK | GTK_FILL), (GtkAttachOptions)(GTK_EXPAND | GTK_FILL), AUX_BETWEEN_BUTTON_GROUPS, AUX_SPACING );
#endif
}
-
- gtk_widget_show_all( holder );
+ if(i==0){
+ gtk_widget_show_all( holder );
+ } else {
+ gtk_widget_show_now( holder );
+ }
sp_set_font_size_smaller( holder );
gtk_size_group_add_widget( grouper, holder );
@@ -1439,7 +1502,7 @@ void update_aux_toolbox(SPDesktop * /*desktop*/, ToolBase *eventcontext, GtkWidg
for (int i = 0 ; aux_toolboxes[i].type_name ; i++ ) {
GtkWidget *sub_toolbox = GTK_WIDGET(g_object_get_data(G_OBJECT(toolbox), aux_toolboxes[i].data_name));
if (tname && !strcmp(tname, aux_toolboxes[i].type_name)) {
- gtk_widget_show_all(sub_toolbox);
+ gtk_widget_show_now(sub_toolbox);
g_object_set_data(G_OBJECT(toolbox), "shows", sub_toolbox);
} else {
gtk_widget_hide(sub_toolbox);
@@ -1509,13 +1572,12 @@ static void toggle_snap_callback(GtkToggleAction *act, gpointer data) //data poi
SPDesktop *dt = reinterpret_cast<SPDesktop*>(ptr);
SPNamedView *nv = dt->getNamedView();
- SPDocument *doc = nv->document;
-
- if (dt == NULL || nv == NULL) {
- g_warning("No desktop or namedview specified (in toggle_snap_callback)!");
+ if (nv == NULL) {
+ g_warning("No namedview specified (in toggle_snap_callback)!");
return;
}
+ SPDocument *doc = nv->document;
Inkscape::XML::Node *repr = nv->getRepr();
if (repr == NULL) {
diff --git a/src/widgets/tweak-toolbar.cpp b/src/widgets/tweak-toolbar.cpp
index a5d90fc3d..a185ea956 100644
--- a/src/widgets/tweak-toolbar.cpp
+++ b/src/widgets/tweak-toolbar.cpp
@@ -82,12 +82,12 @@ static void sp_tweak_mode_changed( EgeSelectOneAction *act, GObject *tbl )
for (size_t i = 0; i < G_N_ELEMENTS(names); ++i) {
GtkAction *act = GTK_ACTION(g_object_get_data( tbl, names[i] ));
if (act) {
- gtk_action_set_sensitive(act, flag);
+ gtk_action_set_visible(act, flag);
}
}
GtkAction *fid = GTK_ACTION(g_object_get_data( tbl, "tweak_fidelity"));
if (fid) {
- gtk_action_set_sensitive(fid, !flag);
+ gtk_action_set_visible(fid, !flag);
}
}
@@ -276,7 +276,7 @@ void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
ege_output_action_set_use_markup( act, TRUE );
gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
if (mode != Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT && mode != Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) {
- gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
+ gtk_action_set_visible (GTK_ACTION(act), FALSE);
}
g_object_set_data( holder, "tweak_channels_label", act);
}
@@ -288,12 +288,12 @@ void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
NULL,
Inkscape::ICON_SIZE_DECORATION );
//TRANSLATORS: "H" here stands for hue
- g_object_set( act, "short_label", _("H"), NULL );
+ g_object_set( act, "short_label", C_("Hue", "H"), NULL );
gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doh), desktop );
gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doh", true) );
if (mode != Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT && mode != Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) {
- gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
+ gtk_action_set_visible (GTK_ACTION(act), FALSE);
}
g_object_set_data( holder, "tweak_doh", act);
}
@@ -304,12 +304,12 @@ void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
NULL,
Inkscape::ICON_SIZE_DECORATION );
//TRANSLATORS: "S" here stands for Saturation
- g_object_set( act, "short_label", _("S"), NULL );
+ g_object_set( act, "short_label", C_("Saturation", "S"), NULL );
gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dos), desktop );
gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dos", true) );
if (mode != Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT && mode != Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) {
- gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
+ gtk_action_set_visible (GTK_ACTION(act), FALSE);
}
g_object_set_data( holder, "tweak_dos", act );
}
@@ -320,12 +320,12 @@ void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
NULL,
Inkscape::ICON_SIZE_DECORATION );
//TRANSLATORS: "L" here stands for Lightness
- g_object_set( act, "short_label", _("L"), NULL );
+ g_object_set( act, "short_label", C_("Lightness", "L"), NULL );
gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_dol), desktop );
gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/dol", true) );
if (mode != Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT && mode != Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) {
- gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
+ gtk_action_set_visible (GTK_ACTION(act), FALSE);
}
g_object_set_data( holder, "tweak_dol", act );
}
@@ -336,12 +336,12 @@ void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
NULL,
Inkscape::ICON_SIZE_DECORATION );
//TRANSLATORS: "O" here stands for Opacity
- g_object_set( act, "short_label", _("O"), NULL );
+ g_object_set( act, "short_label", C_("Opacity", "O"), NULL );
gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(tweak_toggle_doo), desktop );
gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/tweak/doo", true) );
if (mode != Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT && mode != Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) {
- gtk_action_set_sensitive (GTK_ACTION(act), FALSE);
+ gtk_action_set_visible (GTK_ACTION(act), FALSE);
}
g_object_set_data( holder, "tweak_doo", act );
}
@@ -358,9 +358,9 @@ void sp_tweak_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObj
labels, values, G_N_ELEMENTS(labels),
sp_tweak_fidelity_value_changed, NULL /*unit tracker*/, 0.01, 0, 100 );
gtk_action_group_add_action( mainActions, GTK_ACTION(eact) );
- gtk_action_set_sensitive( GTK_ACTION(eact), TRUE );
+ gtk_action_set_visible( GTK_ACTION(eact), TRUE );
if (mode == Inkscape::UI::Tools::TWEAK_MODE_COLORPAINT || mode == Inkscape::UI::Tools::TWEAK_MODE_COLORJITTER) {
- gtk_action_set_sensitive (GTK_ACTION(eact), FALSE);
+ gtk_action_set_visible (GTK_ACTION(eact), FALSE);
}
g_object_set_data( holder, "tweak_fidelity", eact );
}
diff --git a/src/xml/quote.cpp b/src/xml/quote.cpp
index 02c12dfb0..b889b890d 100644
--- a/src/xml/quote.cpp
+++ b/src/xml/quote.cpp
@@ -1,81 +1,77 @@
/** \file
- * XML quoting routines.
- */
-
-/* Based on Lauris' repr_quote_write in repr-io.cpp.
- *
- * Copyright (C) 1999-2002 Lauris Kaplinski
- * Copyright (C) 2004 Monash University
- *
- * May be modified and/or redistributed under the terms of version 2
- * of the GNU General Public License: see the file `COPYING'.
+ * @brief XML quoting routines
+ *//*
+ * Authors:
+ * Krzysztof Kosiński <tweenk.pl@gmail.com>
+ *
+ * This file is in the public domain.
*/
+#include "xml/quote.h"
#include <cstring>
#include <glib.h>
-#include "quote.h"
-
-/** \return strlen(xml_quote_strdup(\a val)) (without doing the malloc).
- * \pre val != NULL
- */
-size_t
-xml_quoted_strlen(char const *val)
+/// Returns the length of the string after quoting the characters <code>"&amp;&lt;&gt;</code>.
+size_t xml_quoted_strlen(char const *val)
{
- size_t ret = 0;
- if (val != NULL) {
- for (; *val != '\0'; val++) {
- switch (*val) {
- case '"': ret += sizeof("&quot;") - 1; break;
- case '&': ret += sizeof("&amp;") - 1; break;
- case '<': ret += sizeof("&lt;") - 1; break;
- case '>': ret += sizeof("&gt;") - 1; break;
- default: ++ret; break;
- }
+ if (!val) return 0;
+ size_t len = 0;
+
+ for (char const *valp = val; *valp; ++valp) {
+ switch (*valp) {
+ case '"':
+ len += 6; // &quot;
+ break;
+ case '&':
+ len += 5; // &amp;
+ break;
+ case '<':
+ case '>':
+ len += 4; // &lt; or &gt;
+ break;
+ default:
+ ++len;
+ break;
}
}
- return ret;
+ return len;
}
-/** Writes \a src (including the NUL byte) to \a dest, doing XML quoting as necessary.
- *
- * \pre \a src != NULL.
- * \pre \a dest must have enough space for (xml_quoted_strlen(src) + 1) bytes.
- */
-static void
-xml_quote(char *dest, char const *src)
+char *xml_quote_strdup(char const *src)
{
-#define COPY_LIT(_lit) do { \
- size_t cpylen = sizeof(_lit "") - 1; \
- memcpy(dest, _lit, cpylen); \
- dest += cpylen; \
- } while(0)
+ size_t len = xml_quoted_strlen(src);
+ char *result = static_cast<char*>(g_malloc(len + 1));
+ char *resp = result;
- for (; *src != '\0'; ++src) {
- switch (*src) {
- case '"': COPY_LIT("&quot;"); break;
- case '&': COPY_LIT("&amp;"); break;
- case '<': COPY_LIT("&lt;"); break;
- case '>': COPY_LIT("&gt;"); break;
- default: *dest++ = *src; break;
+ for (char const *srcp = src; *srcp; ++srcp) {
+ switch(*srcp) {
+ case '"':
+ strcpy(resp, "&quot;");
+ resp += 6;
+ break;
+ case '&':
+ strcpy(resp, "&amp;");
+ resp += 5;
+ break;
+ case '<':
+ strcpy(resp, "&lt;");
+ resp += 4;
+ break;
+ case '>':
+ strcpy(resp, "&gt;");
+ resp += 4;
+ break;
+ default:
+ *resp++ = *srcp;
+ break;
}
}
- *dest = '\0';
-
-#undef COPY_LIT
+ *resp = 0;
+ return result;
}
-/** \return A g_malloc'd buffer containing an XML-quoted version of \a src.
- * \pre src != NULL.
- */
-char *
-xml_quote_strdup(char const *src)
-{
- size_t const quoted_size = xml_quoted_strlen(src) + 1;
- char *ret = (char *) g_malloc(quoted_size);
- xml_quote(ret, src);
- return ret;
-}
+// quote: ", &, <, >
+
/*
Local Variables:
diff --git a/src/xml/rebase-hrefs.cpp b/src/xml/rebase-hrefs.cpp
index 9d4f4f9fc..2bcae5d81 100644
--- a/src/xml/rebase-hrefs.cpp
+++ b/src/xml/rebase-hrefs.cpp
@@ -220,9 +220,9 @@ void Inkscape::XML::rebase_hrefs(SPDocument *const doc, gchar const *const new_b
*
* Note also that Inkscape only supports fragment hrefs (href="#pattern257") for many of these
* cases. */
- GSList const *images = doc->getResourceList("image");
- for (GSList const *l = images; l != NULL; l = l->next) {
- Inkscape::XML::Node *ir = static_cast<SPObject *>(l->data)->getRepr();
+ std::set<SPObject *> images = doc->getResourceList("image");
+ for (std::set<SPObject *>::const_iterator it = images.begin(); it != images.end(); ++it) {
+ Inkscape::XML::Node *ir = (*it)->getRepr();
std::string uri;
{
diff --git a/src/xml/repr-io.cpp b/src/xml/repr-io.cpp
index a4146f215..4a6f59b43 100644
--- a/src/xml/repr-io.cpp
+++ b/src/xml/repr-io.cpp
@@ -38,6 +38,7 @@
#include "preferences.h"
#include <glibmm/miscutils.h>
+#include <map>
using Inkscape::IO::Writer;
using Inkscape::Util::List;
@@ -50,8 +51,8 @@ using Inkscape::XML::calc_abs_doc_base;
using Inkscape::XML::rebase_href_attrs;
Document *sp_repr_do_read (xmlDocPtr doc, const gchar *default_ns);
-static Node *sp_repr_svg_read_node (Document *xml_doc, xmlNodePtr node, const gchar *default_ns, GHashTable *prefix_map);
-static gint sp_repr_qualified_name (gchar *p, gint len, xmlNsPtr ns, const xmlChar *name, const gchar *default_ns, GHashTable *prefix_map);
+static Node *sp_repr_svg_read_node (Document *xml_doc, xmlNodePtr node, const gchar *default_ns, std::map<std::string, std::string> &prefix_map);
+static gint sp_repr_qualified_name (gchar *p, gint len, xmlNsPtr ns, const xmlChar *name, const gchar *default_ns, std::map<std::string, std::string> &prefix_map);
static void sp_repr_write_stream_root_element(Node *repr, Writer &out,
bool add_whitespace, gchar const *default_ns,
int inlineattrs, int indent,
@@ -486,8 +487,7 @@ Document *sp_repr_do_read (xmlDocPtr doc, const gchar *default_ns)
return NULL;
}
- GHashTable * prefix_map;
- prefix_map = g_hash_table_new (g_str_hash, g_str_equal);
+ std::map<std::string, std::string> prefix_map;
Document *rdoc = new Inkscape::XML::SimpleDocument();
@@ -536,21 +536,17 @@ Document *sp_repr_do_read (xmlDocPtr doc, const gchar *default_ns)
}
}
- g_hash_table_destroy (prefix_map);
-
return rdoc;
}
-gint sp_repr_qualified_name (gchar *p, gint len, xmlNsPtr ns, const xmlChar *name, const gchar */*default_ns*/, GHashTable *prefix_map)
+gint sp_repr_qualified_name (gchar *p, gint len, xmlNsPtr ns, const xmlChar *name, const gchar */*default_ns*/, std::map<std::string, std::string> &prefix_map)
{
const xmlChar *prefix;
if (ns){
if (ns->href ) {
prefix = reinterpret_cast<const xmlChar*>( sp_xml_ns_uri_prefix(reinterpret_cast<const gchar*>(ns->href),
reinterpret_cast<const char*>(ns->prefix)) );
- void* p0 = reinterpret_cast<gpointer>(const_cast<xmlChar *>(prefix));
- void* p1 = reinterpret_cast<gpointer>(const_cast<xmlChar *>(ns->href));
- g_hash_table_insert( prefix_map, p0, p1 );
+ prefix_map[reinterpret_cast<const char*>(prefix)] = reinterpret_cast<const char*>(ns->href);
}
else {
prefix = NULL;
@@ -567,7 +563,7 @@ gint sp_repr_qualified_name (gchar *p, gint len, xmlNsPtr ns, const xmlChar *nam
}
}
-static Node *sp_repr_svg_read_node (Document *xml_doc, xmlNodePtr node, const gchar *default_ns, GHashTable *prefix_map)
+static Node *sp_repr_svg_read_node (Document *xml_doc, xmlNodePtr node, const gchar *default_ns, std::map<std::string, std::string> &prefix_map)
{
xmlAttrPtr prop;
xmlNodePtr child;
diff --git a/src/xml/repr-util.cpp b/src/xml/repr-util.cpp
index f7a437163..ce93bccab 100644
--- a/src/xml/repr-util.cpp
+++ b/src/xml/repr-util.cpp
@@ -528,6 +528,7 @@ unsigned int sp_repr_set_svg_double(Inkscape::XML::Node *repr, gchar const *key,
{
g_return_val_if_fail(repr != NULL, FALSE);
g_return_val_if_fail(key != NULL, FALSE);
+ g_return_val_if_fail(val==val, FALSE);//tests for nan
Inkscape::SVGOStringStream os;
os << val;