X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Fbox3d-context.cpp;h=0ef2277ea0a638e50c8729aa588112dfc69ba405;hb=88013f5100c818a1b1c0d9d9cf773930373491cf;hp=0bcf9ffa46ccbbaaca3558fa189985b057778674;hpb=dd077ad5b18808e4d36956554368377cf25c2eb6;p=inkscape.git diff --git a/src/box3d-context.cpp b/src/box3d-context.cpp index 0bcf9ffa4..0ef2277ea 100644 --- a/src/box3d-context.cpp +++ b/src/box3d-context.cpp @@ -50,8 +50,8 @@ static void sp_3dbox_context_set(SPEventContext *ec, gchar const *key, gchar con 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 void sp_3dbox_drag(SP3DBoxContext &bc, guint state); +static void sp_3dbox_finish(SP3DBoxContext *bc); static SPEventContextClass *parent_class; @@ -90,7 +90,6 @@ static void sp_3dbox_context_class_init(SP3DBoxContextClass *klass) event_context_class->item_handler = sp_3dbox_context_item_handler; } -Box3D::Perspective3D * SP3DBoxContext::current_perspective = NULL; guint SP3DBoxContext::number_of_handles = 3; static void sp_3dbox_context_init(SP3DBoxContext *box3d_context) @@ -111,42 +110,30 @@ static void sp_3dbox_context_init(SP3DBoxContext *box3d_context) 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(500.0,1000.0), - NR::Point( 0.0, 1.0), Box3D::VP_INFINITE), - // VP in z-direction - Box3D::VanishingPoint( NR::Point(700.0, 500.0), - NR::Point(sqrt(3.0),1.0), Box3D::VP_INFINITE)); - } + box3d_context->_vpdrag = NULL; + new (&box3d_context->sel_changed_connection) sigc::connection(); } static void sp_3dbox_context_dispose(GObject *object) { - SP3DBoxContext *rc = SP_3DBOX_CONTEXT(object); + SP3DBoxContext *bc = SP_3DBOX_CONTEXT(object); SPEventContext *ec = SP_EVENT_CONTEXT(object); ec->enableGrDrag(false); - rc->sel_changed_connection.disconnect(); - rc->sel_changed_connection.~connection(); + delete (bc->_vpdrag); + bc->_vpdrag = NULL; + + bc->sel_changed_connection.disconnect(); + bc->sel_changed_connection.~connection(); /* fixme: This is necessary because we do not grab */ - if (rc->item) { - sp_3dbox_finish(rc); + if (bc->item) { + sp_3dbox_finish(bc); } if (ec->shape_knot_holder) { @@ -160,8 +147,8 @@ static void sp_3dbox_context_dispose(GObject *object) ec->shape_repr = 0; } - if (rc->_message_context) { - delete rc->_message_context; + if (bc->_message_context) { + delete bc->_message_context; } G_OBJECT_CLASS(parent_class)->dispose(object); @@ -181,8 +168,8 @@ 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); + SP3DBoxContext *bc = SP_3DBOX_CONTEXT(data); + SPEventContext *ec = SP_EVENT_CONTEXT(bc); if (ec->shape_knot_holder) { // destroy knotholder sp_knot_holder_destroy(ec->shape_knot_holder); @@ -203,21 +190,29 @@ void sp_3dbox_context_selection_changed(Inkscape::Selection *selection, gpointer ec->shape_repr = shape_repr; Inkscape::GC::anchor(shape_repr); sp_repr_add_listener(shape_repr, &ec_shape_repr_events, ec); - - // FIXME: The following really belongs in sp_3dbox_build. But when undoing & redoing the - // creation of a 3D box, we have no means of accessing the recreated paths, which - // seem to be built after the box itself. Thus we need to check for untracked paths - // here and hook them to the box if the latter was created by a redo operation. - if (SP_IS_3DBOX(item)) { - sp_3dbox_link_to_existing_paths (SP_3DBOX(item), shape_repr); + } + if (SP_IS_3DBOX (item)) { + Box3D::Perspective3D::current_perspective = Box3D::get_persp_of_box (SP_3DBOX (item)); + } + } else { + /* If several boxes sharing the same perspective are selected, + we can still set the current selection accordingly */ + std::set perspectives; + for (GSList *i = (GSList *) selection->itemList(); i != NULL; i = i->next) { + if (SP_IS_3DBOX (i->data)) { + perspectives.insert (Box3D::get_persp_of_box (SP_3DBOX (i->data))); } } + if (perspectives.size() == 1) { + Box3D::Perspective3D::current_perspective = *(perspectives.begin()); + } + // TODO: What to do if several boxes with different perspectives are selected? } } static void sp_3dbox_context_setup(SPEventContext *ec) { - SP3DBoxContext *rc = SP_3DBOX_CONTEXT(ec); + SP3DBoxContext *bc = SP_3DBOX_CONTEXT(ec); if (((SPEventContextClass *) parent_class)->setup) { ((SPEventContextClass *) parent_class)->setup(ec); @@ -234,13 +229,12 @@ static void sp_3dbox_context_setup(SPEventContext *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) + bc->sel_changed_connection.disconnect(); + bc->sel_changed_connection = sp_desktop_selection(ec->desktop)->connectChanged( + sigc::bind(sigc::ptr_fun(&sp_3dbox_context_selection_changed), (gpointer)bc) ); - sp_event_context_read(ec, "rx"); - sp_event_context_read(ec, "ry"); + bc->_vpdrag = new Box3D::VPDrag(ec->desktop); if (prefs_get_int_attribute("tools.shapes", "selcue", 0) != 0) { ec->enableSelectionCue(); @@ -250,24 +244,26 @@ static void sp_3dbox_context_setup(SPEventContext *ec) ec->enableGrDrag(); } - rc->_message_context = new Inkscape::MessageContext((ec->desktop)->messageStack()); + bc->_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); + //SP3DBoxContext *bc = 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 + bc->rx = ( val ? g_ascii_strtod (val, NULL) : 0.0 ); } else if ( strcmp(key, "ry") == 0 ) { - rc->ry = ( val + bc->ry = ( val ? g_ascii_strtod (val, NULL) : 0.0 ); } + **/ } static gint sp_3dbox_context_item_handler(SPEventContext *event_context, SPItem *item, GdkEvent *event) @@ -278,7 +274,7 @@ static gint sp_3dbox_context_item_handler(SPEventContext *event_context, SPItem switch (event->type) { case GDK_BUTTON_PRESS: - if ( event->button.button == 1 ) { + if ( event->button.button == 1 && !event_context->space_panning) { Inkscape::setup_for_drag_start(desktop, event_context, event); ret = TRUE; } @@ -302,14 +298,14 @@ static gint sp_3dbox_context_root_handler(SPEventContext *event_context, GdkEven SPDesktop *desktop = event_context->desktop; Inkscape::Selection *selection = sp_desktop_selection (desktop); - SP3DBoxContext *rc = SP_3DBOX_CONTEXT(event_context); + SP3DBoxContext *bc = 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 ) { + if ( event->button.button == 1 && !event_context->space_panning) { NR::Point const button_w(event->button.x, event->button.y); @@ -325,14 +321,14 @@ static gint sp_3dbox_context_root_handler(SPEventContext *event_context, GdkEven /* 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; + bc->drag_origin = button_dt; + bc->drag_ptB = button_dt; + bc->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(); + bc->center = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, + button_dt, bc->item).getPoint(); sp_canvas_item_grab(SP_CANVAS_ITEM(desktop->acetate), ( GDK_KEY_PRESS_MASK | @@ -345,7 +341,7 @@ static gint sp_3dbox_context_root_handler(SPEventContext *event_context, GdkEven break; case GDK_MOTION_NOTIFY: if ( dragging - && ( event->motion.state & GDK_BUTTON1_MASK ) ) + && ( event->motion.state & GDK_BUTTON1_MASK ) && !event_context->space_panning) { if ( event_context->within_tolerance && ( abs( (gint) event->motion.x - event_context->xp ) < event_context->tolerance ) @@ -362,53 +358,53 @@ static gint sp_3dbox_context_root_handler(SPEventContext *event_context, GdkEven 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(); + motion_dt = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, motion_dt, bc->item).getPoint(); - rc->ctrl_dragged = event->motion.state & GDK_CONTROL_MASK; + bc->ctrl_dragged = event->motion.state & GDK_CONTROL_MASK; - if (event->motion.state & GDK_SHIFT_MASK && !rc->extruded) { - /* once shift is pressed, set rc->extruded (no need to create further faces; + if (event->motion.state & GDK_SHIFT_MASK && !bc->extruded) { + /* once shift is pressed, set bc->extruded (no need to create further faces; all of them are already created in sp_3dbox_init) */ - rc->extruded = true; + bc->extruded = true; } - if (!rc->extruded) { - rc->drag_ptB = motion_dt; - rc->drag_ptC = motion_dt; + if (!bc->extruded) { + bc->drag_ptB = motion_dt; + bc->drag_ptC = 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::Z, motion_dt); + if (!bc->ctrl_dragged) { + bc->drag_ptC = Box3D::perspective_line_snap (bc->drag_ptB, Box3D::Z, motion_dt, Box3D::Perspective3D::current_perspective); } else { - rc->drag_ptC = motion_dt; + bc->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::Y); - Box3D::PerspectiveLine pl2 (rc->drag_ptB, Box3D::X); + bc->drag_ptC = m.freeSnap(Inkscape::Snapper::SNAPPOINT_NODE, bc->drag_ptC, bc->item).getPoint(); + if (bc->ctrl_dragged) { + Box3D::PerspectiveLine pl1 (NR::Point (event_context->xp, event_context->yp), Box3D::Y, Box3D::Perspective3D::current_perspective); + Box3D::PerspectiveLine pl2 (bc->drag_ptB, Box3D::X, Box3D::Perspective3D::current_perspective); NR::Point corner1 = pl1.meet(pl2); - Box3D::PerspectiveLine pl3 (corner1, Box3D::X); - Box3D::PerspectiveLine pl4 (rc->drag_ptC, Box3D::Z); - rc->drag_ptB = pl3.meet(pl4); + Box3D::PerspectiveLine pl3 (corner1, Box3D::X, Box3D::Perspective3D::current_perspective); + Box3D::PerspectiveLine pl4 (bc->drag_ptC, Box3D::Z, Box3D::Perspective3D::current_perspective); + bc->drag_ptB = pl3.meet(pl4); } } - sp_3dbox_drag(*rc, event->motion.state); + sp_3dbox_drag(*bc, event->motion.state); ret = TRUE; } break; case GDK_BUTTON_RELEASE: event_context->xp = event_context->yp = 0; - if ( event->button.button == 1 ) { + if ( event->button.button == 1 && !event_context->space_panning) { dragging = false; if (!event_context->within_tolerance) { // we've been dragging, finish the box - sp_3dbox_finish(rc); + sp_3dbox_finish(bc); } else if (event_context->item_to_select) { // no dragging, select clicked item if any if (event->button.state & GDK_SHIFT_MASK) { @@ -455,13 +451,72 @@ static gint sp_3dbox_context_root_handler(SPEventContext *event_context, GdkEven ret = TRUE; break; + case GDK_I: + Box3D::Perspective3D::print_debugging_info(); + ret = true; + break; + + case GDK_L: + case GDK_l: + bc->_vpdrag->show_lines = !bc->_vpdrag->show_lines; + bc->_vpdrag->updateLines(); + ret = true; + break; + + case GDK_A: + case GDK_a: + if (MOD__CTRL) break; // Don't catch Ctrl+A ("select all") + if (bc->_vpdrag->show_lines) { + bc->_vpdrag->front_or_rear_lines = bc->_vpdrag->front_or_rear_lines ^ 0x2; // toggle rear PLs + } + bc->_vpdrag->updateLines(); + ret = true; + break; + case GDK_x: case GDK_X: - if (MOD__ALT_ONLY) { - // desktop->setToolboxFocusTo ("altx-rect"); - ret = TRUE; + { + if (MOD__CTRL) break; // Don't catch Ctrl+X ('cut') and Ctrl+Shift+X ('open XML editor') + // FIXME: Shouldn't we access _vpdrag->selection instead? + Inkscape::Selection *selection = sp_desktop_selection (bc->_vpdrag->desktop); + for (GSList const *i = selection->itemList(); i != NULL; i = i->next) { + if (!SP_IS_3DBOX (i->data)) continue; + sp_3dbox_switch_front_face (SP_3DBOX (i->data), Box3D::X); + } + bc->_vpdrag->updateLines(); + ret = true; + break; + } + + case GDK_y: + case GDK_Y: + { + if (MOD__CTRL) break; // Don't catch Ctrl+Y ("redo") + // FIXME: Shouldn't we access _vpdrag->selection instead? + Inkscape::Selection *selection = sp_desktop_selection (bc->_vpdrag->desktop); + for (GSList const *i = selection->itemList(); i != NULL; i = i->next) { + if (!SP_IS_3DBOX (i->data)) continue; + sp_3dbox_switch_front_face (SP_3DBOX (i->data), Box3D::Y); } + bc->_vpdrag->updateLines(); + ret = true; break; + } + + case GDK_z: + case GDK_Z: + { + if (MOD__CTRL) break; // Don't catch Ctrl+Z ("undo") + // FIXME: Shouldn't we access _vpdrag->selection instead? + Inkscape::Selection *selection = sp_desktop_selection (bc->_vpdrag->desktop); + for (GSList const *i = selection->itemList(); i != NULL; i = i->next) { + if (!SP_IS_3DBOX (i->data)) continue; + sp_3dbox_switch_front_face (SP_3DBOX (i->data), Box3D::Z); + } + bc->_vpdrag->updateLines(); + ret = true; + break; + } case GDK_Escape: sp_desktop_selection(desktop)->clear(); @@ -475,7 +530,7 @@ static gint sp_3dbox_context_root_handler(SPEventContext *event_context, GdkEven dragging = false; if (!event_context->within_tolerance) { // we've been dragging, finish the box - sp_3dbox_finish(rc); + sp_3dbox_finish(bc); } // do not return true, so that space would work switching to selector } @@ -542,6 +597,11 @@ static void sp_3dbox_drag(SP3DBoxContext &bc, guint state) } bc.item->updateRepr(); + sp_3dbox_set_z_orders (SP_3DBOX (bc.item)); + + // TODO: It would be nice to show the VPs during dragging, but since there is no selection + // at this point (only after finishing the box), we must do this "manually" + bc._vpdrag->updateDraggers(); sp_canvas_force_full_redraw_after_interruptions(desktop->canvas, 5); } @@ -561,6 +621,7 @@ static void sp_3dbox_drag(SP3DBoxContext &bc, guint state) NR::Point origin_w(ec->xp, ec->yp); NR::Point origin(desktop->w2d(origin_w)); sp_3dbox_position_set(bc); + sp_3dbox_set_z_orders (SP_3DBOX (bc.item)); // status text //GString *Ax = SP_PX_TO_METRIC_STRING(origin[NR::X], desktop->namedview->getDefaultMetric()); @@ -570,28 +631,29 @@ static void sp_3dbox_drag(SP3DBoxContext &bc, guint state) //g_string_free(Ay, FALSE); } -static void sp_3dbox_finish(SP3DBoxContext *rc) +static void sp_3dbox_finish(SP3DBoxContext *bc) { - rc->_message_context->clear(); + bc->_message_context->clear(); - if ( rc->item != NULL ) { + if ( bc->item != NULL ) { SPDesktop * desktop; - desktop = SP_EVENT_CONTEXT_DESKTOP(rc); + desktop = SP_EVENT_CONTEXT_DESKTOP(bc); - SP_OBJECT(rc->item)->updateRepr(); + SP_OBJECT(bc->item)->updateRepr(); + sp_3dbox_set_ratios(SP_3DBOX(bc->item)); sp_canvas_end_forced_full_redraws(desktop->canvas); - sp_desktop_selection(desktop)->set(rc->item); + sp_desktop_selection(desktop)->set(bc->item); sp_document_done(sp_desktop_document(desktop), SP_VERB_CONTEXT_3DBOX, _("Create 3D box")); - rc->item = NULL; + bc->item = NULL; } - rc->ctrl_dragged = false; - rc->extruded = false; + bc->ctrl_dragged = false; + bc->extruded = false; } /*