Reset buttons - fixed rotation of instances with multiple volumes
Mirroring buttons now hide where appropriate
This commit is contained in:
parent
a3c1644ead
commit
980c6673d4
BIN
resources/icons/mirroring_off.png
Normal file
BIN
resources/icons/mirroring_off.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 589 B |
BIN
resources/icons/mirroring_on.png
Normal file
BIN
resources/icons/mirroring_on.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 600 B |
BIN
resources/icons/mirroring_transparent.png
Normal file
BIN
resources/icons/mirroring_transparent.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 93 B |
@ -172,33 +172,50 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||||||
def.type = coString;
|
def.type = coString;
|
||||||
def.width = field_width - mirror_btn_width;//field_width/*50*/;
|
def.width = field_width - mirror_btn_width;//field_width/*50*/;
|
||||||
|
|
||||||
|
// Load bitmaps to be used for the mirroring buttons:
|
||||||
|
m_mirror_bitmap_on = ScalableBitmap(parent, "mirroring_on.png");
|
||||||
|
m_mirror_bitmap_off = ScalableBitmap(parent, "mirroring_off.png");
|
||||||
|
m_mirror_bitmap_hidden = ScalableBitmap(parent, "mirroring_transparent.png");
|
||||||
|
|
||||||
for (const std::string axis : { "x", "y", "z" }) {
|
for (const std::string axis : { "x", "y", "z" }) {
|
||||||
const std::string label = boost::algorithm::to_upper_copy(axis);
|
const std::string label = boost::algorithm::to_upper_copy(axis);
|
||||||
def.set_default_value(new ConfigOptionString{ " " + label });
|
def.set_default_value(new ConfigOptionString{ " " + label });
|
||||||
Option option = Option(def, axis + "_axis_legend");
|
Option option = Option(def, axis + "_axis_legend");
|
||||||
|
|
||||||
|
unsigned int axis_idx = (axis[0] - 'x'); // 0, 1 or 2
|
||||||
|
|
||||||
// We will add a button to toggle mirroring to each axis:
|
// We will add a button to toggle mirroring to each axis:
|
||||||
auto mirror_button = [=](wxWindow* parent) {
|
auto mirror_button = [=](wxWindow* parent) {
|
||||||
m_mirror_bitmap_on = ScalableBitmap(parent, "colorchange_add_on.png");
|
wxSize btn_size(em_unit(parent) * mirror_btn_width, em_unit(parent) * mirror_btn_width);
|
||||||
m_mirror_bitmap_off = ScalableBitmap(parent, "colorchange_delete_off.png");
|
auto btn = new ScalableButton(parent, wxID_ANY, "mirroring_off.png", wxEmptyString, btn_size, wxDefaultPosition, wxBU_EXACTFIT | wxNO_BORDER | wxTRANSPARENT_WINDOW);
|
||||||
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")), label));
|
||||||
btn->SetToolTip(wxString::Format(_(L("Toggle %s axis mirroring")), boost::algorithm::to_upper_copy(axis)));
|
|
||||||
m_mirror_buttons[axis] = btn;
|
m_mirror_buttons[axis_idx].first = btn;
|
||||||
|
m_mirror_buttons[axis_idx].second = mbShown;
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
sizer->Add(btn, wxBU_EXACTFIT/* | wxRESERVE_SPACE_EVEN_IF_HIDDEN*/);
|
sizer->Add(btn);
|
||||||
|
|
||||||
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
||||||
wxWindow* btn = dynamic_cast<wxWindow*>(e.GetEventObject());
|
Axis axis = (Axis)(axis_idx + X);
|
||||||
Axis axis = (btn == m_mirror_buttons["x"] ? X : ( btn == m_mirror_buttons["y"] ? Y : Z));
|
if (m_mirror_buttons[axis_idx].second == mbHidden)
|
||||||
|
return;
|
||||||
|
|
||||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
Selection& selection = canvas->get_selection();
|
Selection& selection = canvas->get_selection();
|
||||||
GLVolume* volume = const_cast<GLVolume*>(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<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()));
|
||||||
volume->set_volume_mirror(axis, -volume->get_volume_mirror(axis));
|
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<GLVolume*>(selection.get_volume(idx));
|
||||||
|
volume->set_instance_mirror(axis, -volume->get_instance_mirror(axis));
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
canvas->do_mirror();
|
canvas->do_mirror();
|
||||||
canvas->set_as_dirty();
|
canvas->set_as_dirty();
|
||||||
UpdateAndShow(true);
|
UpdateAndShow(true);
|
||||||
@ -238,7 +255,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||||||
};
|
};
|
||||||
// Add reset scale button
|
// Add reset scale button
|
||||||
auto reset_scale_button = [=](wxWindow* parent) {
|
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")));
|
btn->SetToolTip(_(L("Reset scale")));
|
||||||
m_reset_scale_button = btn;
|
m_reset_scale_button = btn;
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
@ -255,7 +272,7 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||||||
else if (option_name == "Rotation") {
|
else if (option_name == "Rotation") {
|
||||||
// Add reset rotation button
|
// Add reset rotation button
|
||||||
auto reset_rotation_button = [=](wxWindow* parent) {
|
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")));
|
btn->SetToolTip(_(L("Reset rotation")));
|
||||||
m_reset_rotation_button = btn;
|
m_reset_rotation_button = btn;
|
||||||
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
auto sizer = new wxBoxSizer(wxHORIZONTAL);
|
||||||
@ -263,12 +280,17 @@ ObjectManipulation::ObjectManipulation(wxWindow* parent) :
|
|||||||
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
btn->Bind(wxEVT_BUTTON, [=](wxCommandEvent &e) {
|
||||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
Selection& selection = canvas->get_selection();
|
Selection& selection = canvas->get_selection();
|
||||||
GLVolume* volume = const_cast<GLVolume*>(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<GLVolume*>(selection.get_volume(*selection.get_volume_idxs().begin()));
|
||||||
volume->set_volume_rotation(Vec3d::Zero());
|
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<GLVolume*>(selection.get_volume(idx));
|
||||||
|
volume->set_instance_rotation(Vec3d::Zero());
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -534,25 +556,42 @@ void ObjectManipulation::update_mirror_buttons_visibility()
|
|||||||
{
|
{
|
||||||
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
GLCanvas3D* canvas = wxGetApp().plater()->canvas3D();
|
||||||
Selection& selection = canvas->get_selection();
|
Selection& selection = canvas->get_selection();
|
||||||
std::array<bool, 3> show = {false, false, false};
|
std::array<MirrorButtonState, 3> new_states = {mbHidden, mbHidden, mbHidden};
|
||||||
|
|
||||||
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
if (!m_world_coordinates) {
|
||||||
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
if (selection.is_single_full_instance() || selection.is_single_modifier() || selection.is_single_volume()) {
|
||||||
Vec3d mirror;
|
const GLVolume* volume = selection.get_volume(*selection.get_volume_idxs().begin());
|
||||||
|
Vec3d mirror;
|
||||||
|
|
||||||
if (selection.is_single_full_instance())
|
if (selection.is_single_full_instance())
|
||||||
mirror = volume->get_instance_mirror();
|
mirror = volume->get_instance_mirror();
|
||||||
else
|
else
|
||||||
mirror = volume->get_volume_mirror();
|
mirror = volume->get_volume_mirror();
|
||||||
|
|
||||||
for (unsigned char i=0; i<3; ++i)
|
for (unsigned char i=0; i<3; ++i)
|
||||||
show[i] = mirror[i] < 0.;
|
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]{
|
// Hiding the buttons through Hide() always messed up the sizers. As a workaround, the button
|
||||||
m_mirror_buttons["x"]->SetBitmap(show[0] ? m_mirror_bitmap_on.bmp() : m_mirror_bitmap_off.bmp());
|
// is assigned a transparent bitmap. We must of course remember the actual state.
|
||||||
m_mirror_buttons["y"]->SetBitmap(show[1] ? m_mirror_bitmap_on.bmp() : m_mirror_bitmap_off.bmp());
|
wxGetApp().CallAfter([this, new_states]{
|
||||||
m_mirror_buttons["z"]->SetBitmap(show[2] ? m_mirror_bitmap_on.bmp() : m_mirror_bitmap_off.bmp());
|
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_on.msw_rescale();
|
||||||
m_mirror_bitmap_off.msw_rescale();
|
m_mirror_bitmap_off.msw_rescale();
|
||||||
|
m_mirror_bitmap_hidden.msw_rescale();
|
||||||
m_reset_scale_button->msw_rescale();
|
m_reset_scale_button->msw_rescale();
|
||||||
m_reset_rotation_button->msw_rescale();
|
m_reset_rotation_button->msw_rescale();
|
||||||
|
|
||||||
|
@ -56,9 +56,19 @@ class ObjectManipulation : public OG_Settings
|
|||||||
// Non-owning pointers to the reset buttons, so we can hide and show them.
|
// Non-owning pointers to the reset buttons, so we can hide and show them.
|
||||||
ScalableButton* m_reset_scale_button = nullptr;
|
ScalableButton* m_reset_scale_button = nullptr;
|
||||||
ScalableButton* m_reset_rotation_button = nullptr;
|
ScalableButton* m_reset_rotation_button = nullptr;
|
||||||
std::map<std::string, ScalableButton*> m_mirror_buttons;
|
|
||||||
|
// Mirroring buttons and their current state
|
||||||
|
enum MirrorButtonState {
|
||||||
|
mbHidden,
|
||||||
|
mbShown,
|
||||||
|
mbActive
|
||||||
|
};
|
||||||
|
std::array<std::pair<ScalableButton*, MirrorButtonState>, 3> m_mirror_buttons;
|
||||||
|
|
||||||
|
// Bitmaps for the mirroring buttons.
|
||||||
ScalableBitmap m_mirror_bitmap_on;
|
ScalableBitmap m_mirror_bitmap_on;
|
||||||
ScalableBitmap m_mirror_bitmap_off;
|
ScalableBitmap m_mirror_bitmap_off;
|
||||||
|
ScalableBitmap m_mirror_bitmap_hidden;
|
||||||
|
|
||||||
// Needs to be updated from OnIdle?
|
// Needs to be updated from OnIdle?
|
||||||
bool m_dirty = false;
|
bool m_dirty = false;
|
||||||
|
Loading…
Reference in New Issue
Block a user