From 9f236bc6030a2a59db714e41d366e63d8855683e Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Fri, 17 May 2019 14:17:49 +0200 Subject: [PATCH 1/4] Added transformation reset buttons in object manipulation panel --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 91 ++++++++++++++++++++++- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 10 ++- src/slic3r/GUI/OptionsGroup.cpp | 2 +- 3 files changed, 95 insertions(+), 8 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 5bf25f3fc..a67eaa4f0 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -190,8 +190,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : def.set_default_value(new ConfigOptionFloat(0.0)); def.width = field_width/*50*/; - // Add "uniform scaling" button in front of "Scale" option if (option_name == "Scale") { + // Add "uniform scaling" button in front of "Scale" option line.near_label_widget = [this](wxWindow* parent) { auto btn = new LockButton(parent, wxID_ANY); btn->Bind(wxEVT_BUTTON, [btn, this](wxCommandEvent &event){ @@ -201,8 +201,52 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : m_lock_bnt = btn; return btn; }; + // Add reset scale button + auto reset_scale_button = [=](wxWindow* parent) { + auto btn = new ScalableButton(parent, wxID_ANY, "colorchange_delete_off.png"); + btn->SetToolTip(_(L("Reset scale"))); + m_reset_scale_button = btn; + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(btn, wxBU_EXACTFIT); + btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) { + change_scale_value(0, 100.); + change_scale_value(1, 100.); + change_scale_value(2, 100.); + }); + return sizer; + }; + line.append_widget(reset_scale_button); } + else if (option_name == "Rotation") { + // Add reset rotation button + auto reset_rotation_button = [=](wxWindow* parent) { + auto btn = new ScalableButton(parent, wxID_ANY, "colorchange_delete_off.png"); + btn->SetToolTip(_(L("Reset rotation"))); + m_reset_rotation_button = btn; + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(btn, wxBU_EXACTFIT); + btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) { + // The following makes sure that the LOCAL coordinate system rotation is reset by calling + // methods that are readily available here - it is not nice but gets the work done. + GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); + Selection& selection = canvas->get_selection(); + GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); + if (selection.is_single_volume() || selection.is_single_modifier()) + volume->set_volume_rotation(Vec3d::Zero()); + else if (selection.is_single_full_instance()) + volume->set_instance_rotation(Vec3d::Zero()); + else + return; + + canvas->do_rotate(); + + UpdateAndShow(true); + }); + return sizer; + }; + line.append_widget(reset_rotation_button); + } // Add empty bmp (Its size have to be equal to PrusaLockButton) in front of "Size" option to label alignment else if (option_name == "Size") { line.near_label_widget = [this](wxWindow* parent) { @@ -224,8 +268,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : return line; }; - // Settings table + m_og->sidetext_width = 3; m_og->append_line(add_og_to_object_settings(L("Position"), L("mm")), &m_move_Label); m_og->append_line(add_og_to_object_settings(L("Rotation"), "°"), &m_rotate_Label); m_og->append_line(add_og_to_object_settings(L("Scale"), "%"), &m_scale_Label); @@ -408,9 +452,49 @@ void ObjectManipulation::update_if_dirty() else m_og->disable(); + update_reset_buttons_visibility(); + m_dirty = false; } + + +void ObjectManipulation::update_reset_buttons_visibility() +{ + GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); + if (!canvas) + return; + const Selection& selection = canvas->get_selection(); + + bool show_rotation = false; + bool show_scale = false; + + if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + Vec3d rotation; + Vec3d scale; + + if (selection.is_single_full_instance()) { + rotation = volume->get_instance_rotation(); + scale = volume->get_instance_scaling_factor(); + } + else { + rotation = volume->get_volume_rotation(); + scale = volume->get_volume_scaling_factor(); + } + show_rotation = !rotation.isApprox(Vec3d::Zero()); + show_scale = !scale.isApprox(Vec3d::Ones()); + } + + wxGetApp().CallAfter([this, show_rotation, show_scale]{ + m_reset_rotation_button->Show(show_rotation); + m_reset_scale_button->Show(show_scale); + }); +} + + + + #ifndef __APPLE__ void ObjectManipulation::emulate_kill_focus() { @@ -493,7 +577,7 @@ void ObjectManipulation::change_rotation_value(int axis, double value) m_cache.rotation = rotation; m_cache.rotation_rounded(axis) = DBL_MAX; - this->UpdateAndShow(true); + this->UpdateAndShow(true); } void ObjectManipulation::change_scale_value(int axis, double value) @@ -511,6 +595,7 @@ void ObjectManipulation::change_scale_value(int axis, double value) this->UpdateAndShow(true); } + void ObjectManipulation::change_size_value(int axis, double value) { if (std::abs(m_cache.size_rounded(axis) - value) < EPSILON) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 7c359f3d7..6a13a3c09 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -53,6 +53,10 @@ class ObjectManipulation : public OG_Settings wxStaticText* m_scale_Label = nullptr; wxStaticText* m_rotate_Label = nullptr; + // Non-owning pointers to the reset buttons, so we can hide and show them. + ScalableButton* m_reset_scale_button = nullptr; + ScalableButton* m_reset_rotation_button = nullptr; + // Needs to be updated from OnIdle? bool m_dirty = false; // Cached labels for the delayed update, not localized! @@ -111,10 +115,8 @@ private: void reset_settings_value(); void update_settings_value(const Selection& selection); - // update size values after scale unit changing or "gizmos" - void update_size_value(const Vec3d& size); - // update rotation value after "gizmos" - void update_rotation_value(const Vec3d& rotation); + // Show or hide scale/rotation reset buttons if needed + void update_reset_buttons_visibility(); // change values void change_position_value(int axis, double value); diff --git a/src/slic3r/GUI/OptionsGroup.cpp b/src/slic3r/GUI/OptionsGroup.cpp index 2ac6b00af..014932900 100644 --- a/src/slic3r/GUI/OptionsGroup.cpp +++ b/src/slic3r/GUI/OptionsGroup.cpp @@ -276,7 +276,7 @@ void OptionsGroup::append_line(const Line& line, wxStaticText** full_Label/* = n // add sidetext if any if (option.sidetext != "") { auto sidetext = new wxStaticText( this->ctrl_parent(), wxID_ANY, _(option.sidetext), wxDefaultPosition, - /*wxSize(sidetext_width*wxGetApp().em_unit(), -1)*/wxDefaultSize, wxALIGN_LEFT); + wxSize(sidetext_width != -1 ? sidetext_width*wxGetApp().em_unit() : -1, -1) /*wxDefaultSize*/, wxALIGN_LEFT); sidetext->SetBackgroundStyle(wxBG_STYLE_PAINT); sidetext->SetFont(wxGetApp().normal_font()); sizer_tmp->Add(sidetext, 0, wxLEFT | wxALIGN_CENTER_VERTICAL, 4); From a3c1644ead545bfac6aab46d5761c8521fc8d48c Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Mon, 3 Jun 2019 10:40:15 +0200 Subject: [PATCH 2/4] Added mirroring buttons into object manipulation panel --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 75 ++++++++++++++++++++++- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 5 ++ 2 files changed, 77 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index a67eaa4f0..c2782df2d 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -92,6 +92,7 @@ void msw_rescale_word_local_combo(wxBitmapComboBox* combo) combo->SetValue(selection); } + ObjectManipulation::ObjectManipulation(wxWindow* parent) : OG_Settings(parent, true) #ifndef __APPLE__ @@ -162,16 +163,50 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : const int field_width = 5; + // Mirror button size: + const int mirror_btn_width = 3; + // Legend for object modification line = Line{ "", "" }; def.label = ""; def.type = coString; - def.width = field_width/*50*/; + def.width = field_width - mirror_btn_width;//field_width/*50*/; for (const std::string axis : { "x", "y", "z" }) { const std::string label = boost::algorithm::to_upper_copy(axis); def.set_default_value(new ConfigOptionString{ " " + label }); Option option = Option(def, axis + "_axis_legend"); + + // We will add a button to toggle mirroring to each axis: + auto mirror_button = [=](wxWindow* parent) { + m_mirror_bitmap_on = ScalableBitmap(parent, "colorchange_add_on.png"); + m_mirror_bitmap_off = ScalableBitmap(parent, "colorchange_delete_off.png"); + auto btn = new ScalableButton(parent, wxID_ANY, "colorchange_delete_off.png", wxEmptyString, wxSize(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width)); + btn->SetToolTip(wxString::Format(_(L("Toggle %s axis mirroring")), boost::algorithm::to_upper_copy(axis))); + m_mirror_buttons[axis] = btn; + auto sizer = new wxBoxSizer(wxHORIZONTAL); + sizer->Add(btn, wxBU_EXACTFIT/* | wxRESERVE_SPACE_EVEN_IF_HIDDEN*/); + btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) { + wxWindow* btn = dynamic_cast(e.GetEventObject()); + Axis axis = (btn == m_mirror_buttons["x"] ? X : ( btn == m_mirror_buttons["y"] ? Y : Z)); + GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); + Selection& selection = canvas->get_selection(); + GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); + + if (selection.is_single_volume() || selection.is_single_modifier()) + volume->set_volume_mirror(axis, -volume->get_volume_mirror(axis)); + else if (selection.is_single_full_instance()) + volume->set_instance_mirror(axis, -volume->get_instance_mirror(axis)); + else + return; + canvas->do_mirror(); + canvas->set_as_dirty(); + UpdateAndShow(true); + }); + return sizer; + }; + + option.side_widget = mirror_button; line.append_option(option); } line.near_label_widget = [this](wxWindow* parent) { @@ -226,8 +261,6 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : auto sizer = new wxBoxSizer(wxHORIZONTAL); sizer->Add(btn, wxBU_EXACTFIT); btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) { - // The following makes sure that the LOCAL coordinate system rotation is reset by calling - // methods that are readily available here - it is not nice but gets the work done. GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); @@ -283,6 +316,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : ctrl->msw_rescale(); }; } + + void ObjectManipulation::Show(const bool show) { @@ -453,6 +488,7 @@ void ObjectManipulation::update_if_dirty() m_og->disable(); update_reset_buttons_visibility(); + update_mirror_buttons_visibility(); m_dirty = false; } @@ -494,6 +530,34 @@ void ObjectManipulation::update_reset_buttons_visibility() +void ObjectManipulation::update_mirror_buttons_visibility() +{ + GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); + Selection& selection = canvas->get_selection(); + std::array show = {false, false, false}; + + if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + Vec3d mirror; + + if (selection.is_single_full_instance()) + mirror = volume->get_instance_mirror(); + else + mirror = volume->get_volume_mirror(); + + for (unsigned char i=0; i<3; ++i) + show[i] = mirror[i] < 0.; + } + + wxGetApp().CallAfter([this, show]{ + m_mirror_buttons["x"]->SetBitmap(show[0] ? m_mirror_bitmap_on.bmp() : m_mirror_bitmap_off.bmp()); + m_mirror_buttons["y"]->SetBitmap(show[1] ? m_mirror_bitmap_on.bmp() : m_mirror_bitmap_off.bmp()); + m_mirror_buttons["z"]->SetBitmap(show[2] ? m_mirror_bitmap_on.bmp() : m_mirror_bitmap_off.bmp()); + }); +} + + + #ifndef __APPLE__ void ObjectManipulation::emulate_kill_focus() @@ -751,6 +815,11 @@ void ObjectManipulation::msw_rescale() m_manifold_warning_bmp.msw_rescale(); m_fix_throught_netfab_bitmap->SetBitmap(m_manifold_warning_bmp.bmp()); + m_mirror_bitmap_on.msw_rescale(); + m_mirror_bitmap_off.msw_rescale(); + m_reset_scale_button->msw_rescale(); + m_reset_rotation_button->msw_rescale(); + get_og()->msw_rescale(); } diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 6a13a3c09..11b07cda6 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -56,6 +56,9 @@ class ObjectManipulation : public OG_Settings // Non-owning pointers to the reset buttons, so we can hide and show them. ScalableButton* m_reset_scale_button = nullptr; ScalableButton* m_reset_rotation_button = nullptr; + std::map m_mirror_buttons; + ScalableBitmap m_mirror_bitmap_on; + ScalableBitmap m_mirror_bitmap_off; // Needs to be updated from OnIdle? bool m_dirty = false; @@ -117,6 +120,8 @@ private: // Show or hide scale/rotation reset buttons if needed void update_reset_buttons_visibility(); + //Show or hide mirror buttons + void update_mirror_buttons_visibility(); // change values void change_position_value(int axis, double value); From 980c6673d42e561d7bf53937e8213e2ce1f0e943 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 5 Jun 2019 11:23:30 +0200 Subject: [PATCH 3/4] Reset buttons - fixed rotation of instances with multiple volumes Mirroring buttons now hide where appropriate --- resources/icons/mirroring_off.png | Bin 0 -> 589 bytes resources/icons/mirroring_on.png | Bin 0 -> 600 bytes resources/icons/mirroring_transparent.png | Bin 0 -> 93 bytes src/slic3r/GUI/GUI_ObjectManipulation.cpp | 104 +++++++++++++++------- src/slic3r/GUI/GUI_ObjectManipulation.hpp | 12 ++- 5 files changed, 83 insertions(+), 33 deletions(-) create mode 100644 resources/icons/mirroring_off.png create mode 100644 resources/icons/mirroring_on.png create mode 100644 resources/icons/mirroring_transparent.png diff --git a/resources/icons/mirroring_off.png b/resources/icons/mirroring_off.png new file mode 100644 index 0000000000000000000000000000000000000000..c16655271a7e10d9d83047189086d4d6b509abc3 GIT binary patch literal 589 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S0wixl{&NRXEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZEE?e4>iGH4#PT$HOWYUVmw=D)W4<$2R?NV2M}KA?FdtNTmJp~!15S*|LT8;MoC zXsZ3%W24$-moh2c@9l*fmo+q>Gq62KSXA699k*xgMiDE{G|yhA4QhurtG<}@uu!C_ z<$>}m-=I62B~!k9UHS2l6URxP__|{b{!P~`Som^z%$(k+UE0pWDc5vL>wMPBh1~ac zOgPu;&>~>6W*@_Frwy&D=l0S8q@B+Qm*U`007}-kq7#>;Nm&p5M&yqHoBEQzy zY0CSzuP^(vnT8meSs9vI xnHp;w7+M(^oS(SL7)3*FeoAIqCAtPfD`O*whU@kljsZ0=c)I$ztaD0e0ssxu+3)}W literal 0 HcmV?d00001 diff --git a/resources/icons/mirroring_on.png b/resources/icons/mirroring_on.png new file mode 100644 index 0000000000000000000000000000000000000000..6ddeccbe0a2a82019c5c2efd1773c20c0833c4d4 GIT binary patch literal 600 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S3?yCqj{O5tEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBC{YpM6XNqfL!5oT`ng2Uv7KO- z`>oK>c;wi#w-Y8-9OfwbtPfPmnB?v5!uX#__a2bLS>O>_%)p?h48n{ROYO^mg6t)p zzOL*KxFrR+#s37PM*)TAdb&7gOf=4WlTK;F^nd^Dc_ijpxxR1T zX#3n&TDl=r(%}>cpt3=meXk`S|u=mmKH$V*x Mp00i_>zopr04OBpdH?_b literal 0 HcmV?d00001 diff --git a/resources/icons/mirroring_transparent.png b/resources/icons/mirroring_transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..841010fcc14ba7f06f09feae3affb3d9ba64c0f5 GIT binary patch literal 93 zcmeAS@N?(olHy`uVBq!ia0vp^!XV7S1|*9D%+3HQmSQK*5Dp-y;YjHK@SetToolTip(wxString::Format(_(L("Toggle %s axis mirroring")), boost::algorithm::to_upper_copy(axis))); - m_mirror_buttons[axis] = btn; + wxSize btn_size(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width); + auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off.png", wxEmptyString, btn_size, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW); + btn->SetToolTip(wxString::Format(_(L("Toggle %s axis mirroring")), label)); + + m_mirror_buttons[axis_idx].first = btn; + m_mirror_buttons[axis_idx].second = mbShown; auto sizer = new wxBoxSizer(wxHORIZONTAL); - sizer->Add(btn, wxBU_EXACTFIT/* | wxRESERVE_SPACE_EVEN_IF_HIDDEN*/); + sizer->Add(btn); + btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) { - wxWindow* btn = dynamic_cast(e.GetEventObject()); - Axis axis = (btn == m_mirror_buttons["x"] ? X : ( btn == m_mirror_buttons["y"] ? Y : Z)); + Axis axis = (Axis)(axis_idx + X); + if (m_mirror_buttons[axis_idx].second == mbHidden) + return; + GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); - GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); - if (selection.is_single_volume() || selection.is_single_modifier()) + if (selection.is_single_volume() || selection.is_single_modifier()) { + GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); volume->set_volume_mirror(axis, -volume->get_volume_mirror(axis)); - else if (selection.is_single_full_instance()) - volume->set_instance_mirror(axis, -volume->get_instance_mirror(axis)); + } + else if (selection.is_single_full_instance()) { + for (unsigned int idx : selection.get_volume_idxs()){ + GLVolume* volume = const_cast(selection.get_volume(idx)); + volume->set_instance_mirror(axis, -volume->get_instance_mirror(axis)); + } + } else return; + canvas->do_mirror(); canvas->set_as_dirty(); UpdateAndShow(true); @@ -238,7 +255,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : }; // Add reset scale button auto reset_scale_button = [=](wxWindow* parent) { - auto btn = new ScalableButton(parent, wxID_ANY, "colorchange_delete_off.png"); + auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo")); btn->SetToolTip(_(L("Reset scale"))); m_reset_scale_button = btn; auto sizer = new wxBoxSizer(wxHORIZONTAL); @@ -255,7 +272,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : else if (option_name == "Rotation") { // Add reset rotation button auto reset_rotation_button = [=](wxWindow* parent) { - auto btn = new ScalableButton(parent, wxID_ANY, "colorchange_delete_off.png"); + auto btn = new ScalableButton(parent, wxID_ANY, ScalableBitmap(parent, "undo")); btn->SetToolTip(_(L("Reset rotation"))); m_reset_rotation_button = btn; auto sizer = new wxBoxSizer(wxHORIZONTAL); @@ -263,12 +280,17 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) { GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); - GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); - if (selection.is_single_volume() || selection.is_single_modifier()) + if (selection.is_single_volume() || selection.is_single_modifier()) { + GLVolume* volume = const_cast(selection.get_volume(*selection.get_volume_idxs().begin())); volume->set_volume_rotation(Vec3d::Zero()); - else if (selection.is_single_full_instance()) - volume->set_instance_rotation(Vec3d::Zero()); + } + else if (selection.is_single_full_instance()) { + for (unsigned int idx : selection.get_volume_idxs()){ + GLVolume* volume = const_cast(selection.get_volume(idx)); + volume->set_instance_rotation(Vec3d::Zero()); + } + } else return; @@ -534,25 +556,42 @@ void ObjectManipulation::update_mirror_buttons_visibility() { GLCanvas3D* canvas = wxGetApp().plater()->canvas3D(); Selection& selection = canvas->get_selection(); - std::array show = {false, false, false}; + std::array new_states = {mbHidden, mbHidden, mbHidden}; - if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { - const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); - Vec3d mirror; + if (!m_world_coordinates) { + if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) { + const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin()); + Vec3d mirror; - if (selection.is_single_full_instance()) - mirror = volume->get_instance_mirror(); - else - mirror = volume->get_volume_mirror(); + if (selection.is_single_full_instance()) + mirror = volume->get_instance_mirror(); + else + mirror = volume->get_volume_mirror(); - for (unsigned char i=0; i<3; ++i) - show[i] = mirror[i] < 0.; + for (unsigned char i=0; i<3; ++i) + new_states[i] = (mirror[i] < 0. ? mbActive : mbShown); + } + } + else { + // the mirroring buttons should be hidden in world coordinates, + // unless we make it actually mirror in world coords. } - wxGetApp().CallAfter([this, show]{ - m_mirror_buttons["x"]->SetBitmap(show[0] ? m_mirror_bitmap_on.bmp() : m_mirror_bitmap_off.bmp()); - m_mirror_buttons["y"]->SetBitmap(show[1] ? m_mirror_bitmap_on.bmp() : m_mirror_bitmap_off.bmp()); - m_mirror_buttons["z"]->SetBitmap(show[2] ? m_mirror_bitmap_on.bmp() : m_mirror_bitmap_off.bmp()); + // Hiding the buttons through Hide() always messed up the sizers. As a workaround, the button + // is assigned a transparent bitmap. We must of course remember the actual state. + wxGetApp().CallAfter([this, new_states]{ + for (int i=0; i<3; ++i) { + if (new_states[i] != m_mirror_buttons[i].second) { + const wxBitmap* bmp; + switch (new_states[i]) { + case mbHidden : bmp = &m_mirror_bitmap_hidden.bmp(); m_mirror_buttons[i].first->Enable(false); break; + case mbShown : bmp = &m_mirror_bitmap_off.bmp(); m_mirror_buttons[i].first->Enable(true); break; + case mbActive : bmp = &m_mirror_bitmap_on.bmp(); m_mirror_buttons[i].first->Enable(true); break; + } + m_mirror_buttons[i].first->SetBitmap(*bmp); + m_mirror_buttons[i].second = new_states[i]; + } + } }); } @@ -817,6 +856,7 @@ void ObjectManipulation::msw_rescale() m_mirror_bitmap_on.msw_rescale(); m_mirror_bitmap_off.msw_rescale(); + m_mirror_bitmap_hidden.msw_rescale(); m_reset_scale_button->msw_rescale(); m_reset_rotation_button->msw_rescale(); diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.hpp b/src/slic3r/GUI/GUI_ObjectManipulation.hpp index 11b07cda6..cc2154514 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.hpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.hpp @@ -56,9 +56,19 @@ class ObjectManipulation : public OG_Settings // Non-owning pointers to the reset buttons, so we can hide and show them. ScalableButton* m_reset_scale_button = nullptr; ScalableButton* m_reset_rotation_button = nullptr; - std::map m_mirror_buttons; + + // Mirroring buttons and their current state + enum MirrorButtonState { + mbHidden, + mbShown, + mbActive + }; + std::array, 3> m_mirror_buttons; + + // Bitmaps for the mirroring buttons. ScalableBitmap m_mirror_bitmap_on; ScalableBitmap m_mirror_bitmap_off; + ScalableBitmap m_mirror_bitmap_hidden; // Needs to be updated from OnIdle? bool m_dirty = false; From 7b07a8da83633c5391b5b8ca8db5813ff1c367c9 Mon Sep 17 00:00:00 2001 From: Lukas Matena Date: Wed, 5 Jun 2019 15:27:20 +0200 Subject: [PATCH 4/4] Reset buttons: synchronization of instances/volumes --- src/slic3r/GUI/GUI_ObjectManipulation.cpp | 5 +++++ src/slic3r/GUI/Selection.hpp | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/slic3r/GUI/GUI_ObjectManipulation.cpp b/src/slic3r/GUI/GUI_ObjectManipulation.cpp index 2cbd048e5..224c053e4 100644 --- a/src/slic3r/GUI/GUI_ObjectManipulation.cpp +++ b/src/slic3r/GUI/GUI_ObjectManipulation.cpp @@ -216,6 +216,9 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : else return; + selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); + selection.synchronize_unselected_volumes(); + canvas->do_mirror(); canvas->set_as_dirty(); UpdateAndShow(true); @@ -294,6 +297,8 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) : else return; + selection.synchronize_unselected_instances(Selection::SYNC_ROTATION_GENERAL); + selection.synchronize_unselected_volumes(); canvas->do_rotate(); UpdateAndShow(true); diff --git a/src/slic3r/GUI/Selection.hpp b/src/slic3r/GUI/Selection.hpp index 54bf52706..5da1e477b 100644 --- a/src/slic3r/GUI/Selection.hpp +++ b/src/slic3r/GUI/Selection.hpp @@ -333,6 +333,8 @@ private: void render_sidebar_rotation_hint(Axis axis) const; void render_sidebar_scale_hint(Axis axis) const; void render_sidebar_size_hint(Axis axis, double length) const; + +public: enum SyncRotationType { // Do not synchronize rotation. Either not rotating at all, or rotating by world Z axis. SYNC_ROTATION_NONE = 0, @@ -343,6 +345,8 @@ private: }; void synchronize_unselected_instances(SyncRotationType sync_rotation_type); void synchronize_unselected_volumes(); + +private: void ensure_on_bed(); bool is_from_fully_selected_instance(unsigned int volume_idx) const;