From 16a8c7d5e433b176636a4a1260c42ea43932110b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Krzysztof=20Kosi=C5=84ski?= Date: Sun, 29 Nov 2009 16:33:18 +0100 Subject: [PATCH] First GSoC node tool commit to Bazaar --- configure.ac | 7 +- po/POTFILES.in | 333 ++-- po/POTFILES.skip | 1 + src/2geom/chebyshev.cpp | 2 +- src/2geom/svg-path-parser.cpp | 1 - src/Makefile.am | 1 + src/Makefile_insert | 1 - src/desktop.cpp | 94 +- src/desktop.h | 5 + src/display/sp-canvas-util.cpp | 7 +- src/display/sp-canvas.cpp | 28 +- src/display/sp-canvas.h | 1 + src/dom/io/httpclient.cpp | 4 +- src/dom/odf/SvgOdg.cpp | 1551 ------------------- src/event-context.cpp | 1 - src/extension/dxf2svg/entities2elements.cpp | 10 +- src/extension/dxf2svg/read_dxf.cpp | 10 +- src/extension/dxf2svg/tables2svg_info.cpp | 8 +- src/extension/internal/cairo-renderer.cpp | 1 + src/gc-allocator.h | 106 -- src/libnrtype/FontFactory.cpp | 2 +- src/libnrtype/FontFactory.h | 6 +- src/libnrtype/FontInstance.cpp | 2 +- src/libnrtype/font-instance.h | 6 +- src/libvpsc/pairingheap/.dirstamp | 0 src/live_effects/parameter/path.cpp | 16 +- src/preferences-skeleton.h | 2 +- src/preferences.cpp | 22 + src/preferences.h | 24 + src/selection-chemistry.cpp | 89 +- src/shape-editor.cpp | 14 - src/shape-editor.h | 20 - src/sp-lpe-item.cpp | 17 +- src/tools-switch.cpp | 5 +- src/ui/dialog/aboutbox.cpp | 4 +- src/ui/dialog/align-and-distribute.cpp | 11 +- src/ui/dialog/inkscape-preferences.cpp | 13 +- src/ui/dialog/inkscape-preferences.h | 3 + src/ui/tool/Makefile_insert | 29 + src/ui/tool/commit-events.h | 51 + src/ui/tool/control-point-selection.cpp | 530 +++++++ src/ui/tool/control-point-selection.h | 140 ++ src/ui/tool/control-point.cpp | 619 ++++++++ src/ui/tool/control-point.h | 167 ++ src/ui/tool/curve-drag-point.cpp | 185 +++ src/ui/tool/curve-drag-point.h | 60 + src/ui/tool/event-utils.cpp | 113 ++ src/ui/tool/event-utils.h | 129 ++ src/ui/tool/manipulator.cpp | 89 ++ src/ui/tool/manipulator.h | 184 +++ src/ui/tool/multi-path-manipulator.cpp | 568 +++++++ src/ui/tool/multi-path-manipulator.h | 133 ++ src/ui/tool/node-tool.cpp | 563 +++++++ src/ui/tool/node-tool.h | 84 + src/ui/tool/node-types.h | 48 + src/ui/tool/node.cpp | 965 ++++++++++++ src/ui/tool/node.h | 366 +++++ src/ui/tool/path-manipulator.cpp | 1183 ++++++++++++++ src/ui/tool/path-manipulator.h | 146 ++ src/ui/tool/selectable-control-point.cpp | 135 ++ src/ui/tool/selectable-control-point.h | 71 + src/ui/tool/selector.cpp | 133 ++ src/ui/tool/selector.h | 59 + src/ui/tool/transform-handle-set.cpp | 653 ++++++++ src/ui/tool/transform-handle-set.h | 96 ++ src/util/accumulators.h | 113 ++ src/util/hash.h | 41 + src/verbs.cpp | 65 +- src/widgets/toolbox.cpp | 234 ++- 69 files changed, 8168 insertions(+), 2212 deletions(-) delete mode 100644 src/libvpsc/pairingheap/.dirstamp create mode 100644 src/ui/tool/Makefile_insert create mode 100644 src/ui/tool/commit-events.h create mode 100644 src/ui/tool/control-point-selection.cpp create mode 100644 src/ui/tool/control-point-selection.h create mode 100644 src/ui/tool/control-point.cpp create mode 100644 src/ui/tool/control-point.h create mode 100644 src/ui/tool/curve-drag-point.cpp create mode 100644 src/ui/tool/curve-drag-point.h create mode 100644 src/ui/tool/event-utils.cpp create mode 100644 src/ui/tool/event-utils.h create mode 100644 src/ui/tool/manipulator.cpp create mode 100644 src/ui/tool/manipulator.h create mode 100644 src/ui/tool/multi-path-manipulator.cpp create mode 100644 src/ui/tool/multi-path-manipulator.h create mode 100644 src/ui/tool/node-tool.cpp create mode 100644 src/ui/tool/node-tool.h create mode 100644 src/ui/tool/node-types.h create mode 100644 src/ui/tool/node.cpp create mode 100644 src/ui/tool/node.h create mode 100644 src/ui/tool/path-manipulator.cpp create mode 100644 src/ui/tool/path-manipulator.h create mode 100644 src/ui/tool/selectable-control-point.cpp create mode 100644 src/ui/tool/selectable-control-point.h create mode 100644 src/ui/tool/selector.cpp create mode 100644 src/ui/tool/selector.h create mode 100644 src/ui/tool/transform-handle-set.cpp create mode 100644 src/ui/tool/transform-handle-set.h create mode 100644 src/util/accumulators.h create mode 100644 src/util/hash.h diff --git a/configure.ac b/configure.ac index fbfa2e5df..5bf86e096 100644 --- a/configure.ac +++ b/configure.ac @@ -600,8 +600,11 @@ dnl with_inkboard="no" dnl fi dnl AM_CONDITIONAL(WITH_INKBOARD, test "x$with_inkboard" = "xyes") -dnl AC_SUBST(INKBOARD_LIBS) -dnl AC_SUBST(INKBOARD_CFLAGS) + +INKBOARD_CFLAGS="" +INKBOARD_LIBS="" +AC_SUBST(INKBOARD_LIBS) +AC_SUBST(INKBOARD_CFLAGS) dnl ****************************** dnl Check for libwpg for extension diff --git a/po/POTFILES.in b/po/POTFILES.in index 395a4a988..df09acc22 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,18 +1,155 @@ + # List of source files containing translatable strings. # Please keep this file sorted alphabetically. -# Generated by ./generate_POTFILES.sh at Wed Jun 3 14:29:48 CDT 2009 +# Generated by Waf at Sun Oct 4 01:04:56 2009 + [encoding: UTF-8] +[type: gettext/xml] share/extensions/addnodes.inx +[type: gettext/xml] share/extensions/ai_input.inx +[type: gettext/xml] share/extensions/aisvg.inx +[type: gettext/xml] share/extensions/ccx_input.inx +[type: gettext/xml] share/extensions/cdr_input.inx +[type: gettext/xml] share/extensions/cdt_input.inx +[type: gettext/xml] share/extensions/cgm_input.inx +[type: gettext/xml] share/extensions/cmx_input.inx +[type: gettext/xml] share/extensions/color_brighter.inx +[type: gettext/xml] share/extensions/color_custom.inx +[type: gettext/xml] share/extensions/color_darker.inx +[type: gettext/xml] share/extensions/color_desaturate.inx +[type: gettext/xml] share/extensions/color_grayscale.inx +[type: gettext/xml] share/extensions/color_lesshue.inx +[type: gettext/xml] share/extensions/color_lesslight.inx +[type: gettext/xml] share/extensions/color_lesssaturation.inx +[type: gettext/xml] share/extensions/color_morehue.inx +[type: gettext/xml] share/extensions/color_morelight.inx +[type: gettext/xml] share/extensions/color_moresaturation.inx +[type: gettext/xml] share/extensions/color_negative.inx +[type: gettext/xml] share/extensions/color_randomize.inx +[type: gettext/xml] share/extensions/color_removeblue.inx +[type: gettext/xml] share/extensions/color_removegreen.inx +[type: gettext/xml] share/extensions/color_removered.inx +[type: gettext/xml] share/extensions/color_replace.inx +[type: gettext/xml] share/extensions/color_rgbbarrel.inx +[type: gettext/xml] share/extensions/convert2dashes.inx +[type: gettext/xml] share/extensions/dia.inx +[type: gettext/xml] share/extensions/dimension.inx +[type: gettext/xml] share/extensions/dots.inx +[type: gettext/xml] share/extensions/draw_from_triangle.inx +[type: gettext/xml] share/extensions/dxf_input.inx +[type: gettext/xml] share/extensions/dxf_outlines.inx +[type: gettext/xml] share/extensions/dxf_output.inx +[type: gettext/xml] share/extensions/edge3d.inx +[type: gettext/xml] share/extensions/embedimage.inx +[type: gettext/xml] share/extensions/eps_input.inx +[type: gettext/xml] share/extensions/eqtexsvg.inx +[type: gettext/xml] share/extensions/export_gimp_palette.inx +[type: gettext/xml] share/extensions/extractimage.inx +[type: gettext/xml] share/extensions/extrude.inx +[type: gettext/xml] share/extensions/fig_input.inx +[type: gettext/xml] share/extensions/flatten.inx +[type: gettext/xml] share/extensions/foldablebox.inx +[type: gettext/xml] share/extensions/fractalize.inx +[type: gettext/xml] share/extensions/funcplot.inx +[type: gettext/xml] share/extensions/gears.inx +[type: gettext/xml] share/extensions/gimp_xcf.inx +[type: gettext/xml] share/extensions/grid_cartesian.inx +[type: gettext/xml] share/extensions/grid_polar.inx +[type: gettext/xml] share/extensions/guides_creator.inx +[type: gettext/xml] share/extensions/handles.inx +[type: gettext/xml] share/extensions/hpgl_output.inx +[type: gettext/xml] share/extensions/inkscape_help_askaquestion.inx +[type: gettext/xml] share/extensions/inkscape_help_commandline.inx +[type: gettext/xml] share/extensions/inkscape_help_faq.inx +[type: gettext/xml] share/extensions/inkscape_help_keys.inx +[type: gettext/xml] share/extensions/inkscape_help_manual.inx +[type: gettext/xml] share/extensions/inkscape_help_relnotes.inx +[type: gettext/xml] share/extensions/inkscape_help_reportabug.inx +[type: gettext/xml] share/extensions/inkscape_help_svgspec.inx +[type: gettext/xml] share/extensions/interp.inx +[type: gettext/xml] share/extensions/interp_att_g.inx +[type: gettext/xml] share/extensions/lindenmayer.inx +[type: gettext/xml] share/extensions/lorem_ipsum.inx +[type: gettext/xml] share/extensions/markers_strokepaint.inx +[type: gettext/xml] share/extensions/measure.inx +[type: gettext/xml] share/extensions/motion.inx +[type: gettext/xml] share/extensions/outline2svg.inx +[type: gettext/xml] share/extensions/param_curves.inx +[type: gettext/xml] share/extensions/pathalongpath.inx +[type: gettext/xml] share/extensions/pathscatter.inx +[type: gettext/xml] share/extensions/perfectboundcover.inx +[type: gettext/xml] share/extensions/perspective.inx +[type: gettext/xml] share/extensions/plt_input.inx +[type: gettext/xml] share/extensions/plt_output.inx +[type: gettext/xml] share/extensions/polyhedron_3d.inx +[type: gettext/xml] share/extensions/printing-marks.inx +[type: gettext/xml] share/extensions/ps_input.inx +[type: gettext/xml] share/extensions/radiusrand.inx +[type: gettext/xml] share/extensions/render_alphabetsoup.inx +[type: gettext/xml] share/extensions/render_barcode.inx +[type: gettext/xml] share/extensions/restack.inx +[type: gettext/xml] share/extensions/rtree.inx +[type: gettext/xml] share/extensions/rubberstretch.inx +[type: gettext/xml] share/extensions/scour.inx +[type: gettext/xml] share/extensions/sk1_input.inx +[type: gettext/xml] share/extensions/sk1_output.inx +[type: gettext/xml] share/extensions/sk_input.inx +[type: gettext/xml] share/extensions/spirograph.inx +[type: gettext/xml] share/extensions/straightseg.inx +[type: gettext/xml] share/extensions/summersnight.inx +[type: gettext/xml] share/extensions/svg2xaml.inx +[type: gettext/xml] share/extensions/svg_and_media_zip_output.inx +[type: gettext/xml] share/extensions/svgcalendar.inx +[type: gettext/xml] share/extensions/text_braille.inx +[type: gettext/xml] share/extensions/text_flipcase.inx +[type: gettext/xml] share/extensions/text_lowercase.inx +[type: gettext/xml] share/extensions/text_randomcase.inx +[type: gettext/xml] share/extensions/text_replace.inx +[type: gettext/xml] share/extensions/text_sentencecase.inx +[type: gettext/xml] share/extensions/text_titlecase.inx +[type: gettext/xml] share/extensions/text_uppercase.inx +[type: gettext/xml] share/extensions/triangle.inx +[type: gettext/xml] share/extensions/txt2svg.inx +[type: gettext/xml] share/extensions/web-set-att.inx +[type: gettext/xml] share/extensions/web-transmit-att.inx +[type: gettext/xml] share/extensions/whirl.inx +[type: gettext/xml] share/extensions/wmf_input.inx +[type: gettext/xml] share/extensions/wmf_output.inx +[type: gettext/xml] share/extensions/xaml2svg.inx +[type: gettext/xml] src/extension/dxf2svg/dxf_input.inx +[type: gettext/xml] src/extension/dxf2svg/dxf_input_windows.inx +cxxtest/cxxtestgen.py inkscape.desktop.in +share/extensions/dimension.py +share/extensions/draw_from_triangle.py +share/extensions/dxf_outlines.py +share/extensions/embedimage.py +share/extensions/export_gimp_palette.py +share/extensions/extractimage.py +share/extensions/guides_creator.py +share/extensions/inkex.py +share/extensions/markers_strokepaint.py +share/extensions/pathalongpath.py +share/extensions/pathmodifier.py +share/extensions/pathscatter.py +share/extensions/perspective.py +share/extensions/polyhedron_3d.py +share/extensions/summersnight.py +share/extensions/svg_and_media_zip_output.py +share/extensions/uniconv_output.py +share/extensions/web-set-att.py +share/extensions/web-transmit-att.py share/filters/filters.svg.h +share/filters/i18n.py +share/patterns/i18n.py share/patterns/patterns.svg.h src/arc-context.cpp src/box3d-context.cpp src/box3d.cpp src/connector-context.cpp src/context-fns.cpp -src/desktop.cpp src/desktop-events.cpp +src/desktop.cpp src/dialogs/clonetiler.cpp src/dialogs/export.cpp src/dialogs/find.cpp @@ -54,8 +191,8 @@ src/extension/internal/bitmap/enhance.cpp src/extension/internal/bitmap/equalize.cpp src/extension/internal/bitmap/gaussianBlur.cpp src/extension/internal/bitmap/implode.cpp -src/extension/internal/bitmap/levelChannel.cpp src/extension/internal/bitmap/level.cpp +src/extension/internal/bitmap/levelChannel.cpp src/extension/internal/bitmap/medianFilter.cpp src/extension/internal/bitmap/modulate.cpp src/extension/internal/bitmap/negate.cpp @@ -79,15 +216,15 @@ src/extension/internal/cairo-renderer-pdf-out.cpp src/extension/internal/clear-n_.h src/extension/internal/emf-win32-inout.cpp src/extension/internal/filter/drop-shadow.h -src/extension/internal/filter/filter.cpp src/extension/internal/filter/filter-file.cpp +src/extension/internal/filter/filter.cpp src/extension/internal/filter/snow.h src/extension/internal/gdkpixbuf-input.cpp src/extension/internal/gimpgrad.cpp src/extension/internal/grid.cpp src/extension/internal/javafx-out.cpp -src/extension/internal/latex-pstricks.cpp src/extension/internal/latex-pstricks-out.cpp +src/extension/internal/latex-pstricks.cpp src/extension/internal/odf.cpp src/extension/internal/pdfinput/pdf-input.cpp src/extension/internal/pov-out.cpp @@ -110,39 +247,62 @@ src/filter-enums.cpp src/flood-context.cpp src/gradient-context.cpp src/gradient-drag.cpp -src/helper/units.cpp src/helper/units-test.h +src/helper/units.cpp src/inkscape.cpp src/interface.cpp src/io/sys.cpp +src/jabber_whiteboard/invitation-confirm-dialog.cpp +src/jabber_whiteboard/message-queue.cpp +src/jabber_whiteboard/message-utilities.cpp +src/jabber_whiteboard/pedrogui.cpp +src/jabber_whiteboard/session-file-selector.cpp +src/jabber_whiteboard/session-manager.cpp src/knot.cpp src/knotholder.cpp src/libgdl/gdl-dock-bar.c -src/libgdl/gdl-dock.c -src/libgdl/gdl-dock-item.c src/libgdl/gdl-dock-item-grip.c +src/libgdl/gdl-dock-item.c src/libgdl/gdl-dock-master.c src/libgdl/gdl-dock-notebook.c src/libgdl/gdl-dock-object.c src/libgdl/gdl-dock-paned.c src/libgdl/gdl-dock-placeholder.c src/libgdl/gdl-dock-tablabel.c -src/libgdl/gdl-i18n.c +src/libgdl/gdl-dock.c src/libgdl/gdl-i18n.h src/libgdl/gdl-switcher.c src/libnrtype/FontFactory.cpp src/live_effects/effect.cpp +src/live_effects/lpe-angle_bisector.cpp src/live_effects/lpe-bendpath.cpp +src/live_effects/lpe-boolops.cpp +src/live_effects/lpe-circle_with_radius.cpp src/live_effects/lpe-constructgrid.cpp +src/live_effects/lpe-copy_rotate.cpp src/live_effects/lpe-curvestitch.cpp +src/live_effects/lpe-dynastroke.cpp src/live_effects/lpe-envelope.cpp src/live_effects/lpe-gears.cpp src/live_effects/lpe-interpolate.cpp src/live_effects/lpe-knot.cpp +src/live_effects/lpe-lattice.cpp +src/live_effects/lpe-line_segment.cpp +src/live_effects/lpe-mirror_symmetry.cpp +src/live_effects/lpe-offset.cpp +src/live_effects/lpe-parallel.cpp +src/live_effects/lpe-path_length.cpp src/live_effects/lpe-patternalongpath.cpp +src/live_effects/lpe-perp_bisector.cpp +src/live_effects/lpe-perspective_path.cpp +src/live_effects/lpe-recursiveskeleton.cpp src/live_effects/lpe-rough-hatches.cpp src/live_effects/lpe-ruler.cpp +src/live_effects/lpe-skeleton.cpp src/live_effects/lpe-sketch.cpp +src/live_effects/lpe-tangent_to_curve.cpp +src/live_effects/lpe-test-doEffect-stack.cpp +src/live_effects/lpe-text_label.cpp src/live_effects/lpe-vonkoch.cpp src/live_effects/parameter/bool.cpp src/live_effects/parameter/enum.h @@ -153,6 +313,7 @@ src/live_effects/parameter/random.cpp src/live_effects/parameter/text.cpp src/live_effects/parameter/unit.cpp src/live_effects/parameter/vector.cpp +src/lpe-tool-context.cpp src/main-cmdlineact.cpp src/main.cpp src/menus-skeleton.h @@ -160,11 +321,11 @@ src/node-context.cpp src/nodepath.cpp src/object-edit.cpp src/path-chemistry.cpp -src/pencil-context.cpp src/pen-context.cpp +src/pencil-context.cpp src/persp3d.cpp -src/preferences.cpp src/preferences-skeleton.h +src/preferences.cpp src/rdf.cpp src/rect-context.cpp src/select-context.cpp @@ -175,28 +336,24 @@ src/shape-editor.cpp src/sp-anchor.cpp src/sp-ellipse.cpp src/sp-flowregion.cpp -src/sp-flowtext.cpp src/sp-guide.cpp src/sp-image.cpp -src/spiral-context.cpp -src/sp-item.cpp src/sp-item-group.cpp +src/sp-item.cpp src/sp-line.cpp -src/splivarot.cpp src/sp-lpe-item.cpp src/sp-namedview.cpp src/sp-offset.cpp -src/sp-path.cpp src/sp-polygon.cpp src/sp-polyline.cpp src/sp-rect.cpp src/sp-spiral.cpp -src/sp-star.cpp -src/sp-switch.cpp src/sp-text.cpp src/sp-tref.cpp src/sp-tspan.cpp src/sp-use.cpp +src/spiral-context.cpp +src/splivarot.cpp src/star-context.cpp src/text-chemistry.cpp src/text-context.cpp @@ -230,11 +387,21 @@ src/ui/dialog/messages.cpp src/ui/dialog/ocaldialogs.cpp src/ui/dialog/print.cpp src/ui/dialog/scriptdialog.cpp +src/ui/dialog/session-player.cpp src/ui/dialog/svg-fonts-dialog.cpp src/ui/dialog/swatches.cpp src/ui/dialog/tile.cpp src/ui/dialog/tracedialog.cpp src/ui/dialog/transformation.cpp +src/ui/dialog/whiteboard-connect.cpp +src/ui/dialog/whiteboard-sharewithchat.cpp +src/ui/dialog/whiteboard-sharewithuser.cpp +src/ui/tool/curve-drag-point.cpp +src/ui/tool/multi-path-manipulator.cpp +src/ui/tool/node-tool.cpp +src/ui/tool/node.cpp +src/ui/tool/path-manipulator.cpp +src/ui/tool/transform-handle-set.cpp src/ui/view/edit-widget.cpp src/ui/widget/combo-enums.h src/ui/widget/entity-entry.cpp @@ -275,133 +442,3 @@ src/widgets/sp-xmlview-attr-list.cpp src/widgets/sp-xmlview-content.cpp src/widgets/stroke-style.cpp src/widgets/toolbox.cpp -share/extensions/dimension.py -share/extensions/draw_from_triangle.py -share/extensions/dxf_outlines.py -share/extensions/embedimage.py -share/extensions/export_gimp_palette.py -share/extensions/extractimage.py -share/extensions/guides_creator.py -share/extensions/inkex.py -share/extensions/markers_strokepaint.py -share/extensions/pathalongpath.py -share/extensions/pathmodifier.py -share/extensions/pathscatter.py -share/extensions/perspective.py -share/extensions/polyhedron_3d.py -share/extensions/summersnight.py -share/extensions/svg_and_media_zip_output.py -share/extensions/uniconv_output.py -share/extensions/web-set-att.py -share/extensions/web-transmit-att.py -[type: gettext/xml] share/extensions/addnodes.inx -[type: gettext/xml] share/extensions/ai_input.inx -[type: gettext/xml] share/extensions/aisvg.inx -[type: gettext/xml] share/extensions/ccx_input.inx -[type: gettext/xml] share/extensions/cdr_input.inx -[type: gettext/xml] share/extensions/cdt_input.inx -[type: gettext/xml] share/extensions/cgm_input.inx -[type: gettext/xml] share/extensions/cmx_input.inx -[type: gettext/xml] share/extensions/color_brighter.inx -[type: gettext/xml] share/extensions/color_custom.inx -[type: gettext/xml] share/extensions/color_darker.inx -[type: gettext/xml] share/extensions/color_desaturate.inx -[type: gettext/xml] share/extensions/color_grayscale.inx -[type: gettext/xml] share/extensions/color_lesshue.inx -[type: gettext/xml] share/extensions/color_lesslight.inx -[type: gettext/xml] share/extensions/color_lesssaturation.inx -[type: gettext/xml] share/extensions/color_morehue.inx -[type: gettext/xml] share/extensions/color_morelight.inx -[type: gettext/xml] share/extensions/color_moresaturation.inx -[type: gettext/xml] share/extensions/color_negative.inx -[type: gettext/xml] share/extensions/color_randomize.inx -[type: gettext/xml] share/extensions/color_removeblue.inx -[type: gettext/xml] share/extensions/color_removegreen.inx -[type: gettext/xml] share/extensions/color_removered.inx -[type: gettext/xml] share/extensions/color_replace.inx -[type: gettext/xml] share/extensions/color_rgbbarrel.inx -[type: gettext/xml] share/extensions/convert2dashes.inx -[type: gettext/xml] share/extensions/dia.inx -[type: gettext/xml] share/extensions/dimension.inx -[type: gettext/xml] share/extensions/dots.inx -[type: gettext/xml] share/extensions/draw_from_triangle.inx -[type: gettext/xml] share/extensions/dxf_input.inx -[type: gettext/xml] share/extensions/dxf_outlines.inx -[type: gettext/xml] share/extensions/dxf_output.inx -[type: gettext/xml] share/extensions/edge3d.inx -[type: gettext/xml] share/extensions/embedimage.inx -[type: gettext/xml] share/extensions/eps_input.inx -[type: gettext/xml] share/extensions/eqtexsvg.inx -[type: gettext/xml] share/extensions/export_gimp_palette.inx -[type: gettext/xml] share/extensions/extractimage.inx -[type: gettext/xml] share/extensions/extrude.inx -[type: gettext/xml] share/extensions/fig_input.inx -[type: gettext/xml] share/extensions/flatten.inx -[type: gettext/xml] share/extensions/foldablebox.inx -[type: gettext/xml] share/extensions/fractalize.inx -[type: gettext/xml] share/extensions/funcplot.inx -[type: gettext/xml] share/extensions/gears.inx -[type: gettext/xml] share/extensions/gimp_xcf.inx -[type: gettext/xml] share/extensions/grid_cartesian.inx -[type: gettext/xml] share/extensions/grid_polar.inx -[type: gettext/xml] share/extensions/guides_creator.inx -[type: gettext/xml] share/extensions/handles.inx -[type: gettext/xml] share/extensions/hpgl_output.inx -[type: gettext/xml] share/extensions/inkscape_help_askaquestion.inx -[type: gettext/xml] share/extensions/inkscape_help_commandline.inx -[type: gettext/xml] share/extensions/inkscape_help_faq.inx -[type: gettext/xml] share/extensions/inkscape_help_keys.inx -[type: gettext/xml] share/extensions/inkscape_help_manual.inx -[type: gettext/xml] share/extensions/inkscape_help_relnotes.inx -[type: gettext/xml] share/extensions/inkscape_help_reportabug.inx -[type: gettext/xml] share/extensions/inkscape_help_svgspec.inx -[type: gettext/xml] share/extensions/interp_att_g.inx -[type: gettext/xml] share/extensions/interp.inx -[type: gettext/xml] share/extensions/lindenmayer.inx -[type: gettext/xml] share/extensions/lorem_ipsum.inx -[type: gettext/xml] share/extensions/markers_strokepaint.inx -[type: gettext/xml] share/extensions/measure.inx -[type: gettext/xml] share/extensions/motion.inx -[type: gettext/xml] share/extensions/outline2svg.inx -[type: gettext/xml] share/extensions/param_curves.inx -[type: gettext/xml] share/extensions/pathalongpath.inx -[type: gettext/xml] share/extensions/pathscatter.inx -[type: gettext/xml] share/extensions/perfectboundcover.inx -[type: gettext/xml] share/extensions/perspective.inx -[type: gettext/xml] share/extensions/plt_input.inx -[type: gettext/xml] share/extensions/plt_output.inx -[type: gettext/xml] share/extensions/polyhedron_3d.inx -[type: gettext/xml] share/extensions/printing-marks.inx -[type: gettext/xml] share/extensions/ps_input.inx -[type: gettext/xml] share/extensions/radiusrand.inx -[type: gettext/xml] share/extensions/render_alphabetsoup.inx -[type: gettext/xml] share/extensions/render_barcode.inx -[type: gettext/xml] share/extensions/restack.inx -[type: gettext/xml] share/extensions/rtree.inx -[type: gettext/xml] share/extensions/rubberstretch.inx -[type: gettext/xml] share/extensions/scour.inx -[type: gettext/xml] share/extensions/sk1_input.inx -[type: gettext/xml] share/extensions/sk1_output.inx -[type: gettext/xml] share/extensions/sk_input.inx -[type: gettext/xml] share/extensions/spirograph.inx -[type: gettext/xml] share/extensions/straightseg.inx -[type: gettext/xml] share/extensions/summersnight.inx -[type: gettext/xml] share/extensions/svg2xaml.inx -[type: gettext/xml] share/extensions/svg_and_media_zip_output.inx -[type: gettext/xml] share/extensions/svgcalendar.inx -[type: gettext/xml] share/extensions/text_braille.inx -[type: gettext/xml] share/extensions/text_flipcase.inx -[type: gettext/xml] share/extensions/text_lowercase.inx -[type: gettext/xml] share/extensions/text_randomcase.inx -[type: gettext/xml] share/extensions/text_replace.inx -[type: gettext/xml] share/extensions/text_sentencecase.inx -[type: gettext/xml] share/extensions/text_titlecase.inx -[type: gettext/xml] share/extensions/text_uppercase.inx -[type: gettext/xml] share/extensions/triangle.inx -[type: gettext/xml] share/extensions/txt2svg.inx -[type: gettext/xml] share/extensions/web-set-att.inx -[type: gettext/xml] share/extensions/web-transmit-att.inx -[type: gettext/xml] share/extensions/whirl.inx -[type: gettext/xml] share/extensions/wmf_input.inx -[type: gettext/xml] share/extensions/wmf_output.inx -[type: gettext/xml] share/extensions/xaml2svg.inx diff --git a/po/POTFILES.skip b/po/POTFILES.skip index 1aaf436dc..f287fd6a1 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -1,5 +1,6 @@ # All source files whose translatable messages should not be seen as of now +cxxtest/cxxtest.py src/jabber_whiteboard/invitation-confirm-dialog.cpp src/jabber_whiteboard/message-queue.cpp src/jabber_whiteboard/message-utilities.cpp diff --git a/src/2geom/chebyshev.cpp b/src/2geom/chebyshev.cpp index 447c5183f..73baf7b6b 100644 --- a/src/2geom/chebyshev.cpp +++ b/src/2geom/chebyshev.cpp @@ -93,7 +93,7 @@ SBasis chebyshev_approximant_interpolating (double (*f)(double,void*), wr.fa = fa; wr.fb = fb; wr.in = in; - printf("%f %f\n", fa, fb); + //printf("%f %f\n", fa, fb); wr.f = f; wr.pp = p; return compose(Linear(in[0], in[1]), Linear(fa, fb)) + chebyshev_approximant(f_interp, order, in, &wr) + Linear(fa, fb); diff --git a/src/2geom/svg-path-parser.cpp b/src/2geom/svg-path-parser.cpp index 071b171b3..691ddf022 100644 --- a/src/2geom/svg-path-parser.cpp +++ b/src/2geom/svg-path-parser.cpp @@ -1,4 +1,3 @@ -#line 1 "/home/njh/svn/lib2geom/src/2geom/svg-path-parser.rl" /** * \file * \brief parse SVG path specifications diff --git a/src/Makefile.am b/src/Makefile.am index 63b27398a..ecc0f522b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -134,6 +134,7 @@ include algorithms/Makefile_insert include ui/Makefile_insert include ui/cache/Makefile_insert include ui/dialog/Makefile_insert +include ui/tool/Makefile_insert include ui/view/Makefile_insert include ui/widget/Makefile_insert include util/Makefile_insert diff --git a/src/Makefile_insert b/src/Makefile_insert index de986ca16..dfc9daf96 100644 --- a/src/Makefile_insert +++ b/src/Makefile_insert @@ -56,7 +56,6 @@ ink_common_sources += \ fixes.cpp \ flood-context.cpp flood-context.h \ forward.h \ - gc-allocator.h \ gc-alloc.h \ gc-anchored.h gc-anchored.cpp \ gc-core.h \ diff --git a/src/desktop.cpp b/src/desktop.cpp index 319a0d407..b1b9a2955 100644 --- a/src/desktop.cpp +++ b/src/desktop.cpp @@ -91,6 +91,11 @@ #include "widgets/desktop-widget.h" #include "box3d-context.h" +// TODO those includes are only for the braindead quick zoom implementation. +// Remove them after fixing this. +#include "ui/tool/node-tool.h" +#include "ui/tool/control-point-selection.h" + #include "display/sp-canvas.h" namespace Inkscape { namespace XML { class Node; }} @@ -619,9 +624,12 @@ SPDesktop::set_event_context (GtkType type, const gchar *config) while (event_context) { ec = event_context; sp_event_context_deactivate (ec); - event_context = ec->next; + // we have to keep event_context valid during destruction - otherwise writing + // destructors is next to impossible + SPEventContext *next = ec->next; sp_event_context_finish (ec); g_object_unref (G_OBJECT (ec)); + event_context = next; } ec = sp_event_context_new (type, this, config, SP_EVENT_CONTEXT_STATIC); @@ -780,11 +788,12 @@ SPDesktop::set_display_area (double x0, double y0, double x1, double y1, double int clear = FALSE; if (!NR_DF_TEST_CLOSE (newscale, scale, 1e-4 * scale)) { - /* Set zoom factors */ + // zoom changed - set new zoom factors _d2w = Geom::Scale(newscale, -newscale); _w2d = Geom::Scale(1/newscale, 1/-newscale); sp_canvas_item_affine_absolute(SP_CANVAS_ITEM(main), _d2w); clear = TRUE; + signal_zoom_changed.emit(_d2w.descrim()); } /* Calculate top left corner (in document pixels) */ @@ -870,11 +879,6 @@ SPDesktop::next_zoom() zooms_future = g_list_remove (zooms_future, ((NRRect *) zooms_future->data)); } -#include "tools-switch.h" -#include "node-context.h" -#include "shape-editor.h" -#include "nodepath.h" - /** \brief Performs a quick zoom into what the user is working on \param enable Whether we're going in or out of quick zoom @@ -890,67 +894,27 @@ SPDesktop::zoom_quick (bool enable) _quick_zoom_stored_area = get_display_area(); bool zoomed = false; - if (!zoomed) { - SPItem * singleItem = selection->singleItem(); - if (singleItem != NULL && tools_isactive(this, TOOLS_NODES)) { - - Inkscape::NodePath::Path * nodepath = event_context->shape_editor->get_nodepath(); - // printf("I've got a nodepath, crazy\n"); - - if (nodepath) { - Geom::Rect nodes; - bool firstnode = true; - - if (nodepath->selected) { - for (GList *spl = nodepath->subpaths; spl != NULL; spl = spl->next) { - Inkscape::NodePath::SubPath *subpath = (Inkscape::NodePath::SubPath *) spl->data; - for (GList *nl = subpath->nodes; nl != NULL; nl = nl->next) { - Inkscape::NodePath::Node *node = (Inkscape::NodePath::Node *) nl->data; - if (node->selected) { - // printf("\tSelected node\n"); - if (firstnode) { - nodes = Geom::Rect(node->pos, node->pos); - firstnode = false; - } else { - nodes.expandTo(node->pos); - } - - if (node->p.other != NULL) { - /* Include previous node pos */ - nodes.expandTo(node->p.other->pos); - - /* Include previous handle */ - if (!sp_node_side_is_line(node, &node->p)) { - nodes.expandTo(node->p.pos); - } - } - - if (node->n.other != NULL) { - /* Include previous node pos */ - nodes.expandTo(node->n.other->pos); - - /* Include previous handle */ - if (!sp_node_side_is_line(node, &node->n)) { - nodes.expandTo(node->n.pos); - } - } - } - } - } - - if (!firstnode && nodes.area() * 2.0 < _quick_zoom_stored_area.area()) { - set_display_area(nodes, 10); - zoomed = true; - } - } - } + // TODO This is brain damage. This needs to migrate into the node tool, + // but currently the design of this method is sufficiently broken + // to prevent this. + if (!zoomed && INK_IS_NODE_TOOL(event_context)) { + InkNodeTool *nt = static_cast(event_context); + if (!nt->_selected_nodes->empty()) { + Geom::Rect nodes = *nt->_selected_nodes->bounds(); + double area = nodes.area(); + // do not zoom if a single cusp node is selected aand the bounds + // have zero area. + if (!Geom::are_near(area, 0) && area * 2.0 < _quick_zoom_stored_area.area()) { + set_display_area(nodes, true); + zoomed = true; + } } } if (!zoomed) { Geom::OptRect const d = selection->bounds(); if (d && d->area() * 2.0 < _quick_zoom_stored_area.area()) { - set_display_area(*d, 10); + set_display_area(*d, true); zoomed = true; } } @@ -960,7 +924,7 @@ SPDesktop::zoom_quick (bool enable) zoomed = true; } } else { - set_display_area(_quick_zoom_stored_area, 0); + set_display_area(_quick_zoom_stored_area, false); } _quick_zoom_enabled = enable; @@ -1801,7 +1765,7 @@ Geom::Point SPDesktop::dt2doc(Geom::Point const &p) const } -/** +/* * Pop event context from desktop's context stack. Never used. */ // void @@ -1843,4 +1807,4 @@ Geom::Point SPDesktop::dt2doc(Geom::Point const &p) const fill-column:99 End: */ -// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 : +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/desktop.h b/src/desktop.h index cfb977425..2d3c9b6e4 100644 --- a/src/desktop.h +++ b/src/desktop.h @@ -143,6 +143,11 @@ struct SPDesktop : public Inkscape::UI::View::View sigc::signal _layer_changed_signal; sigc::signal::accumulated _set_style_signal; sigc::signal::accumulated _query_style_signal; + + /// Emitted when the zoom factor changes (not emitted when scrolling). + /// The parameter is the new zoom factor + sigc::signal signal_zoom_changed; + sigc::connection connectDocumentReplaced (const sigc::slot & slot) { return _document_replaced_signal.connect (slot); diff --git a/src/display/sp-canvas-util.cpp b/src/display/sp-canvas-util.cpp index 30cd0dfa0..a23b157df 100644 --- a/src/display/sp-canvas-util.cpp +++ b/src/display/sp-canvas-util.cpp @@ -112,10 +112,11 @@ void sp_canvas_item_move_to_z (SPCanvasItem * item, gint z) if (z == current_z) return; - if (z > current_z) + if (z > current_z) { sp_canvas_item_raise (item, z - current_z); - - sp_canvas_item_lower (item, current_z - z); + } else { + sp_canvas_item_lower (item, current_z - z); + } } gint diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index aee53838f..6d996fbe2 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -103,6 +103,7 @@ static void group_remove (SPCanvasGroup *group, SPCanvasItem *item); /* SPCanvasItem */ enum {ITEM_EVENT, ITEM_LAST_SIGNAL}; +enum {PROP_0, PROP_VISIBLE}; static void sp_canvas_request_update (SPCanvas *canvas); @@ -113,12 +114,11 @@ static void sp_canvas_item_init (SPCanvasItem *item); static void sp_canvas_item_dispose (GObject *object); static void sp_canvas_item_construct (SPCanvasItem *item, SPCanvasGroup *parent, gchar const *first_arg_name, va_list args); + static int emit_event (SPCanvas *canvas, GdkEvent *event); static guint item_signals[ITEM_LAST_SIGNAL] = { 0 }; -static GtkObjectClass *item_parent_class; - /** * Registers the SPCanvasItem class with Glib and returns its type number. */ @@ -151,9 +151,6 @@ sp_canvas_item_class_init (SPCanvasItemClass *klass) { GObjectClass *object_class = (GObjectClass *) klass; - /* fixme: Derive from GObject */ - item_parent_class = (GtkObjectClass*)gtk_type_class (GTK_TYPE_OBJECT); - item_signals[ITEM_EVENT] = g_signal_new ("event", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, @@ -172,6 +169,9 @@ sp_canvas_item_class_init (SPCanvasItemClass *klass) static void sp_canvas_item_init (SPCanvasItem *item) { + // TODO items should not be visible on creation - this causes kludges with items + // that should be initially invisible; examples of such items: node handles, the CtrlRect + // used for rubberbanding, path outline, etc. item->flags |= SP_CANVAS_ITEM_VISIBLE; item->xform = Geom::Matrix(Geom::identity()); } @@ -277,7 +277,7 @@ sp_canvas_item_dispose (GObject *object) group_remove (SP_CANVAS_GROUP (item->parent), item); } - G_OBJECT_CLASS (item_parent_class)->dispose (object); + G_OBJECT_CLASS (g_type_class_peek(g_type_parent(sp_canvas_item_get_type())))->dispose (object); } /** @@ -477,6 +477,13 @@ sp_canvas_item_lower (SPCanvasItem *item, int positions) item->canvas->need_repick = TRUE; } +bool +sp_canvas_item_is_visible (SPCanvasItem *item) +{ + return item->flags & SP_CANVAS_ITEM_VISIBLE; +} + + /** * Sets visible flag on item and requests a redraw. */ @@ -542,8 +549,13 @@ sp_canvas_item_grab (SPCanvasItem *item, guint event_mask, GdkCursor *cursor, gu if (item->canvas->grabbed_item) return -1; - if (!(item->flags & SP_CANVAS_ITEM_VISIBLE)) - return -1; + // This test disallows grabbing events by an invisible item, which may be useful + // sometimes. An example is the hidden control point used for the selector component, + // where it is used for object selection and rubberbanding. There seems to be nothing + // preventing this except this test, so I removed it. + // -- Krzysztof Kosiński, 2009.08.12 + //if (!(item->flags & SP_CANVAS_ITEM_VISIBLE)) + // return -1; if (HAS_BROKEN_MOTION_HINTS) { event_mask &= ~GDK_POINTER_MOTION_HINT_MASK; diff --git a/src/display/sp-canvas.h b/src/display/sp-canvas.h index 35e3fb5de..a2af080ef 100644 --- a/src/display/sp-canvas.h +++ b/src/display/sp-canvas.h @@ -101,6 +101,7 @@ void sp_canvas_item_affine_absolute(SPCanvasItem *item, Geom::Matrix const &aff) void sp_canvas_item_raise(SPCanvasItem *item, int positions); void sp_canvas_item_lower(SPCanvasItem *item, int positions); +bool sp_canvas_item_is_visible(SPCanvasItem *item); void sp_canvas_item_show(SPCanvasItem *item); void sp_canvas_item_hide(SPCanvasItem *item); int sp_canvas_item_grab(SPCanvasItem *item, unsigned int event_mask, GdkCursor *cursor, guint32 etime); diff --git a/src/dom/io/httpclient.cpp b/src/dom/io/httpclient.cpp index 4245d71f2..97c8575cf 100644 --- a/src/dom/io/httpclient.cpp +++ b/src/dom/io/httpclient.cpp @@ -73,7 +73,7 @@ bool HttpClient::openGet(const URI &uri) socket.enableSSL(true); else { - printf("Bad proto scheme:%d\n", uri.getScheme()); + //printf("Bad proto scheme:%d\n", uri.getScheme()); return false; } @@ -106,7 +106,7 @@ bool HttpClient::openGet(const URI &uri) { if (!socket.readLine(msg)) return false; - printf("header:'%s'\n", msg.c_str()); + //printf("header:'%s'\n", msg.c_str()); if (msg.size() < 1) break; } diff --git a/src/dom/odf/SvgOdg.cpp b/src/dom/odf/SvgOdg.cpp index 2b1161310..e69de29bb 100644 --- a/src/dom/odf/SvgOdg.cpp +++ b/src/dom/odf/SvgOdg.cpp @@ -1,1551 +0,0 @@ -/** - * - * This is a small experimental class for converting between - * SVG and OpenDocument .odg files. This code is not intended - * to be a permanent solution for SVG-to-ODG conversion. Rather, - * it is a quick-and-easy test bed for ideas which will be later - * recoded into C++. - * - * --------------------------------------------------------------------- - * - * SvgOdg - A program to experiment with conversions between SVG and ODG - * Copyright (C) 2006 Bob Jamison - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * For more information, please write to rwjj@earthlink.net - * - */ - - -/** - * - */ -public class SvgOdg -{ - - - -/** - * Namespace declarations - */ -public static final String SVG_NS = - "http://www.w3.org/2000/svg"; -public static final String XLINK_NS = - "http://www.w3.org/1999/xlink"; -public static final String ODF_NS = - "urn:oasis:names:tc:opendocument:xmlns:office:1.0"; -public static final String ODG_NS = - "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"; -public static final String ODSVG_NS = - "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"; - - -DecimalFormat nrfmt; -//static final double pxToCm = 0.0339; -static final double pxToCm = 0.0275; -static final double piToRad = 0.0174532925; -BufferedWriter out; -BufferedReader in; -int imageNr; -int styleNr; - -//######################################################################## -//# M E S S A G E S -//######################################################################## - -/** - * - */ -void err(String msg) -{ - System.out.println("SvgOdg ERROR:" + msg); -} - -/** - * - */ -void trace(String msg) -{ - System.out.println("SvgOdg:" + msg); -} - - - - -//######################################################################## -//# I N P U T / O U T P U T -//######################################################################## - -boolean po(String s) -{ - try - { - out.write(s); - } - catch(IOException e) - { - return false; - } - return true; -} - -//######################################################################## -//# U T I L I T Y -//######################################################################## - -public void dumpDocument(Document doc) -{ - String s = ""; - try - { - TransformerFactory factory = TransformerFactory.newInstance(); - Transformer trans = factory.newTransformer(); - DOMSource source = new DOMSource(doc); - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - StreamResult result = new StreamResult(bos); - trans.transform(source, result); - byte buf[] = bos.toByteArray(); - s = new String(buf); - } - catch (javax.xml.transform.TransformerException e) - { - } - trace("doc:" + s); -} - - -//######################################################################## -//# I N N E R C L A S S ImageInfo -//######################################################################## -public class ImageInfo -{ -String name; -String newName; -byte buf[]; - -public String getName() -{ - return name; -} - -public String getNewName() -{ - return newName; -} - - -public byte[] getBuf() -{ - return buf; -} - -public ImageInfo(String name, String newName, byte buf[]) -{ - this.name = name; - this.name = newName; - this.buf = buf; -} - -} -//######################################################################## -//# I N N E R C L A S S StyleInfo -//######################################################################## -public class StyleInfo -{ - -String name; -public String getName() -{ - return name; -} - -String cssStyle; -public String getCssStyle() -{ - return cssStyle; -} - -String stroke; -public String getStroke() -{ - return stroke; -} - -String strokeColor; -public String getStrokeColor() -{ - return strokeColor; -} - -String strokeWidth; -public String getStrokeWidth() -{ - return strokeWidth; -} - -String fill; -public String getFill() -{ - return fill; -} - -String fillColor; -public String getFillColor() -{ - return fillColor; -} - -public StyleInfo(String name, String cssStyle) -{ - this.name = name; - this.cssStyle = cssStyle; - fill = "none"; - stroke = "none"; -} - -} -//######################################################################## -//# E N D I N N E R C L A S S E S -//######################################################################## - - - - -//######################################################################## -//# V A R I A B L E S -//######################################################################## - -/** - * ODF content.xml file - */ -Document content; -public Document getContent() -{ - return content; -} - -/** - * ODF meta.xml file - */ -Document meta; -public Document getMeta() -{ - return meta; -} - -/** - * SVG file - */ -Document svg; -public Document getSvg() -{ - return svg; -} - -/** - * Loaded ODF or SVG images - */ -ArrayList images; -public ArrayList getImages() -{ - return images; -} - -/** - * CSS styles - */ -HashMap styles; -public HashMap getStyles() -{ - return styles; -} - - - - - -//######################################################################## -//# S V G T O O D F -//######################################################################## - -class PathData -{ -String cmd; -double nr[]; -PathData(String s, double buf[]) -{ - cmd=s; nr = buf; -} -} - -double getPathNum(StringTokenizer st) -{ - if (!st.hasMoreTokens()) - return 0.0; - String s = st.nextToken(); - double nr = Double.parseDouble(s); - return nr; -} - -String parsePathData(String pathData, double bounds[]) -{ - double minx = Double.MAX_VALUE; - double maxx = Double.MIN_VALUE; - double miny = Double.MAX_VALUE; - double maxy = Double.MIN_VALUE; - //trace("#### pathData:" + pathData); - ArrayList data = new ArrayList(); - StringTokenizer st = new StringTokenizer(pathData, " ,"); - while (true) - { - String s = st.nextToken(); - if ( s.equals("z") || s.equals("Z") ) - { - PathData pd = new PathData(s, new double[0]); - data.add(pd); - break; - } - else if ( s.equals("h") || s.equals("H") ) - { - double d[] = new double[1]; - d[0] = getPathNum(st) * pxToCm; - if (d[0] < minx) minx = d[0]; - else if (d[0] > maxx) maxx = d[0]; - PathData pd = new PathData(s, d); - data.add(pd); - } - else if ( s.equals("v") || s.equals("V") ) - { - double d[] = new double[1]; - d[0] = getPathNum(st) * pxToCm; - if (d[0] < miny) miny = d[0]; - else if (d[0] > maxy) maxy = d[0]; - PathData pd = new PathData(s, d); - data.add(pd); - } - else if ( s.equals("m") || s.equals("M") || - s.equals("l") || s.equals("L") || - s.equals("t") || s.equals("T") ) - { - double d[] = new double[2]; - d[0] = getPathNum(st) * pxToCm; - d[1] = getPathNum(st) * pxToCm; - if (d[0] < minx) minx = d[0]; - else if (d[0] > maxx) maxx = d[0]; - if (d[1] < miny) miny = d[1]; - else if (d[1] > maxy) maxy = d[1]; - PathData pd = new PathData(s, d); - data.add(pd); - } - else if ( s.equals("q") || s.equals("Q") || - s.equals("s") || s.equals("S") ) - { - double d[] = new double[4]; - d[0] = getPathNum(st) * pxToCm; - d[1] = getPathNum(st) * pxToCm; - if (d[0] < minx) minx = d[0]; - else if (d[0] > maxx) maxx = d[0]; - if (d[1] < miny) miny = d[1]; - else if (d[1] > maxy) maxy = d[1]; - d[2] = getPathNum(st) * pxToCm; - d[3] = getPathNum(st) * pxToCm; - if (d[2] < minx) minx = d[2]; - else if (d[2] > maxx) maxx = d[2]; - if (d[3] < miny) miny = d[3]; - else if (d[3] > maxy) maxy = d[3]; - PathData pd = new PathData(s, d); - data.add(pd); - } - else if ( s.equals("c") || s.equals("C") ) - { - double d[] = new double[6]; - d[0] = getPathNum(st) * pxToCm; - d[1] = getPathNum(st) * pxToCm; - if (d[0] < minx) minx = d[0]; - else if (d[0] > maxx) maxx = d[0]; - if (d[1] < miny) miny = d[1]; - else if (d[1] > maxy) maxy = d[1]; - d[2] = getPathNum(st) * pxToCm; - d[3] = getPathNum(st) * pxToCm; - if (d[2] < minx) minx = d[2]; - else if (d[2] > maxx) maxx = d[2]; - if (d[3] < miny) miny = d[3]; - else if (d[3] > maxy) maxy = d[3]; - d[4] = getPathNum(st) * pxToCm; - d[5] = getPathNum(st) * pxToCm; - if (d[4] < minx) minx = d[4]; - else if (d[4] > maxx) maxx = d[4]; - if (d[5] < miny) miny = d[5]; - else if (d[5] > maxy) maxy = d[5]; - PathData pd = new PathData(s, d); - data.add(pd); - } - else if ( s.equals("a") || s.equals("A") ) - { - double d[] = new double[6]; - d[0] = getPathNum(st) * pxToCm; - d[1] = getPathNum(st) * pxToCm; - if (d[0] < minx) minx = d[0]; - else if (d[0] > maxx) maxx = d[0]; - if (d[1] < miny) miny = d[1]; - else if (d[1] > maxy) maxy = d[1]; - d[2] = getPathNum(st) * piToRad;//angle - d[3] = getPathNum(st) * piToRad;//angle - d[4] = getPathNum(st) * pxToCm; - d[5] = getPathNum(st) * pxToCm; - if (d[4] < minx) minx = d[4]; - else if (d[4] > maxx) maxx = d[4]; - if (d[5] < miny) miny = d[5]; - else if (d[5] > maxy) maxy = d[5]; - PathData pd = new PathData(s, d); - data.add(pd); - } - //trace("x:" + x + " y:" + y); - } - - trace("minx:" + minx + " maxx:" + maxx + - " miny:" + miny + " maxy:" + maxy); - - StringBuffer buf = new StringBuffer(); - for (PathData pd : data) - { - buf.append(pd.cmd); - buf.append(" "); - for (double d:pd.nr) - { - buf.append(nrfmt.format(d * 1000.0)); - buf.append(" "); - } - } - - bounds[0] = minx; - bounds[1] = miny; - bounds[2] = maxx; - bounds[3] = maxy; - - return buf.toString(); -} - - - -boolean parseTransform(String transStr, AffineTransform trans) -{ - trace("== transform:"+ transStr); - StringTokenizer st = new StringTokenizer(transStr, ")"); - while (st.hasMoreTokens()) - { - String chunk = st.nextToken(); - StringTokenizer st2 = new StringTokenizer(chunk, " ,("); - if (!st2.hasMoreTokens()) - continue; - String name = st2.nextToken(); - trace(" ++name:"+ name); - if (name.equals("matrix")) - { - double v[] = new double[6]; - for (int i=0 ; i<6 ; i++) - { - if (!st2.hasMoreTokens()) - break; - v[i] = Double.parseDouble(st2.nextToken()) * pxToCm; - } - AffineTransform mat = new AffineTransform(v); - trans.concatenate(mat); - } - else if (name.equals("translate")) - { - double dx = 0.0; - double dy = 0.0; - if (!st2.hasMoreTokens()) - continue; - dx = Double.parseDouble(st2.nextToken()) * pxToCm; - if (st2.hasMoreTokens()) - dy = Double.parseDouble(st2.nextToken()) * pxToCm; - trans.translate(dx, dy); - } - else if (name.equals("scale")) - { - double sx = 1.0; - double sy = 1.0; - if (!st2.hasMoreTokens()) - continue; - sx = sy = Double.parseDouble(st2.nextToken()); - if (st2.hasMoreTokens()) - sy = Double.parseDouble(st2.nextToken()); - trans.scale(sx, sy); - } - else if (name.equals("rotate")) - { - double r = 0.0; - double cx = 0.0; - double cy = 0.0; - if (!st2.hasMoreTokens()) - continue; - r = Double.parseDouble(st2.nextToken()) * piToRad; - if (st2.hasMoreTokens()) - { - cx = Double.parseDouble(st2.nextToken()) * pxToCm; - if (!st2.hasMoreTokens()) - continue; - cy = Double.parseDouble(st2.nextToken()) * pxToCm; - trans.rotate(r, cx, cy); - } - else - { - trans.rotate(r); - } - } - else if (name.equals("skewX")) - { - double angle = 0.0; - if (!st2.hasMoreTokens()) - continue; - angle = Double.parseDouble(st2.nextToken()); - trans.shear(angle, 0.0); - } - else if (name.equals("skewY")) - { - double angle = 0.0; - if (!st2.hasMoreTokens()) - continue; - angle = Double.parseDouble(st2.nextToken()); - trans.shear(0.0, angle); - } - } - return true; -} - - - -String coordToOdg(String sval) -{ - double nr = Double.parseDouble(sval); - nr = nr * pxToCm; - String s = nrfmt.format(nr) + "cm"; - return s; -} - - -boolean writeSvgAttributes(Element elem, AffineTransform trans) -{ - NamedNodeMap attrs = elem.getAttributes(); - String ename = elem.getLocalName(); - for (int i=0 ; i\n"); - NodeList children = elem.getChildNodes(); - for (int i=0 ; i\n"); - } - else if (tagName.equals("text")) - { - String x = coordToOdg(elem.getAttribute("x")); - String y = coordToOdg(elem.getAttribute("y")); - String width = "5cm"; - String height = "2cm"; - String txt = elem.getTextContent(); - po("\n"); - po(" \n"); - po(" " + txt + "\n"); - po(" \n"); - po("\n"); - return true; - } - else if (tagName.equals("image")) - { - String x = coordToOdg(elem.getAttribute("x")); - String y = coordToOdg(elem.getAttribute("y")); - String width = coordToOdg(elem.getAttribute("width")); - String height = coordToOdg(elem.getAttribute("height")); - String imageName = elem.getAttributeNS(XLINK_NS, "href"); - po("\n"); - po(" \n"); - po("\n"); - return true; - } - else if (tagName.equals("path")) - { - double bounds[] = new double[4]; - String d = elem.getAttribute("d"); - String newd = parsePathData(d, bounds); - double x = bounds[0]; - double y = bounds[1]; - double width = (bounds[2]-bounds[0]); - double height = (bounds[3]-bounds[1]); - po("\n"); - //po(" svg:d=\"" + d + "\"/>\n"); - return true; - } - - else - { - //Verbatim tab mapping - po("\n"); - po("\n"); - } - - return true; -} - - -boolean writeOdfContent(ZipOutputStream outs) -{ - try - { - ZipEntry ze = new ZipEntry("content.xml"); - outs.putNextEntry(ze); - out = new BufferedWriter(new OutputStreamWriter(outs)); - } - catch (IOException e) - { - return false; - } - - NodeList res = svg.getElementsByTagNameNS(SVG_NS, "svg"); - if (res.getLength() < 1) - { - err("saveOdf: no root in .svg file"); - return false; - } - Element root = (Element)res.item(0); - - - po("\n"); - po("\n"); - po("\n"); - po("\n"); - po("\n"); - po("\n"); - po("\n"); - po("\n"); - po(" \n"); - po("\n"); - po("\n"); - po(" \n"); - po("\n"); - - //## Dump our style table - for (StyleInfo s : styles.values()) - { - po("\n"); - po(" \n"); - po("\n"); - } - po("\n"); - po("\n"); - po("\n"); - po("\n"); - po("\n"); - po("\n"); - po("\n\n\n"); - AffineTransform trans = new AffineTransform(); - //trans.scale(12.0, 12.0); - po("\n"); - writeOdfContent(root, trans); - po("\n"); - po("\n\n\n"); - - po("\n"); - po("\n"); - po("\n"); - po("\n"); - - - try - { - out.flush(); - outs.closeEntry(); - } - catch (IOException e) - { - err("writeOdfContent:" + e); - return false; - } - return true; -} - -boolean writeOdfMeta(ZipOutputStream outs) -{ - try - { - ZipEntry ze = new ZipEntry("meta.xml"); - outs.putNextEntry(ze); - out = new BufferedWriter(new OutputStreamWriter(outs)); - } - catch (IOException e) - { - return false; - } - - po("\n"); - po("\n"); - po("\n"); - po(" Inkscape-0.43\n"); - po(" clark kent\n"); - po(" 2005-12-10T10:55:13\n"); - po(" clark kent\n"); - po(" 2005-12-10T10:56:20\n"); - po(" en-US\n"); - po(" 2\n"); - po(" PT1M13S\n"); - po(" \n"); - po(" \n"); - po(" \n"); - po(" \n"); - po(" \n"); - po("\n"); - po("\n"); - - - try - { - out.flush(); - outs.closeEntry(); - } - catch (IOException e) - { - err("writeOdfContent:" + e); - return false; - } - return true; -} - - -boolean writeOdfManifest(ZipOutputStream outs) -{ - try - { - ZipEntry ze = new ZipEntry("META-INF/manifest.xml"); - outs.putNextEntry(ze); - out = new BufferedWriter(new OutputStreamWriter(outs)); - } - catch (IOException e) - { - return false; - } - - po("\n"); - po("\n"); - po("\n"); - po(" \n"); - po(" \n"); - po(" \n"); - po(" \n"); - for (int i=0 ; i\n"); - } - po("\n"); - - try - { - out.flush(); - outs.closeEntry(); - } - catch (IOException e) - { - err("writeOdfContent:" + e); - return false; - } - return true; -} - -boolean writeOdfImages(ZipOutputStream outs) -{ - for (int i=0 ; i style.length()-2) - continue; - String attrName = style.substring(0, pos); - String attrVal = style.substring(pos+1); - trace(" =" + attrName + ':' + attrVal); - if ("stroke".equals(attrName)) - { - si.stroke = "solid"; - si.strokeColor = attrVal; - } - else if ("stroke-width".equals(attrName)) - { - si.strokeWidth = attrVal; - } - else if ("fill".equals(attrName)) - { - si.fill = "solid"; - si.fillColor = attrVal; - } - } - styles.put(css, si); - return true; -} - -boolean readSvg(InputStream ins) -{ - //### LOAD XML - try - { - DocumentBuilderFactory factory = - DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - DocumentBuilder builder = - factory.newDocumentBuilder(); - builder.setEntityResolver(new EntityResolver() - { - public InputSource resolveEntity(String publicId, String systemId) - { - return new InputSource(new ByteArrayInputStream(new byte[0])); - } - }); - Document doc = builder.parse(ins); - svg = doc; - } - catch (javax.xml.parsers.ParserConfigurationException e) - { - err("making DOM parser:"+e); - return false; - } - catch (org.xml.sax.SAXException e) - { - err("parsing svg document:"+e); - return false; - } - catch (IOException e) - { - err("parsing svg document:"+e); - return false; - } - //dumpDocument(svg); - - //### LOAD IMAGES - imageNr = 0; - images = new ArrayList(); - NodeList res = svg.getElementsByTagNameNS(SVG_NS, "image"); - for (int i=0 ; i(); - res = svg.getElementsByTagName("*"); - for (int i=0 ; i 0) - parseCss(style); - } - - return true; -} - -boolean readSvg(String fileName) -{ - try - { - FileInputStream fis = new FileInputStream(fileName); - if (!readSvg(fis)) - return false; - fis.close(); - } - catch (IOException e) - { - err("opening svg file:"+e); - return false; - } - return true; -} - - -//######################################################################## -//# O D F T O S V G -//######################################################################## - -/** - * - */ -public boolean readOdfEntry(ZipInputStream zis, ZipEntry ent) -{ - String fileName = ent.getName(); - trace("fileName:" + fileName); - if (fileName.length() < 4) - return true; - String ext = fileName.substring(fileName.length() - 4); - trace("ext:" + ext); - ArrayList arr = new ArrayList(); - try - { - while (true) - { - int inb = zis.read(); - if (inb < 0) - break; - arr.add((byte)inb); - } - } - catch (IOException e) - { - return false; - } - byte buf[] = new byte[arr.size()]; - for (int i=0 ; i(); - styleNr = 0; - styles = new HashMap(); - ZipInputStream zis = new ZipInputStream(ins); - while (true) - { - try - { - ZipEntry ent = zis.getNextEntry(); - if (ent == null) - break; - if (!readOdfEntry(zis, ent)) - return false; - zis.closeEntry(); - } - catch (IOException e) - { - err("reading zip entry"); - return false; - } - } - - return true; -} - - -/** - * - */ -public boolean readOdf(String fileName) -{ - boolean ret = true; - try - { - FileInputStream fis = new FileInputStream(fileName); - ret = readOdf(fis); - fis.close(); - } - catch (IOException e) - { - err("reading " + fileName + " : " + e); - ret = false; - } - return true; -} - - - - -public boolean writeSvgElement(Element elem) -{ - String ns = elem.getNamespaceURI(); - String tagName = elem.getLocalName(); - trace("tag:" + tagName + " : " + ns); - if (ns.equals(ODSVG_NS)) - { - po("<"); po(tagName); - NamedNodeMap attrs = elem.getAttributes(); - for (int i=0 ; i\n"); - } - NodeList children = elem.getChildNodes(); - for (int i=0 ; i\n"); - } - return true; -} - - -public boolean saveSvg(String svgFileName) -{ - trace("====== Saving images ==========="); - try - { - for (int i=0 ; i\n"); - po("\n"); - - writeSvgElement(page); - - po("\n"); - - try - { - out.close(); - } - catch (IOException e) - { - err("save:close:" + e); - return false; - } - return true; -} - - - -//######################################################################## -//# C O N S T R U C T O R -//######################################################################## - -SvgOdg() -{ - //init, if necessary - nrfmt = new DecimalFormat("#.####"); -} - - -//######################################################################## -//# C O M M A N D L I N E -//######################################################################## - -public boolean odfToSvg(String odfName, String svgName) -{ - if (!readOdf(odfName)) - return false; - if (!saveSvg(svgName)) - return false; - return true; -} - -public boolean svgToOdf(String svgName, String odfName) -{ - if (!readSvg(svgName)) - return false; - System.out.println("ok"); - if (!saveOdf(odfName)) - return false; - return true; -} - -void usage() -{ - System.out.println("usage: SvgOdf input_file.odg output_file.svg"); - System.out.println(" SvgOdf input_file.svg output_file.odg"); -} - - -boolean parseArguments(String argv[]) -{ - if (argv.length != 2) - { - usage(); - return false; - } - - String fileName1 = argv[0]; - String fileName2 = argv[1]; - - if (fileName1.length()<5 || fileName2.length()<5) - { - System.out.println("one or more file names is too short"); - usage(); - return false; - } - - String ext1 = fileName1.substring(fileName1.length()-4); - String ext2 = fileName2.substring(fileName2.length()-4); - //System.out.println("ext1:"+ext1+" ext2:"+ext2); - - //##### ODG -> SVG ##### - if ((ext1.equals(".odg") || ext1.equals(".odf") || ext1.equals(".zip") ) && - ext2.equals(".svg")) - { - if (!odfToSvg(argv[0], argv[1])) - { - System.out.println("Conversion from ODG to SVG failed"); - return false; - } - } - - //##### SVG -> ODG ##### - else if (ext1.equals(".svg") && - ( ext2.equals(".odg") || ext2.equals(".odf") || ext2.equals(".zip") ) ) - { - if (!svgToOdf(fileName1, fileName2)) - { - System.out.println("Conversion from SVG to ODG failed"); - return false; - } - } - - //##### none of the above ##### - else - { - usage(); - return false; - } - return true; -} - - -public static void main(String argv[]) -{ - SvgOdg svgodg = new SvgOdg(); - svgodg.parseArguments(argv); -} - - -} - -//######################################################################## -//# E N D O F F I L E -//######################################################################## - diff --git a/src/event-context.cpp b/src/event-context.cpp index 9b846f2b7..ec0169573 100644 --- a/src/event-context.cpp +++ b/src/event-context.cpp @@ -56,7 +56,6 @@ #include "attributes.h" #include "rubberband.h" #include "selcue.h" -#include "node-context.h" #include "lpe-tool-context.h" static void sp_event_context_class_init(SPEventContextClass *klass); diff --git a/src/extension/dxf2svg/entities2elements.cpp b/src/extension/dxf2svg/entities2elements.cpp index cf42dac32..15d3e76ae 100644 --- a/src/extension/dxf2svg/entities2elements.cpp +++ b/src/extension/dxf2svg/entities2elements.cpp @@ -20,10 +20,12 @@ SoC 2005 */ -#include"entities2elements.h" -#include"tables2svg_info.h" -#include -#include +#include "entities2elements.h" +#include "tables2svg_info.h" +#include +#include +#include +#include // The names indicate the DXF entitiy first and the SVG element last // Common elements diff --git a/src/extension/dxf2svg/read_dxf.cpp b/src/extension/dxf2svg/read_dxf.cpp index 8a6a6d6ac..ecda343c6 100644 --- a/src/extension/dxf2svg/read_dxf.cpp +++ b/src/extension/dxf2svg/read_dxf.cpp @@ -11,11 +11,13 @@ -#include -#include -#include"read_dxf.h" +#include +#include +#include "read_dxf.h" -#include +#include +#include +#include using namespace std; diff --git a/src/extension/dxf2svg/tables2svg_info.cpp b/src/extension/dxf2svg/tables2svg_info.cpp index 17bc47beb..3b27a9c38 100644 --- a/src/extension/dxf2svg/tables2svg_info.cpp +++ b/src/extension/dxf2svg/tables2svg_info.cpp @@ -10,9 +10,11 @@ */ -#include"tables2svg_info.h" -#include -#include +#include "tables2svg_info.h" +#include +#include +#include +#include char* pattern2dasharray(ltype info, int precision, double scaling, char* out){ std::vector< double > pattern = info.ret_pattern(); diff --git a/src/extension/internal/cairo-renderer.cpp b/src/extension/internal/cairo-renderer.cpp index 8cc386135..0e68ae130 100644 --- a/src/extension/internal/cairo-renderer.cpp +++ b/src/extension/internal/cairo-renderer.cpp @@ -29,6 +29,7 @@ #include #include "libnr/nr-rect.h" +#include "libnrtype/Layout-TNG.h" #include <2geom/transforms.h> #include <2geom/pathvector.h> diff --git a/src/gc-allocator.h b/src/gc-allocator.h index 4d809cfe4..e69de29bb 100644 --- a/src/gc-allocator.h +++ b/src/gc-allocator.h @@ -1,106 +0,0 @@ -/** @file - * @brief Garbage-collected STL allocator for standard containers - */ -/* Authors: - * Krzysztof Kosiński - * - * Copyright 2008 Authors - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * See the file COPYING for details. - */ - -#ifndef SEEN_INKSCAPE_GC_ALLOCATOR_H -#define SEEN_INKSCAPE_GC_ALLOCATOR_H - -#include -#include -#include "gc-core.h" - -namespace Inkscape { -namespace GC { - -/** - * @brief Garbage-collected allocator for the standard containers - * - * STL containers with default parameters cannot be used as members in garbage-collected - * objects, because by default the destructors are not called, causing a memory leak - * (the memory allocated by the container is not freed). To address this, STL containers - * can be told to use this garbage-collected allocator. It usually is the last template - * parameter. For example, to define a GC-managed map of ints to Unicode strings: - * - * @code typedef std::map, Inkscape::GC::Allocator> gcmap; @endcode - * - * Afterwards, you can place gcmap as a member in a non-finalized GC-managed object, because - * all memory used by gcmap will also be reclaimable by the garbage collector, therefore - * avoiding memory leaks. - */ -template -class Allocator { - // required typedefs - typedef T value_type; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef T * pointer; - typedef T const * const_pointer; - typedef T & reference; - typedef T const & const_reference; - - // required structure that allows accessing the same allocator for a different type - template - struct rebind { - typedef Allocator other; - }; - - // constructors - no-ops since the allocator doesn't have any state - Allocator() throw() {} - Allocator(Allocator const &) throw() {} - template Allocator(Allocator const &) throw() {} - ~Allocator() throw() {} - - // trivial required methods - pointer address(reference ref) { return &ref; } - const_pointer address(const_reference ref) { return &ref; } - void construct(pointer p, T const &value) { new (static_cast(p)) T(value); } - void destroy(pointer p) { p->~T(); } - - // maximum meaningful memory amount that can be requested from the allocator - size_type max_size() { - return numeric_limits::max() / sizeof(T); - } - - // allocate memory for num elements without initializing them - pointer allocate(size_type num, Allocator::const_pointer) { - return static_cast( Inkscape::GC::Core::malloc(num * sizeof(T)) ); - } - - // deallocate memory at p - void deallocate(pointer p, size_type) { - Inkscape::GC::Core::free(p); - } -}; - -// required comparison operators -template -bool operator==(Allocator const &, Allocator const &) { return true; } -template -bool operator!=(Allocator const &, Allocator const &) { return false; } - -} // namespace GC -} // namespace Inkscape - -#endif // !SEEN_INKSCAPE_GC_ALLOCATOR_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:encoding=utf-8:textwidth=99 : diff --git a/src/libnrtype/FontFactory.cpp b/src/libnrtype/FontFactory.cpp index fec9316b9..db7cd9747 100644 --- a/src/libnrtype/FontFactory.cpp +++ b/src/libnrtype/FontFactory.cpp @@ -43,7 +43,7 @@ size_t font_descr_hash::operator()( PangoFontDescription *const &x) const { h += (int)pango_font_description_get_stretch(x); return h; } -bool font_descr_equal::operator()( PangoFontDescription *const&a, PangoFontDescription *const &b) { +bool font_descr_equal::operator()( PangoFontDescription *const&a, PangoFontDescription *const &b) const { //if ( pango_font_description_equal(a,b) ) return true; char const *fa = pango_font_description_get_family(a); char const *fb = pango_font_description_get_family(b); diff --git a/src/libnrtype/FontFactory.h b/src/libnrtype/FontFactory.h index 9f4b31a2e..5253f6bbd 100644 --- a/src/libnrtype/FontFactory.h +++ b/src/libnrtype/FontFactory.h @@ -11,7 +11,7 @@ #include #include -#include +#include #ifdef HAVE_CONFIG_H # include @@ -46,7 +46,7 @@ struct font_descr_hash : public std::unary_function { - bool operator()(PangoFontDescription *const &a, PangoFontDescription *const &b); + bool operator()(PangoFontDescription *const &a, PangoFontDescription *const &b) const; }; // Comparison functions for style names @@ -84,7 +84,7 @@ public: double fontSize; /**< The huge fontsize used as workaround for hinting. * Different between freetype and win32. */ - __gnu_cxx::hash_map loadedFaces; + std::tr1::unordered_map loadedFaces; font_factory(); virtual ~font_factory(); diff --git a/src/libnrtype/FontInstance.cpp b/src/libnrtype/FontInstance.cpp index e1413b46e..d9a0c43e6 100644 --- a/src/libnrtype/FontInstance.cpp +++ b/src/libnrtype/FontInstance.cpp @@ -60,7 +60,7 @@ size_t font_style_hash::operator()(const font_style &x) const { return h; } -bool font_style_equal::operator()(const font_style &a,const font_style &b) { +bool font_style_equal::operator()(const font_style &a,const font_style &b) const { for (int i=0;i<6;i++) { if ( (int)(100*a.transform[i]) != (int)(100*b.transform[i]) ) return false; } diff --git a/src/libnrtype/font-instance.h b/src/libnrtype/font-instance.h index 4209a20af..ce3f6cf1b 100644 --- a/src/libnrtype/font-instance.h +++ b/src/libnrtype/font-instance.h @@ -1,7 +1,7 @@ #ifndef SEEN_LIBNRTYPE_FONT_INSTANCE_H #define SEEN_LIBNRTYPE_FONT_INSTANCE_H -#include +#include #include #include #include @@ -26,13 +26,13 @@ struct font_style_hash : public std::unary_function { }; struct font_style_equal : public std::binary_function { - bool operator()(font_style const &a, font_style const &b); + bool operator()(font_style const &a, font_style const &b) const; }; class font_instance { public: // hashmap to get the raster_font for a given style - __gnu_cxx::hash_map loadedStyles; + std::tr1::unordered_map loadedStyles; // the real source of the font PangoFont* pFont; // depending on the rendering backend, different temporary data diff --git a/src/libvpsc/pairingheap/.dirstamp b/src/libvpsc/pairingheap/.dirstamp deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index 33e50155c..93dfd2667 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -195,23 +195,13 @@ PathParam::param_newWidget(Gtk::Tooltips * tooltips) void PathParam::param_editOncanvas(SPItem * item, SPDesktop * dt) { - // If not already in nodecontext, goto it! - if (!tools_isactive(dt, TOOLS_NODES)) { - tools_switch(dt, TOOLS_NODES); - } - - ShapeEditor * shape_editor = dt->event_context->shape_editor; - if (!href) { - shape_editor->set_item_lpe_path_parameter(item, param_effect->getLPEObj(), param_key.c_str()); - } else { - // set referred item for editing - shape_editor->set_item(ref.getObject(), SH_NODEPATH); - } + // TODO this whole method is broken! } void PathParam::param_setup_nodepath(Inkscape::NodePath::Path *np) -{ +{ + // TODO this too! np->show_helperpath = true; np->helperpath_rgba = 0x009000ff; np->helperpath_width = 1.0; diff --git a/src/preferences-skeleton.h b/src/preferences-skeleton.h index 6185ff729..075d2b031 100644 --- a/src/preferences-skeleton.h +++ b/src/preferences-skeleton.h @@ -112,7 +112,7 @@ static char const preferences_skeleton[] = " \n" -" \n" +" \n" " \n" " \n" " \n" diff --git a/src/preferences.cpp b/src/preferences.cpp index 39a9e4d69..315c668b4 100644 --- a/src/preferences.cpp +++ b/src/preferences.cpp @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -446,6 +447,13 @@ void Preferences::setDouble(Glib::ustring const &pref_path, double value) _setRawValue(pref_path, buf); } +void Preferences::setColor(Glib::ustring const &pref_path, guint32 value) +{ + gchar buf[16]; + g_snprintf(buf, 16, "#%08x", value); + _setRawValue(pref_path, buf); +} + /** * @brief Set a string attribute of a preference * @param pref_path Path of the preference to modify @@ -732,6 +740,20 @@ Glib::ustring Preferences::_extractString(Entry const &v) return Glib::ustring(static_cast(v._value)); } +guint32 Preferences::_extractColor(Entry const &v) +{ + gchar const *s = static_cast(v._value); + std::istringstream hr(s); + guint32 color; + if (s[0] == '#') { + hr.ignore(1); + hr >> std::hex >> color; + } else { + hr >> color; + } + return color; +} + SPCSSAttr *Preferences::_extractStyle(Entry const &v) { SPCSSAttr *style = sp_repr_css_attr_new(); diff --git a/src/preferences.h b/src/preferences.h index a7be08009..5e1ccf9d6 100644 --- a/src/preferences.h +++ b/src/preferences.h @@ -177,6 +177,11 @@ public: */ inline Glib::ustring getString() const; + /** + * @brief Interpret the preference as an RGBA color value. + */ + inline guint32 getColor(guint32 def) const; + /** * @brief Interpret the preference as a CSS style. * @return A CSS style that has to be unrefed when no longer necessary. Never NULL. @@ -329,6 +334,10 @@ public: return getEntry(pref_path).getString(); } + guint32 getColor(Glib::ustring const &pref_path, guint32 def=0x000000ff) { + return getEntry(pref_path).getColor(def); + } + /** * @brief Retrieve a CSS style * @param pref_path Path to the retrieved preference @@ -383,6 +392,11 @@ public: */ void setString(Glib::ustring const &pref_path, Glib::ustring const &value); + /** + * @brief Set an RGBA color value + */ + void setColor(Glib::ustring const &pref_path, guint32 value); + /** * @brief Set a CSS style */ @@ -459,6 +473,7 @@ protected: int _extractInt(Entry const &v); double _extractDouble(Entry const &v); Glib::ustring _extractString(Entry const &v); + guint32 _extractColor(Entry const &v); SPCSSAttr *_extractStyle(Entry const &v); SPCSSAttr *_extractInheritedStyle(Entry const &v); @@ -567,6 +582,15 @@ inline Glib::ustring Preferences::Entry::getString() const } } +inline guint32 Preferences::Entry::getColor(guint32 def) const +{ + if (!this->isValid()) { + return def; + } else { + return Inkscape::Preferences::get()->_extractColor(*this); + } +} + inline SPCSSAttr *Preferences::Entry::getStyle() const { if (!this->isValid()) { diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index e55bba2a5..a9736e991 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -88,9 +88,7 @@ // For clippath editing #include "tools-switch.h" -#include "shape-editor.h" -#include "node-context.h" -#include "nodepath.h" +#include "ui/tool/node-tool.h" #include "ui/clipboard.h" @@ -1716,53 +1714,52 @@ void sp_selection_next_patheffect_param(SPDesktop * dt) } } +/*bool has_path_recursive(SPObject *obj) +{ + if (!obj) return false; + if (SP_IS_PATH(obj)) { + return true; + } + if (SP_IS_GROUP(obj) || SP_IS_OBJECTGROUP(obj)) { + for (SPObject *c = obj->children; c; c = c->next) { + if (has_path_recursive(c)) return true; + } + } + return false; +}*/ + void sp_selection_edit_clip_or_mask(SPDesktop * dt, bool clip) { - if (!dt) return; + return; + /*if (!dt) return; + using namespace Inkscape::UI; Inkscape::Selection *selection = sp_desktop_selection(dt); - if ( selection && !selection->isEmpty() ) { - SPItem *item = selection->singleItem(); - if ( item ) { - SPObject *obj = NULL; - if (clip) - obj = item->clip_ref ? SP_OBJECT(item->clip_ref->getObject()) : NULL; - else - obj = item->mask_ref ? SP_OBJECT(item->mask_ref->getObject()) : NULL; - - if (obj) { - // obj is a group object, the children are the actual clippers - for ( SPObject *child = obj->children ; child ; child = child->next ) { - if ( SP_IS_ITEM(child) ) { - // If not already in nodecontext, goto it! - if (!tools_isactive(dt, TOOLS_NODES)) { - tools_switch(dt, TOOLS_NODES); - } - - ShapeEditor * shape_editor = dt->event_context->shape_editor; - // TODO: should we set the item for nodepath or knotholder or both? seems to work with both. - shape_editor->set_item(SP_ITEM(child), SH_NODEPATH); - shape_editor->set_item(SP_ITEM(child), SH_KNOTHOLDER); - Inkscape::NodePath::Path *np = shape_editor->get_nodepath(); - if (np) { - // take colors from prefs (same as used in outline mode) - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - np->helperpath_rgba = clip ? - prefs->getInt("/options/wireframecolors/clips", 0x00ff00ff) : - prefs->getInt("/options/wireframecolors/masks", 0x0000ffff); - np->helperpath_width = 1.0; - sp_nodepath_show_helperpath(np, true); - } - break; // break out of for loop after 1st encountered item - } - } - } else if (clip) { - dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("The selection has no applied clip path.")); - } else { - dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, _("The selection has no applied mask.")); - } - } - } + if (!selection || selection->isEmpty()) return; + + GSList const *items = selection->itemList(); + bool has_path = false; + for (GSList *i = const_cast(items); i; i= i->next) { + SPItem *item = SP_ITEM(i->data); + SPObject *search = clip + ? SP_OBJECT(item->clip_ref ? item->clip_ref->getObject() : NULL) + : SP_OBJECT(item->mask_ref ? item->mask_ref->getObject() : NULL); + has_path |= has_path_recursive(search); + if (has_path) break; + } + if (has_path) { + if (!tools_isactive(dt, TOOLS_NODES)) { + tools_switch(dt, TOOLS_NODES); + } + ink_node_tool_set_mode(INK_NODE_TOOL(dt->event_context), + clip ? NODE_TOOL_EDIT_CLIPPING_PATHS : NODE_TOOL_EDIT_MASKS); + } else if (clip) { + dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, + _("The selection has no applied clip path.")); + } else { + dt->messageStack()->flash(Inkscape::WARNING_MESSAGE, + _("The selection has no applied mask.")); + }*/ } diff --git a/src/shape-editor.cpp b/src/shape-editor.cpp index 44ad9dc9e..d416e0c92 100644 --- a/src/shape-editor.cpp +++ b/src/shape-editor.cpp @@ -35,20 +35,6 @@ #include "shape-editor.h" - -ShapeEditorsCollective::ShapeEditorsCollective(SPDesktop */*dt*/) { -} - -ShapeEditorsCollective::~ShapeEditorsCollective() { -} - - -void ShapeEditorsCollective::update_statusbar() { - -//!!! move from nodepath: sp_nodepath_update_statusbar but summing for all nodepaths - -} - ShapeEditor::ShapeEditor(SPDesktop *dt) { this->desktop = dt; this->grab_node = -1; diff --git a/src/shape-editor.h b/src/shape-editor.h index 98dbb35d7..6f0907fb9 100644 --- a/src/shape-editor.h +++ b/src/shape-editor.h @@ -147,26 +147,6 @@ private: Inkscape::XML::Node *nodepath_listener_attached_for; }; - -/* As the next stage, this will be a collection of multiple ShapeEditors, -with the same interface as the single ShapeEditor, passing the actions to all its -contained ShapeEditors. Thus it should be easy to switch node context from -using a single ShapeEditor to using a ShapeEditorsCollective. */ - -class ShapeEditorsCollective { -public: - - ShapeEditorsCollective(SPDesktop *desktop); - ~ShapeEditorsCollective(); - - void update_statusbar(); - -private: - std::vector editors; - - SPNodeContext *nc; // who holds us -}; - #endif diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index 6b71541e6..1bb500dd2 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -33,7 +33,6 @@ #include "message-stack.h" #include "inkscape.h" #include "desktop.h" -#include "node-context.h" #include "shape-editor.h" #include @@ -261,18 +260,7 @@ sp_lpe_item_update(SPObject *object, SPCtx *ctx, guint flags) } // update the helperpaths of all LPEs applied to the item - // TODO: is there a more canonical place for this, since we don't have instant access to the item's nodepath? - // FIXME: this is called multiple (at least 3) times; how can we avoid this? - - // FIXME: ditch inkscape_active_event_context() - SPEventContext *ec = inkscape_active_event_context(); - if (!SP_IS_NODE_CONTEXT(ec)) return; - ShapeEditor *sh = ec->shape_editor; - g_assert(sh); - if (!sh->has_nodepath()) return; - - Inkscape::NodePath::Path *np = sh->get_nodepath(); - sp_nodepath_update_helperpaths(np); + // TODO: re-add for the new node tool } /** @@ -395,7 +383,8 @@ sp_lpe_item_update_patheffect (SPLPEItem *lpeitem, bool wholetree, bool write) if (dynamic_cast(lpe)) { if (!lpe->isVisible()) { // we manually disable text for LPEPathLength - dynamic_cast(lpe)->hideCanvasText(); + // use static_cast, because we already checked for the right type above + static_cast(lpe)->hideCanvasText(); } } } diff --git a/src/tools-switch.cpp b/src/tools-switch.cpp index 7902a7988..380267408 100644 --- a/src/tools-switch.cpp +++ b/src/tools-switch.cpp @@ -26,7 +26,7 @@ #include #include "select-context.h" -#include "node-context.h" +#include "ui/tool/node-tool.h" #include "tweak-context.h" #include "sp-path.h" #include "rect-context.h" @@ -124,10 +124,9 @@ tools_switch(SPDesktop *dt, int num) inkscape_eventcontext_set(sp_desktop_event_context(dt)); break; case TOOLS_NODES: - dt->set_event_context(SP_TYPE_NODE_CONTEXT, tool_names[num]); + dt->set_event_context(INK_TYPE_NODE_TOOL, tool_names[num]); dt->activate_guides(true); inkscape_eventcontext_set(sp_desktop_event_context(dt)); - dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("To edit a path, click, Shift+click, or drag around nodes to select them, then drag nodes and handles. Click on an object to select.")); break; case TOOLS_TWEAK: dt->set_event_context(SP_TYPE_TWEAK_CONTEXT, tool_names[num]); diff --git a/src/ui/dialog/aboutbox.cpp b/src/ui/dialog/aboutbox.cpp index 025bec37a..bbd02fa5d 100644 --- a/src/ui/dialog/aboutbox.cpp +++ b/src/ui/dialog/aboutbox.cpp @@ -103,8 +103,8 @@ AboutBox::AboutBox() : Gtk::Dialog(_("About Inkscape")) { Gtk::Label *label=new Gtk::Label(); gchar *label_text = - g_strdup_printf("Inkscape %s, built %s", - Inkscape::version_string, __DATE__); + g_strdup_printf("Inkscape %s", + Inkscape::version_string); label->set_markup(label_text); label->set_alignment(Gtk::ALIGN_RIGHT, Gtk::ALIGN_CENTER); g_free(label_text); diff --git a/src/ui/dialog/align-and-distribute.cpp b/src/ui/dialog/align-and-distribute.cpp index a54f83758..f38d674fd 100644 --- a/src/ui/dialog/align-and-distribute.cpp +++ b/src/ui/dialog/align-and-distribute.cpp @@ -27,17 +27,17 @@ #include "graphlayout/graphlayout.h" #include "inkscape.h" #include "macros.h" -#include "node-context.h" //For access to ShapeEditor #include "preferences.h" #include "removeoverlap/removeoverlap.h" #include "selection.h" -#include "shape-editor.h" //For node align/distribute methods #include "sp-flowtext.h" #include "sp-item-transform.h" #include "sp-text.h" #include "text-editing.h" #include "tools-switch.h" #include "ui/icon-names.h" +#include "ui/tool/node-tool.h" +#include "ui/tool/multi-path-manipulator.h" #include "util/glib-list-iterators.h" #include "verbs.h" #include "widgets/icon.h" @@ -429,12 +429,13 @@ private : if (!_dialog.getDesktop()) return; SPEventContext *event_context = sp_desktop_event_context(_dialog.getDesktop()); - if (!SP_IS_NODE_CONTEXT (event_context)) return ; + if (!INK_IS_NODE_TOOL (event_context)) return; + InkNodeTool *nt = INK_NODE_TOOL(event_context); if (_distribute) - event_context->shape_editor->distribute((Geom::Dim2)_orientation); + nt->_multipath->distributeNodes(_orientation); else - event_context->shape_editor->align((Geom::Dim2)_orientation); + nt->_multipath->alignNodes(_orientation); } }; diff --git a/src/ui/dialog/inkscape-preferences.cpp b/src/ui/dialog/inkscape-preferences.cpp index c7dc789ca..1d93eab6b 100644 --- a/src/ui/dialog/inkscape-preferences.cpp +++ b/src/ui/dialog/inkscape-preferences.cpp @@ -436,12 +436,19 @@ void InkscapePreferences::initPageTools() _page_node.add_group_header( _("Path outline:")); _t_node_pathoutline_color.init(_("Path outline color"), "/tools/nodes/highlight_color", 0xff0000ff); _page_node.add_line( false, _("Path outline color"), _t_node_pathoutline_color, "", _("Selects the color used for showing the path outline."), false); - _t_node_pathflash_enabled.init ( _("Path outline flash on mouse-over"), "/tools/nodes/pathflash_enabled", false); + _t_node_show_path_direction.init(_("Show path direction"), "/tools/nodes/show_path_direction", false); + _page_node.add_line( true, "", _t_node_show_path_direction, "", _("Visualize the direction of selected paths by drawing small arrows in the middle of each segment.")); + _t_node_pathflash_enabled.init ( _("Show temporary path outline"), "/tools/nodes/pathflash_enabled", false); _page_node.add_line( true, "", _t_node_pathflash_enabled, "", _("When hovering over a path, briefly flash its outline.")); - _t_node_pathflash_unselected.init ( _("Suppress path outline flash when one path selected"), "/tools/nodes/pathflash_unselected", false); - _page_node.add_line( true, "", _t_node_pathflash_unselected, "", _("If a path is selected, do not continue flashing path outlines.")); + _t_node_pathflash_unselected.init ( _("Show temporary outline for selected paths"), "/tools/nodes/pathflash_unselected", false); + _page_node.add_line( true, "", _t_node_pathflash_unselected, "", _("Show temporary outline even when a path is selected for editing")); _t_node_pathflash_timeout.init("/tools/nodes/pathflash_timeout", 0, 10000.0, 100.0, 100.0, 1000.0, true, false); _page_node.add_line( false, _("Flash time"), _t_node_pathflash_timeout, "ms", _("Specifies how long the path outline will be visible after a mouse-over (in milliseconds). Specify 0 to have the outline shown until mouse leaves the path."), false); + _page_node.add_group_header(_("Transform Handles:")); + _t_node_show_transform_handles.init(_("Show transform handles"), "/tools/nodes/show_transform_handles", true); + _page_node.add_line( true, "", _t_node_show_transform_handles, "", _("Show scaling, rotation and skew handles for node selections.")); + _t_node_single_node_transform_handles.init(_("Show transform handles for single nodes"), "/tools/nodes/single_node_transform_handles", false); + _page_node.add_line( true, "", _t_node_single_node_transform_handles, "", _("Show transform handles even when only a single node is selected.")); //Tweak this->AddPage(_page_tweak, _("Tweak"), iter_tools, PREFS_PAGE_TOOLS_TWEAK); diff --git a/src/ui/dialog/inkscape-preferences.h b/src/ui/dialog/inkscape-preferences.h index 364b0eb1d..0fc1be21e 100644 --- a/src/ui/dialog/inkscape-preferences.h +++ b/src/ui/dialog/inkscape-preferences.h @@ -143,6 +143,9 @@ protected: PrefCheckButton _t_node_pathflash_enabled; PrefCheckButton _t_node_pathflash_unselected; PrefSpinButton _t_node_pathflash_timeout; + PrefCheckButton _t_node_show_path_direction; + PrefCheckButton _t_node_show_transform_handles; + PrefCheckButton _t_node_single_node_transform_handles; PrefColorPicker _t_node_pathoutline_color; PrefRadioButton _win_dockable, _win_floating; diff --git a/src/ui/tool/Makefile_insert b/src/ui/tool/Makefile_insert new file mode 100644 index 000000000..e14943021 --- /dev/null +++ b/src/ui/tool/Makefile_insert @@ -0,0 +1,29 @@ +## Makefile.am fragment sourced by src/Makefile.am. + +ink_common_sources += \ + ui/tool/control-point.cpp \ + ui/tool/control-point.h \ + ui/tool/control-point-selection.cpp \ + ui/tool/control-point-selection.h \ + ui/tool/commit-events.h \ + ui/tool/curve-drag-point.cpp \ + ui/tool/curve-drag-point.h \ + ui/tool/event-utils.cpp \ + ui/tool/event-utils.h \ + ui/tool/manipulator.cpp \ + ui/tool/manipulator.h \ + ui/tool/multi-path-manipulator.cpp \ + ui/tool/multi-path-manipulator.h \ + ui/tool/node.cpp \ + ui/tool/node.h \ + ui/tool/node-types.h \ + ui/tool/node-tool.cpp \ + ui/tool/node-tool.h \ + ui/tool/path-manipulator.cpp \ + ui/tool/path-manipulator.h \ + ui/tool/selectable-control-point.cpp \ + ui/tool/selectable-control-point.h \ + ui/tool/selector.cpp \ + ui/tool/selector.h \ + ui/tool/transform-handle-set.cpp \ + ui/tool/transform-handle-set.h diff --git a/src/ui/tool/commit-events.h b/src/ui/tool/commit-events.h new file mode 100644 index 000000000..d99872766 --- /dev/null +++ b/src/ui/tool/commit-events.h @@ -0,0 +1,51 @@ +/** @file + * Commit events. + */ +/* Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2009 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_UI_TOOL_COMMIT_EVENTS_H +#define SEEN_UI_TOOL_COMMIT_EVENTS_H + +namespace Inkscape { +namespace UI { + +/// This is used to provide sensible messages on the undo stack. +enum CommitEvent { + COMMIT_MOUSE_MOVE, + COMMIT_KEYBOARD_MOVE_X, + COMMIT_KEYBOARD_MOVE_Y, + COMMIT_MOUSE_SCALE, + COMMIT_MOUSE_SCALE_UNIFORM, + COMMIT_KEYBOARD_SCALE_UNIFORM, + COMMIT_KEYBOARD_SCALE_X, + COMMIT_KEYBOARD_SCALE_Y, + COMMIT_MOUSE_ROTATE, + COMMIT_KEYBOARD_ROTATE, + COMMIT_MOUSE_SKEW_X, + COMMIT_MOUSE_SKEW_Y, + COMMIT_KEYBOARD_SKEW_X, + COMMIT_KEYBOARD_SKEW_Y, + COMMIT_FLIP_X, + COMMIT_FLIP_Y +}; + +} // namespace UI +} // 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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/tool/control-point-selection.cpp b/src/ui/tool/control-point-selection.cpp new file mode 100644 index 000000000..d10045c62 --- /dev/null +++ b/src/ui/tool/control-point-selection.cpp @@ -0,0 +1,530 @@ +/** @file + * Node selection - implementation + */ +/* Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2009 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include <2geom/transforms.h> +#include "desktop.h" +#include "preferences.h" +#include "ui/tool/control-point-selection.h" +#include "ui/tool/event-utils.h" +#include "ui/tool/selectable-control-point.h" +#include "ui/tool/transform-handle-set.h" + +namespace Inkscape { +namespace UI { + +/** + * @class ControlPointSelection + * @brief Group of selected control points. + * + * Some operations can be performed on all selected points regardless of their type, therefore + * this class is also a Manipulator. It handles the transformations of points using + * the keyboard. + * + * The exposed interface is similar to that of an STL set. Internally, a hash map is used. + * @todo Correct iterators (that don't expose the connection list) + */ + +/** @var ControlPointSelection::signal_update + * Fires when the display needs to be updated to reflect changes. + */ +/** @var ControlPointSelection::signal_point_changed + * Fires when a control point is added to or removed from the selection. + * The first param contains a pointer to the control point that changed sel. state. + * The second says whether the point is currently selected. + */ +/** @var ControlPointSelection::signal_commit + * Fires when a change that needs to be committed to XML happens. + */ + +ControlPointSelection::ControlPointSelection(SPDesktop *d, SPCanvasGroup *th_group) + : Manipulator(d) + , _handles(new TransformHandleSet(d, th_group)) + , _dragging(false) + , _handles_visible(true) + , _one_node_handles(false) + , _sculpt_enabled(false) + , _sculpting(false) +{ + signal_update.connect( sigc::bind( + sigc::mem_fun(*this, &ControlPointSelection::_updateTransformHandles), + true)); + signal_point_changed.connect( + sigc::hide( sigc::hide( + sigc::bind( + sigc::mem_fun(*this, &ControlPointSelection::_updateTransformHandles), + false)))); + _handles->signal_transform.connect( + sigc::mem_fun(*this, &ControlPointSelection::transform)); + _handles->signal_commit.connect( + sigc::mem_fun(*this, &ControlPointSelection::_commitTransform)); +} + +ControlPointSelection::~ControlPointSelection() +{ + clear(); + delete _handles; +} + +/** Add a control point to the selection. */ +std::pair ControlPointSelection::insert(const value_type &x) +{ + iterator found = _points.find(x); + if (found != _points.end()) { + return std::pair(found, false); + } + + boost::shared_ptr clist(new connlist_type()); + + // hide event param and always return false + clist->push_back( + x->signal_grabbed.connect( + sigc::bind_return( + sigc::bind<0>( + sigc::mem_fun(*this, &ControlPointSelection::_selectionGrabbed), + x), + false))); + clist->push_back( + x->signal_dragged.connect( + sigc::mem_fun(*this, &ControlPointSelection::_selectionDragged))); + // hide event parameter + clist->push_back( + x->signal_ungrabbed.connect( + sigc::hide( + sigc::mem_fun(*this, &ControlPointSelection::_selectionUngrabbed)))); + + found = _points.insert(std::make_pair(x, clist)).first; + + x->updateState(); + _rot_radius.reset(); + signal_point_changed.emit(x, true); + + return std::pair(found, true); +} + +/** Remove a point from the selection. */ +void ControlPointSelection::erase(iterator pos) +{ + SelectableControlPoint *erased = pos->first; + boost::shared_ptr clist = pos->second; + for (connlist_type::iterator i = clist->begin(); i != clist->end(); ++i) { + i->disconnect(); + } + _points.erase(pos); + erased->updateState(); + _rot_radius.reset(); + signal_point_changed.emit(erased, false); +} +ControlPointSelection::size_type ControlPointSelection::erase(const key_type &k) +{ + iterator pos = _points.find(k); + if (pos == _points.end()) return 0; + erase(pos); + return 1; +} +void ControlPointSelection::erase(iterator first, iterator last) +{ + while (first != last) erase(first++); +} + +/** Remove all points from the selection, making it empty. */ +void ControlPointSelection::clear() +{ + for (iterator i = begin(); i != end(); ) + erase(i++); +} + +/** Transform all selected control points by the supplied affine transformation. */ +void ControlPointSelection::transform(Geom::Matrix const &m) +{ + for (iterator i = _points.begin(); i != _points.end(); ++i) { + SelectableControlPoint *cur = i->first; + cur->transform(m); + } + // TODO preserving the rotation radius needs some rethinking... + if (_rot_radius) (*_rot_radius) *= m.descrim(); + signal_update.emit(); +} + +/** Align control points on the specified axis. */ +void ControlPointSelection::align(Geom::Dim2 axis) +{ + if (empty()) return; + Geom::Dim2 d = static_cast((axis + 1) % 2); + + Geom::OptInterval bound; + for (iterator i = _points.begin(); i != _points.end(); ++i) { + bound.unionWith(Geom::OptInterval(i->first->position()[d])); + } + + double new_coord = bound->middle(); + for (iterator i = _points.begin(); i != _points.end(); ++i) { + Geom::Point pos = i->first->position(); + pos[d] = new_coord; + i->first->move(pos); + } +} + +/** Equdistantly distribute control points by moving them in the specified dimension. */ +void ControlPointSelection::distribute(Geom::Dim2 d) +{ + if (empty()) return; + + // this needs to be a multimap, otherwise it will fail when some points have the same coord + typedef std::multimap SortMap; + + SortMap sm; + Geom::OptInterval bound; + // first we insert all points into a multimap keyed by the aligned coord to sort them + // simultaneously we compute the extent of selection + for (iterator i = _points.begin(); i != _points.end(); ++i) { + Geom::Point pos = i->first->position(); + sm.insert(std::make_pair(pos[d], i->first)); + bound.unionWith(Geom::OptInterval(pos[d])); + } + + // now we iterate over the multimap and set aligned positions. + double step = size() == 1 ? 0 : bound->extent() / (size() - 1); + double start = bound->min(); + unsigned num = 0; + for (SortMap::iterator i = sm.begin(); i != sm.end(); ++i, ++num) { + Geom::Point pos = i->second->position(); + pos[d] = start + num * step; + i->second->move(pos); + } +} + +/** Get the bounds of the selection. + * @return Smallest rectangle containing the positions of all selected points, + * or nothing if the selection is empty */ +Geom::OptRect ControlPointSelection::pointwiseBounds() +{ + Geom::OptRect bound; + for (iterator i = _points.begin(); i != _points.end(); ++i) { + SelectableControlPoint *cur = i->first; + Geom::Point p = cur->position(); + if (!bound) { + bound = Geom::Rect(p, p); + } else { + bound->expandTo(p); + } + } + return bound; +} + +Geom::OptRect ControlPointSelection::bounds() +{ + Geom::OptRect bound; + for (iterator i = _points.begin(); i != _points.end(); ++i) { + SelectableControlPoint *cur = i->first; + Geom::OptRect r = cur->bounds(); + bound.unionWith(r); + } + return bound; +} + +void ControlPointSelection::showTransformHandles(bool v, bool one_node) +{ + _one_node_handles = one_node; + _handles_visible = v; + _updateTransformHandles(false); +} + +void ControlPointSelection::hideTransformHandles() +{ + _handles->setVisible(false); +} +void ControlPointSelection::restoreTransformHandles() +{ + _updateTransformHandles(true); +} + +void ControlPointSelection::_selectionGrabbed(SelectableControlPoint *p, GdkEventMotion *event) +{ + hideTransformHandles(); + _dragging = true; + if (held_alt(*event) && _sculpt_enabled) { + _sculpting = true; + _grabbed_point = p; + } else { + _sculpting = false; + } +} + +void ControlPointSelection::_selectionDragged(Geom::Point const &old_pos, Geom::Point &new_pos, + GdkEventMotion *event) +{ + Geom::Point delta = new_pos - old_pos; + /*if (_sculpting) { + // for now we only support the default sculpting profile (bell) + // others will be added when preferences will be able to store enumerated values + double pressure, alpha; + if (gdk_event_get_axis (event, GDK_AXIS_PRESSURE, &pressure)) { + pressure = CLAMP(pressure, 0.2, 0.8); + } else { + pressure = 0.5; + } + + alpha = 1 - 2 * fabs(pressure - 0.5); + if (pressure > 0.5) alpha = 1/alpha; + + for (iterator i = _points.begin(); i != _points.end(); ++i) { + SelectableControlPoint *cur = i->first; + double dist = Geom::distance(cur->position(), _grabbed_point->position()); + + cur->move(cur->position() + delta); + } + } else*/ { + for (iterator i = _points.begin(); i != _points.end(); ++i) { + SelectableControlPoint *cur = i->first; + cur->move(cur->position() + delta); + } + _handles->rotationCenter().move(_handles->rotationCenter().position() + delta); + } + signal_update.emit(); +} + +void ControlPointSelection::_selectionUngrabbed() +{ + _dragging = false; + _grabbed_point = NULL; + restoreTransformHandles(); + signal_commit.emit(COMMIT_MOUSE_MOVE); +} + +void ControlPointSelection::_updateTransformHandles(bool preserve_center) +{ + if (_dragging) return; + + if (_handles_visible && size() > 1) { + Geom::OptRect b = pointwiseBounds(); + _handles->setBounds(*b, preserve_center); + _handles->setVisible(true); + } else if (_one_node_handles && size() == 1) { // only one control point in selection + SelectableControlPoint *p = begin()->first; + _handles->setBounds(p->bounds()); + _handles->rotationCenter().move(p->position()); + _handles->rotationCenter().setVisible(false); + _handles->setVisible(true); + } else { + _handles->setVisible(false); + } +} + +/** Moves the selected points along the supplied unit vector according to + * the modifier state of the supplied event. */ +bool ControlPointSelection::_keyboardMove(GdkEventKey const &event, Geom::Point const &dir) +{ + if (held_control(event)) return false; + unsigned num = 1 + consume_same_key_events(shortcut_key(event), 0); + + Geom::Point delta = dir * num; + if (held_shift(event)) delta *= 10; + if (held_alt(event)) { + delta /= _desktop->current_zoom(); + } else { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + double nudge = prefs->getDoubleLimited("/options/nudgedistance/value", 2, 0, 1000); + delta *= nudge; + } + + transform(Geom::Translate(delta)); + if (fabs(dir[Geom::X]) > 0) { + signal_commit.emit(COMMIT_KEYBOARD_MOVE_X); + } else { + signal_commit.emit(COMMIT_KEYBOARD_MOVE_Y); + } + return true; +} + +/** Rotates the selected points in the given direction according to the modifier state + * from the supplied event. + * @param event Key event to take modifier state from + * @param dir Direction of rotation (math convention: 1 = counterclockwise, -1 = clockwise) + */ +bool ControlPointSelection::_keyboardRotate(GdkEventKey const &event, int dir) +{ + if (empty()) return false; + + Geom::Point rc = _handles->rotationCenter(); + if (!_rot_radius) { + Geom::Rect b = *(size() == 1 ? bounds() : pointwiseBounds()); + double maxlen = 0; + for (unsigned i = 0; i < 4; ++i) { + double len = (b.corner(i) - rc).length(); + if (len > maxlen) maxlen = len; + } + _rot_radius = maxlen; + } + + double angle; + if (held_alt(event)) { + // Rotate by "one pixel". We interpret this as rotating by an angle that causes + // the topmost point of a circle circumscribed about the selection's bounding box + // to move on an arc 1 screen pixel long. + angle = atan2(1.0 / _desktop->current_zoom(), *_rot_radius) * dir; + } else { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int snaps = prefs->getIntLimited("/options/rotationsnapsperpi/value", 12, 1, 1000); + angle = M_PI * dir / snaps; + } + + // translate to origin, rotate, translate back to original position + Geom::Matrix m = Geom::Translate(-rc) + * Geom::Rotate(angle) * Geom::Translate(rc); + transform(m); + signal_commit.emit(COMMIT_KEYBOARD_ROTATE); + return true; +} + + +bool ControlPointSelection::_keyboardScale(GdkEventKey const &event, int dir) +{ + if (empty()) return false; + + // TODO should the saved rotation center or the current center be used? + Geom::Rect bound = (size() == 1 ? *bounds() : *pointwiseBounds()); + double maxext = bound.maxExtent(); + if (Geom::are_near(maxext, 0)) return false; + Geom::Point center = _handles->rotationCenter().position(); + + double length_change; + if (held_alt(event)) { + // Scale by "one pixel". It means shrink/grow 1px for the larger dimension + // of the bounding box. + length_change = 1.0 / _desktop->current_zoom() * dir; + } else { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + length_change = prefs->getDoubleLimited("/options/defaultscale/value", 2, 1, 1000); + length_change *= dir; + } + double scale = (maxext + length_change) / maxext; + + Geom::Matrix m = Geom::Translate(-center) * Geom::Scale(scale) * Geom::Translate(center); + transform(m); + signal_commit.emit(COMMIT_KEYBOARD_SCALE_UNIFORM); + return true; +} + +bool ControlPointSelection::_keyboardFlip(Geom::Dim2 d) +{ + if (empty()) return false; + + Geom::Scale scale_transform(1, 1); + if (d == Geom::X) { + scale_transform = Geom::Scale(-1, 1); + } else { + scale_transform = Geom::Scale(1, -1); + } + + SelectableControlPoint *scp = + dynamic_cast(ControlPoint::mouseovered_point); + Geom::Point center = scp ? scp->position() : _handles->rotationCenter().position(); + + Geom::Matrix m = Geom::Translate(-center) * scale_transform * Geom::Translate(center); + transform(m); + signal_commit.emit(d == Geom::X ? COMMIT_FLIP_X : COMMIT_FLIP_Y); + return true; +} + +void ControlPointSelection::_commitTransform(CommitEvent ce) +{ + _updateTransformHandles(true); + signal_commit.emit(ce); +} + +bool ControlPointSelection::event(GdkEvent *event) +{ + // implement generic event handling that should apply for all control point selections here; + // for example, keyboard moves and transformations. This way this functionality doesn't need + // to be duplicated in many places + // Later split out so that it can be reused in object selection + + switch (event->type) { + case GDK_KEY_PRESS: + // do not handle key events if the selection is empty + if (empty()) break; + + switch(shortcut_key(event->key)) { + // moves + case GDK_Up: + case GDK_KP_Up: + case GDK_KP_8: + return _keyboardMove(event->key, Geom::Point(0, 1)); + case GDK_Down: + case GDK_KP_Down: + case GDK_KP_2: + return _keyboardMove(event->key, Geom::Point(0, -1)); + case GDK_Right: + case GDK_KP_Right: + case GDK_KP_6: + return _keyboardMove(event->key, Geom::Point(1, 0)); + case GDK_Left: + case GDK_KP_Left: + case GDK_KP_4: + return _keyboardMove(event->key, Geom::Point(-1, 0)); + + // rotates + case GDK_bracketleft: + return _keyboardRotate(event->key, 1); + case GDK_bracketright: + return _keyboardRotate(event->key, -1); + + // scaling + case GDK_less: + case GDK_comma: + return _keyboardScale(event->key, -1); + case GDK_greater: + case GDK_period: + return _keyboardScale(event->key, 1); + + // TODO: skewing + + // flipping + // NOTE: H is horizontal flip, while Shift+H switches transform handle mode! + case GDK_h: + case GDK_H: + if (held_shift(event->key)) { + // TODO make a method for mode switching + if (_handles->mode() == TransformHandleSet::MODE_SCALE) { + _handles->setMode(TransformHandleSet::MODE_ROTATE_SKEW); + if (size() == 1) _handles->rotationCenter().setVisible(false); + } else { + _handles->setMode(TransformHandleSet::MODE_SCALE); + } + return true; + } + // any modifiers except shift should cause no action + if (held_any_modifiers(event->key)) break; + return _keyboardFlip(Geom::X); + case GDK_v: + case GDK_V: + if (held_any_modifiers(event->key)) break; + return _keyboardFlip(Geom::Y); + default: break; + } + break; + default: break; + } + return false; +} + +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/tool/control-point-selection.h b/src/ui/tool/control-point-selection.h new file mode 100644 index 000000000..0f0daffaa --- /dev/null +++ b/src/ui/tool/control-point-selection.h @@ -0,0 +1,140 @@ +/** @file + * Node selection - stores a set of nodes and applies transformations + * to them + */ +/* Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2009 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_UI_TOOL_NODE_SELECTION_H +#define SEEN_UI_TOOL_NODE_SELECTION_H + +#include +#include +#include +#include +#include +#include +#include <2geom/forward.h> +#include <2geom/point.h> +#include "display/display-forward.h" +#include "util/accumulators.h" +#include "util/hash.h" +#include "ui/tool/commit-events.h" +#include "ui/tool/manipulator.h" + +namespace std { using namespace tr1; } + +class SPDesktop; + +namespace Inkscape { +namespace UI { + +class TransformHandleSet; +class SelectableControlPoint; + +class ControlPointSelection : public Manipulator { +public: + ControlPointSelection(SPDesktop *d, SPCanvasGroup *th_group); + ~ControlPointSelection(); + typedef std::list connlist_type; + typedef std::unordered_map< SelectableControlPoint *, + boost::shared_ptr > map_type; + + // boilerplate typedefs + typedef map_type::iterator iterator; + typedef map_type::const_iterator const_iterator; + typedef map_type::size_type size_type; + + typedef SelectableControlPoint *value_type; + typedef SelectableControlPoint *key_type; + + // size + bool empty() { return _points.empty(); } + size_type size() { return _points.size(); } + + // iterators + iterator begin() { return _points.begin(); } + const_iterator begin() const { return _points.begin(); } + iterator end() { return _points.end(); } + const_iterator end() const { return _points.end(); } + + // insert + std::pair insert(const value_type& x); + template + void insert(InputIterator first, InputIterator last) { + for (; first != last; ++first) { + insert(*first); + } + } + + // erase + void clear(); + void erase(iterator pos); + size_type erase(const key_type& k); + void erase(iterator first, iterator last); + + // find + iterator find(const key_type &k) { return _points.find(k); } + + virtual bool event(GdkEvent *); + + void transform(Geom::Matrix const &m); + void align(Geom::Dim2 d); + void distribute(Geom::Dim2 d); + + Geom::OptRect pointwiseBounds(); + Geom::OptRect bounds(); + + void showTransformHandles(bool v, bool one_node); + // the two methods below do not modify the state; they are for use in manipulators + // that need to temporarily hide the handles + void hideTransformHandles(); + void restoreTransformHandles(); + + // TODO this is really only applicable to nodes... maybe derive a NodeSelection? + void setSculpting(bool v) { _sculpt_enabled = v; } + + sigc::signal signal_update; + sigc::signal signal_point_changed; + sigc::signal signal_commit; +private: + void _selectionGrabbed(SelectableControlPoint *, GdkEventMotion *); + void _selectionDragged(Geom::Point const &, Geom::Point &, GdkEventMotion *); + void _selectionUngrabbed(); + void _updateTransformHandles(bool preserve_center); + bool _keyboardMove(GdkEventKey const &, Geom::Point const &); + bool _keyboardRotate(GdkEventKey const &, int); + bool _keyboardScale(GdkEventKey const &, int); + bool _keyboardFlip(Geom::Dim2); + void _keyboardTransform(Geom::Matrix const &); + void _commitTransform(CommitEvent ce); + map_type _points; + boost::optional _rot_radius; + TransformHandleSet *_handles; + SelectableControlPoint *_grabbed_point; + unsigned _dragging : 1; + unsigned _handles_visible : 1; + unsigned _one_node_handles : 1; + unsigned _sculpt_enabled : 1; + unsigned _sculpting : 1; +}; + +} // namespace UI +} // 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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/tool/control-point.cpp b/src/ui/tool/control-point.cpp new file mode 100644 index 000000000..74dd6e31c --- /dev/null +++ b/src/ui/tool/control-point.cpp @@ -0,0 +1,619 @@ +/** @file + * Desktop-bound visual control object - implementation + */ +/* Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2009 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include +#include +#include <2geom/point.h> +#include "ui/tool/control-point.h" +#include "ui/tool/event-utils.h" +#include "preferences.h" +#include "desktop.h" +#include "desktop-handles.h" +#include "event-context.h" +#include "message-context.h" + +namespace Inkscape { +namespace UI { + +// class and member documentation goes here... + +/** + * @class ControlPoint + * @brief Draggable point, the workhorse of on-canvas editing. + * + * Control points (formerly known as knots) are graphical representations of some significant + * point in the drawing. The drawing can be changed by dragging the point and the things that are + * attached to it with the mouse. Example things that could be edited with draggable points + * are gradient stops, the place where text is attached to a path, text kerns, nodes and handles + * in a path, and many more. Control points use signals heavily - read the libsigc++ + * tutorial on the wiki before using this class. + * + * @par Control point signals + * @par + * The control point has several signals which allow you to react to things that happen to it. + * The most important singals are the grabbed, dragged, ungrabbed and moved signals. + * When a drag happens, the order of emission is as follows: + * - signal_grabbed + * - signal_dragged + * - signal_dragged + * - signal_dragged + * - ... + * - signal_dragged + * - signal_ungrabbed + * + * The control point can also respond to clicks and double clicks. On a double click, + * signal_clicked is emitted, followed by signal_doubleclicked. + * + * A few signal usage hints if you can't be bothered to read the tutorial: + * - If you want some other object or a global function to react to signals of a control point + * from some other object, and you want to access the control point that emitted the signal + * in the handler, use sigc::bind like this: + * @code + * void handle_clicked_signal(ControlPoint *point, int button); + * point->signal_clicked.connect( + * sigc::bind<0>( sigc::ptr_fun(handle_clicked_signal), + * point )); + * @endcode + * - You can ignore unneeded parameters using sigc::hide. + * - If you want to get rid of the handlers added by constructors in superclasses, + * use the clear() method: @code signal_clicked.clear(); @endcode + * - To connect at the front of the slot list instead of at the end, use: + * @code + * signal_clicked.slots().push_front( + * sigc::mem_fun(*this, &FunkyPoint::_clickedHandler)); + * @endcode + * - Note that calling slots() does not copy anything. You can disconnect + * and reorder slots by manipulating the elements of the slot list. The returned object is + * of type @verbatim (signal type)::slot_list @endverbatim. + * + * @par Which method to override? + * @par + * You might wonder which hook to use when you want to do things when the point is relocated. + * Here are some tips: + * - If the point is used to edit an object, override the move() method. + * - If the point can usually be dragged wherever you like but can optionally be constrained + * to axes or the like, add a handler for signal_dragged that modifies its new + * position argument. + * - If the point has additional canvas items tied to it (like handle lines), override + * the setPosition() method. + */ + +/** + * @var ControlPoint::signal_dragged + * Emitted while dragging, but before moving the knot to new position. + * Old position will always be the same as position() - there are two parameters + * only for convenience. + * - First parameter: old position, always equal to position() + * - Second parameter: new position (after drag). This is passed as a non-const reference, + * so you can change it from the handler - that's how constrained dragging is implemented. + * - Third parameter: motion event + */ + +/** + * @var ControlPoint::signal_clicked + * Emitted when the control point is clicked, at mouse button release. The parameter contains + * the event that caused the signal to be emitted. Your signal handler should return true + * if the click had some effect. If it did nothing, return false. Improperly handling this signal + * can cause the context menu not to appear when a control point is right-clicked. + */ + +/** + * @var ControlPoint::signal_doubleclicked + * Emitted when the control point is doubleclicked, at mouse button release. The parameter + * contains the event that caused the signal to be emitted. Your signal handler should return true + * if the double click had some effect. If it did nothing, return false. + */ + +/** + * @var ControlPoint::signal_grabbed + * Emitted when the control point is grabbed and a drag starts. The parameter contains + * the causing event. Return true to prevent further processing. Because all control points + * handle drag tolerance, signal_dragged will be emitted immediately after this signal + * to move the point to its new position. + */ + +/** + * @var ControlPoint::signal_ungrabbed + * Emitted when the control point finishes a drag. The parameter contains the event which + * caused the signal, but it can be NULL if the grab was broken. + */ + +/** + * @enum ControlPoint::State + * Enumeration representing the possible states of the control point, used to determine + * its appearance. + * @var ControlPoint::STATE_NORMAL + * Normal state + * @var ControlPoint::STATE_MOUSEOVER + * Mouse is hovering over the control point + * @var ControlPoint::STATE_CLICKED + * First mouse button pressed over the control point + */ + +// Default colors for control points +static ControlPoint::ColorSet default_color_set = { + {0xffffff00, 0x01000000}, // normal fill, stroke + {0xff0000ff, 0x01000000}, // mouseover fill, stroke + {0x0000ffff, 0x01000000} // clicked fill, stroke +}; + +/** Holds the currently mouseovered control point. */ +ControlPoint *ControlPoint::mouseovered_point = 0; + +/** Emitted when the mouseovered point changes. The parameter is the new mouseovered point. + * When a point ceases to be mouseovered, the parameter will be NULL. */ +sigc::signal ControlPoint::signal_mouseover_change; + +/** Stores the window point over which the cursor was during the last mouse button press */ +Geom::Point ControlPoint::_drag_event_origin(Geom::infinity(), Geom::infinity()); + +/** Stores the desktop point from which the last drag was initiated */ +Geom::Point ControlPoint::_drag_origin(Geom::infinity(), Geom::infinity()); + +/** Events which should be captured when a handle is being dragged. */ +int const ControlPoint::_grab_event_mask = (GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK); + +bool ControlPoint::_drag_initiated = false; +bool ControlPoint::_event_grab = false; + +/** A color set which you can use to create an invisible control that can still receive events. + * @relates ControlPoint */ +ControlPoint::ColorSet invisible_cset = { + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000}, + {0x00000000, 0x00000000} +}; + +/** + * Create a regular control point. + * Derive to have constructors with a reasonable number of parameters. + * + * @param d Desktop for this control + * @param initial_pos Initial position of the control point in desktop coordinates + * @param anchor Where is the control point rendered relative to its desktop coordinates + * @param shape Shape of the control point: square, diamond, circle... + * @param size Pixel size of the visual representation + * @param cset Colors of the point + * @param group The canvas group the point's canvas item should be created in + */ +ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, + Gtk::AnchorType anchor, SPCtrlShapeType shape, + unsigned int size, ColorSet *cset, SPCanvasGroup *group) + : _desktop (d) + , _canvas_item (NULL) + , _cset (cset ? cset : &default_color_set) + , _state (STATE_NORMAL) + , _position (initial_pos) +{ + _canvas_item = sp_canvas_item_new( + group ? group : sp_desktop_controls (_desktop), SP_TYPE_CTRL, + "anchor", (GtkAnchorType) anchor, "size", (gdouble) size, "shape", shape, + "filled", TRUE, "fill_color", _cset->normal.fill, + "stroked", TRUE, "stroke_color", _cset->normal.stroke, + "mode", SP_CTRL_MODE_XOR, NULL); + _commonInit(); +} + +/** + * Create a control point with a pixbuf-based visual representation. + * + * @param d Desktop for this control + * @param initial_pos Initial position of the control point in desktop coordinates + * @param anchor Where is the control point rendered relative to its desktop coordinates + * @param pixbuf Pixbuf to be used as the visual representation + * @param cset Colors of the point + * @param group The canvas group the point's canvas item should be created in + */ +ControlPoint::ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, + Gtk::AnchorType anchor, Glib::RefPtr pixbuf, + ColorSet *cset, SPCanvasGroup *group) + : _desktop (d) + , _canvas_item (NULL) + , _cset(cset ? cset : &default_color_set) + , _position (initial_pos) +{ + _canvas_item = sp_canvas_item_new( + group ? group : sp_desktop_controls(_desktop), SP_TYPE_CTRL, + "anchor", (GtkAnchorType) anchor, "size", (gdouble) pixbuf->get_width(), + "shape", SP_CTRL_SHAPE_BITMAP, "pixbuf", pixbuf->gobj(), + "filled", TRUE, "fill_color", _cset->normal.fill, + "stroked", TRUE, "stroke_color", _cset->normal.stroke, + "mode", SP_CTRL_MODE_XOR, NULL); + _commonInit(); +} + +ControlPoint::~ControlPoint() +{ + // avoid storing invalid points in mouseovered_point + if (this == mouseovered_point) { + _clearMouseover(); + } + + g_signal_handler_disconnect(G_OBJECT(_canvas_item), _event_handler_connection); + //sp_canvas_item_hide(_canvas_item); + gtk_object_destroy(_canvas_item); +} + +void ControlPoint::_commonInit() +{ + _event_handler_connection = g_signal_connect(G_OBJECT(_canvas_item), "event", + G_CALLBACK(_event_handler), this); + SP_CTRL(_canvas_item)->moveto(_position); +} + +/** Relocate the control point without side effects. + * Overload this method only if there is an additional graphical representation + * that must be updated (like the lines that connect handles to nodes). If you override it, + * you must also call the superclass implementation of the method. + * @todo Investigate whether this method should be protected */ +void ControlPoint::setPosition(Geom::Point const &pos) +{ + _position = pos; + SP_CTRL(_canvas_item)->moveto(pos); +} + +/** Move the control point to new position with side effects. + * This is called after each drag. Override this method if only some positions make sense + * for a control point (like a point that must always be on a path and can't modify it), + * or when moving a control point changes the positions of other points. */ +void ControlPoint::move(Geom::Point const &pos) +{ + setPosition(pos); +} + +/** Apply an arbitrary affine transformation to a control point. This is used + * by ControlPointSelection, and is important for things like nodes with handles. + * The default implementation simply moves the point according to the transform. */ +void ControlPoint::transform(Geom::Matrix const &m) { + move(position() * m); +} + +bool ControlPoint::visible() const +{ + return sp_canvas_item_is_visible(_canvas_item); +} + +/** Set the visibility of the control point. An invisible point is not drawn on the canvas + * and cannot receive any events. If you want to have an invisible point that can respond + * to events, use invisible_cset as its color set. */ +void ControlPoint::setVisible(bool v) +{ + if (v) sp_canvas_item_show(_canvas_item); + else sp_canvas_item_hide(_canvas_item); +} + +Glib::ustring ControlPoint::format_tip(char const *format, ...) +{ + va_list args; + va_start(args, format); + char *dyntip = g_strdup_vprintf(format, args); + va_end(args); + Glib::ustring ret = dyntip; + g_free(dyntip); + return ret; +} + +unsigned int ControlPoint::_size() const +{ + double ret; + g_object_get(_canvas_item, "size", &ret, NULL); + return static_cast(ret); +} + +SPCtrlShapeType ControlPoint::_shape() const +{ + SPCtrlShapeType ret; + g_object_get(_canvas_item, "shape", &ret, NULL); + return ret; +} + +GtkAnchorType ControlPoint::_anchor() const +{ + GtkAnchorType ret; + g_object_get(_canvas_item, "anchor", &ret, NULL); + return ret; +} + +Glib::RefPtr ControlPoint::_pixbuf() +{ + GdkPixbuf *ret; + g_object_get(_canvas_item, "pixbuf", &ret, NULL); + return Glib::wrap(ret); +} + +// Same for setters. + +void ControlPoint::_setSize(unsigned int size) +{ + g_object_set(_canvas_item, "size", (gdouble) size, NULL); +} + +void ControlPoint::_setShape(SPCtrlShapeType shape) +{ + g_object_set(_canvas_item, "shape", shape, NULL); +} + +void ControlPoint::_setAnchor(GtkAnchorType anchor) +{ + g_object_set(_canvas_item, "anchor", anchor, NULL); +} + +void ControlPoint::_setPixbuf(Glib::RefPtr p) +{ + g_object_set(_canvas_item, "pixbuf", Glib::unwrap(p), NULL); +} + +// re-routes events into the virtual function +int ControlPoint::_event_handler(SPCanvasItem *item, GdkEvent *event, ControlPoint *point) +{ + return point->_eventHandler(event) ? TRUE : FALSE; +} + +// main event callback, which emits all other callbacks. +bool ControlPoint::_eventHandler(GdkEvent *event) +{ + // NOTE the static variables below are shared for all points! + + // offset from the pointer hotspot to the center of the grabbed knot in desktop coords + static Geom::Point pointer_offset; + // number of last doubleclicked button, to be + static unsigned next_release_doubleclick = 0; + + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + int drag_tolerance = prefs->getIntLimited("/options/dragtolerance/value", 0, 0, 100); + + switch(event->type) + { + case GDK_2BUTTON_PRESS: + // store the button number for next release + next_release_doubleclick = event->button.button; + return true; + + case GDK_BUTTON_PRESS: + next_release_doubleclick = 0; + if (event->button.button == 1) { + // mouse click. internally, start dragging, but do not emit signals + // or change position until drag tolerance is exceeded. + _drag_event_origin[Geom::X] = event->button.x; + _drag_event_origin[Geom::Y] = event->button.y; + pointer_offset = _position - _desktop->w2d(_drag_event_origin); + _drag_initiated = false; + // route all events to this handler + sp_canvas_item_grab(_canvas_item, _grab_event_mask, NULL, event->button.time); + _event_grab = true; + _setState(STATE_CLICKED); + } + return true; + + case GDK_MOTION_NOTIFY: + if (held_button<1>(event->motion) && !_desktop->event_context->space_panning) { + bool transferred = false; + if (!_drag_initiated) { + bool t = fabs(event->motion.x - _drag_event_origin[Geom::X]) <= drag_tolerance && + fabs(event->motion.y - _drag_event_origin[Geom::Y]) <= drag_tolerance; + if (t) return true; + + // if we are here, it means the tolerance was just exceeded. + next_release_doubleclick = 0; + _drag_origin = _position; + transferred = signal_grabbed.emit(&event->motion); + // _drag_initiated might change during the above signal emission + if (!_drag_initiated) { + // this guarantees smooth redraws while dragging + sp_canvas_force_full_redraw_after_interruptions(_desktop->canvas, 5); + _drag_initiated = true; + } + } + if (transferred) return true; + // the point was moved beyond the drag tolerance + Geom::Point new_pos = _desktop->w2d(event_point(event->motion)) + pointer_offset; + + // the new position is passed by reference and can be changed in the handlers. + signal_dragged.emit(_position, new_pos, &event->motion); + move(new_pos); + _updateDragTip(&event->motion); // update dragging tip after moving to new position + + _desktop->scroll_to_point(new_pos); + _desktop->set_coordinate_status(_position); + return true; + } + break; + + case GDK_BUTTON_RELEASE: + if (_event_grab) { + sp_canvas_item_ungrab(_canvas_item, event->button.time); + _setMouseover(this, event->button.state); + _event_grab = false; + + if (_drag_initiated) { + sp_canvas_end_forced_full_redraws(_desktop->canvas); + } + + if (event->button.button == next_release_doubleclick) { + _drag_initiated = false; + return signal_doubleclicked.emit(&event->button); + } + if (event->button.button == 1) { + if (_drag_initiated) { + // it is the end of a drag + signal_ungrabbed.emit(&event->button); + _drag_initiated = false; + return true; + } else { + // it is the end of a click + return signal_clicked.emit(&event->button); + } + } + _drag_initiated = false; + } + break; + + case GDK_ENTER_NOTIFY: + _setMouseover(this, event->crossing.state); + return true; + case GDK_LEAVE_NOTIFY: + _clearMouseover(); + return true; + + case GDK_GRAB_BROKEN: + if (!event->grab_broken.keyboard && _event_grab) { + { + signal_ungrabbed.emit(0); + if (_drag_initiated) + sp_canvas_end_forced_full_redraws(_desktop->canvas); + } + _setState(STATE_NORMAL); + _event_grab = false; + _drag_initiated = false; + return true; + } + break; + + // update tips on modifier state change + case GDK_KEY_PRESS: + case GDK_KEY_RELEASE: + if (mouseovered_point != this) return false; + if (_drag_initiated) { + return true; // this prevents the tool from overwriting the drag tip + } else { + unsigned state = state_after_event(event); + if (state != event->key.state) { + // we need to return true if there was a tip available, otherwise the tool's + // handler will process this event and set the tool's message, overwriting + // the point's message + return _updateTip(state); + } + } + break; + + default: break; + } + + return false; +} + +void ControlPoint::_setMouseover(ControlPoint *p, unsigned state) +{ + bool visible = p->visible(); + if (visible) { // invisible points shouldn't get mouseovered + p->_setState(STATE_MOUSEOVER); + } + p->_updateTip(state); + + if (visible && mouseovered_point != p) { + mouseovered_point = p; + signal_mouseover_change.emit(mouseovered_point); + } +} + +bool ControlPoint::_updateTip(unsigned state) +{ + Glib::ustring tip = _getTip(state); + if (!tip.empty()) { + _desktop->event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, + tip.data()); + return true; + } else { + _desktop->event_context->defaultMessageContext()->clear(); + return false; + } +} + +bool ControlPoint::_updateDragTip(GdkEventMotion *event) +{ + if (!_hasDragTips()) return false; + Glib::ustring tip = _getDragTip(event); + if (!tip.empty()) { + _desktop->event_context->defaultMessageContext()->set(Inkscape::NORMAL_MESSAGE, + tip.data()); + return true; + } else { + _desktop->event_context->defaultMessageContext()->clear(); + return false; + } +} + +void ControlPoint::_clearMouseover() +{ + if (mouseovered_point) { + mouseovered_point->_desktop->event_context->defaultMessageContext()->clear(); + mouseovered_point->_setState(STATE_NORMAL); + mouseovered_point = 0; + signal_mouseover_change.emit(mouseovered_point); + } +} + +/** Transfer the grab to another point. This method allows one to create a draggable point + * that should be dragged instead of the one that received the grabbed signal. + * This is used to implement dragging out handles in the new node tool, for example. + * + * This method will NOT emit the ungrab signal of @c prev_point, because this would complicate + * using it with selectable control points. If you use this method while dragging, you must emit + * the ungrab signal yourself. + * + * Note that this will break horribly if you try to transfer grab between points in different + * desktops, which doesn't make much sense anyway. */ +void ControlPoint::transferGrab(ControlPoint *prev_point, GdkEventMotion *event) +{ + if (!_event_grab) return; + + signal_grabbed.emit(event); + sp_canvas_item_ungrab(prev_point->_canvas_item, event->time); + sp_canvas_item_grab(_canvas_item, _grab_event_mask, NULL, event->time); + + if (!_drag_initiated) { + sp_canvas_force_full_redraw_after_interruptions(_desktop->canvas, 5); + _drag_initiated = true; + } + + prev_point->_setState(STATE_NORMAL); + _setMouseover(this, event->state); +} + +/** + * @brief Change the state of the knot + * Alters the appearance of the knot to match one of the states: normal, mouseover + * or clicked. + */ +void ControlPoint::_setState(State state) +{ + ColorEntry current = {0, 0}; + switch(state) { + case STATE_NORMAL: + current = _cset->normal; break; + case STATE_MOUSEOVER: + current = _cset->mouseover; break; + case STATE_CLICKED: + current = _cset->clicked; break; + }; + _setColors(current); + _state = state; +} +void ControlPoint::_setColors(ColorEntry colors) +{ + g_object_set(_canvas_item, "fill_color", colors.fill, "stroke_color", colors.stroke, NULL); +} + +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/tool/control-point.h b/src/ui/tool/control-point.h new file mode 100644 index 000000000..c4b0a42be --- /dev/null +++ b/src/ui/tool/control-point.h @@ -0,0 +1,167 @@ +/** @file + * Desktop-bound visual control object + */ +/* Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2009 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_UI_TOOL_CONTROL_POINT_H +#define SEEN_UI_TOOL_CONTROL_POINT_H + +#include +#include +#include +#include +#include <2geom/point.h> + +#include "display/display-forward.h" +#include "forward.h" +#include "util/accumulators.h" +#include "display/sodipodi-ctrl.h" + +namespace Inkscape { +namespace UI { + +// most of the documentation is in the .cpp file + +class ControlPoint : boost::noncopyable, public sigc::trackable { +public: + typedef Inkscape::Util::ReverseInterruptible RInt; + typedef Inkscape::Util::Interruptible Int; + // these have to be public, because GCC doesn't allow protected types in constructors, + // even if the constructors are protected themselves. + struct ColorEntry { + guint32 fill; + guint32 stroke; + }; + struct ColorSet { + ColorEntry normal; + ColorEntry mouseover; + ColorEntry clicked; + }; + enum State { + STATE_NORMAL, + STATE_MOUSEOVER, + STATE_CLICKED + }; + + virtual ~ControlPoint(); + + /// @name Adjust the position of the control point + /// @{ + /** Current position of the control point. */ + Geom::Point const &position() const { return _position; } + operator Geom::Point const &() { return _position; } + virtual void move(Geom::Point const &pos); + virtual void setPosition(Geom::Point const &pos); + virtual void transform(Geom::Matrix const &m); + /// @} + + /// @name Toggle the point's visibility + /// @{ + bool visible() const; + virtual void setVisible(bool v); + /// @} + + /// @name Transfer grab from another event handler + /// @{ + void transferGrab(ControlPoint *from, GdkEventMotion *event); + /// @} + + /// @name Receive notifications about control point events + /// @{ + sigc::signal signal_dragged; + sigc::signal::accumulated signal_clicked; + sigc::signal::accumulated signal_doubleclicked; + sigc::signal::accumulated signal_grabbed; + sigc::signal signal_ungrabbed; + /// @} + + /// @name Inspect the state of the control point + /// @{ + State state() { return _state; } + bool mouseovered() { return this == mouseovered_point; } + /// @} + + static ControlPoint *mouseovered_point; + static sigc::signal signal_mouseover_change; + static Glib::ustring format_tip(char const *format, ...) G_GNUC_PRINTF(1,2); + +protected: + ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, Gtk::AnchorType anchor, + SPCtrlShapeType shape, unsigned int size, ColorSet *cset = 0, SPCanvasGroup *group = 0); + ControlPoint(SPDesktop *d, Geom::Point const &initial_pos, Gtk::AnchorType anchor, + Glib::RefPtr pixbuf, ColorSet *cset = 0, SPCanvasGroup *group = 0); + + /// @name Manipulate the control point's appearance in subclasses + /// @{ + virtual void _setState(State state); + void _setColors(ColorEntry c); + + unsigned int _size() const; + SPCtrlShapeType _shape() const; + GtkAnchorType _anchor() const; + Glib::RefPtr _pixbuf(); + + void _setSize(unsigned int size); + void _setShape(SPCtrlShapeType shape); + void _setAnchor(GtkAnchorType anchor); + void _setPixbuf(Glib::RefPtr); + /// @} + + virtual bool _eventHandler(GdkEvent *event); + virtual Glib::ustring _getTip(unsigned state) { return ""; } + virtual Glib::ustring _getDragTip(GdkEventMotion *event) { return ""; } + virtual bool _hasDragTips() { return false; } + + SPDesktop *const _desktop; ///< The desktop this control point resides on. + SPCanvasItem * _canvas_item; ///< Visual representation of the control point. + ColorSet *_cset; ///< Describes the colors used to represent the point + State _state; + + static int const _grab_event_mask; + static Geom::Point const &_last_click_event_point() { return _drag_event_origin; } + static Geom::Point const &_last_drag_origin() { return _drag_origin; } + +private: + ControlPoint(ControlPoint const &other); + void operator=(ControlPoint const &other); + + static int _event_handler(SPCanvasItem *item, GdkEvent *event, ControlPoint *point); + static void _setMouseover(ControlPoint *, unsigned state); + static void _clearMouseover(); + bool _updateTip(unsigned state); + bool _updateDragTip(GdkEventMotion *event); + void _setDefaultColors(); + void _commonInit(); + + Geom::Point _position; ///< Current position in desktop coordinates + gulong _event_handler_connection; + + static Geom::Point _drag_event_origin; + static Geom::Point _drag_origin; + static bool _event_grab; + static bool _drag_initiated; +}; + +extern ControlPoint::ColorSet invisible_cset; + + +} // namespace UI +} // 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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/tool/curve-drag-point.cpp b/src/ui/tool/curve-drag-point.cpp new file mode 100644 index 000000000..889e245c6 --- /dev/null +++ b/src/ui/tool/curve-drag-point.cpp @@ -0,0 +1,185 @@ +/** @file + * Control point that is dragged during path drag + */ +/* Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2009 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include <2geom/bezier-curve.h> +#include "desktop.h" +#include "ui/tool/control-point-selection.h" +#include "ui/tool/curve-drag-point.h" +#include "ui/tool/event-utils.h" +#include "ui/tool/multi-path-manipulator.h" +#include "ui/tool/path-manipulator.h" +#include "ui/tool/node.h" + +namespace Inkscape { +namespace UI { + +/** + * @class CurveDragPoint + * An invisible point used to drag curves. This point is used by PathManipulator to allow editing + * of path segments by dragging them. It is defined in a separate file so that the node tool + * can check if the mouseovered control point is a curve drag point and update the cursor + * accordingly, without the need to drag in the full PathManipulator header. + */ + +// This point should be invisible to the user - use the invisible_cset from control-point.h +// TODO make some methods from path-manipulator.cpp public so that this point doesn't have +// to be declared as a friend + +bool CurveDragPoint::_drags_stroke = false; + +CurveDragPoint::CurveDragPoint(PathManipulator &pm) + : ControlPoint(pm._path_data.node_data.desktop, Geom::Point(), Gtk::ANCHOR_CENTER, + SP_CTRL_SHAPE_CIRCLE, 1.0, &invisible_cset, pm._path_data.dragpoint_group) + , _pm(pm) +{ + setVisible(false); + signal_grabbed.connect( + sigc::bind_return( + sigc::mem_fun(*this, &CurveDragPoint::_grabbedHandler), + false)); + signal_dragged.connect( + sigc::hide( + sigc::mem_fun(*this, &CurveDragPoint::_draggedHandler))); + signal_ungrabbed.connect( + sigc::hide( + sigc::mem_fun(*this, &CurveDragPoint::_ungrabbedHandler))); + signal_clicked.connect( + sigc::mem_fun(*this, &CurveDragPoint::_clickedHandler)); + signal_doubleclicked.connect( + sigc::mem_fun(*this, &CurveDragPoint::_doubleclickedHandler)); +} + +void CurveDragPoint::_grabbedHandler(GdkEventMotion *event) +{ + _pm._selection.hideTransformHandles(); + NodeList::iterator second = first.next(); + + // move the handles to 1/3 the length of the segment for line segments + if (first->front()->isDegenerate() && second->back()->isDegenerate()) { + + // delta is a vector equal 1/3 of distance from first to second + Geom::Point delta = (second->position() - first->position()) / 3.0; + first->front()->move(first->front()->position() + delta); + second->back()->move(second->back()->position() - delta); + + signal_update.emit(); + } +} + +void CurveDragPoint::_draggedHandler(Geom::Point const &old_pos, Geom::Point const &new_pos) +{ + if (_drags_stroke) { + // TODO + } else { + NodeList::iterator second = first.next(); + // Magic Bezier Drag Equations follow! + // "weight" describes how the influence of the drag should be distributed + // among the handles; 0 = front handle only, 1 = back handle only. + double weight, t = _t; + if (t <= 1.0 / 6.0) weight = 0; + else if (t <= 0.5) weight = (pow((6 * t - 1) / 2.0, 3)) / 2; + else if (t <= 5.0 / 6.0) weight = (1 - pow((6 * (1-t) - 1) / 2.0, 3)) / 2 + 0.5; + else weight = 1; + + Geom::Point delta = new_pos - old_pos; + Geom::Point offset0 = ((1-weight)/(3*t*(1-t)*(1-t))) * delta; + Geom::Point offset1 = (weight/(3*t*t*(1-t))) * delta; + + first->front()->move(first->front()->position() + offset0); + second->back()->move(second->back()->position() + offset1); + } + + signal_update.emit(); +} + +void CurveDragPoint::_ungrabbedHandler() +{ + _pm._updateDragPoint(_desktop->d2w(position())); + _pm._commit(_("Drag curve")); + _pm._selection.restoreTransformHandles(); +} + +bool CurveDragPoint::_clickedHandler(GdkEventButton *event) +{ + // This check is probably redundant + if (!first || event->button != 1) return false; + // the next iterator can be invalid if we click very near the end of path + NodeList::iterator second = first.next(); + if (!second) return false; + + if (held_shift(*event)) { + // if both nodes of the segment are selected, deselect; + // otherwise add to selection + if (first->selected() && second->selected()) { + _pm._selection.erase(first.ptr()); + _pm._selection.erase(second.ptr()); + } else { + _pm._selection.insert(first.ptr()); + _pm._selection.insert(second.ptr()); + } + } else { + // without Shift, take selection + _pm._selection.clear(); + _pm._selection.insert(first.ptr()); + _pm._selection.insert(second.ptr()); + } + return true; +} + +bool CurveDragPoint::_doubleclickedHandler(GdkEventButton *event) +{ + if (event->button != 1 || !first || !first.next()) return false; + + // The purpose of this call is to make way for the just created node. + // Otherwise clicks on the new node would only work after the user moves the mouse a bit. + // PathManipulator will restore visibility when necessary. + setVisible(false); + NodeList::iterator inserted = _pm.subdivideSegment(first, _t); + _pm._selection.clear(); + _pm._selection.insert(inserted.ptr()); + + signal_update.emit(); + _pm._commit(_("Add node")); + return true; +} + +Glib::ustring CurveDragPoint::_getTip(unsigned state) +{ + if (!first || !first.next()) return NULL; + bool linear = first->front()->isDegenerate() && first.next()->back()->isDegenerate(); + if (state_held_shift(state)) { + return C_("Path segment statusbar tip", + "Shift: click to toggle segment selection"); + } + if (linear) { + return C_("Path segment statusbar tip", + "Linear segment: drag to convert to a Bezier segment, " + "doubleclick to insert node, click to select this segment"); + } else { + return C_("Path segment statusbar tip", + "Bezier segment: drag to shape the segment, doubleclick to insert node, " + "click to select this segment"); + } +} + +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/tool/curve-drag-point.h b/src/ui/tool/curve-drag-point.h new file mode 100644 index 000000000..c9f32f709 --- /dev/null +++ b/src/ui/tool/curve-drag-point.h @@ -0,0 +1,60 @@ +/** @file + * Control point that is dragged during path drag + */ +/* Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2009 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_UI_TOOL_CURVE_DRAG_POINT_H +#define SEEN_UI_TOOL_CURVE_DRAG_POINT_H + +#include "ui/tool/control-point.h" +#include "ui/tool/node.h" + +class SPDesktop; +namespace Inkscape { +namespace UI { + +class PathManipulator; +struct PathSharedData; + +class CurveDragPoint : public ControlPoint { +public: + CurveDragPoint(PathManipulator &pm); + void setSize(double sz) { _setSize(sz); } + void setTimeValue(double t) { _t = t; } + void setIterator(NodeList::iterator i) { first = i; } + sigc::signal signal_update; +protected: + virtual Glib::ustring _getTip(unsigned state); +private: + void _grabbedHandler(GdkEventMotion *); + void _draggedHandler(Geom::Point const &, Geom::Point const &); + bool _clickedHandler(GdkEventButton *); + bool _doubleclickedHandler(GdkEventButton *); + void _ungrabbedHandler(); + double _t; + PathManipulator &_pm; + NodeList::iterator first; + static bool _drags_stroke; + static Geom::Point _stroke_drag_origin; +}; + +} // namespace UI +} // 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:encoding=utf-8:textwidth=99 : diff --git a/src/ui/tool/event-utils.cpp b/src/ui/tool/event-utils.cpp new file mode 100644 index 000000000..6912897da --- /dev/null +++ b/src/ui/tool/event-utils.cpp @@ -0,0 +1,113 @@ +/** @file + * Collection of shorthands to deal with GDK events. + */ +/* Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2009 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#include +#include +#include "ui/tool/event-utils.h" + +namespace Inkscape { +namespace UI { + + +guint shortcut_key(GdkEventKey const &event) +{ + guint shortcut_key = 0; + gdk_keymap_translate_keyboard_state( + gdk_keymap_get_for_display(gdk_display_get_default()), + event.hardware_keycode, + (GdkModifierType) event.state, + 0 /*event->key.group*/, + &shortcut_key, NULL, NULL, NULL); + return shortcut_key; +} + +unsigned consume_same_key_events(guint keyval, gint mask) +{ + GdkEvent *event_next; + gint i = 0; + + event_next = gdk_event_get(); + // while the next event is also a key notify with the same keyval and mask, + while (event_next && (event_next->type == GDK_KEY_PRESS || event_next->type == GDK_KEY_RELEASE) + && event_next->key.keyval == keyval + && (!mask || (event_next->key.state & mask))) { + if (event_next->type == GDK_KEY_PRESS) + i ++; + // kill it + gdk_event_free(event_next); + // get next + event_next = gdk_event_get(); + } + // otherwise, put it back onto the queue + if (event_next) gdk_event_put(event_next); + + return i; +} + +/** Returns the modifier state valid after this event. Use this when you process events + * that change the modifier state. Currently handles only Shift, Ctrl, Alt. */ +unsigned state_after_event(GdkEvent *event) +{ + unsigned state = 0; + switch (event->type) { + case GDK_KEY_PRESS: + state = event->key.state; + switch(shortcut_key(event->key)) { + case GDK_Shift_L: + case GDK_Shift_R: + state |= GDK_SHIFT_MASK; + break; + case GDK_Control_L: + case GDK_Control_R: + state |= GDK_CONTROL_MASK; + break; + case GDK_Alt_L: + case GDK_Alt_R: + state |= GDK_MOD1_MASK; + break; + default: break; + } + break; + case GDK_KEY_RELEASE: + state = event->key.state; + switch(shortcut_key(event->key)) { + case GDK_Shift_L: + case GDK_Shift_R: + state &= ~GDK_SHIFT_MASK; + break; + case GDK_Control_L: + case GDK_Control_R: + state &= ~GDK_CONTROL_MASK; + break; + case GDK_Alt_L: + case GDK_Alt_R: + state &= ~GDK_MOD1_MASK; + break; + default: break; + } + break; + default: break; + } + return state; +} + +} // namespace UI +} // namespace Inkscape + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 : diff --git a/src/ui/tool/event-utils.h b/src/ui/tool/event-utils.h new file mode 100644 index 000000000..74907d61c --- /dev/null +++ b/src/ui/tool/event-utils.h @@ -0,0 +1,129 @@ +/** @file + * Collection of shorthands to deal with GDK events. + */ +/* Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2009 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_UI_TOOL_EVENT_UTILS_H +#define SEEN_UI_TOOL_EVENT_UTILS_H + +#include +#include <2geom/point.h> + +namespace Inkscape { +namespace UI { + +inline bool state_held_shift(unsigned state) { + return state & GDK_SHIFT_MASK; +} +inline bool state_held_control(unsigned state) { + return state & GDK_CONTROL_MASK; +} +inline bool state_held_alt(unsigned state) { + return state & GDK_MOD1_MASK; +} +inline bool state_held_only_shift(unsigned state) { + return (state & GDK_SHIFT_MASK) && !(state & (GDK_CONTROL_MASK | GDK_MOD1_MASK)); +} +inline bool state_held_only_control(unsigned state) { + return (state & GDK_CONTROL_MASK) && !(state & (GDK_SHIFT_MASK | GDK_MOD1_MASK)); +} +inline bool state_held_only_alt(unsigned state) { + return (state & GDK_MOD1_MASK) && !(state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK)); +} +inline bool state_held_any_modifiers(unsigned state) { + return state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK); +} +inline bool state_held_no_modifiers(unsigned state) { + return !state_held_any_modifiers(state); +} +template +inline bool state_held_button(unsigned state) { + return (button == 0 || button > 5) ? false : state & (GDK_BUTTON1_MASK << (button-1)); +} + + +/** Checks whether Shift was held when the event was generated. */ +template +inline bool held_shift(E const &event) { + return state_held_shift(event.state); +} + +/** Checks whether Control was held when the event was generated. */ +template +inline bool held_control(E const &event) { + return state_held_control(event.state); +} + +/** Checks whether Alt was held when the event was generated. */ +template +inline bool held_alt(E const &event) { + return state_held_alt(event.state); +} + +/** True if from the set of Ctrl, Shift and Alt only Ctrl was held when the event + * was generated. */ +template +inline bool held_only_control(E const &event) { + return state_held_only_control(event.state); +} + +/** True if from the set of Ctrl, Shift and Alt only Shift was held when the event + * was generated. */ +template +inline bool held_only_shift(E const &event) { + return state_held_only_shift(event.state); +} + +/** True if from the set of Ctrl, Shift and Alt only Alt was held when the event + * was generated. */ +template +inline bool held_only_alt(E const &event) { + return state_held_only_alt(event.state); +} + +template +inline bool held_no_modifiers(E const &event) { + return state_held_no_modifiers(event.state); +} + +template +inline bool held_any_modifiers(E const &event) { + return state_held_any_modifiers(event.state); +} + +template +inline Geom::Point event_point(E const &event) { + return Geom::Point(event.x, event.y); +} + +/** Use like this: + * @code if (held_button<2>(event->motion)) { ... @endcode */ +template +inline bool held_button(E const &event) { + return state_held_button