diff options
Diffstat (limited to 'src/ui/toolbar/box3d-toolbar.cpp')
| -rw-r--r-- | src/ui/toolbar/box3d-toolbar.cpp | 561 |
1 files changed, 279 insertions, 282 deletions
diff --git a/src/ui/toolbar/box3d-toolbar.cpp b/src/ui/toolbar/box3d-toolbar.cpp index fb59b13b9..50838a393 100644 --- a/src/ui/toolbar/box3d-toolbar.cpp +++ b/src/ui/toolbar/box3d-toolbar.cpp @@ -58,168 +58,176 @@ using Inkscape::UI::PrefPusher; //## 3D Box ## //######################## -// normalize angle so that it lies in the interval [0,360] -static double box3d_normalize_angle (double a) { - double angle = a + ((int) (a/360.0))*360; - if (angle < 0) { - angle += 360.0; - } - return angle; -} -static void box3d_set_button_and_adjustment(Persp3D *persp, - Proj::Axis axis, - GtkAdjustment *adj, - GtkAction *act, - GtkToggleAction *tact) -{ - // TODO: Take all selected perspectives into account but don't touch the state button if not all of them - // have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states - // are reset). - bool is_infinite = !persp3d_VP_is_finite(persp->perspective_impl, axis); - - if (is_infinite) { - gtk_toggle_action_set_active(tact, TRUE); - gtk_action_set_sensitive(act, TRUE); - double angle = persp3d_get_infinite_angle(persp, axis); - if (angle != Geom::infinity()) { // FIXME: We should catch this error earlier (don't show the spinbutton at all) - gtk_adjustment_set_value(adj, box3d_normalize_angle(angle)); - } - } else { - gtk_toggle_action_set_active(tact, FALSE); - gtk_action_set_sensitive(act, FALSE); - } -} +static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events = +{ + nullptr, /* child_added */ + nullptr, /* child_removed */ + Inkscape::UI::Toolbar::Box3DToolbar::event_attr_changed, + nullptr, /* content_changed */ + nullptr /* order_changed */ +}; -static void box3d_resync_toolbar(Inkscape::XML::Node *persp_repr, GObject *data) +namespace Inkscape { +namespace UI { +namespace Toolbar { +GtkWidget * +Box3DToolbar::prep(SPDesktop *desktop, GtkActionGroup* mainActions) { - if (!persp_repr) { - g_print ("No perspective given to box3d_resync_toolbar().\n"); - return; - } + auto holder = new Box3DToolbar(desktop); - GtkWidget *tbl = GTK_WIDGET(data); - GtkAdjustment *adj = nullptr; - GtkAction *act = nullptr; - GtkToggleAction *tact = nullptr; - Persp3D *persp = persp3d_get_from_repr(persp_repr); - if (!persp) { - // Hmm, is it an error if this happens? - return; - } - { - adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x")); - act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_x_action")); - tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_x_state_action"))->action; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + SPDocument *document = desktop->getDocument(); + Persp3DImpl *persp_impl = document->getCurrentPersp3DImpl(); - box3d_set_button_and_adjustment(persp, Proj::X, adj, act, tact); - } + /* Angle X */ { - adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y")); - act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_y_action")); - tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_y_state_action"))->action; - - box3d_set_button_and_adjustment(persp, Proj::Y, adj, act, tact); + gchar const* labels[] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; + gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; + holder->_angle_x_action = create_adjustment_action( "3DBoxAngleXAction", + _("Angle in X direction"), _("Angle X:"), + // Translators: PL is short for 'perspective line' + _("Angle of PLs in X direction"), + "/tools/shapes/3dbox/box3d_angle_x", 30, + GTK_WIDGET(desktop->canvas), + nullptr, // dataKludge + TRUE, "altx-box3d", + -360.0, 360.0, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + nullptr // callback + ); + holder->_angle_x_adj = Glib::wrap(ege_adjustment_action_get_adjustment(holder->_angle_x_action)); + holder->_angle_x_adj->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*holder, &Box3DToolbar::angle_value_changed), + holder->_angle_x_adj, Proj::X)); + gtk_action_group_add_action( mainActions, GTK_ACTION(holder->_angle_x_action) ); } - { - adj = GTK_ADJUSTMENT(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z")); - act = GTK_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_angle_z_action")); - tact = &INK_TOGGLE_ACTION(g_object_get_data(G_OBJECT(tbl), "box3d_vp_z_state_action"))->action; - box3d_set_button_and_adjustment(persp, Proj::Z, adj, act, tact); + if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::X)) { + gtk_action_set_sensitive( GTK_ACTION(holder->_angle_x_action), TRUE ); + } else { + gtk_action_set_sensitive( GTK_ACTION(holder->_angle_x_action), FALSE ); } -} -static void box3d_persp_tb_event_attr_changed(Inkscape::XML::Node *repr, - gchar const * /*name*/, - gchar const * /*old_value*/, - gchar const * /*new_value*/, - bool /*is_interactive*/, - gpointer data) -{ - GtkWidget *tbl = GTK_WIDGET(data); - // quit if run by the attr_changed or selection changed listener - if (g_object_get_data(G_OBJECT(tbl), "freeze")) { - return; + /* VP X state */ + { + holder->_vp_x_state_action = ink_toggle_action_new( "3DBoxVPXStateAction", + // Translators: VP is short for 'vanishing point' + _("State of VP in X direction"), + _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"), + INKSCAPE_ICON("perspective-parallel"), + GTK_ICON_SIZE_MENU ); + gtk_action_group_add_action( mainActions, GTK_ACTION( holder->_vp_x_state_action ) ); + g_signal_connect_after( G_OBJECT(holder->_vp_x_state_action), "toggled", G_CALLBACK(Box3DToolbar::vp_state_changed), (gpointer)Proj::X ); + gtk_action_set_sensitive( GTK_ACTION(holder->_angle_x_action), !prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(holder->_vp_x_state_action), prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) ); } - // set freeze so that it can be caught in box3d_angle_z_value_changed() (to avoid calling - // SPDocumentUndo::maybeDone() when the document is undo insensitive) - g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(TRUE)); - - // TODO: Only update the appropriate part of the toolbar -// if (!strcmp(name, "inkscape:vp_z")) { - box3d_resync_toolbar(repr, G_OBJECT(tbl)); -// } - - Persp3D *persp = persp3d_get_from_repr(repr); - persp3d_update_box_reprs(persp); + /* Angle Y */ + { + gchar const* labels[] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; + gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; + holder->_angle_y_action = create_adjustment_action( "3DBoxAngleYAction", + _("Angle in Y direction"), _("Angle Y:"), + // Translators: PL is short for 'perspective line' + _("Angle of PLs in Y direction"), + "/tools/shapes/3dbox/box3d_angle_y", 30, + GTK_WIDGET(desktop->canvas), + nullptr, // dataKludge + FALSE, nullptr, + -360.0, 360.0, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + nullptr // callback + ); + holder->_angle_y_adj = Glib::wrap(ege_adjustment_action_get_adjustment(holder->_angle_y_action)); + holder->_angle_y_adj->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*holder, &Box3DToolbar::angle_value_changed), + holder->_angle_y_adj, Proj::Y)); + gtk_action_group_add_action( mainActions, GTK_ACTION(holder->_angle_y_action) ); + } - g_object_set_data(G_OBJECT(tbl), "freeze", GINT_TO_POINTER(FALSE)); -} + if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::Y)) { + gtk_action_set_sensitive( GTK_ACTION(holder->_angle_y_action), TRUE ); + } else { + gtk_action_set_sensitive( GTK_ACTION(holder->_angle_y_action), FALSE ); + } -static Inkscape::XML::NodeEventVector box3d_persp_tb_repr_events = -{ - nullptr, /* child_added */ - nullptr, /* child_removed */ - box3d_persp_tb_event_attr_changed, - nullptr, /* content_changed */ - nullptr /* order_changed */ -}; + /* VP Y state */ + { + holder->_vp_y_state_action = ink_toggle_action_new( "3DBoxVPYStateAction", + // Translators: VP is short for 'vanishing point' + _("State of VP in Y direction"), + _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"), + INKSCAPE_ICON("perspective-parallel"), + GTK_ICON_SIZE_MENU ); + gtk_action_group_add_action( mainActions, GTK_ACTION( holder->_vp_y_state_action ) ); + g_signal_connect_after( G_OBJECT(holder->_vp_y_state_action), "toggled", G_CALLBACK(Box3DToolbar::vp_state_changed), (gpointer)Proj::Y); + gtk_action_set_sensitive( GTK_ACTION(holder->_angle_y_action), !prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(holder->_vp_y_state_action), prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) ); + } -/** - * \param selection Should not be NULL. - */ -// FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each -// Change of the perspective, and not of the current selection (but how to refer to the toolbar then?) -static void box3d_toolbox_selection_changed(Inkscape::Selection *selection, GObject *tbl) -{ - // Here the following should be done: If all selected boxes have finite VPs in a certain direction, - // disable the angle entry fields for this direction (otherwise entering a value in them should only - // update the perspectives with infinite VPs and leave the other ones untouched). + /* Angle Z */ + { + gchar const* labels[] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; + gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; + holder->_angle_z_action = create_adjustment_action( "3DBoxAngleZAction", + _("Angle in Z direction"), _("Angle Z:"), + // Translators: PL is short for 'perspective line' + _("Angle of PLs in Z direction"), + "/tools/shapes/3dbox/box3d_angle_z", 30, + GTK_WIDGET(desktop->canvas), + nullptr, // dataKludge + FALSE, nullptr, + -360.0, 360.0, 1.0, 10.0, + labels, values, G_N_ELEMENTS(labels), + nullptr // callback + ); + holder->_angle_z_adj = Glib::wrap(ege_adjustment_action_get_adjustment(holder->_angle_z_action)); + holder->_angle_z_adj->signal_value_changed().connect(sigc::bind(sigc::mem_fun(*holder, &Box3DToolbar::angle_value_changed), + holder->_angle_z_adj, Proj::Z)); + gtk_action_group_add_action( mainActions, GTK_ACTION(holder->_angle_z_action) ); + } - Inkscape::XML::Node *persp_repr = nullptr; - purge_repr_listener(tbl, tbl); + if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::Z)) { + gtk_action_set_sensitive( GTK_ACTION(holder->_angle_z_action), TRUE ); + } else { + gtk_action_set_sensitive( GTK_ACTION(holder->_angle_z_action), FALSE ); + } - SPItem *item = selection->singleItem(); - SPBox3D *box = dynamic_cast<SPBox3D *>(item); - if (box) { - // FIXME: Also deal with multiple selected boxes - Persp3D *persp = box3d_get_perspective(box); - persp_repr = persp->getRepr(); - if (persp_repr) { - g_object_set_data(tbl, "repr", persp_repr); - Inkscape::GC::anchor(persp_repr); - sp_repr_add_listener(persp_repr, &box3d_persp_tb_repr_events, tbl); - sp_repr_synthesize_events(persp_repr, &box3d_persp_tb_repr_events, tbl); + /* VP Z state */ + { + holder->_vp_z_state_action = ink_toggle_action_new( "3DBoxVPZStateAction", + // Translators: VP is short for 'vanishing point' + _("State of VP in Z direction"), + _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"), + INKSCAPE_ICON("perspective-parallel"), + GTK_ICON_SIZE_MENU ); + gtk_action_group_add_action( mainActions, GTK_ACTION( holder->_vp_z_state_action ) ); + g_signal_connect_after( G_OBJECT(holder->_vp_z_state_action), "toggled", G_CALLBACK(Box3DToolbar::vp_state_changed), (gpointer)Proj::Z ); + gtk_action_set_sensitive( GTK_ACTION(holder->_angle_z_action), !prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(holder->_vp_z_state_action), prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) ); + } - SP_ACTIVE_DOCUMENT->setCurrentPersp3D(persp3d_get_from_repr(persp_repr)); - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - prefs->setString("/tools/shapes/3dbox/persp", persp_repr->attribute("id")); + desktop->connectEventContextChanged(sigc::mem_fun(*holder, &Box3DToolbar::check_ec)); - g_object_set_data(tbl, "freeze", GINT_TO_POINTER(TRUE)); - box3d_resync_toolbar(persp_repr, tbl); - g_object_set_data(tbl, "freeze", GINT_TO_POINTER(FALSE)); - } - } + return GTK_WIDGET(holder->gobj()); } -static void box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, Proj::Axis axis) +void +Box3DToolbar::angle_value_changed(Glib::RefPtr<Gtk::Adjustment> &adj, + Proj::Axis axis) { - SPDesktop *desktop = static_cast<SPDesktop *>(g_object_get_data( dataKludge, "desktop" )); - SPDocument *document = desktop->getDocument(); + SPDocument *document = _desktop->getDocument(); // quit if run by the attr_changed or selection changed listener - if (g_object_get_data( dataKludge, "freeze" )) { + if (_freeze) { return; } // in turn, prevent listener from responding - g_object_set_data(dataKludge, "freeze", GINT_TO_POINTER(TRUE)); + _freeze = true; - std::list<Persp3D *> sel_persps = desktop->getSelection()->perspList(); + std::list<Persp3D *> sel_persps = _desktop->getSelection()->perspList(); if (sel_persps.empty()) { // this can happen when the document is created; we silently ignore it return; @@ -227,33 +235,18 @@ static void box3d_angle_value_changed(GtkAdjustment *adj, GObject *dataKludge, P Persp3D *persp = sel_persps.front(); persp->perspective_impl->tmat.set_infinite_direction (axis, - gtk_adjustment_get_value(adj)); + adj->get_value()); persp->updateRepr(); // TODO: use the correct axis here, too DocumentUndo::maybeDone(document, "perspangle", SP_VERB_CONTEXT_3DBOX, _("3D Box: Change perspective (angle of infinite axis)")); - g_object_set_data( dataKludge, "freeze", GINT_TO_POINTER(FALSE) ); + _freeze = false; } - -static void box3d_angle_x_value_changed(GtkAdjustment *adj, GObject *dataKludge) -{ - box3d_angle_value_changed(adj, dataKludge, Proj::X); -} - -static void box3d_angle_y_value_changed(GtkAdjustment *adj, GObject *dataKludge) -{ - box3d_angle_value_changed(adj, dataKludge, Proj::Y); -} - -static void box3d_angle_z_value_changed(GtkAdjustment *adj, GObject *dataKludge) -{ - box3d_angle_value_changed(adj, dataKludge, Proj::Z); -} - - -static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction * /*box3d_angle*/, Proj::Axis axis ) +void +Box3DToolbar::vp_state_changed(GtkToggleAction *act, + Proj::Axis axis ) { // TODO: Take all selected perspectives into account std::list<Persp3D *> sel_persps = SP_ACTIVE_DESKTOP->getSelection()->perspList(); @@ -267,167 +260,171 @@ static void box3d_vp_state_changed( GtkToggleAction *act, GtkAction * /*box3d_an persp3d_set_VP_state (persp, axis, set_infinite ? Proj::VP_INFINITE : Proj::VP_FINITE); } -static void box3d_vp_x_state_changed( GtkToggleAction *act, GtkAction *box3d_angle ) +void +Box3DToolbar::check_ec(SPDesktop* desktop, Inkscape::UI::Tools::ToolBase* ec) { - box3d_vp_state_changed(act, box3d_angle, Proj::X); -} - -static void box3d_vp_y_state_changed( GtkToggleAction *act, GtkAction *box3d_angle ) -{ - box3d_vp_state_changed(act, box3d_angle, Proj::Y); + if (SP_IS_BOX3D_CONTEXT(ec)) { + _changed = desktop->getSelection()->connectChanged(sigc::mem_fun(*this, &Box3DToolbar::selection_changed)); + selection_changed(desktop->getSelection()); + } else { + if (_changed) + _changed.disconnect(); + } } -static void box3d_vp_z_state_changed( GtkToggleAction *act, GtkAction *box3d_angle ) +Box3DToolbar::~Box3DToolbar() { - box3d_vp_state_changed(act, box3d_angle, Proj::Z); + if (_repr) { // remove old listener + _repr->removeListenerByData(this); + Inkscape::GC::release(_repr); + _repr = nullptr; + } } -static void box3d_toolbox_check_ec(SPDesktop* dt, Inkscape::UI::Tools::ToolBase* ec, GObject* holder); - -void box3d_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) +/** + * \param selection Should not be NULL. + */ +// FIXME: This should rather be put into persp3d-reference.cpp or something similar so that it reacts upon each +// Change of the perspective, and not of the current selection (but how to refer to the toolbar then?) +void +Box3DToolbar::selection_changed(Inkscape::Selection *selection) { - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); - EgeAdjustmentAction* eact = nullptr; - SPDocument *document = desktop->getDocument(); - Persp3DImpl *persp_impl = document->getCurrentPersp3DImpl(); + // Here the following should be done: If all selected boxes have finite VPs in a certain direction, + // disable the angle entry fields for this direction (otherwise entering a value in them should only + // update the perspectives with infinite VPs and leave the other ones untouched). - EgeAdjustmentAction* box3d_angle_x = nullptr; - EgeAdjustmentAction* box3d_angle_y = nullptr; - EgeAdjustmentAction* box3d_angle_z = nullptr; + Inkscape::XML::Node *persp_repr = nullptr; - /* Angle X */ - { - gchar const* labels[] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; - gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; - eact = create_adjustment_action( "3DBoxAngleXAction", - _("Angle in X direction"), _("Angle X:"), - // Translators: PL is short for 'perspective line' - _("Angle of PLs in X direction"), - "/tools/shapes/3dbox/box3d_angle_x", 30, - GTK_WIDGET(desktop->canvas), holder, TRUE, "altx-box3d", - -360.0, 360.0, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - box3d_angle_x_value_changed ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - g_object_set_data( holder, "box3d_angle_x_action", eact ); - box3d_angle_x = eact; + if (_repr) { // remove old listener + _repr->removeListenerByData(this); + Inkscape::GC::release(_repr); + _repr = nullptr; } - if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::X)) { - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } else { - gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); - } + SPItem *item = selection->singleItem(); + SPBox3D *box = dynamic_cast<SPBox3D *>(item); + if (box) { + // FIXME: Also deal with multiple selected boxes + Persp3D *persp = box3d_get_perspective(box); + persp_repr = persp->getRepr(); + if (persp_repr) { + _repr = persp_repr; + Inkscape::GC::anchor(_repr); + _repr->addListener(&box3d_persp_tb_repr_events, this); + _repr->synthesizeEvents(&box3d_persp_tb_repr_events, this); + SP_ACTIVE_DOCUMENT->setCurrentPersp3D(persp3d_get_from_repr(_repr)); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->setString("/tools/shapes/3dbox/persp", _repr->attribute("id")); - /* VP X state */ - { - InkToggleAction* act = ink_toggle_action_new( "3DBoxVPXStateAction", - // Translators: VP is short for 'vanishing point' - _("State of VP in X direction"), - _("Toggle VP in X direction between 'finite' and 'infinite' (=parallel)"), - INKSCAPE_ICON("perspective-parallel"), - GTK_ICON_SIZE_MENU ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "box3d_vp_x_state_action", act ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_x_state_changed), box3d_angle_x ); - gtk_action_set_sensitive( GTK_ACTION(box3d_angle_x), !prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_x_state", true) ); + _freeze = true; + resync_toolbar(_repr); + _freeze = false; + } } +} - /* Angle Y */ - { - gchar const* labels[] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; - gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; - eact = create_adjustment_action( "3DBoxAngleYAction", - _("Angle in Y direction"), _("Angle Y:"), - // Translators: PL is short for 'perspective line' - _("Angle of PLs in Y direction"), - "/tools/shapes/3dbox/box3d_angle_y", 30, - GTK_WIDGET(desktop->canvas), holder, FALSE, nullptr, - -360.0, 360.0, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - box3d_angle_y_value_changed ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - g_object_set_data( holder, "box3d_angle_y_action", eact ); - box3d_angle_y = eact; +void +Box3DToolbar::resync_toolbar(Inkscape::XML::Node *persp_repr) +{ + if (!persp_repr) { + g_print ("No perspective given to box3d_resync_toolbar().\n"); + return; } - if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::Y)) { - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); - } else { - gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); + Persp3D *persp = persp3d_get_from_repr(persp_repr); + if (!persp) { + // Hmm, is it an error if this happens? + return; } + set_button_and_adjustment(persp, Proj::X, + _angle_x_adj, + GTK_ACTION(_angle_x_action), + GTK_TOGGLE_ACTION(_vp_x_state_action)); + set_button_and_adjustment(persp, Proj::Y, + _angle_y_adj, + GTK_ACTION(_angle_y_action), + GTK_TOGGLE_ACTION(_vp_y_state_action)); + set_button_and_adjustment(persp, Proj::Z, + _angle_z_adj, + GTK_ACTION(_angle_z_action), + GTK_TOGGLE_ACTION(_vp_z_state_action)); +} - /* VP Y state */ - { - InkToggleAction* act = ink_toggle_action_new( "3DBoxVPYStateAction", - // Translators: VP is short for 'vanishing point' - _("State of VP in Y direction"), - _("Toggle VP in Y direction between 'finite' and 'infinite' (=parallel)"), - INKSCAPE_ICON("perspective-parallel"), - GTK_ICON_SIZE_MENU ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "box3d_vp_y_state_action", act ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_y_state_changed), box3d_angle_y ); - gtk_action_set_sensitive( GTK_ACTION(box3d_angle_y), !prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_y_state", true) ); - } +void +Box3DToolbar::set_button_and_adjustment(Persp3D *persp, + Proj::Axis axis, + Glib::RefPtr<Gtk::Adjustment>& adj, + GtkAction *act, + GtkToggleAction *tact) +{ + // TODO: Take all selected perspectives into account but don't touch the state button if not all of them + // have the same state (otherwise a call to box3d_vp_z_state_changed() is triggered and the states + // are reset). + bool is_infinite = !persp3d_VP_is_finite(persp->perspective_impl, axis); - /* Angle Z */ - { - gchar const* labels[] = { nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr }; - gdouble values[] = {-90, -60, -30, 0, 30, 60, 90}; - eact = create_adjustment_action( "3DBoxAngleZAction", - _("Angle in Z direction"), _("Angle Z:"), - // Translators: PL is short for 'perspective line' - _("Angle of PLs in Z direction"), - "/tools/shapes/3dbox/box3d_angle_z", 30, - GTK_WIDGET(desktop->canvas), holder, FALSE, nullptr, - -360.0, 360.0, 1.0, 10.0, - labels, values, G_N_ELEMENTS(labels), - box3d_angle_z_value_changed ); - gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); - g_object_set_data( holder, "box3d_angle_z_action", eact ); - box3d_angle_z = eact; - } + if (is_infinite) { + gtk_toggle_action_set_active(tact, TRUE); + gtk_action_set_sensitive(act, TRUE); - if (!persp_impl || !persp3d_VP_is_finite(persp_impl, Proj::Z)) { - gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); + double angle = persp3d_get_infinite_angle(persp, axis); + if (angle != Geom::infinity()) { // FIXME: We should catch this error earlier (don't show the spinbutton at all) + adj->set_value(normalize_angle(angle)); + } } else { - gtk_action_set_sensitive( GTK_ACTION(eact), FALSE ); + gtk_toggle_action_set_active(tact, FALSE); + gtk_action_set_sensitive(act, FALSE); } +} - /* VP Z state */ - { - InkToggleAction* act = ink_toggle_action_new( "3DBoxVPZStateAction", - // Translators: VP is short for 'vanishing point' - _("State of VP in Z direction"), - _("Toggle VP in Z direction between 'finite' and 'infinite' (=parallel)"), - INKSCAPE_ICON("perspective-parallel"), - GTK_ICON_SIZE_MENU ); - gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); - g_object_set_data( holder, "box3d_vp_z_state_action", act ); - g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(box3d_vp_z_state_changed), box3d_angle_z ); - gtk_action_set_sensitive( GTK_ACTION(box3d_angle_z), !prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) ); - gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/shapes/3dbox/vp_z_state", true) ); +void +Box3DToolbar::event_attr_changed(Inkscape::XML::Node *repr, + gchar const * /*name*/, + gchar const * /*old_value*/, + gchar const * /*new_value*/, + bool /*is_interactive*/, + gpointer data) +{ + auto toolbar = reinterpret_cast<Box3DToolbar*>(data); + + // quit if run by the attr_changed or selection changed listener + if (toolbar->_freeze) { + return; } - desktop->connectEventContextChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_check_ec), holder)); - g_signal_connect(holder, "destroy", G_CALLBACK(purge_repr_listener), holder); + // set freeze so that it can be caught in box3d_angle_z_value_changed() (to avoid calling + // SPDocumentUndo::maybeDone() when the document is undo insensitive) + toolbar->_freeze = true; + + // TODO: Only update the appropriate part of the toolbar +// if (!strcmp(name, "inkscape:vp_z")) { + toolbar->resync_toolbar(repr); +// } + + Persp3D *persp = persp3d_get_from_repr(repr); + persp3d_update_box_reprs(persp); + + toolbar->_freeze = false; } -static void box3d_toolbox_check_ec(SPDesktop* desktop, Inkscape::UI::Tools::ToolBase* ec, GObject* holder) -{ - static sigc::connection changed; - if (SP_IS_BOX3D_CONTEXT(ec)) { - changed = desktop->getSelection()->connectChanged(sigc::bind(sigc::ptr_fun(box3d_toolbox_selection_changed), holder)); - box3d_toolbox_selection_changed(desktop->getSelection(), holder); - } else { - if (changed) - changed.disconnect(); +/** + * \brief normalize angle so that it lies in the interval [0,360] + * + * TODO: Isn't there something in 2Geom or cmath that does this? + */ +double +Box3DToolbar::normalize_angle(double a) { + double angle = a + ((int) (a/360.0))*360; + if (angle < 0) { + angle += 360.0; } + return angle; +} + +} } +} + /* Local Variables: |
