diff --git a/src/slic3r/GUI/GUI_ObjectList.cpp b/src/slic3r/GUI/GUI_ObjectList.cpp index eb34e1251..9a789633f 100644 --- a/src/slic3r/GUI/GUI_ObjectList.cpp +++ b/src/slic3r/GUI/GUI_ObjectList.cpp @@ -66,9 +66,12 @@ ObjectList::ObjectList(wxWindow* parent) : // describe control behavior Bind(wxEVT_DATAVIEW_SELECTION_CHANGED, [this](wxEvent& event) { -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - std::cout << "SELECTION_CHANGED" << std::endl; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +#ifndef __APPLE__ + // On Windows and Linux, forces a kill focus emulation on the object manipulator fields because this event handler is called + // before the kill focus event handler on the object manipulator when changing selection in the list, invalidating the object + // manipulator cache with the following call to selection_changed() + wxGetApp().obj_manipul()->emulate_kill_focus(); +#endif // __APPLE__ selection_changed(); #ifndef __WXMSW__ set_tooltip_for_item(get_mouse_position_in_control()); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 86c9fda09..dc725bf88 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -17,85 +17,23 @@ namespace GUI ObjectManipulation::ObjectManipulation(wxWindow* parent) : OG_Settings(parent, true) +#ifndef __APPLE__ + , m_focused_option("") +#endif // __APPLE__ { m_og->set_name(_(L("Object Manipulation"))); m_og->label_width = 125; m_og->set_grid_vgap(5); - m_og->m_on_change = [this](const std::string& opt_key, const boost::any& value) { - // needed to hide the visual hints in 3D scene - wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false); - -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - std::cout << "KILL_FOCUS" << std::endl; -//@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ - - if (!m_cache.is_valid()) - return; - - std::vector axes{ "_x", "_y", "_z" }; - - std::string param; - std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param)); - - size_t i = 0; - Vec3d new_value; - for (auto axis : axes) - new_value(i++) = boost::any_cast(m_og->get_value(param+axis)); - - if (param == "position") - change_position_value(new_value); - else if (param == "rotation") - change_rotation_value(new_value); - else if (param == "scale") - change_scale_value(new_value); - else if (param == "size") - change_size_value(new_value); - }; - - m_og->m_fill_empty_value = [this](const std::string& opt_key) - { - // needed to hide the visual hints in 3D scene - wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false); - - if (!m_cache.is_valid()) - return; - - std::string param; - std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param)); - - double value = 0.0; - - if (param == "position") { - int axis = opt_key.back() == 'x' ? 0 : - opt_key.back() == 'y' ? 1 : 2; - - value = m_cache.position(axis); - } - else if (param == "rotation") { - int axis = opt_key.back() == 'x' ? 0 : - opt_key.back() == 'y' ? 1 : 2; - - value = m_cache.rotation(axis); - } - else if (param == "scale") { - int axis = opt_key.back() == 'x' ? 0 : - opt_key.back() == 'y' ? 1 : 2; - - value = m_cache.scale(axis); - } - else if (param == "size") { - int axis = opt_key.back() == 'x' ? 0 : - opt_key.back() == 'y' ? 1 : 2; - - value = m_cache.size(axis); - } - - m_og->set_value(opt_key, double_to_string(value)); - }; + m_og->m_on_change = std::bind(&ObjectManipulation::on_change, this, std::placeholders::_1, std::placeholders::_2); + m_og->m_fill_empty_value = std::bind(&ObjectManipulation::on_fill_empty_value, this, std::placeholders::_1); m_og->m_set_focus = [this](const std::string& opt_key) { +#ifndef __APPLE__ + m_focused_option = opt_key; +#endif // __APPLE__ + // needed to show the visual hints in 3D scene wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, true); }; @@ -383,6 +321,23 @@ void ObjectManipulation::update_if_dirty() m_dirty = false; } +#ifndef __APPLE__ +void ObjectManipulation::emulate_kill_focus() +{ + if (m_focused_option.empty()) + return; + + // we need to use a copy because the value of m_focused_option is modified inside on_change() and on_fill_empty_value() + std::string option = m_focused_option; + + // see TextCtrl::propagate_value() + if (static_cast(m_og->get_fieldc(option, 0)->getWindow())->GetValue().empty()) + on_fill_empty_value(option); + else + on_change(option, 0); +} +#endif // __APPLE__ + void ObjectManipulation::reset_settings_value() { m_new_position = Vec3d::Zero(); @@ -504,5 +459,80 @@ void ObjectManipulation::change_size_value(const Vec3d& size) m_cache.size = size; } +void ObjectManipulation::on_change(const t_config_option_key& opt_key, const boost::any& value) +{ + // needed to hide the visual hints in 3D scene + wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false); +#ifndef __APPLE__ + m_focused_option = ""; +#endif // __APPLE__ + + if (!m_cache.is_valid()) + return; + + std::vector axes{ "_x", "_y", "_z" }; + + std::string param; + std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param)); + + size_t i = 0; + Vec3d new_value; + for (auto axis : axes) + new_value(i++) = boost::any_cast(m_og->get_value(param + axis)); + + if (param == "position") + change_position_value(new_value); + else if (param == "rotation") + change_rotation_value(new_value); + else if (param == "scale") + change_scale_value(new_value); + else if (param == "size") + change_size_value(new_value); +} + +void ObjectManipulation::on_fill_empty_value(const std::string& opt_key) +{ + // needed to hide the visual hints in 3D scene + wxGetApp().plater()->canvas3D()->handle_sidebar_focus_event(opt_key, false); +#ifndef __APPLE__ + m_focused_option = ""; +#endif // __APPLE__ + + if (!m_cache.is_valid()) + return; + + std::string param; + std::copy(opt_key.begin(), opt_key.end() - 2, std::back_inserter(param)); + + double value = 0.0; + + if (param == "position") { + int axis = opt_key.back() == 'x' ? 0 : + opt_key.back() == 'y' ? 1 : 2; + + value = m_cache.position(axis); + } + else if (param == "rotation") { + int axis = opt_key.back() == 'x' ? 0 : + opt_key.back() == 'y' ? 1 : 2; + + value = m_cache.rotation(axis); + } + else if (param == "scale") { + int axis = opt_key.back() == 'x' ? 0 : + opt_key.back() == 'y' ? 1 : 2; + + value = m_cache.scale(axis); + } + else if (param == "size") { + int axis = opt_key.back() == 'x' ? 0 : + opt_key.back() == 'y' ? 1 : 2; + + value = m_cache.size(axis); + } + + m_og->set_value(opt_key, double_to_string(value)); +} + } //namespace GUI } //namespace Slic3r \ No newline at end of file diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index b761beda8..16160c84d 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -77,6 +77,11 @@ class ObjectManipulation : public OG_Settings bool m_uniform_scale {true}; PrusaLockButton* m_lock_bnt{ nullptr }; +#ifndef __APPLE__ + // Currently focused option name (empty if none) + std::string m_focused_option; +#endif // __APPLE__ + public: ObjectManipulation(wxWindow* parent); ~ObjectManipulation() {} @@ -94,6 +99,12 @@ public: bool get_uniform_scaling() const { return m_uniform_scale; } void reset_cache() { m_cache.reset(); } +#ifndef __APPLE__ + // On Windows and Linux, emulates a kill focus event on the currently focused option (if any) + // Used only in ObjectList wxEVT_DATAVIEW_SELECTION_CHANGED handler which is called before the regular kill focus event + // bound to this class when changing selection in the objects list + void emulate_kill_focus(); +#endif // __APPLE__ private: void reset_settings_value(); @@ -108,6 +119,9 @@ private: void change_rotation_value(const Vec3d& rotation); void change_scale_value(const Vec3d& scale); void change_size_value(const Vec3d& size); + + void on_change(const t_config_option_key& opt_key, const boost::any& value); + void on_fill_empty_value(const std::string& opt_key); }; }}