summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: 1b9ce9d)
raw | patch | inline | side by side (parent: 1b9ce9d)
author | cilix42 <cilix42@users.sourceforge.net> | |
Thu, 21 Jun 2007 13:01:57 +0000 (13:01 +0000) | ||
committer | cilix42 <cilix42@users.sourceforge.net> | |
Thu, 21 Jun 2007 13:01:57 +0000 (13:01 +0000) |
26 files changed:
diff --git a/share/icons/icons.svg b/share/icons/icons.svg
index b1e578200da156fd16d4961e8f7f896cfe92ab30..a579af7194c15da18e60dabd73eac4fa8ee845c8 100644 (file)
--- a/share/icons/icons.svg
+++ b/share/icons/icons.svg
y1="154.99997"
x2="526.70886"
y2="161.71585" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4350"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.13356,0,0,1.133368,199.5737,-131.407)"
+ x1="101.09393"
+ y1="221.06877"
+ x2="112.20101"
+ y2="234.00311" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4352"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.809546,0,0,0.809417,202.9983,-4.125322)"
+ x1="144.08243"
+ y1="157.82079"
+ x2="176.86269"
+ y2="188.41277" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4362"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.13356,0,0,1.133368,195.5737,-135.407)"
+ x1="101.09393"
+ y1="221.06877"
+ x2="112.20101"
+ y2="234.00311" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4364"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.809546,0,0,0.809417,198.9983,-8.125322)"
+ x1="144.08243"
+ y1="157.82079"
+ x2="176.86269"
+ y2="188.41277" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4952"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.13356,0,0,1.133368,339.5737,-131.407)"
+ x1="101.09393"
+ y1="221.06877"
+ x2="112.20101"
+ y2="234.00311" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4954"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.809546,0,0,0.809417,342.9983,-4.125322)"
+ x1="144.08243"
+ y1="157.82079"
+ x2="176.86269"
+ y2="188.41277" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4978"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.13356,0,0,1.133368,195.5737,-135.407)"
+ x1="101.09393"
+ y1="221.06877"
+ x2="112.20101"
+ y2="234.00311" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4980"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.809546,0,0,0.809417,198.9983,-8.125322)"
+ x1="144.08243"
+ y1="157.82079"
+ x2="176.86269"
+ y2="188.41277" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4982"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.13356,0,0,1.133368,339.5737,-131.407)"
+ x1="101.09393"
+ y1="221.06877"
+ x2="112.20101"
+ y2="234.00311" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4985"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.809546,0,0,0.809417,342.9983,-4.125322)"
+ x1="144.08243"
+ y1="157.82079"
+ x2="176.86269"
+ y2="188.41277" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4991"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.13356,0,0,1.133368,339.5737,-131.407)"
+ x1="101.09393"
+ y1="221.06877"
+ x2="112.20101"
+ y2="234.00311" />
+ <linearGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5740"
+ id="linearGradient4993"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0.809546,0,0,0.809417,342.9983,-4.125322)"
+ x1="144.08243"
+ y1="157.82079"
+ x2="176.86269"
+ y2="188.41277" />
</defs>
<sodipodi:namedview
inkscape:guide-bbox="true"
inkscape:window-x="6"
inkscape:window-height="764"
inkscape:window-width="1021"
- inkscape:cy="860.52734"
- inkscape:cx="563.9888"
- inkscape:zoom="0.71599583"
+ inkscape:cy="1119.1738"
+ inkscape:cx="696.90117"
+ inkscape:zoom="4.050284"
gridtolerance="6"
snaptogrid="false"
showgrid="true"
guidetolerance="0.50000000px"
gridempspacing="2"
fill="#8ab3de"
- stroke="#646464" />
+ stroke="#646464"
+ inkscape:object-nodes="true"
+ objecttolerance="11" />
<metadata
id="metadata1810">
<rdf:RDF>
@@ -14854,4 +14976,115 @@ http://www.inkscape.org/</dc:description>
d="M 504.50005,157.49995 L 515.50005,157.49995 L 511.50005,152.49995 L 500.50005,152.49995 L 504.50005,157.49995 z"
style="opacity:1;color:#000000;fill:url(#linearGradient9119);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient9121);stroke-width:1;stroke-linecap:square;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" />
</g>
+ <g
+ id="draw_3dbox">
+ <g
+ transform="translate(144,4)"
+ id="g4354">
+ <rect
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline"
+ id="rect4356"
+ width="24"
+ height="24"
+ x="450"
+ y="115" />
+ <rect
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline"
+ id="rect4358"
+ width="18.991669"
+ height="18.991783"
+ x="452.50833"
+ y="117.50822" />
+ <rect
+ style="color:#000000;fill:url(#linearGradient4978);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4980);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline"
+ id="rect4360"
+ width="17"
+ height="17"
+ x="453.5"
+ y="118.5" />
+ </g>
+ <rect
+ y="115"
+ x="590"
+ height="24"
+ width="24"
+ id="rect4344"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" />
+ <rect
+ y="117.50822"
+ x="592.5083"
+ height="18.991783"
+ width="18.991669"
+ id="rect4346"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" />
+ <rect
+ y="118.5"
+ x="593.5"
+ height="17"
+ width="17"
+ id="rect4348"
+ style="color:#000000;fill:url(#linearGradient4991);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient4993);stroke-width:0.99999982;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:0;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4960"
+ d="M 611.49997,117.50822 L 615.5,121.50822"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4962"
+ d="M 611.49997,117.50822 L 615.5,121.50822"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path4964"
+ d="M 592.5083,136.5 L 596.50833,140.5"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path5001"
+ d="M 611.49997,136.5 L 615.5,140.5"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ </g>
+ <g
+ id="toggle_vp_x"
+ transform="matrix(1,0,0,1.0907248,0,-12.901177)">
+ <path
+ sodipodi:nodetypes="cc"
+ d="M 646.36929,119.70888 L 646.36929,140.20127"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.83003211;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4997" />
+ <path
+ sodipodi:nodetypes="cc"
+ d="M 653.38169,119.70888 L 653.38169,140.20127"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.83003211;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4979" />
+ </g>
+ <g
+ id="toggle_vp_y"
+ transform="matrix(1,0,0,1.0907248,40,-12.901177)">
+ <path
+ sodipodi:nodetypes="cc"
+ d="M 646.36929,119.70888 L 646.36929,140.20127"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.83003211;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4987" />
+ <path
+ sodipodi:nodetypes="cc"
+ d="M 653.38169,119.70888 L 653.38169,140.20127"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.83003211;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4989" />
+ </g>
+ <g
+ id="toggle_vp_z"
+ transform="matrix(1,0,0,1.0907248,80,-12.901177)">
+ <path
+ sodipodi:nodetypes="cc"
+ d="M 646.36929,119.70888 L 646.36929,140.20127"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.83003211;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4993" />
+ <path
+ sodipodi:nodetypes="cc"
+ d="M 653.38169,119.70888 L 653.38169,140.20127"
+ style="color:#000000;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:3.83003211;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+ id="path4995" />
+ </g>
</svg>
diff --git a/src/Makefile_insert b/src/Makefile_insert
index 9ded1945f600ad9ae59eeac9e436159c5cda502a..f1ba21920d4b60e649f96ea99dd0483440471e13 100644 (file)
--- a/src/Makefile_insert
+++ b/src/Makefile_insert
arc-context.cpp arc-context.h \
attributes.cpp attributes.h \
bad-uri-exception.h \
+ box3d.cpp box3d.h \
+ box3d-context.cpp box3d-context.h \
+ box3d-face.cpp box3d-face.h \
brokenimage.xpm \
color-rgba.h \
color-profile.cpp color-profile.h \
knotholder.cpp knotholder.h \
layer-fns.cpp layer-fns.h \
layer-manager.cpp layer-manager.h \
+ line-geometry.cpp line-geometry.h \
macros.h \
main-cmdlineact.cpp main-cmdlineact.h \
media.cpp media.h \
pen-context.h \
pencil-context.cpp \
pencil-context.h \
+ perspective-line.cpp perspective-line.h \
+ perspective3d.cpp perspective3d.h \
preferences.cpp preferences.h \
preferences-skeleton.h \
menus-skeleton.h \
text-tag-attributes.h \
tools-switch.cpp tools-switch.h\
uri-references.cpp uri-references.h \
+ vanishing-point.cpp vanishing-point.h \
verbs.cpp verbs.h \
version.cpp version.h \
zoom-context.cpp zoom-context.h
diff --git a/src/box3d-context.cpp b/src/box3d-context.cpp
--- /dev/null
+++ b/src/box3d-context.cpp
@@ -0,0 +1,608 @@
+#define __SP_3DBOX_CONTEXT_C__
+
+/*
+ * 3D box drawing context
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * bulia byak <buliabyak@users.sf.net>
+ *
+ * Copyright (C) 2007 Maximilian Albert <Anhalter42@gmx.de>
+ * Copyright (C) 2006 Johan Engelen <johan@shouraizou.nl>
+ * Copyright (C) 2000-2005 authors
+ * Copyright (C) 2000-2001 Ximian, Inc.
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "config.h"
+
+#include <gdk/gdkkeysyms.h>
+
+#include "macros.h"
+#include "display/sp-canvas.h"
+#include "document.h"
+#include "sp-namedview.h"
+#include "selection.h"
+#include "desktop-handles.h"
+#include "snap.h"
+#include "display/curve.h"
+#include "desktop.h"
+#include "message-context.h"
+#include "pixmaps/cursor-rect.xpm"
+#include "box3d.h"
+#include "box3d-context.h"
+#include "sp-metrics.h"
+#include <glibmm/i18n.h>
+#include "object-edit.h"
+#include "xml/repr.h"
+#include "xml/node-event-vector.h"
+#include "prefs-utils.h"
+#include "context-fns.h"
+
+static void sp_3dbox_context_class_init(SP3DBoxContextClass *klass);
+static void sp_3dbox_context_init(SP3DBoxContext *box3d_context);
+static void sp_3dbox_context_dispose(GObject *object);
+
+static void sp_3dbox_context_setup(SPEventContext *ec);
+static void sp_3dbox_context_set(SPEventContext *ec, gchar const *key, gchar const *val);
+
+static gint sp_3dbox_context_root_handler(SPEventContext *event_context, GdkEvent *event);
+static gint sp_3dbox_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event);
+
+static void sp_3dbox_drag(SP3DBoxContext &rc, guint state);
+static void sp_3dbox_finish(SP3DBoxContext *rc);
+
+static SPEventContextClass *parent_class;
+
+
+GtkType sp_3dbox_context_get_type()
+{
+ static GType type = 0;
+ if (!type) {
+ GTypeInfo info = {
+ sizeof(SP3DBoxContextClass),
+ NULL, NULL,
+ (GClassInitFunc) sp_3dbox_context_class_init,
+ NULL, NULL,
+ sizeof(SP3DBoxContext),
+ 4,
+ (GInstanceInitFunc) sp_3dbox_context_init,
+ NULL, /* value_table */
+ };
+ type = g_type_register_static(SP_TYPE_EVENT_CONTEXT, "SP3DBoxContext", &info, (GTypeFlags) 0);
+ }
+ return type;
+}
+
+static void sp_3dbox_context_class_init(SP3DBoxContextClass *klass)
+{
+ GObjectClass *object_class = (GObjectClass *) klass;
+ SPEventContextClass *event_context_class = (SPEventContextClass *) klass;
+
+ parent_class = (SPEventContextClass *) g_type_class_peek_parent(klass);
+
+ object_class->dispose = sp_3dbox_context_dispose;
+
+ event_context_class->setup = sp_3dbox_context_setup;
+ event_context_class->set = sp_3dbox_context_set;
+ event_context_class->root_handler = sp_3dbox_context_root_handler;
+ event_context_class->item_handler = sp_3dbox_context_item_handler;
+}
+
+Box3D::Perspective3D * SP3DBoxContext::current_perspective = NULL;
+
+static void sp_3dbox_context_init(SP3DBoxContext *box3d_context)
+{
+ SPEventContext *event_context = SP_EVENT_CONTEXT(box3d_context);
+
+ event_context->cursor_shape = cursor_rect_xpm;
+ event_context->hot_x = 4;
+ event_context->hot_y = 4;
+ event_context->xp = 0;
+ event_context->yp = 0;
+ event_context->tolerance = 0;
+ event_context->within_tolerance = false;
+ event_context->item_to_select = NULL;
+
+ event_context->shape_repr = NULL;
+ event_context->shape_knot_holder = NULL;
+
+ box3d_context->item = NULL;
+
+ box3d_context->rx = 0.0;
+ box3d_context->ry = 0.0;
+
+ box3d_context->ctrl_dragged = false;
+ box3d_context->extruded = false;
+
+ /* create an initial perspective */
+ if (!SP3DBoxContext::current_perspective) {
+ SP3DBoxContext::current_perspective = new Box3D::Perspective3D (
+ // VP in x-direction
+ Box3D::VanishingPoint( NR::Point( 50.0, 600.0),
+ NR::Point( -1.0, 0.0), Box3D::VP_INFINITE),
+ // VP in y-direction
+ Box3D::VanishingPoint( NR::Point(700.0, 500.0),
+ NR::Point(sqrt(3.0),1.0), Box3D::VP_INFINITE),
+ // VP in z-direction
+ Box3D::VanishingPoint( NR::Point(500.0,1000.0),
+ NR::Point( 0.0, 1.0), Box3D::VP_INFINITE));
+ }
+
+ new (&box3d_context->sel_changed_connection) sigc::connection();
+}
+
+static void sp_3dbox_context_dispose(GObject *object)
+{
+ SP3DBoxContext *rc = SP_3DBOX_CONTEXT(object);
+ SPEventContext *ec = SP_EVENT_CONTEXT(object);
+
+ ec->enableGrDrag(false);
+
+ rc->sel_changed_connection.disconnect();
+ rc->sel_changed_connection.~connection();
+
+ /* fixme: This is necessary because we do not grab */
+ if (rc->item) {
+ sp_3dbox_finish(rc);
+ }
+
+ if (ec->shape_knot_holder) {
+ sp_knot_holder_destroy(ec->shape_knot_holder);
+ ec->shape_knot_holder = NULL;
+ }
+
+ if (ec->shape_repr) { // remove old listener
+ sp_repr_remove_listener_by_data(ec->shape_repr, ec);
+ Inkscape::GC::release(ec->shape_repr);
+ ec->shape_repr = 0;
+ }
+
+ if (rc->_message_context) {
+ delete rc->_message_context;
+ }
+
+ G_OBJECT_CLASS(parent_class)->dispose(object);
+}
+
+static Inkscape::XML::NodeEventVector ec_shape_repr_events = {
+ NULL, /* child_added */
+ NULL, /* child_removed */
+ ec_shape_event_attr_changed,
+ NULL, /* content_changed */
+ NULL /* order_changed */
+};
+
+/**
+\brief Callback that processes the "changed" signal on the selection;
+destroys old and creates new knotholder
+*/
+void sp_3dbox_context_selection_changed(Inkscape::Selection *selection, gpointer data)
+{
+ SP3DBoxContext *rc = SP_3DBOX_CONTEXT(data);
+ SPEventContext *ec = SP_EVENT_CONTEXT(rc);
+
+ if (ec->shape_knot_holder) { // destroy knotholder
+ sp_knot_holder_destroy(ec->shape_knot_holder);
+ ec->shape_knot_holder = NULL;
+ }
+
+ if (ec->shape_repr) { // remove old listener
+ sp_repr_remove_listener_by_data(ec->shape_repr, ec);
+ Inkscape::GC::release(ec->shape_repr);
+ ec->shape_repr = 0;
+ }
+
+ SPItem *item = selection->singleItem();
+ if (item) {
+ ec->shape_knot_holder = sp_item_knot_holder(item, ec->desktop);
+ Inkscape::XML::Node *shape_repr = SP_OBJECT_REPR(item);
+ if (shape_repr) {
+ ec->shape_repr = shape_repr;
+ Inkscape::GC::anchor(shape_repr);
+ sp_repr_add_listener(shape_repr, &ec_shape_repr_events, ec);
+ }
+ }
+}
+
+static void sp_3dbox_context_setup(SPEventContext *ec)
+{
+ SP3DBoxContext *rc = SP_3DBOX_CONTEXT(ec);
+
+ if (((SPEventContextClass *) parent_class)->setup) {
+ ((SPEventContextClass *) parent_class)->setup(ec);
+ }
+
+ SPItem *item = sp_desktop_selection(ec->desktop)->singleItem();
+ if (item) {
+ ec->shape_knot_holder = sp_item_knot_holder(item, ec->desktop);
+ Inkscape::XML::Node *shape_repr = SP_OBJECT_REPR(item);
+ if (shape_repr) {
+ ec->shape_repr = shape_repr;
+ Inkscape::GC::anchor(shape_repr);
+ sp_repr_add_listener(shape_repr, &ec_shape_repr_events, ec);
+ }
+ }
+
+ rc->sel_changed_connection.disconnect();
+ rc->sel_changed_connection = sp_desktop_selection(ec->desktop)->connectChanged(
+ sigc::bind(sigc::ptr_fun(&sp_3dbox_context_selection_changed), (gpointer)rc)
+ );
+
+ sp_event_context_read(ec, "rx");
+ sp_event_context_read(ec, "ry");
+
+ if (prefs_get_int_attribute("tools.shapes", "selcue", 0) != 0) {
+ ec->enableSelectionCue();
+ }
+
+ if (prefs_get_int_attribute("tools.shapes", "gradientdrag", 0) != 0) {
+ ec->enableGrDrag();
+ }
+
+ rc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack());
+}
+
+static void sp_3dbox_context_set(SPEventContext *ec, gchar const *key, gchar const *val)
+{
+ SP3DBoxContext *rc = SP_3DBOX_CONTEXT(ec);
+
+ /* fixme: Proper error handling for non-numeric data. Use a locale-independent function like
+ * g_ascii_strtod (or a thin wrapper that does the right thing for invalid values inf/nan). */
+ if ( strcmp(key, "rx") == 0 ) {
+ rc->rx = ( val
+ ? g_ascii_strtod (val, NULL)
+ : 0.0 );
+ } else if ( strcmp(key, "ry") == 0 ) {
+ rc->ry = ( val
+ ? g_ascii_strtod (val, NULL)
+ : 0.0 );
+ }
+}
+
+static gint sp_3dbox_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event)
+{
+ SPDesktop *desktop = event_context->desktop;
+
+ gint ret = FALSE;
+
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+ if ( event->button.button == 1 ) {
+ Inkscape::setup_for_drag_start(desktop, event_context, event);
+ ret = TRUE;
+ }
+ break;
+ // motion and release are always on root (why?)
+ default:
+ break;
+ }
+
+ if (((SPEventContextClass *) parent_class)->item_handler) {
+ ret = ((SPEventContextClass *) parent_class)->item_handler(event_context, item, event);
+ }
+
+ return ret;
+}
+
+static gint sp_3dbox_context_root_handler(SPEventContext *event_context, GdkEvent *event)
+{
+ static bool dragging;
+
+ SPDesktop *desktop = event_context->desktop;
+ Inkscape::Selection *selection = sp_desktop_selection (desktop);
+
+ SP3DBoxContext *rc = SP_3DBOX_CONTEXT(event_context);
+
+ event_context->tolerance = prefs_get_int_attribute_limited("options.dragtolerance", "value", 0, 0, 100);
+
+ gint ret = FALSE;
+ switch (event->type) {
+ case GDK_BUTTON_PRESS:
+ if ( event->button.button == 1 ) {
+ NR::Point const button_w(event->button.x,
+ event->button.y);
+
+ // save drag origin
+ event_context->xp = (gint) button_w[NR::X];
+ event_context->yp = (gint) button_w[NR::Y];
+ event_context->within_tolerance = true;
+
+ // remember clicked item, disregarding groups, honoring Alt
+ event_context->item_to_select = sp_event_context_find_item (desktop, button_w, event->button.state & GDK_MOD1_MASK, TRUE);
+
+ dragging = true;
+
+ /* Position center */
+ NR::Point const button_dt(desktop->w2d(button_w));
+ rc->drag_origin = button_dt;
+ rc->drag_ptB = button_dt;
+ rc->drag_ptC = button_dt;
+
+ /* Snap center */
+ SnapManager const &m = desktop->namedview->snap_manager;
+ rc->center = m.freeSnap(Inkscape::Snapper::SNAP_POINT | Inkscape::Snapper::BBOX_POINT,
+ button_dt, rc->item).getPoint();
+
+ sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate),
+ ( GDK_KEY_PRESS_MASK |
+ GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK |
+ GDK_BUTTON_PRESS_MASK ),
+ NULL, event->button.time);
+ ret = TRUE;
+ }
+ break;
+ case GDK_MOTION_NOTIFY:
+ if ( dragging
+ && ( event->motion.state & GDK_BUTTON1_MASK ) )
+ {
+ if ( event_context->within_tolerance
+ && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance )
+ && ( abs( (gint) event->motion.y - event_context->yp ) < event_context->tolerance ) ) {
+ break; // do not drag if we're within tolerance from origin
+ }
+ // Once the user has moved farther than tolerance from the original location
+ // (indicating they intend to draw, not click), then always process the
+ // motion notify coordinates as given (no snapping back to origin)
+ event_context->within_tolerance = false;
+
+ NR::Point const motion_w(event->motion.x,
+ event->motion.y);
+ NR::Point motion_dt(desktop->w2d(motion_w));
+
+ SnapManager const &m = desktop->namedview->snap_manager;
+ motion_dt = m.freeSnap(Inkscape::Snapper::BBOX_POINT | Inkscape::Snapper::SNAP_POINT, motion_dt, rc->item).getPoint();
+
+ rc->ctrl_dragged = event->motion.state & GDK_CONTROL_MASK;
+
+ if (event->motion.state & GDK_SHIFT_MASK)
+ rc->extruded = true; // set rc->extruded once shift is pressed
+
+ if (!rc->extruded) {
+ rc->drag_ptB = motion_dt;
+ } else {
+ // Without Ctrl, motion of the extruded corner is constrained to the
+ // perspective line from drag_ptB to vanishing point Y.
+ if (!rc->ctrl_dragged) {
+ rc->drag_ptC = Box3D::perspective_line_snap (rc->drag_ptB, Box3D::Y, motion_dt);
+ } else {
+ rc->drag_ptC = motion_dt;
+ }
+ rc->drag_ptC = m.freeSnap(Inkscape::Snapper::BBOX_POINT | Inkscape::Snapper::SNAP_POINT, rc->drag_ptC, rc->item).getPoint();
+ if (rc->ctrl_dragged) {
+ Box3D::PerspectiveLine pl1 (NR::Point (event_context->xp, event_context->yp), Box3D::Z);
+ Box3D::PerspectiveLine pl2 (rc->drag_ptB, Box3D::X);
+ NR::Point corner1 = pl1.meet(pl2);
+
+ Box3D::PerspectiveLine pl3 (corner1, Box3D::X);
+ Box3D::PerspectiveLine pl4 (rc->drag_ptC, Box3D::Y);
+ rc->drag_ptB = pl3.meet(pl4);
+ }
+ }
+
+
+ sp_3dbox_drag(*rc, event->motion.state);
+
+ ret = TRUE;
+ }
+ ret = TRUE;
+ break;
+ case GDK_BUTTON_RELEASE:
+ event_context->xp = event_context->yp = 0;
+ if ( event->button.button == 1 ) {
+ dragging = false;
+
+ if (!event_context->within_tolerance) {
+ // we've been dragging, finish the rect
+ sp_3dbox_finish(rc);
+ } else if (event_context->item_to_select) {
+ // no dragging, select clicked item if any
+ if (event->button.state & GDK_SHIFT_MASK) {
+ selection->toggle(event_context->item_to_select);
+ } else {
+ selection->set(event_context->item_to_select);
+ }
+ } else {
+ // click in an empty space
+ selection->clear();
+ }
+
+ event_context->item_to_select = NULL;
+ ret = TRUE;
+ sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate),
+ event->button.time);
+ }
+ break;
+ case GDK_KEY_PRESS:
+ switch (get_group0_keyval (&event->key)) {
+ case GDK_Alt_L:
+ case GDK_Alt_R:
+ case GDK_Control_L:
+ case GDK_Control_R:
+ case GDK_Shift_L:
+ case GDK_Shift_R:
+ case GDK_Meta_L: // Meta is when you press Shift+Alt (at least on my machine)
+ case GDK_Meta_R:
+ if (!dragging){
+ sp_event_show_modifier_tip (event_context->defaultMessageContext(), event,
+ _("<b>Ctrl</b>: make square or integer-ratio rect, lock a rounded corner circular"),
+ _("<b>Shift</b>: draw around the starting point"),
+ NULL);
+ }
+ break;
+ case GDK_Up:
+ case GDK_Down:
+ case GDK_KP_Up:
+ case GDK_KP_Down:
+ // prevent the zoom field from activation
+ if (!MOD__CTRL_ONLY)
+ ret = TRUE;
+ break;
+
+ case GDK_x:
+ case GDK_X:
+ if (MOD__ALT_ONLY) {
+ desktop->setToolboxFocusTo ("altx-rect");
+ ret = TRUE;
+ }
+ break;
+
+ case GDK_Escape:
+ sp_desktop_selection(desktop)->clear();
+ //TODO: make dragging escapable by Esc
+ break;
+
+ case GDK_space:
+ if (dragging) {
+ sp_canvas_item_ungrab(SP_CANVAS_ITEM(desktop->acetate),
+ event->button.time);
+ dragging = false;
+ if (!event_context->within_tolerance) {
+ // we've been dragging, finish the rect
+ sp_3dbox_finish(rc);
+ }
+ // do not return true, so that space would work switching to selector
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+ case GDK_KEY_RELEASE:
+ switch (get_group0_keyval (&event->key)) {
+ case GDK_Alt_L:
+ case GDK_Alt_R:
+ case GDK_Control_L:
+ case GDK_Control_R:
+ case GDK_Shift_L:
+ case GDK_Shift_R:
+ case GDK_Meta_L: // Meta is when you press Shift+Alt
+ case GDK_Meta_R:
+ event_context->defaultMessageContext()->clear();
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (!ret) {
+ if (((SPEventContextClass *) parent_class)->root_handler) {
+ ret = ((SPEventContextClass *) parent_class)->root_handler(event_context, event);
+ }
+ }
+
+ return ret;
+}
+
+static void sp_3dbox_drag(SP3DBoxContext &rc, guint state)
+{
+ SPDesktop *desktop = SP_EVENT_CONTEXT(&rc)->desktop;
+
+ if (!rc.item) {
+
+ if (Inkscape::have_viable_layer(desktop, rc._message_context) == false) {
+ return;
+ }
+
+ /* Create object */
+ Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_EVENT_CONTEXT_DOCUMENT(&rc));
+ Inkscape::XML::Node *repr = xml_doc->createElement("svg:g");
+ repr->setAttribute("sodipodi:type", "inkscape:3dbox");
+
+ /* Set style */
+ //sp_desktop_apply_style_tool (desktop, repr, "tools.shapes.3dbox", false);
+
+ rc.item = (SPItem *) desktop->currentLayer()->appendChildRepr(repr);
+ Inkscape::GC::release(repr);
+ rc.item->transform = SP_ITEM(desktop->currentRoot())->getRelativeTransform(desktop->currentLayer());
+
+ /* The separate faces (created from rear to front) */
+ SP3DBox *box3d = SP_3DBOX(rc.item);
+ box3d->face3.hook_path_to_3dbox();
+ box3d->face4.hook_path_to_3dbox();
+ box3d->face5.hook_path_to_3dbox();
+ box3d->face6.hook_path_to_3dbox();
+ box3d->face1.hook_path_to_3dbox();
+ box3d->face2.hook_path_to_3dbox();
+
+ rc.item->updateRepr();
+
+ sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 5);
+ }
+
+ // FIXME: remove these extra points
+ NR::Point pt = rc.drag_ptB;
+ NR::Point shift_pt = rc.drag_ptC;
+
+ NR::Rect r;
+ if (!(state & GDK_SHIFT_MASK)) {
+ r = Inkscape::snap_rectangular_box(desktop, rc.item, pt, rc.center, state);
+ } else {
+ r = Inkscape::snap_rectangular_box(desktop, rc.item, shift_pt, rc.center, state);
+ }
+
+ /*** artefacts of rect ***
+ if ( rc.rx != 0.0 ) {
+ sp_3dbox_set_rx (SP_3DBOX(rc.item), TRUE, rc.rx);
+ }
+ if ( rc.ry != 0.0 ) {
+ if (rc.rx == 0.0)
+ sp_3dbox_set_ry (SP_3DBOX(rc.item), TRUE, CLAMP(rc.ry, 0, MIN(r.dimensions()[NR::X], r.dimensions()[NR::Y])/2));
+ else
+ sp_3dbox_set_ry (SP_3DBOX(rc.item), TRUE, CLAMP(rc.ry, 0, r.dimensions()[NR::Y]));
+ }
+ ***/
+
+ SPEventContext *ec = SP_EVENT_CONTEXT(&rc);
+ NR::Point origin_w(ec->xp, ec->yp);
+ NR::Point origin(desktop->w2d(origin_w));
+ sp_3dbox_position_set(rc);
+
+ // status text
+ GString *xs = SP_PX_TO_METRIC_STRING(r.dimensions()[NR::X], desktop->namedview->getDefaultMetric());
+ GString *ys = SP_PX_TO_METRIC_STRING(r.dimensions()[NR::Y], desktop->namedview->getDefaultMetric());
+ rc._message_context->setF(Inkscape::NORMAL_MESSAGE, _("<b>Rectangle</b>: %s × %s; with <b>Ctrl</b> to make square or integer-ratio rectangle; with <b>Shift</b> to draw around the starting point"), xs->str, ys->str);
+ g_string_free(xs, FALSE);
+ g_string_free(ys, FALSE);
+}
+
+static void sp_3dbox_finish(SP3DBoxContext *rc)
+{
+ rc->_message_context->clear();
+
+ if ( rc->item != NULL ) {
+ SPDesktop * desktop;
+
+ desktop = SP_EVENT_CONTEXT_DESKTOP(rc);
+
+ SP_OBJECT(rc->item)->updateRepr();
+
+ sp_canvas_end_forced_full_redraws(desktop->canvas);
+
+ sp_desktop_selection(desktop)->set(rc->item);
+ sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX,
+ _("Create 3d box"));
+
+ rc->item = NULL;
+ }
+
+ rc->ctrl_dragged = false;
+ rc->extruded = false;
+}
+
+/*
+ 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/box3d-context.h b/src/box3d-context.h
--- /dev/null
+++ b/src/box3d-context.h
@@ -0,0 +1,69 @@
+#ifndef __SP_3DBOX_CONTEXT_H__
+#define __SP_3DBOX_CONTEXT_H__
+
+/*
+ * 3D box drawing context
+ *
+ * Author:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ *
+ * Copyright (C) 2000 Lauris Kaplinski
+ * Copyright (C) 2000-2001 Ximian, Inc.
+ * Copyright (C) 2002 Lauris Kaplinski
+ * Copyright (C) 2007 Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Released under GNU GPL
+ */
+
+#include <sigc++/sigc++.h>
+#include "event-context.h"
+#include "perspective3d.h"
+
+struct SPKnotHolder;
+
+#define SP_TYPE_3DBOX_CONTEXT (sp_3dbox_context_get_type ())
+#define SP_3DBOX_CONTEXT(obj) (GTK_CHECK_CAST ((obj), SP_TYPE_3DBOX_CONTEXT, SP3DBoxContext))
+#define SP_3DBOX_CONTEXT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), SP_TYPE_3DBOX_CONTEXT, SP3DBoxContextClass))
+#define SP_IS_3DBOX_CONTEXT(obj) (GTK_CHECK_TYPE ((obj), SP_TYPE_3DBOX_CONTEXT))
+#define SP_IS_3DBOX_CONTEXT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), SP_TYPE_3DBOX_CONTEXT))
+
+class SP3DBoxContext;
+class SP3DBoxContextClass;
+
+struct SP3DBoxContext : public SPEventContext {
+ SPItem *item;
+ NR::Point center;
+
+ gdouble rx; /* roundness radius (x direction) */
+ gdouble ry; /* roundness radius (y direction) */
+
+ /**
+ * save three corners while dragging:
+ * 1) the starting point (already done by the event_context)
+ * 2) drag_ptB --> the opposite corner of the front face (before pressing shift)
+ * 3) drag_ptC --> the "extruded corner" (which coincides with the mouse pointer location
+ * if we are ctrl-dragging but is constrained to the perspective line from drag_ptC
+ * to the vanishing point Y otherwise)
+ */
+ NR::Point drag_origin;
+ NR::Point drag_ptB;
+ NR::Point drag_ptC;
+ bool ctrl_dragged; /* whether we are ctrl-dragging */
+ bool extruded; /* whether shift-dragging already occured (i.e. the box is already extruded) */
+
+ static Box3D::Perspective3D *current_perspective;
+
+ sigc::connection sel_changed_connection;
+
+ Inkscape::MessageContext *_message_context;
+};
+
+struct SP3DBoxContextClass {
+ SPEventContextClass parent_class;
+};
+
+/* Standard Gtk function */
+
+GtkType sp_3dbox_context_get_type (void);
+
+#endif
diff --git a/src/box3d-face.cpp b/src/box3d-face.cpp
--- /dev/null
+++ b/src/box3d-face.cpp
@@ -0,0 +1,161 @@
+#define __SP_3DBOX_FACE_C__
+
+/*
+ * Face of a 3D box ('perspectivic rectangle')
+ *
+ * Authors:
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "box3d-face.h"
+#include <iostream>
+
+Box3DFace::Box3DFace(SP3DBox *box3d) : corner1 (0, 0), corner2 (0, 0), corner3 (0, 0), corner4 (0, 0),
+ dir1 (Box3D::NONE), dir2 (Box3D::NONE), path (NULL), parent_box3d (box3d)
+{
+}
+
+void Box3DFace::set_shape(NR::Point const ul, NR::Point const lr,
+ Box3D::PerspDir const dir1, Box3D::PerspDir const dir2,
+ unsigned int shift_count, NR::Maybe<NR::Point> pt_align, bool align_along_PL)
+{
+ corner1 = ul;
+ if (!pt_align) {
+ corner3 = lr;
+ } else {
+ if (align_along_PL) {
+ Box3D::PerspDir dir3;
+ if (dir1 == Box3D::X && dir2 == Box3D::Y) dir3 = Box3D::Z;
+ if (dir1 == Box3D::X && dir2 == Box3D::Z) dir3 = Box3D::Y;
+ if (dir1 == Box3D::Y && dir2 == Box3D::X) dir3 = Box3D::Z;
+ if (dir1 == Box3D::Y && dir2 == Box3D::Z) dir3 = Box3D::X;
+ if (dir1 == Box3D::Z && dir2 == Box3D::X) dir3 = Box3D::Y;
+ if (dir1 == Box3D::Z && dir2 == Box3D::Y) dir3 = Box3D::X;
+ Box3D::Line line1(*SP3DBoxContext::current_perspective->get_vanishing_point(dir1), lr);
+ Box3D::Line line2(*pt_align, *SP3DBoxContext::current_perspective->get_vanishing_point(dir3));
+ corner3 = *line1.intersect(line2);
+ } else {
+ corner3 = Box3D::Line(*pt_align, *SP3DBoxContext::current_perspective->get_vanishing_point(dir1)).closest_to(lr);
+ }
+ }
+
+ Box3D::PerspectiveLine first_line (corner1, dir1);
+ Box3D::PerspectiveLine second_line (corner3, dir2);
+ NR::Maybe<NR::Point> ur = first_line.intersect(second_line);
+
+ Box3D::PerspectiveLine third_line (corner1, dir2);
+ Box3D::PerspectiveLine fourth_line (corner3, dir1);
+ NR::Maybe<NR::Point> ll = third_line.intersect(fourth_line);
+
+ // FIXME: How to handle the case if one of the intersections doesn't exist?
+ // Maybe set them equal to the corresponding VPs?
+ if (!ur) ur = NR::Point(0.0, 0.0);
+ if (!ll) ll = NR::Point(0.0, 0.0);
+
+ corner2 = *ll;
+ corner4 = *ur;
+
+ this->dir1 = dir1;
+ this->dir2 = dir2;
+
+ // FIXME: More effective with array of corners
+ NR::Point tmp_pt;
+ for (unsigned int i=0; i < shift_count; i++) {
+ tmp_pt = corner4;
+ corner2 = corner1;
+ corner3 = corner2;
+ corner4 = corner3;
+ corner1 = tmp_pt;
+ }
+}
+
+Box3DFace::Box3DFace(Box3DFace const &box3dface)
+{
+ this->corner1 = box3dface.corner1;
+ this->corner2 = box3dface.corner2;
+ this->corner3 = box3dface.corner3;
+ this->corner4 = box3dface.corner4;
+ this->dir1 = box3dface.dir1;
+ this->dir2 = box3dface.dir2;
+}
+
+NR::Point Box3DFace::operator[](unsigned int i)
+{
+ unsigned int index = i % 4;
+ switch (index) {
+ case 0: return corner1; break;
+ case 1: return corner2; break;
+ case 2: return corner3; break;
+ case 3: return corner4; break;
+ }
+ // The following two lines are just to prevent a compiler warning ("control reaches
+ // end of non-void function); they can be removed if desired
+ g_message ("Error: This code line hould not be reached\n");
+ return NR::Point (0, 0);
+}
+
+/**
+ * Append the curve's path as a child to the given 3D box (since SP3DBox
+ * is derived from SPGroup, so we can append children to its svg representation)
+ */
+void Box3DFace::hook_path_to_3dbox()
+{
+ SPDesktop *desktop = inkscape_active_desktop();
+ Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_EVENT_CONTEXT_DOCUMENT(inkscape_active_event_context()));
+ Inkscape::XML::Node *repr_face = xml_doc->createElement("svg:path");
+ sp_desktop_apply_style_tool (desktop, repr_face, "tools.shapes.3dbox", false);
+ this->path = SP_PATH(SP_OBJECT(parent_box3d)->appendChildRepr(repr_face));
+ Inkscape::GC::release(repr_face);
+}
+
+/**
+ * Write the path's "d" attribute to the SVG representation.
+ */
+void Box3DFace::set_path_repr()
+{
+ SP_OBJECT(this->path)->repr->setAttribute("d", svg_repr_string());
+}
+
+void Box3DFace::set_curve()
+{
+ SPDocument *doc = SP_OBJECT_DOCUMENT(this->parent_box3d);
+ gdouble height = sp_document_height(doc);
+
+ SPCurve *curve = sp_curve_new();
+ sp_curve_moveto(curve, corner1[NR::X], height - corner1[NR::Y]);
+ sp_curve_lineto(curve, corner2[NR::X], height - corner2[NR::Y]);
+ sp_curve_lineto(curve, corner3[NR::X], height - corner3[NR::Y]);
+ sp_curve_lineto(curve, corner4[NR::X], height - corner4[NR::Y]);
+ sp_curve_closepath(curve);
+ sp_shape_set_curve(SP_SHAPE(this->path), curve, true);
+ sp_curve_unref(curve);
+}
+
+gchar * Box3DFace::svg_repr_string()
+{
+ SPDocument *doc = SP_OBJECT_DOCUMENT(this->parent_box3d);
+ gdouble height = sp_document_height(doc);
+
+ GString *pstring = g_string_new("");
+ g_string_sprintf (pstring, "M %f,%f L %f,%f L %f,%f L %f,%f z",
+ corner1[NR::X], height - corner1[NR::Y],
+ corner2[NR::X], height - corner2[NR::Y],
+ corner3[NR::X], height - corner3[NR::Y],
+ corner4[NR::X], height - corner4[NR::Y]);
+ return pstring->str;
+}
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/box3d-face.h b/src/box3d-face.h
--- /dev/null
+++ b/src/box3d-face.h
@@ -0,0 +1,59 @@
+#ifndef __SP_3DBOX_FACE_H__
+#define __SP_3DBOX_FACE_H__
+
+/*
+ * Face of a 3D box ('perspectivic rectangle')
+ *
+ * Authors:
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 Authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "perspective-line.h"
+#include "display/curve.h"
+#include "sp-path.h"
+#include "sp-object.h"
+#include "inkscape.h"
+#include "desktop-style.h"
+#include "desktop.h"
+#include "xml/document.h"
+
+class SP3DBox;
+
+class Box3DFace {
+public:
+ Box3DFace(SP3DBox *box3d);
+ //Box3DFace(SP3DBox *box3d, NR::Point const ul, NR::Point const lr,
+ // Box3D::PerspDir const dir1, Box3D::PerspDir const dir2,
+ // unsigned int shift_count = 0, NR::Maybe<NR::Point> pt_align = NR::Nothing(), bool align_along_PL = false);
+ Box3DFace(Box3DFace const &box3dface);
+ NR::Point operator[](unsigned int i);
+ void draw(SP3DBox *box3d, SPCurve *c);
+
+ void set_shape(NR::Point const ul, NR::Point const lr,
+ Box3D::PerspDir const dir1, Box3D::PerspDir const dir2,
+ unsigned int shift_count = 0, NR::Maybe<NR::Point> pt_align = NR::Nothing(),
+ bool align_along_PL = false);
+
+ void hook_path_to_3dbox();
+ void set_path_repr();
+ void set_curve();
+ gchar * svg_repr_string();
+
+private:
+ NR::Point corner1;
+ NR::Point corner2;
+ NR::Point corner3;
+ NR::Point corner4;
+
+ Box3D::PerspDir dir1;
+ Box3D::PerspDir dir2;
+
+ SPPath *path;
+ SP3DBox *parent_box3d; // the parent box
+};
+
+#endif
diff --git a/src/box3d.cpp b/src/box3d.cpp
--- /dev/null
+++ b/src/box3d.cpp
@@ -0,0 +1,257 @@
+#define __SP_3DBOX_C__
+
+/*
+ * SVG <box3d> implementation
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * bulia byak <buliabyak@users.sf.net>
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 Authors
+ * Copyright (C) 1999-2002 Lauris Kaplinski
+ * Copyright (C) 2000-2001 Ximian, Inc.
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "box3d.h"
+
+static void sp_3dbox_class_init(SP3DBoxClass *klass);
+static void sp_3dbox_init(SP3DBox *box3d);
+
+static void sp_3dbox_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr);
+static void sp_3dbox_set(SPObject *object, unsigned int key, const gchar *value);
+static void sp_3dbox_update(SPObject *object, SPCtx *ctx, guint flags);
+static Inkscape::XML::Node *sp_3dbox_write(SPObject *object, Inkscape::XML::Node *repr, guint flags);
+
+//static gchar *sp_3dbox_description(SPItem *item);
+
+//static void sp_3dbox_set_shape(SPShape *shape);
+static void sp_3dbox_set_shape(SP3DBox *box3d);
+
+static SPGroupClass *parent_class;
+
+GType
+sp_3dbox_get_type(void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ GTypeInfo info = {
+ sizeof(SP3DBoxClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) sp_3dbox_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof(SP3DBox),
+ 16, /* n_preallocs */
+ (GInstanceInitFunc) sp_3dbox_init,
+ NULL, /* value_table */
+ };
+ type = g_type_register_static(SP_TYPE_GROUP, "SP3DBox", &info, (GTypeFlags) 0);
+ }
+
+ return type;
+}
+
+static void
+sp_3dbox_class_init(SP3DBoxClass *klass)
+{
+ SPObjectClass *sp_object_class = (SPObjectClass *) klass;
+ SPItemClass *item_class = (SPItemClass *) klass;
+
+ parent_class = (SPGroupClass *) g_type_class_ref(SP_TYPE_GROUP);
+
+ sp_object_class->build = sp_3dbox_build;
+ sp_object_class->set = sp_3dbox_set;
+ sp_object_class->write = sp_3dbox_write;
+ sp_object_class->update = sp_3dbox_update;
+
+ //item_class->description = sp_3dbox_description;
+}
+
+static void
+sp_3dbox_init(SP3DBox *box3d)
+{
+ box3d->face1 = Box3DFace (box3d);
+ box3d->face2 = Box3DFace (box3d);
+ box3d->face3 = Box3DFace (box3d);
+ box3d->face4 = Box3DFace (box3d);
+ box3d->face5 = Box3DFace (box3d);
+ box3d->face6 = Box3DFace (box3d);
+}
+
+static void
+sp_3dbox_build(SPObject *object, SPDocument *document, Inkscape::XML::Node *repr)
+{
+ if (((SPObjectClass *) (parent_class))->build) {
+ ((SPObjectClass *) (parent_class))->build(object, document, repr);
+ }
+
+ //sp_object_read_attr(object, "width");
+}
+
+static void sp_3dbox_set(SPObject *object, unsigned int key, const gchar *value)
+{
+ //SP3DBox *box3d = SP_3DBOX(object);
+
+ switch (key) {
+ /***
+ case SP_ATTR_WIDTH:
+ rect->width.readOrUnset(value);
+ object->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ break;
+ ***/
+ default:
+ if (((SPObjectClass *) (parent_class))->set) {
+ ((SPObjectClass *) (parent_class))->set(object, key, value);
+ }
+ break;
+ }
+}
+
+
+static void
+sp_3dbox_update(SPObject *object, SPCtx *ctx, guint flags)
+{
+ //SP3DBox *box3d = SP_3DBOX(object);
+
+ /* Invoke parent method */
+ if (((SPObjectClass *) (parent_class))->update)
+ ((SPObjectClass *) (parent_class))->update(object, ctx, flags);
+
+ //sp_3dbox_set_shape (box3d);
+}
+
+
+
+static Inkscape::XML::Node *sp_3dbox_write(SPObject *object, Inkscape::XML::Node *repr, guint flags)
+{
+ SP3DBox *box3d = SP_3DBOX(object);
+ // FIXME: How to handle other contexts???
+ // FIXME: Is tools_isactive(..) more recommended to check for the current context/tool?
+ if (!SP_IS_3DBOX_CONTEXT(inkscape_active_event_context()))
+ return repr;
+ SP3DBoxContext *bc = SP_3DBOX_CONTEXT(inkscape_active_event_context());
+
+ if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) {
+ Inkscape::XML::Document *xml_doc = sp_document_repr_doc(SP_OBJECT_DOCUMENT(object));
+ repr = xml_doc->createElement("svg:g");
+ repr->setAttribute("sodipodi:type", "inkscape:3dbox");
+ }
+
+
+ box3d->face1.set_path_repr();
+ if (bc->extruded) {
+ NR::Point corner1, corner2, corner3, corner4;
+ sp_3dbox_compute_specific_corners (bc, corner1, corner2, corner3, corner4);
+ box3d->face2.set_path_repr();
+ box3d->face3.set_path_repr();
+ box3d->face4.set_path_repr();
+ box3d->face5.set_path_repr();
+ box3d->face6.set_path_repr();
+ }
+ if (((SPObjectClass *) (parent_class))->write) {
+ ((SPObjectClass *) (parent_class))->write(object, repr, flags);
+ }
+
+ return repr;
+}
+
+void
+sp_3dbox_position_set (SP3DBoxContext &bc)
+{
+ SP3DBox *box3d = SP_3DBOX(bc.item);
+
+ sp_3dbox_set_shape(box3d);
+
+ // FIXME: Why does the following call not automatically update the children
+ // of box3d (which is an SPGroup, which should do this)?
+ //SP_OBJECT(box3d)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+
+ /**
+ SP_OBJECT(box3d->path_face1)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ SP_OBJECT(box3d->path_face2)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ SP_OBJECT(box3d->path_face3)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ SP_OBJECT(box3d->path_face4)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ SP_OBJECT(box3d->path_face5)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ SP_OBJECT(box3d->path_face6)->requestDisplayUpdate(SP_OBJECT_MODIFIED_FLAG);
+ ***/
+}
+
+static void
+// FIXME: Note that this is _not_ the virtual set_shape() method inherited from SPShape,
+// since SP3DBox is inherited from SPGroup. The following method is "artificially"
+// called from sp_3dbox_update().
+//sp_3dbox_set_shape(SPShape *shape)
+sp_3dbox_set_shape(SP3DBox *box3d)
+{
+ // FIXME: How to handle other contexts???
+ // FIXME: Is tools_isactive(..) more recommended to check for the current context/tool?
+ if (!SP_IS_3DBOX_CONTEXT(inkscape_active_event_context()))
+ return;
+ SP3DBoxContext *bc = SP_3DBOX_CONTEXT(inkscape_active_event_context());
+
+ // FIXME: Why must the coordinates be flipped vertically???
+ //SPDocument *doc = SP_OBJECT_DOCUMENT(box3d);
+ //gdouble height = sp_document_height(doc);
+
+ /* Curve-adaption variant: */
+ NR::Point corner1, corner2, corner3, corner4;
+ corner1 = bc->drag_origin;
+
+ if (bc->extruded) {
+ sp_3dbox_compute_specific_corners (bc, corner1, corner2, corner3, corner4);
+ box3d->face3.set_shape(bc->drag_origin, corner4, Box3D::Y, Box3D::Z);
+ box3d->face3.set_curve();
+ box3d->face4.set_shape(corner2, corner4, Box3D::X, Box3D::Z);
+ box3d->face4.set_curve();
+ box3d->face5.set_shape(bc->drag_origin, corner2, Box3D::X, Box3D::Y);
+ box3d->face5.set_curve();
+ box3d->face6.set_shape(bc->drag_ptB, corner4, Box3D::X, Box3D::Y);
+ box3d->face6.set_curve();
+
+ box3d->face2.set_shape(corner1, bc->drag_ptC, Box3D::Y, Box3D::Z);
+ box3d->face2.set_curve();
+ }
+ box3d->face1.set_shape(bc->drag_origin, bc->drag_ptB, Box3D::X, Box3D::Z);
+ box3d->face1.set_curve();
+}
+
+
+void
+sp_3dbox_compute_specific_corners (SP3DBoxContext *box3d_context, NR::Point &corner1, NR::Point &corner2, NR::Point &corner3, NR::Point &corner4)
+{
+ // TODO: Check for numerical stability and handle "wrong" cases more gracefully.
+ // (This now mostly applies to the intersection code in the PerspectiveLine class)
+ Box3D::PerspectiveLine pl1 (box3d_context->drag_origin, Box3D::X);
+ Box3D::PerspectiveLine pl2 (box3d_context->drag_ptB, Box3D::Z);
+ corner1 = pl1.meet(pl2);
+
+ Box3D::PerspectiveLine pl3 (corner1, Box3D::Y);
+ Box3D::PerspectiveLine pl4 (box3d_context->drag_ptC, Box3D::Z);
+ corner2 = pl3.meet(pl4);
+
+ Box3D::PerspectiveLine pl5 (corner2, Box3D::X);
+ Box3D::PerspectiveLine pl6 (box3d_context->drag_origin, Box3D::Y);
+ corner3 = pl5.meet(pl6);
+
+ Box3D::PerspectiveLine pl7 (box3d_context->drag_ptC, Box3D::X);
+ Box3D::PerspectiveLine pl8 (corner3, Box3D::Z);
+ corner4 = pl7.meet(pl8);
+}
+
+
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/box3d.h b/src/box3d.h
--- /dev/null
+++ b/src/box3d.h
@@ -0,0 +1,55 @@
+#ifndef __SP_3DBOX_H__
+#define __SP_3DBOX_H__
+
+/*
+ * SVG <box3d> implementation
+ *
+ * Authors:
+ * Lauris Kaplinski <lauris@kaplinski.com>
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 Authors
+ * Copyright (C) 1999-2002 Lauris Kaplinski
+ * Copyright (C) 2000-2001 Ximian, Inc.
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "inkscape.h"
+#include "perspective-line.h"
+//#include "display/curve.h"
+
+#include "sp-item-group.h"
+#include "sp-path.h"
+#include "xml/document.h"
+#include "xml/repr.h"
+#include "line-geometry.h"
+#include "box3d-face.h"
+
+
+#define SP_TYPE_3DBOX (sp_3dbox_get_type ())
+#define SP_3DBOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SP_TYPE_3DBOX, SP3DBox))
+#define SP_3DBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SP_TYPE_3DBOX, SP3DBoxClass))
+#define SP_IS_3DBOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SP_TYPE_3DBOX))
+#define SP_IS_3DBOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SP_TYPE_3DBOX))
+
+
+struct SP3DBox : public SPGroup {
+ Box3DFace face1;
+ Box3DFace face2;
+ Box3DFace face3;
+ Box3DFace face4;
+ Box3DFace face5;
+ Box3DFace face6;
+};
+
+struct SP3DBoxClass {
+ SPGroupClass parent_class;
+};
+
+GType sp_3dbox_get_type (void);
+
+void sp_3dbox_position_set (SP3DBoxContext &bc);
+void sp_3dbox_compute_specific_corners (SP3DBoxContext *box3d_context, NR::Point &corner1, NR::Point &corner2, NR::Point &corner3, NR::Point &corner4);
+
+#endif
diff --git a/src/knotholder.cpp b/src/knotholder.cpp
index c67f22933f760ec298ecf2ea912b3e808bc5514e..a24bb16259d0bcf2b70d7459e0f9436e67448810 100644 (file)
--- a/src/knotholder.cpp
+++ b/src/knotholder.cpp
#include "spiral-context.h"
#include "sp-spiral.h"
#include "sp-offset.h"
+#include "box3d.h"
#include <libnr/nr-matrix-div.h>
#include <glibmm/i18n.h>
if (SP_IS_RECT(item))
object_verb = SP_VERB_CONTEXT_RECT;
+ else if (SP_IS_3DBOX(item))
+ object_verb = SP_VERB_CONTEXT_3DBOX;
else if (SP_IS_GENERICELLIPSE(item))
object_verb = SP_VERB_CONTEXT_ARC;
else if (SP_IS_STAR(item))
@@ -289,6 +292,8 @@ static void knot_ungrabbed_handler(SPKnot *knot, unsigned int state, SPKnotHolde
if (SP_IS_RECT(object))
object_verb = SP_VERB_CONTEXT_RECT;
+ else if (SP_IS_3DBOX(object))
+ object_verb = SP_VERB_CONTEXT_3DBOX;
else if (SP_IS_GENERICELLIPSE(object))
object_verb = SP_VERB_CONTEXT_ARC;
else if (SP_IS_STAR(object))
diff --git a/src/line-geometry.cpp b/src/line-geometry.cpp
--- /dev/null
+++ b/src/line-geometry.cpp
@@ -0,0 +1,112 @@
+#define __LINE_GEOMETRY_C__
+
+/*
+ * Routines for dealing with lines (intersections, etc.)
+ *
+ * Authors:
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "line-geometry.h"
+#include "inkscape.h"
+#include "desktop-style.h"
+#include "desktop-handles.h"
+#include "display/sp-canvas.h"
+#include "display/sodipodi-ctrl.h"
+//#include "display/curve.cpp"
+
+namespace Box3D {
+
+/**
+ * Draw a line beginning at 'start'. If is_endpoint is true, use 'vec' as the endpoint
+ * of the segment. Otherwise interpret it as the direction of the line.
+ * FIXME: Think of a better way to distinguish between the two constructors of lines.
+ */
+Line::Line(NR::Point const &start, NR::Point const &vec, bool is_endpoint) {
+ pt = start;
+ if (is_endpoint)
+ v_dir = vec - start;
+ else
+ v_dir = vec;
+ normal = v_dir.ccw();
+ d0 = NR::dot(normal, pt);
+}
+
+Line::Line(Line const &line) {
+ pt = line.pt;
+ v_dir = line.v_dir;
+ normal = line.normal;
+ d0 = line.d0;
+}
+
+Line &Line::operator=(Line const &line) {
+ pt = line.pt;
+ v_dir = line.v_dir;
+ normal = line.normal;
+ d0 = line.d0;
+
+ return *this;
+}
+
+NR::Maybe<NR::Point> Line::intersect(Line const &line) {
+ NR::Coord denom = NR::dot(v_dir, line.normal);
+ g_return_val_if_fail(fabs(denom) > 1e-6, NR::Nothing());
+
+ NR::Coord lambda = (line.d0 - NR::dot(pt, line.normal)) / denom;
+ return pt + lambda * v_dir;
+}
+
+void Line::set_direction(NR::Point const &dir)
+{
+ v_dir = dir;
+ normal = v_dir.ccw();
+ d0 = NR::dot(normal, pt);
+}
+
+NR::Point Line::closest_to(NR::Point const &pt)
+{
+ /* return the intersection of this line with a perpendicular line passing through pt */
+ NR::Maybe<NR::Point> result = this->intersect(Line(pt, (this->v_dir).ccw(), false));
+ g_return_val_if_fail (result, NR::Point (0.0, 0.0));
+ return *result;
+}
+
+void create_canvas_point(NR::Point const &pos, double size, guint32 rgba)
+{
+ SPDesktop *desktop = inkscape_active_desktop();
+ SPCanvasItem * canvas_pt = sp_canvas_item_new(sp_desktop_controls(desktop), SP_TYPE_CTRL,
+ "size", size,
+ "filled", 1,
+ "fill_color", rgba,
+ "stroked", 1,
+ "stroke_color", 0x000000ff,
+ NULL);
+ SP_CTRL(canvas_pt)->moveto(pos);
+}
+
+void create_canvas_line(NR::Point const &p1, NR::Point const &p2, guint32 rgba)
+{
+ SPDesktop *desktop = inkscape_active_desktop();
+ SPCanvasItem *line = sp_canvas_item_new(sp_desktop_controls(desktop),
+ SP_TYPE_CTRLLINE, NULL);
+ sp_ctrlline_set_coords(SP_CTRLLINE(line), p1, p2);
+ sp_ctrlline_set_rgba32 (SP_CTRLLINE(line), rgba);
+ sp_canvas_item_show (line);
+}
+
+} // namespace Box3D
+
+/*
+ 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/line-geometry.h b/src/line-geometry.h
--- /dev/null
+++ b/src/line-geometry.h
@@ -0,0 +1,74 @@
+/*
+ * Routines for dealing with lines (intersections, etc.)
+ *
+ * Authors:
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_LINE_GEOMETRY_H
+#define SEEN_LINE_GEOMETRY_H
+
+#include "libnr/nr-point.h"
+#include "libnr/nr-point-fns.h"
+#include "libnr/nr-maybe.h"
+#include "glib.h"
+#include "display/sp-ctrlline.h"
+#include "vanishing-point.h"
+
+#include "document.h"
+#include "ui/view/view.h"
+
+namespace Box3D {
+
+class Line {
+public:
+ Line(NR::Point const &start, NR::Point const &vec, bool is_endpoint = true);
+ Line(Line const &line);
+ Line &operator=(Line const &line);
+ virtual NR::Maybe<NR::Point> intersect(Line const &line);
+ void set_direction(NR::Point const &dir); // FIXME: Can we avoid this explicit assignment?
+
+ NR::Point closest_to(NR::Point const &pt); // returns the point on the line closest to pt
+
+ friend inline std::ostream &operator<< (std::ostream &out_file, const Line &in_line);
+
+private:
+ NR::Point pt;
+ NR::Point v_dir;
+ NR::Point normal;
+ NR::Coord d0;
+};
+
+/*** For testing purposes: Draw a knot/node of specified size and color at the given position ***/
+void create_canvas_point(NR::Point const &pos, double size = 4.0, guint32 rgba = 0xff00007f);
+
+/*** For testing purposes: Draw a line between the specified points ***/
+void create_canvas_line(NR::Point const &p1, NR::Point const &p2, guint32 rgba = 0xff00007f);
+
+
+/** A function to print out the Line. It just prints out the coordinates of start end end point
+ on the given output stream */
+inline std::ostream &operator<< (std::ostream &out_file, const Line &in_line) {
+ out_file << "Start: " << in_line.pt << " Direction: " << in_line.v_dir;
+ return out_file;
+}
+
+} // namespace Box3D
+
+
+#endif /* !SEEN_LINE_GEOMETRY_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/perspective-line.cpp b/src/perspective-line.cpp
--- /dev/null
+++ b/src/perspective-line.cpp
@@ -0,0 +1,63 @@
+#define __PERSPECTIVE_LINE_C__
+
+/*
+ * Perspective line for 3D perspectives
+ *
+ * Authors:
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "perspective-line.h"
+
+namespace Box3D {
+
+PerspectiveLine::PerspectiveLine (NR::Point const &pt, PerspDir const axis, Perspective3D *perspective) :
+ Line (pt, *(perspective->get_vanishing_point(axis)), true)
+{
+ g_assert (perspective != NULL);
+
+ if (perspective->get_vanishing_point(axis)->state == VP_INFINITE) {
+ this->set_direction(perspective->get_vanishing_point(axis)->v_dir);
+ }
+ this->vp_dir = axis;
+ this->persp = perspective;
+}
+
+// This function makes sure not to return NR::Nothing()
+// FIXME: How to gracefully handle parallel lines?
+NR::Maybe<NR::Point> PerspectiveLine::intersect (Line const &line)
+{
+ NR::Maybe<NR::Point> pt = this->Line::intersect(line);
+ if (!pt) {
+ Box3D::VanishingPoint vp = *(persp->get_vanishing_point(vp_dir));
+ if (vp.state == VP_INFINITE) {
+ pt = vp;
+ } else {
+ pt = NR::Point (0.0, 0.0); // FIXME: Better solution needed
+ }
+ }
+ return pt;
+}
+
+// FIXME: Do we really need two intersection methods?
+NR::Point PerspectiveLine::meet(Line const &line)
+{
+ return *intersect(line); // works since intersect() does not return NR::Nothing()
+}
+
+} // namespace Box3D
+
+/*
+ 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/perspective-line.h b/src/perspective-line.h
--- /dev/null
+++ b/src/perspective-line.h
@@ -0,0 +1,63 @@
+/*
+ * Perspective line for 3D perspectives
+ *
+ * Authors:
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_PERSPECTIVE_LINE_H
+#define SEEN_PERSPECTIVE_LINE_H
+
+#include "vanishing-point.h"
+#include "box3d-context.h"
+#include <glib.h>
+
+namespace Box3D {
+
+class PerspectiveLine : public Box3D::Line {
+public:
+ /**
+ * Create a perspective line starting at 'pt' and pointing in the direction of the
+ * vanishing point corresponding to 'axis'. If the VP has style VP_FINITE then the
+ * PL runs through it; otherwise it has the direction specified by the v_dir vector
+ * of the VP.
+ */
+ PerspectiveLine (NR::Point const &pt, PerspDir const axis,
+ Perspective3D *perspective = SP3DBoxContext::current_perspective);
+ NR::Maybe<NR::Point> intersect (Line const &line); // FIXME: Can we make this return only a NR::Point to remove the extra method meet()?
+ NR::Point meet (Line const &line);
+
+private:
+ PerspDir vp_dir; // direction of the associated VP
+ Perspective3D *persp;
+};
+
+
+} // namespace Box3D
+
+
+/** A function to print out the VanishingPoint (prints the coordinates) **/
+/***
+inline std::ostream &operator<< (std::ostream &out_file, const VanishingPoint &vp) {
+ out_file << vp;
+ return out_file;
+}
+***/
+
+
+#endif /* !SEEN_PERSPECTIVE_LINE_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/perspective3d.cpp b/src/perspective3d.cpp
--- /dev/null
+++ b/src/perspective3d.cpp
@@ -0,0 +1,98 @@
+#define __PERSPECTIVE3D_C__
+
+/*
+ * Class modelling a 3D perspective
+ *
+ * Authors:
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "box3d-context.h"
+#include "perspective-line.h"
+#include <iostream>
+
+namespace Box3D {
+
+/**
+ * Computes the intersection of the two perspective lines from pt1 and pt2 to the respective
+ * vanishing points in the given directions.
+ */
+// FIXME: This has been moved to a virtual method inside PerspectiveLine; can probably be purged
+NR::Point perspective_intersection (NR::Point pt1, Box3D::PerspDir dir1, NR::Point pt2, Box3D::PerspDir dir2)
+{
+ VanishingPoint const *vp1 = SP3DBoxContext::current_perspective->get_vanishing_point(dir1);
+ VanishingPoint const *vp2 = SP3DBoxContext::current_perspective->get_vanishing_point(dir2);
+ NR::Maybe<NR::Point> meet = Line(pt1, *vp1).intersect(Line(pt2, *vp2));
+ // FIXME: How to handle parallel lines (also depends on the type of the VPs)?
+ if (!meet) { meet = NR::Point (0.0, 0.0); }
+ return *meet;
+}
+
+/**
+ * Find the point on the perspective line from line_pt to the
+ * vanishing point in direction dir that is closest to ext_pt.
+ */
+NR::Point perspective_line_snap (NR::Point line_pt, PerspDir dir, NR::Point ext_pt)
+{
+ return PerspectiveLine(line_pt, dir).closest_to(ext_pt);
+}
+
+Perspective3D::Perspective3D (VanishingPoint const &pt_x, VanishingPoint const &pt_y, VanishingPoint const &pt_z)
+ : vp_x (pt_x),
+ vp_y (pt_y),
+ vp_z (pt_z)
+{
+ // Draw the three vanishing points
+ vp_x.draw(X);
+ vp_y.draw(Y);
+ vp_z.draw(Z);
+}
+
+VanishingPoint *Perspective3D::get_vanishing_point (PerspDir const dir)
+{
+ // FIXME: Also handle value 'NONE' in switch
+ switch (dir) {
+ case X:
+ return &vp_x;
+ break;
+ case Y:
+ return &vp_y;
+ break;
+ case Z:
+ return &vp_z;
+ break;
+ }
+}
+
+void Perspective3D::set_vanishing_point (PerspDir const dir, VanishingPoint const &pt)
+{
+ // FIXME: Also handle value 'NONE' in switch
+ switch (dir) {
+ case X:
+ vp_x = pt;
+ break;
+ case Y:
+ vp_y = pt;
+ break;
+ case Z:
+ vp_z = pt;
+ break;
+ }
+}
+
+} // namespace Box3D
+
+/*
+ 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/perspective3d.h b/src/perspective3d.h
--- /dev/null
+++ b/src/perspective3d.h
@@ -0,0 +1,61 @@
+/*
+ * Class modelling a 3D perspective
+ *
+ * Authors:
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_PERSPECTIVE3D_H
+#define SEEN_PERSPECTIVE3D_H
+
+#include "vanishing-point.h"
+
+namespace Box3D {
+
+NR::Point perspective_intersection (NR::Point pt1, Box3D::PerspDir dir1, NR::Point pt2, Box3D::PerspDir dir2);
+NR::Point perspective_line_snap (NR::Point pt, PerspDir dir, NR::Point ext_pt);
+
+class PerspectiveLine;
+
+class Perspective3D {
+public:
+ Perspective3D(VanishingPoint const &pt_x, VanishingPoint const &pt_y, VanishingPoint const &pt_z);
+
+ VanishingPoint *get_vanishing_point (PerspDir const dir);
+ void set_vanishing_point (PerspDir const dir, VanishingPoint const &pt);
+
+private:
+ VanishingPoint vp_x;
+ VanishingPoint vp_y;
+ VanishingPoint vp_z;
+};
+
+
+} // namespace Box3D
+
+
+/** A function to print out the VanishingPoint (prints the coordinates) **/
+/***
+inline std::ostream &operator<< (std::ostream &out_file, const VanishingPoint &vp) {
+ out_file << vp;
+ return out_file;
+}
+***/
+
+
+#endif /* !SEEN_PERSPECTIVE3D_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
index 28b1fe01849f5988591500b58944aeb097bf8cb0..ead8e7a623f6b6fd9d0a28f1e5a698b94a3234d5 100644 (file)
" style=\"fill:none;stroke:black;stroke-opacity:1;stroke-width:1px;stroke-linejoin:miter;stroke-linecap:butt;\">\n"
" <group id=\"shapes\" style=\"fill-rule:evenodd;\" selcue=\"1\" gradientdrag=\"1\">\n"
" <eventcontext id=\"rect\" style=\"fill:blue;\" usecurrent=\"1\"/>\n"
+" <eventcontext id=\"3dbox\" style=\"fill:blue;\" usecurrent=\"1\"/>\n"
" <eventcontext id=\"arc\" style=\"fill:red;\" end=\"0\" start=\"0\" usecurrent=\"1\"/>\n"
" <eventcontext id=\"star\" magnitude=\"5\" style=\"fill:yellow;\" usecurrent=\"1\"/>\n"
" <eventcontext id=\"spiral\" style=\"fill:none;\" usecurrent=\"0\"/>\n"
diff --git a/src/sp-object-repr.cpp b/src/sp-object-repr.cpp
index 43c946670397d515e2069f141305ce68191f3024..5a1554cbd1d59a14233e33068dac766f2f99856f 100644 (file)
--- a/src/sp-object-repr.cpp
+++ b/src/sp-object-repr.cpp
#include "sp-path.h"
#include "sp-radial-gradient-fns.h"
#include "sp-rect.h"
+#include "box3d.h"
#include "sp-ellipse.h"
#include "sp-star.h"
#include "sp-stop-fns.h"
{ "arc", SP_TYPE_ARC },
{ "inkscape:offset", SP_TYPE_OFFSET },
{ "spiral", SP_TYPE_SPIRAL },
- { "star", SP_TYPE_STAR }
+ { "star", SP_TYPE_STAR },
+ { "inkscape:3dbox", SP_TYPE_3DBOX }//,
+ //{ "inkscape:3dboxface", SP_TYPE_3DBOX_FACE }
};
NameTypeEntry const *const t2entries[] = {
diff --git a/src/tools-switch.cpp b/src/tools-switch.cpp
index 3393263599c17c0f1348a647c723e5171b0b40a7..bc9655a83b0d201691c3a8cffabf065d7ba32596 100644 (file)
--- a/src/tools-switch.cpp
+++ b/src/tools-switch.cpp
#include "sp-path.h"
#include "rect-context.h"
#include "sp-rect.h"
+#include "box3d-context.h"
+#include "box3d.h"
#include "arc-context.h"
#include "sp-ellipse.h"
#include "star-context.h"
"tools.select",
"tools.nodes",
"tools.shapes.rect",
+ "tools.shapes.3dbox",
"tools.shapes.arc",
"tools.shapes.star",
"tools.shapes.spiral",
"select",
"nodes",
"rect",
+ "3dbox",
"arc",
"star",
"spiral",
inkscape_eventcontext_set(sp_desktop_event_context(dt));
dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to create a rectangle. <b>Drag controls</b> to round corners and resize. <b>Click</b> to select."));
break;
+ case TOOLS_SHAPES_3DBOX:
+ dt->set_event_context(SP_TYPE_3DBOX_CONTEXT, tool_names[num]);
+ dt->activate_guides(false);
+ inkscape_eventcontext_set(sp_desktop_event_context(dt));
+ dt->tipsMessageContext()->set(Inkscape::NORMAL_MESSAGE, _("<b>Drag</b> to create a 3D box. <b>Drag controls</b> to resize in perspective. <b>Click</b> to select."));
+ break;
case TOOLS_SHAPES_ARC:
dt->set_event_context(SP_TYPE_ARC_CONTEXT, tool_names[num]);
dt->activate_guides(false);
diff --git a/src/tools-switch.h b/src/tools-switch.h
index 252add75855c932a9b8a3c0971fc0153241451ed..aac48d8343bdf3e55c71aeeac312ed50d67d0e55 100644 (file)
--- a/src/tools-switch.h
+++ b/src/tools-switch.h
TOOLS_SELECT,
TOOLS_NODES,
TOOLS_SHAPES_RECT,
+ TOOLS_SHAPES_3DBOX,
TOOLS_SHAPES_ARC,
TOOLS_SHAPES_STAR,
TOOLS_SHAPES_SPIRAL,
index 5694a3ea3ddd1b3be777a7db061818e893f09f6a..f3429ce7b59de9964f5d78242115fd92858bc52d 100644 (file)
//Rectangle
this->AddPage(_page_rectangle, _("Rectangle"), iter_shapes, PREFS_PAGE_TOOLS_SHAPES_RECT);
this->AddNewObjectsStyle(_page_rectangle, "tools.shapes.rect");
+ //3D box
+ this->AddPage(_page_3dbox, _("3D Box"), iter_shapes, PREFS_PAGE_TOOLS_SHAPES_3DBOX);
+ this->AddNewObjectsStyle(_page_3dbox, "tools.shapes.3dbox");
//ellipse
this->AddPage(_page_ellipse, _("Ellipse"), iter_shapes, PREFS_PAGE_TOOLS_SHAPES_ELLIPSE);
this->AddNewObjectsStyle(_page_ellipse, "tools.shapes.arc");
index f2a61d1ba8081e4415cb91caf95c28bd340b5676..91b7a83ec9679c7ffdd7fe6fcabc7272309aef17 100644 (file)
PREFS_PAGE_TOOLS_ZOOM,
PREFS_PAGE_TOOLS_SHAPES,
PREFS_PAGE_TOOLS_SHAPES_RECT,
+ PREFS_PAGE_TOOLS_SHAPES_3DBOX,
PREFS_PAGE_TOOLS_SHAPES_ELLIPSE,
PREFS_PAGE_TOOLS_SHAPES_STAR,
PREFS_PAGE_TOOLS_SHAPES_SPIRAL,
_page_clones, _page_mask, _page_transforms, _page_filters, _page_select, _page_misc;
DialogPage _page_selector, _page_node, _page_zoom, _page_shapes, _page_pencil, _page_pen,
_page_calligraphy, _page_text, _page_gradient, _page_connector, _page_dropper;
- DialogPage _page_rectangle, _page_ellipse, _page_star, _page_spiral, _page_paintbucket;
+ DialogPage _page_rectangle, _page_3dbox, _page_ellipse, _page_star, _page_spiral, _page_paintbucket;
PrefSpinButton _mouse_sens, _mouse_thres;
PrefCheckButton _mouse_use_ext_input;
diff --git a/src/vanishing-point.cpp b/src/vanishing-point.cpp
--- /dev/null
+++ b/src/vanishing-point.cpp
@@ -0,0 +1,101 @@
+#define __VANISHING_POINT_C__
+
+/*
+ * Vanishing point for 3D perspectives
+ *
+ * Authors:
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#include "vanishing-point.h"
+#include <iostream>
+
+namespace Box3D {
+
+// FIXME: We should always require to have both the point (for finite VPs)
+// and the direction (for infinite VPs) set. Otherwise toggling
+// shows very unexpected behaviour.
+// Later on we can maybe infer the infinite direction from the finite point
+// and a suitable center of the scene. How to go in the other direction?
+VanishingPoint::VanishingPoint(NR::Point const &pt, NR::Point const &inf_dir, VPState st)
+ : NR::Point (pt), state (st), v_dir (inf_dir) {}
+
+VanishingPoint::VanishingPoint(NR::Point const &pt)
+ : NR::Point (pt), state (VP_FINITE), v_dir (0.0, 0.0) {}
+
+VanishingPoint::VanishingPoint(NR::Point const &pt, NR::Point const &direction)
+ : NR::Point (pt), state (VP_INFINITE), v_dir (direction) {}
+
+VanishingPoint::VanishingPoint(NR::Coord x, NR::Coord y)
+ : NR::Point(x, y), state(VP_FINITE), v_dir(0.0, 0.0) {}
+
+VanishingPoint::VanishingPoint(NR::Coord dir_x, NR::Coord dir_y, VPState st)
+ : NR::Point(0.0, 0.0), state(st), v_dir(dir_x, dir_y) {}
+
+VanishingPoint::VanishingPoint(NR::Coord x, NR::Coord y, NR::Coord dir_x, NR::Coord dir_y)
+ : NR::Point(x, y), state(VP_INFINITE), v_dir(dir_x, dir_y) {}
+
+VanishingPoint::VanishingPoint(VanishingPoint const &rhs) : NR::Point (rhs)
+{
+ this->state = rhs.state;
+ //this->ref_pt = rhs.ref_pt;
+ this->v_dir = rhs.v_dir;
+}
+
+
+bool VanishingPoint::is_finite()
+{
+ return this->state == VP_FINITE;
+}
+
+VPState VanishingPoint::toggle_parallel()
+{
+ if (this->state == VP_FINITE) {
+ this->state = VP_INFINITE;
+ } else {
+ this->state = VP_FINITE;
+ }
+
+ return this->state;
+}
+
+void VanishingPoint::draw(PerspDir const axis)
+{
+ switch (axis) {
+ case X:
+ if (state == VP_FINITE)
+ create_canvas_point(*this, 6.0, 0xff000000);
+ else
+ create_canvas_point(*this, 6.0, 0xffffff00);
+ break;
+ case Y:
+ if (state == VP_FINITE)
+ create_canvas_point(*this, 6.0, 0x0000ff00);
+ else
+ create_canvas_point(*this, 6.0, 0xffffff00);
+ break;
+ case Z:
+ if (state == VP_FINITE)
+ create_canvas_point(*this, 6.0, 0x00770000);
+ else
+ create_canvas_point(*this, 6.0, 0xffffff00);
+ break;
+ }
+}
+
+} // namespace Box3D
+
+/*
+ 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/vanishing-point.h b/src/vanishing-point.h
--- /dev/null
+++ b/src/vanishing-point.h
@@ -0,0 +1,91 @@
+/*
+ * Vanishing point for 3D perspectives
+ *
+ * Authors:
+ * Maximilian Albert <Anhalter42@gmx.de>
+ *
+ * Copyright (C) 2007 authors
+ *
+ * Released under GNU GPL, read the file 'COPYING' for more information
+ */
+
+#ifndef SEEN_VANISHING_POINT_H
+#define SEEN_VANISHING_POINT_H
+
+#include "libnr/nr-point.h"
+#include "line-geometry.h"
+
+namespace Box3D {
+
+enum VPState {
+ VP_FINITE = 0, // perspective lines meet in the VP
+ VP_INFINITE // perspective lines are parallel
+};
+
+enum PerspDir {
+ X,
+ Y,
+ Z,
+ NONE
+};
+
+// FIXME: Store the PerspDir of the VP inside the class
+class VanishingPoint : public NR::Point {
+public:
+ inline VanishingPoint() : NR::Point() {};
+ /***
+ inline VanishingPoint(NR::Point const &pt, NR::Point const &ref = NR::Point(0,0))
+ : NR::Point (pt),
+ ref_pt (ref),
+ v_dir (pt[NR::X] - ref[NR::X], pt[NR::Y] - ref[NR::Y]) {}
+ inline VanishingPoint(NR::Coord x, NR::Coord y, NR::Point const &ref = NR::Point(0,0))
+ : NR::Point (x, y),
+ ref_pt (ref),
+ v_dir (x - ref[NR::X], y - ref[NR::Y]) {}
+ ***/
+ VanishingPoint(NR::Point const &pt, NR::Point const &inf_dir, VPState st);
+ VanishingPoint(NR::Point const &pt);
+ VanishingPoint(NR::Point const &dir, VPState const state);
+ VanishingPoint(NR::Point const &pt, NR::Point const &direction);
+ VanishingPoint(NR::Coord x, NR::Coord y);
+ VanishingPoint(NR::Coord x, NR::Coord y, VPState const state);
+ VanishingPoint(NR::Coord x, NR::Coord y, NR::Coord dir_x, NR::Coord dir_y);
+ VanishingPoint(VanishingPoint const &rhs);
+
+ bool is_finite();
+ VPState toggle_parallel();
+ void draw(PerspDir const axis); // Draws a point on the canvas if state == VP_FINITE
+ //inline VPState state() { return state; }
+
+ VPState state;
+ //NR::Point ref_pt; // point of reference to compute the direction of parallel lines
+ NR::Point v_dir; // direction of perslective lines if the VP has state == VP_INFINITE
+
+private:
+};
+
+
+} // namespace Box3D
+
+
+/** A function to print out the VanishingPoint (prints the coordinates) **/
+/***
+inline std::ostream &operator<< (std::ostream &out_file, const VanishingPoint &vp) {
+ out_file << vp;
+ return out_file;
+}
+***/
+
+
+#endif /* !SEEN_VANISHING_POINT_H */
+
+/*
+ Local Variables:
+ mode:c++
+ c-file-style:"stroustrup"
+ c-file-offsets:((innamespace . 0)(inline-open . 0))
+ indent-tabs-mode:nil
+ fill-column:99
+ End:
+*/
+// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
diff --git a/src/verbs.cpp b/src/verbs.cpp
index 01172f1021e8587ccedc89b617a4e26136731b6b..04a49f37c4bd3a58d9ad03275d5e548d96a5f974 100644 (file)
--- a/src/verbs.cpp
+++ b/src/verbs.cpp
case SP_VERB_CONTEXT_RECT:
tools_switch_current(TOOLS_SHAPES_RECT);
break;
+ case SP_VERB_CONTEXT_3DBOX:
+ tools_switch_current(TOOLS_SHAPES_3DBOX);
+ break;
case SP_VERB_CONTEXT_ARC:
tools_switch_current(TOOLS_SHAPES_ARC);
break;
prefs_set_int_attribute("dialogs.preferences", "page", PREFS_PAGE_TOOLS_SHAPES_RECT);
dt->_dlg_mgr->showDialog("InkscapePreferences");
break;
+ case SP_VERB_CONTEXT_3DBOX_PREFS:
+ prefs_set_int_attribute("dialogs.preferences", "page", PREFS_PAGE_TOOLS_SHAPES_3DBOX);
+ dt->_dlg_mgr->showDialog("InkscapePreferences");
+ break;
case SP_VERB_CONTEXT_ARC_PREFS:
prefs_set_int_attribute("dialogs.preferences", "page", PREFS_PAGE_TOOLS_SHAPES_ELLIPSE);
dt->_dlg_mgr->showDialog("InkscapePreferences");
N_("Edit path nodes or control handles"), "draw_node"),
new ContextVerb(SP_VERB_CONTEXT_RECT, "ToolRect", N_("Rectangle"),
N_("Create rectangles and squares"), "draw_rect"),
+ new ContextVerb(SP_VERB_CONTEXT_3DBOX, "Tool3DBox", N_("3D Box"),
+ N_("Create 3D boxes"), "draw_3dbox"),
new ContextVerb(SP_VERB_CONTEXT_ARC, "ToolArc", N_("Ellipse"),
N_("Create circles, ellipses, and arcs"), "draw_arc"),
new ContextVerb(SP_VERB_CONTEXT_STAR, "ToolStar", N_("Star"),
N_("Open Preferences for the Node tool"), NULL),
new ContextVerb(SP_VERB_CONTEXT_RECT_PREFS, "RectPrefs", N_("Rectangle Preferences"),
N_("Open Preferences for the Rectangle tool"), NULL),
+ new ContextVerb(SP_VERB_CONTEXT_3DBOX_PREFS, "3DBoxPrefs", N_("3D Box Preferences"),
+ N_("Open Preferences for the 3D Box tool"), NULL),
new ContextVerb(SP_VERB_CONTEXT_ARC_PREFS, "ArcPrefs", N_("Ellipse Preferences"),
N_("Open Preferences for the Ellipse tool"), NULL),
new ContextVerb(SP_VERB_CONTEXT_STAR_PREFS, "StarPrefs", N_("Star Preferences"),
diff --git a/src/verbs.h b/src/verbs.h
index 3ebc129d16d41c7ebb88dcc2330c6f1d9c23d047..f8e25f94df78782cda5398f69500ba791778405c 100644 (file)
--- a/src/verbs.h
+++ b/src/verbs.h
SP_VERB_CONTEXT_SELECT,
SP_VERB_CONTEXT_NODE,
SP_VERB_CONTEXT_RECT,
+ SP_VERB_CONTEXT_3DBOX,
SP_VERB_CONTEXT_ARC,
SP_VERB_CONTEXT_STAR,
SP_VERB_CONTEXT_SPIRAL,
SP_VERB_CONTEXT_SELECT_PREFS,
SP_VERB_CONTEXT_NODE_PREFS,
SP_VERB_CONTEXT_RECT_PREFS,
+ SP_VERB_CONTEXT_3DBOX_PREFS,
SP_VERB_CONTEXT_ARC_PREFS,
SP_VERB_CONTEXT_STAR_PREFS,
SP_VERB_CONTEXT_SPIRAL_PREFS,
index 9f8e675c2ab5a24502bb210cd5c0eb4aa47b466b..4c497134f5c4879323dbc3317e478d9a5aa4dd79 100644 (file)
--- a/src/widgets/toolbox.cpp
+++ b/src/widgets/toolbox.cpp
#include "node-context.h"
#include "shape-editor.h"
#include "sp-rect.h"
+#include "box3d-context.h"
#include "sp-star.h"
#include "sp-spiral.h"
#include "sp-ellipse.h"
static void sp_star_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
static void sp_arc_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
+static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
static void sp_spiral_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
static void sp_pencil_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
static void sp_pen_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder);
{ "SPNodeContext", "node_tool", SP_VERB_CONTEXT_NODE, SP_VERB_CONTEXT_NODE_PREFS },
{ "SPZoomContext", "zoom_tool", SP_VERB_CONTEXT_ZOOM, SP_VERB_CONTEXT_ZOOM_PREFS },
{ "SPRectContext", "rect_tool", SP_VERB_CONTEXT_RECT, SP_VERB_CONTEXT_RECT_PREFS },
+// { "SP3DBoxContext", "3dbox_tool", SP_VERB_CONTEXT_3DBOX, SP_VERB_CONTEXT_3DBOX_PREFS },
{ "SPArcContext", "arc_tool", SP_VERB_CONTEXT_ARC, SP_VERB_CONTEXT_ARC_PREFS },
{ "SPStarContext", "star_tool", SP_VERB_CONTEXT_STAR, SP_VERB_CONTEXT_STAR_PREFS },
{ "SPSpiralContext", "spiral_tool", SP_VERB_CONTEXT_SPIRAL, SP_VERB_CONTEXT_SPIRAL_PREFS },
SP_VERB_CONTEXT_STAR_PREFS, "tools.shapes.star", _("Style of new stars")},
{ "SPRectContext", "rect_toolbox", 0, sp_rect_toolbox_prep, "RectToolbar",
SP_VERB_CONTEXT_RECT_PREFS, "tools.shapes.rect", _("Style of new rectangles")},
+ { "SP3DBoxContext", "3dbox_toolbox", 0, sp_3dbox_toolbox_prep, "3DBoxToolbar",
+ SP_VERB_CONTEXT_3DBOX_PREFS, "tools.shapes.3dbox", _("Style of new 3D boxes")},
{ "SPArcContext", "arc_toolbox", 0, sp_arc_toolbox_prep, "ArcToolbar",
SP_VERB_CONTEXT_ARC_PREFS, "tools.shapes.arc", _("Style of new ellipses")},
{ "SPSpiralContext", "spiral_toolbox", 0, sp_spiral_toolbox_prep, "SpiralToolbar",
" <toolitem action='RectResetAction' />"
" </toolbar>"
+ " <toolbar name='3DBoxToolbar'>"
+ " <toolitem action='3DBoxVPXAction' />"
+ " <toolitem action='3DBoxVPYAction' />"
+ " <toolitem action='3DBoxVPZAction' />"
+ " </toolbar>"
+
" <toolbar name='SpiralToolbar'>"
" <toolitem action='SpiralStateAction' />"
" <toolitem action='SpiralRevolutionAction' />"
@@ -2089,6 +2100,89 @@ static void sp_rect_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions
g_signal_connect( holder, "destroy", G_CALLBACK(purge_repr_listener), holder );
}
+//########################
+//## 3D Box ##
+//########################
+
+static void sp_3dbox_toggle_vp_changed( GtkToggleAction *act, gpointer data )
+{
+ guint dir = (guint) data;
+ Box3D::PerspDir axis;// = (Box3D::PerspDir) data;
+
+ GString *pstring;
+ switch (dir) {
+ case 0:
+ pstring = g_string_new("togglevpx");
+ axis = Box3D::X;
+ break;
+ case 1:
+ pstring = g_string_new("togglevpy");
+ axis = Box3D::Y;
+ break;
+ case 2:
+ pstring = g_string_new("togglevpz");
+ axis = Box3D::Z;
+ break;
+ }
+
+ if (SP3DBoxContext::current_perspective) {
+ Box3D::VanishingPoint *vp = SP3DBoxContext::current_perspective->get_vanishing_point(axis);
+ vp->toggle_parallel();
+ vp->draw(axis);
+ prefs_set_int_attribute( "tools.shapes.3dbox", pstring->str, vp->is_finite() ? 0 : 1);
+ }
+
+}
+
+static void sp_3dbox_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder)
+{
+ bool toggled = false;
+ /* toggle VP in X direction */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXAction",
+ _("Toggle VP in X direction"),
+ _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"),
+ "toggle_vp_x",
+ Inkscape::ICON_SIZE_DECORATION );
+ gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_changed), (gpointer) 0);
+ if (SP3DBoxContext::current_perspective) {
+ toggled = SP3DBoxContext::current_perspective->get_vanishing_point(Box3D::X)->is_finite();
+ }
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), toggled );
+ }
+
+ /* toggle VP in Y direction */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYAction",
+ _("Toggle VP in Y direction"),
+ _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"),
+ "toggle_vp_y",
+ Inkscape::ICON_SIZE_DECORATION );
+ gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_changed), (gpointer) 1);
+ if (SP3DBoxContext::current_perspective) {
+ toggled = SP3DBoxContext::current_perspective->get_vanishing_point(Box3D::Y)->is_finite();
+ }
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), toggled );
+ }
+
+ /* toggle VP in Z direction */
+ {
+ InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZAction",
+ _("Toggle VP in Z direction"),
+ _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"),
+ "toggle_vp_z",
+ Inkscape::ICON_SIZE_DECORATION );
+ gtk_action_group_add_action( mainActions, GTK_ACTION( act ) );
+ g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_3dbox_toggle_vp_changed), (gpointer) 2);
+ if (SP3DBoxContext::current_perspective) {
+ toggled = SP3DBoxContext::current_perspective->get_vanishing_point(Box3D::Z)->is_finite();
+ }
+ gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), toggled );
+ }
+}
+
//########################
//## Spiral ##
//########################